基于STM32的串口DMA发送

发布时间:2023-07-03  

问题描述

使用STM32的串口进行DMA发送(Noraml模式),在某个任务中连续调用两次发送函数log_printf(),但是发回的数据在串口调试助手上显示与预期不符。第一次发送的数据有一部分被第二次发送的数据覆盖,如图所示:

基于STM32的串口DMA发送

任务代码如下:

/* Log_Task function */void Log_Task(void const * argument)

{ /* USER CODE BEGIN Log_Task */

/* Infinite loop */

for(;;)

{ if(router_rx_flag == 1)

{

router_rx_flag = 0;

log_printf(“Get okrn”);

log_printf(“%s”,router_rx_buffer);

}

osDelay(100);

} /* USER CODE END Log_Task */}1234567891011121314151617

从代码中可以看出,期望的结果应该是下图这样:

基于STM32的串口DMA发送

log_printf函数代码如下:

/*

* 名称: log_printf

* 功能: 在串口1上打印出日志内容

* 输入: 格式化输出的字符串

* 输出: 无

*/

void log_printf(const char *format ,。。。 )

{

va_list arg;

static char tx_buffer[256]={“”};

//把数据处理后放进缓冲区

va_start(arg, format);

vsprintf((char *)tx_buffer, format, arg);

va_end(arg);

//开始发送数据

send_to_router((u8 *)tx_buffer,strlen(tx_buffer));

}

send_to_router函数代码如下:

void send_to_router(unsigned char *buffer,unsigned int length)

{

//等待上一次的数据发送完毕

while(HAL_DMA_GetState(&hdma_usart1_tx) == HAL_DMA_STATE_BUSY) osDelay(1);

/* 关闭DMA */

__HAL_DMA_DISABLE(&hdma_usart1_tx);

//开始发送数据

HAL_UART_Transmit_DMA(&huart1,buffer,length);

// while(HAL_DMA_GetState(&hdma_usart1_tx) == HAL_DMA_STATE_BUSY) osDelay(1); /* 放在此处可以保证每次发送完全,但会占用时间 */

}

串口中断接收处理函数如下:

/*

* 名称: router_parse

* 功能: 接收路由器数据的解析,在回调函数中调用

* 输入: 空闲中断时串口1接收的数据长度

* 输出: 无

*/

void router_parse(uint16_t buffer_len)

{

char *p_start = NULL,*p_end = NULL;

/* 只提取一帧NMEA数据,$开头,n结尾 */

p_start = strchr(usart1_rx_buffer,‘$’);

if(p_start != NULL)

{

p_end = strchr(p_start,‘n’);

if(p_end != NULL)

{

memcpy(router_rx_buffer, p_start, (p_end - p_start + 1)); /* 保存数据 */

router_rx_flag = 1;

}

}

}

分析过程

以前一直以为是send_to_router函数中的

//等待上一次的数据发送完毕

while(HAL_DMA_GetState(&hdma_usart1_tx) == HAL_DMA_STATE_BUSY) osDelay(1);

这一句的问题,即由于某种原因导致DMA缓存中数据未发送完全,但DMA状态却被释放了,结果重新开始了新一轮的发送,导致上次数据的后半部分被覆盖。但无论如何调试,都无法证实这个猜想,DMA外设没有出过任何异常。

今天仔细观察了一下,“Getckey”和“Get okrn”和”$Mickeyrn“,为什是第二次发送的内容的后半部覆盖了第一次发送的内容,一般不应该是前半部分”(美元符号,此处会排版出错)Mic”吗?问题的原因可能与状态位无关。于是我再审视了一下send_to_router函数:void send_to_router(unsigned char *buffer,unsigned int length)突然间想到,入参只是一个指针,发送缓存区在log_printf函数中

static char tx_buffer[256]={“”};

整理一下,整个发送过程流程如下:

log_printf(“Get okrn”);时,“Get okrn”被装进了tx_buffer,附带一个发送长度8字节。

send_to_router函数中,HAL_UART_Transmit_DMA(&huart1,buffer,length);开启了这个8个字节的发送。

8个字节可能只完成了“Get”的发送, log_printf(“%s”,router_rx_buffer);(即log_printf(“$Mickeyrn“);)已经开始执行。

”$Mickeyrn“被装进tx_buffer,附带一个发送长度9字节。

send_to_router函数中,因为上一次数据还没有发送完全,进入DMA状态等待循环。但是DMA发送指针char *buffer原本指向的那个地址的内容” okrn“已经被”ckeyrn“代替,所以就变成了”Getckeyr“。由于显示原因,只看到”Getckey“。

解决办法

把while(HAL_DMA_GetState(&hdma_usart1_tx) == HAL_DMA_STATE_BUSY) osDelay(1);这一句放到缓存区tx_buffer装载步骤之前即可:

/*

* 名称: log_printf

* 功能: 在串口1上打印出日志内容

* 输入: 格式化输出的字符串

* 输出: 无

*/

void log_printf(const char *format ,。。。 )

{

va_list arg;

static char tx_buffer[256]={“”};

//等待上一次的数据发送完毕

while(HAL_DMA_GetState(&hdma_usart1_tx) == HAL_DMA_STATE_BUSY) osDelay(1);

//把数据处理后放进缓冲区

va_start(arg, format);

vsprintf((char *)tx_buffer, format, arg);

va_end(arg);

//开始发送数据

send_to_router((u8 *)tx_buffer,strlen(tx_buffer));

}

至于send_to_router函数中的该代码,保留或删除都可以。

后言

很久以前就开始使用STM32的DMA串口发送功能,套路基本上就是曾经的博文《iar中使用DMA+printf+uart1》所描述的那样。后来开始用STM32CubeMX了,把之前的例程稍微做了一些修改,调试成功之后,就一直沿用至今。期间,这个问题困扰了我很久,虽然在写代码时稍微注意一下就可避免其发生,但做技术的人都明白:千里之堤,溃于蝼蚁,放过任何一个小细节都可能在将来引发重大灾难。很庆幸今天能够找到问题的原因。

再回去看来一遍《iar中使用DMA+printf+uart1》,其实这个问题的答案很早就写在里面了。。。

找个时间,我会专门写一篇使用DMA串口Normal模式发送的博文,还是以Cube来创建工程。届时,再用一个例程完整复现和解决这个问题。


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>