1

I am a newbie in this of embedded systems. For my final degree project I am developing a system working with a STM NUCLEO Board with a STM32F411RE microcontroller.

In addition, I am working with stmcube32 for loading initialization code.

At this point I am stuck, but first let me explain you a litle background:

  • I have three interrupt routines handling the same flag, as you can see in the source file stm32f4xx_it.c:

    void EXTI15_10_IRQHandler(void) {
    
        /* USER CODE BEGIN EXTI15_10_IRQn 0 */
    
        if (__HAL_GPIO_EXTI_GET_IT(BOTON1_Pin) != RESET) {
            __HAL_GPIO_EXTI_CLEAR_IT(BOTON1_Pin);
            boton_Flag = 1;
        }
        if (__HAL_GPIO_EXTI_GET_IT(BOTON2_Pin) != RESET) {
            __HAL_GPIO_EXTI_CLEAR_IT(BOTON2_Pin);
            boton_Flag = 2;
        }
        if (__HAL_GPIO_EXTI_GET_IT(BOTON3_Pin) != RESET) {
            __HAL_GPIO_EXTI_CLEAR_IT(BOTON3_Pin);
            boton_Flag = 3;
        }
        /* USER CODE END EXTI15_10_IRQn 0 */
        //HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_10);
        //HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_11);
        //HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12);
        /* USER CODE BEGIN EXTI15_10_IRQn 1 */
    
        /* USER CODE END EXTI15_10_IRQn 1 */
    }
    
  • In the header file stm32f4xx_it.h it is declared my global variable this way:

     extern volatile uint8_t boton_Flag;
    
  • BOTON_1, BOTON_2, BOTON_3 are the names assigned to the pins, which are configured as interrupts by raising trigger edge detection.

  • While debugging, the three interrupts work perfectly when pressing the buttons, each one at its right time.

  • The variable boton_Flag is defined in main.c this way:

    volatile uint8_t boton_Flag = 0;
    
  • Inside the main function I pass my global variable boton_Flag to a function which is declared in controlpanel.h (I have #include "controlpanel.h" at the beginning of the file):

    int main(void) {
    
        /* USER CODE BEGIN 1 */
    
        /* USER CODE END 1 */
    
        /* MCU Configuration----------------------------------------------------------*/
    
        /* Reset of all peripherals, Initializes the Flash interface and the Systick.*/
        HAL_Init();
    
        /* Configure the system clock */
        SystemClock_Config();
    
        /* Initialize all configured peripherals */
        MX_GPIO_Init();
        MX_TIM3_Init();
        MX_TIM4_Init();
    
        /* Initialize interrupts */
        MX_NVIC_Init();
    
        /* USER CODE BEGIN 2 */
        init_PanelConfig();
    
        numeroJugadores(boton_Flag);
    
        /* USER CODE END 2 */
    
        /* Infinite loop */
        /* USER CODE BEGIN WHILE */
        while (1) {
            /* USER CODE END WHILE */
    
            /* USER CODE BEGIN 3 */
    
        }
        /* USER CODE END 3 */
    }
    
  • The function numeroJugadores(boton_Flag); does the following:

    uint8_t numeroJugadores(uint8_t boton_Flag) {
        uint8_t players = 4;
    
        while (boton_Flag != 2);
        boton_Flag = 0;
    
        while (boton_Flag != 2) {
            if (boton_Flag == 1)
                boton_Flag = 0;
            {
                players++;
                if ((players > 4) || (players < 1) ) {
                     players = 0;
                }
            }
            while (boton_Flag != 1);
    
            switch(players) {
              case 1:
                lcd_clear();
                lcd_goto(0, 0);
                lcd_on();
                lcd_puts("Numero de");
                lcd_goto(0, 1);
                lcd_puts("jugadores: 1");
                break;
              case 2:
                lcd_clear();
                lcd_goto(0, 0);
                lcd_on();
                lcd_puts("Numero de");
                lcd_goto(0, 1);
                lcd_puts("jugadores: 2");
                break;
              case 3:
                lcd_clear();
                lcd_goto(0, 0);
                lcd_on();
                lcd_puts("Numero de");
                lcd_goto(0, 1);
                lcd_puts("jugadores: 3");
                break;
              case 4:
                lcd_clear();
                lcd_goto(0, 0);
                lcd_on();
                lcd_puts("Numero de");
                lcd_goto(0, 1);
                lcd_puts("jugadores: 4");
                break;
            }
        }
        return players;
    }
    

So, what is my problem? When debugging, I realise that the program remains stuck in the first statement while (boton_Flag != 2); inside the function above.

It should stay there until I press the BOTON2 to change the flag to value 2 and this way the program keep running. However, when I press the button, in spite of the program JUMPS TO THE INTERRUPT AND CHANGES THE VALUE, when it returns to the function, the value is again 0 (its initialized value).

My conclusion, which may be wrong, is that I am not passing the variable to the function correctly, and the program interpret it as a local variable inside the function, but I am not sure at all.

I hope to have been explained as well as possible, if not, please let me know.

too honest for this site
  • 12,050
  • 4
  • 30
  • 52

1 Answers1

2

You're right, you aren't passing the variable correctly. The way you have it, when the function is called you create a local variable (local to the function) and assign it the value of your global boton_flag.

There are two ways that you could fix this:
1. Just use the global variable in the function. If it's already global there is no need to pass it to your function.
2. Pass boton_flag by reference. i.e. numeroJugadores(&boton_Flag);. If you do it this way, you'll have a pointer to boton_flag which slightly changes the code in numeroJugadores (you have to dereference boton_flag every time you use it).

Riley
  • 698
  • 6
  • 11
  • You are right! It was quite obvious. My head is burnt at this time. – Sergio Castillo Aug 18 '16 at 15:52
  • @SergioCastillo Still, you should avoid using that global variable all over the place, that's just spaghetti coding and will cause bugs. Just read it into a temporary local variable and have a simple state machine act on that value. – Lundin Aug 19 '16 at 06:15
  • 1
    @Lundin It has to be a global because it's being used in an interrupt handler. In my opinion it's messier to have extra local variables that aren't needed. The variable name should start with `G_` or something to make it clear that it's global. – Riley Aug 19 '16 at 12:31
  • @Riley Yes it has to be a global but it only needs to be shared with the main program at one place - ideally you declare it `static` and just copy it at one place, then do all the work on local variables. This is not only to avoid spaghetti code, but also to avoid problems with compiler optimizations and re-entrancy. All reads/writes to the variable has to be atomic, for example. The variable might have to be acompanied by semaphores, in which case you don't want to spam it all over the place. It is problematic in general to work with a variable which may change at any time. – Lundin Aug 19 '16 at 12:43
  • @Lundin `static` is a good idea. Everywhere that it's being used he's expecting something outside the function to to change its value. Also, I would argue that in this specific code reads/writes do not have to be atomic. – Riley Aug 19 '16 at 13:12