【裸机开发】中断系统(二)—— Reset 中断服务函数(汇编实现)

目录

一、Reset 中断服务函数的实现步骤

二、汇编实现 Reset 中断服务函数

1、禁止/打开全局中断

2、设置SP指针

3、清除 .bss 段

4、完整 Reset 中断服务函数


一、Reset 中断服务函数的实现步骤

实现 Reset 中断服务函数的基本步骤如下:

  • 设置各个模式下的SP指针。当中断发生后,会进入到对应的工作模式下,每个工作模式下要运行程序,肯定要用到栈,因此我们需要初始化不同模式下的栈指针。
  • 清除 bss 段。
  • 跳转到 main 函数。

有的时候我们为了防止执行中断服务函数的时候,不会被其他更高优先级的中断打断,我们可以在最开始禁止全局中断(禁止 IRQ、FIQ中断),然后在末尾打开全局中断。

  • 禁止全局中断
  • 设置各个模式下的SP指针
  • 清除 bss 段
  • 打开全局中断
  • 跳转到 main 函数

二、汇编实现 Reset 中断服务函数

1、禁止/打开全局中断

这里我们可以操作 CPSR 寄存器来实现,但汇编给我们提供了简单快捷的指令来禁用/打开全局中断

指令 描述
cpsid i 禁止IRQ中断
cpsie i 使能IRQ中断
cpsid f 禁止 FIQ 中断
cpsie f 使能 FIQ 中断

2、设置SP指针

ARM 一共有九种工作模式,但是这里我们不打算一个个设置,只设置一些可能会用到的,比如 SVC、IRQ、USER、SYS 等。因为 SYS 和 USER 模式共用一个SP指针,即共用一个栈,所以二选一设置即可。(每种模式下的栈都给 2 M 大小

每一种模式下的 SP 设置方式都类似:

  • 修改 CPSR 寄存器切换到某一模式下
  • 设置该模式下的SP指针(R13寄存器)

【裸机开发】中断系统(二)—— Reset 中断服务函数(汇编实现)_第1张图片

/* 切换到 SVC 模式 */
mrs r0, cpsr                @ 将 cpsr 寄存器的内容读取到 r0 寄存器
bic r0, r0, #0x1f           @ 将 r0 的低五位清零,运算结果放到 r0
orr r0, r0, #0x13           @ 让 r0 的低五位或上 10011(0x13),结果保存到 r0
msr cpsr, r0                @ 将 r0 的值写入到 cpsr 寄存器
ldr sp,=0x80200000          @ 设置栈指针

/* 切换到 SYS 模式 */
mrs r0, cpsr                @ 将 cpsr 寄存器的内容读取到 r0 寄存器
bic r0, r0, #0x1f           @ 将 r0 的低五位清零,运算结果放到 r0
orr r0, r0, #0x1f           @ 让 r0 的低五位或上 11111(0x1f),结果保存到 r0
msr cpsr, r0                @ 将 r0 的值写入到 cpsr 寄存器
ldr sp,=0x80400000          @ 设置栈指针

/* 切换到 IRQ 模式 */   
mrs r0, cpsr                @ 将 cpsr 寄存器的内容读取到 r0 寄存器
bic r0, r0, #0x1f           @ 将 r0 的低五位清零,运算结果放到 r0
orr r0, r0, #0x12           @ 让 r0 的低五位或上 10010(0x12),结果保存到 r0
msr cpsr, r0                @ 将 r0 的值写入到 cpsr 寄存器
ldr sp,=0x80600000          @ 设置栈指针

3、清除 .bss 段

4、完整 Reset 中断服务函数

/* 复位中断 */ 
Reset_Handler:
    cpsid i                     /* 禁止IRQ */
    cpsid f                     /* 禁止FIQ */

    /* 切换到 SVC 模式 */
    mrs r0, cpsr                @ 将 cpsr 寄存器的内容读取到 r0 寄存器
    bic r0, r0, #0x1f           @ 将 r0 的低五位清零,运算结果放到 r0
    orr r0, r0, #0x13           @ 让 r0 的低五位或上 10011(0x13),结果保存到 r0
    msr cpsr, r0                @ 将 r0 的值写入到 cpsr 寄存器
    ldr sp,=0x80200000          @ 设置栈指针

    /* 切换到 SYS 模式 */
    mrs r0, cpsr                @ 将 cpsr 寄存器的内容读取到 r0 寄存器
    bic r0, r0, #0x1f           @ 将 r0 的低五位清零,运算结果放到 r0
    orr r0, r0, #0x1f           @ 让 r0 的低五位或上 11111(0x1f),结果保存到 r0
    msr cpsr, r0                @ 将 r0 的值写入到 cpsr 寄存器
    ldr sp,=0x80400000          @ 设置栈指针

    /* 切换到 IRQ 模式 */   
    mrs r0, cpsr                @ 将 cpsr 寄存器的内容读取到 r0 寄存器
    bic r0, r0, #0x1f           @ 将 r0 的低五位清零,运算结果放到 r0
    orr r0, r0, #0x12           @ 让 r0 的低五位或上 10010(0x12),结果保存到 r0
    msr cpsr, r0                @ 将 r0 的值写入到 cpsr 寄存器
    ldr sp,=0x80600000          @ 设置栈指针

    /* bss 段清零 */
    ldr r0, =__bss_start
    ldr r1, =__bss_end
    mov r2, #0
    bl bss_loop                 @ 跳转到 bss_loop,LR寄存器自动保存下一条指令地址

    cpsie f                     /* 使能FIQ */
    cpsie i                     /* 使能IRQ */

    b main                      @ 跳转到 main 函数

bss_loop:
    stmia, r0!, {0}
    cmp r0, r1
    bne bss_loop

    mov pc, lr                  @ 清零完毕后回到原位置

跳转指令参考:b、bl 跳转指令

你可能感兴趣的:(#,裸机开发,单片机,嵌入式硬件)