這裏分析一下RT-Thread中串口DMA方式的實現,以供作新處理器串口支持時的參考。函數
在現在的芯片性能和外設強大功能的狀況下,串口不實現DMA/中斷方式操做,我認爲在實際項目中基本是不可接受的,但遺憾的是,rt-thread現有支持的實現中,基本上沒有支持串口的DMA,文檔也沒有關於串口DMA支持相關的說明,這裏以STM32實現爲背景,梳理一下串口DMA的實現流程,以供新處理器實現時以做參考。性能
啓用DMA接收,須要在打開設備的時候作一些處理,入口函數爲rt_device_open()。主體實現是:ui
rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflag) { ...... result = device_init(dev); ...... result = device_open(dev, oflag); ...... }
device_init()就是rt_serial_init()函數,其主要是調用configure()函數,spa
static rt_err_t rt_serial_init(struct rt_device *dev) { ...... if (serial->ops->configure) result = serial->ops->configure(serial, &serial->config); ...... }
在stm32下,其configure()函數是stm32_configure(),其根據設備打開參數,配置STM32外設的寄存器。包括波特率、校驗等串口工做參數。code
device_open()函數就是rt_serial_open()函數,其主要實現是:隊列
static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag) { ...... #ifdef RT_SERIAL_USING_DMA else if (oflag & RT_DEVICE_FLAG_DMA_RX) { if (serial->config.bufsz == 0) { struct rt_serial_rx_dma* rx_dma; rx_dma = (struct rt_serial_rx_dma*) rt_malloc (sizeof(struct rt_serial_rx_dma)); RT_ASSERT(rx_dma != RT_NULL); rx_dma->activated = RT_FALSE; serial->serial_rx = rx_dma; } else { struct rt_serial_rx_fifo* rx_fifo; rx_fifo = (struct rt_serial_rx_fifo*) rt_malloc (sizeof(struct rt_serial_rx_fifo) + serial->config.bufsz); RT_ASSERT(rx_fifo != RT_NULL); rx_fifo->buffer = (rt_uint8_t*) (rx_fifo + 1); rt_memset(rx_fifo->buffer, 0, serial->config.bufsz); rx_fifo->put_index = 0; rx_fifo->get_index = 0; rx_fifo->is_full = RT_FALSE; serial->serial_rx = rx_fifo; /* configure fifo address and length to low level device */ serial->ops->control(serial, RT_DEVICE_CTRL_CONFIG, (void *) RT_DEVICE_FLAG_DMA_RX); } dev->open_flag |= RT_DEVICE_FLAG_DMA_RX; } #endif /* RT_SERIAL_USING_DMA */ ...... #ifdef RT_SERIAL_USING_DMA else if (oflag & RT_DEVICE_FLAG_DMA_TX) { struct rt_serial_tx_dma* tx_dma; tx_dma = (struct rt_serial_tx_dma*) rt_malloc (sizeof(struct rt_serial_tx_dma)); RT_ASSERT(tx_dma != RT_NULL); tx_dma->activated = RT_FALSE; rt_data_queue_init(&(tx_dma->data_queue), 8, 4, RT_NULL); serial->serial_tx = tx_dma; dev