×
单片机 > 单片机程序设计 > 详情

OK6410裸机之中断处理过程

发布时间:2020-06-16 发布时间:
|

start.S文件:

.globl _start

_start:

    // 0 地址 

    b reset                                                // 复位时,cpu跳到0地址 

    ldr pc, =undefined_instruction         // cpu遇到不能识别的指令时 

    ldr pc, _vector_swi                              // 当执行swi指令时, 进入swi模 式 

    b halt     @ldr    pc, _prefetch_abort // 预取中止异常 

    b halt     @ldr    pc, _data_abort       // 数据访问异常 

    b halt     @ldr    pc, _not_used          // 没用到 

    ldr    pc, _irq                                       // 0x18 中断异常 

    b halt     @ldr    pc, _fiq                     // 快中断异常 

_irq :

    .word vector_irq

_vector_swi:

    .word vector_swi

   

vector_swi:

    // 1. 保存现场 

    ldr sp, =0x56000000

    stmdb sp!, {r0-r12, lr}      // lr就是swi的下一条指令地址 

    // 2. 处理异常 

    mrs r0, cpsr

    ldr r1, =swi_str

    bl print_cpsr

    // 3. 恢复现场 

    ldmia sp!, {r0-r12, pc}^ // ^表示把spsr恢复到cpsr 

swi_str:

    .word 0x00697773        // swi 

    

undefined_instruction:

    // 1. 保存现场 

    ldr sp, =0x55000000

    stmdb sp!, {r0-r12, lr}

    // 2. 处理异常 

    mrs r0, cpsr

    ldr r1, =und_str

    bl print_cpsr

    // 3. 恢复现场 

    ldmia sp!, {r0-r12, pc}^  // ^表示把spsr恢复到cpsr 

und_str:

    .word 0x00646e75         // und 

usr_str:

    .word 0x00727375         // usr 

vector_irq:

    // 1. 保存现场 

    ldr sp, =0x54000000

    sub lr, lr, #4           

    //为什么这里的lr要减4? 因为在每条指令执行之前判断有无中断,这条指令并未执行,

    //而此时的lr指向了下一条指令,故返回时lr要减4指向那条没有运行的指令

    //只有处理swi和und异常的时候lr指向下一条指令,其他的异常发生的时候lr都是指向下两条指令

    stmdb sp!, {r0-r12, lr}       // lr就是swi的下一条指令地址 

    // 2. 处理异常 

    bl do_irq

    

    // 3. 恢复现场 

    ldmia sp!, {r0-r12, pc}^     // ^表示把spsr恢复到cpsr 

reset:

// 硬件相关的设置 

    // Peri port setup 

    ldr r0, =0x70000000

    orr r0, r0, #0x13

    mcr p15,0,r0,c15,c2,4       @ 256M(0x70000000-0x7fffffff)

    

// 关看门狗 

    // 往WTCON(0x7E004000)写0 

    ldr r0, =0x7E004000

    mov r1, #0

    str r1, [r0]

    

    // 设置栈 

    ldr sp, =8*1024                 // sp_svc 

    // 设置时钟 

    bl clock_init

    bl ddr_init

    bl init_uart

// 把程序的代码段、数据段复制到它的链接地址去     

    adr r0, _start                  // 获得_start指令当前所在的地址 : 0

    ldr r1, =_start                // _start的链接地址 0x51000000 

    

    ldr r2, =bss_start          // bss段的起始链接地址 

    

    sub r2, r2, r1

    

    cmp r0,r1

    beq clean_bss

    

    bl copy2ddr

    cmp r0, #0

    bne halt

        

// 清BSS 

// 把BSS段对应的内存清零 

clean_bss:

    ldr r0, =bss_start

    ldr r1, =bss_end

    mov r3, #0

    cmp r0, r1

    ldreq pc, =on_ddr

clean_loop:

    str r3, [r0], #4

    cmp r0, r1    

    bne clean_loop        

    ldr pc, =on_ddr

on_ddr:    

    bl irq_init

    mrs r0, cpsr

    bic    r0,r0,#0x9f         // 清cpsr的I位,M4~M0 

    orr    r0,r0,#0x10

    msr    cpsr,r0              // 进入user mode 

    ldr sp, =0x57000000  // sp_sys/usr 

    ldr r1, =usr_str

    bl print_cpsr

    

    swi 0

    // cpu进入svc模式

    // 把之前的cpsr保存到spsr_svc 

    // 切换到r13_svc, r14_svc

    // 把swi的下一条指令存到r14(lr)_svc

    // 跳到地址8

              

    bl hello

undef:

    .word 0xff000000

    // cpu进入Undefined模式

    // 把之前的cpsr保存到spsr_und 

    // 切换到r13_und, r14_und

    // 把下一条指令存到r14(lr)_und

    // 跳到地址4

swi_ret:

    bl main

halt:

    b halt    

====================================================================

irq.c源码:

#define GPNCON     (*((volatile unsigned long *)0x7F008830))

#define GPNDAT     (*((volatile unsigned long *)0x7F008834))

#define EINT0CON0  (*((volatile unsigned long *)0x7F008900))

#define EINT0MASK  (*((volatile unsigned long *)0x7F008920))

#define EINT0PEND  (*((volatile unsigned long *)0x7F008924))

#define PRIORITY    (*((volatile unsigned long *)0x7F008280))

#define SERVICE     (*((volatile unsigned long *)0x7F008284))

#define SERVICEPEND (*((volatile unsigned long *)0x7F008288))

#define VIC0IRQSTATUS  (*((volatile unsigned long *)0x71200000))

#define VIC0FIQSTATUS  (*((volatile unsigned long *)0x71200004))

#define VIC0RAWINTR    (*((volatile unsigned long *)0x71200008))

#define VIC0INTSELECT  (*((volatile unsigned long *)0x7120000c))

#define VIC0INTENABLE  (*((volatile unsigned long *)0x71200010))

#define VIC0INTENCLEAR (*((volatile unsigned long *)0x71200014))

#define VIC0PROTECTION (*((volatile unsigned long *)0x71200020))

#define VIC0SWPRIORITYMASK (*((volatile unsigned long *)0x71200024))

#define VIC0PRIORITYDAISY  (*((volatile unsigned long *)0x71200028))

#define VIC0ADDRESS        (*((volatile unsigned long *)0x71200f00))

void irq_init(void)

{

    // 配置GPIO引脚为中断引脚 

    // GPN0~5 设为中断引脚 

    GPNCON &= ~(0xfff);

    GPNCON |= 0xaaa;

    // 设置中断触发方式为: 双边沿触发 

    EINT0CON0 &= ~(0xfff);

    EINT0CON0 |= 0x777;

    // 使能中断 

    EINT0MASK &= ~(0x3f);

    // 在中断控制器里使能这些中断 

    VIC0INTENABLE |= (0x3);          // bit0: eint0~3, bit1: eint4~11  

    // 设置优先级 

}

void do_irq(void)

{

    int i = 0;

    

    printf("do_irq\n\r");

    printf("SERVICE     = 0x%x\n\r", SERVICE);

    printf("SERVICEPEND = 0x%x\n\r", SERVICEPEND);

    printf("EINT0PEND   = 0x%x\n\r", EINT0PEND);  //发生了哪一个外部中断

    

    // 2.1 简单的分辨一下是哪个中断 

    for (i = 0; i < 6; i ++)

    {

        if (EINT0PEND & (1<

        {

            if (GPNDAT & (1<

            {

                printf("K%d released\n\r", i+1);

            }

            else

            {

                printf("K%d pressed\n\r", i+1);

            }

        }

    }

    // 2.2 调用它的处理函数     

    // 2.3 清中断     

    EINT0PEND   = 0x3f;  // 清中断 

    VIC0ADDRESS = 0;

}


关键字:OK6410  裸机  中断  处理过程 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
Keil(MDK-ARM)系列教程(七)_菜单