UART¶
1. UART 驱动说明¶
1.1 简介¶
UART是通用异步收发传输器(Universal Asynchronous Receiver/Transmitter), 是设备间进行异步通信的关键模块. 思澈平台UART特性主要包括:
全双工异步通讯;
可配置 16 或 8 的过采样方法,以在速度和时钟容差之间提供灵活性;
可编程数据字长(7、8 或 9 位);
可配置的停止位(1 或 2 个停止位);
支持DMA 的连续通信;
支持硬件流控(CTS/RTS);
UART总线的工作原理,可以参考 UART设备
1.2 UART资源分布¶
思澈平台最多支持 6 个UART实例,其中:3个在HCPU上,3个在 LCPU;
具体分布如下:
平台 |
HCPU |
LCPU |
|---|---|---|
52x |
UART1/UART2/UART3 |
|
56x |
UART1/UART2/UART3 |
UART4/UART5/UART6 |
55x |
UART1/UART2 |
UART3/UART4/UART5 |
58x |
UART1/UART2/UART3 |
UART4/UART5/UART6 |
UART的总线名称依次为“uart1”~“uart6”;
UART总线的配置信息还可以参考uart_config.h;
备注
HCPU可以使用LCPU的UART,但LCPU只能使用LCPU的UART
IO口灵活性存在差异
55x/58x系列:UART的IO口为固定分配,需参考芯片规格书确认具体IO对应的UART,不可随意切换;
52x/56x系列:灵活性更高,任何带有I2C_UART功能的IO,均可通过配置映射为 UART;
规格对比参考图:
1.3 UART 三种工作模式¶
UART 支持询(polling)/中断(INT)/DMA三种模式;
模式 |
CPU占用率 |
代码复杂度 |
适用场景 |
|---|---|---|---|
轮询 |
高,CPU持续参与,需不断检查状态,占用CPU资源 |
低 |
低速、小数据量、简单应用; |
中断 |
中,CPU无需持续查询状态,仅在事件发生时响应中断,减少CPU等待时间 |
低 |
中等数据量、实时性要求较高; |
DMA |
低,DMA控制器直接管理数据传输,CPU无需参与数据搬运 |
高 |
高速、大数据量、高吞吐量场景; |
下面的流程图展示了三种模式的区别:
中断模式和DMA模式都采用了自动收取UART数据到缓存,应用层从缓存获取UART数据的方式;
区别在于DMA模式收到UART数据可以自动搬运到缓存,而中断模式收到每个BYTE UART数据都会触发中断靠CPU来进行搬运到缓存;
备注
DMA模式,仅作用于数据段,适合高吞吐,低CPU占有率,通讯过程中不需要CPU参与,被CPU打断的概率低;
对于UART RX 而言,建议使用DMA模式,以避免被打断导致接收异常;
1.4 UART 硬件流控模式¶
UART硬件流控模式是指通过CTS(Clear To Send,清除发送)和RTS(Request To Send,请求发送)两根控制信号线实现流量控制,防止接收方因缓冲区满导致数据丢失。
优点:
适用于高速据传输时双方速率不匹配或数据突发。
缺点:
需要额外引脚CTS和RTS,增加硬件复杂度。
1.5 UART 总线接口¶
打开、配置UART,相关接口如下
函数 |
描述 |
|---|---|
rt_device_find() |
查找设备 |
rt_device_open() |
打开设备 |
rt_device_read() |
读取数据 |
rt_device_write() |
写入数据 |
rt_device_control() |
控制设备 |
rt_device_set_rx_indicate() |
设置接收回调函数 |
rt_device_set_tx_complete() |
设置发送完成回调函数 |
rt_device_close() |
关闭设备 |
UART总线一般使用流程:
rt_device_find()-> rt_device_open()->rt_device_control()->rt_device_set_rx_indicate()/rt_device_set_tx_complete()->rt_device_read()/rt_device_write()
1.6 UART的使用¶
UART的使用需经过配置选型、硬件绑定、参数设置和驱动调用四个核心步骤,以下为详细说明:
1.6.2 配置 Pinmux(绑定 IO 与 UART总线)¶
Pinmux 配置的核心作用是建立物理 IO 引脚与目标UART总线的硬件映射关系,告知芯片“哪个 IO 负责UART通讯”。只有完成绑定,UART总线才能和UART设备进行通讯。
配置逻辑与示例 以“PA19 作为 USART1_TXD(UART1总线的发送),PA18作为 USART1_RXD(UART1总线的接收)”为例,配置代码如下:
// 函数:HAL_PIN_Set(引脚标识, 功能别名, 上下拉配置, 核心选择)
HAL_PIN_Set(
PAD_PA19, // 物理 IO 引脚
USART1_TXD, // UART1总线的发送
PIN_PULLUP, // 上下拉配置(外部有上拉的时候可以配置成NOPULL)
1 // 1:引脚位于HCPU;0:引脚位于LCPU
);
HAL_PIN_Set(
PAD_PA18, // 物理 IO 引脚
USART1_RXD, // UART1总线的接收
PIN_PULLUP, // 上下拉配置(外部有上拉的时候可以配置成NOPULL)
1 // 1:引脚位于HCPU;0:引脚位于LCPU
);
1.6.3 配置应用的使用的UART总线¶
在应用层配置要使用的UART总线。以“使用UART1总线”为例,配置界面如下:
1.6.4 调用uart总线驱动接口¶
通过RT-Thread接口完成uart的初始化与控制; 参考代码:
// 查找UART总线
rt_device_find(device_name);
//打开UART总线
rt_device_open(dev, oflag);
// 设置rx_indicate
rt_device_set_rx_indicate(dev, finsh_rx_ind);
//配置波特率,数据字长,停止位
rt_device_control(dev, RT_DEVICE_CTRL_CONFIG, &config)
// 读取UART总线
rt_device_read(shell->device, -1, &ch, 1);
1.6.4 调用uart总线驱动接口¶
1.7 UART模式的配置¶
I2C 模式,可以在rt_device_open(bus_handle, flag_open)时,通过flag_open来区分;
轮询模式
flag_open = RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_STREAM
中断模式
flag_open = RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_STREAM | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX
DMA模式
flag_open = RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_STREAM | RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX
以下显示所有支持的flag
#define RT_DEVICE_FLAG_RDONLY 0x001 /**< read only */
#define RT_DEVICE_FLAG_WRONLY 0x002 /**< write only */
#define RT_DEVICE_FLAG_RDWR 0x003 /**< read and write */
#define RT_DEVICE_FLAG_REMOVABLE 0x004 /**< removable device */
#define RT_DEVICE_FLAG_STANDALONE 0x008 /**< standalone device */
#define RT_DEVICE_FLAG_ACTIVATED 0x010 /**< device is activated */
#define RT_DEVICE_FLAG_SUSPENDED 0x020 /**< device is suspended */
#define RT_DEVICE_FLAG_STREAM 0x040 /**< stream mode */
#define RT_DEVICE_FLAG_INT_RX 0x100 /**< INT mode on Rx */
#define RT_DEVICE_FLAG_DMA_RX 0x200 /**< DMA mode on Rx */
#define RT_DEVICE_FLAG_INT_TX 0x400 /**< INT mode on Tx */
#define RT_DEVICE_FLAG_DMA_TX 0x800 /**< DMA mode on Tx */
1.8 UART DMA模式的配置¶
DMA模式配置包括: menuconfig使能UART总线DMA,配置dma_config,UART总线flag_open包含RT_DEVICE_FLAG_DMA_TX/RT_DEVICE_FLAG_DMA_RX;
UART 的TX和RX全双工异步通讯,需要使用不同的DMA通道.
1.8.2 配置dma_config¶
在dma_config.c中,配置DMA相关的宏
#define UART1_DMA_RX_IRQHandler DMAC1_CH7_IRQHandler /*DMA中断回调*/
#define UART1_RX_DMA_IRQ_PRIO 0 /*DMA中断优先级*/
#define UART1_RX_DMA_INSTANCE DMA1_Channel7 /*DMA中断通道实例*/
#define UART1_RX_DMA_IRQ DMAC1_CH7_IRQn /*DMA中断*/
#define UART1_RX_DMA_REQUEST DMA_REQUEST_5 /*UART1 RX的DMA设备序号,序号唯一*/
下图展示了所有平台的UART总线的DMA_REQUEST
(悬空部分表格表示对应平台没有对应的UART总线或UART总线不支持DMA)
UART总线 |
52x |
55x |
56x |
58x |
|---|---|---|---|---|
UART1_TX |
DMAC1_4 |
DMAC1_4 |
DMAC1_4 |
DMAC1_4 |
UART1_RX |
DMAC1_5 |
DMAC1_5 |
DMAC1_5 |
DMAC1_5 |
UART2_TX |
DMAC1_6 |
DMAC1_6 |
DMAC1_6 |
DMAC1_6 |
UART2_RX |
DMAC1_7 |
DMAC1_7 |
DMAC1_7 |
DMAC1_7 |
UART3_TX |
DMAC1_26 |
DMAC2_0 |
DMAC1_26 |
DMAC1_26 |
UART3_RX |
DMAC1_27 |
DMAC2_1 |
DMAC1_27 |
DMAC1_27 |
UART4_TX |
DMAC2_2 |
DMAC2_0 |
DMAC3_0 |
|
UART4_RX |
DMAC2_2 |
DMAC2_1 |
DMAC3_1 |
|
UART5_TX |
DMAC2_4 |
DMAC2_2 |
DMAC3_2 |
|
UART5_RX |
DMAC2_5 |
DMAC2_3 |
DMAC3_3 |
|
UART6_TX |
DMAC2_4 |
DMAC3_4 |
||
UART6_RX |
DMAC2_5 |
DMAC3_5 |
1.8.3 配置I2C 总线flag_open包含RT_DEVICE_FLAG_DMA_TX/RT_DEVICE_FLAG_DMA_RX¶
执行rt_device_open(bus_handle, flag_open)时
flag_open = RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_STREAM | RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX
1.9 UART 使用的其他注意事项¶
1.9.1 UART波特率的配置¶
UART波特率超过1M的时候,建议使用1M/2M/3M/4M/6M等档位;
原因:UART从系统分频48M分频,需要避免分频参数无法被整除;
1.9.2 HCPU 使用LCPU的UART¶
对于56x/55x/58x平台,HCPU使用LCPU的UART DMA,务必确保使用的是外部32k晶振。
原因:56x/55x/58x平台的rc10k校准位于LCPU,RC10K校准的时候会把PCLK2降频到6M,校准期间通过APB总线访问PMU寄存器,会占用APB总线2~3us。
而HCPU通过访问小核UART 也需要通过APB总线。 对于UART连续通讯时,APB总线被RC10K占用2~3us时,可能会存在1byte的丢失。
总线结构:
使用外部32k晶振配置方法
menuconfig
电路图
