AVR2: Create live LED pattern

In this scenario, you will implement a pattern using multiple LEDS. There are 4 LEDs connected to GPIOs 13, 12, 11, and 10 (D1 on top is GPIO 13; D4 at the bottom is GPIO 10). In this scenario, you will use blocking nested loops and manual calculation of the ticks needed to run them, to obtain precise delay, as presented in the chapter Introduction to the Arduino Uno programming in Assembler. You will use binary operations to control the GPIOs and to drive them in parallel.

Prerequisites
You need to book one of the AVR laboratory nodes and ensure the video stream is live.

Scenario
Implement two patterns in a loop, using four LEDs (D1, D2, D3, and D4) as shown in the figures 1 and 2. The code below presents a solution for the pattern presented in figure 1. Implement the other pattern.

Pattern 1:

Figure 1: AVR Scenario 2, Pattern 1

Pattern 2:

Figure 2: AVR Scenario 2, Pattern 2

Result
Observe the LED sequence via the video stream.

Note, LEDs are controlled with active LOW (0), not HIGH. So to switch the LED on, provide 0 to the bit corresponding to the LED pin in the Port.

Start
Use AVR GCC syntax (as in the instruction): node compilation facilities are preconfigured, and you do not need to build a Makefile; still, it is necessary to follow the exact AVR GCC syntax, e.g., in the case of .equ.
There are multiple approaches to solving the problem. One interesting approach is to create binary masks representing the state of the LEDs at subsequent time-discrete steps, store them in memory, and then iterate over this array to control the GPIO. Another option is to explicitly set and reset bits using LED IDs and bit-shift operations or constant-defined patterns (as we present); this approach requires no RAM.
Also note you need to define a stack to use delay separately (if you use rcall and ret instructions). It is obligatory.

Step 1
Compose application definitions and configuration. Set up a stack. We do not use the'.section' directive here, but if you plan to use RAM, '.sections' are required and simplify your code.

; --- IO Register Addresses ---
.equ SPH,        0x3E    
.equ SPL,        0x3D    
.equ DDRB,       0x04    
.equ PORTB,      0x05    
 
; --- Single .equ for RAM End ---
.equ RAM_END,    0x08FF  ; Last address of SRAM for ATmega328P
 
; --- Bitmask & Pattern Definitions ---
.equ LED_MASK,   0x3C    ; 00111100 (Pins 10, 11, 12, 13)
 
; Active-Low Logic (0=ON, 1=OFF)
; Pattern 1 (Image Left): D2 & D4 ON  -> 11101011
.equ PATTERN_A,  0xEB 
; Pattern 2 (Image Right): D1 & D3 ON -> 11010111
.equ PATTERN_B,  0xD7 
 
.org 0x0000
    rjmp reset
 
reset:
    ; Initialise Stack Pointer using hi8 and lo8 functions
    ldi r16, lo8(RAM_END)
    out SPL, r16
    ldi r16, hi8(RAM_END)
    out SPH, r16

Step 2
Configure GPIO13 ↔ GPIO10 as outputs. Note, we do it in a bunch, not individually, thus instead of setting individual bits in DDRB, it is easier to write a proper bit mask (LED_MASK):

; Configure GPIO: Set PB2-PB5 as outputs
    ldi r16, LED_MASK
    out DDRB, r16

Step 3
Implement pattern logic. Here are just two steps, repeatedly executed in a loop. Note, code won't compile, because you will need to implement a delay_ms function in the Step4.

main_loop:
    ; Display Pattern A (D2, D4 ON)
    ldi r16, PATTERN_A
    out PORTB, r16
    rcall delay_2s
 
    ; Display Pattern B (D1, D3 ON)
    ldi r16, PATTERN_B
    out PORTB, r16
    rcall delay_2s
 
    rjmp main_loop

Step 4
Implement a delay function as shown in other examples (here, it is named delay_2s). Remember about the ret function at the end of it!
You may want to use .global delay_2s to smartly inform the linker that your delay_2s function is defined after the main code.

A good approach is to run the outer loop 208 times and two inner, nested loops 255 times each. ;-)

Result validation
The LEDs should be flashing on an implemented time basis. Note that some irregularity may is observed due to the nature of video streaming over the network. It is natural and OK. If you want to measure more precise timing, increase the period, e.g. to 5s.

FAQ
When using the printed version of this manual, please refer to the latest online version for the most up-to-date list of FAQs.

It does not flash: Did you compile and upload to the device? Those are separate steps: it is not enough to just compile, but you also need to “flash” the MCU. Also, check your video stream if it “ticks” - the time embedded into the video stream should change. Your code may be working OK, but the video stream can be frozen, so you cannot see it working properly!

I need a longer delay: To obtain a delay function with a period of about 2.5s, you need to introduce a fourth loop (an outer loop) in the delay; 3 will not provide you enough ticks. Eventually, you can switch to 16-bit counters.

en/multiasm/exercisesbook/avr/sut/scenarios/avr2.txt · Last modified: by pczekalski
CC Attribution-Share Alike 4.0 International
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0