1. NVIC和系统控制块特性

Cortex-M0处理器集成了嵌套向量中断控制器(NVIC),其特性主要包含以下几点:

  • 灵活的中断管理:使能/禁止,优先级配置;

  • 硬件嵌套中断支持

  • 向量化的异常入口

  • 中断屏蔽

Cortex-M0处理器中的NVIC支持最多32个外部中断和一个不可屏蔽中断(NMI),中断输入请求可以是电平触发,也可以脉冲触发。每个外部中断都可以独立地使能或禁止,并且其挂起状态也可以手动地设置和清除。

NVIC的寄存器经过了存储器映射,并且用C语言访问也很容易,其寄存器的起始地址为 0xE000E100。Cortex-M0处理器,对NVIC寄存器的访问必须是每次一个字。

SCB寄存器也可以按照字来访问,起始地址为0xE000E010,SCB寄存器涉及的特性包括SysTick寄存器操作、系统异常管理、优先级控制和休眠模式控制。

STM32F030xx中的core_cm0.h文件定义:

/* Memory mapping of Cortex-M0 Hardware */
#define SCS_BASE            (0xE000E000UL)                            /*!< System Control Space Base Address */
#define CoreDebug_BASE      (0xE000EDF0UL)                            /*!< Core Debug Base Address           */
#define SysTick_BASE        (SCS_BASE +  0x0010UL)                    /*!< SysTick Base Address              */
#define NVIC_BASE           (SCS_BASE +  0x0100UL)                    /*!< NVIC Base Address                 */
#define SCB_BASE            (SCS_BASE +  0x0D00UL)                    /*!< System Control Block Base Address */

#define SCB                 ((SCB_Type       *)     SCB_BASE      )   /*!< SCB configuration struct           */
#define SysTick             ((SysTick_Type   *)     SysTick_BASE  )   /*!< SysTick configuration struct       */
#define NVIC                ((NVIC_Type      *)     NVIC_BASE     )   /*!< NVIC configuration struct          */

2. 中断控制寄存器

中断控制寄存器,用于控制中断请求(异常编号为16及以上)的使能和禁止。寄存器的宽度根据支持的中断数量而不同,最大为32位,最小为1位。可以通过两个独立的地址编程这个寄存器,使能中断时使用SETENA地址,而禁止中断则使用CLRENA地址。

中断使能和清除中断使能和清除.png

将设置和清除操作分为两个不同地址。主要优势有两点:

  • 减少了使能中断所需要的步骤,因此也就减少了程序代码并且降低了执行时间;

  • 多个应用程序进程同时访问寄存器,可能会导致已变成的控制信息丢失,而设置和清除分离则能放置这种情况发生;

例如,使能中断#2,编程NVIC只需要一次访问:

*((volatile unsigned long * )(0xE000E100)) = 0x04;  // 使能中断#2

或者汇编表示:

LDR  R0, = 0xE000E100 ;在R0中设置地址
MOVS  R1, #0x4   ;中断#2
STR  R1, [R0]   ;设置中断使能

开发中,建议使用符合CMSIS设备驱动库里的NVIC控制函数来使能或禁止中断,以提高代码的可移植性。

void NVIC_EnableIRQ(IRQn_Type IRQn);   // 使能中断,IRQn为0时对应中断#0
void NVIC_DisableIRQ(IRQn_Type IRQn);  // 禁止中断,IRQn为0时对应中断#0

3. 中断挂起状态寄存器

如果一个中断发生了,却无法立即处理,这个中断请求将被挂起。挂起状态保存在一个寄存器中,如果处理器的当前优先级还没有降低到可以处理挂起的请求,并且没有手动清除挂起状态,该状态将一直保持合法。

通过操作中断设置挂起(SETPEND)和中断清除挂起(CLRPEND)两个寄存器来访问或修改中断挂起状态。类似中断使能控制寄存器,中断挂起状态寄存器也是物理上为一个寄存器,而通过两个地址来实现设置和清除相关位。

中断挂起和清除挂起中断挂起和清除挂起.png

中断挂起状态寄存器允许使用软件来触发中断。如果中断已经使能并且没有被屏蔽掉,当前还没有更高优先级的中断在运行,这时该中断的服务程序就会几乎立即得以执行。

例如,若触发了中断#2,代码如下:

*((volatile unsigned long *)(0xE000E100)) = 0x4; // 使能中断#2
*((volatile unsigned long *)(0xE000E200)) = 0x4;    // 挂起中断#2

清除#2的挂起状态,代码如下:

*((volatile unsigned long *)(0xE000E280)) = 0x4;    // 挂起中断#2的挂起状态

开发中,建议使用符合CMSIS设备驱动库函数,如下:

void NVIC_SetPendingIRQ(IRQn_Type IRQn);  // 设置中断挂起
void NVIC_ClearPendingIRQ(IRQn_Type IRQn);  // 清除中断挂起
uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn); // 返回true表示中断挂起状态位1

4. 中断优先级

每个外部中断都有一个对应的优先级寄存器,每个优先级都是2位宽,并且使用中断优先级寄存器的最高两位,每个寄存器占1个字节(8位)。Cortex-M0中的NVIC寄存器只支持字传输,这样每次访问都会同时涉及4个中断优先级寄存器。

中断优先级寄存器中断优先级寄存器.png

未使用的位读出为0,写入这些位的操作会被忽略,而读出时则为0。

具体中断优先级寄存器具体中断优先级寄存器.png

由于每次访问优先级寄存器就相当远访问4个中断的优先级,如果只想改变其中的1个,需要将整个字读出,修改1个字节,然后写回整个字。

例如,如果将中断#2的优先级设置为0xC0,代码如下:

unsigned long temp;                                  // 临时变量
temp = *((volatile unsigned long *)(0xE000E400));    // 获取IRP0
temp = temp & (0xFF00FFFF) | (0xC0 << 16);           // 修改优先级
*((volatile unsigned long *)(0xE000E400)) = tmp;     // 设置IRP0

开发中,建议使用符合CMSIS设备驱动库函数,如下:

void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority); // 设置中断或异常优先级
uint32_t NVIC_GetPriority(IRQn_Type IRQn);                // 返回中断或异常优先级

5. 异常屏蔽寄存器(PRIMASK)

有些对时间敏感的应用,需要在一段较短的时间内禁止所有中断。对于这种应用,Cortex-M0没有使用中断使能/禁止控制寄存器来禁止所有中断然后再恢复,而是提供了一个单独的特性,特殊寄存器中有一个被称为PRIMASK,通过它可以屏蔽掉NMI和硬件错误异常的其它所有中断和系统异常。

关于PRIMASK寄存器,可以查看之前章节 2.2 PRIMASK 寄存器

例如,设置PRIMASK(禁止中断),代码如下:

MOVS R0, #1   ;PRIMASK的新值
MSR  PRIMASK, R0  ;将R0的值送到PRIMASK中

另外,也可以使用CPS指令来设置或清除PRIMASK:

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

若使用C语言,建议使用以下函数:

void __enable_irq(void); // 清除PRIMASK
void __disable_irq(void); // 设置PRIMASK

6. 中断处理

Cortex-M0 处理器允许两种形式的中断请求:电平触发和脉冲输入。

使用电平触发中断,当中断事件发生时,由于外设连接到了NVIC上,中断信号会得到确认。在处理器执行中断服务并且清除外设的中断信号以前,该信号保持高电平。在NVIC内部,当检测有中断发生时,该中断的挂起状态会被置位,当处理器接收该中断并且开始执行中断服务程序后,挂起状态就会被清除。

中断激活和挂起中断激活和挂起.png

有些中断源会产生脉冲形式的中断请求(至少持续1个时钟周期)。在这种情况下,在中断得到服务之前,挂起状态寄存器将会一直保持该请求。

脉冲中断激活和挂起脉冲中断激活和挂起.png

7. 系统异常控制寄存器

除了外部中断,有些异常也有可编程的优先级和挂起状态寄存器。对于Cortex-M0,只有3个与OS相关的系统异常才具有可编程的优先级,他们包括SVC、PenSV和SysTick,其他像NMI和硬件错误等系统异常的优先级则固定。

可编程的系统异常控制器可编程的系统异常控制器.png

系统优先级寄存器:

系统优先级寄存器系统优先级寄存器.png

CMSIS中,系统优先级寄存器方式:

CMSIS_系统优先级命名方式CMSIS_系统优先级命名方式.png

SCB相关struct的定义:

/** \brief  Structure type to access the System Control Block (SCB).
 */
typedef struct
{
  __I  uint32_t CPUID;                   /*!< Offset: 0x000 (R/ )  CPUID Base Register                                   */
  __IO uint32_t ICSR;                    /*!< Offset: 0x004 (R/W)  Interrupt Control and State Register                  */
       uint32_t RESERVED0;
  __IO uint32_t AIRCR;                   /*!< Offset: 0x00C (R/W)  Application Interrupt and Reset Control Register      */
  __IO uint32_t SCR;                     /*!< Offset: 0x010 (R/W)  System Control Register                               */
  __IO uint32_t CCR;                     /*!< Offset: 0x014 (R/W)  Configuration Control Register                        */
       uint32_t RESERVED1;
  __IO uint32_t SHP[2];                  /*!< Offset: 0x01C (R/W)  System Handlers Priority Registers. [0] is RESERVED   */
  __IO uint32_t SHCSR;                   /*!< Offset: 0x024 (R/W)  System Handler Control and State Register             */
} SCB_Type;

8. 系统控制寄存器

NVIC地址区域(0xE000E000 ~ 0xE000EFFF)中包含了多个系统控制寄存器,因此NVIC的整个存储区域又被称为系统控制空间(SCS)。

8.1 CPU ID基址寄存器

CPU ID基址寄存器中包含了处理器ID,并且只读的,它为应用软件以及调试器提供了处理器内核类型和版本信息。当前发行的Cortex-M0处理器的CPU ID为0x410CC200,如下图:

CPU_IDCPU_ID.png

CMSIS中,可以使用“SCB -> CPUID“ 来访问CPUID寄存器,如下:

CMSIS_CPU_IDCMSIS_CPU_ID.png

软件可以使用这个寄存器来识别CPU类型,CPUID的Bit[7:4]为“0”代表Cortex-M0,“1”代表Cortex-M1,“3”代表Cortex-M3,以及“4”则代表Cortex-M4。

8.2 应用中断和复位控制寄存器

应用中断和复位控制寄存器(AIRCR)具有多个功能,可以用于应用程序请求系统复位,识别系统的大小端以及清除所有的异常活动状态(只能由调试器完成)。

CMSIS中,可以使用“SCB -> AIRCR”来访问。

应用中断和复位控制寄存器应用中断和复位控制寄存器.png

使用SIRCR寄存器复位系统,可以使用CMSIS函数:

void NVIC_SystemReset(void);

8.3 配置和控制寄存器

Cortex-M0处理器上的配置和控制寄存器(CCR)为只读,它决定了栈的双字对齐设置和非对齐访问处理。

配置和控制寄存器配置和控制寄存器.png

STACKALIGN为1,表示当产生异常压栈时,栈帧总是自动对齐到双字对齐的存储器位置上。UNALIGN_TRP位为1,表示试图执行非对齐访问的操作,会导致错误异常发生。

CMSIS中,可以使用“SCB -> CCR”来访问。

注意:本站所有文章除特别说明外,均为原创,转载请务必以超链接方式并注明作者出处。 标签:ARM,Cortex-M0,Cortex-M0中断控制