这几天用STM32F10X控制WS2812B,看了网上说的,用SPI的DMA模式发送数据,可以很大提高效率,于是用STM32CubeMx生成了SPI DMA发送的代码。
下载了STM32CubeMx,将SPI只发模式,固件库按提示随便下载了以下,没关注不是最新版本。简单的设置后即可生成工程。
程序一运行就死机,好不容易跟踪到 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固件库我还继续用用,希望不要再有坑了,小伙伴们使用过程中,也尽量用新版的固件库。