浅谈ARM Cortex-M0/M0+ 中的中断抢占问题

来源:本站
导读:目前正在解读《浅谈ARM Cortex-M0/M0+ 中的中断抢占问题》的相关信息,《浅谈ARM Cortex-M0/M0+ 中的中断抢占问题》是由用户自行发布的知识型内容!下面请观看由(电工技术网 - www.9ddd.net)用户发布《浅谈ARM Cortex-M0/M0+ 中的中断抢占问题》的详细说明。
简介:Cortex-M0/M0+, M3/M4 中的中断控制器英文名叫做NVIC,Nested Vectored Interrupt Controller,翻译过来就是嵌套向量中断控制器,所谓中断嵌套是指当正在执行一个中断服务程序时,这时如果来了优先级更高的中断,新来的中断会打断原来还没有处理完的中断服务程序,等新中断处理完毕之后再回到原中断服务继续处理。

下面让我们在Kinetis KL26芯片上来实际操作一把吧。KL26芯片为ARM Cortex M0+内核。

硬件:FRDM_KL26Z

软件:FRDM-KL26Z_SC_Rev_1.0 + IAR7.4

1) 先做第一个实验:程序中开启了两个定时器,一个为TPM2,周期10ms,另外一个PIT,周期1s。TPM2中断中断里打印一个字符X,PIT中断里while(1)循环,不断打印~~~~~~~。

int main (void){    char ch;        printf("nrnr*** Running the NVIC_Test project ***nr");        enable_irq(INT_TPM2-16);    init_TPM2();        enable_irq(INT_PIT-16);    init_PIT();        while(1)    {      ch = in_char();      out_char(ch);    } } /*   10 ms     */void init_TPM2(void){  SIM_SCGC6 |= (SIM_SCGC6_TPM2_MASK );  SIM_SOPT2 |= SIM_SOPT2_TPMSRC(1);           //input clock source is MCGPLL/2=24MHz  TPM2_SC = TPM_SC_DMA_MASK | TPM_SC_PS(3);   //Divide by 3M=24M/8  TPM2_CNT = 0;  TPM2_MOD = 30000;                //timer interrupt triger with 100Hz  TPM2_SC |= TPM_SC_TOIE_MASK;    // enable Interrupt  TPM2_SC |= TPM_SC_CMOD(1);    //start the counter}void TPM2_IRQHandler(void){     if (TPM2_SC & TPM_SC_TOF_MASK )       TPM2_SC |=  TPM_SC_TOF_MASK;   // Clear Flag        printf("X"); } /*   1 s     */void init_PIT(void) {    SIM_SCGC6 |= SIM_SCGC6_PIT_MASK;                                    PIT_MCR &= ~(1 << PIT_MCR_MDIS_SHIFT);                                                                     PIT_LDVAL0 = 24000000;          // 1 hz                                         PIT_TFLG0 |= PIT_TFLG_TIF_MASK;                                        PIT_TCTRL0 |= PIT_TCTRL_TIE_MASK | PIT_TCTRL_TEN_MASK;              }void PIT_IRQHandler(void) {  if(PIT_TFLG0 & PIT_TFLG_TIF_MASK)      PIT_TFLG0 |= PIT_TFLG_TIF_MASK;  // Clear Flag                                    while(1)   {     printf("~~~~~~~~~~~~~~~");    }}

该实验现象如下:

浅谈ARM Cortex-M0/M0+ 中的中断抢占问题

刚开始一直打印X,也就是不断进入TPM2中断服务,然后就一直打印~,即进到PIT中断里,就再也出不来了。

出现该现象的原因是:TPM2和PIT的中断优先级是一样的(默认都是0),所以当进入到PIT中断服务后,由于while(1)原因,即使TPM2中断来了也无法响应。

2)让我们做第二个实验,加入优先级设置,将TPM2 的优先级设置为1,PIT的优先级设置为2。数字越小,表示优先级越高。

    enable_irq(INT_TPM2-16);    set_irq_priority(INT_TPM2-16,1);    init_TPM2();        enable_irq(INT_PIT-16);    set_irq_priority(INT_PIT-16,2);    init_PIT();

理论来说TPM2中断会打算PIT中断,可是当我们观察实验现象时却发现,还是一直在PIT中断里,和第一个试验想象没有区别。

浅谈ARM Cortex-M0/M0+ 中的中断抢占问题

这到底是怎么回事??? 理论与实际不符啊!!!!!

经过调试才发现,原来是代码里的set_irq_priority 函数压根就没起作用,有图为证:

这是调用set_irq_priority 函数之前的寄存器值:

浅谈ARM Cortex-M0/M0+ 中的中断抢占问题

这是执行完set_irq_priotiy 函数之后的寄存器值:

浅谈ARM Cortex-M0/M0+ 中的中断抢占问题

该函数为什么不起作用呢?问题出在最后两条语句上,原因在于Cortex-M0/M0+ 中的NVIC寄存器只支持字传输,不能单字节的去操作。

void set_irq_priority (int irq, int prio){       /*irq priority pointer*/    uint8 *prio_reg;    uint8 err = 0;    uint8 p = 0;        /* Make sure that the IRQ is an allowable number. Right now up to 32 is      * used.     *     * NOTE: If you are using the interrupt definitions from the header     * file, you MUST SUBTRACT 16!!!     */    if (irq > 32)    {        printf("nERR! Invalid IRQ value passed to priority irq function!n");        err = 1;    }    if (prio > 3)    {        printf("nERR! Invalid priority value passed to priority irq function!n");        err = 1;    }        if (err != 1)    {        /* Determine which of the NVICIPx corresponds to the irq */        p = irq / 4;        prio_reg = (uint8 *)((uint32)&NVIC_IP(p));        /* Assign priority to IRQ */        *prio_reg = ( (prio&0x3) << (8 - ARM_INTERRUPT_LEVEL_BITS) );                 }}

针对这个问题,有两种途径去解决:

1) 修改set_irq_priority 函数,这个写法不唯一,有一点必须注意的是必须按字操作,也就是一下写四字节数据。

void set_irq_priority (int irq, int prio){       /*irq priority pointer*/    //uint8 *prio_reg;    uint32 prio_reg;  // wenxue    uint8 err = 0;    uint8 p = 0;        /* Make sure that the IRQ is an allowable number. Right now up to 32 is      * used.     *     * NOTE: If you are using the interrupt definitions from the header     * file, you MUST SUBTRACT 16!!!     */    if (irq > 32)    {        printf("nERR! Invalid IRQ value passed to priority irq function!n");        err = 1;    }    if (prio > 3)    {        printf("nERR! Invalid priority value passed to priority irq function!n");        err = 1;    }        if (err != 1)    {        /* Determine which of the NVICIPx corresponds to the irq */        p = irq / 4;      //  prio_reg = (uint8 *)((uint32)&NVIC_IP(p));        prio_reg = *(uint32 *)((uint32)&NVIC_IP(p));                prio_reg = prio_reg  & ( ~(0xFFUL <<  ((irq &  0x03UL) * 8UL)) );                  prio_reg =  prio_reg |  (((prio << (8 - 2)) & (uint32_t)0xFFUL) << ((irq &  0x03UL) * 8UL) );                *(uint32 *)((uint32)&NVIC_IP(p)) =prio_reg ;                         }}

2) 最简单最可靠的是调用CMSIS 标准接口函数NVIC_SetPriority

void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority){  if((int32_t)(IRQn) < 0) {    SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |       (((priority << (8 - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn)));  }  else {    NVIC->IP[_IP_IDX(IRQn)]  = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)]  & ~(0xFFUL << _BIT_SHIFT(IRQn))) |       (((priority << (8 - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn)));  }}

修改完set_irq_priority 函数之后,我们观察调试结果,这时优先级确实做了改变

浅谈ARM Cortex-M0/M0+ 中的中断抢占问题

再次观察最后的实验现象,结果如下:

浅谈ARM Cortex-M0/M0+ 中的中断抢占问题

我们可以看到TPM2中断会不断打断PIT中断。

总结如下:

1) 大家在使用FRDM-KL26Z_SC_Rev_1.0 代码时,注意set_irq_priority 函数有bug的,它起不了实际作用。

2) ARM Cortex-M0/M0+中断抢占只需要设置好优先级即可,优先级高的会抢占优先级低的中断。

补充说明:

Cortex-M3/M4里面涉及到一个优先级分组概念,在Cortex-M0/M3 里面是没有的。

上述测试代码如下:http://www.ippipp.com/file/id/40480

提醒:《浅谈ARM Cortex-M0/M0+ 中的中断抢占问题》最后刷新时间 2024-03-14 00:57:31,本站为公益型个人网站,仅供个人学习和记录信息,不进行任何商业性质的盈利。如果内容、图片资源失效或内容涉及侵权,请反馈至,我们会及时处理。本站只保证内容的可读性,无法保证真实性,《浅谈ARM Cortex-M0/M0+ 中的中断抢占问题》该内容的真实性请自行鉴别。