# Introducing the Adafruit nRF52840 Feather

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/068/633/medium800thumb/circuitpython_ezgif-3-fbb67604c54f.jpg?1546530250)

Warning: 

The **Adafruit Feather nRF52840 Express** is the new Feather family member with Bluetooth Low Energy and _native USB support_ featuring the nRF52840!&nbsp; It's our take on an 'all-in-one' Arduino-compatible + Bluetooth Low Energy with built in USB plus battery charging. With native USB it's even ready to join the CircuitPython party. [We have other boards in the Feather family, check'em out here.](https://www.adafruit.com/feather)

This chip has twice the flash, and four times the SRAM of it's earlier sibling, the nRF52832 - 1 MB of FLASH and 256KB of SRAM. Compared to the nRF51, this board has 4-8 times more of everything.

![](https://cdn-learn.adafruit.com/assets/assets/000/068/596/medium800/circuitpython_4062_iso_ORIG_2018_12.jpg?1546453950)

 **For this chip, we've added Arduino IDE support** - you can program the nRF52840 chip directly to take full advantage of the Cortex-M4 processor, and then calling into the Nordic SoftDevice radio stack when you need to communicate over BLE. Since the underlying API and peripherals are the same for the '832 and '840, you can supercharge your older nRF52832 projects with the same exact code, with a single recompile!

You can also use [MakeCode](https://maker.makecode.com/)'s block-based GUI coding environment on this board.

**We've also chosen this chip for our first BLE-friendly CircuitPython board**! CircuitPython works best with disk drive access, and this is the only BLE-plus-USB-native chip that has the memory to handle running a the little Python interpreter. The massive RAM and speedy Cortex M4F chip makes this a good match.

![](https://cdn-learn.adafruit.com/assets/assets/000/068/595/medium800/circuitpython_4062_iso_demo_ORIG_2018_12.jpg?1546453942)

It's got tons of awesome peripherals: plenty of GPIO, analog inputs, PWM, timers, etc. Best of all, it's got that native USB! Finally, no need for a separate USB serial chip like CP2104 or FT232. Serial is handled as a USB CDC descriptor, and the chip can act like a keyboard, mouse, MIDI device or even disk drive. (Note that we don't have support for anything but CDC for Arduino at this time)

Some other upgrades we've tossed in are an extra 'USER' switch that could be used to trigger OTA updates (or whatever you choose), a NeoPixel LED for status updates, 2 MB of QSPI Flash for storing CircuitPython files, and a SWD connector.

[We have quite a few BTLE-capable Feathers (it's a popular protocol!) so check out our BT Feather guide for some comparison information.](https://learn.adafruit.com/adafruit-feather/bluetooth-feathers)

![](https://cdn-learn.adafruit.com/assets/assets/000/068/598/medium800/circuitpython_4062_quarter_ORIG_2018_12.jpg?1546453964)

We pre-programed the chip with our UF2 bootloader, which can use either commandline UART programming with nrfutil (we use this for Arduino) or drag-n-drop mass storage, for CircuitPython installation and also because mass-storage-drive bootloaders make updating firmware so easy. Want to program the chip directly? You can use our command line tools with your favorite editor and toolchain. If you want to use an SWD programmer/debugger (for even more advanced usage), we have a standard 2x5 0.05" connector.

Best of all, we've done all the heavy lifting&nbsp;of getting the&nbsp;low level BLE stack into shape so you can focus on your project from day one! The example code works great with our existing iOS and Android app.

 **Features:**

- ARM Cortex M4F (with HW floating point acceleration) running at 64MHz
- 1MB flash and 256KB SRAM
- **Native Open Source USB stack** - pre-programmed with UF2 bootloader
- Bluetooth Low Energy compatible 2.4GHz radio (Details available in the&nbsp;[nRF52840](https://www.nordicsemi.com/Products/Low-power-short-range-wireless/nRF52840) product specification)
- **FCC / IC / TELEC certified module**
- Up to +8dBm output power
- 1.7v to 3.3v operation with internal linear and DC/DC voltage regulators
- 21 GPIO, 6 x 12-bit ADC pins, up to 12 PWM outputs (3 PWM modules with 4 outputs each)
- Pin #3 red LED for general purpose blinking, NeoPixel for colorful feedback
- Power/enable pin
- Measures 2.0" x 0.9" x 0.28" (51mm x 23mm x 7.2mm) without headers soldered in
- Light as a (large?) feather - 6 grams
- 4 mounting holes
- Reset button
- SWD connector for debugging
- [Works out of the box with all of our Adafruit FeatherWings!](https://www.adafruit.com/categories/814) (Even the UART-using ones like the GPS FeatherWing)

Bluetooth Low Energy is the hottest new low-power, 2.4GHz spectrum wireless protocol. In particular, it's the only wireless protocol that you can use with iOS without needing special certification, and it's supported by all modern smart phones. This makes it excellent for use in portable projects that will make use of an iOS or Android phone or tablet. It also is supported in Mac OS X and Windows 8+.

To make it easy to use for portable projects, we added a connector for any of our 3.7V Lithium polymer batteries and built in battery charging. You don't need a battery&nbsp;because it will run just fine straight from the micro USB connector. But, if you do have a battery, you can take it on the go, then plug in the USB to recharge. The Feather will automatically switch over to USB power when it's available. We also tied the battery thru a divider to an analog pin, so you can measure and monitor the battery voltage to detect when you need a recharge.

**The Power of Bluefruit LE**

The Bluefruit LE module is an nRF52840 chipset from Nordic, which can be used as both a main microcontroller and a bluetooth low energy interface. For most people, they'll be very happy to use the standard Nordic UART RX/TX connection profile - code is provided! In this profile, the Bluefruit acts as a data pipe, that can 'transparently' transmit back and forth from your iOS or Android device. You can use our&nbsp;[iOS App](https://learn.adafruit.com/bluefruit-le-connect-for-ios)&nbsp;or&nbsp;[Android App](https://play.google.com/store/apps/details?id=com.adafruit.bluefruit.le.connect&hl=en), or&nbsp;[write your own to communicate with the UART service](https://learn.adafruit.com/bluefruit-nrf52-feather-learning-guide/bleuart).

The board is capable of much more than just sending strings over the air! &nbsp;Thanks to an Arduino wrapper library, you have full control over how the device behaves, including the ability to define and manipulate your own&nbsp;[GATT Services&nbsp;and Characteristics](https://learn.adafruit.com/bluefruit-nrf52-feather-learning-guide/blecharacteristic), or&nbsp;change the way that the device advertises itself for other Bluetooth Low Energy devices to see.

&nbsp;

 **Use the Bluefruit App to get your project started**

Using our Bluefruit&nbsp;[iOS App](https://learn.adafruit.com/bluefruit-le-connect-for-ios)&nbsp;or&nbsp;[Android App](https://play.google.com/store/apps/details?id=com.adafruit.bluefruit.le.connect&hl=en), you can quickly get your project prototyped by using your iOS or Android phone/tablet as a controller. We have a&nbsp;[color&nbsp;picker](https://learn.adafruit.com/bluefruit-le-connect-for-ios/controller#color-picker), [quaternion/accelerometer/gyro/magnetometer or location (GPS)](https://learn.adafruit.com/bluefruit-le-connect-for-ios/controller#sensors), and an 8-button&nbsp;[control game pad](https://learn.adafruit.com/bluefruit-le-connect-for-ios/controller#control-pad). This data can be read over BLE and processed directly by the nRF52 microcontroller

Comes fully assembled and tested, with a USB bootloader that lets you quickly use it with the Arduino IDE or to install CircuitPython. We also toss in some header so you can solder it in and plug into a solderless breadboard.&nbsp;**[Lipoly battery](https://www.adafruit.com/categories/138) and [MicroUSB cable](https://www.adafruit.com/index.php?main_page=adasearch&q=microusb%20cable) not included**&nbsp;(but we do have lots of options in the shop if you'd like!)

![](https://cdn-learn.adafruit.com/assets/assets/000/068/597/medium800/circuitpython_4062_kit_ORIG_2018_12.jpg?1546453957)

# Introducing the Adafruit nRF52840 Feather

## Update Bootloader

Warning: 

Older versions of Adafruit's nRF52840 boards were shipped with a bootloader that does not handle large UF2's, including CircuitPython 8.2.0 and later, and has other issues. To check whether you need to update the bootloader, double-click the reset button, and look in the `...BOOT` drive for **INFO\_UF2.TXT**.

Inside that file, check the version number of the bootloader. There are multiple version numbers. Look for the number just after "UF2 Bootloader" on the first line. See the picture below **It should be 0.6.1 or newer**.

![](https://cdn-learn.adafruit.com/assets/assets/000/129/812/medium800/circuitpython_nrf52-bootloader-version-number.png?1714684011)

The Adafruit nRF52 Bootloader can be upgraded/downgraded without any additional hardware. There are 3 different ways to update the bootloader, each has its pros and cons:

Warning: You **cannot** use the UF2 updater if your existing bootloader is version 0.3.x or earlier. You must use Arduino IDE or the Command Line.

- **Use UF2:&nbsp;** This is the fastest and safest way to update bootloader. However, it requires your existing bootloader version is at least **0.4.0&nbsp;** and only work with nRF52840 (not nRF52832).
- **Use Arduino IDE** : work with all Adafruit nRF52 boards and bootloader version, typo free but may not be the latest bootloader version due to the BSP release cycle.
- **Use Command Line** : work with all boards and bootloader version (including 3rd party one). This command line uses the back-end of the Arduino IDE method above.&nbsp;

# Introducing the Adafruit nRF52840 Feather

## Use UF2

This is the fastest and safest way to update bootloader. However, it requires your existing bootloader is at least **0.4.0&nbsp;** and only work with nRF52840 (not nRF52832) since UF2 make use of USB MSC interface.

Danger: You **cannot** use the UF2 updater if your existing bootloader is version 0.3.x or earlier. You must use Arduino IDE or the Command Line.

## Download update-bootloader UF2

You need a .`uf2` file containing the latest version of the bootloader. The most common updaters are linked below. For updaters for other boards, look for the [.uf2 files here](https://github.com/adafruit/Adafruit_nRF52_Bootloader/releases/latest) that begin with **update-...**

Info: Note if you click the link above, you must scroll down to the UF2 files that begin with the word update as the zip files do not include UF2s. Most users will click the appropriate green button below to select the file for their board.

[Feather nRF52840 Express bootloader updater UF2](https://github.com/adafruit/Adafruit_nRF52_Bootloader/releases/latest/update-feather_nrf52840_express_bootloader-*_nosd.uf2)
[Circuit Playground Bluefruit bootloader updater UF2](https://github.com/adafruit/Adafruit_nRF52_Bootloader/releases/latest/update-circuitplayground_nrf52840_bootloader-*_nosd.uf2)
[ItsyBitsy nRF52840 bootloader updater UF2](https://github.com/adafruit/Adafruit_nRF52_Bootloader/releases/latest/update-itsybitsy_nrf52840_express_bootloader-*_nosd.uf2)
[CLUE nRF52840 bootloader updater UF2](https://github.com/adafruit/Adafruit_nRF52_Bootloader/releases/latest/update-clue_nrf52840_bootloader-*_nosd.uf2)
[Feather Sense nRF52840 bootloader updater UF2](https://github.com/adafruit/Adafruit_nRF52_Bootloader/releases/latest/update-feather_nrf52840_sense_bootloader-*_nosd.uf2)
## Enter Bootloader Mode

Double-click the&nbsp; **Reset&nbsp;** button on your board, and you will see the NeoPixel RGB LED turn green (identified by the arrow in the image). If it turns red, check the USB cable, try another USB port, etc.

**Note:** on **nRF52840 USB Key with TinyUF2 (PID 5199)** you need to hold its button while plugging into your PC.

## Drag & Drop UF2

You will see a new **BOOT** disk drive appear e.g **FTHR840BOOT**. Drag the downloaded **.** `uf2`&nbsp;file to **FTHR840BOOT.&nbsp;** The LED will flash. Then, the&nbsp; **FTHR840BOOT** drive will disappear. That's it, you have successfully update your board to the latest version.&nbsp;&nbsp;&nbsp;

![](https://cdn-learn.adafruit.com/assets/assets/000/107/816/medium800/circuitpython_update_bootloader_uf2.png?1642140755)

## Issues

If you download the wrong UF2 file for your board, dragging the file to the **...BOOT** drive will close the drive but will not update the firmware (as it is the firmware for the wrong board). You can check the **INFO\_UF2.TXT** on the board and see if the firmware was updated (likely with the wrong UF2 file it was not).&nbsp;

If you cannot find the correct UF2 check all the files in [https://github.com/adafruit/Adafruit\_nRF52\_Bootloader/releases](https://github.com/adafruit/Adafruit_nRF52_Bootloader/releases) for the correct UF2 (they all start with the word `update-boardname-bootloader-version.uf2` so scroll the list down to the files starting with u.

Non Adafruit board firmware updates can be found using this method also.

# Introducing the Adafruit nRF52840 Feather

## Use Arduino IDE

Arduino IDE **Burn Bootloader** menu option will pick the correct bootloader binary for your selected board and prevent any command typos or other common errors.

Danger: 

Info: 

Pink: If you have previously installed CircuitPython on the board, double click the reset button prior to flashing the firmware to put it in bootloader mode.

If you have not already done so, set up Arduino IDE for nRF52, using the instructions in [Arduino Support Setup](https://learn.adafruit.com/adafruit-circuit-playground-bluefruit/arduino-support-setup).

Make sure no other program is attached to the serial port on the board, such as Mu, the Serial Monitor in Arduino, or a terminal program. Then, to start, select the correct board you are using under **Tools -\> Board**

![](https://cdn-learn.adafruit.com/assets/assets/000/107/810/medium800/circuitpython_update_bootloader_arduino.png?1642132225)

Then select " **Bootloader DFU for Bluefruit nRF52**" for **Tools-\>Programmer**

![](https://cdn-learn.adafruit.com/assets/assets/000/107/814/medium800/circuitpython_update_bootloader_arduino_2.png?1642132445)

 **Double check all of the following: Board, Programmer...**

Then select **Tools-\>Burn Bootloader** to start the upgrade.

![](https://cdn-learn.adafruit.com/assets/assets/000/107/815/medium800/circuitpython_update_bootloader_arduino_3.png?1642132501)

After receiving the new Bootloader over the serial connection, the old Bootloader will erase itself! The new bootloader will then be flashed. The process typically takes 30-60 seconds to complete. Make sure you see the " **Device programmed**" in the output log before launching Serial monitor or uploadinga new sketch.

```terminal
Upgrading target on /dev/ttyACM0 with DFU package /Adafruit_nRF52_Arduino/bootloader/feather_nrf52840_express/feather_nrf52840_express_bootloader-0.6.2_s140_6.1.1.zip. Flow control is disabled, Dual bank, Touch 1200
Touched serial port /dev/ttyACM0
Opened serial port /dev/ttyACM0
Starting DFU upgrade of type 3, SoftDevice size: 151016, bootloader size: 39000, application size: 0
Sending DFU start packet
Sending DFU init packet
Sending firmware file
########################################
########################################
########################################
########################################
########################################
########################################
########################################
########################################
########################################
############
Activating new firmware

DFU upgrade took 20.50154972076416s
Device programmed.
```

Drawbacks of this method are that you will need to install the Arduino IDE, and the bundled bootloader may not be the latest one. Check out the next page for a more advanced command line version.

# Introducing the Adafruit nRF52840 Feather

## Use Command Line

Info: 

## Download Bootloader Package

To update the bootloader you need a **.zip** file containing the latest version of the bootloader. The most common bootloader **.zip** files are linked below. For **.zip** files for other boards, look for the [.zip files here](https://github.com/adafruit/Adafruit_nRF52_Bootloader/releases/latest) that begin with the name of the board you want to update.

Info: Pick the download below for the board that you have. If you have a different board, look for the right .zip file for the board you have at the link just above.

[Bootloader .zip package for Adafruit Feather nRF52840 (latest version)](https://github.com/adafruit/Adafruit_nRF52_Bootloader/releases/latest/feather_nrf52840_express_bootloader-*.zip)
[Bootloader .zip package for Adafruit Feather nRF52840 Sense (latest version)](https://github.com/adafruit/Adafruit_nRF52_Bootloader/releases/latest/feather_nrf52840_sense_bootloader-*.zip)
[Bootloader .zip package for Adafruit CLUE (latest version)](https://github.com/adafruit/Adafruit_nRF52_Bootloader/releases/latest/clue_nrf52840_bootloader-*.zip)
[Bootloader .zip package for Circuit Playground Bluefruit (latest version)](https://github.com/adafruit/Adafruit_nRF52_Bootloader/releases/latest/circuitplayground_nrf52840_bootloader-*.zip)
[Bootloader .zip package for Adafruit ItsyBitsy nRF52840 (latest version)](https://github.com/adafruit/Adafruit_nRF52_Bootloader/releases/latest/itsybitsy_nrf52840_express_bootloader-*.zip)
Warning: 

## Download **adafruit-nrfutil**

You will also need the utility program **adafruit-nrfutil,** which has slightly different names on different platforms.

### **adafruit-nrfutil** for Linux

On Linux, you can download and install **adafruit-nrfutil** &nbsp;by doing:

```terminal
pip3 install --user adafruit-nrfutil
```

### **adafruit-nrfutil** for macOS

On macOS, if you have **python3** and **pip3** installed, you can install via **pip3** , as above for Linux. Otherwise download the zip file **adafruit-nrfutil-macos...zip** from the link below, and then extract the file&nbsp; **adafruit-nrfutil** from the zip file.

[adafruit-nrfutil-macos for MacOS (in .zip file)](https://github.com/adafruit/Adafruit_nRF52_nrfutil/releases/latest/adafruit-nrfutil-*-macos.zip)
Then make **adafruit-nrfutil** &nbsp;executable by doing:

```terminal
chmod +x adafruit-nrfutil
```

### **adafruit-nrfutil** for Windows

Download the .zip file&nbsp;from this link, and extract the file **adafruit-nrfutil.exe**.

[adafruit-nrfutil.exe for Windows (in .zip file)](https://github.com/adafruit/Adafruit_nRF52_nrfutil/releases/latest/adafruit-nrfutil-*-win.zip)
## Update Bootloader

To update the bootloader, first connect the board, and then double-click the RESET button to get the ... **BOOT** drive to appear.

Info: 

### Updating on Linux

Run a command similar to the one below in a shell window. **Substitute the name of the .zip file you downloaded above for the file given below**.

```terminal
adafruit-nrfutil --verbose dfu serial --package feather_nrf52840_express_bootloader-0.8.0_s140_6.1.1.zip -p /dev/ttyACM0 -b 115200 --singlebank --touch 1200
```

### Updating on macOS

Find out the device name for the connected board, by doing:

```terminal
ls /dev/cu.*
```

The device name will be something like `/dev/cu.usbmodem411`. Use this command, substituting the device name you've discovered. **Substitute the name of the .zip file you downloaded above for the file given below**. and the name of the .zip package you downloaded above. If you are running it other than where you downloaded **adafruit-nrfutil-macos** , change the path to the command accordingly. If you installed it via pip3, it's just called **adafruit-nrfutil** , and it should be in your `PATH`.

```terminal
./adafruit-nrfutil-macos --verbose dfu serial --package feather_nrf52840_express_bootloader-0.8.0_s140_6.1.1.zip -p /dev/cu.usbmodem411 -b 115200 --singlebank --touch 1200
```

### Updating on Windows

Use this command in the folder where you downloaded the other two files above. You'll need to specify the correct COM port, instead of `COMxx`. Look in **Device Manager-\>Ports** for the name of the COM port (it will be listed as a "USB Serial Device" on Windows 10) after you have double-clicked the RESET button. **Substitute the name of the .zip file you downloaded above for the file given below**.

```terminal
adafruit-nrfutil.exe --verbose dfu serial --package feather_nrf52840_express_bootloader-0.8.0_s140_6.1.1.zip --port COMxx -b 115200 --singlebank --touch 1200
```

### Output when Updating

When you run the **adafruit-nrfutil** program, you will see output similar to this (it will vary slightly depending on your OS).

```terminal
Upgrading target on COM29 with DFU package C:\Users\halbe\Desktop\update-feather-nrf52840-bootloader-0.8.0-windows\feather_nrf52840_express_bootloader-0.8.0_s140_6.1.1.zip. Flow control is disabled, Single bank, Touch 1200
Touched serial port COM29
Opened serial port COM29
Starting DFU upgrade of type 3, SoftDevice size: 151016, bootloader size: 39000, application size: 0
Sending DFU start packet
Sending DFU init packet
Sending firmware file
########################################
########################################
########################################
########################################
########################################
########################################
########################################
########################################
########################################
############
Activating new firmware

DFU upgrade took 21.119003295898438s
Device programmed.
```

Once done, click the RESET button again - the bootloader will be running!

# Introducing the Adafruit nRF52840 Feather

## Pinouts

![](https://cdn-learn.adafruit.com/assets/assets/000/068/578/medium800/circuitpython_Screenshot_2019-01-02_at_12.04.27.png?1546446487)

Warning: 

![](https://cdn-learn.adafruit.com/assets/assets/000/114/673/medium800/circuitpython_Adafruit_Feather_nRF52840_Pinout.png?1662064111)

[Click here to view a PDF version of the pinout diagram](https://github.com/adafruit/Adafruit-nRF52-Bluefruit-Feather-PCB/blob/master/Adafruit%20Feather%20nRF52840%20pinout.pdf)

# Special Notes

The following pins have some restrictions that need to be taken into account when using them:

- **D2/NFC2** : The D2 pin is uses the same pad as one-half of the NFC antenna pins. By default, the nRF52840 Feather ships with these pins configured for GPIO mode, which is done by writing a value to the UICR flash config memory. If you wish to use NFC, you will need to erase the UICR memory which requires erasing the entire chip, and you will need a [Segger J-Link](https://www.adafruit.com/product/3571) to reflash the bootloader and firmware.

# Power Pins

- **3V** : This pin is connected to the output of the on board 3.3V regulator. It can be used to supply 3.3V power to external sensors, breakouts or Feather Wings.
- **LIPO Input (Bat)**: This is the voltage supply off the optional LIPO cell that can be connected via the JST PH connector. It is nominally ~3.5-4.2V.
- **VREG Enable (En)**: This pin can be set to GND to disable the 3.3V output from the on board voltage regulator. By default it is set high via a pullup resistor.
- **USB Power&nbsp;(USB)**: This is the voltage supply off USB connector, nominally 4.5-5.2V.

![](https://cdn-learn.adafruit.com/assets/assets/000/068/617/medium800/circuitpython_nRF52840_Power.png?1546459953)

# Analog Inputs

The **6** available analog inputs ( **A0 .. A5** ) can be configured to generate 8, 10 or 12-bit data (or 14-bits with over-sampling), at speeds up to 200kHz (depending on the bit-width of the values generated), based on either an internal 0.6V reference or the external supply.

The following default values are used for Arduino. See this guide's [nRF52 ADC page](https://learn.adafruit.com/introducing-the-adafruit-nrf52840-feather/nrf52-adc) for details about changing these settings.

- **Default voltage range** : 0-3.6V (uses the internal 0.6V reference with 1/6 gain)
- **Default resolution** : 12-bit (0..4096)
- **Default mV per lsb** (assuming 3.6V and 12-bit resolution): **1 LSB = 0.87890625 mV**

CircuitPython uses 1/4 gain with a VDD/4 reference voltage.

An additional two ADC pins are available but pre-connected to provide specific functionality:

- **AREF** ( **A7 / P0.31** ), which can be used as an optional external analog reference for the internal comparator (COMP) peripheral. AREF is not available for use with the ADC. This pin can be accessed in code via **PIN\_AREF** or&nbsp; **A7**. If using an external AREF, this&nbsp; **must be less than or equal to VDD** , which is usually 3.3V!
- **VDIV (A6 / P0.29)**: This pin is hard wired to a voltage-divider on the LIPO battery input, allowing you to safely measure the LIPO battery level on your device. This pin is not broken out to the edge of the board.

Danger: 

Info: 

# PWM Outputs

Any GPIO pin can be configured as a PWM output, using the dedicated PWM block.

Three PWM modules can provide up to 12 PWM channels with individual frequency control in groups of up to four channels.

# I2C Pins

I2C pins on the nRF52840 require external pullup resistors to function, which are not present on the Adafruit nRF52840 Feather by default. You will need to supply external pullups to use these. All Adafruit I2C breakouts have appropriate pullups on them already, so this normally won't be an issue for you.

# User/DFU Switch

A tactile switch is provided for use in your projects, which is connected to&nbsp;P1.02&nbsp;and is accessible in code as&nbsp; **D7** in Arduino and **SWITCH** in CircuitPython.

Holding this button down coming out of a board reset will also force the device to enter and remain in USB bootloader mode, which can be useful if you lock your board up with bad application code!

![](https://cdn-learn.adafruit.com/assets/assets/000/068/613/medium800/circuitpython_nRF52840_USERSW.png?1546458847)

# SWD Connector

For advanced debugging or to reprogram your nRF52840 Feather Express, a 2\*5 pin 0.05" standard SWD header is populated on the boards. This allows you to use something like a [Segger J-Link](https://www.adafruit.com/product/3571) and a [1.27mm SWD cable](https://www.adafruit.com/product/1675) to connect from your PC to the nRF52840.

![](https://cdn-learn.adafruit.com/assets/assets/000/068/611/medium800/circuitpython_nRF52840_SWD.png?1546458624)

# LEDs

There are numerous LEDs available on the nRF52840 Feather Express which can be used as status indicators, or be placed under user control in your application:

## Basic LEDs

There are three basic LEDs available on the nRF52840 Feather Express:

![](https://cdn-learn.adafruit.com/assets/assets/000/068/614/medium800/circuitpython_nRF52840_LEDs.png?1546459086)

- **D3** is a general-purpose RED LED that can be used for blinky, or other purposes. When running in bootloader mode it is used under the control of the bootloader as a status indicator, with a rapid blinky pattern indicating that the board is currently in DFU bootloader mode. This LED is on **D3** (or&nbsp;**P1.15)**. Programmatically you can access this LED as **LED\_RED**.
- **CONN** can be used as a general-purpose BLUE LED, but is generally controlled by the examples to indicate connection status for BLE. This LED is on **P1.10**. Programmatically you can access this LED as **LED\_BLUE**.
- **CHG** indicates that the on-board LIPO charger is currently charging the connected LIPO battery cell, using USB as a power supply.

## RGB NeoPixel

In addition to the basic LEDs, there is also a single&nbsp; **RGB NeoPixel** (connected to&nbsp; **P0.16** ), which can be programmatically access as&nbsp; **PIN\_NEOPIXEL**.

![](https://cdn-learn.adafruit.com/assets/assets/000/068/615/medium800/circuitpython_nRF52840_Neopixel.png?1546459489)

# 16MBit (2MB) QSPI Flash

Since this board is part of the&nbsp; **Express** family for&nbsp; **CircuitPython** , a 2MB Quad-SPI flash is also included on the board by default. QSPI requires 6 pins, which are not broken out on the 0.1" pin headers to avoid conflicts.

QSPI is neat because it allows you to have 4 data in/out lines instead of just SPI's single line in and single line out. This means that QSPI is&nbsp;_at least_&nbsp;4 times faster. But in reality is at least 10x faster because you can clock the QSPI peripheral much faster than a plain SPI peripheral

![](https://cdn-learn.adafruit.com/assets/assets/000/068/616/medium800/circuitpython_nRF52840_QSPI.png?1546459842)

# Introducing the Adafruit nRF52840 Feather

## Power Management

![](https://cdn-learn.adafruit.com/assets/assets/000/113/597/medium800/sensors_image.png?1658941319)

# Battery + USB Power

We wanted to make our Feather boards easy to power both when connected to a computer as well as via battery.

There's **two ways to power** a Feather:

1. You can connect with a USB cable (just plug into the jack) and the Feather will regulate the 5V USB down to 3.3V.
2. You can also connect a 4.2/3.7V Lithium Polymer (LiPo/LiPoly) or Lithium Ion (LiIon) battery to the JST jack. This will let the Feather run on a rechargeable battery.

**When the USB power is powered, it will automatically switch over to USB for power, as well as start charging the battery (if attached).** This happens 'hot-swap' style so you can always keep the LiPoly connected as a 'backup' power that will only get used when USB power is lost.

Danger: 

![](https://cdn-learn.adafruit.com/assets/assets/000/113/598/medium800/sensors_Feather_Sense_pinouts_USB_battery.png?1658941358)

The above shows the Micro USB jack (left), LiPoly JST jack (top left), as well as the changeover diode (just to the right of the JST jack) and the LiPoly charging circuitry (to the right of the JST jack).

There's also a **CHG** LED next to the USB jack, which will light up while the battery is charging. This LED might also flicker if the battery is not connected, it's normal.

Info: 

# Power Supplies

You have a lot of power supply options here! We bring out the **BAT** pin, which is tied to the LiPoly JST connector, as well as **USB** which is the +5V from USB if connected. We also have the **3V** pin which has the output from the 3.3V regulator. We use a 500mA peak regulator. While you can get 500mA from it, you can't do it continuously from 5V as it will overheat the regulator.

It's fine for, say, powering an ESP8266 WiFi chip or XBee radio though, since the current draw is 'spikey' & sporadic.

![](https://cdn-learn.adafruit.com/assets/assets/000/113/599/medium800/sensors_Feather_Sense_pinouts_power_pins.png?1658941482)

# Measuring Battery

If you're running off of a battery, chances are you wanna know what the voltage is at! That way you can tell when the battery needs recharging. LiPoly batteries are 'maxed out' at 4.2V and stick around 3.7V for much of the battery life, then slowly sink down to 3.2V or so before the protection circuitry cuts it off. By measuring the voltage you can quickly tell when you're heading below 3.7V.

To make this easy we stuck a double-100K resistor divider on the&nbsp; **BAT** &nbsp;pin, and connected it to&nbsp; **A6** &nbsp;which is not exposed on the feather breakout

In Arduino, you can read this pin's voltage, then double it, to get the battery voltage.

```cpp
// Arduino Example Code snippet

#define VBATPIN A6

float measuredvbat = analogRead(VBATPIN);
measuredvbat *= 2;    // we divided by 2, so multiply back
measuredvbat *= 3.6;  // Multiply by 3.6V, our reference voltage
measuredvbat /= 1024; // convert to voltage
Serial.print("VBat: " ); Serial.println(measuredvbat);
```

For CircuitPython, we've written a&nbsp;`get_voltage()`&nbsp;helper function to do the math for you. All you have to do is call the function, provide the pin and print the results.

```cpp
import board
from analogio import AnalogIn

vbat_voltage = AnalogIn(board.VOLTAGE_MONITOR)


def get_voltage(pin):
    return (pin.value * 3.6) / 65536 * 2


battery_voltage = get_voltage(vbat_voltage)
print("VBat voltage: {:.2f}".format(battery_voltage))
```

# ENable pin

If you'd like to turn off the 3.3V regulator, you can do that with the **EN** (able) pin. Simply tie this pin to **Ground** and it will disable the 3V regulator. The **BAT** and **USB** pins will still be powered.

![](https://cdn-learn.adafruit.com/assets/assets/000/113/600/medium800/sensors_arduino_compatibles_en.jpg?1658941554)

# Alternative Power Options

The two primary ways for powering a feather are a 3.7/4.2V LiPo battery plugged into the JST port _or_ a USB power cable.

If you need other ways to power the Feather, here's what we recommend:

- For permanent installations, a [5V 1A USB wall adapter](https://www.adafruit.com/product/501) will let you plug in a USB cable for reliable power
- For mobile use, where you don't want a LiPoly, [use a USB battery pack!](https://www.adafruit.com/product/1959)
- If you have a higher voltage power supply, [use a 5V buck converter](https://www.adafruit.com/?q=5V%20buck) and wire it to a [USB cable's 5V and GND input](https://www.adafruit.com/product/3972)

Here's what you cannot do:

- **Do not use alkaline or NiMH batteries** and connect to the battery port - this will destroy the LiPoly charger
- **Do not use 7.4V RC batteries on the battery port** - this will destroy the board

The Feather _is not designed for external power supplies_ - this is a design decision to make the board compact and low cost. It is not recommended, but technically possible:

- **Connect an external 3.3V power supply to the 3V and GND pins.** Not recommended, this may cause unexpected behavior and the **EN** pin will no longer work. Also this doesn't provide power on **BAT** or **USB** and some Feathers/Wings use those pins for high current usages. You may end up damaging your Feather.
- **Connect an external 5V power supply to the USB and GND pins.** Not recommended, this may cause unexpected behavior when plugging in the USB port because you will be back-powering the USB port, which _could_ confuse or damage your computer.

# Introducing the Adafruit nRF52840 Feather

## Assembly

We ship Feathers fully tested but without headers attached - this gives you the most flexibility on choosing how to use and configure your Feather

# Header Options!

Before you go gung-ho on soldering, there's a few options to consider!

The first option is soldering in plain male headers, this lets you plug in the Feather into a solderless breadboard

![feather_3010-05.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/192/medium640/feather_3010-05.jpg?1454100293)

![feather_3010-01.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/201/medium640/feather_3010-01.jpg?1454100690)

Another option is to go with socket female headers. This won't let you plug the Feather into a breadboard but it will let you attach featherwings very easily

A few Feather boards require access to top-side components like buttons or connectors, making stacking impractical. Sometimes you can stack in the opposite order—FeatherWing underneath—or, if _both_ Feather and Wing require top-side access,&nbsp;place the boards side-by-side with a [FeatherWing Doubler](https://www.adafruit.com/product/2890) or [Tripler](https://www.adafruit.com/product/3417).

![feather_2886-01.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/195/medium640/feather_2886-01.jpg?1454100431)

![feather_2886-02.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/196/medium640/feather_2886-02.jpg?1454100477)

![adafruit_products_2890-02.jpg](https://cdn-learn.adafruit.com/assets/assets/000/117/300/medium640/adafruit_products_2890-02.jpg?1672855047)

We also&nbsp; have 'slim' versions of the female headers, that are a little shorter and give a more compact shape

![feather_2940-01.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/197/medium640/feather_2940-01.jpg?1454100533)

![feather_2940-04.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/198/medium640/feather_2940-04.jpg?1454100544)

Finally, there's the "Stacking Header" option. This one is sort of the best-of-both-worlds. You get the ability to plug into a solderless breadboard _and_ plug a featherwing on top. But its a little bulky

![feather_2830-01.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/199/medium640/feather_2830-01.jpg?1454100588)

![feather_2830-00.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/200/medium640/feather_2830-00.jpg?1454100660)

# Soldering in Plain Headers
## Prepare the header strip:

Cut the strip to length if necessary. It will be easier to solder if you insert it into a breadboard - **long pins down**

![feather_headers.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/183/medium640/feather_headers.jpg?1454099573)

## Add the breakout board:

Place the breakout board over the pins so that the short pins poke through the breakout pads

## And Solder!

Be sure to solder all pins for reliable electrical contact.  
  
_(For tips on soldering, be sure to check out our_ [_Guide to Excellent Soldering_](http://learn.adafruit.com/adafruit-guide-excellent-soldering)_)._

![feather_solder1.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/184/medium640/feather_solder1.jpg?1454099592)

![feather_solder2.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/185/medium640/feather_solder2.jpg?1454099649)

![feather_solder3.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/186/medium640/feather_solder3.jpg?1454099655)

Solder the other strip as well.

![feather_solder4.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/187/medium640/feather_solder4.jpg?1454099662)

![feather_solder5.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/188/medium640/feather_solder5.jpg?1454099665)

![feather_solder6.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/189/medium640/feather_solder6.jpg?1454099667)

You're done! Check your solder joints visually and continue onto the next steps

![feather_done.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/190/medium640/feather_done.jpg?1454099807)

# Soldering on Female Header
## Tape In Place

For sockets you'll want to tape them in place so when you flip over the board they don't fall out

![feather_taped.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/203/medium640/feather_taped.jpg?1454101091)

## Flip & Tack Solder

After flipping over, solder one or two points on each strip, to 'tack' the header in place

![feather_tack1.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/204/medium640/feather_tack1.jpg?1454101126)

![feather_tack2.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/205/medium640/feather_tack2.jpg?1454101143)

![feather_tack3.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/206/medium640/feather_tack3.jpg?1454101147)

## And Solder!

Be sure to solder all pins for reliable electrical contact.  
  
_(For tips on soldering, be sure to check out our_ [_Guide to Excellent Soldering_](http://learn.adafruit.com/adafruit-guide-excellent-soldering)_)._

![feather_soldre1.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/207/medium640/feather_soldre1.jpg?1454101162)

![feather_solder2.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/208/medium640/feather_solder2.jpg?1454101165)

![feather_solder3.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/209/medium640/feather_solder3.jpg?1454101168)

You're done! Check your solder joints visually and continue onto the next steps

![feather_soldered.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/210/medium640/feather_soldered.jpg?1454101174)

![feather_done.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/211/medium640/feather_done.jpg?1454101177)

# Introducing the Adafruit nRF52840 Feather

## Arduino Support Setup

You can&nbsp;install the Adafruit Bluefruit nRF52 BSP (Board Support Package) in two steps:

Danger: 

Danger: 

# 1. BSP Installation

### Recommended: Installing the BSP&nbsp;via the Board Manager

- [Download and install the Arduino IDE](https://www.arduino.cc/en/Main/Software) (At least **v1.8** )
- Start the Arduino IDE
- Go into Preferences
- Add `https://adafruit.github.io/arduino-board-index/package_adafruit_index.json`&nbsp;as an ' **Additional Board Manager URL**' (see image below)

![](https://cdn-learn.adafruit.com/assets/assets/000/108/459/medium800/microcontrollers_arduino-preferences-highlight-url.png?1643388037)

- Restart the Arduino IDE
- Open the **Boards Manager** &nbsp;option from the **Tools -\> Board** menu and install ' **Adafruit nRF52 by Adafruit**' (see image below)

![](https://cdn-learn.adafruit.com/assets/assets/000/039/907/medium800/microcontrollers_nRF52BSP.png?1488964156)

It will take up to a few minutes to finish installing the cross-compiling toolchain and tools associated with this BSP.

**The delay during the installation stage shown in the image below is normal** , please be patient and let the installation terminate normally:

![](https://cdn-learn.adafruit.com/assets/assets/000/040/938/medium800/microcontrollers_Screen_Shot_2017-04-19_at_20.23.20.png?1492626239)

Once the BSP is installed, select

- **Adafruit Bluefruit nRF52832 Feather** (for the nRF52 Feather)
- **Adafruit Bluefruit nRF52840 Feather Express** (for the nRF52840 Feather)
- **Adafruit ItsyBitsy nRF52840** (for the Itsy '850)
- **Adafruit Circuit Playground Bluefruit** (for the CPB)
- etc...

from the **Tools -\> Board** menu, which will update your system config to use the right compiler and settings for the nRF52:

![](https://cdn-learn.adafruit.com/assets/assets/000/094/506/medium800/microcontrollers_image.png?1598977463)

# 2. LINUX ONLY: adafruit-nrfutil Tool Installation

[adafruit-nrfutil](https://github.com/adafruit/Adafruit_nRF52_nrfutil)&nbsp;is a **&nbsp;modified version** &nbsp;of [Nordic's nrfutil](https://github.com/NordicSemiconductor/pc-nrfutil), which is used to flash boards using the built in serial bootloader. It is originally written for Python 2, but have been migrated to Python 3 and renamed to&nbsp; **adafruit-nrfutil** &nbsp;since BSP version 0.8.5.

Warning: 

Install Python 3 if it is not installed in your system already

```
$ sudo apt-get install python3
```

Then run the following command to install the tool from PyPi

```
$ pip3 install --user adafruit-nrfutil
```

Add pip3 installation dir to your **PATH** if it is not added already. Make sure adafruit-nrfutil can be executed in terminal by running

```
$ adafruit-nrfutil version
adafruit-nrfutil version 0.5.3.post12
```

# 3. Update the bootloader (nRF52832 ONLY)

To keep up with Nordic's SoftDevice advances, you will likely need to update your bootloader if you are using the original nRF52832 based&nbsp; **Bluefruit nRF52 Feather** boards.

Follow this link for instructions on how to do that

Info: 

[Update the nRF52832 Bootloader](https://learn.adafruit.com/bluefruit-nrf52-feather-learning-guide/updating-the-bootloader)
# Advanced Option: Manually Install the BSP via 'git'

If you wish to do any development against the core codebase (generate pull requests, etc.), you can also optionally install the Adafruit nRF52 BSP manually using 'git', as decribed below:

### Adafruit nRF52 BSP via git (for core development and PRs only)

1. Install BSP via Board Manager as above to install compiler & tools.
2. Delete the core folder **nrf52** installed by Board Manager in Adruino15, depending on your OS. It could be  
**macOS** :&nbsp;`~/Library/Arduino15/packages/adafruit/hardware/nrf52` **Linux** :&nbsp;`~/.arduino15/packages/adafruit/hardware/nrf52` **Windows** :&nbsp;`%APPDATA%\Local\Arduino15\packages\adafruit\hardware\nrf52`
3. Go to&nbsp;the sketchbook folder on your command line, which should be one of the following:  
**macOS** : `~/Documents/Arduino` **Linux** : `~/Arduino` **Windows** : `~/Documents/Arduino`
4. Create a folder named `hardware/Adafruit`, if it does not exist, and change directories into it.
5. Clone the [Adafruit\_nRF52\_Arduino](https://github.com/adafruit/Adafruit_nRF52_Arduino) repo in the folder described in step 2:   
`git clone --recurse-submodules git@github.com:adafruit/Adafruit_nRF52_Arduino.git`
6. This should result in a final folder name like `~/Documents/Arduino/hardware/Adafruit/Adafruit_nRF52_Arduino`&nbsp;(macOS).

7. Restart the Arduino IDE

# Introducing the Adafruit nRF52840 Feather

## Arduino Board Testing

Info: 

Once you have the Bluefruit nRF52 BSP setup on your system, you need to select the appropriate board, which will determine the compiler and expose some new menus options:

# 1. Select the Board Target

- Go to the&nbsp; **Tools** menu
- Select&nbsp; **Tools \> Board \> Adafruit Bluefruit nRF52 Feather** for&nbsp; **nRF52832-based boards**
- Select&nbsp; **Tools \> Board \> Adafruit Bluefruit nRF52840 Feather Express** for&nbsp; **nRF52840-based boards**
- Select **Tools \> Board \> Adafruit CLUE** for the **Adafruit CLUE**

![](https://cdn-learn.adafruit.com/assets/assets/000/068/538/medium800/microcontrollers_Screenshot_2019-01-01_at_12.59.47.png?1546364737)

# 2. Select the USB CDC Serial Port

Finally, you need to set the serial port used by Serial Monitor and the serial bootloader:

- Go to **Tools** \> **Port** and select the appropriate device

![](https://cdn-learn.adafruit.com/assets/assets/000/110/248/medium800/microcontrollers_Screen_Shot_2022-03-28_at_15.29.45.png?1648456240)

## 2.1 Download & Install CP2104 Driver (nRF52832)

For Feather nRF52832 If you don't see the serial ports device listed, you may need to install the [SiLabs CP2104 driver](https://www.silabs.com/developers/usb-to-uart-bridge-vcp-drivers?tab=downloads) on your system.

On MacOS&nbsp;If you see this dialog message while installing driver

On MacOS If you see this dialog message while installing driver, **System Extension Blocked**

&nbsp;

And cannot find the serial port of CP2104, it is highly possible that driver is blocked.

![microcontrollers_tn2459_blocked.png](https://cdn-learn.adafruit.com/assets/assets/000/055/243/medium640/microcontrollers_tn2459_blocked.png?1545931975)

To enable it go to **System Preferences -\> Security & Privacy** and click allow if you see Silab in the developer name.

![microcontrollers_tn2459_approval.png](https://cdn-learn.adafruit.com/assets/assets/000/055/242/medium640/microcontrollers_tn2459_approval.png?1532011025)

Info: 

## 2.2 Download & Install Adafruit Driver (nRF52840 Windows)

For Feather nRF52840, If you are using Windows, you will need to follows&nbsp;[Windows Driver Installation](https://learn.adafruit.com/adafruit-arduino-ide-setup/windows-driver-installation%C2%A0)&nbsp;to download and install driver.

# 3. Update the bootloader (nRF52832 Feather Only)

To keep up with Nordic's SoftDevice advances, you will likely need to update your bootloader

Follow this link for instructions on how to do that

Info: 

[Update the Bootloader](https://learn.adafruit.com/bluefruit-nrf52-feather-learning-guide/updating-the-bootloader)
# 4. Run a Test Sketch

At this point, you should be able to run a test sketch from the&nbsp; **Examples** folder, or just flash the following blinky code from the Arduino IDE:

Info: 

```auto
#if defined(USE_TINYUSB)
#include &lt;Adafruit_TinyUSB.h&gt; // for Serial
#endif

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
}
```

This will blink the red LED beside the USB port on the Feather, or the red LED labeled "LED" by the corner of the USB connector on the CLUE.

### 

If the sketch fails to compile and reports an error message like this:

`collect2.exe: error: ld returned 1 exit status`

`exit status 1`

`Compilation error: exit status 1`

Look in the rest of the compile message output (turn on verbose output if needed) and check if the actual error(s) look something like:

`undefined reference to `Adafruit_USBD_CDC::begin(unsigned long)`

`undefined reference to `Adafruit_USBD_CDC::write(unsigned char const*, unsigned int)`

If so, the required `#include ` is missing. See the example code above and add the required lines to your sketch.

### 

#### **If you get this error:**

`Timed out waiting for acknowledgement from device.Failed to upgrade target. Error is: No data received on serial port. Not able to proceed.Traceback (most recent call last):  File "nordicsemi\ __main__.py", line 294, in serial  File "nordicsemi\dfu\dfu.py", line 235, in dfu_send_images  File "nordicsemi\dfu\dfu.py", line 203, in _dfu_send_image  File "nordicsemi\dfu\dfu_transport_serial.py", line 155, in send_init_packet  File "nordicsemi\dfu\dfu_transport_serial.py", line 243, in send_packet  File "nordicsemi\dfu\dfu_transport_serial.py", line 282, in get_ack_nrnordicsemi.exceptions.NordicSemiException: No data received on serial port. Not able to proceed.`

This is probably caused by the **bootloader** version mismatched on your Feather and installed BSP. Due to the difference in flash layout ([more details](https://learn.adafruit.com/bluefruit-nrf52-feather-learning-guide/hathach-memory-map)) and Softdevice API (which is bundled with bootloader), sketch built with selected bootloader can only upload to board having the same version. In short, you need to **upgrade/burn bootloader to match** on your Feather, follow above&nbsp;[Update The Bootloader](https://learn.adafruit.com/bluefruit-nrf52-feather-learning-guide/updating-the-bootloader)&nbsp;guide

It only has to be done once to update your Feather

### 

This is probably caused by a conflict between 32-bit and 64-bit versions of the compiler, libc and the IDE. The compiler uses 32-bit binaries, so you also need to have a 32-bit version of libc installed on your system ([details](http://forum.arduino.cc/index.php?topic=221979.0)). Try running the following commands from the command line to resolve this:

```
sudo dpkg--add-architecture i386sudo apt-getupdatesudo apt-getinstall libc6:i386
```
# Introducing the Adafruit nRF52840 Feather

## Arduino BLE Examples

There are numerous examples available for the Bluefruit nRF52/nRF52840 Feathers in the&nbsp; **Examples** menu of the nRF52 BSP, and these are always up to date. You're first stop looking for example code should be there:

![](https://cdn-learn.adafruit.com/assets/assets/000/039/998/medium800/microcontrollers_Screen_Shot_2017-03-09_at_15.55.02.png?1489071326)

# Example Source Code

The latest example source code is always available and visible on Github, and the public git repository should be considered the definitive source of example code for this board.

[Click here to browse the example source code on Github](https://github.com/adafruit/Adafruit_nRF52_Arduino/tree/master/libraries/Bluefruit52Lib/examples)
# Documented Examples

To help explain some common use cases for the nRF52 BLE API, feel free to consult the example documentation in this section of the learning guide:

- **Advertising: Beacon** - Shows how to use the BLEBeacon helper class to configure your Bleufruit nRF52 Feather as a beacon
- **BLE UART: Controller** - Shows how to use the **Controller** &nbsp;utility in our Bluefruit LE Connect apps to send basic data between your peripheral and your phone or tablet.
- **Custom: HRM** - Shows how to defined and work with a custom GATT Service and Characteristic, using the officially adopted Heart Rate Monitor (HRM) service as an example.
- **BLE Pin I/O** (StandardFirmataBLE) Shows how to control Pin I/O of nRF52 with Firmata protocol

For more information on the Arduino nRF52 API, check out [this page](https://learn.adafruit.com/bluefruit-nrf52-feather-learning-guide/bluefruit-nrf52-api).

# Introducing the Adafruit nRF52840 Feather

## Advertising: Beacon

This example shows how you can use the BLEBeacon helper class and advertising API to configure your Bluefruit nRF52 board as a 'Beacon'.

# Complete Code
https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/examples/Peripheral/beacon/beacon.ino

The **bluefruit.h** file is below (which includes the `Bluefruit.setTxPower()` allowed values.

https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/src/bluefruit.h

# Output

You can use the nRF Beacons application from Nordic Semiconductors to test this sketch:

- [nRF Beacons for iOS](https://itunes.apple.com/app/nrf-beacons/id879614768?mt=8)
- [nRF Beacons for Android](https://play.google.com/store/apps/details?id=no.nordicsemi.android.nrfbeacon)

Make sure that you set the UUID, Major and Minor values to match the sketch above, and then run the sketch at the same time as the nRF Beacons application.

With the default setup you should see a Mona Lisa icon when the beacon is detected. If you don't see this, double check the UUID, Major and Minor values to be sure they match exactly.

![](https://cdn-learn.adafruit.com/assets/assets/000/040/306/medium800/microcontrollers_Beacons.png?1490019091)

# Introducing the Adafruit nRF52840 Feather

## BLE UART: Controller

This examples shows you you can use the BLEUart helper class and the Bluefruit LE Connect applications to send based keypad and sensor data to your nRF52.

# Setup

In order to use this sketch, you will need to open Bluefruit LE Connect on your mobile device using our free [iOS](https://itunes.apple.com/app/adafruit-bluefruit-le-connect/id830125974?mt=8), [Android](https://play.google.com/store/apps/details?id=com.adafruit.bluefruit.le.connect) or [OS X](https://itunes.apple.com/us/app/adafruit-bluefruit-le-connect/id1082414600?mt=12) applications.

- Load the&nbsp;[**Controller** example sketch](https://github.com/adafruit/Adafruit_nRF52_Arduino/tree/master/libraries/Bluefruit52Lib/examples/Peripheral/controller) in the Arduino IDE
- Compile the sketch and flash it to your nRF52 based Feather
- Once you are done uploading, open the&nbsp; **Serial Monitor** (Tools \> Serial Monitor)
- Open the **Bluefruit LE Connect** application on your mobile device
- Connect to the appropriate target (probably ' **Bluefruit52**')
- Once connected switch to the&nbsp; **Controller** &nbsp;application inside the app
- Enable an appropriate control surface. The&nbsp; **Color Picker** control surface is shown below, for example (screen shot taken from the iOS application):

![](https://cdn-learn.adafruit.com/assets/assets/000/039/829/medium800/microcontrollers_bluefruitcolorpicker.jpeg?1488809248)

As you change the color (or as other data becomes available) you should receive the data on the nRF52, and see it in the Serial Monitor output:

![](https://cdn-learn.adafruit.com/assets/assets/000/039/830/medium800/microcontrollers_Screen_Shot_2017-03-06_at_15.08.33.png?1488809331)

# Complete Code

&nbsp;

https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/examples/Peripheral/controller/controller.ino

You will also need the following helper class in a file called&nbsp; **packetParser.cpp** :

https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/examples/Peripheral/controller/packetParser.cpp

# Introducing the Adafruit nRF52840 Feather

## Custom: HRM

The BLEService and BLECharacteristic classes can be used to implement any custom or officially adopted BLE service of characteristic using a set of basic properties and callback handlers.

The example below shows how to use these classes to implement the [Heart Rate Monitor](https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.heart_rate.xml) service, as defined by the Bluetooth SIG.

# HRM Service Definition

**UUID** : [0x180D](https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.heart_rate.xml)

Only the first characteristic is mandatory, but we will also implement the optional&nbsp; **Body Sensor Location** characteristic. Heart Rate Control Point won't be used in this example to keep things simple.

# Implementing the HRM Service and Characteristics

The core service and the first two characteristics can be implemented with the following code:

First, define the BLEService and BLECharacteristic variables that will be used in your project:

```
/* HRM Service Definitions
 * Heart Rate Monitor Service:  0x180D
 * Heart Rate Measurement Char: 0x2A37
 * Body Sensor Location Char:   0x2A38
 */
BLEService        hrms = BLEService(UUID16_SVC_HEART_RATE);
BLECharacteristic hrmc = BLECharacteristic(UUID16_CHR_HEART_RATE_MEASUREMENT);
BLECharacteristic bslc = BLECharacteristic(UUID16_CHR_BODY_SENSOR_LOCATION);
```

Then you need to 'populate' those variables with appropriate values. For simplicity sake, you can define a custom function for your service where all of the code is placed, and then just call this function once in the 'setup' function:

```
void setupHRM(void)
{
  // Configure the Heart Rate Monitor service
  // See: https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.heart_rate.xml
  // Supported Characteristics:
  // Name                         UUID    Requirement Properties
  // ---------------------------- ------  ----------- ----------
  // Heart Rate Measurement       0x2A37  Mandatory   Notify
  // Body Sensor Location         0x2A38  Optional    Read
  // Heart Rate Control Point     0x2A39  Conditional Write       &lt;-- Not used here
  hrms.begin();

  // Note: You must call .begin() on the BLEService before calling .begin() on
  // any characteristic(s) within that service definition.. Calling .begin() on
  // a BLECharacteristic will cause it to be added to the last BLEService that
  // was 'begin()'ed!

  // Configure the Heart Rate Measurement characteristic
  // See: https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.heart_rate_measurement.xml
  // Permission = Notify
  // Min Len    = 1
  // Max Len    = 8
  //    B0      = UINT8  - Flag (MANDATORY)
  //      b5:7  = Reserved
  //      b4    = RR-Internal (0 = Not present, 1 = Present)
  //      b3    = Energy expended status (0 = Not present, 1 = Present)
  //      b1:2  = Sensor contact status (0+1 = Not supported, 2 = Supported but contact not detected, 3 = Supported and detected)
  //      b0    = Value format (0 = UINT8, 1 = UINT16)
  //    B1      = UINT8  - 8-bit heart rate measurement value in BPM
  //    B2:3    = UINT16 - 16-bit heart rate measurement value in BPM
  //    B4:5    = UINT16 - Energy expended in joules
  //    B6:7    = UINT16 - RR Internal (1/1024 second resolution)
  hrmc.setProperties(CHR_PROPS_NOTIFY);
  hrmc.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
  hrmc.setFixedLen(2);
  hrmc.setCccdWriteCallback(cccd_callback);  // Optionally capture CCCD updates
  hrmc.begin();
  uint8_t hrmdata[2] = { 0b00000110, 0x40 }; // Set the characteristic to use 8-bit values, with the sensor connected and detected
  hrmc.notify(hrmdata, 2);                   // Use .notify instead of .write!

  // Configure the Body Sensor Location characteristic
  // See: https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.body_sensor_location.xml
  // Permission = Read
  // Min Len    = 1
  // Max Len    = 1
  //    B0      = UINT8 - Body Sensor Location
  //      0     = Other
  //      1     = Chest
  //      2     = Wrist
  //      3     = Finger
  //      4     = Hand
  //      5     = Ear Lobe
  //      6     = Foot
  //      7:255 = Reserved
  bslc.setProperties(CHR_PROPS_READ);
  bslc.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
  bslc.setFixedLen(1);
  bslc.begin();
  bslc.write8(2);    // Set the characteristic to 'Wrist' (2)
}
```

## Service + Characteristic Setup Code Analysis

1. The first thing to do is to call&nbsp;**.begin()** on the BLEService ( **hrms** above). Since the UUID is set in the object declaration at the top of the sketch, there is normally nothing else to do with the BLEService instance.

Danger: 

2. Next, you can configure the&nbsp; **Heart Rate Measurement** characteristic ( **hrmc** above). The values that you set for this will depend on the characteristic definition, but for convenience sake we've documented the key information in the comments in the code above.

- '`hrmc.setProperties(CHR_PROPS_NOTIFY);`' - This sets the PROPERTIES value for the characteristic, which determines how the characteristic can be accessed. In this case, the Bluetooth SIG has defined the characteristic as&nbsp; **Notify** , which means that&nbsp;the peripheral will receive a request ('notification') from the Central when the Central wants to receive data using this characteristic.
- ``hrmc.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);`` - This sets the security for the characteristic, and should normally be set to the values used in this example.
- ``hrmc.setFixedLen(2);`` - This tells the Bluetooth stack how many bytes the characteristic contains (normally a value between 1 and 20). In this case, we will use a fixed size of two bytes, so we call&nbsp; **.setFixedLen**. If the characteristic has a variable length, you would need to set the max size via **.setMaxLen**.&nbsp;
- '`hrmc.setCccdWriteCallback(cccd_callback);`' - This optional code sets the callback that will be fired when the CCCD record is updated by the central. This is relevant because the characteristic is setup with the NOTIFY property. When the Central sets to 'Notify' bit, it will write to the CCCD record, and you can capture this write even in the CCCD callback and turn the sensor on, for example, allowing you to save power by only turning the sensor on (and back off) when it is or isn't actually being used. For the implementation of the CCCD callback handler, see the full sample code at the bottom of this page.
- '`hrmc.begin();`' Once all of the properties have been set, you must call&nbsp;**.begin()** which will add the characteristic definition to the last BLEService that was '.begin()ed'.

3. Optionally set an initial value for the characteristic(s), such as the following code that populates 'hrmc' with a correct values, indicating that we are providing 8-bit heart rate monitor values, that the Body Sensor Location characteristic is present, and setting the first heart rate value to 0x04:

Info: 

```
// Set the characteristic to use 8-bit values, with the sensor connected and detected
uint8_t hrmdata[2] = { 0b00000110, 0x40 };

// Use .notify instead of .write!
hrmc.notify(hrmdata, 2);
```

The CCCD callback handler has the following signature:

```
void cccd_callback(uint16_t conn_hdl, BLECharacteristic* chr, uint16_t cccd_value)
{
    // Display the raw request packet
    Serial.print("CCCD Updated: ");
    //Serial.printBuffer(request-&gt;data, request-&gt;len);
    Serial.print(cccd_value);
    Serial.println("");

    // Check the characteristic this CCCD update is associated with in case
    // this handler is used for multiple CCCD records.
    if (chr-&gt;uuid == htmc.uuid) {
        if (chr-&gt;indicateEnabled(conn_hdl)) {
            Serial.println("Temperature Measurement 'Indicate' enabled");
        } else {
            Serial.println("Temperature Measurement 'Indicate' disabled");
        }
    }
}
```

4. Repeat the same procedure for any other BLECharacteristics in your service.

# Full Sample Code

The full sample code for this example can be seen below:

https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/examples/Peripheral/custom_hrm/custom_hrm.ino

# Introducing the Adafruit nRF52840 Feather

## BLE Pin I/O

Firmata is a generic protocol for communicating with microcontrollers and controlling the board's pins such as setting the GPIO outputs and inputs, PWM output, analog reads, etc....

# Setup

In order to run this demo, you will need to open Bluefruit LE Connect on your mobile device&nbsp;using our free [iOS](https://itunes.apple.com/app/adafruit-bluefruit-le-connect/id830125974?mt=8), [Android](https://play.google.com/store/apps/details?id=com.adafruit.bluefruit.le.connect) or [OS X](https://itunes.apple.com/us/app/adafruit-bluefruit-le-connect/id1082414600?mt=12) applications.

- Load the [**StandardFirmataBLE** example sketch](https://github.com/adafruit/Adafruit_nRF52_Arduino/tree/master/libraries/Bluefruit52Lib/examples/Peripheral/StandardFirmataBLE) in the Arduino IDE
- Compile the sketch and flash it to your nRF52 based Feather
- Once you are done uploading, open the&nbsp; **Serial Monitor** (Tools \> Serial Monitor)
- Open the **Bluefruit LE Connect** application on your mobile device
- Connect to the appropriate target (probably ' **Bluefruit52**')
- Once connected switch to the&nbsp; **Pin I/O** &nbsp;application inside the app

For more information using Pin I/O module, you could check out this tutorial here&nbsp;https://learn.adafruit.com/bluefruit-le-connect-for-ios/pin-i-o

![](https://cdn-learn.adafruit.com/assets/assets/000/049/548/medium800/microcontrollers_IMG_0042.png?1513942618)

# Complete Code

The latest version of this code is always available on [Github](https://github.com/adafruit/Adafruit_nRF52_Arduino/tree/master/libraries/Bluefruit52Lib/examples/Peripheral/controller), and in the&nbsp; **Examples** folder of the nRF52 BSP.

Danger: 

https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/examples/Peripheral/StandardFirmataBLE/StandardFirmataBLE.ino

# Introducing the Adafruit nRF52840 Feather

## Central BLEUART

This example show you how to use Feather nRF52/nRF52840 as a **Central** to talk to other Bluefruit (nRF52 or nRF51) peripherals exposing the bleuart (AKA 'NUS') service.

# Client Services

Since the Central role accesses the GATT server on the peripheral, we first need to declare a client bleuart instance using the **BLEClientUart** &nbsp;helper class. We can also conveniently read Device Information if **BLEClientDis** is also used.

```
BLEClientDis  clientDis;
BLEClientUart clientUart;

```

Before we can configure client services, `Bluefruit.begin()` must be called with at least 1 for the number of concurrent connections supported in central mode. Since we won't be running the nRF52 as a peripheral in this instance, we will set the peripheral count to 0:

```
// Initialize Bluefruit with maximum connections as Peripheral = 0, Central = 1
Bluefruit.begin(0, 1);
```

Afterward this, the client service(s) must be initialized by calling their `begin()`&nbsp;function, and you can&nbsp;setup any callbacks that you wish to use from the helper class:

```
// Configure DIS client
clientDis.begin();

// Init BLE Central Uart Serivce
clientUart.begin();
clientUart.setRxCallback(bleuart_rx_callback);
```

# Scanner

Let's start the advertising scanner to find a peripheral.

We'll hook up the scan result callback with **setRxCallback().&nbsp;**

Whenever advertising data is found by the scanner, it will be passed to this callback handler, and we can examine the advertising data there, and only connect to peripheral(s) that advertise the bleuart service.

Note: If the peripheral has multiple services and bleuart is not included in the UUID list in the advertising packet, you could optionally use another check such as matching the MAC address, name checking, using "another service", etc.

Once we find a peripheral that we wish to communicate with, call `Bluefruit.Central.connect()` to establish connection with it:

```
void setup()
{
  // Other set up .....

  /* Start Central Scanning
   * - Enable auto scan if disconnected
   * - Interval = 100 ms, window = 80 ms
   * - Don't use active scan
   * - Start(timeout) with timeout = 0 will scan forever (until connected)
   */
  Bluefruit.Scanner.setRxCallback(scan_callback);
  Bluefruit.Scanner.restartOnDisconnect(true);
  Bluefruit.Scanner.setInterval(160, 80); // in unit of 0.625 ms
  Bluefruit.Scanner.useActiveScan(false);
  Bluefruit.Scanner.start(0);                   // // 0 = Don't stop scanning after n seconds
}

/**
 * Callback invoked when scanner pick up an advertising data
 * @param report Structural advertising data
 */
void scan_callback(ble_gap_evt_adv_report_t* report)
{
  // Check if advertising contain BleUart service
  if ( Bluefruit.Scanner.checkReportForService(report, clientUart) )
  {
    Serial.print("BLE UART service detected. Connecting ... ");

    // Connect to device with bleuart service in advertising
    Bluefruit.Central.connect(report);
  }
}
```

# Central Role

You normally need to setup the Central mode device's **connect callback** , which&nbsp;fires when a connection is established/disconnected with a peripheral device. Alternatively you could poll the connection status with connected(), but callbacks help to simplify the code significantly:&nbsp;

```
// Callbacks for Central
Bluefruit.Central.setConnectCallback(connect_callback);
Bluefruit.Central.setDisconnectCallback(disconnect_callback);
```

In the connect callback, we will try to **discover&nbsp;** the bleuart service by browsing the GATT table of the peripheral. This will help to determine the handle values for characteristics (e.g TXD, RXD, etc.). This is all done by BLEClientUart's `.discover()`. Once the service is found, enable the TXD characteristic's CCCD to allow the peripheral to send data, and we are ready to send data back and forth&nbsp;between the devices:

```
void connect_callback(uint16_t conn_handle)
{
  Serial.println("Connected");

  Serial.print("Dicovering DIS ... ");
  if ( clientDis.discover(conn_handle) )
  {
    Serial.println("Found it");
    char buffer[32+1];
    
    // read and print out Manufacturer
    memset(buffer, 0, sizeof(buffer));
    if ( clientDis.getManufacturer(buffer, sizeof(buffer)) )
    {
      Serial.print("Manufacturer: ");
      Serial.println(buffer);
    }

    // read and print out Model Number
    memset(buffer, 0, sizeof(buffer));
    if ( clientDis.getModel(buffer, sizeof(buffer)) )
    {
      Serial.print("Model: ");
      Serial.println(buffer);
    }

    Serial.println();
  }  

  Serial.print("Discovering BLE Uart Service ... ");

  if ( clientUart.discover(conn_handle) )
  {
    Serial.println("Found it");

    Serial.println("Enable TXD's notify");
    clientUart.enableTXD();

    Serial.println("Ready to receive from peripheral");
  }else
  {
    Serial.println("Found NONE");
    
    // disconect since we couldn't find bleuart service
    Bluefruit.Central.disconnect(conn_handle);
  }  
}
```

# Full Sample Code

The full sample code for this example can be seen below:

https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/examples/Central/central_bleuart/central_bleuart.ino

And **bluefruit.h**

https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/src/bluefruit.h

# Introducing the Adafruit nRF52840 Feather

## Dual Roles BLEUART

Info: 

This example demonstrates how you can use a Feather nRF52/nRF52840 to connect to two other Bluefruit or BLE devices using the bleuart (AKA 'NUS') service concurrently, with the device running at both&nbsp;a peripheral and a central at the same time.

This dual role example acts as a BLE bridge that sits between a central and a peripheral forwarding bleuart messages back and forth, as shown in the image below:

![](https://cdn-learn.adafruit.com/assets/assets/000/049/793/medium800/microcontrollers_dual_roles.jpg?1514891413)

# Server & Client Service Setup

Since the Bluefruit device will act as both a central and a peripheral, we will need to declare both server and client instance of the bleuart helper class:

```
// Peripheral uart service
BLEUart bleuart;

// Central uart client
BLEClientUart clientUart;
```

Before we can configure client services, `Bluefruit.begin()` must be called with at least 1 for the number of concurrent connection for both peripheral and central mode:

```
// Initialize Bluefruit with max concurrent connections as Peripheral = 1, Central = 1
Bluefruit.begin(1, 1);
```

After this, client services must be initialized by calling their `begin()` function, followed by any callbacks that you wish to wire up as well:

```
// Configure and Start BLE Uart Service
bleuart.begin();
bleuart.setRxCallback(prph_bleuart_rx_callback);

// Init BLE Central Uart Serivce
clientUart.begin();
clientUart.setRxCallback(cent_bleuart_rx_callback);
```

We are then ready to forward data from central to peripheral and vice versa using callbacks:

```
void cent_bleuart_rx_callback(BLEClientUart&amp; cent_uart)
{
  char str[20+1] = { 0 };
  cent_uart.read(str, 20);
      
  Serial.print("[Cent] RX: ");
  Serial.println(str);

  if ( bleuart.notifyEnabled() )
  {
    // Forward data from our peripheral to Mobile
    bleuart.print( str );
  }else
  {
    // response with no prph message
    clientUart.println("[Cent] Peripheral role not connected");
  }  
}

void prph_bleuart_rx_callback(void)
{
  // Forward data from Mobile to our peripheral
  char str[20+1] = { 0 };
  bleuart.read(str, 20);

  Serial.print("[Prph] RX: ");
  Serial.println(str);  

  if ( clientUart.discovered() )
  {
    clientUart.print(str);
  }else
  {
    bleuart.println("[Prph] Central role not connected");
  }
}

```

# Peripheral Role

The first thing to do for the peripheral part of our code is to setup the **connect callback** , which fires when a connection is established/disconnected with the central. Alternatively you could poll the connection status with connected(), but callbacks helps to simplify the code significantly:

```
// Callbacks for Peripheral
Bluefruit.setConnectCallback(prph_connect_callback);
Bluefruit.setDisconnectCallback(prph_disconnect_callback);
```

# Central Role

Next we setup the Central mode **connect callback** , which fires when a connection is established/disconnected with a peripheral device:

```
// Callbacks for Central
Bluefruit.Central.setConnectCallback(cent_connect_callback);
Bluefruit.Central.setDisconnectCallback(cent_disconnect_callback);
```

# Advertising and Scanner

It is possible to start both the scanner and advertising at the same time so that we can discover and be discovered by other BLE devices. For the scanner, we use a filter that only fires the callback if a specific UUID is found in the advertising data of the peer device:

```
/* Start Central Scanning
 * - Enable auto scan if disconnected
 * - Interval = 100 ms, window = 80 ms
 * - Filter only accept bleuart service
 * - Don't use active scan
 * - Start(timeout) with timeout = 0 will scan forever (until connected)
 */
Bluefruit.Scanner.setRxCallback(scan_callback);
Bluefruit.Scanner.restartOnDisconnect(true);
Bluefruit.Scanner.setInterval(160, 80); // in unit of 0.625 ms
Bluefruit.Scanner.filterUuid(bleuart.uuid);
Bluefruit.Scanner.useActiveScan(false);
Bluefruit.Scanner.start(0);                   // 0 = Don't stop scanning after n seconds

// Advertising packet
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();

// Include bleuart 128-bit uuid
Bluefruit.Advertising.addService(bleuart);

// Secondary Scan Response packet (optional)
// Since there is no room for 'Name' in Advertising packet
Bluefruit.ScanResponse.addName();

/* Start Advertising
 * - Enable auto advertising if disconnected
 * - Interval:  fast mode = 20 ms, slow mode = 152.5 ms
 * - Timeout for fast mode is 30 seconds
 * - Start(timeout) with timeout = 0 will advertise forever (until connected)
 *
 * For recommended advertising interval
 * https://developer.apple.com/library/content/qa/qa1931/_index.html
 */
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244);    // in unit of 0.625 ms
Bluefruit.Advertising.setFastTimeout(30);      // number of seconds in fast mode
Bluefruit.Advertising.start(0);                // 0 = Don't stop advertising after n seconds
```

# Full Sample Code

The full sample code for this example can be seen below:

https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/examples/DualRoles/dual_bleuart/dual_bleuart.ino

# Introducing the Adafruit nRF52840 Feather

## Custom: Central HRM

The BLEClientService and BLEClientCharacteristic classes can be used to implement any custom or officially adopted BLE service of characteristic on the client side (most often is Central) using a set of basic properties and callback handlers.

The example below shows how to use these classes to implement the [Heart Rate Monitor](https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.heart_rate.xml) service, as defined by the Bluetooth SIG. To run this example, you will need an extra nRF52 running&nbsp;[peripheral HRM sketch](../../../../bluefruit-nrf52-feather-learning-guide/custom-hrm)

# HRM Service Definition

**UUID** : [0x180D](https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.heart_rate.xml)

Only the first characteristic is mandatory, but we will also implement the optional&nbsp; **Body Sensor Location** characteristic. Heart Rate Control Point won't be used in this example to keep things simple.

# Implementing the HRM Service and Characteristics

The core service and the first two characteristics can be implemented with the following code:

First, define the BLEService and BLECharacteristic variables that will be used in your project:

```
/* HRM Service Definitions
 * Heart Rate Monitor Service:  0x180D
 * Heart Rate Measurement Char: 0x2A37 (Mandatory)
 * Body Sensor Location Char:   0x2A38 (Optional)
 */

BLEClientService        hrms(UUID16_SVC_HEART_RATE);
BLEClientCharacteristic hrmc(UUID16_CHR_HEART_RATE_MEASUREMENT);
BLEClientCharacteristic bslc(UUID16_CHR_BODY_SENSOR_LOCATION);
```

Then you need to initialize those variables by calling their begin().

```
// Initialize HRM client
hrms.begin();

// Initialize client characteristics of HRM.
// Note: Client Char will be added to the last service that is begin()ed.
bslc.begin();

// set up callback for receiving measurement
hrmc.setNotifyCallback(hrm_notify_callback);
hrmc.begin();
```

## Client Service + Characteristic Code Analysis

1. The first thing to do is to call&nbsp;**.begin()** on the BLEClientService ( **hrms** above). Since the UUID is set in the object declaration at the top of the sketch, there is normally nothing else to do with the BLEClientService instance.

Danger: 

2. Since&nbsp; **Heart Rate Measurement** characteristic ( **clientMeasurement** &nbsp;above) is&nbsp;_notifiable._&nbsp;You need to set up callback for it

- '`hrmc.setNotifyCallback(hrm_notify_callback);`' This sets the callback that will be fired when we receive a Notify message from peripheral. This is needed to handle notifiable characteristic since callback allow us to response to the message in timely manner. For this example is just simply printing out value to Serial.
- '`hrmc.begin();`' Once all of the properties have been set, you must call&nbsp;**.begin()** which will add the characteristic definition to the last BLEClientService that was '.begin()ed'.

Info: 

3. Next, we can start to scan and connect to peripheral that advertises HRM service. Once connected, we need to go through peripheral GATT table to find out the Gatt handle for our interest. In this example they are handle for **hrms** ,&nbsp; **hrmc** and&nbsp; **bslc.&nbsp;** This looking up process for interested service/characteristic is called **Discovery.&nbsp;**

**Note** : Gatt handle (or just handle) is required to perform any operations at all such as read, write, enable notify. It is required that a client characteristic must be discovered before we could doing anything with it.

The service should be discovered before we could discover its characteristic. This can be done by calling&nbsp;`hrms.discover(conn_handle)`&nbsp;. Where conn\_handle is the connection ID i.e peripheral that we want to discover since it is possible for Bluefruit nRF52 to connect to multiple peripherals concurrently. If the service is found, the function will return true, otherwise false.

```
// Connect Callback Part 1
void connect_callback(uint16_t conn_handle)
{
  Serial.println("Connected");
  Serial.print("Discovering HRM Service ... ");

  // If HRM is not found, disconnect and return
  if ( !hrms.discover(conn_handle) )
  {
    Serial.println("Found NONE");

    // disconect since we couldn't find HRM service
    Bluefruit.Central.disconnect(conn_handle);

    return;
  }

  // Once HRM service is found, we continue to discover its characteristic
  Serial.println("Found it");

  .............
}
```

4. Afterwards, we continue to discover all the interested characteristics within the service by calling&nbsp;`.discover()`. The function return true if characteristics is found, and false otherwise. You could also check with&nbsp;`.discovered()`&nbsp;function. A service could contain more characteristics but we don't need to discover them all, only those that we want to interact with.

**Advanced:** Alternatively, you could discover all the interested characteristics of a service within a&nbsp; function call by using`Bluefruit.Discovery.discoverCharacteristic()`&nbsp;(not used in the example). The API can take up to 5 characteristics, if you need more, the variant with passing array of characteristics is also available. The function will return the number of characteristic it found.

**Note** : when a characteristic is discovered by above API, all necessarily meta data such as handles, properties&nbsp;( read,write, notify etc ...), cccd handle&nbsp; will be updated automatically. You can then use&nbsp;[BLECLientCharacteristic](../../../../bluefruit-nrf52-feather-learning-guide/bleclientcharacteristic)&nbsp;API such as read(), write(), enableNotify() on it provided that its properties support such as operation.&nbsp;

```
// Connect Callback Part 2
void connect_callback(uint16_t conn_handle)
{
  Serial.print("Discovering Measurement characteristic ... ");
  if ( !hrmc.discover() )
  {
    // Measurement chr is mandatory, if it is not found (valid), then disconnect
    Serial.println("not found !!!");  
    Serial.println("Measurement characteristic is mandatory but not found");
    Bluefruit.Central.disconnect(conn_handle);
    return;
  }
  Serial.println("Found it");

  // Measurement is found, continue to look for option Body Sensor Location
  // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.body_sensor_location.xml
  // Body Sensor Location is optional, print out the location in text if present
  Serial.print("Discovering Body Sensor Location characteristic ... ");
  if ( bslc.discover() )
  {
    Serial.println("Found it");
    
    // Body sensor location value is 8 bit
    const char* body_str[] = { "Other", "Chest", "Wrist", "Finger", "Hand", "Ear Lobe", "Foot" };

    // Read 8-bit BSLC value from peripheral
    uint8_t loc_value = bslc.read8();
    
    Serial.print("Body Location Sensor: ");
    Serial.println(body_str[loc_value]);
  }else
  {
    Serial.println("Found NONE");
  }
  
  ...............
}
```

5. Once hrmc is discovered, you should enable its notification by calling `hrmc.enableNotify()`. If this succeeded (return true), peripheral can now send data to us using notify message. Which will trigger the callback that we setup earlier to handle incoming data.

```
// Connect Callback Part 3
void connect_callback(uint16_t conn_handle)
{
  .......
  
  // Reaching here means we are ready to go, let's enable notification on measurement chr
  if ( hrmc.enableNotify() )
  {
    Serial.println("Ready to receive HRM Measurement value");
  }else
  {
    Serial.println("Couldn't enable notify for HRM Measurement. Increase DEBUG LEVEL for troubleshooting");
  }
}
```

```
/**
 * Hooked callback that triggered when a measurement value is sent from peripheral
 * @param chr   Pointer to client characteristic that even occurred,
 *              in this example it should be hrmc
 * @param data  Pointer to received data
 * @param len   Length of received data
 */
void hrm_notify_callback(BLEClientCharacteristic* chr, uint8_t* data, uint16_t len)
{
  // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.heart_rate_measurement.xml
  // Measurement contains of control byte0 and measurement (8 or 16 bit) + optional field
  // if byte0's bit0 is 0 --&gt; measurement is 8 bit, otherwise 16 bit.

  Serial.print("HRM Measurement: ");

  if ( data[0] &amp; bit(0) )
  {
    uint16_t value;
    memcpy(&amp;value, data+1, 2);

    Serial.println(value);
  }
  else
  {
    Serial.println(data[1]);
  }
}
```

# Full Sample Code

The full sample code for this example can be seen below:

https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/examples/Peripheral/custom_hrm/custom_hrm.ino

# Introducing the Adafruit nRF52840 Feather

## Arduino Bluefruit nRF52 API

The Adafruit nRF52 core defines a number of custom classes that aim to make it easy to work with BLE in your projects.

The key classes are listed below, and examined in more detail elsewhere in this learning guide:

- **AdafruitBluefruit** &nbsp;is the main entry point to the Adafruit Bluefruit nRF52 API. This class exposes a number of essential functions and classes, such as advertising, the list of GATT services and characteristics defined on your device, and connection status.
- **BLEService** &nbsp;is a wrapper class for BLE GATT service records, and can be used to define custom service definitions, or acts as the base class for any service helper classes.
- **BLECharacteristic** is a wrapper class for a BLE GATT characteristic record, and can be used to define custom characteristics, or acts as &nbsp;the base class for any characteristic helper classes.
- **BLEDis** is a helper class for the DIS or 'Device Information Service'.
- **BLEUart** is a helper class for the NUS or 'Nordic UART Service'.
- **BLEBeacon** is a helper class to configure your nRF52 as a beacon using the advertising packet to send out properly formatted beacon data.
- **BLEMidi** is a helper class to work with MIDI data over BLE.
- **BLEHidAdafruit** is a helper class to emulate an HID mouse or keyboard over BLE.

Info: 

# Introducing the Adafruit nRF52840 Feather

## AdafruitBluefruit

Danger: 

This base class is the main entry point to the Adafruit Bluefruit nRF52 API, and exposes most of the helper classes and functions that you use to configure your device.

# API

AdafruitBluefruit has the following public API:

```
// Constructor
AdafruitBluefruit(void);

/*------------------------------------------------------------------*/
/* Lower Level Classes (Bluefruit.Advertising.*, etc.)
 *------------------------------------------------------------------*/
BLEGap             Gap;
BLEGatt            Gatt;

BLEAdvertising     Advertising;
BLEAdvertisingData ScanResponse;
BLEScanner         Scanner;
BLECentral         Central;
BLEDiscovery       Discovery;

/*------------------------------------------------------------------*/
/* SoftDevice Configure Functions, must call before begin().
 * These function affect the SRAM consumed by SoftDevice.
 *------------------------------------------------------------------*/
void     configServiceChanged (bool     changed);
void     configUuid128Count   (uint8_t  uuid128_max);
void     configAttrTableSize  (uint32_t attr_table_size);

// Config Bandwidth for connections
void     configPrphConn        (uint16_t mtu_max, uint8_t event_len, uint8_t hvn_qsize, uint8_t wrcmd_qsize);
void     configCentralConn     (uint16_t mtu_max, uint8_t event_len, uint8_t hvn_qsize, uint8_t wrcmd_qsize);

// Convenient function to config connection
void     configPrphBandwidth   (uint8_t bw);
void     configCentralBandwidth(uint8_t bw);

err_t    begin(uint8_t prph_count = 1, uint8_t central_count = 0);

/*------------------------------------------------------------------*/
/* General Functions
 *------------------------------------------------------------------*/
void     setName            (const char* str);
uint8_t  getName            (char* name, uint16_t bufsize);

bool     setTxPower         (int8_t power);
int8_t   getTxPower         (void);

bool     setApperance       (uint16_t appear);
uint16_t getApperance       (void);

void     autoConnLed        (bool enabled);
void     setConnLedInterval (uint32_t ms);

/*------------------------------------------------------------------*/
/* GAP, Connections and Bonding
 *------------------------------------------------------------------*/
bool     connected         (void);
bool     disconnect        (void);

bool     setConnInterval   (uint16_t min, uint16_t max);
bool     setConnIntervalMS (uint16_t min_ms, uint16_t max_ms);

uint16_t connHandle        (void);
bool     connPaired        (void);
uint16_t connInterval      (void);

bool     requestPairing    (void);
void     clearBonds        (void);

ble_gap_addr_t getPeerAddr (void);
uint8_t        getPeerAddr (uint8_t addr[6]);

void     printInfo(void);

/*------------------------------------------------------------------*/
/* Callbacks
 *------------------------------------------------------------------*/
void setConnectCallback   ( BLEGap::connect_callback_t    fp);
void setDisconnectCallback( BLEGap::disconnect_callback_t fp);
```

These functions are generally available via ' **Bluefruit.\***'. For example, to check the connection status in your sketch you could run '`if (Bluefruit.connected()) { ... }`'.

# Examples

For examples of how to work with the parent&nbsp; **Bluefruit** class, see the&nbsp; **Examples** section later in this guide. It's better to examine this class in the context of a real world use case.

You can also browse the latest example code online via Github:

[Browse the latest example code on Github](https://github.com/adafruit/Adafruit_nRF52_Arduino/tree/master/libraries/Bluefruit52Lib/examples)
# Introducing the Adafruit nRF52840 Feather

## BLEGap

Danger: 

This GAP API for Bluefruit is accessible via&nbsp;`Bluefruit.Gap.***`&nbsp;and has the following public functions:

```
typedef void (*connect_callback_t    ) (uint16_t conn_handle);
typedef void (*disconnect_callback_t ) (uint16_t conn_handle, uint8_t reason);

uint8_t        getAddr               (uint8_t mac[6]);
bool           setAddr               (uint8_t mac[6], uint8_t type);

bool           connected            (uint16_t conn_handle);

uint8_t        getRole              (uint16_t conn_handle);

uint8_t        getPeerAddr          (uint16_t conn_handle, uint8_t addr[6]);
ble_gap_addr_t getPeerAddr          (uint16_t conn_handle);
uint16_t       getPeerName          (uint16_t conn_handle, char* buf, uint16_t bufsize);

uint16_t       getMTU               (uint16_t conn_handle);
uint16_t       getMaxMtuByConnCfg   (uint8_t conn_cfg);
uint16_t       getMaxMtu            (uint8_t conn_handle);

```

# Introducing the Adafruit nRF52840 Feather

## BLEAdvertising

Danger: 

'Advertising' is what makes your Bluetooth Low Energy devices visible to other devices in listening range. The radio sends out specially formatter advertising packets that contain information like the device name, whether you can connect to the device (or if it only advertises), etc.

You can also include custom data in the advertising packet, which is essential how beacons work.

The _BLEAdvertisingData and&nbsp;BLEAdvertising_&nbsp;classes exposes a number of helper functions to make it easier to create well-formatted advertising packets, as well as to use the&nbsp; **Scan Response** option, which is an optional secondary advertising packet that can be requested by a Central device. (This gives you another 27 bytes of advertising data, but isn't sent out automatically like the main advertising packet.).

This two advertising packets are accessible via the&nbsp;parent AdafruitBluefruit class, calling '`Bluefruit.Advertising.*`' and '`Bluefruit.ScanResponse.*`' from your user sketches.

For examples of using these helper classes, see any of the&nbsp; **examples** &nbsp;later on in this guide, since all devices will advertise as part of the startup process.

# API

The **BLEAdvertisingData** class has the following public API:

```
/*------------- Adv Data -------------*/
bool addData(uint8_t type, const void* data, uint8_t len);
bool addFlags(uint8_t flags);
bool addTxPower(void);
bool addName(void);
bool addAppearance(uint16_t appearance);
bool addManufacturerData(const void* data, uint8_t count);

/*------------- UUID -------------*/
bool addUuid(BLEUuid bleuuid);
bool addUuid(BLEUuid bleuuid1, BLEUuid bleuuid2);
bool addUuid(BLEUuid bleuuid1, BLEUuid bleuuid2, BLEUuid bleuuid3);
bool addUuid(BLEUuid bleuuid1, BLEUuid bleuuid2, BLEUuid bleuuid3, BLEUuid bleuuid4);

bool addUuid(BLEUuid bleuuid[], uint8_t count);

/*------------- Service -------------*/
bool addService(BLEService&amp; service);
bool addService(BLEService&amp; service1, BLEService&amp; service2);
bool addService(BLEService&amp; service1, BLEService&amp; service2, BLEService&amp; service3);
bool addService(BLEService&amp; service1, BLEService&amp; service2, BLEService&amp; service3, BLEService&amp; service4);

/*------------- Client Service -------------*/
bool addService(BLEClientService&amp; service);

// Functions to work with the raw advertising packet
uint8_t  count(void);
uint8_t* getData(void);
bool     setData(const uint8_t* data, uint8_t count);
void     clearData(void);

bool     setData(Advertisable&amp; adv_able) { return adv_able.setAdv(*this); }
```

In addition to API from BLEAdvertisingData, The **BLEAdvertising** class also has functions that dictate the behavior of advertising such as slow/fast timeout, adv intervals, and callbacks etc...&nbsp; &nbsp;

```
typedef void (*stop_callback_t) (void);
typedef void (*slow_callback_t) (void);

void setType(uint8_t adv_type);
void setFastTimeout(uint16_t sec);

void setSlowCallback(slow_callback_t fp);
void setStopCallback(stop_callback_t fp);

void setInterval  (uint16_t fast, uint16_t slow);
void setIntervalMS(uint16_t fast, uint16_t slow);

uint16_t getInterval(void);

bool setBeacon(BLEBeacon&amp; beacon);
bool setBeacon(EddyStoneUrl&amp; eddy_url);

bool isRunning(void);

void restartOnDisconnect(bool enable);
bool start(uint16_t timeout = 0);
bool stop (void);

```

# Related Information

- [Generic Access Profile](https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile): This page contains the official list of assigned numbers for the&nbsp;'Data' type field. Data is inserted into the advertising packet by supplying a valid 'data' type, optionally followed by a properly formatted payload corresponding to the selected value.

# Example

For practical example code, see the&nbsp; **Examples** section later on in this guide. The snippet below is provided for illustration purposes, but advertising should be examined in the context of a real use case since it varies from one setup to the next!

```
void setup(void)
{
  // Other startup code here 
  // ...
  
  // Set up Advertising Packet
  setupAdv();

  // Start Advertising
  Bluefruit.Advertising.start();
}

void startAdv(void)
{
  // Advertising packet
  Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
  Bluefruit.Advertising.addTxPower();

  // Include bleuart 128-bit uuid
  Bluefruit.Advertising.addService(bleuart);

  // Secondary Scan Response packet (optional)
  // Since there is no room for 'Name' in Advertising packet
  Bluefruit.ScanResponse.addName();
  
  /* Start Advertising
   * - Enable auto advertising if disconnected
   * - Interval:  fast mode = 20 ms, slow mode = 152.5 ms
   * - Timeout for fast mode is 30 seconds
   * - Start(timeout) with timeout = 0 will advertise forever (until connected)
   * 
   * For recommended advertising interval
   * https://developer.apple.com/library/content/qa/qa1931/_index.html   
   */
  Bluefruit.Advertising.restartOnDisconnect(true);
  Bluefruit.Advertising.setInterval(32, 244);    // in unit of 0.625 ms
  Bluefruit.Advertising.setFastTimeout(30);      // number of seconds in fast mode
  Bluefruit.Advertising.start(0);                // 0 = Don't stop advertising after n seconds  
}
```

# Introducing the Adafruit nRF52840 Feather

## BLEScanner

Danger: 

Warning: 

The BLEScanner class is used in&nbsp; **Central Mode** , and facilitates scanning for BLE peripherals in range and parsing the advertising data that is being sent out by the peripherals.

The BLEScanner class is normally accessed via the Bluefruit class (instantiated at startup), as shown below:

```
/* Start Central Scanning
 * - Enable auto scan if disconnected
 * - Filter for devices with a min RSSI of -80 dBm
 * - Interval = 100 ms, window = 50 ms
 * - Use active scan (requests the optional scan response packet)
 * - Start(0) = will scan forever since no timeout is given
 */
Bluefruit.Scanner.setRxCallback(scan_callback);
Bluefruit.Scanner.restartOnDisconnect(true);
Bluefruit.Scanner.filterRssi(-80);            // Only invoke callback when RSSI &gt;= -80 dBm
Bluefruit.Scanner.setInterval(160, 80);       // in units of 0.625 ms
Bluefruit.Scanner.useActiveScan(true);        // Request scan response data
Bluefruit.Scanner.start(0);                   // 0 = Don't stop scanning after n seconds
```

# API

BLEScanner has the following public API:

```
typedef void (*rx_callback_t) (ble_gap_evt_adv_report_t*);
typedef void (*stop_callback_t) (void);

BLEScanner(void);

ble_gap_scan_params_t* getParams(void);
bool isRunning(void);

void useActiveScan(bool enable);
void setInterval(uint16_t interval, uint16_t window);
void setIntervalMS(uint16_t interval, uint16_t window);
void restartOnDisconnect(bool enable);

void filterRssi(int8_t min_rssi);
void filterMSD(uint16_t manuf_id);

void filterUuid(BLEUuid ble_uuid);
void filterUuid(BLEUuid ble_uuid1, BLEUuid ble_uuid2);
void filterUuid(BLEUuid ble_uuid1, BLEUuid ble_uuid2, BLEUuid ble_uuid3);
void filterUuid(BLEUuid ble_uuid1, BLEUuid ble_uuid2, BLEUuid ble_uuid3, BLEUuid ble_uuid4);
void filterUuid(BLEUuid ble_uuid[], uint8_t count);

void clearFilters(void);

bool start(uint16_t timeout = 0);
bool stop(void);

/*------------- Callbacks -------------*/
void setRxCallback(rx_callback_t fp);
void setStopCallback(stop_callback_t fp);

/*------------- Data Parser -------------*/
uint8_t parseReportByType(const uint8_t* scandata, uint8_t scanlen, uint8_t type, uint8_t* buf, uint8_t bufsize = 0);
uint8_t parseReportByType(const ble_gap_evt_adv_report_t* report, uint8_t type, uint8_t* buf, uint8_t bufsize = 0);

bool    checkReportForUuid(const ble_gap_evt_adv_report_t* report, BLEUuid ble_uuid);
bool    checkReportForService(const ble_gap_evt_adv_report_t* report, BLEClientService svc);
bool    checkReportForService(const ble_gap_evt_adv_report_t* report, BLEService svc);
```

## setRxCallback(rx\_callback\_t fp)

Whenever a valid advertising packet is detected (based on any optional filters that are applied in the BLEScanner class), a dedicated callback function (see `rx_callback_t`) will be called.

The callback function has the following signature:

**NOTE** : `ble_gap_evt_adv_report_t` is part of the Nordic nRF52 SD and is defined in ble\_gap.h

```
void scan_callback(ble_gap_evt_adv_report_t* report)
{
  /* Display the timestamp and device address */
  if (report-&gt;scan_rsp)
  {
    /* This is a Scan Response packet */
    Serial.printf("[SR%10d] Packet received from ", millis());
  }
  else
  {
    /* This is a normal advertising packet */
    Serial.printf("[ADV%9d] Packet received from ", millis());
  }
  Serial.printBuffer(report-&gt;peer_addr.addr, 6, ':');
  Serial.print("\n");

  /* Raw buffer contents */
  Serial.printf("%14s %d bytes\n", "PAYLOAD", report-&gt;dlen);
  if (report-&gt;dlen)
  {
    Serial.printf("%15s", " ");
    Serial.printBuffer(report-&gt;data, report-&gt;dlen, '-');
    Serial.println();
  }

  /* RSSI value */
  Serial.printf("%14s %d dBm\n", "RSSI", report-&gt;rssi);

  /* Adv Type */
  Serial.printf("%14s ", "ADV TYPE");
  switch (report-&gt;type)
  {
    case BLE_GAP_ADV_TYPE_ADV_IND:
      Serial.printf("Connectable undirected\n");
      break;
    case BLE_GAP_ADV_TYPE_ADV_DIRECT_IND:
      Serial.printf("Connectable directed\n");
      break;
    case BLE_GAP_ADV_TYPE_ADV_SCAN_IND:
      Serial.printf("Scannable undirected\n");
      break;
    case BLE_GAP_ADV_TYPE_ADV_NONCONN_IND:
      Serial.printf("Non-connectable undirected\n");
      break;
  }

  /* Check for BLE UART UUID */
  if ( Bluefruit.Scanner.checkReportForUuid(report, BLEUART_UUID_SERVICE) )
  {
    Serial.printf("%14s %s\n", "BLE UART", "UUID Found!");
  }

  /* Check for DIS UUID */
  if ( Bluefruit.Scanner.checkReportForUuid(report, UUID16_SVC_DEVICE_INFORMATION) )
  {
    Serial.printf("%14s %s\n", "DIS", "UUID Found!");
  }

  Serial.println();
}
```

## void useActiveScan(bool enable);

Enabling 'Active Scan' by setting the `enable`&nbsp;parameter to 1 will cause the device to request the optional&nbsp; **Scan Response** advertising packet, which is a second 31 byte advertising packet that can be used to transmit additional information.

By default active scanning is disabled, so no Scan Response packets will be received by BLEScanner unless this function is called and set to 1 before calling `Bluefruit.Scanner.start(0)`.

## void filterRssi(int8\_t min\_rssi); void filterMSD(uint16\_t manuf\_id); void filterUuid(BLEUuid ble\_uuid); void filterUuid(BLEUuid ble\_uuid1, BLEUuid ble\_uuid2); void filterUuid(BLEUuid ble\_uuid1, BLEUuid ble\_uuid2, BLEUuid ble\_uuid3); void filterUuid(BLEUuid ble\_uuid1, BLEUuid ble\_uuid2, BLEUuid ble\_uuid3, BLEUuid ble\_uuid4); void filterUuid(BLEUuid ble\_uuid[], uint8\_t count);

Filters can be applied to BLEScanner to narrow down the data sent to the callback handler, and make processing advertising packets easier for you.

As of BSP 0.7.0 the following three filters are present:

- `filterRssi(int8_t min_rssi)`: Filters advertising results to devices with at least the specified RSSI value, which allows you to ignore devices that are too far away or whose signal is too weak. The higher the number, the strong the signal so -90 is a very weak signal, and -60 is a much stronger one.
- `filterUuid(BLEUuid ble_uuid)`: Filters advertising results to devices that advertise themselves as having the specified service UUID. If multiple UUIDs are entered, they will be filtered with boolean OR logic, meaning any single UUID present will be considered a match.
- `void filterMSD(uint16_t manuf_id)`: Fitlers advertising results to devices that contain a Manufacturer Specific Data data type, and who use the specifed Bluetooth Customer ID (`manuf_id)`. This can be useful to filter iBeacon versus Eddystone devices, for example, which both used the MSD field, or to look for custom MSD data matching your own CID.

Info: 

## void clearFilters(void);

This function clears and filter values set using the functions above.

## bool start(uint16\_t timeout = 0); bool stop(void);

The `.start` and `.stop` functions can be used to start and stop scanning, and should be called after all of the main parameters (timing, filters, etc.) have been set.

The `.start` function has a single parameter called timeout, which sets the number of seconds to scan for advertising packets. Setting this to '0' (the default value) will cause the device to scan forever.

Info: 

## void restartOnDisconnect(bool enable);

Setting this function to '1' will cause the scanning process to start again as soon as you disconnect from a peripheral device. The default behaviour is to automatically restart scanning on disconnect.

# Examples

For an example that uses almost all of the BLEScanner and advertising API in Central mode, see [central\_scan\_advanced.ino](https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/examples/Central/central_scan_advanced/central_scan_advanced.ino) in the Central examples folder.

[central_scan_advanced.ino on Github](https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/examples/Central/central_scan_advanced/central_scan_advanced.ino)
Info: 

# Introducing the Adafruit nRF52840 Feather

## BLEService

Danger: 

This base class is used when defining custom BLE Gatt Services, such as the various service helper classes that make up the Adafruit Bluefruit nRF52 API described here.

Unless you are implementing a custom GATT service and characteristic, you normally won't use this base class directly, and would instantiate and call a higher level helper service or characteristic included in the Bluefruit nRF52 API.

# Basic Usage

There are normally only two operation required to use the BLEService class:

You need to declare and instantiate the class with an appropriate 16-bit or 128-bit UUID in the constructor:

```
BLEService myService = BLEService(0x1234);
```

You then need to call the&nbsp;**.begin()**&nbsp;method on the instance before adding any BLECharacteristics to it (via the BLECharacteristic's respective .begin() function call):

```
myService.begin();
```

# Order of Operations (Important!)

One very important thing to take into consideration when working with BLEService and BLECharacteristic, is that any BLECharacteristic will automatically be added to the last BLEService that had it's `.begin()` function called. As such, you **must call&nbsp;yourService.begin() before adding any characteristics!**

See the example at the bottom of this page for a concrete example of how this works in practice.

# API

BLEService has the following overall class structure:

Info: 

```
BLEUuid uuid;

static BLEService* lastService;

BLEService(void);
BLEService(uint16_t uuid16);
BLEService(uint8_t const  uuid128[]);

void setUuid(uint16_t uuid16);
void setUuid(uint8_t const  uuid128[]);

virtual err_t begin(void);
```

# Example

The following example declares a HRM (Heart Rate Monitor) service, and assigns some characteristics to it:

Info: 

```
/* HRM Service Definitions
 * Heart Rate Monitor Service:  0x180D
 * Heart Rate Measurement Char: 0x2A37
 * Body Sensor Location Char:   0x2A38
 */
BLEService        hrms = BLEService(UUID16_SVC_HEART_RATE);
BLECharacteristic hrmc = BLECharacteristic(UUID16_CHR_HEART_RATE_MEASUREMENT);
BLECharacteristic bslc = BLECharacteristic(UUID16_CHR_BODY_SENSOR_LOCATION);

void setupHRM(void)
{
  // Configure the Heart Rate Monitor service
  // See: https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.heart_rate.xml
  // Supported Characteristics:
  // Name                         UUID    Requirement Properties
  // ---------------------------- ------  ----------- ----------
  // Heart Rate Measurement       0x2A37  Mandatory   Notify
  // Body Sensor Location         0x2A38  Optional    Read
  // Heart Rate Control Point     0x2A39  Conditional Write       &lt;-- Not used here
  hrms.begin();

  // Note: You must call .begin() on the BLEService before calling .begin() on
  // any characteristic(s) within that service definition.. Calling .begin() on
  // a BLECharacteristic will cause it to be added to the last BLEService that
  // was 'begin()'ed!

  // Configure the Heart Rate Measurement characteristic
  // See: https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.heart_rate_measurement.xml
  // Permission = Notify
  // Min Len    = 1
  // Max Len    = 8
  //    B0      = UINT8  - Flag (MANDATORY)
  //      b5:7  = Reserved
  //      b4    = RR-Internal (0 = Not present, 1 = Present)
  //      b3    = Energy expended status (0 = Not present, 1 = Present)
  //      b1:2  = Sensor contact status (0+1 = Not supported, 2 = Supported but contact not detected, 3 = Supported and detected)
  //      b0    = Value format (0 = UINT8, 1 = UINT16)
  //    B1      = UINT8  - 8-bit heart rate measurement value in BPM
  //    B2:3    = UINT16 - 16-bit heart rate measurement value in BPM
  //    B4:5    = UINT16 - Energy expended in joules
  //    B6:7    = UINT16 - RR Internal (1/1024 second resolution)
  hrmc.setProperties(CHR_PROPS_NOTIFY);
  hrmc.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
  hrmc.setFixedLen(2);
  hrmc.setCccdWriteCallback(cccd_callback);  // Optionally capture CCCD updates
  hrmc.begin();
  uint8_t hrmdata[2] = { 0b00000110, 0x40 }; // Set the characteristic to use 8-bit values, with the sensor connected and detected
  hrmc.notify(hrmdata, 2);                   // Use .notify instead of .write!

  // Configure the Body Sensor Location characteristic
  // See: https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.body_sensor_location.xml
  // Permission = Read
  // Min Len    = 1
  // Max Len    = 1
  //    B0      = UINT8 - Body Sensor Location
  //      0     = Other
  //      1     = Chest
  //      2     = Wrist
  //      3     = Finger
  //      4     = Hand
  //      5     = Ear Lobe
  //      6     = Foot
  //      7:255 = Reserved
  bslc.setProperties(CHR_PROPS_READ);
  bslc.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
  bslc.setFixedLen(1);
  bslc.begin();
  bslc.write8(2);    // Set the characteristic to 'Wrist' (2)
}

void cccd_callback(BLECharacteristic&amp; chr, uint16_t cccd_value)
{
    // Display the raw request packet
    Serial.print("CCCD Updated: ");
    //Serial.printBuffer(request-&gt;data, request-&gt;len);
    Serial.print(cccd_value);
    Serial.println("");

    // Check the characteristic this CCCD update is associated with in case
    // this handler is used for multiple CCCD records.
    if (chr.uuid == hrmc.uuid) {
        if (chr.notifyEnabled()) {
            Serial.println("Heart Rate Measurement 'Notify' enabled");
        } else {
            Serial.println("Heart Rate Measurement 'Notify' disabled");
        }
    }
}
```

# Introducing the Adafruit nRF52840 Feather

## BLECharacteristic

Danger: 

This base class is used when defining custom BLE GATT characteristics, and is used throughput the Adafruit Bluefruit nRF52 API and helper classes.

Unless you are implementing a custom GATT service and characteristic, you normally won't use this base class directly, and would instantiate and call a higher level helper service or characteristic included in the Bluefruit nRF52 API.

# Basic Usage

There are two main steps to using the BLECharacteristic class.

First, you need to declare and instantiate your BLECharacteristic class with a 16-bit or 128-bit UUID:

```
BLECharacteristic myChar = BLECharacteristic(0xABCD);

```

Then you need to set the relevant properties for the characteristic, with the following values at minimum:

```
myChar.setProperties(CHR_PROPS_READ);
myChar.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
myChar.setFixedLen(1); // Alternatively .setMaxLen(uint16_t len)
myChar.begin();
```

- **.setProperties** can be set to one or more of the following macros, which correspond to a single bit in the eight bit 'properties' field for the characteristic definition:

  - CHR\_PROPS\_BROADCAST = bit(0),
  - CHR\_PROPS\_READ = bit(1),
  - CHR\_PROPS\_WRITE\_WO\_RESP = bit(2),
  - CHR\_PROPS\_WRITE = bit(3),
  - CHR\_PROPS\_NOTIFY = bit(4),
  - CHR\_PROPS\_INDICATE = bit(5)

- **.setPermission** sets the security level for the characteristic, where the first value sets the read permissions, and the second value sets the write permissions, where both fields can have one of the following values:

  - SECMODE\_NO\_ACCESS = 0x00,
  - SECMODE\_OPEN = 0x11,
  - SECMODE\_ENC\_NO\_MITM = 0x21,
  - SECMODE\_ENC\_WITH\_MITM = 0x31,
  - SECMODE\_SIGNED\_NO\_MITM = 0x12,
  - SECMODE\_SIGNED\_WITH\_MITM = 0x22

- **.setFixedLen()** indicates how many bytes this characteristic has. For characteristics that use 'notify' or 'indicate' this value can be from 1..20, other characteristic types can be set from 1..512 and values \>20 bytes will be sent across multiple 20 byte packets. If the characteristic has a variable len, you set the **.setMaxLen()** value to the maximum value it will hold (up to 20 bytes).
- **.begin()** will cause this characteristic to be added to the last&nbsp; **BLEService** that had it's&nbsp;**.begin()** method called.

# Order of Operations (Important!)

One very important thing to take into consideration when working with BLEService and BLECharacteristic, is that any BLECharacteristic will automatically be added to the last BLEService that had it's `.begin()` function called. As such, you **must call&nbsp;yourService.begin() before adding any characteristics!**

See the example at the bottom of this page for a concrete example of how this works in practice.

# API

BLECharacteristic has the following overall class structure:

Info: 

```
/*--------- Callback Signatures ----------*/
typedef void (*read_authorize_cb_t)  (BLECharacteristic&amp; chr, ble_gatts_evt_read_t * request);
typedef void (*write_authorize_cb_t) (BLECharacteristic&amp; chr, ble_gatts_evt_write_t* request);
typedef void (*write_cb_t)           (BLECharacteristic&amp; chr, uint8_t* data, uint16_t len, uint16_t offset);
typedef void (*write_cccd_cb_t)      (BLECharacteristic&amp; chr, uint16_t value);

BLEUuid uuid;

// Constructors
BLECharacteristic(void);
BLECharacteristic(BLEUuid bleuuid);

// Destructor
virtual ~BLECharacteristic();

BLEService&amp; parentService(void);

void setTempMemory(void);

/*------------- Configure -------------*/
void setUuid(BLEUuid bleuuid);
void setProperties(uint8_t prop);
void setPermission(BleSecurityMode read_perm, BleSecurityMode write_perm);
void setMaxLen(uint16_t max_len);
void setFixedLen(uint16_t fixed_len);

/*------------- Descriptors -------------*/
void setUserDescriptor(const char* descriptor); // aka user descriptor
void setReportRefDescriptor(uint8_t id, uint8_t type); // TODO refactor to use addDescriptor()
void setPresentationFormatDescriptor(uint8_t type, int8_t exponent, uint16_t unit, uint8_t name_space = 1, uint16_t descritpor = 0);

/*------------- Callbacks -------------*/
void setWriteCallback        (write_cb_t fp);
void setCccdWriteCallback    (write_cccd_cb_t fp);
void setReadAuthorizeCallback(read_authorize_cb_t fp);
void setWriteAuthorizeCallbak(write_authorize_cb_t fp);

virtual err_t begin(void);

// Add Descriptor function must be called right after begin()
err_t addDescriptor(BLEUuid bleuuid, void const * content, uint16_t len, BleSecurityMode read_perm = SECMODE_OPEN, BleSecurityMode write_perm = SECMODE_NO_ACCESS);

ble_gatts_char_handles_t handles(void);

/*------------- Write -------------*/
uint16_t write(const void* data, uint16_t len);
uint16_t write(const char* str);

uint16_t write8    (uint8_t  num);
uint16_t write16   (uint16_t num);
uint16_t write32   (uint32_t num);
uint16_t write32   (int      num);


/*------------- Read -------------*/
uint16_t read(void* buffer, uint16_t bufsize);

uint8_t  read8 (void);
uint16_t read16(void);
uint32_t read32(void);

/*------------- Notify -------------*/
uint16_t getCccd(void);

bool notifyEnabled(void);

bool notify(const void* data, uint16_t len);
bool notify(const char* str);

bool notify8    (uint8_t  num);
bool notify16   (uint16_t num);
bool notify32   (uint32_t num);
bool notify32   (int      num);

/*------------- Indicate -------------*/
bool indicateEnabled(void);

bool indicate(const void* data, uint16_t len);
bool indicate(const char* str);

bool indicate8    (uint8_t  num);
bool indicate16   (uint16_t num);
bool indicate32   (uint32_t num);
bool indicate32   (int      num);

```

# Example

The following example configures an instance of the Heart Rate Monitor (HRM) Service and it's related characteristics:

Info: 

```
/* HRM Service Definitions
 * Heart Rate Monitor Service:  0x180D
 * Heart Rate Measurement Char: 0x2A37
 * Body Sensor Location Char:   0x2A38
 */
BLEService        hrms = BLEService(UUID16_SVC_HEART_RATE);
BLECharacteristic hrmc = BLECharacteristic(UUID16_CHR_HEART_RATE_MEASUREMENT);
BLECharacteristic bslc = BLECharacteristic(UUID16_CHR_BODY_SENSOR_LOCATION);

void setupHRM(void)
{
  // Configure the Heart Rate Monitor service
  // See: https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.heart_rate.xml
  // Supported Characteristics:
  // Name                         UUID    Requirement Properties
  // ---------------------------- ------  ----------- ----------
  // Heart Rate Measurement       0x2A37  Mandatory   Notify
  // Body Sensor Location         0x2A38  Optional    Read
  // Heart Rate Control Point     0x2A39  Conditional Write       &lt;-- Not used here
  hrms.begin();

  // Note: You must call .begin() on the BLEService before calling .begin() on
  // any characteristic(s) within that service definition.. Calling .begin() on
  // a BLECharacteristic will cause it to be added to the last BLEService that
  // was 'begin()'ed!

  // Configure the Heart Rate Measurement characteristic
  // See: https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.heart_rate_measurement.xml
  // Permission = Notify
  // Min Len    = 1
  // Max Len    = 8
  //    B0      = UINT8  - Flag (MANDATORY)
  //      b5:7  = Reserved
  //      b4    = RR-Internal (0 = Not present, 1 = Present)
  //      b3    = Energy expended status (0 = Not present, 1 = Present)
  //      b1:2  = Sensor contact status (0+1 = Not supported, 2 = Supported but contact not detected, 3 = Supported and detected)
  //      b0    = Value format (0 = UINT8, 1 = UINT16)
  //    B1      = UINT8  - 8-bit heart rate measurement value in BPM
  //    B2:3    = UINT16 - 16-bit heart rate measurement value in BPM
  //    B4:5    = UINT16 - Energy expended in joules
  //    B6:7    = UINT16 - RR Internal (1/1024 second resolution)
  hrmc.setProperties(CHR_PROPS_NOTIFY);
  hrmc.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
  hrmc.setFixedLen(2);
  hrmc.setCccdWriteCallback(cccd_callback);  // Optionally capture CCCD updates
  hrmc.begin();
  uint8_t hrmdata[2] = { 0b00000110, 0x40 }; // Set the characteristic to use 8-bit values, with the sensor connected and detected
  hrmc.notify(hrmdata, 2);                   // Use .notify instead of .write!

  // Configure the Body Sensor Location characteristic
  // See: https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.body_sensor_location.xml
  // Permission = Read
  // Min Len    = 1
  // Max Len    = 1
  //    B0      = UINT8 - Body Sensor Location
  //      0     = Other
  //      1     = Chest
  //      2     = Wrist
  //      3     = Finger
  //      4     = Hand
  //      5     = Ear Lobe
  //      6     = Foot
  //      7:255 = Reserved
  bslc.setProperties(CHR_PROPS_READ);
  bslc.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
  bslc.setFixedLen(1);
  bslc.begin();
  bslc.write8(2);    // Set the characteristic to 'Wrist' (2)
}

void cccd_callback(BLECharacteristic&amp; chr, uint16_t cccd_value)
{
    // Display the raw request packet
    Serial.print("CCCD Updated: ");
    //Serial.printBuffer(request-&gt;data, request-&gt;len);
    Serial.print(cccd_value);
    Serial.println("");

    // Check the characteristic this CCCD update is associated with in case
    // this handler is used for multiple CCCD records.
    if (chr.uuid == hrmc.uuid) {
        if (chr.notifyEnabled()) {
            Serial.println("Heart Rate Measurement 'Notify' enabled");
        } else {
            Serial.println("Heart Rate Measurement 'Notify' disabled");
        }
    }
}
```

# Introducing the Adafruit nRF52840 Feather

## BLEClientService

Danger: 

This base class is used when defining custom BLE Gatt Clients.

Unless you are implementing a custom GATT client service and characteristic, you normally won't use this base class directly, and would instantiate and call a higher level helper service or characteristic included in the Bluefruit nRF52 API.

# Basic Usage

There are normally only threes operations required to use the BLEClientService class:

1.) You need to declare and instantiate the class with an appropriate 16-bit or 128-bit UUID in the constructor:

```
BLEClientService myService = BLEService(0x1234);
```

2.) You then need to call the&nbsp;**.begin()**&nbsp;method on the instance before adding any BLEClientCharacteristics to it (via the BLEClientCharacteristic's respective **.begin()** function call):

```
myService.begin();
```

3) When connected e.g in connect callback, you should call **.discover()**&nbsp;to discover the service

```
myService.discover();
```

# API

BLEClientService has the following overall class structure:

Info: 

```
BLEUuid uuid;

// Constructors
BLEClientService(void);
BLEClientService(BLEUuid bleuuid);

virtual bool     begin(void);

virtual bool     discover  (uint16_t conn_handle);
        bool     discovered(void);

        uint16_t connHandle(void);

        void             setHandleRange(ble_gattc_handle_range_t handle_range);
ble_gattc_handle_range_t getHandleRange(void);
```

# Example

The following example declares a HRM (Heart Rate Monitor) service, and assigns some characteristics to it:

```
/*********************************************************************
 This is an example for our nRF52 based Bluefruit LE modules

 Pick one up today in the adafruit shop!

 Adafruit invests time and resources providing this open source code,
 please support Adafruit and open-source hardware by purchasing
 products from Adafruit!

 MIT license, check LICENSE for more information
 All text above, and the splash screen below must be included in
 any redistribution
*********************************************************************/

/* This sketch show how to use BLEClientService and BLEClientCharacteristic
 * to implement a custom client that is used to talk with Gatt server on
 * peripheral.
 *
 * Note: you will need another feather52 running peripheral/custom_HRM sketch
 * to test with.
 */

#include &lt;bluefruit.h&gt;

/* HRM Service Definitions
 * Heart Rate Monitor Service:  0x180D
 * Heart Rate Measurement Char: 0x2A37 (Mandatory)
 * Body Sensor Location Char:   0x2A38 (Optional)
 */

BLEClientService        hrms(UUID16_SVC_HEART_RATE);
BLEClientCharacteristic hrmc(UUID16_CHR_HEART_RATE_MEASUREMENT);
BLEClientCharacteristic bslc(UUID16_CHR_BODY_SENSOR_LOCATION);

void setup()
{
  Serial.begin(115200);

  Serial.println("Bluefruit52 Central Custom HRM Example");
  Serial.println("--------------------------------------\n");

  // Initialize Bluefruit with maximum connections as Peripheral = 0, Central = 1
  // SRAM usage required by SoftDevice will increase dramatically with number of connections
  Bluefruit.begin(0, 1);

  Bluefruit.setName("Bluefruit52 Central");

  // Initialize HRM client
  hrms.begin();

  // Initialize client characteristics of HRM.
  // Note: Client Char will be added to the last service that is begin()ed.
  bslc.begin();

  // set up callback for receiving measurement
  hrmc.setNotifyCallback(hrm_notify_callback);
  hrmc.begin();

  // Increase Blink rate to different from PrPh advertising mode
  Bluefruit.setConnLedInterval(250);

  // Callbacks for Central
  Bluefruit.Central.setDisconnectCallback(disconnect_callback);
  Bluefruit.Central.setConnectCallback(connect_callback);

  /* Start Central Scanning
   * - Enable auto scan if disconnected
   * - Interval = 100 ms, window = 80 ms
   * - Don't use active scan
   * - Filter only accept HRM service
   * - Start(timeout) with timeout = 0 will scan forever (until connected)
   */
  Bluefruit.Scanner.setRxCallback(scan_callback);
  Bluefruit.Scanner.restartOnDisconnect(true);
  Bluefruit.Scanner.setInterval(160, 80); // in unit of 0.625 ms
  Bluefruit.Scanner.filterUuid(hrms.uuid);
  Bluefruit.Scanner.useActiveScan(false);
  Bluefruit.Scanner.start(0);                   // // 0 = Don't stop scanning after n seconds
}

void loop()
{
  // do nothing
}

/**
 * Callback invoked when scanner pick up an advertising data
 * @param report Structural advertising data
 */
void scan_callback(ble_gap_evt_adv_report_t* report)
{
  // Connect to device with HRM service in advertising
  Bluefruit.Central.connect(report);
}

/**
 * Callback invoked when an connection is established
 * @param conn_handle
 */
void connect_callback(uint16_t conn_handle)
{
  Serial.println("Connected");
  Serial.print("Discovering HRM Service ... ");

  // If HRM is not found, disconnect and return
  if ( !hrms.discover(conn_handle) )
  {
    Serial.println("Found NONE");

    // disconect since we couldn't find HRM service
    Bluefruit.Central.disconnect(conn_handle);

    return;
  }

  // Once HRM service is found, we continue to discover its characteristic
  Serial.println("Found it");

  
  Serial.print("Discovering Measurement characteristic ... ");
  if ( !hrmc.discover() )
  {
    // Measurement chr is mandatory, if it is not found (valid), then disconnect
    Serial.println("not found !!!");  
    Serial.println("Measurement characteristic is mandatory but not found");
    Bluefruit.Central.disconnect(conn_handle);
    return;
  }
  Serial.println("Found it");

  // Measurement is found, continue to look for option Body Sensor Location
  // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.body_sensor_location.xml
  // Body Sensor Location is optional, print out the location in text if present
  Serial.print("Discovering Body Sensor Location characteristic ... ");
  if ( bslc.discover() )
  {
    Serial.println("Found it");
    
    // Body sensor location value is 8 bit
    const char* body_str[] = { "Other", "Chest", "Wrist", "Finger", "Hand", "Ear Lobe", "Foot" };

    // Read 8-bit BSLC value from peripheral
    uint8_t loc_value = bslc.read8();
    
    Serial.print("Body Location Sensor: ");
    Serial.println(body_str[loc_value]);
  }else
  {
    Serial.println("Found NONE");
  }

  // Reaching here means we are ready to go, let's enable notification on measurement chr
  if ( hrmc.enableNotify() )
  {
    Serial.println("Ready to receive HRM Measurement value");
  }else
  {
    Serial.println("Couldn't enable notify for HRM Measurement. Increase DEBUG LEVEL for troubleshooting");
  }
}

/**
 * Callback invoked when a connection is dropped
 * @param conn_handle
 * @param reason
 */
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
  (void) conn_handle;
  (void) reason;

  Serial.println("Disconnected");
}


/**
 * Hooked callback that triggered when a measurement value is sent from peripheral
 * @param chr   Pointer client characteristic that even occurred,
 *              in this example it should be hrmc
 * @param data  Pointer to received data
 * @param len   Length of received data
 */
void hrm_notify_callback(BLEClientCharacteristic* chr, uint8_t* data, uint16_t len)
{
  // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.heart_rate_measurement.xml
  // Measurement contains of control byte0 and measurement (8 or 16 bit) + optional field
  // if byte0's bit0 is 0 --&gt; measurement is 8 bit, otherwise 16 bit.

  Serial.print("HRM Measurement: ");

  if ( data[0] &amp; bit(0) )
  {
    uint16_t value;
    memcpy(&amp;value, data+1, 2);

    Serial.println(value);
  }
  else
  {
    Serial.println(data[1]);
  }
}

```

# Introducing the Adafruit nRF52840 Feather

## BLEClientCharacteristic

Danger: 

This base class is used when defining custom client for BLE GATT characteristics, and is used throughout the Adafruit Bluefruit nRF52 API and helper classes.

Unless you are implementing a custom client for GATT service and characteristic, you normally won't use this base class directly, and would instantiate and call a higher level helper service or characteristic included in the Bluefruit nRF52 API.

# Basic Usage

There are three main steps to using the BLECharacteristic class.

1.) First, you need to declare and instantiate your BLECharacteristic class with a 16-bit or 128-bit UUID:

```
BLEClientCharacteristic myChar = BLEClientCharacteristic(0xABCD);
```

2.) Then you need to set the relevant callback for the characteristic if it supports notify or indicate.

```
myChar.setNotifyCallback(notify_callback);
myChar.begin();
```

- **.setNotifyCallback&nbsp;** This sets the callback that will be fired when we receive a Notify message from peripheral. This is needed to handle notifiable characteristic since callback allow us to response to the message in timely manner
- **.begin()** will cause this characteristic to be added to the last&nbsp; **BLEClientService** that had it's&nbsp;**.begin()** method called.

3) Discover the characteristic after connected to peripheral by calling&nbsp;`.discover()`&nbsp;It is a must in order to perform any operation such as .read(), .write(), .enableNotify().

```
if ( myChar.discover() )
{
  uint32_t value = myChar.read32();
}
```

# API

BLEClientCharacteristic has the following overall class structure:

Info: 

```
/*--------- Callback Signatures ----------*/
typedef void (*notify_cb_t  ) (BLEClientCharacteristic* chr, uint8_t* data, uint16_t len);
typedef void (*indicate_cb_t) (BLEClientCharacteristic* chr, uint8_t* data, uint16_t len);

BLEUuid uuid;

// Constructors
BLEClientCharacteristic(void);
BLEClientCharacteristic(BLEUuid bleuuid);

// Destructor
virtual ~BLEClientCharacteristic();

void     begin(BLEClientService* parent_svc = NULL);

bool     discover(void);
bool     discovered(void);

uint16_t connHandle(void);
uint16_t valueHandle(void);
uint8_t  properties(void);

BLEClientService&amp; parentService(void);

/*------------- Read -------------*/
uint16_t read(void* buffer, uint16_t bufsize);
uint8_t  read8 (void);
uint16_t read16(void);
uint32_t read32(void);

/*------------- Write without Response-------------*/
uint16_t write     (const void* data, uint16_t len);
uint16_t write8    (uint8_t value);
uint16_t write16   (uint16_t value);
uint16_t write32   (uint32_t value);

/*------------- Write with Response-------------*/
uint16_t write_resp(const void* data, uint16_t len);
uint16_t write8_resp    (uint8_t value);
uint16_t write16_resp   (uint16_t value);
uint16_t write32_resp   (uint32_t value);

/*------------- Notify -------------*/
bool     writeCCCD       (uint16_t value);

bool     enableNotify    (void);
bool     disableNotify   (void);

bool     enableIndicate  (void);
bool     disableIndicate (void);

/*------------- Callbacks -------------*/
void     setNotifyCallback(notify_cb_t fp, bool useAdaCallback = true);
void     setIndicateCallback(indicate_cb_t fp, bool useAdaCallback = true);
```

# Example

The following example configures an instance of the Heart Rate Monitor (HRM) Service and it's related characteristics:

```auto
/*********************************************************************
 This is an example for our nRF52 based Bluefruit LE modules

 Pick one up today in the adafruit shop!

 Adafruit invests time and resources providing this open source code,
 please support Adafruit and open-source hardware by purchasing
 products from Adafruit!

 MIT license, check LICENSE for more information
 All text above, and the splash screen below must be included in
 any redistribution
*********************************************************************/

/* This sketch show how to use BLEClientService and BLEClientCharacteristic
 * to implement a custom client that is used to talk with Gatt server on
 * peripheral.
 *
 * Note: you will need another feather52 running peripheral/custom_HRM sketch
 * to test with.
 */

#include &lt;bluefruit.h&gt;

/* HRM Service Definitions
 * Heart Rate Monitor Service:  0x180D
 * Heart Rate Measurement Char: 0x2A37 (Mandatory)
 * Body Sensor Location Char:   0x2A38 (Optional)
 */

BLEClientService        hrms(UUID16_SVC_HEART_RATE);
BLEClientCharacteristic hrmc(UUID16_CHR_HEART_RATE_MEASUREMENT);
BLEClientCharacteristic bslc(UUID16_CHR_BODY_SENSOR_LOCATION);

void setup()
{
  Serial.begin(115200);

  Serial.println("Bluefruit52 Central Custom HRM Example");
  Serial.println("--------------------------------------\n");

  // Initialize Bluefruit with maximum connections as Peripheral = 0, Central = 1
  // SRAM usage required by SoftDevice will increase dramatically with number of connections
  Bluefruit.begin(0, 1);

  Bluefruit.setName("Bluefruit52 Central");

  // Initialize HRM client
  hrms.begin();

  // Initialize client characteristics of HRM.
  // Note: Client Char will be added to the last service that is begin()ed.
  bslc.begin();

  // set up callback for receiving measurement
  hrmc.setNotifyCallback(hrm_notify_callback);
  hrmc.begin();

  // Increase Blink rate to different from PrPh advertising mode
  Bluefruit.setConnLedInterval(250);

  // Callbacks for Central
  Bluefruit.Central.setDisconnectCallback(disconnect_callback);
  Bluefruit.Central.setConnectCallback(connect_callback);

  /* Start Central Scanning
   * - Enable auto scan if disconnected
   * - Interval = 100 ms, window = 80 ms
   * - Don't use active scan
   * - Filter only accept HRM service
   * - Start(timeout) with timeout = 0 will scan forever (until connected)
   */
  Bluefruit.Scanner.setRxCallback(scan_callback);
  Bluefruit.Scanner.restartOnDisconnect(true);
  Bluefruit.Scanner.setInterval(160, 80); // in unit of 0.625 ms
  Bluefruit.Scanner.filterUuid(hrms.uuid);
  Bluefruit.Scanner.useActiveScan(false);
  Bluefruit.Scanner.start(0);                   // // 0 = Don't stop scanning after n seconds
}

void loop()
{
  // do nothing
}

/**
 * Callback invoked when scanner pick up an advertising data
 * @param report Structural advertising data
 */
void scan_callback(ble_gap_evt_adv_report_t* report)
{
  // Connect to device with HRM service in advertising
  Bluefruit.Central.connect(report);
}

/**
 * Callback invoked when an connection is established
 * @param conn_handle
 */
void connect_callback(uint16_t conn_handle)
{
  Serial.println("Connected");
  Serial.print("Discovering HRM Service ... ");

  // If HRM is not found, disconnect and return
  if ( !hrms.discover(conn_handle) )
  {
    Serial.println("Found NONE");

    // disconect since we couldn't find HRM service
    Bluefruit.disconnect(conn_handle);

    return;
  }

  // Once HRM service is found, we continue to discover its characteristic
  Serial.println("Found it");

  
  Serial.print("Discovering Measurement characteristic ... ");
  if ( !hrmc.discover() )
  {
    // Measurement chr is mandatory, if it is not found (valid), then disconnect
    Serial.println("not found !!!");  
    Serial.println("Measurement characteristic is mandatory but not found");
    Bluefruit.disconnect(conn_handle);
    return;
  }
  Serial.println("Found it");

  // Measurement is found, continue to look for option Body Sensor Location
  // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.body_sensor_location.xml
  // Body Sensor Location is optional, print out the location in text if present
  Serial.print("Discovering Body Sensor Location characteristic ... ");
  if ( bslc.discover() )
  {
    Serial.println("Found it");
    
    // Body sensor location value is 8 bit
    const char* body_str[] = { "Other", "Chest", "Wrist", "Finger", "Hand", "Ear Lobe", "Foot" };

    // Read 8-bit BSLC value from peripheral
    uint8_t loc_value = bslc.read8();
    
    Serial.print("Body Location Sensor: ");
    Serial.println(body_str[loc_value]);
  }else
  {
    Serial.println("Found NONE");
  }

  // Reaching here means we are ready to go, let's enable notification on measurement chr
  if ( hrmc.enableNotify() )
  {
    Serial.println("Ready to receive HRM Measurement value");
  }else
  {
    Serial.println("Couldn't enable notify for HRM Measurement. Increase DEBUG LEVEL for troubleshooting");
  }
}

/**
 * Callback invoked when a connection is dropped
 * @param conn_handle
 * @param reason
 */
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
  (void) conn_handle;
  (void) reason;

  Serial.println("Disconnected");
}


/**
 * Hooked callback that triggered when a measurement value is sent from peripheral
 * @param chr   Pointer client characteristic that even occurred,
 *              in this example it should be hrmc
 * @param data  Pointer to received data
 * @param len   Length of received data
 */
void hrm_notify_callback(BLEClientCharacteristic* chr, uint8_t* data, uint16_t len)
{
  // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.heart_rate_measurement.xml
  // Measurement contains of control byte0 and measurement (8 or 16 bit) + optional field
  // if byte0's bit0 is 0 --&gt; measurement is 8 bit, otherwise 16 bit.

  Serial.print("HRM Measurement: ");

  if ( data[0] &amp; bit(0) )
  {
    uint16_t value;
    memcpy(&amp;value, data+1, 2);

    Serial.println(value);
  }
  else
  {
    Serial.println(data[1]);
  }
}
```

# Introducing the Adafruit nRF52840 Feather

## BLEDiscovery

Danger: 

BLEDiscovery is a helper class to make finding characteristics on a Gatt server (hosted on a BLE peripheral) easier. For service discovery, the BLEClientService's `discover()` API must be used, as shown below:

# API
```
BLEDiscovery(void); // Constructor

void     begin(void);
bool     begun(void);

void                     setHandleRange(ble_gattc_handle_range_t handle_range);
ble_gattc_handle_range_t getHandleRange(void);

uint8_t  discoverCharacteristic(uint16_t conn_handle, BLEClientCharacteristic* chr[], uint8_t count);
uint8_t  discoverCharacteristic(uint16_t conn_handle, BLEClientCharacteristic&amp; chr1);
uint8_t  discoverCharacteristic(uint16_t conn_handle, BLEClientCharacteristic&amp; chr1, BLEClientCharacteristic&amp; chr2);
uint8_t  discoverCharacteristic(uint16_t conn_handle, BLEClientCharacteristic&amp; chr1, BLEClientCharacteristic&amp; chr2, BLEClientCharacteristic&amp; chr3);
uint8_t  discoverCharacteristic(uint16_t conn_handle, BLEClientCharacteristic&amp; chr1, BLEClientCharacteristic&amp; chr2, BLEClientCharacteristic&amp; chr3, BLEClientCharacteristic&amp; chr4);
uint8_t  discoverCharacteristic(uint16_t conn_handle, BLEClientCharacteristic&amp; chr1, BLEClientCharacteristic&amp; chr2, BLEClientCharacteristic&amp; chr3, BLEClientCharacteristic&amp; chr4, BLEClientCharacteristic&amp; chr5);
```

Info: 

# Introducing the Adafruit nRF52840 Feather

## BLEDis

Danger: 

This helper class acts as a wrapper for the Bluetooth [Device Information Service](https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.device_information.xml)&nbsp;(0x180A). This official GATT service allows you to publish basic information about your device in a generic manner.

The Bluefruit BLEDis helper class exposes the following characteristics:

- [Model Number String](https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.model_number_string.xml) (0x2A24), exposed via **.setModel(const char\*)**
- [Serial Number String](https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.serial_number_string.xml) (0x2A25),&nbsp;private
- [Firmware Revision String](https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.firmware_revision_string.xml)&nbsp;(0x2A26), private
- [Hardware Revision String](https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.hardware_revision_string.xml)&nbsp;(0x2A27), exposed via **.setHardwareRev(const char\*)**
- [Software Revision String](https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.software_revision_string.xml) (0x2A28), exposed via **.setSoftwareRev(const char\*)**
- [Manufacturer Name String](https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.manufacturer_name_string.xml) (0x2A29), exposed via **.setManufacturer(const char\*)**

The **Serial Number String** &nbsp;is private and is populated with a unique device ID that nRF52832 SoCs are programmed with during manufacturing.

The&nbsp; **Firmware Revision String** is also private and is populated with the following fields (to help us track issues and offer better feedback in the support forums):

  - Softdevice Name (Sxxx)
  - Softdevice Version (x.x.x)
  - Bootloader Version (x.x.x)

Info: 

The remaining characteristics are all public and can be set to an value (up to 20 chars in length) using the appropriate helper function, but they have&nbsp;the following default values (for the nRF52832):

- **Model Number String** :&nbsp;Bluefruit Feather 52
- **Hardware Revision String** : NULL
- **Software Revision String** : The nRF52 BSP version number
- **Manufacturer Name String** : Adafruit Industries

Setting a public value to NULL will prevent the characteristic from being present in the DIS service.

# API

The following functions and constructors are defined in the BLEDis class:

```
BLEDis(void);

void setModel(const char* model);
void setHardwareRev(const char* hw_rev);
void setSoftwareRev(const char* sw_rev);
void setManufacturer(const char* manufacturer);

err_t begin(void);
```

The individual characteristic values are set via the&nbsp;**.set\*()** functions above, and when all values have been set you call the&nbsp;**.begin()** function to add the service to the device's internal GATT registry.

# Example

The following bare bones examples show how to setup the device information service with user-configurable strings for values:

```
#include &lt;bluefruit.h&gt;

BLEDis bledis;

void setup() 
{
  Serial.begin(115200);

  Serial.println("Bluefruit52 DIS Example");

  Bluefruit.begin();
  Bluefruit.setName("Bluefruit52");

  // Configure and Start Device Information Service
  bledis.setManufacturer("Adafruit Industries");
  bledis.setModel("Bluefruit Feather52");
  bledis.begin();

  // Set up Advertising Packet
  setupAdv();

  // Start Advertising
  Bluefruit.Advertising.start();
}

void setupAdv(void)
{  
  Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
  Bluefruit.Advertising.addTxPower();
  
  // There isn't enough room in the advertising packet for the
  // name so we'll place it on the secondary Scan Response packet
  Bluefruit.ScanResponse.addName();
}

void loop() 
{
}
```

# Output

If you examine the device using the Bluefruit LE Connect app on iOS, Android or OS X you should see something resembling the following output:

![](https://cdn-learn.adafruit.com/assets/assets/000/039/915/medium800/microcontrollers_Screen_Shot_2017-03-08_at_15.30.28.png?1488983967)

# Introducing the Adafruit nRF52840 Feather

## BLEUart

Danger: 

BLEUart is a wrapper class for NUS (Nordic UART Service), which is a proprietary service defined by Nordic Semiconductors that we use as a baseline transport mechanism between Bluefruit modules and our mobile and desktop Bluefruit LE Connect applications. You can use it to easily send ASCII or binary data in both directions, between the peripheral and the central device.

# API

BLEUart has the following public API:

```
// RX Callback signature (fires when data was written by the central)
typedef void (*rx_callback_t) (void);

// Constructor
BLEUart(uint16_t fifo_depth = BLE_UART_DEFAULT_FIFO_DEPTH);

virtual err_t begin(void);

bool notifyEnabled(void);

void setRxCallback( rx_callback_t fp);

// Stream API
virtual int       read       ( void );
virtual int       read       ( uint8_t * buf, size_t size );
virtual size_t    write      ( uint8_t b );
virtual size_t    write      ( const uint8_t *content, size_t len );
virtual int       available  ( void );
virtual int       peek       ( void );
virtual void      flush      ( void );

// Pull in write(str) and write(buf, size) from Print
using Print::write;
```

# Example

The following example shows how to use the BLEUart helper class.

This example may be out of date, and you should always consult the latest example code in the nRF52 BSP!

```
#include &lt;bluefruit.h&gt;

BLEDis  bledis;
BLEUart bleuart;
BLEBas  blebas;

#define STATUS_LED  (17)
#define BLINKY_MS   (2000)

uint32_t blinkyms;

void setup()
{
  Serial.begin(115200);

  Serial.println("Bluefruit52 BLEUART Example");

  // Setup LED pins and reset blinky counter
  pinMode(STATUS_LED, OUTPUT);
  blinkyms = millis();

  // Setup the BLE LED to be enabled on CONNECT
  // Note: This is actually the default behaviour, but provided
  // here in case you want to control this manually via PIN 19
  Bluefruit.autoConnLed(true);

  Bluefruit.begin();
  Bluefruit.setName("Bluefruit52");
  Bluefruit.setConnectCallback(connect_callback);
  Bluefruit.setDisconnectCallback(disconnect_callback);

  // Configure and Start Device Information Service
  bledis.setManufacturer("Adafruit Industries");
  bledis.setModel("Bluefruit Feather52");
  bledis.begin();

  // Configure and Start BLE Uart Service
  bleuart.begin();

  // Start BLE Battery Service
  blebas.begin();
  blebas.update(100);

  // Set up Advertising Packet
  setupAdv();

  // Start Advertising
  Bluefruit.Advertising.start();
}

void setupAdv(void)
{
  Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
  Bluefruit.Advertising.addTxPower();

  // Include bleuart 128-bit uuid
  Bluefruit.Advertising.addService(bleuart);

  // There is no room for Name in Advertising packet
  // Use Scan response for Name
  Bluefruit.ScanResponse.addName();
}

void loop()
{
  // Blinky!
  if (blinkyms+BLINKY_MS &lt; millis()) {
    blinkyms = millis();
    digitalToggle(STATUS_LED);
  }

  // Forward from Serial to BLEUART
  if (Serial.available())
  {
    // Delay to get enough input data since we have a
    // limited amount of space in the transmit buffer
    delay(2);

    uint8_t buf[64];
    int count = Serial.readBytes(buf, sizeof(buf));
    bleuart.write( buf, count );
  }

  // Forward from BLEUART to Serial
  if ( bleuart.available() )
  {
    uint8_t ch;
    ch = (uint8_t) bleuart.read();
    Serial.write(ch);
  }
}

void connect_callback(void)
{
  Serial.println("Connected");
}

void disconnect_callback(uint8_t reason)
{
  (void) reason;

  Serial.println();
  Serial.println("Disconnected");
  Serial.println("Bluefruit will start advertising again");
}
```

# Introducing the Adafruit nRF52840 Feather

## BLEClientUart

Danger: 

BLEClientUart is a wrapper class for the client side of the NUS or 'Nordic UART Service' (aka 'BLE UART'). It is only required when your Bluefruit nRF52 board is acting as Central communicating to other BLE peripherals that expose the&nbsp;[BLEUart](../../../../bluefruit-nrf52-feather-learning-guide/bleuart)&nbsp;service.

# API

BLEClientUart has the following public API:

```
// Callback Signatures
typedef void (*rx_callback_t) (BLEClientUart&amp; svc);

BLEClientUart(uint16_t fifo_depth = BLE_UART_DEFAULT_FIFO_DEPTH);

virtual bool  begin(void);
virtual bool  discover(uint16_t conn_handle);

void setRxCallback( rx_callback_t fp);

bool enableTXD(void);
bool disableTXD(void);

// Stream API
virtual int       read       ( void );
virtual int       read       ( uint8_t * buf, size_t size );
        int       read       ( char    * buf, size_t size ) { return read( (uint8_t*) buf, size); }
virtual size_t    write      ( uint8_t b );
virtual size_t    write      ( const uint8_t *content, size_t len );
virtual int       available  ( void );
virtual int       peek       ( void );
virtual void      flush      ( void );
```

# Examples

The following example shows how to use the BLEClientUart helper class.

```
#include &lt;bluefruit.h&gt;

BLEClientDis  clientDis;
BLEClientUart clientUart;

void setup()
{
  Serial.begin(115200);

  Serial.println("Bluefruit52 Central BLEUART Example");
  Serial.println("-----------------------------------\n");
  
  // Initialize Bluefruit with maximum connections as Peripheral = 0, Central = 1
  // SRAM usage required by SoftDevice will increase dramatically with number of connections
  Bluefruit.begin(0, 1);
  
  Bluefruit.setName("Bluefruit52 Central");

  // Configure DIS client
  clientDis.begin();

  // Init BLE Central Uart Serivce
  clientUart.begin();
  clientUart.setRxCallback(bleuart_rx_callback);

  // Increase Blink rate to different from PrPh advertising mode
  Bluefruit.setConnLedInterval(250);

  // Callbacks for Central
  Bluefruit.Central.setConnectCallback(connect_callback);
  Bluefruit.Central.setDisconnectCallback(disconnect_callback);

  /* Start Central Scanning
   * - Enable auto scan if disconnected
   * - Interval = 100 ms, window = 80 ms
   * - Don't use active scan
   * - Start(timeout) with timeout = 0 will scan forever (until connected)
   */
  Bluefruit.Scanner.setRxCallback(scan_callback);
  Bluefruit.Scanner.restartOnDisconnect(true);
  Bluefruit.Scanner.setInterval(160, 80); // in unit of 0.625 ms
  Bluefruit.Scanner.useActiveScan(false);
  Bluefruit.Scanner.start(0);                   // // 0 = Don't stop scanning after n seconds
}

/**
 * Callback invoked when scanner pick up an advertising data
 * @param report Structural advertising data
 */
void scan_callback(ble_gap_evt_adv_report_t* report)
{
  // Check if advertising contain BleUart service
  if ( Bluefruit.Scanner.checkReportForService(report, clientUart) )
  {
    Serial.print("BLE UART service detected. Connecting ... ");

    // Connect to device with bleuart service in advertising
    Bluefruit.Central.connect(report);
  }
}

/**
 * Callback invoked when an connection is established
 * @param conn_handle
 */
void connect_callback(uint16_t conn_handle)
{
  Serial.println("Connected");

  Serial.print("Dicovering DIS ... ");
  if ( clientDis.discover(conn_handle) )
  {
    Serial.println("Found it");
    char buffer[32+1];
    
    // read and print out Manufacturer
    memset(buffer, 0, sizeof(buffer));
    if ( clientDis.getManufacturer(buffer, sizeof(buffer)) )
    {
      Serial.print("Manufacturer: ");
      Serial.println(buffer);
    }

    // read and print out Model Number
    memset(buffer, 0, sizeof(buffer));
    if ( clientDis.getModel(buffer, sizeof(buffer)) )
    {
      Serial.print("Model: ");
      Serial.println(buffer);
    }

    Serial.println();
  }  

  Serial.print("Discovering BLE Uart Service ... ");

  if ( clientUart.discover(conn_handle) )
  {
    Serial.println("Found it");

    Serial.println("Enable TXD's notify");
    clientUart.enableTXD();

    Serial.println("Ready to receive from peripheral");
  }else
  {
    Serial.println("Found NONE");
    
    // disconect since we couldn't find bleuart service
    Bluefruit.Central.disconnect(conn_handle);
  }  
}

/**
 * Callback invoked when a connection is dropped
 * @param conn_handle
 * @param reason
 */
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
  (void) conn_handle;
  (void) reason;
  
  Serial.println("Disconnected");
}

/**
 * Callback invoked when uart received data
 * @param uart_svc Reference object to the service where the data 
 * arrived. In this example it is clientUart
 */
void bleuart_rx_callback(BLEClientUart&amp; uart_svc)
{
  Serial.print("[RX]: ");
  
  while ( uart_svc.available() )
  {
    Serial.print( (char) uart_svc.read() );
  }

  Serial.println();
}

void loop()
{
  if ( Bluefruit.Central.connected() )
  {
    // Not discovered yet
    if ( clientUart.discovered() )
    {
      // Discovered means in working state
      // Get Serial input and send to Peripheral
      if ( Serial.available() )
      {
        delay(2); // delay a bit for all characters to arrive
        
        char str[20+1] = { 0 };
        Serial.readBytes(str, 20);
        
        clientUart.print( str );
      }
    }
  }
}

```

# Introducing the Adafruit nRF52840 Feather

## BLEBeacon

Danger: 

The BLEBeacon helper class allows you to easily configure the nRF52 as a 'Beacon', which uses the advertising packet to send out a specifically format chunk of data to any devices in listening range.

The following values must be set in order to generate a valid 'Beacon' packet:

- **Manufacturer ID** : A 16-bit value ([registered with the Bluetooth SIG](https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers)!) that identifies the manufacturer.
- **Major** : A 16-bit 'Major' number, used to differentiate beacon nodes.
- **Minor** : A 16-bit 'Minor' number, used to differentiate beacon nodes.
- **RSSI @ 1M** : A signed 8-bit value (int8\_t) indicating the RSSI measurement at 1m distance from the node, used to estimate distance to the beacon itself.

These values can either be set in the constructor, or via the individual functions exposed as part of this helper class.

# API

BLEBeacon has the following public API:

```
// Constructors
BLEBeacon(void);
BLEBeacon(uint8_t const uuid128[16]);
BLEBeacon(uint8_t const uuid128[16], uint16_t major, uint16_t minor, int8_t rssi);

// Set the beacon payload values
void setManufacturer(uint16_t manfacturer);
void setUuid(uint8_t const uuid128[16]);
void setMajorMinor(uint16_t major, uint16_t minor);
void setRssiAt1m(int8_t rssi);

// Start advertising
bool start(void);
bool start(BLEAdvertising&amp; adv);
```

In addition to these functions, the BLEAdvertising class (accessible via `Bluefruit.Advertising.*`) exposes the following function to assign Beacon payload to the advertising payload:

```
bool setBeacon(BLEBeacon&amp; beacon);
```

See the example below for a concrete usage example.

# Example

The following example will configure the nRF52 to advertise a 'Beacon' payload:

```
#include &lt;bluefruit.h&gt;

// Beacon uses the Manufacturer Specific Data field in the advertising
// packet, which means you must provide a valid Manufacturer ID. Update
// the field below to an appropriate value. For a list of valid IDs see:
// https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers
// 0x004C is Apple (for example)
#define MANUFACTURER_ID   0x004C 

// AirLocate UUID: E2C56DB5-DFFB-48D2-B060-D0F5A71096E0
uint8_t beaconUuid[16] = 
{ 
  0xE2, 0xC5, 0x6D, 0xB5, 0xDF, 0xFB, 0x48, 0xD2, 
  0xB0, 0x60, 0xD0, 0xF5, 0xA7, 0x10, 0x96, 0xE0, 
};

// A valid Beacon packet consists of the following information:
// UUID, Major, Minor, RSSI @ 1M
BLEBeacon beacon(beaconUuid, 0x0001, 0x0000, -54);

void setup() 
{
  Serial.begin(115200);

  Serial.println("Bluefruit52 Beacon Example");

  Bluefruit.begin();
  Bluefruit.setName("Bluefruit52");

  // Manufacturer ID is required for Manufacturer Specific Data
  beacon.setManufacturer(MANUFACTURER_ID);

  // Setup the advertising packet
  setupAdv();

  // Start advertising
  Bluefruit.Advertising.start();
}

void setupAdv(void)
{  
  // Set the beacon payload using the BLEBeacon class populated
  // earlier in this example
  Bluefruit.Advertising.setBeacon(beacon);

  // char* adv = Bluefruit.Advertising.getData();

  // There is no room left for 'Name' in the advertising packet
  // Use the optinal secondary Scan Response packet for 'Name' instead
  Bluefruit.ScanResponse.addName();
}

void loop() 
{
  // Toggle both LEDs every second
  digitalToggle(LED_BUILTIN);
  delay(1000);
}
```

# Testing

If you test with the nRF Beacons application ([iOS](https://itunes.apple.com/app/nrf-beacons/id879614768?mt=8) or [Android](https://play.google.com/store/apps/details?id=no.nordicsemi.android.nrfbeacon)) you can configure the app to look for the UUID, Manufacturer ID, Major and Minor values you provided, and you should be able to see the beacon, as shown in the two screenshots below:

Info: 

![](https://cdn-learn.adafruit.com/assets/assets/000/039/997/medium800/microcontrollers_nRFBeacons.png?1489070637)

# Introducing the Adafruit nRF52840 Feather

## BLEMidi

Danger: 

BLEMidi is a helper class that adds support for sending and receiving MIDI Messages using the [MIDI over Bluetooth LE specification][ble-spec]. BLEMidi supports the full standard MIDI protocol (including SysEx messages), and it also can act as the hardware interface for the [Arduino MIDI Library][midi-lib].

[ble-spec]: https://www.midi.org/specifications-old/item/bluetooth-le-midi
[midi-lib]: http://playground.arduino.cc/Main/MIDILibrary

## API

BLEMidi has the following public API.

```
// Constructor
BLEMidi(uint16_t fifo_depth = 128);

err_t     begin         (void);
bool      notifyEnabled (void);

// Stream API for Arduino MIDI Library Interface
int       read       (void);
size_t    write      (uint8_t b);
int       available  (void);
int       peek       (void);
void      flush      (void);

size_t    write      (const char *str);
size_t    write      (const uint8_t *buffer, size_t size);
```

## Installing the Arduino MIDI Library

BLEMidi is easiest to use when combined with the [Arduino MIDI Library][midi-lib] by Francois Best, lathoub. You will need version 4.3.1 installed before continuing with the example code.

[midi-lib]: http://playground.arduino.cc/Main/MIDILibrary

![](https://cdn-learn.adafruit.com/assets/assets/000/040/254/medium800/microcontrollers_library_manager.png?1489783708)

Next, select **Communication** from the topic dropdown, and enter **MIDI Library** into the search box. Click the **Install** button to install version 4.3.0 or higher of the **MIDI Library**.

![](https://cdn-learn.adafruit.com/assets/assets/000/040/256/medium800thumb/microcontrollers_install.jpg?1489784023)

## Example

The **blemidi** example demonstrates how to use the BLEMidi helper class with the **Arduino MIDI Library**. The example sends a looping arpeggio, and prints any incoming MIDI note on and note off messages to the Arduino Serial Monitor.

![](https://cdn-learn.adafruit.com/assets/assets/000/040/257/medium800/microcontrollers_Screen_Shot_2017-03-17_at_5.09.58_PM.png?1489785055)

This example may be out of date, and you should always consult the latest example code in the Bluefruit52 example folder!

```
/*********************************************************************
 This is an example for our nRF52 based Bluefruit LE modules

 Pick one up today in the adafruit shop!

 Adafruit invests time and resources providing this open source code,
 please support Adafruit and open-source hardware by purchasing
 products from Adafruit!

 MIT license, check LICENSE for more information
 All text above, and the splash screen below must be included in
 any redistribution
*********************************************************************/
#include &lt;bluefruit.h&gt;
#include &lt;MIDI.h&gt;

BLEDis bledis;
BLEMidi blemidi;

// Create a new instance of the Arduino MIDI Library,
// and attach BluefruitLE MIDI as the transport.
MIDI_CREATE_BLE_INSTANCE(blemidi);

// Variable that holds the current position in the sequence.
int position = 0;

// Store example melody as an array of note values
byte note_sequence[] = {
  74,78,81,86,90,93,98,102,57,61,66,69,73,78,81,85,88,92,97,100,97,92,88,85,81,78,
  74,69,66,62,57,62,66,69,74,78,81,86,90,93,97,102,97,93,90,85,81,78,73,68,64,61,
  56,61,64,68,74,78,81,86,90,93,98,102
};

void setup()
{
  Serial.begin(115200);
  Serial.println("Adafruit Bluefruit52 MIDI over Bluetooth LE Example");

  Bluefruit.begin();
  Bluefruit.setName("Bluefruit52 MIDI");

  // Setup the on board blue LED to be enabled on CONNECT
  Bluefruit.autoConnLed(true);

  // Configure and Start Device Information Service
  bledis.setManufacturer("Adafruit Industries");
  bledis.setModel("Bluefruit Feather52");
  bledis.begin();

  // Initialize MIDI, and listen to all MIDI channels
  // This will also call blemidi service's begin()
  MIDI.begin(MIDI_CHANNEL_OMNI);

  // Attach the handleNoteOn function to the MIDI Library. It will
  // be called whenever the Bluefruit receives MIDI Note On messages.
  MIDI.setHandleNoteOn(handleNoteOn);

  // Do the same for MIDI Note Off messages.
  MIDI.setHandleNoteOff(handleNoteOff);

  // Set General Discoverable Mode flag
  Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);

  // Advertise TX Power
  Bluefruit.Advertising.addTxPower();

  // Advertise BLE MIDI Service
  Bluefruit.Advertising.addService(blemidi);

  // Advertise device name in the Scan Response
  Bluefruit.ScanResponse.addName();

  // Start Advertising
  Bluefruit.Advertising.start();

  // Start MIDI read loop
  Scheduler.startLoop(midiRead);
}

void handleNoteOn(byte channel, byte pitch, byte velocity)
{
  // Log when a note is pressed.
  Serial.printf("Note on: channel = %d, pitch = %d, velocity - %d", channel, pitch, velocity);
  Serial.println();
}

void handleNoteOff(byte channel, byte pitch, byte velocity)
{
  // Log when a note is released.
  Serial.printf("Note off: channel = %d, pitch = %d, velocity - %d", channel, pitch, velocity);
  Serial.println();
}

void loop()
{
  // Don't continue if we aren't connected.
  if (! Bluefruit.connected()) {
    return;
  }

  // Don't continue if the connected device isn't ready to receive messages.
  if (! blemidi.notifyEnabled()) {
    return;
  }

  // Setup variables for the current and previous
  // positions in the note sequence.
  int current = position;
  int previous  = position - 1;

  // If we currently are at position 0, set the
  // previous position to the last note in the sequence.
  if (previous &lt; 0) {
    previous = sizeof(note_sequence) - 1;
  }

  // Send Note On for current position at full velocity (127) on channel 1.
  MIDI.sendNoteOn(note_sequence[current], 127, 1);

  // Send Note Off for previous note.
  MIDI.sendNoteOff(note_sequence[previous], 0, 1);

  // Increment position
  position++;

  // If we are at the end of the sequence, start over.
  if (position &gt;= sizeof(note_sequence)) {
    position = 0;
  }

  delay(286);

}

void midiRead()
{
  // Don't continue if we aren't connected.
  if (! Bluefruit.connected()) {
    return;
  }

  // Don't continue if the connected device isn't ready to receive messages.
  if (! blemidi.notifyEnabled()) {
    return;
  }

  // read any new MIDI messages
  MIDI.read();
}
```

## Usage

You will need to do a small bit of setup on your selected platform to connect to the BLE MIDI enabled Bluefruit52.

Click on a platform below to view BLE MIDI setup instructions for your device:

* [macOS (OS X)](https://learn.adafruit.com/wireless-untztrument-using-ble-midi/macos-os-x)
* [iOS](https://learn.adafruit.com/wireless-untztrument-using-ble-midi/ios)
* [Android](https://learn.adafruit.com/wireless-untztrument-using-ble-midi/android)
* [Windows](https://learn.adafruit.com/wireless-untztrument-using-ble-midi/windows)

The arpeggio should automatically play once the Bluefruit52 is connected to your software synth. The video below shows the Bluefruit52 connected to [Moog's Animoog on iOS](https://www.moogmusic.com/products/apps/animoog-0).

Info: 

https://youtu.be/NkkDP_NkIQ4

# Introducing the Adafruit nRF52840 Feather

## BLEHidAdafruit

Danger: 

BLEHidAdafruit allows you to simulate a mouse or keyboard using the HID (Human Interface Device) profile&nbsp;that is part of the Bluetooth Low Energy standard.

Most modern mobile devices with Bluetooth Low Energy support, and the latest operating systems generally support Bluetooth Low Energy mice and keyboards out of the box, once you pair your Bluefruit nRF52/nRF52840 Feather and run an appropriate sketch.

# API

The BLEHidAdafruit helper class has the following public API:

```
// Constructor
BLEHidAdafruit(void);

// Call this once to start the HID service
virtual err_t begin(void);

// Keyboard
err_t keyboardReport(hid_keyboard_report_t* report);
err_t keyboardReport(uint8_t modifier, uint8_t keycode[6]);
err_t keyboardReport(uint8_t modifier, uint8_t keycode0, uint8_t keycode1=0, uint8_t keycode2=0, uint8_t keycode3=0, uint8_t keycode4=0, uint8_t keycode5=0);

err_t keyPress(char ch);
err_t keyRelease(void);
err_t keySequence(const char* str, int interal=5);

// Consumer Media Keys
err_t consumerReport(uint16_t usage_code);
err_t consumerKeyPress(uint16_t usage_code);
err_t consumerKeyRelease(void);

// Mouse
err_t mouseReport(hid_mouse_report_t* report);
err_t mouseReport(uint8_t buttons, int8_t x, int8_t y, int8_t wheel=0, int8_t pan=0);

err_t mouseButtonPress(uint8_t buttons);
err_t mouseButtonRelease(void);

err_t mouseMove(int8_t x, int8_t y);
err_t mouseScroll(int8_t scroll);
err_t mousePan(int8_t pan);
```

# Example Sketches

There are a variety of example sketches showing how to use the BLEHidAdafruit class. You can browse the latest source code on Github with the following links:

- [hid\_keyboard](https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/examples/Peripheral/blehid_keyboard/blehid_keyboard.ino): This example will simulate an HID keyboard,&nbsp;waiting for data to arrive via the nRF52's serial port (via USB serial), and send that data over the air to the bonded Central device.
- [hid\_mouse](https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/examples/Peripheral/blehid_mouse/blehid_mouse.ino): This example will simulate an HID mouse. To use it run the sketch and open the Serial Monitor, then enter the appropriate characters to move the mouse or trigger/release the mouse buttons.

# Bonding HID Devices

In order to use your HID mouse or keyboard, you will first need to&nbsp; **bond** the two devices. The bonding process involves the following steps:

- The two devices will connect to each other normally
- A set of security keys are exchanged between the two devices, and stores in non-volatile memory on each side. This is to ensure that each side is reasonably confident it is talking to the device it thinks it is for future connections, and to encrypt over the air communication between the devices (so that people can 'sniff' your keyboard data, etc.).
- On the nRF52 side this key data will be stored in a section of flash memory reserved for this purpose using an internal file system.
- The process of storing these security keys is referred to as&nbsp; **bonding** , and allows bonded devices to securely communicate without user interaction in the future.
- To cancel the bonding agreement, you can simply delete the keys on the nRF52 via the [clearbonds](https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/examples/Peripheral/clearbonds/clearbonds.ino)&nbsp;sketch, or delete the bonding data on your mobile device of computer.

Danger: 

## Setting up your Bluefruit device for bonding

To bond an device, run an appropriate HID sketch on the nRF52 to emulate either an HID mouse or an HID keyboard. In the event that you use the HID mouse example you may need to open the Serial Monitor to use it.

In this example we'll run the&nbsp; **hid\_keyboard** example sketch, flashing it to the nRF52, which should give you the following results:

![](https://cdn-learn.adafruit.com/assets/assets/000/040/349/medium800/microcontrollers_Screen_Shot_2017-03-21_at_19.13.24.png?1490120023)

Opening the Serial Monitor will give you the following output (though it may differ depending on the debug level you have selected):

![](https://cdn-learn.adafruit.com/assets/assets/000/040/351/medium800/microcontrollers_Screen_Shot_2017-03-21_at_19.35.37.png?1490121378)

## Bonding on iOS

To bond to an iOS device, make sure the sketch is running (as described above) and go into your&nbsp; **Settings** &nbsp;app and Select&nbsp; **Bluetooth**.

You should see a device at the bottom of this page called&nbsp; **Bluefruit52** (this may vary depending on the version of the sketch you are using!):

![](https://cdn-learn.adafruit.com/assets/assets/000/040/352/medium800/microcontrollers_iOSBonding.png?1490121766)

Click the device, and you will get a pairing request like this:

![](https://cdn-learn.adafruit.com/assets/assets/000/040/353/medium800/microcontrollers_iOSPairingConfirm.png?1490121904)

Click the&nbsp; **Pair** button, and the devices will be paired and bonded, and will automatically connect to each other in the future.

If everything went will, you will see the device in your&nbsp; **MY DEVICES** list, as follows:

![](https://cdn-learn.adafruit.com/assets/assets/000/040/354/medium800/microcontrollers_iOSBonded.png?1490121988)

## Testing the HID Keyboard and Bonding

To test the HID keyboard sketch and bonding process, open&nbsp;the **Serial Monitor** (or your favorite terminal emulator), enter some text, and if you are using the Serial Monitor click the **Send** button. This will send some text over the air to whatever&nbsp;textbox or text control has focus in your app.

![](https://cdn-learn.adafruit.com/assets/assets/000/040/355/medium800/microcontrollers_Screen_Shot_2017-03-21_at_19.47.39.png?1490122145)

The text will then appear in your mobile app or bonded device.

If the characters don't match exactly what you send, be sure to check your&nbsp; **keyboard language** settings, since you may be sending data to a device with a different keyboard setup!

# Introducing the Adafruit nRF52840 Feather

## BLEAncs

Danger: 

BLEAncs is a helper class that enables you to receive notifications from the [Apple Notification Center Service](https://developer.apple.com/library/archive/documentation/CoreBluetooth/Reference/AppleNotificationCenterServiceSpecification/Introduction/Introduction.html) from devices such as an iPhone or iPad. It can be used to receive alerts such as incoming or missed calls, email messages, or most alerts that appear on the mobile device's screen when locked.

# API

Because the BLEAncs class is a work in progress, the latest public API for the BLEAncs helper class should be viewed&nbsp;[here](https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/src/clients/BLEAncs.h).

# ANCS OLED Example

The **[ancs\_oled](https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/examples/Peripheral/ancs_oled/ancs_oled.ino)** example uses the [Adafruit FeatherWing OLED](https://www.adafruit.com/product/2900) to display any incoming alerts.

## Sketch Requirements

In order to use this example sketch the following libraries must be installed on your system:

- [Adafruit\_GFX](../../../../adafruit-oled-featherwing/download?view=all#install-adafruit-gfx) ([Github source](https://github.com/adafruit/Adafruit-GFX-Library))
- [Adafruit\_SSD1306](../../../../adafruit-oled-featherwing/download?view=all#install-adafruit-ssd1306-library) ([Github source](https://github.com/adafruit/Adafruit_SSD1306))
- Version 0.6.0 or higher of the Bluefruit nRF52 BSP

## Loading the Sketch

The ancs\_oled sketch can be&nbsp;loaded via the examples menu under&nbsp; **Peripheral \> ancs\_oled** :

![](https://cdn-learn.adafruit.com/assets/assets/000/042/984/medium800/microcontrollers_Screen_Shot_2017-06-25_at_23.48.30.png?1498427297)

With the sketch loaded, you can build the firmware and then flash it to your device via the&nbsp; **Upload** button or menu option:

![](https://cdn-learn.adafruit.com/assets/assets/000/042/985/medium800/microcontrollers_Screen_Shot_2017-06-25_at_23.56.54.png?1498427916)

Danger: 

Once the sketch is running on the nRF52 Feather you can proceed with the one-time&nbsp;pairing process, described below.

## Pairing&nbsp;to your Mobile Device

Before you can start receiving notifications, you will need to 'pair' the nRF52 Feather and the mobile device.

The pairing&nbsp;process causes a set of keys to be exchanged and stored on the two devices so that each side knows it is talking to the same device it originally bonded with, and preventing any devices in the middle from eavesdropping on potentially sensitive data.

The one-time pairing process is described below, and assumes you are already running the ancs\_oled sketch on your nRF52 device.

1. In the&nbsp; **Settings** app go to **Bluetooth** :

![](https://cdn-learn.adafruit.com/assets/assets/000/042/990/medium800/microcontrollers_bonding1.jpg?1498429233)

2. Scroll to the bottom of the list of 'My Devices'&nbsp;and click on&nbsp; **Bluefruit52&nbsp;** under&nbsp; **Other Devices** :

![](https://cdn-learn.adafruit.com/assets/assets/000/042/991/medium800/microcontrollers_bonding2.jpg?1498429240)

3. When the pairing dialog box comes up, click the&nbsp; **Pair** button:

![](https://cdn-learn.adafruit.com/assets/assets/000/042/988/medium800/microcontrollers_bonding3.jpg?1498428945)

4.&nbsp;Wait for the pairing process to complete, at which point&nbsp; **Bluefruit52** &nbsp;should appear in the&nbsp; **My Devices** list with the&nbsp; **Connected** status:

![](https://cdn-learn.adafruit.com/assets/assets/000/042/992/medium800/microcontrollers_bonding4.jpg?1498429251)

Info: 

## Wait for Alerts

At this point, any alerts that the mobile device generates will be displayed on the OLED display along with the notification category and date:

![](https://cdn-learn.adafruit.com/assets/assets/000/042/993/medium800/microcontrollers_alert1.jpg?1498429792)

Certain alerts (such as incoming calls) can also have actions associated with them, making use of the three buttons on the left-hand side of the display to decide which action to take.

In the ancs\_oled example, we have a special section of code for incoming calls where you can accept or decline a call with an appropriate button press:

```
  // Check buttons
  uint32_t presedButtons = readPressedButtons();

  if ( myNotifs[activeIndex].ntf.categoryID == ANCS_CAT_INCOMING_CALL )
  {
    /* Incoming call event
     * - Button A to accept call
     * - Button C to decline call
     */
    if ( presedButtons &amp; bit(BUTTON_A) )
    {
      bleancs.actPositive(myNotifs[activeIndex].ntf.uid);
    }

    if ( presedButtons &amp; bit(BUTTON_C) )
    {
      bleancs.actNegative(myNotifs[activeIndex].ntf.uid);
    }
  }

```

# Introducing the Adafruit nRF52840 Feather

## BLEClientCts

Danger: 

BLEClientCts is a helper class that implements adopted&nbsp;[Current Time Service](https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.current_time.xml)&nbsp;, which enables you to receive time&nbsp;from devices such as an iPhone or iPad.

# API
```
// Callback Signatures
typedef void (*adjust_callback_t) (uint8_t reason);

BLEClientCts(void);

virtual bool  begin(void);
virtual bool  discover(uint16_t conn_handle);

bool getCurrentTime(void);
bool getLocalTimeInfo(void);

bool enableAdjust(void);
void setAdjustCallback(adjust_callback_t fp);

// https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.current_time.xml
struct ATTR_PACKED {
  uint16_t year;
  uint8_t  month;
  uint8_t  day;
  uint8_t  hour;
  uint8_t  minute;
  uint8_t  second;
  uint8_t  weekday;
  uint8_t  subsecond;
  uint8_t  adjust_reason;
} Time;

// https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.local_time_information.xml
struct ATTR_PACKED {
  int8_t  timezone;
  uint8_t dst_offset;
}LocalInfo;
```

# Client CTS OLED Example

The **[client\_cts\_oled](https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/examples/Peripheral/client_cts_oled/client_cts_oled.ino)** example uses the [Adafruit FeatherWing OLED](https://www.adafruit.com/product/2900) to display received time.

## Sketch Requirements

In order to use this example sketch the following libraries must be installed on your system:

- [Adafruit\_GFX](../../../../adafruit-oled-featherwing/download?view=all#install-adafruit-gfx) ([Github source](https://github.com/adafruit/Adafruit-GFX-Library))
- [Adafruit\_SSD1306](../../../../adafruit-oled-featherwing/download?view=all#install-adafruit-ssd1306-library) ([Github source](https://github.com/adafruit/Adafruit_SSD1306))

## Loading the Sketch

The client\_cts\_oled sketch can be&nbsp;loaded via the examples menu under&nbsp; **Peripheral \> client\_cts\_oled** :

![](https://cdn-learn.adafruit.com/assets/assets/000/049/794/medium800/microcontrollers_Screenshot_from_2018-01-02_20-34-11.png?1514903066)

With the sketch loaded, you can build the firmware and then flash it to your device via the&nbsp; **Upload** button or menu option.&nbsp;Once the sketch is running on the nRF52 Feather you can proceed with the one-time pairing process, described below.

Danger: 

## Pairing&nbsp;to your Mobile Device

Before you can start receiving notifications, you will need to 'pair' the nRF52 Feather and the mobile device.

The pairing&nbsp;process causes a set of keys to be exchanged and stored on the two devices so that each side knows it is talking to the same device it originally bonded with, and preventing any devices in the middle from eavesdropping on potentially sensitive data.

The one-time pairing process is described below, and assumes you are already running the ancs\_oled sketch on your nRF52 device.

1. In the&nbsp; **Settings** app go to **Bluetooth** :

![](https://cdn-learn.adafruit.com/assets/assets/000/049/795/medium800/microcontrollers_bonding1.jpg?1514903514)

2. Scroll to the bottom of the list of 'My Devices'&nbsp;and click on&nbsp; **Bluefruit52&nbsp;** under&nbsp; **Other Devices** :

![](https://cdn-learn.adafruit.com/assets/assets/000/049/796/medium800/microcontrollers_bonding2.jpg?1514903542)

3. When the pairing dialog box comes up, click the&nbsp; **Pair** button:

![](https://cdn-learn.adafruit.com/assets/assets/000/049/797/medium800/microcontrollers_bonding3.jpg?1514903556)

4.&nbsp;Wait for the pairing process to complete, at which point&nbsp; **Bluefruit52** &nbsp;should appear in the&nbsp; **My Devices** list with the&nbsp; **Connected** status:

![](https://cdn-learn.adafruit.com/assets/assets/000/049/798/medium800/microcontrollers_bonding4.jpg?1514903589)

Info: 

## Wait for Time Data

At this point,&nbsp; time data from the mobile device will be read and display on the the OLED. For demo purpose the sketch will read time data from mobile once every second. However, in reality, nRF52 should have an internal timer that keep track of second, and only read/sync with mobile after several hours or days, similar to how IP device got time from NTP server.

![](https://cdn-learn.adafruit.com/assets/assets/000/049/799/medium800/microcontrollers_DSCF1277.jpg?1514907827)

# Introducing the Adafruit nRF52840 Feather

## BLECentral

Danger: 

The Central mode API is accessible via&nbsp;`Bluefruit.Central.*`&nbsp;and has the following public functions:

```
void begin(void);

/*------------------------------------------------------------------*/
/* GAP
 *------------------------------------------------------------------*/
bool     setConnInterval(uint16_t min, uint16_t max);
bool     setConnIntervalMS (uint16_t min_ms, uint16_t max_ms);

bool     connect(const ble_gap_evt_adv_report_t* adv_report);
bool     connect(const ble_gap_addr_t *peer_addr);
bool     disconnect(uint16_t conn_handle);

bool     connected (uint16_t conn_handle); // If connected to a specific peripheral
bool     connected (void);                 // If connected to any peripherals

/*------------- Callbacks -------------*/
void setConnectCallback   ( BLEGap::connect_callback_t    fp);
void setDisconnectCallback( BLEGap::disconnect_callback_t fp);
```

For examples of how to use the Central mode API, see the [Central examples folder](https://github.com/adafruit/Adafruit_nRF52_Arduino/tree/master/libraries/Bluefruit52Lib/examples/Central).

# Introducing the Adafruit nRF52840 Feather

## nRF52 ADC

The nRF52 family includes an adjustable 'successive-approximation ADC' which can be configured to convert data with up to 14-bit resolution (0..16383), and the reference voltage can be adjusted up to 3.6V internally.

The default values for the ADC are **10-bit resolution (0..1023)** with a **3.6V reference voltage** , meaning every digit returned from the ADC =&nbsp;3600mV/1024 =&nbsp; **3.515625mV**.

# Analog Reference Voltage

The internal reference voltage is 0.6V with a variable gain setting, and can be adjust via the&nbsp;**analogReference(...)** function, providing one of the following values:

- **AR\_INTERNAL** &nbsp;(0.6V Ref \* 6 = 0..3.6V) \<-- DEFAULT
- **AR\_INTERNAL\_3\_0** &nbsp;(0.6V Ref \* 5 = 0..3.0V)
- **AR\_INTERNAL\_2\_4** &nbsp;(0.6V Ref \* 4 = 0..2.4V)
- **AR\_INTERNAL\_1\_8** &nbsp;(0.6V Ref \* 3 = 0..1.8V)
- **AR\_INTERNAL\_1\_2** &nbsp;(0.6V Ref \* 2 = 0..1.6V)
- **AR\_VDD4** &nbsp;(VDD/4 REF \* 4 = 0..VDD)

For example:

```
// Set the analog reference to 3.0V (default = 3.6V)
analogReference(AR_INTERNAL_3_0);
```

# Analog Resolution

The ADC resolution can be set to 8, 10, 12 or 14 bits using the&nbsp;**analogReadResolution(...)** function, with the default value being 10-bit:

```
// Set the resolution to 12-bit (0..4095)
analogReadResolution(12); // Can be 8, 10, 12 or 14
```

# Default ADC Example (10-bit, 3.6V Reference)

The original source for this code is included in the nRF52 BSP and can be viewed online [here](https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/examples/Hardware/adc/adc.ino).

https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/examples/Hardware/adc/adc.ino

# Advanced Example (12-bit, 3.0V Reference)

The original source for this code is included in the nRF52 BSP and can be viewed online [here](https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/examples/Hardware/adc_vbat/adc_vbat.ino).

https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/examples/Hardware/adc_vbat/adc_vbat.ino

# Introducing the Adafruit nRF52840 Feather

## CircuitPython for Feather nRF52840

[CircuitPython](https://github.com/adafruit/circuitpython) is a derivative of [MicroPython](https://micropython.org) designed to simplify experimentation and education on low-cost microcontrollers. It makes it easier than ever to get prototyping by requiring no upfront desktop software downloads. Simply copy and edit files on the **CIRCUITPY** drive to iterate.

The following instructions will show you how to install CircuitPython. If you've already installed CircuitPython but are looking to update it or reinstall it, the same steps work for that as well!

## Set up CircuitPython Quick Start!

Follow this quick step-by-step for super-fast Python power :)

[Download the latest version of CircuitPython for this board via CircuitPython.org](https://circuitpython.org/board/feather_nrf52840_express/)
 **Click the link above to download the latest UF2 file.**

&nbsp;

Download and save it to your desktop (or wherever is handy).

![circuitpython_nRF52840_UF2.png](https://cdn-learn.adafruit.com/assets/assets/000/070/318/medium640/circuitpython_nRF52840_UF2.png?1548963877)

Plug your Feather nRF52840 into your computer using a known-good USB cable.

**A lot of people end up using charge-only USB cables and it is very frustrating! So make sure you have a USB cable you know is good for data sync.**

Double-click the **Reset** button next to the USB connector on your board, and you will see the NeoPixel RGB LED turn green (identified by the arrow in the image). If it turns red, check the USB cable, try another USB port, etc. **Note:** The little red LED next to the USB connector will pulse red. That's ok!

If double-clicking doesn't work the first time, try again. Sometimes it can take a few tries to get the rhythm right!

![circuitpython_FeathernRF52840_Top_Product_Image.jpg](https://cdn-learn.adafruit.com/assets/assets/000/070/319/medium640/circuitpython_FeathernRF52840_Top_Product_Image.jpg?1548963972)

You will see a new disk drive appear called **FTHR840BOOT**.

&nbsp;

&nbsp;

&nbsp;

Drag the **adafruit\_circuitpython\_etc.uf2** file to **FTHR840BOOT****.**

![circuitpython_FTHR840BOOT.png](https://cdn-learn.adafruit.com/assets/assets/000/070/320/medium640/circuitpython_FTHR840BOOT.png?1548964488)

![circuitpython_Drag_nRF52840_UF2.png](https://cdn-learn.adafruit.com/assets/assets/000/070/321/medium640/circuitpython_Drag_nRF52840_UF2.png?1548964497)

The LED will flash. Then, the&nbsp; **FTHR840BOOT** drive will disappear and a new disk drive called **CIRCUITPY** will appear.

&nbsp;

That's it, you're done! :)

![circuitpython_nRF52840_CIRCUITPY.png](https://cdn-learn.adafruit.com/assets/assets/000/070/322/medium640/circuitpython_nRF52840_CIRCUITPY.png?1548964511)

# Introducing the Adafruit nRF52840 Feather

## Welcome to CircuitPython

# Introducing the Adafruit nRF52840 Feather

## CircuitPython Pins and Modules

CircuitPython is designed to run on microcontrollers and allows you to interface with all kinds of sensors, inputs and other hardware peripherals. There are tons of guides showing how to wire up a circuit, and use CircuitPython to, for example, read data from a sensor, or detect a button press. Most CircuitPython code includes hardware setup which requires various modules, such as `board` or `digitalio`. You import these modules and then use them in your code. How does CircuitPython know to look for hardware in the specific place you connected it, and where do these modules come from?

This page explains both. You'll learn how CircuitPython finds the pins on your microcontroller board, including how to find the available pins for your board and what each pin is named. You'll also learn about the modules built into CircuitPython, including how to find all the modules available for your board.

# CircuitPython Pins

When using hardware peripherals with a CircuitPython compatible microcontroller, you'll almost certainly be utilising pins. This section will cover how to access your board's pins using CircuitPython, how to discover what pins and board-specific objects are available in CircuitPython for your board, how to use the board-specific objects, and how to determine all available pin names for a given pin on your board.

## `import board`

When you're using any kind of hardware peripherals wired up to your microcontroller board, the import list in your code will include `import board`. The `board` module is built into CircuitPython, and is used to provide access to a series of board-specific objects, including pins. Take a look at your microcontroller board. You'll notice that next to the pins are pin labels. You can always access a pin by its pin label. However, there are almost always multiple names for a given pin.

To see all the available board-specific objects and pins for your board, enter the REPL (`>>>`) and run the following commands:

```python
import board
dir(board)
```

Here is the output for the QT Py SAMD21. **You may have a different board, and this list will vary, based on the board.**

![](https://cdn-learn.adafruit.com/assets/assets/000/099/189/medium800/circuitpython_dir-board-output-qt-py.png?1612291495)

The following pins have labels on the physical QT Py SAMD21 board: A0, A1, A2, A3, SDA, SCL, TX, RX, SCK, MISO, and MOSI. You see that there are many more entries available in `board` than the labels on the QT Py.

You can use the pin names on the physical board, regardless of whether they seem to be specific to a certain protocol.

For example, you do not _have_ to use the SDA pin for I2C - you can use it for a button or LED.

On the flip side, there may be multiple names for one pin. For example, on the QT Py SAMD21, pin **A0** is labeled on the physical board silkscreen, but it is available in CircuitPython as both `A0` and `D0`. For more information on finding all the names for a given pin, see the [What Are All the Available Pin Names?](https://learn.adafruit.com/circuitpython-essentials/circuitpython-pins-and-modules#what-are-all-the-available-names-3082670-14) section below.

The results of `dir(board)` for CircuitPython compatible boards will look similar to the results for the QT Py SAMD21 in terms of the pin names, e.g. A0, D0, etc. However, some boards, for example, the Metro ESP32-S2, have different styled pin names. Here is the output for the Metro ESP32-S2.

![](https://cdn-learn.adafruit.com/assets/assets/000/099/215/medium800/circuitpython_Essentials_dir_board_Metro_ESP32-S2.png?1612374794)

Note that most of the pins are named in an IO# style, such as **IO1** and **IO2**. Those pins on the physical board are labeled only with a number, so an easy way to know how to access them in CircuitPython, is to run those commands in the REPL and find the pin naming scheme.

Info: 

## I2C, SPI, and UART

You'll also see there are often (_ **but not always!** _) three special board-specific objects included: `I2C`, `SPI`, and `UART` - each one is for the default pin-set used for each of the three common protocol busses they are named for. These are called _singletons_.

What's a singleton? When you create an object in CircuitPython, you are _instantiating_ ('creating') it. Instantiating an object means you are creating an instance of the object with the unique values that are provided, or "passed", to it.

For example, When you instantiate an I2C object using the `busio` module, it expects two pins: clock and data, typically SCL and SDA. It often looks like this:

```python
i2c = busio.I2C(board.SCL, board.SDA)
```

Then, you pass the I2C object to a driver for the hardware you're using. For example, if you were using the TSL2591 light sensor and its CircuitPython library, the next line of code would be:

```python
tsl2591 = adafruit_tsl2591.TSL2591(i2c)
```

However, CircuitPython makes this simpler by including the `I2C` singleton in the `board` module. Instead of the two lines of code above, you simply provide the singleton as the I2C object. So if you were using the TSL2591 and its CircuitPython library, the two above lines of code would be replaced with:

```python
tsl2591 = adafruit_tsl2591.TSL2591(board.I2C())
```

Info: 

This eliminates the need for the `busio` module, and simplifies the code. Behind the scenes, the `board.I2C()`&nbsp; object is instantiated when you call it, but not before, and on subsequent calls, it returns the same object. Basically, it does not create an object until you need it, and provides the same object every time you need it. You can call `board.I2C()` as many times as you like, and it will always return the same object.

Info: 

## What Are All the Available Names?

Many pins on CircuitPython compatible microcontroller boards have multiple names, however, typically, there's only one name labeled on the physical board. So how do you find out what the other available pin names are? Simple, with the following script! Each line printed out to the serial console contains the set of names for a particular pin.

On a microcontroller board running CircuitPython, first, connect to the serial console.

In the example below, click the **Download Project Bundle** button below to download the necessary libraries and the **code.py** file in a zip file. Extract the contents of the zip file, open the directory **CircuitPython\_Essentials/Pin\_Map\_Script/** and then click on the directory that matches the version of CircuitPython you're using and copy the contents of that directory to your **CIRCUITPY** drive.

Your **CIRCUITPY** drive should now look similar to the following image:

![CIRCUITPY](https://adafruit.github.io/Adafruit_Learning_System_Guides/CircuitPython_Essentials_Pin_Map_Script.png )

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/CircuitPython_Essentials/Pin_Map_Script/code.py

Here is the result when this script is run on QT Py SAMD21:

![](https://cdn-learn.adafruit.com/assets/assets/000/122/945/medium800/leds_CPE_pin_map_script_QT_Py_M0.png?1690233285)

Each line represents a single pin. Find the line containing the pin name that's labeled on the physical board, and you'll find the other names available for that pin. For example, the first pin on the board is labeled **A0**. The first line in the output is `board.A0 board.D0 (PA02)`. This means that you can access pin **A0** in CircuitPython using both `board.A0` and `board.D0`.

The pins in parentheses are the microcontroller pin names. See the next section for more info on those.

You'll notice there are two "pins" that aren't labeled on the board but appear in the list: `board.NEOPIXEL` and `board.NEOPIXEL_POWER`. Many boards have several of these special pins that give you access to built-in board hardware, such as an LED or an on-board sensor. The QT Py SAMD21 only has one on-board extra piece of hardware, a NeoPixel LED, so there's only the one available in the list. But you can also control whether or not power is applied to the NeoPixel, so there's a separate pin for that.

That's all there is to figuring out the available names for a pin on a compatible microcontroller board in CircuitPython!

## Microcontroller Pin Names

The pin names available to you in the CircuitPython `board` module are not the same as the names of the pins on the microcontroller itself. The board pin names are aliases to the microcontroller pin names. If you look at the datasheet for your microcontroller, you'll likely find a pinout with a series of pin names, such as "PA18" or "GPIO5". If you want to get to the actual microcontroller pin name in CircuitPython, you'll need the `microcontroller.pin` module. As with `board`, you can run `dir(microcontroller.pin)` in the REPL to receive a list of the microcontroller pin names.

![](https://cdn-learn.adafruit.com/assets/assets/000/099/290/medium800/circuitpython_Essentials_microcontroller_pin_names.png?1612822277 Microcontroller pin names for QT Py SAMD21.)

# CircuitPython Built-In Modules

There is a set of modules used in most CircuitPython programs. One or more of these modules is always used in projects involving hardware. Often hardware requires installing a separate library from the Adafruit CircuitPython Bundle. But, if you try to find `board` or `digitalio` in the same bundle, you'll come up lacking. So, where do these modules come from? They're built into CircuitPython! You can find an comprehensive list of built-in CircuitPython modules and the technical details of their functionality from CircuitPython [here](https://circuitpython.readthedocs.io/en/latest/shared-bindings/index.html#modules) and the Python-like modules included [here](https://circuitpython.readthedocs.io/en/latest/docs/library/index.html). However, **not every module is available for every board** due to size constraints or hardware limitations. How do you find out what modules are available for your board?

There are two options for this. You can check the [support matrix](https://circuitpython.readthedocs.io/en/latest/shared-bindings/support_matrix.html#), and search for your board by name. Or, you can use the REPL.

Plug in your board, connect to the serial console and enter the REPL. Type the following command.

```python
help("modules")
```

![](https://cdn-learn.adafruit.com/assets/assets/000/099/208/medium800/circuitpython_Essentials_help_modules_QT_Py.png?1612372532 help("modules") results for QT Py)

That's it! You now know two ways to find all of the modules built into CircuitPython for your compatible microcontroller board.

# Introducing the Adafruit nRF52840 Feather

## Frequently Asked Questions

These are some of the common questions regarding CircuitPython and CircuitPython microcontrollers.

### 
       
       
       
        What are some common acronyms to know? 
 
       
        
       
     
       
        
       
     
       
        
       
     
       
        
       
    

CP or CPy = [CircuitPython](https://circuitpython.org)  
CPC = [Circuit Playground Classic](https://www.adafruit.com/product/3000)&nbsp;(does not run CircuitPython)  
CPX = [Circuit Playground Express](https://www.adafruit.com/product/3333)  
CPB = [Circuit Playground Bluefruit](https://www.adafruit.com/product/4333)

## Using Older Versions
Danger: 

### I have to continue using CircuitPython 8.x or earlier. Where can I find compatible libraries?

**We are no longer building or supporting the CircuitPython 8.x or earlier library bundles. We highly encourage you to&nbsp;[update CircuitPython to the latest version](https://circuitpython.org/downloads)&nbsp;and use&nbsp;[the current version of the libraries](https://circuitpython.org/libraries).**&nbsp;However, if for some reason you cannot update, here are the last available library bundles for older versions:

- [2.x bundle](https://github.com/adafruit/Adafruit_CircuitPython_Bundle/releases/download/20190903/adafruit-circuitpython-bundle-2.x-mpy-20190903.zip)
- [3.x bundle](https://github.com/adafruit/Adafruit_CircuitPython_Bundle/releases/download/20190903/adafruit-circuitpython-bundle-3.x-mpy-20190903.zip)
- [4.x bundle](https://github.com/adafruit/Adafruit_CircuitPython_Bundle/releases/download/20200707/adafruit-circuitpython-bundle-4.x-mpy-20200707.zip)
- [5.x bundle](https://github.com/adafruit/Adafruit_CircuitPython_Bundle/releases/download/20210129/adafruit-circuitpython-bundle-5.x-mpy-20210129.zip)
- [6.x bundle](https://github.com/adafruit/Adafruit_CircuitPython_Bundle/releases/download/20211213/adafruit-circuitpython-bundle-6.x-mpy-20211213.zip)
- [7.x bundle](https://github.com/adafruit/Adafruit_CircuitPython_Bundle/releases/download/20231003/adafruit-circuitpython-bundle-7.x-mpy-20231003.zip)
- [8.x bundle](https://github.com/adafruit/Adafruit_CircuitPython_Bundle/releases/download/20250213/adafruit-circuitpython-bundle-8.x-mpy-20250213.zip)

## Python Arithmetic
### 
       
       
       
        Does CircuitPython support floating-point numbers? 
 
       
        
       
     
       
        
       
     
       
        
       
     
       
        
       
    

All CircuitPython boards support floating point arithmetic, even if the microcontroller chip does not support floating point in hardware. Floating point numbers are stored in 30 bits, with an 8-bit exponent and a 22-bit mantissa. Note that this is two bits less than standard 32-bit single-precision floats. You will get about 5-1/2 digits of decimal precision.&nbsp;

(The&nbsp; **broadcom** &nbsp;port may provide 64-bit floats in some cases.)

### 
       
       
       
        Does CircuitPython support long integers, like regular Python? 
 
       
        
       
     
       
        
       
     
       
        
       
     
       
        
       
    

Python long integers (integers of arbitrary size) are available on most builds, except those on boards with the smallest available firmware size. On these boards, integers are stored in 31 bits.

Boards without long integer support are mostly SAMD21 ("M0") boards without an external flash chip, such as the Adafruit Gemma M0, Trinket M0, QT Py M0, and the Trinkey series. There are also a number of third-party boards in this category. There are also a few small STM third-party boards without long integer support.

`time.localtime()`, `time.mktime()`, `time.time()`, and `time.monotonic_ns()` are available only on builds with long integers.

## Wireless Connectivity
### 
       
       
       
        How do I connect to the Internet with CircuitPython? 
 
       
        
       
     
       
        
       
     
       
        
       
     
       
        
       
    

If you'd like to include WiFi in&nbsp; your project, your best bet is to use a board that is running natively on ESP32 chipsets - those have WiFi built in!

If your development board has an SPI port and at least 4 additional pins, you can check out [this guide](https://learn.adafruit.com/adafruit-io-basics-airlift) on using AirLift with CircuitPython - extra wiring is required and some boards like the MacroPad or NeoTrellis do not have enough available pins to add the hardware support.

For further project examples, and guides about using AirLift with specific hardware, check out [the Adafruit Learn System](https://learn.adafruit.com/search?q=airlift).

### How do I do BLE (Bluetooth Low Energy) with CircuitPython?

nRF52840, nRF52833, and **as of CircuitPython 9.1.0** , ESP32, ESP32-C3, and ESP32-S3 boards (with 8MB) have the most complete BLE implementation. Your program can act as both a BLE central and peripheral. As a central, you can scan for advertisements, and connect to an advertising board. As a peripheral, you can advertise, and you can create services available to a central. Pairing and bonding are supported.

**Most Espressif boards with only 4MB of flash do not have enough room to include BLE in CircuitPython 9.** &nbsp; Check the [Module Support Matrix](https://docs.circuitpython.org/en/latest/shared-bindings/support_matrix.html) to see if your board has support for `_bleio`. CircuitPython 10 is planned to support `_bleio` on Espressif boards with 4MB flash.

Note that the ESP32-S2 does not have Bluetooth capability.

On most other boards with adequate firmware space, [BLE is available for use with AirLift](https://learn.adafruit.com/adafruit-airlift-breakout/circuitpython-ble) or other NINA-FW-based co-processors. Some boards have this coprocessor on board, such as the [PyPortal](https://learn.adafruit.com/adafruit-pyportal/circuitpython-ble). Currently, this implementation only supports acting as a BLE peripheral. Scanning and connecting as a central are not yet implemented. Bonding and pairing are not supported.

### 
       
       
       
        Are there other ways to communicate by radio with CircuitPython? 
 
       
        
       
     
       
        
       
     
       
        
       
     
       
        
       
    

Check out [Adafruit's RFM boards](https://www.adafruit.com/?q=rfm&sort=BestMatch)for simple radio communication supported by CircuitPython, which can be used over distances of 100m to over a km, depending on the version. The RFM SAMD21 M0 boards can be used, but they were not designed for CircuitPython, and have limited RAM and flash space; using the RFM breakouts or FeatherWings with more capable boards will be easier.

## Asyncio and Interrupts
### 
       
       
       
        Is there asyncio support in CircuitPython? 
 
       
        
       
     
       
        
       
     
       
        
       
     
       
        
       
    

There is support for asyncio starting with CircuitPython 7.1.0, on all boards except the smallest SAMD21 builds. Read about using it in the [Cooperative Multitasking in CircuitPython](https://learn.adafruit.com/cooperative-multitasking-in-circuitpython) Guide.

### 
       
       
       
        Does CircuitPython support interrupts? 
 
       
        
       
     
       
        
       
     
       
        
       
     
       
        
       
    

No. CircuitPython does not currently support interrupts - please use asyncio for multitasking / 'threaded' control of your code

## Status RGB LED
### 
       
       
       
        My RGB NeoPixel/DotStar LED is blinking funny colors - what does it mean? 
 
       
        
       
     
       
        
       
     
       
        
       
     
       
        
       
    

The status LED can tell you what's going on with your CircuitPython board. [Read more here for what the colors mean!](https://learn.adafruit.com/welcome-to-circuitpython/troubleshooting#circuitpython-rgb-status-light-2978455-24)

## Memory Issues
### 
       
       
       
        What is a MemoryError? 
 
       
        
       
     
       
        
       
     
       
        
       
     
       
        
       
    

Memory allocation errors happen when you're trying to store too much on the board. The CircuitPython microcontroller boards have a limited amount of memory available. You can have about 250 lines of code on the M0 Express boards. If you try to `import` too many libraries, a combination of large libraries, or run a program with too many lines of code, your code will fail to run and you will receive a `MemoryError` in the serial console.

### 
       
       
       
        What do I do when I encounter a MemoryError? 
 
       
        
       
     
       
        
       
     
       
        
       
     
       
        
       
    

Try resetting your board. Each time you reset the board, it reallocates the memory. While this is unlikely to resolve your issue, it's a simple step and is worth trying.

Make sure you are using **.mpy** versions of libraries. All of the CircuitPython libraries are available in the bundle in a **.mpy** format which takes up less memory than **.py** format. Be sure that you're using [the latest library bundle](https://github.com/adafruit/Adafruit_CircuitPython_Bundle/releases) for your version of CircuitPython.

If that does not resolve your issue, try shortening your code. Shorten comments, remove extraneous or unneeded code, or any other clean up you can do to shorten your code. If you're using a lot of functions, you could try moving those into a separate library, creating a **.mpy** of that library, and importing it into your code.

You can turn your entire file into a **.mpy** and `import` that into **code.py**. This means you will be unable to edit your code live on the board, but it can save you space.

### 
       
       
       
        Can the order of my <code class=

It can because the memory gets fragmented differently depending on allocation order and the size of objects. Loading **.mpy** files uses less memory so its recommended to do that for files you aren't editing.

### How can I create my own <strong>.mpy</strong> files?

You can make your own **.mpy** versions of files with `mpy-cross`.

You can download **mpy-cross** for your operating system from [here](https://adafruit-circuit-python.s3.amazonaws.com/index.html?prefix=bin/mpy-cross/). Builds are available for Windows, macOS, x64 Linux, and Raspberry Pi Linux. Choose the latest **mpy-cross** whose version matches the version of CircuitPython you are using.

On macOS and Linux, after you download&nbsp; **mpy-cross** , you must make the the file executable by doing `chmod +x name-of-the-mpy-cross-executable`.

To make a **.mpy** file, run `./mpy-cross path/to/yourfile.py` to create a **yourfile.mpy** in the same directory as the original file.

### 
       
       
       
        How do I check how much memory I have free? 
 
       
        
       
     
       
        
       
     
       
        
       
     
       
        
       
    

Run the following to see the number of bytes available for use:

`import gc`  
`gc.mem_free()`

## Unsupported Hardware
### 
       
       
       
        Is ESP8266 or ESP32 supported in CircuitPython? Why not? 
 
       
        
       
     
       
        
       
     
       
        
       
     
       
        
       
    

We dropped ESP8266 support as of 4.x - For more information please read about it [here](https://learn.adafruit.com/welcome-to-circuitpython/circuitpython-for-esp8266)!

[As of CircuitPython 8.x we have started to support ESP32 and ESP32-C3 and have added a WiFi workflow for wireless coding!](https://learn.adafruit.com/circuitpython-with-esp32-quick-start)

We also support ESP32-S2 & ESP32-S3, which have native USB.

### 
       
       
       
        Does Feather M0 support WINC1500? 
 
       
        
       
     
       
        
       
     
       
        
       
     
       
        
       
    

No, WINC1500 will not fit into the M0 flash space.

### 
       
       
       
        Can AVRs such as ATmega328 or ATmega2560 run CircuitPython? 
 
       
        
       
     
       
        
       
     
       
        
       
     
       
        
       
    

No.

# Introducing the Adafruit nRF52840 Feather

## Getting Started with BLE and CircuitPython

# Guides

- [Getting Started with CircuitPython and Bluetooth Low Energy](https://learn.adafruit.com/circuitpython-nrf52840) - Get started with CircuitPython, the Adafruit nRF52840 and the Bluefruit LE Connect app.
- [BLE Light Switch with Feather nRF52840 and Crickit](https://learn.adafruit.com/bluetooth-light-switch-with-crickit-and-nrf52840) - Control a robot finger from across the room to flip on and off the lights!
- [Color Remote with Circuit Playground Bluefruit](https://learn.adafruit.com/color-remote-with-circuit-playground-bluefruit) - Mix NeoPixels wirelessly with a Bluetooth LE remote control!
- [MagicLight Bulb Color Mixer with Circuit Playground Bluefruit](https://learn.adafruit.com/magiclight-bulb-mixer) - Mix colors on a MagicLight Bulb wirelessly with a Bluetooth LE remote control.
- [Bluetooth Turtle Bot with CircuitPython and Crickit](https://learn.adafruit.com/bluetooth-turtle-bot-with-circuitpython-and-crickit) - Build your own Bluetooth controlled turtle rover!
- [Wooden NeoPixel Xmas Tree](https://learn.adafruit.com/wooden-neopixel-xmas-tree) - Cut a Christmas tree of wood and mount some NeoPixels in the tree to create a festive yuletide light display.
- [Bluefruit TFT Gizmo ANCS Notifier for iOS](https://learn.adafruit.com/ancs-gizmo) - Circuit Playground Bluefruit displays your iOS notification icons so you know when there's fresh activity!
- [Bluefruit Playground Hide and Seek](https://learn.adafruit.com/hide-n-seek-bluefruit-ornament) - Use Circuit Playground Bluefruit devices to create a colorful signal strength-based proximity detector!
- [Snow Globe with Circuit Playground Bluefruit](https://learn.adafruit.com/snow-globe-bluefruit-cpb) - Make your own festive (or creatively odd!) snow globe with custom lighting effects and Bluetooth control.
- [Bluetooth Controlled NeoPixel Lightbox](https://learn.adafruit.com/bluetooth-neopixel-lightbox) - Great for tracing and writing, this lightbox lets you adjust color and brightness with your phone.
- [Circuit Playground Bluefruit NeoPixel Animation and Color Remote Control](https://learn.adafruit.com/circuit-playground-bluefruit-neopixel-animation-and-color-remote-control) - Control NeoPixel colors and animation remotely over Bluetooth with the Circuit Playground Bluefruit!
- [Circuit Playground Bluetooth Cauldron](https://learn.adafruit.com/cpx-cauldron) - Build a Bluetooth Controlled Light Up Cauldron.
- [NeoPixel Badge Lanyard with Bluetooth LE](https://learn.adafruit.com/bluetooth-neopixel-badge-lanyard) - Light up your convention badge and control colors with your phone!
- [CircuitPython BLE Controlled NeoPixel Hat](https://learn.adafruit.com/circuitpython-feather-ble-neopixel-hat) - Wireless control NeoPixels on your wearables!
- [Bluefruit nRF52 Feather Learning Guide](https://learn.adafruit.com/bluefruit-nrf52-feather-learning-guide) - Get started now with our most powerful Bluefruit board yet!
- [CircusPython: Jump through Hoops with CircuitPython Bluetooth LE](https://learn.adafruit.com/circuspython-jump-through-hoops-with-bluetooth-le) - Blinka jumps through a ring of fire, controlled via Bluetooth LE and the Bluefruit LE Connect app!
- [A CircuitPython BLE Remote Control On/Off Switch](https://learn.adafruit.com/circuitpython-ble-remote-control-on-off) - Make a remote control on/off switch for a computer with CircuitPython and BLE.
- [NeoPixel Infinity Cube](https://learn.adafruit.com/neopixel-infinity-cube) - Build a 3D printed, Bluetooth controlled Mirrored Acrylic and NeoPixel Infinity cube.
- [CircuitPython BLE Crickit Rover](https://learn.adafruit.com/circuitpython-ble-crickit-rover) - Purple Robot with Feather nRF52840 and Crickit plus NeoPixel underlighting!
- [Circuit Playground Bluefruit Pumpkin with Lights and Sounds](https://learn.adafruit.com/pumpkin-with-circuit-playground-bluefruit) - Add the Circuit Playground Bluefruit and STEMMA speaker to an inexpensive plastic pumpkin.
- [No-Solder LED Disco Tie with Bluetooth](https://learn.adafruit.com/no-solder-circuit-playground-bluetooth-disco-tie) - Build an LED tie controlled by Bluetooth LE.
- [Bluetooth Remote Control for the Lego Droid Developer Kit](https://learn.adafruit.com/bluetooth-remote-for-lego-droid) - Reinvigorating the Lego Star Wars Droid Developer Kit with an Adafruit powered remote control using Bluetooth LE.

# Introducing the Adafruit nRF52840 Feather

## CircuitPython Essentials

# Introducing the Adafruit nRF52840 Feather

## Memory Map

Danger: 

# BSP release & Bootloader version

The memory usage depends on the version of the Softdevice and/or bootloader (single/dual bank). Following is the Bootloader and Softdevice version included with BSP release

- **0.9.x** :nRF52832 S132 v6.1.1 single bank andnRF52840 S140 v6.1.1 single bank

- **0.8.x** :nRF52832 S132 v2.0.1 dual banks and S132 v5.1.0 dual banks

- **0.7.x and older** :nRF52832 S132 v2.0.1 dual banks

Info: 

# Flash Memory

The nRF52832 has 512 KB flash, nRF52840 has 1024 KB flash. The flash layout varies as follows:

![](https://cdn-learn.adafruit.com/assets/assets/000/065/418/medium800/microcontrollers_S132_and_S140_v6.png?1541757141)

![](https://cdn-learn.adafruit.com/assets/assets/000/065/419/medium800/microcontrollers_S132_v2_and_v5.png?1541757322)

- **SoftDevice** : This section of flash memory contains the **Soft Device** , which is Nordic's black box Bluetooth Low Energy stack.
- **Application** : This section of flash memory stores the user sketches that you compile in the Arduino IDE.
- **Reserved** : This section of flash memory is kept empty to enable **dual banks** safe firmware updates. Whenever you try to update the Application are, the new application data will first be written to the free memory section, and the verified before it is swapped out with the current application code. This is to ensure that DFU complete successfully and that the entire image is safely store on the device to avoid losing the application code. This region is not used by **single bank** bootloader
- **User Data** : This 28KB section of flash memory is reserved for config settings. It uses an open source file system called [Little File System](https://github.com/ARMmbed/littlefs), which is a part of ARM Mbed OpenSource to store bonding data. For example, when you bond the nRF52 with another Central device.
- **DFU Bootloader** : This section of flash memory stores the actual bootloader code that will be executed by the MBR described earlier.

# SRAM Layout

The nRF52832 has 64KB of SRAM available, and actual memory use will depend on your project, although the stack and heap memory locations are described below:

- **Soft Device:** amount of SRAM exclusive allocated for SoftDevice by Linker script. The size is subject to change and varies by releases. For BSP release&nbsp; **0.8.0** it is **12.5 KB**. However, the actual memory required by the SoftDevice depends on the&nbsp; run-time configuration determined by Bluefruit's configNNN() API.
- **Sketch BSS:&nbsp;** static and global data used by your sketch.
- **Heap Memory:** &nbsp;The largest memory region, this is used for allocating the real time operating systems (RTOS) thread stack, malloc() etc. The size, based on the variables shown below, is **Y = 64 - 12.5 - X - 2 ( KB ),&nbsp;**where 12.5KB will vary depending on the SoftDevice used.
- **Stack Memory** : Used by non RTOS thread code, this is mostly for Interrupt Service Routines (ISRs) and SoftDevice API calls. The current size is **2 KB**.

## Functions affecting SoftDevice SRAM usage

The Bluefruit nRF52&nbsp; **configNNN** () functions set the behavior of SoftDevice, thus determining the total SRAM usage. **These functions must be called before begin().**

- **configUuid128Count** () : Defines the number of UUID128 entries that the SoftDevice supports, e.g Bleuart, BleMidi, or other services and characteristics.&nbsp; **Default value is 10.&nbsp;**
- **configAttrTableSize():&nbsp;**The total size of the attribute table, which holds services and characteristics. If your application needs lots of characteristics you may need to increase this. **Default value is 2048 bytes.**
- **configPrphConn(),&nbsp;configPrphBandwidth():&nbsp;**These function set the parameters that determine the bandwidth for peripheral's connections.&nbsp;configPrphBandwidth() is a convenient helper that calls configPrphConn() with appropriate parameters.
- **configCentralConn(), configCentralBandwidth():&nbsp;**These functions set the parameters that determine the bandwidth for central mode connections. configCentralBandwidth() is a convenient helper that calls configCentralConn() with appropriate parameters.
- **begin():&nbsp;**Bluefruit nRF52's **begin()**&nbsp;function also affects the bandwidth since it takes 2 (optional) parameters. The first one is the number of concurrent connections for peripheral links (to mobile phones, your computer, etc.), the second one is the number of central links (to BLE accessories, or another feather52 running in peripheral mode). **The maximum number of concurrent connections for SoftDevice v5.x is 20**.

![](https://cdn-learn.adafruit.com/assets/assets/000/049/696/medium800/microcontrollers_Bluefruit_nrf52_S132_v5.x.x_RAM_%283%29.jpg?1514362181)

Info: 

```
[CFG] SoftDevice config requires more SRAM than provided by the linker.
App Ram Start must be at least 0x20004180 (provided 0x20003200).
Please update linker file or re-config SoftDevice.
```

# Introducing the Adafruit nRF52840 Feather

## Software Resources

To help you get your Bluefruit LE module talking to other Central devices, we've put together a number of open source tools for most of the major platforms supporting Bluetooth Low Energy.

# Bluefruit LE Client Apps and Libraries

Adafruit has put together the following mobile or desktop apps and libraries to make it as easy as possible to get your Bluefruit LE module talking to your mobile device or laptop, with full source available where possible:

## [Bluefruit LE Connect](https://play.google.com/store/apps/details?id=com.adafruit.bluefruit.le.connect)&nbsp;(Android/Java)

Bluetooth Low Energy support was added to Android starting with Android 4.3 (though it was only really stable starting with 4.4), and we've already released&nbsp;[Bluefruit LE Connect to the Play Store](https://play.google.com/store/apps/details?id=com.adafruit.bluefruit.le.connect).

The full&nbsp;[source code](https://github.com/adafruit/Bluefruit_LE_Connect_Android)&nbsp;for Bluefruit LE Connect for Android is also available on Github to help you get started with your own Android apps. &nbsp;You'll need a recent version of [Android Studio](https://developer.android.com/sdk/index.html)&nbsp;to use this project.

![](https://cdn-learn.adafruit.com/assets/assets/000/027/737/medium800/adafruit_products_Screen_Shot_2015-09-18_at_11.00.51.png?1442566883)

## [Bluefruit LE Connect](https://itunes.apple.com/app/adafruit-bluefruit-le-connect/id830125974?mt=8)&nbsp; (iOS/Swift)

Apple was very early to adopt Bluetooth Low Energy, and we also have an iOS version of the [Bluefruit LE Connect](https://itunes.apple.com/app/adafruit-bluefruit-le-connect/id830125974?mt=8)&nbsp;app available in Apple's app store.

The full swift source code&nbsp;for Bluefruit LE Connect for iOS&nbsp;is also available on Github. You'll need XCode and access to Apple's developper program to use this project:

- Version 1.x source code:&nbsp;[https://github.com/adafruit/Bluefruit\_LE\_Connect](https://github.com/adafruit/Bluefruit_LE_Connect)
- Version 2.x source code:&nbsp;[https://github.com/adafruit/Bluefruit\_LE\_Connect\_v2](https://github.com/adafruit/Bluefruit_LE_Connect_v2)

Info: 

![](https://cdn-learn.adafruit.com/assets/assets/000/027/738/medium800/adafruit_products_Screen_Shot_2015-09-18_at_11.01.54.png?1442566930)

# [Bluefruit LE Connect for OS X](https://itunes.apple.com/us/app/adafruit-bluefruit-le-connect/id1082414600?mt=12)&nbsp;(Swift)

This OS X desktop application is based on the same V2.x codebase as the iOS app, and gives you access to BLE UART, basic Pin I/O and OTA DFU firmware updates from the convenience of your laptop or mac.

This is a great choice for logging sensor data locally and exporting it as a CSV, JSON or XML file for parsing in another application, and uses the native hardware on your computer so no BLE dongle is required on any recent mac.

The full source is also [available on Github](https://github.com/adafruit/Bluefruit_LE_Connect_v2).

![](https://cdn-learn.adafruit.com/assets/assets/000/032/850/medium800/adafruit_products_screen800x500.jpeg?1465218103)

# [Bluefruit LE Command Line Updater for OS X](https://github.com/adafruit/Bluefruit_LE_Connect_v2/releases/tag/OSXcommandline_0.3) (Swift)

This experimental command line tool is unsupported and provided purely as a proof of concept, but can be used to allow firmware updates for Bluefruit devices from the command line.

This utility&nbsp;performs automatic firmware updates similar to the way that the GUI application does, by checking the firmware version on your Bluefruit device (via the Device Information Service), and comparing this against the firmware versions available online, downloading files in the background if appropriate.

Simply install the pre-compiled tool via the [DMG file](https://github.com/adafruit/Bluefruit_LE_Connect_v2/releases/tag/OSXcommandline_0.3) and place it somewhere in the system path, or run the file locally via './bluefruit' to see the help menu:

```
$ ./bluefruit
bluefruit v0.3
Usage:
	bluefruit &lt;command&gt; [options...]

Commands:
	Scan peripherals:   scan
	Automatic update:   update [--enable-beta] [--uuid &lt;uuid&gt;]
	Custom firmware:    dfu --hex &lt;filename&gt; [--init &lt;filename&gt;] [--uuid &lt;uuid&gt;]
	Show this screen:   --help
	Show version:       --version

Options:
	--uuid &lt;uuid&gt;    If present the peripheral with that uuid is used. If not present a list of peripherals is displayed
	--enable-beta    If not present only stable versions are used

Short syntax:
	-u = --uuid, -b = --enable-beta, -h = --hex, -i = --init, -v = --version, -? = --help
```

## Deprecated:&nbsp;[Bluefruit Buddy](https://itunes.apple.com/us/app/bluefruit-buddy/id1042412646?mt=12)&nbsp;(OS X)

This native OS X application is a basic proof of concept app that allows you to connect to your Bluefruit LE module using most recent macbooks or iMacs. You can get basic information about the modules and use the UART service to send and receive data.

The full source for the application is available in the github repo at [Adafruit\_BluefruitLE\_OSX](https://github.com/adafruit/Adafruit_BluefruitLE_OSX).

![](https://cdn-learn.adafruit.com/assets/assets/000/031/571/medium800/adafruit_products_bluefruitbuddy.jpeg?1459962152)

## [ABLE](https://github.com/adafruit/adafruit-bluefruit-le-desktop/releases)&nbsp;(Cross Platform/Node+Electron)

[ABLE](https://github.com/adafruit/adafruit-bluefruit-le-desktop/releases)&nbsp;(Adafruit Bluefruit LE Desktop) is a cross-platform desktop application based on Sandeep Misty's [noble library](https://github.com/sandeepmistry/noble)&nbsp;and the [Electron](https://github.com/atom/electron)&nbsp;project from Github (used by Atom).

It runs on OS X, Windows 7+ and select flavours of Linux (Ubuntu tested locally). &nbsp;Windows 7 support is particularly interesting since Windows 7 has no native support for Bluetooth Low Energy but the noble library talks directly to [supported Bluetooth 4.0 USB dongles](https://www.adafruit.com/products/1327)&nbsp;to emulate BLE on the system (though at this stage it's still in early BETA and drops the connection and takes more care to work with).

This app allows you to collect sensor data or perform many of the same functionality offered by the mobile Bluefruit LE Connect apps, but on the desktop.

The app is still in BETA, but full [source](https://github.com/adafruit/adafruit-bluefruit-le-desktop)&nbsp;is available in addition to the easy to use [pre-compiled binaries](https://github.com/adafruit/adafruit-bluefruit-le-desktop/releases).

![](https://cdn-learn.adafruit.com/assets/assets/000/027/747/medium800/adafruit_products_bluefruitdesktop.png?1442813066)

## [Bluefruit LE Python Wrapper](https://github.com/adafruit/Adafruit_Python_BluefruitLE)

As a proof of concept, we've played around a bit with getting Python working with the native Bluetooth APIs on OS X and the latest version of Bluez on certain Linux targets.

There are currently example sketches showing how to retreive BLE UART data as well as some basic details from the Device Information Service (DIS).

This isn't an actively support project and was more of an experiment, but if you have a recent Macbook or a Raspberry Pi and know Python, you might want to look at [Adafruit\_Python\_BluefruitLE](https://github.com/adafruit/Adafruit_Python_BluefruitLE)&nbsp;in our github account.

# Debug Tools

If your sense of adventure gets the better of you, and your Bluefruit LE module goes&nbsp;off into the weeds, the following tools might be useful to get it back&nbsp;from unknown lands.

Danger: 

## [AdaLink](https://github.com/adafruit/Adafruit_Adalink)&nbsp;(Python)

This command line tool is a python-based wrapper for programming ARM MCUs using either a [Segger J-Link](https://www.adafruit.com/search?q=J-Link)&nbsp;or an [STLink/V2](https://www.adafruit.com/product/2548).&nbsp;You can use it to reflash your Bluefruit LE module using the latest firmware from the [Bluefruit LE firmware repo](https://github.com/adafruit/Adafruit_BluefruitLE_Firmware).

Details on how to use the tool are available in the readme.md file on the main [Adafruit\_Adalink](https://github.com/adafruit/Adafruit_Adalink)&nbsp;repo on Github.

Completely reprogramming a Bluefruit LE module with AdaLink would require four files, and would look something like this (using a JLink):

```
adalink nrf51822 --programmer jlink --wipe
  --program-hex "Adafruit_BluefruitLE_Firmware/softdevice/s110_nrf51_8.0.0_softdevice.hex" 
  --program-hex "Adafruit_BluefruitLE_Firmware/bootloader/bootloader_0002.hex"
  --program-hex "Adafruit_BluefruitLE_Firmware/0.6.7/blefriend32/blefriend32_s110_xxac_0_6_7_150917_blefriend32.hex"
  --program-hex "Adafruit_BluefruitLE_Firmware/0.6.7/blefriend32/blefriend32_s110_xxac_0_6_7_150917_blefriend32_signature.hex"
```

You can also use the AdaLink tool to get some basic information about your module, such as which SoftDevice is currently programmed or the IC revision (16KB SRAM or 32KB SRAM) via the --info command:

```
$ adalink nrf51822 -p jlink --info
Hardware ID : QFACA10 (32KB)
Segger ID   : nRF51822_xxAC
SD Version  : S110 8.0.0
Device Addr : **:**:**:**:**:**
Device ID   : ****************
```

## [Adafruit nRF51822 Flasher](https://github.com/adafruit/Adafruit_nRF51822_Flasher)&nbsp;(Python)

Adafruit's nRF51822 Flasher&nbsp;is an internal Python tool we use in production to flash boards as they go through the test procedures and off the assembly line, or just testing against different firmware releases when debugging.

It relies&nbsp;on AdaLink or OpenOCD beneath the surface (see above), but you can use this command line tool to flash your nRF51822 with a specific SoftDevice, Bootloader and Bluefruit firmware combination.

It currently supports using either a Segger J-Link or STLink/V2 via AdaLink, or [GPIO on a Raspberry Pi](https://github.com/adafruit/Adafruit_nRF51822_Flasher#rpi-gpio-requirements)&nbsp;if you don't have access to a traditional ARM SWD debugger. &nbsp;(A pre-built version of OpenOCD for the RPi is included in the repo since building it from scratch takes a long time on the original RPi.)

We don't provide active support for this tool since it's purely an internal project, but made it public just in case it might help an adventurous customer debrick a board on their own.

```
$ python flash.py --jtag=jlink --board=blefriend32 --softdevice=8.0.0 --bootloader=2 --firmware=0.6.7
jtag       	: jlink
softdevice 	: 8.0.0
bootloader 	: 2
board      	: blefriend32
firmware   	: 0.6.7
Writing Softdevice + DFU bootloader + Application to flash memory
adalink -v nrf51822 --programmer jlink --wipe --program-hex "Adafruit_BluefruitLE_Firmware/softdevice/s110_nrf51_8.0.0_softdevice.hex" --program-hex "Adafruit_BluefruitLE_Firmware/bootloader/bootloader_0002.hex" --program-hex "Adafruit_BluefruitLE_Firmware/0.6.7/blefriend32/blefriend32_s110_xxac_0_6_7_150917_blefriend32.hex" --program-hex "Adafruit_BluefruitLE_Firmware/0.6.7/blefriend32/blefriend32_s110_xxac_0_6_7_150917_blefriend32_signature.hex"
...
```

# Introducing the Adafruit nRF52840 Feather

## Downloads

The following resources may be useful working with the Bluefruit nRF52 Feather:

- [Adafruit\_nRF52\_Arduino](https://github.com/adafruit/Adafruit_nRF52_Arduino): The core code for this device (hosted on Github)
- [nRF52 Example Sketches](https://github.com/adafruit/Adafruit_nRF52_Arduino/tree/master/libraries/Bluefruit52Lib/examples): Browse the example code from the core repo on Github
- [Hardware Design Files](https://github.com/adafruit/Adafruit-nRF52-Bluefruit-Feather-PCB): EagleCAD files for the nRF52840 Feather Express on Github.
- [3D Models on GitHub](https://github.com/adafruit/Adafruit_CAD_Parts/tree/master/4062%20nRF52840%20Feather)
- [PDF for nRF52840 Feather PrettyPins Pinout Diagram](https://github.com/adafruit/Adafruit-nRF52-Bluefruit-Feather-PCB/blob/master/Adafruit%20Feather%20nRF52840%20pinout.pdf)

[update-feather-nrf52840-bootloader-0.8.0-windows.zip](https://cdn-learn.adafruit.com/assets/assets/000/125/940/original/update-feather-nrf52840-bootloader-0.8.0-windows.zip?1699460842)
[SVG for nRF52840 Feather PrettyPins Pinout Diagram](https://cdn-learn.adafruit.com/assets/assets/000/110/599/original/Adafruit_Feather_nRF52840_pinout.svg?1649266202)
![](https://cdn-learn.adafruit.com/assets/assets/000/083/329/medium800thumb/circuitpython_4062-nRF52830-Feather.jpg?1572539679)

[nRF52840 Production specification v1.1 (PDF)](https://cdn-learn.adafruit.com/assets/assets/000/092/427/original/nRF52840_PS_v1.1.pdf)
# Module Details

The Bluefruit nRF52840 Feather Express uses the&nbsp;MDBT50Q module from Raytac. Details on the module, including FCC and other certifications are available in the document below:

[Raytac_MDBT50Q.pdf](https://cdn-learn.adafruit.com/assets/assets/000/068/544/original/Raytac_MDBT50Q.pdf?1546346679)
# Schematic and Fab Print

Click on the image for full-size versions.

The board files are available on [Github](https://github.com/adafruit/Adafruit-nRF52-Bluefruit-Feather-PCB)

## Rev E
![schematic for rev e](https://cdn-learn.adafruit.com/assets/assets/000/136/592/medium800/circuitpython_schem_nrf.png?1746448867 )

![fab print of rev e](https://cdn-learn.adafruit.com/assets/assets/000/136/591/medium800/circuitpython_nrf52_fab.png?1746448834 )

## Rev D
Danger: In the section labeled **JS PH LIPO INPUT**, in the schematic, mention is made of `D5`. This should be `A6`

![](https://cdn-learn.adafruit.com/assets/assets/000/068/545/medium800/circuitpython_nRF52840_Schematic_REV-D.png?1546364754)

![](https://cdn-learn.adafruit.com/assets/assets/000/068/592/medium800/circuitpython_nRF52840_Board_Layout.png?1546452290)

# Introducing the Adafruit nRF52840 Feather

## Using nRF52840 SPI on Battery Power

Danger: 

The nRF52840 has three low-speed SPI peripherals, **SPIM0** , **SPIM1** , and **SPIM2** , and one high-speed SPI peripheral, **SPIM3**. SPIM0-2 have a maximum clock rate of 8 MHz, and SPIM3 has a maximum clock rate of 32 MHz. (SPIM0-2 are shared with the I2C peripherals, so not all SPI peripherals are always available.)

There appears to be a hardware bug with SPIM3: it does not operate properly when the board is not powered via the USB port. More precisely, it does not work when the VUSB pin to the nRF52840 is not energized.

In Arduino, avoid using SPIM3 if you are not powering the board via USB.

CircuitPython allocates which SPIM to use automatically. The first time you call `busio.SPI(),` or use `board.SPI()`, it will allocate SPIM3, so that you get the highest SPI speed possible.

To avoid getting the non-functional SPIM3 when not powering via USB, allocate the first SPI object, which will use SPIM3, and then just don't use it. Allocate a second one for your use, which will pick one of the other ones. For example:

```python
import busio, board
# Allocate and then don't use the first SPI object.
# Choose pins you are not otherwise using. The pins below are just examples.
# You only need to specify a clock and a MOSI pin.

# Will allocate but not use SPIM3. SPIM3 doesn't work when not powered by USB.
do_not_use_this_spi = busio.SPI(clock=board.A0, MOSI=board.A1)

# Will allocate one of the working SPIM peripherals.
spi = board.SPI()

# ...
```

This bug is being tracked in [this CircuitPython issue](https://github.com/adafruit/circuitpython/issues/5233).

# Introducing the Adafruit nRF52840 Feather

## FAQs

 **NOTE:** For FAQs relating to the **BSP** , see the dedicated [BSP FAQ list](../../../../bluefruit-nrf52-feather-learning-guide/arduino-bsp-setup#bsp-setup-faqs).

### 

The two board families take very different design approaches.

All of the nRF51 based modules are based on an AT command set (over UART or SPI), and require two MCUs to run: the nRF51 hosting the AT command parser, and an external MCU sending AT style commands.

The nRF52 boards run code directly on the nRF52, executing natively and calling the Nordic S132 SoftDevice (their proprietary Bluetooth Low Energy stack) directly. This allows for more efficient code since there is no intermediate AT layer or transport, and also allows for lower overall power consumption since only a single device is involved.

The nRF52 will generally give you better performance, but for situation where you need to use an MCU with a feature the nRF52 doesn't have (such as USB), the nRF51 based boards will still be the preferable solution.

### 

No. The two board families are fundamentally different, and have entirely separate APIs and programming models. If you are migrating from the nRF51 to the nRF52, you will need to redesign your sketches to use the newer API, enabling you to build code that runs natively on the nRF52832 MCU.

### 

The S132 Soft Device and the nRF52832 HW support Central mode, so yes this is&nbsp;_possible **.** _ At this early development stage, though, there is only bare bones support for Central mode in the Adafruit nRF52 codebase, simply to test the HW and S132 and make sure that everything is configured properly. An example is provided of listening for incoming advertising packets, printing the packet contents and meta-data out to the Serial Monitor. We hope to add further Central mode examples in the future, but priority has been given to the Peripheral API and examples for the initial release.

### 

In order to run Arduino code on the nRF52 at the same time as the low level Bluetooth Low Energy stack, the Bluefruit nRF52 Feather uses FreeRTOS as a task scheduler. The scheduler will automatically switch between tasks, assigning clock cycles to the highest priority task at a given moment. This process is generally transparent to you, although it can have implications if you have hard real time requirements. There is no guarantee on the nRF52 to meet hard timing requirements when the radio is enabled an being actively used for Bluetooth Low Energy. This isn't&nbsp;possible on the nRF52 even without FreeRTOS, though, since the SoftDevice (Nordic's propietary binary blob stack) has higher priority than any user code, including control over interrupt handlers.

### 

You can, yes, but it will require a Segger J-Link (that's what we've tested against anyway, other options exist), and it's an advanced operation. But if you're asking about it, you probably know that.

Assuming you have the Segger J-Link drivers installed, you can start Segger's GDB Server from the command line as follows (OSX/Linux used here):

`$ JLinkGDBServer -device nrf52832_xxaa -if swd -speed auto`

Then open a new terminal window, making sure that you have access to `gcc-arm-none-eabi-gdb` from the command line, and enter the following command:

`$ ./arm-none-eabi-gdb something.ino.elf`

``something.ino.elf`` is the name of the .elf file generated when you built your sketch. You can find this by enabling 'Show verbose output during: [x] compilation' in the Arduino IDE preferences. You CAN run GDB without the .elf file, but pointing to the .elf file will give you all of the meta data like displaying the actual source code at a specific address, etc.

Once you have the `(gdb)` prompt, enter the following command to connect to the Segger GDB server (updating your IP address accordingly, since the HW isn't necessarily local!):

`(gdb) target remote 127.0.0.1:2331`

If everything went well, you should see the current line of code where the device is halted (normally execution on the nRF52 will halt as soon as you start the Segger GDB Server).

At this point, you can send GDB debug commands, which is a tutorial in itself! As a crash course, though:

- To continue execution, type '`monitor go`' then '`continue`'
- To stop execution (to read register values, for example.), type '`monitor halt`'
- To display the current stack trace (when halted) enter '`bt`'
- To get information on the current stack frame (normally the currently executing function), try these:

  - `info frame`: Display info on the current stack frame
  - `info args`: Display info on the arguments&nbsp;passed into the stack frame
  - `info locals`: Display local variables in the stack frame
  - `info registers`: Dump the core ARM register values, which can be useful for debugging specific fault conditions

### 

If you have a [Segger J-Link](https://www.adafruit.com/new?q=jlink&), you can also use [Segger's OZone debugger GUI](https://www.segger.com/ozone.html) to interact with the device, though check the license terms since there are usage restrictions depending on the J-Link module you have.

You will need to connect your nRF52 to the J-Link via the SWD and SWCLK pins on the bottom of the PCB, or if you are OK with fine pitch soldering via the SWD header.

You can either solder on a standard [2x5 SWD header](https://www.adafruit.com/product/752)&nbsp;on the pad available in the board, or you can solder wires to the SWD and SWCLK pads on the bottom of the PCB and use an [SWD Cable Breakout Board](https://www.adafruit.com/product/2743), or just connect cables directly to your J-Link via some other means.

You will also need to connect the **VTRef** pin on the JLink to&nbsp; **3.3V** on the Feather to let the J-Link know what voltage level the target has, and share a common GND by connecting the GND pins on each device.&nbsp;

Before you can start to debug, you will need to get the .elf file that contains all the debug info for your sketch. You can find this file by enabling&nbsp; **Show Verbose Output During: compilation** in the&nbsp; **Arduino Preferences&nbsp;** dialogue box. When you build your sketch, you need to look at the log output, and find the .elf file, which will resemble something like this (it will vary depending on the OS used):&nbsp;`/var/folders/86/hb2vp14n5_5_yvdz_z8w9x_c0000gn/T/arduino_build_118496/ancs_oled.ino.elf`

In the OZone New Project Wizard, when prompted to select a target device in OZone select&nbsp; **nRF52832\_xxAA** , then make sure that you have set the Target Interface for the debugger to&nbsp; **SWD** , and finally point to the .elf file above:

![](https://cdn-learn.adafruit.com/assets/assets/000/041/395/medium800/microcontrollers_Screen_Shot_2017-05-01_at_18.06.55.png?1493654959)

![](https://cdn-learn.adafruit.com/assets/assets/000/041/396/medium800/microcontrollers_Screen_Shot_2017-05-01_at_18.07.10.png?1493655002)

![](https://cdn-learn.adafruit.com/assets/assets/000/041/397/medium800/microcontrollers_Screen_Shot_2017-05-01_at_18.15.55.png?1493655377)

Next select the&nbsp; **Attach to running program** option in the top-left hand corner, or via the menu system, which will cause the debugger to connect to the nRF52 over SWD:

![](https://cdn-learn.adafruit.com/assets/assets/000/041/399/medium800/microcontrollers_Screen_Shot_2017-05-01_at_18.18.38.png?1493655613)

![](https://cdn-learn.adafruit.com/assets/assets/000/041/398/medium800/microcontrollers_Screen_Shot_2017-05-01_at_18.18.55.png?1493655599)

At this point, you can click the&nbsp; **PAUSE** icon to stop program execution, and then analyze variables, or set breakpoints at appropriate locations in your program execution, and debug as you would with most other embedded IDEs!

![](https://cdn-learn.adafruit.com/assets/assets/000/041/400/medium800/microcontrollers_Screen_Shot_2017-05-01_at_18.21.24.png?1493655706)

Clicking on the left-hand side of the text editor will set a breakpoint on line 69 in the image below, for example, and the selecting **Debug \> Reset \> Reset & Run** from the menu or icon will cause the board to reset, and you should stop at the breakpoint you set:

![](https://cdn-learn.adafruit.com/assets/assets/000/041/401/medium800/microcontrollers_Screen_Shot_2017-05-01_at_18.25.25.png?1493656066)

You can experiment with adding some of the other debug windows and options via the&nbsp; **View** menu item, such as the&nbsp; **Call Stack** which will show you all of the functions that were called before arriving at the current breakpoint:

![](https://cdn-learn.adafruit.com/assets/assets/000/041/402/medium800/microcontrollers_Screen_Shot_2017-05-01_at_19.15.00.png?1493658968)

### 

Yes, by running one board in peripheral mode and one board in central mode, where the central will establish a connection with the peripheral board and you can communicate using BLE UART or a custom service.&nbsp; See the following Central BLE UART example to help you get started:&nbsp;https://github.com/adafruit/Adafruit\_nRF52\_Arduino/tree/master/libraries/Bluefruit52Lib/examples/Central

### 

This is probably caused by a conflict between 32-bit and 64-bit versions of the compiler, libc and the IDE. The compiler uses 32-bit binaries, so you also need to have a 32-bit version of libc installed on your system ([details](http://forum.arduino.cc/index.php?topic=221979.0)). Try running the following commands from the command line to resolve this:

```
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install libc6:i386
```
### 

#### **If you get this error:**

`Timed out waiting for acknowledgement from device.Failed to upgrade target. Error is: No data received on serial port. Not able to proceed.Traceback (most recent call last):  File "nordicsemi\ __main__.py", line 294, in serial  File "nordicsemi\dfu\dfu.py", line 235, in dfu_send_images  File "nordicsemi\dfu\dfu.py", line 203, in _dfu_send_image  File "nordicsemi\dfu\dfu_transport_serial.py", line 155, in send_init_packet  File "nordicsemi\dfu\dfu_transport_serial.py", line 243, in send_packet  File "nordicsemi\dfu\dfu_transport_serial.py", line 282, in get_ack_nrnordicsemi.exceptions.NordicSemiException: No data received on serial port. Not able to proceed.`

This is probably caused by the **bootloader** version mismatched on your feather and installed BSP. Due to the difference in flash layout ([more details](https://learn.adafruit.com/bluefruit-nrf52-feather-learning-guide/hathach-memory-map)) and Softdevice API (which is bundled with bootloader), sketch built with selected bootloader can only upload to board having the same version. In short, you need to **upgrade/burn bootloader to match** on your Feather, follow above&nbsp;[Update The Bootloader](https://learn.adafruit.com/bluefruit-nrf52-feather-learning-guide/updating-the-bootloader)&nbsp;guide

It only has to be done once to update your Feather

### 

They all support BLE Mesh, but we don't provide Arduino library for Mesh. You need to write code based on Nordic sdk mesh.&nbsp;

### 

If you get error similar to this:

`Arduino: 1.8.8 (Mac OS X), Board: "Adafruit Bluefruit nRF52832 Feather, 0.2.9 (s132 6.1.1), Level 0 (Release)"`  
  
`[1716] Error loading Python lib '/var/folders/gw/b0cg4zm508qf_rf2m655gd3m0000gn/T/_MEIE6ec69/Python': dlopen: dlopen(/var/folders/gw/b0cg4zm508qf_rf2m655gd3m0000gn/T/_MEIE6ec69/Python, 10): Symbol not found: _futimens`  
`  Referenced from: /var/folders/gw/b0cg4zm508qf_rf2m655gd3m0000gn/T/_MEIE6ec69/Python (which was built for Mac OS X 10.13)`  
`  Expected in: /usr/lib/libSystem.B.dylib`  
` in /var/folders/gw/b0cg4zm508qf_rf2m655gd3m0000gn/T/_MEIE6ec69/Python`  
`exit status 255`  
`Error compiling for board Adafruit Bluefruit nRF52832 Feather.`

It is probably due to the pre-built adafruit-nrfutil cannot run on your Mac. The binary is generated on MacOS 10.13, if your Mac is older than that. Please update your macOS, or you could follow this repo's readme here&nbsp;[https://github.com/adafruit/Adafruit\_nRF52\_nrfutil&nbsp;](https://github.com/adafruit/Adafruit_nRF52_nrfutil)to manual install it ( tried with pip3 first, or install from source if it doesn't work). Then use the installed binary to replace the one in the BSP.


## Primary Products

### Adafruit Feather nRF52840 Express

[Adafruit Feather nRF52840 Express](https://www.adafruit.com/product/4062)
The **Adafruit Feather nRF52840 Express** is the new Feather family member with Bluetooth® Low Energy and _native USB support_ featuring the nRF52840!&nbsp; It's our take on an 'all-in-one' Arduino-compatible + Bluetooth® Low Energy with built-in USB...

In Stock
[Buy Now](https://www.adafruit.com/product/4062)
[Related Guides to the Product](https://learn.adafruit.com/products/4062/guides)

## Featured Products

### SEGGER J-Link EDU - JTAG/SWD Debugger

[SEGGER J-Link EDU - JTAG/SWD Debugger](https://www.adafruit.com/product/1369)
[Discontinued - **you can grab&nbsp;** SEGGER J-Link EDU Mini - JTAG/SWD Debugger **instead!**](https://www.adafruit.com/product/3571)

The SEGGER J-Link EDU is identical to the more expensive [J-Link BASE](https://www.adafruit.com/products/2209) model except...

No Longer Stocked
[Buy Now](https://www.adafruit.com/product/1369)
[Related Guides to the Product](https://learn.adafruit.com/products/1369/guides)
### SEGGER J-Link BASE - JTAG/SWD Debugger

[SEGGER J-Link BASE - JTAG/SWD Debugger](https://www.adafruit.com/product/2209)
The SEGGER J-Link BASE is identical to the cheaper&nbsp;[J-Link EDU](https://www.adafruit.com/products/1369)&nbsp;model except for the **terms of use**.

If you're going to use your debugger strictly for personal, non-commercial projects, such as publishing...

In Stock
[Buy Now](https://www.adafruit.com/product/2209)
[Related Guides to the Product](https://learn.adafruit.com/products/2209/guides)
### SEGGER J-Link EDU Mini - JTAG/SWD Debugger

[SEGGER J-Link EDU Mini - JTAG/SWD Debugger](https://www.adafruit.com/product/3571)
Doing some serious development on any ARM-based platform, and tired of 'printf' plus an LED to debug? A proper JTAG/SWD HW debugger can make debugging more of a pleasure and less of a pain. It allows you to program your devices at the click of a button, read or write memory addresses...

In Stock
[Buy Now](https://www.adafruit.com/product/3571)
[Related Guides to the Product](https://learn.adafruit.com/products/3571/guides)
### 10-pin 2x5 Socket-Socket 1.27mm IDC (SWD) Cable - 150mm long

[10-pin 2x5 Socket-Socket 1.27mm IDC (SWD) Cable - 150mm long](https://www.adafruit.com/product/1675)
These little cables are handy when programming or debugging a tiny board that uses 10-pin 1.27mm (0.05") pitch SWD programming connectors. We see these connectors often on ARM Cortex dev kits, and have a few handy in our ARM-dev box. We thought you may want a backup cable as well, so now...

In Stock
[Buy Now](https://www.adafruit.com/product/1675)
[Related Guides to the Product](https://learn.adafruit.com/products/1675/guides)
### JTAG (2x10 2.54mm) to SWD (2x5 1.27mm) Cable Adapter Board

[JTAG (2x10 2.54mm) to SWD (2x5 1.27mm) Cable Adapter Board](https://www.adafruit.com/product/2094)
This adapter board is designed for adapting a 'classic' 2x10 (0.1"/2.54mm pitch) JTAG cable to a slimmer 2x5 (0.05"/1.27mm pitch) SWD Cable. &nbsp;It's helpful for using products like the [JTAGulator](https://www.adafruit.com/products/1550) or <a...></a...>

In Stock
[Buy Now](https://www.adafruit.com/product/2094)
[Related Guides to the Product](https://learn.adafruit.com/products/2094/guides)
### Lithium Ion Polymer Battery Ideal For Feathers - 3.7V 400mAh

[Lithium Ion Polymer Battery Ideal For Feathers - 3.7V 400mAh](https://www.adafruit.com/product/3898)
Lithium-ion polymer (also known as 'lipo' or 'lipoly') batteries are thin, light, and powerful. The output ranges from 4.2V when completely charged to 3.7V. This battery has a capacity of **400mAh** for a total of about 1.9 Wh. If you need a larger (or smaller!)...

Out of Stock
[Buy Now](https://www.adafruit.com/product/3898)
[Related Guides to the Product](https://learn.adafruit.com/products/3898/guides)
### Lithium Ion Polymer Battery - 3.7v 500mAh

[Lithium Ion Polymer Battery - 3.7v 500mAh](https://www.adafruit.com/product/1578)
Lithium-ion polymer (also known as 'lipo' or 'lipoly') batteries are thin, light, and powerful. The output ranges from 4.2V when completely charged to 3.7V. This battery has a capacity of 500mAh for a total of about 1.9 Wh. If you need a larger (or smaller!) battery, <a...></a...>

Out of Stock
[Buy Now](https://www.adafruit.com/product/1578)
[Related Guides to the Product](https://learn.adafruit.com/products/1578/guides)

## Related Guides

- [Debugging the SAMD21 with GDB](https://learn.adafruit.com/debugging-the-samd21-with-gdb.md)
- [Adafruit seesaw](https://learn.adafruit.com/adafruit-seesaw-atsamd09-breakout.md)
- [BLE Sniffer with nRF52840](https://learn.adafruit.com/ble-sniffer-with-nrf52840.md)
- [Multi-tasking with CircuitPython](https://learn.adafruit.com/multi-tasking-with-circuitpython.md)
- [A CircuitPython BLE Remote Control On/Off Switch](https://learn.adafruit.com/circuitpython-ble-remote-control-on-off.md)
- [Programming an M0 using an Arduino](https://learn.adafruit.com/programming-an-m0-using-an-arduino.md)
- [Adafruit Metro M4 Express AirLift (WiFi)](https://learn.adafruit.com/adafruit-metro-m4-express-airlift-wifi.md)
- [Bluetooth Controlled NeoPixel Lightbox](https://learn.adafruit.com/bluetooth-neopixel-lightbox.md)
- [Doomscroll and Chill - A Wireless BLE Scroll Wheel Remote](https://learn.adafruit.com/doomscroll-and-chill-wireless-ble-scroll-wheel-rotary-encoder-remote.md)
- [Debugging CircuitPython On SAMD w/Atmel Studio 7](https://learn.adafruit.com/circuitpython-samd-debugging-w-atmel-studio-7.md)
- [Bluetooth-Controlled Matrix LED Sign using Bluefruit Connect](https://learn.adafruit.com/bluetooth-controlled-matrix-led-sign-using-bluefruit-connect.md)
- [All the Internet of Things - Episode Four: Adafruit IO](https://learn.adafruit.com/all-the-internet-of-things-episode-four-adafruit-io.md)
- [Touch Deck: DIY Customizable TFT Control Pad](https://learn.adafruit.com/touch-deck-diy-tft-customized-control-pad.md)
- [Bluefruit Ouija Board](https://learn.adafruit.com/bluefruit-ouija-board.md)
- [NeoPixel Badge Lanyard with Bluetooth LE](https://learn.adafruit.com/bluetooth-neopixel-badge-lanyard.md)
