首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

MicroBlaze中断编程——以PS/2键盘输入为例 

MicroBlaze中断编程——以PS/2键盘输入为例 

在最近的工程中,需要用到PS/2键盘和鼠标作为控制输入,所以在网上找了一些相关的资料,内容很丰富,看来已经有很多人做过了这方面的编程。本篇Blog算是实践总结,为以后的开发积累一些基础知识。MicroBlaze支持重启(reset),中断( interrupt), 暂停(break)和异常( exception)。这里粗略的介绍:
  • reset当 外部按键发出reset信号或者XMD通过MDM(MicroBlaze Debug module)发出reset信号,这些信号都会被proc_sys_reset模块接收,然后该模块产生一个16周期长的高电平信号至 MicroBlaze的MB_RESET管脚。MicroBlaze响应reset, PC 寄存器指向0x0地址,依照向量表中代码执行。
  • exception异常是MicroBlaze对内部运行发生错误的情况发做出的响应,这些情况包括:非法指令,指令和数据总线错误和未对齐的访问(unaligned access)。如除0操作,非法操作码异常,数据总线异常等。
  • breakbreak 分为software break和hardware break。hardware break,这时MDM模块的输出端口Ext_BRK和Ext_NM_BRK跟MicroBlaze对应的输入端口相连。一旦break响应,暂停返回地 址(break return address)自动装入R16寄存器中。而software break通过brk和brki指令来完成。
  • interruptMicroBlaze 只支持一个外部中断源(连接于Interrupt 端口),所以需要多个中断输入的话,就得添加中断控制器(xps_intc)了。只有当机器状态寄存器(Machine Status Register,MSR)中的中断使能位(interrupt enable)置'1',MicroBlaze才能响应中断。MicroBlaze响应中断,PC指向中断向量(地址:0x10),R14存储了中断返回 地址。

注:具体细节问题,请见参考1。注:该表格来自于MicroBlaze参考手册,见参考1下面具体介绍如何对MicroBlaze进行中断编程。
  • 中断信号的物理连接system.mhs文件定义了物理硬件的相关信息,包括总线架构、外围设备、处理器、系统内部信号互连和地址空间等。所以这里就通过MHS定义文件给出关于中断信号互连的信息。当然MicroBlaze的中断输入,可以配置成电平触发或者边沿触发,在配置MicroBlaze的GUI或者在MicroBlaze.mpd中通过设置 C_INTERRUPT_IS_EDGE ,C_EDGE_IS_POSITIVE来完成对中断的触发的配置。BEGIN microblaze  . . .   PORT MB_RESET = mb_reset PORT Interrupt = InterruptENDBEGIN xps_uartlite. . .   PORT Interrupt = RS232_Uart_1_InterruptENDBEGIN xps_intc. . . PORT Irq = Interrupt PORT Intr = RS232_Uart_1_Interrupt&plb_ps2_controller_0_IP2INTC_IrptENDBEGIN plb_ps2_controller. . . PORT IP2INTC_Irpt = plb_ps2_controller_0_IP2INTC_IrptPORT mouse_clk = plb_ps2_controller_0_mouse_clkPORT mouse_data = plb_ps2_controller_0_mouse_dataPORT key_clk = plb_ps2_controller_0_key_clkPORT key_data = plb_ps2_controller_0_key_dataEND
  • EDK提供的驱动以及相关函数的介绍void microblaze_enable_interrupts(void)该函数使MicroBlaze可以响应中断,即MSR中的“interrupt enable”位置’1’;void microblaze_disable_interrupts(void)该函数使MicroBlaze不能响应中断,即MSR中的“interrupt enable”位置 ’0’;这几个函数都定义包含在$EDK_project/microblaze_0/include/mb_interface.h头文件中XIntc_Initialize(&InterruptController, (Xuint16)INTC_DEVICE_ID);该函数用于初始化中断控制器,主要包括初始化XIntc的结构体,初始化向量列表,以及所有中断源输入禁用,中断输出禁用。int XIntc_Connect(XIntc * InstancePtr, u8 Id,    XInterruptHandler Handler, void *CallBackRef)中断源的标示和相关中断处理程序的连接。XIntc_Start(XIntcInstancePtr, XIN_REAL_MODE);该函数使得中断控制器输出的中断信号启用。XIN_REAL_MODE 意思是只允许硬件中断(hardware interrupt)void XIntc_Enable(XIntc * InstancePtr, u8 Id)该函数使得对应ID的中断源输入启用这几个函数定义在$EDK_project/microblaze_0/libsrc/intc_v1_11_a/src/xintc.c需要包含的头文件:xintc.h
  • C语言编程实例/**Date      2010-12-27*author    Qi Yao*decription main function code for interrupt program*           such as timer or keyboard and mouse interrupt.*//* FPGA includes */#include      /* for printf */#include     /* for usleep */#include "xparameters.h"#include "xutil.h"#include "xintc.h"#include "plb_ps2_controller.h"#include "mb_interface.h"#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_IDint init_input(void);XStatus SetUpInterruptSystem(XIntc *XIntcInstancePtr);static XIntc InterruptController;/*Instance of the Interrupt Control*//*** Input interrupt handler*/void PS2_InterruptHandler(void *CallbackRef){    u32 mouse_state, keybd_state, flags;    Xuint32 baseaddr = (Xuint32) XPAR_PLB_PS2_CONTROLLER_0_BASEADDR;    /* read information from device registers */    keybd_state = ((u32 *)baseaddr)[0];    mouse_state = ((u32 *)baseaddr)[1];    flags       = PLB_PS2_CONTROLLER_mReadReg(baseaddr, PLB_PS2_CONTROLLER_INTR_IPISR_OFFSET);    if (flags & EVENT_FROM_MOUSE)        /*mouse event handler*/        handle_mouse_event(mouse_state);    if (flags & EVENT_FROM_KEYBD)        /*keyboard event handler*/        handle_keybd_event(keybd_state);    /* clear interrupt flags in PS/2 controller */    PLB_PS2_CONTROLLER_mWriteReg(baseaddr, PLB_PS2_CONTROLLER_INTR_IPISR_OFFSET, flags);}XStatus init_input(void){    XStatus Status;    Xuint32 baseaddr = (Xuint32) XPAR_PLB_PS2_CONTROLLER_0_BASEADDR;    /* initialize PS/2 interrupts */    PLB_PS2_CONTROLLER_mWriteReg(baseaddr, PLB_PS2_CONTROLLER_INTR_DIER_OFFSET, 0);    PLB_PS2_CONTROLLER_mWriteReg(baseaddr, PLB_PS2_CONTROLLER_INTR_DGIER_OFFSET, 0xFFFFFFFF);    PLB_PS2_CONTROLLER_mWriteReg(baseaddr, PLB_PS2_CONTROLLER_INTR_IPIER_OFFSET, 0xFFFFFFFF);    PLB_PS2_CONTROLLER_mWriteReg(baseaddr, PLB_PS2_CONTROLLER_INTR_IPISR_OFFSET, 0);    /* initialize Interrupt controller */    Status = XIntc_Initialize(&InterruptController, (Xuint16)INTC_DEVICE_ID);    if (Status != XST_SUCCESS)    {        return XST_FAILURE;    }    Status = XIntc_SelfTest(&InterruptController);    if (Status != XST_SUCCESS)    {    return XST_FAILURE;    }    /*     * Connect a device driver handler that will be called when an interrupt     * for the device occurs, the device driver handler performs the specific     * interrupt processing for the device     */    Status = XIntc_Connect(XIntcInstancePtr, XPAR_XPS_INTC_0_PLB_PS2_CONTROLLER_0_IP2INTC_IRPT_INTR,                           (XInterruptHandler)PS2_InterruptHandler,                           (void *)0);    if (Status != XST_SUCCESS)    {        return XST_FAILURE;}    /*     * Start the interrupt controller such that interrupts are enabled for     * all devices that cause interrupts, specify simulation mode so that     * an interrupt can be caused by software rather than a real hardware     * interrupt     */    Status = XIntc_Start(XIntcInstancePtr, XIN_REAL_MODE);    if (Status != XST_SUCCESS)    {        return XST_FAILURE;    }    /*     * Enable the interrupt for the device and then cause (simulate) an     * interrupt so the handlers will be called     */    XIntc_Enable(XIntcInstancePtr, XPAR_XPS_INTC_0_PLB_PS2_CONTROLLER_0_IP2INTC_IRPT_INTR);    /*     * Enable the Interrupts for the MicroBlaze Processor     */    microblaze_enable_interrupts();    return XST_SUCCESS;}int main(void){    /*Initialization*/    init_input();    /*wait for interrupt*/    while(1);   return 1;}
  • 汇编代码详解使用mb-objdump工具对实例进行了反汇编,想看看到底是个什么情况Disassembly of section .vectors.reset:00000000 <_start>:   0:    b0009000     imm    -28672   4:    b8080000     brai    0                                   #main()程序起始地址是0x90000000Disassembly of section .vectors.sw_exception:00000008 <_vector_sw_exception>:   8:    b0009000     imm    -28672   c:    b8080438     brai    1080Disassembly of section .vectors.interrupt:00000010 <_vector_interrupt>:  10:    b0009000     imm    -28672  14:    b8080474     brai    1140                         #中断处理程序起始地址是0x90000474Disassembly of section .vectors.hw_exception:00000020 <_vector_hw_exception>:  20:    b0009000     imm    -28672  24:    b8080450     brai    110490000474 <__interrupt_handler>:                 #中断处理程序起始地址和汇编代码90000474: 3021ffb0  addik r1, r1, -8090000478: f9e10000  swi r15, r1, 09000047c: f8610020  swi r3, r1, 3290000480: f8810024  swi r4, r1, 3690000484: f8a10028  swi r5, r1, 4090000488: f8c1002c  swi r6, r1, 449000048c: f8e10030  swi r7, r1, 4890000490: f9010034  swi r8, r1, 5290000494: f9210038  swi r9, r1, 5690000498: f941003c  swi r10, r1, 609000049c: f9610040  swi r11, r1, 64900004a0: f9810044  swi r12, r1, 68900004a4: fa210048  swi r17, r1, 72
  • 总结主要描述了MicroBlaze的中断的基本原理,以及编程。

参考文献:

来源:KiKi的博客
记录学习中的点点滴滴,让每一天过的更加有意义!
返回列表