本文主要探讨轮询按键和中断安按键的相关知识。
按键
无按下,GPIO引脚处高电平,电路断开
按下,GPIO引脚接低电平,电路导通
SoC内部通过检测GPIO电平高低判断按键作为SoC的输入信号
按键响应
轮询方式:SoC每隔一段时间读取GPIO电平获取按键信息,影响CPU处理其他事务
中断方式:设定GPIO触发中断处理程序ISR,按键触发GPIO外部中断,ISR程序处理按键信息
轮询处理按键
按键
SW5:GPH0_2
SW6:GPH0_3
SW7:GPH2_0
SW8:GPH2_1
SW9:GPH2_2
SW10:GPH2_3
初始化GPIO模式为input,循环读取GPIO的电平值,判断按键,并串口输出
按键消抖
电平高到低(按键按下)或电平低到高(按键弹起)电平变化不是瞬时变化,是有短暂的稳定后变化
触发按键按下/弹起,延时时间(10~20ms)再次获取按键信息和上次对比,若相同则认为弹起或按下
demo1:
轮询按键延时监测,不同led灯亮表示不同按键按下
start.S
#define WTCON 0xE2700000
#define SVC_STACK 0xd0037d80
.global _start
_start:
//关看门狗
ldr r0, =WTCON
ldr r1, =0x0
str r1, [r0]
//设置SVC栈
ldr sp, =SVC_STACK
//开/关icache
mrc p15,0,r0,c1,c0,0; // 读出cp15的c1到r0中
orr r0, r0, #(1<<12) // bit12 置1 开icache
mcr p15,0,r0,c1,c0,0;
bl key_init
bl key_polling
b .
key.c
#define GPH0CON 0xE0200C00
#define GPH0DAT 0xE0200C04
#define GPH2CON 0xE0200C40
#define GPH2DAT 0xE0200C44
#define rGPH0CON (*(volatile unsigned int *)GPH0CON)
#define rGPH0DAT (*(volatile unsigned int *)GPH0DAT)
#define rGPH2CON (*(volatile unsigned int *)GPH2CON)
#define rGPH2DAT (*(volatile unsigned int *)GPH2DAT)
void key_init(void)
{
// 设置GPHxCON寄存器,设置为输入模式
rGPH0CON &= ~(0xFF<<8);
rGPH2CON &= ~(0xFFFF<<0);
}
void key_polling(void)
{
while (1)
{
if (rGPH0DAT & (1<<2))
{
//按键未按下
led_off();
}
else
{
//LEFT按键按下
delay_time();
led1();
}
if (rGPH0DAT & (1<<3))
{
//按键未按下
led_off();
}
else
{
//DOWN按键按下
delay_time();
led2();
}
if (rGPH2DAT & (1<<0))
{
//按键未按下
led_off();
}
else
{
//UP按键按下
delay_time();
led3();
}
}
}
led.c
#define GPJ0CON 0xE0200240
#define GPJ0DAT 0xE0200244
#define rGPJ0CON *((volatile unsigned int *)GPJ0CON)
#define rGPJ0DAT *((volatile unsigned int *)GPJ0DAT)
//亮1个led
void led1()
{
rGPJ0CON = 0x11111111;
rGPJ0DAT = ((0<<3) | (1<<4) | (1<<5));
}
//亮2个led
void led2()
{
rGPJ0CON = 0x11111111;
rGPJ0DAT = ((0<<3) | (0<<4) | (1<<5));
}
//亮3个led
void led3()
{
rGPJ0CON = 0x11111111;
rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5));
}
//led灭
void led_off()
{
rGPJ0CON = 0x11111111;
rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));
}
//延时
void delay_time()
{
unsigned volatile int i = 900000;
while(i--);
}
Makefile
key.bin: start.o led.o key.o
arm-linux-ld -Ttext 0x0 -o key.elf $^
arm-linux-objcopy -O binary key.elf key.bin
arm-linux-objdump -D key.elf > key.dis
gcc mkv210_image.c -o mkx210
./mkx210 key.bin 210.bin
%.o : %.S
arm-linux-gcc -o $@ $< -c -nostdlib
%.o : %.c
arm-linux-gcc -o $@ $< -c -nostdlib
clean:
rm *.o *.elf *.bin *.dis mkx210 -f
210外部中断
外部中断是SoC外部设备通过GPIO引脚产生的中断,GPIO配置为外部中断模式,按键触发电压高低会触发外部中断通过引脚传给CPU处理
电平触发分为高电平触发和低电平触发,GPIO上电平会不停触发中断。
边沿触发分为上升沿触发、下降沿触发和双边沿触发,边沿触发即为电平变化的瞬间触发
按键
同上
GPIO
同上
外部中断关键寄存器:EXT_CON、EXT_PEND、EXT_MASK
EXT_INT_n_CON配置外部中断触发方式
EXT_INT_n_PEND是中断挂起,中断触发设置1,若为处理则一直为1直至处理
EXT_INT_n_MASK中断使能或禁止禁止开关。
EINT2、EINT3、EINT16_19(VIC0)
中断
单核CPU不能并行执行事务,需要中断机制,断开在执行事务处理中断,结束后返回继续执行事务
异常处理程序和异常向量表绑定,异常触发后cpu跳转到异常向量表执行绑定的处理程序
中断处理使用汇编实现跳转和返回
跳转到IRQ,保存SVC下寄存器(保存r0~r12(scv),保存运行地址(svc)到lr(irq),保存cpsr(svc)到spsr(irq))
210中断
异常向量表跳转
保存现场:
跳转到IRQ
保存SVC下寄存器(保存r0~r12(scv)
保存运行地址(svc)到lr(irq)
保存cpsr(svc)到spsr(irq))
执行异常处理程序irq_handler
210有4个中断寄存器,每位对应一个中断源
中断发生irq_handler查询置1位,判断中断编号和寄存器
210中断寄存器
VICnINTENABLE和VICnINTENCLEAR
VICnINTENABLE 中断使能
INTENCLEAR 中断禁止
使能VICnINTENABLE对应位写1
禁止INTENCLEAR对应位写1
不存在同为1或0冲突,使能或禁止时另一寄存器会被自发修改
VICnINTSELECT
设置对应位中断模式为irq或fiq
fiq模式有专有的r8~r12
VICnIRQSTATUS和VICnFIQSTATUS
中断状态寄存器且只读,发生中断,对应位自发置1,由此获得中断编号
VICnVECTPRIORITY0~VICnVECTPRIORITY31
中断优先级设置
VICnVECTADDR0~VICnVECTADDR31、VICnADDRESS
VICnVECTADDR存放各中断isr函数地址
VICnADDRESS发生中断,自动识别中断编号并且会自动找到对应VECnTADDR,复制isr函数地址到VICADDRESS
demo2:
按键中断监测,printf串口打印哪个按键被按下
start.S
#define WTCON 0xE2700000
#define SVC_STACK 0xd0037d80
#define IRQ_STACK 0xd0037f80
.global IRQ_handle
.global _start
_start:
//关看门狗
ldr r0, =WTCON
ldr r1, =0x0
str r1, [r0]
//设置SVC栈
ldr sp, =SVC_STACK
//开/关icache
mrc p15,0,r0,c1,c0,0; // 读出cp15的c1到r0中
orr r0, r0, #(1<<12) // bit12 置1 开icache
mcr p15,0,r0,c1,c0,0;
bl main
b .
//现场保护和恢复,调用中断处理程序
IRQ_handle:
//设置IRQ模式下的栈
ldr sp, =IRQ_STACK
// 保存LR
sub lr, lr, #4
//保存r0-r12和lr到irq模式下的栈
stmfd sp!, {r0-r12, lr}
//调用isr处理程序
bl irq_handler
//恢复现场
ldmfd sp!, {r0-r12, pc}^
main.c
#include "stdio.h"
#include "uart.h"
#include "key.h"
#include "interrupt.h"
#define KEY_EINT2 NUM_EINT2 //left
#define KEY_EINT3 NUM_EINT3 //down
#define KEY_EINT16_19 NUM_EINT16_31 //else
void dealy_time()
{
unsigned int i = 900000;
while(i--);
}
int main()
{
//初始化串口
init_uart();
//初始化按键
key_init_interrupt();
//初始化中断控制器
system_init_exception();
//绑定isr到中断控制器硬件
intc_setvectaddr(KEY_EINT2, isr_eint2);
intc_setvectaddr(KEY_EINT3, isr_eint3);
intc_setvectaddr(KEY_EINT16_19, isr_eint16_19);
//使能中断
intc_enable(KEY_EINT2);
intc_enable(KEY_EINT3);
intc_enable(KEY_EINT16_19);
//延时
while (1)
{
dealy_time();
}
return 0;
}
uart.c
#define GPA0CON0 0xE0200000
#define UCON0 0xE2900004
#define ULCON0 0xE2900000
#define UMCON0 0xE290000C
#define UFCON0 0xE2900008
#define UBRDIV0 0xE2900028
#define UDIVSLOT0 0xE290002C
#define UTRSTAT0 0xE2900010
#define UTXH0 0xE2900020
#define URXH0 0xE2900024
#define rGPA0CON0 (*(volatile unsigned int *)GPA0CON0)
#define rUCON0 (*(volatile unsigned int *)UCON0)
#define rULCON0 (*(volatile unsigned int *)ULCON0)
#define rUMCON0 (*(volatile unsigned int *)UMCON0)
#define rUFCON0 (*(volatile unsigned int *)UFCON0)
#define rUBRDIV0 (*(volatile unsigned int *)UBRDIV0)
#define rUDIVSLOT0 (*(volatile unsigned int *)UDIVSLOT0)
#define rUTRSTAT0 (*(volatile unsigned int *)UTRSTAT0)
#define rUTXH0 (*(volatile unsigned int *)UTXH0)
#define rURXH0 (*(volatile unsigned int *)URXH0)
void init_uart()
{
//set GPIO uart mode(TX,RX)
rGPA0CON0 &= ~(0xff);
rGPA0CON0 |= ((1 << 2) | (1<< 6));
//set uart polling mode
rUCON0 = 0x5;
//set uart,prohibit afc
rUMCON0 = 0x0;
//set uart,prohibit fifo
rUFCON0 = 0x0;
//set clock device frequence
//DIV_VAL = (PCLK / (bps x 16)) -1
//DIV_VAL = (66000000 / (115200*16)) -1 = 34.8
rUBRDIV0 = 34;
//0.8 * 16 = 13,check 210 table
rUDIVSLOT0 = 0xdfdd;
}
void putc(char cdata)
{
//judge send buff is'not or is empty,then send data
while (!(rUTRSTAT0 & (1 << 1)));
rUTXH0 = cdata;
}
char getc()
{
//judge get buff is'not or is empty,then get data
while (!(rUTRSTAT0 & 1));
return (rURXH0 & 0x0f);
}
uart.h
void init_uart();
void send_data(char cdata);
char get_data();
key.c
#include "stdio.h"
#include "interrupt.h"
#define GPH0CON 0xE0200C00
#define GPH0DAT 0xE0200C04
#define GPH2CON 0xE0200C40
#define GPH2DAT 0xE0200C44
#define rGPH0CON (*(volatile unsigned int *)GPH0CON)
#define rGPH0DAT (*(volatile unsigned int *)GPH0DAT)
#define rGPH2CON (*(volatile unsigned int *)GPH2CON)
#define rGPH2DAT (*(volatile unsigned int *)GPH2DAT)
#define EXT_INT_0_CON 0xE0200E00
#define EXT_INT_2_CON 0xE0200E08
#define EXT_INT_0_PEND 0xE0200F40
#define EXT_INT_2_PEND 0xE0200F48
#define EXT_INT_0_MASK 0xE0200F00
#define EXT_INT_2_MASK 0xE0200F08
#define rEXT_INT_0_CON (*(volatile unsigned int *)EXT_INT_0_CON)
#define rEXT_INT_2_CON (*(volatile unsigned int *)EXT_INT_2_CON)
#define rEXT_INT_0_PEND (*(volatile unsigned int *)EXT_INT_0_PEND)
#define rEXT_INT_2_PEND (*(volatile unsigned int *)EXT_INT_2_PEND)
#define rEXT_INT_0_MASK (*(volatile unsigned int *)EXT_INT_0_MASK)
#define rEXT_INT_2_MASK (*(volatile unsigned int *)EXT_INT_2_MASK)
//按键初始化
void key_init_interrupt()
{
//GPIO模式设置为外部中断模式
rGPH0CON |= 0xFF<<8;
rGPH2CON |= 0xFFFF<<0;
//中断触发模式设置
rEXT_INT_0_CON &= ~(0xFF<<8);
rEXT_INT_0_CON |= ((2<<8)|(2<<12)); //EXT_INT2和EXT_INT3设置为下降沿触发
rEXT_INT_2_CON &= ~(0xFFFF<<0);
rEXT_INT_2_CON |= ((2<<0)|(2<<4)|(2<<8)|(2<<12)); //EXT_INT16_19设置为下降沿触发
//中断允许
rEXT_INT_0_MASK &= ~(3<<2);
rEXT_INT_2_MASK &= ~(0x0f<<0);
//清挂起,清除是写1
rEXT_INT_0_PEND |= (3<<2);
rEXT_INT_2_PEND |= (0x0F<<0);
}
//EINT2按键<==>GPH0_2引脚<==>LEFT按键,处理程序
void isr_eint2()
{
printf("isr_eint2_LEFT.\n");
//清除中断挂起
rEXT_INT_0_PEND |= (1<<2);
intc_clearvectaddr();
}
//EINT3按键<==>GPH0_3引脚<==>DOWN按键,处理程序
void isr_eint3()
{
printf("isr_eint3_DOWN.\n");
//清除中断挂起
rEXT_INT_0_PEND |= (1<<3);
intc_clearvectaddr();
}
void isr_eint16_19()
{
if (rEXT_INT_2_PEND & (1<<0))
{
printf("eint16\n");
}
if (rEXT_INT_2_PEND & (1<<1))
{
printf("eint17\n");
}
if (rEXT_INT_2_PEND & (1<<2))
{
printf("eint18\n");
}
if (rEXT_INT_2_PEND & (1<<3))
{
printf("eint19\n");
}
//清除中断挂起
rEXT_INT_2_PEND |= (0x0f<<0);
intc_clearvectaddr();
}
key.h
void key_init_interrupt();
void isr_eint2();
void isr_eint3();
void isr_eint16_19();
interrupt.c
#include "stdio.h"
#include "interrupt.h"
void reset_exception()
{
printf("reset_exception.\n");
}
void undef_exception()
{
printf("undef_exception.\n");
}
void sotf_int_exception()
{
printf("sotf_int_exception.\n");
}
void prefetch_exception()
{
printf("prefetch_exception.\n");
}
void data_exception()
{
printf("data_exception.\n");
}
//绑定异常向量表;禁止所有中断;选择中断类型为IRQ;清除VICnADDR为0
void system_init_exception()
{
//绑定异常向量表
r_exception_reset = (unsigned int)reset_exception;
r_exception_undef = (unsigned int)undef_exception;
r_exception_sotf_int = (unsigned int)sotf_int_exception;
r_exception_prefetch = (unsigned int)prefetch_exception;
r_exception_data = (unsigned int)data_exception;
r_exception_irq = (unsigned int)IRQ_handle;
//r_exception_fiq = (unsigned int)FIQ_handle;
//初始化中断控制器的基本寄存器
intc_init();
}
//清除中断处理函数地址
void intc_clearvectaddr()
{
// VICxADDR:当前正在处理的中断的中断处理函数的地址
VIC0ADDR = 0;
VIC1ADDR = 0;
VIC2ADDR = 0;
VIC3ADDR = 0;
}
//初始化中断控制器
void intc_init()
{
//禁止所有中断
VIC0INTENCLEAR = 0xffffffff;
VIC1INTENCLEAR = 0xffffffff;
VIC2INTENCLEAR = 0xffffffff;
VIC3INTENCLEAR = 0xffffffff;
//选择中断类型为IRQ
VIC0INTSELECT = 0x0;
VIC1INTSELECT = 0x0;
VIC2INTSELECT = 0x0;
VIC3INTSELECT = 0x0;
//清VICnADDR
intc_clearvectaddr();
}
//绑定我们写的isr到VICnVECTADDR寄存器
void intc_setvectaddr(unsigned long intnum, void (*handler)(void))
{
//VIC0
if(intnum<32)
{
*( (volatile unsigned long *)(VIC0VECTADDR + 4*(intnum-0)) ) = (unsigned)handler;
}
//VIC1
else if(intnum<64)
{
*( (volatile unsigned long *)(VIC1VECTADDR + 4*(intnum-32)) ) = (unsigned)handler;
}
//VIC2
else if(intnum<96)
{
*( (volatile unsigned long *)(VIC2VECTADDR + 4*(intnum-64)) ) = (unsigned)handler;
}
//VIC3
else
{
*( (volatile unsigned long *)(VIC3VECTADDR + 4*(intnum-96)) ) = (unsigned)handler;
}
}
//使能中断
void intc_enable(unsigned long intnum)
{
unsigned long temp;
//确定intnum
if(intnum<32)
{
temp = VIC0INTENABLE;
temp |= (1<<intnum);
VIC0INTENABLE = temp;
}
else if(intnum<64)
{
temp = VIC1INTENABLE;
temp |= (1<<(intnum-32));
VIC1INTENABLE = temp;
}
else if(intnum<96)
{
temp = VIC2INTENABLE;
temp |= (1<<(intnum-64));
VIC2INTENABLE = temp;
}
else if(intnum<NUM_ALL)
{
temp = VIC3INTENABLE;
temp |= (1<<(intnum-96));
VIC3INTENABLE = temp;
}
else
{
VIC0INTENABLE = 0xFFFFFFFF;
VIC1INTENABLE = 0xFFFFFFFF;
VIC2INTENABLE = 0xFFFFFFFF;
VIC3INTENABLE = 0xFFFFFFFF;
}
}
//禁止中断
void intc_disable(unsigned long intnum)
{
unsigned long temp;
if(intnum<32)
{
temp = VIC0INTENCLEAR;
temp |= (1<<intnum);
VIC0INTENCLEAR = temp;
}
else if(intnum<64)
{
temp = VIC1INTENCLEAR;
temp |= (1<<(intnum-32));
VIC1INTENCLEAR = temp;
}
else if(intnum<96)
{
temp = VIC2INTENCLEAR;
temp |= (1<<(intnum-64));
VIC2INTENCLEAR = temp;
}
else if(intnum<NUM_ALL)
{
temp = VIC3INTENCLEAR;
temp |= (1<<(intnum-96));
VIC3INTENCLEAR = temp;
}
else
{
VIC0INTENCLEAR = 0xFFFFFFFF;
VIC1INTENCLEAR = 0xFFFFFFFF;
VIC2INTENCLEAR = 0xFFFFFFFF;
VIC3INTENCLEAR = 0xFFFFFFFF;
}
}
//读取VICnIRQSTATUS判断具体VIC中断
unsigned long intc_getvicirqstatus(unsigned long ucontroller)
{
if(ucontroller == 0)
return VIC0IRQSTATUS;
else if(ucontroller == 1)
return VIC1IRQSTATUS;
else if(ucontroller == 2)
return VIC2IRQSTATUS;
else if(ucontroller == 3)
return VIC3IRQSTATUS;
else
{
}
return 0;
}
//中断处理
void irq_handler(void)
{
unsigned long vicaddr[4] = {VIC0ADDR,VIC1ADDR,VIC2ADDR,VIC3ADDR};
int i=0;
void (*isr)(void) = NULL;
for(i=0; i<4; i++)
{
if(intc_getvicirqstatus(i) != 0)
{
isr = (void (*)(void)) vicaddr[i];
break;
}
}
(*isr)(); //调用函数
}
interrupt.h
#ifndef __INTERRUPT_H__
#define __INTERRUPT_H__
#define VIC0_BASE (0xF2000000)
#define VIC1_BASE (0xF2100000)
#define VIC2_BASE (0xF2200000)
#define VIC3_BASE (0xF2300000)
//VIC0
#define VIC0IRQSTATUS ( *((volatile unsigned long *)(VIC0_BASE + 0x00)) )
#define VIC0FIQSTATUS ( *((volatile unsigned long *)(VIC0_BASE + 0x04)) )
#define VIC0INTSELECT ( *((volatile unsigned long *)(VIC0_BASE + 0x0c)) )
#define VIC0INTENABLE ( *((volatile unsigned long *)(VIC0_BASE + 0x10)) )
#define VIC0INTENCLEAR ( *((volatile unsigned long *)(VIC0_BASE + 0x14)) )
#define VIC0VECTADDR (VIC0_BASE + 0x100)
#define VIC0ADDR ( *((volatile unsigned long *)(VIC0_BASE + 0xf00)) )
//VIC1
#define VIC1IRQSTATUS ( *((volatile unsigned long *)(VIC1_BASE + 0x00)) )
#define VIC1FIQSTATUS ( *((volatile unsigned long *)(VIC1_BASE + 0x04)) )
#define VIC1INTSELECT ( *((volatile unsigned long *)(VIC1_BASE + 0x0c)) )
#define VIC1INTENABLE ( *((volatile unsigned long *)(VIC1_BASE + 0x10)) )
#define VIC1INTENCLEAR ( *((volatile unsigned long *)(VIC1_BASE + 0x14)) )
#define VIC1VECTADDR (VIC1_BASE + 0x100)
#define VIC1ADDR ( *((volatile unsigned long *)(VIC1_BASE + 0xf00)) )
//VIC2
#define VIC2IRQSTATUS ( *((volatile unsigned long *)(VIC2_BASE + 0x00)) )
#define VIC2FIQSTATUS ( *((volatile unsigned long *)(VIC2_BASE + 0x04)) )
#define VIC2INTSELECT ( *((volatile unsigned long *)(VIC2_BASE + 0x0c)) )
#define VIC2INTENABLE ( *((volatile unsigned long *)(VIC2_BASE + 0x10)) )
#define VIC2INTENCLEAR ( *((volatile unsigned long *)(VIC2_BASE + 0x14)) )
#define VIC2VECTADDR (VIC2_BASE + 0x100)
#define VIC2ADDR ( *((volatile unsigned long *)(VIC2_BASE + 0xf00)) )
// VIC3
#define VIC3IRQSTATUS ( *((volatile unsigned long *)(VIC3_BASE + 0x00)) )
#define VIC3FIQSTATUS ( *((volatile unsigned long *)(VIC3_BASE + 0x04)) )
#define VIC3INTSELECT ( *((volatile unsigned long *)(VIC3_BASE + 0x0c)) )
#define VIC3INTENABLE ( *((volatile unsigned long *)(VIC3_BASE + 0x10)) )
#define VIC3INTENCLEAR ( *((volatile unsigned long *)(VIC3_BASE + 0x14)) )
#define VIC3VECTADDR (VIC3_BASE + 0x100)
#define VIC3ADDR ( *((volatile unsigned long *)(VIC3_BASE + 0xf00)) )
#define exception_vector_table_base 0xD0037400
#define exception_reset (exception_vector_table_base + 0x00)
#define exception_undef (exception_vector_table_base + 0x04)
#define exception_sotf_int (exception_vector_table_base + 0x08)
#define exception_prefetch (exception_vector_table_base + 0x0C)
#define exception_data (exception_vector_table_base + 0x10)
#define exception_irq (exception_vector_table_base + 0x18)
#define exception_fiq (exception_vector_table_base + 0x1C)
#define r_exception_reset (*(volatile unsigned int *)exception_reset)
#define r_exception_undef (*(volatile unsigned int *)exception_undef)
#define r_exception_sotf_int (*(volatile unsigned int *)exception_sotf_int)
#define r_exception_prefetch (*(volatile unsigned int *)exception_prefetch)
#define r_exception_data (*(volatile unsigned int *)exception_data)
#define r_exception_irq (*(volatile unsigned int *)exception_irq)
#define r_exception_fiq (*(volatile unsigned int *)exception_fiq)
//中断源编号
#define INT_LIMIT (96)
//INT NUM - VIC0
#define NUM_EINT0 (0)
#define NUM_EINT1 (1)
#define NUM_EINT2 (2)
#define NUM_EINT3 (3)
#define NUM_EINT4 (4)
#define NUM_EINT5 (5)
#define NUM_EINT6 (6)
#define NUM_EINT7 (7)
#define NUM_EINT8 (8)
#define NUM_EINT9 (9)
#define NUM_EINT10 (10)
#define NUM_EINT11 (11)
#define NUM_EINT12 (12)
#define NUM_EINT13 (13)
#define NUM_EINT14 (14)
#define NUM_EINT15 (15)
#define NUM_EINT16_31 (16)
#define NUM_Reserved17 (17)
#define NUM_MDMA (18)
#define NUM_PDMA0 (19)
#define NUM_PDMA1 (20)
#define NUM_TIMER0 (21)
#define NUM_TIMER1 (22)
#define NUM_TIMER2 (23)
#define NUM_TIMER3 (24)
#define NUM_TIMER4 (25)
#define NUM_SYSTIMER (26)
#define NUM_WDT (27)
#define NUM_RTC_ALARM (28)
#define NUM_RTC_TICK (29)
#define NUM_GPIOINT (30)
#define NUM_FIMC3 (31)
//INT NUM - VIC1
#define NUM_CORTEX0 (32+0)
#define NUM_CORTEX1 (32+1)
#define NUM_CORTEX2 (32+2)
#define NUM_CORTEX3 (32+3)
#define NUM_CORTEX4 (32+4)
#define NUM_IEM_APC (32+5)
#define NUM_IEM_IEC (32+6)
#define NUM_Reserved39 (32+7)
#define NUM_NFC (32+8)
#define NUM_CFC (32+9)
#define NUM_UART0 (32+10)
#define NUM_UART1 (32+11)
#define NUM_UART2 (32+12)
#define NUM_UART3 (32+13)
#define NUM_I2C (32+14)
#define NUM_SPI0 (32+15)
#define NUM_SPI1 (32+16)
#define NUM_SPI2 (32+17)
#define NUM_AUDIO (32+18)
#define NUM_I2C_PMIC (32+19)
#define NUM_I2C_HDMI (32+20)
#define NUM_HSIRX (32+21)
#define NUM_HSITX (32+22)
#define NUM_UHOST (32+23)
#define NUM_OTG (32+24)
#define NUM_MSM (32+25)
#define NUM_HSMMC0 (32+26)
#define NUM_HSMMC1 (32+27)
#define NUM_HSMMC2 (32+28)
#define NUM_MIPI_CSI (32+29)
#define NUM_MIPI_DSI (32+30)
#define NUM_ONENAND_AUDI (32+31)
//INT NUM - VIC2
#define NUM_LCD0 (64+0)
#define NUM_LCD1 (64+1)
#define NUM_LCD2 (64+2)
#define NUM_LCD3 (64+3)
#define NUM_ROTATOR (64+4)
#define NUM_FIMC_A (64+5)
#define NUM_FIMC_B (64+6)
#define NUM_FIMC_C (64+7)
#define NUM_JPEG (64+8)
#define NUM_2D (64+9)
#define NUM_3D (64+10)
#define NUM_MIXER (64+11)
#define NUM_HDMI (64+12)
#define NUM_HDMI_I2C (64+13)
#define NUM_MFC (64+14)
#define NUM_TVENC (64+15)
#define NUM_I2S0 (64+16)
#define NUM_I2S1 (64+17)
#define NUM_I2S2 (64+18)
#define NUM_AC97 (64+19)
#define NUM_PCM0 (64+20)
#define NUM_PCM1 (64+21)
#define NUM_SPDIF (64+22)
#define NUM_ADC (64+23)
#define NUM_PENDN (64+24)
#define NUM_KEYPAD (64+25)
#define NUM_Reserved90 (64+26)
#define NUM_HASH (64+27)
#define NUM_FEEDCTRL (64+28)
#define NUM_PCM2 (64+29)
#define NUM_SDM_IRQ (64+30)
#define NUM_SMD_FIQ (64+31)
//INT NUM - VIC3
#define NUM_IPC (96+0)
#define NUM_HOSTIF (96+1)
#define NUM_HSMMC3 (96+2)
#define NUM_CEC (96+3)
#define NUM_TSI (96+4)
#define NUM_MDNIE0 (96+5)
#define NUM_MDNIE1 (96+6)
#define NUM_MDNIE2 (96+7)
#define NUM_MDNIE3 (96+8)
#define NUM_ADC1 (96+9)
#define NUM_PENDN1 (96+10)
#define NUM_ALL (200)
void system_init_exception();
void intc_clearvectaddr();
void intc_init();
void intc_setvectaddr(unsigned long intnum, void (*handler)(void));
void intc_enable(unsigned long intnum);
void intc_disable(unsigned long intnum);
unsigned long intc_getvicirqstatus(unsigned long ucontroller);
void irq_handler(void);
void IRQ_handle();
#endif
Makefile
CC = arm-linux-gcc
LD = arm-linux-ld
OBJCOPY = arm-linux-objcopy
OBJDUMP = arm-linux-objdump
AR = arm-linux-ar
INCDIR := $(shell pwd)
# C预处理器的flag,flag就是编译器可选的选项
CPPFLAGS := -nostdlib -nostdinc -I$(INCDIR)/include
# C编译器的flag
CFLAGS := -Wall -O2 -fno-builtin
#导出这些变量到全局,其实就是给子文件夹下面的Makefile使用
export CC LD OBJCOPY OBJDUMP AR CPPFLAGS CFLAGS
objs := start.o uart.o main.o key.o interrupt.o
objs += lib/libc.a
uart.bin: $(objs)
$(LD) -Ttext 0x0 -o interrupt.elf $^
$(OBJCOPY) -O binary interrupt.elf interrupt.bin
$(OBJDUMP) -D interrupt.elf > interrupt.dis
gcc mkv210_image.c -o mkx210
./mkx210 interrupt.bin 210.bin
lib/libc.a:
cd lib; make; cd ..
%.o : %.S
$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -c
%.o : %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -c
clean:
rm *.o *.elf *.bin *.dis mkx210 -f
cd lib; make clean; cd ..
printf