How a decent IDE can help highlight embedded software bugs earlier...

Originally this post was going to review another code failure case in Lisa Simone's book "If I only changed the software, why is the phone on fire?". The intrepid development team of "Hudson Technologies" are opening up, yet again, ancient code that has been working fine, up until now…

Before we start any new post we try out the situation ourselves, writing small code snippets and testing out ideas so that we can ensure we have researched all corners of the problem before typing. And naturally, it has to be executed on an embedded target. Due to their ease of use, we have a pile of Arduino boards on the desk as they are ideally suited to trying out code especially where peripheral interfaces also need to be used. Our preference is the Arduino M0 Pro or Genuino Zero/Arduino Zero because of the ARM Cortex M0+ based SAMD21 MCU from Atmel and integrated CMSIS-DAP debug interface that plays nicely with winIDEA Community Edition, our free development IDE. In reviewing this particular example, we realised the value a decent embedded development tool delivers…

In Chapter 4 of Lisa Simone's book, Josie and Li Mei are confronted by a PWM controlled oven that pre-warms an enclosure component prior to assembly. The oven is controlled by a microcontroller based system that monitors the temperature and controls the heating element. Unfortunately, instead of heating enclosures to 126°F/52°C as it is configured for, it has been going crazy and has tried to toast them instead. What makes debugging this issue more challenging is that it is a rare transient condition; some days all is OK, other days everything going into the oven gets burnt to a crisp. After some analysis of the machine in operation, they sit down to review the code:

unsigned char ovenPW = 0;
unsigned char actual_temp;
unsigned char reference_temp;

#define GAIN               2.7
#define NOMINAL_TEMP_PW    17

void calculate_new_oven_ON_time()
    signed char delta_temp;

    delta_temp = actual_temp - reference_temp;

    /* Calculate new PWM value from temperature delta */
    ovenPW = NOMINAL_TEMP_PW + GAIN * delta_temp;

    /* Check result is in bounds (i.e. < 100%) */
    if (ovenPW > 100)
        ovenPW = 100;

    if (ovenPW < 0)
        ovenPW = 0;

The variables actual_temp and reference_temp are regularly updated by reading two ADC inputs after which this function is called to calculate the new PWM value required to control the heating element. Obviously there are some serious flaws here, such as no PID control and the use of global variables, but the learning value is in the analysis of the problem, not reviewing methodological failure. But the actual problem has to do with the fact that ovenPW is an unsigned char variable and thus cannot handle a calculated result of less than zero...

We entered this code snippet into the Arduino IDE, built the code with no failures and could run it on our M0 Pro board with no problem. This is the Arduino development environment after the build:

PWM calculation code in Arduino IDE

By using this simple development environment, we have no hint at all of the sort of issues that are hidden behind the error we have made. The code compiled, we can download it, test it and, like Josie and Li Mei, will get burnt (excuse the pun) sometime in the future if we don't test for temperatures that cause an underflow in the unsigned ovenPW variable.

Next, we did the same exercise with the winIDEA Community Edition IDE. This is the result you see once you have compiled and downloaded your code:

Same PWM calculation code in winIDEA Open

The key thing we see here with a full development environment is that our code, once downloaded, is highlighted in the glyph margin (where the line numbering is displayed) with boxes. Each box indicates a point in the source code where we can set a breakpoint. And noticeably there are no boxes shown against the if statement for if (ovenPW < 0).

Firstly, the compiler has already figured out that this code is irrelevant in this program, that it cannot be reached (because an unsigned char cannot be less than zero), and thus has not generated any assembler code for this code block. The winIDEA Open IDE has taken that information from the ELF file that the tool chain created and has annotated the source code appropriately in the editor window. Had the original programmer been using such a development environment at the time, this particular error could have been detected during the development process without even needing to test the code on the target hardware.

Arduino is one of the first embedded development platforms many future engineers will lay their hands on in the coming years. With the winIDEA Community Edition IDE and the Cortex-M based Arduinos, they have a chance to really get to understand how professional development tools work and are used to develop quality embedded software.

So, until next time, Happy BugHunting!