zoukankan      html  css  js  c++  java
  • 第16章 STM32中断应用概览—零死角玩转STM32-F429系列

    第16章     STM32中断应用概览

    全套200集视频教程和1000PDF教程请到秉火论坛下载:www.firebbs.cn

    野火视频教程优酷观看网址:http://i.youku.com/firege

    本章参考资料《STM32F4xx 中文参考手册》第十章-中断和事件、《 ARM Cortex-M4F 技术参考手册》-4.3 章节:NVIC4.4章节:SCB4.4.5AIRCR

    STM32中断非常强大,每个外设都可以产生中断,所以中断的讲解放在哪一个外设里面去讲都不合适,这里单独抽出一章来做一个总结性的介绍,这样在其他章节涉及到中断部分的知识我们就不用费很大的篇幅去讲解,只要示意性带过即可。

    本章如无特别说明,异常就是中断,中断就是异常,请不要刻意钻牛角尖较劲。

    16.1 异常类型

    F429在内核水平上搭载了一个异常响应系统,支持为数众多的系统异常和外部中断。其中系统异常有10个,外部中断有91个。除了个别异常的优先级被定死外,其它异常的优先级都是可编程的。有关具体的系统异常和外部中断可在标准库文件stm32f4xx.h这个头文件查询到,在IRQn_Type这个结构体里面包含了F4系列全部的异常声明。

    表格 12 F429系统异常清单

    编号

    优先级

    优先级类型

    名称

    说明

    地址

     

    -

    -

    -

    保留(实际存的是MSP地址)

    0X0000 0000

     

    -3

    固定

    Reset

    复位

    0X0000 0004

     

    -2

    固定

    NMI

    不可屏蔽中断。 RCC 时钟安全系统
    (CSS)
    连接到 NMI 向量

    0X0000 0008

     

    -1

    固定

    HardFault

    所有类型的错误

    0X0000 000C

     

    0

    可编程

    MemManage

    存储器管理

    0X0000 0010

     

    1

    可编程

    BusFault

    预取指失败,存储器访问失败

    0X0000 0014

     

    2

    可编程

    UsageFault

    未定义的指令或非法状态

    0X0000 0018

     

    -

    -

    -

    保留

    0X0000 001C-

    0X0000 002B

     

    3

    可编程

    SVCall

    通过 SWI 指令调用的系统服务

    0X0000 002C

     

    4

    可编程

    Debug Monitor

    调试监控器

    0X0000 0030

     

    -

    -

    -

    保留

    0X0000 0034

     

    5

    可编程

    PendSV

    可挂起的系统服务

    0X0000 0038

     

    6

    可编程

    SysTick

    系统嘀嗒定时器

    0X0000 003C

    表格 13 F429外部中断清单

    编号

    优先级

    优先级类型

    名称

    说明

    地址

    0

    7

    可编程

    -

    窗口看门狗中断

    0X0000 0040

    1

    8

    可编程

    PVD

    连接EXTI 线的可编程电压检测中断

    0X0000 0044

    2

    9

    可编程

    TAMP_STAMP

    连接EXTI 线的入侵和时间戳中断

    0X0000 0048

    中间部分省略,详情请参考STM32F4xx 中文参考手册》第十章-中断和事件-向量表部分

    84

    91

    可编程

    SPI4

    SPI4全局中断

    0X0000 0190

    85

    92

    可编程

    SPI5

    SPI5全局中断

    0X0000 0194

    86

    93

    可编程

    SPI6

    SPI6全局中断

    0X0000 0198

    87

    94

    可编程

    SAI1

    SAI1全局中断

    0X0000 019C

    88

    95

    可编程

    LTDC

    LTDC全局中断

    0X0000 01A0

    89

    96

    可编程

    LTDC_ER

    LTDC_ER全局中断

    0X0000 01A4

    90

    97

    可编程

    DMA2D

    DMA2D全局中断

    0X0000 01A8

    16.2 NVIC简介

    在讲如何配置中断优先级之前,我们需要先了解下NVICNVIC是嵌套向量中断控制器,控制着整个芯片中断相关的功能,它跟内核紧密耦合,是内核里面的一个外设。但是各个芯片厂商在设计芯片的时候会对Cortex-M4内核里面的NVIC进行裁剪,把不需要的部分去掉,所以说STM32NVICCortex-M4NVIC的一个子集。

    16.2.1 NVIC寄存器简介

    在固件库中,NVIC的结构体定义可谓是颇有远虑,给每个寄存器都预览了很多位,恐怕为的是日后扩展功能。不过STM32F429可用不了这么多,只是用了部分而已,具体使用了多少可参考《 ARM Cortex-M4F 技术参考手册》-4.3.11:NVIC寄存器映射。

    代码 17 NVIC结构体定义,来自固件库头文件:core_cm4.h

     1 typedef
    							struct {
    				
     2     __IO uint32_t ISER[8];       // 中断使能寄存器
    			
     3 
    							uint32_t RESERVED0[24];
    				
     4     __IO uint32_t ICER[8];       // 中断清除寄存器
    			
     5 
    							uint32_t RSERVED1[24];
    				
     6     __IO uint32_t ISPR[8];       // 中断使能悬起寄存器
    			
     7 
    							uint32_t RESERVED2[24];
    				
     8     __IO uint32_t ICPR[8];       // 中断清除悬起寄存器
    			
     9 
    							uint32_t RESERVED3[24];
    				
    10     __IO uint32_t IABR[8];       // 中断有效位寄存器
    			
    11 
    							uint32_t RESERVED4[56];
    				
    12     __IO uint8_t  IP[240];       // 中断优先级寄存器(8Bit wide)
    				
    13 
    							uint32_t RESERVED5[644];
    				
    14     __O  uint32_t STIR;          // 软件触发中断寄存器
    			
    15 }  NVIC_Type;
    				
    			

    在配置中断的时候我们一般只用ISERICERIP这三个寄存器,ISER用来使能中断,ICER用来失能中断,IP用来设置中断优先级。

    16.2.2 NVIC 中断配置固件库

    固件库文件core_cm4.h的最后,还提供了NVIC的一些函数,这些函数遵循CMSI规则,只要是Cortex-M4 的处理器都可以使用,具体如下:

    表格 14 符合CMSIS标准的NVIC库函数

    NVIC库函数

    描述

    void NVIC_EnableIRQ(IRQn_Type IRQn)

    使能中断

    void NVIC_DisableIRQ(IRQn_Type IRQn)

    失能中断

    void NVIC_SetPendingIRQ(IRQn_Type IRQn)

    设置中断悬起位

    void NVIC_ClearPendingIRQ(IRQn_Type IRQn)

    清除中断悬起位

    uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn)

    获取悬起中断编号

    void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)

    设置中断优先级

    uint32_t NVIC_GetPriority(IRQn_Type IRQn)

    获取中断优先级

    void NVIC_SystemReset(void)

    系统复位

    这些库函数我们在编程的时候用的都比较少,甚至基本都不用。在配置中断的时候我们还有更简洁的方法,请看中断编程小节。

    16.3 优先级的定义

    16.3.1 优先级定义

    NVIC 有一个专门的寄存器:中断优先级寄存器NVIC_IPRx(在F429中,x=0...90)用来配置外部中断的优先级,IPR宽度为8bit,原则上每个外部中断可配置的优先级为0~255,数值越小,优先级越高。但是绝大多数CM4芯片都会精简设计,以致实际上支持的优先级数减少,在F429中,只使用了高4bit,如下所示:

    表格 15 F429 使用4bit表达优先级

    bit7

    bit6

    bit5

    bit4

    bit3

    bit2

    bit1

    bit0

    用于表达优先级

    未使用,读回为0

    用于表达优先级的这4bit,又被分组成抢占优先级和子优先级。如果有多个中断同时响应,抢占优先级高的就会抢占抢占优先级低的优先得到执行,如果抢占优先级相同,就比较子优先级。如果抢占优先级和子优先级都相同的话,就比较他们的硬件中断编号,编号越小,优先级越高。

    16.3.2 优先级分组

    优先级的分组由内核外设SCB的应用程序中断及复位控制寄存器AIRCRPRIGROUP[10:8]位决定,F429分为了5组,具体如下:主优先级=抢占优先级

    PRIGROUP[2:0]

    中断优先级值PRI_N[7:4]

    级数

    二进制点

    主优先级位

    子优先级位

    主优先级

    子优先级

    0b 011

    0b xxxx

    [7:4]

    None

    16

    None

    0b 100

    0b xxx.y

    [7:5]

    [4]

    8

    2

    0b 101

    0b xx.yy

    [7:6]

    [5:4]

    4

    4

    0b 110

    0b x.yyy

    [7]

    [6:4]

    2

    9

    0b 111

    0b .yyyy

    None

    [7:4]

    None

    16

    设置优先级分组可调用库函数NVIC_PriorityGroupConfig()实现,有关NVIC中断相关的库函数都在库文件misc.cmisc.h中。

    代码 18 中断优先级分组库函数

     1 /**
    				
     2   * 配置中断优先级分组:抢占优先级和子优先级
    			
     3   * 形参如下:
    			
     4   * @arg NVIC_PriorityGroup_0: 0bit for抢占优先级
    			
     5   *                            4 bits for 子优先级
    			
     6   * @arg NVIC_PriorityGroup_1: 1 bit for抢占优先级
    			
     7   *                            3 bits for 子优先级
    			
     8   * @arg NVIC_PriorityGroup_2: 2 bit for抢占优先级
    			
     9   *                            2 bits for 子优先级
    			
    10   * @arg NVIC_PriorityGroup_3: 3 bit for抢占优先级
    			
    11   *                            1 bits for 子优先级
    			
    12   * @arg NVIC_PriorityGroup_4: 4 bit for抢占优先级
    			
    13   *                            0 bits for 子优先级
    			
    14   * @注意如果优先级分组为0,则抢占优先级就不存在,优先级就全部由子优先级控制
    				
    15   */
    				
    16 void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
    				
    17 {
    				
    18 
    							// 设置优先级分组
    			
    19     SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
    				
    20 }
    

    表格 16 优先级分组真值表

    优先级分组

    主优先级

    子优先级

    描述

    NVIC_PriorityGroup_0

    0

    0-15

    -0bit,子-4bit

    NVIC_PriorityGroup_1

    0-1

    0-7

    -1bit,子-3bit

    NVIC_PriorityGroup_2

    0-3

    0-3

    -2bit,子-2bit

    NVIC_PriorityGroup_3

    0-7

    0-1

    -3bit,子-1bit

    NVIC_PriorityGroup_4

    0-15

    0

    -4bit,子-0bit

    16.4 中断编程

    在配置每个中断的时候一般有3个编程要点:

    1、使能外设某个中断,这个具体由每个外设的相关中断使能位控制。比如串口有发送完成中断,接收完成中断,这两个中断都由串口控制寄存器的相关中断使能位控制。

    2、初始化NVIC_InitTypeDef结构体,配置中断优先级分组,设置抢占优先级和子优先级,使能中断请求。

    代码 19 NVIC初始化结构体

     1 typedef
    							struct {
    				
     2 
    							uint8_t NVIC_IRQChannel;                    // 中断源
    			
     3 
    							uint8_t NVIC_IRQChannelPreemptionPriority;  // 抢占优先级
    			
     4 
    							uint8_t NVIC_IRQChannelSubPriority;         // 子优先级
    			
     5     FunctionalState NVIC_IRQChannelCmd;         // 中断使能或者失能
    			
     6 } NVIC_InitTypeDef;
    

    有关NVIC初始化结构体的成员我们一一解释下:

    1)NVIC_IROChannel:用来设置中断源,不同的中断中断源不一样,且不可写错,即使写错了程序不会报错,只会导致不想要中断。具体的成员配置可参考stm32f4xx.h头文件里面的IRQn_Type结构体定义,这个结构体包含了所有的中断源。

    代码 20 IRQn_Type中断源结构体

     1 typedef
    							enum IRQn {
    				
     2 
    							//Cortex-M4 处理器异常编号
    			
     3     NonMaskableInt_IRQn      = -14,
    				
     4     MemoryManagement_IRQn    = -12,
    				
     5     BusFault_IRQn            = -11,
    				
     6     UsageFault_IRQn          = -10,
    				
     7     SVCall_IRQn              = -5,
    				
     8     DebugMonitor_IRQn        = -4,
    				
     9     PendSV_IRQn              = -2,
    				
    10     SysTick_IRQn             = -1,
    				
    11 
    							//STM32 外部中断编号
    			
    12     WWDG_IRQn                = 0,
    				
    13     PVD_IRQn                 = 1,
    				
    14     TAMP_STAMP_IRQn          = 2,
    				
    15 
    			
    16 
    								// 限于篇幅,中间部分代码省略,具体的可查看库文件stm32f4xx.h
    				
    17 
    			
    18     SPI4_IRQn                = 84,
    				
    19     SPI5_IRQn                = 85,
    				
    20     SPI6_IRQn                = 86,
    				
    21     SAI1_IRQn                = 87,
    				
    22     LTDC_IRQn                = 88,
    				
    23     LTDC_ER_IRQn             = 89,
    				
    24     DMA2D_IRQn               = 90
    				
    25 } IRQn_Type;
    				
    			

    2)NVIC_IRQChannelPreemptionPriority:抢占优先级,具体的值要根据优先级分组来确定,具体参考表格 16 优先级分组真值表 。

    3)NVIC_IRQChannelSubPriority:子优先级,具体的值要根据优先级分组来确定,具体参考表格 16 优先级分组真值表 。

    4)NVIC_IRQChannelCmd:中断使能(ENABLE)或者失能(DISABLE)。操作的是NVIC_ISER和NVIC_ICER这两个寄存器。

    3、编写中断服务函数

    在启动文件startup_stm32f429_439xx.s中我们预先为每个中断都写了一个中断服务函数,只是这些中断函数都是为空,为的只是初始化中断向量表。实际的中断服务函数都需要我们重新编写,中断服务函数我们统一写在stm32f4xx_it.c这个库文件中。

    关于中断服务函数的函数名必须跟启动文件里面预先设置的一样,如果写错,系统就在中断向量表中找不到中断服务函数的入口,直接跳转到启动文件里面预先写好的空函数,并且在里面无限循环,实现不了中断。

    16.5 每课一问

    1、库文件core_cm4.h主要实现了什么?回去认真看库的源码

    2、库文件mics.c和mics.h主要实现了什么?回去认真看库的源码

    3、如果实现一次软件系统复位,具体是操作哪个寄存器的哪个位实现?答案:给内核外设SCB的AIRCR寄存器的位2:SYSRESETREQ 写1即可实现一次系统复位。

  • 相关阅读:
    Android环境配置问题
    Android diary 1
    Android diary 2
    myeclipse常见问题
    Mysql常用命令
    桉树系统公司市场高级副总裁David Butler:全球最广泛应用的企业内部云平台
    引用外部.css或.js文件的路径问题
    [基础知识]巧用项目生成事件属性自动打包
    TSQL经验总结
    [Silverlight]UI 开发规范
  • 原文地址:https://www.cnblogs.com/firege/p/5805708.html
Copyright © 2011-2022 走看看