cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H755ZI SPI / Proper way to receive data

DSchl.1
Associate III

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:

  • LL_SPI_PROTOCOL_MOTOROLA
  • LL_SPI_NSS_POLARITY_HIGH
  • Enable NSS Pulse Management
  • Enable GPIO Control

After initialization, I'm trying to read 2 bytes of data. I'm using the following procedure:

  • Start the transfer size (with requested number of bytes + 1, so this is set to 3)
  • Enable the SPI peripheral and start master transfer
  • Wait for TXP, send first dummy data byte (0xFF)
  • Wait for TXP, send second dummy data byte (0xFF) and read first data byte if FIFO packing level is > 0
  • Read second data byte if FIFO packing level is > 0
  • Wait until EOT
  • Clear EOT and TXTF flags
  • Suspend master transfer and disable SPI peripheral

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);
}

11 REPLIES 11
DSchl.1
Associate III

I have added a code snippet to show my routine to send/receive data to clarify the problem... Hopefully someone can help me.

TDK
Guru

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);
    }

If you feel a post has answered your question, please click "Accept as Solution".
DSchl.1
Associate III

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 :(

TDK
Guru

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.

If you feel a post has answered your question, please click "Accept as Solution".
DSchl.1
Associate III

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.

DSchl.1
Associate III

Has anybody some more hints? Has anybody had similar problems? I'm still having the issue and I'm out of ideas :(

TDK
Guru

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.

If you feel a post has answered your question, please click "Accept as Solution".
DSchl.1
Associate III

> 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?

DSchl.1
Associate III

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 ?