Working with Bits and Bytes: Logic Instructions and Programs

READING

The AVR Microcontroller and Embedded Systems using Assembly and C
by Muhammad Ali Mazidi, Sarmad Naimi, and Sepehr Naimi

Sections: 5.3, 5.4, 5.5

Table of Contents

OVERVIEW

Clearing and Setting a Bit In …

Where Instruction Alternative Notes
I/O (0 – 31) cbi, sbi Use with I/O Ports
SREG cl{i,t,h,s,v,n,z,c}

se{i,t,h,s,v,n,z,c}

bclr

bset

Working with General Purpose Register Bits
Clearing and Setting a Byte clr, ser
Clearing Bits and, cbr andi
Testing Bits and  Also consider using sbrc, sbrs, sbic, sbis (see Control Transfer Lecture)
Testing a Bit bst  brts, brtc
Testing a Byte tst  breq, brne
Setting Bits or, sbr  ori
Inserting a Bit Pattern cbr  sbr and  or
Complementing (Toggling) Bits eor
Rotating Bits rol, ror
Shifting Bits lsl, lsr, asr
Swapping Nibbles swap

SAMPLE APPLICATION – KNIGHT RIDER

Figure 1: Knight Rider Poster

KnightRider:

; See page 5 and 6 – Clearing and Setting Bits

clr r16 // start with r9 bit 6 set – LED 6
sbr r16, 0b10000000

; Q1: How could we have done this using 1 instruction?

ldi r17,(1<<sreg_t) equivalent=”” to=”” 0b01000000<=”” span=””></sreg_t)>

; See page 7 – Clearing and Setting a Bit in the AVR Status Register

clt // initialize T = 0, scan right

; See page 8 – Testing Bits
loop:

ldi r19, 0b100000001
and r19,r16 // test if LED hit is at an edge
breq contScan // continue scan if z = 0

; See page 9 – Toggling Bits

in r16,SREG // toggle T bit
eor r16, r17
out SREG,r16

; See page 10 – Rotating and Shifting Bits
contScan:

brts scanLeft // rotate right or left
lsr r16
rjmp cont

scanLeft:

lsl r16

cont:

mov spiLEDS, r16
call WriteDisplay
rcall Delay
rjmp loop

SAMPLE APPLICATION – BICYCLE LIGHT

Figure 2: Bicycle Light

A bicycle light has 5 LEDs.

BicycleLight1: A repeating pattern starts with the center LED turned ON. The center LED is then turned OFF, and the LEDs to the left and right of the center LED are turned ON. Each LED continues its scan to the left or right. Once the LEDs reach the end the pattern repeats itself. Using the CSULB shield, write a program to simulate this bicycle light.

BicycleLight2: Same as Bicycle1 except when LEDs reach the edge, they scan back to the center.

BicycleLight1:

clr r7 // turn off 7 segment

begin: ldi r16, 0x04 // scan register r16 = 4

mov r17, r16 // scan register r17 = 4
scan: mov r8, r16 // do not modify r16
cbr r17, 0x20 // r17 bit 5 = 1 at end of cycle
or r8, r17 // combine scan registers
rcall Delay
call WriteDisplay
lsr r16 // scan r16 right
lsl r17 // scan r17 left, r17 = 0 at end of cycle
brne scan // if r17 <> 0 then continue scan
rjmp begin // else start next cycle

BicycleLight2:

ldi r16, 0x08 // 000|0_1000 start just in from edges
ldi r17, 0x02 // 000|0_0010

scan: mov r8, r16

or r8, r17
rcall Delay
call WriteDisplay
lsl r17 // scan r17 left
lsr r16 // scan r16 right
brcc scan
rjmp BicycleLight2

CLEARING BITS

To clear a bit set the corresponding mask bit to 0
and source/dest register, mask register

Figure 3: AND Truth Table Where ‘A’ Determines Which Bit to Clear

Problem: Convert numeric ASCII value (‘0’ – ‘9’) to its
binary coded decimal (BCD) equivalent (0 – 9).

  • What we have: ‘0’ to ‘9’ which equals 3016 to 3916
  • What we want: 0 to 9 which equals 0016 to 0916

Solution: Mask out high-order nibble
lds r16, ascii_value
ldi r17, 0x0F
and r16, r17 // or simply andi
sts bcd_value, r16

An alternative to the and instruction is the Clear Bits in Register cbr instruction.

cbr source/dest register, mask bits

The cbr instruction clears the specified bits in the source/Destination Register (Rd). It performs the logical AND between the contents of register Rd and the complement of the constant mask (K). The result will be placed in register Rd.

Rd  Rd ∙ (0xFF – K)

Here is how the previous problem would be solved using the cbr instruction.

lds r16, ascii_value
cbr r16, 0xF0
sts bcd_value, r16

SETTING BITS

To set a bit set the corresponding mask bit to 0
or source/dest register, control register

Figure 4: OR Truth Table Where ‘A’ Determines Which Bit to Set

Example: Set to one (1) bits 4 and 2 in some port.
in r16, some_port
ldi r17, 0b00010100
or r16, r17 // or simply ori
out some_port, r16

An alternative to the or instruction is the Set Bits in Register sbr instruction.

sbr source/dest register, mask bits

The sbr instruction sets the specified bits in the source/Destination Register (Rd). It performs the logical ORI between the contents of register Rd and the constant control (K). The result will be placed in register Rd.

Rd  Rd + K

Here is how the previous problem would be solved using the cbr instruction.

in r16, some_port
sbr r16, 0b00010100
out some_port, r16

CLEARING AND SETTING A BIT IN THE AVR STATUS REGISTER

Figure 5: Status Register

AVR Instructions for Clearing and Setting SREG bits
cl{i,t,h,s,v,n,z,c} or bclr SREG_{I,T,H,S,V,N,Z,C} // defined in m328Pdef.inc
se{i,t,h,s,v,n,z,c} or bset SREG_{I,T,H,S,V,N,Z,C} // defined in m328Pdef.inc

Examples:
Disable all Interrupts

cli

Set T bit

set

TESTING BITS

Use the andi instruction to test if more than one bit is set
andi source/dest register, mask bits

Figure 6: By Setting ‘A,’ the Tested Bit Reveals if the Source Bit was Set

Example 1: Branch if bit 7 or bit 0 is set

// 7654 3210

lds r16, some_bits // 1000 0000  example
andi r16, 0b10000001 // 1000 0001
brbc SREG_Z, bit_set // 1000 0000 (alt. brne)

Example 2: Branch if bit 4 and bit 2 are clear

// 7654 3210

lds r16, some_bits // 1101 1001  example
andi r16, 0b00010100 // 0001 0100
brbs SREG_Z, bits_zero // 0001 0000 (alt. breq)

Consider using one of the “Skip if Bit” instructions if you only need to test one bit.

Review “Control Transfer” lecture material for details.

Use the tst instructions to test if a register is Zero or Minus.

Tests if a register is zero or negative. Performs a logical AND between a register and itself. The register will remain
unchanged.

Example: Branch if bear is in the forest
rcall inForest // returns false(r24 = 0) if bear is not in the forest
tst r24
breq not_in_forest // branch if r24 = 0

TOGGLING BITS

To toggle (complement) a bit set the corresponding mask bit to 1
eor source/dest register, mask register

Figure 7: EOR/XOR Truth Table Where ‘A’ Determines Which Bit to Toggle

Example: Toggle bits 5 and 3 of I/O-Port D.

//7654 3210

in r16, PORTD // 1101 1001  example
ldi r17, 0x28 // 0010 1000
eor r16, r17 // 1111 0001
out PORTD, r16

When toggling an I/O-Port bit, consider writing a one to the corresponding pin.

Review “AVR Peripherals” lecture material for details.

Example: Toggle bits 5 and 3 of I/O-Port D.
sbi PIND, PIND5 // equivalent to sbi 0x09, 5
sbi PIND, PIND3

When toggling a byte (8 bits), use the Complement instruction.

Example: Write TurnAround code snip-it (i.e., toggle SRAM variable dir)

// 7654 3210

lds r16, dir // 1101 1001  facing East
com r16 //_____ 0010 0110  facing West
cbr r16, 0xFC //1111 1100 clear unused bits (optional)
sts dir, r16 // 0000 0010

Question: How could you have complemented dir without modifying the other 6 bits?

ROTATING AND SHIFTING BITS

Rotate Instructions allow us to rearrange bits without losing information and to sequentially test bit (brcc, brcs). Shift instructions allow us to quickly multiply and/or divide signed and/or unsigned numbers by 2.

Figure 8: Rotate Left Diagram

Rotate Left through Carry

rol Rd

Shifts all bits in Rd one place to the left. The C Flag is shifted into bit 0 of Rd. Bit 7 is shifted into the C Flag. This operation, combined with LSL, effectively multiplies multi-byte signed and unsigned values by two.

Figure 9: Rotate Right Diagram

Rotate Right through Carry
ror Rd

Shifts all bits in Rd one place to the right. The C Flag is shifted into bit 7 of Rd. Bit 0 is shifted into the C Flag. This operation, combined with ASR, effectively divides multi-byte signed values by two. Combined with LSR it effectively divides multibyte unsigned values by two. The Carry Flag can be used to round the result.

Figure 10: Logical Shift Left Diagram

Logical Shift Left (Arithmetic Shift Left)
lsl Rd

Shifts all bits in Rd one place to the left. Bit 0 is cleared. Bit 7 is loaded into the C Flag of the SREG. This operation effectively multiplies signed and unsigned values by two.

Figure 11: Logical Shift Right Diagram

Logical Shift Right
lsr Rd

Shifts all bits in Rd one place to the right. Bit 7 is cleared. Bit 0 is loaded into the C Flag of the SREG. This operation effectively divides an unsigned value by two. The C Flag can be used to round the result.

Figure 12: Arithmetic Shift Right Diagram

Arithmetic Shift Right
asr Rd

Shifts all bits in Rd one place to the right. Bit 7 is held constant. Bit 0 is loaded into the C Flag of the SREG. This operation effectively divides a signed value by two without changing its sign. The Carry Flag can be used to round the result.

CLEARING AND SETTING A BIT IN ONE OF THE FIRST 32 I/O REGISTERS

Example: Pulse Clock input of Proto-Shield Debounce D Flip-flop (PORTD5). Assume currently at logic 0.

sbi PORTD, 5
cbi PORTD, 5

Figure 13: Address Table

SETTING A BIT PATTERN

Use the Clear Bits in Register cbr or functionally equivalent andi instruction in combination with the Set Bits in Register sbr to set a bit pattern in a register.

Problem: Convert a binary coded decimal (BCD) (0 – 9) number to its ASCII equivalent value (‘0’ – ‘9’).

  • What we have: 0 to 9 which equals X016 to X916
    The X indicates that we do not know what is contained in this nibble.
  • What we want: ‘0’ to ‘9’ which equals 3016 to 3916

Solution: Set high-order nibble to 316
lds r16, bcd_value
andi r16, 0x0F // clear most significant nibble
sbr r16, 0x30 // set bits 5 and 4
sts ascii_value, r16

What is Happening

QUESTIONS

  1. What instruction is used to divide a signed number by 2?
  2. What instruction is used to multiply an unsigned number by 2?
  3. What instruction(s) would be used to convert a word pointer into a byte pointer? A word pointer is a register pair like Z containing the address of a 16-bit data (2 byte) word in an SRAM Table. A byte pointer is a register pair like Z containing the address of an 8-bit data byte in a corresponding SRAM Table. Assuming there is a one-to-one relationship between each word in the first table with a byte in the second table. And remembering that SRAM is always addressed at the Byte level, how would convert a pointer defined for the word table into a pointer defined for the byte table.

Appendix

APPENDIX A: KNIGHT RIDER OPTIMIZED

.INCLUDE

rjmp reset

.INCLUDE “spi_shield.inc”

reset:

call InitShield

// initialize knight rider

ldi r16, 0b10000000 // start with r9 bit 7 set – LED 7
mov spiLEDS, r16

// initialize roulette

ldi r19,0xE0
ldi r20,0x1F
ldi r16,0x01
mov spi7SEG,r16

loop:
// night rider routine

ldi r16, 0b10000001
and r16, spiLEDS // test if LED hit is at an edge
breq contScan // continue scan if z = 0
bst spiLEDS, 0 // if right LED ON, then T = 1

contScan:

brts scanLeft // rotate right or left
lsr spiLEDS
rjmp cont

scanLeft:

lsl spiLEDS

cont:
// roulette routine

add spi7SEG, r19
and spi7SEG, r20
rol spi7SEG
rcall WriteDisplay
rcall Delay
// display routine
rcall WriteDisplay
rcall Delay
rjmp loop

APPENDIX B: KNIGHT RIDER ADDRESSING INDIRECT

begin:

ldi r16, 14 // loop 14 times
ldi ZH, high(Table<<1) // set base address
ldi ZL, low(Table<<1)

scan:

lpm r9, Z+ // load constant to LED display register
rcall WriteDisplay // display routine
rcall Delay
dec r16
brne scan // if r17 <> 0 then continue scan
rjmp begin // else start next cycle

KnightRider: .DB 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02

.DB 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40

Knight Rider Dual Scan

ldi r18, 0x01
clr r19
ldi r20, 0b10000001

loop:

lsl r18
lsr r19
mov r8, r18
or r8, r19
rcall Delay
rcall WriteDisplay
and r8, r20
breq loop
push r18
push r19
pop r18
pop r19
rjmp loop

BICYCLE LIGHT SOLUTION BY ARTHUR KU FALL 2017

The idea behind this one is that the different numerical states of our LEDs have a difference from their neighbors by +6,+7,-7,-6 repeating, and so I can use the half-carry to decide when to toggle r16.

BicycleLight4:

ldi r16, 0x0A
mov r8, r16
ldi r16, 0x06

scan4:

inc r16
add r8, r16
rcall WriteDisplay
rcall Delay
brhc scan 4
com r16
rjmp scan4