|
|
View previous topic :: View next topic |
Author |
Message |
fmartinezs
Joined: 16 Aug 2006 Posts: 19
|
Question regarding SPI using low bit rate |
Posted: Wed Nov 30, 2022 8:34 am |
|
|
Hello everyone:
I need to talk to a device (send and receive data) which has an synchronous serial port; the device acts as a DTE, and expects the DCE (modem) to provide both TX and RX clocks. The PIC would be "impersonating" the modem and providing an asynchronous serial port, so I can TX and RX data from the device with a PC. I'm using a PIC24FJ128GB202, as I have several of them lying around.
As a proof of concept, I just want to read from UART and send with SPI, but I have a problem I can't get a grip on: The baud rate the device expects is 2400 [bps], and the compiler complain it's too low of a baud rate...
So I tried to get the clock from TIMER2, and then the compiler complained it doesn't know the option SPI_CLK_T2 for setup_spi()...
This is the code I have so far, as you see, is very basic...
main.c
Code: |
#include <24FJ128GB202.h>
#include "spi_modes.h"
#fuses HS
#fuses LVR
#fuses NOWDT
#fuses NOJTAG
#fuses NOPLL
#fuses NOIESO
#fuses CKSFSM
#fuses NOBROWNOUT
#fuses NODEBUG
#fuses NOPROTECT
#fuses NOWRT
//#pin_select function = pin
#pin_select U1RX = PIN_B9
#pin_select U1TX = PIN_B8
#pin_select SCK1OUT = PIN_B15
#pin_select SCK1IN = PIN_B15
#pin_select SDI1 = PIN_B14
#pin_select SDO1 = PIN_B13
#use delay(clock=20M, type=xtal)
#use rs232(UART1, stream = PC, baud=4800, RCV=PIN_B9, XMIT=PIN_B8, parity=N, bits=8, STOP=1, ERRORS)
//#use spi(SPI1, stream = SYNC, baud = 2400)
#use standard_io(A)
#use standard_io(B)
/////////////////////////
// INTERRUPTS HANDLERS //
/////////////////////////
////////////////////////////////////////////
// Serial port 1 data reception interrupt //
////////////////////////////////////////////
#INT_RDA
void serial_rx1_isr()
{
unsigned int8 data1;
data1 = getc(PC);
fputc(data1,PC);
}
///////////////////////
// Timer 2 interrupt //
///////////////////////
void timer2_isr()
{
output_toggle(PIN_A0);
}
////////////////////////////////////
// Main routine and infinite loop //
////////////////////////////////////
void main(void)
{
setup_timer2(TMR_INTERNAL|TMR_DIV_BY_1,2080);
//setup_spi(SPI_MASTER|SPI_CLK_T2|SPI_SS_DISABLED|SPI_MODE_1);
enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA);
enable_interrupts(INT_TIMER2);
while(1)
{
}
}
|
spi_modes.h
Code: |
// MOTOROLA | MICROCHIP | CCS
//-----------------------------------------------------------------------
// SPI Mode 0,0 | CKP = 0, CKE = 1 | SPI_L_TO_H | SPI_XMIT_L_TO_H
// SPI Mode 0,1 | CKP = 0, CKE = 0 | SPI_L_TO_H
// SPI Mode 1,0 | CKP = 1, CKE = 1 | SPI_H_TO_L
// SPI Mode 1,1 | CKP = 1, CKE = 0 | SPI_H_TO_L | SPI_XMIT_L_TO_H
#define SPI_MODE_0_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_0_1 (SPI_L_TO_H)
#define SPI_MODE_1_0 (SPI_H_TO_L)
#define SPI_MODE_1_1 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
#define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1 (SPI_L_TO_H)
#define SPI_MODE_2 (SPI_H_TO_L)
#define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
|
The serial isr just sends back anything you send it; that's where i'd include the spi_xfer() or spi_write() functions if required.
I'm stuck so far, as I have no idea how to make the SPI peripheral work at 2400 bps.
Any help will be appreciated.
Best regards,
Fernando |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1909
|
|
Posted: Wed Nov 30, 2022 9:33 am |
|
|
Just directly configure the SPI yourself by setting the SPI registers to what they should be and test.
The SPI's baud rate register allows 13 bits (0 - 8191 valid). The equation for the SPI speed can be found on the bottom of page 243 of the data sheet and is:
SPI speed (baud rate) = peripheral bus clock / (2 * (baud register + 1))
Not sure what your peripheral bus's clock source is, but if you use the 20MHz you show in your code, then a baud register setting of 4167 would give you an SPI baud rate of 2399.2 Hz. Good enough for your modem. |
|
|
fmartinezs
Joined: 16 Aug 2006 Posts: 19
|
|
Posted: Wed Nov 30, 2022 9:54 am |
|
|
Thanks newguy, I will try your suggestion and comment how it went down.
Best regards,
Fernando. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Wed Nov 30, 2022 11:20 am |
|
|
Or just use software SPI. Can go as slow as you want.
The SPI is not like the MSSP. It doesn't offer an option to use Timer2.
Only MCLK or PBCLK. MCLK is Fosc, not Fosc/2. So NewGuy's calculation
is out by a factor of 2.
The SPBRG, is only an 13bit register on this chip. So off the MCLK
can't quite get to the frequency. Hence the error. What you need to do
is force PBCLK to be used. This then would allow the frequency.
Ask CCS if there is an option to select PBCLK. It is Fosc/2, so would
work.
What you post can't compile since the clock setup uses the wrong syntax.
You want:
#use delay(crystal=20M)
'type' is not a keyword here...
Last edited by Ttelmah on Thu Dec 01, 2022 2:35 am; edited 2 times in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Thu Dec 01, 2022 2:25 am |
|
|
OK. Hopefully CCS will give a tidier way to do this, but I've patched your
code to select PBCLK:
Code: |
#include <24FJ128GB202.h>
#include "spi_modes.h"
#fuses LVR
#fuses NOWDT
#fuses NOJTAG
#fuses NOPLL
#fuses NOIESO
#fuses CKSFSM
#fuses NOBROWNOUT
#fuses NODEBUG
#fuses NOPROTECT
#fuses NOWRT
//#pin_select function = pin
#pin_select U1RX = PIN_B9
#pin_select U1TX = PIN_B8
#pin_select SCK1OUT = PIN_B15
#pin_select SCK1IN = PIN_B15
#pin_select SDI1 = PIN_B14
#pin_select SDO1 = PIN_B13
#use delay(crystal=20M)
#use rs232(UART1, stream = PC, baud=4800, RCV=PIN_B9, XMIT=PIN_B8, parity=N, bits=8, STOP=1, ERRORS)
#use spi(SPI1, stream = SYNC, baud = 9600) //select an accepted rate
#use standard_io(A)
#use standard_io(B)
#bit MCLKEN=getenv("BIT:MCLKEN")
#bit SPIEN=getenv("BIT:SPIEN")
#word SPIBRG=getenv("SPIBRG")
/////////////////////////
// INTERRUPTS HANDLERS //
/////////////////////////
////////////////////////////////////////////
// Serial port 1 data reception interrupt //
////////////////////////////////////////////
#INT_RDA
void serial_rx1_isr()
{
unsigned int8 data1;
data1 = getc(PC);
fputc(data1,PC);
}
///////////////////////
// Timer 2 interrupt //
///////////////////////
void timer2_isr()
{
output_toggle(PIN_A0);
}
////////////////////////////////////
// Main routine and infinite loop //
////////////////////////////////////
void main(void)
{
SPIEN=FALSE; //SPI has to be off for baud changes
/* The code is already setting this so only need to change BRG
//Now need to switch SPI to /2
MCLKEN=0; //select PBCLK
*/
//Now set the BRG - PBCLK is Fosc/2, and division is by 2*(BRG+1)
//so BRG needs to be 2081
SPIBRG=2081;
SPIEN=TRUE; //should now be running at 2400bps
enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA);
enable_interrupts(INT_TIMER2);
while(1)
{
}
}
|
Touch wood on this, but it should now be running at 2400.
I must admit I'm slightly suspicious that CCS may only be treating the
BRG register as 12bits not 13bits. Working from the master oscillator,
they seem to limit the minimum baud higher than I'd expect.
Be aware that you can put modes directly into #use SPI, and these
will correctly apply to the port setup with this.
Last edited by Ttelmah on Fri Dec 02, 2022 3:28 am; edited 1 time in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Fri Dec 02, 2022 2:18 am |
|
|
Edit:
Change the SPIBRG line to:
#word SPIBRG= 0x310 //getenv("SPIBRG")
Just looked at the assembler generated, and the compiler is not correctly
finding the SPIBRG register!.
It thinks SPIBRG is W0. Duh!...
Also a quick check shows it is calculating the value it puts into BRG
incorrectly. Seems to be limiting it way below what is actually allowed
as well...
The code is already selecting PBCLK. It is only limiting the SPBRG value
so I've amended the post above to reflect this. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Sat Dec 03, 2022 6:05 am |
|
|
As a further thought, you do realise that the UART's are capable of
generating a clock during I/O at 16* the baud rate?. This is used in the
IRDA mode to clock this. Strikes me that if you added an external /16
divider, you might be able to use this to give the required clocks, and
use a UART instead of the SPI. Might just be worth investigating.
Do you need the cryptographic engine?. If not there are other PIC's
in the same footprint, that have a USART instead of a UART, so could
operate this in synchronous mode.
Just thoughts. |
|
|
fmartinezs
Joined: 16 Aug 2006 Posts: 19
|
|
Posted: Tue Jan 03, 2023 9:46 am |
|
|
Hello Mr. T:
First I have to excuse myself, I had to work on other projects, so I left this somewhat abandoned... I have time now, so I'll get back to it.
I noticed you put a lot of effort in this, so thank you very very much, and I'll try this out as soon as possible and report back the results.
Best regards,
Fernando |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|