Category: MCP9808

UPM library for MCP9808 in XDK.

If you have read my blog at all you may be beginning to think I have a fetish for the MCP9808. Well, maybe a little, but for a good reason. If we look it’s data sheet we see the MCP9808 is a surprisingly complex device. Some of the features the data sheet lists:

  • Accuracy:
    •  ±0.25 (typical) from -40°C to +125°C
    • ±0.5°C (maximum) from -20°C to 100°C
    • ±0.5°C (maximum) from -20°C to 100°C
  • User-Selectable Measurement Resolution:
    • +0.5°C, +0.25°C, +0.125°C, +0.0625°C
  • User-Programmable Temperature Limits:
    • Temperature Window Limit
    • Critical Temperature Limit
  • User-Programmable Temperature Alert Output
  • Operating Voltage Range: 2.7 V to 5.5V
  • Operating Current:  200 µA (typical)
  • Shutdown Current: 0.1 µA (typical)
  • I2C bus compatible

These features make the MCP9808 ideal for a variety of temperature monitoring applications when being precise would be an advantage.

The devices I have been using I got from Adafruit.  They have a driver library for the Arduino  that is useful, but I want to use the device with Linux based IoT platforms such as the Intel Edison or the Beaglebone Black. Both of these platforms support the Intel UPM library , so it made sense to add a driver for the MCP9808 to that. I implemented the driver and added a pull request to have it incorporated into the Intel UPM library. The MCP9808 was accepted in to version 4.0 of the library and should be available after upgrading the version of MRAA on your board. If not — I have a blog post that lists various ways to update MRAA/UPM on your boards. (UPM is very easy to compile).

I provided a C++ program to the UPM repo that exercises all of the implemented functions.  You can copy the code from that example into an Intel iotdk-ide project (Eclipse) and run it from there. But I didn’t include a very good example for Nodejs. That brings us to the purpose of this post — I want to go over how to use the MCP9808 in Nodejs with XDK on the Edison (or compatible) MRAA board.

In order to give a proper demo I created a Nodejs/Socket.io app that illustrates all the implemented features of the MCP9808 UPM driver. It is setup as an XDK project so you can download it and open it in the XDK ide to run it on your Edison. Before you run it open the server.js file and change the line

var temp = new mcp.MCP9808(1) 

to whatever i2c bus you are using. I generally use a handmade boardthat extends the Edison Mini breakout board so I use bus 1. It will be bus 6 on the Arduino or DFRobot breakout, 0 on the Galileo.

When you download and start the app on the board browse to it’s url :8085 (like edison.local:8085) and you should see something that looks like this:

mcp9808_default_celcus

This is a single page app that uses socket.io to communicate with the Edison. The Edison serves the app via Express and the UI is basic HTML with the  Bootstrap framework. The four sections of the app (from right to left) are:

Temperature:

The radial gauge will reflect the current temperature at the device. The MCP9808 reports temperatures as Celsius (C), but the driver provides a conversion to Fahrenheit (F). The F values are calculated, so when we switch between C and F there are sometimes rounding differences. All the other temperature values in the UI will convert to C or F except for resolution. Resolution is always reported as C. I have the temperature limited from  freezing to boiling range, but the MCP9808’s range is little wider than that — see the specsheet.

Temp limits: 

These reflect the state of the three temperature limit registers detailed in section 5.1.2 of the spec sheet. These registers are used to allow the setting of temperature limits the MCP9808 can monitor so that we don’t have to constantly check for out of limit temps in code. The limit registers will cause flags in the ambient temp register (section 5.1.3)  to set if a threshold has passed. The driver exposes these bits as flags that can be read (see lines 158 to 167 of the server code) via a simple function call.  The thing to remember with these flags is that they reflect the state of the bits as of the most recent getTemp() call, so you need to read the temp before reading the flags.

I use the state of the Temp limit bits to set the color of the subheadings in the Temp Limit section. Since at power on the temps are set at 0 C, so the bits for TCrit and TUpper are set. Using the sliders to set a value greater than the current temperature will allow the TCrit and TUpper values to go green:

MCP9808_alert_off

The temp limit registers are also used in the Alert functionality.

Alert Control: 

Described in section 5.2.3 of the spec sheet,  the MCP9808 has the ability to control an alert pin when certain conditions arise.  On power up alerts are disabled. Default sets the device to comparator mode (section 5.2.3.1). The alert will assert (in this case pull low — you need to use a pull up on the pin) whenever one of the monitor temps are crossed. When the temp comes back within limits the alert will de-assert. In interrupt mode the just the TUpper and TLower are monitored. It the temp goes over a threshold the alert is asserted and will not de-assert until the temp goes back with range and the interrupt is cleared by code. These calls are illustrated in the server code.

Other:

The Other section contains controls for  resolution and hysteresis and display for device info, id and rev.

Resolution will always be reported in Celsius. Startup default is 0.0625 and equates to 4 temp measurements per second. Temperature resolution is detailed in section 5.2.4 of the spec sheet.

Hysteresis will be reported in either C of F depending on the driver settings. Hysteresis is detailed in section 5.2.2 and Figure 5-10. If the alerts are not clearing as you expect, check the hysteresis settings.

About:

The about menu item is a list of helpful links concerning the MCP9808.

What’s not Illustrated:

I didn’t use the sleep and wake function in this application. It is illustrated in the test file in the UPM library.

What’s not implemented: 

There were a couple of things that I did not implement. First: The temp monitoring registers can be locked by setting bits in the config register. It takes a power cycle to unlock them so I didn’t implement this. The alert can be set to assert active high. I didn’t add this functionality either. If either of these capabilities are needed you can just make an MRAA call directly to the device to do so. If you need help with either of these just ask me in the comments.

 

Intel Edison and I2C sensors with XDK

The Intel Edison is becoming a popular system to use for IOT devices. Despite its small form factor it is a surprisingly capable platform. This makes the Edison a good choice for interfacing with sensors.

I like the Edison mini breakout board over the Edison kit for Arduino because of the form factor. The  mini breakout board provides USB connectivity, power input and a battery charging circuit to the Edison that covers most the of my requirements for devices.

The drawback of the mini breakout is that you need to either solder in some wires or add a header to the break out board to access i/o for the Edison. Also, the Edison I/o on this board operates at 1.8 volts while most sensors operate at 3.3 volts or higher so a level converter is needed.

The Intel Edison, on the mini breakout, supports various types of i/o but the one we are interested in today is I2C  Inter-Integrated circuit is a two wire serial protocol that is used by components to transfer data between one-another. On the mini-break out board we will be using I2C bus number 1.

Here the Edison is connected to a breadboard containing the MCP9808. There are other devices on the board.
Here the Edison is connected to a breadboard containing the MCP9808. There are other devices on the board.
Here is one way to make the i/o needed for connection available.
Here is one way to make the i/o needed for connection available.

Parts list:

  1. Intel Edison mini breakout board kit.
  2. Sparkfun bi-directional level shift converter.
  3. Adafruit MCP9808 temperature sensor board.
  4. Mini bread board.
  5. Solderless bread board jumpers. 
  6. Dupont male to female cable. 
  7. 90 degree dual row header. 

Items 6 and 7 are optional – you could just solder some wire onto the Edison if you prefer, or use some other type of pin headers.

Connection:

Edison                     Level Shifter                     MCP9808

J17  – 8                          LV1

NC                                 HV1                                  SDA

J18 – 6                           LV2

NC                                HV2                                   SCL

JP19 – 2                         LV — 1.8 volt

JP20 – 2                         HV — 3.3 volt                   VDD

JP19 – 3                        Both grounds                  Ground

The connection looks something like this. The level shifter and MCP9808 are in the center of the yellow board.
The connection looks something like this. The level shifter and MCP9808 are in the center of the yellow board.

With this connection we are ready to code.

I will be using the Intel  XDK IOT edition  to read values from our temp sensor. If you have not used the XDK you can learn how to get started here. Just create a blank project and paste the following code in. Running the code will display the temperature in the console every second.

function char(x) { return parseInt(x, 16)}; // helper for writing registers

var mraa = require('mraa'); //require mraa
console.log('MRAA Version: ' + mraa.getVersion()); //write the mraa version to the Intel XDK console

var x = new mraa.I2c(1); //We will use a device in I2C bus number 1
x.address(0x18); //Default for MCP9808 is 0x10

//x.writeWordReg(char('0x01'), char('0x0100')); // Controls sleep mode for the temp sensor.

periodicActivity();

function periodicActivity()
{

var t = x.readWordReg(char('0x05')); // 0x05 is the register for the current temp.
//The byte order of words is not the same between Edison and the MCP9808
//The edison stores the most significant byte first - big endian, where the
//MCP9808 stores the lowest byte first -- little endian.
//Here is a wikipedia article on endianness. 
var s = ((t & 0xFF) << 8) | ((t >> 8 ) & 0xFF); //swap the bytes.
var r = s & 0xFFF; // Mask of the control bits to get the temp value
r /= 16.0; // dividing by 16 will give us the temp in celcius as long as the temp is above 0.

s = r * 9 / 5 + 32; //get the farenheit value.

console.log(r + " C " + s + " F"); //log the values

setTimeout(periodicActivity,1000); //do it again in a second.
}

For a more thorough explanation of the MCP9808 control registers see it’s data sheet.

And there we have it. It is not a very complex thing to interface an I2C sensor with the Intel Edison. We just need to use a level shifter and connect the thing up. Using the XDK it is fairly easy to read the temp data and control the MCP9808. The complexity comes in when more complex devices are integrated. It can take some time studying the data sheet of a device to figure out how to get everything working correctly.

There are other options for interfacing with I2C and other devices, but MRAA is the easiest in this case as it is already installed. If our sensor had been in the UPM library we could have used a predefined class to operate it.