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。

规格对比参考图:

../../_images/UART_IO.png

1.3 UART 工作模式

UART 支持轮询(polling)、中断(INT)和 DMA 三种模式。

模式

CPU 占用

代码复杂度

适用场景

轮询

高,CPU 持续参与检查状态

低速、小数据量、简单应用

中断

中,事件发生时响应中断

中等数据量、实时性要求较高

DMA

低,DMA 控制器直接传输

高速、大数据量、高吞吐量

下面流程图展示三种模式区别:

../../_images/uart_mode.png

中断模式和 DMA 模式均通过缓存接收 UART 数据,应用层从缓存获取数据。 区别在于:

  • 中断模式每个字节到来时触发中断,由 CPU 将数据搬运到缓存;

  • DMA 模式由 DMA 自动搬运数据到缓存,CPU 参与较少。

备注

DMA 模式适合高吞吐、低 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()

2. UART 使用流程

UART 使用一般包含配置选型、硬件绑定、参数设置和驱动调用四个核心步骤。

2.2 Pinmux 配置(绑定 IO 与 UART 总线)

Pinmux 配置用于建立物理 IO 引脚与 UART 总线的硬件映射关系,只有完成绑定后,UART 才能正常通信。

示例:使用 PA19 作为 USART1_TXDPA18 作为 USART1_RXD

// 函数:HAL_PIN_Set(引脚标识, 功能别名, 上下拉配置, 核心选择)
HAL_PIN_Set(
    PAD_PA19,       // 物理 IO 引脚
    USART1_TXD,     // UART1 发送
    PIN_PULLUP,     // 上下拉配置
    1               // 1:HCPU,0:LCPU
);
HAL_PIN_Set(
    PAD_PA18,       // 物理 IO 引脚
    USART1_RXD,     // UART1 接收
    PIN_PULLUP,     // 上下拉配置
    1               // 1:HCPU,0:LCPU
);

2.3 应用层选择 UART 总线

在应用层选择要使用的 UART 总线。

示例配置界面:

../../_images/use_uart1.png

2.4 打开与配置 UART

通过 RT-Thread 接口完成 UART 初始化与控制,常见流程如下:

// 查找 UART 总线
rt_device_find(device_name);
// 打开 UART 总线
rt_device_open(dev, oflag);
// 设置接收回调
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);

2.5 UART 模式配置

通过 flag_open 选择 UART 工作模式。

  • 轮询模式:

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 */

2.6 DMA 模式配置

DMA 模式配置包括:menuconfig 使能 UART DMA、配置 dma_config、并在 rt_device_open 时打开 DMA 标志。

2.6.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 总线

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

2.6.3 启用 DMA 模式

打开 UART 时使用 DMA 标志:

flag_open = RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_STREAM | RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX;

3. 其他注意事项

3.1 UART 波特率建议

当 UART 波特率超过 1M 时,建议选择 1M、2M、3M、4M、6M 等档位。 原因:UART 的时钟由 48M 分频生成,使用整除分频值可降低速率误差。

3.2 HCPU 使用 LCPU UART 的说明

3.2.1 适用平台与风险

对于 56x/55x/58x 平台,HCPU 使用 LCPU UART DMA 通讯为非推荐方案。 因为 HCPU 访问 LCPU UART 需要经过 APB 总线,若系统处于 LCPU RC10K 校准阶段,APB 总线会被占用 2~3us,可能导致连续数据传输过程中出现丢包。

建议:仅在无法避免时,才使用 HCPU 访问 LCPU UART DMA。

3.2.2 必要条件

若必须使用 HCPU 访问 LCPU UART DMA,必须满足以下两个要求:

  1. 使用外部 32k 晶振。

  2. HCPU 的 UART 缓冲区使用 LCPU 的 SRAM 空间。

3.2.3 外部 32k 晶振要求

原因如下:

  • 56x/55x/58x 平台的 RC10K 校准在 LCPU 上完成;

  • 校准期间 PCLK2 会降频到 6M;

  • 访问 PMU 寄存器会占用 APB 总线约 2~3us;

  • HCPU 访问 LCPU UART 也需经过 APB 总线,因此连续通信时可能发生 1 字节丢失。

总线结构:

../../_images/UART_HCPU2LCPU_APB.png

配置方式:

../../_images/LCPU_use_32k_menuconfig.png

电路图:

../../_images/32k_crystal.png

3.2.4 HCPU 缓冲区使用 LCPU SRAM

HCPU 使用LCPU 的 UART 时,建议将 UART 缓冲区分配到 LCPU SRAM,以避免跨核访问带来的数据不一致和延迟问题。

  • 修改 LCPU mem_map.h,调整 LCPU SRAM 分布,从 LCPU_RAM_DATA 预留 SRAM 空间。

../../_images/hcpu_use_lcpu_sram_memmap.png
  • 修改驱动文件 serial.c,在打开 UART 时判断 HCPU 使用 LCPU UART 场景,并使用 LCPU 预留的 SRAM 空间。

../../_images/hcpu_use_lcpu_sram_serial_drv.png

发布版本未包含HCPU 使用LCPU 的 UART的支持,用户可以自己修改或向我司索要相关patch.