RISCV_UART USER GUIDE


REVISION HISTORY

Revision No.
Description
Date
1.0
  • Initial release
  • 04/18/2023
    1.1
  • Modify document format
  • 04/09/2025

    1. OVERVIEW

    UART generally refers to a universal asynchronous communication transceiver, and its communication characteristics are asynchronous and serial. The UART bus has two data lines, TX and RX, to achieve full-duplex transmission and reception. The sender and receiver parse the received signal through their own set frame format and baud rate, so the sender and receiver are required to use the same frame format and baud rate during the communication process.

    SigmaStar UART is a module that complies with the standard serial communication protocol. It contains multiple UARTs, among which there are different names of FUART and UART. The difference is that FUART has more CTS/RTS hardware flow control function than UART. Generally, UART0 is used as the console port by default. This article describes how to use the Sigmastar UART driver under riscv.


    2. Keyword Description

    • TX

      Data transmission function/pin, sends UART signal according to the set frame format and baud rate.

    • RX

      Data reception function/pin, the received signal will be parsed by UART according to the set frame format and baud rate, TX and RX share the same set of settings.

    • CTS

      Flow control pin/signal, input signal, interpreted as "send permission". Used to determine whether data can be sent to the other party, low level is valid.

    • RTS

      Flow control pin/signal, output signal, interpreted as "send request". Used to indicate that this device is ready to receive data, low level is valid.

    • FIFO mode

      Each frame of data needs to be passed to the UART hardware send buffer register by the CPU, and then the UART takes it out of the send buffer and sends it out. The hardware send buffer is 32 bytes. Or when receiving, the CPU reads from the UART hardware receive buffer register, and the hardware receive buffer is 32 bytes.

    • DMA mode

      Each frame of data no longer needs to be sent or read by the CPU one by one. It only needs to write the data to be sent to the storage location specified by DMA at one time before triggering communication, and then trigger communication; or take all the received data from the specified storage at one time; during the communication execution, the data interaction between UART is completed by URDMA itself, without the CPU participating.
      DMA mode can make the transmission more coherent, reduce the CPU loading, reduce the number of UART communication interrupts, and at the same time, the 4096-byte storage space provided for receiving and sending can greatly reduce the possibility of data loss.

    • URDMA

      A module dedicated to providing data handling services for UART, which needs to be enabled in DMA mode. After enabling, UART will no longer be interrupted, and URDMA will be interrupted; and when DMA is enabled, the CPU can no longer access the UART register, otherwise it will cause a jam.

    • CONSOLE PORT

      The console is a buffer concept, which is specially used for the kernel to print and busybox to receive shell commands. The PC is connected to the Console Port, and the terminal application of the PC is used to display print information or input operation instructions.

    • PADMUX

      Pin multiplexing, connect UART PAD with actual pins, so that signals can be transmitted through pins.

    • DIGMUX

      Used to connect UART TX/RX digital message with UART PAD. Different UART PADs can be connected to different UART modules. However, the PAD group PAD_PM_UART_TX and PAD_PM_UART_RX, which are used as CONSOLE PORT by default, cannot switch digmux.

      For example, when the hardware layout is fixed, assuming that the function of UART1 is originally used, HW CTS/RTS support is required at this time, and fuart does not have the corresponding PADMUX to switch to this group of hardware pins. You can switch UART1 and FUART by switching DIGMUX. At this time, the TX/RX signal connection of FUART and the TX/RX signal connection of UART1 are interchanged, but CTS/RTS is still the pin originally set by FUART, which meets the use of HW CTS/RTS.


    3. Functional Description

    3.1. UART Resource

    PCUPID provides 6 sets of standard UART, 4 sets of FUART (uart modules with hardware flow control, supporting CTS/RTS, namely fuart, uart1, uart2, uart3, flow control can be enabled by configuring sctpen_u8 in SYSDESC) and one set of PM_UART (DMA mode is not supported).

    The correspondence between each UART/URDMA and bank address is as follows. UART is uniquely bound to URDMA, for example, FUART is bound to URDMA, and UART0 is bound to 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. Function Support

    The following table provides the support status of each UART for each function.

    Function FIFO mode FIFO buffer size(byte) DMA mode DMA buffer size(byte) HW CTS/RTS baudrate protocol
    Support status 32 ✔ (except for PM_UART) 4096 only fuart

    The baud rate support is as follows:

    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

    The UART communication protocol support is as follows:

    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

    The communication sequence diagram is shown in Figure 3-1:


    Figure 3-1: UART Timing Procotol

    3.3. Notes

    • External pull-up

      RX must be connected to an external pull-up, and TX is recommended to be connected to an external pull-up.

    • FIFO mode

      When using FIFO mode, the HW buffer size is only 32 bytes. When UART cannot respond to the UART interrupt in time before the buffer is filled, and then read the data from the HW buffer, the received data will be lost.

    3.4. Baud Rate Calculation

    The baud rate refers to the modulation rate of the data signal on the carrier. It is expressed by the number of times the carrier modulation state changes per unit time and is an important indicator of UART. The actual baud rate output by the current hardware design UART is determined by the Clk source input to the UART and the set frequency division value. The relationship between the baud rate (BAUD), the frequency division value (DIV) and the input CLK frequency (CLK) is as follows:

    DIV = CLK / (BAUD x 16)
    

    Since the CLK rate given to the UART is not continuous, the baud rate (error 3%) that the UART can support is also not continuous according to the formula.

    The modification of the baud rate.

    It can be set in the test program. The setting method refers to the test demo picture below.

    4. HARDWARE CONNECTION INTRODUCTION

    1. Standard UART refers to a UART communication method that does not contain any hardware flow control mechanism. It only relies on the start bit, data bit, parity bit (optional) and stop bit to define the data frame. Just use TX to connect to the other end RX, and RX to connect to the other end TX.

    2. FUART (flow control UART) refers to adding hardware or software flow control mechanism on the basis of standard UART to prevent data loss and improve communication reliability. On the basis of standard UART, add CTX to connect to the other end CTS, and CTS to connect to the other end RTS.


      Figure 4-1: UART Connection


    5. RISCV USAGE INTRODUCTION

    When testing UART communication, the following basic steps need to be ensured:

    • Hardware device connection, external pull-up resistor confirmation, a simple test method is to short-circuit tx and rx;

    • CONFIG supports UART driver, enabled by default;

    • SYSDESC file configures attributes required;

    • PADMUX settings;

    • API calls to execute communication.

    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 Configuration

    The UART driver compilation option is enabled by default in RISCV. The config file is located at mak/options_chipname_riscv_isw.mak, and CONFIG_UART_SUPPORT is enabled.

    CONFIG_UART_SUPPORT = TRUE
    

    5.3. SYSDESC Configuration

    The chipname-default.sys file is located in sc/driver/sysdriver/sysdesc/hal/chipname/pub. Take fuart as an example, the node content is as follows:

    <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;
    

    The description of the attributes in the node is as follows:

    Attribute value Description Remark
    reg_u32 Used to specify the bank and range where UART (and URDMA) is located No modification required
    interrupts_u32 Specify the interrupt and trigger mode of UART (and URDMA) No modification required
    camclk_u16 Specify the clock source of UART No modification required
    dma_u8 Enable DMA function of FUART Write to 1 when needed
    sctpen_u8 HW CTS/RTS enable 1: enable
    0: disable
    digmux_u8 Select which digmux the rx tx pin is connected to. Each uart will be connected to the corresponding digmux by default. If there is no special requirement, there is no need to set this attribute; 0xFF means that the driver will not modify the default digmux of the uart Modify as needed, if there is no special requirement, it is recommended to delete this attribute
    rx_fifo_level_u8 Select the level of uart rx fifo, which affects how many bytes are received to trigger an interrupt, and timeout will also trigger an interrupt. The current fifo depth is 32bytes;
    "0" - 1 character in the FIFO;
    "1" - FIFO ¼ full;
    "2" - FIFO ½ full;
    "3" - FIFO 2 less than full
    Modify as needed, if there is no special requirement, this attribute can be deleted. The default initial value of the driver is 0; it is only effective when the dma attribute is set to 0
    tx_fifo_level_u8 Select the level of the uart tx fifo, which affects how many bytes are left in the txfifo to trigger an interrupt. Timeout will also trigger an interrupt. The current fifo depth is 32 bytes;
    "0" - FIFO empty;
    "1" - 2 characters in the FIFO;
    "2" - FIFO ¼ full;
    "3" - FIFO ½ full;
    Modify as needed, if there is no special requirement, this attribute can be deleted. The default initial value of the driver is 0; it is only effective when the dma attribute is set to 0
    Status_u8 Select whether to enable the UART driver Modify as needed

    5.4. PADMUX Setting

    CONFIG configuration: CONFIG_PADMUX_SUPPORT=Y

    If the chipname-default.sys file is configured with the attribute <padmux>, then the PADMUX setting is directly configured here, for example, 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;
    

    Otherwise, enable the PADMUX driver and configure the pin multiplexing function in the chipname-xxx-padmux.c file, which is located in sc/driver/sysdriver/padmux/hal/chipname/src. You only need to add the following content to the corresponding schematic attribute:

    pad_info_t schematic[] =
    {
        {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},
    };
    

    The first column is the pin index number, which can be queried in sc/drivers/sysdriver/gpio/hal/chipname/pub/gpio.h;

    The second column is the mode definition, which can be queried in sc/drivers/sysdriver/gpio/hal/chipname/pub/padmux.h;

    The third column is the index name of the pin and matching mode, which can be queried in sc/drivers/sysdriver/padmux/drv/pub/drv_puse.h;

    5.5 Sample code

    Demo source code reference: 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 reference

    1. The header file is located in 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. This function module provides the following interfaces:

      API name Function
      drv_uart_open Used to open the uart device, which will perform initialization operations
      drv_uart_close Close the open uart.
      drv_uart_ioctrl Set the uart communication protocol.
      drv_uart_write Uart sends data to the obtained handle.
      drv_uart_read Uart receives data from the obtained handle.

    6.1 drv_uart_open

    • Function

      Used to open the uart device, which will perform initialization operations

    • Syntax

      uart_handle drv_uart_open(char *name)
      
    • Parameters

      Parameter name Description
      name uart device name
      uart0: uart0
      uart1: uart1
      fuart: fuart
    • Return Value

      Result Description
      Non-NULL Successful
      NULL Failed

    6.2 drv_uart_close

    • Function

      Close the open uart

    • Syntax

      void drv_uart_close(uart_handle handle)
      
    • Parameters

      Parameter name Description
      handle Handle returned by open Successfully
    • Return Value

      none

    6.3 drv_uart_ioctrl

    • Function

      Set the uart communication protocol.

    • Syntax

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

      Parameter name Description
      handle uart handle, Successfully obtained by open
      cmd command, set protocol using UART_CMD_CONFIG
      arg protocol content
    • Return Value

      result Description
      0 Successful
      -1 Failed

    6.4 drv_uart_write

    • Function

      Uart sends data to the obtained handle.

    • Syntax

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

      Parameter name Description
      handle uart handle, Successfully obtained by open
      buf send data buffer
      len send bytes
      timeout_ms blocking waiting time
      = 0: non-blocking
      < 0: blocking until completion
      > 0: blocking set time
    • Return Value

      Result Description
      0 uart is not enabled
      -1 error handle
      >0 completed bytes

    6.5 drv_uart_read

    • Function

      Uart receives data from the obtained handle.

    • Syntax

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

      Parameter name Description
      handle uart handle, Successfully obtained by open
      buf Receive data buffer
      len Number of received bytes
      timeout_ms Block waiting time
      = 0: non-blocking
      < 0: block until completion
      > 0: block for a set time
    • Return Value

      Result Description
      0 uart not enabled
      -1 error handle
      >0 Number of bytes completed

    7. FAQ

    When communication anomalies occur, you can refer to the following aspects for problem debugging. Several common troubleshooting directions are provided. In addition, it is recommended to capture waveforms for easy analysis during the debugging process. The debug method will be continuously updated later.

    Troubleshooting direction
    Common problems
    Remarks
    Padmux 1. Blocking mode, stuck in loop reading, console stuck and not moving;
    2. No waveform, can't be triggered
    Refer to the PADMUX chapter, or padmux module description
    Communication baud rate UART is in busy state, baud rate cannot be set The client device keeps sending data to UART RX
    Clock source No waveform Refer to CLKGEN module description
    Interrupt RX data loss When UART interrupts, Linux interrupts are disabled (spin_lock_irqsave, etc.). You can use LA to capture the waveform for analysis