Prototyping BLE apps on the nRF52840 USB Dongle (Part A)

Prototyping with the nRF52840 USB Dongle Part A

In the previous post (The nRF52840 USB Dongle Tutorial (Part 1)), we explored how to use the new nRF52840 USB Dongle to enable nRF Connect PC applications such as the Bluetooth Low Energy application (central and peripheral emulator), the nRF Cloud Gateway application, and the RSSI Viewer application.

More importantly, we also talked about how the dongle can be used as a development kit (similar to the main nRF52840 development kit). The low price and small size of this dongle make it perfect for prototyping projects that require devices in a small form factor (e.g. large-scale Bluetooth mesh deployments).

However, the dongle also has a few disadvantages compared to the fully-featured nRF52840 development kit.


  • More compact and much smaller in size
  • Plugs directly into and powers from a USB Type A port (making it perfect for powering via a USB wall adapter)
  • Ideal for prototyping and quickly developing proof-of-concepts
  • Much lower cost ($10 compared to around $45 for the full DK)
  • Can be easily mounted onto a breadboard (after some soldering work)


  • No support for an onboard debugger
  • Requires some work to get external peripherals connected including soldering
  • Limited peripheral support (15 GPIOs only) compared to full access to all pins on the full development kit
  • A limited number of built-in LEDs and buttons. It provides 4 LEDs (One Green and one multicolor LED (R, G, B)) and one user-configurable button. This compares to 4 (Green) LEDs and 4 user-configurable buttons on the full development kit

Simple BLE Project Description

We’ll be going over the implementation of a simple BLE application using this dongle, and we’ll do this over a series of two posts.

The project will implement a BLE Peripheral device that includes one external button and one external LED.

We could’ve just used the built-in LEDs and button, but that would be no fun. Besides, learning how to configure the GPIO will help us in the long-run for adding other sensors and I/O devices such as displays, temperature sensors and all sorts of other peripherals.

The basic operation of the project:

  • The dongle will operate as a BLE Peripheral that allows a connection from a BLE Central device
  • We will implement our own custom service with two characteristics:
    • The LED can be controlled by writing to a characteristic
    • The button status will be reported via an additional characteristic (that can be either read or automatically notified)
  • We’ll use one of the built-in LEDs (Green LED) to indicate connectivity (Solid for connected and flashing for disconnected/advertising)

In today’s post will go over the following steps:

  • Installing the necessary software packages
  • Getting your hardware ready for prototyping on a breadboard
  • Physically connecting the dongle and external peripherals (LED and button) on the breadboard
  • Implementing the firmware modifications necessary to add the external LED and button to the GPIOs of the dongle
  • Flashing the application to the dongle
  • Testing basic functionality

In next week’s post we’ll go over:

  • Design of our custom GATT (services and characteristics) to allow control of the LED and reporting the state of the button (pressed vs. released)
  • Full implementation of the firmware application on the nRF52840 USB Dongle
  • Testing of the device by connecting to and interacting with it from a mobile application

In future posts, we will build upon this foundation and hardware to add more features including:

  • Implementing a Central and Peripheral device pair that communicate in long-range mode (Bluetooth 5 Coded PHY) over long distances
  • Implementing a weather station device that reads temperature, humidity, and other environmental parameters and transfers the data to another dongle connected to an external display to show the latest readings
  • Bluetooth mesh network of multiple nodes implemented on the dongle

What project would you build using the nRF52840 USB dongle? Or maybe you’re already using it for a project? Let me know in the comments section below.



  1. SES (Segger Embedded Studio download link)
  2. nRF5 SDK version 15.2.0 (download link)
  3. nRF Connect for Desktop (download link)
    • Install the Programmer application within nRF Connect for Desktop

For further details for steps 1 & 2, follow my previous tutorial here: The complete cross-platform nRF development tutorial. For step 3, refer back to part 1 of the nRF52840 USB dongle tutorial series: The nRF52840 USB Dongle Tutorial (Part 1).


Here are the hardware pieces I am using for this project:

  • One nRF52840 USB Dongle

    Figure 1: nRF52840 USB Dongle
  • One breadboard

    Figure 2: Breadboard
  • Two header rows of 10 pins each

    Figure 3: Header rows
  • Breadboard jumper or copper wires

    Figure 4: Jumper wires
  • One LED

    Figure 5: LED
  • One push button switch

    Figure 6: Push button switch
  • One resistor (I’m using a 220 Ohm resistor)

    Figure 7: Resistor
  • Optional: USB male to female extension cable (or simply connect the dongle directly to the PC)

    Figure 8: USB male-to-female extension cable

Preparing the Hardware

Step 1: Solder the header rows to the dongle (one row on each side of the castellated edges):

Figure 9: Soldered header rows

Step 2: Mount the dongle onto a breadboard:

Figure 10: Dongle mounted on a breadboard

Step 3: Connect the LED as shown in the following picture. The LED’s anode pin (long leg) is connected to the resistor to VDD on the dongle, and the LED’s cathode node (short leg) is connected to Pin 1.10.

Figure 11: Connecting LED

Step 4: Connect the external button as shown in the following picture. The button is connected to Pin 0.24 on one end and to GND on the other.

Figure 12: Connecting button

As a reference, here’s the schematic for the connections to the dongle:

Figure 13: Schematic

Step 5: Connect the dongle to the PC

Figure 14: Connecting the dongle to the PC

Firmware Modifications for Connecting the Peripherals (LED and Push Button)

The nRF52840 USB dongle obviously utilizes the nRF52840, but that doesn’t mean it’s identical to the nRF52840 development kit. In order to build and run an example originally created for the development kit on the USB dongle, a few changes need to be made to the firmware and configuration.

There are a few examples in the nRF5 SDK that have SES project files for the USB dongle (named PCA10059), but knowing which changes need to be made can help when creating your own examples from scratch or modifying an existing project to run on the USB dongle.

I highly recommend reading through this excellent tutorial over at Nordic’s website before moving forward: nRF52840 Dongle Programming Tutorial

We’ll take the BLE template (PCA10056/nRF52840 development kit) example in the nRF5 SDK and use it as a base for our project. The example can be found at <SDK root>/examples/ble_peripheral/ble_app_template/.

  • Step 1: Make a copy of the template example folder and name it appropriately (I named it “nRF52840_Dongle”).

    Figure 15: Template example folder copied and renamed
  • Step 2: Rename the pca10056 folder to pca10059
    It’s also helpful to rename the project/solution file accordingly
  • Step 3: Replace the flash_placement.xml file with the following code (which you can get from any of the PCA10059 examples included in the SDK)
    <!DOCTYPE Linker_Placement_File>
    <Root name="Flash Section Placement">
      <MemorySegment name="FLASH" start="$(FLASH_PH_START)" size="$(FLASH_PH_SIZE)">
        <ProgramSection load="no" name=".reserved_flash" start="$(FLASH_PH_START)" size="$(FLASH_START)-$(FLASH_PH_START)" />
        <ProgramSection alignment="0x100" load="Yes" name=".vectors" start="$(FLASH_START)" />
        <ProgramSection alignment="4" load="Yes" name=".init" />
        <ProgramSection alignment="4" load="Yes" name=".init_rodata" />
        <ProgramSection alignment="4" load="Yes" name=".text" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_soc_observers" inputsections="*(SORT(.sdh_soc_observers*))" address_symbol="__start_sdh_soc_observers" end_symbol="__stop_sdh_soc_observers" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_ble_observers" inputsections="*(SORT(.sdh_ble_observers*))" address_symbol="__start_sdh_ble_observers" end_symbol="__stop_sdh_ble_observers" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".pwr_mgmt_data" inputsections="*(SORT(.pwr_mgmt_data*))" address_symbol="__start_pwr_mgmt_data" end_symbol="__stop_pwr_mgmt_data" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".nrf_queue" inputsections="*(.nrf_queue*)" address_symbol="__start_nrf_queue" end_symbol="__stop_nrf_queue" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_stack_observers" inputsections="*(SORT(.sdh_stack_observers*))" address_symbol="__start_sdh_stack_observers" end_symbol="__stop_sdh_stack_observers" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_req_observers" inputsections="*(SORT(.sdh_req_observers*))" address_symbol="__start_sdh_req_observers" end_symbol="__stop_sdh_req_observers" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_state_observers" inputsections="*(SORT(.sdh_state_observers*))" address_symbol="__start_sdh_state_observers" end_symbol="__stop_sdh_state_observers" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".nrf_balloc" inputsections="*(.nrf_balloc*)" address_symbol="__start_nrf_balloc" end_symbol="__stop_nrf_balloc" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".cli_command" inputsections="*(.cli_command*)" address_symbol="__start_cli_command" end_symbol="__stop_cli_command" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".crypto_data" inputsections="*(SORT(.crypto_data*))" address_symbol="__start_crypto_data" end_symbol="__stop_crypto_data" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".log_const_data" inputsections="*(SORT(.log_const_data*))" address_symbol="__start_log_const_data" end_symbol="__stop_log_const_data" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".log_backends" inputsections="*(SORT(.log_backends*))" address_symbol="__start_log_backends" end_symbol="__stop_log_backends" />
        <ProgramSection alignment="4" keep="Yes" load="No" name=".nrf_sections" address_symbol="__start_nrf_sections" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".cli_sorted_cmd_ptrs"  inputsections="*(.cli_sorted_cmd_ptrs*)" runin=".cli_sorted_cmd_ptrs_run"/>
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".fs_data"  inputsections="*(.fs_data*)" runin=".fs_data_run"/>
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".log_dynamic_data"  inputsections="*(SORT(.log_dynamic_data*))" runin=".log_dynamic_data_run"/>
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".log_filter_data"  inputsections="*(SORT(.log_filter_data*))" runin=".log_filter_data_run"/>
        <ProgramSection alignment="4" load="Yes" name=".dtors" />
        <ProgramSection alignment="4" load="Yes" name=".ctors" />
        <ProgramSection alignment="4" load="Yes" name=".rodata" />
        <ProgramSection alignment="4" load="Yes" name=".ARM.exidx" address_symbol="__exidx_start" end_symbol="__exidx_end" />
        <ProgramSection alignment="4" load="Yes" runin=".fast_run" name=".fast" />
        <ProgramSection alignment="4" load="Yes" runin=".data_run" name=".data" />
        <ProgramSection alignment="4" load="Yes" runin=".tdata_run" name=".tdata" />
      <MemorySegment name="RAM" start="$(RAM_PH_START)" size="$(RAM_PH_SIZE)">
        <ProgramSection load="no" name=".reserved_ram" start="$(RAM_PH_START)" size="$(RAM_START)-$(RAM_PH_START)" />
        <ProgramSection alignment="0x100" load="No" name=".vectors_ram" start="$(RAM_START)" address_symbol="__app_ram_start__"/>
        <ProgramSection alignment="4" keep="Yes" load="No" name=".nrf_sections_run" address_symbol="__start_nrf_sections_run" />
        <ProgramSection alignment="4" keep="Yes" load="No" name=".cli_sorted_cmd_ptrs_run" address_symbol="__start_cli_sorted_cmd_ptrs" end_symbol="__stop_cli_sorted_cmd_ptrs" />
        <ProgramSection alignment="4" keep="Yes" load="No" name=".fs_data_run" address_symbol="__start_fs_data" end_symbol="__stop_fs_data" />
        <ProgramSection alignment="4" keep="Yes" load="No" name=".log_dynamic_data_run" address_symbol="__start_log_dynamic_data" end_symbol="__stop_log_dynamic_data" />
        <ProgramSection alignment="4" keep="Yes" load="No" name=".log_filter_data_run" address_symbol="__start_log_filter_data" end_symbol="__stop_log_filter_data" />
        <ProgramSection alignment="4" keep="Yes" load="No" name=".nrf_sections_run_end" address_symbol="__end_nrf_sections_run" />
        <ProgramSection alignment="4" load="No" name=".fast_run" />
        <ProgramSection alignment="4" load="No" name=".data_run" />
        <ProgramSection alignment="4" load="No" name=".tdata_run" />
        <ProgramSection alignment="4" load="No" name=".bss" />
        <ProgramSection alignment="4" load="No" name=".tbss" />
        <ProgramSection alignment="4" load="No" name=".non_init" />
        <ProgramSection alignment="4" size="__HEAPSIZE__" load="No" name=".heap" />
        <ProgramSection alignment="8" size="__STACKSIZE__" load="No" place_from_segment_end="Yes" name=".stack"  address_symbol="__StackLimit" end_symbol="__StackTop"/>
        <ProgramSection alignment="8" size="__STACKSIZE_PROCESS__" load="No" name=".stack_process" />
  • Step 4: Edit the “.emProject” file in a text editor and modify the following
    c_preprocessor_definitions=”BOARD_PCA10056;  to c_preprocessor_definitions=”BOARD_PCA10059;
  • Step 5: In sdk_config.h, make sure that NRF_LOG_BACKEND_UART_ENABLED is disabled
  • Step 6: Switch the selected configuration to “Release”

    Figure 16: Release configuration
  • Step 7: Let’s go ahead and change the advertising name to make it more obvious when we test from the mobile app. Modify the code in main.c:
    #define DEVICE_NAME                     "nRF52840 Dongle"                       /**< Name of device. Will be included in the advertising data. */
  • Step 8: Add macros to define the pin configuration of the LED and push button. As we mentioned in the hardware preparation section above, we’ll be connecting the LED to pin 1.10 and the push button to pin 0.24. To configure this, we define the following macros:
    // External GPIO Button Definitions
    #define EXTERNAL_BUTTON       NRF_GPIO_PIN_MAP(0,24) // Connected to P0.24
    #define MAIN_LED              NRF_GPIO_PIN_MAP(1,10) // Connected to P1.10

For now, we will just define the pins. In the next tutorial, we’ll implement the full implementation code needed to initialize, trigger the LED, monitor the push button, and the remaining functionality of the application.

Building and Flashing the Firmware to the Dongle

By default, the “ble_app_template” example that we used behaves as follows:

  • It advertises as “Nordic_Template” and flashes the onboard green LED while it’s advertising
  • It allows a connection from a BLE Central and turns the green LED solid ON when connected
  • It does not, however, implement any services and characteristics.

We can still test that it’s running correctly on the nRF52840 dongle by observing the green LED behavior and connecting to it from a BLE Central device (a BLE mobile app).

First, build the example from within SES by right-clicking on the Project name in the Project Explorer window and choosing Build.

Once the project is built, now we can go through the steps of flashing the binary to the dongle.

Step 1: Launch the nRF Connect for Desktop application

Figure 17: nRF Connect Desktop

Step 2: Run the Programmer application from within nRF Connect

Figure 18: nRF Connect Programmer

Step 3: While connected to the PC, press the Reset button on the dongle to put it in DFU mode. LED 2 should start flashing Red.

Figure 19: Reset button

Step 4: Click the Select device dropdown menu and you should be able to see a device listed as follows:

Figure 20: Select Device

If you see multiple devices listed, disconnect any other development kits.

Step 5: Once you’ve selected the dongle, you should see the nRF52840 show up with the contents of its memory listed.

Figure 21: Memory of device shows up in Programmer app

Step 6: Now, to flash the dongle we have to first add the hex files to be loaded. We need to add two files:

  • The application hex file. This file is located under <example folder>/pca10059/s140/ses/Output/Release/Exe/
  • The SoftDevice hex file. This file is located under <SDK>/components/softdevice/s140/hex/

Step 7: Once you’ve added the files, you should now see the File Memory Layout show the loaded hex files.

Figure 22: Loaded file overview

Step 8: The final step is to flash the dongle with the loaded files. You do this by pressing the Write button under Device.

Figure 23: Write file(s) option

Once you select Write the left-hand side layout overview will indicate the dongle is being flashed. The log output will also show log messages.

Figure 24: Flashing in progress

Once you flash it, the dongle will exit DFU mode, start the application, and will disappear from the device list and left view.

Figure 25: Flashing completed

Note: remember that the nRF52840 USB Dongle does not have onboard debug capabilities, so I recommend that you verify your application as much as you can on the nRF52840 development kit before moving it over to the dongle.

Testing Functionality

To test the functionality all we want to do is make sure the BLE peripheral can be discovered from a BLE scanning mobile app such as the Nordic nRF Connect (iOS, Android) or the LightBlue Explorer app (iOS, Android).

After flashing the dongle and scanning from the mobile app, we can see that the advertising device shows up in the list. You should also see that the green LED (LED 1) is flashing while advertising.

Figure 26: Dongle found advertising

Once you connect to the device from the mobile app, you’ll see that LED 2 turns solid green.

Figure 27: Dongle connected and LED solid

In the next tutorial, we’ll run more extensive testing once we’ve added our custom service and characteristics, LED control, button presses, etc.


In today’s tutorial, we learned how to develop BLE applications for the nRF52840 USB dongle – which makes an ideal device for prototyping. We covered:

  • Installing the necessary software packages
  • Getting your hardware ready for prototyping on a breadboard
  • Physically connecting the dongle and external peripherals (LED and button) on the breadboard
  • Implementing the firmware modifications necessary to add the external LED and button to the GPIOs of the dongle
  • Building and flashing the application to the dongle
  • Testing the functionality

Next week, we’ll continue this tutorial and implement the full application to allow:

  • Control of an external LED from a BLE central connected to the dongle (the peripheral)
  • Reporting of the button status to a BLE central connected to the dongle

What project would you build using the nRF52840 USB dongle? Or maybe you’re already using it for a project? Let me know in the comments section below.

To download the source code for this post, and be notified when the next blog post publishes, be sure to enter your email address in the form below!



If you would like to download the code used in this post, please enter your email address in the form below. You’ll get a .zip containing all the source code, and I will also send you a FREE 9-page Report on the Essential Bluetooth Developer Tools. In addition to that, you will receive exclusive content, tips, and tricks that I don’t post to the blog!

“Learn The Basics of Bluetooth Low Energy EVEN If You Have No Coding Or Wireless Experience!"

Don't miss out on the latest articles & tutorials. Sign-up for our newsletter today!

Take your BLE knowledge to the next level.

If you’re looking to get access to full video courses covering more topics, then check out the Bluetooth Developer Academy.

As part of all the courses within the Academy, you’ll also be able to download the full source code to use as a reference or use within your own application.

By joining the Bluetooth Developer Academy, you will get access to a growing library of video courses.

The Academy also features access to a private community of Bluetooth experts, developers, and innovators. You’ll get to connect and interact with me and other experts in the Bluetooth space, learn from others’ experiences and knowledge, and share yours as well.

So, what are you waiting for?? Join today!