This tutorial show how to use the Microsoft Azure Sphere Avnet Starter Kit to read Air Quality data from Mikroe Air Quality 4 click module. This module don't have a public software driver for Azure Sphere, than we will show how use Avnet project code, and create the driver for read the air quality data from the module.
Mikroe moduleMikroe produces a line of modules called click, they have a default interface call Mikro BUS that's make ease to connect this complexity sensors to a microcontroller. In this case we are using the Air Quality 4 click, that uses the SGP30 sensor from SENSIRION. You can find more information about this module on the website: https://www.mikroe.com/air-quality-4-click Basically the sensor produces information about two air quality parameters: CO2 and TVOC. The CO2 value is measure in parts per million, and the inicial value is 400 ppm, and the TVOC is measure in parts per billion the inicial value is zero. The higher the values, the more harmful the air breathed into the environment is. More detail about the sensor SGP30 could be found here: https://download.mikroe.com/documents/datasheets/SGP30_Datasheet.pdf
This module uses de I2C protocol to exchange data with the microcontroller. I2C is an industrial protocol that uses two data wires SDA e SCL and has one MASTER device and many SLAVE devices. The Azure Sphere will work with MASTER device, and the Air Quality 4 click one SLAVE device. Every device on this network has a unique identifier and all comunication must inform this identifier for the correct device responde the message.
OK now we know what the sensor do and what protocol we will use to comunicate with it. But how we can do that? To start we will use the project provide by Avnet in your GitHub: https://github.com/CloudConnectKits/Azure_Sphere_SK_ADC_RTApp This repository has two projects we will use the AvnetAzureSphereSK_OLED, because this project has the code necessary to use I2C protocol and send data to Azure IoT Central. If you prefer I will publish in another repository my version of this same project with the changes ready. Clone this project and open with Visual Studio 2017 or 2019. If you look at the main.c file, you will find the call for a function named initI2C().
This function initI2C do two important fings, first they inicialize the Azure Sphere as a I2C MASTER device and write the pointer for the I2C library on the variable i2cFd, remeber this name.
At the end of the initI2C function code, it still schedules the execution of the function AccelTimerEventHandler. This second function will be responsible for collect data from sensors and send to Azure IoT Hub or Azure IoT Central. We will code our final code in this function.
Ok now we have to look at the SGP30 datasheet to understand how to communicate. On this section we will find that the sensor will respond on the I2C address 0x58 in hexadecimal.
Most I2C sensors have some type of communication test command. The SGP30 has a measure test, if we send the command 0x2032 we will get a reply default value 0xD400.
To test that we will use this simple code, into the initi2c() after I2C Master inicialization.
uint8_t buff[2];
buff[0] = 0x20;
buff[1] = 0x32;
int32_t retVal;
uint8_t sgp30_buffer[2];
Log_Debug("SEND [%d] 0x%02x [%d] 0x%02x\n", 0, buff[0], 1, buff[1]);
retVal = I2CMaster_Write(i2cFd, 0x58, buff, 16);
sleep(1);
retVal = I2CMaster_Read(i2cFd, 0x58, sgp30_buffer, 2);
Log_Debug("RET [%d] 0x%02x [%d] 0x%02x\n", 0, sgp30_buffer[0], 1, sgp30_buffer[1]);
if (retVal < 0) {
Log_Debug("ERROR: platform_read(read step): errno=%d (%s)\n", errno, strerror(errno));
}
The variable buff is the buffer that contains the command in hexadecimal that we want o send. The I2CMaster_Write send the command in buff variable, using the i2cFd pointer for the MASTER I2C device, and the address 0x58 that represents the sensor. The last parameter is the number of the bytes that has in the buffer variabel (16 bytes).
We wait a long time 1 second, but you can a smaller value. Than we use the I2CMaster_Read to read the response and writes on sgp30_buffer. If we lookat the output console, we will see that the sensor respond with the correct value.
Now we go back to the datasheet and find this instructions to get de sensor data. First we need to send the command Initi_air_quality 0x2003 then we can send the command Measure_air_quality 0x2008. For 15 seconds the response will be 400 for CO2 and zero for TVOC. IMPORTANT: put in comment ou remove the code that we did in the last step.
On the begin of initi2c() function we will put this code, to send the Init_air_quality command.
uint8_t buff[2];
int32_t retVal;
buff[0] = 0x20;
buff[1] = 0x03;
Log_Debug("INIT [%d] 0x%02x [%d] 0x%02x \n", 0, buff[0], 1, buff[1]);
retVal = I2CMaster_Write(i2cFd, 0x58, buff, 16);
On the begin of AccelTimerEventHandler() function we will put this code, they first send the Measure_air_quality command 0x2008 then wait for 1 second. After that, we use the I2CMaster_Read() function to get the values in the sgp30_buffer. The data return will be structured like this:
8bits_CO2 | 8bits_CO2 | 8bits_CRC_CO2 | 8bits_TVOC | 8bits_TVOC | 8bits_CRC_TVOC
In the end we use the command to convert hexadecimal values to decimal.
uint8_t buff[2];
int32_t retVal;
uint8_t sgp30_buffer[6];
buff[0] = 0x20;
buff[1] = 0x08;
Log_Debug("READ [%d] 0x%02x [%d] 0x%02x \n", 0, buff[0], 1, buff[1]);
retVal = I2CMaster_Write(i2cFd, 0x58, buff, 16);
sleep(1);
retVal = I2CMaster_Read(i2cFd, 0x58, sgp30_buffer, 6);
Log_Debug("RET [%d] 0x%02x ", 0, sgp30_buffer[0]);
Log_Debug("[%d] 0x%02x ", 1, sgp30_buffer[1]);
Log_Debug("[%d] 0x%02x \n", 2, sgp30_buffer[2]);
Log_Debug("RET [%d] 0x%02x ", 3, sgp30_buffer[3]);
Log_Debug("[%d] 0x%02x ", 4, sgp30_buffer[4]);
Log_Debug("[%d] 0x%02x \n", 5, sgp30_buffer[5]);
int co2 = (sgp30_buffer[0]<<8) | sgp30_buffer[1];
int tvoc = (sgp30_buffer[3] << 8) | sgp30_buffer[4];
Log_Debug("[ CO2 %d ] [ TVOC %d ]", co2, tvoc);
if (retVal < 0) {
Log_Debug("ERROR: platform_read(read step): errno=%d (%s)\n", errno, strerror(errno));
}
You will see that the sensor reacts as expected, returning constant values first and then changing after 15 seconds.
To send this data to Azure IoT Central, we need to alter the sensor_var struct to include out two new parameters.
And then write this to the sensor_data structure.
Than we need to enable the IOT_CENTRAL_APPLICATION preprocessor on
build_options.h
Than we need to alter de i2c.c file to change the JSON message generation, to add your new parameters. Search for this snprintf on the code.
On the end of this command we add the two new variables and change the format of the JSON message.
You have too change the deviceTwin.h file to increase the JSON_BUFFER_SIZE used to generate the new JSON message.
To connect using a simple way with Azure IoT Central we will use part of this tutorial from Microsoft, to use de Device Provision Service to generate the connection string: https://docs.microsoft.com/pt-br/azure/iot-central/howto-connect-windowsiotcore?WT.mc_id=AZ-MVP-5003638
You have to enter on Azure Portal, and create a new or access a existing instance of Azure IoT Central.
First we click on device models and create a new model.
Than we enter in create a new telemetry parameter, and use the names: co2 and tvoc
Once the two parameters co2 and tvoc are add to your model, we can continue and create a new device.
Enter on devices and create a new device use the new model type we create in the last step. Select the type REAL device when you are creating the new one.
On the device list, select your new device and click on connect link on the top right corner, this screen will show, copy the Azure IoT Central Scope code, the device id and the SAS primary key.
Now you need the NodeJS installed in your computer to use npm package manager to install de dps-keygen. This module will generate connection string we need in your device code.
npm i -g dps-keygen
Use this command fillin the gaps with the informations from Azure IoT Central device connection screen.
dps-keygen -di:<Device ID> -dk:<Primary or Secondary Key> -si:<Scope ID>
Copy the connection string show on the console and paste into the MY_CONNECTION_STRING into the connection_string.h file.
At last, change the app_manifest.json copy the Azure IoT Hub URL from the connection string to the AllowedConnections parameter.
If you run your code on Azure Sphere and go to Azure IoT Central you will see the data from the Air Quality Sensor display into the graph.
Comments