1

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

OXO
  • 61
  • 4
  • 14

1 Answers1

1

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.

Guillaume Michel
  • 1,189
  • 8
  • 14
  • Thanks. Because this is a slave, it must respond to the received poll very quickly, otherwise the master will do its clocking and the slave won't have loaded the values. This is all quite confusing and not helped by the lack of documentation for the HAL. – OXO Aug 30 '17 at 13:47
  • OK. Make sense. I haven't realised it was a slave. The HAL is rather well documented in [STM32CubeF0](http://www.st.com/content/st_com/en/products/embedded-software/mcus-embedded-software/stm32-embedded-software/stm32cube-embedded-software/stm32cubef0.html). Especially the user manual UM1785. – Guillaume Michel Aug 30 '17 at 17:19