1
votes

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 ?

1
Race condition? Can it be that you get second interrupt while serving first one? And hey, for the >1000 rating can you mark your code with something like <!-- language: lang-c -->?0andriy
No race condition. I did the same test with both codes in polling and no other interrupt enabled.Guillaume Petitjean
Didn't understand your remark about rating and marking the code.Guillaume Petitjean

1 Answers

0
votes

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.