MSPM0G3505: compiler error with TIclang?

Part Number: MSPM0G3505

I'm implementing a trivial for loop and it is failing.

see debug screen shot. 

I watch as I step through my for loop - 

for(i = 0; i < 8; i++){ ...}
I see  it increment from 0 to past 8.  i =  20 in screen shot.  how is this a thing?
 
MSPM0G3505, CCS Version: 20.4.1.4__1.10.1  TI Clang 4.0.4 LTS
 
debug screen shot image failing to upload, code below:
 
void SetDisp(volatile uint8_t mask){
	volatile unsigned char i;
	for(i = 0; i < 8; i++){
  		DL_GPIO_clearPins(DISP_GRP_PORT,DISP_GRP_SHFT_PIN);
		if((mask & (0x80 >> i))==0){
			DL_GPIO_clearPins(DISP_GRP_PORT,DISP_GRP_DOUT_PIN);
		}
		else{
			DL_GPIO_setPins(DISP_GRP_PORT,DISP_GRP_DOUT_PIN);
		}
  		DL_GPIO_setPins(DISP_GRP_PORT,DISP_GRP_SHFT_PIN);
	}
}

..
 
Debug window info:

CORTEX_M0P
 
Halted
  
SetDisp() 0x00000494display.c32:23
DispSplash() 0x0000047Adisplay.c46:3
main() 0x00000348main.c0:5
  
Locals
 
i: 20     0x20203FE0
 
 
  • Hi Dan,

    Could you try to use optimization level 0, and try the same code again, I want to make sure the function is not optimized by compiler.

    And when do you observe the variable "i", did you observe during the loop execution?

  • Outside of the for loop, i can be used for something else.

    Where is the debugger breaking?

  • Thanks for the fast reply...

    I was breaking inside the loop -  line "DL_GPIO_setPins(DISP_GRP_PORT,DISP_GRP_SHFT_PIN);"  

    I also had a breakpoint just past the loop that was never reached.

    Changing from 2 to 0 on the optimization does resolve the issue though that seems like a rather weak fix.

    Also, FYI I tried a different form of loop (see below) and it too failed - x got to 0 but the loop never exited. 

    In addition to watching the variables in debug, I monitored the pins externally with my scope and saw that the code stuck in the loop, so definitely real world issue, not some weird debug halucination.

    void SetDisp(uint8_t mask){

        volatile unsigned char x;
        x = 0x80;
        do{
            DL_GPIO_clearPins(DISP_GRP_PORT,DISP_GRP_SHFT_PIN);
            if(mask & x)
                DL_GPIO_setPins(DISP_GRP_PORT,DISP_GRP_DOUT_PIN);
            else
                DL_GPIO_clearPins(DISP_GRP_PORT,DISP_GRP_DOUT_PIN);
            DL_GPIO_setPins(DISP_GRP_PORT,DISP_GRP_SHFT_PIN);
            x = x >> 1;
        }while(x != 0);

    }
  • Have you tried it without "volatile" it is not really doing anything here.

  • On the contrary, "volatile" is allowing me to catch the code in the act.  I didn't use it originally and my variable (x or i depending on the loop version) was optimized out so I couldn't watch it.. But when I began to suspect that the loop was not behaving properly, I tagged the index with volatile forcing the compiler to keep it visible so I could watch it increment past the test condition.

    So, yes, the loop fails with and without the "volatile" denotation.

  • FYI setting optimization to 1,2, 3, or "fast" "z" or "g" (what are these non numeric optimizations) causes the loop to execute infinitely.

    Setting to 's' (what is this?) drops me into a fault trap:

    /* This is the code that gets called when the processor receives an unexpected  */
    /* interrupt.  This simply enters an infinite loop, preserving the system state */
    /* for examination by a debugger.                                               */
    void Default_Handler(void)
    {
        /* Enter an infinite loop. */
        while (1) {
        }
    }
  • Hi Dan,

    One of my suspicion on this issue is that the "x" is defined "unsigned char" which is actual 8bit type. It may be defined in an address where the higher 24bit has other variable defined with a compiler optimization. When you access "x" it may get the whole 32bit data from the address.

    You could try to define x with uint32_t type, or try to use ((uint8_t) x) to replace (x) when you access "x", and try whether it could solve the problem.

  • Looking at the disassembly, it would appear that the compiler optimized out the test. I don't see a compare or conditional branch anywhere.
    The PC is at 0x0BFE when I break on

    for(i = 0; i < 8; i++)



        0x00000BF2    06C2                lsls    r2, r0, #0x1b
        0x00000BF4    600A                str     r2, [r1]
        0x00000BF6    6020                str     r0, [r4]
        0x00000BF8    200A                movs    r0, #0xa
        0x00000BFA    F9B8F000            bl      0xf6e <DL_Common_delayCycles>
        0x00000BFE    9802                ldr     r0, [sp, #0x8]
        0x00000C00    1C40                adds    r0, r0, #0x1
        0x00000C02    9002                str     r0, [sp, #0x8]
        0x00000C04    9802                ldr     r0, [sp, #0x8]
        0x00000C06    2001                movs    r0, #0x1
        0x00000C08    6120                str     r0, [r4, #0x10]
        0x00000C0A    9903                ldr     r1, [sp, #0xc]
        0x00000C0C    9A02                ldr     r2, [sp, #0x8]
        0x00000C0E    4091                lsls    r1, r2
        0x00000C10    0609                lsls    r1, r1, #0x18
        0x00000C12    D4ED                bmi     0xbf0
        0x00000C14    4621                mov     r1, r4
        0x00000C16    3110                adds    r1, #0x10
        0x00000C18    E7EB                b       0xbf2
        0x00000C1A    B004                add     sp, #0x10
        0x00000C1C    BD10                pop     {r4, pc}
        0x00000C1E    46C0                mov     r8, r8
        0x00000C20    400A1290            .word      0x400A1290
        0x00000C24    00000FAF            .word      0x00000FAF

  • I wrapped this function (both versions) with a simple-minded main() which called it with different mask values, and I don't see any of the symptoms you've described. I tried [-O2, -O3, -Os] The waveforms look right, and I even see the correct value of "i" (I usually only half-believe what the debugger tells me about these things.) In the second version, the debugger reported that both "'x" and "mask" had been optimized out.

    I suspect there's something going on outside the code you've posted. Given the range of symptoms you've seen, a stack overflow (maybe from a stray interrupt?) seems a possibility. If you can generate that (presumed) HardFault again, working backwards from there might tell you something.

  • Interesting suggestion. But it still seems to come down to the compiler generating code that is an infinite loop.

    Please explain what I'm seeing in the disassembly:

    If I'm reading the assembly code correctly, I see that at 0xC12 there is a conditional branch (bmi) to 0xBF0 (one instruction above what I pasted - 0xBF0: mov     r1, r4 ), or you get to 0xC18 where you hit an unconditional branch to 0xBF2.  So no matter what, this code stays infinitely between 0xBF0 and 0xC18 - Am I misreading this?  Regardless of what happens with ISRs, the stack, etc., the instructions in this section of code appear to be fundamentally wrong.

  • The functions you posted didn't call delay_cycles(), so I suspected that the entire function had been subsumed (inline-d) into the caller. In that case -- just guessing at what the caller did -- there might not be any reason to exit the loop. That didn't happen in my experiment, but all that means is that your caller is different from mine.

    It could be a compiler bug; those happen, but they're quite rare. More common are illusions created by the optimizer and/or debugger.

    If you want to report it, the first thing the compiler people will ask for is a complete, minimal, self-contained project which exhibits the symptom. Constructing that might give you some insight into what you're seeing.

    [Edit: Minor clarification.]

**Attention** This is a public forum