Embedded systems use a lot of diverse sensors from accelerometers and gyroscopes to magnetometers, vibration, temperature and humidity. Often, we interface with these sensors using SPI or I2C interfaces.
I was looking at the MiniZed for a project recently and was reminded that it has an on-board accelerometer and temperature sensor connected over I2C. Interestingly, the I2C also connects to the power supplies. We will explore how to work with I2C and power convertors soon.
For now, I thought a good first step was to look at the I2C accelerometer and outline how we can preform the following steps:
1. Detect the accelerometer using I2C tools
2. Read and write registers from the accelerometers
3. Convert the values read from the accelerometer into physical values
The accelerometer used on the MiniZed is the LIS2DS12 which provides both X/Y/Z measurements in either 10- or 14-bit resolution but also an 8-bit temperature reading.
This accelerometer is connected to the programmable logic side of the Zynq-7007S device. As a result, we can connect to it using either the PS I2C set to interface to EMIO or the AXI IIC IP core instantiated in the programmable logic.
For this example, I connected the accelerometer to the PS I2C interface and use EMIO to route the pins to the PL IO. The block diagram is simple and can be seen below. This project was built and a new PetaLinux project was created.
The PetaLinux project is left unchanged apart from the addition of the I2C tools to the root file system. I2C tools enables the developer to be able to detect, set, get, dump, and transfer data over I2C networks.
With the PetaLinux project built, we can load the image onto the MiniZed using either JTAG or programming the QSPI.
With the MiniZed running PetaLinux, we can use I2C tools to detect the I2C devices that are connected to the PS I2C interface using the command below.
i2cdetect -y -r 0
If we have multiple I2C interfaces, we can use the command i2cdetect -l to list the I2C interfaces and their associated bus.
In this example, we can see the accelerometer and the power supplies on the MiniZed. The accelerometer is present at address 0x1D while the power supplies can be seen at address 0x58.
To be able to control the accelerometer, we first need to ensure we can communicate with it. The best way to do this in I2C or any other sensor is to read a register with known contents back. Helpfully the accelerometer has a Who Am I register which is set to a value of 0x43 at address 0x0F.
Reading this register over I2C requires that we first perform a write to the accelerometer defining the register we wish to read (0x0f), and then read back one byte. We can do this using the I2C transfer command which allows us to specify an address to write several bytes to and then several bytes to read back.
In this case, we can use the command i2ctransfer 0 w1@0x1D 0x0f r1. This command will write one byte of data 0x0F to the I2C address 0x1D and then read one byte back. This should read back the value of the register at 0x0F.
Reading this register shows a correct value and illustrates that we are able to talk to the accelerometer successfully.
The next stage is to enable the accelerometer data outputs. We do this by writing to register 0x20 and setting the output data rate and bit resolution. To get this running I used the command i2ctransfer 0 w2@0x1D 0x20 0x80.
Following this command, data will be available in the X, Y, and Z outputs. There are two registers for each output to provide the 10 or 14-bit resolution.
We can read out each of the X, Y or Z registers using the command i2ctransfer 0 w1@0x1D 0x28 r2. This will read the X lower and higher registers, lower first.
We can read out the values of Y and Z using appropriate addresses.
This provides three values for the X = 0xFF40, Y = 0xFF80 and Z = 0x40C0. These numbers are twos compliment encoded.
To determine the actual value of G being seen by the sensor, we need to convert these to a decimal value and multiply it by the mG sensitivity per LSB. These change depending on the sensitivity setting of the accelerometer in its default setting (+/-2G) it is 0.061 mG per LSB.
Of course, we should expect the Z direction to be 1G when the MiniZed is lying flat. By converting the reported values, we see the following which looks aligned with expectations:
Z = 1.01136 G
X = -0.00799 G
Y = -0.011773 G
We can now write a Python or C program if we want to work with the accelerometer and take readings in our application.
This is one of the benefits of using PetaLinux with sensors. By using I2C tools, we can interact with the sensor and de-risk the application development.