一. 中斷概念編程
CPU在工做的過程當中,常常須要與外設進行交互,交互的方式包括「輪詢方式」,「中斷方式」。oop
CPU不斷地查詢設備的狀態。該方式實現比較簡單,可是CPU利用率很低,不適合多任務的系統。字體
CPU在告知硬件開始一項工做後,就去作別的事去了,當硬件完成了該項工做後,向CPU發送一個信號,告知CPU它已經完成了這項工做。這種方式就是咱們所說的中斷。fetch
串口控制器——中斷控制器——CPU核優化
串口產生了事件,可是事件並非直接送到CPU,而是送到中斷處理器,進行判斷是否適合CPU來處理,如果適合CPU的處理,就將事件傳送給CPU。具體的流程能夠變成以下的方式:生命週期
中斷信號產生(中斷源)——中斷信號過濾(中斷控制器)——中斷信號處理(CPU)事件
二. 中斷源it
在中斷的生命週期中,中斷源的做用是負責產生中斷信號。(芯片手冊瀏覽中斷源)io
S3C2440支持60箇中斷源;S3C6410支持64中斷源;S5PV210支持93箇中斷源。asm
第一關卡:
SUBSRCPND:當外界來了中斷的時候,對應的只中斷就會被置1。裏面的每一個位對應一個只中斷。
SUBMASK:進行第一重過濾,每一位對應着一個只中斷,咱們把相應的位設置爲1,就是把該位屏蔽了。0表示容許經過。
第二關卡:
SRCPND:進行中斷的斷定。
MASK:中斷的過濾。
Mode:判斷中斷是優先的仍是普通的
Priority:判斷多箇中斷的優先級別
S3C2440支持60箇中斷源;
S3C6410支持64箇中斷源;
S5PV210支持93箇中斷源。(經過芯片手冊瀏覽中斷源)
中斷信號產生(中斷源)——中斷信號過濾(中斷控制器)——中斷信號處理(CPU)
(1)非向量方式(2440)
(2)向量方式(6410/210)
中斷程序總入口——保存環境——判斷中斷源——調用對應該中斷源的中斷處理程序——回覆環境
當中斷產生時CPU直接調轉到用戶設置好的中斷處理程序處——保存環境——設備的中斷處理——恢復環境
以上紅色的字體表示咱們須要用軟件來實現的操做。
一.程序結構優化
將完整的程序劃分爲多個曉得程序。
二.中斷編程
l Botton
#define GPFCON (volatile unsigned long *)0x56000050
/*
* K1,K2,K3,K4對應GPF一、GPF四、GPF二、GPF0
*/
#define GPF0_int (0x2<<(0*2))
#define GPF1_int (0x2<<(1*2))
#define GPF2_int (0x2<<(2*2))
#define GPF4_int (0x2<<(4*2))
#define GPF0_msk (3<<(0*2))
#define GPF1_msk (3<<(1*2))
#define GPF2_msk (3<<(2*2))
#define GPF4_msk (3<<(4*2))
void button_init()
{
*(GPFCON) &= ~(GPF0_msk | GPF1_msk | GPF2_msk | GPF4_msk);
*(GPFCON) |= GPF0_int | GPF1_int | GPF2_int | GPF4_int;
}
l Interrupt
/*interrupt registes*/
#define SRCPND (volatile unsigned long *)0x4A000000
#define INTMOD (volatile unsigned long *)0x4A000004
#define INTMSK (volatile unsigned long *)0x4A000008
#define PRIORITY (volatile unsigned long *)0x4A00000c
#define INTPND (volatile unsigned long *)0x4A000010
#define INTOFFSET (volatile unsigned long *)0x4A000014
#define SUBSRCPND (volatile unsigned long *)0x4A000018
#define INTSUBMSK (volatile unsigned long *)0x4A00001c
#define EINTMASK (volatile unsigned long *)0x560000a4
#define EINTPEND (volatile unsigned long *)0x560000a8
void init_irq()
{
// 對於EINT4,須要在EINTMASK寄存器中使能它
*(EINTMASK) &= ~(1<<4);
// EINT0、EINT一、EINT二、EINT4_7使能
*(INTMSK) &= (~(1<<0)) & (~(1<<1)) & (~(1<<2)) & (~(1<<4));
__asm__(
/*開中斷*/
"mrs r0,cpsr\n"
"bic r0, r0, #0x80\n"
"msr cpsr_c, r0\n"
:
:
);
}
void handle_int()
{
/*讀取產生中斷的源*/
unsigned long value = *(INTOFFSET);
switch(value)
{
case 0: //EINT0~K4
led_on();
break;
case 1: //EINT1~K1
led_off();
break;
case 2: //EINT2~K3
led_on();
break;
case 4: //EINT4~K2
led_off();
break;
default:
break;
}
/* 中斷清除 */
if(value == 4)
*(EINTPEND) = (1 << 4);
*(SRCPND) = 1 << value;
*(INTPND) = 1 << value;
}
l Led
#define GPBCON (volatile unsigned long*)0x56000010
#define GPBDAT (volatile unsigned long*)0x56000014
#define GPB5_out (1<<(5*2))
#define GPB6_out (1<<(6*2))
#define GPB7_out (1<<(7*2))
#define GPB8_out (1<<(8*2))
void led_init()
{
*(GPBCON) = GPB5_out | GPB6_out | GPB7_out | GPB8_out;
}
void led_off()
{
*(GPBDAT) = 0x7ff;
}
void led_on()
{
*(GPBDAT) = 0x61f;
}
l Main
int gboot_main()
{
#ifdef MMU_ON
mmu_init();
#endif
led_init();
button_init();
init_irq();
while(1);
return 0;
}
l MMU
/*
* 用於段描述符的一些宏定義
*/
#define MMU_FULL_ACCESS (3 << 10) /* 訪問權限 */
#define MMU_DOMAIN (0 << 5) /* 屬於哪一個域 */
#define MMU_SPECIAL (1 << 4) /* 必須是1 */
#define MMU_CACHEABLE (1 << 3) /* cacheable */
#define MMU_BUFFERABLE (1 << 2) /* bufferable */
#define MMU_SECTION (2 << 0) /* 段描述符 */
#define MMU_SECDESC (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL | MMU_SECTION)
#define MMU_SECDESC_WB (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL | MMU_CACHEABLE | MMU_BUFFERABLE | MMU_SECTION)
void create_page_table(void)
{
unsigned long *ttb = (unsigned long *)0x31000000;
unsigned long vaddr, paddr;
vaddr = 0x00000000;
paddr = 0x30000000;
*(ttb + (vaddr >> 20))= (paddr & 0xfff00000) | MMU_SECDESC_WB;
vaddr = 0x56000000;
paddr = 0x56000000;
*(ttb + (vaddr >> 20)) = (paddr & 0xFFF00000) | MMU_SECDESC;
vaddr = 0x4A000000;
paddr = 0x4A000000;
*(ttb + (vaddr >> 20)) = (paddr & 0xfff00000) | MMU_SECDESC;
vaddr = 0x30000000;
paddr = 0x30000000;
while (vaddr < 0x34000000)
{
*(ttb + (vaddr >> 20)) = (paddr & 0xFFF00000) | MMU_SECDESC_WB;
vaddr += 0x100000;
paddr += 0x100000;
}
}
void mmu_enable()
{
__asm__(
/*設置TTB*/
"ldr r0, =0x31000000\n"
"mcr p15, 0, r0, c2, c0, 0\n"
/*不進行權限檢查*/
"mvn r0, #0\n"
"mcr p15, 0, r0, c3, c0, 0\n"
/*使能MMU*/
"mrc p15, 0, r0, c1, c0, 0\n"
"orr r0, r0, #0x0001\n"
"mcr p15, 0, r0, c1, c0, 0\n"
:
:
);
}
void mmu_init()
{
create_page_table();
mmu_enable();
}
l Start.s
.text
.global _start
_start:
b reset
ldr pc, _undifined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
_undifined_instruction: .word undifined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort: .word data_abort
_not_used: .word not_used
_irq: .word irq
_fiq: .word reset
undifined_instruction:
nop
software_interrupt:
nop
prefetch_abort:
nop
data_abort:
nop
not_used:
nop
irq:
sub lr, lr, #4
stmfd sp!, {r0-r12, lr} /* 保護現場 */
bl handle_int
ldmfd sp!, {r0-r12, pc}^ /* 恢復現場,^表示把spsr恢復到cpsr */
fiq:
nop
reset:
bl set_svc
bl disable_watchdog
bl disable_interrupt
bl disable_mmu
bl init_clock
bl init_sdram
bl copy_to_ram
bl init_stack
bl clean_bss
ldr pc, =gboot_main
@ bl light_led
set_svc:
mrs r0, cpsr
bic r0, r0,#0x1f
orr r0, r0,#0xd3
msr cpsr, r0
mov pc, lr
#define pWTCON 0x53000000
disable_watchdog:
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]
mov pc, lr
disable_interrupt:
mvn r1, #0x0
ldr r0, =0x4a000008
str r1, [r0]
mov pc, lr
disable_mmu:
mcr p15,0,r0,c7,c7,0
mrc p15,0,r0,c1,c0,0
bic r0, r0, #0x00000007
mcr p15,0,r0,c1,c0,0
mov pc, lr
#define CLKDIVN 0x4c000014
#define MPLLCON 0x4c000008
#define MPLL_405MHZ ((127<<12)|(2<<4)|(1<<0))
init_clock:
ldr r0, =CLKDIVN
mov r1, #0x5
str r1, [r0]
mcr p15,0,r0,c1,c0,0
orr r0,r0,#0xc0000000
mcr p15,0,r0,c1,c0,0
ldr r0, =MPLLCON
ldr r1, =MPLL_405MHZ
str r1, [r0]
mov pc, lr
#define mem_contrl 0x48000000
init_sdram:
ldr r0, =mem_contrl
add r3, r0, #4*13
adrl r1, mem_data
0:
ldr r2, [r1], #4
str r2, [r0], #4
cmp r0, r3
bne 0b
mov pc, lr
copy_to_ram:
ldr r0, =0x0
ldr r1, =0x30008000
add r3, r0, #1024*4
copy_loop:
ldr r2, [r0], #4
str r2, [r1], #4
cmp r0, r3
bne copy_loop
mov pc, lr
init_stack:
msr cpsr_c, #0xd2
ldr sp, =0x33000000 @此處實際設置的是r13_irq
msr cpsr_c, #0xd3
ldr sp, =0x34000000 @此處實際設置的是r13_svc
mov pc, lr
clean_bss:
ldr r0, =bss_start
ldr r1, =bss_end
cmp r0, r1
moveq pc, lr
clean_loop:
mov r2, #0
str r2, [r0], #4
cmp r0, r1
bne clean_loop
mov pc, lr
mem_data:
.long 0x22000000
.long 0x00000700
.long 0x00000700
.long 0x00000700
.long 0x00000700
.long 0x00000700
.long 0x00000700
.long 0x00018001
.long 0x00018001
.long 0x008c04f5
.long 0x000000b1
.long 0x00000030
.long 0x00000030
#define GPBCON 0x56000010
#define GPBDAT 0x56000014
light_led:
ldr r0, =GPBCON
ldr r1,=0x15400
str r1, [r0]
ldr r0, =GPBDAT
ldr r1,=0x6BF
str r1, [r0]
mov pc, lr
當完成全部的程序編程後,咱們要不一些過濾用的寄存器清零。