This is an old revision of the document!
This lazy-guide is a short summary about how I made my Adafruit Feather nRF52840 Express work with ANT+.
The Feather is an Arduino compatible board using the nRF52840 SoC from Nordic Semiconductor (NordicSemi).
ANT (Adaptive Network Topology) is a wireless communication network standard intended for sensor networks. Originally developed by DynaStream, it currently belongs to Garmin. It operates in the ISM spectrum and most of its specs available publicly. Certain IPR-s remains controlled by Garmin, but for non-commerical use it can be used without a license fee.
ANT+ is a interoperability standard on top of the ANT transport standard in order to create an “ultra low-power wireless” ecosystem for fitness and medical applications. Notably, Garmin runners' and bikers' watches and bike-computers uses this standard to communicate with various measurement sensors.
The nRF52840 SoC is part of the nRF52 series of chips from NordicSemi. It is multi-protocol capable and a number of Arduino compatible boards sports this chipset. The most notable ones:
For legal (and probably other reasons) neither of these boards come with the ANT+ protocol stack pre-installed, albeit they are fully capable of running that stack. This guide is a summary of how I made my Adafruit nRF52840 Feather ANT+ capable while I kept its original functionality, i.e., being Arduino compatible and supporting Adafruit's Bluefruit Bluetooth library.
The adaptation removes the Bluetooth only S140 SoftDevice from the firmware and replaces it with the S340 combined SoftDevice running BLE5 and ANT+ concurrently.
Note: The CircuitPython capability will be lost, since the stock CircuitPython interpreter for this Feather is provided as a binary UF2 firmware update is bound to the S140 Bluetooth-only softdevice.
BEWARE: trying to install the CircuitPython UF2 package to a S340-adapted Feather will brick your Feather and you will need to use a SWD programmer device to make your Feather usable again!
A number of internet resources helped me. The biggest help came as form of a personal mail from “Ryan”, whom I got acquainted with by Curtis Malainey. It was “Ryan”, who first managed the S340 SoftDevice to work with his Feather and he kindly shared his steps with me. This guide is based primarily on his work.
Note: the nRF52840-DK from NordicSemi contains an On-Board Segger programmer (Segger-OB), which is free to use for Nordic chipsets. The Segger OB on the NordicSemi DevKit also has an SWD connector for external boards, so it can be used with the Feather, as well. Otherwise the Segger EDU can be a not-so-expensive alternative
Note: this tutorial is based on the v.6.1.1 versions of the NordicSemi softdevices and the 0.3.0 version of the Adafruit bootloader
1. Clone the Adafruit bootloader from https://github.com/adafruit/Adafruit_nRF52_Bootloader. It contains two submodules, hence you need to clone it recursively. I used to the GitHub Desktop, which does recursive cloning automagically
git clone https://github.com/adafruit/Adafruit_nRF52_Bootloader cd Adafruit_nRF52_Bootloader git submodule update --init --recursive
Follow its readme: https://github.com/adafruit/Adafruit_nRF52_Bootloader/blob/master/README.md
$ pip3 install --user adafruit-nrfutil
2. Make sure that you can succesfully build and flash it into your board.
Follow the instructions at https://github.com/adafruit/Adafruit_nRF52_Bootloader/blob/master/README.md. Change the serial to your actual serial device. For me, under Windows10 it was COM5. Under Linux it could be, for example, /dev/ttyACM0
$ make BOARD=feather_nrf52840_express all combinehex $ make BOARD=feather_nrf52840_express SERIAL=COM5 dfu-flash
If you run into any trouble, then DO NOT PROCEED further down within this lazy-guide until you can successfully rebuild the original bootloader and flash it into your device!! (If you can't build and flash the original version, then it makes no sense to try to hack it.)
Download S340 SoftDevice from thisisant.com. Unpack it somewhere. You will need to rename and copy it later.
Insert the following after setting flags according to MCU_SUB_VARIANTS after line #106:
ifdef USE_S340 #if S340 then adjust SD_NAME and MCU SD_NAME = s340 MCU_FLAGS = -DNRF52840_XXAA -DS340 endif
The graphical diff looks like this (left is orginal, right is modified)
Go to …\lib\softdevice\. Create a dir called s340_nrf52_6.1.1:
...\lib\softdevice $ mkdir s340_nrf52_6.1.1
This directory needs to store the v6.1.1 version of the BLE+ANT combinded S340 softdevice headers + the .hex binary. The way you can get that is described here: https://www.nordicsemi.com/Software-and-tools/Software/S340-ANT
IMPORTANT:
That is, your resulted library tree should look exactly like this:
s340_nrf52_6.1.1/ ├── s340_nrf52_6.1.1_API │ └── include │ ├── ant_error.h │ ├── ant_interface.h │ ├── ant_parameters.h │ ├── ble.h │ ├── ble_err.h │ ├── ble_gap.h │ ├── ble_gatt.h │ ├── ble_gattc.h │ ├── ble_gatts.h │ ├── ble_hci.h │ ├── ble_l2cap.h │ ├── ble_ranges.h │ ├── ble_types.h │ ├── nrf52 │ │ └── nrf_mbr.h │ ├── nrf_error.h │ ├── nrf_error_sdm.h │ ├── nrf_error_soc.h │ ├── nrf_nvic.h │ ├── nrf_sd_def.h │ ├── nrf_sdm.h │ ├── nrf_soc.h │ └── nrf_svc.h └── s340_nrf52_6.1.1_softdevice.hex
The graphical diff looks like this (left is orginal, right is modified)
The graphical diff looks like this (left is orginal, right is modified)
The graphical diff looks like this (left is orginal, right is modified)
Go to …/src/usb/uf2. Modify the “USER_FLASH_START” definition inside uf2cfg.h:
That is, the “USER_FLASH_START” shall be defined as follows:
#ifdef S340 #define USER_FLASH_START 0x31000 #elif // #ifdef S340 #define USER_FLASH_START 0x26000 #endif // #ifdef S340
The graphical diff looks like this (left is orginal, right is modified)
src/linker $ cp nrf52840_s140_v6.ld nrf52840_s340_v6.ld
#ifndef ANT_LICENSE_KEY APP_ERROR_CHECK( sd_softdevice_enable(&clock_cfg, app_error_fault_handler) ); #else APP_ERROR_CHECK( sd_softdevice_enable(&clock_cfg, app_error_fault_handler, ANT_LICENSE_KEY) ); #endif
The graphical diff looks like this (left is orginal, right is modified)
Go to the root of the bootloader directory tree. Build and flash as follows. NOTE: adapt the GNU_INSTALL_ROOT and SERIAL definitions according to your local setup!
make GNU_INSTALL_ROOT="C:/Program Files (x86)/GNU Tools Arm Embedded/9 2019-q4-major/bin/" BOARD=feather_nrf52840_express_s340 all combinehex make GNU_INSTALL_ROOT="C:/Program Files (x86)/GNU Tools Arm Embedded/9 2019-q4-major/bin/" BOARD=feather_nrf52840_express_s340 SERIAL=COM5 dfu-flash
Enjoy :)
If you got confused you can check my forked repo at: https://github.com/orrmany/Adafruit_nRF52_Bootloader/tree/s340-for-nrf52840-Feather
C:\Users\egbozie\Google Drive\Arduino\libraries\Adafruit_nRF52_Bootloader>make BOARD=feather_nrf52840_express all combinehex CC main.c CC boards.c CC flash_nrf5x.c CC dfu_ble_svc.c CC dfu_init.c CC nrfx_power.c CC nrfx_nvmc.c CC system_nrf52840.c CC bootloader.c CC bootloader_settings.c CC bootloader_util.c CC dfu_transport_serial.c CC dfu_transport_ble.c CC dfu_single_bank.c CC pstorage_raw.c CC ble_dfu.c CC ble_dis.c CC app_timer.c CC app_scheduler.c CC app_error.c CC app_util_platform.c CC crc16.c CC hci_mem_pool.c CC hci_slip.c CC hci_transport.c CC nrf_assert.c CC usb_desc.c CC usb.c CC msc_uf2.c CC ghostfat.c CC dcd_nrf5x.c CC tusb_fifo.c CC usbd.c CC usbd_control.c CC cdc_device.c CC msc_device.c CC tusb.c AS gcc_startup_nrf52840.S LD feather_nrf52840_express_bootloader-0.2.13-21-g454b281-dirty-nosd.out '' text data bss dec hex filename 30376 212 22426 53014 cf16 _build-feather_nrf52840_express/feather_nrf52840_express_bootloader-0.2.13-21-g454b281-dirty-nosd.out '' CR feather_nrf52840_express_bootloader-0.2.13-21-g454b281-dirty-nosd.hex CR feather_nrf52840_express_bootloader-0.2.13-21-g454b281-dirty_s340_6.1.1.hex C:\Users\egbozie\Google Drive\Arduino\libraries\Adafruit_nRF52_Bootloader>make BOARD=feather_nrf52840_express SERIAL=COM5 dfu-flash LD feather_nrf52840_express_bootloader-0.2.13-21-g454b281-dirty-nosd.out CR feather_nrf52840_express_bootloader-0.2.13-21-g454b281-dirty-nosd.hex Zip created at _build-feather_nrf52840_express/feather_nrf52840_express_bootloader-0.2.13-21-g454b281-dirty_s340_6.1.1.zip adafruit-nrfutil --verbose dfu serial --package _build-feather_nrf52840_express/feather_nrf52840_express_bootloader-0.2.13-21-g454b281-dirty_s340_6.1.1.zip -p COM5 -b 115200 --singlebank --touch 1200 Upgrading target on COM5 with DFU package C:\Users\egbozie\Google Drive\Arduino\libraries\Adafruit_nRF52_Bootloader\_build-feather_nrf52840_express\feather_nrf52840_express_bootloader-0.2.13-21-g454b281-dirty_s340_6.1.1.zip. Flow control is disabled, Single bank, Touch 1200 Touched serial port COM5 Opened serial port COM5 Starting DFU upgrade of type 3, SoftDevice size: 190272, bootloader size: 30580, application size: 0 Sending DFU start packet Sending DFU init packet Sending firmware file ######################################## ######################################## ######################################## ######################################## ######################################## ######################################## ######################################## ######################################## ######################################## ######################################## ################################ Activating new firmware DFU upgrade took 24.582117557525635s Device programmed. C:\Users\egbozie\Google Drive\Arduino\libraries\Adafruit_nRF52_Bootloader>