在(1)中我提到调用HAL_SPI_DeInit可以完全消除DMA和SPI的初始化内对于结构体的赋值,之后再调用HAL_SPI_Init()就可以开启新一轮的传输。一开始确实可以,但后来出了问题。
出现error的代码为:
HAL_SPI_Init()下的HAL_SPI_MspInit()下的HAL_DMA_Init()出了error
该函数原型为:
HAL_StatusTypeDef HAL_DMA_Init(DMA_HandleTypeDef *hdma)
{
uint32_t tmp = 0U;
uint32_t tickstart = HAL_GetTick();
DMA_Base_Registers *regs;
/* Check the DMA peripheral state */
if(hdma == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_DMA_STREAM_ALL_INSTANCE(hdma->Instance));
assert_param(IS_DMA_CHANNEL(hdma->Init.Channel));
assert_param(IS_DMA_DIRECTION(hdma->Init.Direction));
assert_param(IS_DMA_PERIPHERAL_INC_STATE(hdma->Init.PeriphInc));
assert_param(IS_DMA_MEMORY_INC_STATE(hdma->Init.MemInc));
assert_param(IS_DMA_PERIPHERAL_DATA_SIZE(hdma->Init.PeriphDataAlignment));
assert_param(IS_DMA_MEMORY_DATA_SIZE(hdma->Init.MemDataAlignment));
assert_param(IS_DMA_MODE(hdma->Init.Mode));
assert_param(IS_DMA_PRIORITY(hdma->Init.Priority));
assert_param(IS_DMA_FIFO_MODE_STATE(hdma->Init.FIFOMode));
/* Check the memory burst, peripheral burst and FIFO threshold parameters only
when FIFO mode is enabled */
if(hdma->Init.FIFOMode != DMA_FIFOMODE_DISABLE)
{
assert_param(IS_DMA_FIFO_THRESHOLD(hdma->Init.FIFOThreshold));
assert_param(IS_DMA_MEMORY_BURST(hdma->Init.MemBurst));
assert_param(IS_DMA_PERIPHERAL_BURST(hdma->Init.PeriphBurst));
}
/* Allocate lock resource */
__HAL_UNLOCK(hdma);
/* Change DMA peripheral state */
hdma->State = HAL_DMA_STATE_BUSY;
/* Disable the peripheral */
__HAL_DMA_DISABLE(hdma);
/* Check if the DMA Stream is effectively disabled */
while((hdma->Instance->CR & DMA_SxCR_EN) != RESET)
{
/* Check for the Timeout */
if((HAL_GetTick() - tickstart ) > HAL_TIMEOUT_DMA_ABORT)
{
/* Update error code */
hdma->ErrorCode = HAL_DMA_ERROR_TIMEOUT;
/* Change the DMA state */
hdma->State = HAL_DMA_STATE_TIMEOUT;
return HAL_TIMEOUT;
}
}
/* Get the CR register value */
tmp = hdma->Instance->CR;
/* Clear CHSEL, MBURST, PBURST, PL, MSIZE, PSIZE, MINC, PINC, CIRC, DIR, CT and DBM bits */
tmp &= ((uint32_t)~(DMA_SxCR_CHSEL | DMA_SxCR_MBURST | DMA_SxCR_PBURST | \
DMA_SxCR_PL | DMA_SxCR_MSIZE | DMA_SxCR_PSIZE | \
DMA_SxCR_MINC | DMA_SxCR_PINC | DMA_SxCR_CIRC | \
DMA_SxCR_DIR | DMA_SxCR_CT | DMA_SxCR_DBM));
/* Prepare the DMA Stream configuration */
tmp |= hdma->Init.Channel | hdma->Init.Direction |
hdma->Init.PeriphInc | hdma->Init.MemInc |
hdma->Init.PeriphDataAlignment | hdma->Init.MemDataAlignment |
hdma->Init.Mode | hdma->Init.Priority;
/* the Memory burst and peripheral burst are not used when the FIFO is disabled */
if(hdma->Init.FIFOMode == DMA_FIFOMODE_ENABLE)
{
/* Get memory burst and peripheral burst */
tmp |= hdma->Init.MemBurst | hdma->Init.PeriphBurst;
}
/* Write to DMA Stream CR register */
hdma->Instance->CR = tmp;
/* Get the FCR register value */
tmp = hdma->Instance->FCR;
/* Clear Direct mode and FIFO threshold bits */
tmp &= (uint32_t)~(DMA_SxFCR_DMDIS | DMA_SxFCR_FTH);
/* Prepare the DMA Stream FIFO configuration */
tmp |= hdma->Init.FIFOMode;
/* The FIFO threshold is not used when the FIFO mode is disabled */
if(hdma->Init.FIFOMode == DMA_FIFOMODE_ENABLE)
{
/* Get the FIFO threshold */
tmp |= hdma->Init.FIFOThreshold;
/* Check compatibility between FIFO threshold level and size of the memory burst */
/* for INCR4, INCR8, INCR16 bursts */
if (hdma->Init.MemBurst != DMA_MBURST_SINGLE)
{
if (DMA_CheckFifoParam(hdma) != HAL_OK)
{
/* Update error code */
hdma->ErrorCode = HAL_DMA_ERROR_PARAM;
/* Change the DMA state */
hdma->State = HAL_DMA_STATE_READY;
return HAL_ERROR;
}
}
}
/* Write to DMA Stream FCR */
hdma->Instance->FCR = tmp;
/* Initialize StreamBaseAddress and StreamIndex parameters to be used to calculate
DMA steam Base Address needed by HAL_DMA_IRQHandler() and HAL_DMA_PollForTransfer() */
regs = (DMA_Base_Registers *)DMA_CalcBaseAndBitshift(hdma);
/* Clear all interrupt flags */
regs->IFCR = 0x3FU << hdma->StreamIndex;
/* Initialize the error code */
hdma->ErrorCode = HAL_DMA_ERROR_NONE;
/* Initialize the DMA state */
hdma->State = HAL_DMA_STATE_READY;
return HAL_OK;
}
返回的errorcode为HAL_TimeOut ,提示信息为/* Check if the DMA Stream is effectively disabled */
原来是DMA的流还存在,_HAL_DMA_DISABLE()失败了。
经过两天,我找到了自己需要的函数原型:HAL_DMA_Abort()
在HAL_SPI_DeInit()之后调用,再重新Init,就得到了SPI+DMA的一个完全初始化的状态。
本文档记录了在使用SPI和DMA进行传输时遇到的问题,即调用HAL_SPI_DeInit后仍存在残留的DMA流。通过分析错误提示,发现HAL_DMA_Disable无法有效关闭流。最终,通过引入HAL_DMA_Abort函数,在HAL_SPI_DeInit之后调用来彻底清除DMA流,从而实现完全初始化,解决了问题。
&spm=1001.2101.3001.5002&articleId=103468476&d=1&t=3&u=62102eb4c4f742c69eea0ee4a9a591cf)
1971

被折叠的 条评论
为什么被折叠?



