|
又来说一个比较偏的问题..
//---------------------------------
我认为你已经基本了解了dma传输,和协议栈下uart利用dma传输的机制
然后我们来谈谈这个伪bug:
//---------------------------------
先来看看这个结构体:- typedef struct
- {
- uint16 rxBuf[HAL_UART_DMA_RX_MAX];
- rxIdx_t rxHead;
- rxIdx_t rxTail;
- uint8 rxTick;
- uint8 rxShdw;
- uint8 txBuf[2][HAL_UART_DMA_TX_MAX];
- txIdx_t txIdx[2];
- volatile uint8 txSel;
- uint8 txMT;
- uint8 txTick;
- volatile uint8 txShdw; // Sleep Timer LSB shadow.
- volatile uint8 txShdwValid; // TX shadow value is valid
- uint8 txDMAPending; // UART TX DMA is pending
- halUARTCBack_t uartCB;
- } uartDMACfg_t;
复制代码 rxBuf[HAL_UART_DMA_RX_MAX]就是缓存,数组大小是256
只关注rxHead,rxTail只是为了判断超时用的,有了rxHead数组就变成链表了
然后简单说下,
设备上电,rxHead=0,DMA传输指针dmhead=0;
rxHead在rxBuf被读取时++
dmhead在串口有数据时++
情况1:
接收一个字节,rxHead=0,dmhead=1;读走这个字节rxHead=1,dmhead=1;
再接收一个字节,rxHead=1,dmhead=2;读走这个字节rxHead=2,dmhead=2;
再接收254个字节,rxHead=2,dmhead=0;再读走着254个字节,rxHead=0,dmhead=0;
情况2:
然而如果一下子接收了257个字节!!rxHead=0,dmhead=1;读取这257个字节,实际只能读到256个,rxHead=0,dmhead=1;而且读取的第一个字节rxBuf[0]会被第257个字节覆盖
然后再接收1个字节,rxHead=0,dmhead=2;这时候无法读走这个字节,因为读取函数中判断rxBuf[0]无效,而实际接收位置是rxBuf[1]
产生这种情况的根本原因是:- else if (cnt >= HAL_UART_DMA_HIGH)
- {
- evt = HAL_UART_RX_ABOUT_FULL;
- PxOUT |= HAL_UART_Px_RTS; // Disable Rx flow.
- }
复制代码 在串口缓存快满的时候,会Disable Rx flow,然后- PxOUT &= ~HAL_UART_Px_RTS; // Re-enable the flow on any read.//keke
复制代码 读取函数后重新使能
在两线串口下这个功能是没有的
所以需要注意,不然就用额外的代码来解决,比如关dma中断
即使是4线串口也存在这个问题,因为- PxOUT |= HAL_UART_Px_RTS; // Disable Rx flow.
复制代码 这个是在主osal循环里面,不可能及时执行到
所以一切都是浮云
有人说我缓冲256个字节不会满,那当然没问题,
也注意这种情况,你在处理一个任务id的某事件的时候,耗时比较长,同时有串口数据过来,大量的短的串口数据可能使串口缓冲溢出!
有人说开串口中断吧不要dma了,ok很好,没有这个问题,因为dma传输是覆盖链表数据,而串口isr是不会覆盖的(没时间验证,个人推测)
自己mark
关于协议栈下的串口和dma,可以看看我写的日志:
http://user.qzone.qq.com/744721131/infocenter#!
欢迎大家测试和指正 |
|