喜欢1次
当用下列代码运行时,串口中断可以正常触发,回环数据接受正常。
#define UART_BAUDRATE 115200
static void uart_pinmux_init(void) {
#if defined(SOC_HBIRDV2)
GPIOA->IOFCFG |= IOF_UART_MASK; // 使能 UART RX/TX 的 IOF 复用
#elif defined(SOC_HBIRD)
GPIO->IOFCFG |= IOF_UART_MASK;
#endif
}
/* 低层使能 UART 接收中断、FIFO */
static void uart_rx_irq_enable(UART_TypeDef *U) {
/* FCR: bit0 FIFO_EN, bit1 RX_FIFO_RST, bit2 TX_FIFO_RST
0x07 = 使能 FIFO 并清 RX/TX FIFO */
U->FCR = 0x07;
/* IER: bit0 ERBFI(接收数据可用), bit2 ELSI(行状态) */
U->IER |= (1u << 0) | (1u << 2);
}
/* 读取并处理 IIR,按类型清空接收 FIFO;返回是否还有挂起中断 */
static int uart_service_interrupt(UART_TypeDef *U) {
/* IIR bit0 == 0 表示有挂起中断;[3:1] 是中断类型 */
while ( (U->IIR & 0x01u) == 0 ) {
uint32_t iid = (U->IIR >> 1) & 0x07u;
switch (iid) {
case 0x02: /* THRE - 发送保持寄存器空,若需要可填充发送缓冲 */
(void)U->LSR; /* 读一下 LSR,很多实现里这是无害的 */
break;
case 0x03: /* RLS - 接收线路状态,比如帧/奇偶/溢出错误 */
(void)U->LSR; /* 读取 LSR 清除异常标志 */
break;
case 0x06: /* RX 超时(FIFO 中有数据但超时)fallthrough */
case 0x04: /* RDA - 接收数据可用 */
{
/* 把 FIFO 里的字节读完 */
while (U->LSR & 0x01u) { /* LSR bit0: Data Ready */
uint8_t c = (uint8_t)U->RBR;
/* 轻量回显(ISR 内尽量短),生产上建议放环形缓冲 */
uart_write(U, c);
}
break;
}
default:
/* 其它:MODEM 等,按需处理 */
(void)U->IIR;
break;
}
}
/* 到这儿 IIR bit0 为 1(无挂起中断) */
return 0;
}
/* UART0 PLIC 中断服务函数 */
void plic_uart0_handler(void) {
uart_service_interrupt(UART0);
}
/* 板级初始化:Pinmux + UART 初始化 + 开 RX 中断 */
static void board_init(void) {
uart_pinmux_init();
/* 初始化 UART:波特率/8N1 等(假定 uart_init 做好这些) */
uart_init(UART0, UART_BAUDRATE);
/* 开 FIFO、开接收中断(IER) */
uart_rx_irq_enable(UART0);
uart_puts(UART0, "UART Interrupt Test (115200 8N1)\r\n");
uart_puts(UART0, "Type something to see echo...\r\n");
}
void run_nomal_mode(SPI_TypeDef *spi, UART_TypeDef *uart)
{
/* 初始化板级(仅串口) */
board_init();
/* 注册 UART0 的 PLIC 中断,优先级 1(可按需调整) */
int32_t rc = PLIC_Register_IRQ(PLIC_UART0_IRQn, 1, plic_uart0_handler);
if (rc != 0) {
//printf("UART0 interrupt register failed!\r\n");
uart_puts(UART0, "UART0 interrupt register failed!\r\n");
while (1) { }
}
/* 开全局中断 */
__enable_irq();
/* 主循环空转(中断处理收发) */
while (1) {
/* 可在此做其它任务;尽量不要在 ISR 里做重活 */
// delay_1ms(10);
}
}
而当用下列代码时,会卡死在uart_write(UART0, c),
#define UART_BAUDRATE 115200
static volatile uint8_t uart_rx_flag = 0; // ISR置位,主循环读取后清零
/* 可选:把 UART 引脚复用到 IOF(按你板卡选择 GPIOA 或 GPIO) */
static void uart_pinmux_init(void) {
#if defined(SOC_HBIRDV2)
/* HBirdv2: UART 通常走 GPIOA 的 IOF */
GPIOA->IOFCFG |= IOF_UART_MASK; // 使能 UART RX/TX 的 IOF 复用
#elif defined(SOC_HBIRD)
/* 老 HBird: 如果有 GPIO->IOFCFG 则用之;没有就忽略 */
GPIO->IOFCFG |= IOF_UART_MASK;
#endif
}
/* 低层使能 UART 接收中断、FIFO */
static void uart_rx_irq_enable(UART_TypeDef *U) {
/* FCR: bit0 FIFO_EN, bit1 RX_FIFO_RST, bit2 TX_FIFO_RST
0x07 = 使能 FIFO 并清 RX/TX FIFO */
U->FCR = 0x07;
/* IER: bit0 ERBFI(接收数据可用), bit2 ELSI(行状态) */
U->IER |= (1u << 0) | (1u << 2);
}
/* 读取并处理 IIR,按类型清空接收 FIFO;返回是否还有挂起中断 */
static int uart_service_interrupt(UART_TypeDef *U) {
/* IIR bit0 == 0 表示有挂起中断;[3:1] 是中断类型 */
while ( (U->IIR & 0x01u) == 0 ) {
uint32_t iid = (U->IIR >> 1) & 0x07u;
switch (iid) {
case 0x02: /* THRE - 发送保持寄存器空,若需要可填充发送缓冲 */
(void)U->LSR; /* 读一下 LSR,很多实现里这是无害的 */
break;
case 0x03: /* RLS - 接收线路状态,比如帧/奇偶/溢出错误 */
(void)U->LSR; /* 读取 LSR 清除异常标志 */
break;
case 0x06: /* RX 超时(FIFO 中有数据但超时)fallthrough */
case 0x04: /* RDA - 接收数据可用 */
{ uart_rx_flag = 1; // 通知主循环
U->IER &= ~(1u << 0); // ★ 关闭 ERBFI(接收可用中断),防止中断风暴
return 0; // ★ 立即退出 ISR,把处理权交给主循环
/*
while (U->LSR & 0x01u) {
uint8_t c = (uint8_t)U->RBR;
uart_rx_flag =1;
uart_write(U, c);
printf("123uart_rx_flag=%d",uart_rx_flag);
}
break;*/
}
default:
/* 其它:MODEM 等,按需处理 */
(void)U->IIR;
break;
}
}
/* 到这儿 IIR bit0 为 1(无挂起中断) */
return 0;
}
/* UART0 PLIC 中断服务函数 */
void plic_uart0_handler(void) {
uart_service_interrupt(UART0);
}
/* 板级初始化:Pinmux + UART 初始化 + 开 RX 中断 */
static void board_init(void) {
uart_pinmux_init();
/* 初始化 UART:波特率/8N1 等(假定 uart_init 做好这些) */
uart_init(UART0, UART_BAUDRATE);
/* 开 FIFO、开接收中断(IER) */
uart_rx_irq_enable(UART0);
uart_puts(UART0, "UART Interrupt Test (115200 8N1)\r\n");
uart_puts(UART0, "Type something to see echo...\r\n");
}
int main(void)
{
/* 初始化板级(仅串口) */
board_init();
uart_rx_flag =0;
uint8_t test = 0;
uint8_t c;
uint8_t test2;
uint8_t test3;
/* 注册 UART0 的 PLIC 中断,优先级 1(可按需调整) */
int32_t rc = PLIC_Register_IRQ(PLIC_UART0_IRQn, 1, plic_uart0_handler);
if (rc != 0) {
//printf("UART0 interrupt register failed!\r\n");
uart_puts(UART0, "UART0 interrupt register failed!\r\n");
while (1) { }
}
/* 开全局中断 */
__enable_irq();
/* 主循环空转(中断处理收发) */
while (1) {
test = uart_rx_flag;
if (uart_rx_flag==1) {
uart_rx_flag = 0;
/* 把这波 FIFO 数据全部读掉(直到 LSR.DR=0) */
while (UART0->LSR & 0x01u) {
test2 = UART0->LSR & 0x01u;
c = (uint8_t)UART0->RBR;
//uart_puts(UART0, "IRQ RX\r\n"); // 用 uart_puts,别用 printf
}
uart_write(UART0, c); // 回显或存入你的缓冲
//printf("frame_result_tccccc=%d",c);
//uart_puts(UART0, "IRQ RX\r\n"); // 用 uart_puts,别用 printf
/* ★ 关键:读完再开 ERBFI,允许下一次中断 */
UART0->IER |= (1u << 0);
}
//uart_puts(UART0, "IRQ RX\r\n"); // 用 uart_puts,别用 printf
delay_1ms(1000);
}
}
两个代码区别在于,一个发送数据在中断服务函数中完成,一个是在while中完成,在while中完成的就存在卡死的现象。跪求大佬指导!