今天使用串口DMA做收发数据,在使用DMA接收数据的过程中,有一些关于HAL库的使用问题,和大家讨论分享一下。
下面是关于串口的配置,就不贴所有配置了。大家关注重点哈。
关于串口DMA配置:
首先说第一个问题,在使用stm32cubemx生成HAL库代码时,偶尔会出现SystemClock_Config();重复被调用的情况,由于这部分代码是软件生成的,部分人可能注意不到有这样的问题,但这里第二次调用后会使程序进入error状态,问题出现的原因还不清楚,希望有大佬看见能给出原因和j解决办法哈。
uint8_t ping_str[256];
uint8_t pang_str[256];
uint8_t *rxdata = ping_str ;
首先在main函数中启动串口DMA,调用函数HAL_UART_Receive_DMA(&huart1,rxdata,256);
这里串口DMA通道为DMA1_Channel5。接收方式为乒乓接收,就是每次接收成功后重新调用HAL_UART_Receive_DMA(&huart1,rxdata,256);而rxdata指向的地址在ping_str和pang_str之间切换,解析数据也是在pingstr和pangstr之间相互解析,在调试过程中发现,每两次才能成功的接收一次数据,再次调试时发现只有开始时指向ping_str生效了,后面切换的pang_str没有生效,导致第二次解析pang_str数据时,数据内容为0。还有就是DMA1_Channel5->CNDTR在每次解析完成数据后,没有被重置。导致一直检测缓冲区中有数据,影响程序运行。
以上所有的问题,原因都是在二次调用HAL_UART_Receive_DMA(&huart1,rxdata,256);函数时,没有生效导致的。第一步是huart->RxState == HAL_UART_STATE_READY判断不通过导致失败,强行赋值huart1.RxState = HAL_UART_STATE_READY;后,通过判断。
通过判断后,其中HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t *)tmp, Size);也没有生效,问题在于__HAL_LOCK(hdma);不通过。这里也没有办法解决,同样希望有大佬指导。
虽然有以上的问题,但是我发现可以通过改造重写DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength);实现DMA重新配置。
这是HAL库的源代码
/**
* @brief Sets the DMA Transfer parameter.
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @param SrcAddress: The source memory Buffer address
* @param DstAddress: The destination memory Buffer address
* @param DataLength: The length of data to be transferred from source to destination
* @retval HAL status
*/
static void DMA_SetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
{
/* Clear all flags */
hdma->DmaBaseAddress->IFCR = (DMA_ISR_GIF1 << hdma->ChannelIndex);
/* Configure DMA Channel data length */
hdma->Instance->CNDTR = DataLength;
/* Memory to Peripheral */
if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH)
{
/* Configure DMA Channel destination address */
hdma->Instance->CPAR = DstAddress;
/* Configure DMA Channel source address */
hdma->Instance->CMAR = SrcAddress;
}
/* Peripheral to Memory */
else
{
/* Configure DMA Channel source address */
hdma->Instance->CPAR = SrcAddress;
/* Configure DMA Channel destination address */
hdma->Instance->CMAR = DstAddress;
}
}
这是改造后的代码
void DMA1_SetConfig(uint8_t *pData, uint32_t DataLength)
{
uint32_t *tmp = (uint32_t *)&pData;
uint32_t DstAddress = *tmp;
/* Clear all flags */
huart1.hdmarx->DmaBaseAddress->IFCR = (DMA_ISR_GIF1 << huart1.hdmarx->ChannelIndex);
/* Configure DMA Channel data length */
DMA1_Channel5->CNDTR = DataLength;
/* Configure DMA Channel source address */
DMA1_Channel5->CPAR = (uint32_t)&USART1->DR;
/* Configure DMA Channel destination address */
DMA1_Channel5->CMAR = DstAddress;
}
DMA1_Channel5->CCR &= 0xFFFE;
DMA1_SetConfig((uint8_t*)SciaRxbufHandle->DATA.inbuff,256);
DMA1_Channel5->CCR |= 0x01;
通过调用以上代码,基本上实现乒乓接收。