AVR035_efficient C coding.pdf
(
125 KB
)
Pobierz
AVR035: Efficient C Coding for AVR
Features
•
•
•
•
•
•
•
•
•
•
•
Accessing I/O Memory Locations
Accessing Memory Mapped I/O
Accessing Data in Flash
Accessing Data in EEPROM
Creating EEPROM Data Files
Efficient Use of Variables and Data Types
Use of Bit-field and Bit-mask
Use of Macros and Functions
Eighteen Ways to Reduce Code Size
Five Ways to Reduce RAM Requirements
Checklist for Debugging Programs
8-bit
Microcontroller
Application
Note
Introduction
The C High-level Language (HLL) has become increasingly popular for programming
microcontrollers. The advantages of using C compared to Assembler are numerous:
reduced development time, easier maintainability and portability, and easier to reuse
code. The penalty is larger code size and as a result of that often reduced speed. To
reduce these penalties the AVR architecture is tuned to efficiently decode and execute
instructions that are typically generated by C compilers.
The C Compiler development was done by IAR systems before the AVR architecture
and instruction set specifications were completed. The result of the co-operation
between the compiler development team and the AVR development team is a micro-
controller for which highly efficient, high performance code is generated.
This application note describes how to utilize the advantages of the AVR architecture
and the development tools to achieve more efficient C code than for any other
microcontroller.
Architecture Tuned for C Code
The thirty two working registers is one of the keys to efficient C coding. These regis-
ters have the same function as the traditional accumulator, except that there are thirty
two of them. In one clock cycle, AVR can feed two arbitrary registers from the Register
File to the ALU, perform an operation, and write back the result to the Register File.
When data are stored in the 32 working registers there are no need to move the data
to and from memory between each arithmetic instruction. Some of the registers can
be combined to 16-bits pointers that efficiently access data in the data and program
memories. For large memory sizes the memory pointers can be combined with a third
8-bit register to form 24-bits pointers that can access 16M bytes of data, with no
paging.
Rev. 1497B–AVR–05/02
1
Addressing Modes
The AVR architecture has four memory pointers that are used to access data and Pro-
gram memory. The Stack Pointer (SP) is dedicated for storing the return address after
return from a function. The C compiler allocates one pointer as parameter stack. The
two remaining pointers are general purpose pointers used by the C Compiler to load and
store data. The example below shows how efficiently the pointers are used for typical
pointer operations in C.
char *pointer1 = &table[0];
char *pointer2 = &table[49];
*pointer1++ = *--pointer2;
This generates the following Assembly code:
LD
ST
R16,-Z
X+,R16
; Pre-decrement Z pointer and load data
; Store data and post increment
The four pointer addressing modes and examples are shown below. All pointer opera-
tions are single-word instructions that execute in two clock cycles.
1. Indirect addressing: For addressing of arrays and pointer variables:
*pointer = 0x00;
2. Indirect addressing with displacement: Allows accesses to all elements in a
structure by pointing to the first element and add displacement without having to
change the pointer value. Also used for accessing variables on the software
stack and array accesses.
3. Indirect addressing with post-increment: For efficient addressing of arrays and
pointer variables with increment after access:
*pointer++ = 0xFF;
4. Indirect addressing with pre-decrement: For efficient addressing of arrays and
pointer variables with decrement before access:
*--pointer = 0xFF
The pointers are also used to access the Flash Program memory. In addition to indirect
addressing with pointers, the data memory can also be accessed by direct addressing.
This gives access to the entire data memory in a two-word instruction.
Support for 16-/32-bit
Variables
The AVR instruction set includes special instructions for handling 16-bit numbers. This
includes Add/Subtract Immediate Values to Word (ADIW, SBIW). Arithmetic operations
and comparison of 16-bit numbers are completed with two instructions in two clock
cycles. 32-bit arithmetic operations and comparison are ready in four instructions and
four cycles. This is more efficient than most 16-bit processors.
2
AVR035
1497B–AVR–05/02
AVR035
C Code for AVR
Initializing the Stack
Pointer
After Power-up or RESET the Stack Pointer needs to be set up before any function is
called. The linker command file determines the placement and size of the Stack Pointer.
The configuration of memory sizes and Stack Pointer setup is explained in application
note “AVR032: Modifying Linker Command Files”.
The AVR I/O Memory is easily accessed in C. All registers in the I/O Memory are
declared in a header file usually named “ioxxxx.h”, where xxxx is the AVR part number.
The code below shows examples of accessing I/O location. The assembly code gener-
ated for each line is shown below each C code line.
#include <io8515.h>
void C_task main(void)
{
char temp;
/* Declare a temporary variable*/
/* Include header file with symbolic names */
Accessing I/O Memory
Locations
/*To read and write to an I/O register*/
temp = PIND;
//
IN
R16,LOW(16)
/* Read PIND into a variable*/
; Read I/O memory
TCCR0 = 0x4F;
//
//
LDI
OUT
R17,79
LOW(51),R17
/* Write a value to an I/O location*/
; Load value
; Write I/O memory
/*Set and clear a single bit */
PORTB |= (1<<PIND2);
//
SBI
/* PIND2 is pin number(0..7)in port */
LOW(24),LOW(2) ; Set bit in I/O
/* Clear ADEN bit in ADCSR register */
ADCSR &= ~(1<<ADEN);
//
CBI
/* Set and clear a bitmask*/
DDRD |= 0x0C;
//
//
//
IN
ORI
OUT
R17,LOW(17)
R17,LOW(12)
LOW(17),R17
LOW(6),LOW(7) ; Clear bit in I/O
/* Set bit 2 and 3 in DDRD register*/
; Read I/O memory
; Modify
; Write I/O memory
/* Clear bit 2 and 3 in ACSR register*/
; Read I/O memory
; Modify
; Write I/O memory
ACSR &= ~(0x0C);
//
//
//
IN
ANDI
OUT
R17,LOW(8)
R17,LOW(243)
LOW(8),R17
/* Test if a single bit is set or cleared */
if(USR & (1<<TXC))
{
PORTB |= (1<<PB0);
//
//
SBIC
SBI
LOW(11),LOW(6) ; Test direct on I/O
LOW(24),LOW(0)
/* Check if UART Tx flag is set*/
3
1497B–AVR–05/02
while(!(SPSR & (1<<WCOL)))
//
//
?0003:SBIS
RJMP
?0003
;/* Wait for WCOL flag to be set */
LOW(14),LOW(6); Test direct on I/O
/* Test if an I/O register equals a bitmask */
if(UDR & 0xF3)
{
}
//
//
//
IN
ANDI
BREQ
R16,LOW(12)
R16,LOW(243)
?0008
; Read I/O memory
; "And" value
; Branch if equal
/* Check if UDR register "and" 0xF3 is non-zero
//?0008:
}
/* Set and clear bits in I/O registers can also be declared as macros */
#define SETBIT(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
#define CLEARBIT(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
/* Macro for testing of a single bit in an I/O location*/
#define CHECKBIT(ADDRESS,BIT) (ADDRESS & (1<<BIT))
/* Example of usage*/
if(CHECKBIT(PORTD,PIND1))
{
CLEARBIT(PORTD,PIND1); /* Clear PIN 1 on PORTD*/
}
if(!(CHECKBIT(PORTD,PIND1)))
{
SETBIT(PORTD,PIND1);
}
/* Set PIN 1 on PORTD*/
/* Test if PIN 1 is cleared*/
/* Test if PIN 1 is set*/
4
AVR035
1497B–AVR–05/02
AVR035
Accessing Memory
Mapped I/O
Some AVR devices include an external data memory interface. This interface can be
used to access external RAM, EEPROM, or it can be used to access memory mapped
I/O. The following examples show how to declare, write and read memory mapped I/O:
#include <io8515.h>
#define reg (* (char *) 0x8004)/* Declare a memory mapped I/O address*/
void C_task main(void)
{
char
xram;
/* Local temp variable
*/
reg = 0x05;
xram = reg;
}
/* Write a value to the memory mapped address*/
/* Read the memory mapped I/O address */
If consecutive memory mapped addresses are accessed the most efficient way to
access them is to declare a constant pointer and add an displacement value to this off-
set. The example below shows how to access memory mapped I/O this way. The
generated assembly code for each instruction is shown in italic.
/* Define the memory mapped addresses
#define data
#define address_high
#define address_low
0x0003
0x0002
0x0001
*/
void C_task main(void)
{
/* Start address for memory map */
unsigned char *pointer = (unsigned char *) 0x0800;
//
//
LDI
LDI
R30,LOW(0)
R31,8
/* Read and modify one address*/
; Init Z-pointer
*(pointer+address_low) |= 0x40;
//
//
//
LDD
ORI
STD
R18,Z+1
R18,LOW(64)
Z+1,R18
; Modify
; Load variable
; Store Back
/* Write an address*/
*(pointer+address_high) = 0x00;
//
STD
Z+2,R30
; Store zero
/* Read an address*/
; Load variable
; Output to port
PORTC = *(pointer+data);
//
//
}
LDD
OUT
R16,Z+3
LOW(21),R16
Note that the Z-pointer is initialized before the memory is accessed, and the LDD and
STD (Load and Store with Displacement) instructions are used to access the data. LDD
and STD are one-word instructions that execute in two cycles. The pointer is only
loaded once. Memory mapped I/O locations can be declared as
volatile
, this indicates
that the variable locations may be modified by hardware and the access will not be
removed by optimization.
5
1497B–AVR–05/02
Plik z chomika:
fred1144
Inne pliki z tego folderu:
tiny11_12s_OLD.pdf
(267 KB)
Осваиваем AVR микроконтроллеры - с чего начать.url
(0 KB)
ARM7_Atmel.zip
(23369 KB)
1129173459.rar
(6869 KB)
1.rar
(4548 KB)
Inne foldery tego chomika:
- Разные
! Осциллограф РАДИОПРОГИ РАСЧЁТЫ СПРАВОЧНИКИ
!avr test
!Измерения и константы
# PIC
Zgłoś jeśli
naruszono regulamin