UART示例
源码路径:example\rt_device\uart
支持的平台
例程可以运行在以下开发板.
- em-lb525 
- em-lb587 
概述
- 在RT-Thread操作系统下采用RX DMA方式,操作UART2检验其串口的收发能力 
- 注意开发板复位之后uart2打印log同下方图片内容一致即为发送成功,验证uart2接收能力使用的是默认串口打印log来验证其接收内容的准确性 
例程的使用
编译和烧录
关于编译、下载的详细步骤,请参考上手指南的相关介绍。
- 此例程中用到了uart2,在采用RT-Thread操作系统时,uart2外设会虚拟成了一个rt_device来进行读写操作,此时需要确认工程编译所在路径下 - rtconfig.h文件中是否包含了下面3个宏:
#define BSP_USING_UART 1
#define BSP_USING_UART2 1
#define BSP_UART2_RX_USING_DMA 1
只有包含了上面三个宏,在rt_hw_usart_init函数中才会通过rt_hw_serial_register函数注册"uart2这个rt_device,后面该设备才能rt_device_find和rt_device_open成功。
如果缺失上面三个宏,就需要通过menuconfig如下命令进行打开(注意:缺失可能并不会报出错误,若配置串口没有信息打印请及时查看是否打开)
menuconfig --board=em-lb525
如下图,选择uart2和rx dma,保存并退出menuconfig,查看rtconfig.h宏是否生成

- 切换到例程project目录,运行scons命令执行编译: 
scons --board=em-lb525 -j8
- 运行 - build_em-lb525_hcpu\uart_download.bat,按提示选择端口即可进行下载:
build_em-lb525_hcpu\uart_download.bat
Uart Download
please input the serial port num:5
硬件连接
| 版型名称 | UART | TX(物理位置) | RX(物理位置) | 
|---|---|---|---|
| 525 | UART2 | PAD_PA27(8) | PAD_PA20(10) | 
| 587 | UART2 | PAD_PA28 (CONN2 5) | PAD_PA29 (CONN2 3) | 
- PA27软件配置为UART2的TX,连接到电脑usb转串口的RX 
- PA20软件配置为UART2的RX,连接到电脑usb转串口的TX 
- GND连接到usb转串口的GND,如下图: 

例程输出结果展示:
- log输出:左边为机器log,右边为电脑usb转串口端发送数据和接收数据:  
- 注意:串口开启有两个串口,一个是代码配置电脑usb转串口的uart2,一个是自带的调试口uart1 
log结尾收到的rev: 为接收到的电脑USB转串口TX发来的字符
- 注意:这里打印接收数据是用默认串口打印而不是uart2,因为uart2的发送数据功能也是例程中的一项 
    SFBL
    Serial:c2,Chip:4,Package:3,Rev:3  Reason:00000080
     \ | /
    - SiFli Corporation
     / | \     build on Oct 23 2024, 2.2.0 build 00000000
     2020 - 2022 Copyright by SiFli team
    mount /dev sucess
    [32m][490] I/drv.rtc: PSCLR=0x80000100 DivAI=128 DivAF=0 B=256
    [0m][32m][517] I/drv.rtc: RTC use LXT RTC_CR=00000001
    [0m][32m][538] I/drv.rtc: Init RTC, wake = 1
    [0m][32m][565] I/drv.audprc: init 00 ADC_PATH_CFG0 0x606
    [0m][32m][587] I/drv.audprc: HAL_AUDPRC_Init res 0
    [0m][32m][609] I/drv.audcodec: HAL_AUDCODEC_Init res 0
    [0m][32m][630] I/TOUCH: Regist touch screen driver, probe=1203a299 
    [0mcall par CFG1](35bb)
    fc 9, xtal 2000, pll 2050
    call par CFG1(35bb)
    fc 9, xtal 2000, pll 2051
    Start uart demo!
    [796] D/uart2: uart device config 0
    send:uart2 demo
    uart demo end!
    msh />
    uart_rec: cnt = 5,count = 5
    uart_rec: cnt = 0,count = 5
    rev:abc
下面为开发板复位后电脑USB转串口发送的数据uart2 demo字符以及检验uart2是否能接收串口数据而人为发送的数据
    uart2 demo
    TX:abc
检验uart2的接收内容正确性功能:在uart2的log窗口下发送了abc,进入对应uart2的中断后会接收到abc字符、换行符,回车符,共5个字符ASCII码,打印以下内容
- 注意:始终多打印一次log是考虑到持续接收会导致超出可接收的最大值从而分多次接收如:接收最大为256而接收的是260则会打印 
 uart_rec: cnt = 256,count = 256
 uart_rec: cnt = 4,count = 260
 uart_rec: cnt = 0,count = 260
    uart_rec: cnt = 5,count = 5
    uart_rec: cnt = 0,count = 5
    rev:abc
uart2配置流程
- 确保 - rtconfig.h文件中是否包含了下面3个宏: 编译窗口输入命令查看board=(版型)
#define BSP_USING_UART 1
#define BSP_USING_UART2 1
#define BSP_UART2_RX_USING_DMA 1
menuconfig --board=em-lb525
- 设置对应的Uart2对应的IO口 
   #if defined(BSP_USING_BOARD_EM_LB525XXX)
    HAL_PIN_Set(PAD_PA20, USART2_RXD, PIN_PULLUP, 1);
    HAL_PIN_Set(PAD_PA27, USART2_TXD, PIN_PULLUP, 1);
    #elif defined (BSP_USING_BOARD_EM_LB587XXX)
    HAL_PIN_Set(PAD_PA29, USART2_RXD, PIN_PULLUP, 1);
    HAL_PIN_Set(PAD_PA28, USART2_TXD, PIN_PULLUP, 1);
    #endif
注意:
- 除55x芯片外,可以配置到任意带有PA*_I2C_UART功能的IO输出UART2波形(想查询引脚复用表可在项目路径下文件中查找如:bf0_pin_const.c) 
- HAL_PIN_Set 最后一个参数为hcpu/lcpu选择, 1:选择hcpu,0:选择lcpu 
- Hcpu的PA口不能配置为Lcpu的uart外设,比如uart5,uart6输出 
- 串口初始化函数int uart2_init(void)部分内容讲解: 
 先后- rt_device_find,- rt_device_control,- rt_device_open分别查找、配置和打开- uart2设备
#define UART_DEMO_NAME "uart2"
    /* 2, find  and config uart2 device */
    g_uart_device = rt_device_find(UART_DEMO_NAME);
    if (!g_uart_device)
    {
        LOG_E("find %s failed!\n", UART_DEMO_NAME);
        return RT_ERROR;
    }
    /* config uart2 baud_rate */
    {
        rt_err_t err;
        struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
        config.baud_rate = 1000000; /* 配置uart2波特率为1000000 */
        err = rt_device_control(g_uart_device, RT_DEVICE_CTRL_CONFIG, &config);
        LOG_D("uart device config %d", err);
    }
    /* 初始化rx_sem信号量,在uart_rx_ind函数内释放,在serial_rx_thread_entry线程内使用 */
    rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
	/* 配置uart2 采用rx dma方式接收 */
	rt_err_t open_result = rt_device_open(g_uart_device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_RX);
	//using interring mode when DMA mode not supported
	if (open_result == -RT_EIO)
	{
	    rt_device_open(g_uart_device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX);/* 配置uart2中断 */
    }
    /* set the callback function of recieving */
- 配置uart2的中断回调函数 - uart_rx_ind,并创建启动线程- serial_rx_thread_entry来接收处理RX DMA收到的数据
    /* 设置uart_rx_ind为uart2 中断回调函数 */
    rt_device_set_rx_indicate(g_uart_device, uart_rx_ind);
    
    /* creat the thread of g_uart_device */
    rt_thread_t thread = rt_thread_create("g_uart_device", serial_rx_thread_entry, RT_NULL,  3 * 1024, 12, 10);
    /* start the thread of g_uart_device */
    if (thread != RT_NULL)
    {
        rt_thread_startup(thread);
    }
    else
    {
        ret = RT_ERROR;
    }
- static void serial_rx_thread_entry(void parameter)接收处理RX DMA收到的数据:使用默认的串口打印函数 - rt_kprintf来检验uart2接收到的数据,不断循环使用- cnt = rt_device_read()检验当前是否接收到数据,所以log打印会始终多打印一次cnt=0时的情况
uint16_t count = 0;
    uint8_t cnt = 0;
    while (1)
    {
        rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
        while (1)
        {
            cnt = rt_device_read(g_uart_device, -1, &data[count], ONE_DATA_MAXLEN);
            count += cnt;
            rt_kprintf("uart_rec: cnt = %d,count = %d\n", cnt, count);
            if (0 == cnt) break;
        }
        rt_kprintf("rev:");
        for (uint16_t i = 0; i < count; i++)
        {
            rt_kprintf("%c", data[i]);
        }
        count = 0;
        rt_kprintf("\n");
    }
- uart2通过uart_send_data函数发送数据 
    uint8_t tx_data[ONE_DATA_MAXLEN] = {'u','a','r','t','2',' ','d','e','m','o','\n'};
    uart_send_data(tx_data,12);
- 打开 - finsh功能后,可以log串口终端输入- list_device可以查看- uart2是否open状态,0表示设备已经注册,1,2表示设备open的次数
 TX:list_device
   list_device
   device           type         ref count
   -------- -------------------- ----------
   audcodec Sound Device         0       
   audprc   Sound Device         0       
   rtc      RTC                  0       
   pwm3     Miscellaneous Device 0       
   touch    Graphic Device       0       
   lcdlight Character Device     0       
   lcd      Graphic Device       0       
   i2c4     I2C Bus              0       
   i2c1     I2C Bus              0       
   lptim1   Timer Device         0       
   btim1    Timer Device         0       
   uart2    Character Device     1       
   uart1    Character Device     2       
   pin      Miscellaneous Device 0       
   msh />
- 这里只是演示了uart的一种推荐用法,其他操作,在rt-thread操作系统下,可以参考rt-thread官网使用手册 
异常诊断
- uart2无波形输出 
- pin status 20/27命令查看对应PA20,PA27的IO状态FUNC对不对,VAL电平应该是1
    msh />
 TX:pin status 20
    pin status 20
    [I/TEST.GPIO] PIN 20, FUNC=4, VAL=1, DIG_IO_PU, GPIO_MODE_INPUT, irqhdr=/, arg=/
    msh />
    msh />
 TX:pin status 27
    pin status 27
    [I/TEST.GPIO] PIN 27, FUNC=4, VAL=1, DIG_IO_PU, GPIO_MODE_INPUT, irqhdr=/, arg=/
    msh />
    msh />
- list_device命令查看- uart2设备是不是存在并且打开了
- 检查uart2配置流程是否都已生效 
- uart2波形正常,电脑串口接收不到数据 
- 检测uart2输出和电脑串口连接是否正常,需要TX接RX,RX连接TX,波特率是否一致,以及引脚对应的TX,RX是否正确 
- 检测硬件连接,包括uart2输出电平跟电脑uart电平是否一致 
- 电脑串口发出数据,uart2出现数据接收丢失现象 
- 确认串口DMA的buffer长度是否足够 - #define RT_SERIAL_RB_BUFSZ 256
/* 
&data[count]:为接收到数据的内存地址;
ONE_DATA_MAXLEN:准备接收的长度,可以大于DMA的buffer长度;
返回值为:实际接收到的长度,0为已经接收完毕;
*/
rt_device_read(g_uart_device, -1, &data[count], ONE_DATA_MAXLEN);
参考文档
- EH-SF32LB52X_Pin_config_V1.3.0_20231110.xlsx 
- DS0052-SF32LB52x-芯片技术规格书 V0p3.pdf 
- DS0058-SF32LB58x-芯片技术规格书 V1p8.pdf 
- RT-Thread官网 https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/README 
更新记录
| 版本 | 日期 | 发布说明 | 
|---|---|---|
| 0.0.1 | 10/2024 | 初始版本 | 
| 0.0.2 | 12/2024 | 2.0 | 
