Red Point

十年饮冰 , 热血难凉 ; 山高万仞 , 只登一步

  博客园 :: 首页 :: 博问 :: 闪存 :: :: :: :: 管理 ::

 

stm32每个外设比如usart,spi能使用的DMA通道是固定的.看<<STM32F10x中文参考手册>>第10章P148,表59.

 

1

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

 

https://www.bilibili.com/opus/559173998573672049

一、NVIC概述

       NVIC(Nested Vector Interrupt Controller),就是嵌套向量中断控制器。

然后我们试着把这个名字拆成词语来解释,这样就很明了啦。

       我们都知道(也许你没有计算机组成原理的学习背景,那这里的“都”字就打点水份儿吧)中断(或异常)是突发的状况(系统错误或外设输入响应等)造成CPU中断当前程序,转而执行一段“中断服务程序,ISR”以解决这种突发状况。

       不过ISR也是一段程序,它还可能被中断(当然要优先级高于当前正在处理的中断),这就是嵌套的意义,即“中断再被中断”(注:ARM7时代,是不支持嵌套中断的)。

       向量是中断以向量表的形式进行管理(ARM7时代提供非向量中断,没办法!ARM7的向量表只有7项,不够用的),每个ISR的入口地址占据四个字节空间,有序排列在向量表中。

       控制器说明它在中断机制中起到控制的作用,对中断机制进行管理——中断使能/失能,中断挂起,中断优先权等。

       NVIC位于CM3内核,它支持16个系统异常(都是ARM内核产生的),240个外设中断(厂商的外围接口产生的)。F1只实现了60个中断,这是因为它并没有那么多外设,也就没有更高的中断数量需求。STM32F107因为具备以太网接口,所以有68个中断。

二、NVIC寄存器

       NVIC的寄存器组位于CM3的0xE000 0000 ~ 0xE010 0000,F1的设计中,NVIC寄存器的起始地址是:0xE000 E100,其中的寄存器信息见下表。

1

1、NVIC寄存器数量

       寄存器缩写中的“x”表示有多个。为什么需要多个呢?又到底需要多少个呢?下面我们就来分析原因。

       我们分析寄存器的名字,可以看到一个中断,有四个基本控制操作:使能(enable)——允许中断,失能(或称:除能,disable)——禁止中断,挂起(set-pending)——等待处理中断,解挂(clear-pending)——停止挂起转而处理中断。NVIC为每个中断,提供四个bit(分布在四个寄存器中)以控制四种操作,bit置位则启动控制操作,bit清零没有效果不产生任何操作。

       首先,我们来看使能中断,NVIC使用一个bit来控制一个中断的使能操作。那么CM3支持240个中断,就需要240 bits。这240 bits分布在8个32位寄存器中,即ISER0 – ISER7。由于F1只有60个中断,所以F1中只有ISER0和ISER1是有效的。ISER0 bit[31:0]对应外设中断31-0,ISER1 bit[27:0]对应外设中断59-32。向ISERx的某个bit写“1”可以使能对应的中断,而写“0”则没有任何效果。F1的外设中断59-0请见下表,比如ISER0[6]置位,就是允许EXTI0中断。

 1

1

 同理,F1中有效的寄存器还有ICER0-1,ISPR0-1和ICPR0-1,它们中的bit同样是置位产生控制操作,而清零没有效果。

2、NVIC寄存器介绍

1)NVIC_ISERx

       中断使能寄存器(Interrupt set-enable registers),包括8个32位寄存器(ISER0 – ISER7),而F1因为只有60个中断,所以有效的只有ISER0和ISER1。向ISER0和ISER1某位写“1”则使能对应中断。

2)NVIC_ICERx

       中断失能寄存器(Interrupt clear-enable registers),共有8个,F1中有效的是ICER0和ICER1。向ICER0和ICER1某位写“1”则禁止对应中断。

       ISERx和ICERx在读取时,效果一致,都是读出“1”表示对应中断使能,读出“0”表示对应中断失能。

3)NVIC_ISPRx

       中断挂起寄存器(Interrupt set-pending registers),共有8个,F1中有效的是ISPR0和ISPR1。首先,当产生某个中断请求(Interrupt Request,后面简称:IRQ)时,ISPRx中的对应bit会置位,表示中断产生。然后,如果内核正在执行某个中断的ISR,此时产生了更高级别的IRQ,则当前中断在ISPRx中的对应bit也会置位。以上情况都是依靠硬件自动实现的。

       我们也可以软件编程向ISPRx某位写“1”,则可以手动挂起正在运行的对应中断,转而处理同级或高级中断。可以说,挂起操作是嵌套中断的重要体现。

4)NVIC_ICPRx

       中断解挂寄存器(Interrupt clear-pending registers),共有8个,F1中有效的是ICPR0和ICPR1。向ICPR0和ICPR1某位写“1”则解除挂起的对应中断,并继续对其进行处理。

       ISPRx和ICPRx在读取时,也是效果一致的,读出“1”则表示对应中断挂起,读出“0”则表示没有挂起。

       补充说明一点,以上四个寄存器都是写“1”有效,写“0”无效,这在编程时可以带来便利,比如要设置某个寄存器的第N位,只需向其写入“1&lt;&lt;N”就可以,因为写0无效,所以其它位不会受到影响。

5)NVIC_IABRx

       中断标志寄存器(Interrupt active bit registers),共有8个,都是只读的,F1中有效的是IABR0和IABR1。如果IABR0和IABR1某位读出是“1”则表示对应中断正在处理中。

6)NVIC_IPRx

       中断优先级寄存器(Interrupt priority registers),共有60个32位寄存器IPR0 – IPR59。不过每个IPR又可以视作是四个8位的IP寄存器,那么就有240个8位寄存器IP0 – IP239。CM3支持240个中断,这里很容易就分析出正好一个IP寄存器对应一个中断,用于设置这个中断的优先级号。那么F1中也只有IP0 – IP59有效。

1

7)NVIC_STIR

       软中断寄存器(Software trigger interrupt register),只是单独一个32位只写寄存器,而且只有bit[8:0](称为INTID[8:0])有效。向INTID中写入数值n,就表示以软件的方式发出中断请求n(IRQn),比如:INTID = 6(即000000110),就是启动EXTI0(F1中的IRQ6)的软中断。

       我们都知道中断请求是突发情况引起的,由硬件电路完成对ISR的调用。但是有时可能需要主动调用ISR,就可以通过编程软中断的方式来实现了。

3、NVIC寄存器映射的C实现

       寄存器地址使用常量指针的思路是不能改变的,不过这里我们要注意两点:

1)NVIC同类寄存器是多个

       NVIC有七种寄存器,其中六种都是多个,这个问题的解决方法就是——采用数组。同种多个寄存器定义为数组,数组分量对应单个寄存器,比如NVIC_ISERx定义成“__IO uint32_t ISER[8];”,那么ISER[n]就代表ISERn寄存器。

2)NVIC寄存器地址不连续

       NVIC的寄存器之间地址并不连续,留有保留空间,其实也是为了未来扩展CM3架构的考虑。比如NVIC_ISERx的地址(只计算偏移地址)是:0x000 ~ 0x1F(4字节*8个 = 32),而之后的NVIC_ICERx的起始地址是0x080,它们之间有0x060(96个字节)的未使用地带。

       这个问题的解决方法还是采用数组,在ISER[8]和ICER[8]两个成员之间,定义一个成员“uint32_t RESERVED0[24]”——24个成员的uint32_t数组,正好填充了96个字节的空间。

       这种定义数组填充保留区的方法在库函数中十分常见,就是针对地址不连续,有未使用空间的情况,同时数组名一般直接用“RESERVED”,就是“保留的”意思。因为是未使用区,所以这样编写不会浪费存储空间,但是要注意这个保留区在程序逻辑上是可以编写代码进行访问的,但是由于真实存储系统中并没有这个区域,所以一旦在程序中访问到保留区,就会触发“总线fault”异常。

3)标准库中的NVIC寄存器代码

       由于NVIC属于CM3内核结构,所以标准库将其结构体定义代码放在“core_cm3.h”中。

三、优先级设置

       NVIC_IPx寄存器共有240个,它可以为每个IRQ分配一个优先级编号,这个编号越小则优先级越高。不过我们要注意,IPx寄存器只有高四位即bit[7:4]用来设置编号,低四位没有使用。因此,NVIC最多支持16(2^4)个中断优先级别。

       但是,实际上NVIC的优先级管理还要复杂一点,它将优先级分为两级:抢占优先级和子优先级(又叫响应优先级)。高抢占级别的中断可以打断低抢占级别的中断,这体现了“嵌套”的意义。同一抢占级的中断,同时发生中断请求时,子优先级高的会先被处理。但是,高子优先级中断,不能中断正在被处理的同一抢占级的低子优先级中断。

       因此,IPx寄存器的高四位还需要分成两段,分别用于设置抢占优先级和子优先级。而这四位如何分段,是由SCB_AIRCR寄存器的bit[10:8]来设置的,具体方法见下表。

 1

四、NVIC标准库函数

       F1标准库中关于NVIC的库函数位于“misc.c”,相关函数说明见下表。

 后边的省略...
posted on 2025-08-19 13:11  Red_Point  阅读(18)  评论(0)    收藏  举报