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

MicroBlaze中断处理程序未触发:PS/2鼠标数据包捕获求助

PS/2鼠标中断未触发问题排查

问题背景

在嵌入式系统中需捕获PS/2模式初始化的鼠标移动数据包,但中断处理程序始终未被触发。已配置处理器启用外部中断,仅将一个信号连接至处理器的中断输入端口,未使用中断控制器,采用软件循环缓冲区来捕获输入移动。

相关代码

C++ PS/2核心类实现

#include "xparameters.h"
#include "xil_exception.h"
#include "ps2_core.h"

Ps2Core::Ps2Core(uint32_t core_base_addr) {
   base_addr = core_base_addr;
   registerCallback();
}

Ps2Core::~Ps2Core() {
}

void Ps2Core::enqueue(unsigned char value) {
    if ((tail + 1) % QUEUE_SIZE == head) {
    // queue is full, do nothing
    return;
    }
    queue[tail] = value;
    queueCount++;
    tail = (tail + 1) % QUEUE_SIZE;
}

unsigned char Ps2Core::dequeue(void) {
    if (head == tail) {
    // queue is empty, do nothing
    return 0;
    }
    unsigned char value = queue[head];
    queueCount--;
    head = (head + 1) % QUEUE_SIZE;
    return value;
}

void Ps2Core::handleInterrupt(Ps2Core *ps2) {
    uint8_t byte;
    byte = ps2->rx_byte();
    ps2->enqueue(byte);
}


void Ps2Core::registerCallback(){
    Xil_ExceptionInit();
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
                                    (Xil_ExceptionHandler)handleInterrupt,
                                    this);
    Xil_ExceptionEnable();
}

int Ps2Core::get_mouse_activity(int *lbtn, int *rbtn, int *xmov,
      int *ymov, int *zmov) {
   uint8_t b1, b2, b3, b4;

   uint32_t tmp;

   /* retrieve bytes only if 4 or a multiple of 4 exist in queue */
   if (queueCount >= 4) {
       b1 = dequeue();
       b2 = dequeue();
       b3 = dequeue();
       b4 = dequeue();
   }
   else
       return (0);
   /* extract button info */
   *lbtn = (int) (b1 & 0x01);      // extract bit 0
   *rbtn = (int) (b1 & 0x02) >> 1; // extract bit 1
   /* extract x movement; manually convert 9-bit 2's comp to int */
   tmp = (uint32_t) b2;
   if (b1 & 0x10)                // check MSB (sign bit) of x movement
      tmp = tmp | 0xffffff00;    // manual sign-extension if negative
   *xmov = (int) tmp;            // data conversion
   /* extract y movement; manually convert 9-bit 2's comp to int */
   tmp = (uint32_t) b3;
   if (b1 & 0x20)                // check MSB (sign bit) of y movement
      tmp = tmp | 0xffffff00;    // manual sign-extension if negative
   *ymov = (int) tmp;            // data conversion
   tmp = (uint32_t) b4;
   if (b4 & 0x08)               // check MSB (sign bit) of z movement
      tmp = tmp | 0xfffffff0;   // manual sign-extension if negative
   *zmov = (int) tmp;           // data conversion
   /* success */
   return (1);
}

Verilog模块实例

//instantiate uBlaze MCS
cpu cpu_unit (
    .Clk(clk_100M),                          
    .Reset(reset),            
    .IO_addr_strobe(io_addr_strobe),    
    .IO_address(io_address),            
    .IO_byte_enable(io_byte_enable),    
    .IO_read_data(io_read_data),        
    .IO_read_strobe(io_read_strobe),    
    .IO_ready(io_ready),                
    .IO_write_data(io_write_data),      
    .IO_write_strobe(io_write_strobe),
    .INTC_Interrupt(interrupt)
);
    

// instantiated i/o subsystem
mmio_sys_sampler_arty_a7  mmio_unit (
    .clk(clk_100M),
    .reset(reset),
    .mmio_cs(fp_mmio_cs),
    .mmio_wr(fp_wr),
    .mmio_rd(fp_rd),
    .mmio_addr(fp_addr), 
    .mmio_wr_data(fp_wr_data),
    .mmio_rd_data(fp_rd_data),
    .rx_done_tick(interrupt),
    .ps2d_in(ps2d_in),
    .ps2c_in(ps2c_in),
    .tri_c(tri_c),
    .tri_d(tri_d),
    .ps2c_out(ps2c_out),
    .ps2d_out(ps2d_out),          
    .rx(rx),
    .tx(tx)
);   

关键排查点与修复建议

  • 中断触发配置匹配:确认rx_done_tick的有效电平/边沿与uBlaze外部中断的触发设置一致。比如uBlaze默认外部中断为高电平触发,若rx_done_tick是上升沿脉冲,需修改处理器中断配置为边沿触发。
  • 处理器中断使能:除了调用Xil_ExceptionEnable(),需通过指令手动使能uBlaze的外部中断:
    // 启用uBlaze外部中断
    mtspr(SPR_MSR, mfspr(SPR_MSR) | MSR_EE);
    
  • 中断信号同步:在Verilog的mmio_sys_sampler_arty_a7模块中,对rx_done_tick添加两级同步寄存器,避免亚稳态:
    reg [1:0] rx_done_sync;
    always @(posedge clk or posedge reset) begin
        if(reset) begin
            rx_done_sync <= 2'b00;
        end else begin
            rx_done_sync <= {rx_done_sync[0], rx_done_tick_raw};
        end
    end
    assign interrupt = rx_done_sync[1];
    
  • 回调函数签名修正:调整中断回调函数的签名以匹配Xilinx异常框架要求,避免参数传递错误:
    static void handleInterrupt(void *data) {
        Ps2Core *ps2 = static_cast<Ps2Core*>(data);
        uint8_t byte = ps2->rx_byte();
        ps2->enqueue(byte);
    }
    
  • 验证PS/2模块信号:使用FPGA内部逻辑分析仪(ILA)观测rx_done_tick、ps2d_in、ps2c_in信号,确认鼠标移动时rx_done_tick是否产生有效脉冲,排查PS/2模块本身的数据包解析问题。
  • 并发访问保护:在中断回调和get_mouse_activity函数中,对循环缓冲区的操作添加中断禁用/启用保护,避免数据竞争:
    void Ps2Core::enqueue(unsigned char value) {
        Xil_ExceptionDisable();
        if ((tail + 1) % QUEUE_SIZE != head) {
            queue[tail] = value;
            queueCount++;
            tail = (tail + 1) % QUEUE_SIZE;
        }
        Xil_ExceptionEnable();
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 12:25:14