cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F746 - SPI sends twice problem

M G_2
Associate III
Posted on July 11, 2018 at 11:43

The original post was too long to process during our migration. Please click on the attachment to read the original post.
1 ACCEPTED SOLUTION

Accepted Solutions
Posted on July 12, 2018 at 08:32

The original post was too long to process during our migration. Please click on the provided URL to read the original post. https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I6vw&d=%2Fa%2F0X0000000byB%2F4W5WyI1UpqGSrCOqMSJPThu_n7129pFVGLKDcZF0A2E&asPdf=false

View solution in original post

5 REPLIES 5
Posted on July 12, 2018 at 00:14

I assume the two halfwords are being sent in a loop, and the presented waveform is not from the first run after reset (I can't at the moment explain 'doubling' immediately after reset, nevertheless the whole concept is flawed and has to be rethought).

So let's assume that in the first call of Send_a_2Bytes(), the halfword has been started to be transmitted and, thanks to waiting for the BUSY flag to be cleared, it is completely transmitted by the end of the routine, which also means that RXNE gets set at the moment.

In the next call of Send_a_2Bytes(),   LL_SPI_EnableIT_RXNE(SPIx); is performed first.

What happens? RXNE is already set, so immediately it goes into the interrupt. In that, the mcu receives data but also sees, hey, TXE is set, let's transmit. There's nothing being transmitted at this point, so this write goes immediately from holding to the shift register, thus TXE is set immediately.

Returning from the interrupt, the next line performs LL_SPI_EnableIT_TXE(SPIx);. TXE is set, so interrupt fires. Depending on the accidental ratio between execution speed of this code (given by compiler optimization, SPI baudrate, FLASH latency and similar factors) the previous halfword might have been already shifted out/in, in that case RXNE is set and the newly received halfword overwrites the previously received one in MaRxBuffer; otherwise it gets overwritten by the next received data in the SPI_Rx register and there's an overflow indicated. Next, TXE is set, so the same MaTxBuffer gets transmitted again.

After returning from this interrupt, waiting for BUSY ensures that RXNE gets set before Send_a_2Bytes() is called again, starting the whole process all over again.

The conventional solution is to keep a count of data to be transmitted (more precisely, this is kept indirectly, as difference between the head and tail pointer of the circular buffer used to store the data to be transmitted), enabling the Tx interrupt when main stores data into the buffer, and the interrupt disabling it when the buffer gets empty. Similarly, employing circular buffers for Rx is more 'normal'; there is no need to enable/disable that interrupt.

JW

Posted on July 12, 2018 at 08:32

The original post was too long to process during our migration. Please click on the provided URL to read the original post. https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I6vw&d=%2Fa%2F0X0000000byB%2F4W5WyI1UpqGSrCOqMSJPThu_n7129pFVGLKDcZF0A2E&asPdf=false
Posted on July 12, 2018 at 09:00

I’ve checked how often the interrupt routine was called after enabling both the interrupts TX and RX.

How? By placing a breakpoint and observing it in the debugger? The debugger is intrusive - if nyou display the content of SPI registers, it will read SPI->DR thus clear Rx.

Restore the original code. Place one counter into the ISR and other into Send_a_Byte(), run, and then compare after several calls to Send_a_Byte(); while *not* displaying the SPI registers in the debugger.

What you did is a symptomatic fix, which will bite you later.

JW

Posted on July 12, 2018 at 10:37

Hi Jan,

yes I've used the debugger and a volatile count++ placed inside the ISR. But to be sure that I've not overlooked something I've setup the experiment again: I've placed again a count++ (volatile int) inside the ISR and the result I’ve send from main via USART to a pc without using debug. So you right: The result is that indeed the ISR is called twice if the Send_a_2bytes routine from my first post was used (no matter whether both RX and TX interrupts are enabled or only the TX interrupt).

However to also check your hypothesis that the phenomenon happens because I call Send_a_2bytes a second time I just removed the second call. The result is that still the routine causes SPIx to send out data two times and the ISR is called twice. I also swapped the lines DisableIT and SPXy->DR = data with the same result.

In contrast and accordingly to my suggestion where SPIx-DR is loaded before enabling the TX/RX interrupt the ISR is called just once. I don’t know why STM32F7 behaves else than the other STM32F <7 but this is how I can proceed further with my investigation.

Can you support your doubts reading my suggestion how to overcome the problem ?

Posted on July 12, 2018 at 16:11

I have no doubts 🙂

As long as you don't and won't do anything else, it looks OK.

However, to send and receive one frame in a blocking manner (i.e. waiting for the result) you don't need interrupts - simply instead of waiting for flags (variables) to be set by the interrupt, wait for the respective flags in the status register of SPI.

JW