cancel
Showing results for 
Search instead for 
Did you mean: 

SPI timing issues on STM32F103

rluck1
Associate II
Posted on May 25, 2012 at 03:36

I'm having some issues with the SPI on the STM32 and I can't seem to figure out what the problem is.  I'm having issues on both the TX and RX directions. I'm using it in master mode in both cases.  I have multiple devices hanging onto the SPI bus so I'm using GPIO under software control slave selects.

A) In unidirectional TX mode I do the following:

1) Set RCC->APB2ENR to 1 on bits 12 and 0 to enable the SPI1 clock and enable the SPI.

2) Fill a structure typedef'ed by SPI_InitTypeDef i.e. master, 16 bits, TX only, etc.

3) SPI_Init(SPI1, &SPI_typedef);

4) SPI_Cmd(SPI1, ENABLE);

5) Reset a GPIO line low for the software controlled slave select

6) SPI_I2S_SendData(SPI1, (u16)(MyOutputData));

7) while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE)==RESET); //wait for TXE = 1

😎 Set the GPIO line back high for the software controlled slave select.

9) SPI_Cmd(SPI1, DISABLE);

Now everything seems fine except for the fact that when I look at the SCLK versus the GPIO slave select on a scope, I see that the slave select goes back high before the SCLK finishes the transaction.  I thought that by waiting for TXE to become set, the software slave select would only be able to go back high after the transaction was completed?  What am I missing?  In order to get things to look right, I have to insert a short software delay before retting the slave select back high.

B) In unidirectional RX mode I do the following:

1) Set RCC->APB2ENR to 1 on bits 12 and 0 to enable the SPI1 clock and enable the SPI.

2) Fill a structure typedef'ed by SPI_InitTypeDef.  16 bits, RX only, etc

3) SPI_Init(SPI1, &SPI_typedef);

4) Reset a GPIO line low for the software controlled slave select

5) SPI_Cmd(SPI1, ENABLE);

6) while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE)==SET);

7) MyInData = SPI_I2S_ReceiveData(SPI1));

😎 Set the GPIO line high for the software controlled slave select

SPI_Cmd(SPI1, DISABLE);

 

Now in this case, several odd things are happening.  Again the slave select is going high before the transaction is complete.  But the main issue is that I have set SPI_InitTypeDef.SPI_DataSize = SPI_DataSize_16b so I'm expecting there to be only 16 clocks in the transaction.  But instead I'm seeing 48 clocks.  Why is that happening?

Thanks!

#spi-stm32
2 REPLIES 2
Posted on May 25, 2012 at 04:34

One thing to understand with TXE is that it goes high when the data in the HOLDING register is moved to the SHIFT register, and thus you have ~16 bit times to get the next word loaded into the HOLDING register before the last bit departs the SHIFT register. Thus if you keep supplying data you will not get an underrun and the bit stream and clock will keep going.

To determine if the last bit was shifted out of the current word, the RXNE might be more helpful, provided you clear it before you start. RXNE goes high when the last bit from the slave enters the shift register, and it is copied to the holding register.

The serial port has a TC (Transmit Complete), the SPI does not, but RXNE is an equivalent given how the TX and RX are tied together.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
rluck1
Associate II
Posted on May 25, 2012 at 16:20

I'm trying to only do single transactions on the SPI, not continuous ones.  Something else triggers an interrupt and I have these SPI transactions in the ISR.  The interrupt period is 32 milliseconds (comes from USB HID) and these SPI transactions take only a few microseconds.

OK, so TXE is not really a ''done'' bit then.  On the master TX version, my short delay then seems to do the trick:

1) Set RCC->APB2ENR to 1 on bits 12 and 0 to enable the SPI1 clock and enable the SPI.

2) Fill a structure typedef'ed by SPI_InitTypeDef i.e. master, 16 bits, TX only, etc.

3) SPI_Init(SPI1, &SPI_typedef);

4) SPI_Cmd(SPI1, ENABLE);

5) Reset a GPIO line low for the software controlled slave select

6) SPI_I2S_SendData(SPI1, (u16)(MyOutputData));

7) while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE)==RESET); //wait for TXE = 1

😎 for (delay=0; delay < 4; delay++);  ////// this seems to do the trick with baud_4

😎 Set the GPIO line back high for the software controlled slave select.

9) SPI_Cmd(SPI1, DISABLE);

On the master RX version I rearranged things slightly,

1) Set RCC->APB2ENR to 1 on bits 12 and 0 to enable the SPI1 clock and enable the SPI.

2) Fill a structure typedef'ed by SPI_InitTypeDef.  i.e. master, 16 bits, RX only, etc

3) SPI_Init(SPI1, &SPI_typedef);

4) Reset a GPIO line low for the software controlled slave select

5) SPI_Cmd(SPI1, ENABLE);

6) MyInData = SPI_I2S_ReceiveData(SPI1));

7) while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE)==SET);

😎 SPI_Cmd(SPI1, DISABLE); ///// moved this up to get only a single 16 clock transaction

                                                  ///// with baud > 4

9) for (delay=0; delay<4; delay++);  ///// added delay here to move the GPIO slave select out

10) Set the GPIO line high for the software controlled slave select

 

The other thing I discovered with the RX version is that I had to set the SPI clock rate from baud_4 to baud_8.  In my system, baud_4 was giving an SPI clock rate of about 18MHz and baud_4 gives a rate of about 9 MHz.  I'm thinking that the SPI was running too fast for the while check of RXNE to work.  I'm still not that happy with having to insert tweaked delays because it makes things less portable.  But it seems to work.

I'll experiment with checking RXNE as you suggest.

Thanks!