转自http://blog.163.com/gcs_gcs/blog/static/17448606620121193113914/
在最近的工程中,需要用到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 =
InterruptEND
BEGIN xps_uartlite . .
. PORT Interrupt =
RS232_Uart_1_InterruptEND
BEGIN
xps_intc . . . PORT Irq =
Interrupt PORT
Intr =
RS232_Uart_1_Interrupt&plb_ps2_controller_0_IP2INTC_IrptEND
BEGIN
plb_ps2_controller . . . PORT IP2INTC_Irpt =
plb_ps2_controller_0_IP2INTC_IrptPORT mouse_clk =
plb_ps2_controller_0_mouse_clk PORT mouse_data =
plb_ps2_controller_0_mouse_data PORT key_clk =
plb_ps2_controller_0_key_clk PORT key_data =
plb_ps2_controller_0_key_data END
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语言编程实例
#include
#include #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_ID int init_input(void); XStatus SetUpInterruptSystem(XIntc
*XIntcInstancePtr); static XIntc InterruptController;
void PS2_InterruptHandler(void
*CallbackRef) { u32
mouse_state, keybd_state, flags; Xuint32
baseaddr = (Xuint32)
XPAR_PLB_PS2_CONTROLLER_0_BASEADDR; 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) handle_mouse_event(mouse_state); if (flags
& EVENT_FROM_KEYBD) handle_keybd_event(keybd_state); 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; 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); 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; }
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;}
Status =
XIntc_Start(XIntcInstancePtr,
XIN_REAL_MODE); if (Status
!= XST_SUCCESS) { return XST_FAILURE; } XIntc_Enable(XIntcInstancePtr,
XPAR_XPS_INTC_0_PLB_PS2_CONTROLLER_0_IP2INTC_IRPT_INTR); microblaze_enable_interrupts(); return
XST_SUCCESS; }
int
main(void){ init_input(); while(1); return
1; }
汇编代码详解使用mb-objdump工具对实例进行了反汇编,想看看到底是个什么情况 Disassembly of
section .vectors.reset: 00000000 <_start>: 0: b0009000 imm -28672 4: b8080000 brai 0 #main()程序起始地址是0x90000000
Disassembly of section
.vectors.sw_exception: 00000008 <_vector_sw_exception>: 8: b0009000 imm -28672 c: b8080438 brai 1080
Disassembly of section
.vectors.interrupt: 00000010 <_vector_interrupt>: 10: b0009000 imm -28672 14: b8080474 brai 1140 #中断处理程序起始地址是0x90000474
Disassembly of section
.vectors.hw_exception: 00000020 <_vector_hw_exception>: 20: b0009000 imm -28672 24: b8080450 brai 1104
90000474
<__interrupt_handler>: #中断处理程序起始地址和汇编代码 90000474: 3021ffb0 addik r1, r1,
-80 90000478: f9e10000 swi r15, r1,
0 9000047c: f8610020 swi r3, r1,
32 90000480: f8810024 swi r4, r1,
36 90000484: f8a10028 swi r5, r1,
40 90000488: f8c1002c swi r6, r1,
44 9000048c: f8e10030 swi r7, r1,
48 90000490: f9010034 swi r8, r1,
52 90000494: f9210038 swi r9, r1,
56 90000498: f941003c swi r10, r1,
60 9000049c: f9610040 swi r11, r1,
64 900004a0: f9810044 swi r12, r1,
68 900004a4: fa210048 swi r17, r1, 72
总结 主要描述了MicroBlaze的中断的基本原理,以及编程。
参考文献:
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/201093.html原文链接:https://javaforall.cn