/* Check the parameters */
assert(IS_FUNCTIONAL_STATE(NVIC_InitStruct->NVIC_IRQChannelCmd));
assert(IS_NVIC_IRQ_CHANNEL(NVIC_InitStruct->NVIC_IRQChannel));
assert(IS_NVIC_PREEMPTION_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority));
assert(IS_NVIC_SUB_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelSubPriority));
if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE)
{
/* Compute the Corresponding IRQ Priority --------------------------------*/
tmppriority = (0x700 - (SCB->AIRC & (u32)0x700))>> 0x08;//算出来得到的就是占先优先级的位数占四位中的几位
tmppre = (0x4 - tmppriority);
//算出来得到的就是响应优先级的位数占四位中的几位
tmpsub = tmpsub >> tmppriority;
//然后将四位掩码通过抢占优先级位数得到响应优先级的掩码
tmppriority = (u32)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre;
//把用户输入的优先级组别参数 结合 前面计算出来的响应优先级的位数 通过 移位放置到抢占优先级相应的bit上
tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub;//与上相应优先级掩码得到单纯的相应优先级
//然后 或上(|) 响应优先级得到了该中断通道8位的优先级数
//接下来的问题就是如何将这个优先级放置到相应的通道中断优先级寄存器中?
tmppriority = tmppriority << 0x04;
//首先将这个优先级数左移四位放置到相应通道优先级寄存器8位的高四位(优先级8位从左边算起的)
tmppriority = ((u32)tmppriority) << ((NVIC_InitStruct->NVIC_IRQChannel & (u8)0x03) * 0x08);
//因为一个32位中包含4个八位,而同时又包括好几个32位,这样的话,需要有一个对准的问题,比如我现在
//是第六个通道,我就需要将其放置到第二个32位中的第二个八位(从左边数),具体算法是:
//首先将该通道在32位中的第几个八位算出来,所以同0x03相与,将通道序号按照模4(MOD)计算,结果其实就是通道数除以4得到的余数,
//然后再乘以8得到的便是该通道在32位中的第几位,有0*8=0,1*8=8,2*8=16,3*8=24,这四种情况
//总之该语句将该通道优先级寄存在其32位当中从第几位开始的8位找出来了放在tmppriority相应的地方中
tmpreg = NVIC->Priority[(NVIC_InitStruct->NVIC_IRQChannel >> 0x02)];
//接下来将通道数除以四(这里通道移位来运算除法的),得到的其实就是该通道在第几个32位优先级寄存器上,把这个32位寄存
//结果读出来放在tmpreg中!
tmpmask = (u32)0xFF << ((NVIC_InitStruct->NVIC_IRQChannel & (u8)0x03) * 0x08);
//该语句将该通道优先级寄存器在32位当中的第几位开始的八位加上了掩码,以便后面方便写入到该通道优先级寄存器的八位上
tmpreg &= ~tmpmask;
//将该通道在32位的优先级寄存器组上的8位清零,其他位也就是其它通道的响应优先级寄存器保证同一相与,不会改变
tmppriority &= tmpmask;
//该语句只保留该通道的响应优先级寄存器在32位上的八位,其他的通道响应优先级寄存器全部用0屏蔽,
tmpreg |= tmppriority;
//终于现在,tmpreg中该通道响应优先级寄存器的8位全部为0,其他通道响应优先级寄存器的8位(还有三组)全部为原来本身的数而没有改变
//tmppriority中该通道响应优先级寄存器的8位数据完好,其他通道响应优先级寄存器的8位(还有三组)全部为0
//两者相"或",该32位tmpreg便是已经包含了本次用户输入的通道中断响应优先级寄存器的8位信息
NVIC->Priority[(NVIC_InitStruct->NVIC_IRQChannel >> 0x02)] = tmpreg;
//输入到包含该通道中断响应优先级寄存器的32位寄存器中,可以看出,本质上也是一个读--修改--写的过程
/* Enable the Selected IRQ Channels --------------------------------------*/
NVIC->Enable[(NVIC_InitStruct->NVIC_IRQChannel >> 0x05)] =
(u32)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (u8)0x1F);
}
else
{
/* Disable the Selected IRQ Channels -------------------------------------*/
NVIC->Disable[(NVIC_InitStruct->NVIC_IRQChannel >> 0x05)] =
(u32)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (u8)0x1F);
}
}
NVIC是矢量嵌入中断控制,包括:1) ISER;2) ICER; 3) ISPR; 4) ICPR; 5) IABR; 6)IPR 这几个寄存器。
typedef struct
{
vu32 ISER[2];
u32 RESERVED0[30];
vu32 ICER[2];
u32 RSERVED1[30];
vu32 ISPR[2];
u32 RESERVED2[30];
vu32 ICPR[2];
u32 RESERVED3[30];
vu32 IABR[2];
u32 RESERVED4[62];
vu32 IPR[15];
} NVIC_TypeDef;
首先分析为什么定义。这是因为ISER的地址是从E000E100开始的,ICER是从E000E180开始的,依次类推;可见从0xE000E100到0xE000E180间隔128个8位,也就是32个32位的数据;这就是vu32 XXX[2]+u32 RESERVED0[30]总的位数。
1)
ISER包括ISER[0]和ISER[1],它们的每位值依次对应一个中断的开启和关闭。例如ISER[0]中的第0位对应
WWDG 窗口定时器中断;第25位对应TIM1_UP TIM1更新中断。---用来开中断
ICER写响应的位为1则对应的中断禁止,默认全0,读如果该位为1则相应的中断允许--用来关中断。
2)
ISPR中某位为1则挂起相应中断;
ICPR中某位为1则清除挂起的中断;
3)
IABR只读用来指示是否有中断发生或要处理;
4)
IPR用来设置优先级别
NVIC->ISER = Interrupt Set-Enable Registers
NVIC->ICER = Interrupt Clear-Enable Registers
NVIC->ISPR = Interrupt Set-Pending Register
NVIC->ICPR = Interrupt Clear-Pending Register
NVIC->IABR = Interrupt Active Bit Register
NVIC->IPR = Interrupt Priority Registers
STM32有"60 maskable interrupt channels (not including the 16 interrupt lines of Cortex-M3)"[翻译]60个可屏蔽中断通道(不包含16个Cortex-M3的中断线),这60个可屏蔽中断通道的Position依次为0——59
所以尽管在core_cm3.h(Copyright (C) 2009 ARM Limited.)定义了__IO uint32_t ISER[8]; ,实际上只用到了ISER[0]和ISER[1]。
其中Position0——31的使能位放到ISER[0]里,Position32——59的使能位放到ISER[1]里。
因此NVIC_InitStruct->NVIC_IRQChannel >> 0x05的值要么等于0,要么等于1。(Position0——31右移5位得0,Position32——59右移5位得1)
文章评论(0条评论)
登录后参与讨论