Atmels AVR 8-bit Microcontroller
Prof. Ben Lee
Oregon State University School of Electrical Engineering and Computer Science
Why Microcontrollers?
Ratio of Embedded Devices / Desktop PCs is greater than 100. The typical house may contain over 50 embedded processors. A high-end car can have over 50 embedded processors. Embedded systems account for the most of the worlds production of microprocessors!
Why AVR Microcontroller?
The most popular 8-bit processor!!
Source: EETimes and Embedded Systems Design Magazine 2006 Embedded Market Survey
Some AVR-based Products
802.15.4/ZigBee LR-WPAN Devices Automotive Applications RFID
Wireless Sensor Networks
Motor Control
Remote Access Controller
USB controller
General Characteristics
RISC (Reduced Instruction Set Computing) architecture.
Instructions same size Load/store architecture Only few addressing modes Most instructions complete in 1 cycle
8-bit AVR Microcontroller
8-bit data, 16-bit instruction Used as embedded controller
Provides convenient instructions to allow easy control of I/O devices.
Provides extensive peripheral features
Timer/counter, Serial UART, Serial interface, etc.
General Architecture
I/O Ports
CPU Core
I/O Ports
ATmega128
Many versions of AVR processors. Our discussion based on ATmega128.
See [Link] See [Link] (373 pages!)
ATmega128 characteristics:
128-Kbyte program memory on-chip 4-Kbyte on-chip SRAM data memory (expandable to 64Kbyte external) 7 I/O ports
Memory
Separate Program Memory and Data Memory.
FLASH memory for program => non-volatile SRAM for data => volatile
Program Memory
0x0000 0x0000 0x001F 0x0020 0x005F 0x0060
Data Memory 32 8-bit GPRs 64 8-bit I/O regs. 160 Ext. 8-bit I/O regs.
Program Flash (64K x 16)
0x00FF 0x0100
Internal SRAM (4096x8)
0xFFFF
0x10FF
16 bits
8 bits
Registers
32 8-bit GPRs (General Purpose Registers)
R0 - R31
16-bit X-, Y-, and Z-register
Used as address pointers
PC (Program Counter) 16-bit SP (Stack Pointer) 8-bit SREG (Status Register) 7 8-bit I/O registers (ports)
GPRs and X, Y, Z Registers
X, Y, Z registers are mapped to R26-R31
Status Register
I T H S V N Z C
I/O Register $3F
I - Global Interrupt Enable T - Bit Copy Storage H - Half Carry Flag S - Sign Bit V - 2s Complement Overflow Flag N - Negative Flag Z - Zero Flag C - Carry Flag
Addressing Modes
Addressing mode defines the way operands are accessed. Gives the programmer flexibility by providing facilities such as
Pointers to memory, counters for loop control, indexing of data, and program relocation
Addressing modes in AVR:
Register (with 1 and 2 registers) Direct Indirect
w/Displacement (also referred to as indexed) Pre-decrement Post-increment
Program Memory Constant Addressing Direct Program Memory Addressing Indirect Program Memory Addressing Relative Program Memory Addressing
Register Addressing (1 register)
Register Addressing (2 register)
Direct Addressing
I/O Direct Addressing
Indirect Addressing
Indirect with Displacement
Indirect with Pre-Decrement
Indirect with Post-Increment
Program Memory Addressing
R0 is the destination register
Indirect Program Addressing
Relative Addressing
Called PC relative jump
AVR Instructions
AVR has 133 different instructions Instruction Types
Data Transfer Arithmetic and Logic Control Transfer (branch/jump) Bit and bit-test
Data Transfer Instructions (1)
MOV - transfers data between two registers.
MOV Rd, Rr
LD - loads data from memory or immediate value (Indirect Addressing):
LD dest, src (Load)
dest = Rd src = X, X+, -X, Y, Y+, -Y, Z, Z+, -Z
LDD
dest, src
(Load with Displacement)
dest = Rd src = Y+displacement, Z+displacement
LDI
Rd, immediate (Load Immediate)
Binary => 0b00001010 Decimal => 10 Hexadecimal => 0X0A, $0A
LDS
Rd, k
(Load SRAM)
Data Transfer Instructions (2)
LPM - load program memory
LPM dest, src
dest = Rd src = Z, Z+
LPM
dest = R0 (implied) src = Z (implied)
ST - stores data to memory
ST dest, src
dest = X, X+, -X, Y, Y+, -Y, Z, Z+, -Z src = Rr
STD
dest, src
dest = Y+displacement, Z+displacement src = Rr
STS
k, Rr
Data Transfer Instructions (3)
IN/OUT - input/output
IN OUT PUSH POP Rd, A A, Rr Rr Rd
PUSH/POP - stack operations
Data Transfer Examples (1)
LD Rd, Y
LD R16, Y; R16 M(Y) Y is implied in the opcode
1000 000d dddd 1001
10000
LDI Rd, K
LDI R30, 0xF0; R30 0xF0 (hexadecimal) Destination register can only be R16-R31 8 bit constant K (0 K 255)
1110 KKKK dddd KKKK
1111
0000
Data Transfer Examples (2)
LDD Rd, Y+q
LDD R4, Y+2; R4 M(Y+2) Y is implied in the opcode 6 bit displacement q (0 q 63)
10q0 qq0d dddd 1qqq
qqqqqq=000010
00100
IN Rd, A
IN R25, $16; R25 I/O($16) $16 is an I/O register connected to Port B (PIN7-PIN0) 6 bit A (0 A 63) => 64 I/O registers.
1011 0AAd dddd AAAA
01
0110
ALU Instructions (1)
Arithmetic instructions ADD/SUB
ADD dest, src dest = Rd src = Rr Also ADC/SBC -> add/subtract with carry
MUL - Multiply unsigned
MUL Rd, Rr R1<-Result(high), R0<-Result(low) Also MULS -> multiply signed
INC/DEC - increment/decrement register CLR/SER - clear/set register
ALU Instructions (2)
Logic instructions AND/ANDI - logical AND & /w immediate
AND ANDI Rd, Rr Rd, immediate
OR/ORI - logical OR & /w immediate
OR Rd, Rr ORI Rd, immediate Also EOR -> exclusive OR
COM/NEG - ones/twos complement
COM TST RD Rd
TST - test for zero or minus
ALU Examples
MUL Rd, Rr
MUL R15, R16; R1:R0 R15 x R16 Both operand unsigned (signed version => MULS) Product high and low stored in R1 and R0, respectively.
1001 11rd dddd rrrr
rrrrr = 10000 ddddd = 01111
Branch Instructions
BRcond - Branch on condition
BRcond address cond = EQ, NE, CS, CC, SH, LO, MI, PL, GE, LT, HS, HC, TS, TC, VS, VC, IE, ID
CP - compare
CP CPC CPI COM TST Rd, Rr Rd, Rr Rd, immediate RD Rd
COM/NEG - ones/twos complement TST - test for zero or minus many more
Branch Example
Example
Branches are PC-relative: if (Z=1) then PC <-PC + address +1 0232 CP R0, R0 ; compare 0233 BREQ SKIP 0234 next inst. 0259 SKIP: 0259H - 0234H = 0025H 1111 BREQ SKIP =>
00kk
kkkk
k001
0100101
Address range => -64 k +63
Jump Instruction
JMP instructions
JMP address Also, RJMP, IJMP
CALL/RET - subroutine call/return
CALL address RET Stack implied Also RETI -> return from interrupt
and few more
Jump Example
Example
Subroutines are implemented using CALL and RET 0230 CALL SUBR SP 0232 next inst.
SP (initially) After CALL Low PC=03F0 High
02 32
03F0
SUBR:
{my subroutine} RET
After RET
CALL is 32-bit instruction
1001 kkkk 010k kkkk kkkk kkkk 111k kkkk SP
02 32
PC=0232
0000001111110000
Bit and Bit Test Instructions
LSL/LSR - Logical Shift Left/Right
LSL ROL Rd Rd
ROL/ROR - Rotate Left/Right through carry SEflag/CLflag - Set/Clear flag
flag = C, N, Z, I, S, V, T, H SEZ => set zero flag
many more
AVR Assembly Directives
Called pseudo opcodes
ORG: tells the assembler where to put the instructions that follow it.
.ORG 0x37
EXIT: tells the assembler to stop assembling the file EQU: Assigns a value to a label.
Syntax: .EQU label = expression .EQU io_offset = 0x23
BYTE: reserves memory in data memory
Syntax: LABEL: .BYTE expression var: .BYTE 1
DB: Allows arbitrary bytes to be placed in the code.
Syntax: LABEL: .DB expressionlist consts: .DB 0, 255, 0b01010101, -128, 0xaa" Text: .DB This is a text.
DW: Allows 16-bit words to be placed into the code
Syntax: LABEL: .DW expressionlist varlist: .DW 0,0xffff,0b1001110001010101,-32768,65535
Addition of 8 Numbers
".include ".ORG "rjmp ".ORG Init_addr: "ldi "ldi "lpm "ldi "ldi Init_acc: "clr "clr Loop: "lpm "add "brcc "inc Skip: "dec "brne Done: "jmp Nums: ".DB Count: ".DB "[Link]" "$0000" "Init_addr" "$000B" "ZL,low(Count<<1) ";" "ZH,high(Count<<1) ";" "R16,Z " "; R16 =8" "ZL,low(Nums<<1) ";" "ZH,high(Nums<<1) "; Z points to 12" "R1 " "; Accumulate the result in R1(H) and R0(L) " "R0 " ";" "R2,Z+ " "; Load data to R2 and post inc. pointer" "R0, R2 " "; Add R2 to R0(L)" "Skip " "; No carry, skip next step " "R1 " "; Add carry R1(H)" "R16 " "; Count down the # words to add" "Loop " "; If not done loop" "Done " "; Done. Loop forever. " " " "12, 24, 0x3F, 255, 0b00001111, 2, 21, 6" "8 ""
Program Memory
" " " 0A " " " " " " " " " " " " " " " " " "000000 "000002 "000004 "000006 "000008 "00000A "00000C "00000E "000010 "000012 "000014 "000016 "000018 "00001A "00001C "00001E "000020 "000022 "000024 " "0AC0 "FFFF "FFFF "FFFF "FFFF "FFFF "F0E0 "E4E3 "0024 "2990 "08F4 "0A95 "0C94 "0C18 "0F02 "0800 "FFFF "FFFF "FFFF " "FFFF" "FFFF" "FFFF" "FFFF" "FFFF "" "ECE3 "" Pointer "0491 Initialization " "F0E0" "1124" "020C " "1394" Main Loop "D1F7" "1800" "3FFF" "1506" Data "FFFF" "FFFF" "FFFF "FFFF" "
C
1100
0
0000
0
0000
A
1010
rjmp Init_addr
""
940C 0018
1001 0000 0100 0000 0000 0001 1100 1000
jmp Done
" " Nums: .db 12, 24, 0x3F, 255, 0b00001111, 2, 21, 6" "" Count: .db 8"
Main Loop
; Assume Z points to the " "" Init_acc: "" "clr "R1 "clr "R0 Loop: "" "lpm "R2,Z+ "add "R0 R2 "brcc "Skip "inc "R1 Skip: "" "dec "R16 "brne "Loop Done: "" "jmp "Done " " " " " first word & R16 points to # of words" "; Accumulate the result in R1(H) and R0(L) " "" "; "; "; "; Load data Add R2 to No carry, Add carry to R2 and post inc. pointer" R0(L)" skip next step " R1(H)"
"; Count down the # words to add" "; If not done loop" "; Done. Loop forever. " " " "" "
"
"
Pointer Initialization
Where are the 8 numbers & number of words stored and how do we point to it? Depends on where data is stored: program memory or data memory." Stored in Program memory as constants:"
".ORG "$000B" "ldi "ZL,low(Count<<1) ";" "ldi "ZH,high(Count<<1) ";" "lpm "R16,Z " " ";R16 =8" "ldi "ZL,low(Nums<<1) ";" "ldi "ZH,high(Nums<<1) ";Z points to 12" "" NUMS: "" ".DB "12, 24, 0x3F, 255, 0b00001111, 2, 21, 6" COUNT: "" ".DB "8 "" low()and high() are macros that extracts low and high byte (defined in [Link])
Pointer Initialization
<< means shift left (multiply by 2)
" " "
Instructions are on ""word (2 bytes) ""boundaries, but data is in bytes!
15 8 7 0 001A 001B 001C
Program Memory
15 87 0
00000000 00110100 Z-Register
NUMS=1A 1A = 00011010 00011010<<1 => 00110100" 12" 0x3F" 0b00001111" 24" 255" 2"
We could have also used high(2*NUMS) and low(2*NUMS)
Data Memory
What if data is not predefined (i.e., constants)? Then, we need to allocate space in data memory using .BYTE. Data memory:"
Nums: "" ".BYTE "8; Sets storage in data memory" Count: "" ".BYTE "1; Data generated on the fly or read in "ldi "YL,low(Count) ";" "ldi "YH,high(Count) ;" "ld "R16,Y " ";R16 =8" "ldi "YL,low(Nums) ";" "ldi "YH,high(Nums) ";Y points to first word" "" "" Loop: "" "ld "R2,Y+ " "; Load data and post inc. pointer" "" " " " " " ""
" ""
""
Result
Registers R1 (H) and R0 (L) hold the result.
12 24 63 (3F) 255 15 (0b00001111) 2 21 6 398 => 018E
R1=01 & R0=8E"
" ""
Testing for Overflow
Suppose we want to detect overflow and call a subroutine (e.g., to print error message)
""
Loop: "" "lpm "R2,Z+ "; Load data to R2 and post inc. pointer" "add "R0, R2 "; Add R2 to R0(L)" "brcc"Skip "; No carry, skip next step " "inc "R1 "; Add carry R1(H)" "brvc"Skip "; If V=0 branch to skip" " " "; (Branch if overflow cleared)" "rcall "ERROR "; We could also use CALL" Skip: "" "" "" ERROR: "" " " "; My subroutine would go here" "RET