Closed armink closed 7 years ago
1、这个问题我接下来发起个 pr 2、恩,现在能想明白这个过程了,buffer 由上层应用来提供,设备驱动框架内部并不提供 buffer ,因为 DMA 传输需要人为启动,并不是时刻都在传输的。那这也就意味着,同样的应用程序,在采用 DMA 与 中断 两种不同的底层驱动接收数据时,上层处理业务流程会有差异,无法兼容。所以我现在的做法是改造了 DMA 串口驱动框架,跟中断方式一样,设备驱动层提供 buffer ,专心负责数据的接收,应用层业务也得到简化和统一。 @BernardXiong 你觉得这种方式怎么样?
可以考虑,不过这样必然需要做buffer复制了。
是的,写 buffer 是 DMA 自动完成的, device read 需要做 buffer 复制。
@BernardXiong 或者我把驱动完善为新旧模式都支持,判断 serial->config.bufsz
,等于 0 时,则使用原先的那种传递指针的非缓冲模式,否则使用我说的这种底层缓冲接收的模式。你看可以吗?
用Keil MDK编译,好像会编译失败,确认下代码。
@BernardXiong 熊大,新驱动刚用 stm32f10x BSP 在 Keil 里测试了下,没有问题。
_serial_dma_tx => serial->ops->dma_transmit(serial, data, length, RT_SERIAL_DMA_TX); 应该会报一个const数据类型不匹配的错误,或警告吧。
由于众多 BSP 中缺少最新 DMA 方式的串口设备驱动的实现,整个设备驱动的流程并不明确,自己摸索中实现了一套 DMA 方式的串口驱动,但涉及到 RTT 源码中一些细节存在冲突,便产生如下疑问:
dma_transmit
使用疑问?串口操作回调接口中的
dma_transmit
方法,我的理解应该是 DMA 传输的操作接口,direction
代表方向,那么在接收数据时,由于const rt_uint8_t *buf
指向的是一个只读缓冲区,则无法传入上层接收缓冲区的地址。我以往的串口设备读取数据的流程是,先调用
rt_device_read
读取串口 FIFO 中已经接收到的数据。如果数据不够时,设置接收回调,此时读数据线程被阻塞。在接收回调中会检测接收长度,如果长度够了,则唤醒被阻塞的读数据线程,设置回调为 NULL。 但是,对于 RTT 自带的 DMA 串口驱动中,在打开设备到关闭设备之间,必须得时刻存在接收回调接口(见 https://github.com/RT-Thread/rt-thread/blob/master/components/drivers/serial/serial.c#L615 )。同时,在这段代码中(https://github.com/RT-Thread/rt-thread/blob/master/components/drivers/serial/serial.c#L174-L179 ),有强制要求, DMA 是在激活状态才允许传输 一次 ,如果一次不把数据全部读走,剩下的数据只能等待下次接收传输结束时才能够读取走。所以顺着以往的思路去处理 DMA 接收驱动,发现跟 RTT 设计意图应该有所背离。虽然最后注释掉rx_dma->activated
检测逻辑(stm32f10x 驱动在这里,还没来得及整理),DMA 驱动已经能够按照往的流程稳定工作,但还是想了解当时 RTT 的 DMA 串口驱动设计思想及实现流程。