Search code examples
interruptstm32spivariable-length

Read variable length messages over SPI using Low Level (LL) api on STM32 MCU


My system is composed by an STM32NUCLEO board and a slave device connected over SPI. The slave device sends commands with a variable length: possible lengths are 4, 8, 10, 14 bits.

I'm trying to detect these messages on my nucleo board using the LL APIs and interrupts.

The solution I'm currently working on is based on setting the SPI with a data-width of 4 bits (SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_4BIT) and then counting the number of words (1 word = 4 bits) that I receive. In this way, if I receive 1 word then it means that I have received a 4 bit command, 2 word --> 8 bit command. If I receive 3 words, it should mean that I have received a 10bit command (2 bits should be discarded), and so on.

Unfortunately, I have noticed that the LL APIs provides functions only for reading 8 bits or 16 bits at a time and currently I'm having issue in receiving a 4 bit command, since the function LL_SPI_ReceiveData8 expects to receive 8 bits.

Here is my implementation for the IRQ handler and for the callback:

IRQ Handler:

void SPI1_IRQHandler(void)
{
  /* Check RXNE flag value in ISR register */
  if(LL_SPI_IsActiveFlag_RXNE(SPI1))
  {
    /* Call function Slave Reception Callback */
    SPI1_Rx_Callback();
  }
  /* Check STOP flag value in ISR register */
  else if(LL_SPI_IsActiveFlag_OVR(SPI1))
  {
    /* Call Error function */
    SPI1_TransferError_Callback();
  }
}

Callback

void SPI1_Rx_Callback(void)
{
  /* Read character in Data register.
  RXNE flag is cleared by reading data in DR register */
  aRxBuffer[ubReceiveIndex++] = LL_SPI_ReceiveData8(SPI1);
}

As said before in my opinion, the problem seems that I'm using the LL_SPI_ReceiveData8 function to read since I could not find something like LL_SPI_ReceiveData4.

Do you have some suggestions?

Furthermore, is it possible to set the SPI to use 2 bit datawidth instead of 4? Something like SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_2BIT: in this way it should be easier to detect the commands since 4, 8, 10 and 14 are multiples of 2.

Thank you.


Solution

  • With the new information about the used controller:

    It supports SPI data transfer length between 4 and 16 bit. So your first try seems not so bad.

    Your "problem" is that there is no 4 bit read function. This is caused by the receive data register that will always contain 16 bit but there are only 4 bit valid data in your case. the other bits are '0'.

    Your callback function

    aRxBuffer[ubReceiveIndex++] = LL_SPI_ReceiveData8(SPI1);
    

    will write values from 0..15 to the aRxBuffer and you don't need a LL_SPI_ReceiveData4() to get your answer :-)

    So also the Reference manual for the STM32L4 series Reference Manual at page 1333f.