cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H743 getting SPI interrupt when no SPI interrupts are enabled.

rammit
Senior

My STM32H743 SPI interrupt handler is being repeatedly called even though the interrupt enable register (IER) is 0. I'm running in slave mode and probably doing something really wrong for this to happen.

Here are the register values:

Name   Value   Access   

CR1   0x00000001   ReadWrite   

    IOLOCK   0   ReadWrite   

    TCRCI   0   ReadWrite   

    RCRCI   0   ReadWrite   

    CRC33_17   0   ReadWrite   

    SSI   0   ReadWrite   

    HDDIR   0   ReadWrite   

    CSUSP   0   ReadWrite   

    CSTART   0   ReadWrite   

    MASRX   0   ReadWrite   

    SPE   1   ReadWrite   

CR2   0x00000003   ReadWrite   

    TSER   0x0000   ReadWrite   

    TSIZE   0x0003   ReadWrite   

CFG1   0x2000040F   ReadWrite   

CFG2   0x05000000   ReadWrite   

IER   0x00000000   ReadWrite   

    TSERFIE   0   ReadWrite   

    MODFIE   0   ReadWrite   

    TIFREIE   0   ReadWrite   

    CRCEIE   0   ReadWrite   

    OVRIE   0   ReadWrite   

    UDRIE   0   ReadWrite   

    TXTFIE   0   ReadWrite   

    EOTIE   0   ReadWrite   

    DPXPIE   0   ReadWrite   

    TXPIE   0   ReadWrite   

    RXPIE   0   ReadWrite   

SR   0xFFF80002   ReadOnly   

    CTSIZE   0xFFF8   ReadOnly   

    RXWNE   0   ReadOnly   

    RXPLVL   0x0   ReadOnly   

    TXC   0   ReadOnly   

    SUSP   0   ReadOnly   

    TSERF   0   ReadOnly   

    MODF   0   ReadOnly   

    TIFRE   0   ReadOnly   

    CRCE   0   ReadOnly   

    OVR   0   ReadOnly   

    UDR   0   ReadOnly   

    TXTF   0   ReadOnly   

    EOT   0   ReadOnly   

    DXP   0   ReadOnly   

    TXP   1   ReadOnly   

    RXP   0   ReadOnly   

16 REPLIES 16
rammit
Senior

Sorry for the confusion. I enable the interrupt, and in my handler I disable the TXP interrupt after TxXferCount goes to 0 similar to HAL's handler.

But, the handler is being repeatedly called afterwards even though the interrupt enable register (IER) is 0.

   while (HAL_IS_BIT_SET(trigger, SPI_FLAG_TXP)) // TXP = packet space available

   {

       txData = *((SPIDataType *)hspi->pTxBuffPtr);

       (*(__IO SPIDataType *)&hspi->Instance->TXDR) = txData;

       hspi->pTxBuffPtr += sizeof(SPIDataType);

       hspi->TxXferCount -= sizeof(SPIDataType);

       /* Disable IT if no more data excepted */

       if (hspi->TxXferCount == 0UL)

       {

         __HAL_SPI_DISABLE_IT(hspi, SPI_IT_TXP);

         break;

       }

       trigger = hspi->Instance->SR & itsource;   

   }

I see.

If the disable is close to the iterrupt's end,and there's one more "inexplicable" interrupt after this, it may be the usual "it takes time until changes in peripherals propagate until NVIC" problem.

JW

rammit
Senior

That makes sense, but the SPI interrupt handler is being repeatedly called even though the interrupt enable register (IER) is 0.

DFuchs
Associate III

Hi,

the interrupt (SPI1..6) within the NVIC is enabled so any SPI interrupt triggers the NVIC to call your handler.

You can have a look at the 'SR' register to see which SPI flag is set.

To clear the flag you have to set the corresponding bit in the 'IFCR' register.

Sorry, but i am not using the HAL so i don't know if 'trigger = hspi->Instance->SR & itsource' does the business.

Edit: TXTFC is bit 4 in 'IFCR' and TXP is bit 2 in 'SR'. So this doesn't fit directly.

Kind regards

Daniel

rammit
Senior

That's good to know. I'm only using SPI4.

Only the TXP bit is set in the SR register and the IER register is 0.

Reduce your code to minimal but complete compilable one (or start from scratch). Still exhibiting the problem?

Remove the interrupt enable from EXTI and move it to main (), checking the given pin. Still exhibiting the problem?

If yes, you may want to contact ST directly, through web support form it through FAE.

JW

I can confirm that EXTI will cause an empty firing of the SPI IRQ.

I can also confirm that SPI Slave TXE IRQ can fire twice on the first byte sent by Master before the RXNE fires. Then for the subsequent bytes sent from Master, TXE IRQ will fire just once. This due to the need for the digital state machine of the SPI peripheral to meet timing requirements. Due to causality, rx data is delayed the bit width and so tx is queued up first with two bytes. Then symmetrically we finish with two reads in a row, allowing TXE to remain high.

Recommend following TRM procedure for your specific use case without any interrupt or DMA first. Then optimize.

Here is the TRM's 5 steps for continuous mode txrx:

 

        while (SPI2_nCS_GPIO_Port->IDR & SPI2_nCS_Pin);  // start when it's low

        // 3 byte example
        SPI2->CR1 |= SPI_CR1_SPE;       // 1
        while ((SPI2->SR & SPI_SR_TXE) == 0);
        SPI2->DR = rsp[0];              // 2


        while ((SPI2->SR & SPI_SR_TXE) == 0);
        SPI2->DR = rsp[1];              // 3.1
        while ((SPI2->SR & SPI_SR_RXNE) == 0);
        rx[0] = SPI2->DR;               // 3.1
        size_t len = 3;


        while ((SPI2->SR & SPI_SR_TXE) == 0);
        SPI2->DR = rsp[i+1];            // 3.2
//        dlog("%d rx %02X tx %02X", i, rx[0], rsp[1]);
        while ((SPI2->SR & SPI_SR_RXNE) == 0);
        rx[i] = SPI2->DR;               // 3.2


        while ((SPI2->SR & SPI_SR_RXNE) == 0);
        rx[i+1] = SPI2->DR;             // 4
//        dlog("%d rx %02X tx %02X", i, rx[i], rsp[i+1]);


        while ((SPI2->SR & SPI_SR_TXE) == 0);
        while ((SPI2->SR & SPI_SR_BSY) != 0);
        SPI2->CR1 &= ~SPI_CR1_SPE;      // 5


        dlog();
        dprintf("rx ");
        dump_hex_str_n(rx, len);
        dprintf("tx ");
        dump_hex_str_n(rsp, len);

 

Note that the printf debug embedded within will break the flow. Typically I see SPI_SR_RXNE go low, causing it to get stuck waiting on step 4 to finish the packet. Data is in the SPI2->DR register, though.

Cheers