UART
外设特性
SPV1x有2个UART模块,每个模块均支持以下功能特性。
支持5~8bit数据位宽
支持奇偶校验和0/1校验
支持1bit/2bit停止位
支持自动波特率检测
支持Timeout功能
支持Loopback功能
支持帧错误检测
接收和发送以不同的波特率运行
接收和发送各自有8级深度的FIFO
外设使用
1. UART时钟和复位配置
配置CMU_UARTnCLK,选择UART时钟源。
配置CMU_CLKEN0.UARTn,开启UART时钟。
配置RMU_RSTEN0.UARTn,释放UART模块。
2. 数据位宽选择
配置UART_CFG.DATA_WIDTH,选择数据位宽。
3. 校验功能配置
4. 停止位选择
配置UART_CFG.STOP_BIT选择1bit/2bit停止位。
5. 波特率配置
UART支持收发以不同的波特率进行。UART_DIV分为高16bit(RX_DIV)和低16bit(TX_DIV),RX_DIV用于控制接收的波特率,TX_DIV用于控制发送的波特率。 UART的波特率计算公式为:DIV = CLOCK/BAUD - 1。 DIV为波特率分频值(RX_DIV或TX_DIV),CLOCK为UART时钟源的频率,BAUD为目标波特率。
6. Timeout功能配置
7. Loopback功能配置
配置UART_CFG.LOOPBACK_EN可开启和关闭Loopback功能。Loopback功能开启后,UART的RX会在内部接到TX。 Loopback功能用于快速验证UART的模块的收发配置是否正常。
8. 帧错误检测功能
9. FIFO相关配置
UART的发送和接收都有8级FIFO。合理的使用FIFO资源,可以降低软件的复杂度,提升软件的性能。FIFO主要用到的功能有2点:
10. UART使能
11. 中断功能配置
12. 自动波特率检测功能配置
如果使用自动波特率检测功能,则按以下步骤操作:
配置UART_CTL.ABD,开启自动波特率检测。
如果不使用中断,则等待UART_CTL.ABD变回0。UART完成自动波特率检测后,硬件会将UART_CTL.ABD清零。
如果使用中断,则开启UART_IE.ABD,并配置CLIC和全局中断使能。自动波特率检测完成后,将触发UART中断。
自动波特率检测完成后,读取UART_RX_CNT中的测量值。如果测量的是单比特的位宽,则UART_RX_CNT的值可以作为RX_DIV或TX_DIV直接写入UART_DIV寄存器;如果测量的是多比特位宽(比如N比特),则RX_DIV或TX_DIV=(UART_RX_CNT+1)/N-1。
注意事项
当使用自动波特率检测功能时,测量单比特的位宽往往导致计算出来的波特率误差较大,在高波特率下,误差尤为明显。建议通过测量多个比特的位宽,以减少计算出来的波特率的误差。此外,在自动波特率检测完成之前,先不要使能UART的 接收功能,避免收到无用的数据。
向TX_FIFO写入数据时,需要确认TX_FIFO的剩余空间,避免写入过量的数据,导致TX_FIFO上溢。同理,从RX_FIFO读取数据时,需要确认RX_FIFO中有效数据的数量,避免过量读取数据,导致RX_FIFO下溢。
如果UART在使用过程中,会动态开启和关闭UART内部中断,则在UART中断函数中,需要同时判断UART_IE和UART_PD,确认中断使能且相应Pending bit置位,再去执行对应的处理逻辑。处理完对应的中断后,软件需要显式的对UART_PD中对应的Pending bit写1,以清除其Pending状态。
写入TX_FIFO中的数据需要一定的时间才能从TX引脚发送完成(通过CPU写入和DMA写入都如此)。当UART_STA.TX_BUSY为0,且UART_STA.TX_FIFO_EMPTY为1时,就可以确定写入的数据已全部传输完成。
如果要配合DMA进行UART数据收发,配置UART_CTL.RX_DMA_EN和UART_CTL.TX_DMA_EN开启接收和发送的DMA请求。此外,还需要将UART_CFG.RX_FIFO_THR设为1,使得UART每收到一个字节数据,都发起一次DMA请求,将数据读到指定的内存空间。
API说明
UART API提供基础的UART初始化和数据收发功能,便于快速上手UART的使用。
-
void uart_set_tx_pin(gpio_pin_t gpio_pin, uint32_t mfp)
设置UART的发送引脚。
- 参数
gpio_pin – GPIO端口号,gpio_pin_t中的枚举值。
mfp – 引脚的MFP值。
- 返回
无
-
void uart_set_rx_pin(gpio_pin_t gpio_pin, uint32_t mfp)
设置UART的接收引脚。
- 参数
gpio_pin – GPIO端口号,gpio_pin_t中的枚举值。
mfp – 引脚的MFP值。
- 返回
无
-
void uart_init(uint32_t chx, uint32_t baud, void (*recv_cb)(uint8_t))
UART初始化。
- 参数
chx – UART通道,0~1。
baud – UART波特率。
recv_cb – 串口接收回调函数。
- 返回
无
-
void uart_deinit(uint32_t chx)
UART去初始化。
- 参数
chx – UART通道,0~1。
- 返回
无
-
void uart_write(uint32_t chx, uint8_t *buf, uint32_t len)
UART写(发送)数据。
- 参数
chx – UART通道,0~1。
buf – 指向待写入的数据
len – 待写入数据的长度
- 返回
无
-
uint32_t uart_read(uint32_t chx, uint8_t *buf, uint32_t len, uint32_t timeout)
UART读(接收)数据。
- 参数
chx – UART通道,0~1。
buf – 指向容纳待读取数据的缓冲区
len – 待读取数据的长度
timeout – 读取超时时间,单位us
- 返回
实际读取到数据量
- 返回类型
uint32_t
API使用示例
在 “board.h” 中设置 __USE_UART0_PIN_CFG 或 __USE_UART1_PIN_CFG 为1,表示需要启用UART0或UART1引脚配置。
#define __USE_UART1_PIN_CFG (1)
在 “board.h” 中设置并定义对应UART需要用到的引脚以及引脚对应的MFP值。
#define UART1_TX_PIN (GPIO_Pin_08) #define UART1_TX_MFP (3) #define UART1_RX_PIN (GPIO_Pin_09) #define UART1_RX_MFP (3)备注
如果 __USE_UART0_PIN_CFG 或 __USE_UART1_PIN_CFG 为0,则需要用户手动配置UART引脚。
调用 uart_init() 初始化对应的UART模块。
该函数会初始化UART用到的引脚(如果 __USE_UART0_PIN_CFG 或 __USE_UART1_PIN_CFG 为1),设置OSC_DEV时钟作为UART的时钟。如果 recv_cb 参数为NULL,那么UART接收通过 uart_read() 函数完成,否则,UART接收到数据后,将调用 recv_cb 函数指针,并传入接收到的数据。
uart_init(1, 115200, uart1_cb);
调用 uart_write() 发送数据
uart_write() 阻塞式发送数据,直到所有数据从引脚上发送完成。在低波特率下, uart_write() 的执行时间会较长。
uart_write(1, "hello", 5);
调用 uart_read() 接收数据,或者在 recv_cb 中处理接收的数据。
uart_read() 会阻塞式接收数据,直到指定长度的数据接收完成或者超时。
recv_cb 会在UART接收中断被调用,当接收连续数据时, recv_cb 会被频繁调用。
备注
由于 recv_cb 是在中断函数中被调用的,因此 recv_cb 所指向的函数应力求简短。
如果不需要再使用UART,调用 uart_deinit() 去初始化。
去初始化会关闭UART的时钟,并让模块处于复位状态。相应的引脚复用也会被清除(如果 __USE_UART0_PIN_CFG 或 __USE_UART1_PIN_CFG 为1)。
寄存器定义