历史上的今天
返回首页

历史上的今天

今天是:2024年12月03日(星期二)

正在发生

2021年12月03日 | STM32中断笔记——关于NVIC的两个问题

2021-12-03 来源:eefocus

       STM32 中断非常强大,每个外设都可以产生中断,中断也是STM32非常重要的一个内容。


       NVIC:嵌套向量中断控制器,属于内核外设,管理着包括内核和片上所有外设的中断相关的功能。


       ARM cortex_m3 内核支持 256 个中断(16 个内核+240 外部)和可编程 256 级中断优先级的设置,与其相关的中断控制和中断优先级控制寄存器(NVIC、SYSTICK 等)也都属于cortex_m3 内核的部分。STM32 采用了 cortex_m3 内核,所以这部分仍旧保留使用,但 STM32并没有使用 cortex_m3 内核全部的东西(如内存保护单元 MPU 等),因此它的 NVIC 是cortex_m3 内核的 NVIC 的子集。


       这篇文章主要记录我学习中断时关于NVIC的两个问题。


问题1:NVIC_Type和NVIC_InitTypeDef结构体的关系?

       NVIC寄存器的定义是在core_cm3.h中:


typedef struct

{

  __IO uint32_t ISER[8];                      /*!< Offset: 0x000  Interrupt Set Enable Register 中断使能寄存器          */

       uint32_t RESERVED0[24];                                   

  __IO uint32_t ICER[8];                      /*!< Offset: 0x080  Interrupt Clear Enable Register 中断清除寄存器        */

       uint32_t RSERVED1[24];                                    

  __IO uint32_t ISPR[8];                      /*!< Offset: 0x100  Interrupt Set Pending Register 中断使能悬起寄存器         */

       uint32_t RESERVED2[24];                                   

  __IO uint32_t ICPR[8];                      /*!< Offset: 0x180  Interrupt Clear Pending Register 中断清除悬起寄存器       */

       uint32_t RESERVED3[24];                                   

  __IO uint32_t IABR[8];                      /*!< Offset: 0x200  Interrupt Active bit Register 中断有效位寄存器          */

       uint32_t RESERVED4[56];                                   

  __IO uint8_t  IP[240];                      /*!< Offset: 0x300  Interrupt Priority Register (8Bit wide)中断有效位寄存器 */

       uint32_t RESERVED5[644];                                  

  __O  uint32_t STIR;                         /*!< Offset: 0xE00  Software Trigger Interrupt Register 软件触发中断寄存器    */

}  NVIC_Type;                                               


       在配置中断的时候我们一般只用 ISER、ICER 和 IP 这三个寄存器,ISER 用来使能中断,ICER用来失能中断,IP 用来设置中断优先级。而初始化这个结构体的函数就是void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct),在misc.c中定义,比较复杂,有兴趣可以看看:


/**

  * @brief  Initializes the NVIC peripheral according to the specified

  *         parameters in the NVIC_InitStruct.

  * @param  NVIC_InitStruct: pointer to a NVIC_InitTypeDef structure that contains

  *         the configuration information for the specified NVIC peripheral.

  * @retval None

  */

void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)

{

  uint32_t tmppriority = 0x00, tmppre = 0x00, tmpsub = 0x0F;

  

  /* Check the parameters */

  assert_param(IS_FUNCTIONAL_STATE(NVIC_InitStruct->NVIC_IRQChannelCmd));

  assert_param(IS_NVIC_PREEMPTION_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority));  

  assert_param(IS_NVIC_SUB_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelSubPriority));

    

  if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE)

  {

    /* Compute the Corresponding IRQ Priority --------------------------------*/    

    tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08;

    tmppre = (0x4 - tmppriority);

    tmpsub = tmpsub >> tmppriority;


    tmppriority = (uint32_t)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre;

    tmppriority |=  NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub;

    tmppriority = tmppriority << 0x04;

        

    NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority;

    

    /* Enable the Selected IRQ Channels --------------------------------------*/

    NVIC->ISER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =

      (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);

  }

  else

  {

    /* Disable the Selected IRQ Channels -------------------------------------*/

    NVIC->ICER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =

      (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);

  }

}


       NVIC初始化函数是通过传递的参数NVIC_InitTypeDef* NVIC_InitStruct来初始化NVIC_Type结构体的,而对NVIC_InitTypeDef结构体的初始化就要看具体情况,比如说普通的按键外部中断等等。


       NVIC_InitTypeDef结构体结构体定义在misc.h中:


typedef struct

{

  uint8_t NVIC_IRQChannel;                    /*!< Specifies the IRQ channel to be enabled or disabled.

                                                   This parameter can be a value of @ref IRQn_Type 

                                                   (For the complete STM32 Devices IRQ Channels list, please

                                                    refer to stm32f10x.h file) */


  uint8_t NVIC_IRQChannelPreemptionPriority;  /*!< Specifies the pre-emption priority for the IRQ channel

                                                   specified in NVIC_IRQChannel. This parameter can be a value

                                                   between 0 and 15 as described in the table @ref NVIC_Priority_Table */


  uint8_t NVIC_IRQChannelSubPriority;         /*!< Specifies the subpriority level for the IRQ channel specified

                                                   in NVIC_IRQChannel. This parameter can be a value

                                                   between 0 and 15 as described in the table @ref NVIC_Priority_Table */


  FunctionalState NVIC_IRQChannelCmd;         /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannel

                                                   will be enabled or disabled. 

                                                   This parameter can be set either to ENABLE or DISABLE */   

} NVIC_InitTypeDef;


       NVIC_Type和NVIC_InitTypeDef这两个结构体就是通过NVIC_Init函数来联系起来的。即NVIC_Type和NVIC_InitTypeDef的关系就是:先在具体的外部中断里将NVIC_InitTypeDef结构体初始化完成,然后通过NVIC_Init函数,把NVIC_InitTypeDef作为参数,将NVIC_Type结构体初始化。


问题2:关于中断优先级和中断优先级分组的问题,这两个有什么区别?

       中断优先级分组的设定是在NVIC_Type和NVIC_InitTypeDef结构体初始化的前面。


       中断优先级的设定是NVIC->IPRx寄存器(共8bit,只使用高4bit):

       相关函数:NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) // core_cm3.h 1586行


/**

 * @brief  Set the priority for an interrupt

 *

 * @param  IRQn      The number of the interrupt for set priority

 * @param  priority  The priority to set

 *

 * Set the priority for the specified interrupt. The interrupt 

 * number can be positive to specify an external (device specific) 

 * interrupt, or negative to specify an internal (core) interrupt.

 *

 * Note: The priority cannot be set for every core interrupt.

 */

static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)

{

  if(IRQn < 0) {

    SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for Cortex-M3 System Interrupts */

  else {

    NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff);    }        /* set Priority for device specific Interrupts  */

推荐阅读

史海拾趣

Enable Semiconductor Corp公司的发展小趣事

在半导体产业链中,Enable Semiconductor Corp公司注重与上下游企业的合作。公司与多家芯片设计公司、封装测试企业建立了紧密的合作关系,共同开发新产品、新技术。这种合作模式不仅降低了公司的研发成本,也加快了产品上市的速度。同时,通过与合作伙伴的资源共享和优势互补,Enable Semiconductor Corp公司在市场上形成了强大的竞争力。

EG & G Inc公司的发展小趣事

随着市场竞争的加剧,EG & G Inc公司意识到通过并购和整合来提升自身竞争力的重要性。公司先后收购了多家具有技术优势和市场潜力的企业,将其纳入自己的业务体系。这些并购不仅增强了公司的技术实力和市场地位,也为其未来的发展奠定了坚实的基础。

台湾丰宾(CapXon)公司的发展小趣事

面对日益激烈的市场竞争,CapXon公司始终坚持以技术创新为驱动,不断推动产业升级。公司投入大量资金用于研发新的技术和产品,以满足市场对高品质、高性能电容器的需求。通过不断的努力,CapXon成功研发出了一系列具有自主知识产权的高性能电容器产品,这些产品不仅具有更高的稳定性和可靠性,而且能够满足更广泛的应用场景需求。

Analogix Semiconductor公司的发展小趣事

CapXon公司一直高度重视品质管理,建立了完善的质量管理体系和检测机制。公司严格把控原材料采购、生产过程、成品检验等各个环节,确保产品的品质符合国际标准和客户要求。同时,CapXon还不断优化生产流程,提高生产效率,降低生产成本,为客户提供更具竞争力的价格和服务。

泽耀科技(Ashining)公司的发展小趣事

泽耀科技(Ashining)深知品质是企业生存和发展的关键。因此,公司始终将品质管理放在首位,从原材料采购到生产流程控制,再到产品出厂检验,每一个环节都严格把控品质。同时,泽耀科技还注重品牌建设,通过提升产品形象和服务水平,逐渐树立了良好的品牌形象。

Capar Components Corp公司的发展小趣事

作为一家有社会责任感的企业,Capar Components Corp积极参与公益事业,回馈社会。公司定期组织员工参与社区服务活动,帮助困难群体解决实际问题。此外,公司还设立了奖学金和助学金,支持教育事业的发展。这些举措不仅彰显了公司的社会责任感,也为公司树立了良好的企业形象。


这些故事是基于一个虚构的电子行业公司背景编写的,您可以根据Capar Components Corp的实际情况进行调整和修改,以使其更符合该公司的历史和发展轨迹。请注意,由于我无法获取Capar Components Corp的具体信息,这些故事仅为示例性质,并非真实事件。

问答坊 | AI 解惑

msp430与ARM7比较

mcu选型指南 方向比努力更重要…

查看全部问答>

Pmos管电流流向的问题

在附件中Q1使用P沟道的MOS管,主要是为了防止电池反接。 利用mos管的寄生二极管,造成VGS大于栅源阈值而导通。 电流流向是由MOS管的D流向S,对于PMOS管一般的电流都是从S流向D, 对于衬底电平和源极连一起的PMOS管来说,一般不建议这么用吧。 对 ...…

查看全部问答>

一个小问题困惑了我,求高手指点(反映打不开电路图,再发一次)

大家好 我是想从手机的耳机孔取信号,来推动一个单稳态电路  (看不到电路图的话,附件中也有) 从左往右把门电路分别称为门1、门2、门3、门4. 门3、门4.组成的单稳态电路,很成功 ,用手指碰门2的输入端可使单稳态翻转。  门1组成 ...…

查看全部问答>

键盘防抖问题

8个独立中断按键。 在中断后,先进行延时防抖,然后进行检查哪个按键被按下。当按键检查完后,判断按键是否释放,若释放,则返回。程序如下所示。 但是运行的时候,发现有时候按键后,按键次数加2 ,也就是说进入中断两次。难道判断按键释放的程 ...…

查看全部问答>

VHDL的一个小小问题

--有如下语句: ... ... GENERIC(CONSTANT BUS_WIDTH: INTEGER := 15);        --总线宽度定义 ... ... po1: INOUT         STD_LOGIC_VECTOR(BUS_WIDTH DOWNTO 0); ... ... po1 …

查看全部问答>

请问:如何在用C语言写的程序中加入CPL和EFLAGS这两个关键字

编译的时候总是说CPL和EFLAGS是undeclared identifier.是不是应该Link什么库? 谢谢!…

查看全部问答>

看论坛里有那么多好书,出个读书活动吧

看论坛里有那么多好书。咱出个读书活动吧。找几个人主持,定期读专业书,大家一起讨论。  …

查看全部问答>

实际考虑:光电流脉冲形状对LIV扫描的影响

光电流脉冲[1]形状对于LIV扫描非常重要。从理想角度看,光电流脉冲应当具有完美的平顶,表示一个“固定”值,它等于针对同样连续波功率输入值而测量的光电流值。为了确定每个到达脉冲的最终光电流值,2520型积分球对其10MHz A/D转换器采集的数据 ...…

查看全部问答>

求教msp430g2553 DTC配置

配置ADC10DTC进行双通道AD转换时数据只能采样n次,传送一次。请问如何配置DTC才能实现每次按键输入控制时,AD都能进行采样n次,并且都能通过DTC传送??…

查看全部问答>