You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ZYNQ-7000 UART接收PC数据时未触发中断问题求助

ZYNQ-7000 UART中断模式回传功能故障排查

发送通路可正常打印初始化信息,说明UART引脚配置、发送逻辑、波特率配置基本正常,中断完全不触发按以下优先级排查修复:

一、核心代码错误(90%概率为该类问题)

1. 未显式使能UART接收通路、未复位FIFO

XUartPs_CfgInitialize执行完成后,UART控制寄存器默认将RX通路禁用(RX_DIS位默认置1),XUartPs_SetOperMode仅修改工作模式位,不会自动打开RX通路,RX FIFO不会接收引脚数据,自然不会产生任何接收中断。
在UartInit函数的XUartPs_SetRecvTimeout调用前,添加如下配置:

// 读取当前控制寄存器值
u32 cr_reg = XUartPs_ReadReg(uart_ps->Config.BaseAddress, XUARTPS_CR_OFFSET);
// 清除TX_DIS、RX_DIS位,使能收发通路
cr_reg &= ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS);
// 触发TX/RX FIFO复位
cr_reg |= XUARTPS_CR_TXRST | XUARTPS_CR_RXRST;
XUartPs_WriteReg(uart_ps->Config.BaseAddress, XUARTPS_CR_OFFSET, cr_reg);
// 等待FIFO复位完成
while (XUartPs_ReadReg(uart_ps->Config.BaseAddress, XUARTPS_CR_OFFSET) & (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST));

2. 中断初始化顺序错误、未清除上电默认挂起的中断标志

当前中断初始化顺序存在时序问题,且未清除UART模块上电时默认挂起的中断状态位,容易导致中断锁死。将UartIntrInit调整为如下逻辑:

int UartIntrInit(XScuGic *intc, XUartPs *uart_ps){
    int status;
    XScuGic_Config *intc_cfg;

    intc_cfg = XScuGic_LookupConfig(INTC_DEVICE_ID);
    if(NULL == intc_cfg) return XST_FAILURE;

    status = XScuGic_CfgInitialize(intc, intc_cfg, intc_cfg->CpuBaseAddress);
    if(status != XST_SUCCESS) return XST_FAILURE;

    // 注册CPU全局IRQ处理函数
    Xil_ExceptionInit();
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
        (Xil_ExceptionHandler) XScuGic_InterruptHandler, (void *) intc);

    // 绑定UART中断处理函数
    XScuGic_Connect(intc, UART_INT_IRQ_ID, (Xil_ExceptionHandler) Handler, (void *) uart_ps);

    // 先清除UART所有挂起的中断标志:写1清零
    XUartPs_WriteReg(uart_ps->Config.BaseAddress, XUARTPS_ISR_OFFSET, 0xFFFFFFFF);

    // 使能需要的UART中断
    XUartPs_SetInterruptMask(uart_ps, XUARTPS_IXR_RXOVR | XUARTPS_IXR_TOUT);

    // 先使能GIC层面的UART中断
    XScuGic_Enable(intc, UART_INT_IRQ_ID);
    // 最后打开CPU全局中断开关
    Xil_ExceptionEnable();

    return XST_SUCCESS;
}

3. 中断处理函数逻辑问题

当前中断处理函数存在三个会导致功能异常的问题:

  • 中断上下文调用xil_printf这类阻塞轮询发送函数,极易触发死锁,调试阶段建议用计数器标记中断触发,不要直接打印
  • 用else if判断中断位,多个中断同时挂起时会漏处理,改为逐个判断
  • 读中断状态顺序错误,先读ISR再和IMR做与操作,避免时序问题
  • 回传数据时优先使用传入的UART实例指针,不要直接用全局变量
    修正后的中断处理函数参考:
// 调试用计数器,观察是否进入中断
volatile u32 intr_trigger_cnt = 0;
void Handler(void *call_back_ref){
    intr_trigger_cnt++;
    XUartPs *uart_instance_ptr = (XUartPs *) call_back_ref;
    u32 ReceivedCount = 0;
    u32 IsrValue;

    // 先读中断状态,再和中断屏蔽位与
    IsrValue = XUartPs_ReadReg(uart_instance_ptr->Config.BaseAddress, XUARTPS_ISR_OFFSET);
    IsrValue &= XUartPs_ReadReg(uart_instance_ptr->Config.BaseAddress, XUARTPS_IMR_OFFSET);

    // 接收FIFO达到阈值触发
    if( IsrValue & XUARTPS_IXR_RXOVR ){
        // 清除中断标志
        XUartPs_WriteReg(uart_instance_ptr->Config.BaseAddress, XUARTPS_ISR_OFFSET, XUARTPS_IXR_RXOVR);
        ReceivedCount = XUartPs_Recv(uart_instance_ptr, ReceivedBuffer + ReceivedByteNum, MAX_LEN - ReceivedByteNum);
        ReceivedByteNum += ReceivedCount;
    }
    // 接收超时触发(FIFO非空且一段时间无新数据),不要用else if
    if( IsrValue & XUARTPS_IXR_TOUT ){
        XUartPs_WriteReg(uart_instance_ptr->Config.BaseAddress, XUARTPS_ISR_OFFSET, XUARTPS_IXR_TOUT);
        ReceivedCount = XUartPs_Recv(uart_instance_ptr, ReceivedBuffer + ReceivedByteNum, MAX_LEN - ReceivedByteNum);
        ReceivedByteNum += ReceivedCount;

        // 回传数据,小数据量可在中断里处理,大数据量建议放主循环
        for(u32 sendByte=0;sendByte<ReceivedByteNum;sendByte++){
            XUartPs_SendByte(uart_instance_ptr->Config.BaseAddress, ReceivedBuffer[sendByte]);
        }
        ReceivedByteNum = 0;
    }
}

二、配置逻辑问题

当前设置的RX FIFO触发阈值为32字节,XUARTPS_IXR_RXOVR中断仅当FIFO内数据量≥32字节时才会触发,单次输入字符少于32时完全依赖超时中断触发,可先将阈值改小(比如1字节)做验证:

XUartPs_SetFifoThreshold(uart_ps, 1);

确认中断可正常进入后再调整阈值到合适值。

三、硬件排查点

如果代码修改后仍无法进入中断,按以下步骤验证硬件通路:

  1. 先屏蔽中断初始化代码,在主循环加轮询收发测试,确认RX硬件通路正常:
while (1) {
    if(XUartPs_IsReceiveData(Uart_Ps.Config.BaseAddress)){
        u8 recv = XUartPs_RecvByte(Uart_Ps.Config.BaseAddress);
        XUartPs_SendByte(Uart_Ps.Config.BaseAddress, recv);
    }
}

如果轮询模式下也收不到数据,检查:

  • 串口线交叉连接是否正确:ZYNQ MIO48(UART1 TX)接USB转串口RX,MIO49(UART1 RX)接USB转串口TX,共地
  • 串口终端关闭RTS/CTS硬件流控,波特率设置为115200、8位数据位、1位停止位、无校验
  • 确认Vivado工程中MIO48/49的配置正确,没有被其他外设复用

内容的提问来源于stack exchange,提问作者Jie Han

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 22:09:39