Recently I needed to design and build a small battery-operated device with 4 outputs sequenced at a variable rate. After playing with a 555 timer IC and some CMOS flip-flops, I realised that the modern way would be to use a microcontroller. So it was time for me to learn about Arduino. Although there is a lot of information about Arduino on the web, it’s not very well organised, and the tutorials on arduino.cc don’t go as deep as I needed. I had to hunt around for the information I required. So here is a guide to developing an embedded project based around an ATmega series processor, using nothing but an Arduino Uno to both develop the system and program a virgin ATmega chip in the prototype.
The Arduino is an open source development platform for the AVR family of microcontrollers. It makes getting into microcontrollers easy and inexpensive. Just buy an Arduino Uno (cost in the UK is around £20+VAT), download the software from Arduino.cc, read the introductory tutorials, and you’re away. However, if you want to move your design off the Arduino and on to your own hardware, there are a few more things you need to know, as follows.
Which pins should I choose to use for I/O?
The following types of I/O are available on the Arduino:
- Analog input
- Digital input (with optional pull-up to Vcc)
- Digital input with interrupt on change
- Digital output
- Digital output with hardware pulse width modulation
The Arduino Uno provides I/O pins labelled A0-A5 and 0-13. Of these, A0-A5 can each be used as analog input, digital input, or digital output. Pins 0-13 can all be used as digital input or output, and pins 3, 5, 6 and 9-11 can do hardware PWM. However, you need to choose how you use them carefully for the following reasons:
- Pin 0 is preassigned to serial input. It’s driven from the on-board USB to serial converter on the Uno. However, there is a 1K resistor between the two. This means that if you don’t need the serial port, you can safely use it as an output, provided that whatever is attached to it isn’t going to object to the signals that appear on it when the Arduino bootloader is running. You could even use it as an input if the device driving it can cope with a 1K resistor connected to ground and Vcc at different times. You can’t use the internal pull-up because it isn’t strong enough to drive a 1K resistor to ground.
- Pin 1 is preassigned to serial output and is connected to the USB to serial converter via a 1K resistor. You can safely use it as an output. I don’t recommend using it as an input, because it will be driven as an output while the bootloader is running, even if your program reconfigures it as an input.
- Pins 2 and 3 are the ones that can generate an interrupt. [Actually you can generate an interrupt from any pin using the pin change interrupt facility, but the direct interrupt facility on pins 2 and 3 is easier to use.]
- Pins 4-10 can be used for digital I/O as required.
- 11 and 12 can be configured as inputs or outputs. However, these pins are also used for in-circuit serial programming (ICSP). If your hardware design includes a standard 6-pin Atmel ICSP header (and I strongly recommend that it does), then these lines will be driven during programming. So you should use these pins as outputs, and make sure that whatever is connected to them can cope with whatever signals appear on them (I typically use them to drive an LCD). Alternatively, they can be used as inputs with pull-up enabled for press-to-make push buttons or key pads, provided you are careful not to press the buttons during programming.
- Pin 13 is also used during in-circuit serial programming, so the same considerations apply as for pins 11 and 12. Additionally, on the Arduino Uno it is connected through a 1K resistor to a LED and then ground. So you can’t use it as an input with pull-up unless you disconnect the LED.
What supply voltage and clock should I use in my hardware?
If your hardware will be battery operated, consider using a lower clock speed than the 16MHz of the Uno to reduce current consumption, and perhaps a lower supply voltage (see the processor data sheet for permitted supply voltage and speed combinations). If timing is not critical, you can use the 8MHz RC oscillator in the chip, optionally pre-scaled down to 1MHz. This oscillator is factory-calibrated to be within ±10% of 8MHz at 25°C when the chip is powered with 3V. With a 5V supply it is likely to be around 8.1MHz. If you need better accuracy than that, but ±0.5% is good enough, use a 3-terminal ceramic resonator. Otherwise, use the standard arrangement of a crystal and two capacitors.
How do I program a virgin ATmega328 to use in my own hardware?
If your design uses an ATmega328P and you don’t mind if it runs the bootloader when it powers up, then you can transfer the chip straight from the Uno to your target hardware, and buy a new ATmega328P with bootloader already installed for your next project. Otherwise, you’ll want to program the processor without the bootloader. If you’re going to do a lot of designs using Atmel processors, then it’s worth buying an in-circuit serial programmer. However, if your project is a one-off, you can use the Arduino Uno itself as an ICSP. In the following, I’ve assumed that the Arduino software is installed into C:\arduino-0022 under Windows.
Turn your Arduino Uno into an ISP
- In the Arduino programming environment, select ArduinoISP from the example projects and upload it to your Arduino. Then disconnect the Arduino USB cable.
- Make up a cable to connect a 6 way socket for the ICSP header on your own hardware (you did include one, didn’t you?) to the 6 way ICSP header on the Arduino Uno (the main one, not the one for the USB to serial converter). However, you must cut the line connecting the pin 5s together. Connect pin 5 of the header on the target hardware to pin 10 of the Arduino Uno board instead.
- Connect a capacitor between the GND and Reset pins of the Arduino. A 10uF capacitor works fine, but as low as 1uF should do. This is needed to disable the auto-reset when programming data is received.
Configure the Arduino development environment
- If your target hardware is not a ATmega328P running at 16MHz, you will need to define its properties. With the Arduino programming environment not running, edit file C:\arduino-0022\hardware\boards.txt [replace arduino-0022 by the path appropriate to the version of the Arduino software you are using, e.g. arduino-1.0.1]. Create a new board definition by copying all the lines in the “uno” block at the start, changing “uno.” in the copy to something else, e.g. “mydevice.”. Change the text after “mydevice.name” to some text to identify your target hardware. Change the values of mydevice.build.mcu and mydevice.build.f_cpu to your target processor and clock speed.
- [This step is no longer needed if you are using Arduino 1.0 or later]. Locate and edit the preferences file (under Windows 7 this will be in C:\Users\<your user name>\AppData\Roaming\Arduino\preferences.txt). Change the line “upload.using=bootloader” to “upload.using=arduinoisp”.
Program the device
- Install a virgin ATmega328 (or other Atmel device) in your hardware.
- Connect your Uno to the target hardware via the 6-way cable. The target hardware is powered by 5v through the cable during programming, so should not be powered independently.
- Reconnect the Arduino USB cable.
- Load the Arduino environment, open your project, select your target hardware in the Boards menu (or leave it set to Arduino Uno if you didn’t create a new board definition), and upload your project [if you are using Arduino 1.0 or later, use the "Upload using programmer" option in the File menu instead of the usual Upload option]. If everything is OK, this should program the processor in your target hardware.
Set the fuses
If you started with a virgin ATmega328, the device will be configured to use its internal 8MHz (approx.) clock and prescale it by a factor of 8, so that it runs at about 1MHz. Also, the brownout detector will not be enabled. To fix these, you need to program the fuses, as follows:
- Use this embedded fuse calculatorto calculate the values of the Low, High and Extended fuses that you need. If you’re not sure what clock values to use or you’re using a ceramic resonator, see the processor data sheet.
- Open a command prompt and navigate to C:\arduino-0022\hardware\tools\avr\bin.
Here’s the command to program the low fuse byte, assuming that your Arduino Uno is using serial port COM5, the processor is an ATmega328P, and the required fuse byte is 0xEE:
avrdude -C ..\etc\avrdude.conf -c avrisp -p m328p -P COM5 -b 19200 -U lfuse:w:0xEE:m
To program the high fuse byte or the extended fuse byte, use hfuse or efuse in place of lfuse. Note that when programming the extended fuse, the unused bits come back as zeros, so if e.g. you tried to program 0xFD into it then it will read back as 0x05. For more info on avrdude see this tutorial.
That’s all there is to it. Don’t forget to change” upload.using=” back to “bootloader” when you want to load a different program on to your Arduino! Shame the regulations don’t allow me to build my own Arduino autopilot…