ARM单片机中断的各类问题

引子

还记得在给WS2812B写驱动时,最开始采用的方式是使用DMA向定时器传输数据以满足WS2812B单极性归零码的传输要求,但是实际运行时却发现第一个灯珠的颜色出现了异常,当时真的耽搁了很久,最后也没有找出来是为什么,现在我想就很可能是在配置DMA时发生了中断引起了许多不可控的因素。

中断概述

简单来说,中断及其外围部件包含了中断向量表(用于储存中断的入口地址),NVIC(Nested Vectored Interrupt Controller,嵌套向量中断控制器,用于控制中断使能、优先级等),如果是由外部触发的话还包括EXIT(Extended interrupt and event controller,外部中断事件控制器,用于外部触发中断,这是以STM32为例,其他厂商单片机可能并不是这样设计)。

中断向量表

中断向量表在对应的位置存放中断函数的地址(32位),因此中断向量表其实就相当于一个32位的数组,在启动文件进入主函数之前就需要将中断向量表初始化,并且中断向量表是从0x00000000开始存放的:

; Vector Table Mapped to Address 0 at Reset

                AREA    RESET, DATA, READONLY
                EXPORT  __Vectors
                EXPORT  __Vectors_End
                EXPORT  __Vectors_Size

__Vectors       DCD     __initial_sp              ; Top of Stack
                DCD     Reset_Handler             ; Reset Handler
                DCD     NMI_Handler               ; NMI Handler
                DCD     HardFault_Handler         ; Hard Fault Handler
                DCD     MemManage_Handler         ; MPU Fault Handler
                DCD     BusFault_Handler          ; Bus Fault Handler
                DCD     UsageFault_Handler        ; Usage Fault Handler
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     SVC_Handler               ; SVCall Handler
                DCD     DebugMon_Handler          ; Debug Monitor Handler
                DCD     0                         ; Reserved
                DCD     PendSV_Handler            ; PendSV Handler
                DCD     SysTick_Handler           ; SysTick Handler

MSP

其中在0x00000000处第一个存放的不是任何中断入口,而是__initial_sp(MSP,即SP寄存器的初始值),这个标号在之前定义栈(stack)时出现,代表着栈顶,即栈结束的地址(栈由高向低生长):

; Stack Configuration
; Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>

Stack_Size      EQU     0x00002000

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size
__initial_sp

复位中断

第二个地址是复位中断(软或硬)的入口函数,这个复位中断函数在启动文件中已经有定义(仅为若定义,可以再他处重新定义),这个函数就做了两件事,一件是初始化时钟等(SystemInit),并进入主函数(__main):

Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  SystemInit
                IMPORT  __main

而实际在任何一次的启动过程中都是先将第一个地址装入SP寄存器,然后执行第二个地址的函数(实际将该地址装入PC寄存器),从而实现系统启动。需要注意的是,这里虽然叫复位中断但是实际表现并不像普通的中断,而更类似于普通运行程序,具体可以看硬汉嵌入式论坛 – 【不是问题的问题】为什么复位中断服务程序里面直接调用的main函数,难道所有程序都在复位中断里面执行的?

不可屏蔽中断NMI

随后是NMI(不可屏蔽中断)是由于时钟或者Flash错误等引起的。

Fault中断

HardFault

HardFault是所有类型的错误,这个错误通常是由于内存溢出引起的,一般修改栈的大小即可,也可能是指针越界,未对齐等问题引发。硬 fault 状态寄存器(HFSR),地址:0xE000ED2C

MemManage

MemManage是储存器错误引发中断,一般因为某次访问触犯了 MPU 设置的保护规范。另外,某些非法访问,例如,在不可执行的存储器区域试图取指,也会触发一个MemManage fault,存储器管理 fault 状态寄存器(MFSR),地址:0xE000ED28

BusFault

BusFault是总线错误中断,例如预取指令失败、访问储存器失败。总线 fault 状态寄存器(BFSR),地址:0xE000ED29

UsageFault

UsageFault一般是由于使用未定义的指令或非法状态引起,用法 fault 状态寄存器(UFSR),地址:0xE000ED2A

其他系统中断

剩下的是SVC(SWI调用的系统系统服务),DebugMon(调试监控器),PendSV(可挂起的系统服务),SysTick(系统滴答定时器,用于提供一个基本定时器),剩下的部分就都属于外设中断了,总结如下:

NVIC

NVIC是内核的一个外设,通常通常并不会完整实现,NVIC主要功能是使能或禁用中断,悬起与解悬,设置中断优先级。在发生中断时会优先执行高优先级的中断程序,若优先级相同则比较硬件中断编号,编号小的优先执行。并且在中断过程中不能被同级或更低优先级的中断打断,此时新产生的中断被悬起。

EXIT

EXTI管理中断/事件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿的检测。它不仅可以产生中断,也可以产生事件(比如DMA传输,ADC采样)。中断/事件线一般包含外部引脚、RTC的功能、以太网、USB的唤醒等。一般需要先连接到EXIT,再配置对应的EXIT。

MDK中Fault标志位查看

MDK提供了一个方便的方法来查看Fault的各个标志位,使用方法为在调试时打开菜单栏的Peripherals -> Core Peripherals -> Fault Reports。

各标志位的意义也可以在ARM的手册中找到。

中断屏蔽

__disable_irq()__enable_irq()__set_PRIMASK(1)__set_PRIMASK(0)cmsis_armcc.h)可以控制禁用中断和使能中断,在执行临界操作时需要加上防止因为中断导致配置错误等。

/**
  \brief   Set Priority Mask
  \details Assigns the given value to the Priority Mask Register.
  \param [in]    priMask  Priority Mask
 */
__STATIC_INLINE void __set_PRIMASK(uint32_t priMask)
{
  register uint32_t __regPriMask         __ASM("primask");
  __regPriMask = (priMask);
}

实际上是操控中断屏蔽特殊寄存器PRIMASK来实现的,PRIMASK用于禁止除复位、NMI和HardFalut外的所有异常和中断。实际也可以使用CPS指令:

CPSIE i ;清除PRIMASK(使能中断)
CPSID i ;设置PRIMASK(禁止中断)
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
下一篇