cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with switch/case

Jakub B
Associate III
Posted on April 03, 2018 at 15:22

Hi

I got a problem with a switch in my MCU. I use custom board with STM32F030C8T6.

This here is part of my program:

void rozkaz3(void) {

switch(bufor[3]){

case 0:

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET);

HAL_Delay(1000);

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_SET);

break;

case 1: HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);

HAL_Delay(1000);

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);

break;

case 2:

HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_RESET);

HAL_Delay(1000);

HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_SET);

break;

case 3:

HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6, GPIO_PIN_RESET);

HAL_Delay(1000);

HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6, GPIO_PIN_SET);

break;

case 5:

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_RESET);

HAL_Delay(1000);

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_SET);

break;

case 6:

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);

HAL_Delay(1000);

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);

break;

case 7:

case 4:

default:

break;

case 12:

NVIC_SystemReset();

break;

it switches on and off outputs i chose based on number. My board has 6 outputs. Case 4 and case 7 are not configured and not connected.

If i order case 0,1,2,3,5,6,11,12 all works well.

If i order case 4 or 7 my program works on case 0 then case 4/7. If i delete case 0 it will work on case 1 and then case 4/7 and so on.

It works first available case in switch then case i ordered.

Now if i change only this:

case 7:

case 4:

default:

HAL_Delay(1000);

break;

I works ok.

And with HAL_Delay(1) its not working again.

Whats happening and how to make it work right without HAL_Delay ?

Note: this post was migrated and contained many threaded conversations, some content may be missing.
34 REPLIES 34
Posted on April 05, 2018 at 16:55

switch/case has no requirement or restriction that the case label values be in numerical order.  The case labels may appear in any order, and often do.

Coding style guidelines adopted or imposed by a given project may say to always order the case labels, but such a rule is misguided.  A better rule of thumb is that the most likely candidate (other than 'default') should appear first because the compiler will often compare against that value first when the switch is translated to 'if ((int t = bufor[3]) == x) { } else if (t == y) {} else if ... {} else {}' style assembly.  Nothing wrong with 'default' appearing first, but the compiler will branch to the code in the default clause when nothing else matches, and if you put it first and don't have optimization enabled, you're likely to have an unconditional jump around that code and then a branch to the generated code for the statement following the 'switch' body.  The optimizer will move code around as it sees fit based on optimization levels, CPU architecture, and flow analysis.  (The optimizer may also use a jump table when the case label values are sufficiently dense and in a restricted range, at which point the order does not matter even as hint to the compiler.)

Any value that is not included in a case label will end up in the 'default' clause code, so don't bother with the case labels that fall through to 'default' unless doing so for stylistic or documentation purposes.  Most compilers will eliminate the comparisons for those values, but not all.

As has already been determined later in this thread, the problem with the code is race conditions that the delay mitigates.  In general, I don't use global variables or arrays for things like this; instead, I would pass the value of 'bufor[3]' to the function containing the switch, since this is the only thing that the function cares about.  If you had done that, the control variable of the switch would not be volatile (would not change if 'bufor[3]' is updated) and it would have been much easier to see what was wrong in the debugger.  Also, as others have said, you need to be sure that the input has completed, at least up 'bufor[3]' getting set, before evaluating 'bufor[3]'.

Posted on April 05, 2018 at 16:59

j.beling

‌: The debugger changes the timing on you. The interrupt processing only happens during step or run. Your code is, in effect, multithreaded due to interrupt handling.

Jakub B
Associate III
Posted on April 06, 2018 at 15:55

You all focused on race condition and cant understand one thing so ill try to show you something:

0690X0000060AS9QAM.png

Those in color are only possible packages for now

1st yellow one is stany - it goes every 2 seconds and works properly

those from rozkaz part in yellow works properly

red ones when sent work as if i sent green one

green one works properly.

If i had race condition on bufor[3] i would have all orders on yellow switched to green too.

But only those two red dont work. Why would race condition be triggered only on those 2 and not all of them?

Posted on April 06, 2018 at 15:56

btw: ill do pictures of debug later when im in lab. probably on monday

Posted on April 06, 2018 at 17:58

I would suggest to set a data breakpoint on the 'incorrect' case, conditionally triggering on those erraneous conditions.

Perhaps toggle a free GPIO before, and trigger a scope showing the serial communication.