|
楼主 |
发表于 2008-11-28 14:43:24
|
显示全部楼层
>>AVR32 UC3 中断系统的幻象
<font color=red>[说在前面的话]
很多事情,不知道其实是幸福的。我发誓,我下面所说的关于AVR32中断系统的内容都是某种
意义上的幻象——你可以理解为虚假的繁荣。真相是什么?你有知情权。但是如果你坚信自己不会
离开AVR32 Software Framework的襁褓,那么所谓的真相对你来说也许是灾难性的。幻象有它存在
的意义——很多时候它能让事情显得简单和谐——事实上隐藏在幻象背后的内幕也只对少部分人有
意义。
问题一:你知道AVR32 UC3在理论上最多能支持多少路中断么?
答案: AVR32 UC3系列对于中断是分组管理的,理论上每个组可以容纳最大32个中断请求,同
时AVR32 UC3支持最大64个组。显然AVR32 UC3在理论上支持最多64 * 32 = 2048路中断。
问题二:你知道AVR32 UC3有几个中断优先级么?
答案: 4个。分别时INT0~INT3,其中INT0中断优先级最低。高等级中断可以打断低等级中断,
低等级中断不能打断高等级中断。
问题三:编写中断处理程序有什么特殊要求么?
答案: 除了多个中断使用同一个中断向量号的情况以外,没有什么特殊要求。中断处理程序
不能带任何参数,也不能带任何返回值。记得在中断处理程序前加以下的代码:
#if __GNUC__
__attribute__((__interrupt__))
#elif __ICCAVR32__
__interrupt
#endif
记得一定要加,否则出了问题我不负责。
问题四:如何声明一个中断向量?
答案: 用一个Software Framework提供的函数,可以动态的注册中断向量。声明一个中断向量
只需要传递一个中断处理函数的函数指针,外加用于描述中断源的IRQ编号,再指定一个
中断优先级就可以了。
问题五:还有其他什么注意事项么?
答案: 如果你奉公守法,那么没有了。
[寄存器概述]
大体看一下这个图,知道差不多是那么回事就OK了。寄存器什么的与你无关……
从图上的内容我们很容易知道,AVR32将所有的中断请求都是分组存放的,每个组中最多容纳32个
中断。实际应用中,有的组是满满当当的32个中断,有的组里只有1个中断。具体情况请参考对应型号
的器件手册。又因为AVR32有4个中断优先级,所以我们可以将64个组任意分配到4个中断优先级的门下。
对于每个组,有一个IPR寄存器,用于保存当前这个组中断优先级是多少,当这个组发生中断时,执行
哪个中断处理程序(保存了中断处理程序的函数地址)。当一个组发生中断时,我们需要知道是组内
具体哪个中断源闯得祸,因此有一个专门的寄存器IRR用于用于记录组内各个成员的是否发出了中断请
求。
当一个中断发生的时候,系统如何知道是哪个组发出的中断呢?有一个专门的寄存器ICR记录了发
出中断请求,并且优先级最高的那个组的编号。根据这个编号,我们可以找到这个组,在根据组内的寄
存器IRR知道是组内哪个具体的中断源发出了请求。如果一个组内同时有多个中断请求怎么办?编号最
大的优先。当同时有多个相同优先级的组发出中断请求怎么办呢?也是编号最大的那个组获胜。
[Software Framework 的使用]
当我们通过AVR32 Studio的Software Framework添加向导增加了Power Manager驱动模块以后,系统
会自动在DRIVERS模块下增加一个INTC文件夹,其中包含了操作AVR32 UC3 INTC模块的底层API,我们只需
要在工程中增加一个 #inludeINTC.h 语句,就可以获得以下函数的使用权限:
extern void INTC_init_interrupts(void);
函数说明:没啥好说的,初始化整个中断系统,芯片初始化的时候调用一次即可。
输入参数:无
extern void INTC_register_interrupt(__int_handler handler, unsigned int irq, unsigned int int_lev);
函数说明:注册一个中断向量。也就是告诉系统当某个由IRQ描述的中断源发生了中断时,调用指定的中断
处理程序。同时该函数还给这个中断分配了一个优先级。
输入参数:指向中断处理函数的指针,
用于描述中断源的IRQ
该中断的优先级,注意,当同一个组内存在多个不同优先级的中断源时,改组最后一个调用该函
数注册的中断所指定的优先级对整个组的中断源都有效。
[应用实例]
#include <avr32/io.h>
#include compiler.h
#include board.h
#include print_funcs.h
#include intc.h
#include pm.h
#include gpio.h
#include usart.h
/*! \name USART Settings
*/
//! @{
#if BOARD == EVK1100
# define EXAMPLE_USART (&AVR32_USART0)
# define EXAMPLE_USART_RX_PIN AVR32_USART0_RXD_0_0_PIN
# define EXAMPLE_USART_RX_FUNCTION AVR32_USART0_RXD_0_0_FUNCTION
# define EXAMPLE_USART_TX_PIN AVR32_USART0_TXD_0_0_PIN
# define EXAMPLE_USART_TX_FUNCTION AVR32_USART0_TXD_0_0_FUNCTION
# define EXAMPLE_USART_IRQ AVR32_USART0_IRQ
# define EXAMPLE_USART_BAUDRATE 57600
#elif BOARD == EVK1101
# define EXAMPLE_USART (&AVR32_USART1)
# define EXAMPLE_USART_RX_PIN AVR32_USART1_RXD_0_0_PIN
# define EXAMPLE_USART_RX_FUNCTION AVR32_USART1_RXD_0_0_FUNCTION
# define EXAMPLE_USART_TX_PIN AVR32_USART1_TXD_0_0_PIN
# define EXAMPLE_USART_TX_FUNCTION AVR32_USART1_TXD_0_0_FUNCTION
# define EXAMPLE_USART_IRQ AVR32_USART1_IRQ
# define EXAMPLE_USART_BAUDRATE 57600
#elif BOARD == STK1000
# define EXAMPLE_USART (&AVR32_USART1)
# define EXAMPLE_USART_RX_PIN AVR32_USART1_RXD_0_PIN
# define EXAMPLE_USART_RX_FUNCTION AVR32_USART1_RXD_0_FUNCTION
# define EXAMPLE_USART_TX_PIN AVR32_USART1_TXD_0_PIN
# define EXAMPLE_USART_TX_FUNCTION AVR32_USART1_TXD_0_FUNCTION
# define EXAMPLE_USART_IRQ AVR32_USART1_IRQ
# define EXAMPLE_USART_BAUDRATE 115200
#elif BOARD == NGW100
# define EXAMPLE_USART (&AVR32_USART1)
# define EXAMPLE_USART_RX_PIN AVR32_USART1_RXD_0_PIN
# define EXAMPLE_USART_RX_FUNCTION AVR32_USART1_RXD_0_FUNCTION
# define EXAMPLE_USART_TX_PIN AVR32_USART1_TXD_0_PIN
# define EXAMPLE_USART_TX_FUNCTION AVR32_USART1_TXD_0_FUNCTION
# define EXAMPLE_USART_IRQ AVR32_USART1_IRQ
# define EXAMPLE_USART_BAUDRATE 115200
#endif
//! @}
/*! \brief The USART interrupt handler.
*
* \note The ~__attribute__((__interrupt__))' (under GNU GCC for AVR32) and
* ~__interrupt' (under IAR Embedded Workbench for Atmel AVR32) C function
* attributes are used to manage the ~rete' instruction.
*/
#if __GNUC__
__attribute__((__interrupt__))
#elif __ICCAVR32__
__interrupt
#endif
static void usart_int_handler(void)
{
int c;
// In the code line below, the interrupt priority level does not need to be
// explicitly masked as it is already because we are within the interrupt
// handler.
// The USART Rx interrupt flag is cleared by side effect when reading the
// received character.
// Waiting until the interrupt has actually been cleared is here useless as
// the call to usart_write_char will take enough time for this before the
// interrupt handler is leaved and the interrupt priority level is unmasked by
// the CPU.
usart_read_char(EXAMPLE_USART, &c);
// Print the received character to USART.
// It is a simple echo, so there will be no translation of '\r' to \r\n. The
// connected terminal has to be configured accordingly to send '\n' after
// '\r'.
usart_write_char(EXAMPLE_USART, c);
}
/*! \brief The main function.
*
* It sets up the USART module on EXAMPLE_USART. The terminal settings are 57600
* 8N1.
* Then it sets up the interrupt handler and waits for a USART interrupt to
* trigger.
*/
int main(void)
{
static const gpio_map_t USART_GPIO_MAP =
{
{EXAMPLE_USART_RX_PIN, EXAMPLE_USART_RX_FUNCTION},
{EXAMPLE_USART_TX_PIN, EXAMPLE_USART_TX_FUNCTION}
};
// USART options.
static const usart_options_t USART_OPTIONS =
{
.baudrate = EXAMPLE_USART_BAUDRATE,
.charlength = 8,
.paritytype = USART_NO_PARITY,
.stopbits = USART_1_STOPBIT,
.channelmode = USART_NORMAL_CHMODE
};
#if BOARD == EVK1100 || BOARD == EVK1101
// Switch main clock to external oscillator 0 (crystal).
pm_switch_to_osc0(&AVR32_PM, FOSC0, OSC0_STARTUP);
#endif
// Assign GPIO to USART.
gpio_enable_module(USART_GPIO_MAP,
sizeof(USART_GPIO_MAP) / sizeof(USART_GPIO_MAP[0]));
// Initialize USART in RS232 mode.
usart_init_rs232(EXAMPLE_USART, &USART_OPTIONS, FOSC0);
print(EXAMPLE_USART, .: Using interrupts with the USART :.\n\n);
//关闭AVR32的全局中断响应,类似AVR系列的CLI();.
Disable_global_interrupt();
//初始化中断系统
INTC_init_interrupts();
// Register the USART interrupt handler to the interrupt controller.
// usart_int_handler is the interrupt handler to register.
// EXAMPLE_USART_IRQ is the IRQ of the interrupt handler to register.
// AVR32_INTC_INT0 is the interrupt priority level to assign to the group of
// this IRQ.
// void INTC_register_interrupt(__int_handler handler, unsigned int irq, unsigned int int_lev);
//注册USART中断,中断处理函数是usart_int_handler,优先级是INT0
//需要强调的是,USART的发送和接收使用的都是同一个中断IRQ,详细情形请参阅
//后面的讲座,或者直接参考官方Datasheet。
INTC_register_interrupt(&usart_int_handler, EXAMPLE_USART_IRQ, AVR32_INTC_INT0);
// Enable USART Rx interrupt.
EXAMPLE_USART->ier = AVR32_USART_IER_RXRDY_MASK;
print(EXAMPLE_USART, Type a character to use the interrupt handler.\n
It will show up on your screen.\n\n);
// 开启AVR32的全局中断响应,类似AVR的SEI()
Enable_global_interrupt();
while (TRUE);
}
本贴被 Gorgon Meducer 编辑过,最后修改时间:2008-12-03,23:52:51. |
|