一:外部中断
在之前我们学习按键驱动的时候,我们检测按键有没有按下是通过轮循的方式(也就是我们说的死循环),这样虽然可以检测实现按键,但太浪费系统资源了,不论我们按键中断有没有发生,cpu都要一直进行检测;这样操作系统就不能做其他事情了,因此这样肯定是不可取得,因此我们可以通过外部中断解决它;
要处理一个中断,我们需要了解模式,而了解模式,有需要了解mmu;在学习这些之后我们就可以返回来处理我们按键驱动的时候留下的问题了;
通过之前的按前驱动我们已经了解了按前驱动在板子上的位置以及按键的电路图以及他的引脚作用,下面我们就如何实现这个程序的步骤:
我们知道控制按键的寄存器为:
外部中断对应的是:
0xf = EXT_INT43[2]
在EXT_INT43[2]中我们选择边沿触发方式:
通过key在核心板的引脚图我们可以知道外部中断源为26,中断号为64
需要我们配置的寄存器:
(1) EXT_INT43PEND (2)EXT_INT43MASK (3)EXT_INT43CON
需要注意的是:中断状态:EXT_INT43_PEND[2],特别注意的是,要清中断,将值赋值为1.
实现一个外部中断大致需要五步:
(1)cpu允许中断
(2)启用GIC
(3)配置外部中断寄存器(xeint)
(4)配置gpio(General Purpose Input Output (通用输入/输出)简称为GPIO,每个GPIO端口可通过软件分别配置成输入或输出)
(5)外部中断源
下面是实现的具体代码:
#ifndef __BUNFLY_H
#define __BUNFLY_H #define ICCICR_CPU0 (*(volatile unsigned long *)0x10480000)
#define ICCPMR_CPU0 (*(volatile unsigned long *)0x10480004)
#define ICDDCR (*(volatile unsigned long *)0x10490000)
#define ICDIPR0_CPU0 (*(volatile unsigned long *)0x10490400)
#define ICDIPTR0_CPU0 (*(volatile unsigned long *)0x10490800)
#define ICDISER0_CPU0 (*(volatile unsigned long *)0x10490100)
#define ICDSGIR (*(volatile unsigned long *)0x10490f00)
#define ICCEOIR_CPU0 (*(volatile unsigned long *)0x10480010)
#define ICCIAR_CPU0 (*(volatile unsigned long *)0x1048000c)
#define ICDIPR2_CPU0 (*(volatile unsigned long *)0x10490408)
#define ICDIPTR2_CPU0 (*(volatile unsigned long *)0x10490808)
#define ICDIPR3_CPU0 (*(volatile unsigned long *)0x1049040c)
#define ICDIPTR3_CPU0 (*(volatile unsigned long *)0x1049080c)
#define ICDIPR16_CPU0 (*(volatile unsigned long *)0x10490440)
#define ICDIPTR16_CPU0 (*(volatile unsigned long *)0x10490840)
#define ICDIPR18_CPU0 (*(volatile unsigned long *)0x10490448)
#define ICDIPTR18_CPU0 (*(volatile unsigned long *)0x10490848)
#define ICDISER2_CPU0 (*(volatile unsigned long *)0x10490108) #define WTCON (*(volatile unsigned long *)0x10060000)
#define WTDAT (*(volatile unsigned long *)0x10060004)
#define WTCNT (*(volatile unsigned long *)0x10060008)
#define WTCLRINT (*(volatile unsigned long *)0x1006000C) #define EXT_INT43_CON (*(volatile unsigned long *)0x11000e0c)
#define EXT_INT43_MASK (*(volatile unsigned long *)0x11000f0c)
#define EXT_INT43_PEND (*(volatile unsigned long *)0x11000f4c)
#define GPX3CON (*(volatile unsigned long *)0x11000c60) #define GPM4CON (*(volatile unsigned long *)0x110002e0)
#define GPM4DAT (*(volatile unsigned long *)0x110002e4) #endif //__BUNFLY_H
#include "bunfly.h" int (*printf)(char *, ...) = 0xc3e114d8;
void enable_mmu();
void init_table(unsigned long *addr);
void memcpy(unsigned char *dest, unsigned char *src, int len);
extern unsigned long vector_start;
void do_irq(); int main()
{
memcpy(0x70000000, vector_start, 0x10000);
enable_mmu(); *(unsigned long *)0x47000000 = do_irq; //step 1: cpu permit interrupt
__asm__ __volatile__ (
"mrs r0, cpsr\n"
"bic r0, r0, #0x80\n"
"msr cpsr, r0\n"
::: "r0"
); //step 2: GIC (cgi) enable
ICCICR_CPU0 = ;//总开关
ICCPMR_CPU0 = 0xff;//总优先级(门槛)
ICDDCR = ; //本中断开关 ICDIPR16_CPU0 = ( << ); //本中断优先级
ICDIPTR16_CPU0 = ( << ); //目标cpu
ICDISER2_CPU0 = ( << ); //启用本中断 //step 3: Xeint
EXT_INT43_CON = ( << );//Triggers Both edge (设置为边沿触发)
EXT_INT43_MASK = ; //开启中断 //step 4: set gpio
GPX3CON = (0xf << ); //0xF = EXT_INT43[2] (gpio配置为外部中断)
//step 5: interrupt source printf("welcome back\n");
} void do_irq()
{
unsigned long data = ICCIAR_CPU0;
int irq = data & 0x3ff; //获得中断号
int cpu = (data >> ) & 0x7; //获得目标cpu
ICCEOIR_CPU0 = irq | (cpu << ); //清除中断
EXT_INT43_PEND |= ( << ); //清中断
printf("key 1 down, cpu is %d, irq is %d\n", cpu, irq);
} void enable_mmu()
{
unsigned long addr = 0x50000000;
init_table(addr);
unsigned long mmu = ;
mmu = | ( << ) | ( << ) | ( << ); __asm__ __volatile__ (
"mov r0, #3\n"
"MCR p15, 0, r0, c3, c0, 0\n"
"MCR p15, 0, %0, c2, c0, 0\n"
"MCR p15, 0, %1, c1, c0, 0\n"
:
: "r" (addr), "r" (mmu)
:
);
} void init_table(unsigned long *addr)
{
unsigned long va = ;
unsigned long phys = ; for(va = 0x40000000; va < 0x80000000; va+=0x100000)
{
phys = va;
addr[va >> ] = phys | ;
} for(va = 0x10000000; va < 0x14000000; va+=0x100000)
{
phys = va;
addr[va >> ] = phys | ;
} for(va = 0x0; va < 0x10000000; va+=0x100000)
{
phys = va + 0x70000000;
addr[va >> ] = phys | ;
}
} __asm__ (
"vector:\n"
" b reset\n"
" b undefined\n"
" b swi\n"
" b pre_abt\n"
" b data_abt\n"
" .word 0x0\n"
" b irq\n"
" b fiq\n" "reset:\n"
"undefined:\n"
" mov sp, #0x47000000\n"
" stmdb sp!, {r0-r12, lr}\n" "ldr r3, =0x47000004\n"
"ldr r2, [r3]\n"
"blx r2\n" " mov sp, #0x47000000\n"
" ldmdb sp, {r0-r12, pc}^\n"
"swi:\n"
" mov sp, #0x47000000\n"
" stmdb sp!, {r0-r12, lr}\n" " mov sp, #0x47000000\n"
" ldmdb sp, {r0-r12, pc}^\n"
"pre_abt:\n"
"data_abt:\n"
" mov sp, #0x47000000\n"
" sub lr, lr, #4\n"
" stmdb sp!, {r0-r12, lr}\n" "ldr r3, =0x47000008\n"
"ldr r2, [r3]\n"
"blx r2\n" " mov sp, #0x47000000\n"
" ldmdb sp, {r0-r12, pc}^\n"
"irq:\n"
" mov sp, #0x47000000\n"
" sub lr, lr, #4\n"
" stmdb sp!, {r0-r12, lr}\n" "mov r3, #0x47000000\n"
"ldr r2, [r3]\n"
"blx r2\n" " mov sp, #0x47000000\n"
" ldmdb sp, {r0-r12, pc}^\n"
"fiq:\n" ".global vector_start\n"
"vector_start:\n"
".word vector\n"
); void memcpy(unsigned char *dest, unsigned char *src, int len)
{
int i = ;
for(i = ; i < len; i++)
dest[i] = src[i];
}
下面我们通过外部中断(KEY1)控制watchdog,在通过watchdog控制led灯,当key1按下时,led灯开始闪烁,再次按下停止闪烁:
下面贴出代码:
#ifndef __BUNFLY_H
#define __BUNFLY_H #define ICCICR_CPU0 (*(volatile unsigned long *)0x10480000)
#define ICCPMR_CPU0 (*(volatile unsigned long *)0x10480004)
#define ICDDCR (*(volatile unsigned long *)0x10490000)
#define ICDIPR0_CPU0 (*(volatile unsigned long *)0x10490400)
#define ICDIPTR0_CPU0 (*(volatile unsigned long *)0x10490800)
#define ICDISER0_CPU0 (*(volatile unsigned long *)0x10490100)
#define ICDSGIR (*(volatile unsigned long *)0x10490f00)
#define ICCEOIR_CPU0 (*(volatile unsigned long *)0x10480010)
#define ICCIAR_CPU0 (*(volatile unsigned long *)0x1048000c)
#define ICDIPR2_CPU0 (*(volatile unsigned long *)0x10490408)
#define ICDIPTR2_CPU0 (*(volatile unsigned long *)0x10490808)
#define ICDIPR3_CPU0 (*(volatile unsigned long *)0x1049040c)
#define ICDIPTR3_CPU0 (*(volatile unsigned long *)0x1049080c)
#define ICDIPR16_CPU0 (*(volatile unsigned long *)0x10490440)
#define ICDIPTR16_CPU0 (*(volatile unsigned long *)0x10490840)
#define ICDIPR18_CPU0 (*(volatile unsigned long *)0x10490448)
#define ICDIPTR18_CPU0 (*(volatile unsigned long *)0x10490848)
#define ICDISER2_CPU0 (*(volatile unsigned long *)0x10490108) #define WTCON (*(volatile unsigned long *)0x10060000)
#define WTDAT (*(volatile unsigned long *)0x10060004)
#define WTCNT (*(volatile unsigned long *)0x10060008)
#define WTCLRINT (*(volatile unsigned long *)0x1006000C) #define EXT_INT43_CON (*(volatile unsigned long *)0x11000e0c)
#define EXT_INT43_MASK (*(volatile unsigned long *)0x11000f0c)
#define EXT_INT43_PEND (*(volatile unsigned long *)0x11000f4c)
#define GPX3CON (*(volatile unsigned long *)0x11000c60) #define GPM4CON (*(volatile unsigned long *)0x110002e0)
#define GPM4DAT (*(volatile unsigned long *)0x110002e4) #endif //__BUNFLY_H
#include "bunfly.h" void (*udelay)(int) = 0xc3e25f90;
int (*printf)(char *, ...) = 0xc3e114d8;
void enable_mmu();
void init_table(unsigned long *addr);
void memcpy(unsigned char *dest, unsigned char *src, int len);
extern unsigned long vector_start;
void do_irq();
void led_on();
void led_off();
void wdt_on();
void wdt_off(); int main()
{
memcpy(0x70000000, vector_start, 0x1000);
enable_mmu(); *(unsigned long *)0x47000000 = do_irq; //step 1: cpu permit interrupt
__asm__ __volatile__(
"mrs r0, cpsr\n"
"bic r0,r0, #0x80\n"
"msr cpsr, r0\n"
:::"r0"
); //step 2: GIC (cgi) enable
ICCICR_CPU0 = ; //总开关
ICCPMR_CPU0 =0xff;//总优先级
ICDDCR = ; //本中断开关 //KEY
ICDIPR16_CPU0 = ( << );//本中断优先级
ICDIPTR16_CPU0 = ( << );//目标cpu
ICDISER2_CPU0 = ( << );//启用本中断 //WDT
ICDIPR18_CPU0 = ( << );
ICDIPTR18_CPU0 = ( << );
ICDISER2_CPU0 = ( << ); //step 3: Xeint
EXT_INT43_CON = (0x2 << );
EXT_INT43_MASK = ; //step 4: set gpio
GPX3CON = (0xf << ); //step 5: interrupt source printf("welcom back\n"); } void do_irq()
{
unsigned long data = ICCIAR_CPU0;
int irq = data & 0x3ff;
int cpu = (data >> ) & 0x7;
ICCEOIR_CPU0 = irq | (cpu << );
static int flags = ; if( == irq) {
printf("key 1 down\n");
if(EXT_INT43_PEND & (0x1 << )) {
EXT_INT43_PEND |= ( << );
if(flags) {
wdt_on();
flags = ;
}
else {
wdt_off();
led_off();
flags = ;
}
}
} if( == irq) {
WTCLRINT = ;//清中断
printf("wang wang wang ...\n");
if(flags) {
led_on();
flags = ;
}
else {
led_off();
flags = ;
}
}
} void led_on()
{
GPM4CON &= ~0xffff;
GPM4CON |= 0x1111;
GPM4DAT &= ~0xf;
} void led_off()
{ GPM4CON &= ~0xffff;
GPM4CON |= 0x1111;
GPM4DAT |= 0xf;
} void wdt_on()
{
WTCNT = 0x8000;
WTDAT = 0x8000;
WTCON = | ( << ) | ( << ) | ( << ) | ( << );
} void wdt_off()
{
WTCON = ;
} void memcpy(unsigned char *dest, unsigned char *src, int len)
{
int i = ;
for(i = ; i < len; i++) {
dest[i] = src[i];
}
} void enable_mmu()
{
/*构建表*/
unsigned long addr = 0x50000000;
init_table(addr);
/*打开mmu*/
unsigned long mmu = ;
mmu = | ( << ) | ( << ) | ( << );
__asm__ __volatile__ (
"mov r0, #3\n"
"MCR p15, 0, r0, c3, c0, 0\n"//设置为管理员
"MCR p15, 0, %0, c2, c0, 0\n"//设置表的地址
"MCR p15, 0, %1, c1, c0, 0\n"//开启mmu
:
: "r" (addr), "r" (mmu)
:
); } __asm__( "vector: \n"
" b reset\n"
" b und\n"
" b swi\n"
" b pre_abt\n"
" b data_abt\n"
" .word 0x0\n"
" b irq\n"
" b fiq\n"
"reset:\n"
"und:\n"
" mov sp, #0x47000000\n"
" stmdb sp!, {r0-r12, lr}\n" " ldr r3, =0x47000004\n"
" ldr r2, [r3]\n"
" blx r2\n" " mov sp, #0x47000000\n"
" ldmdb sp, {r0-r12, pc}^ \n" "swi:\n"
" mov sp, #0x47000000\n"
" stmdb sp!, {r0-r12, lr}^\n" " mov sp, #0x47000000\n"
" ldmdb sp, {r0-r12, pc}^ \n" "pre_abt:\n" "data_abt:\n"
" mov sp, #0x47000000\n"
" sub lr, lr, #4\n"
" stmdb sp!, {r0-r12, lr}\n" " ldr r3, =0x47000008\n"
" ldr r2, [r3]\n"
" blx r2\n" " mov sp, #0x47000000\n"
" ldmdb sp, {r0-r12, pc}^ \n"
"irq:\n" " mov sp, #0x47000000\n"
" sub lr, lr, #4\n"
" stmdb sp!, {r0-r12, lr}\n" " ldr r3, =0x47000000\n"
" ldr r2, [r3]\n"
" blx r2\n" " mov sp, #0x47000000\n"
" ldmdb sp, {r0-r12, pc}^ \n" "fiq:\n" ".global vector_start\n"
"vector_start: \n"
".word vector \n " ); void init_table(unsigned long *addr)
{
unsigned long va = ;
unsigned long phys = ; //0x40000000-0x80000000 -> 0x40000000-0x80000000
for(va = 0x40000000; va < 0x80000000; va += 0x100000) {
phys = va;
addr[va >> ] = phys | ;
} //0x10000000-0x14000000 -> 0x10000000-0x140000000
for(va = 0x10000000; va < 0x14000000; va += 0x100000) {
phys = va;
addr[va >> ] = phys | ;
}
//0x10000000-0x14000000 -> 0x10000000-0x140000000
for(va = 0x0; va < 0x10000000; va += 0x100000) {
phys = va + 0x70000000;
addr[va >> ] = phys | ;
} }