Make: AVR Programming (2014)
Part III. Advanced AVR Topics
Chapter 20. Conclusion, Parting Words, and Encouragement
Learning AVR: The Missing Chapters
That was quite a lot of material! Surely there is nothing left to learn about working with the AVR microcontroller or any of its peripherals, right? Wrong!
By now you should have the base knowledge to read the datasheet or scour around the interwebs to find what you need. In that spirit, here is a list of all the topics that I didn’t have room for, but that I feel like you should know about anyway.
The Watchdog Timer
The watchdog system is a very slow timer that can be configured to run from 16 milliseconds all the way up to 8 seconds. It is special in that when it reaches the end of its time, it can fire an interrupt or reset the chip. Why would you want to reset the chip every second?
The primary use of the watchdog timer is as a safeguard against runaway code. If your event loop normally takes, say, 20 milliseconds, you can configure the watchdog timer for 40 milliseconds. At the bottom of your event loop, you zero the watchdog timer out again. When your code is running normally, the watchdog timer will never fire.
But if anything goes horribly wrong and your chip freezes up—say you’re doing a blocking wait for peripheral input that never arrives—the watchdog will reset your AVR at least once in a while. You can very cleverly structure your code to take advantage of this and provide nearly foolproof functionality of the first part of your routine.
Another use of the watchdog is as a source of sleep-mode interrupts. If you are putting the chip to sleep for long periods of time, and you configure the watchdog to use a normal interrupt rather than the system reset, it can be a handy wakeup source because it runs so slowly. You can put your chip to sleep for up to eight seconds at a time.
For more on the watchdog system, see the chapter in the datasheet on “System Control and Reset.”
I hardly scratched the surface of power saving and sleep modes. You saw how to enter sleep mode and vary the CPU prescaler, but there’s even more you can do. For instance, if you really need to minimize power use, you can turn off all of the peripherals that you don’t need. Read up on these in the “Power Management” section of the datasheet, but then go straight to the avr/power.h library for implementation because it’s much more readable in your code.
My first choice for lowering power consumption is just to stay in sleep mode as much as possible. Following that, I’ll shut down whatever peripherals I can, but this gets tricky if you’re actually using some of them. A no-code-change method to reduce your power usage is just to use a lower voltage for VCC—all of the A series chips run on 3.3–3.6 V just fine.
Crystals and Alternate Clock Sources
Here, we always used the internal calibrated RC oscillator as a timebase, but you can also supply an external crystal and set some fuses to use it. This gives you the advantage of a super-accurate timebase. I’ve only really needed a crystal for high-speed USART serial communications and USB emulation. Other people swear by them.
Another option, if you’ve got an accurate external timebase, is to calibrate the internal oscillator to the external source by varying the byte in the OSCCAL register to change the speed. The problem is that the OSCCAL register is a normal, volatile, register and gets lost on reset.
A solution, once you’ve found a good value, is to write the calibration byte to a safe place in EEPROM and then read the value back out and store it back in the OSCCAL register as part of your initialization routine at the top of main().
With a number of the ATmega chips, notably the mega88 and mega168, you have the option to reserve some space at the end of the program memory for a bootloader program that gets automatically called on reset, if the right fuses are enabled. This bootloader code is able to write to program flash memory, so that you can program the chip with only a serial cable. The old-school Arduinos used to do this, for instance.
I’m not a big fan of bootloaders because the serial port depends so much on the CPU speed that it can get messed up if you play around with the CPU speed fuse settings. That said, you can’t set the fuses from within a bootloader either, so it makes for a nice safe playground. You should have an ISP on hand as a fallback.
The AVR not only has an ADC, but also an analog comparator built in. In short, it can trigger interrupts when the analog voltage on one pin (AIN0) exceeds that on another pin (AIN1). With a fixed voltage threshold, you could just use the ADC and compare it to a number in code. But the ADC allows you to figure out the difference between two signals.
The comparator can also share the ADC multiplexer, so you can use same ADC pins in place of AIN1. You do have to turn off the ADC to use its multiplexer for the comparator, however.
If there’s anything I like about microcontrollers, it’s putting together a project quickly and having it work. Of course, it’s sometimes fun and sometimes frustrating to debug the darn thing for a few hours, but I usually learn something along the way.
Advice on debugging is usually the same old chestnuts, and I’m afraid I’m going to dish them up as well:
§ Is it powered?
§ Is the reset line pulled low?
§ Have you declared variables used in your ISRs as volatile?
§ Have you actually called those initialization subroutines that you just defined? (How many times do I write a timer init, and then forget to call the darn function!)
§ When all else fails, reduce or simplify to the closest known working state.
§ Toss a 0.1 uF decoupling capacitor on the power pins of any or all ICs.
§ Never assume anything. Or at least test or verify your assumptions.
§ Put LEDs on everything. (Within reason.) Do you see the problem?
§ Put oscilloscope probes on everything you can’t use an LED for. Are the voltage levels what you expect? Why or why not?
§ Buy all critical parts in pairs, and don’t hesitate to swap one out if you think it may be buggy. Even if it’s a low probability of being the problem, it’s a quick fix.
Put This Book Down and Build!
Now get out there and build stuff! Take photos, post project writeups, and post your code for all to see.