关于LM3S1XXX的中断嵌套问题



首先呢,我得承认做为菜鸟,一直不是很明白M3的“中断组优先级”“中断优先级”这两个概念。在本项目中,有如下定义:

使用工具为Keil

char  a,b,c,d,e[10],*P;

int f,g,h,i,j;...............................................等等,有N多的全局变量及指针

然后是相关的配置:

/******************************************************************************************/
//PWM配置动作
/******************************************************************************************/
    SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM);      // 使能PWM模块
    SysCtlPWMClockSet(SYSCTL_PWMDIV_1);             // PWM时钟配置:不分频

    GPIOPinTypePWM(SINA_PORT,SINA_PIN);// PG2配置为PWM0功能
 GPIOPinTypePWM(SINB_PORT,SINB_PIN);// PD1配置为PWM1功能
 GPIOPinTypePWM(SINC_PORT,SINC_PIN);// PH0配置为PWM1功能
 GPIOPinTypePWM(SIND_PORT,SIND_PIN);// PH1配置为PWM1功能
                  
    PWMGenConfigure(PWM_BASE, PWM_GEN_0,PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_NO_SYNC);// 配置PWM发生器0:加减计数,不同步
    PWMGenConfigure(PWM_BASE, PWM_GEN_1,PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_NO_SYNC);// 配置PWM发生器1:加减计数,不同步
                
    PWMGenPeriodSet(PWM_BASE, PWM_GEN_0, 1040);     // 设置PWM发生器0的周期
 PWMGenPeriodSet(PWM_BASE, PWM_GEN_1, 1040);     // 设置PWM发生器1的周期

    PWMPulseWidthSet(PWM_BASE, PWM_OUT_0, 64);    // 设置PWM0输出的脉冲宽度
    PWMPulseWidthSet(PWM_BASE, PWM_OUT_1, 64);    // 设置PWM1输出的脉冲宽度
 PWMPulseWidthSet(PWM_BASE, PWM_OUT_2, 64);    // 设置PWM2输出的脉冲宽度
    PWMPulseWidthSet(PWM_BASE, PWM_OUT_3, 64);    // 设置PWM3输出的脉冲宽度

 PWMSyncUpdate(PWM_BASE,PWM_GEN_0_BIT | PWM_GEN_1_BIT);//配置PWM发生器0、1同步

    PWMOutputState(PWM_BASE,PWM_OUT_0_BIT|PWM_OUT_1_BIT|PWM_OUT_2_BIT|PWM_OUT_3_BIT,true);// 使能PWM0、1、2、3的输出
 IntPrioritySet(INT_PWM0, 0<< 5);       注意这个优先级设置为0,后面会改为1           
    IntPrioritySet(INT_PWM1, 1<< 5);     注意这个优先级设置为1,后面会改为2           
    PWMGenEnable(PWM_BASE, PWM_GEN_0);              // 使能PWM发生器0,开始产生PWM方波
 PWMGenEnable(PWM_BASE, PWM_GEN_1);              // 使能PWM发生器1,开始产生PWM方波

 PWMGenIntTrigEnable(PWM_BASE,PWM_GEN_0,PWM_INT_CNT_ZERO);//使能PWM发生器0归零触发中断
 PWMGenIntTrigEnable(PWM_BASE,PWM_GEN_1,PWM_INT_CNT_ZERO);//使能PWM发生器1归零触发中断
    PWMIntEnable(PWM_BASE, PWM_INT_GEN_0 | PWM_INT_GEN_1);//使能PWM发生器0、1中断
// PWMIntEnable(PWM_BASE, PWM_INT_GEN_1);//使能PWM发生器0中断
    IntEnable(INT_PWM0);//使能PWM发生器0中断
 IntEnable(INT_PWM1);//使能PWM发生器1中断
    IntMasterEnable();//使能总中断

/******************************************************************************************/
//UART配置动作
/******************************************************************************************/

SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1);            //  使能UART模块
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);            //  使能RX/TX所在的GPIO端口
     
    GPIOPinTypeUART(GPIO_PORTD_BASE,                        //  配置RX/TX所在管脚为
                    GPIO_PIN_2 | GPIO_PIN_3);               //  UART收发功能
                
    UARTConfigSet(UART1_BASE,                               //  配置UART端口
                  9600,                                     //  波特率
                  UART_CONFIG_WLEN_8 |                      //  数据位:8
                  UART_CONFIG_STOP_ONE |                    //  停止位:1
                  UART_CONFIG_PAR_NONE);                    //  校验位:无

 UARTFIFOLevelSet(UART1_BASE,                            //  设置发送和接收FIFO深度
                     UART_FIFO_TX2_8,                       //  发送FIFO为2/8深度(4B)
                     UART_FIFO_RX6_8);                      //  接收FIFO为6/8深度(12B)取值有1/8、2/8 、4/8  6/8、 7/8
 IntPrioritySet(INT_UART1, 2 << 5);注意这个优先级设置为2,后面会改为3
    UARTIntEnable(UART1_BASE, UART_INT_RX | UART_INT_RT);   //  使能接收和接收超时中断UART_INT_TX|
    IntEnable(INT_UART1);                                   //  使能UART总中断
    IntMasterEnable();                                      //  使能处理器中断
    UARTEnable(UART1_BASE);

到此,配置了相关中断处理函数(IRQ)后,在main()里面,PWM0,PWM1,UART等程序运行一切都正常。

后来又增加了I2C模块,并配置相关中断及中断处理函数:

/******************************************************************************************/
//I2C配置动作
/******************************************************************************************/

I2CM_DeviceInitSet(&gtDevice, 0, 0, 0, (void *)0, 0);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C1);           //  使能I2C1模块

    SysCtlPeripheralEnable(I2CSCL_PERIPH);            //  使能SCL所在的GPIO模块
    GPIOPinTypeI2C(I2CSCL_PORT, I2CSCL_PIN);            //  配置相关管脚为SCL功能

    SysCtlPeripheralEnable(I2CSDA_PERIPH);               //  使能SDA所在的GPIO模块
    GPIOPinTypeI2C(I2CSDA_PORT, I2CSDA_PIN);            //  配置相关管脚为SDA功能
 IntPrioritySet(INT_I2C1, 0 << 5);注意这个优先级设置为0,并把上面的PWM0,PWM1,UART的优先级做向后顺延。意图是设I2C为最高优先级

    IntEnable(INT_I2C1);                                  //  使能I2C1中断


    I2CMasterInit(I2C1_MASTER_BASE, true);                        //  I2C主机模块初始化,100kbps
    I2CMasterIntEnable(I2C1_MASTER_BASE);                          //  使能I2C主模块中断
    IntMasterEnable();                                      //  使能处理器中断
    I2CMasterEnable(I2C1_MASTER_BASE);                             //  使能I2C主机

 

于是可悲的事情发生了,程序跑起来后,开始正常,不一会就会精神错乱。程序开始处定义的全局变量、指针就会莫名其妙的乱了,完全不是应该有的样子。

关于NVIC,仅仅是在M3的默认状态增加了 IntPrioritySet(INT_I2C1, 0 << 5);这一改变优先级的库函数。

本菜鸟试图找原因,却始终不明白原因。怀疑堆栈溢出,或者LR错误,又或者中断设置及嵌套存在问题。

请各位大侠们帮忙诊断一下病因。不胜感激。

 

 

  • 重新找了此资料,与中断优先级相关的库函数只有“ IntPrioritySet()”和“ IntPriorityGroupingSet()“这两个函数。

    添加了此代码,测试M3复位后的状态,默认的组优先级为7.就是说可以有8级嵌套。可我在上面只用到了4个中断呀。它们之间嵌套的话也最多只有4个啊。怎么会出现数据错乱呢?

    通过 IntPriorityGroupingSet(3)把组优先级设置为3.情况还是这样。无语,无解。

    今天周六,大侠们都过周未去了吗?谁能帮帮我?

  • Dong :

       看了半天没发现你要证实什么。如果怀疑堆栈溢出的话,可以将堆栈值设大一点。

      关于M3的NVIC,中断优先级与中断级优先级的说明可参考Register 14: Interrupt 0-3 Priority (PRI0), offset 0x400中描述

  •          看来是我描述的不清楚了,I2C呢,接了一个DS1302时钟。PWM驱动电机。UART做控制台。起初没添加相关DS1302的I2C中断时,控制台与电机运行都一切正常。
            关闭PWM中断输出。仅仅使用UART控制台中断和I2C的中断在UART上输出时间也是正常的。
           如果PWM和I2C一旦同时工作(运行在可中断状态)。电机运行,时钟读取并从UART输出时间一开始也正常,但很快时间就不能正确的从DS1302中读出。
    利用硬件调试,发现指向DS1302的I2C从地址的指针,还有一些全局变量等出现了异常。从而不能从DS1302中读出正确的时间。

    程序中有如下语句:

    typedef struct
    {
        unsigned char ucSLA;            //  从机地址(这是7位纯地址,不含读写控制位)
        unsigned char ulAddr;           //  数据地址
        unsigned char uiLen;             //  数据地址长度(取值1、2或4)
        char *pcData;                   //  指向收发数据缓冲区的指针
        unsigned cahr uiSize;            //  收发数据长度
    } tI2CM_DEVICE;

    tI2CM_DEVICE C_DS1302;

    C_DS1302.ucSLA=0xa0;(在这里将I2C从机地址初始化为0xa0)

    main(){

            while(1){

          ..........................................................

          I2CM_DeviceDataSet(&C_DS1302, 0x00+i, &h[i], 1);

         ...................................................

         }

    }

    当时间输出正常时,每当程序运行到I2CM_DeviceDataSet(),观察C_DS1302.ucSLA=0xa0.

    而当不能正常读出时间时,观察C_DS1302.ucSLA=0xXX           XX表示处于不定,为任意值。

    此变量的改变仅是特例,还有其它的变量会改变为不正常状态。

    将KEIL的断点设置在C_DS1302.ucSLA改变时。每次C_DS1302.ucSLA由0xa0变为其它值时程序都停止在PWM0_ISR的中断服务函数入口处。(此种状态为I2C中断优先级为0,PWM0中断优先级为1)。如设置PWM1中断优先级为1,PWM0中断优先级设置为2。则每次C_DS1302.ucSLA由0xa0变为其它值时程序停止在PWM1_ISR的中断服务入口处。

    至此,严重怀疑程序错乱是由中断引起的。本人菜鸟级别,再无从下手。

    在没有更好办法的情况下,现已将硬件中断I2C模式改为软件模拟I2C从而不再使用I2C中断。程序运行及测试全部正常。

    可心中的疑惑却没有答案。

  • Dong :

    "当时间输出正常时,每当程序运行到I2CM_DeviceDataSet(),观察C_DS1302.ucSLA=0xa0.

    而当不能正常读出时间时,观察C_DS1302.ucSLA=0xXX           XX表示处于不定,为任意值。"

    你的C_DS1302是什么性质的变量呀?是局部还是全局呀?

    看你那样描述,应该是中断嵌套过多导致的栈溢出

  • 十分感谢JSW-P J的热心帮助。

    C_DS1302全局静态变量。

    本来程序已经测试好了(采用软件模拟I2C),不打算纠结这个问题了。可是还是过不了自己这关。还是决定把中断方式的I2C加进去测试一下。又Google了一下Keil怎么设置栈的大小。将栈则默认的0x100修改为0x200。重新编译和测试,竟然就完全好了。再改回0x100,就又回到“精神错乱”的状态。看来问题就在于栈的大小设置了。

    遥想当年,用KEIL加汇编方式做51的时候。那个SP是一点一点的计算,从没发生过这样的问题。

    后来用Keil加C,一直采用默认,也一直没发生问题,慢慢的就忽略了堆栈。直到这次问题发生。

    在通往大侠的路上,菜鸟的路还很漫长。。。。。