打印

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

[复制链接]
4014|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 SuperX-man 于 2012-7-13 13:21 编辑

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

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

这里首先介绍一下Microblaze的中断系统及软件操作,Microblaze内核支持外部中断响应,但仅支持一个外部中断,其中断入口地址为0x10。PC指针保存在R14寄存器内,中断控制位为MSR的IEbit(详细介绍请看附件中PDF手册)。
单中断操作比较简单,仅需用
void myISR( ) __attribute__ ((interrupt_handler));
函数声明即可,然后添加用户代码即可
void myISR( void ) 
{
}

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

void myISR( void );

void myISR( void )
{
}

Compiles to:

myISR:
  .frame r1,0,r15    # vars= 0, regs= 0, args= 0
  .mask  0x00000000
$LM2:
  .stabn  68,0,55,$LM2-myISR
  rtsd  r15,8  
  nop    # Unfilled delay slot

  .end  myISR

使用函数声明编译后的代码
void myISR( void ) __attribute__ ((interrupt_handler)); 

void myISR( void )
{
}

myISR:
_interrupt_handler:
.frame r1,20,r15 # vars= 0, regs= 3, args= 0
.mask 0x00060800
addik r1,r1,-20
swi r15,r1,0
swi r11,r1,8
swi r17,r1,12
mfs r11,rmsr #mfs
swi r18,r1,16
swi r11,r1,4
$LM2:
.stabn 68,0,55,$LM2-myISR
lwi r15,r1,0
lwi r11,r1,4
mts rmsr,r11 #mts
lwi r11,r1,8
lwi r17,r1,12
lwi r18,r1,16
rtid r14,0

addik r1,r1,20

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

// ISR Code****************************************************************
#define   TIMER_INT  XPAR_TIMER_INTERRUPT_MASK
#define   BTN_INT  XPAR_BUTTONS_IP2INTC_IRPT_MASK
#define   SPI_INT  XPAR_SPI_IP2INTC_IRPT_MASK

#define   INTC_IPR  (*((volatile unsigned long *)(XPAR_INT_CTRL_BASEADDR + 0x04)))
#define   INTC_IER  (*((volatile unsigned long *)(XPAR_INT_CTRL_BASEADDR + 0x08)))
#define   INTC_IAR  (*((volatile unsigned long *)(XPAR_INT_CTRL_BASEADDR + 0x0C)))
#define   INTC_MER  (*((volatile unsigned long *)(XPAR_INT_CTRL_BASEADDR + 0x1C)))

void myISR( void ) __attribute__ ((interrupt_handler));

void myISR( void )
{
  if( INTC_IPR & TIMER_INT )    // Timer Interrupt Is Pending
    timer_ISR();
   
  if( INTC_IPR & BTN_INT )    // Button interrupt is pending
    button_ISR();
   
  if( INTC_IPR & SPI_INT )    // SPI interrupt is pending
    spi_ISR();
   
  INTC_IAR = INTC_IPR;      // Acknowledge Interrupts
}
// *************************************************************************


// Timer Specific Code *****************************************************
#define  TCSR0   (*((volatile unsigned long *)(XPAR_TIMER_BASEADDR + 0x00)))
#define   TLR0    (*((volatile unsigned long *)(XPAR_TIMER_BASEADDR + 0x04)))

void timer_ISR( void )
{
  // Do Stuff Here
  TCSR0 = TCSR0;   // Acknogledge Interrupt In Timer (Clear pending bit)
}
// *************************************************************************


// GPIO (Connected to Buttons) Specific Code *******************************
#define  BTNS    (*((volatile unsigned long *)(XPAR_BUTTONS_BASEADDR)))
#define  BTN_OE  (*((volatile unsigned long *)(XPAR_BUTTONS_BASEADDR + 0x04)))
#define  BTN_GIE  (*((volatile unsigned long *)(XPAR_BUTTONS_BASEADDR + 0x11C)))
#define  BTN_IER  (*((volatile unsigned long *)(XPAR_BUTTONS_BASEADDR + 0x128)))
#define  BTN_ISR  (*((volatile unsigned long *)(XPAR_BUTTONS_BASEADDR + 0x120)))

void button_ISR( void )
{
  // Do Stuff Here
  BTN_ISR = BTN_ISR;  // Clear any pending button interrupts
}
// *************************************************************************

// SPI Specific Code *******************************************************
#define  SPI_GIE  (*((volatile unsigned long *)(XPAR_SPI_BASEADDR+0x1C)))
#define   SPI_ISR  (*((volatile unsigned long *)(XPAR_SPI_BASEADDR+0x20)))
#define   SPI_IER  (*((volatile unsigned long *)(XPAR_SPI_BASEADDR+0x28)))

void spi_ISR( void )
{
  // Do Stuff Here
  SPI_ISR = SPI_ISR;  // Clear pending interrupts
}
// *************************************************************************

  void main( void )
{
  // ...

TCSR0 = 0x000007F6;    // Timer Load and Clear any Pending Ints
  TCSR0 = 0x000007D6;    // Timer Clear Load Bit

BTN_OE = ~0x00;    // Buttons are inputs
BTN_IER = BTN_CHNL1;    // Enable Interrupts for all 3 buttons;
  BTN_GIE = ~0x00;    // Enable Interrupts for Button GPIO

SPI_IER = SPI_TxEMPTY;   // Enable Interrupt for empty  
SPI_GIE = ~0x00000000;   // Global SPI Interrupt Enable

// Enable Timer and Button Interrupt in IntC
INTC_IER = TIMER_INT | BTN_INT | SPI_INT;   
  INTC_MER = 0x03;    // Int Controller Master Enable
  microblaze_enable_interrupts();

  //...
}


下面是使用库函数后的代码,要简洁的多,,此例程硬件有多个中断,使用int_ctrl控制器,但程序中仅声明一个中断
 
  T8255_EnableInterrupt(XPAR_T8255_0_BASEADDR);
   // Enable MicroBlaze Interrupts
  microblaze_enable_interrupts();
   
  /* Register the t8255 interrupt handler in the vector table */
  XIntc_RegisterHandler(XPAR_XPS_INTC_0_BASEADDR,
                             XPAR_XPS_INTC_0_T8255_0_IP2INTC_IRPT_INTR,
                             (XInterruptHandler) t8255_int_handler,
                             (void *)XPAR_T8255_0_BASEADDR);

  /* Start the interrupt controller */
  XIntc_MasterEnable(XPAR_XPS_INTC_0_BASEADDR);
  XIntc_EnableIntr(XPAR_XPS_INTC_0_BASEADDR, 0x1);


说完软件,来看看硬件中断是怎么连接及生成的。在生成用户IP时,勾选下面图片选项,第一个为使用中断,第二个为中断优先级编码控制,暂时用不上这么高级的玩意。中断数量为2。里面还有一个中断触发条件选项,有上升沿、下降沿、高低电平等。这里选上升沿触发。

生成PLB总线IP代码后,需要修改三个文件t8255_v2_1_0.mpduser_logic.v、t8255.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,将这个信号和用户想要使用的触发中断信号连接起来即可。这里将他和外部按键项链,按键按下触发中断。代码如下
output [0 : C_NUM_INTR-1] IP2Bus_IntrEvent;
assign IP2Bus_IntrEvent[1] = ~wt_cnt;
assign IP2Bus_IntrEvent[0] = rd_cnt;
读写寄存器代码如下,PLB总线读写信号高电平有效,用户需在PLB总线读写信号到来时,将数据输出或输入到总线上即可。代码如下
 
  // --USER logic implementation added here
    /***  read data logic  ***/
    reg           rd_cnt;
    reg    [3:0]  rd_reg1;
   
    always @(posedge Bus2IP_Clk or posedge Bus2IP_Reset) begin
       if(Bus2IP_Reset)  begin
           rd_cnt     <= 1'd0;
           rd_reg1    <= 4'd0;
       end else begin
           if(key1[0] == 1'd1) begin
              rd_cnt <= 1'd1;
              rd_reg1    <= switch1;
           end
           if(Bus2IP_RdCE[0])   rd_cnt <= 1'd0;
       end
    end
   
    assign IP2Bus_IntrEvent[0]  = rd_cnt;
    assign IP2Bus_Data   = {28'd0,rd_reg1};   
    //assign   led1[7]    = ~rd_cnt;
    /***  wite data logic  ***/
    reg           wt_cnt;
    reg    [3:0]  wt_reg1;
    reg    [3:0]  led_reg;
   
    always @(posedge Bus2IP_Clk or posedge Bus2IP_Reset) begin
       if(Bus2IP_Reset) begin
           wt_cnt <= 1'd0;
           wt_reg1    <= 4'd0;
       end else begin
           if(Bus2IP_WrCE[0]) begin
              wt_cnt <= 1'd1;
              wt_reg1    <= Bus2IP_Data[0:3];
           end
           if(key1[1] == 1'd1)begin
              wt_cnt <= 1'd0;
              led_reg    <= wt_reg1;
           end
       end
    end
   
    assign IP2Bus_IntrEvent[1]  = ~wt_cnt;
    assign led1 = {~rd_cnt,wt_cnt,2'd0,led_reg};

t8255_v2_1_0.mpd文件里更改需要添加进的端口,代码如下
 
## Ports
PORT key1 = "",DIR = I,VEC = [0:1]
PORT switch1 = "",DIR = I,VEC = [0:3]
PORT led1 = "",DIR = O,VEC = [0:7]

t8255.vhd同样,这里就不贴出来了。修改完成后,双击左边T8255IP添加进MICROBLAZE内核,并将其接入mb_plb总线,连接网表,连接t8255中断至microblaze—interrupt,下拉key1,switch1,和led1的选项,选择make external将IP端口引出,引出网标如下。分配t8255地址,至此整个工程结束图片如下:



附件lab5为基于Spartan3e的EDK13.2工程,为多中断系统使用中断控制器例子。
Atyls_success为基于Atyls的EDK13.2工程,为单中断系统不使用中断控制器例子。
Lab_source为程序原文件。

lab5.rar

3.22 MB

atlys_success.rar

1.53 MB

lab_source.rar

13.14 KB

th_ublaze_interrupts.pdf

317.59 KB

相关帖子

沙发
5509| | 2012-7-13 12:59 | 只看该作者
支持超版的大作,等待完善

使用特权

评论回复
板凳
jakfens| | 2012-7-13 15:17 | 只看该作者
哦哦

使用特权

评论回复
地板
jakfens| | 2012-7-13 15:18 | 只看该作者
还是verilog的好 vhdl看不懂

使用特权

评论回复
5
GoldSunMonkey| | 2012-7-13 15:21 | 只看该作者
:)

使用特权

评论回复
6
GoldSunMonkey| | 2012-7-13 15:21 | 只看该作者
超版厉害啊

使用特权

评论回复
7
gaochy1126| | 2012-7-13 16:09 | 只看该作者
看的有点乱啦!

使用特权

评论回复
8
SuperX-man|  楼主 | 2012-7-14 22:00 | 只看该作者
7# gaochy1126

东西太多了,抱歉啊,就挑了几个重点写了下,有什么疑问可以提出来?

使用特权

评论回复
9
GoldSunMonkey| | 2012-7-15 17:32 | 只看该作者
7# gaochy1126  

东西太多了,抱歉啊,就挑了几个重点写了下,有什么疑问可以提出来?
SuperX-man 发表于 2012-7-14 22:00
其实我觉得很不错

使用特权

评论回复
10
JD21IC| | 2012-10-15 14:20 | 只看该作者
请问,如果是定时器中断,2个GPIO输入中断,那么是不是进入void myISR( void )。先要判断是否是GPIO中断,再去读GPIO口。判断是哪个引脚的中断?

使用特权

评论回复
11
GoldSunMonkey| | 2012-10-15 21:36 | 只看该作者
等超版回复你吧。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

12

主题

925

帖子

1

粉丝