cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F103C8: Master full-duplex SPI problem

juan
Associate II
Posted on August 22, 2013 at 09:54

Hi all,

I am using a STM32F103C8 as a master in a SPI communication to an external ADS.

My project has other interrupt sources, so I am not using additional interrupts for this SPI communication.The communication does both tx and rx, and for that I have followed the protocol specified in the MCU datasheet. 

The problem is that the program often gets stuck in the last part of the communication, when the last two data bytes have to be received. When the RXNE flag should be set for second time (because the last data should be entering the serial register), it is not set so the program keeps waiting for it.

At first I thought it could be possible that if an interupt arrives in the middle of the receiving of the last two data bytes the communication might be disrupted, so I framed the last two waits for RXNE between __disable_irq() and __enable_irq(), but that did not solve the problem. For now I will implement it with software timeouts and retries, but it is a workaround, I would like to know the real cause.

Can anyone point out some ideas?? Below you can find the code snippet for the communication.

Kind regards,

Juan Antuna

    //First select the slave

    GPIOB->BRR = 0x00001000;

    //Wait until the SPI bus is free

    while(((SPI2->SR & SPI_I2S_FLAG_TXE) == (u16)RESET));

    //Write the first command

    SPI2->DR = RDATA_COMMAND;

    //Wait until the SPI bus is free

    while(((SPI2->SR & SPI_I2S_FLAG_TXE) == (u16)RESET));

    //Write the second command: 

    SPI2->DR = NOP_COMMAND;

    //Wait until RXNE is set (data received)

    while(((SPI2->SR & SPI_I2S_FLAG_RXNE) == (u16)RESET));

    //Read the first response

    temp = SPI2->DR;

    //Wait until the SPI bus is free

    while(((SPI2->SR & SPI_I2S_FLAG_TXE) == (u16)RESET));

    //Write the third command:

    SPI2->DR = NOP_COMMAND;

    //Wait until RXNE is set (data received)

    while(((SPI2->SR & SPI_I2S_FLAG_RXNE) == (u16)RESET));

    //Read the second response

    data1 = (u8)(SPI2->DR);

    //Wait until the SPI bus is free

    while(((SPI2->SR & SPI_I2S_FLAG_TXE) == (u16)RESET));

    //Write the third command:    

    SPI2->DR = NOP_COMMAND;

    //Wait until RXNE is set (data received)

    while(((SPI2->SR & SPI_I2S_FLAG_RXNE) == (u16)RESET));

    //Read the third response

    data2 = (u8)(SPI2->DR);

    //Wait until RXNE is set (last data received)

    while(((SPI2->SR & SPI_I2S_FLAG_RXNE) == (u16)RESET));

    //Read the last response

    data3 = (u8)(SPI2->DR);

    //Wait until the SPI bus is free

    while(((SPI2->SR & SPI_I2S_FLAG_TXE) == (u16)RESET));

    //Wait until BSY flag is 0

    while(((SPI1->SR & SPI_I2S_FLAG_BSY) != (u16)RESET));

    //Deselect the slave

    GPIOB->BSRR = 0x00001000;

#stm32 #stm32 #stm32 #spi
7 REPLIES 7
Posted on August 22, 2013 at 13:17

You need to send a byte for each you want to get back, you don't do that at the latter sequence where you have two reads of DR, with no write prior to the last one.

Without a write the interface does not clock.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
juan
Associate II
Posted on August 22, 2013 at 13:56

Hi clive1,

Thanks for your answer.

I know at the end I have two reads of DR, but if I look at RM0008 (page 683, SPI full duplex transmit and receive procedure):

1. Enable the SPI by setting the SPE bit to 1.

2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE

flag).

3. Wait until TXE=1 and write the second data item to be transmitted. Then wait until

RXNE=1 and read the SPI_DR to get the first received data item (this clears the RXNE

bit). Repeat this operation for each data item to be transmitted/received until the n–1

received data.

4. Wait until RXNE=1 and read the last received data.

5. Wait until TXE=1 and then wait until BSY=0 before disabling the SPI.

So I thought at the very end I have to do two consecutive reads from the DR, to get the last two bytes from the communication. For the very last data, it should already be dangling at the input of the interface until the DR is freed by reading the previous one.

Regards,

Juan

Posted on August 22, 2013 at 14:33

I could argue this with you, but it's not working, and I told you why.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
John F.
Senior
Posted on August 22, 2013 at 14:41

Have a look at,

http://en.wikipedia.org/wiki/Digital_timing_diagram

During each of the 8 clock cycles the transfer is

http://en.wikipedia.org/wiki/Full_duplex

:
  • The master writes on the MOSI line and reads the MISO line
  • The slave writes on the MISO line and reads the MOSI line

juan
Associate II
Posted on August 22, 2013 at 15:39

Hi,

Thanks for the asnwer. Sorry if I sounded like defending my code at all costs, I totally did not mean it. What I just wanted to say is, perhaps the SPI protocol in the RM0008 is not correct. So, you would propose to do the read/write to/from the DR always one by one rather than the way I implemented it?

John,

Thanks for your answer and your links, too. I understand that the SPI communication is full-duplex, and its nature. However, the issue is not about the data being placed on the physiscal wires, but rather on how data enters the DR on the MCU itself.

regards,

Juan

Posted on August 22, 2013 at 15:56

but rather on how data enters the DR on the MCU itself.

The DR is a holding register (read/write point a different internal registers), the bus is symetrical, as data shifts out to the slave, data shifts back to the master. The clock is generated by the sending, initiated by writing DR, which can be junk/null/nop bytes in order to precipitate the transfer and clocking required to get something back.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
John F.
Senior
Posted on August 22, 2013 at 16:38

Yeah - almost as though the physical wires were connected to physical shift registers ...