Skip to content

Instantly share code, notes, and snippets.

@jfamousket
Last active December 18, 2020 13:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jfamousket/6bb36547fbfc2669c87ff7f1cbe47a44 to your computer and use it in GitHub Desktop.
Save jfamousket/6bb36547fbfc2669c87ff7f1cbe47a44 to your computer and use it in GitHub Desktop.
AVR Assembly Programming CheatSheet

Registers:

CPU uses registers to store data temporairly. Most AVRs have 8 bit registers. Two kinds of registers. The General Purpose Registers(GPRs) & I/O registers.

GPRs:

ARVs have 32 general purpose registers. They are R0 to R31. And located in the lowers location of memory address($0000 to $001F). They can be used by all arithmatic and logical instructions.

I/O Registers:

I/O registers are dedicated to special functions such as status register, timers, serial comunications, I/O port, ADC etc. For this reason they are called special functions registers(SFRs). The function of each I/O register is fixed by the CPU designer as they are used to controll the microcontroller or peripheral functions supported by the microcontroller.

Internal SRAM:

Internal SRAM is used for storing data. Each loacation of the SRAM can be accessed directly by its address. Each location is 8 bit wide.

Difference between SRAM and EEPROM

EEPROM stores data permanently. data stays if power is off. SRAM loses data if power is off.

Some Instructions

; is used for comment in assembly programming.

LDI instruction is used to Load a data into a GPR

LDI Rd, k

Load Imidiate value. Load value k into GPR Rd where 16 <= d <= 32. k can be any binary, hexadecimal or decimal number.


LDS instruction is used to load data into GPRs from a memory address

LDS Rd, K

Load from data space. Load Rd with data from a memory address K where 0 <= d <= 32. K is a memory address between $0000 to $FFFF


STS instruction is used to store data to a memory address from GPRs

STS K, Rd

Store directly into memory address K from GPR Rd. Here K is an address of a memory location


ADD instruction is used to add the data of two GPRs

ADD Rd, Rr	       ; Rd = Rd + Rr`

Add register Rd and Rr. And store result in Rd


IN instruction is used to store data into GPRs from I/O registers

IN Rd, A

Retrieve data from I/O register location A and store into the GPR Rd. A is the memory location of the I/O register. 0<= d <= 32, 0<= A <= 63


OUT instruction is used to store value in I/O registers from GPRs

OUT A, Rr

Store GPR Rr's value to an I/O register who's location is A


MOV instruction is used to copy data among GPRs

MOV Rd,Rr		; Rd = Rr

copy data from Rr to Rd.


INC instruction is used to increment data of a register by 1

INC Rd			; Rd = Rd + 1

Increment the value of Rd by 1.


SUB instruction is used to substract one GPR's value from another GPR's value

SUB Rd, Rr		; Rd = Rd - Rr

substarct the value of Rr from the value of Rd and store the result into Rd.


DEC instruction is used to decrement the value of a GPR by 1

DEC Rd			; Rd = Rd - 1

COM instruction is used to make 1's complement of a GPR

COM Rd

invert the bits of Rd and then store the value into Rd


NOP(No Operation) instruction wastes time by spending one CPU cycle without executing any operation.

NOP			; Spend 1 CPU cycle doing nothing

CLR(Clear) instruction is used to clear a register's value or set to zero.

CLR R20		; R20 = 0

DIRECTIVES

.EQU directive is used to define a constant value / Label for some value of address.

.EQU HEXNUM = 0xFF

define HEXNUM as a constant hex value 0xFF


.SET directive is same as .EQU but value assigned by set can be re-assigned leter

.SET HEXNUM = 0xFF

define HEXNUM as a hex value 0xFF


.ORG directive is used to specify start of a ROM location. Where codes will be burnt.

.ORG $0		; Burn From ROM location 0x0

STATUS REGISTER's FLAGS

Bits  D7                             D0
      ---------------------------------
SREG  | I | T | H | S | V | N | Z | C |
      ---------------------------------

C = Carry Flag, This flag is set whenever there is a carry out from the D7 bit after an arithmetic operation(Addition, subtraction, increment, decrement etc). This flag bit is affected after an 8 bit addition or substruction.

Z = Zero Flag, This flag is affected after an arithmetic or logic operation. If the result is zero than Z = 1, else Z = 0.

N = Negative Flag, It reflects the result of an arithmetic operation. If the D7 bit of the result is zero then N = 0 and the result is positive. Else N = 1 and the result is negative.

V = Overflow Flag,

S = Sign Flag,

H = Half Carry Flag, This bit is set if there is a carry from D3 to D4 bit after ADD or SUB instruction.

T = Bit Copy Storage. Used as a temporary storage for bit. It can be used to copy a bit from a GPR to another GPR.

I = Global Inturrupt Enable

CLC(CLear Carry) instruction is used to clear carry bit, C = 0

SEC(SEt Carry) instruction is used to set carry bit, C = 1

BRANCHING INSTRUCTIONS

BRNE (Branch If Not Equal) instruction is used for looping. BRNE instruction uses the zero or Z flag in the status register. CPU jumps to target address if zero flag is low. Z = 0.

LABEL:          ; loop body
   DEC Rn       ; Z flag = 1 if Rn = 0. Decrement Rn untill it becomes zero
   BRNE LABEL   ; Goto LABEL if Rn != 0 that means zero flag = 0

Example: Add 10 times

LDI R16, 10
LDI R20, 0
LDI R21, 20
AGAIN:
    ADD R20, R21
    DEC R16
    BRNE AGAIN

BREQ (BRanch If EQual). CPU jumps to target address if zero flag is High.

AGAIN:
  IN R20, PORTB  ; Load R20 from PORTB
  TST R20        ; Examine R20 and set Z & N flag accordingly
  BREQ AGAIN     ; if Z = 1, goto AGAIN

BRCC (BRanch if Carry Cleared). Branch if C = 0


BRSH (BRanch if Same or Higher) Branch if C = 0


BRLO (BRanch if LOwer) Branch if C = 1

JUMP INSTRUCTIONS

TO DO

PROGRAM COUNTER

TO DO

AVR I/O PORT PROGRAMMING

A powerful feature of AVR I/O ports is their capability of access individual bits of the port without altering the rest of the bits.

32 I/O register's name and their address: $ sign indicates hexadecimal value.

Mem Add I/O Add Name Mem Add I/O Add Name
$20 $00 TWBR $30 $10 PIND
$21 $01 TWSR $31 $11 DDRD
$22 $02 TWAR $32 $12 PORTD
$23 $03 TWDR $33 $13 PINC
$24 $04 ADCL $34 $14 DDRC
$25 $05 ADCH $35 $15 PORTC
$26 $06 ADCSRA $36 $16 PINB
$27 $07 ADMUX $37 $17 DDRB
$28 $08 ACSR $38 $18 PORTB
$29 $09 UBRRL $39 $19 PINA
$2A $0A UCSRB $3A $1A DDRA
$2B $0B UCSRA $3B $1B PORTA
$2C $0C UDR $3C $1C EECR
$2D $0D SPCR $3D $1D EEDR
$2E $0E SPSR $3E $1E EEARL
$2F $0F SPDR $3F $1F EEARH

Following instructions are used to manipulate single bit:

SBI(Set Bit in I/O register) instruction is used to set a bit in I/O register. To make a bit 1.

SBI ioReg, bitNumber  ; ioReg is the name of I/O register, which is any
                      ; lower 32 I/O register. bitNumber(0 - 7) is the
                      ; position of the bit of the register to manipulate

Example:

SBI PORTB, 5      ; This will set the D5(6th) bit of the PORTB register
                  ; to 1. As a result the PB4(5th) pin of Port B will
                  ; output high

CBI(Clear Bit in I/O register) instruction is used to clear a bit in I/O register. To make a bit 0.

CBI ioReg, bitNumber  ; ioReg is the name of I/O register, which is any
                      ; lower32 I/O register. bitNumber is the
                      ; number of the bit of the register to manipulate

Following instructions are used for checking an input pin & make decisions based on the input pin's status.

SIBS(Skip if Bit in I/O register is Set) instruction tests a bit and skip next instruction if it is HIGH.

SIBS ioReg, bitNumber ; Skip next instruction if bitNumber bit of ioReg
                      ; register is HIGH

SIBC(Skip if Bit in I/O register is cleared) instruction tests a bit and skip next instruction if it is LOW.

SIBC ioReg, bitNumber ; Skip next instruction if bitNumber bit of ioReg
                      ; register is LOW

ARITHMETIC & LOGICAL OPERATIONS

Unsigned Number Operations: In this case the sign bit(8th bit) is not taken into account. So numbers can be from 0 to 255.

ADD Rd, Rr

This instruction adds register Rd with Rr and store the number into Rd. Z(Zero), C(Carry), N(Negative), V(Overflow), H(Half Carry), S(Sign) bits of the status register can be affected after this operation.

ADC(Add with carry) instruction is used to add with carry bit. As it add with carry bit, 16 bit addition is possible with ADC instruction. As when adding two 16 bit data operands we need to concerned about the carry out from lower byte to upper byte. Its is called multi byte addition.

Example: Add 0x3CE7 with 0x3B8D

LDI R16, 0x8D   ; R16 = 8D
LDI R17, 0x3B   ; R17 = 3B
LDI R18, 0xE7   ; R18 = E7
LDI R19, 0x3C   ; R19 = 3C

ADD R18, R16    ; R18 = R18 + R16 = E7 + 8D = 74 with C = 1(Carry Out)
                ; ADD instruction is used for lower byte as carry is
                ; not a concern here

ADC R19, R17    ; R19 = R19 + R17 + C(Carry out from previous operation)
                ; 	  = 3C + 3B + 1
                ;	    = 78
                ; ADC instruction is used as carry is a concern for upper
                ; byte
                ; Result: 7874. R19 = 78, R18 = 74

There are five instrtuctions for substraction in AVR.

  • SUB(Subtract)
  • SBC(Subtruct with borrow)
  • SBI(Subtract immediate)
  • SBCI(Subtract immediate with borrow)
  • SBIW(Subtract a immediate value from register pair)

C flag is used for borrow.

Subtraction Instruction Summary:

SUB Rd, Rr      ; Rd = Rd - Rr.	Borrow is not a concern for this instruction

SBC Rd, Rr      ; Subtract with Borrow. Rd = Rd - Rr - C . In this case
                ; C flag is checked for Borrow. This instruction is useful
                ; for 16 bit subtraction.

SUBI Rd, K      ; Subtract a value K from Rd without borrow. Rd = Rd - K.

SBCI Rd, K      ; Subtract a value K from Rd with borrow. Rd = Rd - K - C
                ; In this case C flag is checked for borrow.

SBIW Rd:Rd+1, K ; Subtract a value K from Rd+1:Rd register pair.

In AVR(And most other CPUs) subtraction is done using 2's complement. Separate circuitry isn't used for subtraction as it takes too many transistors. Assuming that the AVR is executing a simple subtractions and C = 0 prior to this execution. The steps of SUB instruction for unsigned numbers are following:

  1. Take 2's complement of the righthand operator
  2. Add it with the lefthand operator.
  3. Invert the carry. Notice that carry is inverted after above operations.

Example: Subtract 0x23 from 0x3F

LDI R20, 0x23		; R20 = 0x23
LDI R21, 0x3F		; R21 = 0x3F
SUB R21, R20		; R21 = R21 - R20

There are 3 Multiplication instruction in AVR.

MUL Rd, Rr      ; Multiply two unsigned numbers
MULS Rd, Rr     ; Multiply two signed numbers
MULSU Rd, Rr    ; Multiply signed number with unsigned number

Result is stored in R1(Higher byte) and R2(Lower byte) registers.

LDI R23, 0x25   ; R23 = 0x25
LDI R24, 0x65   ; R24 = 0x65

MUL R24, R23    ; R24 * R23 = 0x65 * 0x25 = 0xE99
                ; R1 = 0x0E, R2 = 0x99

There is no division instruction. But division can be done by repeated subtraction. To divide 95 with 10. Subtract 10 from 95, 9 times. The result is 05. So the quotient is 9 and remainder is 5.

So to divide in this method numerator is kept in a register. And the denuminator is subtracted repeatedly. So the quotient is the number of times subtracted. And the remainder is in the register.

Example: devide 95 by 10

.DEF NUM = R20       ; Define R20 as NUM
.DEF DENUM = R21     ; Define R21 as DENUM
.DEF QUOTIENT = R22  ; Define R22 as QUOTIENT

LDI NUM, 90
LDI DENUM, 10
CLR QUOTIENT

L1:
    INC QUOTIENT    ; Increment QUOTIENT
		SUB NUM, DENUM  ; Subtact DENUM from NUM
		BRCC L1         ; Branch if Carry is Cleared. C = 0. After repeated
                    ; subtraction if the result is negative C = 1. And the
                    ; branching / looping will be stopped.

		DEC QUOTIENT    ; As once too many
		ADD NUM, DENUM  ; add back to it

Signed Numbers: For signed numbers the most significant bit(D7 bit for 8 bit number) is reserved for sign. And number is represented by other bits. 0 in the D7 bit indicates positive number & 1 indicates negative number.

Positive Number: for positive number D7 = 0. So the range of positive number is from +1 to +127.

Negative Number: For negative number D7 = 1. Negative numbers are represented using 2's complement. To find the binary representation of a negative number first write the magnitude of the number in the 8 bit format. Now take 2's complete of that. It will be the binary of the negative number of that magnitude. ; For example binary of -5 is 11111011. Binary of 5 in 8 bit format is 00000101. Take 2's complement. Its 11111011. So its the binary of -5. Notice that the D7 bit is 1. its indicating that the number is negative.


Overflow & V flag: TO DO


Difference between N & S flag: TO DO


Logic AND operator:

AND Rd, Rr		; Rd = Rd & Rr
ANDI Rd, K		; Rd = Rd & K

AND effects N, Z, S flags. N is the D7 bit of the result. Z = 1 if the result is zero.

AND is often use to mask(Set to zero) bit. For example say I want to mask the D5 & D6 bits of 01100011. I can AND it with 10011111.

LDI R16, 0x63   ; R16 = 0x63 = 0b01100011
ANDI R16, 0x9F  ; 0x63 & 0x9F = 01100011 & 10011111 = 00000011 = 0x03
                ; R16 = 0x03

Logic OR operator:

OR Rd, Rr		; Rd = Rd | Rr
ORI Rd, K		; Rd = Rd | K

OR effects N, Z, S flags. N is the D7 bit of the result. Z = 1 if the result is zero.

OR is often used to set certain bits to 1. For example say I want to set the D3 & D4 bit of the 01100101 to 1. I can OR it with 00011000.

LDI R16, 0x65 ; R16 = 0x65 = 0b01100101
ORI R16, 0x18 ; 0x65 | 0x18 = 01100101 | 00011000 = 01111101 = 0x7D
              ; R16 = 0x7D

Logic exclusive or XOR:

XOR Rd, Rr		; Rd = Rd XOR Rr

XOR effects N, Z, S flags. N is the D7 bit of the result. Z = 1 if the result is zero.

XOR can be used to check equality of two registers. If two registers are equal then the result of XOR of them will be zero. So Z will be set to 1. And we can take decision based on that.

another application of XOR can be toggling the bits. 10101010 XOR 11111111 = 01010101


Logic Inverter / Complement COM:

LDI R20, 0xAA ; R20 = 0xAA = 10101010
COM R20       ; R20 = 0x55 = 01010101

Negation / 2's complement NEG:

LDI R20, 0x56 ; R20 = 0x56 = 01010110 = 86 in decimal
NEG R20       ; R20 = 2's complement of 0x56 = 10101001 + 1 = 10101010 = 0xAA = -86 in decimal

Compare Instruction CP:

CP Rd, Rr   ; Compare Rd with Rr
CPI Rd, K   ; Compare Rd with imediate value K

compare instruction is really a subtraction except it doesn't change the left hand operator.

Compare instruction affects Z, C & S flags. Different branching instruction can be used based on this.

After CP instruction Z = 0 means operands are not equal. Z = 1 means operands are equal.

After CP instruction for unsigned numbers C = 0 means left hand operand is same or higher than the right hand operator. C = 1 means left hand operator is lower

After CP instruction for signed numbers S = 0 means left hand operand is greater than or equal. S = 1 means left hand operand is less than the right hand operand.


Branching Instructions: There are several branching instructions in AVR. Here is most frequently used instructions

BREQ LABEL    ; BRanch if EQual zero. Branch to LABEL if the result
              ; of the previous
              ; instruction is zero( Z = 1 ). For example if the two
              ; operands are equal in CP instruction.

BRNE LABEL    ; BRanch if Not Equal zero. Branch to LABEL if the result
              ; of the previous
              ; instruction is not zero( Z = 0 ). For example if the two
              ; operands are not equal in CP instruction.

BRSH LABEL    ; BRanch if Same or Higher. Branch to LABEL if C = 0
              ; after previous instruction. For example if the left hand
              ; operand is same or higher in CP instruction. Can be used for
              ; unsigned numbers

BRLO LABEL    ; BRanch if LOwer. Branch to LABEL if C = 1
              ; after previous instruction. For example if the left hand
              ; operand is lower in CP instruction. Can be used for
              ; unsigned numbers

BRGE LABEL    ; BRanch if Greater than or Equal. Branch to LABEL if S = 0
              ; after previous instruction. For example if the left hand
              ; operand is greater than or equal in CP instruction. Used
              ; for signed numbers

BRLT LABEL    ; BRanch if Less Than. Branch to LABEL if S = 1
              ; after previous instruction. For example if the left hand
              ; operand is less than right hand operand in CP instruction.
              ; Used for signed numbers.

BRCS LABEL    ; BRanch to LABEL if Carry is Set. C = 1

BRCC LABEL    ; BRanch to LABEL if Carry is Cleared. C = 0

BRVS LABEL    ; BRanch if V flag is Set. Branch to LABEL if overflow
              ; happens(V = 1)

BRVC LABEL    ; BRanch if V flag is Cleared. Branch to LABEL if overflow
              ; does not happen(V = 0)

Some example of branch instructions: TO DO


Rotational & Shift Instruction:

ROR(Rotate right) instruction rotate 1 bit from left to right through carry. As rotate from left to right after rotate command the carry flag enters to MSB and LSB exits to carry.

ROR Rd          ; Rotate Rd right through carry

Example

CLC             ; Clear carry C = 0
LDI R20, 0x26   ; R20 = 0x26 = 0b00100110
ROR R20         ; R20 = 00010011	C = 0
ROR R20         ; R20 = 00001001	C = 1
ROR R20         ; R20 = 10000100	C = 1

ROL(Rotate Left) instruction rotate 1 bit from right to left through carry. As rotate from right to left after rotate command the carry flag enters to LSB and MSB exits to carry.

ROL	Rd         ; Rotate Rd left through carry

; Example

SEC				    ; Set carry C = 1
LDI R20, 0x15	; R20 = 0x15 = 00010101
ROL R20			  ; R20 = 00101011	C = 0
ROL R20			  ; R20 = 01010110	C = 0
ROL R20			  ; R20 = 10101100	C = 0
ROL R20			  ; R20 = 01011000	C = 1

There are three logical shift operator in AVR:

LSL(Logical Shift Left) instruction shifts bits from right to left. After shift instruction 0 is entered into LSB and MSB exits to carry. Notice shift instruction multiply the content of the register by 2.

CLC             ; Clear carry C = 0
LDI R20, 0x26   ; R20 = 0x26 = 00100110 = 38
LSL R20         ; R20 = 01001100 = 76	C = 0
LSL R20         ; R20 = 10011000 = 152	C = 0
LSL R20         ; R20 = 00110000 = 48	C = 1
                ; Notice not multiplied as C = 1, overflow

LSR(Logical Shift Right) instruction shifts bits from left to right. After shift instruction 0 is entered into MSB and LSB exits to carry. Notice shift instruction devides the content of the register by 2.

CLC             ; Clear carry C = 0
LDI R20, 0x26   ; R20 = 0x26 = 00100110 = 38
LSR R20         ; R20 = 00010011 = 19	C = 0
LSR R20         ; R20 = 00001001 = 9	C = 1
LSR R20         ; R20 = 00000100 = 4	C = 1

ASR(Arithmetic shift right) istruction can devide signed numbers by two. As ASR can shift bits to right without altering MSB. LSB exits to carry.

CLC             ; C = 0
LDI R20, 0xD0   ; R20 = 11010000 = -48
ASR R20         ; R20 = 11101000 = -24	C = 0
ASR R20         ; R20 = 11110100 = -12	C = 0
ASR R20         ; R20 = 11111010 = -6	C = 0
ASR R20         ; R20 = 11111101 = -3	C = 0
ASR R20         ; R20 = 11111110 = -1	C = 1

SWAP instruction swaps the nibble of a byte.

SWAP Rd				; Swaps nibble of Rd register where 0 <= d <= 31
Before: |D7|D6|D5|D4|D3|D2|D1|D0|
After:	|D3|D2|D1|D0|D7|D6|D5|D4|

ADDRESS MODE

CPU can access data in various ways. The data could be in registers, in memory or provided as a direct value. These various ways of accessing data is called addressing modes. AVR supports 13 distinct address modes. They can be catagorized into following groups:

  1. Single Register or Immediate address mode(Only single register is involved)
  2. Two Register addressing mode
  3. Direct address mode(Memory is accessed by their direct addresses)
  4. Indirect address mode(Memory is accessed by using registers as pointers pointing to memory)
  5. Flash Direct address mode(Direct access to flash rom by flash memory addresses)
  6. Flash Indirect address mode (Accessed using pointers)

Single register address mode: In this address mode operand is single register. imediate values can be used in this address mode. So its called immediate address mode too. Registers from R16 to R31 can be used in this address mode.

Example:

NEG R16               ; Negate R16 contents
COM R16               ; Take complement
DEC R16               ; Decrement R16's content by 1
INC R16               ; Increment R16's content by 1

LDI R16, 0xFF         ; Load R16 with immediate value
ADI R16, 0x05         ; Add R16 with an immediate value
ANDI R16, 0b00100101  ; AND R16 with 0x25
  • These are 16 bit instructions.
  • In instructions involving only register: 12 bit for opcode & 4 bit for register's address.
  • In insstructions with immediate values: 4 bits for opcode, 8 bits for immediate value & 4 bits for register's address.

Two register address mode: Instructions involving two registers.

Example:

ADD R16, R17		; R16 = R16 + R17
MOV R16, R17		; Move content of R17 to R16
  • 16 bits instructions.
  • 6 bits for opcode, 5 bits for left hand register & 5 bits for right hand register.

Direct address mode: In this address mode content of RAM memory or I/O registers are accessed by their direct addresses.

Example:

LDS R16, 0x200		; Load R16 with the contents of location $200
STS 0x305, R20		; Save R20's contents is RAM location $305

I/O registers can be accessed by their direct memory address or their direct I/O address. Direct memory address is used in direct memory instructions & I/O addressing is used in I/O instructions. For example following two instructions are same:

OUT 0x18, R16   ; 0x18 is the I/O address of port B.
                ; This instruction is sending content of R16 to port B.
STS 0x38, R16   ; 0x38 is the memory address of port B.
                ; This instruction also sending content of R16 to port B.

I/O instructions are faster than memory instructions. also I/O registers name can be used instead of address. These names are defined in .INCLUDE file. Its safer and portable. As I/O addresses can be different in different AVR.

OUT PORTB, R16   ; Send contents of R16 to port B

In memory instructions 16 bit is reserved for memory location. So from $0000 to $FFFF locations of memory can be addressed. So 65536 bytes of data from RAM can be accessed. In I/O instructions address field is 6 bits. So from $00 to $3F addresses can be accessed. So total 64(0 to 63) I/O registers can be accessed. These are standard I/O register memory space.

In some AVRs there is more than 64 I/O registers. These extra I/O registers are called extended I/O registers. As in I/O direct addressing mode address space is 6 bits, extended I/O registers can't be accessed via I/O direct addressing mode. For these direct memory addressing mode have to be used.

STS 0x62, R20   ; Save content of R20 in PORT F, which is an extended I/O
                ; register in ATmega128

Indirect memory addressing:

  • X pointer is mapped to R26(low byte, XL) & R27(hight byte, XH)
  • Y pointer is mapped to R28(low byte, YL) & R29(hight byte, YH)
  • Z pointer is mapped to R30(low byte, ZL) & R31(high byte, ZH)

LD instruction is used to read from the location pointed to by pointer. For example to read from location pointed by X:

LD R16, X   ; Load R16 with the content of data memory location
            ; pointed to by X

Load the content of data memory location 0x302 into R20:

LDI XL, 0x02    ; Load R26(Lower byte of X) with 0x02
LDI XH, 0x03    ; Load R27(Higher byte of X) with 0x03.
                ; So, Now X is pointing to 0x302

LD R20, X       ; Load R20 with content of location 0x302
                ; which is pointed to by X

ST instruction is used to store a value into a location pointed to by a pointer.

Example: Store the content of R20 into location 0x139F

LDI XL, 0x9F    ; Load XL with lower byte of the address
LDI XH, 0x13    ; Load XH with higher byte of the address
ST X, R20       ; Store the content of R20 into location
                ; pointed to by X, 0x139F

Auto increment: Incrementing pointer's lower byte with INC instruction has a problem. If the address is 0x1FF, if we increment XL, carry will not propagate into XH. In this case we can use auto increment feature:

LD Rn, X+     ; Load Rn with the content of memory location pointed to
              ; by X and then increment X to point to the next location.
              ; In this case if there is a carry from lower byte of
              ; the address, carry will be propagate to higher byte.

Indirect addressing with displacement: Suppose we want to read / write from a few bytes higher than where Z is pointing. In that case we can use indirect addressing with displacement. LDD & STD instruction is used for indirect addresing with displacement.

LDD Rn, Z+q			; Load Rn with the contents of memory location pointed to by Z+q
STD Z+q, Rn			; Store content of Rn into location pointed to by Z+q

Example: Store 0x55 into location 0x401 & 0x405

LDI R20, 0x55
LDI ZL,  0x01
LDI ZH,  0x04

ST  Z,   R20
STD Z+4, R20

Look up table: TO DO


Manipulating the bits of I/O Registers


Setting & Clearing Bit: To set and clear lower 32 I/O register(I/O address 0 to 31) we can use SBI( Set Bit in I/O Register ) and CBI( Clear Bit in I/O Register ) instruction.

SBI PORTA, 1			; Set bit 1 of PORTA
CBI PORTB, 5			; Clear bit 5 of PORTB

Example: Toggle PB2 200 times

SBI DDRB, 2         ; PB2 is output
LDI R16, 200

LOOP:
      SBI PORTB, 2  ; PB2 is HIGH
      CBI PORTB, 2  ; PB2 is LOW

      DEC R16
      BRNE LOOP

HERE: RJMP HERE    ; Infinite Loop

Checking the bits of I/O Registers: To check if the bit of a I/O register is set or cleared we can use SBIS(Skip next instruction if Bit in I/O register is Set) andSBIC(Skip next instruction if Bit in I/O register is Cleared).

Example: A switch is connected to pin PC7. Check the status of switch. If switch is HIGH send 'Y' to Port D. Else send 'N' to Port D.

CBI DDRC, 7         ; PC7 is input pin

LDI R16, 0xFF
OUT DDRD, R16       ; Port D is output

LOOP:
      SBIS PINC, 7  ; Skip next if PC7 is HIGH
      RJMP SHOWN
      LDI R16, 'Y'
      OUT PORTD, R16
      RJMP LOOP
SHOWN:
      LDI R16, 'N'
      OUT PORTD, R16
      RJMP LOOP

Status Register's Bit Addressability


Status Reguster:

Bit:  D7                             D0
      ---------------------------------
SREG: | I | T | H | S | V | N | Z | C |
      ---------------------------------

I = Global Interrupt    V = Overflow Flag
T = Bit Copy            N = Negative Flag
H = Half Carry          Z = Zero Flag
S = Sign Flag           C = Carry Flag

Manipulating Status Register's Bits: BSET and BCLR instruction can be used to set and clear the bit of a status register.

BSET s			; Set the bit s of status register
BCLR s			; Clear the bit s of status register

Example:

BSET 0			; Set carry flag, C = 1
BCLR 1			; Clear Zero flag Z = 0

There are also dedicated instructions for setting and clearing each flags. Shown in the following table:

Instruction Action Instruction Action
SEC Set Carry, C = 1 CLC Clear Carry, C = 0
SEZ Set Zero, Z = 1 CLZ Clear Zero, Z = 0
SEN Set Negative, N = 1 CLN Clear Negative, N = 0
SEV Set Overflow, V = 1 CLV Clear Overflow, V = 0
SEH Set Half Carry, H = 1 CLH Clear Half Carry, H = 0
SES Set Sign, S = 1 CLS Clear sign, S = 0
SET Set Temporary, T = 1 CLT Clear Temporary, T = 0
SEI Set Global Interrupt, I = 1 CLI Clear Global Interrupt, I = 0

Checking Status Register Bits: BRBS(Branch if status register Bit is Set) and BRBC(Branch if status register Bit is Cleared) instruction can be used to examine status register flags and take decisions according to their value.

BRBS s,k		; Branch if bit s is set and go to relative address k
BRBC s,k		; Branch if bit s is cleared and go to relative address k

Example:

BRBS 0, L1    ; Branch if bit 0 of SREG is set and goto L1
LDI R17, 0xFF ; Otherwise insert 0xFF into R17

L1:           ; address L1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment