When first diving in to explore the Azure Sphere MCU, I was a bit dismayed that I2C and ADC are currently unsupported. My spirits were then lifted when I discovered that the Grove Shield for the Azure Sphere MT3620 removes that barrier!
The MT3620 Grove Shield
When I first purchased my Azure Sphere, I also added the Azure Sphere Grove Starter Kit. I have had a lot of good experiences with Seeed Grove kits in the past, so picking this one up was only logical. It provides the shield that sits atop of the Azure Sphere and exposes plug and play options for GPIO, Analog, and UART peripherals. The starter kit also shipped with a series of popular sensors so that you can get started designing your devices without having to breadboard or solder anything. There are tons of affordable Grove sensors available, each with accompanying schematics and source libraries for various hardware platforms.
The MT3620 Grove Shield Library
Seeed Studio has provided full C source code to their library that interfaces with the Azure Sphere board. In the same repository, they’ve also included code samples for each of the Grove sensors provided in the starter kit.
Creating an app that reads temperature and humidity at the press of a button
Prepping the hardware
In this project, we’ll be using two groves that come from the starter kit – the Grove – Blue LED Button and the Grove – Temperature and Humidity Sensor (SHT31).
Plug the Temperature/Humidity sensor into one of the I2C ports, and the button into the GPIO0 slot (this ultimately ends up using GPIO0 and GPIO1).
Setting up the Visual Studio project
The first step to any development is to clone the MT3620 Shield Library repository. Remember where you cloned this repository – we’ll be needing it shortly!
Once cloned, open Visual Studio 2017, and create a new project using the ‘Blank Application for MT3620 RDB (Azure Sphere)’ template (located in Other Languages -> Visual C++ -> Cross Platform -> Azure Sphere). I have named mine ‘OnDemandTemperatureAndHumidity’.
Once the project has been generated, we need to add the cloned MT3620 Shield Library project to the solution. Do so by right-clicking the solution in solution explorer, and select ‘Add existing project’, then find the ‘MT3620_Grove_Shield_Library.vcxproj’ that is located in the MT3620_Grove_Shield_Library folder of the cloned repository.
Next, add a project reference to the Grove Shield Library project that we just added. Do so by right-clicking on your ‘OnDemandTemperatureAndHumidity’ project, and select ‘Add’ -> ‘Reference’, then select ‘Projects’ -> ‘Solution’ in the left-hand treeview, and place a checkmark next to the MT3620_Grove_Shield_Library item.
Now we need to add the location of the MT3620_Grove_Shield_Library to the include directories of the project. To do so, right click on the ‘OnDemandTemperatureAndHumidity’ project and select ‘Properties’. Then in the left-hand treeview, expand ‘Configuration Properties’ -> ‘C/C++’ -> ‘General’. In the ‘Additional Include Directories’ field, add the path to the MT3620_Grove_Shield_Library folder (it contains the ‘Grove.h’ file). My field value (will vary based on where you cloned the library), now looks similar to this:
C:\SourceCode\AzureSphere\MT3620_Grove_Shield\MT3620_Grove_Shield_Library;%(AdditionalIncludeDirectories)
Bring on the Source Code!
In order to gain access to the functionality of the shield, we will need to add some capabilities to the app manifest of the project. In the root of the OnDemandTemperatureAndHumidity project, open ‘app_manifest.json’ and modify the Capabilities property to the following:
"Capabilities": {
"AllowedConnections": [],
"Gpio": [ 8, 9, 10, 15, 16, 17, 18, 19, 20, 12, 13, 0, 1, 4, 5, 57, 58, 11, 14, 48 ],
"Uart": [ "ISU0", "ISU3" ],
"WifiConfig": false
}
Next, in the Source Files folder, modify your main.c file with the following listing (my code additions are numbered, and commented inline):
#include <signal.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "applibs_versions.h"
#include <applibs/log.h>
#include "mt3620_rdb.h"
// 1. include the Grove, Grove LED Button, and Grove Temp Humidity Headers from the MT3620_Grove_Shield_Libary
#include "Grove.h"
#include "Sensors/GroveLEDButton.h"
#include "Sensors/GroveTempHumiSHT31.h"
static volatile sig_atomic_t terminationRequested = false;
static void TerminationHandler(int signalNumber)
{
terminationRequested = true;
}
int main(int argc, char *argv[])
{
// 2. define variables for button and initial state
static GPIO_Value_Type buttonState, lastButtonState;
void *ledButton = GroveLEDButton_Init(1, 0);
lastButtonState = GroveLEDButton_GetBtnState(ledButton);
// 3. initialize i2c feed with baud rate and temp humidity sensor
int i2cFeed;
GroveShield_Initialize(&i2cFeed, 115200);
void* tempHumiditySensor = GroveTempHumiSHT31_Open(i2cFeed);
struct sigaction action;
memset(&action, 0, sizeof(struct sigaction));
action.sa_handler = TerminationHandler;
sigaction(SIGTERM, &action, NULL);
// FYI - loop is every 1000 nanoseconds
const struct timespec sleepTime = { 0, 1000 };
while (!terminationRequested) {
// 4. determine button state and if it has changed, toggle LED accordingly
buttonState = GroveLEDButton_GetBtnState(ledButton);
if (buttonState != lastButtonState) {
if (buttonState == 0) {
GroveLEDButton_LedOn(ledButton);
Log_Debug("Button pressed.\n");
// 5. take a temperature and humidity reading every time button is pressed
GroveTempHumiSHT31_Read(tempHumiditySensor);
float temperature = GroveTempHumiSHT31_GetTemperature(tempHumiditySensor);
float humidity = GroveTempHumiSHT31_GetHumidity(tempHumiditySensor);
Log_Debug("Temperature: %.1fC\n", temperature);
Log_Debug("Humidity: %.1f\%c\n", humidity, 0x25);
}
else {
GroveLEDButton_LedOff(ledButton);
Log_Debug("Button released.\n");
}
}
lastButtonState = buttonState;
nanosleep(&sleepTime, NULL);
}
return 0;
}
Build and run your project on your device – every time you press the button, the LED will light up, and the debug output will indicate the current temperature and humidity. The resulting output will look similar to the following:
Remote debugging from host 192.168.35.1
Button pressed.
Temperature: 22.4C
Humidity: 40.2%
Button released.
Button pressed.
Temperature: 22.3C
Humidity: 43.3%
Button released.
Button pressed.
Temperature: 22.3C
Humidity: 42.9%
Button released.
Button pressed.
Temperature: 22.3C
Humidity: 41.9%
Button released.
Button pressed.
Temperature: 22.3C
Humidity: 41.3%
Button released.
Conclusion
The Azure Sphere Grove Starter kit greatly simplifies creating a proof of concept on the platform. What is especially nice is that the libraries provided by Seeed Studio have all the source code available on GitHub. This makes it easy to start creating code to interface with additional Groves, or if you are adventurous, creating your own custom Groves adhering to the interface.
Looking at the Grove code, it’s got some nice features like a simple hardware abstraction layer. That should mean that when the SDK catches up it should not be too much hastle to port the code back to native functions. One concern is the presence of “SeeedIoTHubTest.azure-devices.netβ in the manifest and a JSON parser. Is the board “Calling home”
I don’t think it is – the connection is in an app_manifest.json as being allowable, but there isn’t an actual app in the library – it looks like it may be left over from some type of early development. The app_manifest.json that is used is the one that resides in the same project as the main. I took a quick look around and don’t see anywhere it is calling out to an external resource. It may be good to submit a question on their GitHub π – good catch though – I hadn’t noticed that!
Have done, also read their readme (and re-read your article) and see that the process for including their library is by compiling from source code. Hence you can be fairly certain what you are putting on the board.
Agreed – I love that Seeed has made this code available to be combed through