蜗牛

一起交流,共同进步
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

(原创)SOPC系统自定义外设之:软件设计

Posted on 2009-05-09 22:19  路漫漫...  阅读(3608)  评论(14编辑  收藏  举报
      完成自定义外设的硬件设计后,就需要编写软件来测试外设的设计是否正确了。

在这之前首先要弄清楚Nios II中的地址对齐,对Avalon slave来说,有两种地址对齐方式:动态地址对齐和静态地址对齐。

动态地址对齐:动态地址对齐可以自动适应和Avalon master端口宽度不同的器件,而同时保持地址增长的方式是以字节为单位增长的方式。匹配不同端口宽度的master和slave时使用动态地址对齐方式可以得到一个连续的存贮器空间。但动态地址对齐在读操作的时候有附作用。当一个32位Nios II core读一个8位宽的slave时,物理会产生4次8位的读操作,而读一个16位宽的slave时,则要产生2次的读操作。大部分寄存器类型的外设不能容忍这种附作用,所以动态地址对齐一般不适合用于寄存器外设,主要用于存贮器。如果外部存贮器的宽度大于8位时,比如16位或32位,则必然有字节使能信号,以便进行字节粒度的写操作。所以在为这些存贮器做接口的时候,如果采用动态地址对齐的方式,则一定要连接字节使能信号。

静态地址对齐:静态地址对齐的地址增长单位是Avalon master的端口宽度,每次读写都只对应一次操作没有什么附作用。但在匹配不同端口宽度的master和slave时,地址不能自动调整,某些地址没有相应的物理实体和它对应。当一个32位的Nios II core读一个8位宽的slave时,其获得的32位数据低8位从slave获取,而高24位则没有定义。同样,当它读16宽的slave时,其获得的32位数据低16位从slave获取,而高16位则没有定义。当Nios II core想继续读下一个8位(或16位)时,则需要增长字节地址4。除非你一定需要一个连续的地址空间,否则使用静态地址对齐方式是比较保险的方式。

在刚调试期间遇到这样一个问题:用IOWR(KEYBOARD_BASE,2,0);清楚irq中断信号,在用SignalTap II逻辑分析仪始终抓不到write信号,一直保持低电平,后来用IOWR(KEYBOARD_BASE,0,0)就能抓到write信号了。我想一定是地址对齐的问题,然后打开SOPC Builder,准备地址对齐对齐方式,可是始终没有看到那一项,以前6.0版本是有这个选项的。折腾了我一天,后来只好硬着头皮看Altera官方文档,终于找到答案了。

 

于是决定找到源文件,改代码,在生成的key_hw.tcl中

#set_interface_property avalon_slave addressAlignment DYNAMIC

set_interface_property avalon_slave addressAlignment NATIVE

   注释掉DYNAMIC,改成NATIVE。

   重新编译,问题就不服存在了,用SignalTap II成功到捕捉write信号

 

测试源程序如下:

 1 #include "system.h"
 2 #include <stdio.h>
 3 #include <io.h>
 4 #include "alt_types.h"
 5 #include "sys/alt_irq.h"
 6 static void key_isr(void* context, alt_u32 id);
 7 volatile int irq_capture;
 8 int main (void) __attribute__ ((weak, alias ("alt_main")));
 9 int alt_main (void
10 
11   alt_irq_init(ALT_IRQ_BASE); //使能中断
12   alt_irq_register(KEYBOARD_IRQ,NULL , key_isr);//注册中断服务程序
13   while (1);
14   return 0
15 }
16  static void key_isr(void* context, alt_u32 id)
17   {
18      irq_capture = IORD(KEYBOARD_BASE,1);
19      IOWR(KEYBOARD_BASE,2,0); 
20      printf("key_value:%d\n",irq_capture);    
21  }
22 

 

为了能弄清楚中断的工作流程,决定进行单步调试。但必须先知道中断时如何控制和执行的。

中断由三个寄存器控制:state,ienable,ipending。

state:最后一位PIE,中断开关,1:中断使能。0:禁止外部中断

ipending:32位,第n位为1则表示正在处理第n个中断。

ienable:32位,每1位对应1个外部中断源的使能位,若第n位为1,则使能对应的中断,为0则禁止对应的中断。

注意,ienable变成了0x4,联想到上一篇(原创)SOPC系统自定义外设之:硬件设计,中断号为2,表示键盘中断已经使能。

还有一个就是终端向量表alt_irq,一共有32个,每一个对应一个中断优先级,如果中断注册成功,就会向中断向量表里面写入ISR和context

 

如上图,alt_irq[2]的handler指向key_isr()中断服务程序,中断注册成功!

Context为全0,因为程序在注册中断服务程序时设置的context参数为NULL。

alt_irq_active是一个32位的全局变量,当某个中断被使能后,对应位就为1。

开始硬件上运行程序,让程序执行key_isr()中断服务程序。在按键时,输出如下:

 

中断服务程序成功执行!!

经过这次自定义外设软硬件的调试,实在是让人感叹SOPC的灵活性!