I2C with Azure Sphere Hardware

Azure Sphere MT3620 – Painless I2C with the Grove Shield library

Please follow and share!
Twitter
Facebook
LinkedIn
RSS

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.

MT3620 Grove Shield
MT3620 Grove Shield

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).

Hardware Setup
Hardware Setup

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’.

Create Blank Azure Sphere Project
Create Blank Azure Sphere Project

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.

Add reference to the MT3620_Grove_Shield_Library
Add reference to the MT3620_Grove_Shield_Library

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)
Add MT3620 path to 'Additional Include Directories' field
Add MT3620 path to ‘Additional Include Directories’ field

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.
I2C with Azure Sphere and MT3620 Grove Shield

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.

Please follow and share!
Twitter
Facebook
LinkedIn
RSS

Comments

  1. 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”

    1. 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!

Leave a Reply to Andy from Workshopshed Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.