版主: 51FPGA

分享到:
共1条 1/1 1   

蜻蜓点水之Microblaze-Custom-PLBIP及中断

    [您是本帖的第1238位阅读者]
xilinx论坛
我是MM
高级会员

最后登陆时间:2015-03-19 10:58:07

直达楼层
1# 发表于 2015-03-30 22:00:00

本实验完成了使用Microblaze-Custom-IP实现INTEL 8255A芯片的端口A模式2的功能。

输入功能:没有数据输入时LD0亮,输入数据按右下方BTNULD0,船形开关SW0-3数据读入T8255IP读寄存器。随后T8255IPCPU发出中断请求,CPU响应中断并在3秒后读取读寄存器并解除中断,此时LD0重新点亮。
输出功能:有数据输出时,数据先到输出寄存器,此时数据时LD1亮,按右下方BTNL,寄存器数据输出LED4-7,此时LD1灭、并向CPU发出中断请求,CPU响应中断后清空中断请求(本实验数据在输入数据请求按下后即将数据输出,且仅输入输入4bit数据)

这里首先介绍一下Microblaze的中断系统及软件操作,Microblaze内核支持外部中断响应,但仅支持一个外部中断,其中断入口地址为0x10PC指针保存在R14寄存器内,中断控制位为MSRIEbit(详细介绍请看附件中PDF手册)
单中断操作比较简单,仅需用

  1. void myISR( ) __attribute__ ((interrupt_handler));

复制代码

函数声明即可,然后添加用户代码即可

  1. void myISR( void ) 
  2. }

复制代码


未使用函数声明的编译代码

  1. void myISR( void ); 
  2.  
  3. void myISR( void ) 
  4.  
  5. Compiles to: 
  6.  
  7. myISR: 
  8.   .frame r1,0,r15    # vars= 0, regs= 0, args= 0 
  9.   .mask  0x00000000 
  10. $LM2: 
  11.   .stabn  68,0,55,$LM2-myISR 
  12.   rtsd  r15,8  
  13.   nop    # Unfilled delay slot 
  14.  
  15.   .end  myISR

复制代码


使用函数声明编译后的代码

  1. void myISR( void ) __attribute__ ((interrupt_handler)); 
  2.  
  3. void myISR( void ) 
  4.  
  5. myISR: 
  6. _interrupt_handler: 
  7. .frame r1,20,r15 # vars= 0, regs= 3, args= 0 
  8. .mask 0x00060800 
  9. addik r1,r1,-20 
  10. swi r15,r1,0 
  11. swi r11,r1,8 
  12. swi r17,r1,12 
  13. mfs r11,rmsr #mfs 
  14. swi r18,r1,16 
  15. swi r11,r1,4 
  16. $LM2: 
  17. .stabn 68,0,55,$LM2-myISR 
  18. lwi r15,r1,0 
  19. lwi r11,r1,4 
  20. mts rmsr,r11 #mts 
  21. lwi r11,r1,8 
  22. lwi r17,r1,12 
  23. lwi r18,r1,16 
  24. rtid r14,0 
  25.  
  26. addik r1,r1,20 
  27.  
  28. .end _interrupt_handler

复制代码

多中断则需要用到int_ctrl控制器,入下图所示,这个控制器管理所有外部中断,将多个外部中断合为一个,中断响应后通过判断此控制器内部寄存器以判断是哪个中断,下面是没有用到库函数时是例程

  1. // ISR Code**************************************************************** 
  2. #define   TIMER_INT  XPAR_TIMER_INTERRUPT_MASK 
  3. #define   BTN_INT  XPAR_BUTTONS_IP2INTC_IRPT_MASK 
  4. #define   SPI_INT  XPAR_SPI_IP2INTC_IRPT_MASK 
  5.  
  6. #define   INTC_IPR  (*((volatile unsigned long *)(XPAR_INT_CTRL_BASEADDR + 0x04))) 
  7. #define   INTC_IER  (*((volatile unsigned long *)(XPAR_INT_CTRL_BASEADDR + 0x08))) 
  8. #define   INTC_IAR  (*((volatile unsigned long *)(XPAR_INT_CTRL_BASEADDR + 0x0C))) 
  9. #define   INTC_MER  (*((volatile unsigned long *)(XPAR_INT_CTRL_BASEADDR + 0x1C))) 
  10.  
  11. void myISR( void ) __attribute__ ((interrupt_handler)); 
  12.  
  13. void myISR( void ) 
  14.   if( INTC_IPR & TIMER_INT )    // Timer Interrupt Is Pending 
  15.     timer_ISR(); 
  16.    
  17.   if( INTC_IPR & BTN_INT )    // Button interrupt is pending 
  18.     button_ISR(); 
  19.    
  20.   if( INTC_IPR & SPI_INT )    // SPI interrupt is pending 
  21.     spi_ISR(); 
  22.    
  23.   INTC_IAR = INTC_IPR;      // Acknowledge Interrupts 
  24. // ************************************************************************* 
  25.  
  26.  
  27. // Timer Specific Code ***************************************************** 
  28. #define  TCSR0   (*((volatile unsigned long *)(XPAR_TIMER_BASEADDR + 0x00))) 
  29. #define   TLR0    (*((volatile unsigned long *)(XPAR_TIMER_BASEADDR + 0x04))) 
  30.  
  31. void timer_ISR( void ) 
  32.   // Do Stuff Here 
  33.   TCSR0 = TCSR0;   // Acknogledge Interrupt In Timer (Clear pending bit) 
  34. // ************************************************************************* 
  35.  
  36.  
  37. // GPIO (Connected to Buttons) Specific Code ******************************* 
  38. #define  BTNS    (*((volatile unsigned long *)(XPAR_BUTTONS_BASEADDR))) 
  39. #define  BTN_OE  (*((volatile unsigned long *)(XPAR_BUTTONS_BASEADDR + 0x04))) 
  40. #define  BTN_GIE  (*((volatile unsigned long *)(XPAR_BUTTONS_BASEADDR + 0x11C))) 
  41. #define  BTN_IER  (*((volatile unsigned long *)(XPAR_BUTTONS_BASEADDR + 0x128))) 
  42. #define  BTN_ISR  (*((volatile unsigned long *)(XPAR_BUTTONS_BASEADDR + 0x120))) 
  43.  
  44. void button_ISR( void ) 
  45.   // Do Stuff Here 
  46.   BTN_ISR = BTN_ISR;  // Clear any pending button interrupts 
  47. // ************************************************************************* 
  48.  
  49. // SPI Specific Code ******************************************************* 
  50. #define  SPI_GIE  (*((volatile unsigned long *)(XPAR_SPI_BASEADDR+0x1C))) 
  51. #define   SPI_ISR  (*((volatile unsigned long *)(XPAR_SPI_BASEADDR+0x20))) 
  52. #define   SPI_IER  (*((volatile unsigned long *)(XPAR_SPI_BASEADDR+0x28))) 
  53.  
  54. void spi_ISR( void ) 
  55.   // Do Stuff Here 
  56.   SPI_ISR = SPI_ISR;  // Clear pending interrupts 
  57. // ************************************************************************* 
  58.  
  59.   void main( void ) 
  60.   // ... 
  61.  
  62. TCSR0 = 0x000007F6;    // Timer Load and Clear any Pending Ints 
  63.   TCSR0 = 0x000007D6;    // Timer Clear Load Bit 
  64.  
  65. BTN_OE = ~0x00;    // Buttons are inputs 
  66. BTN_IER = BTN_CHNL1;    // Enable Interrupts for all 3 buttons; 
  67.   BTN_GIE = ~0x00;    // Enable Interrupts for Button GPIO 
  68.  
  69. SPI_IER = SPI_TxEMPTY;   // Enable Interrupt for empty  
  70. SPI_GIE = ~0x00000000;   // Global SPI Interrupt Enable 
  71.  
  72. // Enable Timer and Button Interrupt in IntC 
  73. INTC_IER = TIMER_INT | BTN_INT | SPI_INT;   
  74.   INTC_MER = 0x03;    // Int Controller Master Enable 
  75.   microblaze_enable_interrupts(); 
  76.  
  77.   //... 
  78. }

复制代码



下面是使用库函数后的代码,要简洁的多,,此例程硬件有多个中断,使用int_ctrl控制器,但程序中仅声明一个中断

  1.  
  2.   T8255_EnableInterrupt(XPAR_T8255_0_BASEADDR);
  3.    // Enable MicroBlaze Interrupts
  4.   microblaze_enable_interrupts();
  5.    
  6.   /* Register the t8255 interrupt handler in the vector table */
  7.   XIntc_RegisterHandler(XPAR_XPS_INTC_0_BASEADDR,
  8.                              XPAR_XPS_INTC_0_T8255_0_IP2INTC_IRPT_INTR,
  9.                              (XInterruptHandler) t8255_int_handler,
  10.                              (void *)XPAR_T8255_0_BASEADDR);
  11.  
  12.   /* Start the interrupt controller */
  13.   XIntc_MasterEnable(XPAR_XPS_INTC_0_BASEADDR);
  14.   XIntc_EnableIntr(XPAR_XPS_INTC_0_BASEADDR, 0x1);

复制代码


说完软件,来看看硬件中断是怎么连接及生成的。在生成用户IP时,勾选下面图片选项,第一个为使用中断,第二个为中断优先级编码控制,暂时用不上这么高级的玩意。中断数量为2。里面还有一个中断触发条件选项,有上升沿、下降沿、高低电平等。这里选上升沿触发。
<ignore_js_op> 
生成PLB总线IP代码后,需要修改三个文件t8255_v2_1_0.mpduser_logic.vt8255.vhd,分别在目录\lab_8255\atlys\pcores\t8255_v1_00_a\data\lab_8255\atlys\pcores\t8255_v1_00_a\hdl下,由于本版比较熟悉Verilog,所以在生成用户代码时勾选了生成.V选项。
中断线连接很简单,在user_logic.v文件里,已经例化了中断线,数量为刚才选着的2,将这个信号和用户想要使用的触发中断信号连接起来即可。这里将他和外部按键项链,按键按下触发中断。代码如下

  1. output [0 : C_NUM_INTR-1] IP2Bus_IntrEvent;
  2. assign IP2Bus_IntrEvent[1] = ~wt_cnt;
  3. assign IP2Bus_IntrEvent[0] = rd_cnt;

复制代码

读写寄存器代码如下,PLB总线读写信号高电平有效,用户需在PLB总线读写信号到来时,将数据输出或输入到总线上即可。代码如下

  1.  
  2.   // --USER logic implementation added here
  3.     /***  read data logic  ***/
  4.     reg           rd_cnt;
  5.     reg    [3:0]  rd_reg1;
  6.     
  7.     always @(posedge Bus2IP_Clk or posedge Bus2IP_Reset) begin
  8.        if(Bus2IP_Reset)  begin
  9.            rd_cnt     <= 1'd0;
  10.            rd_reg1    <= 4'd0;
  11.        end else begin
  12.            if(key1[0] == 1'd1) begin
  13.               rd_cnt <= 1'd1;
  14.               rd_reg1    <= switch1;
  15.            end 
  16.            if(Bus2IP_RdCE[0])   rd_cnt <= 1'd0;
  17.        end
  18.     end
  19.     
  20.     assign IP2Bus_IntrEvent[0]  = rd_cnt;
  21.     assign IP2Bus_Data   = {28'd0,rd_reg1};   
  22.     //assign   led1[7]    = ~rd_cnt;
  23.     /***  wite data logic  ***/
  24.     reg           wt_cnt;
  25.     reg    [3:0]  wt_reg1;
  26.     reg    [3:0]  led_reg;
  27.     
  28.     always @(posedge Bus2IP_Clk or posedge Bus2IP_Reset) begin
  29.        if(Bus2IP_Reset) begin
  30.            wt_cnt <= 1'd0;
  31.            wt_reg1    <= 4'd0;
  32.        end else begin
  33.            if(Bus2IP_WrCE[0]) begin
  34.               wt_cnt <= 1'd1;
  35.               wt_reg1    <= Bus2IP_Data[0:3];
  36.            end
  37.            if(key1[1] == 1'd1)begin
  38.               wt_cnt <= 1'd0;
  39.               led_reg    <= wt_reg1;
  40.            end
  41.        end
  42.     end
  43.     
  44.     assign IP2Bus_IntrEvent[1]  = ~wt_cnt;
  45.     assign led1 = {~rd_cnt,wt_cnt,2'd0,led_reg};

复制代码

t8255_v2_1_0.mpd文件里更改需要添加进的端口,代码如下

  1.  
  2. ## Ports
  3. PORT key1 = "",DIR = I,VEC = [0:1]
  4. PORT switch1 = "",DIR = I,VEC = [0:3]
  5. PORT led1 = "",DIR = O,VEC = [0:7]

复制代码


t8255.vhd
同样,这里就不贴出来了。修改完成后,双击左边T8255IP添加进MICROBLAZE内核,并将其接入mb_plb总线,连接网表,连接t8255中断至microblaze—interrupt,下拉key1switch1,和led1的选项,选择make externalIP端口引出,引出网标如下。分配t8255地址,至此整个工程结束图片如下:
 
 
 
附件lab5为基于Spartan3eEDK13.2工程,为多中断系统使用中断控制器例子。
Atyls_success
为基于AtylsEDK13.2工程,为单中断系统不使用中断控制器例子。
Lab_source
为程序原文件。

 

 

共1条 1/1 1   
快速回复主题
  • 匿名不能发帖!请先 [ 登陆 注册 ]