Author: marc

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.

 

Debug Node js remotely on Intel Edison with Jetbrains Idea

This blog post will demonstrate how to configure Jetbrains Idea (or similar product) to remotely debug Node js applications on an Intel Edison. Though I will use Edison for this post these instructions should work for remotely debugging most Linux targets running Node.

I’m a big fan of using Node js to power my IoT applications on the Intel Edison. It has a lot of advantages — ease of use (once you get used to the node way of doing things), support for mraa and upm,  and it is pre-installed. Intel even provides a decent ide to code it with – the XDK for IoT.

Jetbrains makes several ide products for various languages. Most will support HTML5 and Node js via a plugin. I find Jetbrains tools are fairly reasonably priced and more than pay for themselves in productivity gains vs other tools. (No, I don’t work for Jetbrains, I’m just a fan). For the remainder of this post when I refer to one of Jetbrains compatible products I’ll refer to it as JB.

The XDK for IoT is a fine tool, but Jetbrains’ tools are an order of magnitude better. With Intellij I get better HTML5 support, Javascript debugging and Node debugging right in the ide. I prefer the Jetbrains ide for the bulk of the coding I do.

To use JB we need to do a little configuring. First – make sure the Node js plugin  is installed.  Jetbrains has detailed instructions on installing plugins on their website.  You should go ahead and install the “Remote Host Access” plugin too — we will need that to transfer files later.

We will be using a ssh tunnel to forward our host Node debugger port (default 5858) to our Edison device. We have a choice of ports to use so we have the option of working with more than one Edison. We will use port 5858 on one Edison in this example.

So — to configure:

On the Edison:

Allow port forwarding: 

SSH by default does not allow remote hosts to forward ports so we need to enable it. Edit /etc/ssh/sshd_config and find the following line somewhere in that config file.

#GatewayPorts no

Change it to this:

GatewayPorts yes

Shutdown the app running in .node_app_slot. 

I generally start my IoT apps from one of the templates included with the XDK (I’m lazy that way). I will also go ahead and use the node_app_slot directory to upload it to. This keeps the apps XDK compatible. I then open the local project directory in JB and setup the configuration for the project.

The problem here is that the Edison will autostart the project on a reboot. This makes us have to take the extra step of starting up the XDK, connecting to the Edison and stopping the running project.

Reboot the Edison to ensure the changes to our files are picked up. If you have code in node_app_slot go ahead and stop it.

On our host machine:

Setup ssh tunnel for port 5858:

The magic that makes our remote debugging work is ssh port forwarding. For Windows users this can be set up with Putty as described here. Just skip to the Putty config part and ignore the rest.  For Linux and Mac users this should work:

ssh -f root@edison.local -L 5858:localhost:5858 -N

Where edison.local is your device mdns name or ip address. This starts the port forwarding session. We have to manage this manually. If we reboot our Edison we need to kill the current ssh tunnel connection and start a new one. To do this first run:

ps aux | grep ssh 

This will list all the currently running ssh process. We need to find the one that matches the signature of the tunnel. It is easy to spot — the output will be look like this:

This is the output of ps aux | grep ssh showing our ssh processes.

From the output we can see the process that matches our ssh tunnel. The process id is the first number from the right (on Mac any way) and is 8084 in this case. To end the connection we need to kill the process with this command:

kill 8084

Windows users will just close Putty. This connection will also be cleared after a reboot.

Create a remote Node debug configuration in JB:

This assumes you already have a project started. What I normally do is start the project using a template in XDK and then open it with JB. This keeps the code compatible with both applications.

In JB select Run/Edit Configurations. We will click the + button and select ‘Node.js Remote Debug’. Name it what ever you like and set it up like this:

Node-js-deployment

When we debug this app we will use this configuration. There is more info on setting up Node js configurations here.

Setup Deployment in JB:

JB will automatically upload our source files to the Edison via a deployment configuration. To access this Select ‘Tools/Deployment/Configuration’ from the JB menu. Click the + button in the upper left and create a configuration that looks something like this:

deployment-1-node-jb

To keep from uploading unwanted files setup some exclude paths (these are local paths):

deploy-exclude-node-jb

To enable autoupload select ‘Tools/Deployment/Automatic Upload (always).  Whenever we save a file in our project it will be automatically sent to the proper location on the Edison. More info on JB deployment settings can be found here.

Once we have the deployment setup, we upload everything to the Edison by selecting “Tools/Deployment/Upload to xxxxx”.  Select the option that works for you.

Now that we have everything configured we are ready to debug. To start the debugging session we first ssh to the Edison and start our app in debug mode like this:

node --debug-brk app.js

Where app.js is the file we want to debug. This will cause node to start up and pause. We then select “Run/Debug” from the JB menu and give the debugger a little while to connect to our target machine.

Then we simply debug and run the app with all the Jetbrains goodness.

References:

https://www.jetbrains.com/idea/help/running-and-debugging-node-js.html

http://stackoverflow.com/questions/8445534/how-to-remote-debug-node-js-with-phpstorm

http://blog.trackets.com/2014/05/17/ssh-tunnel-local-and-remote-port-forwarding-explained-with-examples.html

Updating MRAA and/or UPM on Intel Edison.

Update November 4, 2015

With the release of mraa 8.1 there is now support for Node. 4.X. Upm  4.0 now allows the installation of upm modules via npm. I have updated this post to account for the new capabilities of these libraries.

There is also the option of updating the libraries by using the XDK. Using version 2571 of the XDK for IoT select the device config drop down and click ‘Update libraries on board’. updata-lib-xdk

This has to be the easiest way.

End Upate.

 

This comes up for me quite often so I decided to add a post about it.

Here are some quick and easy to follow step for installing/updating MRAA and UPM on an Intel Edison. The Edison generally  has the prerequisites installed already so you should just have to compile. If you need more comprehensive instructions you can take a look at MRAA/UPM section of my Getting Started with Minnow Board Max post.

These instructions assume you have git installed. If not install git first following the instructions found here.

Install MRAA:

If we just want to update MRAA on an Edison we can use:

echo "src mraa-upm http://iotdk.intel.com/repos/2.0/intelgalactic" > /etc/opkg/mraa-upm.conf

opkg update
opkg install libmraa0

This will install the latest release version of mraa (8.1 as of 3 November 15) and would be the preferred way to go.  If you need something that is upstream from this release you will have to down load and compile the source.

The mraa library can also be installed by npm if you only want the Node js bindings. It’s as simple as this:

npm install mraa

How to install from source is described here:

First we need to clone the MRAA repo from git hub:

git clone https://github.com/intel-iot-devkit/mraa.git

This will download whatever the default branch and tag is currently set at (usually the latest). If you wanted to switch to another tag (like version 7.3 for example) now is the time to do so

Now we are ready to build. We will used the same out of tree build as described in the MRAA documentation.

mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/usr -DBUILDSWIGJAVA=ON
make
make install

Details can be found on the mraa github page.

 

Install UPM:

Upm will be installed with mraa. If you have just installed the latest mraa you should have the latest upm also (4.0 as of Nov. 4, 2015).

As of version 4.0 upm can also be installed via npm. Of course you will only get the node bindings.  It’s as simple as:

npm install jsupm_<module-name>

If there are sensors in the upstream branch you want to use you will have to compile all or part of upm by hand as described here:

UPM can be cloned with the following:

git clone https://github.com/intel-iot-devkit/upm.git

Switch to the desired version (or just use the default). Ensure the version you select is supported by the version of MRAA that is installed.

Now is also the time to add any libraries that you need that are not currently in the release. Just add the directory of the driver to the /src directory with the required support files.

We will again be using the out of tree build as described in the documentation. Enter these commands to build and install:

mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/usr

If you want to only install a specific driver change to that drivers directory in build/src and then run:

make 
make install

If you want to install all of upm just run make and make install in the root of the build directory.

Building UPM on an Edison can take a while, so be patient.

That should do it. If there are no error messages you should be ready to utilize the new libraries.

Details can be found on the upm github page.

Getting started with Minnowboard MAX

Update October 12, 2015

MRAA 8.0 and UPM 4.0 have been released recently. These releases offer improvements in both stability and, in the case of UPM, an increase in number the sensors supported. I have updated this post to install the latest versions of this software.

End Update.

After recently receiving my Minnow Board Max  (MBM)  I found that there are few good resources for getting started with it. Unlike the BeagleBone Black I have used before, the MBM does not have a 4GB eMMC that we can program by flashing a prebuilt OS image. Instead we need to use one of the external connectors to provide storage for the OS. We have a choice of using a mini SD card, USB storage, or a SATA2 device. I chose to use an 230 GB OCZ Vector on the SATA port.

The beauty of the MBM is that it is essentially a low powered X64 compatible computer. This opens up many options for OS that we can use. Since I have such a large SSD on the system I chose to dual boot Windows and Linux. I put Windows 8.1 on just because I could, not because I have any plans to develop with it. Surprisingly, 64 bit Windows runs pretty well on the MBM — not nearly as laggy as I expected. But Windows heavily loads the MBM making it run hot compared to running it with Linux. Complete instructions for installing Windows 8.1 on the MBM can be found here.

For my needs Linux is a better choice. I want to be able to take advantage of the MRAA and UPM libraries as well as have a desktop OS on the board. Since we only have 2 gigs of memory on the MBM I want a distro with a very lightweight window manager. I also want to use Ubuntu as I have a long history with it (plus I am not that crazy about Yocto anyway). This lead me to Xubuntu — an Ubuntu distro that utilizes the XFCE window manager. I chose to use version 15.04.

To get the system I am looking for I will be following these steps:

  1. Update BIOS
  2. Install OS
  3. Install Nodejs
  4. Compile and install SWIG 3.0.7.
  5. Compile and Install MRAA 8.0
  6. Compile and install UPM 4.0

Update BIOS: 

My board shipped with version 0.80 of 64 bit BIOS.  As of 9/10/15 the latest bios is 0.82, which can be found here. I used MinnowBoard.MAX.FirmwareUpdateX64 for the update. Instructions for updating using the MBM Flash Utility can be found here.

Install O/S

Xubuntu 15.04 can be downloaded here. Be sure to get the 64 bit version. The image can be burned to a DVD or put on miniSD or thumb drive. The Ubuntu site has some detailed instructions for setting up install media. I chose to copy the Xubuntu image to a thumb drive for the install. The instructions for installing are here – they describe 14.04 but work for 15.04 as well. When complete you should go ahead and do all the updates before proceeding.

Install Nodejs:

Nodejs is available in the Ubuntu repositories, but that version will not work if we try to compile MRAA nor will it allow us to install the version of MRAA that is in NPM. There are a couple of options to get around this. We can use the Nodesource PPA and use APT or we can just download the tarball from the Node site.

The instructions for using the Nodesource PPA are here. Even though they specify 14.04, the instructions are valid for 15.04 as well.

I will use the tarball from the Node site.

It’s a simple install if we use the compiled download so I downloaded the  0.12.x  version of node. The read me in the archive details the install, but it can be difficult to decipher so I will summarize here. All we need to do is copy the files from the archive to /usr/local in the file system. We can accomplish this as follows:

cd /usr/local
sudo tar --strip-components 1 -xzf /path/to/node-v0.12.7-linux-x64.tar.gz

Or use whatever tool you are comfortable with to copy the files to the correct directories. A favorite tool of mine is Midnight Commander (which can be installed via APT).

Since we are copying the files onto the system we will need to set the NODE_PATH environment variable ourselves. This can be done by editing the /etc/environment file. Add the following line to the file:

NODE_PATH="/usr/lib/node_modules"

We need to get the change picked up by the environment. To do so enter:

 sudo source /etc/environment

Alternatively you can reboot the device. If you see node related errors later, check to make sure the environment is set correctly.

Install SWIG

SWIG needs to be installed if we are going to build MRAA. SWIG has a dependency of Perl regular expressions. Install the the needed files as follows:

sudo apt-get install libpcre3 libpcre3-dev

Then download SWIG 3.0.7 from here. Detailed build instructions can be found here. Download and decompress the SWIG source files. Change to the root of the SWIG source and run the following commands:

./configure
make
sudo make install

Install MRAA:

We need build MRAA so that we can take advantage of the Python and Java bindings as well as Node. Detailed build instructions can be found here. I will summarize the steps I followed:

First – install the perquisites. This includes a Java SDK, python dev modules, cmake and git.

sudo apt-get install python-dev python3-dev cmake git

Version 8.0 of MRAA requires JNI 8, so we need to install oracle java. Instructions for doing so can be found here. (The page may look a little funny because I chose the https address). Just follow the install instructions and  test to ensure Java 8 JDK is installed.  The Java home environment variable should be set during the install. If not set it by editing the /etc/environment again by adding JAVA_HOME. Add this line to /etc/environment:

JAVA_HOME="/usr/lib/jvm/java-8-oracle"

To ensure the JAVA_HOME setting is picked up run ‘sudo source /etc/environment’ (or reboot).

Next we need to clone the MRAA repo from git hub:

git clone https://github.com/intel-iot-devkit/mraa.git

Now we are ready to build. We will used the same out of tree build as described in the MRAA documentation.

mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/usr -DBUILDSWIGJAVA=ON
make
sudo make install

Install UPM:

UPM can be cloned with the following:

git clone https://github.com/intel-iot-devkit/upm.git

We will again be using the out of tree build as described in the documentation. Enter these commands to build and install:

mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/usr
make 
sudo make install

Testing:

There are several examples installed in /usr/share/mraa/examples that can be used to test our installation with. These can be copied to a directory we have write access to and modified to test our set up. Be sure to use the MRAA numbers for the MBM pinouts when connecting devices to the system.

Other options:

I chose a Linux setup that worked for me, but there are other options that could be used. There are several options described on the web at Minnowborad.org using different distros of Linux, 32 bit versions of the firmware and alternate BIOS firmware.

So there it is. Hopefully this post will save you some time in getting your MinnowBoard Max configured for use. It took me a couple of days to gather all the info I needed to get my setup working. Feel free to hit me up if you have any questions or found something I did wrong.

SSD1306 i2c UPM Library with the Intel Edison

UPDATE October 6, 2015.

The current version of UPM (4.0) includes this driver. However, UPM 4.0 requires MRAA 8.0. It is pretty simple to install both of these on your Edison. I have updated this guide to use the latest library.

End Update.

The SSD1306 is a very common display driver. There are tons of SSD1306 based devices to be found on Ebay and Amazon – some very inexpensive. Adafruit has several versions for sell that can easily be added to a Edison project. The main stumbling block to using these low cost displays has been the lack of an easy to use driver. Well that problem has been solved. I have recently contributed to the intel-iot-devkit UPM library an implementation of an i2c driver for this device. As of 1-Sept-15 I have been told it will be accepted and be available in the next release.

Why the UPM library? The UPM library provides a set of commonly used drivers that can be used in multiple languages. Each driver can be made available for C/C++, nodejs, java and python. The library I implemented is configured for all supported languages but only tested on C++ and nodejs. If someone uses the driver on java or python I’d like to hear about the results.

But what if we want to use the library in node before the next release? Well that is the topic of this blog post. We will go through the steps needed to compile the driver and install it on an Edison.

For C++ utilizing the driver is simpler than nodejs, python and java. All you need to do is add the source files to your iot dev kit project. The files needed are:

  1. hd44780_bits.h
  2. lcd.h
  3. lcd.cxx
  4. ssd.h
  5. ssd1306.h
  6. ssd1306.cxx

All are available in the repo  in the src/lcd directory. There is a C++ test file in the examples directory. (Make sure you are in the ssd1306 branch). If you need help configuring the iot dev kit check out this link.

If we want to use nodejs or one of the other languages we have a little more work to do.

As always, lets unsure we have the latest version of the Yocto on our system. To check your version login to your Edison and run the following:

configure_edison --version

You will need to be on version 159 to use this driver. If you need to update I find it is really easy to use the flash tool for Edison.

Once we are up to date we need to install git on our Edison. The instructions for installing git are here.

Install MRAA

Next we need to clone the MRAA repo from git hub:

git clone https://github.com/intel-iot-devkit/mraa.git

Change to the mraa directory and  checkout the 8.0 version.

git checkout tags/v0.8.0

Then we are ready to build. We will used the same out of tree build as described in the MRAA documentation.

mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/usr 
make
sudo make install

Install UPM:

Change back to your home directory and run the following:

git clone https://github.com/intel-iot-devkit/upm.git

Then cd to the upm directory and checkout the 4.0 version with this command:

git checkout tags/v0.4.0

We will again be using the out of tree build as described in the documentation. Enter these commands to build and install:

mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/usr
make 
sudo make install

There is a test script for nodejs in my repo.  Simply load this up in the XDK and run it on your device. This script will run through all the functions available in the SSD1306 driver.

Installing the SSD1306 driver is a little complicated but not that difficult to accomplish. I hope these instructions make it easy for you do get this working. If you have problems feel free to let me know in the comments and I’ll see if I can help.

This should be considered the initial implementation of this driver. I have plans to add further functionality to the driver after I get a few other things done. I’d like to have the driver handle multiple display geometries (currently it only accommodates 128*64) as well and add some graphics drawing abilities. The current implementation is very functional though, and fits my requirements pretty well.

Scanning i2c bus 6 on Intel Edison

In a previous post I discussed using the LMSensors project programs to scan I2C buses on the Intel Edison. As I mentioned in that post, I only had luck scanning bus 1 on the Edison (which is only available on the mini breakout board).

Generally, when using i2ctools to scan bus 6 on the Edison the scan will run very slowly and no devices will be found. I have been a little confused by this in the past because occasionally I would find that I am able to scan the bus normally with those tools. I even went so far as to create a tool using the MRAA libraries to implement similar functionality with a Nodejs script. But I have found something interesting.

What I found was that i2c bus 6 is not configured when the system is started. If I have a node application running that uses i2c (which most of mine do) I find I am able to scan the bus with i2c tools without a problem. Also my tool — m2ctool — can serve to configure the bus so that it can be accessed by i2ctools.

To see what I am talking about try this:

  1. Start up your Edison and login. Ensure no programs are running.
  2. Enter the command i2cdetect -r 6. Press enter when prompted.
  3. The bus should scan very slowly and show no devices.
  4. Download and install m2ctool. See instructions on the read me to install.
  5. Enter the command m2ctool scan 6.
  6. The bus should scan normally and show any devices that are installed.
  7. Enter the command i2cdetect -r  6.
  8. The bus should scan normally and show any devices that are installed.

So if you need to probe i2c bus 6 on Edison but don’t have a program running that utilizes i2c, just run ‘m2ctool scan 6’ and then use i2ctools as you normally would. I have only tried this on Edison, I don’t know if this is true on other MRAA based systems.

The m2ctool has other features, I had intended it to stand in for i2ctools when dealing with MRAA based i2c buses. But given that all I need to do is initialize the bus by running a program once I could have saved myself a bit of work. For more info on m2ctool see the read me in the git hub repo.

Using a Rotary Encoder on Intel Edison, XDK

Rotary Encoders are supported by the UPM library. There is already example code that can be leveraged when we want to use one.  The code was created for the Grove Rotary Encoder but in reality we can use it for any rotary encoder we choose to implement. The Grove encoder  would be a good choice if you are using Seed Studio’s Grove Starter Kit. But that could be a problem if we wanted to use the encoder on and Edison project for the mini breakout board or wanted to access the switch in the encoder (you can not access the switch in the Grove Encoder). In my case, I intend to use the encoder to drive a menu for controlling an Edison on a mini breakout board. To accomplish that I will need to have access to the encoders built in switch so I will roll my on implementation.

Since we are going to use the Grove library for the encoder we will implement ours like theirs. If we look at the schematic for the Grove encoder we can see that it is not really that complicated.

Grove Encoder Schematic
Grove Encoder Schematic. Don’t connect  4 and 5 of the switch this way.

We can also see why the switch is not available on the Grove device – not enough pins available on the connector. (Though it does look like activating the switch will pull SIGA down, which we could look for in code. But the UPM library for this doesn’t have any provision for it.) We will wire up our encoder this way but we will wire the switch a little differently.

For the switch we will wire it so the we get a high value when it is actuated. So pin 4 goes to ground via a 10k pull down resistor and to the signal in for our Edison. Pin 5 will go to VCC.

So we need:

1     Encoder — I used these: 360 Degree Rotary Encoder w Push Button

1     Ceramic Disk 100 nf Capacitor (that is 0.1 micro farads, marked 104 on the cap).

4     3.3k Resistors. I used 2% 1/4 watt.  

And for the switch:

1     10k Resistor – also 2% 1/4 watt.

Optionally:

1     Arduino stackable header.  I plugged the encoder into this so it would fit in a breadboard better.

Wiring it up on a bread board gives us something like this:

Wired to a bead board side view
Side view
IMG_20150814_175210
Overhead view
Connected to an Edison Arduino.
Connected to an Edison Arduino board.

I used my Edison Arduino Board to prototype this, so the connections are:

SIGA —> D2

SIGB —> D3

Switch ( encoder pin 4) —> D4

VCC –> 3.3 Volts.

Don’t forget the ground connection.

The code to test this is pretty simple since we are using the UPM Libraries. We will use the Grove Rotary Encoder library for, of course, the encoder. We will use the Grove Button Library for our button functionality.

We will use socket.io to monitor our encoder with a webpage. Our server code looks like this:

//Setup express 
var express = require('express');
var app = express();
app.use(express.static(__dirname));
var server = app.listen(8085);
var io = require('socket.io').listen(server);



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

//var myOnboardLed = new mraa.Gpio(3, false, true); //LED hooked up to digital pin (or built in pin on Galileo Gen1)
var myOnboardLed = new mraa.Gpio(13); //LED hooked up to digital pin 13 (or built in pin on Intel Galileo Gen2 as well as Intel Edison)
myOnboardLed.dir(mraa.DIR_OUT); //set the gpio direction to output

//Require the encoder and button libraries. 
var rotaryEncoder = require("jsupm_rotaryencoder");
var groveSensor = require('jsupm_grove'); 
// Instantiate a Grove Rotary Encoder, using signal pins D2 and D3
var myRotaryEncoder = new rotaryEncoder.RotaryEncoder(2, 3);
//Set up a button on D4
var button = new groveSensor.GroveButton(4); 
 
//We will send data to our client with this object. 
var data = {}; 

//When we get a socket connection we will monitor the switch. 
io.sockets.on('connection', function (socket) {
 
 //Every 100 milli seconds we will send an update to the client. 
 //You won't want to monitor encoder this way for a real project
 //but it will demonstrate the encoder and switch. 
 setInterval(function () {
 //See what the switch value is.
 readButtonValue(); 
 //Sample the current position of the encoder. 
 //Since this is an incremental encoder we will
 //get increasing or decreasing int values from 
 //the encoder library. 
 data.position = myRotaryEncoder.position();
 //For the porposes of this demo, if we go lower than -40
 //or higher than 40 we will reset the encoder init to 0. 
 if(Math.abs(data.position) > 40 ) {
 myRotaryEncoder.initPosition(0);
 data.position = 0; 
 }
 //Send the position in a json encoded string. 
 socket.emit( 'position' , JSON.stringify(data));
 }, 100);

 //Toggle the on board led on or off. 
 socket.on('toggle_led', function(data){
 if(data === 'on'){
 myOnboardLed.write(0);
 } else {
 myOnboardLed.write(1); 
 }
 });
 

});

//A fuction to read our button value
function readButtonValue() {
 //If our button is pressed set the 
 //encoder init to 0. 
 if(button.value() === 1 ) {
 myRotaryEncoder.initPosition(0); 
 } 
}
 


// When exiting: clear interval and print message

process.on('SIGINT', function()

{

 clearInterval(myInterval);

 console.log("Exiting...");

 process.exit(0); 
 
});

A Github repo with working code is located here.

When you load this on your Edison and browse to the web page it will look something like this:

Or demo page contains a gauge the reads from -40 t- 40.
Or demo page contains a gauge the reads from -40 to 40.

Rotating the knob on the encoder clockwise will increase the reading on the dial. Counter clockwise will decrease it. Activating the button on the encoder will reset the dial to 0. If we go below -40 or above 40 the dial will reset to 0. This code is based on the socket.io demo I posted about previously.

So there we have it. Using a rotary encoder in our projects will give us the ability to add controls with out the need of using potentiometers and switches. With an encoder we can implement multi-level menus to enable our end users to configure and control our devices even if they are not connected to wifi or a usb port. Implementing a menu such as this will be the subject of an up coming post.

Implementing the MICS-VZ-89T gas sensor on Intel Edison i2c

On my current project I have the requirement to monitor indoor air quality. What is of interest are the levels of Volatile Organic Compounds (VOCs) and CO2.  There are specific thresholds that we are looking for that when exceeded should trigger an action. For VOCs it is when the concentration is greater that 0.9 ppm. For CO2 it is when the concentration is 1000 ppm above ambient out side C02 — which is generally around 400 ppm. The links above out line the dangers of these indoor pollutants. When the threshold is reached we want to start the ventilation system and optionally message a user.

When I need a sensor my first choice is to find one that implements i2c. In this case I found a good candidate for the job in the SGX Sensortech MICS-VZ-89T. The VZ89 product is a small board with a MICS SMD device integrated with an i2c controller. The board comes in both 5 volt (VZ89) and 3.3 volt (VZ89T) versions that are are easy to implement using a logic level shifter with the Edison on a mini breakout board. (For an example of using a logic level shifter you can see my article Intel Edison and I2C sensors with XDK.)

There was no driver that I could find for implementing the board with my setup so I had to roll my own. This wasn’t too hard, but I did have to break out the logic analyzer to get it right. If we examine the MICS-VZ-89T I2C Specification page  we see that the device only has two commands. These are Set ppmC02 and Get VZ89 Status. According to the MICS-VZ-89T Data Sheet the device comes calibrated from the factory so we don’t need to implement Set ppmC02. That leaves us Get VZ89 Status. The code that follows here is available in an XDK project on git hub.

To read the status we have to perform a two step process. First we write a command byte of 0x09 to register address 0x70. We follow this by writing two data bytes to the same register. I write 0x00 twice.

We then read 6 bytes immediately after writing the command byte. The bytes are decoded as follows:

Data byte 1 = CO2-equivalent value. 
Data byte 2 = VOC_SHORT value. 
Data byte 3 = VOC_LONG value 
Data byte 4 = Raw sensor 1st byte (LSB). 
Data byte 5 = Raw sensor 2nd byte 
Data byte 6 = Raw sensor 3rd byte (MSB).

To implement the functionality I created the following class in a node module:

//Import mraa 
var mraa = require('mraa');

//Constructor -- set defaults and populate tx_buf
function VZ89(bus , address){

 this.bus = new mraa.I2c(bus || 1); 
 this.bus.address(address || 0x70); 
 
 this.tx_buf = new Buffer(3); 
 this.tx_buf[0] = 0x09;
 this.tx_buf[1] = 0x00;
 this.tx_buf[2] = 0x00; 
 
}

//Add a function to get the device readings. 
VZ89.prototype.getReadings = function() {
 this.bus.frequency(mraa.I2C_STD);
 this.bus.write(this.tx_buf); 
 return this.bus.read(6);
 
};
//Export as a node module 
module.exports = VZ89;

The MRAA library is used to access the i2c bus, so it is imported at the top or the file. There is a constructor that optionally takes a bus number and a devices address. The VZ89 is addressed at 0x70 so we don’t really need to change that. If the Edison mini-breakout is used we have a choice of busses. I have set this to bus 6 as I am using the Edison Arduino for this example.

A class function is added to implement named getReadings to perform the measurements and return data from the device. In this case the buffer is passed back to the calling program for use.

To use the class the code in the server file would look like this:

//Import our sensor file from the file system
var Sensor = require('./VZ89.js'); 
//Create an instance of the sensor object. 
var sensor = new Sensor();
//Create a var for the receive buffer.
var rx_buf; 

//Call the readBuf function every minute. 
setInterval(readBuf , 60000); 

//A function to read the sensor data, perform data conversions and display on the console every minute.
function readBuf(){

    rx_buf = sensor.getReadings();
 
    console.log("Co2_equ: " + ((rx_buf[0] - 13) * (1600/229) + 400) + " ppm"); 
    console.log("VOC_short: " + (rx_buf[1])); 
    console.log("tVOC: " + (rx_buf[2] * (1000/229)) + " ppb"); 
    console.log("Resistor Value: " + 10 * (rx_buf[3] + (256 * rx_buf[4]) + (65536 * rx_buf[5])) + " ohms"); 
}

The details of converting the rx_buf data to usable values are in the data sheet.  The ones we are most interested in are Co2 equivalent (rx_buf[0]) and total VOC (rx_buf[2]).

As you can see, the MICS-VZ89T is a pretty easy to use device once you know how. There are only a couple of gotchas to be aware of. First, the device can only be polled once a second. I find if I try to get the readings faster than that the device will return nulls. Secondly, care must be taken when handling the device. It contains organic material that is susceptible to solvents.

Nodejs, Socket.io and Intel Edison

One of the things I really like about the Intel Edison (and the Galileo) is that they can be run as little Linux computers. We can use a lot of tools that are available for Linux machines. One of those tools in particular is nodejs.

Nodejs is a very powerful server side platform. It comes preinstalled on the Edison and Galileo Yocto images so it is very easy to get started with. We can implement code on the Edison and Galileo with the Intel XDK IoT Edition. With this combination of tools it is very easy to create applications that can monitor and control a remote Edison via a web based interface.

To get started I have created a repo on Git Hub that contains a project for the XDK. This project utilizes several technologies — node js, express , socket.io and  mraa library  on the server side. Jquery and an open source library to implement a gauge are used on the client side. I will be using the MCP9808 setup that I blogged about previously but any sensor (or group of sensors) could be utilized.

Before we jump into the code lets make sure we our Edison in up to date. I am using version 146 of the stock Yocto image. To check the version of your Edison execute the following:

configure_edison --version

If you need to update your Edison you can use the following:

configure_edison --upgrade

If you upgrade your Edison you will have to set up the wifi again.

To install the code on your Edison use the Intel XDK to open the project downloaded from Git hub. If you are using the Edison Arduino board open app.js and change line 23 to use i2c bus 6. Upload the project and use the build action to install all the Node dependencies. If you had an app running on the Edison previously you will need to stop it and start this one with the start and stop buttons.

The server code is located in the root of the project in the app.js file.  Here are lines 6 thru 10:

6  var express = require('express');
7  var app = express();
8  app.use(express.static(__dirname));
9  var server = app.listen(8085);
10 var io = require('socket.io').listen(server);

The first  four lines set up Express. Express is a full featured web framework for Node, but here I am just going to use it to serve up my static files from the file system.  The static server is set up on line 8. Line 9 instructs our server to listen on port 8085. Socket.io is initialized on line 10 and instructed to listen for connections on line 10.

Express may seem like overkill for this application, but I like to use if because it is easy to configure and is well supported. There are other, lighter foot print modules that can be used. You can find these other http servers by looking in the NPM Registry .

The real work in the server is done on lines 28 thru 44 :

28 io.sockets.on('connection', function (socket) {
 
30  setInterval(function () { 
31 socket.emit( 'temp' , JSON.stringify(getTemp())); //send temp every interval
32 }, 2000);

35 socket.on('toggle_led', function(data){
36   if(data === 'on'){
37     myOnboardLed.write(0);
38   } else {
39     myOnboardLed.write(1); 
40   }
41 });
 

44 });

Line 28 sets up socket.io to listen for connections. Each client connecting to this device will start the callback that sends the current temperature every 2 seconds (lines 30 – 32 ) and listen for the ‘toggle_led’ event (lines 35 – 41) to allow an led to be turned on and off.

The client side code is just as simple. The index.html page contains divs that hold the guage and a button.  The javascript code that does the work is in /js/app.js . This is all pretty standard stuff, but the first time I worked with socket.io I was stumped for awhile trying to find the source file for the socket.io client (Line 11 in index.html). This file is served automatically from our node server when we run it and is included in the server side socket.io code. All we need to do is add the line to load it in index.html.

If we look at the client side javascript in /js/app.js :

1  var socket = io.connect();
2
3  socket.on('temp', function (data) {
4    var status = JSON.parse(data);
5    Gauge.Collection.get('temp').setValue(status.farenheit); 
6   });
7
8  function toggle_led(state){
9  
10   socket.emit('toggle_led' , state ); 
11   var button = $('#led_button'); 
12   if(state === 'on'){
13      button.attr("onclick", "toggle_led('off')"); 
14      button.html('Turn off led'); 
15    } else {
16      button.attr("onclick", "toggle_led('on')"); 
17     button.html("Turn on led");1
19    }
20 }

We see that the code is fairly simple as well. The socket.io client is initialized on line 1 with a connection to the server we loaded our script from. We then setup a listener for the “temp” event on line 3. If we get a “temp” event the callback function will parse the json string from the server and update the guage in our page to the current value of our MCP9808. (Check the guage git hub page for comprehensive details on its use.)

To toggle the onboard led we have implemented the function at line 10 to emit the “toggle_led” event to the server. We also swap out the events on the button so we can just use one button to toggle the led.

The thing to remember is that the socket.emit sends an event with the name that we provide (in this case “toggle_led”). We need to ensure that the listener for this event uses the exact string. I’ve messed this up a couple of times.

It should look something like this when we have it running:

When the page is running it will look something like this.
When the page is running it will look something like this.

So there you have it. We have implemented a simple web page on the Edison so that we can get the temperature from out MCP9808 and display it. We have implemented the ability to toggle an led on the Edison from the web page. These examples are pretty basic, but the demonstrate a good starting point for more enhanced functionality that could be implemented. Feel free to use the template as a starting point in your projects.

I2C Interfacing on Intel Edison

Edit October 24, 2015.

The I2C tools  project has split from lm-sensors and has gone mia recently. Some of the links I had provided stopped working. I have not been able to track down a good reference for all the tools as yet. When I do I will update this post to let you know. In the mean time I have updated the links to the command to the best reference I can find. More information about each command can always be found on the command’s man page from *nix command line.

Marc

End update.

 

In a previous post I discussed how to read the temperature from a MCP9808 temperature sensor. In this post I want to back up a bit to demonstrate some techniques for figuring out how to interface with an i2c chip and some basic verification techniques. I will be using the Intel Edison on the mini-breakout board, but these techniques will apply to most Linux based embedded systems.

The MCP9808 is an i2c bus device. I2C is short for Inter-Integrated Circuit, a two wire bus used for connecting components to each other on electronic devices. I2C is just one option used for interconnecting devices. Other options  include. SPI, 1-wire, and Serial. When using devices for an embedded project we generally find SPI or I2C on devices. I tend to go for I2C devices when I can because they allow me to get away with using less wires to hook up.

When we do integrate a device it is handy to ensure the device is recognized by the system before we try to write code for it. There are tools that are already installed on the Edison called I2C tools. Formerly a part of the LM-Sensors project, I2C tools allow low level access to I2C busses and the devices connected to them.

Before we get started lets make sure our Edison is up to date. We can do this by logging in via ssh (or use the terminal) and executing the command:

configure-edison --upgrade

You need to have your Edison attached to a network.

Let’s get started. There are four commands we are interested in that are summarized in the table here:

Bus scanning i2cdetect
Device register dumping i2cdump
Device register reading i2cget
Device register setting i2cset

Bus scanning:  

We use the i2cdetect command to both find the busses available as well as the devices on the bus. If we execute

i2cdetect -l

we can get a list of the currently installed I2C busses. The output is as as follows:

The result of i2cdetect -l on Intel Edison.
The result of i2cdetect -l on Intel Edison.

We can see we have 8 I2C buses on the Edison. But according to the docs we are only able to use bus 1 and 6 on the mini-break out board. I have only used bus 1 in my projects so far. If we wanted to see the devices on bus 1, we would enter:

i2cdetect -r 1

and get something like the following output:

The result of i2cdetect -r 1. This gives us a dump listing the devices on i2c bus 1.
The result of i2cdetect -r 1. This gives us a dump listing the devices on i2c bus 1.

When executing this command we get the standard warning that executing this command may jack up our device. It’s true, we can cause errors if we run this command on some of the other busses, but it has always cleared up for me with a power cycle of the Edison. Usually the device just hangs.

Looking at the output we can see we have four devices on bus 1. At 0x18 we have a MCP9808 temperature sensor, 0x3C is a SSD1306 display, 0x48 is an ADS1819 ADC , and 0x77 is a BMP085 barometric pressure and temperature sensor.

Device register dumping:

Now that we know what devices are on the board (or more accurately all the devices we wired to the Edison are recognized by our system) we can start working with the devices. Each device has internal registers that control the device and provide output from the device. We use the i2cdump command to take a look at these registers. Let’s take a look at the MCP9808

i2cdump 1 0x18 w

The form of the command is 12cdump (bus | device address | option). The ‘w’ option give us word output which makes it easier (for me at least) to read the registers. Executing the command gives us output that looks like this:

i2cdump of our MCP9808 on i2c bus 1 in word format. There is a lot of register space for devices, but we see we only have 13 registers in our device.
i2cdump of our MCP9808 on i2c bus 1 in word format. There is a lot of register space for devices, but we see we only have 13 registers in our device.

To understand what we are seeing in the dump we need to study the data sheet for our MCP9808.

If we study the data sheet for the MCP9808 we can decipher the registers we dumped.
If we study the data sheet for the MCP9808 we can decipher the registers we dumped.

Keeping in mind that the MCP9808 is a little endian device, we see the 16 bit data registers storing their values with the least significant  byte (LSB) first and most significant byte (MSB) second. We just need to do a quick byte swap to look at register 0 to see the value is 0x001d. According to the spec sheet the MSB should always be 0x00 as well as the LSB bits 7-4. Bits 3-0 in the LSB are the pointer used to select which register we read and write to when communicating to the device. The MCP9808 is a surprisingly complex device, so we won’t look at all the registers. But a thorough explanation of the registers and their function begins on page 16 of the data sheet.

Read a specific register:

We could certainly read the registers from the output of  i2cdump but there is a specific command for reading a single register. If we wanted to read the the current temperature the data sheet tells us the register containing this value is 0x05. To read this register we would issue this command:

i2cget 1 0x18 0x05 w

The command is in the form i2cget (bus | device address | register | option) . This gives is the following output:

Use i2cget to read the current temperature from our MCP9808.
Use i2cget to read the current temperature from our MCP9808.

We get the requisite warning and then the little endian contents of the register. Swapping the bytes to 0xC152 and referencing page 25 of the data sheet we can get the current temperature in Celsius. Briefly —   Bits 15-13 are flags that are used when we set the device to monitor a high and low set point. They can tell us if a threshold was passed, and which one. We don’t have those set so the values are not significant to us in this case. Bit 12 of the word is the sign of the two’s compliment value, since it is 0 our value is positive. Stripping those four bits out we are left with 0x0152 which is the temperature value. The rest is a base conversion and a little math — the MSB is 1 decimal, the LSB is 82. So using the data sheet formula  –> 1 * 16 + 82 / 16  = 21 degrees Celsius. Thats a cool 69.8 F in the office today.

Set a register:

If we want to manually control the MCP9808 we can set its registers with the i2cset command. Before we use the command a little back ground.

The MCP9808 has two modes of operation — continuous conversion and shutdown mode. Shutdown mode puts the device into a low power state and , as you might have guessed, stops updating the temperature measurement. If we read the temperature register while the device is in shutdown we will retrieve the last measurement made. In a battery powered device it might be a good idea to shutdown the device and only power it up when we need to update the temperature. This is controlled by bit 8 of the config register located at 0x01.

We can use the following command to enter into shutdown mode:

 i2cset 1 0x18 0x01 0x0001 w

Remember that we need to swap the bytes in the word due to endianness. This can be tested by reading the temperature while heating up the sensor (I just put my finger on it). You can use i2cget or i2cdump to read register 0x05 of the device. To set the sensor to continuous conversion mode use this command:

i2cset 1 0x18 0x01 0x0000 w

This post covered the basics of verifying a device is detected on an I2C bus and determining if the device is functioning properly. We used the four I2C tools commands to detect the busses and devices installed, dump a device registers, read a specific register, and to write a register. With these four commands we can certainly see if our devices are working correctly as we implement an embedded system.

The i2c tools do have other modes of operation that I did not touch on here. These modes can be read about by accessing each command’s man page. Armed with these tools and the data sheet for a device we are ready to get coding.