STM32H7 SPI communication: FIFO management problem

1

I've been struggling for quite a while now on my SPI setup.

The setup is as follows:

  • SPI Slave is a Nucleo STM32H743 in simplex mode, clocks at maximum (sysclk 400MHz, hclck 200Mhz, APB clock 100MHz)
  • SPI master is another identical Nucleo in simplex mode, clocks divided by 2: sysclk 200MHz, etc... and spi_ker_clk = 100MHz
  • SPI master with a prescaler of 16 ie. clock SPI around 6MHz. CRC enabled. Data frame 8 bits. FIFO threshold 4 bytes
  • SPI slave: CRC enabled, 8 bits. FIFO threshold 4 bytes

There is no Slave Select signal to control the slave.

Here is the code for the master. Everything done in polling and I've added some delay to let time to the Slave to work. The following function is called in loop, nothing else is done by the Master (in this simplified version that I used for debug):

uint32_t SPI_EnvoiCommandeTest(void)
{
uint32_t resp;
uint8_t statut;

SPI1->CFG2 |= SPI_CFG2_COMM_0;
SPI1->CFG2 &= ~SPI_CFG2_COMM_1;

SPI1->CR2 = 4;

SPI1->CR1 |= SPI_CR1_SPE;
SPI1->CR1 |= SPI_CR1_CSTART;

SPI1->TXDR = 0x12345678;

while ( (SPI1->SR & SPI_SR_EOT)  == 0 );

if ( (SPI1->SR & SPI_SR_ERR_MASK) != 0 )
{
    return ( SPI1->SR & SPI_SR_ERR_MASK);
}


SPI1->IFCR = 0xFFFFFFFF;


SPI1->CR1 &= ~SPI_CR1_SPE;

Delay(1000); 


SPI1->CFG2 |= SPI_CFG2_COMM_1;
SPI1->CFG2 &= ~SPI_CFG2_COMM_0;


SPI1->CR2 = 5;


SPI1->CR1 |= SPI_CR1_SPE;
SPI1->CR1 |= SPI_CR1_CSTART;

while ( (SPI1->SR & SPI_SR_EOT)  == 0 );
resp = SPI1->RXDR;
statut = *((__IO octet *)&(SPI1->RXDR));
if ( resp != 0x9ABCDEFF)
    while(1);
if ( statut != 0x77)
    while(1);

while ( (SPI1->SR & SPI_SR_EOT)  == 0 );

if ( (SPI1->SR & SPI_SR_ERR_MASK) != 0 )
{
    return ( SPI1->SR & SPI_SR_ERR_MASK);
}


SPI1->IFCR = 0xFFFFFFFF;


SPI1->CR1 &= ~SPI_CR1_SPE;


Delay(1000); 


return 0;
}

For the Slave, the reception is done by the interrupt handler. The main thread is just waiting for a flag to be set (set by SPI_StopReception()) and send 5 bytes of answer.

static void SPI_GenericHandler(SpiId_e SpiId)
{
SPI_TypeDef *Spi = SpiMgt[SpiId].SpiInstance;
uint32_t trigger = Spi->IER & Spi->SR;
uint32_t cmd;
uint8_t stat;

if (trigger & SPI_SR_RXP)
{


        cmd = Spi->RXDR;
        if (cmd != 0x12345678)
            while(1);
        while((Spi->SR & SPI_SR_EOT) == 0);

        if (Spi->SR & SPI_SR_CRCE)
            while(1);
        SPI_StopReception(SpiId);


    }

}
(...)

My problem is the following.

The communication is working fine hundreds of thousands of times and then fails at Slave side: instead of reading bytes 78 56 34 12 from the SPI FIFO, I read for example 34 12 00 00 or 56 34 12 00.

At first glance one would say it is simply the Slave that is too slow and missed some bytes BUT what is weird is that:

  • I get a RXP interrupt which means the Slave has detected correctly the SPI clock during 4 bytes and has sampled the 4 bytes.
  • there is no CRC error which means the Slave received the correct bits. For example, when I read 56 34 12 00 from the FIFO the RXCRC was 0x08 which is the CRC of the complete frame 78 56 34 12

It is like there is a problem in the reading of the FIFO.

I've used a logic analyser and didn't identify any electrical issue.

Registers values at slave side, during a faulty reception (more precisely I break in the SPI RXP interrupt handler) are the following. In this occurence, I read 34 12 00 00:

  • CR1=1 (SPE)
  • CR2= 4 (TSIZE)
  • CFG1: MBR 0x07, CRCEN, UDRCFG=2, FTHVL=3, DSIZE=7
  • CFG2: SSM=1, COMM=2
  • IER=1(RXPIE)
  • SR=0x0001300A ie. CTSIZE=1 (strange but ref manual says "value is not quite reliable when traffic is ongoing on bus"), RXPLVL=1 (??) , EOT=1 (expected), TXP=1 (expected)
  • RXCRC=0x08 (expected for a complete frame). Worth saying the debugger (Keil) does not read the register properly, I read it in my code.

Values of CTSIZE and RXPLVL are not really consistent (at least I don't understand them): since FTHVL=3 (4-data) and TSIZE=4 (same at Master side) , when I get a RXP event, I should have received at least 4 bytes. I don't see how CTSIZE can be 1 , neither why there would be another byte left in the FIFO (RXPLVL=1).

Any idea or suggestion ?

stm32
spi
cortex-m
asked on Stack Overflow Jun 8, 2020 by Guillaume Petitjean • edited Jun 8, 2020 by Guillaume Petitjean

1 Answer

0

I suggest reducing the sysclock speed below 250 MHz and testing. I am having some SPI communication problems here in my development, directly related to this speed. I believe there is a bug in the micro where it loses SPI packets when the speed is above 250 MHz. My microcontroller is an H750VBT6. I hope this helped. Best regards, Henrique Basso.

answered on Stack Overflow Oct 26, 2020 by Henrique M. Basso

User contributions licensed under CC BY-SA 3.0