单片机
返回首页

s3c6410裸机程序(2)

2024-09-03 来源:cnblogs

本来以为自己可以很快就把中断程序写好的,但是没想到知道昨天才有了点眉目,虽然还不知道对不对,但是写出来给大家批评指正。


笔者自从上次写了一个轮询式的按键驱动LED灯之后就一直在弄中断这一部分,可是弄来弄去都没什么起色,只好也中断一段时间去配置自己的linux系统,写写应用程序,果然停了几天后突然就成了,真是不知道怎么回事。下面说说笔者的思路。


笔者从《ARM体系结构与编程》这本书中知道了ARM中有七种中断,中断需要中断向量表,而且中断向量表需要放在最低端从地址空间0开始的连续32字节内,为什么七个中断要32字节呢?因为倒数第三个四字节的空间需要空出来。然后是ARM中的中断处理体系,想必阅者都知道x86的中断过程吧,外设通过外设控制器发出中断信号,被中断控制器拦截并进行一定的处理然后发送给CPU,那么ARM肯定也是有中断控制器的,是什么呢?根据s3c6410的用户手册,笔者知道了叫作VIC(全称的中文翻译叫作中断向量控制器)。这个VIC就相当于PC机中的APIC,下面是出事换VIC的代码:


/* 先清除所有中断*/

rVIC0INTENCLEAR = ~(0x0);

rVIC1INTENCLEAR = ~(0x0);

 

 

/* 置中断类型, 全部为IRQ中断*/

rVIC0INTSELECT = 0x0;

rVIC1INTSELECT = 0x0;

 

rVIC0INTENABLE |= 1 << 0;

rVIC0INTENABLE |= 1 << 1;


这个其实很简单,就是让所有中断无效,然后使能按键中断。初始化了VIC之后呢?中断需要三方面协调才可以发生,中断控制器是一个方面,除此之外cpu要能够接受中断,还有就是外设要能够发送中断信号。下面初始化按键:


tmp = rGPNCON;

tmp &= ~0xFFF;

tmp |= 0xAAA;   // 六个按键全部为设置为中断引脚

rGPNCON = tmp; 

rGPNPUD &= ~0xFFF;

 

tmp = rEINT0PEND;

tmp |= 0x1;

tmp |= 0x1 << 1;

rEINT0PEND = tmp;

 

 

tmp = rEINT0MASK;

tmp &= ~(0x3F);

rEINT0MASK = tmp;

 

初始化按键除了要把引脚设置为中断模式外,还有比较重要的就是要清除中断状态寄存器(向对应位写’1‘)和清除中断屏蔽寄存器(对应位清0)。


到了这里似乎就万事俱备,只差中断程序了,但是笔者上次就是在这里遇到了问题,中断向量表要求在地址空间的最低端,但是SDRAM是从0x50000000开始的,程序肯定要下载到这个地址之后的空间,那么笔者自己写的中断向量表怎么办呢?于是笔者想到了使用MMU,把0地址映射到物理地址的0x50200000(程序下载到这个地方),其它部分做相同映射:


start

Interrupt_Vec                         ; 中断向量表

    ldr     PC, ResetAddr

    ldr     PC, UndefAddr

    ldr     PC, SWIAddr

    ldr     PC, PrefetchAddr

    ldr     PC, DataAbortAddr

    DCD     0x0

    ldr     PC, IRQAddr

    ldr     PC, FIQAddr

     

ResetAddr   DCD     ResetInit

UndefAddr   DCD     UndefHandler

SWIAddr     DCD     SWIHandler

PrefetchAddr    DCD     PrefetchHandler

DataAbortAddr   DCD     DataAbortHandler

            DCD     0x0

IRQAddr     DCD     IRQHandler

FIQAddr     DCD     FIQHandler

 

ReservedSpace    SPACE  16384 - 64          ; 页表只能16KB对齐

PageTable       SPACE   16384                 ; 页表,只实现一级映射,1MSection

 

 

; 以下是用不到的中断

UndefHandler

    subs        pc, r14, #4

SWIHandler

    subs        pc, r14, #4

PrefetchHandler

    subs        pc, r14, #4

DataAbortHandler

    subs        pc, r14, #4

FIQHandler

    subs        pc, r14, #4

 

     

EnableMMU

    ; Invalidate entire Cache

    mov     r0, #0

    mcr     p15, 0, r0, c7, c7, 0  

     

    ; Load PageTableBase 

    ldr     r0, =PageTable

    mcr     p15, 0, r0, c2, c0, 0   

     

    ;Field control

    ldr     r0, =0xFFFFFFFF

    mcr     p15, 0, r0, c3, c0, 0

      

     

    ; Enable MMU, Enable I Cache, Disable AP bits

    mrc     p15, 0, r0, c1, c0, 0

    orr     r0, r0, #0x1000

    orr     r0, r0, #0x800000

    orr     r0, r0, #0x1

    mcr     p15, 0, r0, c1, c0, 0

     

     

    mov     pc, r14

    LTORG

     

ResetInit                          ; 复位,设置栈

    LDR     r13, =0x50400000

    bl      _SetPageTable

    bl      EnableMMU

    b       Main

    LTORG

     

IRQHandler                       ; 中断处理

    stmfd   sp!, {r0-r3, r12, r14}

    ldr     r14, =IRQRet

    b       _HandleIRQ

IRQRet

    ldmfd   sp!, {r0-r3, r12, r14}

    subs        pc, r14, #4

     

    LTORG

 至于_SetPageTable这个程序使用c语言实现的:


  


extern int PageTable[];

#define L1_DESCRIPTOR       2

 

int _SetPageTable(void)

{

    int PhyBase;

    int i;

     

    PhyBase = 0x50200000 + L1_DESCRIPTOR;

    PageTable[0] = PhyBase;

     

    for (i = 1; i < 4096; i++)

    {

        PhyBase = 0x0 + L1_DESCRIPTOR + i * 0x00100000;

        PageTable[i] = PhyBase;

    }

    return 0;

}


这样以后,MMU就算是开启了,笔者编译仿真了一下,发现EnableMMU这个程序运行顺利,而且这之后的代码还能正确运行,然后笔者写了中断程序,仍然是按键驱动LED,发现竟然正确运行了。


主函数如下:


void Main(void)

{

 

    InitVIC();  

     

    InitGPIO();

 

    EnableIRQ();

     

    while (1);

}


这就是主流程,可以看出来笔者确实用的中断实现了按键驱动LED。


虽然到这里为止笔者的第一个中断程序算是写出来了,但是上述的程序很容易在中断内部或者InitGPIO函数内死循环,不知道为什么,只好以后解决了,先这样吧!


好文要顶 关注我 收藏该文 微信分享


进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • 家用电源无载自动断电装置的设计与制作

  • 短波AM发射器电路设计图

  • 使用ESP8266从NTP服务器获取时间并在OLED显示器上显示

  • RS-485基础知识:处理空闲总线条件的两种常见方法

  • 如何调制IC555振荡器

  • 基于TDA2003的简单低功耗汽车立体声放大器电路

    相关电子头条文章