完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
电子发烧友论坛|
当用下列代码运行时,串口中断可以正常触发,回环数据接受正常。
#define UART_BAUDRATE 115200static 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)rn"); uart_puts(UART0, "Type something to see echo...rn");}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!rn"); uart_puts(UART0, "UART0 interrupt register failed!rn"); while (1) { } } /* 开全局中断 */ __enable_irq(); /* 主循环空转(中断处理收发) */ while (1) { /* 可在此做其它任务;尽量不要在 ISR 里做重活 */ // delay_1ms(10); }}而当用下列代码时,会卡死在uart_write(UART0, c), #define UART_BAUDRATE 115200static 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)rn"); uart_puts(UART0, "Type something to see echo...rn");}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!rn"); uart_puts(UART0, "UART0 interrupt register failed!rn"); 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 RXrn"); // 用 uart_puts,别用 printf } uart_write(UART0, c); // 回显或存入你的缓冲 //printf("frame_result_tccccc=%d",c); //uart_puts(UART0, "IRQ RXrn"); // 用 uart_puts,别用 printf /* ★ 关键:读完再开 ERBFI,允许下一次中断 */ UART0->IER |= (1u << 0); } //uart_puts(UART0, "IRQ RXrn"); // 用 uart_puts,别用 printf delay_1ms(1000); }}两个代码区别在于,一个发送数据在中断服务函数中完成,一个是在while中完成,在while中完成的就存在卡死的现象。跪求大佬指导! |
|
相关推荐
1个回答
|
|
|
要解决串口中断触发卡死的问题,需重点检查中断处理逻辑和硬件配置。以下是关键步骤和解决方案: 1. 检查中断标志清除问题原因:最常见原因是未正确清除中断标志,导致中断持续触发,程序卡死在ISR中。 注意:不同芯片清除方式不同,需查阅手册确认是读取数据自动清除还是手动写寄存器清除。 2. 避免阻塞操作问题原因:在ISR中执行耗时操作(如
3. 检查中断优先级问题原因:高优先级中断抢占导致逻辑错误。
4. 验证硬件连接与配置排查步骤:
5. 完整配置示例6. 调试建议
通过以上步骤,可系统性解决中断卡死问题。重点确保中断标志正确清除和ISR非阻塞设计。 |
|
|
|
|
只有小组成员才能发言,加入小组>>
在软件SDK中选择不同的下载模式时,是哪个部件更改了QSPI0中寄存器的值?
656 浏览 2 评论
cmt_instret_ena的使能为什么要排除branch等指令造成流水线冲刷的情况?
830 浏览 1 评论
e203 rom启动仅仅是引导到itcm执行指令吗?flash启动就是加载指令到itcm中吗?
956 浏览 1 评论
/9
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-12-1 18:02 , Processed in 0.629144 second(s), Total 43, Slave 36 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191

淘帖
1356
