This part of the I2C interfacing project focuses on building an acceleration sensor, but in the process it also explores two other issues: advanced use of the PCF8591 chip (that we have already seen in the pressure sensor) and running the bus at 3.3v. For the rest of my I2C series, see the table of contents.
This project really shows the power of the I2C bus in the NXT. Sensors that report a single analog value, such as temperature or pressure, can be built as analog sensors, just like the NXT's sound and light sensors. But for an acceleration sensor that must report two or three values, the acceleration along two or three axes, anI 2C sensor is the only reasonable solution.
Acceleration sensors are wonderfully useful. They can detect that a robot bumped into a wall, they can detect that it is in a free fall (open that parachute!), they can be used to estimate position and to count steps, and much more. They are so useful that it makes you wonder why Lego did not include one inside the NXT.
There are two commercial acceleration sensors for the NXT, one from HiTechnic and several from Mindsensors. The sensor that I am describing here is better than all of these in some ways (it can be configured by your program to two sensitivities unlike all the commercial sensors that have a fixed sensitivity, and it measures acceleration along 3 axes, whereas some of the commercial ones are 2-axis sensors). But the commercial ones have higher resolution, and of course, you don't have to build them yourself.
Warning: connecting your NXT to any home-made gizmo (like the one described here) can damage it. Beware.
The sensor uses an accelerometer called LIS3L02AS4, manufactured by STMicroelectronics. This device is a single silicon chip that contains sensing elements that can measure accelerateion in three directions and some analog electronics that make it easy to use the chip (amplfiers, multiplexers, and so on). The chip needs a supply of 2.4 to 3.6v. It has three analog outputs. The voltage in each output is proportional to the acceleration in one particular direction (X, Y, or Z). The sensitivity of the outputs can be set so that the chip measures acceleration either in the range ±2g (g is the unit of acceleration, about 9.8 m·s−2) or in the range ±6g.
When there is no acceleration in a given axis, the output voltage is half the supply voltage (Vdd). When the sensor is subject to acceleration or deceleration, the voltage changes by Vdd/5 volts/g in the ±2g scale or by Vdd/15 volts/g in the ±6g scale. This means that if the supply voltage is 3.3v, the outputs range from 0.33v to 2.97v. These are nominal values; the actual sensitivity can differ by up to 10% or so.
You use such a sensor by connecting its outputs to analog-to-digital converters, to obtain digital measurements. The scale is set to ±2g or ±6g by connecting one of the pins to either ground or Vdd. In a device that always use one of the scales, you can connect this pin permanently to the ground or to the supply line. If you want to configure the sensitivity at run time, you can connect this pin to a voltage that you can control from the program.
How does this sensor (and similar like it) work? The principle is fairly simple. Think of a mass that is suspended between two springs that are both at rest, and which can only move left and right, as shown in the diagram on the right. If the whole structure is moving, say to the left, at a constant speed, the two springs will remain at rest and the mass will remain exactly in the middle between the two walls. If the structure is now accelerating (to the left), the inertia of the mass will cause it to continue to travel at a constant speed, which will cause the left spring to compress and the right one to extend a bit. The compression/extension of the springs excerts elastic force to be applied to the mass. If the structure starts moving at a constant speed again, this elastic force will eventually return the mass to the center of the structure.
Silicon accelerometers (often called MEMS devices, which stands for micro electroo-mechanical systems) work pretty much in this way. They include a mass that is suspended in an elastic structure and some mechanism to measure the displacements of the mass. In the LIS3L02AS4, the displacement measurement is done by measuring the capacitance between the mass and the substrate above which it is suspended. In effect, the mass forms one half of a capacitor. When it gets closer to the substrate, the capacitance rises, and when it gets further away, the capacitance drops. The elastic structures in these sensors are not springs, but some sort of solid beams or plates that can deflect a bit. Everything, both the beams and the mass, is carved out of silicon in a process that is essentially the same as the process in which electronic circuits are fabricated on silocon.
The structure of these devices tells us something important: the mass displaces not only due to acceleration, but also due to gravity. If the sensor is standing still on a table, and its Z axis is the vertical one (pointing to the sky and to the center of the earth), then its X and Y outputs will show 0g, but its Z output will show 1g down. This allows you to easily sense the down direction when the sensor is not moving. In the picture above, you can see that the NXT reports readings of 127 and 128 on two axes (X and Y), which indicates 0g (exactly the middle between 0 and 255). The third reading is 76, which indicates 1g.
The chip comes in a 24-pin plastic package called a small-outline package (SO or SOIC). This is a surface mount package with pins 0.05" apart, so you cannot simply plug it in a breadboard or solder it to a perfboard. I soldered it onto an adapter board with pads for an SO chip (I used an adapter from www.futurlec.com, which costs $0.70). Each pad is routed on this adapter board to a holel; the holes are arranged in an 0.1" grid. I soldered a row of 8 headers to 8 holes, which allows me to plug the adapter with the accelerometer into a breadboard. The accelerometer itself has only 8 functional pins (ground, Vdd, 3 ouputs, scale selection, and 2 pins for self-test and power-down signals). Five more pins are reserved; they are used after manufacturing for testing and calibration; 4 of them can remain unconnected and the 5th should be connected to Vdd or ground. I assume that the fact that the chip comes in a 24-pin but only 13 are used indicated that the piece of silicon that contains the sensor and its associated circuit is pretty large and won't fit in a smalle package.
Soldering these surface-mounted chips is easier than it looks. There are several good guides on the internet that show you how to do it. No special tools required, just a soldering iron and a solder wick to remove excess solder.
STMicroelectronics also offers an evaluation board for this accelerometer, which is fairly similar to the adapter board that I constructed. The evaluation board includes only the accelerometer and its two bypass capacitors, and the pins of the chip are connected to standard 0.1" pins.
The accelerometer itself costs about $9 in small quantities.
I connected the accelerometer to the bus using a PCF8591 chip, an analog-to-digital and digital-to-analog chip. The chip has 4 analog inputs, of which we use 3 to measure acceleration in the X, Y, and Z directions.
The PCF8591 also has one analog output, which is handy in this case. I connected this output to the scale-selection pin of the accelerometer. The program that runs on the NXT sets the analog output to either the minimal value (ground) or to the maximal value, Vdd. When the analog ouput is at 0v, the accelerometer's range is ±2g; when the analog ouput is close to the supply line, the range of the accelerometer is ±6g.
Another neat feature of the PCF8591 that is useful here is the auto-increment feature. When the I2C master sends a command to a PCF8591 slave, it sends 2 or three bytes. The first byte is the address of the slave and a read/write bit. The second is a control byte, and the third is the digital-to-analog value, if the master wishes to change the analog output. The control byte tells the slave whether to activate the analog ouput, which analog input is to be read next, and whether to auto-increment the input number (and also whether to configure the inputs as single ended or differential pairs). If the master sets the auto-increment flag and reads more than one byte from the slave, each byte that the slave sends is the convertion of a different input. In my program, I ask the slave for the value at input 0, and tell it to auto increment. I then read 3 bytes, which are the values at inputs 0, 1, and 2, which are connected to the X, Y, and Z voltages outputs of the accelerometer. One I2C transaction reports 3 analog values.
The LIS3L02AS4 runs on 2.4 to 3.6V, so we cannot connect it to the 4.3v line that the NXT provides to sensors. The 4.3V voltage will damage the accelerometer. Therefore, we need to drop the voltage down for the accelerometer. I used a 3.3V low-drop voltage regulator made by Maxim called MAX604. Under light loads (the load here is definitely light) it will work properly even if the input voltage drops to less than 3.8V and it draws very little current. This regulator needs a 10μF output capacitor, which is also required by the accelerometer. On the input side of the regulator you can use a smaller (and more compact) capacitor, down to 0.1μF.
A simple way to arrange the circuit would be to use the 4.3V to power the PCF8591 and to use the regulated 3.3V to power the accelerometer. In this configuration, we would also need to connect the 3.3V to the Vref pin of the PCF8591.
I wanted to test a more interesting configuration, in which the PCF8591 also runs on 3.3V. I wanted to test this because some interesting and useful I2C chips run on 3.3V; these chips will not tolerate 4.3V on any pin, so they cannot be directly powered by the NXT, and more importantly, they cannot be directly connected to an I2C bus that is pulled up to 4.3V by resistors.
Philips, the company that invented the I2C bus, shows how to connect I2C chips connected to a 5V supply to I2C chips connected to a 3.3V supply. If such chips comply with the I2C standard, they cannot be connected directly to the same I2C bus. If they are, and the bus is pulled up to 5V, the 3.3V chips will be damaged by the bus. If the bus is only pulled to 3.3V, it will not register as a high logic value in the 5V chips, because 5V I2C chips should only consider voltages above 3.5V as logic high. The 4.3V supply of the NXT can rise fairly close to 5V, so I was worried about this issue. The Philips solution is based on inserting two MOSFET transistors between the 5V and the 3.3V segments of the bus. Clever, and only requires 2 transistors, but is there a simpler solution?
For the NXT, and for other similar situations, there is. The solution is to only pull the bus up to 3.3V. This is not I2C complient, but it is guaranteed to work with the NXT. The reason is that the I2C of the NXT are connected to the input/output pins of the NXT's main processor, an Atmel AT91SAM7S256 chip. These pins are 5V-tolerant 3.3V pins. What this means is that they provide 3.3V when set to high output, that they can tolerate input voltages of up to 5V, and (most importantly for us), that they consider any input voltage from 5V down to less than 3.3V to be a logic high level. Therefore, I2C busses of the next work perfectly well when pulled up to only 3.3V. I learned of this idea from a posting by Dimiter Popoff on the newsgroup comp.arch.embedded.
What makes this solution work on the NXT is the fact that the pull-up resistors are not built into the NXT, but are expected to be present on the sensor. If the NXT included internal pull-up resistors, we would not be able to connect a 3.3V I2C devices directly to its busses. But the pull-ups are not built in, so we can pull the busses only to 3.3V.
I built the circuit this way and it indeed works without any problem. The complete schematic of the sensor is given below.
For the official specifications, see the PDF file, "The I2C Bus Specification", Version 2.1, January 2000, by Philips Semiconductors. This document describes the 5V/3.3V level shifter, but it is described in more details in a Philips Application Note AN97055, "Bi-Directional Level Shifter for the I2C and Other Systems" from 1997.
Here is a RobotC program that sets up the sensor and displays its outputs. It can be easily converted to NXC, and with the aid of recently-released I2C NXT-G blocks, to NXT-G as well. The program starts by setting up the sensor, which mainly includes setting the analog output of the PCF8591 to select the sensitivity of the accelerometer. The program then repeatedly polls the sensor for 3 acceleration values in the X, Y, and Z directions and displays them on the screen.
The picture below shows a more solid construction of the circuit. The components (including the adapter board with the accelerometer) are soldered to a prototyping board that I cut to size. The prototyping board itself is soldered using header pins to a left-over printed circuit board with Technic-compatible holes and with a NXT socket. This construction is solid enough for a moving robot.
Single chip accelerometers are available from many manufacturers, in many configurations (from single to triple axis), sensitivities (from single g to a thousand g), and precisions.
The PCF8591 is almost perfect for this application, which requires 3 analog inputs and one digital ouput (to control the scale selection of the accelerometer). The PCF8591 has 4 analog inputs and one analog ouput, so it satisfies the requiments and slightly exceeds them. Its main drawback is that the resolution of its analog-to-digital converter is only 8 bits. In fact, we get even less resolution, because the analog outputs of the accelerometer do not swing all the way to ground and Vdd. This means that we should only expect from the A/D converter 204 or 205 different values, not 256. We can raise the resulotion to full 8 bits using a low-gain amplifiers that use a rail-to-rail opamps. These amplifiers will amplify the accelerometer outputs so that they swing from ground to Vdd.
To achive higher resolution, we need a higher resolution analog-to-digital converter. Analog Devices makes 10- and 12-bit I2C A/D converters; the AD7993/4 are 4-input devices that would be suitable for for an acceleration sensor (they also make 2- and 8-input chips). Another solution is to use a microcontroller that has both an I2C interface and higher resolution A/D converter with at least 3 inputs. There are many microcontrollers in this category, such as the MSP430F2012 and MSP430F2013 from TI. These chips cost about the same as the PCF8591. Because they are programmable, they are more versatile than the PCF8591. For the same reason, they are also more difficult to use: you must program them before they will do something useful in a circuit. My understanding is that the commercial acceleration sensors for the NXT, as well as the most of the other commercial sensors and the standard ultrasonic sensor, use this approach.
© 2007, Sivan Toledo