2020-03-20 02:25 AM
Hi everyone
I'm currently working with the STM32H755ZI SPI1 peripheral. I'm using low level driver to read 2 bytes of data. I'm transmitting 2 dummy data bytes (0xFF) in order to get some response from the SPI slaves. Most of the time, the receive works well, but from time to time, I'm receiving 0x00, even though the RxFIFOPackingLevel is > 0 and the signals on the oscilloscope look fine at that time... I used a conditional breakpoint to stop when one of the data bytes is 0x00 and checked the SPI1 registers, and everything looked fine (the RxFIFO packing level / RXPLVL showed 0 at the time, but I assume it gets cleared after reading the rx data register).
I've also tried to lower the SPI1 clock, but this didn't help...
What's the proper way to receive data bytes from the SPI peripheral? Is waiting for RxFIFOPackingLevel > 0 correct?
edit: I've also tried to check RXP flag, but this doesn't change anything.
This question is related to the previous question I had, however I'm posting it as a new topic. Previous question https://community.st.com/s/question/0D53W000002h0qFSAQ/stm32h755zi-spi-behaviour-of-mosi-after-disabling-peripheral.
I'm sorry for the redundancy in my posts, but I thought that these are two totally different questions.
Parameters are as shown below:
Baudrate = LL_SPI_BAUDRATEPRESCALER_DIV256 (clock is 180MHz)
BitOrder = LL_SPI_MSB_FIRST
CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE
CRCPoly = CRCPOLY 0x00
ClockPhase = LL_SPI_PHASE_1EDGE
ClockPolarity = LL_SPI_POLARITY_LOW
DataWidth = LL_SPI_DATAWIDTH_8BIT
Mode = LL_SPI_MODE_MASTER
NSS = LL_SPI_NSS_HARD_OUTPUT
TransferDirection = LL_SPI_FULL_DUPLEX
I'm also setting the following parameters:
After initialization, I'm trying to read 2 bytes of data. I'm using the following procedure:
Any explanation would be greatly appreciated.
Regards
Daniel.
EDIT: To give some more information, here's my routine for sending and receiving the SPI data:
EDIT2: Updated due to comments below. This shows now the actual implementation.
// The following simplified function gets called with a zero-initialized buffer of 2 bytes and size = 2.
void reveive_buffer(uint8_t* buffer, uint32_t size)
{
LL_SPI_SetTransferSize(SPI1, size);
LL_SPI_Enable(SPI1);
LL_SPI_StartMasterTransfer(SPI1);
for (uint32_t i = 0; i < size; ++i)
{
while (LL_SPI_IsActiveFlag_TXP(SPI1) == 0);
LL_SPI_TransmitData8(SPI1, 0xFF);
}
for (uint32_t i = 0; i < size; ++i)
{
while (LL_SPI_GetRxFIFOPackingLevel(SPI1) == 0);
buffer[i] = LL_SPI_ReceiveData8(SPI1);
}
while (LL_SPI_IsActiveFlag_EOT(SPI1) == 0);
LL_SPI_ClearFlag_EOT(SPI1);
LL_SPI_ClearFlag_TXTF(SPI1);
LL_SPI_SuspendMasterTransfer(SPI1);
LL_SPI_Disable(SPI1);
}
2020-03-22 11:44 PM
I have added a code snippet to show my routine to send/receive data to clarify the problem... Hopefully someone can help me.
2020-03-23 01:52 AM
Why set totalSize = size + 1?
If size = 2, you're sending 2 bytes and receiving two bytes.
If you only send 2 bytes but transfer size is set to 3, then EOT flag shouldn't get set and this statement should hang:
while (LL_ISActiveFlag_EOT(SPI1) == 0);
That statement also has typos, which means it's not going to compile. Is that actually your code? The function name is LL_SPI_IsActiveFlag_EOT.
for (uint32_t i = 0; i < size; ++i)
{
while (LL_SPI_IsActiveFlag_TXP(SPI1) == 0);
LL_SPI_TransmitData8(SPI1, 0xFF);
while (LL_SPI_GetRxFIFOPackingLevel(SPI1) == 0);
buffer[i] = LL_SPI_ReceiveData8(SPI1);
}
2020-03-23 03:20 AM
About the typos, you're right. That's just a typing mistake I made (copy&paste of the code doesn't work at the moment). The code actually compiles and works.
The EOT statement doesn't hang, if I'm setting the number of bytes to 3.
I admit that setting the transfer size to 3 doesn't make much sense. However, the for loop didn't work properly If I was setting the size to 2 (I had two groups of SCK signals with 8 pulses instead of one group with 16 pulses, which made me missing the second part of the data).
I have refactored the for loop like shown below:
// The following simplified function gets called with a zero-initialized buffer of 2 bytes and size = 2.
void reveive_buffer(uint8_t* buffer, uint32_t size)
{
LL_SPI_SetTransferSize(SPI1, size);
LL_SPI_Enable(SPI1);
LL_SPI_StartMasterTransfer(SPI1);
for (uint32_t i = 0; i < size; ++i)
{
while (LL_SPI_IsActiveFlag_TXP(SPI1) == 0);
LL_SPI_TransmitData8(SPI1, 0xFF);
}
for (uint32_t i = 0; i < size; ++i)
{
while (LL_SPI_GetRxFIFOPackingLevel(SPI1) == 0);
buffer[i] = LL_SPI_ReceiveData8(SPI1);
}
while (LL_SPI_IsActiveFlag_EOT(SPI1) == 0);
LL_SPI_ClearFlag_EOT(SPI1);
LL_SPI_ClearFlag_TXTF(SPI1);
LL_SPI_SuspendMasterTransfer(SPI1);
LL_SPI_Disable(SPI1);
}
This sends now 2x8 Bits at once and seems to work properly as well. But unfortunately the described problem still occurs. From time to time (sometimes after a few seconds, sometimes only after minutes) the read data is 0x00 :(
2020-03-23 05:49 AM
Two groups of 8 pulses is the same as 1 group of 16 as far as the SPI protocol is concerned.
If size > 16, do you think your code will work? The FIFO size is not unlimited.
When your read data is 0x00, are you checking for error flags? You should be doing this anyway. Might be an RX over/underrun.
2020-03-23 07:49 AM
I meant two distinct groups with a pause of a few pulses in between, where no SCK is generated. This is not the same behaviour as 16 pulses, because I need to read the contents of two shift registers connected in series with each 8 inputs.
Good point about the size > 16, I'll fix this.
Yes, as I've mentioned in the original post, I've set a conditional breakpoint (one of the data bytes reads 0x00) and checked the error flags. None of the flags were set at that time. On the oscilloscope I couldn't spot anything suspect either.
2020-03-25 12:05 AM
Has anybody some more hints? Has anybody had similar problems? I'm still having the issue and I'm out of ideas :(
2020-03-25 06:27 AM
Why not just use the HAL functions? Or if not use them, look at them for guidance?
> I meant two distinct groups with a pause of a few pulses in between, where no SCK is generated.
What does this mean? Pulses typically imply the SCK line.
It's also possible the data coming in is actually 0x00 and there's no software bug.
2020-03-25 07:08 AM
> Why not just use the HAL functions? Or if not use them, look at them for guidance?
We have decided to not use the HAL and stick to the LL functions. However, for the implementation of the receive_buffer() function above, I've already checked out the function HAL_SPI_TransmitReceive (or similar)... In my opinion, my function does roughly the same.
> What does this mean? Pulses typically imply the SCK line.
Yes, I meant to say that the pause duration is as long as a few SCK pulses. But there were two separated groups of each 8 pulses instead of 16 pulses at once.
> It's also possible the data coming in is actually 0x00 and there's no software bug.
I was thinking the same thing. So the waiting until the packing level is > 0 is correct in your opinion?
2020-11-23 10:32 PM
After a while we still experience problems with the SPI peripherals... We have implemented a workaround to ignore the 0-Bytes... but the problem still remains :
The uC tells that there's some data to read (RX FIFO packing level) but upon reading, the data is actually zero. When analyzing the data with a scope / logic analyzer, everything is ok and the data is present. We have also analyzed all of the status / error flags, but everything is alright (no overrun / underrun etc.)...
Now I have found the following thread :
https://stackoverflow.com/questions/62260154/stm32h7-spi-communication-fifo-management-problem
There is the suggestion to reduce the SysClock - Speed. Our sysclock is 180MHz, with a prescaler of 256 we get to around 700kHz for the SPI Clock. Could this be a problem ?