RTOS_UART使用参考


REVISION HISTORY

Revision No.
Description
Date
1.0
  • Initial release
  • 04/18/2023
    1.1
  • 修改文档格式
  • 04/09/2025

    1. 概述

    UART一般指通用异步通讯收发器,通讯特征为异步,串行。UART总线有两条数据线,TX和RX,实现全双工的发送和接收。收发双方通过各自设定的帧格式和波特率解析接收到的信号,因此在通讯过程中要求收发双方使用相同的帧格式和波特率。

    SigmaStar UART符合标准串口通信协议的模块。当中含有多个UART,其中会有FUART、UART的不同称呼,其区别在于FUART相比UART,多了CTS/RTS硬件流控功能。一般默认使用UART0作为console port。本文讲述Sigmastar UART驱动在rtos下的使用方法。


    2. 关键字说明

    • TX

      数据发送功能/引脚,按照设定的帧格式和波特率发出UART信号。

    • RX

      数据接收功能/引脚,接收到的信号会被UART以设定的帧格式和波特率解析,TX和RX共用同一套设定。

    • CTS

      流控引脚/信号,输入信号,解释为“发送允许”。用于判断是否可以向对方发送数据,低电平有效。

    • RTS

      流控引脚/信号,输出信号,解释为“发送请求”。用于指示本设备准备好可接收数据,低电平有效。

    • FIFO mode

      每一帧数据都需要通过CPU传递给UART硬件发送缓存寄存器,再由UART自行从发送缓存拿走往外发送。硬件发送缓存为32字节。或者接收时CPU从UART硬件接收缓存寄存器读取,硬件接收缓存为32字节。

    • DMA mode

      每一帧的数据不再需要CPU逐个下发或读取,只需要在触发通讯之前,将要发送的数据一次性写入DMA指定的存储位置当中,再触发通讯;或者从指定存储当中一次性拿走接收到的所有数据;通讯执行期间,于UART之间的数据交互由URDMA自行完成,无需CPU再参与。
      DMA mode可以使得传输更加连贯,减少CPU loading,减少UART通讯中断数量,同时接收发送各提供的4096字节存储空间,能极大减少数据丢失的可能性。

    • URDMA

      专门用于为UART提供数据搬运服务的模块,DMA mode时需要启用。启用后,UART不再发生中断,由URDMA发生中断;且DMA enable时,CPU不能再去访问UART寄存器,否则会导致卡死。

    • CONSOLE PORT

      console是一个缓冲的概念,专为内核提供打印与busybox接收shell命令使用。PC与Console Port连接,通过PC的终端应用,显示打印信息或输入操作指令。

    • PADMUX

      引脚复用,将UART PAD与实际引脚导通,让信号能通过引脚传递。

    • DIGMUX

      用于导通UART TX/RX digital message与UART PAD。不同的UART PAD可以接入到不同的UART模块。但是默认作为CONSOLE PORT的PAD_PM_UART_TX与PAD_PM_UART_RX这组PAD无法切换digmux。

      例如:当硬件layout固定时,假设原先使用UART1的功能,此时需要HW CTS/RTS的支持,而fuart又没有相应的PADMUX可以切到这组硬件引脚来。则可以通过切换DIGMUX,把UART1与FUART做切换,此时FUART的TX/RX与UART1的TX/RX信号连接互换了,但CTS/RTS则还是原先FUART设定的引脚,满足对HW CTS/RTS的使用。


    3. 功能描述

    3.1 UART资源

    PCUPID共提供了6组标准UART、4组FUART(硬件流控的uart模块,支持CTS/RTS,为fuart、uart1、uart2、uart3,可以在SYSDESC中配置sctp_enable开启流控功能)和一组PM_UAR(不支持DMA mode)。

    各UART/URDMA与bank address对应如下,UART与URDMA唯一绑定,例如FUART和URDMA绑定,UART0和URDMA0绑定:

    UART IP FUART UART0 UART1 UART2 UART3 UART4 UART5 UART6 UART7 UART8 PM_UART
    BANK ADDR 1102 1108 1109 110A 110B 110C 110D 1140 1142 1144 0035
    URDMA IP URDMA URDMA0 URDMA1 URDMA2 URDMA3 URDMA4 URDMA5 URDMA6 URDMA7 URDMA8
    BANK ADDR 1103 1107 110E 110F 1111 1112 1113 1141 1143 1145

    3.2 功能支持

    下表提供各UART对各功能的支持情况

    功能 FIFO mode FIFO buffer size(byte) DMA mode DMA buffer size(byte) HW CTS/RTS baudrate protocol
    支持情况 32 ✔(除PM_UART) 4096 only fuart

    波特率支持情况如下表:

    UART
    BAUDRATE(bps)
    ALL UART 1200
    ALL UART 1800
    ALL UART 2400
    ALL UART 4800
    ALL UART 9600
    ALL UART 19200
    ALL UART 38400
    ALL UART 57600
    ALL UART 115200
    ALL UART 230400
    ALL UART 460800
    ALL UART 500000
    ALL UART 576000
    ALL UART 921600
    ALL UART 1000000
    ALL UART 1152000
    ALL UART 1500000
    ALL UART 2000000
    ALL UART 2500000
    ALL UART 3000000
    ALL UART 3500000

    UART通讯协议支持情况如下:

    UART
    start bits char bits even parity stop bits
    ALL UART 1 bit 5 bits;
    6 bits;
    7 bits;
    8 bits
    Y/N 1 bit;
    1.5 bits

    通讯时序图如下图3-1:


    图3-1 UART timing procotol

    3.3 注意事项

    • 外部上拉

      RX一定要接外部上拉,TX建议接外部上拉。

    • FIFO mode

      使用FIFO mode,HW buffer size仅有32byte,当UART无法在buffer被填满之前,及时响应UART中断,进而从HW buffer当中的数据读走,就会出现接收数据丢失的情况。

    3.4 波特率的计算

    波特率是指数据信号对载波的调制速率,它用单位时间内载波调制状态改变的次数来表示,是UART的一个重要的指标。目前的硬件设计UART实际输出的波特率由输入到UART的Clk source和设置的分频值共同确定。波特率(BAUD)、分频值(DIV)以及输入的CLK频率(CLK)三者的关系如下:

    DIV = CLK / (BAUD × 16)
    

    由于给到UART的CLK rate并不是连续的,根据公式得出UART可以支持的波特率(误差3%)也不是连续的。

    波特率的修改

    可以在测试程序当中设定,其设定方法参考下面测试demo图。

    4. 硬件连接介绍

    1. 标准UART是指不包含任何硬件流控制机制的UART通信方式。它仅依赖于起始位、数据位、奇偶校验位(可选)和停止位来进行数据帧的界定。只是用TX接对端RX,RX接对端TX。

    2. FUART(流控UART)指的是在标准UART的基础上增加了硬件或软件流控制机制,以防止数据丢失并提高通信的可靠性。在标准UART基础上,增加CTX连接对端CTS、CTS连接对端RTS。


      图4-1 UART connect


    5. RTOS用法介绍

    UART通讯测试的时候,需要保证基本的如下步骤:

    • 硬件设备连接,外部上拉电阻确认,简单测试方式就是tx和rx短接;
    • CONFIG支持UART驱动,默认开启;
    • SYSDESC文件配置需求属性;
    • PADMUX设定;
    • API调用,执行通讯。

    5.1 DRIVER PATH

    sc/driver/sysdriver/uart/drv/pub/drv_uart.h
    sc/driver/sysdriver/uart/drv/src/drv_uart.c
    sc/driver/sysdriver/uart/drv/src/drv_uart_test.c
    sc/driver/sysdriver/uart/drv/src/drv_uart_lite.c
    sc/driver/sysdriver/uart/hal/pcupid/src/hal_uart.c
    sc/driver/sysdriver/uart/hal/pcupid/inc/hal_uart.h
    sc/driver/sysdriver/uart/hal/pcupid/inc/hal_uart_cfg.h
    

    5.2 CONFIG配置

    UART驱动编译选项在RTOS中默认开启,config文件位于mak/defconfig/,使能CONFIG_CONSOLE_DRIVER_FUART

    CONFIG_CONSOLE_DRIVER_FUART = TRUE
    

    5.3 SYSDESC配置

    chipname_common.sys文件位于sc/driver/sysdriver/sysdesc/hal/chipname/pub 以fuart为例,节点内容如下所示:

    <fuart>
        [reg_u32] 0x2220400, 0x2220600;
        [interrupts_u32] INT_IRQ_FUART,
                        INT_IRQ_UART_MERGE,
                        INT_IRQ_UART_MERGE;
        [camclk_u16] CAMCLK_fuart;
        [rx_fifo_level_u8] 0;
        [tx_fifo_level_u8] 0;
        [sctpen_u8] 0;
        [dma_u8] 0;
        [digmux_u8] 1;
        [status_u8] 1;
    

    节点中属性的说明如下:

    属性值 描述 备注
    reg_u32 用于指定UART(和URDMA)所在的Bank及范围 不需要修改
    interrupts_u32 指定UART(和URDMA)的中断及触发方式 不需要修改
    camclk_u16 指定UART的时钟源 不需要修改
    dma_u8 使能FUART的DMA功能 需要时写为1
    sctpen_u8 HW CTS/RTS enable 1: enable
    0: disable
    digmux_u8 选择rx tx pin接到哪一组digmux,每一组uart都会默认接到对应的digmux上,若无特殊需求,不需要设置该属性;0xFF代表驱动不会对该uart默认digmux做修改 根据需要修改,若无特殊需求,建议删除该属性
    rx_fifo_level_u8 选择uart rx fifo的等级,影响为接收到多少字节触发一次中断,超时也会触发中断,当前fifo深度为32byte;
    "0" - 1 character in the FIFO;
    "1" - FIFO ¼ full;
    "2" - FIFO ½ full;
    "3" - FIFO 2 less than full
    根据需要修改,若无特殊需求可删除该属性,驱动默认初值为0;仅在dma属性设置为0时有效
    tx_fifo_level_u8 选择uart tx fifo的等级,影响为txfifo剩余多少字节触发一次中断,超时也会触发中断,当前fifo深度为32byte;
    "0" - FIFO empty;
    "1" - 2 characters in the FIFO;
    "2" - FIFO ¼ full;
    "3" - FIFO ½ full;
    根据需要修改,若无特殊需求可删除该属性,驱动默认初值为0;仅在dma属性设置为0时有效
    Status_u8 选择是否使能UART驱动 根据需要修改

    5.4. PADMUX设定

    CONFIG配置:CONFIG_PADMUX_SUPPORT=Y

    如果chipname_XXX.sys文件配置了属性<padmux>,那么PADMUX的设定直接在此配置,例如fuart mode2:

    <padmux>
        [schematic_u32_u32_u32]
                PAD_GPIOC_02    PINMUX_FOR_FUART_MODE_2    MDRV_PUSE_FUART_RX,
                PAD_GPIOC_03    PINMUX_FOR_FUART_MODE_2    MDRV_PUSE_FUART_TX,
                PAD_GPIOC_04    PINMUX_FOR_FUART_MODE_2    MDRV_PUSE_FUART_CTS,
                PAD_GPIOC_05    PINMUX_FOR_FUART_MODE_2    MDRV_PUSE_FUART_RTS;
        [status_u8] 1;
    

    第一列为引脚索引号,可以在sc/drivers/sysdriver/gpio/hal/chipname/pub/gpio.h中查询;

    第二列为模式定义,可以在sc/drivers/sysdriver/gpio/hal/chipname/pub/padmux.h中查询;

    第三列为引脚及搭配模式的索引名称,可以在sc/drivers/sysdriver/padmux/hal/chipname/pub/drv_puse.h中查询;

    5.5 Sample code

    demo源码参考 sc/driver/sysdriver/uart/drv/src/drv_uart_test.c

    static int uart_ut_test(CLI_t * cli, char * p)
    {
        uart_handle handle;
        uart_cfg cfg = {0};
        u8 *read_buf = NULL;
        u8 *write_buf = NULL;
        u32 read_len = 0;
        u32 read_len_left = 0;
        u32 i = 0;
        u8   argc;
        char *uart_name;
    
        argc = CliTokenCount(cli);
    
        if (argc < 1)
            return eCLI_PARSE_INPUT_ERROR;
        //uart test device
        uart_name = CliTokenPop(cli);
    
        cfg.rate = 115200;
        cfg.bit_length = 8;
        cfg.parity = UART_PARITY_NONE;
        cfg.stop = UART_STOP_1BIT;
    
        CamOsPrintf("start test %s...\n", uart_name);
    
        read_buf = CamOsMemAlloc(UART_BUF_SIZE);
        if (read_buf == NULL)
        {
            CamOsPrintf("alloc read buf fail.\n");
            return eCLI_PARSE_ERROR;
        }
        write_buf = CamOsMemAlloc(UART_BUF_SIZE);
        if (write_buf == NULL)
        {
            CamOsPrintf("alloc write buf fail.\n");
            return eCLI_PARSE_ERROR;
        }
    
        for (i = 0; i < UART_BUF_SIZE; i++)
        {
            *(write_buf + i) = i + 0x40;
            *(read_buf + i ) = 0;
        }
    #if 1
        handle = drv_uart_open(uart_name);
    
        if (!handle)
            CamOsPrintf("drv_uart_open fail\n");
        //set attribute
        drv_uart_ioctrl(handle, UART_CMD_CONFIG, (void *)&cfg);
        //uart write
        drv_uart_write(handle, (u8 *)write_buf, UART_BUF_SIZE, -1);
    
        read_len_left = UART_BUF_SIZE;
        while (read_len < UART_BUF_SIZE)
        {
            read_len += drv_uart_read(handle, (read_buf + read_len), read_len_left, 0);
            read_len_left = UART_BUF_SIZE - read_len;
        }
    
        for (i = 0; i < UART_BUF_SIZE; i++)
        {
            if (*(write_buf + i) != *(read_buf + i))
            {
                CamOsPrintf("data check fail index %d.\n", i);
                break;
            }
        }
        drv_uart_close(handle);
    
    #else
    
        handle = drv_uart_open(uart_name);
    
        if (!handle)
            CamOsPrintf("drv_uart_open fail\n");
    
        drv_uart_ioctrl(handle, UART_CMD_CONFIG, (void *)&cfg);
    
        drv_uart_write(handle, (u8 *)debug_char, 28, -1);
    
        do
        {
            read_len = drv_uart_read(handle, read_buf, 28, -1);
    
            if (read_len >= 0)
            {
                read_buf[read_len] = '\0';
    
                CamOsPrintf("%s", read_buf);
    
                if (read_buf[0] == 'q')
                    break;
            }
            read_len_left += read_len;
        } while(1);
    
        drv_uart_close(handle);
    #endif
    
        return eCLI_PARSE_OK;
    }
    

    6. API参考

    1. 头文件位于sc/driver/sysdriver/uart/drv/pub/drv_uart.h

      typedef struct
      {
          u8             bit_length;       ///< length in number of bits
          u8             parity;           ///< parity
          u8             stop;             ///< stop bit
          u8             rtscts;
          u32            rate;             ///< bit rate
      } uart_cfg;
      
    2. 该功能模块提供以下接口:

      API名称 功能
      drv_uart_open 用于打开uart设备,当中会进行初始化操作
      drv_uart_close 关闭open的uart。
      drv_uart_ioctrl uart通讯协议设定。
      drv_uart_write uart对获取到的handle进行数据发送。
      drv_uart_read uart对获取到的handle进行数据接收。

    6.1 drv_uart_open

    • 功能

      用于打开uart设备,当中会进行初始化操作

    • 语法

      uart_handle drv_uart_open(char *name)
      
    • 参数

      参数名称 描述
      name uart设备名
      uart0: uart0
      uart1: uart1
      fuart: fuart
    • 返回值

      结果 描述
      非NULL 成功
      NULL 失败

    6.2 drv_uart_close

    • 功能

      关闭open的uart

    • 语法

      void drv_uart_close(uart_handle handle)
      
    • 参数

      参数名称 描述
      handle open成功返回的句柄
    • 返回值

    6.3 drv_uart_ioctrl

    • 功能

      uart通讯协议设定

    • 语法

      s32 drv_uart_ioctrl(uart_handle handle, u32 cmd, void *arg)
      
    • 参数

      参数名称 描述
      handle uart句柄,open成功获得
      cmd 命令,设定协议使用 UART_CMD_CONFIG
      arg 协议内容
    • 返回值

      结果 描述
      0 成功
      -1 失败

    6.4 drv_uart_write

    • 功能

      uart对获取到的handle进行数据发送

    • 语法

      s32 drv_uart_write(uart_handle handle, u8 *buf, u32 len, s32 timeout_ms)
      
    • 参数

      参数名称 描述
      handle uart句柄,open成功获得
      buf 发送数据缓存
      len 发送字节数
      timeout_ms 阻塞等待时长
      = 0: 非阻塞
      < 0: 阻塞直到完成
      > 0: 阻塞设定时长
    • 返回值

      结果 描述
      0 uart未使能
      -1 错误句柄
      >0 完成的字节数

    6.5 drv_uart_read

    • 功能

      uart对获取到的handle进行数据接收

    • 语法

      s32 drv_uart_read(uart_handle handle, u8 *buf,  u32 len, s32 timeout_ms)
      
    • 参数

      参数名称 描述
      handle uart句柄,open成功获得
      buf 接收数据缓存
      len 接收字节数
      timeout_ms 阻塞等待时长
      = 0: 非阻塞
      < 0: 阻塞直到完成
      > 0: 阻塞设定时长
    • 返回值

      结果 描述
      0 uart未使能
      -1 错误句柄
      >0 完成的字节数

    7. FAQ

    当出现通讯异常时,可以参考如下方面进行问题调试,提供了几种较为常见的排查方向,另调试过程建议抓取波形方便分析。后期会持续更新debug方法

    排查方向
    常见问题
    备注
    padmux 1. 阻塞模式,卡在循环读上,console卡住点不动;
    2. 无波形,触发不了
    参考PADMUX章节,或padmux模块说明
    通信波特率 uart处于busy状态,设置不了波特率 客户设备一直往UART的RX发送数据
    时钟源 无波形 参考CLKGEN模块说明
    中断 RX数据丢失 UART出中断的时候恰好Linux中断被关了(spin_lock_irqsave等)可通过LA抓取波形分析