-
Notifications
You must be signed in to change notification settings - Fork 5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Bug] [stm32][uart v2]DMA RX接收拆包问题 #9533
Comments
这些东西不是bug,是使用者错误使用导致的。没有人保证过dma接收应该是怎么样的,serial就只是一个流而已,怎么处理和拆分数据是上层的事情。如果dma不开启满或者半满中断,那缓冲区不够怎么办?当然要及时通知上层把数据取走。 |
|
框架层并没有传入什么传入上层的标志,只有一个接收回调,这个回调的逻辑是用户自己编写的。再说接收完成的定义是什么?对于uart,接收到停止位就是接收完成。你所谓的帧这个概念根本不在里面。重复触发rx回调没有什么问题,中断模式下还每个字节都触发一次呢。 |
/* Interrupt receive event */
case RT_SERIAL_EVENT_RX_IND:
case RT_SERIAL_EVENT_RX_DMADONE:
{
struct rt_serial_rx_fifo *rx_fifo;
rt_size_t rx_length = 0;
rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx;
rt_base_t level;
RT_ASSERT(rx_fifo != RT_NULL);
/* If the event is RT_SERIAL_EVENT_RX_IND, rx_length is equal to 0 */
rx_length = (event & (~0xff)) >> 8;
if (rx_length)
{ /* RT_SERIAL_EVENT_RX_DMADONE MODE */
level = rt_hw_interrupt_disable();
rt_serial_update_write_index(&(rx_fifo->rb), rx_length);
rt_hw_interrupt_enable(level);
}
/* Get the length of the data from the ringbuffer */
rx_length = rt_ringbuffer_data_len(&rx_fifo->rb);
if (rx_length == 0) break;
if (serial->parent.open_flag & RT_SERIAL_RX_BLOCKING)
{
if (rx_fifo->rx_cpt_index && rx_length >= rx_fifo->rx_cpt_index )
{
rx_fifo->rx_cpt_index = 0;
rt_completion_done(&(rx_fifo->rx_cpt));
}
}
/* Trigger the receiving completion callback */
if (serial->parent.rx_indicate != RT_NULL)
serial->parent.rx_indicate(&(serial->parent), rx_length);
if (serial->rx_notify.notify)
{
serial->rx_notify.notify(serial->rx_notify.dev);
}
break;
} |
我在一开始就说了,这是你本来就用错了导致的,你所谓的一帧数据为什么不可以多次notify?数据都在环形缓冲区里,notify一次上层就可以消费一次,为什么要管是不是空闲?有谁规定空闲了就是一包数据结束了吗?那么在stm32里的空闲是固定的空闲一个字节,在别的MCU上这个说不定是可设置多少个字节呢?驱动本来就只管收数据,怎么处理数据是你自己去做的,不是驱动来做的。这就是个水管,你要多少水,可以一次性接满,也可以一次一次慢慢接,对结果没有影响。 |
引个题外话 最近做的应用,UART每接收到1个字节,自动记录当前精确时间戳,纳秒级。以供应用做细节处理。 |
|
这样并不是复杂了,这样才是简单了,你那样做是耦合的。项目大了是要使用原则和规范来约束的,而不是怎么方便怎么来。要有分层思想,驱动就是驱动,链路就是链路,应用就是应用,你觉得复杂你可以在驱动上再封装,而不是把你的想法揉进驱动里。 |
这种流式的数据在接收的时候是不能有帧的概念的,需要通过上层来通过滑窗或者其它的方式来确定帧。 |
官方库HAL_UARTEx_ReceiveToIdle_DMA的实现是处理了Cplt和HalfCplt的,只是提供了weak回调,应用没有重写这个回调看起来就和没处理一样,而uartV2驱动默认实现了回调,其逻辑是一样的。实现这个回调无非就是想尽快的通知应用把数据取走,避免数据被覆盖,特别是缓存开的小的时候,这是通用的做法。 |
RT-Thread Version
master
Hardware Type/Architectures
STM32F407VGT6
Develop Toolchain
RT-Thread Studio
Describe the bug
https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/uart/uart_v2/uart?id=%e4%b8%b2%e5%8f%a3%e8%ae%be%e5%a4%87%e4%bd%bf%e7%94%a8%e7%a4%ba%e4%be%8b
前两次仅触发空闲中断;第三次触发半满中断后->执行了回调函数唤醒线程接收数据;但是此时数据并未接收完成,导致又进入了空闲中断重复步骤,再次唤醒线程接收数据;导致接收的数据拆包断帧;
HAL_UARTEx_ReceiveToIdle_DMA
,并没有对DMA全满半满做出处理;方法1:注释掉uartV2的全满半满处理逻辑
方法2:uartV2按照uartV1实现的DMA方式实现
Other additional context
No response
The text was updated successfully, but these errors were encountered: