Electronic – Compiler optimization prevents code from running

cdebuggingembeddedoptimizationtexas instruments

I was trying to upload a simple code to my board Tiva C EK-TM4C123GXL but it didn't work. I found out that when I turn the optimizer off, the code works fine. This is the code for blinking the on-board LED:

/* p2_3b.c: Toggling LEDs using special function registers by their names defined in
the TivaWare header file */
#include <stdint.h>
#include "inc/tm4c123gh6pm.h"

void delayMs(volatile int n);

int main(void)
{
    /* enable clock to GPIOF at clock gating control register */
    SYSCTL_RCGCGPIO_R |= SYSCTL_RCGCGPIO_R5;
    /* enable the GPIO pins for the LED (PF3, 2 1) as output */
    GPIO_PORTF_DIR_R = 0x0E;
    /* enable the GPIO pins for digital function */
    GPIO_PORTF_DEN_R = 0x0E;
    while(1)
    {
        GPIO_PORTF_DATA_R = 0x0E; /* turn on all LEDs */
        delayMs(500);
        GPIO_PORTF_DATA_R = 0; /* turn off all LEDs */
        delayMs(500);
    }
}
/* delay n milliseconds (16 MHz CPU clock) */
void delayMs(volatile int n)
{
    volatile int i, j;
    for(i = 0; i < n; i++)
        for(j = 0; j < 3180; j++)
            {} /* do nothing for 1 ms */
}
/* This function is called by the startup assembly code to perform system specific
initialization tasks. */
void SystemInit(void)
{
    /* Grant coprocessor access */
    /* This is required since TM4C123G has a floating point coprocessor. */
    NVIC_CPAC_R |= 0x00F00000;
}

Disassembly of the Non-optimized version:

 9        {
          main():
0000026c:   B508                push       {r3, lr}
11            SYSCTL_RCGCGPIO_R |= SYSCTL_RCGCGPIO_R5;
0000026e:   4920                ldr        r1, [pc, #0x80]
00000270:   6808                ldr        r0, [r1]
00000272:   F0400020            orr        r0, r0, #0x20
00000276:   6008                str        r0, [r1]
13            GPIO_PORTF_DIR_R = 0x0E;
00000278:   491E                ldr        r1, [pc, #0x78]
0000027a:   200E                movs       r0, #0xe
0000027c:   6008                str        r0, [r1]
15            GPIO_PORTF_DEN_R = 0x0E;
0000027e:   491E                ldr        r1, [pc, #0x78]
00000280:   200E                movs       r0, #0xe
00000282:   6008                str        r0, [r1]
18                GPIO_PORTF_DATA_R = 0x0E; /* turn on all LEDs */
          $C$L1:
00000284:   491D                ldr        r1, [pc, #0x74]
00000286:   200E                movs       r0, #0xe
00000288:   6008                str        r0, [r1]
19                delayMs(500);
0000028a:   F44F70FA            mov.w      r0, #0x1f4
0000028e:   F000F808            bl         #0x2a2
20                GPIO_PORTF_DATA_R = 0; /* turn off all LEDs */
00000292:   491A                ldr        r1, [pc, #0x68]
00000294:   2000                movs       r0, #0
00000296:   6008                str        r0, [r1]
21                delayMs(500);
00000298:   F44F70FA            mov.w      r0, #0x1f4
0000029c:   F000F801            bl         #0x2a2
16            while(1)
000002a0:   E7F0                b          $C$L1
26        {
          delayMs():
000002a2:   F1AD0D10            sub.w      sp, sp, #0x10
000002a6:   9000                str        r0, [sp]
28            for(i = 0; i < n; i++)
000002a8:   2000                movs       r0, #0
000002aa:   9001                str        r0, [sp, #4]
000002ac:   9800                ldr        r0, [sp]
000002ae:   9901                ldr        r1, [sp, #4]
000002b0:   4288                cmp        r0, r1
000002b2:   DD15                ble        $C$L5
29                for(j = 0; j < 3180; j++)
          $C$L2:
000002b4:   2000                movs       r0, #0
000002b6:   9002                str        r0, [sp, #8]
000002b8:   9802                ldr        r0, [sp, #8]
000002ba:   F640416C            movw       r1, #0xc6c
000002be:   4281                cmp        r1, r0
000002c0:   DD07                ble        $C$L4
          $C$L3:
000002c2:   9802                ldr        r0, [sp, #8]
000002c4:   1C40                adds       r0, r0, #1
000002c6:   9002                str        r0, [sp, #8]
000002c8:   9802                ldr        r0, [sp, #8]
000002ca:   F640416C            movw       r1, #0xc6c
000002ce:   4281                cmp        r1, r0
000002d0:   DCF7                bgt        $C$L3
28            for(i = 0; i < n; i++)
          $C$L4:
000002d2:   9801                ldr        r0, [sp, #4]
000002d4:   1C40                adds       r0, r0, #1
000002d6:   9001                str        r0, [sp, #4]
000002d8:   9800                ldr        r0, [sp]
000002da:   9901                ldr        r1, [sp, #4]
000002dc:   4288                cmp        r0, r1
000002de:   DCE9                bgt        $C$L2
31        }
          $C$L5:
000002e0:   B004                add        sp, #0x10
000002e2:   4770                bx         lr
38            NVIC_CPAC_R |= 0x00F00000;
          SystemInit():
000002e4:   4906                ldr        r1, [pc, #0x18]
000002e6:   6808                ldr        r0, [r1]
000002e8:   F4400070            orr        r0, r0, #0xf00000
000002ec:   6008                str        r0, [r1]
39        }
000002ee:   4770                bx         lr
          $C$CON1:
000002f0:   E608                b          #0xffffff04
000002f2:   400F                ands       r7, r1
          $C$CON2:
000002f4:   5400                strb       r0, [r0, r0]
000002f6:   4002                ands       r2, r0
          $C$CON3:
000002f8:   551C                strb       r4, [r3, r4]
000002fa:   4002                ands       r2, r0
          $C$CON4:
000002fc:   53FC                strh       r4, [r7, r7]
000002fe:   4002                ands       r2, r0
          $C$CON5:
00000300:   ED88E000            stc        p0, c14, [r8]
133          _c_int00_template(0, 0);
          _c_int00_noinit_noargs():
00000304:   4808                ldr        r0, [pc, #0x20]
00000306:   F3808808            msr        msp, r0
0000030a:   4908                ldr        r1, [pc, #0x20]
0000030c:   6808                ldr        r0, [r1]
0000030e:   F4400070            orr        r0, r0, #0xf00000
00000312:   6008                str        r0, [r1]
00000314:   BF00                nop        
00000316:   BF00                nop        
00000318:   F000F810            bl         #0x33c
0000031c:   2000                movs       r0, #0
0000031e:   F7FFFFA5            bl         #0x26c
00000322:   2001                movs       r0, #1
00000324:   F000F80C            bl         #0x340
          $C$CON1:
00000328:   0200                lsls       r0, r0, #8
0000032a:   2000                movs       r0, #0
          $C$CON2:
0000032c:   ED88E000            stc        p0, c14, [r8]
244           __asm("    .global _c_int00\n"
          ResetISR():
00000330:   F7FFBFE8            b.w        _c_int00_noinit_noargs
246       }
00000334:   4770                bx         lr
261           while(1)
          $C$L1, NmiSR():
00000336:   E7FE                b          NmiSR
279           while(1)
          $C$L2, FaultISR():
00000338:   E7FE                b          FaultISR
297           while(1)
          $C$L3, IntDefaultHandler():
0000033a:   E7FE                b          IntDefaultHandler
58            return 1;
          _system_pre_init():
0000033c:   2001                movs       r0, #1
0000033e:   4770                bx         lr
105       {
          C$$EXIT(), abort():
00000340:   BF00                nop        
124           for (;;);   /* SPINS FOREVER */

Disassembly of the Optimized version:

 26        {
           delayMs():
 0000026c:   F1AD0D10            sub.w      sp, sp, #0x10
 28            for(i = 0; i < n; i++)
 00000270:   2100                movs       r1, #0
 26        {
 00000272:   9000                str        r0, [sp]
 29                for(j = 0; j < 3180; j++)
 00000274:   F640426C            movw       r2, #0xc6c
 28            for(i = 0; i < n; i++)
 00000278:   9101                str        r1, [sp, #4]
 0000027a:   E002                b          $C$L2
           $C$L1:
 0000027c:   9801                ldr        r0, [sp, #4]
 0000027e:   1C40                adds       r0, r0, #1
 00000280:   9001                str        r0, [sp, #4]
           $C$L2:
 00000282:   9800                ldr        r0, [sp]
 00000284:   9B01                ldr        r3, [sp, #4]
 00000286:   4298                cmp        r0, r3
 00000288:   DD07                ble        $C$L4
 29                for(j = 0; j < 3180; j++)
 0000028a:   9102                str        r1, [sp, #8]
           $C$L3:
 0000028c:   9802                ldr        r0, [sp, #8]
 0000028e:   4282                cmp        r2, r0
 00000290:   DDF4                ble        $C$L1
 00000292:   9802                ldr        r0, [sp, #8]
 00000294:   1C40                adds       r0, r0, #1
 00000296:   9002                str        r0, [sp, #8]
 00000298:   E7F8                b          $C$L3
           $C$L4:
 0000029a:   B004                add        sp, #0x10
 0000029c:   4770                bx         lr
  9        {
           main():
 0000029e:   B570                push       {r4, r5, r6, lr}
 11            SYSCTL_RCGCGPIO_R |= SYSCTL_RCGCGPIO_R5;
 000002a0:   490D                ldr        r1, [pc, #0x34]
 13            GPIO_PORTF_DIR_R = 0x0E;
 000002a2:   4C0E                ldr        r4, [pc, #0x38]
 11            SYSCTL_RCGCGPIO_R |= SYSCTL_RCGCGPIO_R5;
 000002a4:   6808                ldr        r0, [r1]
 000002a6:   F0400020            orr        r0, r0, #0x20
 000002aa:   6008                str        r0, [r1]
 13            GPIO_PORTF_DIR_R = 0x0E;
 000002ac:   250E                movs       r5, #0xe
 000002ae:   6065                str        r5, [r4, #4]
 15            GPIO_PORTF_DEN_R = 0x0E;
 000002b0:   F8C45120            str.w      r5, [r4, #0x120]
 000002b4:   2600                movs       r6, #0
 18                GPIO_PORTF_DATA_R = 0x0E; /* turn on all LEDs */
           $C$L5:
 000002b6:   6025                str        r5, [r4]
 19                delayMs(500);
 000002b8:   F44F70FA            mov.w      r0, #0x1f4
 000002bc:   F7FFFFD6            bl         #0x26c
 20                GPIO_PORTF_DATA_R = 0; /* turn off all LEDs */
 000002c0:   6026                str        r6, [r4]
 21                delayMs(500);
 000002c2:   F44F70FA            mov.w      r0, #0x1f4
 000002c6:   F7FFFFD1            bl         #0x26c
 16            while(1)
 000002ca:   E7F4                b          $C$L5
 38            NVIC_CPAC_R |= 0x00F00000;
           SystemInit():
 000002cc:   4904                ldr        r1, [pc, #0x10]
 000002ce:   6808                ldr        r0, [r1]
 000002d0:   F4400070            orr        r0, r0, #0xf00000
 000002d4:   6008                str        r0, [r1]
 000002d6:   4770                bx         lr
           $C$CON1:
 000002d8:   E608                b          #0xfffffeec
 000002da:   400F                ands       r7, r1
           $C$CON2:
 000002dc:   53FC                strh       r4, [r7, r7]
 000002de:   4002                ands       r2, r0
           $C$CON3:
 000002e0:   ED88E000            stc        p0, c14, [r8]
 133          _c_int00_template(0, 0);
           _c_int00_noinit_noargs():
 000002e4:   4808                ldr        r0, [pc, #0x20]
 000002e6:   F3808808            msr        msp, r0
 000002ea:   4908                ldr        r1, [pc, #0x20]
 000002ec:   6808                ldr        r0, [r1]
 000002ee:   F4400070            orr        r0, r0, #0xf00000
 000002f2:   6008                str        r0, [r1]
 000002f4:   BF00                nop        
 000002f6:   BF00                nop        
 000002f8:   F000F810            bl         #0x31c
 000002fc:   2000                movs       r0, #0
 000002fe:   F7FFFFCE            bl         #0x29e
 00000302:   2001                movs       r0, #1
 00000304:   F000F80C            bl         #0x320
           $C$CON1:
 00000308:   0200                lsls       r0, r0, #8
 0000030a:   2000                movs       r0, #0
           $C$CON2:
 0000030c:   ED88E000            stc        p0, c14, [r8]
 239       {
           ResetISR():
 00000310:   F7FFBFE8            b.w        _c_int00_noinit_noargs
 00000314:   4770                bx         lr
 261           while(1)
           $C$L1, NmiSR():
 00000316:   E7FE                b          NmiSR
 297           while(1)
           $C$L2, IntDefaultHandler():
 00000318:   E7FE                b          IntDefaultHandler
 279           while(1)
           $C$L3, FaultISR():
 0000031a:   E7FE                b          FaultISR
 58            return 1;
           _system_pre_init():
 0000031c:   2001                movs       r0, #1
 0000031e:   4770                bx         lr
 105       {
           C$$EXIT(), abort():
 00000320:   BF00                nop        
 124           for (;;);   /* SPINS FOREVER */
           $C$L1:
 00000322:   E7FE                b          $C$L1

This code is an example in Mazidi book. I also changed the variables in delayMs function to volatile (although it is not global) but this had no effect. The code still works only when optimization is off.

I tried debugging the code and the program seems to work fine for both cases (optimization on and off). In debugging, the led blinks, then the control transfers to delayMs with no problem and it counts 500 * 3180 times and returns to main then the code continues with no problem. The Assembly code generated in both cases is different but it works.

The problem is: When trying to load the code through CCS (Code Composer Studio) or through lm4flash tool (it loads the .bin file to the board), the code works only when optimization is off.

I use Code Composer Studio version 9 (latest) with compiler TI v18.12.2.LTS.

OS: Ubuntu Bionic 18.04.2 LTS

Thank you in advance!

Best Answer

Prior to learning to implement this using timers/interrupts I would recommend not rolling your own delayMs function. There is a SysCtlDelay(int count) function described in a similar situation Simple delay functions for TI Launchpad? here.

I found an example gist from someone else here https://gist.github.com/ctring/7f12d812fb594eecc493 which shows how to convert from milliseconds to the proper count based on your system clock:

SysCtlDelay(uintMsec * (SysCtlClockGet() / 3 / 1000));