What debugging methods are used to make embedded software safer?

We probably never take the time to think about it when we drive in our cars, but between our hands sits a small explosive device in the middle of the steering wheel. I am of course referring to the airbag, a device that is now as ubiquitous a safety feature as the seat belt. Of all the electronic systems to be found in the car, it is probably the only one that I never want to experience firsthand. Released under a small collection of suitable conditions, the airbag could save your life; otherwise its inflation could cause serious injury or even death. With this in mind, I personally would want to be sure that the engineers developing the software for such a device had the very best debugging methods available to almost guarantee zero failures…

A microcontroller sits at the heart of an airbag deployment system and monitors a variety of sensors before making the decision to deploy the bag. The decision itself will need to be made in around 15 to 30 milliseconds in order to ensure that there is enough time to inflate the bag, otherwise the passengers would not benefit from the protection it could provide. Here we review three debugging methods are used to ensure that the software really does do that which it should during the software development process.

Trace - code tracing is an approach used to extract the instructions a microcontroller executes. Typically a debug tool will extract this information via a dedicated interface on the microcontroller and present it in a graphical user interface for later analysis. In some cases, the data can be also traced, thereby providing a better picture of what caused the microcontroller to make the decisions it made as it executed its program.

How trace data is displayed in a development environment - executed assembly instructions, interspersed with source code, and timestamps.

With processors today executing millions of instructions every second, this raw data is very difficult to process in isolation. However, once the data has been collected, it can be used for several other purposes.

Profiling - code profiling has two key usage cases; when viewed against a timeline it is possible to see in what order our program code was executed; when viewed as a histogram, we see what percentage of processor time each program function consumed.

The order in which our functions were called can displayed against a time axis in the profile.

In this viewing mode an embedded developer can look to see if the order in which individual functions were called fits with their expectations. Automotive applications tend to make use of a real-time operating system (RTOS) compliant to the AUTOSAR standard, where code analysis mostly operates at the level of the RTOS tasks being executed on the system. Here the profiler can also be used to ensure that the tasks are being woken in the order and manner expected as per the original design requirements.

Another capability of the timebase view is to see if a critical element of the application code, in our example, the function that will cause the airbag to deploy, can be called within the time limit required, for example <30ms. Perhaps the chain of function calls and algorithms being processed is simply taking too long on some occasions.

The profiler statistics view here provides us with how much time was spent in each function and how many times the function was called.

The histogram viewing mode of profiling data makes obvious if an individual function call, RTOS task or interrupt routine is consuming an excessive number of clock cycles. If, for example, we had determined that under certain conditions the our airbag does not deploy in time, this viewing mode would help to find the code elements that take too long to execute.

Code Coverage - Another use for trace data is code coverage. This means analysing whether all elements of our application have been executed or not, how many times, and even whether all decision branches within that code have been exercised. Such information is typically shown in histogram form.

The code coverage window shows how much of our application has been exercised.

Typically you want to aim to achieve 100% code coverage by exercising the final product across all of its possible modes of operation and monitoring if all execution branches were touched in that time. If the device you are building is dependent on remote sensors connected to networked bus systems, such as CAN based remote modules in a vehicle, this whole process is a lot of work and requires excellent planning.

Trace, profiling and code coverage are used daily by embedded developers designing products that need to fulfil functional safety standards, such as ISO26262. And it is such debugging methods that help to ensure that high quality standards are achieved and strict safety requirements are fulfilled.

That's all from us for now - Happy BugHunting!