This article is the second installment in a series that details the creation process of a Bluetooth Low Energy (BLE) sensor beacon (See Part 1). Here, we provide an overview of the firmware structure and functionality without diving into code details.

The BLE beacon project is code-named “Athena,” you may see this name mentioned in the text, schematics, and source code. The source code can be found in the following repository: https://github.com/JasonStoyanov/athena_fw

The main functionalities implemented in the firmware are:

  • BME280 sensor reading
  • BLE communication
  • User button handling and LED indicator
  • Storing user configuration in non-volatile memory
  • Battery voltage monitoring
  • Device firmware update (DFU) over BLE

The project’s firmware uses Zephyr real-time operating system. Although a simple device such as a BLE beacon does not need complex scheduling, an RTOS can simplify integrating the communication stacks and make our code more scalable.

Modes of operation of the BLE beacon:

  • Normal mode – In this mode, the beacon advertises without allowing connections. The BLE advertising contains the sensor’s data. This is the default mode after power-up.
  • Configuration mode – In this mode, the sensor’s data advertising is stopped. The beacon starts advertising that connections can be made. Once a connection is established, the beacon firmware can be updated, or user configuration can be made.

User Interface

Button

The button is used to transition between the two operating modes (“Normal mode” and “Configuration mode”). To trigger a transition, the user must hold the button for 5 seconds and then release it.

When using buttons, it’s important to consider that they can produce electrical noise when pressed or released. This noise, although short-lived, can cause fluctuations in the logic level on the input of the microcontroller unit (MCU) and lead to incorrect readings in the code. To address this issue, it’s necessary to use a de-bounce filter. Many MCUs have integrated filters for this purpose in the GPIO pins. A software debounce filter can also be implemented, and we are using such a filter as it does not require external components. For additional implementation details, you can look at the following article: “How to Debounce Button Inputs in Real-Time Operating Systems”.

LED

The LED provides visual feedback on user operations. In the current version, the LED is toggled when we change the mode of operation using the button. A dedicated Zephyr thread is used to toggle the LED. The thread waits on a semaphore and then enables the LED for a predefined time. The semaphore is set when the button condition for changing the operation mode is met.

Mobile App

The BLE advertising transmitted by the beacon can be detected using various BLE scanner applications, one example being Nordic’s nRF Connect for Mobile. These types of applications allow us to capture the raw BLE advertising bytes. However, to provide a more comprehensive user experience, it is essential to format and visualize the data from our beacon. To achieve this, we will develop a dedicated mobile app, and the detailed process will be explained in an upcoming article.

Sensor Read

Zephyr RTOS includes a driver for BME280, which significantly expedites the prototyping process. We use the sensor configured for SPI communication.

Enabling the usage of BME280 includes enabling the MCU SPI peripheral and selecting the pins in the DeviceTree file.

&spi2 {
	status = "okay";
	cs-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>;
	pinctrl-0 = <&spi2_default>;
	pinctrl-1 = <&spi2_sleep>;
	pinctrl-names = "default", "sleep";
	bme280@0 {
		compatible = "bosch,bme280";
		reg = <0>;
		spi-max-frequency = <1000000>; /* conservatively set to 1MHz */
	};
};

For complete DeviceTree configuration, please refer to the source code available on GitHub.

Enabling the software support of BME280 in the project config file:

CONFIG_SPI=y
CONFIG_SENSOR=y
#Enable the BME280 sensor with the recommended settings for Weather monitoring (see datasheet)
CONFIG_BME280=y
CONFIG_BME280_MODE_FORCED=y
CONFIG_BME280_HUMIDITY_OVER_1X=y
CONFIG_BME280_TEMP_OVER_1X=y
CONFIG_BME280_PRESS_OVER_1X=y
CONFIG_BME280_FILTER_OFF=y

The sensor can be read using Zephyr’s Sensor Interface API:

sensor_sample_fetch(dev);
sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp);
sensor_channel_get(dev, SENSOR_CHAN_HUMIDITY, &humidity);

BLE Communication 

We are using the BLE host stack from Zephyr RTOS and the Host Controller provided by Nordic. For details on the Bluetooth protocol, you can look at the Nordic DevAcademy course, which provides a comprehensive explanation of developing an app with BLE.

Services

In the current firmware version, we have defined one BLE service: the Athena Configuration Service (ACS). It contains a single characteristic, which is the beacon ID. Users can read from and write to this characteristic.

There is also a Bluetooth SMP service used to transfer a new firmware image to the beacon.

Both services are available only in the “Configuration Mode” of the beacon.

Type of Advertising

The beacon uses BLE’s legacy advertising, which operates on channels 37, 38, and 39.

The BLE stack can support multiple advertising sets in a single device, and we will use two advertising sets:

  • Sensor Data Advertising Set—This is non-connectable, non-scannable, undirected advertising that contains the beacon’s data. During “Normal mode”, the beacon will use this advertising. The frame contents are shown in Figure 1.
  • User Configuration Advertising Set — This is a scannable and connectable advertising used during “Configuration Mode”. Once the connection is established, the user can configure the beacon and perform firmware updates.

The two advertising sets are never active at the same time.

Advertising interval

The advertising interval is set to 1000ms.

The advertising interval affects power consumption. A shorter advertising interval requires the transceiver to be more active, thus increasing power consumption. Setting a larger interval will reduce the power consumption but make it harder for a scanning device to detect the advertising, as scanning is also performed at intervals. Therefore, we selected the largest interval a scanning device can detect in a reasonable time.

Using Advertising to Broadcast Sensor Data

The legacy advertising packet’s Protocol Data Unit (PDU) can contain a maximum of 39 bytes. Two bytes are reserved for the header and six for the advertiser’s (MAC) address, leaving 31 bytes that can be utilized for our specific purposes. Popular protocols that use those bytes are iBeaconEddystoneBTHome, etc. Selecting an established protocol makes using external tools a bit easier, as many Bluetooth scanning apps already have filtering for those beacon types. We are using Eddystone for our beacon.

The protocol utilizes some of the available bytes, and we have 20 bytes remaining for use according to the Eddystone specification. The Eddystone defines four frame types (UID, URL, TLM, EID). Since none of them are suitable for use with a sensor beacon, we are using a custom frame utilizing those 20 bytes (See Table 1).

Figure 1. BLE legacy advertising and Eddystone frame
Byte PositionDescription
0Eddystone UUID (0xAA)
1Eddystone UUID (0xFE)
2Reserved
3Reserved
4Reserved
5Temperature (integer part)
6Temperature (fractional part)
7Humidity
8Status
bit 0 – BME280 Initialization Error
bit 1 – Low Battery
bit 2 – Battery Measurement Error
9App Version
10Beacon ID
Table 1. Athena beacon data bytes

Remember that smaller advertising packets minimize power consumption due to the RF transmitter’s shorter active time.

It is important to understand why we have included a Beacon ID byte in our frame for identification. While every BLE advertising device has an advertiser address (MAC address), it is not a good idea to use it for unique identification. This is because you may not have access to this MAC address information on some devices. For example, on iPhones, the BLE MAC address is randomized for security reasons, and developers do not have access to the actual MAC address.

Storing User Data

In almost every embedded product, there is a need for storing information in a non-volatile memory. Fortunately, Zephyr RTOS provides a non-volatile storage (NVS) API for accessing non-volatile memory, significantly speeding up the development process.

Our device uses the NVS API to store and retrieve the beacon ID that the user can configure.

Battery Voltage Monitoring

We monitor the battery voltage level using the microcontroller’s analog-to-digital converter(ADC).

For accurate measurement, the reference voltage of the ADC must be stable. If we use the battery voltage as a reference, it must pass through a regulator that can keep a stable output voltage while the battery voltage fluctuates. Fortunately, the NRF53 ADC can use a reference voltage from an internal regulator. By selecting the internal 0.6V regulator as a reference and configuring the gain of the ADC input signal to 1/6, we achieve a measurement range of 0 to 3.6V.

As we create a low-power device, we must ensure that it will enter low-power mode once the ADC completes a measurement. It is best to schedule the battery voltage sampling while the BLE transmitter is active (advertising). The current consumption is the largest at that moment, and the battery voltage will experience the most significant drop. Checking the measured value is above the beacon’s operating voltage of 1.8V will ensure proper operation.

The battery voltage monitoring from a firmware perspective is organized as follows:

  • A dedicated Zephyr thread is used for ADC measurement.
  • The measurement occurs every 2 minutes.
  • The measurement is placed in a message queue when it is ready.
  • The main thread reads the ADC measurement data from the message queue and checks if it is within the predefined limits.

Device Firmware Update (OTA updates)

In today’s connected world, every IoT device should be capable of being updated. This allows you to fix firmware bugs and introduce new features.

Our beacon’s firmware can be updated over BLE. A Bluetooth SMP service is available as part of Zephyr, and it’s enabled when the beacon is put into “Configuration mode”. A device can connect to the beacon and upload a new image. The image is flashed in the on-chip flash of the NRF53 MCU.

Zephyr uses MCUboot open source bootloader. MCUboot defines a common infrastructure for the bootloader, defines system flash layout on microcontroller systems, and provides a secure bootloader that enables easy software updates.

Future Improvements

  • Reduce the number of bytes in the advertising frame
  • Schedule the sampling of the ADC to be during the BLE advertising
  • Advertise the SMP Service when the “User Configuration Advertising Set” is active.

Was this article helpful?