2013-08-22 12:54 AM
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 #spi2013-08-22 04:17 AM
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.2013-08-22 04:56 AM
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, Juan2013-08-22 05:33 AM
I could argue this with you, but it's not working, and I told you why.
2013-08-22 05:41 AM
Have a look at,
http://en.wikipedia.org/wiki/Digital_timing_diagram
During each of the 8 clock cycles the transfer ishttp://en.wikipedia.org/wiki/Full_duplex
:2013-08-22 06:39 AM
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, Juan2013-08-22 06:56 AM
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.2013-08-22 07:38 AM
Yeah - almost as though the physical wires were connected to physical shift registers ...