An update before the build

When working on my projects I usually take a non standard approach to the design process. Instead of starting with a block diagram and schematic, I put together a working prototype using easy to find components and parts in my personal inventory.

First I develop a rough idea in my project journal (and in my head) and break the project down into smaller modules. Then I dive right into researching how I could accomplish certain tasks in each module, and what devices can be used. After finding suitable candidates I test each module individually for functionality. Once all the modules are successfully tested, then I integrate them with each other, and have the full system working on my breadboard.

After getting a working system on my breadboard, I would make a schematic. This is not the way I am taught in school however. My instructors would never approve wiring up a circuit without a schematic. But since I am testing module by module making a schematic for everything is time consuming. Usually each module involves 5-10 connections, and almost always the device datasheet has a schematic on how to wire it up for a certain application. Although if the module is complicated enough you will usually find a rough schematic in my journal.

Making a schematic for every working circuit is very important. That way you can modify and make significant changes to the existing circuit without fear of losing the circuit you already built. Also a schematic helps when moving the breadboard circuit to a standalone device.

Last few days I have been working on testing various components of the Gyro’clock circuit. They all passed the initial tests. Before starting to put it altogether, I built a complete circuit on the breadboard. For this project, this step is specially important to see if the tiny 150 mAh Lipo battery is enough to power the entire circuit.

So I put together the complete circuit on the breadboard and powered it with a fully charged Lipo battery. Since it is not yet possible to spin it around like the real Gyro’clock would be, I slightly modified the orientation detection module to trigger the clock display module at a reasonable angular rate. This simple test verified that all modules in the circuit are functioning and that the battery is capable of doing its job.

This is an important milestone for this project. Before actually building the device I know that it is going to work if I wire up everything as it is in the breadboard circuit. The next major milestone is a standalone prototype. In the meantime here is the schematic,

The schematic of the first prototype of Gyro'Clock

The schematic of the first prototype of Gyro’Clock

Gyro’clock parts arrived!

Yesterday I received the Gyro’clock parts I ordered from Adafruit. And here is the set that will be used on the first prototype

A set of electronic parts that will be used on the first Gyro'clock prototype

A set of electronic parts that will be used on the first Gyro’clock prototype

The first thing I did was to test the Neopixel stick with the ATTINY since it is the most interesting part of the bunch. I soldered four jumper wires to the terminals of the stick so I can stick it onto my breadboard. As added protection, I used a 470 Ω resistor between the data input pin and the ATTINY data out pin.

All LEDs in the Neopixel array can be individually addressed using a single data pin.

All LEDs in the Neopixel array can be individually addressed using a single data pin.

The Neopixel can be powered from 4-7V. So I used +5 V for both the ATTINY and the Neopixel. To test it, I generated an interrupt signal by momentarily tying the interrupt pin to +5 V. The Neopixel stick flashed as expected when an interrupt is created.  Of course I didn’t see the time displayed yet since I wasn’t actually spinning the device, but this confirms that the Neopixel stick can be controlled with the ATTINY.

 

Neopixel array displaying a sequence upon trigger event

Neopixel stick displaying a sequence upon trigger event

After successfully testing out the Neopixel stick, my next step is to test the L3GD20H gyroscope. Once I am able to read data from the Gyroscope, I am ready to put the hardware together, which I think will be the hardest part.

One step at a time I am getting there, and this is exciting!

Talking to MMA8452 accelerometer with ATTINY85

I am still waiting for the Gyro’clock parts to arrive in the mail. Meanwhile I am doing a bit of coding to get ahead in the software department. Since I already have a MMA8452 accelerometer handy, I decided to test it with the ATTINY85.

First step was to get the ATTINY to talk with the accelerometer. When I used the accelerometer in the first keychain ‘propeller’ clock design I found a handy MMA8452 library that greatly simplified this whole process. However, this library is written for the ATmega family of processors, and uses the Wire library to handle the I2C communication. Unfortunately the Universal Serial Interface (USI) of the ATTINY is a bit different and the Wire library doesn’t work. Fortunately there is TinyWireM, which is written specifically for I2C communication with the ATTINY processors and has the same functions as the Wire library.

So I thought it was a simple matter of modifying the MMA8452 library by changing all the Wire functions to the equivalent TinyWireM functions. Although it successfully compiled, the accelerometer didn’t answer any calls from the ATTINY. So I decided to abandon the MMA8452 library and write my own functions to use with the TinyWireM library. With a quick search I found this well documented sample program written by Nathan Steidel for the MMA8452 accelerometer. Although it is written for the ATmega processors and uses the Wire library, it looked simple enough that I could easily modify it to write a simple program using TinyWireM.

It worked! Finally the accel answered the ATTINY’s call and sent back accel data. I verified it using an LED, by turning it on or off when the acceleration value of one of the axis crosses a threshold. This is why I like LEDs so much! They are the simplest way to figure out if your digital circuit is working. This is good news because now I am pretty certain that I can also get the gyroscope to talk to the ATTINY as well since it also has an I2C interface.

So my next step is to write my own MMA8452 accelerometer library for the ATTINY processors. Until it’s ready here is the sample code that I used to get the ATTINY to talk with the accelerometer:

/**
 AttinyAccelTestV2.ino

 Purpose: To read acceleration data from MMA8452 accelerometer with ATTINY85.
 Code adopted from Nathan Seidel of SparkFun Electronics
 Original code: https://github.com/dmcinnes/acceleromocity/blob/master/accel.ino

 @author Kasun Somaratne
 @version 2 Nov 15, 2014
 */

#include <TinyWireM.h>

#define MMA8452_ADDRESS 0x1D

#define TEST_LED 1

//Some of the registers of the MMA8452
#define OUT_X_MSB 0x01
#define XYZ_DATA_CFG 0x0E
#define WHO_AM_I 0x0D
#define CTRL_REG1 0x2A

//accelerometer sensitivity can be 2,4, or 8g
#define GSCALE 2 

//store current accelerometer values for x,y,z axis
float currentAcc[3] = {0.0, 0.0, 0.0};
const float threshold = 0.5; // set value from -1 to 1

void setup()
{
 pinMode(TEST_LED, OUTPUT);
 digitalWrite(TEST_LED, LOW);

 //Initialize the I2C communication bus
 TinyWireM.begin();

 //Test and initialize the MMA8452
 initMMA8452();
}

void loop()
{
 //Retrieve the current accelerometer readings
 updateAccelData();

 if(currentAcc[2] > threshold)
 {
 digitalWrite(TEST_LED, HIGH);
 }
 else
 {
 digitalWrite(TEST_LED, LOW);
 }

 delay(100);
}

//Test and initialize the accelerometer
void initMMA8452()
{
 //Read WHO_AM_I register. This is the first step to see if
 //communication can be estabilished with the MMA8452
 byte c = readRegister(WHO_AM_I);
 if(c == 0x2A)
 {
 //digitalWrite(TEST_LED, HIGH);
 }
 else
 {
 while(1);
 }

 //Must be in standby mode to change registers
 MMA8452Standby();

 //Set up full scale range to 2, 4, or 8g
 byte fsr = GSCALE;
 if(fsr > 8) fsr = 8; //Easy error check
 fsr >>= 2; //Neat trick, see page 22 of datasheet. 00 = 2G, 01 = 4A, 10 = 8G
 writeRegister(XYZ_DATA_CFG, fsr);

 //The default data rate is 800Hz and we don't modify it in this example code

 // Set to active to start reading
 MMA8452Active();
}

// Read a single byte from addressToRead and return it as a byte
byte readRegister(byte addressToRead)
{
 TinyWireM.beginTransmission(MMA8452_ADDRESS);
 TinyWireM.write(addressToRead);
 //endTransmission but keep the connection active (repeated start)
 TinyWireM.endTransmission(false); 

 //Ask for 1 byte, once done, bus is released by default
 TinyWireM.requestFrom(MMA8452_ADDRESS, 1); 

 while(!TinyWireM.available()) ; //Wait for the data to come back
 return TinyWireM.read(); //Return this one byte
}

// Read bytesToRead sequentially, starting at addressToRead into the dest byte array
void readRegisters(byte addressToRead, int bytesToRead, byte * dest)
{
 TinyWireM.beginTransmission(MMA8452_ADDRESS);
 TinyWireM.write(addressToRead);
 TinyWireM.endTransmission(false); //endTransmission but keep the connection active

 //Ask for bytes, once done, bus is released by default
 TinyWireM.requestFrom(MMA8452_ADDRESS, bytesToRead);
 //Hang out until we get the # of bytes we expect
 while(TinyWireM.available() < bytesToRead); 

 for(int x = 0 ; x < bytesToRead ; x++)
 dest[x] = TinyWireM.read();
}

// Writes a single byte (dataToWrite) into addressToWrite
void writeRegister(byte addressToWrite, byte dataToWrite)
{
 TinyWireM.beginTransmission(MMA8452_ADDRESS);
 TinyWireM.write(addressToWrite);
 TinyWireM.write(dataToWrite);
 TinyWireM.endTransmission(); //Stop transmitting
}

// Sets the MMA8452 to standby mode. It must be in standby to change most register settings
void MMA8452Standby()
{
 byte c = readRegister(CTRL_REG1);
 writeRegister(CTRL_REG1, c & ~(0x01)); //Clear the active bit to go into standby
}

// Sets the MMA8452 to active mode. Needs to be in this mode to output data
void MMA8452Active()
{
 byte c = readRegister(CTRL_REG1);
 writeRegister(CTRL_REG1, c | 0x01); //Set the active bit to begin detection
}

// Updates the accelCount array with current accel readings
void updateAccelData()
{
 int accelCount[3]; // Stores the 12-bit signed value

 readAccelData(accelCount); // Read the x/y/z adc values

 // Now we'll calculate the accleration value into actual g's
 float accelG[3]; // Stores the real accel value in g's
 for (byte i = 0; i < 3; i++)
 {
 // get actual g value, this depends on scale being set
 accelG[i] = (float) accelCount[i] / ((1<<12)/(2*GSCALE)); 

 // use a rolling filter
 currentAcc[i] = 0.95 * accelG[i] + currentAcc[i] * 0.05;
 }
}

// Reads accel data from the MMA8452
void readAccelData(int *destination)
{
 byte rawData[6]; // x/y/z accel register data stored here

 readRegisters(OUT_X_MSB, 6, rawData); // Read the six raw data registers into data array

 // Loop to calculate 12-bit ADC and g value for each axis
 for(int i = 0; i < 3 ; i++)
 {
 //Combine the two 8 bit registers (MSB and LSB) into one 12-bit number
 int gCount = (rawData[i*2] << 8) | rawData[(i*2)+1];
 gCount >>= 4; //The registers are left align, here we right align the 12-bit integer

 // If the number is negative, we have to make it so manually (no 12-bit data type)
 if (rawData[i*2] > 0x7F)
 {
 // Transform into negative 2's complement #
 gCount = ~gCount + 1;
 gCount *= -1;
 }

 destination[i] = gCount; //Record this gCount into the 3 int array
 }
}</pre>
<pre>

From PropClock to Gyro’clock

Hello! It’s been a really long time since my last blog post. Excuse? School! Since school started I barely had time to work on my project. Although, I did work on it here and there and made a bit of progress. Finally I got some time to visit my blog and give you an update on the project.

PropClock to Gyro’clock

First of all a name change for the project. I thought ‘PropClock’ is a confusing name for this project because even though the principal of operation is the same as that of a propeller clock, this project doesn’t really have a propeller. You have to spin it yourself to make it work. So I came up with another more appropriate name: Gyro’clock! The appropriateness (or silliness) of that name will become more clear as you read along.

Accelerometer to Gyroscope

As I explained in my previous post, one of the biggest problems I encountered on the first keychain ‘propeller’ clock is not being able to accurately determine the angle of the spinning device. Back then I used a MMA8452Q accelerometer to determine the angle of rotation by using the gravity vector as a reference. The problem with that method is the noise in the accelerometer readout, which is significant in short time scales. The accelerometer is too sensitive to all the random forces that occur when device is spinning in the air.

This time around I want to measure the rotation angle with much better accuracy to display the time at the same position in space. So move over accelerometer, and here comes the gyroscope! Hopefully the name Gyro’clock is making a bit more sense now. Unlike an accelerometer, a gyroscope is not sensitive to forces. It is only sensitive to the rate of rotation of the device. This makes a gyroscope readings very accurate in short time scales. However, since the gyroscope spits out the rotation rate, we have to integrate it to obtain the rotation angle. Errors in integration accumulate over time making the calculated angle slowly drift away from the true angle. Also we need to figure out a way to define a reference angle. Otherwise any angle calculated from the gyroscope readings will be meaningless.

After a bit of research, I found that a better solution is to use both an accelerometer and a gyroscope to calculate the rotation angle. The accelerometer readings can be used to correct for the angular drift observed in gyroscope measurement by implementing a complimentary filter (more on this technique later on).

LEDs to Neopixel stick

I was really excited to run in to Adafruit’s Neopixel stick. This stick has 8 tightly packed RGB LEDs. Each LED can be addressed individually using a single data pin. Adafruit also has an Arduino library to go with it, and this makes controlling the LEDs really simple.

The Neopixel stick is an almost perfect choice for this project, but it still doesn’t solve one of the key issues I faced in the first keychain clock design. When the device is spun in the air it tumbles around the axis parallel to the chain so the LEDs may not be facing you all the time (the tumble effect). Ideally you would want the LEDs to have a 360 degree field of view or be symmetric along the chain axis.

Although the tumble effect doesn’t significantly affect the functionality of the device, it doesn’t allow a consistent sustained image to be displayed. One solution for this is to aerodynamically design the case of the device in such a way that the LEDs will always face the same direction when spinning. I will continue to search for a simpler solution to this problem, but at this point the Neopixel stick is the best candidate for the job.

A single microprocessor to dual processors

Since this device will need to fit on a keychain and be able to carry around in a pocket I want to use a reasonably compact low power microprocessor. So my first choice is the ATTINY85 since it only has 8 pins! The only issue I have encountered so far with the ATTINY is it’s limited program memory. 8 KB is simply not enough space to implement all of calculating the rotation angle, real time clock, time display and time setting functions.

So I decided to split it up between two ATTINY’s. One of them will be dedicated to calculating the rotation angle since that takes the most amount of processing power, while the other will keep track of time and display it when interrupted by the orientation detection processor.

So what have I actually done?

At this moment I have narrowed down the parts I need to build a first prototype of the Gyro’clock. They are:

  • Adafruit’s L3GD20H three axis gyroscope
  • MMA8452 three axis accelerometer
  • Adafruit’s Neopixel stick
  • Two ATTINY85 microcontrollers
  • 150 mAh rechargeable Lithium Polymer battery
  • Adafruits micro USB Lipo battery charger with 5V boost

I have ordered the parts. While they make their way to me, hopefully before the end of the year, I am working on developing the firmware. I have found some helper libraries to go with the gyroscope, accelerometer and the Neopixel array, and it should make coding significantly easier. The libraries are written for use with the ATmega328p processors, so I have to make some minor modifications to use them with the ATTINY’s.

Hopefully when the parts arrive I will have something interesting to show. Until then stay tuned and Thanks for reading!