Porting NovelBits' BLE Central Lightbulb controller to nRF51 & SDK version 12


Having got the BLE Lightbulb peripheral example working as I wanted it to on the nRF52 development kit (PCA10040), the next step was to get my other dev kit to be the controller for it, in place of the smartphone app. NovelBits helpfully provides all the code for this on the page How to build the simplest nRF52 BLE Central (Lightbulb use case) but it is targeted at the nRF52840 and SDK 15.

Limitation of my available hardware

I only had one nRF52 dev kit and one nRF51 dev kit. As I learned previously, the nRF51 is only supported by SDK version 12, so I had the job of porting the example code down from SDK version 15 and changing it over to the smaller, M0 based chip. At the same time, the Softdevice (BTLE stack) changes from s132 to s130.

Staged Approach

My plan was to proceed cautiously, having seen the problems previously in attempting to make many changes in one step and ending up with an uncompilable codebase.

  1. SDK v15 nRF52 PCA10040 S132
  2. SDK v12 nRF52 PCA10040 S132
  3. SDK v12 nRF51 PCA10028 S130

As soon as you copy the project folder into the same location in the SDK 12 folder and run my SES Include File Manager, you see that of the 133 include paths 29 are not found, so the structure of the SDK 12 folder is different from SDK 15.

SES IFM showing 29 paths missing

Using the All To Relative Paths action cleans up the list to 103 paths but does not help with the files that are in the project but have since been moved. Even if all these are located, the different APIs used between the SDKs becomes an issue. But a bigger problem is the difference in the layout, naming and size of the sdk_config.h file between the two SDKs. Here's a pictorial representation of the differences in WinMerge:
WinMerge showing summary of differences between sdk_config.h for nRF51 and nRF52
sdk_config.hSDK 12SDK 15
file size (kB)83293
Lines377212481
Number of #defines3821147

WinMerge counts 1582 differences, so there is no chance of matching up the two to bring any differences across. It becomes clear that this is not a good approach.

If you want to get there, I wouldn't start from here.

Use A Working Example

Being frustrated that I could not get my BLE Central to run on the nRF51, I wondered if it was even possible. So I explored the examples folder in the SDK 12 and found that there was a ble_central folder and the simplest example within that was ble_app_blinky_c inside the experimental folder. This looks like it could be a solution for me because it has a PC10028 folder, but before getting too excited I had to program both boards as per the instructions and test it out. I didn't find those instructions to be too clear, but with the nRF52 running the code from SDK12\examples\ble_peripheral\experimental_ble_app_blinky and the nRF51 running code from SDK12\examples\ble_central\experimental\ble_app_blinky_c\pca10028\s130 (once turned into a SES project the central did indeed automatically find the peripheral and connect to it. Then the button 1 on one board controlled LED 3 on the other board, in both directions.

So at this point, we know it is possible to run a central on nRF51 with SDK 12. Let's look at the steps needed to make this run using Segger Embedded Studio.

Getting ble_app_blinky_c to work on nRF51 with SES

In examples\ble_central\experimental\ble_app_blinky_c\pca10028\s130, copy arm5_no_packs folder and rename ses.

Proceed as per Getting Started with SES steps 4 to 6, and 13 to 15.

Open SES and Import Project - Import Keil MDK Project - examples\ble_central\experimental\ble_app_blinky_c\pca10028\s130\ses\ble_app_blinky_c_pca10028_s130.uvprojx

Use my SES Include File Manager to clean up the include files and save back to the project file.

Edit sdk_config.h to change #define NRF_LOG_BACKEND_SERIAL_USES_RTT 1 so that you will see the message on startup about RAM start and size corrections that need to be made. These are

linker_section_placement_macros="FLASH_START=0x1B000;SRAM_START=0x20001eb0;SRAM_SIZE=0x6150"

Conversion to Custom Service and Characteristic UUIDs

The difference between the blinky examples and the NovelBits example was that blinky uses Bluetooth standard UUIDs, as part of the ble_lbs_c in SDK\components\ble\ble_services\ble_lbs_c and NovelBits uses custom UUIDs. We don't want to modify standard code in the SDK components folder because this would affect all other projects which use this code, so instead make a local copy in the example folder which can then be modified.

Looking at the difference between the Nordic standard files in ble_lbs_c and NovelBits' led_service_client shows that what Afaneh has done is take the ble_lbs_c as his basis rather than writing it from scratch. Although he doesn't claim anywhere that this is entirely his code, he did replace the Nordic Licence comments at the top of led_service_client with his NovelBits MIT one in the downloaded version. However, there are several giveaways that this must be copied-and-edited code including: same function names, same order of functions, mention of LED Button Service is left in from the original where it should be changed to just LED Service.

Changes to ble_app_blinky_c to make it work as NovelBits' Lightbulb controller

Linker Section Placement FLASH_START=0x1B000;SRAM_START=0x20001eb0;SRAM_SIZE=0x6150

Add folder Clients to within folder ble_app_blinky_c with files led_service_client.c and h from the download on NovelBits' page

Modify main.c to remove #include "ble_lbc_c.h" and add #include "Clients/led_service_client.h". Also modify m_target_periph_name[] = "BLE_Lightbulb"

Modify the project c_user_include_directories to remove components\ble\ble_services\ble_lbs_c and remove the file from the nRF_BLE_Services folder, add a Clients folder with the led_service_client c and h files.

That's it. 

Lesson: Don't attempt to port SDK 15 or 16 projects down to SDK 12, there are too many changes. Instead, find an SDK 12 project which is close to what you want and add functionality to an already working project to build it up to the SDK 15 or 16 version.

Compile Statistics

SDKChipSoftDeviceFlashRAM
15nRF52S132211k32k
12nRF51S13028k6k