Page 97 - The Art of Designing Embedded Systems
P. 97

84  THE ART OF  DESIGNING EMBEDDED SYSTEMS

                            “Safely” is important, as global variables, the old standby of the des-
                       perate programmer, are generally a Bad Idea and are deadly in any inter-
                       rupt-driven  system. We all know  how  globals promote  bugs  by  being
                       available to every function in the code; with multitasking systems they lead
                       to worse conflicts as several tasks may attempt to modify a global all at the
                       same time.
                            Instead, the operating system’s communications resources  let you
                       cleanly pass a message without fear of its corruption by other tasks. Prop-
                       erly implemented code lets you generate the real-time analogy of OOP’s
                       first tenet: encapsulation. Keep all of the task’s data local, bound to the
                       code itself, and hidden from the rest of the system.
                            For instance, one challenge faced by  many  embedded  systems is
                       managing system status info. Generally, lots and lots of different inputs,
                       from door switches to the results of operator commands, affect total status.
                       Maintain the status in a global data structure and you’ll surely find it ham-
                       mered by multiple tasks. Instead, bind the data to a task, and let other tasks
                       set and query it via requests sent through queues or mailboxes.
                            Is this slower than using a global? Sure. It uses more memory, too.
                       Just as we  make some compromises in selecting a compiler over an as-
                       sembler, proper use of an RTOS trades off a bit of raw CPU horsepower
                       for better code that’s easier to understand and maintain.
                            Most operating systems give you tools to manage resources. Surely
                       it’s a bad idea for multiple tasks to communicate with a UART or similar
                       device simultaneously. One way to control this is to lock the resource-
                       often using  a semaphore or other RTOS-supplied  mechanism-so  only
                       one task at a time can access the device.
                            Resource  locking and priority  systems lead to one of  the perils of
                       real-time systems: priority inversion. This is the deadly condition where a
                       low-priority task blocks a ready and willing high-priority task.
                            Suppose the  system  is more or less idle. A  background,  perhaps
                       unimportant, task asks for and gets exclusive access to a comm port. It’s
                       locked now, dedicated to the task until released. Suddenly an oh-my-god
                       interrupt occurs that starts off the system’s highest priority and most criti-
                       cal task. It, too, asks for exclusive comm port access, only to be denied that
                       by the OS since the resource is already in use. The high-priority task is in
                       control; the lower one can’t run, and can’t complete its activity and thus re-
                       lease the comm port. The least important activity of  all has blocked the
                       most important!
                            Most operating systems recognize the problem and provide a work-
                       around. For example in VxWorks you can use their mutual exclusion sem-
                       aphores to enable “priority inheritance.” The task that locks the resource
   92   93   94   95   96   97   98   99   100   101   102