cancel
Showing results for 
Search instead for 
Did you mean: 

In stm32h743, is the TXP interrupt fired endlessly until the Tx FIFO is full?

DGast.1
Associate III

I'm trying to debug a problem by which, if the EOT IRQ is enabled, an SPI slave enters an endless loop of ISR executions. I suspect it might be related with how IRQs are generated.

According to the H7 user manual:

0693W00000aJT0hQAG.png 

The TXP interrupt is generated whenever there is space available in the TxFIFO. Does this mean that the above IRQ will fire endlessly if the Tx FIFO is never filled? In other words, if the above IRQ fires but the corresponding ISR doesn't even write to the TxFIFO, will it fire again immediately after the current ISR returns?

Also, is there any problem in enabling interrupts before filling the TxFIFO?

3 REPLIES 3
FBL
ST Employee

Hello @DGast.1​,

Yes, if the TXP interrupt is enabled (ready) and the Tx FIFO is not being filled by the corresponding ISR, the interrupt will continue to fire indefinitely as long as there is space available and not used in the Tx FIFO. Also, enabling interrupts before filling the TxFIFO should not cause any problems as long as the interrupt priorities and ISR handling are properly configured.

As mentioned in the description, all the pending interrupt requests stay active if the SPI is disabled.

0693W00000aJZMTQA4.pngHope it helps.

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

DGast.1
Associate III

I have done an experiment that seems to demonstrate the opposite @F.Belaid​ 

I have generated a configuration with STM32CubeMX to enable the SPI and send a 32 bit transaction with interrupts enabled and fifo thershold = 1. I have verified it works with my logic analyser. Below there is the 'application' code I have:

uint8_t tx_data[8] = {0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa};
  CDC_Transmit_FS("Hello\r\n", sizeof("Hello\r\n"));
 
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, 0);
  HAL_SPI_Transmit_IT(&hspi1, tx_data, sizeof(tx_data));
  HAL_Delay(500);
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, 1);
 
  CDC_Transmit_FS("Bye\r\n", sizeof("Bye\r\n"));
  HAL_Delay(200);

After that, I have commented out the code in the ISR that reads/writes to/from SPI. In particular, this:

/* SPI in mode Transmitter and Receiver ------------------------------------*/
  if (HAL_IS_BIT_CLR(trigger, SPI_FLAG_OVR) && HAL_IS_BIT_CLR(trigger, SPI_FLAG_UDR) && \
      HAL_IS_BIT_SET(trigger, SPI_FLAG_DXP))
  {
    hspi->TxISR(hspi);
    hspi->RxISR(hspi);
    handled = 1UL;
  }
 
  /* SPI in mode Receiver ----------------------------------------------------*/
  if (HAL_IS_BIT_CLR(trigger, SPI_FLAG_OVR) && HAL_IS_BIT_SET(trigger, SPI_FLAG_RXP) && \
      HAL_IS_BIT_CLR(trigger, SPI_FLAG_DXP))
  {
    hspi->RxISR(hspi);
    handled = 1UL;
  }
 
  /* SPI in mode Transmitter -------------------------------------------------*/
  if (HAL_IS_BIT_CLR(trigger, SPI_FLAG_UDR) && HAL_IS_BIT_SET(trigger, SPI_FLAG_TXP) && \
      HAL_IS_BIT_CLR(trigger, SPI_FLAG_DXP))
  {
    hspi->TxISR(hspi);
    handled = 1UL;
  }

As expected, the transaction never ends: given that the data is never written, TXP interrupts the CPU endlessly not allowing it to print a message I placed just after the HAL_SPI_Transmit_IT call ('Bye' is never printed). I think here the TXP interrupt is fired endlessly because I don't access the SPI TX register at all.

Finally, I have modified the the ISR again to uncomment the code that writes to the Tx register, disable all interrupts except from the TXP one, and I have commented out all the logic below the `hspi->TxISR(hspi)` line, as below:

__HAL_SPI_DISABLE_IT(hspi, (SPI_IT_EOT | SPI_IT_RXP | SPI_IT_DXP | SPI_IT_UDR | SPI_IT_OVR | SPI_IT_FRE | SPI_IT_MODF));
[...]
if (HAL_IS_BIT_CLR(trigger, SPI_FLAG_UDR) && HAL_IS_BIT_SET(trigger, SPI_FLAG_TXP) && \
      HAL_IS_BIT_CLR(trigger, SPI_FLAG_DXP))
  {
    hspi->TxISR(hspi);
    handled = 1UL;
  }
 
// From here, all commented out

And I have modified the SPI_TxISR_8BIT to do nothing if all the bytes required by the transfer have been already written:

static void SPI_TxISR_8BIT(SPI_HandleTypeDef *hspi)
{
  // print_int("SPI_TxISR_8BIT 1 -> ", 0);
  if (hspi->TxXferCount == 0) {
    return;
  }
[...]

At this point, if it was true that the TXP interrupt fires endlessly, I wouldn't see my 'Bye' message printed. Because:

  • I'm sending only 64 bits
  • The h753 FIFO depth is 16*8 = 128 bits, frame size = 8 bits and fifo thereshold = 1, therefore the FIFO will never be full (should therefore fire TXP endlessly)
  • I have disabled (among others) the EOT interrupt and its treatment is commented out anyway, so all the logic corresponding to disable the SPI periph. and disabling its interrupts won't be executed.

I have checked that I can read my 'Bye' message. Furthermore, I have also added some logic for the ISR to fill a matrix of messages, to actually know how many times that ISR has been executed. Before the modifications explained above I saw it being executed 9 times. This makes sense: 8 times to send the 8 bytes plus 1 to detect the EOT event and disable the SPI periph. However, after applying the changes above, I see only 8 interrupts, which is expected: 1 irq per byte (8) and no EOT irq, so 8 only instead of 9 like above.

Having the above, unless I'm misunderstanding something, it's false the TXP will fire endlessly. It will fire 'n' times, where 'n' is the number of data frames to be sent divided by the packet size (a.k.a. fifo threshold). This explains as well why if, for instance, with the above config., if I set the fifo threshold to 4 but I send only 1 byte per ISR (I should send 4 to match the fifo threshold), the TX register is accessed only the expected 4 times. Thus, the EOT flag is never set, because I haven't sent all the bytes I was supposed to with the number of IRQs the SPI periph. will provide (basing on the explanation above). Thus, the EOT IRQ never happens (as less than TSIZE packets have been sent).

DGast.1
Associate III

Hi again,

I have run another experiment, this time with the driver in Zephyr RTOS for H7's SPI. I have printed the SR register in the interrupt handler and had verified that the only flag that is enabled in several of the cases is TXP. This leads to the conclusion of that such IRQ needs to have been triggered by TXP, as that's the only enabled bit. This contradicts my previous experiment though, however this seems more reliable as it's a much simpler experiment.

 

Note: bear in mind that this experiment doesn't set the FIFO threshold at all, so it remains at threshold = 1. My previous experiment did set the FIFO threshold, so maybe the difference in results is caused by that.