如何通过DMA通道读取UART外设数据并写入队列
RP2040 基于DMA实现UART数据写入环形队列配置方案
以下是UART+DMA组件联动的完整配置逻辑,可实现无需CPU介入的UART数据自动接收:
1. UART外设基础配置
先完成UART的常规参数配置(波特率、数据位、停止位、校验位等),同时开启UART的DMA接收触发:
uart_set_dma_enabled(uart0, UART_DMARX, true);
2. DMA通道参数配置
利用RP2040 DMA的地址回绕特性适配环形缓冲区,配置项如下:
- 选择任意空闲DMA通道,设置传输位宽为1字节,匹配UART FIFO的单数据位宽
- 源地址设为对应UART的数据寄存器地址,配置为传输后地址不递增,保证每次都从固定寄存器位置读新数据
- 目的地址设为提前申请的环形缓冲区首地址,开启写地址回绕功能,回绕大小和环形缓冲区大小一致。注意回绕大小必须为2的n次幂,最小值为16字节,缓冲区内存地址需要对齐到回绕大小
- 触发源选择对应UART的RX就绪信号,UART0对应
DREQ_UART0_RX、UART1对应DREQ_UART1_RX,设置为每收到一次触发信号就传输1字节
核心配置代码示例
// 定义环形缓冲区大小,必须是2的幂且≥16 #define UART_RX_BUF_SIZE 256 uint8_t uart_rx_buf[UART_RX_BUF_SIZE] __attribute__((aligned(UART_RX_BUF_SIZE))); uint dma_chan = dma_claim_unused_channel(true); dma_channel_config cfg = dma_channel_get_default_config(dma_chan); // 源地址不递增,目的地址递增 channel_config_set_read_increment(&cfg, false); channel_config_set_write_increment(&cfg, true); // 绑定UART RX触发信号 channel_config_set_dreq(&cfg, DREQ_UART0_RX); // 开启写地址回绕,第二个参数true代表写地址回绕,第三个参数为回绕大小的2次幂指数 channel_config_set_ring(&cfg, true, __builtin_ctz(UART_RX_BUF_SIZE)); // 配置并启动DMA dma_channel_configure(dma_chan, &cfg, uart_rx_buf, &uart0_hw->dr, UART_RX_BUF_SIZE, true );
3. 数据读取逻辑
DMA启动后会自动将UART收到的所有数据写入环形缓冲区,无需CPU干预。读取数据时只需维护一个独立的读指针,对比DMA通道当前的写地址偏移即可得到未读数据长度,读完后更新读指针即可。
注意:访问读写指针时建议添加原子操作保护,避免出现数据竞争导致的读取错误。
内容的提问来源于stack exchange,提问作者asynts
相关产品推荐
相关产品推荐

