Overrun in ST32 HAL SPI slave interrupt

5.1k views Asked by At

I have a difficulty with ST32F030 and Slave SPI

I'm trying to have it respond to an spi command:-

Master sends 0x05, slave responds with an array of 7 bytes. It kind of works the first time, but then loses sync, and get OVR bit set. I can't figure out why.

Heres the code:-

int main(void)
{
   HAL_Init();
   /* Configure the system clock */
   SystemClock_Config();
   /* Initialize all configured peripherals */
   MX_SPI1_Init();
   spi_init();

   while (1)
   {
      HAL_SPI_Receive_IT(&hspi1, &spiData[0], 1);
   }
}

/* SPI1 init function */
static void MX_SPI1_Init(void)
{
   hspi1.Instance = SPI1;
   hspi1.Init.Mode = SPI_MODE_SLAVE;
   hspi1.Init.Direction = SPI_DIRECTION_2LINES;
   hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
   hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
   hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
   hspi1.Init.NSS = SPI_NSS_SOFT;
   hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
   hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
   hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
   hspi1.Init.CRCPolynomial = 7;
   hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
   hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
   /* SPi priority interrupt configuration */
   HAL_NVIC_SetPriority(SPI1_IRQn, 1, 1);
   if (HAL_SPI_Init(&hspi1) != HAL_OK)
   {
      Error_Handler();
   }
}


void spi_init()
{
      HAL_SPI_Receive_IT(&hspi1, spiData, 1);
}

void SPI1_IRQHandler(void)
{
   HAL_SPI_IRQHandler(&hspi1);
}

uint8_t spiData[8];
uint8_t edgesmsg[7];

void spi_interrupt()
{
   uint8_t c;

   c = spiData[0];
   if ( c == 0x05)
      HAL_SPI_Transmit(&hspi1, edgesmsg, 7, 1000);
}

Any suggestions gratefully received

1

There are 1 answers

2
Guillaume Michel On

Your problem is that you are trying to read from the SPI all the time without finishing the previous operation, which is why you get overrun (OVR bit). Try to better sequence things.

For example, remove HAL_SPI_Receive_IT(&hspi1, &spiData[0], 1); from your main loop and call it in your interrupt handler instead. The code should be:

int main(void)
{
   HAL_Init();
   /* Configure the system clock */
   SystemClock_Config();
   /* Initialize all configured peripherals */
   MX_SPI1_Init();
   spi_init();

   while (1)
   {
      //Do not call HAL_SPI_Receive_IT here
      //HAL_SPI_Receive_IT(&hspi1, &spiData[0], 1);
   }
}



void spi_interrupt()
{
   uint8_t c;

   c = spiData[0];
   if ( c == 0x05)
   {
       HAL_SPI_Transmit(&hspi1, edgesmsg, 7, 1000);
   }

   //Re-enable interrupt to read next sequence
   HAL_SPI_Receive_IT(&hspi1, &spiData[0], 1);
}

This is the principle. You reenable the interrupt after you have treated your packet. However, I am not sure what your intentions are and you might need to adapt the above code.

Also note that any interrupt handler should be as fast as possible. So it is not really acceptable to call HAL_SPI_Transmit (a polling function) in your interrupt handler spi_interrupt. You should either call HAL_SPI_Transmit_IT or not using interrupt at all. In the first case, beware of the sequencing again.