Monday, October 4, 2010

Good bearings

So, I finally figured out what the deal was with my accelerometer needing to be asked twice what the value was.

As it turns out, I wasn't actually giving the chip time to reply. I thought the micro would automatically handle receiving the data value, so I all I had to do was send the ACK at the end. In fact, the command that sends the ACK actually tells the micro controller to wait until the entire data byte has been transmitted, and then transmits the ACK.

So, when I was storing the value before sending the ACK, I was storing the value that I originally had in the register (the address of the accelerometer chip) and then waiting for the data and finally sending the ACK. Now, I've changed it so that it waits for the data and sends the ACK before storing the data value in the register.

How did I figure all of this out? With an O-scope! I simply modified my code so that it would give me a voltage spike on one of the output pins while it was reading the data from the register. What I noticed was that it was spiking before it was supposed to. Here's an example of what I mean:


Here's a plot of the two I2C lines while talking to the compass chip. The spike I was noticing was right after the "Chip Address and Read" segment, but before the "High Byte" that means that I never gave it time to actually read back the data!

Oh, what's that? You didn't know that I got the compass working too? Did you even read the title to this post?

Yep, it's working. Doing the reflow soldering was a little tricky because the compass doesn't really have QFN-24 footprint (I don't think it's a standardized footprint). The main difference is that the compass doesn't have the huge ground plate that QFN-24 provides. As seen here:


My solution was to simply cover the stencil with tape:

and carefully cut around the center holes:

Ta Da!

So, the compass works! It did need a little calibration. There's a routine that it can run wherein you're supposed to slowly spin it around while it collects data. When you tell the routine to stop (it recommends anywhere from 6 seconds to 3 minutes long), it does some math and figures out what magnetic fields are local to it (inherent in the circuit it's on) and what magnetic fields are due to the Earth. I didn't know I was going to need a calibration function, so I'll have to work that into the final design somehow.

The compass reports bearing as 1/10 a degree per digit. Here, you can see it displaying the top 4 bits of the compass bearing. Notice how dramatically it changes as the compass passes magnetic north.



Punctual, but Problematic

So, you haven't seen an update out of me in a while. This is because I've been struggling over the past week with getting my clock to return accurate, or at least consistently inaccurate results.

My test method was to use a little program that I wrote that would give me a 10 second count down before starting a timer that increments the LEDs once per minute. The idea was to use the 10 seconds to synchronize the timer with a timer known to be accurate and then let it run for a few hours and see how far off the minute mark it was. Take the number of seconds it's off, divide by total number of seconds elapsed, and multiply by 1 million to get the parts per million (ppm) accuracy.

See, every crystal oscillator needs to be "tuned" with some Load Capacitors. I tried my best to match the Load Caps to the 22pF rating on the crystal's spec sheet (even taking into account the parasitic capacitance on the breadboard), but I still couldn't get good results.

This is me measuring the capacitance that the crystal and chip would see (so, just the load capacitors). I tried to get it as close to 22pF as possible.

Note the two twisted wire pairs sticking up; each of those account for about 2-3pF and were very touchy.

The most upsetting part was how inconsistent my results were. The only certain thing was that wild variations in the capacitance made for wild variations in accuracy.

Well, it turns out that the timer on my iPod, which I assumed to be accurate, was far from it. After switching over to a Timex stopwatch, I got much nicer results. First, I managed to get around 30-35ppm consistently for over a day. Convinced that it was at least consistent, I tried lowering the load capacitance to see if I could improve accuracy. Dropping the 20pF caps for 15pF got me 20ppm accuracy.

I don't think I'll be able to exactly account for all of the capacitances that can interfere with my circuit's accuracy off hand. I think my official solution is going to be guessing the proper load capacitance in my final circuit, and replacing it with a different set of capacitors if it turns out not to be accurate. I'm actually fairly certain that this is how the pros do it. Build a prototype, figure out the best capacitance, and then repeat for 10000 more. At 20ppm, it would lose about 1.7 seconds a day. This is already perfectly acceptable, but I'm sure I can get it even closer when I build the final version.

On another semi-positive note, I got my accelerometer working!

So, convinced that my accelerometer was completely fried last time, I ripped it off the board to survey the damage. It looked like it had been soldered well, but it still didn't work. I was pretty certain that I had baked the chip too hard.

This time around, I wanted to be careful. I grabbed my Le Cruset pot and an infra-red temperature gun and attempted to simulate a reflow oven using a gas stove. The goal was to heat it at 200C for as long as it needed to melt the solder paste and then remove it immediately after.

I even got a video of it!




Well, after all of this, I was sad to learn that my chip still wasn't responding to any input. I simply couldn't get it to acknowledge its own address. This is exactly the behavior I got last time. Completely removing the chip got the same results.

The chip's address consists of a 7-bit number. When talking to it, you always add an 8th bit to indicate if you want to read from it (1) or write to it (0). The address is always sent first followed by the 8th indicator bit.

The address of the accelerometer was listed as 0011100. I was transmitting 00011100, using the aforementioned protocol for writing to the address, and the chip was ignoring me. Well, I was reading up on the I2C protocol at work today when I realized that I was an idiot.

In I2C, numbers are always transmitted most significant bit ("leftmost bit") first! That means that instead of sending 00011100, I should have been sending 00111000! Well, I tried this first thing when I got home, and I got the chip to talk!

Now, it still took me an hour to work out some of the details of getting something useful out of the chip, and I'm fairly convinced that the datasheet is wrong on this one...

The datasheet says that in order to receive a single byte from the chip, you must do the following:



Doing this resulted in me receiving the address of the chip as the current accelerometer data. This was the value that I loaded into the "TWDR" register that was supposed to be replaced by the data from the accelerometer. I was convinced that the whole thing just wasn't working and therefore not updating my register value. I struggled with this for about an hour or so (I had some other bugs along the way), but then I tried this:



This is for reading more than one byte from the slave. Note that the "master" (my microcontroller) sends an Master Acknowledge (MAK) after the first bit of data. Well, I found that for some reason, the first bit of data is always just the address that you sent it. The second piece, however, is what you really want.

I'm not really sure what's going on here. I never got the "single data" condition to return anything but an address, but I suppose I can live with just throwing out a garbage value to get to the good stuff...

The sheet even talks about a special mode of addressing (where you add 0x80 to the subaddress (register address) that you're looking for), that enables "multiple reads", but I'm still not entirely sure how that works. I think it's supposed to run through all the registers sequentially, but I haven't really found a use for it.

If more trouble crops up in the future, I'll look into these issues more, but as is, the accelerometer works exactly how I want to.

Here it is showing its Y data in binary!





It's 2's compliment with each digit representing about 18 milli-Gs. I turned it to 90 degrees and got back 0b111000 which works out to about 1.008G! Awesome!

Now, the real sad part of this story is that, convinced that I had blown yet another chip, I went ahead and ordered another breakout board...two actually (just to be safe), all before realizing my addressing error. That's another $20 down the drain unless I use another .5mm pitch LGA-16 chip in the future. Also, I'll never know for sure, but I might have never fried the first chip after all...