Difficulties of having two nRF51822 Mbed boards communicate over BLE

21 Jul 2014

(Sorry for posting two threads in one day!)

I have some nRF51822 mbed boards for a project. The project requires an array of these boards to communicate with each other via Bluetooth Low Energy (BLE). I am developing on linux, so can't use the Windows-only Keil with my current set-up. For reasons which I will explain below, I cannot use the Mbed online IDE for this project. Thanks partially to some of the very helpful members of the mbed community, I am aware that it is possible to develop for these boards using the ARM gcc toolchain. However, this is a non-trivial task and I have run into a number of issues, which I will explain below.

I am posting this thread largely for two reasons:

1) I hope someone can help me!

2) Whilst perhaps the majority of users of the nRF51822 Mbed kits are developing peripheral devices intended to communicate with phones/other central devices, I know that I'm not the only linux-user with a few of these kits trying to get them to communicate with each other. So most of my issues are not specific to my use-case, and it is worth having this discussion with the community and Mbed team.

Here are some of the technical issues getting up and running with the BLE stuff as far as I understand it (I might be wrong about some of this!):

In order to have two BLE devices communicating, at least one of them needs to be able to scan for devices (i.e. it needs to be able to act in a central/master role). The possible behaviour of the nRF51822 boards is largely determined by the protocol stack they are loaded with (known as SoftDevices or SDs by Nordic).

The Mbed online IDE is set up to work with the S110 SoftDevice, and this is the only SD supported by the Mbed BLE API at this time (see, for example, Kevin Townsend's post https:mbed.org/forum/team-63-Bluetooth-Low-Energy-community/topic/4903/?page=1#comment-24390). S110 only supports peripheral or broadcaster behaviour, which means it can't scan for other BLE devices. So using this SD, our boards have no way of recognising that another nearby board exists and is broadcasting or advertising.

There is another SD released by Nordic: S120 (not supported by the Mbed IDE or BLE API). This supports only central/master roles. Theoretically we could create a solution using a combination of some peripheral boards running S110 software and some central boards running S120 software, but in this case the S110 boards couldn't communicate directly and neither could the S120 boards, so this is not ideal. Regardless, there are difficulties getting S120 to work with the gcc toolchain in the first place for the nRF51822 mkit boards (see below).

This month, Nordic released a third SoftDevice: S130. This promises to offer simultaneous central and peripheral behaviour, ideal for our purposes. However, there are these issues:

  • It is apparently not supported by the latest version (v6.0.0) of Nordic's NRF51 SDK However, SDK downloads from Nordic are limited by product keys activated on your account. On my account with keys activated for the nRF51822 Mkits, only v6.0.0 is available for download. (I have opened a support ticket with Nordic mentioning this.
  • It is not supported by the Mbed IDE. So in order to develop with it on linux, we must use the gcc toolchain.
  • There is little or no documentation or support for using S130 at this time, especially with gcc. Quoting from a comment here (https://devzone.nordicsemi.com/blogs/14/s130-multi-link-softdevice-released-tell-us-what-y/) by user cocoa (I don't know who s/he is but based on post history going back over a year they are quite experienced with developing for Nordic's devices and using their SDKs and APIs): "Great features in S130, but a SDK without S130 documentation (now there are only S110 and S120) no examples using gcc... is not useful."
  • There is no direct guidance on using the nRF51822 mkit with Nordic's SDK with *any* SoftDevice and gcc. This is partially because the mkit uses CMSIS-DAP whereas as far as I can tell, all of Nordic's other devices (including their other nRF51822 boards) use J-Link, so all of their guidance assumes that. There is a guide for using the mkit with their SDK, but it only discusses Keil. (And even if we used Keil and got it to work with the SDK, we would still have the problem of using S130 without proper documentation or support).

None of the above issues are insurmountable, and it should certainly be technically possible to do what we want to do with the boards. However, there is very little published guidance or support for what we want to do, which makes progress difficult.

22 Jul 2014

You can also use the S110 v7.0 softdevice as an Observer/Scanner and Advertiser using the Timeslot API. See the example posted here. http://nordicsemiconductor.github.io/nRF51-multi-role-conn-observer-advertiser/. Unfortunately it is still based on the Keil toolchain, it may however get a bump to gcc as well over the coming weeks.

23 Jul 2014

Hello,

Thanks very much for your feedback; and apologies for the current limitations of the BLE_API and our Nordic offering.

We'll be releasing support for v7 of the S110 softdevice by tomorrow (possibly today).

Here's a CMakeLists.txt (using CMake) which describes how to build using an external toolchain on linux. You'll need to make minor changes to it; but it should be fairly easy.

S130 is still in alpha, but Nordic tells us that it's relatively stable. It's throughput is roughly half that of the S110, and there's no SDK for it yet. But we expect to upgrade to it within the next 4 weeks (hopefully sooner).

Many apologies for having taken this long to provide a ready solution for the kind of application you're trying to build. And thanks again for your feedback.

rohit.

24 Jul 2014

Thank you both very much for taking the time to reply! This is really useful and hopefully will get us up and running quickly. I'll let you know how I get on.

05 Aug 2014

I'm sorry to be a pain, but I wondered if you could help me figure out what is going wrong with my attempts at using the CMake file you suggested.

I have edited it to reflect the locations of the necessary things on my system, and I'm doing it with the Heart Rate Monitor just to get it working. I got it by importing that project into the online compiler and downloading a .zip of it. Here's my CMakeLists.txt: http://pastebin.com/ecE4ZACY

cmake . runs fine:

jimi@horatio:~/cppstuff/dowcmake/hrate$ cmake .
-- C compiler  : /opt/gcc4mbed/gcc4mbed/gcc-arm-none-eabi/bin/arm-none-eabi-g++
-- C++ compiler: /opt/gcc4mbed/gcc4mbed/gcc-arm-none-eabi/bin/arm-none-eabi-g++
-- Size command: size
-- Main target : BLE_HEART_RATE.elf
-- Configuring done
-- Generating done
-- Build files have been written to: /home/jimi/cppstuff/dowcmake/hrate

But then running make fails:

jimi@horatio:~/cppstuff/dowcmake/hrate$ make
[  1%] Building CXX object CMakeFiles/BLE_HEART_RATE.elf.dir/main.cpp.o
arm-none-eabi-g++: error: unrecognized command line option '--cpp'
arm-none-eabi-g++: error: unrecognized command line option '--no_rtti'
arm-none-eabi-g++: error: unrecognized command line option '--cpu=Cortex-M0'
arm-none-eabi-g++: error: unrecognized command line option '--gnu'
arm-none-eabi-g++: error: unrecognized command line option '--split_sections'
arm-none-eabi-g++: error: unrecognized command line option '--brief_diagnostics'
arm-none-eabi-g++: error: unrecognized command line option '--restrict'
arm-none-eabi-g++: error: unrecognized command line option '--md'
arm-none-eabi-g++: error: unrecognized command line option '--no_depend_system_headers'
make[2]: *** [CMakeFiles/BLE_HEART_RATE.elf.dir/main.cpp.o] Error 1
make[1]: *** [CMakeFiles/BLE_HEART_RATE.elf.dir/all] Error 2
make: *** [all] Error 2

EDIT: I've realised the example cmake must have been written for a different toolchain to the one I'm using (ARM GCC). I think I'm ok trying to figure it out for now but if anyone has any suggestions they'd be welcome!

06 Aug 2014

I came to the same conclusion, but haven't been able to figure out the secret sauce.

There are so many partial examples of building programs for the nRF51822 with gcc, but I haven't found a single one that works for me. Even the simple examples in the Nordic SDK aren't working for me.

Please let us know if you have any success.

07 Aug 2014

Based on [Rohit's notebook page](https://mbed.org/users/rgrover1/notebook/cmakegcc-based-offline-build-system-with-mbed-sour/) describing his use of cmake, I tried installing Sourcery CodeBench Lite and modified the earlier linked cmake file to point to the CodeBench compiler, but I still get

$ make
Scanning dependencies of target BLE_HEART_RATE.elf
[  1%] Building CXX object CMakeFiles/BLE_HEART_RATE.elf.dir/main.cpp.o
arm-none-eabi-g++: error: unrecognized command line option '--cpp'
arm-none-eabi-g++: error: unrecognized command line option '--no_rtti'
arm-none-eabi-g++: error: unrecognized command line option '--cpu=Cortex-M0'
arm-none-eabi-g++: error: unrecognized command line option '--gnu'
arm-none-eabi-g++: error: unrecognized command line option '--split_sections'
arm-none-eabi-g++: error: unrecognized command line option '--brief_diagnostics'
arm-none-eabi-g++: error: unrecognized command line option '--restrict'
arm-none-eabi-g++: error: unrecognized command line option '--md'
arm-none-eabi-g++: error: unrecognized command line option '--no_depend_system_headers'
make[2]: *** [CMakeFiles/BLE_HEART_RATE.elf.dir/main.cpp.o] Error 1
make[1]: *** [CMakeFiles/BLE_HEART_RATE.elf.dir/all] Error 2
make: *** [all] Error 2

I'm really curious what compiler was being used with the example CMake file above :p.

07 Aug 2014

OK I saw in another post that Rohit uses the armcc toolchain. So that answers that question!

I've made some progress! Here's my current CMakeLists.txt: https://gist.github.com/2b670e78b1f5de65cc01

And the important bit of the result of running make:

$ cmake .
-- C compiler  : /home/jimi/gcc-arm-none-eabi-4_8-2014q2/bin/arm-none-eabi-g++
-- C++ compiler: /home/jimi/gcc-arm-none-eabi-4_8-2014q2/bin/arm-none-eabi-g++
-- Size command: size
-- Main target : BLE_HEART_RATE.elf
-- Configuring done
-- Generating done
-- Build files have been written to: /home/jimi/cppstuff/dowcmake/hrate

$ make
[  1%] Building CXX object CMakeFiles/BLE_HEART_RATE.elf.dir/main.cpp.o
[  3%] Building C object CMakeFiles/BLE_HEART_RATE.elf.dir/mbed/libraries/mbed/common/gpio.c.o
[  5%] Building C object CMakeFiles/BLE_HEART_RATE.elf.dir/mbed/libraries/mbed/common/rtc_time.c.o
[  6%] Building C object CMakeFiles/BLE_HEART_RATE.elf.dir/mbed/libraries/mbed/common/error.c.o
[  8%] Building C object CMakeFiles/BLE_HEART_RATE.elf.dir/mbed/libraries/mbed/common/pinmap_common.c.o
[ 10%] Building C object CMakeFiles/BLE_HEART_RATE.elf.dir/mbed/libraries/mbed/common/exit.c.o
...

...
[ 71%] Building CXX object CMakeFiles/BLE_HEART_RATE.elf.dir/nRF51822/nRF51822n.cpp.o
[ 72%] Building CXX object CMakeFiles/BLE_HEART_RATE.elf.dir/nRF51822/nRF51GattServer.cpp.o
In file included from /home/jimi/cppstuff/dowcmake/hrate/nRF51822/nordic/nrf-sdk/s110/ble_gap.h:19:0,
                 from /home/jimi/cppstuff/dowcmake/hrate/nRF51822/nordic/nrf-sdk/s110/ble.h:23,
                 from /home/jimi/cppstuff/dowcmake/hrate/nRF51822/nRF51GattServer.h:22,
                 from /home/jimi/cppstuff/dowcmake/hrate/nRF51822/nRF51GattServer.cpp:17:
/home/jimi/cppstuff/dowcmake/hrate/nRF51822/nordic/nrf-sdk/s110/ble_gatts.h: In function 'uint32_t sd_ble_gatts_service_add(uint8_t, const ble_uuid_t*, uint16_t*)':
/home/jimi/cppstuff/dowcmake/hrate/nRF51822/nordic/nrf-sdk/s110/nrf_svc.h:20:6: error: impossible constraint in 'asm'
     ); \
      ^
/home/jimi/cppstuff/dowcmake/hrate/nRF51822/nordic/nrf-sdk/s110/ble_gatts.h:334:1: note: in expansion of macro 'SVCALL'
 SVCALL(SD_BLE_GATTS_SERVICE_ADD, uint32_t, sd_ble_gatts_service_add(uint8_t type, ble_uuid_t const*const p_uuid, uint16_t *const p_handle));
 ^
make[2]: *** [CMakeFiles/BLE_HEART_RATE.elf.dir/nRF51822/nRF51GattServer.cpp.o] Error 1
make[1]: *** [CMakeFiles/BLE_HEART_RATE.elf.dir/all] Error 2
make: *** [all] Error 2

Any idea how to fix these errors? Something to do with the ASM?

08 Aug 2014

Hi,

Apologies for the delay in my response. You've raised an important discussion around getting GCC based toolchains to work for nRF demos. This is important enough for us; and we'd like to setup a useful example for others to follow.

I'd appreciate your help with getting this out; especially since I may not have all the time needed to do a good job of it by myself.

First, please use this CMakeLists.txt as a reference. It is nearly complete, and may need only a tiny bit of work to get everything working.

Refer to this discussion.

Try this patch to overcome the issue.

Please fix the last bit of link error.

And then once you confirm everything is working, we'll proceed to create a tutorial/wiki for all this; and I'll commit the patch to the mainline.

Sorry for offering you an incompletely baked solution.

rohit

08 Aug 2014

Many thanks Rohit, I'll take a look and let you know how I get on.

08 Aug 2014

I wonder if I could ask you for clarification on something, Rohit, so I can be sure I'm working on the right thing. In both the CMake files you've posted, you have paths like

add_sources(${MBED_SRC_PATH}/targets/cmsis/TARGET_NORDIC/TARGET_NRF51822/TOOLCHAIN_GCC_ARM/startup_NRF51822.s)

But in my copy of the mbed library the paths are through

.../TARGET_NORDIC/TARGET_MCU_NRF51822/...

I downloaded my copy by importing the heart rate example into the online IDE and exporting it to zip from there. These paths also seem to agree with the copy on github.

I also had to add these two to include_directories:

    ${MBED_SRC_PATH}/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/TARGET_NRF51822_MKIT/
    ${MBED_SRC_PATH}/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/

I just wanted to check we were working on the same version of the project in case it had an effect on the other errors. Thanks again for all your efforts on this, they are much appreciated!

08 Aug 2014

Jimi,

I had been using an older version of the mbed-src repository. Thanks for pointing it out. I've updated CMakeLists.txt.

09 Aug 2014

Hi Rohit / anyone else... Could you confirm whether you've actually managed to compile a project using this CMakeLists.txt? I'm now getting linker errors (after fixing the path to the linker script):

[snip]
/Users/janek/bin/gcc-arm-none-eabi-4_8-2014q2/bin/../lib/gcc/arm-none-eabi/4.8.4/../../../../arm-none-eabi/bin/ld: BFD (GNU Tools for ARM Embedded Processors) 2.23.2.20140529 assertion fail /Users/build/GCC-4-8-build/gcc-arm-none-eabi-4_8-2014q2-20140609/src/binutils/bfd/elf32-arm.c:12394
/Users/janek/bin/gcc-arm-none-eabi-4_8-2014q2/bin/../lib/gcc/arm-none-eabi/4.8.4/../../../../arm-none-eabi/bin/ld: warning: cannot find entry symbol arch_paths_first; defaulting to 0000000000016000
/Users/janek/bin/gcc-arm-none-eabi-4_8-2014q2/bin/../lib/gcc/arm-none-eabi/4.8.4/../../../../arm-none-eabi/lib/armv6-m/libc.a(lib_a-sbrkr.o): In function `_sbrk_r':
sbrkr.c:(.text._sbrk_r+0xc): undefined reference to `_sbrk'
collect2: error: ld returned 1 exit status
make[2]: *** [BLE_HEART_RATE.elf] Error 1
make[1]: *** [CMakeFiles/BLE_HEART_RATE.elf.dir/all] Error 2

So we can all be on the same page, here is the repo I am working from: https://github.com/janekm/mbed-nrf51-gcc-test

I am using gcc-arm-none-eabi-4_8-2014q2-20140609 on OS X 10.9.4.

I have applied your patches to nRF51822, and put your latest CMakeLists.txt.

All the sub-repos, including mbed-src, are the latest published versions, afaik.

10 Aug 2014

Janek,

I got stuck at the same link error as you point out (missing _sbrk). But I assumed it would not be difficult to resolve this by adding it to the Nordic/GCC specific sys.cpp. Here's an example _sbrk() from another sys.cpp. Could you please try with this, and be willing to make minor alterations if needed?

void *_sbrk(unsigned int incr) {
    void *mem;
    
    unsigned int next = ((((unsigned int)heap_pointer + incr) + 7) & ~7);
    if (next > __get_MSP()) {
        mem = NULL;
    } else {
        mem = (void *)heap_pointer;
    }
    heap_pointer = (void *)next;
    
    return mem;
}

Looking forward to hearing about how you get on with this.

10 Aug 2014

Hi Rohit,

thanks for your response, it put me down the path of some interesting explorations: I tried adding _sbrk (with a few modifications to match the linker script) which solved that linker error but still left me with linker asserts (weird).

Then I did a bit more digging and it turns out that commons/retarget.cpp already provides _sbrk (but the linker was getting confused somehow). I went back to my experiments with the Makefiles created by the exporter in mbed-src, and stepping through the startup code in gcc it turns out it never reaches main but got stuck in _init. I noticed that retarget.cpp tries to wrap main which leads to

--wrap=main

being required in the linker options, I created a pull request for that: https://github.com/mbedmicro/mbed/pull/435

11 Aug 2014

That's great news! I just finished soldering my custom board, and now I need to test it. I'll try out your pull request very soon (first on a known-good board, then my hand-soldered one! ;-).

11 Aug 2014

I've now figured out that it's the nrf51822.ld script that was faulty, so the new pull request also fixed the make.py build. There's still some issues remaining with pyOCD though, but loading the code with gdb and JLink works.

11 Aug 2014

excellent news. Please update once you're satisfied with the state of your repository. It could then be used as a basis for creating some documentation regarding the gcc toolchain for mbed/nRF518.

11 Aug 2014

excellent news. Please update once you're satisfied with the state of your repository. It could then be used as a basis for creating some documentation regarding the gcc toolchain for mbed/nRF518.

31 Aug 2014

Hello, I create a repo to use softdevice 6/7 with gcc toolchain, mbed SDK and mbed BLE API. See https://github.com/Seeed-Studio/mbed_ble

I also try to send pull requests to get nrf51822 gcc support officially.

https://github.com/mbedmicro/mbed/pull/468 and http://mbed.org/teams/Nordic-Semiconductor/code/nRF51822/pull-request/1

08 Sep 2014

@rohit - is there any update on this ?

It would be really great to have a single cmakelists flow for the gcc toolchain.

If it helps, here is an OpenOCD toolchain using the STM32 Discovery board for the nrf51822 - https://github.com/RIOT-OS/RIOT/wiki/Board:-yunjia-nrf51822 . It uses a bunch of makefiles and is obviously not as clean as your cmakelists.

08 Sep 2014

Pull request has been accepted.

08 Sep 2014

I'm trying to program the s120 softdevice and my application code onto an nRF51822-mkit using a gcc based system. Everything was sorking when using the s110 v7 softdevice, having adjusted the application to use the s120 device and compile correctly, I can't get the merge step to work with the s120 device. Any ideas? (I'm wondering if the offset is wrong?)

Merge command

srec_cat s120_nrf51822_1.0.0_softdevice.hex -intel BLE_UART.hex -binary -offset 0x16000 -o combined.hex -intel

srec_cat: BLE_UART.hex: 0x00FF: contradictory 0x00016000 value (previous = 0x00,
    this one = 0x3A)
09 Sep 2014

Offset 0x16000 is very specific to v7 of the S110. You should perhaps refer to the uVision project settings for sample code shipped with Nordic's S120 SDK to learn about relevant bits.

10 Sep 2014

After reading the spec for the s120 soft device, I've found the offset to be 0x18000. Thanks.

11 Sep 2014

@rohit - I have a repository that takes of the sbrk issue (by including a few missing flags, etc). Could you take a look at it and see if it fixes the gcc issue.

https://github.com/sandys/mbed-nrf51-gcc-test