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持续参与,需不断检查状态,占用CPU资源

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

中断

中,CPU无需持续查询状态,仅在事件发生时响应中断,减少CPU等待时间

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

DMA

低,DMA控制器直接管理数据传输,CPU无需参与数据搬运

高速、大数据量、高吞吐量场景;

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

../../_images/uart_mode.png

中断模式和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总线”为例,配置界面如下:

../../_images/use_uart1.png

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的丢失。
总线结构:

../../_images/UART_HCPU2LCPU_APB.png

使用外部32k晶振配置方法
menuconfig

../../_images/LCPU_use_32k_menuconfig.png

电路图

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