Getting started with nRF51 development on Mac OS X

Update: Since this blog was originally written the nrfjprog tool has been ported to OS X (now macOS). This means that the flash programming is much simpler, and it is simply a matter of following the documentation for the tool. Also, nRF Toolbox for iOS is deprecated; use the nRF Connect iOS app instead


I recently decided to try the nRF51 SDK on Mac OS X to see how it was to compile and program the example applications. It worked nicely, and it wasn't even that hard to figure out. But evidently there were things to find out, and before things were actually working there was always the fear of discovering that some of the setup was wrong and you have wasted hours on a stupid mistake.

The questions are many: Do I have the right tools? Where do get started in the SDK? Are there other changes needed? And from experience there are always things you don't think about before they hit you in your face. This blog is the guide I wish I had when I first started out. If by following the steps there is at least some confidence that things are working as they should, then I can go on exploring from there. I hope you find it helpful!

Setting up the tools

First of all, and at the risk of stating the obvious: Buy a development kit!

You will need this for the license to programming and debugging software. For this tutorial the nRF51822-EK (Evaluation Kit) was used.

Assuming nothing, here is the (minimum) software you need download (the version I used are in parenthesis):

  • nRF51-SDK-zip: This is the Nordic Semiconductor SDK for nRF51 (6.0.0). See the nRF51/52 SDK download page to get it. Unpack the SDK to a location of your own choice.
  • S110-SD-v7: The S110 (v7.0.0) softdevice that supports peripheral devices. Find it on the same page as above.
  • GCC ARM Embedded: Compiler tools for ARM Cortex-M. Download the latest version from Launchpad (gcc-arm-none-eabi-4_8-2014q2-20140609-mac). Unpack the tarball to /usr/local.
  • J-Link software for Mac: Get the latest version from Segger (V4.90b) and run the installer.
  • (You might need to install make. Not sure if it is installed byt default or part of XCode.)

Compiling the Bluetooth Smart example

The examples in the SDK each have a makefile (or several) in the gcc folder that works without modification. However, there is one important change that is needed for one of the template files, which is to set the correct toolchain path. This is defined in Makefile.posix: (SDK location)\nrf51822\Source\templates\gcc\Makefile.posix

GNU_INSTALL_ROOT := /usr/local/gcc-arm-none-eabi-4_8-2014q2
GNU_VERSION := 4.8.3
GNU_PREFIX := arm-none-eabi 

Make sure that GNU_INSTALL_ROOT is the correct path GCC toolchain on your computer. Also check that GNU_VERSION is the right one.

To make things interesting I'll use a Bluetooth Smart example: the Heart Rate Monitor application ((SDK location)/nrf51822/Board/pca10001/s110/ble_app_hrs). With the changes in Makefile.posix you should now be able to compile it.

~ em$ cd <SDK location>/nrf51822/Board/pca10001/s110/ble_app_hrs/gcc
gcc em$ make -f ble_app_hrs.Makefile all

This example has more than on makefile so you need to specify which one to use. The build result is found in the _build folder.

Flash Programming

For simplicity in this tutorial copy the softdevice (S110) .hex file to the _build folder of the Heart Rate Monitor example. The programming is performed from the _build folder:

_build em$ JLinkExe -device nrf51822_xxaa -if swd -speed 4000
[...]
J-Link>loadbin s110_nrf51822_7.0.0_softdevice.bin 0
J-Link>loadbin ble_app_hrs_s110_xxaa.hex 0x16000
J-Link>r
J-Link>g
J-Link>exit

Setting the correct device is crucial, and the speed setting is needed to make the programming fast enough. The softdevice is first programmed in the beginning (location 0) and the application is programmed immediately after (0x16000 for S110 v7.0). After the programming a reset is needed ('r' + 'g').

Now, try to connect the HRM to your phone: I used nRF Toolbox for iOS.

Troubleshooting tips

If you are struggling to make the app work it might be a good idea to clean the memory and reprogram. Unfortunately the only way to erase the memory is to do some magic register writes:

JLinkExe
J-Link>w4 4001e504 2
J-Link>w4 4001e50c 1

If you are wondering if things are working at all, try building and programming the blinky_example at memory location 0. Since this example doesn't require the softdevice you have removed one source of error.

Automating Tasks by Modifying the Makefiles

Working with the J-Link CLI quickly gets cumbersome, but by modifying Makefile.posix the things you need to do can be automated. Here is file I used:

GNU_INSTALL_ROOT := /usr/local/gcc-arm-none-eabi-4_8-2014q2
GNU_VERSION := 4.8.3
GNU_PREFIX := arm-none-eabi
GDB_PORT_NUMBER := 9992

FLASH_START_ADDR = $(shell $(OBJDUMP) -h         $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out -j .text | grep .text | awk '{print $$4}')

JLINK_OPTS = -device nrf51822 -if swd -speed 4000
JLINK_GDB_OPTS = -noir
JLINK = JLinkExe $(JLINK_OPTS)
JLINKD_GDB = JLinkGDBServer $(JLINK_GDB_OPTS)


flash-jlink: flash.jlink
    $(JLINK) flash.jlink
 
flash.jlink:
    printf "loadbin $(OUTPUT_BINARY_DIRECTORY)/$(OUTPUT_FILENAME).bin $(FLASH_START_ADDR)\nr\ng\nexit\n" > flash.jlink

erase-all: erase-all.jlink
    $(JLINK) erase-all.jlink

erase-all.jlink:
    # Write to NVMC to enable erase, do erase all, wait for completion. reset
    printf "w4 4001e504 2\nw4 4001e50c 1\nsleep 100\nr\nexit\n" > erase-all.jlink
 
run-debug:
    $(JLINKD_GDB) $(JLINK_OPTS) $(JLINK_GDB_OPTS) -port $(GDB_PORT_NUMBER)
 
.PHONY:  flash-jlink flash.jlink erase-all erase-all.jlink run-debug

With this modification you have makefile targets for flash programming (flash-jlink) and erasing the chip (erase-all). In addition there is a command to launch the debugger (run-debug) which we will look at next.

Tip: For more options and ideas have a look at this Github repo.

Running the Debugger

With the modified Makefile.posix it is easy to start a GDB server:

gcc em$ make -f ble_app_hrs.Makefile run-debug

This will start a GDB server in your current terminal window. Note that there is a port number in the parameter list (9992, GDB_PORT_NUMBER in Makefile.posix) which you need to connect to GDB.

In order to load debug symbols you need to compile the project in debug mode (make clean & make debug). Start the debugger with the .out file to load the symbols. In another terminal window start GDP:

gcc em$ /usr/local/gcc-arm-none-eabi-<version>/bin/arm-none-eabi-gdb _build/ble_app_hrs_s110_xxaa.out
[Loading ... check that symbols are loaded]
(gdb) target remote localhost:9992
(gdb) b main.c:621
(gdb) monitor reset
(gdb) continue 

The line number in main.c might differ, so set it to the Connected case in the on_ble_evt() callback routine. Try to connect the heart rate monitor to your phone and check that the GDB breaks the execution.

Next step - IDE integration

I kept IDE integration out of this guide, but it is a natural next step. The nAN-29 Application Note explains how to set up Eclipse with GCC. Personally I'm tempted to try something else.

  • Thanks for this guide.

    Here are some updates for compiling with the latest SDK (9.0.0):

    The location of makefile.posix has changed from:

    (SDK location)/nrf51822/Source/templates/gcc/Makefile.posix
    

    to:

    (SDK location)/components/toolchain/gcc/Makefile.posix
    

    For the compilation example, the path and filenames have changed a little:

    old:

    cd <SDK location>/nrf51822/Board/pca10001/s110/ble_app_hrs/gcc
    make -f ble_app_hrs.Makefile all
    

    new (just one makefile in the folder):

    cd <SDK location>/examples/ble_peripheral/ble_app_hrs/pca10028/s110/armgcc
    make -f Makefile all
    
  • @patrick: The site you posted to was not launched when I first wrote this blog post. I have updated the link in the post. I also removed the comment that a login is required; it no longer is :)

  • I have been going through the example. A quicker link to the SDK.

    http://developer.nordicsemi.com

    I was confused when it was not in the download section and spent a good amount of time looking through the IOT sdk.

  • I just played around with getting SDK v.8 samples to work on mac. A few notes that might save you some time:

    • There is no need to specify the flash start address when flashing samples build with SoftDevice support. The .hex file contains the correct offsets (based on the sections defined in the custom linker scripts) and LinkExe ignores the start address
    • $(OUTPUT_FILENAME) isn't defined when Makefile.posix is imported into the various example Makefiles. I added hardcoded OUTPUT_FILENAME := nrf51422_xxac to the posix makefile just to get the examples working without changing every makefile individually.

    @kerem - it looks like you copied the entire line including the shell prompt. Try dropping the gcc em$ from the command you're trying to run.

  • I am having problems with compiling the samples using gcc for arm 4.9 on os x 10.9 and nrf51 sdk 8.0. I am getting errors such as:

    clang: error: unknown argument: '-f'

    clang: error: no such file or directory: 'em$'

    clang: error: no such file or directory: 'make'

    Is there a more recent guide for simply compiling any of the examples on os x? Should I just go for the virtualbox/win7/keil setup as that's more relevant to the current documentation?

    I don't have the development board but only a nrf5188 beacon, I'm trying to build one of the examples and flash it on the beacon using nRF Master Control Panel application on Android.