不幸掉了一次STM32 HAL固件库的坑

这几天用STM32F10X控制WS2812B,看了网上说的,用SPI的DMA模式发送数据,可以很大提高效率,于是用STM32CubeMx生成了SPI DMA发送的代码。
下载了STM32CubeMx,将SPI只发模式,固件库按提示随便下载了以下,没关注不是最新版本。简单的设置后即可生成工程。
不幸掉了一次STM32 HAL固件库的坑_第1张图片
不幸掉了一次STM32 HAL固件库的坑_第2张图片

程序一运行就死机,好不容易跟踪到 HAL_SPI_Transmit_DMA函数,该函数在stm32l1xx_hal_spi.c 中,代码如下:

HAL_StatusTypeDef HAL_SPI_Transmit_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size)
{
  if(hspi->State == HAL_SPI_STATE_READY)
  {
    if((pData == NULL) || (Size == 0))
    {
      return  HAL_ERROR;
    }

    /* Check the parameters */
    assert_param(IS_SPI_DIRECTION_2LINES_OR_1LINE(hspi->Init.Direction));

    /* Process Locked */
    __HAL_LOCK(hspi);

    /* Configure communication */
    hspi->State       = HAL_SPI_STATE_BUSY_TX;
    hspi->ErrorCode   = HAL_SPI_ERROR_NONE;

    hspi->pTxBuffPtr  = pData;
    hspi->TxXferSize  = Size;
    hspi->TxXferCount = Size;

    /*Init field not used in handle to zero */
    hspi->TxISR       = 0;
    hspi->RxISR       = 0;
    hspi->pRxBuffPtr  = NULL;
    hspi->RxXferSize  = 0;
    hspi->RxXferCount = 0;

    /* Configure communication direction : 1Line */
    if(hspi->Init.Direction == SPI_DIRECTION_1LINE)
    {
      SPI_1LINE_TX(hspi);
    }

    /* Reset CRC Calculation */
    if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
    {
      SPI_RESET_CRC(hspi);
    }

    /* Set the SPI TxDMA Half transfer complete callback */
    hspi->hdmatx->XferHalfCpltCallback = SPI_DMAHalfTransmitCplt;

    /* Set the SPI TxDMA transfer complete callback */
    hspi->hdmatx->XferCpltCallback = SPI_DMATransmitCplt;

    /* Set the DMA error callback */
    hspi->hdmatx->XferErrorCallback = SPI_DMAError;

    /* Reset content of SPI RxDMA descriptor */
    hspi->hdmarx->XferHalfCpltCallback = 0;
    hspi->hdmarx->XferCpltCallback     = 0;
    hspi->hdmarx->XferErrorCallback    = 0;

    /* Enable the Tx DMA Channel */
    HAL_DMA_Start_IT(hspi->hdmatx, (uint32_t)hspi->pTxBuffPtr, (uint32_t)&hspi->Instance->DR, hspi->TxXferCount);

    /* Enable Tx DMA Request */
    SET_BIT(hspi->Instance->CR2, SPI_CR2_TXDMAEN);

    /* Process Unlocked */
    __HAL_UNLOCK(hspi);

    /* Check if the SPI is already enabled */ 
    if((hspi->Instance->CR1 &SPI_CR1_SPE) != SPI_CR1_SPE)
    {
      /* Enable SPI peripheral */
      __HAL_SPI_ENABLE(hspi);
    }

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

跟踪发现运行到这里必死:
hspi->hdmarx->XferHalfCpltCallback = 0;
hspi->hdmarx->XferCpltCallback = 0;
hspi->hdmarx->XferErrorCallback = 0;

继续分析,发现只发模式下, HAL_SPI_MspInit 中 hspi->hdmarx是个空指针,未被初始化。
去掉这三行代码后不再死机。

HAL固件库真是到处有坑,要么改它的固件代码,要么再人为指定一个没有意义的
hspi->hdmarx,让人恼火。

于是,试着更新一下最新的固件库看看,要仍然有这个问题,打算以后都不用STM32CubeMx了,更新后到STM32Cube_FW_F1_V1.4.0固件库,并删除旧的固件,查看了一下HAL_SPI_Transmit_DMA函数,代码已经修改了:

HAL_StatusTypeDef HAL_SPI_Transmit_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size)
{
  if(hspi->State == HAL_SPI_STATE_READY)
  {
    if((pData == NULL) || (Size == 0))
    {
      return  HAL_ERROR;
    }

    /* Check the parameters */
    assert_param(IS_SPI_DIRECTION_2LINES_OR_1LINE(hspi->Init.Direction));

    /* Process Locked */
    __HAL_LOCK(hspi);

    /* Configure communication */
    hspi->State       = HAL_SPI_STATE_BUSY_TX;
    hspi->ErrorCode   = HAL_SPI_ERROR_NONE;

    hspi->pTxBuffPtr  = pData;
    hspi->TxXferSize  = Size;
    hspi->TxXferCount = Size;

    /*Init field not used in handle to zero */
    hspi->TxISR       = 0;
    hspi->RxISR       = 0;
    hspi->pRxBuffPtr  = NULL;
    hspi->RxXferSize  = 0;
    hspi->RxXferCount = 0;

    /* Configure communication direction : 1Line */
    if(hspi->Init.Direction == SPI_DIRECTION_1LINE)
    {
      SPI_1LINE_TX(hspi);
    }

    /* Reset CRC Calculation */
    if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
    {
      SPI_RESET_CRC(hspi);
    }

    /* Set the SPI TxDMA Half transfer complete callback */
    hspi->hdmatx->XferHalfCpltCallback = SPI_DMAHalfTransmitCplt;

    /* Set the SPI TxDMA transfer complete callback */
    hspi->hdmatx->XferCpltCallback = SPI_DMATransmitCplt;

    /* Set the DMA error callback */
    hspi->hdmatx->XferErrorCallback = SPI_DMAError;

    /* Enable the Tx DMA Channel */
    HAL_DMA_Start_IT(hspi->hdmatx, (uint32_t)hspi->pTxBuffPtr, (uint32_t)&hspi->Instance->DR, hspi->TxXferCount);

    /* Enable Tx DMA Request */
    SET_BIT(hspi->Instance->CR2, SPI_CR2_TXDMAEN);

    /* Process Unlocked */
    __HAL_UNLOCK(hspi);

    /* Check if the SPI is already enabled */ 
    if((hspi->Instance->CR1 &SPI_CR1_SPE) != SPI_CR1_SPE)
    {
      /* Enable SPI peripheral */
      __HAL_SPI_ENABLE(hspi);
    }

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

可以看到该函数中不再出现与DMA接收,也就是hspi->hdmarx相关的操作了。
看来ST的人还是发现了该问题,好吧,那HAL固件库我还继续用用,希望不要再有坑了,小伙伴们使用过程中,也尽量用新版的固件库。

你可能感兴趣的:(不幸掉了一次STM32 HAL固件库的坑)