💾 Archived View for gemini.djph.net › users › gemini › projects › sk6812 › pt2.gmi captured on 2020-09-24 at 00:55:32. Gemini links have been rewritten to link to archived content
-=-=-=-=-=-=-
It's been a few days (err, at least it's only felt like a few days), and I've finally sorted out the two interrupts to handle changing the output color. In order to not change things mid-stream, the interrupt handlers only set a flag that the main loop then uses in order to change the entire strip at once. Debouncing of the buttons is handled via a timer that only re-enables the INT0 interrupt after a few milliseconds, and ensures that there are no pending interrupt flags for INT0 before exiting the timer.
Interrupt 0 ("INT0") is an external interrupt pin that (on the ATTinyX5 series anyway) is on PB2 (Pin7). It can be triggered by one of four conditions - high level, low level, rising edge, or falling edge. For the project, I decided on falling edge. The pin itself is set initially as input with pullup, and external wiring is simply to a normally open momentary pushbutton that pulls the pin to ground.
The service routine is pretty short, comprising only about 5 or 6 real instructions. The remaining instructions primarily save / restore the stack pointer and r16, which is used as a working register.
push r16 ; r16 to stack
in r16, SREG ; SREG to r16
push r16 ; r16 (SREG) to stack
in r16, GIMSK ; load int. mask reg into r16
andi r16, ~(1<<INT0) ; disable INT0 pin
out GIMSK, r16 ; save to register
; enable a ~128 ms debounce timer
; TODO: shorten this
ldi r16, (1<<CS13) | (1<<CS12) | (1<<CS10)
out TCCR1, r16
inc r1 ; increment flag
pop r16 ; restore r16 (SREG)
out SREG, r16 ; restore r16 to SREG
pop r16 ; restore r16
reti
The other interrupt that is in use is the Timer 1 overflow. In this project, the timer is set up to count from 0 to T_MAX once, then shut itself down. This interrupt is used to act as a software de-bouncing routine for the button.
As with the INT0 routine, the overflow routine is quite short - 7 real commands and a handful of others to store / retrieve registers to the SRAM-based stack pointer.
push r16 ; save r16 to stack
in r16, SREG ; SREG to r16
push r16 ; r16 (SREG) to stack
in r16, GIMSK ; load interrupt register to r16
ori r16, (1<<INT0) ; enable INT0 pin
out GIMSK, r16 ; save back to GIMSK register
clr r16 ; clear r16
out TCCR1, r16 ; stop the clock
ldi r16,(1<<INTF0) ; force clear INT0 flag
out GIFR, r16 ; and save to flag register
pop r16 ; restore r16 (SREG)
out SREG, r16 ; restore r16 to SREG
pop r16 ; restore r16
reti ; return from interrupt