Академический Документы
Профессиональный Документы
Культура Документы
,$5$SSOLFDWLRQ1RWH$95
(IILFLHQWSURJUDPPLQJRI$WPHO·V
$95PLFURFRQWUROOHUV
6XPPDU\
This application note provides some useful hints on how to program the
Atmel AVR microcontrollers using the IAR Compiler. There is a small
sample program for each topic enclosed with this application note.
.H\ZRUGV
hardware initialization, macros, flash, I/O, I/O registers
:KRVKRXOGUHDGWKLVDSSOLFDWLRQQRWH"
This application note describes some useful tips and tricks on how to program
the Atmel AVR range of microcontrollers. You should know how to:
• Create a project using the IAR Embedded Workbench
• Alter a linker command file (xcl file) to fit the application
• Set up and modify project build options.
You can download application notes on these topics from IAR’s and Atmel’s
websites (www.iar.com and www.atmel.com respectively).
There are also many other application notes on the Atmel AVR range of
microcontrollers at these sites, so check them out!
All C examples included in this application note can be used on the
AT STK200 Starter Kit for the AVR microcontrollers without modification.
The AT90S8515 is used for all samples.
If you intend to use the code samples in your own applications, or if you are
using another AVR device, please remember to make the required changes
(such as including another header file for the I/O definitions).
7RSLFV
This application note covers the following topics:
1. Hardware initialization
2. Using macros for frequently used instructions
3. Using flash library functions (flash keyword)
4. Using I/O registers for global variables.
1
IAR Application Note AVR-007, January 2000
7KHFLUFXLW
All examples presented in this application note use the following circuit:
Note
The complete diagrams of the starter kits for the AVR microcontrollers can be downloaded from
www.avr-forum.com .
/HW·VVWDUWFRGLQJ
1. Hardware initialization
The ATMEL AVR range of microcontrollers has many peripheral functions,
like timers, ports, serial interfaces, sleep modes, and an A/D Converter. All
these peripherals must be initialized prior to using them. This can be done in
different ways as described below.
1.1. Calling a setup function
The easiest way to initialize the controller is to write a function that includes
all setup instructions. The main program then calls this function:
2
IAR Application Note AVR-007, January 2000
int __low_level_init(void)
{
return(1);
}
int __low_level_init(void)
{
// Initialize I/O ports
DDRB = 0xff; // LEDs were connected to PORTB
// all PORTB pins are outputs
PORTB = 0xff; // switch off LEDs
When you use the library function, the hardware is initialized before the main
program starts to execute. The difference between the methods becomes
obvious if you debug the demo projects Tutor_1, which uses the standard
function call, and Tutor_1_1, which uses __low_level_init().
3
IAR Application Note AVR-007, January 2000
8VLQJPDFURVIRUIUHTXHQWLQVWUXFWLRQV
Note
The SBI and CBI assembly instructions operate on the lower 32 I/O registers of the AVR microcontrollers.
When the application has to react on input signals, you must check the I/O
registers. This is done in the following way:
It is also possible to use macros to replace small functions, i.e. functions that
assemble into 3–4 lines or less of assembly code. The compiler generates less
code and gives higher speed when you use macros, as there is no need to call a
function.
4
IAR Application Note AVR-007, January 2000
Note
When using these macros, please alter your header files by commenting out these lines:
#ifdef __IAR_SYSTEMS_ASM
#endif /* __IAR_SYSTEMS_ASM (Bit definitions)*/
8VLQJIODVKOLEUDU\IXQFWLRQV
In nearly all kinds of applications there are some values which do not change
during the execution of the program. A common way to define these constants
is:
These constants are copied to the controller’s SRAM at startup and remain
there during the rest of the program execution. By defining constans this way
you will waste SRAM, because the constants are only accessed by some of
your functions.
A more efficient way to handle constants is to store them in flash memory and
only load them when they are needed. Use the flash keyword to declare the
constants. The constants can be accessed directly or by pointers.
5
IAR Application Note AVR-007, January 2000
For a constant table, which holds the LED pattern for our next example, this
would look as follows:
flash char led_patt[] = {255, 126, 189, 219, 231, 231, 219, 189, 126, 255};
// holds LED data
You can now use all C pointer operations on this pointer, i.e.:
// indirect addressing
PORTB = *patt_pointer;
The enclosed example Tutor_3 shows how to use macros and the flash library
function.
8VLQJ,2UHJLVWHUVIRUJOREDOYDULDEOHV
You should use local variables with the AVR IAR Compiler. This is because
local variables can be allocated in registers, whereas global variables will
always be stored in SRAM.
In some cases variables are global in nature but cannot be declared locally to a
function, e.g. interrupt functions that need to access variables.
Another possible scenario is that some single-bit flags must be stored in one
byte. Using a bitfield for this is not a good idea, because bitfields are not
stored in registers; they are popped and pushed on the stack each time they are
accessed. Because of this, the code generated by using bitfields is not very
efficient or fast.
When you take a look at the AVR’s I/O registers, you will see that there are
some locations which were not used by your application (e.g. your application
is not using the UART). Some of these locations can therefore be used for
storing global variables. This has some advantages compared to storing the
variable in SRAM:
• Directly accessible in a single cycle using one-word instructions
• Setting or clearing single bits using one-word instructions for I/O
registers 0-31
6
IAR Application Note AVR-007, January 2000
• Testing bits using single-cycle bit-test instructions for I/O registers 0-31.
The following example demonstrates the use of the UART baud-rate register
to store bitflags.
First you must define the bitflags. Create a new header file, for example
bit_flag1.h, with the following contents:
// bit definitions
#define MSC_GE7 7
#define MSC_GE6 6
#define MSC_GE5 5
#define MSC_GE4 4
#define MSC_GE3 3
#define MSC_GE2 2
#define MSC_GE1 1
#define MSC_GE0 0
By including the bit_flag1.h header file you can use the bitflags in your
application.
Note
Using names directly associated to your application (i.e. up, down, left, and right for a motion control
application) makes your code more transparent
void testfunction(void)
{
MSCGEFLAGS |= (1<< MSC_GE0); // set bit 0 in UBRR
The following I/O registers can be considered for this purpose, as long as the
corresponding I/O unit is not in use in your application:
• UART baud-rate register (UBRR)
• ADC multiplexer (ADMUX)
• EEPROM data register
• EEPROM address register low byte (EEARL)
• EEPROM address register high byte (EEARH)
• Timer/Counter registers (TCNTx).
Refer to your controller’s data sheet to determine how many bits can be stored
in these registers!
7
IAR Application Note AVR-007, January 2000
Some other registers can also be used, but require special attention. In each
case, you should carefully study the controller’s data sheet to ensure that the
normal operation of the device is not affected by the use of I/O registers for
storing global variables.
6XPPDU\
By using the methods described in this application note you will gain from the
following benefits:
• The hardware is initialized very fast using the __low_level_init() library
function.
• By using macros to replace small functions your code will be smaller and
faster.
To achieve this, perform the following steps:
1. Create a header file that includes all I/O connections of your application
by using the method described in part 4, and make access to the I/Os using
macros. If the design changes, i.e. you will have to use another I/O pin,
you will only need to modify the header file and not the entire program.
2. Use flash library functions when working with constants. This will
decrease the RAM requirement of your application.
3. If your application permits it, use I/O registers to store bit-flags. This will
make the generated code faster and more efficient.