BlinkenArea - GitList
Repositories
Blog
Wiki
bulb
Code
Commits
Branches
Tags
Search
Tree:
51e0191
Branches
Tags
master
petaflot
1.0.0
1.1.0
1.1.1
bulb
firmware
bulb.asm
version 1.0.0
Stefan Schuermans
commited
51e0191
at 2012-06-06 19:34:07
bulb.asm
Blame
History
Raw
; bulb - BlinkenArea ultimate logo board ; version 1.0.0 date 2011-07-30 ; Copyright (C) 2011-2012 Stefan Schuermans <stefan@blinkenarea.org> ; Copyleft: GNU public license - http://www.gnu.org/copyleft/gpl.html ; ATtiny2313A, clock frequency: 8 MHz (internal oscillator) ; PA0: unused ; PA1: unused ; PA2: reset ; PB0: column 0 output (output, low) ; PB1: column 1 output (output, low) ; PB2: column 2 output (output, low) ; PB3: column 3 output (output, low) ; PB4: column 4 output (output, low) ; PB5: column 5 output (output, low) ; PB6: column 6 output (output, low) ; PB7: push button input (input, pull-up enabled) ; PD0: row 0 output (output, high) ; PD1: row 1 output (output, high) ; PD2: row 2 output (output, high) ; PD3: row 3 output (output, high) ; PD4: row 4 output (output, high) ; PD5: row 5 output (output, high) ; PD6: unused (output, low) .INCLUDE "tn2313def.inc" ; IO pins .equ COL_PORT = PORTB ; column outputs .equ ROW_PORT = PORTD ; row outputs .equ BTN_PIN = PINB .equ BTN_BIT = 7 ; general purpose registers .def TMP = r16 .def CNT = r17 .def DATA = r18 .DSEG .ORG 0x060 ; current frame FRAME: .BYTE 42 .MACRO breqx brne NE rjmp @0 NE: .ENDM ; multiple rcalls in a row ; parameters: label, N .MACRO rcall_N .IF @1 > 0 rcall @0 rcall_N @0, @1 - 1 .ENDIF .ENDM ; check if to turn on pixel in subframe ; parameter: grayscale value (1..15) ; input: X = ptr to pixel data (0..7), ; DATA[7-1] = other pixels ; output: X = ptr to pixel data of next pixel, ; DATA.7 = if _not_ to turn on pixel, DATA.[6-0] = old DATA[7-1] ; changes: TMP, DATA, X ; cycles: 4 .MACRO PIXEL ld TMP,X+ cpi TMP,@0 ror DATA .ENDM ; output row (black/white) ; parameter: grayscale value (1..15) ; input: X = ptr to pixel data (0..15) ; output: - ; changes: TMP, DATA ; cycles: 32 .MACRO ROW_BW PIXEL @0 ; pixel 0 PIXEL @0 ; pixel 1 PIXEL @0 ; pixel 2 PIXEL @0 ; pixel 3 PIXEL @0 ; pixel 4 PIXEL @0 ; pixel 5 PIXEL @0 ; pixel 6 subi XL,7 ; XH not there on ATtiny2313 lsr DATA ; ensure remaining bit stays ; high (pull-up for button) com DATA out COL_PORT,DATA .ENDM ; wait n * 64 cycles ; parameter: n ; input: - ; output: - ; changes: TMP ; cycles: n * 64 .MACRO WAIT64_N .IF @0 > 0 rcall WAIT64 WAIT64_N @0 - 1 .ENDIF .ENDM ; output row for grayscale (black/white) and wait ; parameter: grayscale value (1..15) ; input: X = ptr to pixel data (0..15) ; output: - ; changes: TMP, DATA ; cycles: 32 + (grayscale - 1) * 64 .MACRO ROW_BW_WAIT ROW_BW @0 WAIT64_N @0 - 1 .ENDM ; turn off row (with same timing as ROW_BW) ; input: - ; output: - ; changes: TMP ; cycles: 32 .MACRO ROW_OFF ldi TMP,10 ROW_OFF_LOOP: dec TMP brne ROW_OFF_LOOP ldi TMP,0x80 ; ensure remaining bit stays ; high (pull-up for button) out COL_PORT,TMP .ENDM .CSEG .ORG 0x000 rjmp ENTRY ; RESET reti ; INT0 reti ; INT1 reti ; TIMER1_CAPT reti ; TIMER1_COMPA reti ; TIMER1_OVF reti ; TIMER0_OVF reti ; USART0_RX reti ; USART0_UDRE reti ; USART0_TX reti ; ANALOG_COMP reti ; PC_INT0 reti ; TIMER1_COMPB reti ; TIMER0_COMPA reti ; TIMER0_COMPB reti ; USI_START reti ; USI_OVERFLOW reti ; EE_READY reti ; WDT reti ; PC_INT1 reti ; PC_INT2 ; code entry point ENTRY: ; set system clock prescaler to 1:1 ldi TMP,1<<CLKPCE out CLKPR,TMP ldi TMP,0 out CLKPR,TMP ; initialize output ports ldi TMP,0x00 ; PA[01] to output, low out PORTA,TMP ldi TMP,0x03 out DDRA,TMP ldi TMP,0x80 ; PB[0-6] to output, low - PB7 to input, pull-up enabled out PORTB,TMP ldi TMP,0x7F out DDRB,TMP ldi TMP,0x3F ; PD[0-5] to output, high - PD6 to output, low out PORTD,TMP ldi TMP,0x7F out DDRD,TMP ; initialize stack pointer ldi TMP,RAMEND out SPL,TMP ; enable watchdog (64ms) wdr ldi TMP,1<<WDCE|1<<WDE out WDTCR,TMP ldi TMP,1<<WDE|1<<WDP1 out WDTCR,TMP wdr ; disable analog comparator ldi TMP,1<<ACD out ACSR,TMP ; enable pin change interrupt for button ; to wake up from sleep in TMP,GIMSK ori TMP,1<<PCIE out GIMSK,TMP ldi TMP,1<<PCINT7 out PCMSK,TMP ; jump to main program rjmp MAIN ; wait 64 cycles ; input: - ; output: - ; changes: TMP ; cycles: 64 (including rcall and ret) WAIT64: ldi TMP,19 WAIT64_LOOP: dec TMP brne WAIT64_LOOP ; done ret ; output row (grayscales) ; input: X = ptr to pixel data (0..15) ; output: - ; changes: TMP, DATA ; cycles: 7269 (including rcall and ret) ROW_GRAY: ROW_BW_WAIT 1 ROW_BW_WAIT 2 ROW_BW_WAIT 3 ROW_BW_WAIT 4 ROW_BW_WAIT 5 ROW_BW_WAIT 6 ROW_BW_WAIT 7 ROW_BW_WAIT 8 ROW_BW_WAIT 9 ROW_BW_WAIT 10 ROW_BW_WAIT 11 ROW_BW_WAIT 12 ROW_BW_WAIT 13 ROW_BW_WAIT 14 ROW_BW_WAIT 15 ROW_OFF ; done ret ; output a frame ; input: FRAME = pixel data (0..15) ; output: - ; changes: TMP, CNT, DATA, X ; cycles: 43676 (including rcall and ret) ; time: 5.5ms OUT_FRAME: wdr ldi XL,low(FRAME) ; ptr to pixel data ; XH not there on ATtiny2313 ldi CNT,0x01 ; bitmask loop over rows OUT_FRAME_LOOP: mov TMP,CNT ; select row com TMP andi TMP,0x3F out ROW_PORT,TMP rcall ROW_GRAY ; display row subi XL,-7 ; ptr to next row ; XH not there on ATtiny2313 lsl CNT ; bitmask loop over rows cpi CNT,0x40 brne OUT_FRAME_LOOP ; done ret ; handle on/off button ; input: - ; output: - ; changes: TMP, CNT ; time: usually very short, but may suspend execution BUTTON: ; exit if button not pressed ; require stable press for about 50 ms clr CNT ; loop 65536 times clr TMP BUTTON_CHECK_PRESS_LOOP: wdr sbic BTN_PIN,BTN_BIT ; not pressed -> leave ret dec TMP brne BUTTON_CHECK_PRESS_LOOP dec CNT brne BUTTON_CHECK_PRESS_LOOP ; wait for button to be released ; require stable release for about 50 ms BUTTON_WAIT_RELEASE: clr CNT ; loop 65536 times clr TMP BUTTON_WAIT_RELEASE_LOOP: wdr sbis BTN_PIN,BTN_BIT ; pressed -> start over rjmp BUTTON_WAIT_RELEASE dec TMP brne BUTTON_WAIT_RELEASE_LOOP dec CNT brne BUTTON_WAIT_RELEASE_LOOP ; disable watchdog cli wdr in TMP,WDTCR ori TMP,1<<WDCE|1<<WDE out WDTCR,TMP andi TMP,~(1<<WDCE|1<<WDE) out WDTCR,TMP wdr sei ; sleep in TMP,MCUCR ; configure power-down sleep andi TMP,~(1<<SM1) ori TMP,1<<SE|1<<SM0 out MCUCR,TMP sleep ; go to sleep in TMP,MCUCR ; configure no sleep mode andi TMP,~(1<<SE) out MCUCR,TMP ; enable watchdog cli wdr in TMP,WDTCR ori TMP,1<<WDCE|1<<WDE out WDTCR,TMP andi TMP,~(1<<WDCE) out WDTCR,TMP wdr sei ; wait for button to be released ; require stable release for about 50 ms BUTTON_WAIT2_RELEASE: clr CNT ; loop 65536 times clr TMP BUTTON_WAIT2_RELEASE_LOOP: wdr sbis BTN_PIN,BTN_BIT ; pressed -> start over rjmp BUTTON_WAIT2_RELEASE dec TMP brne BUTTON_WAIT2_RELEASE_LOOP dec CNT brne BUTTON_WAIT2_RELEASE_LOOP ; done ret ; output a frame for some time ; also handles on/off button ; input: FRAME = pixel data (0..15) ; TMP = time to show frame (1..255, in 5.5 ms steps) ; output: - ; changes: X, TMP ; time: TMP * 5.5 ms OUT_FRAME_TIME: ; output frame push TMP push CNT push DATA rcall OUT_FRAME ; 5.5 ms rcall BUTTON pop DATA pop CNT pop TMP ; loop dec TMP brne OUT_FRAME_TIME ; done ret ; clear frame ; input: - ; output: - ; changes: X, FRAME, TMP ; time: short CLEAR: ldi XL,low(FRAME) ; ptr to pixel data ; XH not there on ATtiny2313 clr TMP CLEAR_LOOP: st X+,TMP ; clear pixel cpi XL,low(FRAME)+42 ; bottom of loop ; XH not there on ATtiny2313 brne CLEAR_LOOP ; done ret ; set frame to solid color ; input: DATA = value (0..15) ; output: - ; changes: X, FRAME ; time: short SET_COLOR: ldi XL,low(FRAME) ; ptr to pixel data ; XH not there on ATtiny2313 SET_COLOR_LOOP: st X+,DATA ; set pixel value cpi XL,low(FRAME)+42 ; bottom of loop ; XH not there on ATtiny2313 brne SET_COLOR_LOOP ; done ret ; set pixel ; input: CNT = pixel number (0..41, nothing is done for 42..255) ; DATA = value (0..15) ; output: - ; changes: X, FRAME, TMP ; time: short SET_PIXEL: cpi CNT,42 ; invalid pixel number -> done brsh SET_PIXEL_END ldi XL,low(FRAME) ; ptr to pixel (base + offset) add XL,CNT ; XH not there on ATtiny2313 st X,DATA ; set pixel SET_PIXEL_END: ; done ret ; draw worm ; input: CNT = head of worm (0..55) ; output: - ; changes: X, FRAME, TMP, DATA ; time: short DRAW_WORM: cpi CNT,56 ; invalid head pos -> done brsh DRAW_WORM_END ldi XL,low(FRAME)+1 ; ptr to before head add XL,CNT ; XH not there on ATtiny2313 ldi DATA,15 ; head is full on cpi CNT,42 ; head pos in frame -> go brlo DRAW_WORM_LOOP mov TMP,CNT ; TMP := invisible pixels subi TMP,41 sub XL,TMP ; skip invisible pixels sub DATA,TMP ; XH not there on ATtiny2313 DRAW_WORM_LOOP: st -X,DATA ; set pixel, go back cpi XL,low(FRAME) ; 1st pixel -> done breq DRAW_WORM_END ; XH not there on ATtiny2313 dec DATA ; next pixel darker brne DRAW_WORM_LOOP ; loop DRAW_WORM_END: ; done ret ; draw backwards worm ; input: CNT = tail of worm (0..55) ; output: - ; changes: X, FRAME, TMP, DATA ; time: short DRAW_BW_WORM: cpi CNT,56 ; invalid tail pos -> done brsh DRAW_BW_WORM_END ldi XL,low(FRAME)+1 ; ptr to before tail add XL,CNT ; XH not there on ATtiny2313 ldi DATA,1 ; tail is minimum on cpi CNT,42 ; tail pos in frame -> go brlo DRAW_BW_WORM_LOOP mov TMP,CNT ; TMP := invisible pixels subi TMP,41 sub XL,TMP ; skip invisible pixels add DATA,TMP ; XH not there on ATtiny2313 DRAW_BW_WORM_LOOP: st -X,DATA ; set pixel, go back cpi XL,low(FRAME) ; 1st pixel -> done breq DRAW_BW_WORM_END ; XH not there on ATtiny2313 inc DATA ; next pixel brighter cpi DATA,16 ; loop brne DRAW_BW_WORM_LOOP DRAW_BW_WORM_END: ; done ret ; blink animation ; input: - ; output: - ; changes: X, FRAME, CNT, DATA, TMP ANIM_BLINK: ; off ldi DATA,0 ; minimum color rcall SET_COLOR ; paint ldi TMP,100 ; show frame 550 ms rcall OUT_FRAME_TIME ; on ldi DATA,15 ; maximum color rcall SET_COLOR ; paint ldi TMP,100 ; show frame 550 ms rcall OUT_FRAME_TIME ; done ret ; fade up and down animation ; input: - ; output: - ; changes: X, FRAME, CNT, DATA, TMP ANIM_FADE: ; fade up ldi DATA,0 ; start dark ANIM_FADE_UP: rcall SET_COLOR ; paint ldi TMP,10 ; show frame 55 ms rcall OUT_FRAME_TIME inc DATA ; fade up cpi DATA,15 ; loop until almost full on brne ANIM_FADE_UP ; fade down ANIM_FADE_DOWN: rcall SET_COLOR ; paint ldi TMP,10 ; show frame 55 ms rcall OUT_FRAME_TIME dec DATA ; fade up cpi DATA,255 ; loop until full off brne ANIM_FADE_DOWN ; done ret ; flicker animation ; input: - ; output: - ; changes: X, FRAME, CNT, DATA, TMP ANIM_FLICKER: ; even pixels rcall CLEAR ; clear ldi DATA,15 ; even pixels to maximum ldi CNT,0 ANIM_FLICKER_EVEN: rcall SET_PIXEL subi CNT,-2 ; move two pixels cpi CNT,42 ; loop brlo ANIM_FLICKER_EVEN ldi TMP,40 ; show frame 220 ms rcall OUT_FRAME_TIME ; odd pixels rcall CLEAR ; clear ldi DATA,15 ; odd pixels to maximum ldi CNT,1 ANIM_FLICKER_ODD: rcall SET_PIXEL subi CNT,-2 ; move two pixels cpi CNT,42 ; loop brlo ANIM_FLICKER_ODD ldi TMP,40 ; show frame 220 ms rcall OUT_FRAME_TIME ; done ret ; wobble animation ; input: - ; output: - ; changes: X, FRAME, CNT, DATA, TMP ANIM_WOBBLE: ; even pixels up, odd pixels down ldi DATA,0 ; even pixels start dark ANIM_WOBBLE_UP: ldi CNT,0 ANIM_WOBBLE_UP_DRAW: rcall SET_PIXEL inc CNT ; next pixel ldi TMP,0x0F ; invert color eor DATA,TMP cpi CNT,42 ; loop brlo ANIM_WOBBLE_UP_DRAW ldi TMP,10 ; show frame 55 ms rcall OUT_FRAME_TIME inc DATA ; next color: brighter cpi DATA,16 brlo ANIM_WOBBLE_UP ; even pixels down, odd pixels up ldi DATA,15 ; even pixels start full ANIM_WOBBLE_DOWN: ldi CNT,0 ANIM_WOBBLE_DOWN_DRAW: rcall SET_PIXEL inc CNT ; next pixel ldi TMP,0x0F ; invert color eor DATA,TMP cpi CNT,42 ; loop brlo ANIM_WOBBLE_DOWN_DRAW ldi TMP,10 ; show frame 55 ms rcall OUT_FRAME_TIME dec DATA ; next color: darker cpi DATA,16 brlo ANIM_WOBBLE_DOWN ; done ret ; run animation ; input: - ; output: - ; changes: X, FRAME, CNT, DATA, TMP ANIM_RUN: ldi CNT,255 ; start before 1st pixel ANIM_RUN_LOOP: rcall CLEAR ; clear ldi DATA,15 ; current pixel full on rcall SET_PIXEL ldi TMP,10 ; show frame 55 ms rcall OUT_FRAME_TIME inc CNT ; next pixel cpi CNT,43 ; loop until after last pixel brne ANIM_RUN_LOOP ; done ret ; backwards run animation ; input: - ; output: - ; changes: X, FRAME, CNT, DATA, TMP ANIM_BW_RUN: ldi CNT,42 ; start after last pixel ANIM_BW_RUN_LOOP: rcall CLEAR ; clear ldi DATA,15 ; current pixel full on rcall SET_PIXEL ldi TMP,10 ; show frame 55 ms rcall OUT_FRAME_TIME dec CNT ; previous pixel cpi CNT,255 ; loop until before 1st pixel brne ANIM_BW_RUN_LOOP ; done ret ; worm animation ; input: - ; output: - ; changes: X, FRAME, CNT, DATA, TMP ANIM_WORM: ldi CNT,255 ; worm starts before 1st pixel ANIM_WORM_LOOP: rcall CLEAR ; draw worm rcall DRAW_WORM ldi TMP,10 ; show frame 55 ms rcall OUT_FRAME_TIME inc CNT ; advance worm cpi CNT,57 ; loop until has exits brne ANIM_WORM_LOOP ; done ret ; backwards worm animation ; input: - ; output: - ; changes: X, FRAME, CNT, DATA, TMP ANIM_BW_WORM: ldi CNT,56 ; worm starts behind frame ; head not yet visible ANIM_BW_WORM_LOOP: rcall CLEAR ; draw backwards worm rcall DRAW_BW_WORM ldi TMP,10 ; show frame 55 ms rcall OUT_FRAME_TIME dec CNT ; advance worm backwards cpi CNT,254 ; loop until worm has exited brne ANIM_BW_WORM_LOOP ; done ret ; main program MAIN: wdr ; initialization ; enable interrupts sei MAIN_LOOP: wdr ; main loop rcall_N ANIM_BLINK,3 rcall_N ANIM_WORM,3 rcall_N ANIM_FLICKER,10 rcall_N ANIM_BW_RUN,3 rcall_N ANIM_FADE,2 rcall_N ANIM_BW_WORM,3 rcall_N ANIM_WOBBLE,5 rcall_N ANIM_RUN,3 ; bottom of main loop rjmp MAIN_LOOP