mbed Blog

Changes to our GitHub development repository

Over the next week, we're going to be making some organisational changes to our main development repository that is used to generate our mbed 2 ("Classic") Core Library releases.

Will it impact you?

/media/uploads/simon/mbed-github-modifications.png

For most of you who are using the standard mbed 2 ("Classic") Core Library releases, whether from within the mbed Online Compiler or some other command line or IDE environment, you shouldn't see any changes that impact you. If you do experience problems, please shout as that is almost certainly a bug not a feature!

For those who are using the mbed Github repository directly (e.g. partners and developers who work with us on the core itself), these changes will mean at minimum you'll have to review the new layout. In some cases, especially if you have built scripts or dependencies relying on this layout, you may have to make adjustments and updates based on these changes. We'd suggest during this period to simply stick to an existing revision for the next couple of weeks, and analyse and update based on any implications after that.

Why are we making these changes?

These changes only impact a small number of you, but they are in preparation for some much more important changes that should provide a lot of benefit to you all.

We've been undertaking some significant changes and enhancements to our mbed OS 3 architecture, designed to accelerate important aspects of our roadmap and open up some interesting new opportunities. In particular, we have been incorporating an RTOS in to the core of mbed OS that was previously eventing-only, so applications can benefit from native thread support within the OS. This is to both simplify integration of complex application components, and expand the applicability of the OS. But what this also means, combined with some re-basing and tool changes we're making, is that we've unlocked the opportunity for compatibility with our mbed 2 ("Classic") ecosystem!

Hopefully gives you enough of a hint that there are some very interesting developments afoot. I'll be sharing more over the next weeks!

What if I have issues?

If you see any problems or have questions as we make these changes, feel free to comment or ask here, or email us at support@mbed.org.

Build an ARM mbed BLE beacon with Nordic nRF51-DK and Evothings Studio

Evothings has published the tutorial, Nordic Semiconductor nRF51-DK into a Beacon with mbed, on hackster.io. This exercise takes you through the steps to develop your own ARM mbed Bluetooth Low Energy (BLE) beacon with Nordic nRF51-DK hardware, and Evothings Studio, to create a mobile phone app that connects to your beacon hardware.

/media/uploads/davewuzhere/nordic_mbed_ide.png

According to IndustryARC Analysis, "Bluetooth Low Energy (BLE) enabled device shipments are forecasted to increase to 8.4 billion units by 2020 at a CAGR of 29%." BLE technology is ideal for resource constrained devices that can run on coin-cell batteries for months or years on end. These tiny devices of the Internet of Things are positioned well to capitalize on the benefits of this efficient wireless technology. BLE beacons are popular within segments such as wearables, smart buildings, and smart retail.

Tutorial Hardware and Software Checklist:

  • FREE mbed.org account
  • Computer (Windows, Mac OSX, Linux)
  • Nordic Semiconductor nRF51-DK
  • Evothings Studio installed on your computer
  • Mobile phone or device running Evothings Client
  • MicroUSB communications cable

When you are ready to get started, check out the full instruction article here on hackster.io

Also, we used this same technology in our demo at the Design Automation Conference (DAC) 2016, check out this blog to find out how to replicate our interactive BLE beacon demo.

ARM mbed at DAC 2016 - Interactive BLE Messaging

This past week the ARM mbed team went to the Design Automation Conference (DAC) in Austin, TX. We put together an awesome demo that showed off how to use Bluetooth Low Energy (BLE) to create an interactive beacon demo. Attendees of DAC started at our booth, they received a beacon programmed to display their name and as they walked around the show floor various signage would greet them by name when they walked within 5-10 feet of the screen display.



The demo showed off 3 key technologies:

  1. mbed Remote Compile API - We created a webpage running on a tablet that could remotely compile a new binary with the attendee's name inserted into it.
  2. Wireless Firmware Update via the BLE Firmware Over the Air (FOTA) service - Using the Nordic Master Control Panel smartphone app.
  3. Scanning of BLE signals using NodeJS and noble.

The coolest part of this demo is that it is entirely open source and repeatable at home! If you are interested in checking out the demo source code it can be found at www.mbed.com/s/DAC16. If you are interested in expanding further on the demo you can try to create your own smartphone application using Evothings.

Here are some photos from the event.

A new Bluetooth library: SimpleBLE

TL;DR? Here's the link to the SimpleBLE library.

Four months ago I joined the mbed team as Developer Evangelist. A big part of my job is running around at events and talking to developers. Not only does that make for very entertaining conversations, it also gives some first hand insight into how developers are using mbed. This is especially true for new users, especially if they've never done embedded development before. There's no better way of testing the user-friendliness of your platform than by giving a workshop to novice users.

Last week's event was RISE Manchester, where we held an IoT workshop around Bluetooth Low Energy. The mbed Bluetooth library is one of the most popular libraries on mbed (and the reason I started using mbed!). But we saw that people were struggling with concepts like services, characteristics and advertisement frames - all things that you need to think about, even when you just want to broadcast a sensor value to your phone.

/media/uploads/janjongboom/chnsselwkai9kmm.jpg-large-3.jpeg

Photo by Michelle Hua

A simplified library

This got Jonny Austin and me thinking about a 'workshop-friendly' version of the Bluetooth API, with the following premises:

  • Users should not care about bootstrapping the BLE API.
  • Declaring a new service or characteristic should be done in a single line of code.
  • Characteristics should act like normal variables, magically syncing their state over BLE.

The result of that work is now published as the SimpleBLE library. Here's an example program that exposes a light sensor (on pin A0) over BLE, and lets it update every second:

#include "mbed.h"
#include "SimpleBLE.h"

AnalogIn light(A0);

SimpleBLE ble("MY_LIGHT_SENSOR"); // declare SimpleBLE

// create a new characteristic under service 0x8000, char 0x8001
SimpleChar<uint16_t> lightValue = ble.readOnly_u16(0x8000, 0x8001);

// now treat lightValue like any other variable
void read() {
    lightValue = light.read_u16();
}

int main(int, char**) {
    Ticker t;
    t.attach(&read, 1.0f); // read new value every second

    ble.start();
    while (1) { ble.waitForEvent(); }
}

SimpleBLE will now take care of declaring services, preparing advertisement frames, handling disconnects, and updating the value of the characteristic whenever you write to it. Easy peasy!

You can also read the variable, as it acts like any other variable. For example, this is how you count button presses:

InterruptIn btn(D0);
SimpleChar<uint8_t> presses = ble.readOnly_u8(0x8500, 0x8501);

void btn_press() {
    presses = presses + 1; // read value and up with one
}

btn.fall(&btn_press);

Write callbacks

Another feature that is hard to grasp in the BLE API is how to get write callbacks, as there is only a global onDataWritten callback. We fixed this by adding the possibility to provide a callback function to the SimpleBLE variable. Whenever someone writes a new value over BLE we'll call the callback function, and let you know the new value.

For example, here's how you expose an LED over BLE using SimpleBLE:

DigitalOut led(D0);

void updateLed(bool newState) {
    led = newState;                 // could also do led = ledState here...
}

SimpleChar<bool> ledState = ble.writeOnly_bool(0x8600, 0x8601, &updateLed);

More complicated: a tri-color LED

We can easily write more complicated programs, for example exposing a tri-color LED over BLE. We create one characteristic with 4 bytes (`uint32_t`) where we use the first byte as red, the second as green and the third as blue.

PwmOut red(D0);
PwmOut green(D1);
PwmOut blue(D2);

void update(uint32_t newColor) {
    // read individual bytes
    uint8_t* channels = (uint8_t*)&newColor;

    // cast to float, as PwmOut expects a value between 0.0f and 1.0f
    red   = static_cast<float>(channels[0]) / 255.0f;
    green = static_cast<float>(channels[1]) / 255.0f;
    blue  = static_cast<float>(channels[2]) / 255.0f;
}

SimpleChar<uint32_t> color = ble.writeOnly_u32(0x6200, 0x6201, &update);

API

We currently have three types implemented, which are accessible under an instantiated `SimpleBLE` object:

  • readOnly - Only readable over BLE.
  • readWrite - Readable and writable over BLE.
  • writeOnly - Only writable over BLE.

All types are generic, and a type is selected via a postfix. For example call ble.readWrite_bool(...) to create a boolean variable, or ble.readWrite_u32(...) to create a variable with type `uint32_t`.

Note: The access classifier only applies to BLE. Your program can always read from and write to the variable.

The following arguments can be passed to create a type:

  • serviceUuid - Short (`uint16_t`) or long (`const char*`) UUID.
  • charUuid - See serviceUuid.
  • notify - Whether to allow notifications on the characteristic (default: true).
  • defaultValue - Default value of the characteristic.
  • callback - Function pointer to be called whenever a new value is written over BLE. Only available for readWrite and writeOnly.

We will probably expand this API to enable exposing pins directly over BLE, but we're happy to see what you can build with this today.

Recap

SimpleBLE is a brand-new library, but is built on top of the very well tested normal Bluetooth library. We hope that it significantly decreases the barrier for people to start programming BLE devices, especially in a time-constrained environment like a hackathon or workshop.

You can find the library here, and an example program here. If you want more information on the internals of the library, look at the mbed BLE docs. If you have feedback, please let me know!

-

Jan Jongboom is Developer Evangelist IoT at ARM.

Post-mortem debugging with ARM mbed

When it comes to programming microcontrollers, the one scenario that you never want to face is a device that suddenly hangs. It's already very frustrating while you're developing software, and tracing down these bugs can be very time-consuming; it's even worse when the device is already deployed in the field. Replicating the exact conditions in which the device failed can be almost impossible in the lab, especially when the failure manifested itself months after deployment.

Fortunately, mbed-enabled hardware ships with CMSIS-DAP or its successor DAPLink, which allow you to directly hook into devices using the built-in USB ports (on developer boards), or a debugging probe like SWDAP. CMSIS-DAP is responsible for mounting your mbed board as a mass-storage device for easy flashing, but it can also be used to dump the RAM and ROM of a running device, enabling you to do post-mortem debugging on a hanging device.

In this blog post we'll show you how to install all dependencies, crash a device, and subsequently do a post-mortem debug session. To follow along you'll need:

  1. A development board capable of running mbed.
  2. An account at developer.mbed.org - to write faulty firmware.
  3. ARM KEIL uVision 5 - to load the debug session. On OS X, run uVision in VMWare Fusion; it won't install in VirtualBox.

Note: Unfortunately, you may not be able to run the debug session in an unlicensed version of uVision 5. This depends on the size of your RAM, because of the debugger's 32 Kbyte program limit.

  1. Download dump_firmware_classic.py - a Python script that dumps the RAM and ROM off a device, and sets up a uVision 5 project.

This article assumes knowledge of building applications with the mbed online compiler. If you're unfamiliar with mbed, read Getting started with mbed first.

Creating a program that crashes

Here's an application that reads from a pointer at address 0xfffffff when the button at SW2 is pressed. 0xfffffff is an invalid address, and reading from here is not allowed, so the core hard-faults:

#include "mbed.h"

// change this to reflect a button on your own board
static InterruptIn btn(SW2);
static DigitalOut led(LED1);

static void blink() {
    led = !led;
}

static void btn_interrupt() {
    // this will crash your device!
    char* c = ((char*)0xfffffff);
    printf("I read... %c\n", c[0]);
}


int main() {
    btn.fall(&btn_interrupt);
    
    Ticker t;
    t.attach(blink, 0.5f);
    
    while(1) {}
}

Save the program and verify that it compiles.

Exporting to an offline toolchain

When you build an application with the online compiler you only get access to the firmware. If you want to do a post-mortem debug session you also need the debug symbols for this build. To obtain those you can export the program to an offline toolchain, and build locally.

Right click on your program in the online compiler, and select Export.

/media/uploads/janjongboom/postmortem1.png

Choose GCC (ARM Embedded) as the toolchain and click Export.

/media/uploads/janjongboom/postmortem2.png

A ZIP file with the source code of the application, all libraries and a Makefile is downloaded. Extract the ZIP file to a new directory on your computer.

Building locally

Open a terminal and navigate to the directory to which you extracted the ZIP file. We can now build the program locally and obtain the debug symbols.

$ make
# on some targets (like nrf51-dk), also call $ make merge

When the build finishes, your build directory will have either a *.bin or *-comibned.hex file, depending on your board. Use drag-and-drop to copy the file onto your board to flash the program.

The program starts running and blinks the LED (press the Reset button if the LED does not start blinking). Now press the SW2 button to crash the board.

Starting a post-mortem debug session

Now we can put the dump_firmware_classic.py Python script to good use. Run the script with the crashed device plugged in:

$ pip install intelhex pyOCD
$ python dump_firmware_classic.py
[1/6] Using build directory '.', verifying build...
[2/6] Build verified. Connecting to board...
[3/6] Board recognized as k64f. Downloading ROM...
[4/6] Dumped ROM. Downloading RAM...
[5/6] Dumped RAM. Creating uVision project...
[6/6] Done. Open 'crashdump/crashing-k64f.elf.uvprojx' in uVision 5 to debug.

A crashdump folder is created. It contains debug symbols, the RAM and ROM of the device, and a uVision 5 project file.

Double click on the project file to open uVision.

Loading the session in uVision 5

In uVision, choose Debug > Start/Stop Debug Session to start.

/media/uploads/janjongboom/postmortem3.png

In the Disassembly panel we see that we're in the HardFault_Handler, which is expected. We can drill down into the stack by selecting Debug > Step.

/media/uploads/janjongboom/postmortem4.png

Now we get more information about the state of the application. On the right bottom corner we see the Call Stack that led up to the crash. We can see that we passed an interrupt (handle_interrupt_in) and that we went through one of our own functions (btn_interrupt) right before the device hard faulted.

/media/uploads/janjongboom/postmortem5.png

Now that we found the function we can also find the actual line that our application crashed on. In the Call Stack panel, right click on btn_interrupt and select Show Callee Code.

/media/uploads/janjongboom/postmortem6.png

We now jump into the disassembled source. On the left panel we see the registers, and in the Disassembly panel we see the assembly that led up to the crash:

/media/uploads/janjongboom/postmortem7.png

When we read the assembly we see:

MVN           r3,#0xF0000000              // Move not
LDR           r0,[pc,#4]  ; @0x000004EC   // Load word from memory
LDRB          r1,[r3,#0x00]               // Load word from memory (type: unsigned byte)

On the last line before the crash we tried to read from registry R3 (0x0FFFFFFF) into registry R1. We also see that right after that, we called the printf function. This maps perfectly to our C++ code, and we found the line which crashed the device.

char* c = ((char*)0xfffffff);
printf("I read... %c\n", c[0]);

Never-ending loops

This approach can be used for more than just debugging hard faults. We can also use it when a device hangs because it entered a never-terminating loop. Let's look at the following code:

#include "mbed.h"

static DigitalOut led(LED1);
static void my_loop_function(void) {
    uint8_t turns = 20;

    while(turns-- > -1) {
        led = !led;
        wait_ms(200);
    }
}

int main() {
    my_loop_function();
    return 0;
}

Here turns will always be greater than -1 (because turns is a uint8_t), so the device will never exit the loop. When we start a post-mortem debug session, we can immediately see the function that we are currently stuck in:

/media/uploads/janjongboom/postmortem8.png

And if we're lucky, we can even see the values on the Call Stack, showing that turns overflowed and is now 0xED.

Conclusion

CMSIS-DAP on ARM mbed can be a tremendous help with hard to find issues. The ability to recover a crashed device from the field, and use post-mortem debugging on it, is a great addition to the toolchain of every developer. If you want to learn more, there is a KEIL application note on Using Cortex-M3 and Cortex-M4 Fault Exceptions.

To replicate the tests we used in this article, take a look at post-mortem-debugging on GitHub. You'll find the Python script and all source code used in this article. Happy disassembling!

-

This article was written by Russ Butler (Embedded Software Engineer working on DAPLink and pyOCD) and Jan Jongboom (Developer Evangelist IoT).