This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| en:multiasm:exercisesbook:avr:sut:scenarios:avr5 [2026/05/04 13:00] – pczekalski | en:multiasm:exercisesbook:avr:sut:scenarios:avr5 [2026/05/04 13:27] (current) – pczekalski | ||
|---|---|---|---|
| Line 9: | Line 9: | ||
| ** Scenario **\\ | ** Scenario **\\ | ||
| Create an application that toggles the built-in LED (GPIO 13) on permanently, | Create an application that toggles the built-in LED (GPIO 13) on permanently, | ||
| + | |||
| + | In this example, we will build the code from the bottom up. | ||
| ** Result **\\ | ** Result **\\ | ||
| - | Observe | + | Observe |
| ** Start **\\ | ** Start **\\ | ||
| Line 17: | Line 19: | ||
| ** Step 1 **\\ | ** Step 1 **\\ | ||
| - | Compose a template for your application that includes declarations for GPIO and a timer. We use Timer1 (16-bit) | + | Compose a template for your application that includes declarations for GPIO and a timer. We use Timer1 (16-bit) |
| <code asm> | <code asm> | ||
| - | ; --- Register | + | .equ DDRB, |
| - | .equ SREG, | + | .equ PORTB, |
| - | .equ SPH, | + | .equ SPCR, |
| - | .equ SPL, 0x3D | + | .equ MCUSR, |
| + | .equ SPL, 0x3D ; Stack Pointer Low (I/O) | ||
| + | .equ SPH, 0x3E | ||
| + | .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 | ||
| - | .equ DDRB, 0x04 | + | ; Bit Constants |
| - | .equ PINB, | + | .equ PB2, |
| - | .equ LED_PIN, 5 | + | .equ PB5, 5 ; Pin 13 |
| - | + | .equ COM1B1, 5 | |
| - | .equ RAMEND, | + | .equ WGM10, |
| - | ; --- Timer1 Register Mapping --- | + | .equ CS11, 1 |
| - | .equ TCCR1A, | + | |
| - | .equ TCCR1B, | + | |
| - | .equ OCR1AH, | + | |
| - | .equ OCR1AL, | + | |
| - | .equ TIMSK1, | + | |
| - | .equ TOP_VAL, 0x3D08 | + | |
| - | + | ||
| - | .equ WGM12, 3 ; WGM12 is on bit 3 of the TCCR1B | + | |
| - | .equ CS12, 2 ; CS12 is on bit 2 of the TCCR1B | + | |
| - | .equ CS10, 0 ; CS10 is on bit 0 of the TCCR1B | + | |
| .section .text | .section .text | ||
| + | |||
| + | ; ========================================================== | ||
| + | ; CLASSICAL INTERRUPT VECTOR TABLE (104 Bytes) | ||
| + | ; ========================================================== | ||
| .org 0x0000 | .org 0x0000 | ||
| - | | + | |
| - | .org 0x002C | + | |
| - | rjmp TIMER_ISR | + | |
| - | .org 0x0034 | + | |
| RESET: | RESET: | ||
| - | + | .... | |
| - | ; --- Idle Main Loop --- | + | |
| - | LOOP: | + | |
| - | rjmp LOOP | + | |
| </ | </ | ||
| ** Step 2 **\\ | ** Step 2 **\\ | ||
| - | Initialise stack (obligatory, | + | Initialise stack (obligatory, |
| <code asm> | <code asm> | ||
| ... | ... | ||
| - | ; Prepare stack | ||
| ldi r16, hi8(RAMEND) | ldi r16, hi8(RAMEND) | ||
| out SPH, r16 | out SPH, r16 | ||
| Line 66: | Line 61: | ||
| out SPL, r16 | out SPL, r16 | ||
| - | ; Configure PB5 (built-in LED, GPIO 13) as Output | + | ; Setup Pins using Atomic ' |
| - | sbi DDRB, LED_PIN | + | sbi DDRB, PB5 ; Set Pin 13 as Output |
| + | sbi DDRB, PB2 ; Set Pin 10 as Output | ||
| + | cbi PORTB, PB5 ; Turn ON Pin 13 | ||
| ... | ... | ||
| </ | </ | ||
| - | Note the different method for setting GPIO 13 as an output compared to the [[avr1|]] scenario.\\ | ||
| ** Step 3 **\\ | ** Step 3 **\\ | ||
| - | Configure timer and enable interrupts: | + | Configure timer for PWM (Timer1, channel B -> GPIO 10): |
| <code asm> | <code asm> | ||
| ... | ... | ||
| - | | + | ldi r16, (1 << COM1B1) | (1 << WGM10) |
| - | ; Load the compare value for 1 second | + | |
| - | | + | |
| - | sts OCR1AH, r16 | + | |
| - | ldi r16, lo8(TOP_VAL) | + | |
| - | sts OCR1AL, r16 | + | |
| - | + | ||
| - | ; TCCR1A: Default (0x00) | + | |
| - | ldi r16, 0x00 | + | |
| sts TCCR1A, r16 | sts TCCR1A, r16 | ||
| - | + | | |
| - | ; TCCR1B: | + | |
| - | ; Bit 3 (WGM12) = 1 (CTC Mode) | + | |
| - | ; Bit 2 (CS12) | + | |
| - | ; Bit 0 (CS10) | + | |
| - | | + | |
| sts TCCR1B, r16 | sts TCCR1B, r16 | ||
| - | + | | |
| - | ; 4. Enable Compare Match A Interrupt | + | sts OCR1BH, r16 |
| - | | + | |
| - | sts TIMSK1, r16 | + | |
| - | + | ||
| - | | + | |
| - | sei | + | |
| ... | ... | ||
| Line 105: | Line 84: | ||
| ** Step 4 **\\ | ** Step 4 **\\ | ||
| - | Your loop function remains idle, but you need an ISR implementation, e.g. like this: | + | 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 '' | ||
| + | * Function '' | ||
| + | * Function '' | ||
| <code asm> | <code asm> | ||
| - | TIMER_ISR: | + | ; void pulse(void) |
| - | ; Toggle LED using the PINB write trick. | + | pulse: |
| - | ; Since 'sbi' | + | |
| - | ; | + | 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 ' | ||
| + | delay_N_ms: | ||
| + | | ||
| + | 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 | ||
| + | </ | ||
| + | <note tip> | ||
| + | |||
| + | ** Step 5 **\\ | ||
| + | Set the main loop. Here you're on your own, but the hint for the algorithm | ||
| + | < | ||
| + | loop infinitely: | ||
| + | | ||
| + | pulse() | ||
| + | delay(200) | ||
| + | |||
| + | // --- Second beat (Dub) --- | ||
| + | | ||
| + | | ||
| </ | </ | ||
| ** Result validation **\\ | ** Result validation **\\ | ||
| - | The LED 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 3s. | + | The LED4 should be flashing |
| ** FAQ **\\ | ** 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.\\ | 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 " | + | **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 " |
| + | **Built-in LED is off**: Mind it is driven by zero, not by one. | ||
| - | // | ||