This is an old revision of the document!
In this scenario, you will control the LED brightness using PWM. To compare results, the built-in LED will be set to 100% on while you adjust LED4's brightness.
Prerequisites
You need to book one of the AVR laboratory nodes and ensure the video stream is live.
Get familiar with the scenario: AVR1: Hello World on AVR.
Scenario
Create an application that toggles the built-in LED (GPIO 13) on permanently, and then uses a timer (Timer1, channel B) to control LED4 (GPIO 10). The LED4 should present a heartbeat pattern.
In this example, we will build the code from the bottom up.
Result
Observe the heartbeat on LED4 (GPIO 10) and the solid LED on GPIO 13 (LED1, built-in).
Start
Mind to 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.
Step 1
Compose a template for your application that includes declarations for GPIO and a timer. We use Timer1 (16-bit) to generate PWM on GPIO 10 (channel B):
.equ DDRB, 0x04 ; Port B Data Direction Register (I/O) .equ PORTB, 0x05 ; Port B Data Register (I/O) .equ SPCR, 0x2C ; SPI Control Register (I/O) .equ MCUSR, 0x34 ; MCU Status Register (I/O) .equ SPL, 0x3D ; Stack Pointer Low (I/O) .equ SPH, 0x3E ; Stack Pointer High (I/O) .equ WDTCSR, 0x60 ; Watchdog Timer Control Register (Memory) .equ TCCR1A, 0x80 ; Timer1 Control Register A (Memory) .equ TCCR1B, 0x81 ; Timer1 Control Register B (Memory) .equ OCR1BL, 0x8A ; Timer1 Output Compare Register B Low .equ OCR1BH, 0x8B ; Timer1 Output Compare Register B High ; Bit Constants .equ PB2, 2 ; Pin 10 .equ PB5, 5 ; Pin 13 .equ COM1B1, 5 .equ WGM10, 0 .equ CS11, 1 .section .text ; ========================================================== ; CLASSICAL INTERRUPT VECTOR TABLE (104 Bytes) ; ========================================================== .org 0x0000 jmp RESET RESET: ....
Step 2
Initialise stack (obligatory, we use ISR function calls) and configure GPIOs 10 and 13 as outputs and enable GPIO 13 connected LED on:
... ldi r16, hi8(RAMEND) out SPH, r16 ldi r16, lo8(RAMEND) out SPL, r16 ; Setup Pins using Atomic 'sbi' (Set Bit in I/O) sbi DDRB, PB5 ; Set Pin 13 as Output sbi DDRB, PB2 ; Set Pin 10 as Output cbi PORTB, PB5 ; Turn ON Pin 13 ...
Step 3
Configure timer for PWM (Timer1, channel B → GPIO 10):
... ldi r16, (1 << COM1B1) | (1 << WGM10) sts TCCR1A, r16 ldi r16, (1 << CS11) sts TCCR1B, r16 ldi r16, 0 sts OCR1BH, r16 sts OCR1BL, r16 ...
Step 4
Now, AFTER the loop section (you perhaps don't have it yet, so put a dummy one in the code, temporary, implement functions to delay and to blink. Delays based on timer tick counting, not a timer, because we use Timer1 for PWM generation.
There are 3 functions:
pulse modifies Timer1, channel B comparator value, thus changing the duty cycle of the PWM signal. Change is done every 1 ms. The duty cycle varies linearly.delay_1ms is argument-less and delays (block execution using a loop) for about 1ms.delay_N_ms is just a wrap-arround over delay_1ms: ; void pulse(void) pulse: ldi r18, 0 fade_in: sts OCR1BL, r18 rcall delay_1ms inc r18 brne fade_in ldi r18, 255 fade_out: sts OCR1BL, r18 rcall delay_1ms dec r18 brne fade_out sts OCR1BL, r18 ret ; void delay_N_ms(uint8_t ms) ; Expects argument 'ms' in r24 delay_N_ms: tst r24 breq dn_done dn_loop: rcall delay_1ms dec r24 brne dn_loop dn_done: ret ; void delay_1ms(void) delay_1ms: ldi r21, 21 d1_loop: ldi r22, 250 d2_loop: dec r22 brne d2_loop dec r21 brne d1_loop ret
delay_N_ms function operates on 8-bit arguments, so the maximum delay is 255ms. If you need a longer one, modify it so it works with 16-bit arguments (r25:r24)
Step 5
Set the main loop. Here you're on your own, but the hint for the algorithm is as follows:
loop infinitely:
// --- First beat (Lub) ---
pulse()
delay(200) // Wait 200 milliseconds
// --- Second beat (Dub) ---
pulse()
delay(750) // Wait 750 milliseconds (250 + 250 + 250)
Result validation
The LED4 should be flashing at a set interval (heartbeat), while LED1 (built-in) should be on. Note that some irregularity may is observed due to the nature of video streaming over the network. If you cannot clearly observe via the video stream, increase the heart rate via either the main loop or internally in the pulse function, e.g., by calling delay_N_ms with an appropriate parameter (r24) instead of delay_1ms.
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 work at all: 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!
Built-in LED is off: Mind it is driven by zero, not by one.