930166dd3b763f75cfd3b10b081f1170a1b51843
Stefan Schuermans initial version of firmware

Stefan Schuermans authored 5 years ago

1) ; Chaosknoten - animated logo board
2) ; Copyright (C) 2019 Stefan Schuermans <stefan@blinkenarea.org>
3) ; Copyleft: GNU public license - http://www.gnu.org/copyleft/gpl.html
4) 
5) ; ATtiny2313A, clock frequency: 8 MHz (internal oscillator)
6) 
7) ; PA0: unused
8) ; PA1: unused
9) ; PA2: reset
10) ; PB0: column 0 output (output, low)
11) ; PB1: column 1 output (output, low)
12) ; PB2: column 2 output (output, low)
13) ; PB3: column 3 output (output, low)
14) ; PB4: column 4 output (output, low)
15) ; PB5: column 5 output (output, low)
16) ; PB6: column 6 output (output, low)
17) ; PB7: unused (input, pull-up enabled)
18) ; PD0: row 0 output (output, high)
19) ; PD1: row 1 output (output, high)
20) ; PD2: row 2 output (output, high)
21) ; PD3: row 3 output (output, high)
22) ; PD4: row 4 output (output, high)
23) ; PD5: row 5 output (output, high)
24) ; PD6: mode switch (input, pull-up enabled)
25) 
26) 
27) 
28) .INCLUDE        "tn2313def.inc"
29) 
30) 
31) 
32) ; IO pins
33) .equ    COL_PORT                =       PORTB   ; column outputs
34) .equ    ROW_PORT                =       PORTD   ; row outputs
35) .equ    MODE_SW_PIN             =       PIND
36) .equ    MODE_SW_BIT             =       6
37) 
38) 
39) 
40) ; general purpose registers
41) .def    TMP                     =       r16
42) .def    TMP2                    =       r17
43) .def    CNT                     =       r18
44) .def    DATA                    =       r19
45) .def    GRAY                    =       r20
46) 
47) ; current mode
48) .def    MODE                    =       r21
49) .equ    MODE_ALL                =       0       ; play all animations
50) .equ    MODE_SINGLE             =       1       ; play single animation only
51) .equ    MODE_UNKNOWN            =       0xFF    ; unknown mode
52) 
53) ; current animation number and iterations
54) .def    ANI_NO                  =       r22
55) .def    ANI_IT                  =       r23
56) 
57) 
58) 
59) .DSEG
60) .ORG    0x060
61) 
62) 
63) 
64) ; current frame
65) FRAME:                  .BYTE   42
66) 
67) 
68) 
69) .CSEG
70) .ORG    0x000
71)         rjmp    ENTRY                   ; RESET
72)         reti                            ; INT0
73)         reti                            ; INT1
74)         reti                            ; TIMER1_CAPT
75)         reti                            ; TIMER1_COMPA
76)         reti                            ; TIMER1_OVF
77)         reti                            ; TIMER0_OVF
78)         reti                            ; USART0_RX
79)         reti                            ; USART0_UDRE
80)         reti                            ; USART0_TX
81)         reti                            ; ANALOG_COMP
82)         reti                            ; PC_INT0
83)         reti                            ; TIMER1_COMPB
84)         reti                            ; TIMER0_COMPA
85)         reti                            ; TIMER0_COMPB
86)         reti                            ; USI_START
87)         reti                            ; USI_OVERFLOW
88)         reti                            ; EE_READY
89)         reti                            ; WDT
90)         reti                            ; PC_INT1
91)         reti                            ; PC_INT2
92) 
93) 
94) 
95) ; code entry point
96) ENTRY:
97) ; set system clock prescaler to 1:1
98)         ldi     TMP,1<<CLKPCE
99)         out     CLKPR,TMP
100)         ldi     TMP,0
101)         out     CLKPR,TMP
102) ; initialize output ports
103)         ldi     TMP,0x00                ; PA[01] to output, low
104)         out     PORTA,TMP
105)         ldi     TMP,0x03
106)         out     DDRA,TMP
107)         ldi     TMP,0x80                ; PB[0-6] to output, low - PB7 to input, pull-up enabled
108)         out     PORTB,TMP
109)         ldi     TMP,0x7F
110)         out     DDRB,TMP
111)         ldi     TMP,0x7F                ; PD[0-5] to output, high - PD6 to input, pull-up enabled
112)         out     PORTD,TMP
113)         ldi     TMP,0x3F
114)         out     DDRD,TMP
115) ; initialize stack pointer
116)         ldi     TMP,RAMEND
117)         out     SPL,TMP
118) ; enable watchdog (64ms)
119)         wdr
120)         ldi     TMP,1<<WDCE|1<<WDE
121)         out     WDTCR,TMP
122)         ldi     TMP,1<<WDE|1<<WDP1
123)         out     WDTCR,TMP
124)         wdr
125) ; disable analog comparator
126)         ldi     TMP,1<<ACD
127)         out     ACSR,TMP
128) ; jump to main program
129)         rjmp    MAIN
130) 
131) 
132) 
133) ; wait 61 cycles
134) ; input: -
135) ; output: -
136) ; changes: TMP
137) ; cycles: 61 (including rcall and ret)
138) WAIT61:
139)         ldi     TMP,18
140) WAIT61_LOOP:
141)         dec     TMP
142)         brne    WAIT61_LOOP
143) ; done
144)         ret
145) 
146) 
147) 
148) ; output row for grayscale (black/white) and wait
149) ; input: X = ptr to pixel data (0..15)
150) ;        GRAY = grayscale value (1..15)
151) ; output: -
152) ; changes: TMP, TMP2, DATA
153) ; cycles: GRAY * 64 + 1 (including rcall and ret)
154) ROW_BW_WAIT:
155) ; get data for LEDs
156)         ldi     TMP2,7                  ; 7 pixels
157) ROW_BW_WAIT_PIXEL:
158)         ld      TMP,X+                  ; get pixel value
159)         cp      TMP,GRAY                ; compare with grayscale value
160)         ror     DATA                    ; store result as output bit
161)         dec     TMP2                    ; next pixel
162)         brne    ROW_BW_WAIT_PIXEL
163) ; restore data pointer
164)         subi    XL,7                    ;   XH not there on ATtiny2313
165) ; output
166)         lsr     DATA                    ; ensure remaining bit stays high
167)                                         ;   (pull-up for unused pin)
168)         com     DATA
169)         out     COL_PORT,DATA
170) ; wait 5 + (GRAY - 1) * 64
171)         mov     TMP2,GRAY
172)         rjmp    ROW_BW_WAIT_LOOP_ENTRY
173) ROW_BW_WAIT_LOOP:
174)         rcall   WAIT61
175) ROW_BW_WAIT_LOOP_ENTRY:
176)         dec     TMP2
177)         brne    ROW_BW_WAIT_LOOP
178)         ret
179) 
180) 
181) 
182) ; turn off row (with same timing as ROW_BW_WAIT)
183) ; input: -
184) ; output: -
185) ; changes: TMP
186) ; cycles: 60 (including rcall and ret)
187) ROW_OFF:
188)         ldi     TMP,17
189) ROW_OFF_LOOP:
190)         dec     TMP
191)         brne    ROW_OFF_LOOP
192)         ldi     TMP,0x80                ; ensure remaining bit stays high
193)                                         ;   (pull-up for unused pin)
194)         out     COL_PORT,TMP
195)         ret
196) 
197) 
198) 
199) ; output row (grayscales)
200) ; input: X = ptr to pixel data (0..15)
201) ; output: -
202) ; changes: TMP, TMP2, DATA
203) ; cycles: 7822 (including rcall and ret)
204) ; time: 1ms
205) ROW_GRAY:
206)         ldi     GRAY,1
207) ROW_GRAY_LOOP:
208)         rcall   ROW_BW_WAIT
209)         inc     GRAY
210)         cpi     GRAY,16
211)         brlo    ROW_GRAY_LOOP
212)         rcall   ROW_OFF
213) ; done
214)         ret
215) 
216) 
217) 
218) ; output a frame
219) ; input: FRAME = pixel data (0..15)
220) ; output: -
221) ; changes: TMP, TMP2, CNT, DATA, X
222) ; time: 6ms
223) OUT_FRAME:
224)         wdr
225)         ldi     XL,low(FRAME)           ; ptr to pixel data
226)                                         ;   XH not there on ATtiny2313
227)         ldi     CNT,0x01                ; bitmask loop over rows
228) OUT_FRAME_LOOP:
229)         mov     TMP,CNT                 ; select row
230)         com     TMP
231)         andi    TMP,0x3F
232)         ori     TMP,0x40                ; ensure bit 6 stays high
233)                                         ;   (pull-up for switch input)
234)         out     ROW_PORT,TMP
235)         rcall   ROW_GRAY                ; display row
236)         subi    XL,-7                   ; ptr to next row
237)                                         ;   XH not there on ATtiny2313
238)         lsl     CNT                     ; bitmask loop over rows
239)         cpi     CNT,0x40
240)         brne    OUT_FRAME_LOOP
241) ; done
242)         ret
243) 
244) 
245) 
246) ; output a frame for some time
247) ; input: FRAME = pixel data (0..15)
248) ;        TMP = time to show frame (1..255, in 6 ms steps)
249) ; output: -
250) ; changes: X, TMP, TMP2
251) ; time: TMP * 6 ms
252) OUT_FRAME_TIME:
253) ; output frame
254)         push    TMP
255)         push    CNT
256)         push    DATA
257)         rcall   OUT_FRAME               ; 6 ms
258)         pop     DATA
259)         pop     CNT
260)         pop     TMP
261) ; loop
262)         dec     TMP
263)         brne    OUT_FRAME_TIME
264) ; done
265)         ret
266) 
267) 
268) 
269) ; clear frame
270) ; input: -
271) ; output: -
272) ; changes: X, FRAME, TMP
273) ; time: short
274) CLEAR:
275)         ldi     XL,low(FRAME)           ; ptr to pixel data
276)                                         ;   XH not there on ATtiny2313
277)         clr     TMP
278) CLEAR_LOOP:
279)         st      X+,TMP                  ; clear pixel
280)         cpi     XL,low(FRAME)+42        ; bottom of loop
281)                                         ;   XH not there on ATtiny2313
282)         brne    CLEAR_LOOP
283) ; done
284)         ret
285) 
286) 
287) 
288) ; set frame to solid color
289) ; input: DATA = value (0..15)
290) ; output: -
291) ; changes: X, FRAME
292) ; time: short
293) SET_COLOR:
294)         ldi     XL,low(FRAME)           ; ptr to pixel data
295)                                         ;   XH not there on ATtiny2313
296) SET_COLOR_LOOP:
297)         st      X+,DATA                 ; set pixel value
298)         cpi     XL,low(FRAME)+42        ; bottom of loop
299)                                         ;   XH not there on ATtiny2313
300)         brne    SET_COLOR_LOOP
301) ; done
302)         ret
303) 
304) 
305) 
306) ; set pixel
307) ; input: CNT = pixel number (0..41, nothing is done for 42..255)
308) ;        DATA = value (0..15)
309) ; output: -
310) ; changes: X, FRAME, TMP
311) ; time: short
312) SET_PIXEL:
313)         cpi     CNT,42                  ; invalid pixel number -> done
314)         brsh    SET_PIXEL_END
315)         ldi     XL,low(FRAME)           ; ptr to pixel (base + offset)
316)         add     XL,CNT                  ;   XH not there on ATtiny2313
317)         st      X,DATA                  ; set pixel
318) SET_PIXEL_END:
319) ; done
320)         ret
321) 
322) 
323) 
324) ; blink animation
325) ; input: -
326) ; output: -
327) ; changes: X, FRAME, CNT, DATA, TMP, TMP2
328) ANIM_BLINK:
329) ; off
330)         ldi     DATA,0                  ; minimum color
331)         rcall   SET_COLOR               ; paint
332)         ldi     TMP,100                 ; show frame 600 ms
333)         rcall   OUT_FRAME_TIME
334) ; on
335)         ldi     DATA,15                 ; maximum color
336)         rcall   SET_COLOR               ; paint
337)         ldi     TMP,100                 ; show frame 600 ms
338)         rcall   OUT_FRAME_TIME
339) ; done
340)         ret
341) 
342) 
343) 
344) ; fade up and down animation
345) ; input: -
346) ; output: -
347) ; changes: X, FRAME, CNT, DATA, TMP, TMP2
348) ANIM_FADE:
349) ; fade up
350)         ldi     DATA,0                  ; start dark
351) ANIM_FADE_UP:
352)         rcall   SET_COLOR               ; paint
353)         ldi     TMP,10                  ; show frame 60 ms
354)         rcall   OUT_FRAME_TIME
355)         inc     DATA                    ; fade up
356)         cpi     DATA,15                 ; loop until almost full on
357)         brne    ANIM_FADE_UP
358) ; fade down
359) ANIM_FADE_DOWN:
360)         rcall   SET_COLOR               ; paint
361)         ldi     TMP,10                  ; show frame 60 ms
362)         rcall   OUT_FRAME_TIME
363)         dec     DATA                    ; fade up
364)         cpi     DATA,255                ; loop until full off
365)         brne    ANIM_FADE_DOWN
366) ; done
367)         ret
368) 
369) 
370) 
Stefan Schuermans movie compression, add anot...

Stefan Schuermans authored 5 years ago

371) ; movie data format
372) ;   movie = frame ... frame end
373) ;   frame = 0x0_ ... -> plain frame
374) ;           0x1_ ... -> rle (run length encoded) frame
375) ;           0x2_ ... -> back reference
376) ;   plain frame = duration_high (0x00..0x0F), duration_low (0x00..0xFF),
377) ;                 21 * ( pixel (0x00..0x0F)) << 4 | pixel (0x00..0x0F) )
378) ;   rle frame = 0x10 | duration_high (0x00..0x0F), duration_low (0x00..0xFF),
379) ;               rle entry, ..., rle_entry (until 42 pixels are encoded)
380) ;   rle_entry = repeat (0x00..0x0F) << 4 | value (0x00..0x0F)
381) ;               meaning: repeat + 1 pixels of value
382) ;   back reference = 0x20 | back_high (0x00..0x0F), back_low (0x00..0xFF)
383) ;                    meaning: read frame from earlier position,
384) ;                             frame data start = pos after back ref - back
385) ;   end = 0xF_
386) 
387) 
388) 
389) ; play animation - process code and following section
Stefan Schuermans bbm2Chaosknoten

Stefan Schuermans authored 5 years ago

390) ; input: Z = pointer to movie data
Stefan Schuermans movie compression, add anot...

Stefan Schuermans authored 5 years ago

391) ;        TMP2 = 0 -> initial call, 1 -> nested call
392) ; output: Z = pointer to behind processed movie data (only for initial call)
393) ;         TMP = 0 -> go on, 1 -> end
394) ; changes: X, FRAME, TMP, DATA, CNT
395) ;          Z (only for nested call)
396) ANIM_MOVIE_CODE:
397) ; get 4 bit code and 12 bit value
398)         lpm     DATA,Z+
399)         lpm     CNT,Z+
400)         mov     TMP,DATA
401)         andi    TMP,0xF0                ; 4 bit code (shifted left 4) is in TMP
402)         andi    DATA,0x0F               ; 12 bit value is in DATA:CNT
403) ; interpret code
404)         cpi     TMP,0x20
405)         brsh    ANIM_MOVIE_CODE_2_TO_F
406)         cpi     TMP,0x00
407)         breq    ANIM_MOVIE_CODE_0
408)         rjmp    ANIM_MOVIE_CODE_1
409) ANIM_MOVIE_CODE_2_TO_F:
410)         cpi     TMP,0x20
411)         breq    ANIM_MOVIE_CODE_2
412) ; unknown code -> end
413)         ldi     TMP,1                   ; end
414)         ret
415) 
416) ; plain frame
417) ANIM_MOVIE_CODE_0:
418) ; save 12 bit value
419)         push    DATA
420)         push    CNT
Stefan Schuermans bbm2Chaosknoten

Stefan Schuermans authored 5 years ago

421) ; extract frame to frame buffer
422)         ldi     XL,low(FRAME)           ; ptr to pixel data
423)                                         ;   XH not there on ATtiny2313
Stefan Schuermans movie compression, add anot...

Stefan Schuermans authored 5 years ago

424) ANIM_MOVIE_CODE_FRAME_PLAIN_LOOP:
Stefan Schuermans bbm2Chaosknoten

Stefan Schuermans authored 5 years ago

425)         lpm     DATA,Z+                 ; get two pixels
Stefan Schuermans movie compression, add anot...

Stefan Schuermans authored 5 years ago

426)         mov     TMP,DATA                ; write first pixel
427)         swap    TMP
428)         andi    TMP,0x0F
429)         st      X+,TMP
Stefan Schuermans bbm2Chaosknoten

Stefan Schuermans authored 5 years ago

430)         andi    DATA,0x0F               ; write second pixel
431)         st      X+,DATA
432)         cpi     XL,low(FRAME)+42        ; bottom of loop
433)                                         ;   XH not there on ATtiny2313
Stefan Schuermans movie compression, add anot...

Stefan Schuermans authored 5 years ago

434)         brlo    ANIM_MOVIE_CODE_FRAME_PLAIN_LOOP
435) ; restore 12 bit value
436)         pop     CNT
437)         pop     DATA
Stefan Schuermans bbm2Chaosknoten

Stefan Schuermans authored 5 years ago

438) ; show frame
Stefan Schuermans movie compression, add anot...

Stefan Schuermans authored 5 years ago

439)         rjmp    ANIM_MOVIE_CODE_SHOW
440) 
441) ; rle frame
442) ANIM_MOVIE_CODE_1:
443) ; save 12 bit value
444)         push    DATA
445)         push    CNT
446) ; extract frame to frame buffer
447)         ldi     XL,low(FRAME)           ; ptr to pixel data
448)                                         ;   XH not there on ATtiny2313
449)         ldi     CNT,0                   ; no pixel data yet
450) ANIM_MOVIE_CODE_FRAME_RLE_LOOP:
451) ; load new pixel data if none available
452)         cpi     CNT,0
453)         brne    ANIM_MOVIE_CODE_FRAME_RLE_DATA_OK
454)         lpm     DATA,Z+                 ; get repeat count and pixel value
455)         mov     CNT,DATA
456)         andi    DATA,0x0F               ; pixel value in DATA
457)         swap    CNT
458)         andi    CNT,0x0F                ; repeat count in CNT
459)         inc     CNT                     ; use for repeat count + 1 pixels
460) ANIM_MOVIE_CODE_FRAME_RLE_DATA_OK:
461) ; write pixel data to frame
462)         st      X+,DATA
463) ; count down available pixel data
464)         dec     CNT
465) ; bottom of loop
466)         cpi     XL,low(FRAME)+42        ;   XH not there on ATtiny2313
467)         brlo    ANIM_MOVIE_CODE_FRAME_RLE_LOOP
468) ; restore 12 bit value
469)         pop     CNT
470)         pop     DATA
471) ; show frame
472)         rjmp    ANIM_MOVIE_CODE_SHOW
473) 
474) ; back reference
475) ANIM_MOVIE_CODE_2:
476) ; check if in nested call
477)         cpi     TMP2,0
478)         brne    ANIM_MOVIE_CODE_2_NESTED
479) ; save pointer to frame data
480)         push    ZL
481)         push    ZH
482) ; go back by 12 bit value in DATA:CNT
483)         sub     ZL,CNT
484)         sbc     ZH,DATA
485) ; recursive call
486)         ldi     TMP2,1                  ; nested call
487)         rcall   ANIM_MOVIE_CODE
488) ; restore pointer to frame data
489)         pop     ZH
490)         pop     ZL
491) ; done
492)         ldi     TMP,0                   ; continue
493)         ret
494) 
495) ; back reference - nested call
496) ANIM_MOVIE_CODE_2_NESTED:
497) ; go back by 12 bit value in DATA:CNT
498)         sub     ZL,CNT
499)         sbc     ZH,DATA
500) ; recursive tail call (no need to save Z on nested call)
501)         ldi     TMP2,1                  ; nested call
502)         rjmp    ANIM_MOVIE_CODE
503) 
504) ; show frame
505) ANIM_MOVIE_CODE_SHOW:
506) ; high part of frame time
507)         cpi     DATA,0
508)         breq    ANIM_MOVIE_CODE_SHOW_HIGH_DONE
509)         ldi     TMP,0                   ; means 256 frames times
510)         rcall   OUT_FRAME_TIME
511)         dec     DATA
512)         rjmp    ANIM_MOVIE_CODE_SHOW
513) ANIM_MOVIE_CODE_SHOW_HIGH_DONE:
514) ; low part of frame time
515)         cpi     CNT,0
516)         breq    ANIM_MOVIE_CODE_SHOW_LOW_DONE
517)         mov     TMP,CNT
518)         rcall   OUT_FRAME_TIME
519) ANIM_MOVIE_CODE_SHOW_LOW_DONE:
520) ; done
521)         ldi     TMP,0                   ; continue
522)         ret
523) 
524) 
525) 
526) ; play animation
527) ; input: Z = pointer to movie data
528) ; output: -
529) ; changes: X, Z, FRAME, CNT, DATA, TMP, TMP2
530) ANIM_MOVIE:
531) ; process code block
532)         ldi     TMP2,0                  ; initial call
533)         rcall   ANIM_MOVIE_CODE
534) ; continue if not yet end
535)         cpi     TMP,0
536)         breq    ANIM_MOVIE
537) ; done
Stefan Schuermans bbm2Chaosknoten

Stefan Schuermans authored 5 years ago

538)         ret
539) 
540) 
541) 
542) .INCLUDE        "movie_funcs.inc"
543) 
544) 
545) 
Stefan Schuermans initial version of firmware

Stefan Schuermans authored 5 years ago

546) ; read mode from switch and (store animation number)
547) ; input: MODE = old mode, CNT = animation number
548) ; output: MODE = new mode
549) ; changes: TMP, DATA
550) MODE_READ:
551) ; read new mode (into DATA)
552)         ldi     DATA,MODE_ALL
553)         sbic    MODE_SW_PIN,MODE_SW_BIT
554)         ldi     DATA,MODE_SINGLE
555) ; mode was changed from all to single -> save animation number
556)         cpi     MODE,MODE_ALL           ; old mode not all -> do nothing
557)         brne    MODE_READ_NOT_0_TO_1
558)         cpi     DATA,MODE_SINGLE        ; new mode not single -> do nothing
559)         brne    MODE_READ_NOT_0_TO_1
560)         sbic    EECR,EEPE               ; EEPROM write ongoing -> do nothing
561)         rjmp    MODE_READ_NOT_0_TO_1
562)         ldi     TMP,0<<EEPM1|0<<EEPM0   ; set EEPROM programming mode
563)         out     EECR,TMP
564)         ldi     TMP,0                   ; set EEPROM address
565)         out     EEARL,TMP
566)         mov     TMP,CNT                 ; set EEPROM data to animation number
567)         com     TMP                     ;   with NOTed number in upper nibble
568)         swap    TMP
569)         andi    TMP,0xF0
570)         or      TMP,CNT
571)         out     EEDR,TMP
572)         sbi     EECR,EEMPE              ; begin writing EEPROM
573)         sbi     EECR,EEPE
574) MODE_READ_NOT_0_TO_1:
575) ; remember new mode (in MODE)
576)         mov     MODE,DATA
577) ; done
578)         ret
579) 
580) 
581) 
582) ; animation table: animation function, iteration count (<= 255)
583) ANIM_TAB:
Stefan Schuermans bbm2Chaosknoten

Stefan Schuermans authored 5 years ago

584) .INCLUDE        "movie_tab.inc"