• CortexM0中断控制和系统控制(二)


    转载:https://aijishu.com/a/1060000000237975

    每一个外部中断都有一个对应的优先级寄存器,Cortex-M0中NVIC-IPR共有8个寄存器,而每个寄存器管理4个IRQ中断,所以M0的IRQ中断源最多只支持32个,再加上16个内核中断,也就是说M0最多48个中断源。

    表1.png

    表2.png

    Cortex-M0采用Armv6-M架构,优先级寄存器配置位有8位,但是有效位只有最高2位,这个地方很多人使用了Cortex-M3后一直也认为Cortex-M0也是最高3或4位有效位,在arm官方资料中有对比两个版本的差别。因此Cortex-M0可编程优先级有4个,加上3个固定的优先级(复位、NMI、HardFault),Cortex-M0总共有7个中断优先级。

    image1.png

    Cortex-M0内核的中断优先级寄存器是以最高位(MSB)对齐的,并且只支持字传输,每次访问都会同时涉及4个中断优先级寄存器。见下图:

    表3.png

    因为Bit0 - Bit5没有使用,所以如果没有进行写操作读出都为0。

    由于不同的 Cortex-M 系列,其中断优先级是不一样的,所以在 CMSIS 库中的头文件中可以查看优先级的数量 \_\_NVIC\_PRIO\_BITS。

    中断优先级寄存器的编程应该在中断使能之前,其通常是在程序开始时完成的。arm官方资料提示应该避免在中断使能之后改变中断优先级,因为这种情况的结果在ARMv6-M系统结构是不可预知的,并且不被Cortex-M0处理器支持。Cortex-M3/M4处理器的情况又有所不同,他们都支持中断优先级的动态切换。Cortex-M3处理器和Cortex-M0处理器的另外一个区别是,Cortex-M3访问中断优先级寄存器时支持字节或半字传输,因此可以每次只设置一个寄存器。如果需要改变优先级,程序中需要关闭中断后再重新设置中断优先级寄存器。

    在 Cortex-M内核中,一个中断的优先级数值越低,逻辑优先级却越高。比如,中断优先级为2的中断可以抢占中断优先级为3的中断,但反过来就不行。换句话说,中断优先级2比中断优先级3的优先级更高。

    Cortex-M0处理器对中断嵌套的支持无需任何软件干预,如果MCU已经在运行一个中断,而有了新的更高优先级的中断请求,正在运行的中断将会被暂停,转而执行更高优先级的中断,高优先级中断执行完成后又回到原来的低优先级中断。如果出现两个同一优先级的中断,则是判断谁开始发起中断请求,MCU会先执行同一优先级中首先发起请求的中断。

    MM32F0130系列中断向量表:

    typedef enum IRQn {
    
        NonMaskableInt_IRQn             = -14,                                  ///< 2 Non Maskable Interrupt
        HardFault_IRQn                  = -13,                                  ///< 3 Cortex-M0 Hard Fault Interrupt
        MemoryManagement_IRQn           = -12,                                  ///< 4 Cortex-M0 Memory Management Interrupt
        BusFault_IRQn                   = -11,                                  ///< 5 Cortex-M0 Bus Fault Interrupt
        UsageFault_IRQn                 = -10,                                  ///< 6 Cortex-M0 Usage Fault Interrupt
        SVC_IRQn                        = -5,                                   ///< 11 Cortex-M0 SV Call Interrupt
        DebugMonitor_IRQn               = -4,                                   ///< 12 Cortex-M0 Debug Monitor Interrupt
        PendSV_IRQn                     = -2,                                   ///< 14 Cortex-M0 Pend SV Interrupt
        SysTick_IRQn                    = -1,                                   ///< 15 Cortex-M0 System Tick Interrupt
        WWDG_IWDG_IRQn                  = 0,                                    ///< WatchDog Interrupt
        WWDG_IRQn                       = 0,                                    ///< Window WatchDog Interrupt
        PVD_IRQn                        = 1,                                    ///< PVD through EXTI Line detect Interrupt
        BKP_IRQn                        = 2,                                    ///< BKP through EXTI Line Interrupt
        RTC_IRQn                        = 2,                                    ///< RTC through EXTI Line Interrupt
        FLASH_IRQn                      = 3,                                    ///< FLASH Interrupt
        RCC_CRS_IRQn                    = 4,                                    ///< RCC & CRS Interrupt
        RCC_IRQn                        = 4,                                    ///< RCC Interrupt
        EXTI0_1_IRQn                    = 5,                                    ///< EXTI Line 0 and 1 Interrupts
        EXTI2_3_IRQn                    = 6,                                    ///< EXTI Line 2 and 3 Interrupts
        EXTI4_15_IRQn                   = 7,                                    ///< EXTI Line 4 to 15 Interrupts
        HWDIV_IRQn                      = 8,                                    ///< HWDIV Global Interrupt
        DMA1_Channel1_IRQn              = 9,                                    ///< DMA1 Channel 1 Interrupt
        DMA1_Channel2_3_IRQn            = 10,                                   ///< DMA1 Channel 2 and Channel 3 Interrupts
        DMA1_Channel4_5_IRQn            = 11,                                   ///< DMA1 Channel 4 and Channel 5 Interrupts
        ADC_COMP_IRQn                   = 12,                                   ///< ADC & COMP Interrupts
        COMP_IRQn                       = 12,                                   ///< COMP Interrupts
        ADC_IRQn                        = 12,                                   ///< ADC Interrupts
        ADC1_IRQn                       = 12,                                   ///< ADC Interrupts
        TIM1_BRK_UP_TRG_COM_IRQn        = 13,                                   ///< TIM1 Break, Update, Trigger and Commutation Interrupts
        TIM1_CC_IRQn                    = 14,                                   ///< TIM1 Capture Compare Interrupt
        TIM2_IRQn                       = 15,                                   ///< TIM2 Interrupt
        TIM3_IRQn                       = 16,                                   ///< TIM3 Interrupt
        TIM14_IRQn                      = 19,                                   ///< TIM14 Interrupt
        TIM16_IRQn                      = 21,                                   ///< TIM16 Interrupt
        TIM17_IRQn                      = 22,                                   ///< TIM17 Interrupt
        I2C1_IRQn                       = 23,                                   ///< I2C1 Interrupt
        SPI1_IRQn                       = 25,                                   ///< SPI1 Interrupt
        SPI2_IRQn                       = 26,                                   ///< SPI1 Interrupt
        UART1_IRQn                      = 27,                                   ///< UART1 Interrupt
        UART2_IRQn                      = 28,                                   ///< UART2 Interrupt
        CAN_IRQn                        = 30,                                   ///< CAN Interrupt
        USB_IRQn                        = 31,                                   ///< USB Interrupt
    } IRQn_Type;

    设置中断优先级的流程:先读一个字,再修改对应字节,最后整个字写回。

    1.1 C代码
    void__NVIC_SetPriority()
    {
        unsigned long temp;                              //定义一个临时变量
        temp = *(volatile unsigned long)(0xE000E400); //读取IRP0值
        temp &= (0xFF00FFFF |(0xC0 << 16));            //修改中断#2优先级为0xC0
        *(volatile unsigned long)(0xE000E400) = temp; //设置IPR0
    }
    1.2 汇编代码

    在程序中可以一次设置多个中断优先级。

    void__NVIC_SetPriority()
    {
        LDR R0, =0xE000E100   ;  //设置使能中断寄存器地址
        MOVS R1, #0x4         ;  //中断#2
        STR R1, [R0]          ;  //使能#2中断
        LDR R0, =0xE000E200   ;  //设置挂起中断寄存器地址
        MOVS R1, #0x4         ;  //中断#2
        STR R1, [R0]          ;  //挂起#2中断
        LDR R0, =0xE000E280   ;  //设置清除中断挂起寄存器地址
        MOVS R1, #0x4         ;  //中断#2
        STR R1, [R0]          ;  //清除#2的挂起状态
    }
    1.3 CMSIS标准设备驱动函数
    //设置中断优先级
    __STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
    {
        if ((int32_t)(IRQn) >= 0) {
            NVIC->IP[_IP_IDX(IRQn)]  = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)]  & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
                                        (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn)));
        }
        else {
            SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
                                        (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn)));
        }
    }

    这里的参数IRQn为中断ID号,可以为负,也可以为正。当IRQn为负时,设置系统异常的优先级,当IRQn大于等于0时,设置外设中断优先级,芯片厂商会提供中断向量表IRQn\_Type,应用层只需要调用即可;priority是0、1、2、3,函数内部会自动移位到对应的优先级最高2位。

    方法一:
    void NVIC_SetPriority(TIM1_CC_IRQn, 3) ; //设置#14中断的优先级为0xC0
    方法二:
    void NVIC_Config(void)
    {    NVIC_InitTypeDef NVIC_InitStructure;
    
        NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPriority = 3;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
    }

    设置好中断优先级后,用户还可以读取当前已经设置的中断优先级。

  • 相关阅读:
    maven更新远程仓库速度太慢解决方法
    maven安装配置
    myeclipse中配置maven
    java数组的常用函数
    在数组中插入元素
    MySQL的表使用
    MySQL的数据库与表格创建
    节点的添加与删除
    html常用的综合体
    标签的类添加与删除
  • 原文地址:https://www.cnblogs.com/zhiminyu/p/15620899.html
Copyright © 2020-2023  润新知