Page 1 of 3
Using I2C devices is fairly easy once you have successfully used one - and hence know what information you need and what to look for in a working system. In this chapter we use the HTU21D temperature and humidity sensor as a case study of I2C in action. It also happens to be a useful sensor.
This is a chapter from our ebook on the Intel Edison. The full contents can be seen below. Notice this is a first draft and a work in progress. Use the comments or email firstname.lastname@example.org with your queries or suggestions.
Now On Sale!
You can now buy a print edition of Exploring Intel Edison.
You can buy it from:
USA and World Amazon.com
In this chapter we consider the Edison's pros and cons and get an overview of its structure and the ways in which you can make use of it. If you have ever wondered if you need an Edison or an Arduino or even a Raspberry Pi then this is the place to start.
- First Contact
When you are prototyping with the Edison you are going to need to use one of the two main breakout boards - the Arduino or the mini. This chapter explains how to set up the Edison for both configurations.
- In C
- Mraa GPIO
Using the mraa library is the direct way to work with the GPIO lines and you have to master it. Output is easy but you do need to be aware of how long everything takes. Input is also easy but using it can be more difficult. You can use polling or the Edison interrupt system which might not work exactly as you would expect.
- Fast Memory Mapped I/O
There is a faster way to work with GPIO lines - memory mapped I/O. Using this it is possible to generate pulses as short at 0.25 microsecond and read pulse widths of 5 microseconds. However getting things right can be tricky. We look at how to generate fast accurate pulses of a given width and how to measure pulse widths.
- Near Realtime Linux
You need to be aware how running your programs under a non-realtime operating system like Yocto Linux effects timings and how accurately you can create pulse trains and react to the outside world. In this chapter we look the realtime facilities in every version of Linux.
- Sophisticated GPIO - Pulse Width Modulation
Using the PWM mode of the GPIO lines is often the best way of solving control problems. PWM means you can dim an LED or position a servo and all using mraa.
- Sophisticated GPIO - I2C
I2C is a simple communications bus that allows you to connect any of a very large range of sensors.
- I2C - Measuring Temperature
After looking at the theory of using I2C here is a complete case study using the SparkFun HTU21D hardware and software.
- Life At 1.8V
How to convert a 1.8V input or output to work with 5V or 3.3V including how to deal with bidirectional pull-up buses.
- Using the DHT11/22 Temperature Humidity Sensor at 1.8V
In this chapter we make use of all of the ideas introduced in earlier chapters to create a raw interface with the low cost DHT11/22 temperature and humidity sensor. It is an exercise in interfacing two logic families and implementing a protocol directly in C.
The DS18B20 1-Wire Temperature
The Edison doesn't have built in support for the Maxim 1-Wire bus and this means you can't use the very popular DS18B20 temperature sensor. However with a little careful planning you can and you can do it from user rather than kernel space.
- Using the SPI Bus
The SPI bus can be something of a problem because it doesn't have a well defined standard that every device conforms to. Even so, if you only want to work with one specific device it is usually easy to find a configuration that works - as long as you understand what the possibilities are.
- SPI in Practice The MCP3008 AtoD
The SPI bus can be difficult to make work at first, but once you know what to look for about how the slave claims to work it gets easier. To demonstrate how its done let's add eight channels of 12-bit AtoD using the MCP3008.
- Beyond mraa - Controlling the features mraa doesn't.
There is a Linux-based approach to working with GPIO lines and serial buses that is worth knowing about because it provides an alternative to using the mraa library. Sometimes you need this because you are working in a language for which mraa isn't available. It also lets you access features that mraa doesn't make available.
Using an I2C device has two problems - the physical connection between master and slave and second figuring out what the software has to do to make it work. In this chapter we take the principle outlined in the previous one , see Exploring Edison - I2C Bus, and add the information in the HTU21D data sheet to make a working temperature humidity sensor using mraa.
There is a C++ implementation of the HTU21D in the upm library and you can use this if it is more appropriate to your project. In this case it is the details of the implementation that is important.
First the hardware.
The SparkFun HTU21D
The HTU21D Humidity and Temperature sensor is one of the easiest of I2C devices to use with the Edison mini breakout board. The reason is that it works at 1.5V and therefore works with the Edison's 1.8V logic and use its power supply. This means you don't have to worry about level shifting and this simplifies your first encounter with I2C and provides an attractive way to measure temperature and humidity in a very small package.
The only problem is that the HTU21D is only available in a surface mount package. To overcome this simply solder some wires onto the pads, it is possible to do, or you can buy a general breakout board.
However, it is much simpler to buy the SparkFun HTU21D breakout board because this has easy connections and built-in pull up resistors. This means that you don't need to add any components to get this circuit working - just four connections.
Don't worry about the fact that board and the documentation suggests that this only works at 3.3V - it works "best" at 3.3V, but it also works at 1.8V. If you use the HTU21D breakout then for prototyping the only thing you have to do is solder some pins or wires to the pads.
If you decide to work with some other I2C device you can still follow the steps in this account, but you would have to modify what you do to be correct for the device you are using. In particular if you select a device that works at 3.3V or 5V you need a level convertor and you might also need pull-up resistors.
Wiring the HTU21D
As we are going to use a 1.8V sensor and I2C bus 1 the pins that we are going to use are:
|Physical Pin|| |
Given that the HTU21D has pull up resistors and works at 1.8V connecting it to I2C 1 on the Edision is trivial:
You can use a prototype board to make the connections and this makes it easier to connect other instruments such as a logic analyser.
A First Program
After wiring up any i2C device the first question that needs to be answered is - does it work?
Unfortunately for most complex devices finding out if it works is a multi-step process.
Our first program will aim to read some data back from the HTU21D - any data will do.
If you look at the data sheet you will find that the device address is 0x40 and its supports the following commands:
|Trigger Temperature Measurement
|Trigger Humidity Measurement
|Trigger Temperature Measurement
||No Hold master
|Trigger Humidity Measurement
||No Hold master
| Write user register
| Read user register
| Soft Reset
The easiest of these to get started with is the Read user register command. The user register gives the current setup of the device and can be used to set the resolution of the measurement.
Notice that the codes that you send to the device can often be considered addresses or commands. In this case you can think of sending 0xE7 as a command to read the register or the read address of the register - it makes no difference. In most cases the term command is used when sending the code makes the device do something and and the term address is used when it simply makes the device read or write specific data.
To read the user register we have to write a byte containing 0xE7 and then read the byte the device sends back. Notice that means sending an address frame, a data frame and then another address frame and reading a data frame.
You can do this in two ways. The first is to use raw byte read and write commands:
i2c = mraa_i2c_init(1);
uint8_t data = mraa_i2c_read_byte(i2c);
printf("Register= %d \n", data);
This program sets up I2C-1, sets the address to 0x40 and then sends 0xE7 and immediately reads a byte that the device sends back.
If you run this program you will see:
this is the default value of the register and it corresponds to a resolution of 12 and 14 bits for the humidity and temperature respectively.