Input Devices

This week's assignment: measure something -- add a sensor to a microcontroller board that you have designed and read it.

Continuing on from weeks 4 and 6, I decided to use the LED matrix board which I had previously designed. After seeing a few cool LED matrix demos online, in particular Adafruit's LED sand physics toy, I figured I would like to implement something similar with my LED matrix board. This meant I had to figure out how to connect an accelerometer to my LED board.

Fortunately, I was able to find some nice LIS3DH accelerometer breakout boards in the lab, which saved me a lot of time -- these boards had all the necessary passive components and voltage regulators to pamper the LIS3DH chip. Luckily for me, the LIS3DH can communicate over I2C, a simple two-wire protocol used between microcontrollers and other peripherals. And, because the LED matrix board I had designed used the ATMega328P, the same chip in the ever-so popular Arduino Uno, I had plenty of libraries to work with for I2C communication with the accelerometer.

I figured that this week, I would be spending most of my time on software development, rather than hardware. In any case, I ported the code from Adafruit's LED Sand example onto my own board, and tried running the sand simulator code. Unfortunately, the processing power of the ATMega328P was simply not enough. The current code required the processor to read accelerometer data, calculate the sand grain positions based on a non-trivial physics algorithm, and display everything on the LED matrix. At an 8 MHz clock speed, the ATMega struggled to crank out more than 3 FPS of animation. "Overclocking" the board by switching out the 8 MHz internal clock to an external 20 MHz clock didn't improve performance to an acceptable level, as ~8 FPS was still painful to watch.

The frames per second issue wasn't even the worst part. Because the LED matrix is driven by sequentially driving each row of the LED matrix extremely fast so that persistence-of-vision makes it look like the entire matrix is on, this means the matrix cannot display a useful image while the processor is doing calculations, namely the calculations used to update the sand grain positions. As a result, the apparent brightness of the LED matrix was terribly dim.

My solution was to use another Arduino in conjunction with the LED matrix board to speed up processing time by effectively doubling my compute power. Given that I had already broken out the I2C pins on my LED matrix, I decided that I could have one Arduino solely dedicated to calculating the sand grain positions as fast as possible, and the Arduino (the ATMega) on the LED matrix board could handle all of the display driving. The two Arduinos would be sending the LED display data over I2C, and this ended up working out extremely well. Because one Arduino was taking care of the entire display driving routine, there was never any off time for the LED matrix. This is because I programmed the LED matrix controller to continue displaying the same frame until it received new data from the other Arduino, and then the displayed image frame would then be updated. After this change, I was able to achieve around 100 FPS of display animation speed, which was plenty smooth for my needs. Just for fun, I also added a potentiometer which adjust the animation calculation speed, allowing the effective FPS to be changed from 2 to 100. Here is a demo of the completed project:

[4] File Downloads

SandSimulator RX (.INO)
Code for the LED matrix -- receives data from I2C bus and renders sand particle positions on LED matrix.
SandSimulator TX (.INO)
Code for the sand particle physics simulator -- calculates particle positions using accelerometer data (from I2C) and then sends data to I2C bus.