Microcontroller programming: initial setup

Note: This article is the 4th in a series of posts about electronics.

Once you have acquired the hardware: a breadboard, a programmer, a serial adapter, some wires, and a microcontroller, you’re ready to make it tick. For most future entries, if you’re following along, I will assume that you’re using an AVR Dragon, a Sparkfun FT232RL breakout, and an Atmel ATmega644PA in PDIP package.

Software

Eclipse as an IDE for AVR programming

I personally have been using the Eclipse IDE for most of my AVR work. Eclipse has excellent C language support, and a pretty logical workflow. Its configuration can be a bit painful sometimes, but overall it works very well for AVR development. You’ll want to install at least the AVR Eclipse Plugin and support for your favorite source control (I use the SVN support).

GCC cross-compiler and avr-libc C library

Developing for a microcontroller is a bit different than developing for a PC, because the microcontroller and the PC can’t run each others’ code. Since you can’t exactly hook up a monitor, keyboard, and mouse to the microcontroller and write your code there, you must cross-compile it. Cross-compiling is really the only option you have when developing code for microcontrollers but it’s not an altogether uncommon technique to run into outside of microcontrollers, either. There are two very important terms when dealing with a cross-compiler:

  • Build — The build system runs the compiler and usually the rest of the development suite, such as IDEs
  • Target — The target system is the one the code is being written for. It’s usually not capable of doing the compiling itself because it’s either too new (the tools haven’t been ported), unsupported directly by the tools for one reason or another (a common reason is that it doesn’t have enough RAM), or is primitive enough that it could never actually run the compiler itself in the first place (microcontrollers especially).

Support for cross-compiling for AVR has been in main-line GCC for quite some time now, so it is available in a lot of different places. When GCC is built to cross-compile for AVR it is usually (but not always) named avr-gcc, and many Linux distributions—such as Fedora 12—have packages pre-built for it.

In addition to a C compiler, you will need a C library. The avr-libc project provides a version of libc suitable for the AVR, with much of the libc stuff you’re used to (a type library, malloc, strcpy, etc.), and a bunch of AVR-specific things (delay subroutines, defines for all kinds of microcontrollers, etc.). Again, on many Linux libc is quite easily provided by by the pre-built packages.

Compiling code for the AVR is much the same as you might be used to for the PC, with a few exceptions:

  1. You must always define which exact model of microcontroller your code is “targeted” at using -mmcu=atmega644pa for instance, for the ATmega644PA.
  2. It’s not strictly required, but is generally a good idea to tell the compiler (and thus your code) what frequency you expect the microcontroller to be running at using the F_CPU define; generally it’s best to define this on the gcc command line (rather than using #define) with -DF_CPU=8000000L for 8 MHz, as an example. If you don’t define F_CPU, you can’t use the delay functions (_delay_ms and _delay_us) and some others.
  3. There are substantive differences besides mere performance when running with optimizations off and on. For instance, the delay functions mentioned above require optimization to be enabled to work properly. Generally you should compile with -Os for optimization based on code size.
  4. You need to carefully watch the resultant code size with each compile. The AVR Eclipse plugin automatically runs avr-size with each compile to keep you apprised of the current code size, but if you’re writing your own makefiles you will want to do something like avr-size --format=avr --mcu=atmega644 foo.elf.

Getting the code onto the microcontroller

Once you have a working development environment and you’re able to compile code, you will need a program to transfer that compiled code to the microcontroller. The avrdude program does just that. There is built-in support for it from the AVR Eclipse plugin, which simplifies things a lot, but you can also use it from the command-line.

Communicating with the microcontroller

You will almost certainly want minicom, a serial terminal emulator, to communicate with the microcontroller over the serial port.

What if I use a Mac?

On Mac OS X, of course Apple doesn’t provide any pre-built packages for all of this, but Eclipse is readily available for Mac OS X, and the rest can be provided simply by CrossPack for AVR Development, which bundles avr-gcc, avr-libc, and avrdude into a nice pkg installer. You can get minicom through either Fink or MacPorts.

Architecture of the AVR

Note: This article is the 3rd in a series of posts about electronics.

Once you have all of the hardware you’re going to need, you’re ready to get the software set up! But wait! Maybe you should understand the hardware architecture a bit better, as it quickly starts to matter when you’re writing programs.


AVR Architecture Block Diagram (from ATmega644PA). The Flash, SRAM, and peripheral buses are all separately connected to the CPU.

The AVR memories

The AVR architecture makes use of four different types of memories:

Flash

Flash memory, or just flash, is erasable, non-volatile storage (it doesn’t require any refreshes to keep storing data) used for program storage. When you have compiled a program and you upload it to the device, this is where it’s stored. When your program runs, it is run directly from the flash memory (it is not copied into RAM as most PCs would do).

SRAM

Static RAM (SRAM) is used for transient program state (such as variables) as well as the program stack and any allocations made by the program. When the program starts, all global variables are initialized in SRAM by a special routine generated automatically by the compiler. The AVR architecture does not inherently or automatically reset memory, so without explicit resets by the program (usually automatic) the memory contents is persistent across resets. (This fact can actually be utilized by the program by allocating variables in the “.noinit” section.)

EEPROM

EEPROM (electrically erasable, programmable, read-only memory) is used for non-volatile persistent storage. It is a good place to write configuration values (such as baud rates, unique IDs, etc.), to keep track of counters over a long term, and to keep static data that isn’t needed frequently. Accessing EEPROM memory requires special instructions and is quite slow compared to SRAM, and can be risky if the device loses power (the data can be corrupted). Due to the limited number of writes that EEPROM can handle (approximately 100,000) before failure, care should be taken not to write unnecessarily.

Fuses

In addition to the Flash, SRAM, and EEPROM, AVRs have a few bytes (usually 3) of fuse memory. This memory is used to store “fuse bytes”, which are boot-time configuration values used to initialize the microcontroller itself. On systems that have 3 bytes, such as the ATmega644, they are called “low”, “high”, and “extended” (or “l”, “h”, and “e”), and they each store individual bits or bit values of configuration settings. For example, you use fuses to set the clock input source (CKSEL[0..3]), whether the clock should be divided by 8 (CKDIV8), whether the watchdog timer, SPI, and JTAG should be enabled (WDTON, SPIEN, JTAGEN respectively), and many other important things.

The Harvard architecture

Modern PCs are based on the von Neumann architecture, which uses a CPU and a single memory (generally DRAM) attached by a single bus, which is used for program memory and data memory. In contrast, the Harvard architecture, which is used by the AVR, uses entirely separate buses and memories for program and data memory. This allows for higher performance as well as to allow the program and data buses to be different widths.

Aspects of the Harvard architecture are visible to the programmer in a way which is normally not considered when writing programs for the PC:

  • Static values must be copied from program memory to data memory in order to be used by the program in most contexts. This impacts initializers as well as any strings or structures you may use in the program.
  • It’s possible to use functions to minimize memory usage by copying values (especially strings) from program memory directly to IO channels such as serial output, and this is exposed to the user in the form of PROGMEM declarations and *_p variants of many different functions.
  • Pointers are not all equal. There are pointers to program memory, and pointers to data memory. You cannot mix the two.

Peripherals and pin-sharing

While each AVR generally offers a large number of peripherals, you may have to choose which ones you are able to use based on which pins are shared on the particular device in question. For instance, if you need a large number of GPIO pins, you may not be able to use an external oscillator, you may have to choose between using timers for internal timekeeping versus PWM, etc.

The datasheets are essential for understanding which pins share which functions. In general, the higher pin count devices share less pins between functions, and in fact Atmel offers several devices in lower- and higher-pin-count versions (for instance ATmega1280 [100-pin] versus the ATmega1281 [64-pin]); the same device with more or less pins shared.

The datasheets typically have a section titled “Alternate Port Functions” which does a very good job of describing all of the pin-sharing on each device.

Clock systems, clock sources, and oscillators

Clock systems


AVR Clock Distribution Block Diagram. Clock sources supply the AVR Clock Control Unit via a prescaler, and are then distributed to the various clock system components.

The AVR architecture has several different clock sources, which can be independently halted:

  • clkCPU — The main AVR core clock used for most instruction processing.
  • clkI/O — Most peripherals operate from this clock, such as timers, SPI, and the USART.
  • clkFLASH — Reading and writing from the flash memory used this clock, which is usually synchronized with clkCPU.
  • clkASY — This clock can be set up to clock the real-time timer/counter independently of all other clock sources to allow for unimpeded clocking if necessary, even in power-saving modes.
  • clkADC — The analog-to-digital conversions operate from this clock to allow the other clocks to be halted during conversions to eliminate noise.

Clock sources

One of the most important decisions when setting up a microcontroller is its clkCPU clock source. Typically, AVR microcontrollers offer several clock sources:

  • Internal 8MHz oscillator (pre-scaled by 1/8 to 1MHz by default)
  • Internal 128kHz oscillator (for power-saving)
  • External crystal oscillator up to 20MHz
  • External clock signal (typically from another microcontroller)


AVR Clock Generation. The internal oscillators can be used, but typically an external crystal oscillator is connected across XTAL1 and XTAL2, with a pair of 18pF capacitors to ground.

Prescalers

All of the clock inputs are fed into a prescaler which can scale the clock by anywhere from 1 (no scaling) to 256 (256 cycles of the oscillator to one cycle of the clock). Typically the prescaler is set at run-time, as necessary, to reduce the clock speed, thus saving power by executing less. There is one special way the prescaler is set: a fuse called CKDIV8 can, if set, automatically prescale the clock by 1/8 at boot time. This is used for the default configuration to prescale the 8MHz internal clock to 1MHz.

Oscillators and the choice of frequencies

If you choose to use an external oscillator, you have to choose the frequency. It’s not immediately obvious what the best frequency would be. In reality, the best frequency is usually driven by the application: performance requirements, interoperability with other systems, and communications requirements. There are a few frequencies which are in wide-spread use:

  • 1MHz — The on-board prescaled frequency, which is not terribly fast, but saves a lot of power.
  • 8MHz — The on-board non-prescaled frequency, which is generally fast enough and doesn’t require external components.
  • 14.7456MHz — Why in the world such a specific frequency? There’s a simple answer: standard baud rates, such as 9600, 38400, and 115200 baud, can all be perfectly generated by a microcontroller running at this frequency.
  • 16MHz — A quite fast frequency which is still very compatible with various baud rates, especially if you have control over the baud rate.
  • 20MHz — If you want maximum performance and you control the baud rate, max out the clock speed.

Microcontrollers: a look at hardware

Note: This article is the 2nd in a series of posts about electronics.

In my previous post I mentioned that I identified microcontrollers and microcontroller programming as one of the key disciplines that I needed to study up on. I have been programming in one way or another for about 20 years now, so I have done so on a pretty wide range of computers, but aside from some tinkering with a PIC microcontroller, I never really did anything with these amazing and tiny computers. This post will take a look at the hardware side of the microcontroller picture.

A microcontroller is, more or less, a very tiny and (often) self-contained computer. While compared to the past, modern microcontrollers are extremely advanced, run at very high speeds, and have huge amounts of program storage and RAM, compared to modern PCs, they seem incredibly primitive.

A modern PC such as the one I’m writing this on may have a 2.4GHz processor, 4GB of RAM, and a 320GB hard drive. Comparatively, an Atmel ATmega644 has a 20MHz processor, 4KB of RAM, and 64KB of program storage (flash)—incredibly slow and with a tiny amount of memory and storage—and it’s one of the higher end microcontrollers. So why are they useful? For a few reasons:

  • Size — If you’re looking to build something small, you can still give it a lot of brain power with a modern microcontroller, and it will fit in the palm of your hand.
  • Power consumption — The power consumption of microcontrollers is usually measured in micro-amps (µA). PCs, even very simple ones, can’t even come close, especially once you make use of some of the power saving features on the microcontroller.
  • Durability — Vibration, heat, dust, etc. aren’t really a big problem for most microcontrollers.
  • The sheer number of internal peripherals such as timers, serial interfaces (UART [TTL serial], I2C, SPI, and even USB), analog-to-digital converters (ADCs), pulse-width modulation (PWM), and of course tons of general purpose IO (GPIO) pins. Many of these peripherals can even be used in interrupt-driven background modes, making more processor cycles available to your main program.
  • Speed — While 20MHz (or less!) might not seem like much to us desensitized by modern multi-GHz PCs, when you don’t have the overhead of 12 layers of operating system, and when your tasks are very simple, a few MHz is more than enough; it will be far more responsive than a PC ever could be.
  • Price — Atmel AVR microcontrollers run from less than a dollar up to a few tens of dollars each depending on capacities and features. Most of the ones I use are around $8.

The Atmel AVR series

When I was first looking at trying my hand at microcontroller programming, I more or less chose the Atmel AVR series by accident: some sites that I respected (like Sparkfun) had many projects based on it, and I noticed the avr-gcc (merged into gcc proper) and avr-libc projects seemed to be very well maintained. I knew about the Arduino platform (which is based on the Atmel ATmega328), but I really wanted to get into the internals of everything, and I already know C and low-level systems programming pretty well, so I figured it would be easy. I believe, especially now, that I made the right choice.

The Atmel AVR ATmega and ATtiny series’ of microcontrollers are 8-bit RISC architecture processors combined with a variable amount of erasable flash memory for program storage, static RAM (SRAM) memory for working data, non-volatile EEPROM memory for persistent data, and a bunch of peripherals, but usually a couple of timers, a UART, a few ADCs, and a few PWMs, an I2C bus, an SPI bus, and some GPIOs. They are typically programmed over their SPI bus, and can even be reprogrammed in-circuit. All of that for just a few dollars each.

The Atmel ATmega644

I decided to do most of my microcontroller work on the Atmel ATmega644 (including ATmega644P and ATmega644PA revisions). It has enough flash that I don’t need to worry about running out of space (except by accident, heh) and enough SRAM that most anything I want to do is possible. While it’s kind of chunky in PDIP package, it’s certainly petite enough for my needs in TQFP and QFN packages.

It’s specs are:

  • Processor speed: Up to 20MHz (8MHz internal oscillator)
  • Flash: 64KB
  • SRAM: 4KB (4096 bytes)
  • EEPROM: 2KB (2048 bytes)
  • Timers: 2x 8-bit and 1x 16-bit
  • PWM: 6x
  • ADC: 8x 10-bit
  • Interfaces: 1x USART, 1x SPI, 1x I2C
  • Packages: PDIP 40, TQFP 44 (12.00mm), QFN 44 (7.00mm)

Equipment needed

In order to get started with any Atmel ATmega (or ATtiny) series, there are a few must-haves:

  • Breadboard — These are pretty standard, but you’ll want a few good ones so you don’t have to unplug everything to try something new or test something.
  • Programmer — I got the AVR Dragon, but there are dozens of different programmers out there. It just needs to support the 6/10 pin ICSP programming mode for AVRs. (If you get the AVR Dragon, also get a 40-pin ZIF socket and a bunch of DIP headers to populate its empty through-hole positions. The AVR Dragon with a ZIF socket is very useful if you need to “rescue” a badly programmed microcontroller using its parallel programming (PP) mode, and many cheaper programmers only do ICSP, not PP.)
  • USB serial adapter — Sparkfun sells several based on the FTDI FT232RL serial interface chip (5V and 3.3V), and they work very very well on all operating systems.
  • Crimped jumper wires — These are awesome for making quick and easy connections between boards, for making custom programming cables, etc. I use a ton of them. You will want M-M, M-F, and F-F, and a good selection of crimp connector housings; I find the most useful ones are 1×1 (jumpering), 1×2 (power etc.), 1×3 (I2C, serial, etc), 1×4, 1×6 (ICSP), and 2×3 (ICSP).
  • Pre-cut jumper wires — These are critical for making short connections on the breadboard. Pololu has a good selection of them.

Then of course, you’ll want to get a few actual microcontrollers:

  • Atmel ATmega644PA PDIP 40 — Good for all sorts of hackery, but quite big in PDIP package. Currently $7.50 each individually.
  • Atmel ATmega168 or ATmega328 — These are cheaper, smaller, and less capable. They are great once you’ve written something and want to deploy it at a larger scale for cheaper. They are also great if you want to use the Arduino bootloader. Atmel is having all kinds of supply issues with them right now (welcome to the world of hardware!), so good luck finding them.

This is how my desk usually looks when I’m prototyping something on the breadboard:


My desk during prototyping. A breadboard with ATmega644PA, the AVR Dragon, and a Sparkfun FT232 breakout.

A few cautions

Read the datasheets!

While it may seem incredibly boring, you will learn a lot by reading the datasheets for the parts you’re buying. After having worked in the software industry for 12 years, I am very impressed by the sheer level of accurate documentation in the hardware world. It will save you a lot of time if you at least skim the datasheet for every part you intend to use before you break it out (or even before you buy it).

Don’t mix 5V and 3.3V

You will probably want to choose whether you want to work at 5V or 3.3V. The electronics world is currently fractured between those two voltages pretty evenly (as well as some lower voltages such as 1.8V). Many things are not compatible between the two, so always check the voltage very carefully before you buy something. You do not want to be working out level conversion issues while you’re just trying to learn and get things working. It doesn’t matter which you choose (although arguably more hobbyist stuff is 5V) but everything you buy should be the same voltage unless you have a large budget.

Be careful with fuses

I’ll get into how fuses (basically, non-volatile configuration switches) work in a later blog entry, but suffice it to say, if you see stuff about fuses and setting them, be extremely careful. If you set the fuses incorrectly you can easily get your AVR into a state where it can’t be serially programmed and you’ll need to trash it or rescue it with parallel programming. (See above about why AVR Dragon with a ZIF socket is nice.) I have done this a few times, and it’s not fun to fix them, but at least it’s possible with my setup.

Destination: Robot?

Note: This article is the 1st in a series of posts about electronics.

For more years than I care to count, I have been interested in electronics and circuits in one way or another. I’ve been building useless toys and taking apart radios and such since I was just a few years old, but I never really spent any serious effort on it. Due to my overwhelming interest in computer programming and later databases, electronics never even reached “hobby” status. In my late teens, I applied my well-learned soldering skills and invested in some new gear to make a few bucks by modding Sony Playstations for hire. To do that, I bought a parallel-port-connected EEPROM programmer, so that I could just burn the chips (Microchip PIC, I think) myself. In addition to making and selling mod chips, I dove into the documentation and learned how to program the chips to do stupid simple things in assembly language. Assembly was not nearly enough fun, and programming the chips themselves was slow and painful, so I pretty much went nowhere with that.

Over the past few years I have had a few projects that were in one way or another electronics-based, including an online weather station (now defunct, since we moved to a townhome) and at about the same time, an ill-fated robot project based on an ATX PC. In trying to build a robot, I quickly realized that I don’t know near enough about the low-level things, and I picked a few disciplines that I needed to study up on:

  • Microcontrollers and microcontroller programming — Robots need to do a lot of extremely fast fine-level control, and to offload various low-level tasks from the main CPU (such as checking wheel rotation sensors). There’s a lot to learn about both the interface aspects and the programming aspects of working with microcontrollers. Luckily the Atmel AVR line is awesome, and I was able to pick up on it very quickly due to its C-language gcc support.
  • Communications interfaces — This is in many ways a subset of microcontroller programming, but it gets into a lot of very specific sub-areas, and a whole new area of electrical interfaces. Specifically I knew I’d need I2C, SPI, TTL serial, and potentially RS485, Ethernet and/or WiFi.
  • Circuit board design (EDA) — This one is all about physical space and elegance, really. While you can build a lot of cool things by wiring together a bunch of separate components, I know I’d never be happy with the inelegance of it and the sheer size requirements and constraints placed on you by using only components designed and built by others. I needed to get access to the actual chips and lay them out myself using some electronics design automation (EDA) tools; I chose EAGLE.
  • Surface mount technology — If you’re doing anything related to circuits these days you quickly realize that it’s getting harder and harder to find through-hole components—ones which have legs that poke through the circuit board—for everything you need. In order to build any remotely complex design you have to get into surface mount devices, which are generally much smaller, and sit on “pads” instead of poking through holes. Using SMT requires special tools and some additional knowledge, but they enable you to build much smaller circuits, so I figured I may as well learn.
  • Servos and stepper motors — To make things move, you need motive power. The most common ways to accomplish that is either through servo phase-width modulation or stepper motor control.

In what I hope to be a series of blog posts, I will discuss how I went about learning several of the above topics to build one of my first major projects: a custom-designed LED-based analog clock based on an Atmel ATmega644 microcontroller and 128 0603 surface mount LEDs. You can see it in action here:


LED Analog Clock v2 minute transition sequence

And here:


LED Analog Clock v2 hour transition sequence

I hope that I can provide some useful information and insight in this series. Feel free to ask any questions in the comments section, or by emailing me at jeremy@jcole.us.