This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Compiler/EK-TM4C1294XL: Switch Case ignores directive

Guru 56298 points

Part Number: EK-TM4C1294XL

Tool/software: TI C/C++ Compiler

Hello.

Compiler 18.12.3.LTS, 18.12.2.LTS debug single step into (F5) over (F6) ignores case integer value 0, jumps into case 1. This occurs to switch case existing inside Systick handler function 20ms timer looping with static variables shown below.

Any idea why it happens only in Systick timer and acts as if the stack is not being properly managed? Also the default switch case occurs every single step pass via F6.

void
SysTickIntHandler(void)
{

	static uint32_t TurnOffLED = 0;
	static uint32_t TurnOnLED = 0;
	static unsigned int NextCase = 0;


	/* Engage a flip flop between LED D1 and D2 */
	switch(NextCase)
	{
		case 0:
		{
			/* Turn on LED D2 and Trun off LED D1 */
			if(TurnOnLED <= 65535)
			{
				MAP_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, GPIO_PIN_0);
				MAP_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, ~GPIO_PIN_1);

				TurnOnLED ++;

				if(TurnOnLED >= 65535)
				{
					TurnOffLED = 0;
					NextCase = 1;
					break;
				}
			}
		}
		case 1:
		{
			/* Turn off LED D2 and Turn on LED D1 */
			if(TurnOffLED <= 65535)
			{
				MAP_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, ~GPIO_PIN_0);
				MAP_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, GPIO_PIN_1);

				TurnOffLED++;

				if(TurnOffLED >= 65535)
				{
					TurnOnLED = 0;
					NextCase = 0;
					break;
				}
			}
		}
		default:
		{
			//TurnOffLED = 0;
			//TurnOnLED = 0;
			//NextCase = 0;
			break;
		}
	}
}

  • Above TurnOnLED and TurnOffLED increment together as the break case 0 always falls into case 1 even when switch(NextCase=0). That is not logically possible. Notice in older compiler v5.2.8 the initial static variables values (.bss) were very high 1123456 may explain odd address issue at hand? 

    Also notice more lately the serial roll over (CCS 9.1 debug) unsigned char 0xff often ends up producing 0x00 perhaps at 65536, hence 65535 values above. A remote serial sender don't transmit 0xff but value mysteriously changes to 0x0, never into 0xff. 

  • BTW: Compiler optimization level = 0, speed 2 and the code does not toggle the LED's as expected in 1.3 second intervals.

    Or 0.020ms x 65535 = 1310.7ms LED on and 1310.7ms LED off of tandem GPIO port control.

  • I'm not sure what you intend for this code to do.  But it appears you misunderstand one aspect of how case statements work.  Unless a break statement is present, control falls through from one case to the next.  case 0 and case 1 have break statements, but they are within nested if statements.  So, most of the time, control falls through from case 0 to case 1, and from case 1 to the default.  I doubt this is what you intend.  An internet search on c switch statement provides some good background information.

    Thanks and regards,

    -George

  • George Mock said:
    But it appears you misunderstand one aspect of how case statements work.

    Perhaps not and all CASE by definition must block entry unless the SWITCH value changes. I have coded many other switch cases and the CASE blocks step into unless SWITCH value is an exact mirror or of the switch match CASE step into.

    If CASE did not block by default all step into there would be no need for SWITCH to exist.

  • Perhaps you misunderstand the issue here is CASE should never just fall through into next CASE until SWITCH value changes, default behavior is to block entry.

    The BREAK determines escape from CASE and stops re-entrance, otherwise each new IP miss match of switch CASE blocks and eventually falls through to bottom of function. Thus last match to CASE must be pushed on the stack as the SWITCH (static value) when the function exists.

    Have to wonder if the line of code was missing in the disassemble window. The CCS9.1 CSS editor may have ghosted Thumb instruction code lines, is my gut feeling.

  • Hi,

    BP101 said:
    If CASE did not block by default all step into there would be no need for SWITCH to exist.

    Case statements will block entry until a match is found. When a match is found, the code under the matching case will execute. If a break is not present, all the subsequent case statements (including the default) will execute as well.

    A few visual representations are shown at the reference below:

    http://www.c4learn.com/c-programming/c-switch-case-statement/ 

    And a practical scenario where two case statements are executed is shown at:

    https://www.tutorialspoint.com/cprogramming/switch_statement_in_c.htm 

    Regards,

    Rafael

  • The break out is double nested inside each case. Again CASE depends on SWITCH(value) to match the CASE argument or it is not a reliable argument for CASE entry and will exhibit very destructive behavior. Just because you can find articles that support bad logic behavior does not make it correct or prudent to agree with or to them.

    There is after all a DEFAULT case at the bottom when no CASE match to SWITCH was found by the current IP cycle of the function. So the test of argument to CASE via SWITCH (value) is only correct for CASE=0 and should progress into (default) is your argument. Yet it falls through into case=1 when switch=0, logic tells us the argument to CASE must first block then test for match of switch value unless a Break has occurred in current IP cycle then CPU must again retest switch value with each next case in line to find a matching argument. 

  • Are you familiar with Duff's Device?

    C's switch/case has a lot more in common with spaghetti code than structured programming. Many languages, including C# do much to try to bring the crazyness under control.

  • Find it odd several other switch case functions work correctly in another project using the very same logic. Perhaps the word fall through infers each case in CCS debug is stepped over via F6? Yet F6 seemingly should not execute other code inside a case until step into F5 and switch(value) matches the case but it does and did do that. So both cases above were always being executed well before 65535 was ever reached and default too.

    If anything I'd wager Systick and stack manipulation have issues with Switch Case inside CCS 9.1 debug stepping or both. All my other Switch Case are basic functions and this is the first time to attempt one inside a system timer. Though I have another switch case with 8 steps works from 1ms SW tick derived from PWM interrupt cycles.  It has the same double nested (if) buried breaks and does not fall into each case and execute all of them.