Those of you who are following this blog might already know that Jumper is developing an emulator for IoT and embedded systems. This post tells the story of how using our emulator, we revealed a bug in Nordic’s official nRF5 SDK v13.0.0 .

BACKGROUND

We were implementing the PPI, an nRF52 peripheral that connects an event from one peripheral to a task on another. For example, you can use the PPI to connect a rising-edge event from the GPIO to a START task on the timer. In this case, as soon as the GPIO pin level is rising, the timer will start counting. This process will happen in HW without any interrupts or polling by the CPU.

We implemented the PPI and tried to test it with the PPI example from Nordic’s SDK.

THE PPI EXAMPLE

This is how this example works:

TIMER0 is used in counter mode, meaning it can only be manually incremented . It will only increment while it is started and not while it is stopped.

is used in counter mode, meaning it can only be . It will only increment while it is started and not while it is stopped. TIMER1 is used to generate an event every even number of seconds.

is used to generate an event every number of seconds. TIMER2 is used to generate an event every odd number of seconds.

is used to generate an event every number of seconds. The PPI is used to connect the events from TIMER1 to a STOP TASK on TIMER0 and the events from TIMER2 to a START TASK on TIMER0.

The PPI connects events from TIMER1/2 to TASKS on TIMER0

While the peripherals are doing their thing, the main loop is trying to increment TIMER0 and prints its value:

Since TIMER0 is stopped for one second at a time, the output should and does look like this:

Output running on the nRF52-DK

TRYING IT OUT ON THE EMULATOR

While everything was working well on HW, something went wrong when we tried to run it on the emulator (Jumper Virtual Lab):

Output running in the emulator

As you can see, the timer keeps incrementing even when it shouldn’t.

WHAT WENT WRONG?

Well, we found it right away. You see, the emulator has a log file which reports all events/tasks, interrupts, etc. Checking out this log file quickly revealed the issue:

Emulator log

The log makes it easy to see that TIMER2 creates an event every second instead of creating one every odd second. This causes the PPI to create a STOP event and a START event right after, virtually doing nothing at all.

On HW, the START event was generated right before the STOP event, causing it to appear as the START event never happened.

ROOT CAUSE AND BUG FIX

Checking out the initialization of TIMER2, we immediately saw the issue:

The timer is configured to create an event when its counter gets to 0x7FFF (1 second) and overflow when it passes 0xFFFF (2 seconds) so it should generate an event every odd second. The problem was created by the short created between the compare event and the clear task. As soon as a compare event occurs (when the counter reaches 0x7FFF=1sec), a clear task is initiated and resets the counter. We changed the short mask to zero and voilà, TIMER2 created an event every odd second and everything worked as required.

FINAL THOUGHTS AND CONCLUSIONS

Embedded programming is all about telling HW what to do, you tell your Minions (peripherals) what to do and how to interact with each other. Once they’re on their way, you have very little visibility to what they do and whether or not they are doing it right. Peripheral’s events, tasks and internal state are not accessible by a debugger. Debugging and testing an embedded program with an emulator provides an engineer with a view of the peripherals’ internal states.

As I mentioned before, the program was working well on the actual HW before the fix, but keep in mind that this is exactly the problem. One could have used this code example to use the events from TIMER2 for another purpose, maybe connecting it to an ADC sample task or even a radio task, causing a much more significant affect.