Skip to main content
Graduate
May 30, 2024
Solved

SPI slave mode - data losing

  • May 30, 2024
  • 1 reply
  • 3130 views

Hello

I have two boards. Both of them are based on STM32 MCUs. One is a SPI master and the second is a SPI slave.

Settings for master (STM32H723):

 mHandle.Init.Mode = SPI_MODE_MASTER;
 mHandle.Init.Direction = SPI_DIRECTION_2LINES;
 mHandle.Init.DataSize = SPI_DATASIZE_8BIT;
 mHandle.Init.CLKPolarity = mSclIdle == SclIdle::kLow ? SPI_POLARITY_LOW : SPI_POLARITY_HIGH;
 mHandle.Init.CLKPhase = mSclEdge == SclEdge::k1 ? SPI_PHASE_1EDGE : SPI_PHASE_2EDGE;
 mHandle.Init.BaudRatePrescaler = mPrescaler;
 mHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
 mHandle.Init.TIMode = SPI_TIMODE_DISABLE;
 mHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
 mHandle.Init.CRCPolynomial = 0x00;
 mHandle.Init.NSS = SPI_NSS_SOFT;
 mHandle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
 mHandle.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
 mHandle.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
 mHandle.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
 mHandle.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
 mHandle.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
 mHandle.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
 mHandle.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
 mHandle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;
 mHandle.Init.IOSwap = SPI_IO_SWAP_DISABLE;

 

 Settings for slave(STM32L552):

 mHandle.Init.Mode = SPI_MODE_SLAVE;
 mHandle.Init.Direction = SPI_DIRECTION_2LINES;
 mHandle.Init.DataSize = SPI_DATASIZE_8BIT;
 mHandle.Init.CLKPolarity = SPI_POLARITY_LOW;
 mHandle.Init.CLKPhase = SPI_PHASE_1EDGE;
 mHandle.Init.NSS = SPI_NSS_SOFT;
 mHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
 mHandle.Init.TIMode = SPI_TIMODE_DISABLE;
 mHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
 mHandle.Init.CRCPolynomial = 7;
 mHandle.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
 mHandle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;

So, settings for SPI: 

Oleksandr_0-1717081696365.png

SPI clock frequency: 700kHz

Here is an example of a successful transaction

Oleksandr_2-1717082783119.png

 

The CS signal drops to logic zero. Then the slave receives an instruction on what to do - read or write - and in the second part of the transaction performs this instruction. After the exchange of information, the CS signal returns to its original state.
The figure shows an example when a slave device receives a request to read 16 bytes of data from it.

 

Problem: sometimes the slave device loses data. It can process several hundred transactions correctly, but then a situation happens that it waits for 5 bytes as usually, these 5 bytes actually arrive because I see them with a logical analyzer, but the slave as if at the last byte, stops receiving and gets into an interrupt and stays there all the time until the next packet data (which occurs after some time) from the master.

It looks like this:

Oleksandr_3-1717083091971.png

 

A similar situation can happen in the second part of a transaction. It looks like this:

Oleksandr_5-1717083347815.png

 

I have tried to use pooling, interrupt, and DMA modes. The behavior is the same.

Why might there be similar behavior of the SPI bus in slave mode?

 

 

 

 

 

    This topic has been closed for replies.
    Best answer by Oleksandr

    Looks like I've fixed the problem.
    For the first time in my life, I encountered such a situation that I needed to read the errata document. In all my practice, there have never been any problems with ST's MCU. So, according to this document, it is in SPI slave mode that the microcontroller has hardware issues that can be solved in software, but this is not done in the HAL library. I added the fix myself and the connection works stably.

     

    Have a nice day, everyone!

    1 reply

    Technical Moderator
    May 31, 2024

    Hello @Oleksandr 

     

    Could you please clarify what the signals Tx transaction and Rx transaction represent?

    OleksandrAuthor
    Graduate
    May 31, 2024

    Of course.
    I have two test points on my PCB. They are named accordingly:
    TestPoint::Name::tpTxTransaction and TestPoint::Name::tpRxTransaction.
    They're just GPO ports.

    When I start the Read Transaction I set tpRxTransaction to 1 and when this transaction stops I set tpRxTransaction to 0. The same behavior for the tpTxTransaction test point and Transmit Transactions.

    So, in the code it uses in this way (start):

    /**
     * @brief SPI start transmiting
     *
     */
    void Components::SpiSlave::z0()
    {
     TestPoint::getInstance().set(TestPoint::Name::tpTxTransaction);
    
     mSpiS.transmit(mTxBuffer, mTransaction.len);
    }
    
    /**
     * @brief SPI start receiving
     *
     */
    void Components::SpiSlave::z1()
    {
     TestPoint::getInstance().set(TestPoint::Name::tpRxTransaction);
    
     mSpiS.receive(mRxBuffer, mTransaction.len);
    }

     and the same for stop:

    void Drivers::HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
    {
     Drivers::SPIS::rxComplete(hspi);
     TestPoint::getInstance().rst(TestPoint::Name::tpRxTransaction);
    }
    
    void Drivers::HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
    {
     Drivers::SPIS::txComplete(hspi);
     TestPoint::getInstance().rst(TestPoint::Name::tpTxTransaction);
    }

     

    OleksandrAuthorAnswer
    Graduate
    May 31, 2024

    Looks like I've fixed the problem.
    For the first time in my life, I encountered such a situation that I needed to read the errata document. In all my practice, there have never been any problems with ST's MCU. So, according to this document, it is in SPI slave mode that the microcontroller has hardware issues that can be solved in software, but this is not done in the HAL library. I added the fix myself and the connection works stably.

     

    Have a nice day, everyone!