2020-05-09 07:13 PM
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
2020-05-11 02:42 PM
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;
}
2020-05-11 09:20 PM
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
2020-05-12 06:21 AM
That makes sense, but the SPI interrupt handler is being repeatedly called even though the interrupt enable register (IER) is 0.
2020-05-12 06:58 AM
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
2020-05-14 05:16 PM
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.
2020-05-14 07:21 PM
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
2023-11-29 02:45 PM
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