MCU passes through infinite loop

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

 

I found a very odd behaviour of my code and I decided to share it, it'd be interesting if someone can figure out the mystery.

I am having a code, which is executed when error occurs and what it does is it sends some data to another MCU and awaits power down (done by the other MCU) - if there is no power down there should be an WDR reset, but this is not important in this case.

What actually happens is that in one case the device exits the infinite loop.

 

MCU - XMega E5

Compiler - ImageCraftCB 8.22!

 

Code, in which the infinite loop is actually not infinite and the MCU continues its work:

 

#define TRUE   1    //this is done in a header file

/*************************************************************************/
static void ShutDownRequest(void)
{
    unsigned char wait = 10;
    unsigned char i;

    if (COM_HEADER != sendData.structSendData.header) InitUsart(); //initialize UART if not initialized
    sendData.structSendData.adcFlags.error = TRUE;
    CLI();

    while(TRUE)//FOREVER! (but actually max (wait * time ), which is now 500 ms * 10 = 5 sec
    {
        //asm("nop");

        if ((TCD5_INTFLAGS & TC5_OVFIF_bm) != 0) //time passed
        {
            TCD5_INTFLAGS = TC5_OVFIF_bm; //clear interrupt flag

            /***   send data via uart   ***/
            for (i = 0; i < sizeof(T_SendData); i++)
            {
                SendChar(sendData.sendBytes[i]);
            }

            /***   waited enough   ***/
            if (wait) //waited enough?
            {
                wait--;
                WDR();
            }
            //else there will be no WDR and we will have a merciful restart
        }
    }
}

If I add anything after the while(1) - I've tried with - PORTD_OUTTGL = pin7_bm initially, then I tried with asm("nop") - the loop IS infinite - it works.

 

/*************************************************************************/
static void ShutDownRequest(void)
{
    unsigned char wait = 10;
    unsigned char i;

    if (COM_HEADER != sendData.structSendData.header) InitUsart(); //initialize UART if not initialized
    sendData.structSendData.adcFlags.error = TRUE;
    CLI();

    while (TRUE)//FOREVER! (but actually max (wait * time ), which is now 500 ms * 10 = 5 sec
    {
        asm("nop");

        if ((TCD5_INTFLAGS & TC5_OVFIF_bm) != 0) //time passed
        {
            TCD5_INTFLAGS = TC5_OVFIF_bm; //clear interrupt flag

            /***   send data via uart   ***/
            for (i = 0; i < sizeof(T_SendData); i++)
            {
                SendChar(sendData.sendBytes[i]);
            }

            /***   waited enough   ***/
            if (wait) //waited enough?
            {
                wait--;
                WDR();
            }
            //else there will be no WDR and we will have a merciful restart
        }
    }
}

 

If I change the while(1) to for(;;) the code also works as it is inteded:

 

    for(;;)//FOREVER! (but actually max (wait * time ), which is now 500 ms * 10 = 5 sec
    {
        //asm("nop");

        if ((TCD5_INTFLAGS & TC5_OVFIF_bm) != 0) //time passed
        {
           

 

So I'm just curious, why does this happen?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Post the Asm generated in each case. But let's face it the compiler is going to create the same looping code whether the high level syntax is while(1) or for(;;) so that must be a red herring. I'd suggest this MUSt be something to do with the watchdog. Try putting a statement (perhaps a NOP) immediately after the infinite loop and put a breakpoint on it. Is that breakpoint ever hit in the debugger? Nope, thought not.

 

(of course there's an outside possibility that cosmic rays, electrical noise, sagging Vcc or something is corrupting something like PC but it's very unlikely - is this thing operating in a noisy place or has high current load that could pull Vcc down?)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the reply, clawson.

 

When I use pin toggle just after the loop, it is not reached. When I put breakpoint - there is an error - no such line. The compiler seems to cut that part off, though there is no "unreachable code warning", in contrast from for(;;)

 

Still, the function is not infinite. When I put breakpoint after the function, I can see that the execution of the code continues after it - so I observe very well that the function is entered, it's end is not reached but still the program continues after it. When I don't init the WD, same thing happens. The strange thing is that I use this function for numerous ADC checks. When signals generate ShutDownRequest event, the third time that happens the function is infinite :)

 

The while(1) and for(;;) constructs do not return same code.

 

while(1):

 082E                   .dbfunc s ShutDownRequest _ShutDownRequest#Fvv fV 394 19376700
 082E           ;           wait -> R10
 082E           ;              i -> R12
                        .even
 082E           _ShutDownRequest#Fvv:
 082E 0E940000          xcall push_xgset00FC
 0832                   .dbblock 395
 0832                   .dbline 396
 0832 8AE0              ldi R24,10
 0834 A82E              mov R10,R24
 0836                   .dbline 399
 0836 80911800          lds R24,_sendData#us3_141
 083A 8A3A              cpi R24,170
 083C 11F0              breq L352
 083E           X46:
 083E                   .dbline 399
 083E 0E940000          xcall _InitUsart#Fvv
 0842           L352:
 0842                   .dbline 400
 0842 80912900          lds R24,_sendData#us3_141+17
 0846 90912A00          lds R25,_sendData#us3_141+17+1
 084A 8260              ori R24,2
 084C 80932900          sts _sendData#us3_141+17,R24
 0850 90932A00          sts _sendData#us3_141+17+1,R25
 0854                   .dbline 401
 0854 F894              cli
 0856 1EC0              xjmp L356
 0858           L355:
 0858                   .dbline 405
 0858 20904C09          lds R2,2380
 085C 20FE              sbrs R2,0
 085E 1AC0              rjmp L358
 0860           X47:
 0860                   .dbline 407
 0860 81E0              ldi R24,1
 0862 80934C09          sts 2380,R24
 0866                   .dbline 410
 0866 CC24              clr R12
 0868 0EC0              xjmp L363
 086A           L360:
 086A                   .dbline 412
 086A 80E0              ldi R24,<_sendData#us3_141
 086C 90E0              ldi R25,>_sendData#us3_141
 086E EC2D              mov R30,R12
 0870 FF27              clr R31
 0872 E80F              add R30,R24
 0874 F91F              adc R31,R25
 0876 E080              ldd R14,z+0
 0878           L366:
 0878           L367:
 0878 2090C109          lds R2,2497
 087C 25FE              sbrs R2,5
 087E FCCF              rjmp L366
 0880           X48:
 0880 E092C009          sts 2496,R14
 0884           L369:
 0884           L365:
 0884           L361:
 0884                   .dbline 410
 0884 C394              inc R12
 0886           L363:
 0886                   .dbline 410
 0886 8C2D              mov R24,R12
 0888 8331              cpi R24,19
 088A 78F3              brlo L360
 088C           X49:
 088C                   .dbline 416
 088C AA20              tst R10
 088E 11F0              breq L370
 0890           X50:
 0890                   .dbline 418
 0890 AA94              dec R10
 0892                   .dbline 419
 0892 A895              wdr
 0894           L370:
 0894           L358:
 0894           L356:
 0894                   .dbline 403
 0894 E1CF              xjmp L355
 0896           X51:
 0896                   .dbblkend 424
 0896           L351:
 0896 0C940000          xjmp pop_xgset00FC
 089A 0895              ret

for(;;)

082E           _ShutDownRequest#Fvv:
 082E 0E940000          xcall push_xgset00FC
 0832                   .dbblock 395
 0832                   .dbline 396
 0832 8AE0              ldi R24,10
 0834 A82E              mov R10,R24
 0836                   .dbline 399
 0836 80911800          lds R24,_sendData#us3_141
 083A 8A3A              cpi R24,170
 083C 11F0              breq L352
 083E           X46:
 083E                   .dbline 399
 083E 0E940000          xcall _InitUsart#Fvv
 0842           L352:
 0842                   .dbline 400
 0842 80912900          lds R24,_sendData#us3_141+17
 0846 90912A00          lds R25,_sendData#us3_141+17+1
 084A 8260              ori R24,2
 084C 80932900          sts _sendData#us3_141+17,R24
 0850 90932A00          sts _sendData#us3_141+17+1,R25
 0854                   .dbline 401
 0854 F894              cli
 0856           L355:
 0856                   .dbline 405
 0856 20904C09          lds R2,2380
 085A 20FE              sbrs R2,0
 085C FCCF              rjmp L355
 085E           X47:
 085E                   .dbline 407
 085E 81E0              ldi R24,1
 0860 80934C09          sts 2380,R24
 0864                   .dbline 410
 0864 CC24              clr R12
 0866 0EC0              xjmp L364
 0868           L361:
 0868                   .dbline 412
 0868 80E0              ldi R24,<_sendData#us3_141
 086A 90E0              ldi R25,>_sendData#us3_141
 086C EC2D              mov R30,R12
 086E FF27              clr R31
 0870 E80F              add R30,R24
 0872 F91F              adc R31,R25
 0874 E080              ldd R14,z+0
 0876           L367:
 0876           L368:
 0876 2090C109          lds R2,2497
 087A 25FE              sbrs R2,5
 087C FCCF              rjmp L367
 087E           X48:
 087E E092C009          sts 2496,R14
 0882           L370:
 0882           L366:
 0882           L362:
 0882                   .dbline 410
 0882 C394              inc R12
 0884           L364:
 0884                   .dbline 410
 0884 8C2D              mov R24,R12
 0886 8331              cpi R24,19
 0888 78F3              brlo L361
 088A           X49:
 088A                   .dbline 416
 088A AA20              tst R10
 088C 21F3              breq L355
 088E           X50:
 088E                   .dbline 418
 088E AA94              dec R10
 0890                   .dbline 419
 0890 A895              wdr
 0892                   .dbline 403
 0892 E1CF              xjmp L355
 0894           X51:
 0894                   .dbblkend 424
 0894           L351:
 0894 0C940000          xjmp pop_xgset00FC
 0898 0895              ret

 

So, the code is different, in the while(1) variant we jump to the end of the function and then jump back, but it seems ok?

 

I blame the cosmic rays as well.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Where is the source annotation? Pure Asm is close to unreadable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Idk if I can automatically generate it in Imagecraft (relevance between C and the assembler), probably not, so I will try to note the main points when I can.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't understand the problem:

 

Your code init wait to 10

 

For each <forever loop> it count down, and kick the watchdog  if it's !=0.

 

When wait is ==0 then you don't do anything, and you will soon get a watchdog reset!

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I imagine those .dbline statements are the way it embeds references to source files into this Asm so I think there's probably something created later in the build that pulls together the Asm and the source. Or maybe this is only for the COFF and the only tool that can annotate the Asm with the C source is the Studio debugger?

 

BTW I just grepped your two listings to -v the ".db" stuff and then diff'd the outputs and in reality the codes are virtually identical. One does have a mysterious xjmp to the end that then does an xjmp back to the beginning and this throws off the addressing and labelling of all the subsequent instructions - but those instructions are, otherwise pretty much identical....

 

 

I added those last two text filters to Meld for this. One ignores the first 4 characters on each line (so the 08xx addresses) and the other L followed by any 3 characters (ie the Asm labels).

 

So the bottom line is that apart from the additional XJMP they are identical.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:

I don't understand the problem:

The problem is that in one of the cases the application continues (passes through this function) without WD or any kind of reset, which should be impossible. This happens only in the while(1) case and does not happen in the for(;;) case, also doesn't happen if I add an instruction after the while(1). Besides that, you have correctly understood the purpose of the function and it really behaves like that in all other cases.

 

Clawson, you are right about everything, I will check the imagecraft group for ideas, but I am about to let it go :)

Those .db lines are actually the line numbers in the "C code" in which the instruction takes place probably for viewer's reference, I assume they have no further meaning for the compiler; The code is from .lis file, generated by ImagecraftCB.

 

P.S.

is this thing operating in a noisy place or has high current load that could pull Vcc down?

I forgot to reply to this one - no, I use the device in test conditions without noise or high currents, in its other functions and usage since at least a month tests on this PCB version I haven't seen any unusual behavior and here in this function, it is not a problem which happens just now and then - it happens every time. 

Last Edited: Mon. Jun 27, 2016 - 06:52 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Alex, a very readable C and asm listing file is available under the menu "ImageCraft->View Listing File"

 

Since you posted to the icc mailing list (which arguably is better for ICC/JumpStart C specific questions anyway), I will help you out further there.

Richard Man http://imagecraft.com

Beyond Arduino - When you're ready to get serious...
JumpStart C Tools, The Better Alternative.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks!

 

Here is that version with "for":

(0392) /*************************************************************************/
(0393) static void ShutDownRequest(void)
(0394) {
(0395)     unsigned char wait = 10;
    004DD E08A      LDI	R24,0xA
    004DE 2EA8      MOV	R10,R24
(0396)     unsigned char i;
(0397) 
(0398)     if (COM_HEADER != sendData.structSendData.header) InitUsart(); //initialize UART if not initialized
    004DF 9180 20AB LDS	R24,_sendData
    004E1 3A8A      CPI	R24,0xAA
    004E2 F011      BEQ	0x04E5
    004E3 940E 0723 CALL	_InitUsart
(0399)     sendData.structSendData.adcFlags.error = TRUE;
    004E5 9180 20BC LDS	R24,_sendData+17
    004E7 9190 20BD LDS	R25,_sendData+18
    004E9 6082      ORI	R24,2
    004EA 9380 20BC STS	_sendData+17,R24
    004EC 9390 20BD STS	_sendData+18,R25
(0400)     CLI();
    004EE 94F8      BCLR	7
(0401) 
(0402)     for(;;)//FOREVER! (but actually max (wait * time ), which is now 500 ms * 10 = 5 sec
(0403)     {
(0404)         if ((TCD5_INTFLAGS & TC5_OVFIF_bm) != 0) //time passed
    004EF 9020 094C LDS	R2,0x94C
    004F1 FE20      SBRS	R2,0
    004F2 CFFC      RJMP	0x04EF
(0405)         {
(0406)             TCD5_INTFLAGS = TC5_OVFIF_bm; //clear interrupt flag
    004F3 E081      LDI	R24,1
    004F4 9380 094C STS	0x94C,R24
(0407) 
(0408)             /***   send data via uart   ***/
(0409)             for (i = 0; i < sizeof(T_SendData); i++)
    004F6 24CC      CLR	R12
    004F7 C00E      RJMP	0x0506
(0410)             {
(0411)                 SendChar(sendData.sendBytes[i]);
    004F8 EA8B      LDI	R24,0xAB
    004F9 E290      LDI	R25,0x20
    004FA 2DEC      MOV	R30,R12
    004FB 27FF      CLR	R31
    004FC 0FE8      ADD	R30,R24
    004FD 1FF9      ADC	R31,R25
    004FE 80E0      LD	R14,Z
    004FF 9020 09C1 LDS	R2,0x9C1
    00501 FE25      SBRS	R2,5
    00502 CFFC      RJMP	0x04FF
    00503 92E0 09C0 STS	0x9C0,R14
    00505 94C3      INC	R12
    00506 2D8C      MOV	R24,R12
    00507 3183      CPI	R24,0x13
    00508 F378      BCS	0x04F8
(0412)             }
(0413) 
(0414)             /***   waited enough   ***/
(0415)             if (wait) //waited enough?
    00509 20AA      TST	R10
    0050A F321      BEQ	0x04EF
(0416)             {
(0417)                 wait--;
    0050B 94AA      DEC	R10
(0418)                 WDR();
    0050C 95A8      WDR
    0050D CFE1      RJMP	0x04EF
    0050E 940C 14D8 JMP	pop_xgset00FC
    00510 9508      RET
(0419)             }
(0420)             //else there will be no WDR and we will have a merciful restart
(0421)         }
(0422)     }
(0423) }

and while(1)

 

(0392) /*************************************************************************/
(0393) static void ShutDownRequest(void)
(0394) {
(0395)     unsigned char wait = 10;
    004DD E08A      LDI	R24,0xA
    004DE 2EA8      MOV	R10,R24
(0396)     unsigned char i;
(0397) 
(0398)     if (COM_HEADER != sendData.structSendData.header) InitUsart(); //initialize UART if not initialized
    004DF 9180 20AB LDS	R24,_sendData
    004E1 3A8A      CPI	R24,0xAA
    004E2 F011      BEQ	0x04E5
    004E3 940E 0724 CALL	_InitUsart
(0399)     sendData.structSendData.adcFlags.error = TRUE;
    004E5 9180 20BC LDS	R24,_sendData+17
    004E7 9190 20BD LDS	R25,_sendData+18
    004E9 6082      ORI	R24,2
    004EA 9380 20BC STS	_sendData+17,R24
    004EC 9390 20BD STS	_sendData+18,R25
(0400)     CLI();
    004EE 94F8      BCLR	7
    004EF C01E      RJMP	0x050E
(0401) 
(0402)     while(1)//FOREVER! (but actually max (wait * time ), which is now 500 ms * 10 = 5 sec
(0403)     {
(0404)         if ((TCD5_INTFLAGS & TC5_OVFIF_bm) != 0) //time passed
    004F0 9020 094C LDS	R2,0x94C
    004F2 FE20      SBRS	R2,0
    004F3 C01A      RJMP	0x050E
(0405)         {
(0406)             TCD5_INTFLAGS = TC5_OVFIF_bm; //clear interrupt flag
    004F4 E081      LDI	R24,1
    004F5 9380 094C STS	0x94C,R24
(0407) 
(0408)             /***   send data via uart   ***/
(0409)             for (i = 0; i < sizeof(T_SendData); i++)
    004F7 24CC      CLR	R12
    004F8 C00E      RJMP	0x0507
(0410)             {
(0411)                 SendChar(sendData.sendBytes[i]);
    004F9 EA8B      LDI	R24,0xAB
    004FA E290      LDI	R25,0x20
    004FB 2DEC      MOV	R30,R12
    004FC 27FF      CLR	R31
    004FD 0FE8      ADD	R30,R24
    004FE 1FF9      ADC	R31,R25
    004FF 80E0      LD	R14,Z
    00500 9020 09C1 LDS	R2,0x9C1
    00502 FE25      SBRS	R2,5
    00503 CFFC      RJMP	0x0500
    00504 92E0 09C0 STS	0x9C0,R14
    00506 94C3      INC	R12
    00507 2D8C      MOV	R24,R12
    00508 3183      CPI	R24,0x13
    00509 F378      BCS	0x04F9
(0412)             }
(0413) 
(0414)             /***   waited enough   ***/
(0415)             if (wait) //waited enough?
    0050A 20AA      TST	R10
    0050B F011      BEQ	0x050E
(0416)             {
(0417)                 wait--;
    0050C 94AA      DEC	R10
(0418)                 WDR();
    0050D 95A8      WDR
    0050E CFE1      RJMP	0x04F0
    0050F 940C 14D9 JMP	pop_xgset00FC
    00511 9508      RET
(0419)             }
(0420)             //else there will be no WDR and we will have a merciful restart
(0421)         }
(0422)     }
(0423) }

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please do not cross post. If you are getting help for this on the Imgaecraft support list then don't post here as well or you will end up wasting someone's time (either on the Imagecraft list or here).
 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, no problems - I was posting only here so far (until this morning), I only wrote there today after there was no resolution and the problem might be compiler dependant, rather than wrong code, written by me. I suppose this is not considered cross posting, if it is - I apologize.

Their support will now check out what the problem could be and if there is a resolution, I will post it here to complete the topic, it might be interesting for its future readers.

Thanks for the participation to everyone!

 

With that said, if someone is still curious (don't waste your time otherwise, as clawson noted), I've prepared very simple code, which illustrates the problem (and it still happens), I am just attaching it in case that someone wants to test it out of curiousity.

Attachment(s): 

Last Edited: Mon. Jun 27, 2016 - 10:47 AM