新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 根據韋東山修改的mini2440中斷的裸機代碼

        根據韋東山修改的mini2440中斷的裸機代碼

        作者: 時間:2016-11-21 來源:網絡 收藏
        這是根據韋東山的關于中斷的代碼改成在mini2440板子上可以運行的代碼。
        以下是5個文件的所有內容:
        @是注釋符!!

        head.S文件內容:


        @**************************************************************************
        @ File:head.S
        @ 功能:初始化,設置中斷模式、系統模式的棧,設置好中斷處理函數
        @**************************************************************************

        .extern main
        .text
        .global _start
        _start:
        @**************************************************************************
        @ 中斷向量,本程序中,除Reset和HandleIRQ外,其他異常都沒有使用
        @**************************************************************************
        @0x00地址處的指令為"b Reset",在系統復位后,這條指令將跳去執行標號"Reset"開始的代碼
        b Reset

        @0x04:未定義指令終止模式的向量地址
        HandleUndef:
        b HandleUndef

        @0x08:管理模式的向量地址,通過SWI指令進入此模式
        HandleSWI:
        b HandleSWI

        @0x0c:指令預取終止導致的異常的向量地址
        HandlePrefetchAbort:
        b HandlePrefetchAbort

        @0x10:數據訪問終止導致的異常的向量地址
        HandleDataAbort:
        b HandleDataAbort

        @0x14:保留
        HandleNotUsed:
        b HandleNotUsed

        @0x18:中斷模式的向量地址
        b HandleIRQ

        @0x1c:快中斷模式的向量地址
        HandleFIQ:
        b HandleFIQ

        Reset:
        ldr sp,=4096
        @設置棧指針,以下都是C函數,調用前需要設好棧。棧是用 @來保存C函數的變量和返回地址
        bl disable_watch_dog @關閉WATCHDOG,否則CPU會不斷重啟

        msr cpsr_c,#0xd2 @進入中斷模式
        ldr sp,=3072 @設置中斷模式的棧指針,這里的sp寄存器是sp_irq

        msr cpsr_c,#0xdf @進入系統模式
        ldr sp,=4096 @設置系統模式的棧指針,這里的sp寄存器是sp_sys
        @其實復位之后,CPU就處于系統模式
        @前面的"ldr sp,=4096"完成同樣的功能,此句可省略

        bl init_led @初始化LED的GPIO管腳,在init.c中
        bl init_irq @調用中斷初始化函數,在init.c中
        msr cpsr_c,#0x5f @設置I-bit=0,開IRQ中斷

        ldr lr,=halt_loop @設置返回地址
        ldr pc,=main @調用main函數,main函數是個不做任何事的無限循環。當按下按鍵時,這個循環被打斷,CPU進入
        @中斷模式,執行“b HandleIRQ”的指令
        halt_loop:
        b halt_loop

        HandleIRQ: @HandleIRQ開始的代碼用于處理中斷
        sub lr,lr,#4 @計算中斷處理完畢后的返回地址
        stmdb sp!,{r0-r12,lr} @保存使用到的寄存器
        @注意,此時的sp是中斷模式的sp
        @初始值是上面設置的3072

        ldr lr,=int_return @設置調用ISR即EINT_Handle函數后的返回地址
        ldr pc,=EINT_Handle @調用中斷服務函數,在interrupt.c中

        int_return:
        ldmia sp!,{r0-r12,pc}^ @中斷返回,^表示將spsr的值復制到cpsr


        init.c文件內容:








        #define EINTMASK (*(volatile unsigned long*)0x560000a4)//外部中斷屏蔽寄存器
        #define INTMSK (*(volatile unsigned long*)0x4a000008)


        #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))


        #define GPGCON (*(volatile unsigned long*)0x56000060)
        #define GPGDAT (*(volatile unsigned long*)0x56000064)

        #define GPG0_eint (2<<(0*2)) //K1,EINT8
        #define GPG3_eint (2<<(3*2)) //K2,EINT11
        #define GPG5_eint (2<<(5*2)) //K3,EINT13
        #define GPG6_eint (2<<(6*2)) //K4,EINT14



        #define WTCON (*(volatile unsigned long*)0x53000000)

        void disable_watch_dog(void)
        {
        WTCON=0;
        }

        void init_led(void)
        {
        GPBCON=GPB5_out|GPB6_out|GPB7_out|GPB8_out;
        GPBDAT|=(0x0f<<5); //所有LED熄滅,如果沒有這一句,LED燈默認是全亮的
        }



        void init_irq()
        {
        GPGCON=GPG0_eint|GPG3_eint|GPG5_eint|GPG6_eint;

        //對于EINT8,EINT11,EINT13,EINT14,需要在EINTMASK寄存器使能它們
        EINTMASK&=(~(1<<8))&(~(1<<11))&(~(1<<13))&(~(1<<14));
        //這4個外部中斷的優先級是相同的,EINT8_23都接仲裁器的REQ1引腳
        //所以不用像韋東山程序里那樣再設置優先級了

        //EINT8,EINT11,EINT13,EINT14使能
        INTMSK&=(~(1<<5));
        }



        interrupt.c文件內容:


        #define GPBDAT (*(volatile unsigned long*)0x56000014)
        #define INTOFFSET (*(volatile unsigned long*)0x4A000014)
        #define EINTPEND (*(volatile unsigned long*)0x560000a8)
        #define SRCPND (*(volatile unsigned long*)0x4a000000)
        #define INTPND (*(volatile unsigned long*)0x4a000010)

        void EINT_Handle()
        {
        unsigned long oft=INTOFFSET;
        unsigned long val;


        GPBDAT|=(0x0f<<5); //所有LED熄滅,如果沒有這一句,那么會出現一個結果,就是將程序下到板子里運行時,
        //4個LED燈都是滅的,因為在init.c函數里設置它為全滅。然后你按下K1,LED1亮了,
        //再按下K2,LED2亮了,但是LED1卻沒熄滅,知道你按到K4,4個LED全亮,再按就沒變化了
        //加上這一句就不一樣了,每按一個鍵,只亮相應的燈,這也說明中斷的執行情況
        val=EINTPEND; //EINT寄存器,它的位x為1時,表示EINT已經發生(x為4——23)。
        if(val&(1<<8)) //K1被按下,LED1被點亮
        GPBDAT&=~(1<<5);

        if(val&(1<<11)) //K2被按下,LED2被點亮
        GPBDAT&=~(1<<6);

        if(val&(1<<13)) //K3被按下,LED3被點亮
        GPBDAT&=~(1<<7);

        if(val&(1<<14)) //K4被按下,LED4被點亮
        GPBDAT&=~(1<<8);
        //清除中斷
        if(oft==5)
        EINTPEND=(1<<8)|(1<<11)|(1<<13)|(1<<14); //清除EINTPEND寄存器,往某位寫入1即可清楚此位
        SRCPND=1< //清除SRCPND寄存器,往某位寫入1即可清楚此位
        INTPND=1< //清除INTPND寄存器,往某位寫入1即可清楚此位
        //注意:清除順序很重要:先是EINTPEND,然后是SRCPND,最后是INTPND
        }



        main.c文件內容:



        int main()
        {
        while(1);
        return 0;
        }

        Makfile文件內容:

        objs:=head.o init.o interrupt.o main.o

        int.bin:$(objs)
        arm-linux-ld -Ttext 0x00000000 -o int_elf $^
        arm-linux-objcopy -O binary -S int_elf $@
        arm-linux-objdump -D -m arm int_elf > int.dis

        %.o:%.c
        arm-linux-gcc -Wall -O2 -c -o $@ $<

        %.o:%.S
        arm-linux-gcc -Wall -O2 -c -o $@ $<

        clean:
        rm -f int.bin int_elf int.dis *.o


        評論


        技術專區

        關閉
        主站蜘蛛池模板: 平罗县| 徐州市| 绥德县| 江都市| 九江县| 庆城县| 桃源县| 敦煌市| 永城市| 萨嘎县| 雅安市| 榕江县| 临潭县| 渭南市| 昌都县| 临漳县| 吕梁市| 黎城县| 南涧| 留坝县| 江门市| 宜丰县| 鲜城| 澎湖县| 都昌县| 澳门| 双峰县| 云阳县| 娄底市| 乌拉特中旗| 尼木县| 高平市| 广州市| 图木舒克市| 荔浦县| 安西县| 张家口市| 铜陵市| 荆门市| 灵宝市| 兴宁市|