Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

How to Add Bluetooth Low Energy (BLE) Connection to ARM Cortex-M

DZone's Guide to

How to Add Bluetooth Low Energy (BLE) Connection to ARM Cortex-M

This post is about how to add Bluetooth Low Energy (BLE) to NXP (formerly Freescale) Kinetis devices. Read on to learn more.

· IoT Zone
Free Resource

In many of my embedded projects, I’m successfully using the Nordic Semiconductor nRF24L01+ (see “Tutorial: Nordic Semiconductor nRF24L01+ with the Freescale FRDM-K64F Board“) and the HC-06 Bluetooth transceivers (see “Getting Bluetooth Working with JY-MCU BT_BOARD V1.06“) for wireless communication. However, the nRF24L01+ is using a proprietary protocol, and the HC-06 does not work with Apple products (it does work very well with Android devices). To close that gap, I decided to add Bluetooth Low Energy (BLE, or Bluetooth 4.x). So, this post is about how to add Bluetooth Low Energy (BLE) to NXP (formerly Freescale) Kinetis devices:

Image title

BLE Enabled Kinetis

Outline

In this article, I describe how to use the Adafruit Bluefruit LE Friend (SPI) module with the Freescale/NXP Kinetis microcontroller. The Adafruit tutorials describe how to use it with the Arduino IDE, but this post is about how to use it with a C/C++ environment (Kinetis Design Studio with GNU ARM Embedded tools). It describes the SPI connection and protocol, and how to use it in a command line mode. As an application, it implements a UART-over-BLE (virtual UART over BLE) to send and receive text from a mobile phone or tablet. It even adds an RTOS (FreeRTOS) and Processor Expert components to make life easier, but they are not necessary if you want to do it without them.

The project and source code is available on GitHub: https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/tinyK20/tinyK20_Adafruit_BLE

Bluetooth Low Energy

Bluetooth Low Energy is not Bluetooth, although it does use the same 2.4 GHz band. I think they named it after Bluetooth purely for marketing reasons, because BLE is more like the nRF24L01+ protocol with added security. Regardless of the naming behind BLE, it provides a wireless connectivity for low power and small bandwidth applications.

I recommend reading the "Getting Started with Bluetooth Low Energy" book (ISBN 978-1-491-94951-1, O’Reilly, Kevin Townsend, Carles Cufi, Akiba & Robert Davidson).

Image title

Getting Started With Bluetooth Low Energy

What makes BLE great is that it  easily allows to communication with embedded devices from smartphones and tablets. So, my goal is to drive robots with it, change the color of LEDs and lamps, or do any other interactions with embedded devices.

BLE Module

There are plenty of different BLE modules and stacks available on the market. I have evaluated several modules and I have decided to use the Adafruit 'Bluefruit' LE modules:

  1. 'Ready-to-use' Modules: Unlike other solutions, I don’t have the chance of messing up with a BLE stack. The modules already have a firmware (UART over BLE) loaded.
  2. Open Source: Unlike other solutions which come with libraries and 'secret hidden code', Adafruit shares the source code and has tutorials how I can flash the firmware e.g. with a Segger J-Link.
  3. Multiple Board Options: I have the choice of UART or SPI breakout boards, Arduino Shield, a USB dongle and BLE sniffer version.
  4. Excellent Software and Tutorials: Adafruit provides first class and fun tutorials with lots of background information. Additionally, they have very good community support.
  5. Nordic Semiconductor Transceiver: I see many other module vendors using the Nordic chips, and Nordic has good software and tools support too.

In this post, I’m using the Adafruit Bluefruit LE SPI Friend. I selected this one over the UART version because I don’t want to give up a serial port with hand shaking signals and the board is a bit smaller than the UART version.

The top side of the module has a blue Connection and a red Mode LED. The signals are bread-board friendly:

  • SPI clock SCK (4 MHz max)
  • SPI MISO and MOSI (most significant bit first)
  • SPI chip select CS (low active)
  • IRQ to signal data available (high active)
  • DFU pin to force firmware update or factory reset (optional)
  • RST pin to do reset (optional)
  • GND
  • Supply Voltage VIN (3.3-5V) for onboard regulator to 3.3V

Image title

Bluefruit SPI Board Top Side

The bottom side of the module exposes pads for SWD debugging (DIO and CLK), a pad for factory reset and 3.3V output of the onboard regulator (up to 250 mA). Optionally, the module can be extended with a 32 kHz clock source:

Image title

Bluefruit SPI Board Bottom Side

Main features of the board (mostly based on information from Adafruit):

  • Nordic Semiconductor nRF51822
  • ARM Cortex M0 core running at 16MHz
  • 256KB flash memory
  • 32KB SRAM
  • 2.4 GHz Chip Antenna
  • Peak current draw <20mA (radio actively transmitting/receiving)
  • 3.3V and 5V-safe inputs (Arduino Uno friendly, etc.)
  • On-board 3.3V voltage regulation
  • Bootloader with support for safe OTA firmware updates
  • AT command set for easy configuration

The Adafruit UART/SPI breakout modules cost $18.50 which is reasonable to me. Yes, there are cheaper modules from other vendors, and modules with better hardware specs. But, to me the available software, tools, and tutorials for the Adafruit modules was key for my decision. After the fact, it only took me around one hour to get my first BLE connection with my iPhone.

Hardware Setup

I’m using a tinyK20 (ARM Cortex-M4) with a Freescale/NXP K20DX128 as the application processor. Another tinyK20 is used as debugger. I’m using the tinyK20 because it's easy to use it with a bread-board setup:

Image title

BLE Board Setup With Logic Analyzer

The setup can be changed to use any other board, e.g. one of the Freescale/NXP Freedom boards. If using the Freedom board, you don’t need an extra debugger board as it is already included as OpenSDA.

I highly recommend to use a logic analyzer for this kind of development. If you want to make your own open source logic analyzer, then have a look at Updated Freedom Board Logic Analyzer with DMA.

Wiring

I’m using a bread-board to connect the module to the microcontroller.

Image title

BLE Breadboard Wiring

I have used the following wiring:

  • Power: GND and 3.3V
  • SPI MISO: PTC7
  • SPI MOSI: PTC6
  • SPI CLK: PTC5
  • SPI CS: PTD0
  • IRQ: PTB17

The diagram below shows the complete wiring:

Image title

tinyK20 Wiring With BLE

Software Components

With my tinyK20, I’m using hardware SPI with the help of the Processor Expert SynchroMaster component. But of course it is possible to use any other SPI driver, it is just that with the Processor Expert approach it is super easy. The screenshot below shows the pin assignments and SPI configuration:

Image title

SPI configuration

The SPI component is the most important one. Besides that, I need an interrupt pin (BLE_IRQ) and the SPI chip select (BLE_CS). The screenshot below shows the full set of components:

Image title

BLE Application Components

  • FreeRTOS I’m using the RTOS to simplify running multiple things, but it is easy to use the application bare metal too
  • SynchroMaster is handling the SPI communication to the BLE module
  • BLE_CS implements the SPI chip select
  • A LED is used for status on the tinyK20
  • Wait implements different delay routines
  • Utility implements string manipulation routines
  • CriticalSection implements handling of critical sections outside the RTOS
  • HardFault is a component to help debug hard faults (see "A Processor Expert Component to Help with Hard Faults")
  • KinetisTools implements low level Kinetis functionality
  • BLE_IRQ is for the Bluefruit IRQ pin
  • The Ringbuffer is used to buffer incoming BLE messages
  • FSL_USB_Stack implements an optional USB CDC stack
  • The Shell component offers the command line interface
  • Timeout is used in the Bluefruit interface to avoid blocking for too long
  • SeggerSystemView and SeggerRTT are used for debugging purposes (see "Segger SystemView: Realtime Analysis and Visualization for FreeRTOS")
  • AsynchroSerial is a UART connection to the debugging tinyK20 (Serial-over-USB)

SPI Protocol

The:

AT\n

command is used to verify that the communication is working (command mode). The module shall respond with:

OK\r\n

Image title

BLE AT Command in Shell

The logic analyzer image below shows the:

AT\n

command and the response from the module with:

OK\r\n

Image title

AT Command and Response

  • CS (Chip Select) is LOW ACTIVE and kept low during the transaction
  • IRQ is HIGH ACTIVE and indicates that a message is preset at the module to be retrieved

Below the details of the AT command:

Image title

AT Command Details

And, here the response from the module:

Image title

AT Response

The SPI protocol is using the Adafruit SDEP (Simple Data Exchange Protocol, https://github.com/adafruit/Adafruit_BluefruitLE_nRF51/blob/master/SDEP.md): basically it is a packet oriented protocol over SPI. It is a bus neutral protocol which allows to send request and response over multiple communication channels including SPI. Each message is in the following format:

  • Message type (uint8_t), e.g. 0x10 for ‘command’
  • Command ID (uint16_t), e.g. 0x000A for ‘AT Wrapper’
  • Payload Length (uint8_t) with a ‘more data’ bit
  • Variable Payload

The "AT" command is encoded like this:

0x10 : 0x00 0x0A : 0x02   : 0x41 0x54 
Type : ID        : Length :  'A'  'T'

UART Over BLE Example

To test the BLE functionality, I have implemented a simple UART over BLE application. The functionality is implemented in bleuart_cmdmode.c with the AT command driver in BLEAdafruit.c:

Image title

UART over BLE application

The application runs in an endless loop:

#include "bleuart_cmdmode.h"
#include "UTIL1.h"
#include "LED1.h"
#include "FRTOS1.h"
#include "BLEAdafruit.h"
#include "CLS1.h"
#include "UTIL1.h"

#define MAX_TX_MSG_SIZE     48 /* maximum UART message length to handle */
static uint8_t txBuffer[MAX_TX_MSG_SIZE] = "";
static bool isConnected = FALSE;
static bool isEnabled = FALSE;

static void BleUartTask(void *pvParameters) {
  uint8_t buf[MAX_TX_MSG_SIZE];
  uint8_t txBuf[MAX_TX_MSG_SIZE+sizeof("[Tx] ")+sizeof("AT+BLEUARTTX=\n")];
  uint8_t res;
  CLS1_ConstStdIOType *io = CLS1_GetStdio();
  int i;
  bool prevIsEnabled = FALSE;

  BLE_Init(); /* initialize BLE module, has to be done when interrupts are enabled */
  CLS1_SendStr("******************************************\r\n", io->stdOut);
  CLS1_SendStr("* Adafruit BLE UART CMD Mode Application *\r\n", io->stdOut);
  CLS1_SendStr("******************************************\r\n", io->stdOut);
  for(;;) {
    if (!prevIsEnabled && isEnabled) { /* enabled now */
      prevIsEnabled = TRUE;
      BLE_Echo(FALSE); /* Disable command echo from Bluefruit */
      CLS1_SendStr("Changing LED activity to MODE.\r\n", io->stdOut);
      res = BLE_SendATCommandExpectedResponse("AT+HWMODELED=1\n", buf, sizeof(buf), "OK\r\n"); /* NOTE: "=MODE" failed! */
      if (res!=ERR_OK) {
        CLS1_SendStr("Failed setting LED mode.\r\n", io->stdErr);
      }
      CLS1_SendStr("BLE UART enabled.\r\n", io->stdOut);
    } else if (prevIsEnabled && !isEnabled) { /* disabled now */
      prevIsEnabled = FALSE;
      CLS1_SendStr("BLE UART disabled.\r\n", io->stdOut);
    }
    if (isEnabled) {
      while(isEnabled && !(isConnected=BLE_IsConnected())) { /* wait until connected */
        CLS1_SendStr("Waiting for BLE UART connection...\r\n", io->stdOut);
        for(i=0;i<5 && isEnabled;i++) {
          FRTOS1_vTaskDelay(pdMS_TO_TICKS(1000));
          LED1_Neg();
        }
      }
      if (isConnected) {
        CLS1_SendStr("Connected!\r\n", io->stdOut);
      }
      while(isEnabled) { /* will break */
        isConnected=BLE_IsConnected();
        if (!isConnected) {
          CLS1_SendStr("Disconnected!\r\n", io->stdOut);
          break; /* get out of loop */
        }
        if (txBuffer[0]!='\0') { /* have something to tx */
          /* copy buffer */
          taskENTER_CRITICAL();
          UTIL1_strcpy(txBuf, sizeof(txBuf), "AT+BLEUARTTX=");
          UTIL1_strcat(txBuf, sizeof(txBuf), "[Tx] ");
          UTIL1_strcat(txBuf, sizeof(txBuf), txBuffer);
          txBuffer[0] = '\0';
          taskEXIT_CRITICAL();
          /* send tx string */
          res = BLE_SendATCommandExpectedResponse(txBuf, buf, sizeof(buf), "OK\r\n");
          if (res!=ERR_OK) {
            CLS1_SendStr("Failed to Tx string\r\n", io->stdErr);
          }
        }
        /* check Rx */
        res = BLE_SendATCommandExpectedResponse("AT+BLEUARTRX\n", buf, sizeof(buf), "OK\r\n");
        if (res==ERR_OK) {
          if (UTIL1_strncmp(buf, "OK\r\n", sizeof("OK\r\n")-1)==0) {
            /* only OK as response: no data */
          } else {
            /* print response */
            UTIL1_strCutTail(buf, "OK\r\n"); /* cut off the OK part */
            CLS1_SendStr("[Rx] ", io->stdOut);
            CLS1_SendStr(buf, io->stdOut);
          }
        }
        FRTOS1_vTaskDelay(pdMS_TO_TICKS(50));
        LED1_Neg();
      } /* while */
    } else {
      FRTOS1_vTaskDelay(pdMS_TO_TICKS(500));
      LED1_Neg();
    }
  }
}

After initialization, it waits until a connection is established. Then it checks with "AT+BLEUARTRX\n" if we have incoming characters. If yes, it prints them with [Rx] in front of it. If we have characters to transmit in the txBuffer, then we send them with "AT+BLEUARTTX\n". Strings to be sent in the txBuffer can be sent with the Shell.

I connect to the board with a terminal program (puTTY or Termite). After writing a startup message, it will wait for a BLE UART connection:

Image title

Waiting for BLE UART Connection

To connect to the BLE module I can use the Adafruit mobile app:

Alternatively, the Nordic Semiconductor UART application can be used: https://learn.adafruit.com/getting-started-with-the-nrf8001-bluefruit-le-breakout/testing-uart

In the mobile app, it scans for available BLE devices:

Image title

Scanning for BLE Devices

Connecting to the device gives me a list of available services:

Image title

BLE Services

The Info service provides details about the services available:

Image title

BLE Service Info

Connecting to the UART service gives me a terminal view where I can send and receive text:

Image title

BLE UART Application

The message is then received by the microcontroller and sent to the terminal connected to it:

Image title

BLE UART Rx Message

The same way I can send a message from the microcontroller to the smart phone:

Image title

Sending BLE UART Message from Microcontroller

And, the message is displayed in the smart phone application:

Image title

Received BLE UART Message

It works in a similar way with the nRF UART app from Nordic Semiconductor:

Image title

nRF UART App

That way I can exchange status, commands, and messages between the smartphone and the microcontroller over BLE connection.

Summary

With this I have a working UART-over-BLE connection between a smartphone and the ARM Cortex-M on the tinyK20 board. It is only a small step to extend the current application to a full UART-to-BLE bridge without the interactive part. And, the BLE UART connection is only a start with much more to explore:

  • Driving a Robot with BLE
  • Add BLE connection to a quadrocopter
  • Using the microcontroller as BLE mouse or keyboard
  • Sending smartphone accelerometer and gyro data to the microntroller
  • Using the BLE beacon mode (Apple iBeacon and Google EddyStone)
  • Changing the color of LEDs with a color picker
  • Read/Write microcontroller pins
  • 3D printing a case for the tinyK20 + BLE module
  • And, many more things which can be done with BLE…

But, these are all subject of further posts. Until then, I will extend this BLE project which is available on GitHub.

Happy BLEing!

Links

Topics:
iot hardware ,arduino ,bluetooth ,usb ,adafruit

Published at DZone with permission of Erich Styger, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}