Receive Interrupt

This example demonstrates data communication with a PC terminal using UART interrupt mode.

The PC terminal program (such as PUTTY or UartAssist) sends data.

The SoC receives the data and triggers an interrupt. In the UART interrupt handling function, the received data is stored in the buffer during the UART_INT_RD_AVA interrupt, and the receive_flag is set in the UART_FLAG_RX_IDLE interrupt to indicate the reception is complete.

Once the receive_flag is set, the SoC sends the buffered data back to the PC terminal.

Requirements

The sample supports the following development kits:

Development Kits

Hardware Platforms

Board Name

RTL8752H HDK

RTL8752H EVB

For more requirements, please refer to Quick Start.

Wiring

Connect P3_0 (UART TX) to the RX pin of the FT232 and P3_1 (UART RX) to the TX pin of the FT232.

Building and Downloading

This sample can be found in the SDK folder:

Project file: board\evb\io_sample\UART\Interrupt\mdk

Project file: board\evb\io_sample\UART\Interrupt\gcc

Please follow these steps to build and run the example:

  1. Open sample project file.

  2. To build the target, follow the steps listed on the Generating App Image in Quick Start.

  3. After a successful compilation, the app bin app_MP_xxx.bin will be generated in the directory mdk\bin or gcc\bin.

  4. To download app bin into EVB board, follow the steps listed on the MP Tool Download in Quick Start.

  5. Press reset button on EVB board and it will start running.

Experimental Verification

Preparation Phase

Launch PuTTY or UartAssist or other PC terminals, connect to the used COM port, and configure the following UART settings:

  • Baud rate: 115200

  • 8 data bits

  • 1 stop bit

  • No parity

  • No hardware flow control

Testing Phase

  1. The example starts sending ### Uart interrupt demo ###\r\n, observe the string appearing on the PC terminal.

  2. Input data on the PC terminal and observe if the SoC replies with the same data.

  3. When the length of the data input on the PC terminal does not reach the Rx receive threshold (default is 16 bytes), the type of interrupt generated is UART_INT_ID_RX_DATA_TIMEOUT, and interrupt information and received data information are printed in the Debug Analyzer.

    UART_INT_ID_RX_TIMEOUT
    data = 0x..
    ...
    
  4. When the length of the data input on the PC terminal exceeds the Rx receive threshold (default is 16 bytes), the type of interrupt generated is UART_INT_ID_RX_LEVEL_REACH, and interrupt information and received data information are printed in the Debug Analyzer.

    UART_INT_ID_RX_LEVEL_REACH
    data = 0x..
    ...
    

Code Overview

This chapter will be introduced according to the following several parts:

  1. Source Code Directory.

  2. Peripheral initialization will be introduced in chapter Initialization.

  3. Functional implementation after initialization will be introduced in chapter Function Implementation.

Source Code Directory

  • Project directory: sdk\board\evb\io_sample\UART\Interrupt

  • Source code directory: sdk\src\sample\io_sample\UART\Interrupt

Source files are currently categorized into several groups as below.

└── Project: interrupt
    └── secure_only_app
        └── include
            ├── app_define.h
            └── rom_uuid.h
        ├── cmsis                    includes CMSIS header files and startup files
            ├── overlay_mgr.c
            ├── system_rtl876x.c
            └── startup_rtl876x.s
        ├── lib                      includes all binary symbol files that user application is built on
            ├── rtl8752h_sdk.lib
            ├── gap_utils.lib
            └── ROM.lib
        ├── peripheral               includes all peripheral drivers and module code used by the application
            ├── rtl876x_rcc.c
            ├── rtl876x_pinmux.c
            ├── rtl876x_nvic.c
            └── rtl876x_uart.c
        ├── profile
        └── app                      includes the ble_peripheral user application implementation
            └── main.c

Initialization

When the EVB is reset, the main function is executed, following these steps:

int main(void)
{
    extern uint32_t random_seed_value;
    srand(random_seed_value);
    __enable_irq();
    uart_demo();
}

In uart_demo, it includes PAD/PINMUX settings and UART peripheral initialization processes.

void uart_demo(void)
{
    uint16_t demo_str_len = 0;

    board_uart_init();
    driver_uart_init();

    ...
}

board_uart_init is the PAD/PINMUX settings related to UART, including the following steps:

  1. Configure PAD: Set the pins, PINMUX mode, PowerOn, internal pull-up, and disable output.

  2. Configure PINMUX: Set the pins for UART0_TX and UART0_RX functions.

driver_uart_init is the initialization of the UART peripheral, including the following steps:

  1. Enable RCC clock.

  2. Configure UART baud rate to 115200, with a default receive threshold of 16.

  3. Configure UART receive interrupt: UART_INT_RD_AVA and UART receive idle interrupt: UART_INT_RX_IDLE.

void driver_uart_init(void)
{
    RCC_PeriphClockCmd(APBPeriph_UART0, APBPeriph_UART0_CLOCK, ENABLE);

    /* uart init */
    UART_InitTypeDef UART_InitStruct;
    UART_StructInit(&UART_InitStruct);

    UART_Init(UART0, &UART_InitStruct);

    //enable rx interrupt and line status interrupt
    UART_INTConfig(UART0, UART_INT_RD_AVA, ENABLE);
    UART_INTConfig(UART0, UART_INT_RX_IDLE, ENABLE);

    /*  Enable UART IRQ  */
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel         = UART0_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelCmd      = (FunctionalState)ENABLE;
    NVIC_InitStruct.NVIC_IRQChannelPriority = 3;
    NVIC_Init(&NVIC_InitStruct);
}

Functional Implementation

  1. Define the string ### Uart interrupt demo ###\r\n, and execute uart_senddata_continuous to send the string content to the PC.

    1. In uart_senddata_continuous, poll the flag UART_FLAG_TX_FIFO_EMPTY to determine if the UART TX FIFO is empty.

    2. When the UART TX FIFO is empty, insert data into the TX FIFO in a loop to achieve multi-byte continuous transmission.

    3. The PC serial port assistant can display the string data sent by the SoC.

    void uart_senddata_continuous(UART_TypeDef *UARTx, const uint8_t *pSend_Buf, uint16_t vCount)
    {
        uint8_t count;
    
        while (vCount / UART_TX_FIFO_SIZE > 0)
        {
            while (UART_GetFlagStatus(UARTx, UART_FLAG_TX_FIFO_EMPTY) == 0);
            for (count = UART_TX_FIFO_SIZE; count > 0; count--)
            {
                UARTx->RB_THR = *pSend_Buf++;
            }
            vCount -= UART_TX_FIFO_SIZE;
        }
    
        while (UART_GetFlagStatus(UARTx, UART_FLAG_TX_FIFO_EMPTY) == 0);
        while (vCount--)
        {
            UARTx->RB_THR = *pSend_Buf++;
        }
    }
    
  2. After the PC sends data, when the SoC receives the data, it triggers UART_INT_RD_AVA or UART_INT_RX_IDLE interrupt and enters the interrupt handling function.

  3. In the UART interrupt handling function, if the UART is receiving data, it will trigger the UART_INT_RD_AVA interrupt, and the processing flow is as follows:

    1. Disable the UART_INT_RD_AVA interrupt.

    2. Execute UART_GetIID() to obtain the interrupt flag ID type.

      1. When the ID is UART_INT_ID_RX_LEVEL_REACH (RX FIFO data length reaches the RX FIFO threshold UART_RxThdLevel), receive FIFO data and save it to UART_Recv_Buf.

      2. When the ID is UART_INT_ID_RX_DATA_TIMEOUT (at least one UART data in the RX FIFO and no more data comes in for the duration of 4-byte time), receive FIFO data and save it to UART_Recv_Buf.

    3. Enable the UART_INT_RD_AVA interrupt.

    void UART0_Handler()
    {
        uint16_t lenth = 0;
        uint32_t int_status = UART_GetIID(UART0);
    
        UART_INTConfig(UART0, UART_INT_RD_AVA, DISABLE);
    
        ...
    
        switch (int_status & 0x0E)
        {
        case UART_INT_ID_RX_DATA_TIMEOUT:
            {
                DBG_DIRECT("UART_INT_ID_RX_TMEOUT");
                lenth = UART_GetRxFIFODataLen(UART0);
                UART_ReceiveData(UART0, UART_Recv_Buf, lenth);
                for (uint8_t i = 0; i < lenth; i++)
                {
                    DBG_DIRECT("data=0x%x", UART_Recv_Buf[i]);
                    UART_Send_Buf[UART_Recv_Buf_Lenth + i] = UART_Recv_Buf[i];
                }
                UART_Recv_Buf_Lenth += lenth;
                break;
            }
    
        case UART_INT_ID_RX_LEVEL_REACH:
            {
                DBG_DIRECT("UART_INT_ID_RX_LEVEL_REACH");
    
                lenth = UART_GetRxFIFODataLen(UART0);
                UART_ReceiveData(UART0, UART_Recv_Buf, lenth);
                for (uint8_t i = 0; i < lenth; i++)
                {
                    DBG_DIRECT("data=0x%x", UART_Recv_Buf[i]);
                    UART_Send_Buf[UART_Recv_Buf_Lenth + i] = UART_Recv_Buf[i];
                }
                UART_Recv_Buf_Lenth += lenth;
                break;
            }
        ...
        }
    
        UART_INTConfig(UART0, UART_INT_RD_AVA, ENABLE);
    }
    
  4. In the UART interrupt handler function, the UART completes data reception and triggers the UART_FLAG_RX_IDLE interrupt (after reading the RX FIFO data, no data enters the RX FIFO within the RX idle timeout period), and the workflow is as follows:

    1. Disable the UART_INT_RX_IDLE interrupt.

    2. Clear the receive FIFO.

    3. Re-enable the UART_INT_RX_IDLE interrupt.

    4. Set the receive flag receive_flag to true.

    void UART0_Handler()
    {
        ...
    
        if (UART_GetFlagStatus(UART0, UART_FLAG_RX_IDLE) == SET)
        {
            UART_INTConfig(UART0, UART_INT_RX_IDLE, DISABLE);
    
            UART_ClearRxFIFO(UART0);
            UART_INTConfig(UART0, UART_INT_RX_IDLE, ENABLE);
            receive_flag = true;
        }
        ...
    
    }
    
  5. Loop to check the receive_flag bit. When this flag bit is detected to be set to true, it indicates that the data reception on the SoC side is complete. The received data is then sent back to the PC side, and the received data is cleared.

    while (1)
    {
        if (receive_flag == true)
        {
            receive_flag = false;
            uart_senddata_continuous(UART0, UART_Send_Buf, UART_Recv_Buf_Lenth);
    
            for (uint16_t i = 0; i < UART_Recv_Buf_Lenth; i++)
            {
                UART_Recv_Buf[i] = 0;
            }
            UART_Recv_Buf_Lenth = 0;
        }
    }