Receive Interrupt
该示例演示使用 UART 中断方式与 PC 终端进行数据通信。
PC 终端程序(如 PUTTY 或 UartAssist)发送数据。
SoC 接收数据并触发中断。在 UART 中断处理函数中,在 UART_INT_RD_AVA
中断中将接收到的数据存储到缓冲区中,在 UART_FLAG_RX_IDLE
中断中置位 receive_flag
以表示接收完成。
一旦 receive_flag
被设置,SoC 将缓冲区数据发送回 PC 终端。
环境需求
该示例支持以下开发套件:
Hardware Platforms |
Board Name |
---|---|
RTL8752H HDK |
RTL8752H EVB |
更多信息请参考 快速入门。
硬件连线
连接 P3_0(UART TX)和 FT232 的 RX,P3_1(UART RX)和 FT232 的 TX。
编译和下载
该示例的工程路径如下:
Project file: board\evb\io_sample\UART\Interrupt\mdk
Project file: board\evb\io_sample\UART\Interrupt\gcc
请按照以下步骤操作构建并运行该示例:
打开工程文件。
按照 快速入门 中 编译 APP Image 给出的步骤构建目标文件。
编译成功后,在路径
mdk\bin
或gcc\bin
下会生成 app binapp_MP_xxx.bin
文件。按下 reset 按键,开始运行。
测试验证
准备阶段
启动 PuTTY 或 UartAssist 等 PC 终端,连接到使用的 COM 端口,并进行以下 UART 设置:
波特率: 115200
8 数据位
1 停止位
无校验
无硬件流控
测试阶段
该示例开始发送
### Uart interrupt demo ###\r\n
,观察 PC 终端上出现的字符串。在 PC 终端上输入数据,观察 PC 终端上 SoC 是否回复了相同的数据。
PC 端输入数据的长度未达到 Rx 接收阈值时(默认 16 字节),产生的中断类型为
UART_INT_ID_RX_DATA_TIMEOUT
,在 Debug Analyzer 内打印中断信息与接收到的数据信息。UART_INT_ID_RX_TMEOUT data = 0x.. ...
PC 端输入数据的长度超过 Rx 接收阈值时(默认 16 字节),产生的中断类型为
UART_INT_ID_RX_LEVEL_REACH
,在 Debug Analyzer 内打印中断信息与接收到的数据信息。UART_INT_ID_RX_LEVEL_REACH data = 0x.. ...
代码介绍
该章节分为以下几个部分:
源码路径
工程路径:
sdk\board\evb\io_sample\UART\Interrupt
源码路径:
sdk\src\sample\io_sample\UART\Interrupt
该工程的工程文件代码结构如下:
└── 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
初始化
当 EVB 复位启动时,执行 main
函数,执行以下流程:
int main(void)
{
extern uint32_t random_seed_value;
srand(random_seed_value);
__enable_irq();
uart_demo();
}
在 uart_demo
中,包含 PAD/PINMUX 设置,UART 外设的初始化等流程。
void uart_demo(void)
{
uint16_t demo_str_len = 0;
board_uart_init();
driver_uart_init();
...
}
board_uart_init
为 UART 相关的 PAD/PINMUX 设置,包含如下流程:
配置 PAD:设置引脚,PINMUX 模式,PowerOn,内部上拉,输出失能。
配置 PINMUX:配置引脚分别为 UART0_TX 和 UART0_RX 功能。
driver_uart_init
为 UART 外设的初始化,包含如下流程:
使能 RCC 时钟。
配置 UART 的波特率为 115200,默认接收阈值为 16。
配置 UART 接收中断
UART_INT_RD_AVA
和 UART 接收空闲中断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); }
功能实现
定义字符串
### Uart interrupt demo ###\r\n
,执行uart_senddata_continuous
将字符串内容发送至 PC 端。在
uart_senddata_continuous
内,轮询检测标志位UART_FLAG_TX_FIFO_EMPTY
,判断 UART TX FIFO 是否为空。当 UART TX FIFO 空时,通过循环将数据塞入 TX FIFO 内,实现数据的多字节连续发送。
在 PC 端串口助手可以看到 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++; } }
PC 端发送数据后,SoC 接收到数据时,触发
UART_INT_RD_AVA
或UART_INT_RX_IDLE
中断,进入中断处理函数。在 UART 中断处理函数中,若 UART 正在接收数据会触发
UART_INT_RD_AVA
中断,处理流程如下:关闭
UART_INT_RD_AVA
中断。执行
UART_GetIID()
,获得中断标志 ID 类型。当 ID 为
UART_INT_ID_RX_LEVEL_REACH
(RX FIFO 数据长度达到 RX FIFO 阈值UART_RxThdLevel
)时,接收 FIFO 数据,保存到UART_Recv_Buf
中。当 ID 为
UART_INT_ID_RX_DATA_TIMEOUT
(RX FIFO 中至少有一个 UART 数据,并且不再有数据进来保持 4 个字节时间)时,接收 FIFO 数据,保存到UART_Recv_Buf
中。
开启
UART_INT_RD_AVA
中断。
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); }
在 UART 中断处理函数中,UART 完成接收数据会触发
UART_FLAG_RX_IDLE
中断(读空 RX FIFO 数据后,在 RX 空闲超时时间内没有数据进入 RX FIFO),工作流程如下:失能
UART_INT_RX_IDLE
中断。清除接收 FIFO。
重新使能
UART_INT_RX_IDLE
中断。置位接收标志
receive_flag
为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; } ... }
循环检测
receive_flag
位。当检测到该标志位被置为true
时,代表 SoC 端数据接收完毕,将接收到的数据发回至 PC 端,并清空接收到的数据。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; } }