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

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

不幸掉了一次STM32|不幸掉了一次STM32 HAL固件库的坑
文章图片

程序一运行就死机,好不容易跟踪到 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 =https://www.it610.com/article/= NULL) || (Size == 0)) { returnHAL_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 =https://www.it610.com/article/= NULL) || (Size == 0)) { returnHAL_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; } }

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

    推荐阅读