Wiring, I2C and Bluetooth® Low Energy
In the previous chapter, we specified the required hardware for our Bluetooth® Low Energy application and the software that is required to develop and flash the firmware respectively. Now it’s time to get hands-on. In this part, we are going to connect the sensor to the PAN1781 Evaluation Board (EVB), read it out and send the properly “packaged” data via the Bluetooth® Low Energy Technology. First of all, let’s have a look how the sensor is wired to the PAN1781 EVB.
Wiring of the PAN1781 EVB and SN-GCJA5
Basically, the sensor can be read out via UART interface or I2C bus. In this example, we want to read out the sensor via I2C, because this bus is suitable for the connection of several sensors. The JST-SM05B-GHS-TB(LF)(SN) acts as a connector for the sensor to contact the pins. The pinning of the sensor and the PAN1781 board is illustrated in this table:
But how can we identify the right pin? On the PAN1781 board, all pins on the front and back are legibly labelled. But to identify the pins at the sensor, you just have to look directly at the sensor. The pins are numbered from left to right in ascending order, starting from 1. See in the illustraion on the right side what the connection should look like.
For the PAN1781 EVB to supply power to the sensor, it must be set to board mode. We do this by setting jumper 17 to the horizontal position. Otherwise, in the vertical position, the board would be in shield mode and thus could not supply external components with power. More information on this can be found on page 16 of the EVB User Guide (here).
If you now power the EVB via USB (X1), for example, then the sensor is also supplied with power. You can confirm this by holding the sensor close to your ear and hearing a slight hum from the internal fan. The connection works – and, as a pleasant side-effect, no pull-ups are needed for the I2C bus. The internal pull-ups are located within the sensor.
Sensor Read out
The Registers: As mentioned before, the sensor is read out by I2C. Internally the sensor data is organized in the form of separate registers. The registers of particular interest for our purposes are the ones containing the particle density values 1.0, 2.5 and also 10.0. These are located in (0x00-0x0B).
For every particle density, the actual value is spread across 4 consecutive byte registers in little-endian format, which means the lowest byte or better say Least Significant Byte is placed in the lowest address. This is important to know because when reading out the values one by one, from top to bottom, we have to assemble the bytes in the correct order. This is done by shift operations in the code later. And when we assemble the bytes correctly, we have to divide it by 1,000 since the output values are 1,000 times the real value. This is based on the high precision of the sensor to calculate the particle density to three decimal places.
For the sake of completion, there are also other registers but we don’t use them in the code. In registers (0x0C – 0x19) the particle count data can be found. This is basically the raw data which is the basis for the mass-density values in the aforementioned registers. There is also a sensor status register (0x26), where the state of internal components can be tracked like the sensor itself, photodiode, laser diode and the fan.
Now: what has to be done on the application level to read out the register? The readout can be divided into two parts: An I2C Write command where the device is being addressed - and the memory address from which the consequent readout is being sent. And the I2C Read command delivering the bytes (See illustration).
There is something very important to keep in mind at this point: The readout part must not have a stop bit in the end. This means the main, or more precisely the PAN1781 doesn’t release the bus so that other devices cannot interrupt this micro-transaction. Most Hardware Abstraction Layer (HAL) functions use the stop bit by default, so be careful here. In detail: This is also known as a repeated start condition which has to be supported by the I2C driver. But most low-level drivers do have this option.
Bluetooth® Low Energy - Nordic Service UART
There are certain questions that always arise in every development of a Bluetooth® Low Energy application: I want to transfer data between 2 devices, but how should I do it? Which approach makes the most sense in this area? As most of you definitely already know, there is a list of predefined Bluetooth® services maintained and provided by the Bluetooth® special interest group, with fixed assigned UUIDs for the dedicated services. These services actually cover most of the use cases in sensor applications, and in the end, thanks to this modularity concept, you just need two devices with the same implemented services and you’re good to go. But in the end, if your application doesn’t cover the use case of these predefined services fully, or if you want to cover the whole spectrum of your application, you would either need to implement more and more services, which would take more space in your memory, or you would need to take existing services which target another use case such as the heart rate profile and use that for a battery application.
As you can see, in order to customize the services to fit your requirements, you’ll ultimately find yourself on the other side of Bluetooth® Low Energy programming, which defines your own custom GATT services and profiles.
For a developer without experience in Bluetooth® Low Energy development, getting started with GATT programming could be time-consuming in the beginning to fully understand and effectively use the concept of characteristics, notifications, descriptors, etc. And it’s also necessary to assign an individual UUID for every characteristic and for the whole service itself.
This GATT approach - which seems complicated at the first glance – is worth a closer look and will be the subject of a future blog post. However, with this article, we want to show how a wired communication in the past can now be replaced with Bluetooth® Low Energy.
This matter is addressed by the Serial Port Profile (SPP) which is ultimately just a serial port emulation (UART) over Bluetooth®. The SPP profile played a big role in Bluetooth® Classic (i.e., before 4.2), but there is no standardized SPP profile defined by the Bluetooth® special interest group for Bluetooth® Low Energy. That’s why every chip vendor comes with their own Bluetooth® Low Energy Serial Port Profile which is merely a custom GATT service. This SPP approach fits well in the sweet spot for a balance between very customizable applications with limited functionality that need to be developed in a short time without diving deeper into the Bluetooth® Low Energy concept. In the end, the major workload will be on the application side to actually decode the sent string. But we’ll come to that later.
We use the Nordic UART service (NUS) to send our sensor data here as ASCII string via Bluetooth® Low Energy. It’s a custom serial port profile in the Bluetooth® Low Energy technology by Nordic Semiconductor. It’s actually very easy to use since it contains only two characteristics: TX for sending values out - and RX for receiving data. In order to make the data human-readable, we will send the data already assembled correctly (shifted to the correct position) and with some identifiers in an ASCII String which is again being sent out via UART service’s TX characteristic:
In the next part, you will learn how to do this in the code. Stay tuned!