Receive Interrupt

该示例演示使用 UART 中断方式与 PC 终端进行数据通信。

使用 PC 终端程序(如 PuTTY 或 UartAssist)发送数据。SoC 接收到数据后触发 UART 中断。

在 UART 中断处理函数中,在 UART_INT_RD_AVA 中断中将接到的数据存储到缓冲区中,在 UART_INT_RX_IDLE 中断中会设置 received_flag 以表示接收完成。

一旦 received_flag 被设置,SoC 将缓冲区数据发送回 PC 终端,在 PC 终端程序中可观察到 SoC 回复的数据信息。

环境需求

该示例的环境需求,可参考 环境需求

此外,需要在 PC 终端安装 PuTTY 或 UartAssist 等串口助手工具。

硬件连线

连接 P3_0(UART TX Pin)和 FT232 的 RX,P3_1(UART RX Pin) 和 FT232 的 TX。

配置选项

  1. 可配置如下宏修改引脚定义。

    #define UART_TX_PIN                 P3_0
    #define UART_RX_PIN                 P3_1
    

编译和下载

该示例的编译和下载流程,可参考 编译和下载

测试验证

准备阶段

  1. 启动 PuTTY 或 UartAssist 等 PC 终端,连接到使用的 COM 端口,并进行以下 UART 设置:

  • 波特率: 115200

  • 8 数据位

  • 1 停止位

  • 无校验

  • 无硬件流控

测试阶段

  1. 当 EVB 启动后,在 Debug Analyzer 工具内观察如下 log。

    Start uart rx interrupt test!
    
  2. Soc 开始发送 ### Uart interrupt sample ###\r\n,观察 PC 终端上出现的字符串。

  3. 在 PC 终端上输入字符串并向 SoC 发送,SoC 收到数据后会向 PC 端回复相同的数据。观察 PC 终端上是否出现相同的字符串,同时在 Debug Analyzer 工具上会显示接收到的数据和中断信息。

代码介绍

该章节主要介绍示例中的初始化和相应功能实现的代码和流程说明。

源码路径

工程文件和源码路径如下:

  • 工程路径: sdk\samples\peripheral\uart\rx_interrupt\proj

  • 源码路径: sdk\samples\peripheral\uart\rx_interrupt\src

初始化

外设的初始化流程可参考 General Introduction 中的 初始化流程 部分。

  1. 调用 Pad_Config()Pinmux_Config(),配置对应引脚的 PAD 和 PINMUX。

    void board_uart_init(void)
    {
        Pad_Config(UART_TX_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_HIGH);
        Pad_Config(UART_RX_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_HIGH);
    
        Pinmux_Config(UART_TX_PIN, UART3_TX);
        Pinmux_Config(UART_RX_PIN, UART3_RX);
    }
    
  2. 调用 RCC_PeriphClockCmd() ,开启 UART 时钟。

  3. 对 UART 外设进行初始化:

    1. 定义 UART_InitTypeDef 类型 UART_InitStruct ,调用 UART_StructInit()UART_InitStruct 预填默认值。

    2. 根据需求修改 UART_InitStruct 参数,UART 的初始化参数配置如下表。

    3. 调用 UART_Init(),初始化 UART 外设。

UART 初始化参数

UART Hardware Parameters

Setting in the UART_InitStruct

UART

UART Baudrate Parameter - div

UART_InitTypeDef::UART_Div

BaudRate_Table[BAUD_RATE_115200].div

UART Baudrate Parameter - ovsr

UART_InitTypeDef::UART_Ovsr

BaudRate_Table[BAUD_RATE_115200].ovsr

UART Baudrate Parameter - ovsr_adj

UART_InitTypeDef::UART_OvsrAdj

BaudRate_Table[BAUD_RATE_115200].ovsr_adj

Rx Threshold

UART_InitTypeDef::UART_RxThdLevel

14

IDLE Time

UART_InitTypeDef::UART_IdleTime

UART_RX_IDLE_2BYTE

  1. 配置 UART 接收中断 UART_INT_RD_AVA 和 UART 接收空闲中断 UART_INT_RX_IDLE ,配置 NVIC。NVIC 相关配置可参考 中断配置

功能实现

UART 通过中断接收数据的流程如图所示:

这里应该是 UART RX interrupt flow

UART 中断接收数据流程

  1. 执行 uart_senddata_continuous ,发送 ### Uart interrupt sample ###\r\n 到 PC 终端。在函数 uart_senddata_continuous 内,等待 UART TX FIFO 为空时,分批将数据填入 FIFO 中。

    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->UART_RBR_THR = *pSend_Buf++;
            }
            vCount -= UART_TX_FIFO_SIZE;
        }
    
        while (UART_GetFlagStatus(UARTx, UART_FLAG_TX_FIFO_EMPTY) == 0);
        while (vCount--)
        {
            UARTx->UART_RBR_THR = *pSend_Buf++;
        }
    }
    
  2. PC 终端发送字符串后,SoC 检测接收到数据时,会触发 UART 中断。根据 PC 终端发送的数据长度不同,会触发不同类型的中断。

    1. 若 PC 终端发送的数据长度大于设定的阈值时,SoC 首先会触发 UART_INT_ID_RX_LEVEL_REACH 中断。在中断内调用 UART_GetRxFIFODataLen()UART_ReceiveData(),接收数据并保存到 UART_Recv_Buf 中。

    2. 若 PC 终端发送的数据长度小于设定的阈值时,SoC 检测到 RX FIFO 内存在数据,但是一段时间内 RX FIFO 没有再填入新数据时,会触发 UART_INT_ID_RX_DATA_TIMEOUT 中断。在中断内调用 UART_GetRxFIFODataLen()UART_ReceiveData(),接收数据并保存到 UART_Recv_Buf 中。

备注

触发 UART_INT_ID_RX_DATA_TIMEOUT 中断所需要的时间,为 4 个 Characters 的时间。在 115200 波特率的情况下,一个 Character 的时间为 1/112500 * (1+8+0+1) = 86.8us。Character = start bit + data bits + parity bit + stop bits.

  1. 若 RX FIFO 为空且在设置的 IDLE 时间内没有接收到数据时,触发 UART_FLAG_RX_IDLE 中断。在中断函数内设置 receive_flag 标志位为 true

    void UART_HANDLER()
    {
        uint16_t lenth = 0;
        uint32_t int_status = UART_GetIID(UART_DEMO);
    
        UART_INTConfig(UART_DEMO, UART_INT_RD_AVA, DISABLE);
    
        if (UART_GetFlagStatus(UART_DEMO, UART_FLAG_RX_IDLE) == SET)
        {
            DBG_DIRECT("UART_FLAG_RX_IDLE");
    
            UART_INTConfig(UART_DEMO, UART_INT_RX_IDLE, DISABLE);
    
            UART_ClearRxFIFO(UART_DEMO);
            UART_INTConfig(UART_DEMO, UART_INT_RX_IDLE, ENABLE);
            receive_flag = true;
        }
    
        switch (int_status & 0x0E)
        {
        case UART_INT_ID_RX_DATA_TIMEOUT:
            {
                DBG_DIRECT("UART_INT_ID_RX_TMEOUT");
    
                lenth = UART_GetRxFIFODataLen(UART_DEMO);
                UART_ReceiveData(UART_DEMO, 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_LINE_STATUS:
            break;
    
        case UART_INT_ID_RX_LEVEL_REACH:
            {
                DBG_DIRECT("UART_INT_ID_RX_LEVEL_REACH");
    
                lenth = UART_GetRxFIFODataLen(UART_DEMO);
                UART_ReceiveData(UART_DEMO, 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_TX_EMPTY:
            break;
    
        default:
            break;
        }
    
        UART_INTConfig(UART_DEMO, UART_INT_RD_AVA, ENABLE);
    }
    
  2. 循环判断 receive_flag 的状态。当发现 receive_flag 置为 true 时,代表此次 UART 接收完毕。调用 uart_senddata_continuous 将接收到的数据 UART_Recv_Buf 发送回至 PC 终端。

    while (1)
    {
        if (receive_flag == true)
        {
            receive_flag = false;
            uart_senddata_continuous(UART_DEMO, 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;
        }
    }