|
Issue
127, February 2001
Working
with AVR Microcontrollers
by
Stuart Ball
Start
The Hardware
The Software
Tools
Design Considerations
The Bottom Line
Sources
PDF
Design Considerations
Most of the AVR devices that
have an ADC use an external reference voltage. This voltage
can be between 0 V and the AVR supply voltage, Vcc. Analog
input values can range between 0 V and the reference voltage.
The simplest approach to generating a reference value
is to connect the reference to Vcc. This eliminates the
need for an external reference, but the precision of the
conversion is limited to the accuracy of the Vcc regulation.
The ATtiny15 has an internal
2.56-V reference for its ADC. Analog inputs can range
between 0 V and the reference voltage. According to the
datasheet, the reference has a tolerance of about 6%,
so this is the best accuracy you can achieve with no modifications.
You can apply your own reference
to the ATtiny15, but one way to get better precision out
of the internal reference is to apply a known, precise
voltage to the chip when its programmed. If the
software knows what the ADC value should be with the nominal
2.56-V reference, it can calculate a correction factor
for the actual reference voltage using:
Correction factor = Expected
ADC value/Measured ADC value
The correction factor is
stored in EEPROM and multiplied by all subsequent ADC
readings. Of course, this requires that a pin be available
to put the device into the special calibration mode. You
can do the same thing with an external reference voltage.
This technique allows you to use a less precise (and less
expensive) reference for your application.
You can use a similar technique
with other sensors. Thermistors typically have a 5% or
10% resistance tolerance, which translates directly into
a temperature measurement error. To use this technique
on a thermistor, you have to hold the thermistor at a
precisely known temperature for the calibration.
When you perform this type
of calibration, you can get correction factors that are
either greater or less than one. To avoid doing floating-point
math in real time, you might want to derive a multiply-and-shift-right
sequence to do the multiplication with integer math. Another
alternative is to use a look-up table to correct the ADC
values.
The watchdog timer uses its
internal 1-MHz oscillator. The exact frequency of this
oscillator varies with supply voltage and temperature,
and it varies from one device to the next. Consequently,
you should allow for variation in the value of the watchdog
timeout. For instance, if you program the watchdog timer
for a 2-ms timeout and reset it using a 2-ms interrupt,
you may sometimes get a watchdog timeout even though the
reset is working properly. Or worse, the condition may
only occur at high temperatures and not on all units.
Figure 2 shows how programming
the flash memory and EEPROM works. All AVR devices without
an internal oscillator require that an external crystal
or clock source be connected for programming. Devices
with an internal oscillator, such as the ATtiny15, use
that clock to time the program operations.
 |
| Figure 2There are two methods for serial programming.
(a) shows the low-voltage method while (b) shows the
high-voltage method. cDuring normal operation,
if the AVR is an output, ground this point or tie
it high during programming to keep the programming
wave form from driving whatever logic connects here.
If the AVR pin is an input, you can leave it floating
during programming. |
There are two methods for
serial programming; low-voltage programming is enabled
by grounding the RESET input and high-voltage programming
is enabled by applying 12 V to the RESET input. Not
all of the AVR devices support the high-voltage mode.
The timing diagrams in Figure 2 are typical.
A problem you may run into
with in-circuit programming is the dual nature of the
pins. Ideally, you would leave the ISP pins free for programming,
but this is not always possible. This can make in-circuit
programming difficult.
One way around this problem
is shown in Figure 2c. A 2.2-kW resistor is placed in
series with the AVR pin. In normal operation, the AVR
pin can drive external logic or it can function as an
input from external logic. During programming, the control
signals are directly connected to the AVR pin.
This scheme requires that
the programming driver be able to drive both high- and
low-logic levels into the 2.2-kW load, so a driver with
suitable current capacity is needed. Obviously, if the
AVR pin is being used as an output that has to sink or
source significant current, this approach wont work
because the series resistor will limit the current available
to whatever the AVR is driving.
An alternative way to handle
this problem is to add logic external to the AVR device
that multiplexes the pins between the normal function
and the ISP function. Of course, this complicates the
design of your circuit.
Sometimes you need more pins
than you have. A means to handle this is shown in Figure
3. Here, one of the pins is pulled high with a resistor.
In normal operation, this pin is used as an output. To
put the device into Calibration mode, the pin is grounded
before power is applied.
 |
| Figure 3Sometimes you need more pins than
the device has, so dual-purpose inputs are handy.
(a) shows using a pin as a calibration input and (b)
shows using an ADC input to read two switches. |
To use this scheme, the software
must check the state of the pin before it programs the
direction register to make the pin an output. If the pin
is high, the code executes normally. If the pin is low
(having been externally grounded to enable calibration)
the code enters the special Calibration mode.
This example used an external
pull-up. You could accomplish the same thing with the
internal pull-up on the port pin. However, these are large
value resistors, so the rise time will be slow and the
software may need to introduce a delay before reading
the pin.
Figure 3b shows how a single
AVR ADC input can be used to read two switches. The analog
input voltage has four different values corresponding
to the four possible states of the switches. The switches
could be configuration switches or user pushbuttons.
The AVR timers fall broadly
into two categories of 8- and 16-bit. All AVR devices
have at least one 8-bit timer and some have two. The 16-bit
timers have more functionality than 8-bit timers do. The
timers can be clocked from the CPU clock using a programmable
pre-scale value or from an external pin.
The simpler AVR timers are
a counter that can be clocked by a (programmable) pre-scale
value from the system clock or be clocked by an external
clock. These counters can be loaded by software and generate
an interrupt when they roll over from FF to 00. These
timers have no provision for a repeatable clock other
than divide by 256. If you want a divisor other than 256,
you have to reload the timer each time the overflow interrupt
occurs. If you are using a /1 or /8 clock pre-scale, this
can make the time period vary by whatever your interrupt
latency variation is, because the interrupt latency can
delay interrupt servicing until one or more timer clocks
have occurred.
Some AVR devices have more
sophisticated 8-bit timers, which essentially add an 8-bit
compare register. When the count reaches the compare value,
the compare register can generate an output or interrupt
the CPU. This allows you to have a regular, repeating
interrupt generated in hardware.
Other AVR devices include
16-bit timers. These include a compare function like the
more complex 8-bit counters. The 16-bit timers also have
an input capture function that captures the value of the
free-running counter when an input pin changes state.
When using input capture, the 16-bit timer can roll over
from FFFF to 0000. The software must take this into account.
The 16-bit timers can switch
an output pin when the output compare occurs. And, they
can generate a PWM output. Of course, any timer function
that uses an external pin makes that pin unavailable for
general-purpose I/O.
External clocking allows
you to operate the timer from a timebase other than the
CPU clock. The external clock is internally synchronized
to the CPU clock, so the external clock cannot be any
faster than the CPU clock. Some versions of the AVR allow
you to run a timer from a 32.768-kHz crystal that is connected
to two pins. This allows you to use the timer as a real-time
clock.
Because the AVR is an 8-bit
processor, the 16-bit timers must be loaded in two operations.
This is accomplished with a temporary register. The software
writes the most significant byte of the register values,
then the hardware stores this value in the temporary register.
The software then writes the least significant byte and
the hardware writes both bytes simultaneously to the timer
registers.
Be careful if interrupts
are used. The 16-bit timers have three registers, the
output compare, input capture, and counter registers.
There is only one temporary register. So, if you use interrupts
and if the interrupts access the 16-bit registers, there
is a potential for a race condition when an interrupt
occurs (see Figure 4).
 |
| Figure 4Lets say the non-interrupt code
wants to write a value of 53D7 hex to the timer registers
and the input capture register contains a value of
2245 hex. (a) shows how its supposed to work
and (b) shows what happens when it doesnt work. |
The timer register gets loaded
with the wrong value because the interrupt occurred between
the two timer writes by the non-interrupt code. The result
is that the interrupt code modified the temporary register
before the non-interrupt code could update the timer registers.
The way to avoid this is to disable interrupts before
the non-interrupt code modifies the timer registers.
As with any design, make
sure the power-up state of the port pins does not damage
your hardware. For instance, if you have two port pins
driving both transistors in an H-bridge, be sure that
the power-up state doesnt turn on both transistors
(see Figure 5).
 |
| Figure 5Take a look at the AVR driving an
H-bridge. Make sure the power-up state of the pins
doesnt turn on both transistors. |
In Figure 5, two port pins
of the AVR drive two MOSFET transistors in one half of
an H-bridge. At powerup, both outputs are pulled high
by the pull-up resistors because the ports come up as
inputs (high impedance). Consequently, both transistors
turn on, making a short between Vcc and ground and probably
destroying one of the transistors. The fix is easy, use
an inverter to make one of the transistors turn on when
the output is low. But it illustrates the potential problem.
Similar cases would include two relays or two motors that
must not be turned on at the same time.
As mentioned earlier, the
AVR processors all have 32 internal registers. Even when
using a device with additional SRAM, many applications
can be implemented by using just the 32 registers. If
youre working in an HLL, the compiler typically
assigns the registers for you. If youre working
in assembly, there are a few things you can do to make
efficient use of the registers.
For example, when defining
the registers youll use, identify variables that
wont be used with immediate instructions and assign
those functions to the first 16 registers. Examples include
counters that will be zeroed, incremented, and decremented,
but never loaded with an immediate value.
Similarly, assign the registers
that need to be used in immediate instructions to one
of the upper 16 registers. If you have a general accumulator
register for some operations, make it one of the upper
16 registers.
If you need several on/off
flag values, dont use a complete register for each
flag. Instead, assign one of the upper 16 registers as
a flag register, assign each bit to be a flag value, and
use the bit set/clear/test instructions to manipulate
individual bits. This can reduce the number of registers
you need.
For fast context switching,
dedicate registers for use in the ISR. By dedicating these
registers, you avoid the time needed to push and pop registers
from the stack. Of course, this wont work if the
ISR needs a lot of dedicated variables or if you have
a lot of interrupts, because you will run out of registers.
|