Project

BLE using nRF51: ARM-GCC Build Environment

September 14, 2015 by Travis Fagerness

How to set up the build environment for the nRF51 system-on-chip using makefiles and ARM-GCC.

How to set up the build environment for the nRF51 system-on-chip using makefiles and ARM-GCC.

Overview

This is part of a series of articles on the nRF51. The nRF51 is a system-on-chip with a Cortex M0 and a BLE radio chip all in one. This article demonstrates how to setup an open source build environment and create a simple application that runs on the nRF51 series of microcontrollers. Future articles will cover creating a custom BLE peripheral, using FreeRTOS, and controlling other devices.

The software that runs on the nRF51 consists of a softdevice and the user application. The softdevice is a binary from Nordic that provides the BLE capabilities. The user application calls functions from the softdevice in order to access BLE functions and other capabilities.  All of the tools used in this article are available for Windows, Linux, or Mac. Windows 10 was used during the making of this article. Here is a list of all the software tools that are needed to build software for the nRF51.

Hardware

  • This article and other projects are using the nRF51 Dongle by Nordic. This dongle includes a J-link connection for programming and debugging. It is known as the PCA10031 in the Nordic example code. Any hardware platform based on the nRF51 could be used, but modifications would likely need to be done for programming.
  • GCC ARM
  • Segger JLINK
  • GnuWin32 Make
  • GnuWin32 CoreUtils
    • If you are on Linux this isn't necessary
    • v5.3.0
  • Nordic SDK

Installing Software

GCC ARM

Download the installer for your respective operating system. Follow the on-screen instructions. Check the box that says "Add to system path". Keep a note of where the installion is located, as it will be used later when writing the makefile.

Segger J-link

Download the installer and follow the on-screen instructions. Check the boxes to install the USB drivers. Make a note of the install directory and add it to your system path. This can be done in windows by going to Control Panel -> System -> Advanced System Settings -> Environment Variables -> Select Path in System Variables -> Edit -> Add the path from the installation.

Installation

  

Adding J-link to the system path

GnuWin32 Make and Coreutils

Install make by following the on-screen instructions. Add the install folder to the system path, in my case it is "C:\Program Files (x86)\GnuWin32\bin". This way we can access "make" and other tools from the command line.

Nordic SDK

Download the zip file from the Nordic Developer website. Extract the SDK to a location of you choice. Remember the location, because it will be used later when writing the makefile. I placed mine in C:\nrf51_sdk. Keep the folder structure the same, that way you can easily update the SDK at a later time without affecting your projects.

Basic Project Setup

The Nordic SDK actually has quite a few examples located in the examples folder. Some of them have support for makefiles, but a lot don't. The SDK also has a lot of libraries that make accessing the peripherals much easier.

Blink an LED

To blink an LED, you only need to create three files. For this project, the SDK won't be relied on except to define the microcontroller registers. Create a new folder for your project and create the files "main.c", "gcc_blank_nrf51.ld", and "makefile" in the directory. Alternatively download the zip file and extract them to a project file.

led_example.zip

main.c

The following code sets up the blue LED pin as an output and toggles it on and off. The LED pins are defined based on the schematic for the nRF Dongle.


#include "nrf51.h"
#include "nrf51_bitfields.h"

#define LED_BLUE		23
#define LED_GREEN		22
#define LED_RED			21
#define TOGGLE_TICKS	400000

int main(void)
{
    volatile uint32_t toggle_timer=TOGGLE_TICKS;
    /*configure BLUE LED as output*/
    NRF_GPIO->PIN_CNF[LED_BLUE] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
                                            | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
                                            | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
                                            | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos)
                                            | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
    /*toggle the LED*/
    while (1){
    	toggle_timer--;
    	if(toggle_timer == 0){
    		/*get the status of the LED pin and toggle it*/
    		if(((NRF_GPIO->OUT >> LED_BLUE) & 1UL) == 0){
    			NRF_GPIO->OUTSET = (1UL << LED_BLUE);
    		}
    		else{
    			NRF_GPIO->OUTCLR = (1UL << LED_BLUE);
    		}
    		toggle_timer = TOGGLE_TICKS;
    	}
    }
}

Linker script

The linker script is responsible for placing the comiled code in the correct memory regions. The following linker script places the application at memory location 0. When we use a softdevice for bluetooth applications, the linker script will have to be changed to put the application at memory location 0x18000.


/* Linker script to configure memory regions. */

SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)

MEMORY
{
  FLASH (rx) : ORIGIN = 0x0, LENGTH = 0x40000
  RAM (rwx) :  ORIGIN = 0x20000000, LENGTH = 0x8000
}

INCLUDE "gcc_nrf51_common.ld"

makefile

The makefile is responsible for define the compiler, linker and other various project settings. The Nordic SDK comes with a makefile that I've modified a bit. The following lines are setup variables for your particular system. The path for the SDK and the compiler are defined here.


PROJECT_NAME := blink_led

#path variables, customize to your system
SDK_PATH = C:/nrf51_sdk
OUTPUT_BINARY_DIRECTORY := _build
GNU_INSTALL_ROOT = C:/Program Files (x86)/GNU Tools ARM Embedded/4.9 2015q1

#setup build directories
OBJECT_DIRECTORY = _build
LISTING_DIRECTORY = $(OBJECT_DIRECTORY)
OUTPUT_BINARY_DIRECTORY = $(OBJECT_DIRECTORY)
BUILD_DIRECTORIES := $(sort $(OBJECT_DIRECTORY) $(OUTPUT_BINARY_DIRECTORY) $(LISTING_DIRECTORY) )

The next lines define the source files and include paths for the project. If you want to add more source files, simple add a '\' after the last file and add a new line with the location and name of the source file. The include paths can be added the same way.


#c source files to compile, add files from your project to compile here
C_SOURCE_FILES += \
$(SDK_PATH)/components/toolchain/system_nrf51.c \
main.c

#assembly files to compile
ASM_SOURCE_FILES  += $(SDK_PATH)/components/toolchain/gcc/gcc_startup_nrf51.s

#include paths
INC_PATHS  += \
-I$(SDK_PATH)/components/toolchain/gcc \
-I$(SDK_PATH)/components/toolchain

The next lines define the flags for the compiler, assembler, and linker. Here is where you can setup optimization settings and other GCC options. The newlib nano version is being used in this makefile, which is a standard C library customized for embedded systems.


#compile flags
CFLAGS  = -DNRF51
CFLAGS += -mcpu=cortex-m0
CFLAGS += -mthumb -mabi=aapcs --std=gnu99
CFLAGS += -Wall -Werror -O3
CFLAGS += -mfloat-abi=soft
# keep every function in separate section. This will allow linker to dump unused functions
CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing
CFLAGS += -fno-builtin --short-enums

#linker flags
# keep every function in separate section. This will allow linker to dump unused functions
export OUTPUT_FILENAME
LDFLAGS += -Xlinker -Map=$(LISTING_DIRECTORY)/$(OUTPUT_FILENAME).map
LDFLAGS += -mthumb -mabi=aapcs -L $(SDK_PATH)/components/toolchain/gcc -T$(LINKER_SCRIPT)
LDFLAGS += -mcpu=cortex-m0
# let linker to dump unused sections
LDFLAGS += -Wl,--gc-sections
# use newlib in nano version
LDFLAGS += --specs=nano.specs -lc -lnosys

# Assembler flags
ASMFLAGS += -x assembler-with-cpp
ASMFLAGS += -DNRF51

Finally, the rest of the file automatically builds the necessary files to create the hex file that is used to program the device. This part of the file typically does not need to be modified.

Using Examples from the SDK

There is already an example that takes advantage of the SDK to blink the LED for the PCA10031. To use the example, go to [SDK folder]examples\peripheral\blinky\pca10031\blank\armgcc and type 'make' in the console. The way it works is that there is a driver called nrf_gpio.h that handles all the pin setup. There are also board support package files in "boards.h" that define all of the pins for various demoboards from Nordic. Finally, the driver nrf_delay.h provides many functions to do timing and busy waiting.

Using the Softdevice

The only big difference here is the linker script that gets used during the build process. To test if you can build, go to [SDK folder]examples\ble_peripheral\ble_app_hrs\pca10031\s110\armgcc and type 'make'. This project is a heart-rate sensor that you can connect to your phone and see fake heart rate data. For all of the BLE projects in future articles, we will compile with the softdevice linker script, because we'll always be using the BLE stack. If you use an application that was built using the softdevice linker script, you must have a softdevice installed on the nRF51.

Downloading Using JTAG

There is a tool from Nordic called nRFgo that has a graphical interface for downloading code. The application is for Windows only though. If you want to download software from the command line, you can use Jlink Commander or nrfjprog from Nordic. If you use Jlink, some extra steps must be taken to program the memory in the right location and setup certain registers correctly.

Program application

Use the following batch file to program the application from the command line. This batch file works by creating a JLINK script file and then executing it with the JLINK command line program. It connects to the target processor and downloads the code to the application memory location. Replace "yourprogram.bin" with the file you want to program. If you are not using a softdevice, change the text "0x18000" on line 2 to "0x0". If your device has a softdevice already programmed on it, you will have to do a full erase prior to writing an application to memory location 0x0 because the softdevice is protected.


@echo off
@echo loadbin yourpogram.bin 0x18000 > nrf51_program_app.jlink
@echo r >> nrf51_program_app.jlink
@echo g >> nrf51_program_app.jlink
@echo exit >> nrf51_program_app.jlink
jlink -device nRF51422_xxAC -speed 4000 -commanderscript nrf51_program_app.jlink

Program Softdevice

Programming the softdevice is more involved than the application because of some bootloader and protection registers. The softdevice hex file must be converted to binary files using objcopy. The softdevice is located at [SDK]\components\softdevice\s110\hex\s110_softdevice.hex. Perform the following to convert the hex file to two separate binary files:

  1. Execute the following command from the command prompt in the folder where the softdevice hex file resides. This assumes the folder where arm-none-eabi-objcopy resides was added to the system PATH.
    arm-none-eabi-objcopy -Iihex -Obinary s110_softdevice.hex s110_softdevice.bin
  2. Execute the following batch file. You must either run it from the same folder that the files above reside, or modify the script to point to the absolute location of the files.

@echo off
@echo w4 4001e504 2 > eraseall.jlink
@echo w4 4001e50c 1 >> eraseall.jlink
@echo w4 4001e514 1 >> eraseall.jlink
@echo sleep 100 >> eraseall.jlink
@echo r >> eraseall.jlink
@echo exit >> eraseall.jlink
jlink -device nRF51422_xxAC -speed 4000 -commanderscript eraseall.jlink

@echo w4 4001e504 1 > nrf51_program_sd.jlink
@echo loadbin s110_softdevice.bin 0 >> nrf51_program_sd.jlink
@echo r >> nrf51_program_sd.jlink
@echo g >> nrf51_program_sd.jlink
@echo exit >> nrf51_program_sd.jlink
jlink -device nRF51422_xxAC -speed 4000 -commanderscript nrf51_program_sd.jlink

Next Article in Series: BLE using nRF51: Creating a BLE Peripheral

Give this project a try for yourself! Get the BOM.