#include <msp430fr2476.h> #define CPU_F ((unsigned long int) 2000000) #define delay_us(x) __delay_cycles(CPU_F * x / ((unsigned long int)1000000)) #define delay_ms(x) __delay_cycles(CPU_F * x / ((unsigned long int)1000)) #define delay_s(x) __delay_cycles(CPU_F * x / ((unsigned long int)1)) unsigned long int global_sec_count = 0; //unsigned long int sec_start; unsigned char timer1_cfg() { TA1CTL &= 0xFFCF; // stop TA1CTL |= 0x0004; // clear TA1CTL = 0x01C0; // other TA1CCTL0 = 0x0000; TA1CCR0 = 0x0200; // 32768 / 8 / 8 TA1EX0 = 0x0007; TA1CTL |= 0x0010; //up mode TA1CTL |= 0x0002; // enable interrupt return 0; } #pragma vector = TIMER1_A1_VECTOR __interrupt void TIMER1_A1_ISR(void) { switch(TA1IV) { case 0x00: // Vector 0: No interrupts break; case 0x0E: global_sec_count++; break; default: break; } } unsigned char msp430fr2476_init() { WDTCTL = 0x5A29; // enable watchdog PM5CTL0 &= 0xFFFE; //------------------------------------ PASEL1 = 0x0000; // PA is IO PBSEL1 = 0x0000; // PB is IO PCSEL1 = 0x0000; // PC is IO PASEL0 = 0x0300; // P2.0 & P2.1 is 32768 PBSEL0 = 0x0000; // PB is IO PCSEL0 = 0x0000; // PC is IO //---------------------------------- while(SFRIFG1 & 0x0002) { CSCTL7 &= 0xFFFC; SFRIFG1 &= 0xFFFD; __no_operation(); __no_operation(); } __bis_SR_register(SCG0); // disable FLL CSCTL3 &= 0xFFCF; CSCTL1 = 0x0033; CSCTL2 = 60; // 2M / 32768 = 61 delay_us(10); __bic_SR_register(SCG0); // enable FLL CSCTL4 = 0x0000; return 0; } unsigned char dummy_func() { PAOUT = 0xFFFF; PAOUT = 0x0000; return 0; } unsigned char main() { unsigned long int sec_start; global_sec_count = 0; msp430fr2476_init(); timer1_cfg(); // enable timer1 and global_sec_count start to increase __enable_interrupt(); __no_operation(); __no_operation(); sec_start = global_sec_count; while((global_sec_count - sec_start) <= 3)// wait 3 seconds { // dummy_func(); __no_operation(); delay_s(1); __no_operation(); } __no_operation(); return 0; }
开发环境:
Code Composer Studio 12.4.0.00007
目标平台MSP430FR2476
能够复现问题的代码如上所示。该代码的期望功能是初始化MSP430FR2476,然后开启定时器,定时器每隔1秒钟将global_sec_count的值增加1。之后使用sec_start记录当前global_sec_count的值(因为定时器刚开启,所以sec_start应该为0),在while循环时每隔1秒检测sec_start和global_sec_count的差值,当二者差值超过3,即经过3秒后,结束循环,执行后续代码。
实际执行情况是:
现象1、如果使用在线调试工具让代码自动执行,会发现程序无法跳出循环。暂停程序运行后会发现sec_start的高16位值被改变,使得sec_start的值从正确的值0变为一个随机的值(如图所示为0xE6730000)。此时即使global_sec_count已经大于4(如图所示为7),会仍然在进行循环。
现象2、如果使用仿真器在循环内单步执行程序,sec_start的值能够保持为0,但是即使global_sec_count已经大于4(如图所示为7),会仍然在进行循环。
现象3、如果将77行代码的unsigned long int sec_start;修改为signed long int sec_start;,即将sec_start定义为有符号的长整型,程序就能正确跳出while循环。
现象4、如果将sec_start定义为全局变量,仍然保持其为unsigned long int格式,程序也能正确跳出while循环。
现象5、如果在循环内部调用一个理论上不影响循环的函数(例如代码中的dummy_func()),程序也能正确跳出while循环。
从代码来看现象1和现象2不应该出现,同时在现象3-现象5的情况下解决BUG的问题也很异常。
您好
现象1、如果使用在线调试工具让代码自动执行,会发现程序无法跳出循环。暂停程序运行后会发现sec_start的高16位值被改变,使得sec_start的值从正确的值0变为一个随机的值(如图所示为0xE6730000)。此时即使global_sec_count已经大于4(如图所示为7),会仍然在进行循环。
我假设已启用-O0(寄存器级)优化。您能否尝试完全禁用优化(设置为-Ooff),以便sec_start位于RAM中?然后看看程序是否按预期运行。
上述结果是在已启用-O0(寄存器级)优化时的现象。完全禁用优化(设置为-Ooff)后,sec_start被分配到0x003FF8地址处,程序能够正常跳出循环,按照预期运行。
但是我实际项目中的代码量比较大,为了能让程序运行在MSP430FR2476上,我编译的时候是开启O2级别优化以减小程序存储器占用的。
在开启O2级别优化的情况下,在现象1、2的条件下程序无法退出循环,和O0优化级别相同;在现象5的条件下程序可以退出循环,和O0优化级别相同;但是在现象3、4的条件下程序变得无法退出循环。因为开启O2优化后“Variables”窗口已经无法显示sec_start的数值,所以无法确认其内容是否正确。
有没有办法在不禁用优化的情况下修复这个问题呢?