Electronic – Use of global variables in Embedded Systems

cembeddedfirmware

I started writing firmware for my product and I'm a rookie here. I went through many articles about not using global variables or functions. Is there any limit for using global variables in an 8 bit system or is it a complete 'No-No'. How should I use global variables in my system or should I completely avoid them?

I would like to take valuable advice from you guys on this topic to make my firmware more compact.

Best Answer

You can use global variables successfully, as long as you keep in mind @Phil's guidelines. However, here are some nice ways to avoid their issues without making the compiled code less compact.

  1. Use local static variables for persistent state that you only want to access inside one function.

    #include <stdint.h>
    void skipper()
    {
        static uint8_t skip_initial_cycles = 5;
        if (skip_initial_cycles > 0) {
            skip_initial_cycles -= 1;
            return;
        }
        /* ... */
    }
    
  2. Use a struct to keep related variables together, to make it clearer where they should be used and where not.

    struct machine_state {
         uint8_t level;
         uint8_t error_code;
    } machine_state;
    
    struct led_state {
        uint8_t red;
        uint8_t green;
        uint8_t blue;
    } led_state;
    
    void machine_change_state()
    {
        machine_state.level += 1;
        /* ... */
        /* We can easily remember not to use led_state in this function. */
    }
    
    void machine_set_io()
    {
        switch (machine_state.level) {
        case 1:
            PIN_MACHINE_IO_A = 1;
            /* ... */
        }
    }
    
  3. Use global static variables to make the variables visible only within the current C file. This prevents accidental access by code in other files due to naming conflicts.

    /* time_machine.c */
    static uint8_t current_time;
    /* ... */
    
    /* delay.c */
    static uint8_t current_time; /* A completely separate variable for this C file only. */
    /* ... */
    

As a final note, if you are modifying a global variable within an interrupt routine and reading it elsewhere:

  • Mark the variable volatile.
  • Make sure it is atomic for the CPU (i.e. 8-bit for an 8-bit CPU).

OR

  • Use a locking mechanism to protect access to the variable.