cancel
Showing results for 
Search instead for 
Did you mean: 

SPI Issue - HAL_BUSY (STM32L4)

JayDev
Senior II

I've been having issues with getting an SD card working on an STM32L4R5ZI Nucleo board when using essentially the same code (with minor tweaks) without issues on the STM32WB55 Nucleo board.  I've been going through the code of both to determine where the problem is with the STM32L4 board.  I assumed I had a configuration issue in main (which I might still have, but the issue I found isn't what I was expecting).  

When running my SD_IO_Init function, it's writing dummy bits but when it calls HAL_SPI_TransmitReceive(), it's receiving HAL_BUSY as a response.  Usually when I'm having issues with my code, it's my implementation that's the issue but I'm not sure if that's necessarily the case here.  Below is the code I'm running:

/* SPI INIT */
static void MX_SPI1_Init(void)
{
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH;
  hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
  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;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
}

 

/* MAIN */
int main(void)
{
  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_LPUART1_UART_Init();
  MX_USART3_UART_Init();
  MX_USB_OTG_FS_PCD_Init();
  MX_SPI1_Init();
  MX_FATFS_Init();

  BSP_SD_Init();

  while (1)
  {

  }
}

 

/* SD INIT */
void SD_IO_Init(void)
{
  sd_spi.Instance = SPI1;

  SD_IO_CSState(1);

  for (uint8_t counter = 0; counter <= 9; counter++)
  {
    /* Send dummy byte 0xFF */
    SD_IO_WriteByte(SD_DUMMY_BYTE);
  }
}

 

uint8_t SD_IO_WriteByte(uint8_t Data)
{
  HAL_StatusTypeDef status = HAL_OK;
  uint8_t data;

  status = HAL_SPI_TransmitReceive(&sd_spi, (uint8_t*) &Data, &data, 1, SD_DATATIMEOUT);

  if(status != HAL_OK)
  {
		/* Execute user timeout callback */
		//SPIx_Error();
		//Handle error here
	}

  return data;
}
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size,
                                          uint32_t Timeout)
{
  uint16_t             initial_TxXferCount;
  uint16_t             initial_RxXferCount;
  uint32_t             tmp_mode;
  HAL_SPI_StateTypeDef tmp_state;
  uint32_t             tickstart;
#if (USE_SPI_CRC != 0U)
  __IO uint32_t tmpreg = 0U;
  uint32_t             spi_cr1;
  uint32_t             spi_cr2;
  __IO uint8_t  *ptmpreg8;
  __IO uint8_t  tmpreg8 = 0;
#endif /* USE_SPI_CRC */

  /* Variable used to alternate Rx and Tx during transfer */
  uint32_t             txallowed = 1U;
  HAL_StatusTypeDef    errorcode = HAL_OK;

  /* Check Direction parameter */
  assert_param(IS_SPI_DIRECTION_2LINES(hspi->Init.Direction));

  /* Process Locked */
  __HAL_LOCK(hspi);

  /* Init tickstart for timeout management*/
  tickstart = HAL_GetTick();

  /* Init temporary variables */
  tmp_state           = hspi->State;
  tmp_mode            = hspi->Init.Mode;
  initial_TxXferCount = Size;
  initial_RxXferCount = Size;
#if (USE_SPI_CRC != 0U)
  spi_cr1             = READ_REG(hspi->Instance->CR1);
  spi_cr2             = READ_REG(hspi->Instance->CR2);
#endif /* USE_SPI_CRC */

  if (!((tmp_state == HAL_SPI_STATE_READY) || \
        ((tmp_mode == SPI_MODE_MASTER) && (hspi->Init.Direction == SPI_DIRECTION_2LINES) && (tmp_state == HAL_SPI_STATE_BUSY_RX))))
  {
    errorcode = HAL_BUSY;  /* RETURNING HAL_BUSY HERE */
    goto error;
  }

........ 

I hesitate to report this as a bug as experience shows this is usually an issue on my end but I don't really understand what's causing it to return busy (it appears to be handled on the HAL side.  If that's not working, I assume that would be considered a bug).  

It currently shows "tmp_state" to be "HAL_SPI_STATE_RESET."  I'm not sure where hspi->State is being set

The only thing I could find regarding this state when searching had to do with HAL_SPI callbacks but I'm not using any interrupts so I'm not entirely sure what might cause that problem (or if I need to place empty functions to replace the weak callback functions?).  Essentially, I'm not really sure I understand the issue or where to go from here.  

Any help you can give would be greatly appreciated.  Thanks!

 

4 REPLIES 4
Pavel A.
Evangelist III

It currently shows "tmp_state" to be "HAL_SPI_STATE_RESET."  I'm not sure where hspi->State is being set

Memory overwrite? 

I hesitate to report this as a bug as experience shows this is usually an issue on my end

Yeah. Check for memory overwrite first.

 

TDK
Guru

> I'm not sure where hspi->State is being set

Set up a hardware watchpoint on that variable and the program will break when it gets modified.

See here for how to do that:

https://community.st.com/t5/stm32cubeide-mcus/how-to-add-the-watchpoint/m-p/310217/highlight/true#M16720

 

If you feel a post has answered your question, please click "Accept as Solution".
JayDev
Senior II

Well, it's possible I might have found one bug.  In the WB55, it has the line "goto error" and the error section shows this:

 

error :
  hspi->State = HAL_SPI_STATE_READY;
  __HAL_UNLOCK(hspi);
  return errorcode;
}

 

On the L4, it shows this:

 

error :
  __HAL_UNLOCK(hspi);
  return errorcode;

 

It looks like in HAL_SPI_TransmitReceive() in stm32l4xx.c, it's missing setting the state to ready.  

I'm still having other issues with my SD card functionality so I'm not sure if there are other SPI library issues but this definitely looks like a noticible difference in operation between the two chips (not sure if that makes it a bug or if this is the way it's meant to work?).

 

JayDev
Senior II

Found the release notes for L4+ embedded package and found this line in the notes:

HAL SPI update
Fix driver to don’t update state in case of error. (HAL_SPI_STATE_READY will be set only in case of HAL_TIMEOUT).

I'm not entirely sure what problem this was causing previously but I think it created a new one (or at least the solution isn't as clear).  Should I be manually setting it myself after the function fails and try again?  Seems like a pretty inefficient system (and I just checked the notes, this "fix" appears to have been implemented in all the SPI functions, or at least the ones I looked at).  

I think for the time being, I'm better off rolling back to a previous version because the source of my issues is likely related to this and not my implementation (which, if that's the case, makes me feel a lot better).  I've approached this several ways over many hours and didn't think to suspect the SPI functionality as I've never really had an issue with it in the past.  Rookie mistake, it would appear.