Here is an analysis of the implementation of serial port DMA in RT-Thread for new development Reference when the processor serial port supports.
Background
With today’s chip performance and powerful peripheral functions, the serial port does not implement DMA/interrupt operation. I think it is basically It is unacceptable, but unfortunately, there is basically no support for serial port DMA in the current implementation of rt-thread support, and the document does not have any description about serial port DMA support. Here, taking the STM32 implementation as the background, I will sort out the serial port DMA. The implementation process of the new processor is used as a reference when the new processor is implemented.
DMA reception preparation
Enable DMA reception, you need to do some processing when opening the device, the entry function is rt_device_open(). The main implementation is:
rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflag) { ...... result = device_init(dev); ...... result = device_open(dev, oflag); ...... } span>
device_init() is the rt_serial_init() function, which mainly calls the configure() function ,
static rt_err_t rt_serial_init(struct rt_device *dev< span class="p">) { ...... if (< span class="n">serial->ops->configure) result = serial-> ops->configure(serial, &serial->config); ...... } < /span>
div>
Under stm32, its configure() function is stm32_configure(), which configures the registers of the STM32 peripherals according to the device opening parameters. Including serial port operating parameters such as baud rate and parity.
The device_open() function is the rt_serial_open() function, and its main implementation is:
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(< span class="k">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(< span class="n">rx_fifo != RT_NULL); rx_fifo->buffer = (rt_uint8_t *) (rx_fifo + 1); rt_memset(rx_fifo->buffer, 0, serial->config.bufsz); rx_fifo->< span class="n">put_index = 0; rx_fifo->get_index = 0; rx_fifo< span class="o">->is_full = RT_FALSE; serial->serial_rx = rx_fifo; /* configure fifo address and length to low level device */ serial->ops< span class="o">->control(serial, RT_DEVICE_CTRL_CONFIG, (void *) < span class="n">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< span class="p">, 4, RT_NULL); serial->serial_tx = tx_dma; dev->