Thursday, July 25, 2013

Trials & Tribulations with the ATmega168

I created a board design for some hardware that involves two ATmega chips in TQFP form.  TQFP stands for Thin Quad Flat Package, and is basically on the larger end of the surface-mount chips (but still way smaller than chips in DIP form).  Whether you use ATmega328 or ATmega168 chips on this board is irrelevant until you start talking about large quantities, in which the 168 will spare a great deal of production costs.  What this hardware does is irrelevant for now (though you will find out soon enough), but I wanted to share my experiences trying to get this board and its chips to work in exactly the way I intended.  It was very difficult, for some reason, to get the 168s to cooperate with me, while the 328s worked with no trouble at all.

My Board Design
My Board Design, with ATmega168s and SMD resistors (all soldered on by hand by Yours Truly, who doesn't even have all that much soldering experience :-P)

The Problem?


One of my product requirements is that users can upgrade the firmware on the chips using a simple serial connection, such as in the example at the bottom of this page (where you use an Arduino Duemilanove without a chip installed in order to load a sketch onto a chip in a breadboard).  In order to do this, there must be a bootloader present on the chip to begin with.   Barring that, you will need to write the sketch directly to the ATmega chip using an ISP programmer (like a USBtiny or an Arduino wired up in a different manner) and set the fuses on the ATmega a little differently so it starts with your sketch instead of the non-existent bootloader.

Truth #1.  Long story short: You need a bootloader to install sketches the easy way, or you need special equipment to install sketches without a bootloader.

Well in any case, I purchased twenty ATmega328s from Mike down the street at Kineteka and went about soldering these onto my early prototype boards.  Afterward, I wired up my Arduino to program the bootloader onto each of these chips, and since Arduinos have been shipping with ATmega328s for a long time, this was a piece of cake.  From the Arduino IDE, I just had to select "ATmega328 on a breadboard", then "Burn Bootloader", and the deed was done.  The sketch could easily be installed onto the chip using a much cheaper FTDI module from Sparkfun.

Then, to go with my next batch of boards, I bought twenty ATmega168s from Mouser (also not very far away).  Problems befell me here because the bootloader specified when you choose that "ATmega328 on a breadboard" happens to be just a bit too big for the 168, so it won't let you install it.  I didn't have time to futz around with this since this was just before my wedding and I really wanted to show off these prototypes at the DJ's booth, so I went ahead and made more boards with the 328s and put the 168s in the drawer.

Fast-forward a few months -- I'm settled into a new house and the initial wild & crazy first 6 months of marriage have elapsed (and some contract work was finished).  I have time to look into this project again, and have since acquired the USBtinyISP to help program the bootloaders without needing to spend a whole bunch of time tediously setting up wires from the Arduino to the various pins on my boards.  I also got emboldened with thinking I could make life a little easier by using the USBtinyISP for programming the bootloader and the sketch all in one go.  However, after loading the bootloader onto the chip, the USBtinyISP simply could not write anything at all to the flash section of the chip.

To work through this failure, I dug up my wicked old IBM Thinkpad T42 laptop complete with a parallel port, and dug up an old parallel ribbon cable that went on the inside of some sort of PC slot from way back in the day and featured a nice parallel to 10-pin header connection.  I opened up the parallel port side and was able to rearrange the pins and insert various resistors where the tutorials told me to do so.  I used this parallel cable to attempt to write the program as well, and while it seemed to have success writing the bits, it still didn't really work.  The parallel cable did help me restore many chips though, ones that had fuses corrupted by communication problems and were stuck desiring some kind of external clock non-existent on my board, or any number of other weird states these things can get themselves into.  I even spent an entire weekend building the entire AVR-GCC toolchain from scratch, only to find out:

  • It would end up missing key configuration files that the Arduino IDE has,
  • Truth #2. The Arduino IDE actually has this entire toolchain built-in already, and
  • I didn't even need this toolchain to begin with because
  • the latest Arduino IDE comes with a bootloader that, well I won't spoil it...
From this, you can draw Truth #3: If you build the AVR-GCC toolchain yourself, it won't include the special Arduino configuration "secret sauce."  Don't expect things to work properly.

It's amazing I still have stuff like this lying around.

The reason I went down that whole rabbit-hole of building the toolchain was so I could compile my own bootloader.  I wanted a bootloader that was small and would work with the ATmega168 where the others fell short.  If anything, there are plenty of custom bootloaders available from AVRfreaks, but usually they just give you the source and you have to compile them yourself.  After trying a few of these bootloaders and still short of anything that looked like successful serial communication once any of them were installed, I decided to nix that entire toolchain and go with the latest & greatest Arduino IDE instead.  (This is when I discovered the truth to most of those bullet points above.)

I started screwing around with the predefined bootloaders provided with the Arduino IDE and digging around through the boards.txt file in order to tweak the fuses and the clock speeds that get configured when you install it.  At one point, I noticed the "Lilypad Arduino w/ATmega168" entry existed and happened to invoke pretty much everything I needed -- only it had the clock speed set to 16MHz instead of 8MHz, so I went ahead and changed that in the boards.txt file and restarted the IDE.  I then tried to install my sketch for about the 756th time.

And, finally, I see serial communication happening!  Only it's a bunch of garbledy-goop.  After exhaustively trying numerous combinations of baud rate, 3.3 vs. 5V, and TX<->TX and TX<->RX, I put it down for another week or two.  During this bit of rest & repose, I collected enough of my brain cells off the floor to re-discover something I learned when I was doing this with the ATmega328 chips many months ago:

Truth #4: When many ATmega chips are sharing the same TX/RX lines, and they are powered, they will screw each other up when you try to program just one of them.  When you program one, you must hold the others in reset.

This is very specific to my board, but my protocol calls for each chip to share a common RX line in order to receive instructions from a "heart controller."  That is the main chip that converts basic ASCII text from the client application (PC, mobile app, HTTP request, or whatever you can imagine) and converts it into instructions each ATmega chip is listening for in order to carry out its task.  The TX line is currently unused, but it's still connected to every chip in the same fashion in order to either support something in the future or give me major grief and headaches now.

This is true when you program the bootloader on the second chip, and it's true when you are flashing the sketch onto either chip.  Hold the other chip in reset (which is Active Low for ATmega168s).

The Solution


Let me condense all the above story & findings into some distinct bullet points.  Once I:
  • Downloaded & used the latest Arduino IDE (1.0.5 as of now),
  • Selected the "Lilypad Arduino w/ATmega168" along with some light modifications,
  • And held the other ATmega chips in reset during programming,
I was able to install the bootloader with my USBtinyISP and the sketch using Arduino serial in the manner I linked to above.  I don't know why all my other attempts at bootloading failed when the bootloader for this very old Arduino product actually did the trick for me.  I guess I'll have to look at the difference between the sources, and it'll be educational.

Ahh, success!

No comments:

Post a Comment