]> git.the-white-hart.net Git - atmega/siggen.git/commitdiff
Refactor debouncing and waveform advance to subs
authoruser <none>
Thu, 6 Jul 2023 20:14:46 +0000 (15:14 -0500)
committeruser <none>
Thu, 6 Jul 2023 20:14:46 +0000 (15:14 -0500)
siggen.asm

index 5aa0f40cf29e0f3df6a95698a6e10e4c863152a7..966ecf4670a4cdbaab601e5a7f1db6200b0603c7 100644 (file)
@@ -203,24 +203,12 @@ reset:
 
        ; ----- Set up the initial waveform
 
-       ; Point Z at the first waveform in the rom, X at the waveform buffer
-       ldi     XL, LOW(waveform)
-       ldi     XH, HIGH(waveform)
+       ; Point Z at the first waveform in the rom
        ldi     ZL, LOW(2*wavetable_begin)
        ldi     ZH, HIGH(2*wavetable_begin)
 
-       ; Copy 256 bytes from program memory at Z to data at X
-       ldi     r25, 0x00
-_load_loop:
-       lpm     r24, Z+
-       st      X+, r24
-       inc     r25
-       brne    _load_loop
-
-       ; Point X at the waveform table (table must be 256-byte aligned)
-       ldi     r23, 0x00           ; Fractional part
-       ldi     XL, LOW(waveform)   ; Integer low part, must be zero
-       ldi     XH, HIGH(waveform)  ; Integer high part
+       ; Advance waveforms to load the LUT into ram and reset the cursor
+       rcall   next_waveform
 
        ; Initial step size
        ldi     r16, 0x00  ; Fractional part
@@ -324,74 +312,90 @@ _adc_wait:
        rjmp    _button_done
        ; Button pin status has changed
 
-       ; ----- Advance to next waveform in rom and copy to waveform LUT
+       ; Advance to next waveform in rom and copy to waveform LUT
        ; Do this before the switch debouncing so the time spent copying can be
        ; used as part of the wait time for the switch to settle
+       rcall   next_waveform
 
-       ; Point X at the ram waveform table (Z already points at next in rom)
-       ldi     XL, LOW(waveform)
-       ldi     XH, HIGH(waveform)
+       ; Debounce, wait for button release, and debounce again
+       rcall   debounce
+_button_wait_release:
+       sbis    PINC, PINC5
+       rjmp    _button_wait_release
+       rcall   debounce
 
-       ; Copy 256 bytes from program memory at Z to data at X
-       ldi     r25, 0x00
-_button_load_loop:
-       lpm     r24, Z+
-       st      X+, r24
-       inc     r25
-       brne    _button_load_loop
-       cpi     ZH, HIGH(2*wavetable_end)
-       brne    _button_load_done
-       ldi     ZH, HIGH(2*wavetable_begin)
-_button_load_done:
+_button_done:
+       ; --------------------------------------------------------------
 
-       ; Point X at the waveform table (table must be 256-byte aligned)
-       ldi     r23, 0x00           ; Fractional part
-       ldi     XL, LOW(waveform)   ; Integer low part, must be zero
-       ldi     XH, HIGH(waveform)  ; Integer high part
 
-       ; ----- Debounce - wait until pin is quiet for some duration
+       rjmp    loop
 
-_button_reset_wait:
-       sbi     PCIFR, PCIF1    ; Clear pin change flag (w1c)
-       sbi     TIFR0, OCF0A    ; Clear timer expire flag (w1c)
-       ldi     r25, (1 << TSM) | (1 << PSRSYNC)
-       out     GTCCR, r25      ; Reset prescaler and hold
-       ldi     r25, 0x00       ; Reset timer count value
-       out     TCNT0, r25
-       out     GTCCR, r25      ; Unhalt the prescaler to run the timer
-_button_busyloop:
-       sbic    PCIFR, PCIF1    ; If the pin changed again, reset the clock
-       rjmp    _button_reset_wait
-       sbis    TIFR0, OCF0A    ; If the timer expired, exit the loop
-       rjmp    _button_busyloop
 
-       ; ----- Wait for button release
+; ------------------------------------------------------------------------------
+; Subroutines
+
 
-_button_wait_release:
-       sbis    PINC, PINC5
-       rjmp    _button_wait_release
+next_waveform:
+       ; Throughout execution, Z points to the next wavetable to be loaded into
+       ; the waveform buffer.  This subroutine advances the Z pointer as it
+       ; copies, and wraps it back around to the beginning of the wavetable if
+       ; it reaches the end.
 
-       ; ----- Debounce again
+       ; Copy the next waveform from the wavetable ROM into the waveform buffer
+       ldi     XL, LOW(waveform)            ; Point X at the waveform buffer
+       ldi     XH, HIGH(waveform)
+       ldi     r25, 0x00
+_next_waveform_loop:
+       lpm     r24, Z+                      ; Load a byte from wavetale
+       st      X+, r24                      ; Store it to the waveform buffer
+       inc     r25                          ; Advance counter
+       brne    _next_waveform_loop          ; Exit when counter overflows to zero
+
+       ; Handle wrap-around after cycling through all waveforms
+       ; Waveforms are all 256 bytes long, so the lower byte of Z will always
+       ; be the same after copying, so no need to reload it
+       cpi     ZH, HIGH(2*wavetable_end)    ; Did we copy the final waveform?
+       brne    _next_waveform_nowrap
+       ldi     ZH, HIGH(2*wavetable_begin)  ; If so, reset to the first waveform
+_next_waveform_nowrap:
+
+       ; Reset the current sample pointer
+       ldi     r23, 0x00                    ; Fractional part
+       ldi     XL, LOW(waveform)            ; Integer low part
+       ldi     XH, HIGH(waveform)           ; Integer high part
+
+       ret
+
+
+debounce:
+       ; Debouncing is done by waiting for the pin to be quiet (no transitions)
+       ; for some specified amount of time (1ms for now, see OCR0A in the init
+       ; section above).
+       ;
+       ; We run the timer for 1ms and run in a busyloop until it expires.  If
+       ; during this loop the pin change flag indicates that there was a
+       ; transition, we reset the timer and wait again.
 
-_button_reset_wait_2:
-       sbi     PCIFR, PCIF1    ; Clear pin change flag (w1c)
-       sbi     TIFR0, OCF0A    ; Clear timer expire flag (w1c)
-       ldi     r25, (1 << TSM) | (1 << PSRSYNC)
-       out     GTCCR, r25      ; Reset prescaler and hold
-       ldi     r25, 0x00       ; Reset timer count value
-       out     TCNT0, r25
-       out     GTCCR, r25      ; Unhalt the prescaler to run the timer
-_button_busyloop_2:
-       sbic    PCIFR, PCIF1    ; If the pin changed again, reset the clock
-       rjmp    _button_reset_wait_2
-       sbis    TIFR0, OCF0A    ; If the timer expired, exit the loop
-       rjmp    _button_busyloop_2
+_debounce_reset:
+       sbi     PCIFR, PCIF1         ; Ensure pin change flag is cleared (w1c)
+       sbi     TIFR0, OCF0A         ; Ensure timer expire flag is cleared (w1c)
 
-_button_done:
-       ; --------------------------------------------------------------
+       ; PSRSYNC resets the timer clock prescaler
+       ; TSM forces the prescaler to be held in reset
+       ldi     r25, (1 << TSM) | \
+                    (1 << PSRSYNC)
+       out     GTCCR, r25           ; Reset the prescaler and halt
+       ldi     r25, 0x00
+       out     TCNT0, r25           ; Reset timer count value
+       out     GTCCR, r25           ; Unhalt the prescaler to run the timer
+_debounce_busyloop:
+       sbic    PCIFR, PCIF1         ; If the pin changed again, reset and retry
+       rjmp    _debounce_reset
+       sbis    TIFR0, OCF0A         ; IF the timer expired, exit the loop
+       rjmp    _debounce_busyloop
 
+       ret
 
-       rjmp    loop
 
 
 ; ------------------------------------------------------------------------------