cancel
Showing results for 
Search instead for 
Did you mean: 

SPI EOT interrupt triggered right after SPI enable

Mr_M_from_G
Senior II

Hello,

I do some SPI communication, which in general works fine, now I want to get an interrupt at the end of transmission. I use only TxFifo, so TSIZE is left 0. It works fine to load some data into TxFifo via TXDR. Now I enabled SPI interrupt and set EOTIE. In isr I want to clear TXC, EOT and SUSP, which all correspond to EOTIE by writing all 1s to IFCR (but I only have TXC set).

The result I get is that the isr is executed right after enabling SPI and in SR I don't get TXC cleared which makes the isr being rentered over and over again or hanging in an endless loop checking the bit.

Here is my initialization code and my isr:

( #define SetBitMask(Var,BitMask) (Var|=(BitMask))

#define ClearBitMask(Var,BitMask) (Var&=~(BitMask))

#define BitMaskIsNOTClear(Var,BitMask) ((Var&(BitMask))!=0)

)

  SetBitMask (RCC->APB1LRSTR, RCC_APB1LRSTR_SPI2RST);
  ClearBitMask (RCC->APB1LRSTR, RCC_APB1LRSTR_SPI2RST);
  // enable SPI2 clk
  SetBitMask (RCC->APB1LENR, RCC_APB1LENR_SPI2EN);
  __DSB ();  // needs to be here according to errata, to wait till periph clk is enabled
  // init SPI2:
  SetBitMask (SPI2->CR1, SPI_CR1_SSI);
    // SSI must be set, before SSM gets set and both must be set in master mode without external SS pin control
    // otherwise mode fault occurs and SPI will not work
  SetBitMask (SPI2->CFG1, SPI_CFG1_MBR_2 | SPI_CFG1_MBR_1 | SPI_CFG1_MBR_0 | (16 - 1)); // clk and bit length
  SetBitMask (SPI2->CFG2, SPI_CFG2_AFCNTR | SPI_CFG2_SSM | SPI_CFG2_MASTER | SPI_CFG2_MIDI_0);
 
  SPI2->IFCR = 0xFFFFFFFF; // clear all pending ints
  __DSB (); 
  __ISB ();
  SetBitMask (SPI2->CR1, SPI_CR1_SPE); // enable
  // Enable the SPI2 Interrupt
  NVIC_SetPriority (SPI2_IRQn, IRQ_priority_SPI2);
  NVIC_EnableIRQ (SPI2_IRQn);
 
  SetBitMask (SPI2->IER, SPI_IER_EOTIE);
  SetBitMask (SPI2->CR1, SPI_CR1_CSTART); // start transmission whenever a byte is filled in TXDR
}
 
// ***************************************************************************
 
void SPI2_IRQHandler (void)
{
  if (BitMaskIsSet (SPI2->SR, SPI_SR_TXC))
  {
    // do something at the end of transmission
  }
  SPI2->IFCR = 0xFFFFFFFF; // clear all pending ints
  while (BitMaskIsNOTClear (SPI2->SR, SPI_SR_TXC | SPI_SR_EOT | SPI_SR_SUSP))
  {
     // it is hanging here, because TXC is not cleared, without the while loop the isr is reentered over and over again
  }
}
 

Why is this interrupt firing? RM0433 says it will be triggered, when master transmission is completed, but I did not send a byte before it is triggered.

Why can't I clear TXC or how do I have to do it?

Thanks a lot for any help

Kind regards

Martin

3 REPLIES 3
Mr_M_from_G
Senior II

Hello all,

I found a solution for my problem:

  • I set EOTIE only after I put bytes into TxFifo, hardware has then cleared TXC
  • my isr looks like this:
void SPI2_IRQHandler (void)
{
  if (BitMaskIsSet (SPI2->SR, SPI_SR_TXC))
  {
    // do something after all bytes are out
  }
  ClearBitMask (SPI2->IER, SPI_IER_EOTIE);
  while (BitMaskIsNOTClear (SPI2->IER, SPI_IER_EOTIE))
  {
 
  } 
}

This only fires the interrupt when TxFifo is completely sent out.

This usage of an interrupt flag and an interrupt enable bit is clearly in contrast to anything I have seen in STM32 and other microcontrollers. I really wonder why it is not possible to reset TXC by software.

Hopefully an ST member can give an answer.

Thanks a lot

Martin

LuizLS
Associate II

Hi,

Your question is relevant to the one I have. I am writing an SPI polling transmission application for learning purposes. If I don't load TSIZE, all works fine and I can measure the MOSI and SCK signals with a logic analyzer.

The application checks TXP, load the TX data register, after which it starts transmission (CSTART). When TXC is set, transmission is suspended (CSUSP) , the SUSP flag is cleared, and the process starts all over until all data is transmitted.

Problem: if I write anything to TSIZE, there is no transmission. For testing purposes, I kept the program the same, just loaded TSIZE with the length of the TX data before enabling the SPI peripheral and starting transmission.

The system workbench debugger shows that TSIZE does not decrease (but CTSIZE does) when I load the TX data register and start transmission. No signal is observed on the logic analyzer. The TXC flag, however, is set after I load the TX data register with all the data, together with TXTF (TxFIFO upload finished) and EOT

Have you had any experience with this kind of problem?

Thanks in advance.

LuizLS
Associate II

Got it!

When using TSIZE, application must wait loading all data into TX data register before testing for TXC, while I was testing for TXC every time I loaded some data (in fact waiting for TXC to be set). This works if TSIZE is zero at the start of TX, in which case TXC is set as soon as TxFIFO is empty.