Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
en:multiasm:exercisesbook:avr:sut:scenarios:avr5 [2026/05/04 13:26] pczekalskien:multiasm:exercisesbook:avr:sut:scenarios:avr5 [2026/05/04 13:27] (current) pczekalski
Line 1: Line 1:
 +====== AVR5: Control Brightness with PWM ======
 +
 +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|]].
 +
 +** 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):
 +<code asm>
 +.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:
 +....
 +</code>
 +
 +** 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:
 +<code asm>
 +...
 +   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
 +...
 +</code>
 +
 +** Step 3 **\\
 +Configure timer for PWM (Timer1, channel B -> GPIO 10):
 +<code asm>
 +...
 +    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
 +...
 +
 +</code>
 +
 +** 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:
 +  * Function ''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.
 +  * Function ''delay_1ms'' is argument-less and delays (block execution using a loop) for about 1ms.\\
 +  * Function ''delay_N_ms'' is just a wrap-arround over ''delay_1ms'': 
 +<code asm>
 +; 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
 +</code>
 +<note tip>Remember that the ''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'')</note>
 +
 +** Step 5 **\\
 +Set the main loop. Here you're on your own, but the hint for the algorithm to have a real heartbeat is as follows:
 +<code>
 +loop infinitely:
 +    // --- First beat (Lub) ---
 +    pulse()
 +    delay(200)   // Wait 200 milliseconds
 +
 +    // --- Second beat (Dub) ---
 +    pulse()
 +    delay(750)   // Wait 750 milliseconds (250 + 250 + 250)
 +</code>
 +
 +** 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.
 +
 +
  
en/multiasm/exercisesbook/avr/sut/scenarios/avr5.txt · Last modified: 2026/05/04 13:27 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