我是靠谱客的博主 多情项链,最近开发中收集的这篇文章主要介绍如何使用Nios II的中断:PIO中断与定时器中断,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

软硬件环境

硬件:艾米电子EP2C8核心板+2.4’ TFT套件

软件:Altera Quartus II 10.0  +  Nios II 10.0  Software Build Tools for Eclipse

 

内容

1 PIO中断

此处以ADS的nIRQ引脚为例。

1.1 在SOPC Builder中例化PIO

图1.1 例化PIO核

图1.1 例化PIO核

图1.2 Basic Setting

图1.2 Basic Setting

图1.3 Input Option

图1.3 Input Option

在ADS7843中,当用触摸笔触摸到TFT时,nIRQ引脚会拉低,因此我们可以检测nIRQ引脚的边沿,当为下降沿的时候,产生中断。查看手册Embedded Peripherals IP User Guide中的PIO一节,阅读相关片段。根据图1.4和1.5的描述,对nIRQ的PIO的输入选项的设置如图1.3所示。只需配置图1.2和图1.3所指的选项,其他选项缺省设置即可。

图1.4 Capture功用

图1.4 Capture功用

图1.5 IRQ Generation功用

图1.5 IRQ Generation功用

1.2 PIO中断的C代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include "system.h"                   // 系统
#include "altera_avalon_pio_regs.h"   // PIO,ads_nIRQ
#include "sys/alt_irq.h"              // 中断
//
unsigned int nirq_isr_context; // 定义全局变量以储存isr_context指针
void nIRQ_Initial( void );
void nIRQ_ISR( void * isr_context);
//
int main( void )
{
   nIRQ_Initial(); // 初始化PIO中断
   while (1)
   {
  
}
// nIRQ中断初始化
void nIRQ_Initial( void )
{
   // 改写timer_isr_context指针以匹配alt_irq_register()函数原型
   void * isr_context_ptr = ( void *) &nirq_isr_context;
   IOWR_ALTERA_AVALON_PIO_IRQ_MASK(ADS_NIRQ_BASE, 1); // 使能中断
   IOWR_ALTERA_AVALON_PIO_EDGE_CAP(ADS_NIRQ_BASE, 1); // 清中断边沿捕获寄存器
   // 注册ISR
   alt_ic_isr_register(
       ADS_NIRQ_IRQ_INTERRUPT_CONTROLLER_ID, // 中断控制器标号,从system.h复制
       ADS_NIRQ_IRQ,     // 硬件中断号,从system.h复制
       nIRQ_ISR,         // 中断服务子函数
       isr_context_ptr,  // 指向与设备驱动实例相关的数据结构体
       0x0);             // flags,保留未用
}
// 中断服务子函数
void nIRQ_ISR( void * nirq_isr_context)
{
   IOWR_ALTERA_AVALON_PIO_EDGE_CAP(ADS_NIRQ_BASE, 1); // 清中断边沿捕获寄存器
 
   // 用户中断代码
}

以第21行为例,使能中断和清清中断边沿捕获寄存器都是按位操作的。此处nIRQ引脚为1位,因此所写的值为0或1。

?
1
IOWR_ALTERA_AVALON_PIO_IRQ_MASK(ADS_NIRQ_BASE, 1); // 使能中断

倘若是总线,比方说4位,那么使能的话,就应该如下操作。对其他寄存器的操作也是类似的。

?
1
IOWR_ALTERA_AVALON_PIO_IRQ_MASK(BUS_4_BASE, 0xF); // 使能中断

同时需要注意若是在SOPC Builder中选择了enable bit-clearing for edge capture register的话,那么对于edge capture就应该是写1清中断;若是没有选择enable bit-clearing for edge capture register,则是写任意数清中断。(由韩彬总结)

?
1
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(ADS_NIRQ_BASE, 1); // 清中断边沿捕获寄存器

若是总线,便与上面类似。

在清中断这一点上,我们可以总结一下:arm和mips类的nios是写1清中断;而51单片机是写0清中断。

注意:
1 中断服务代码区不要使用printf(),否则会严重阻塞中断。
2 如果需要中断服务子函数传参,那么参数必须转为空类型。且所传参数为16位的全局变量。
3 9.1版本的以后的中断注册写法有两种,此处示范为增强版的中断注册写法。

 

2 定时器中断

此处以high_res_timer为例。

2.1 在SOPC Builder中例化Timer

图2.1 例化Interval Timer核

图2.1 例化Interval Timer核

图2.2 配置Timer counter size和Hardware option

图2.2 配置Timer counter size和Hardware option

查看手册Embedded Peripherals IP User Guide中的Interval Timer核一节,阅读相关片段。参考图2.3和2.4的描述,配置为32位的全功能定时器(当然也可以配置为64位定时器,但是后面的软件需要稍微修改)。只需配置图2.2,其他选项缺省设置即可。

图2.3 Counter Size功用

图2.3 Counter Size功用

图2.4 Hardware Options功用

图2.4 Hardware Options功用

2.2 定时器中断的C代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include "system.h"                   // 系统
#include "altera_avalon_timer_regs.h" // 定时器
#include "sys/alt_irq.h"              // 中断
//
unsigned int timer_isr_context; // 定义全局变量以储存isr_context指针
void Timer_Initial( void );
void Timer_ISR( void * isr_context);
//
int main( void )
{
   Timer_Initial(); // 初始化定时器中断
   while (1)
   {
  
}
// 定时器中断初始化
void Timer_Initial( void )
{
   // 改写timer_isr_context指针以匹配alt_irq_register()函数原型
   void * isr_context_ptr = ( void *) &timer_isr_context;
   // 设置PERIOD寄存器
   // PERIODH << 16 | PERIODL = 计数器周期因子 * 系统时钟频率因子 - 1
   // PERIODH << 16 | PERIODL = 5m*100M - 1 = 499999 = 0x7A11F
   IOWR_ALTERA_AVALON_TIMER_PERIODH(HIGH_RES_TIMER_BASE, 0x0007);
   IOWR_ALTERA_AVALON_TIMER_PERIODL(HIGH_RES_TIMER_BASE, 0xA11F);
 
   // 设置CONTROL寄存器
   //    位数 |  3   |  2   |  1   |  0  |
   // CONTROL | STOP | START| CONT | ITO |
   // ITO   1,产生IRO;                      0,不产生IRQ
   // CONT  1,计数器连续运行直到STOP被置一;   0,计数到0停止
   // START 1,计数器开始运行;                0,无影响
   // STOP  1,计数器停止运行;                0,无影响
   IOWR_ALTERA_AVALON_TIMER_CONTROL(HIGH_RES_TIMER_BASE,
     ALTERA_AVALON_TIMER_CONTROL_START_MSK | // START = 1
     ALTERA_AVALON_TIMER_CONTROL_CONT_MSK  | // CONT  = 1
     ALTERA_AVALON_TIMER_CONTROL_ITO_MSK);   // ITO   = 1
   // 注册定时器中断
   alt_ic_isr_register(
       HIGH_RES_TIMER_IRQ_INTERRUPT_CONTROLLER_ID, // 中断控制器标号,从system.h复制
       HIGH_RES_TIMER_IRQ,     // 硬件中断号,从system.h复制
       Timer_ISR,              // 中断服务子函数
       isr_context_ptr,        // 指向与设备驱动实例相关的数据结构体
       0x0);                   // flags,保留未用
}
// 定时器中断服务子函数
void Timer_ISR( void * timer_isr_context)
{
   // 应答中断,将STATUS寄存器清零
   IOWR_ALTERA_AVALON_TIMER_STATUS(HIGH_RES_TIMER_BASE,
       ~ ALTERA_AVALON_TIMER_STATUS_TO_MSK);   // TO = 0
 
   // 用户中断代码
}

image

图2.3 32位的Interval Timer核的寄存器结构。

查看手册Embedded Peripherals IP User Guide中的Interval Timer核一节,阅读相关片段。参考图2.3,设置寄存器。此处以5ms为例,系统时钟为100Mhz。之所以还要减去1,是因为从0开始计数的。关于其他寄存器的功用,请参阅手册的相关片段。

?
1
2
3
4
5
// 设置PERIOD寄存器
// PERIODH << 16 | PERIODL = 计数器周期因子 * 系统时钟频率因子 - 1
// PERIODH << 16 | PERIODL = 5m*100M - 1 = 499999 = 0x7A11F
IOWR_ALTERA_AVALON_TIMER_PERIODH(HIGH_RES_TIMER_BASE, 0x0007);
IOWR_ALTERA_AVALON_TIMER_PERIODL(HIGH_RES_TIMER_BASE, 0xA11F);

与PIO注意事项类似。
注意:
1 中断服务代码区不要使用printf(),否则会严重阻塞中断。
2 如果需要中断服务子函数传参,那么参数必须转为空类型。且所传参数为16位的全局变量。
3 9.1版本的以后的中断注册写法有两种,此处示范为增强版的中断注册写法。

3 一点心得

Nios II的中断操作基本类似。今后我会写点其他IP和自定义IP里面的中断如何使用。

Embedded Peripherals IP User Guide提供了很多IP核的功能和用法说明,是学习Nios II的红宝书。关于Nios II软件编程的更多细节,可以参阅Nios II Software Developer's Handbook;关于Nios II软核的更多细节,可以参阅Nios II Processor Reference Handbook。如果你有一些解决不了的问题,可以去alterafoum.com检索相关关键字,很多时候是可以找到前人的经验和答案的。

来自:http://www.cnblogs.com/yuphone/archive/2010/11/25/1887621.html


Nios II 9.1的sys/alt_irq.h与之前版本的区别

引子

以前版本的sys/alt_irq.h,我在这里就不多说了;此处仅浅析9.1版本的增强版的sys/alt_irq.h。

 

浅析

1 增强版的API

表1 增强版的HAL中断的API

表1 增强版的HAL中断的API

 

2 先前的HAL中断API
  • alt_irq_register()
  • alt_irq_disable()
  • alt_irq_enable()
  • alt_irq_disable_all()
  • alt_irq_enable_all()
  • alt_irq_interruptible()
  • alt_irq_non_interruptible()
  • alt_irq_enabled()

 

3 写ISR
(1)使用增强版中断API注册ISR
?
1
2
3
4
5
int alt_ic_isr_register(alt_u32 ic_id,
                         alt_u32 irq,
                         alt_isr_func isr,
                         void *isr_context,
                         void * flags)
  • ic_id为中断控制器标号,定义于system.h之中。在使用菊花链的EIC中,ic_id使用菊花链标识EIC;在IIC中,ic_id则不重要。
  • irq为设备的硬件中断号,定义于system.h之中。
    • 对于IIC来讲,irq就是IRQ号。中断的优先级与IRQ的编号成相反顺序。故IRQ_0代表最高优先级的中断,IRQ_31则是最低优先级的。
    • 对于EIC来讲,irq就是中断端口的ID。
  • isr_context指向与设备驱动实例相关的数据结构体。isr_context传递输入参数给中断服务程序的函数。用于传递特定上下文的信息给ISR,也可指向任何特定ISR的信息。该上下文的值对于HAL是不透明的;it is provided entirely for the benefit of the user-defined ISR。
  • isr指向相应的IRQ号的irq调用的ISR函数的指针。ISR函数原型如下:
?
1
void handle_button_interrupts( void * isr_context);

      给该函数提供的输入参数就是isr_context。

      注: 给isr注册空指针,将会导致中断失去使能;handle_button_interrupts为isr服务函数名称,不固定。

  • flags保留未用。

 

(2)使能或者去使能中断

增强版的中断API提供如下函数:alt_ic_irq_disable(),alt_ic_irq_enable(),alt_ic_irq_enabled(),alt_irq_disable_all(),alt_irq_enable_all()。

  • alt_irq_enable()允许编程以使某些部分的代码禁用硬件中断,或此后重新使能它们。
  • alt_ic_irq_disable()和alt_ic_irq_enable()允许使能或去使能单独的中断。
  • alt_irq_disable_all()去使能所有中断,并返回一上下文值。
  • 欲重新使能硬件中断,可调用alt_irq_enable_all(),并传递上下文参数。中断在返回状态的优先级之前调用alt_irq_disable_all()。
  • 若可屏蔽的异常被使能,则alt_irq_enabled()返回非零值。
  • alt_ic_irq_enabled()则决定那个被指定的中断被使能。

 

(3)升级至增强版的HAL中断

表2 升级HAL中断的API

 表2 升级HAL中断的API

 

(4)支持多种HAL中断的API

在软件编译工具中选择中断API,使用system.h中的如下符号来定义其中之一,来标识哪种中断API可用:

  • ALT_ENHANCED_INTERRUPT_PRESENT——定义使用增强版的API实现
  • ALT_LEGACY_INERRUPT_API_PRESENT——定义使用先前的API实现

在用户的驱动代码中,使用这些符号来决定哪种API被调用。

 

(5)使用HAL注册按键中断的C范例
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include "system.h"
#include "sys/alt_irq.h"
#include "altera_avalon_pio_regs.h"
 
// 定义全局变量以储存边沿捕获值
volatile int edge_capture;
 
//  初始化button_pio
static void init_button_pio()
{
   // 改写edge_capture指针以匹配alt_irq_register()函数原型 
   void * edge_capture_ptr = ( void *) &edge_capture;
 
   // 使能所有4个按钮中断
   IOWR_ALTERA_AVALON_PIO_IRQ_MASK(BUTTON_PIO_BASE, 0xf);
 
   // 清边沿捕获寄存器
   IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE, 0x0);
 
   // 注册ISR
   // Nios II 9.1
   #ifdef ALT_ENHANCED_INTERRUPT_API_PRESENT
   alt_ic_isr_register(BUTTON_PIO_IRQ_INTERRUPT_CONTROLLER_ID,
                       BUTTON_PIO_IRQ,
                       handle_button_interrupts,
                       edge_capture_ptr, 0x0);
   // Nios II 9.1之前版本
   #else
   alt_irq_register(BUTTON_PIO_IRQ,
                    edge_capture_ptr,
                    handle_button_interrupts);
   #endif
}

此处的BUTTON_PIO_IRQ为按钮中断的中断号;handle_button_interrupts为按钮中断的中断服务子程序,未列出。

 

4 完整的ISR使用范例

[笔记].如何使用Nios II的中断:PIO中断与定时器中断

 

附录

1 Nios II HAL 源代码路径

X:Altera91nios2edscomponentsaltera_nios2HAL

来自:http://www.cnblogs.com/yuphone/archive/2010/05/13/1734712.html


niosII ide9.1 include常用头文件来源

1.有关于设备的头文件
头文件位于IPDevice Drivers->altera/altera_avalon_[device kinds]/inc
2.alt_sys_init.h
Nios II SoftwarePackages -> altera_hal/HAL/inc/sys
3.alt_irq.h
Nios II SoftwarePackages ->altera_nios2/HAL/inc/sys
4.alt_types.h
Nios II SoftwarePackages ->altera_nios2/HAL/inc
5.system.h
system_description/
6.alt_irq_register()函数在头文件
Nios II SoftwarePackages ->altera_nios2/HAL/inc/priv/alt_legacy_irq.h中


最后

以上就是多情项链为你收集整理的如何使用Nios II的中断:PIO中断与定时器中断的全部内容,希望文章能够帮你解决如何使用Nios II的中断:PIO中断与定时器中断所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(65)

评论列表共有 0 条评论

立即
投稿
返回
顶部