pretty bug kept for aesthetic purpose
petaflot

petaflot commited on 2019-08-27 18:26:38
Showing 2 changed files, with 1762 additions and 0 deletions.

... ...
@@ -0,0 +1,881 @@
1
+; bulb - BlinkenArea ultimate logo board
2
+; Copyright (C) 2011-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
+.def    BULB                    =       r24
47
+.def    BORDER                  =       r25
48
+
49
+; current mode
50
+.def    MODE                    =       r21
51
+.equ    MODE_ALL                =       0       ; play all animations
52
+.equ    MODE_SINGLE             =       1       ; play single animation only
53
+.equ    MODE_UNKNOWN            =       0xFF    ; unknown mode
54
+
55
+; current animation number and iterations
56
+.def    ANI_NO                  =       r22
57
+.def    ANI_IT                  =       r23
58
+
59
+
60
+
61
+.DSEG
62
+.ORG    0x060
63
+
64
+
65
+
66
+; current frame
67
+FRAME:                  .BYTE   42
68
+
69
+
70
+
71
+.CSEG
72
+.ORG    0x000
73
+        rjmp    ENTRY                   ; RESET
74
+        reti                            ; INT0
75
+        reti                            ; INT1
76
+        reti                            ; TIMER1_CAPT
77
+        reti                            ; TIMER1_COMPA
78
+        reti                            ; TIMER1_OVF
79
+        reti                            ; TIMER0_OVF
80
+        reti                            ; USART0_RX
81
+        reti                            ; USART0_UDRE
82
+        reti                            ; USART0_TX
83
+        reti                            ; ANALOG_COMP
84
+        reti                            ; PC_INT0
85
+        reti                            ; TIMER1_COMPB
86
+        reti                            ; TIMER0_COMPA
87
+        reti                            ; TIMER0_COMPB
88
+        reti                            ; USI_START
89
+        reti                            ; USI_OVERFLOW
90
+        reti                            ; EE_READY
91
+        reti                            ; WDT
92
+        reti                            ; PC_INT1
93
+        reti                            ; PC_INT2
94
+
95
+
96
+
97
+; code entry point
98
+ENTRY:
99
+; set system clock prescaler to 1:1
100
+        ldi     TMP,1<<CLKPCE
101
+        out     CLKPR,TMP
102
+        ldi     TMP,0
103
+        out     CLKPR,TMP
104
+; initialize output ports
105
+        ldi     TMP,0x00                ; PA[01] to output, low
106
+        out     PORTA,TMP
107
+        ldi     TMP,0x03
108
+        out     DDRA,TMP
109
+        ldi     TMP,0x80                ; PB[0-6] to output, low - PB7 to input, pull-up enabled
110
+        out     PORTB,TMP
111
+        ldi     TMP,0x7F
112
+        out     DDRB,TMP
113
+        ldi     TMP,0x7F                ; PD[0-5] to output, high - PD6 to input, pull-up enabled
114
+        out     PORTD,TMP
115
+        ldi     TMP,0x3F
116
+        out     DDRD,TMP
117
+; initialize stack pointer
118
+        ldi     TMP,RAMEND
119
+        out     SPL,TMP
120
+; enable watchdog (64ms)
121
+        wdr
122
+        ldi     TMP,1<<WDCE|1<<WDE
123
+        out     WDTCR,TMP
124
+        ldi     TMP,1<<WDE|1<<WDP1
125
+        out     WDTCR,TMP
126
+        wdr
127
+; disable analog comparator
128
+        ldi     TMP,1<<ACD
129
+        out     ACSR,TMP
130
+; jump to main program
131
+        rjmp    MAIN
132
+
133
+
134
+
135
+; wait 61 cycles
136
+; input: -
137
+; output: -
138
+; changes: TMP
139
+; cycles: 61 (including rcall and ret)
140
+WAIT61:
141
+        ldi     TMP,18
142
+WAIT61_LOOP:
143
+        dec     TMP
144
+        brne    WAIT61_LOOP
145
+; done
146
+        ret
147
+
148
+
149
+
150
+; output row for grayscale (black/white) and wait
151
+; input: X = ptr to pixel data (0..15)
152
+;        GRAY = grayscale value (1..15)
153
+; output: -
154
+; changes: TMP, TMP2, DATA
155
+; cycles: GRAY * 64 + 1 (including rcall and ret)
156
+ROW_BW_WAIT:
157
+; get data for LEDs
158
+        ldi     TMP2,7                  ; 7 pixels
159
+ROW_BW_WAIT_PIXEL:
160
+        ld      TMP,X+                  ; get pixel value
161
+        cp      TMP,GRAY                ; compare with grayscale value
162
+        ror     DATA                    ; store result as output bit
163
+        dec     TMP2                    ; next pixel
164
+        brne    ROW_BW_WAIT_PIXEL
165
+; restore data pointer
166
+        subi    XL,7                    ;   XH not there on ATtiny2313
167
+; output
168
+        lsr     DATA                    ; ensure remaining bit stays high
169
+                                        ;   (pull-up for unused pin)
170
+        com     DATA
171
+        out     COL_PORT,DATA
172
+; wait 5 + (GRAY - 1) * 64
173
+        mov     TMP2,GRAY
174
+        rjmp    ROW_BW_WAIT_LOOP_ENTRY
175
+ROW_BW_WAIT_LOOP:
176
+        rcall   WAIT61
177
+ROW_BW_WAIT_LOOP_ENTRY:
178
+        dec     TMP2
179
+        brne    ROW_BW_WAIT_LOOP
180
+        ret
181
+
182
+
183
+
184
+; turn off row (with same timing as ROW_BW_WAIT)
185
+; input: -
186
+; output: -
187
+; changes: TMP
188
+; cycles: 60 (including rcall and ret)
189
+ROW_OFF:
190
+        ldi     TMP,17
191
+ROW_OFF_LOOP:
192
+        dec     TMP
193
+        brne    ROW_OFF_LOOP
194
+        ldi     TMP,0x80                ; ensure remaining bit stays high
195
+                                        ;   (pull-up for unused pin)
196
+        out     COL_PORT,TMP
197
+        ret
198
+
199
+
200
+
201
+; output row (grayscales)
202
+; input: X = ptr to pixel data (0..15)
203
+; output: -
204
+; changes: TMP, TMP2, DATA
205
+; cycles: 7822 (including rcall and ret)
206
+; time: 1ms
207
+ROW_GRAY:
208
+        ldi     GRAY,1
209
+ROW_GRAY_LOOP:
210
+        rcall   ROW_BW_WAIT
211
+        inc     GRAY
212
+        cpi     GRAY,16
213
+        brlo    ROW_GRAY_LOOP
214
+        rcall   ROW_OFF
215
+; done
216
+        ret
217
+
218
+
219
+
220
+; output a frame
221
+; input: FRAME = pixel data (0..15)
222
+; output: -
223
+; changes: TMP, TMP2, CNT, DATA, X
224
+; time: 6ms
225
+OUT_FRAME:
226
+        wdr
227
+        ldi     XL,low(FRAME)           ; ptr to pixel data
228
+                                        ;   XH not there on ATtiny2313
229
+        ldi     CNT,0x01                ; bitmask loop over rows
230
+OUT_FRAME_LOOP:
231
+        mov     TMP,CNT                 ; select row
232
+        com     TMP
233
+        andi    TMP,0x3F
234
+        ori     TMP,0x40                ; ensure bit 6 stays high
235
+                                        ;   (pull-up for switch input)
236
+        out     ROW_PORT,TMP
237
+        rcall   ROW_GRAY                ; display row
238
+        subi    XL,-7                   ; ptr to next row
239
+                                        ;   XH not there on ATtiny2313
240
+        lsl     CNT                     ; bitmask loop over rows
241
+        cpi     CNT,0x40
242
+        brne    OUT_FRAME_LOOP
243
+; done
244
+        ret
245
+
246
+
247
+
248
+; output a frame for some time
249
+; input: FRAME = pixel data (0..15)
250
+;        TMP = time to show frame (1..255, in 6 ms steps)
251
+; output: -
252
+; changes: X, TMP, TMP2
253
+; time: TMP * 6 ms
254
+OUT_FRAME_TIME:
255
+; output frame
256
+        push    TMP
257
+        push    CNT
258
+        push    DATA
259
+        rcall   OUT_FRAME               ; 6 ms
260
+        pop     DATA
261
+        pop     CNT
262
+        pop     TMP
263
+; loop
264
+        dec     TMP
265
+        brne    OUT_FRAME_TIME
266
+; done
267
+        ret
268
+
269
+
270
+
271
+; clear frame
272
+; input: -
273
+; output: -
274
+; changes: X, FRAME, TMP
275
+; time: short
276
+CLEAR:
277
+        ldi     XL,low(FRAME)           ; ptr to pixel data
278
+                                        ;   XH not there on ATtiny2313
279
+        clr     TMP
280
+CLEAR_LOOP:
281
+        st      X+,TMP                  ; clear pixel
282
+        cpi     XL,low(FRAME)+42        ; bottom of loop
283
+                                        ;   XH not there on ATtiny2313
284
+        brne    CLEAR_LOOP
285
+; done
286
+        ret
287
+
288
+
289
+
290
+; set frame to solid color (all the same)
291
+; input: DATA = value (0..15) intensity for all LEDs
292
+; output: -
293
+; changes: X, FRAME
294
+; time: short
295
+SET_COLOR:
296
+        ldi     XL,low(FRAME)           ; ptr to pixel data
297
+                                        ;   XH not there on ATtiny2313
298
+SET_COLOR_LOOP:
299
+        st      X+,DATA                 ; set pixel value
300
+        cpi     XL,low(FRAME)+42        ; bottom of loop
301
+                                        ;   XH not there on ATtiny2313
302
+        brne    SET_COLOR_LOOP
303
+; done
304
+        ret
305
+
306
+; set bulb to solid color
307
+; input: BULB = value (0..15) intensity for all bulb LEDs except spark (28-40)
308
+; output: -
309
+; changes: X, BULB
310
+; time: short
311
+BULB_COLOR:
312
+        ldi     XL,low(FRAME+26)        ; ptr to pixel data
313
+                                        ;   XH not there on ATtiny2313
314
+BULB_COLOR_LOOP:
315
+        st      X+,BULB                 ; set pixel value
316
+        cpi     XL,low(FRAME)+41        ; bottom of loop
317
+                                        ;   XH not there on ATtiny2313
318
+        ldi     BORDER,15               ; start bright
319
+
320
+        brne    BULB_COLOR_LOOP
321
+; done
322
+        ret
323
+
324
+; set border to solid color
325
+; input: BORDER = value (0..15) intensity for all border LEDs
326
+; output: -
327
+; changes: X, BORDER
328
+; time: short
329
+BORDER_COLOR:
330
+        ldi     XL,low(FRAME)           ; ptr to pixel data
331
+                                        ;   XH not there on ATtiny2313
332
+BORDER_COLOR_LOOP:
333
+        st      X+,BORDER               ; set pixel value
334
+        cpi     XL,low(FRAME)+28        ; bottom of loop
335
+                                        ;   XH not there on ATtiny2313
336
+        brne    BORDER_COLOR_LOOP
337
+; done
338
+        ret
339
+
340
+
341
+; set pixel
342
+; input: CNT = pixel number (0..41, nothing is done for 42..255)
343
+;        DATA = value (0..15)
344
+; output: -
345
+; changes: X, FRAME, TMP
346
+; time: short
347
+SET_PIXEL:
348
+        cpi     CNT,42                  ; invalid pixel number -> done
349
+        brsh    SET_PIXEL_END
350
+        ldi     XL,low(FRAME)           ; ptr to pixel (base + offset)
351
+        add     XL,CNT                  ;   XH not there on ATtiny2313
352
+        st      X,DATA                  ; set pixel
353
+SET_PIXEL_END:
354
+; done
355
+        ret
356
+
357
+
358
+
359
+; draw worm
360
+; input: CNT = head of worm (0..55)
361
+; output: -
362
+; changes: X, FRAME, TMP, DATA
363
+; time: short
364
+DRAW_WORM:
365
+        cpi     CNT,56                  ; invalid head pos -> done
366
+        brsh    DRAW_WORM_END
367
+        ldi     XL,low(FRAME)+1         ; ptr to before head
368
+        add     XL,CNT                  ;   XH not there on ATtiny2313
369
+        ldi     DATA,15                 ; head is full on
370
+        cpi     CNT,42                  ; head pos in frame -> go
371
+        brlo    DRAW_WORM_LOOP
372
+        mov     TMP,CNT                 ; TMP := invisible pixels
373
+        subi    TMP,41
374
+        sub     XL,TMP                  ; skip invisible pixels
375
+        sub     DATA,TMP                ;   XH not there on ATtiny2313
376
+DRAW_WORM_LOOP:
377
+        st      -X,DATA                 ; set pixel, go back
378
+        cpi     XL,low(FRAME)           ; 1st pixel -> done
379
+        breq    DRAW_WORM_END           ;   XH not there on ATtiny2313
380
+        dec     DATA                    ; next pixel darker
381
+        brne    DRAW_WORM_LOOP          ; loop
382
+DRAW_WORM_END:
383
+; done
384
+        ret
385
+
386
+
387
+
388
+; draw backwards worm
389
+; input: CNT = tail of worm (0..55)
390
+; output: -
391
+; changes: X, FRAME, TMP, DATA
392
+; time: short
393
+DRAW_BW_WORM:
394
+        cpi     CNT,56                  ; invalid tail pos -> done
395
+        brsh    DRAW_BW_WORM_END
396
+        ldi     XL,low(FRAME)+1         ; ptr to before tail
397
+        add     XL,CNT                  ;   XH not there on ATtiny2313
398
+        ldi     DATA,1                  ; tail is minimum on
399
+        cpi     CNT,42                  ; tail pos in frame -> go
400
+        brlo    DRAW_BW_WORM_LOOP
401
+        mov     TMP,CNT                 ; TMP := invisible pixels
402
+        subi    TMP,41
403
+        sub     XL,TMP                  ; skip invisible pixels
404
+        add     DATA,TMP                ;   XH not there on ATtiny2313
405
+DRAW_BW_WORM_LOOP:
406
+        st      -X,DATA                 ; set pixel, go back
407
+        cpi     XL,low(FRAME)           ; 1st pixel -> done
408
+        breq    DRAW_BW_WORM_END        ;   XH not there on ATtiny2313
409
+        inc     DATA                    ; next pixel brighter
410
+        cpi     DATA,16                 ; loop
411
+        brne    DRAW_BW_WORM_LOOP
412
+DRAW_BW_WORM_END:
413
+; done
414
+        ret
415
+
416
+
417
+
418
+; blink animation
419
+; input: -
420
+; output: -
421
+; changes: X, FRAME, CNT, DATA, TMP, TMP2
422
+ANIM_BLINK:
423
+; off
424
+        ldi     DATA,0                  ; minimum color
425
+        rcall   SET_COLOR               ; paint
426
+        ldi     TMP,100                 ; show frame 600 ms
427
+        rcall   OUT_FRAME_TIME
428
+; on
429
+        ldi     DATA,15                 ; maximum color
430
+        rcall   SET_COLOR               ; paint
431
+        ldi     TMP,100                 ; show frame 600 ms
432
+        rcall   OUT_FRAME_TIME
433
+; done
434
+        ret
435
+
436
+
437
+
438
+; fade up and down animation
439
+; input: -
440
+; output: -
441
+; changes: X, FRAME, CNT, DATA, TMP, TMP2
442
+ANIM_FADE:
443
+; fade up
444
+        ldi     DATA,0                  ; start dark
445
+ANIM_FADE_UP:
446
+        rcall   SET_COLOR               ; paint
447
+        ldi     TMP,10                  ; show frame 60 ms
448
+        rcall   OUT_FRAME_TIME
449
+        inc     DATA                    ; fade up
450
+        cpi     DATA,15                 ; loop until almost full on
451
+        brne    ANIM_FADE_UP
452
+; fade down
453
+ANIM_FADE_DOWN:
454
+        rcall   SET_COLOR               ; paint
455
+        ldi     TMP,10                  ; show frame 60 ms
456
+        rcall   OUT_FRAME_TIME
457
+        dec     DATA                    ; fade up
458
+        cpi     DATA,255                ; loop until full off
459
+        brne    ANIM_FADE_DOWN
460
+; done
461
+        ret
462
+
463
+; fade up and down animation, bulb and frame are in opposite phase
464
+; input: -
465
+; output: -
466
+; changes: X, FRAME, CNT, DATA, BULB, BORDER, TMP, TMP2
467
+INVERTED_FADE:
468
+        ;rcall   CLEAR                   ; clear
469
+        ldi     DATA,0xf
470
+        sts     FRAME+41,DATA           ; set filament pixel
471
+
472
+        ldi     BORDER,15               ; start bright
473
+        ldi     BULB,0                  ; start dark
474
+INVERTED_FADE_BACK:;EVEN                     ; relative to the bulb
475
+        rcall   BORDER_COLOR            ; paint border (to darker)
476
+        rcall   BULB_COLOR              ; paint bulb (to brighter)
477
+        dec     BORDER                  ; fade down, 0-27
478
+        cpi     BORDER,255              ; loop until full off
479
+        inc     BULB                    ; fade up, 28-41
480
+        cpi     BULB,15                 ; loop until almost full on
481
+        ldi     TMP,10                  ; show frame 60 ms
482
+        rcall   OUT_FRAME_TIME
483
+        brne    INVERTED_FADE_BACK
484
+INVERTED_FADE_FORTH:;ODD
485
+        rcall   BORDER_COLOR            ; paint border (to brighter)
486
+        rcall   BULB_COLOR              ; paint bulb (to darker)
487
+        inc     BORDER                  ; fade up, 28-41
488
+        cpi     BORDER,15               ; loop until almost full on
489
+        dec     BULB                    ; fade down, 0-27
490
+        cpi     BULB,255                ; loop until full off
491
+        ldi     TMP,10                  ; show frame 60 ms
492
+        rcall   OUT_FRAME_TIME
493
+        brne    INVERTED_FADE_FORTH
494
+; done
495
+        ret
496
+
497
+
498
+; border (frame around bulb) blink animation
499
+; input: -
500
+; output: -
501
+; changes: X, FRAME, CNT, BORDER, TMP, TMP2
502
+ANIM_FRAMEBLINK:
503
+        rcall   CLEAR
504
+; off
505
+        ldi     BORDER,0                ; minimum color
506
+        rcall   BORDER_COLOR            ; paint
507
+        ldi     TMP,100                 ; show frame 600 ms
508
+        rcall   OUT_FRAME_TIME
509
+; on
510
+        ldi     BORDER,15               ; maximum color
511
+        rcall   BORDER_COLOR            ; paint
512
+        ldi     TMP,100                 ; show frame 600 ms
513
+        rcall   OUT_FRAME_TIME
514
+; done
515
+        ret
516
+
517
+; bulb blink animation, fast
518
+; input: -
519
+; output: -
520
+; changes: X, FRAME, CNT, BULB, TMP, TMP2
521
+ANIM_BULBFAST:
522
+        rcall   CLEAR
523
+        ldi     DATA,0xf
524
+        sts     FRAME+41,DATA           ; set filament pixel
525
+; off
526
+        ldi     BULB,0                ; minimum color
527
+        rcall   BULB_COLOR            ; paint
528
+        ldi     TMP,10                 ; show frame 20 ms
529
+        rcall   OUT_FRAME_TIME
530
+; on
531
+        ldi     BULB,15               ; maximum color
532
+        rcall   BULB_COLOR            ; paint
533
+        ldi     TMP,10                 ; show frame 20 ms
534
+        rcall   OUT_FRAME_TIME
535
+; done
536
+        ret
537
+
538
+; bulb blink animation, slow
539
+; input: -
540
+; output: -
541
+; changes: X, FRAME, CNT, BULB, TMP, TMP2
542
+ANIM_BULBSLOW:
543
+        rcall   CLEAR
544
+        ldi     DATA,0xf
545
+        sts     FRAME+41,DATA           ; set filament pixel
546
+; off
547
+        ldi     BULB,0                ; minimum color
548
+        rcall   BULB_COLOR            ; paint
549
+        ldi     TMP,200
550
+        rcall   OUT_FRAME_TIME
551
+; on
552
+        ldi     BULB,15               ; maximum color
553
+        rcall   BULB_COLOR            ; paint
554
+        ldi     TMP,200
555
+        rcall   OUT_FRAME_TIME
556
+; done
557
+        ret
558
+
559
+
560
+; flicker animation
561
+; input: -
562
+; output: -
563
+; changes: X, FRAME, CNT, DATA, TMP, TMP2
564
+ANIM_FLICKER:
565
+; even pixels
566
+        rcall   CLEAR                   ; clear
567
+        ldi     DATA,15                 ; even pixels to maximum
568
+        ldi     DATA,0xf
569
+        sts     FRAME+41,DATA                 ; set pixel, go back
570
+        ldi     CNT,0
571
+ANIM_FLICKER_EVEN:
572
+        rcall   SET_PIXEL
573
+        subi    CNT,-2                  ; move two pixels
574
+        cpi     CNT,42                  ; loop
575
+        brlo    ANIM_FLICKER_EVEN
576
+        ldi     TMP,20                  ; show frame 120 ms
577
+        rcall   OUT_FRAME_TIME
578
+; odd pixels
579
+        rcall   CLEAR                   ; clear
580
+        ldi     DATA,15                 ; odd pixels to maximum
581
+        ldi     CNT,1
582
+ANIM_FLICKER_ODD:
583
+        rcall   SET_PIXEL
584
+        subi    CNT,-2                  ; move two pixels
585
+        cpi     CNT,42                  ; loop
586
+        brlo    ANIM_FLICKER_ODD
587
+        ldi     TMP,20                  ; show frame 120 ms
588
+        rcall   OUT_FRAME_TIME
589
+; done
590
+        ret
591
+
592
+ANIM_IDLE:
593
+        rcall   CLEAR                   ; clear
594
+        ldi     TMP,500                 ; show frame 3000 ms
595
+        rcall   OUT_FRAME_TIME
596
+
597
+        ldi     DATA,0xf
598
+        sts     FRAME+41,DATA                 ; set pixel, go back
599
+
600
+        ldi     TMP,10                  ; show frame 60 ms
601
+        rcall   OUT_FRAME_TIME
602
+        ret
603
+
604
+
605
+
606
+
607
+; wobble animation
608
+; input: -
609
+; output: -
610
+; changes: X, FRAME, CNT, DATA, TMP, TMP2
611
+ANIM_WOBBLE:
612
+; even pixels up, odd pixels down
613
+        ldi     DATA,0                  ; even pixels start dark
614
+ANIM_WOBBLE_UP:
615
+        ldi     CNT,0
616
+ANIM_WOBBLE_UP_DRAW:
617
+        rcall   SET_PIXEL
618
+        inc     CNT                     ; next pixel
619
+        ldi     TMP,0x0F                ; invert color
620
+        eor     DATA,TMP
621
+        cpi     CNT,42                  ; loop
622
+        brlo    ANIM_WOBBLE_UP_DRAW
623
+        ldi     TMP,10                  ; show frame 60 ms
624
+        rcall   OUT_FRAME_TIME
625
+        inc     DATA                    ; next color: brighter
626
+        cpi     DATA,16
627
+        brlo    ANIM_WOBBLE_UP
628
+; even pixels down, odd pixels up
629
+        ldi     DATA,15                 ; even pixels start full
630
+ANIM_WOBBLE_DOWN:
631
+        ldi     CNT,0
632
+ANIM_WOBBLE_DOWN_DRAW:
633
+        rcall   SET_PIXEL
634
+        inc     CNT                     ; next pixel
635
+        ldi     TMP,0x0F                ; invert color
636
+        eor     DATA,TMP
637
+        cpi     CNT,42                  ; loop
638
+        brlo    ANIM_WOBBLE_DOWN_DRAW
639
+        ldi     TMP,10                  ; show frame 60 ms
640
+        rcall   OUT_FRAME_TIME
641
+        dec     DATA                    ; next color: darker
642
+        cpi     DATA,16
643
+        brlo    ANIM_WOBBLE_DOWN
644
+; done
645
+        ret
646
+
647
+
648
+
649
+; run animation
650
+; input: -
651
+; output: -
652
+; changes: X, FRAME, CNT, DATA, TMP, TMP2
653
+ANIM_RUN:
654
+        ldi     CNT,255                 ; start before 1st pixel
655
+ANIM_RUN_LOOP:
656
+        rcall   CLEAR                   ; clear
657
+        ldi     DATA,15                 ; current pixel full on
658
+        rcall   SET_PIXEL
659
+        ldi     TMP,10                  ; show frame 60 ms
660
+        rcall   OUT_FRAME_TIME
661
+        inc     CNT                     ; next pixel
662
+        cpi     CNT,41                  ; loop until after last pixel
663
+        brne    ANIM_RUN_LOOP
664
+; done
665
+        ret
666
+
667
+
668
+
669
+; backwards run animation
670
+; input: -
671
+; output: -
672
+; changes: X, FRAME, CNT, DATA, TMP, TMP2
673
+ANIM_BW_RUN:
674
+        ldi     CNT,40                  ; start after last pixel
675
+ANIM_BW_RUN_LOOP:
676
+        rcall   CLEAR                   ; clear
677
+        ldi     DATA,15                 ; current pixel full on
678
+        rcall   SET_PIXEL
679
+        ldi     TMP,10                  ; show frame 60 ms
680
+        rcall   OUT_FRAME_TIME
681
+        dec     CNT                     ; previous pixel
682
+        cpi     CNT,255                 ; loop until before 1st pixel
683
+        brne    ANIM_BW_RUN_LOOP
684
+; done
685
+        ret
686
+
687
+
688
+
689
+; worm animation
690
+; input: -
691
+; output: -
692
+; changes: X, FRAME, CNT, DATA, TMP, TMP2
693
+ANIM_WORM:
694
+        ldi     CNT,255                 ; worm starts before 1st pixel
695
+ANIM_WORM_LOOP:
696
+        rcall   CLEAR                   ; draw worm
697
+        rcall   DRAW_WORM
698
+        ldi     TMP,10                  ; show frame 60 ms
699
+        rcall   OUT_FRAME_TIME
700
+        inc     CNT                     ; advance worm
701
+        cpi     CNT,57                  ; loop until has exits
702
+        brne    ANIM_WORM_LOOP
703
+; done
704
+        ret
705
+
706
+
707
+
708
+; backwards worm animation
709
+; input: -
710
+; output: -
711
+; changes: X, FRAME, CNT, DATA, TMP, TMP2
712
+ANIM_BW_WORM:
713
+        ldi     CNT,56                  ; worm starts behind frame
714
+                                        ;   head not yet visible
715
+ANIM_BW_WORM_LOOP:
716
+        rcall   CLEAR                   ; draw backwards worm
717
+        rcall   DRAW_BW_WORM
718
+        ldi     TMP,10                  ; show frame 60 ms
719
+        rcall   OUT_FRAME_TIME
720
+        dec     CNT                     ; advance worm backwards
721
+        cpi     CNT,254                 ; loop until worm has exited
722
+        brne    ANIM_BW_WORM_LOOP
723
+; done
724
+        ret
725
+
726
+
727
+
728
+; read mode from switch and (store animation number)
729
+; input: MODE = old mode, CNT = animation number
730
+; output: MODE = new mode
731
+; changes: TMP, DATA
732
+MODE_READ:
733
+; read new mode (into DATA)
734
+        ldi     DATA,MODE_ALL
735
+        sbic    MODE_SW_PIN,MODE_SW_BIT
736
+        ldi     DATA,MODE_SINGLE
737
+; mode was changed from all to single -> save animation number
738
+        cpi     MODE,MODE_ALL           ; old mode not all -> do nothing
739
+        brne    MODE_READ_NOT_0_TO_1
740
+        cpi     DATA,MODE_SINGLE        ; new mode not single -> do nothing
741
+        brne    MODE_READ_NOT_0_TO_1
742
+        sbic    EECR,EEPE               ; EEPROM write ongoing -> do nothing
743
+        rjmp    MODE_READ_NOT_0_TO_1
744
+        ldi     TMP,0<<EEPM1|0<<EEPM0   ; set EEPROM programming mode
745
+        out     EECR,TMP
746
+        ldi     TMP,0                   ; set EEPROM address
747
+        out     EEARL,TMP
748
+        mov     TMP,CNT                 ; set EEPROM data to animation number
749
+        com     TMP                     ;   with NOTed number in upper nibble
750
+        swap    TMP
751
+        andi    TMP,0xF0
752
+        or      TMP,CNT
753
+        out     EEDR,TMP
754
+        sbi     EECR,EEMPE              ; begin writing EEPROM
755
+        sbi     EECR,EEPE
756
+MODE_READ_NOT_0_TO_1:
757
+; remember new mode (in MODE)
758
+        mov     MODE,DATA
759
+; done
760
+        ret
761
+
762
+
763
+
764
+; animation table: animation function, iteration count (<= 255)
765
+ANIM_TAB:
766
+        ;.dw     ANIM_FRAMEBLINK
767
+        ;.dw     5
768
+        ;.dw     ANIM_BULBSLOW
769
+        ;.dw     3
770
+        ;.dw     ANIM_WORM
771
+        ;.dw     1
772
+        ;.dw     ANIM_IDLE
773
+        ;.dw     5
774
+        ;.dw     ANIM_BW_WORM
775
+        ;.dw     1
776
+        ;.dw     ANIM_RUN
777
+        ;.dw     1
778
+        ;.dw     ANIM_BW_RUN
779
+        ;.dw     1
780
+        ;.dw     ANIM_WORM
781
+        ;.dw     1
782
+        ;.dw     ANIM_IDLE
783
+        ;.dw     1
784
+        .dw     INVERTED_FADE
785
+        .dw     5
786
+        ;.dw     ANIM_IDLE
787
+        ;.dw     2
788
+        ;.dw     ANIM_FLICKER
789
+        ;.dw     10
790
+        ;.dw     ANIM_IDLE
791
+        ;.dw     2
792
+        ;.dw     ANIM_FRAMEBLINK
793
+        ;.dw     1
794
+        ;.dw     ANIM_BULBFAST
795
+        ;.dw     5
796
+        ;.dw     ANIM_FRAMEBLINK
797
+        ;.dw     1
798
+        ;.dw     ANIM_IDLE
799
+        ;.dw     5
800
+        ;.dw     INVERTED_FADE
801
+        ;.dw     5
802
+        ;.dw     ANIM_IDLE
803
+        ;.dw     2
804
+        ;.dw     ANIM_WOBBLE
805
+        ;.dw     5
806
+ANIM_TAB_END:
807
+
808
+
809
+
810
+; main program
811
+MAIN:
812
+        wdr
813
+
814
+; initialization
815
+        ldi     MODE,MODE_UNKNOWN       ; unknown mode
816
+
817
+; get number of fist animation from EEPROM (into CNT)
818
+        ldi     TMP,0                   ; set EEPROM address
819
+        out     EEARL,TMP
820
+        sbi     EECR,EERE               ; start EEPROM read
821
+        in      ANI_NO,EEDR                ; get read value
822
+        mov     TMP,ANI_NO              ; check if high nibble contains NOTed
823
+        com     TMP                     ;   value
824
+        swap    TMP
825
+        cp      ANI_NO,TMP
826
+        brne    MAIN_FIRST_ANIM_INVALID
827
+        andi    ANI_NO,0x0F             ; throw away check value in high nibble
828
+        cpi     ANI_NO,(ANIM_TAB_END - ANIM_TAB) / 2
829
+        brlo    MAIN_FIRST_ANIM_OK
830
+MAIN_FIRST_ANIM_INVALID:
831
+        ldi     ANI_NO,0
832
+MAIN_FIRST_ANIM_OK:
833
+; first iteration of animation (into DATA)
834
+        ldi     ANI_IT,0
835
+
836
+; main loop
837
+MAIN_LOOP:
838
+        wdr
839
+
840
+; load pointer to animation function and repetition count from table
841
+        ldi     ZL,low(2 * ANIM_TAB)
842
+        ldi     ZH,high(2 * ANIM_TAB)
843
+        mov     TMP,ANI_NO
844
+        lsl     TMP
845
+        lsl     TMP
846
+        add     ZL,TMP
847
+        clr     TMP
848
+        adc     ZH,TMP
849
+        lpm     DATA,Z+                 ; address of function -> TMP:DATA
850
+        lpm     TMP,Z+
851
+        lpm     CNT,Z+                  ; iteration count -> CNT
852
+        mov     ZL,DATA                 ; address of function  -> Z
853
+        mov     ZH,TMP
854
+; save iteration count
855
+        push    CNT
856
+; call animation
857
+        icall
858
+; read new mode
859
+        mov     CNT,ANI_NO
860
+        rcall   MODE_READ
861
+; restore iteration count
862
+        pop     CNT
863
+
864
+; keep playing animation in single animation mode
865
+        cpi     MODE,MODE_SINGLE
866
+        breq    MAIN_NEXT_END
867
+; next iteration
868
+        inc     ANI_IT
869
+        cp      ANI_IT,CNT
870
+        brlo    MAIN_NEXT_END
871
+        clr     ANI_IT
872
+; next animation
873
+        inc     ANI_NO
874
+        cpi     ANI_NO,(ANIM_TAB_END - ANIM_TAB) / 2
875
+        brlo    MAIN_NEXT_END
876
+        clr     ANI_NO
877
+MAIN_NEXT_END:
878
+
879
+; bottom of main loop
880
+        rjmp     MAIN_LOOP
881
+
... ...
@@ -0,0 +1,881 @@
1
+; bulb - BlinkenArea ultimate logo board
2
+; Copyright (C) 2011-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
+.def    BULB                    =       r24
47
+.def    BORDER                  =       r25
48
+
49
+; current mode
50
+.def    MODE                    =       r21
51
+.equ    MODE_ALL                =       0       ; play all animations
52
+.equ    MODE_SINGLE             =       1       ; play single animation only
53
+.equ    MODE_UNKNOWN            =       0xFF    ; unknown mode
54
+
55
+; current animation number and iterations
56
+.def    ANI_NO                  =       r22
57
+.def    ANI_IT                  =       r23
58
+
59
+
60
+
61
+.DSEG
62
+.ORG    0x060
63
+
64
+
65
+
66
+; current frame
67
+FRAME:                  .BYTE   42
68
+
69
+
70
+
71
+.CSEG
72
+.ORG    0x000
73
+        rjmp    ENTRY                   ; RESET
74
+        reti                            ; INT0
75
+        reti                            ; INT1
76
+        reti                            ; TIMER1_CAPT
77
+        reti                            ; TIMER1_COMPA
78
+        reti                            ; TIMER1_OVF
79
+        reti                            ; TIMER0_OVF
80
+        reti                            ; USART0_RX
81
+        reti                            ; USART0_UDRE
82
+        reti                            ; USART0_TX
83
+        reti                            ; ANALOG_COMP
84
+        reti                            ; PC_INT0
85
+        reti                            ; TIMER1_COMPB
86
+        reti                            ; TIMER0_COMPA
87
+        reti                            ; TIMER0_COMPB
88
+        reti                            ; USI_START
89
+        reti                            ; USI_OVERFLOW
90
+        reti                            ; EE_READY
91
+        reti                            ; WDT
92
+        reti                            ; PC_INT1
93
+        reti                            ; PC_INT2
94
+
95
+
96
+
97
+; code entry point
98
+ENTRY:
99
+; set system clock prescaler to 1:1
100
+        ldi     TMP,1<<CLKPCE
101
+        out     CLKPR,TMP
102
+        ldi     TMP,0
103
+        out     CLKPR,TMP
104
+; initialize output ports
105
+        ldi     TMP,0x00                ; PA[01] to output, low
106
+        out     PORTA,TMP
107
+        ldi     TMP,0x03
108
+        out     DDRA,TMP
109
+        ldi     TMP,0x80                ; PB[0-6] to output, low - PB7 to input, pull-up enabled
110
+        out     PORTB,TMP
111
+        ldi     TMP,0x7F
112
+        out     DDRB,TMP
113
+        ldi     TMP,0x7F                ; PD[0-5] to output, high - PD6 to input, pull-up enabled
114
+        out     PORTD,TMP
115
+        ldi     TMP,0x3F
116
+        out     DDRD,TMP
117
+; initialize stack pointer
118
+        ldi     TMP,RAMEND
119
+        out     SPL,TMP
120
+; enable watchdog (64ms)
121
+        wdr
122
+        ldi     TMP,1<<WDCE|1<<WDE
123
+        out     WDTCR,TMP
124
+        ldi     TMP,1<<WDE|1<<WDP1
125
+        out     WDTCR,TMP
126
+        wdr
127
+; disable analog comparator
128
+        ldi     TMP,1<<ACD
129
+        out     ACSR,TMP
130
+; jump to main program
131
+        rjmp    MAIN
132
+
133
+
134
+
135
+; wait 61 cycles
136
+; input: -
137
+; output: -
138
+; changes: TMP
139
+; cycles: 61 (including rcall and ret)
140
+WAIT61:
141
+        ldi     TMP,18
142
+WAIT61_LOOP:
143
+        dec     TMP
144
+        brne    WAIT61_LOOP
145
+; done
146
+        ret
147
+
148
+
149
+
150
+; output row for grayscale (black/white) and wait
151
+; input: X = ptr to pixel data (0..15)
152
+;        GRAY = grayscale value (1..15)
153
+; output: -
154
+; changes: TMP, TMP2, DATA
155
+; cycles: GRAY * 64 + 1 (including rcall and ret)
156
+ROW_BW_WAIT:
157
+; get data for LEDs
158
+        ldi     TMP2,7                  ; 7 pixels
159
+ROW_BW_WAIT_PIXEL:
160
+        ld      TMP,X+                  ; get pixel value
161
+        cp      TMP,GRAY                ; compare with grayscale value
162
+        ror     DATA                    ; store result as output bit
163
+        dec     TMP2                    ; next pixel
164
+        brne    ROW_BW_WAIT_PIXEL
165
+; restore data pointer
166
+        subi    XL,7                    ;   XH not there on ATtiny2313
167
+; output
168
+        lsr     DATA                    ; ensure remaining bit stays high
169
+                                        ;   (pull-up for unused pin)
170
+        com     DATA
171
+        out     COL_PORT,DATA
172
+; wait 5 + (GRAY - 1) * 64
173
+        mov     TMP2,GRAY
174
+        rjmp    ROW_BW_WAIT_LOOP_ENTRY
175
+ROW_BW_WAIT_LOOP:
176
+        rcall   WAIT61
177
+ROW_BW_WAIT_LOOP_ENTRY:
178
+        dec     TMP2
179
+        brne    ROW_BW_WAIT_LOOP
180
+        ret
181
+
182
+
183
+
184
+; turn off row (with same timing as ROW_BW_WAIT)
185
+; input: -
186
+; output: -
187
+; changes: TMP
188
+; cycles: 60 (including rcall and ret)
189
+ROW_OFF:
190
+        ldi     TMP,17
191
+ROW_OFF_LOOP:
192
+        dec     TMP
193
+        brne    ROW_OFF_LOOP
194
+        ldi     TMP,0x80                ; ensure remaining bit stays high
195
+                                        ;   (pull-up for unused pin)
196
+        out     COL_PORT,TMP
197
+        ret
198
+
199
+
200
+
201
+; output row (grayscales)
202
+; input: X = ptr to pixel data (0..15)
203
+; output: -
204
+; changes: TMP, TMP2, DATA
205
+; cycles: 7822 (including rcall and ret)
206
+; time: 1ms
207
+ROW_GRAY:
208
+        ldi     GRAY,1
209
+ROW_GRAY_LOOP:
210
+        rcall   ROW_BW_WAIT
211
+        inc     GRAY
212
+        cpi     GRAY,16
213
+        brlo    ROW_GRAY_LOOP
214
+        rcall   ROW_OFF
215
+; done
216
+        ret
217
+
218
+
219
+
220
+; output a frame
221
+; input: FRAME = pixel data (0..15)
222
+; output: -
223
+; changes: TMP, TMP2, CNT, DATA, X
224
+; time: 6ms
225
+OUT_FRAME:
226
+        wdr
227
+        ldi     XL,low(FRAME)           ; ptr to pixel data
228
+                                        ;   XH not there on ATtiny2313
229
+        ldi     CNT,0x01                ; bitmask loop over rows
230
+OUT_FRAME_LOOP:
231
+        mov     TMP,CNT                 ; select row
232
+        com     TMP
233
+        andi    TMP,0x3F
234
+        ori     TMP,0x40                ; ensure bit 6 stays high
235
+                                        ;   (pull-up for switch input)
236
+        out     ROW_PORT,TMP
237
+        rcall   ROW_GRAY                ; display row
238
+        subi    XL,-7                   ; ptr to next row
239
+                                        ;   XH not there on ATtiny2313
240
+        lsl     CNT                     ; bitmask loop over rows
241
+        cpi     CNT,0x40
242
+        brne    OUT_FRAME_LOOP
243
+; done
244
+        ret
245
+
246
+
247
+
248
+; output a frame for some time
249
+; input: FRAME = pixel data (0..15)
250
+;        TMP = time to show frame (1..255, in 6 ms steps)
251
+; output: -
252
+; changes: X, TMP, TMP2
253
+; time: TMP * 6 ms
254
+OUT_FRAME_TIME:
255
+; output frame
256
+        push    TMP
257
+        push    CNT
258
+        push    DATA
259
+        rcall   OUT_FRAME               ; 6 ms
260
+        pop     DATA
261
+        pop     CNT
262
+        pop     TMP
263
+; loop
264
+        dec     TMP
265
+        brne    OUT_FRAME_TIME
266
+; done
267
+        ret
268
+
269
+
270
+
271
+; clear frame
272
+; input: -
273
+; output: -
274
+; changes: X, FRAME, TMP
275
+; time: short
276
+CLEAR:
277
+        ldi     XL,low(FRAME)           ; ptr to pixel data
278
+                                        ;   XH not there on ATtiny2313
279
+        clr     TMP
280
+CLEAR_LOOP:
281
+        st      X+,TMP                  ; clear pixel
282
+        cpi     XL,low(FRAME)+42        ; bottom of loop
283
+                                        ;   XH not there on ATtiny2313
284
+        brne    CLEAR_LOOP
285
+; done
286
+        ret
287
+
288
+
289
+
290
+; set frame to solid color (all the same)
291
+; input: DATA = value (0..15) intensity for all LEDs
292
+; output: -
293
+; changes: X, FRAME
294
+; time: short
295
+SET_COLOR:
296
+        ldi     XL,low(FRAME)           ; ptr to pixel data
297
+                                        ;   XH not there on ATtiny2313
298
+SET_COLOR_LOOP:
299
+        st      X+,DATA                 ; set pixel value
300
+        cpi     XL,low(FRAME)+42        ; bottom of loop
301
+                                        ;   XH not there on ATtiny2313
302
+        brne    SET_COLOR_LOOP
303
+; done
304
+        ret
305
+
306
+; set bulb to solid color
307
+; input: BULB = value (0..15) intensity for all bulb LEDs except spark (28-40)
308
+; output: -
309
+; changes: X, BULB
310
+; time: short
311
+BULB_COLOR:
312
+        ldi     XL,low(FRAME+26)        ; ptr to pixel data
313
+                                        ;   XH not there on ATtiny2313
314
+BULB_COLOR_LOOP:
315
+        st      X+,BULB                 ; set pixel value
316
+        cpi     XL,low(FRAME)+41        ; bottom of loop
317
+                                        ;   XH not there on ATtiny2313
318
+        ldi     BORDER,15               ; start bright
319
+
320
+        brne    BULB_COLOR_LOOP
321
+; done
322
+        ret
323
+
324
+; set border to solid color
325
+; input: BORDER = value (0..15) intensity for all border LEDs
326
+; output: -
327
+; changes: X, BORDER
328
+; time: short
329
+BORDER_COLOR:
330
+        ldi     XL,low(FRAME)           ; ptr to pixel data
331
+                                        ;   XH not there on ATtiny2313
332
+BORDER_COLOR_LOOP:
333
+        st      X+,BORDER               ; set pixel value
334
+        cpi     XL,low(FRAME)+28        ; bottom of loop
335
+                                        ;   XH not there on ATtiny2313
336
+        brne    BORDER_COLOR_LOOP
337
+; done
338
+        ret
339
+
340
+
341
+; set pixel
342
+; input: CNT = pixel number (0..41, nothing is done for 42..255)
343
+;        DATA = value (0..15)
344
+; output: -
345
+; changes: X, FRAME, TMP
346
+; time: short
347
+SET_PIXEL:
348
+        cpi     CNT,42                  ; invalid pixel number -> done
349
+        brsh    SET_PIXEL_END
350
+        ldi     XL,low(FRAME)           ; ptr to pixel (base + offset)
351
+        add     XL,CNT                  ;   XH not there on ATtiny2313
352
+        st      X,DATA                  ; set pixel
353
+SET_PIXEL_END:
354
+; done
355
+        ret
356
+
357
+
358
+
359
+; draw worm
360
+; input: CNT = head of worm (0..55)
361
+; output: -
362
+; changes: X, FRAME, TMP, DATA
363
+; time: short
364
+DRAW_WORM:
365
+        cpi     CNT,56                  ; invalid head pos -> done
366
+        brsh    DRAW_WORM_END
367
+        ldi     XL,low(FRAME)+1         ; ptr to before head
368
+        add     XL,CNT                  ;   XH not there on ATtiny2313
369
+        ldi     DATA,15                 ; head is full on
370
+        cpi     CNT,42                  ; head pos in frame -> go
371
+        brlo    DRAW_WORM_LOOP
372
+        mov     TMP,CNT                 ; TMP := invisible pixels
373
+        subi    TMP,41
374
+        sub     XL,TMP                  ; skip invisible pixels
375
+        sub     DATA,TMP                ;   XH not there on ATtiny2313
376
+DRAW_WORM_LOOP:
377
+        st      -X,DATA                 ; set pixel, go back
378
+        cpi     XL,low(FRAME)           ; 1st pixel -> done
379
+        breq    DRAW_WORM_END           ;   XH not there on ATtiny2313
380
+        dec     DATA                    ; next pixel darker
381
+        brne    DRAW_WORM_LOOP          ; loop
382
+DRAW_WORM_END:
383
+; done
384
+        ret
385
+
386
+
387
+
388
+; draw backwards worm
389
+; input: CNT = tail of worm (0..55)
390
+; output: -
391
+; changes: X, FRAME, TMP, DATA
392
+; time: short
393
+DRAW_BW_WORM:
394
+        cpi     CNT,56                  ; invalid tail pos -> done
395
+        brsh    DRAW_BW_WORM_END
396
+        ldi     XL,low(FRAME)+1         ; ptr to before tail
397
+        add     XL,CNT                  ;   XH not there on ATtiny2313
398
+        ldi     DATA,1                  ; tail is minimum on
399
+        cpi     CNT,42                  ; tail pos in frame -> go
400
+        brlo    DRAW_BW_WORM_LOOP
401
+        mov     TMP,CNT                 ; TMP := invisible pixels
402
+        subi    TMP,41
403
+        sub     XL,TMP                  ; skip invisible pixels
404
+        add     DATA,TMP                ;   XH not there on ATtiny2313
405
+DRAW_BW_WORM_LOOP:
406
+        st      -X,DATA                 ; set pixel, go back
407
+        cpi     XL,low(FRAME)           ; 1st pixel -> done
408
+        breq    DRAW_BW_WORM_END        ;   XH not there on ATtiny2313
409
+        inc     DATA                    ; next pixel brighter
410
+        cpi     DATA,16                 ; loop
411
+        brne    DRAW_BW_WORM_LOOP
412
+DRAW_BW_WORM_END:
413
+; done
414
+        ret
415
+
416
+
417
+
418
+; blink animation
419
+; input: -
420
+; output: -
421
+; changes: X, FRAME, CNT, DATA, TMP, TMP2
422
+ANIM_BLINK:
423
+; off
424
+        ldi     DATA,0                  ; minimum color
425
+        rcall   SET_COLOR               ; paint
426
+        ldi     TMP,100                 ; show frame 600 ms
427
+        rcall   OUT_FRAME_TIME
428
+; on
429
+        ldi     DATA,15                 ; maximum color
430
+        rcall   SET_COLOR               ; paint
431
+        ldi     TMP,100                 ; show frame 600 ms
432
+        rcall   OUT_FRAME_TIME
433
+; done
434
+        ret
435
+
436
+
437
+
438
+; fade up and down animation
439
+; input: -
440
+; output: -
441
+; changes: X, FRAME, CNT, DATA, TMP, TMP2
442
+ANIM_FADE:
443
+; fade up
444
+        ldi     DATA,0                  ; start dark
445
+ANIM_FADE_UP:
446
+        rcall   SET_COLOR               ; paint
447
+        ldi     TMP,10                  ; show frame 60 ms
448
+        rcall   OUT_FRAME_TIME
449
+        inc     DATA                    ; fade up
450
+        cpi     DATA,15                 ; loop until almost full on
451
+        brne    ANIM_FADE_UP
452
+; fade down
453
+ANIM_FADE_DOWN:
454
+        rcall   SET_COLOR               ; paint
455
+        ldi     TMP,10                  ; show frame 60 ms
456
+        rcall   OUT_FRAME_TIME
457
+        dec     DATA                    ; fade up
458
+        cpi     DATA,255                ; loop until full off
459
+        brne    ANIM_FADE_DOWN
460
+; done
461
+        ret
462
+
463
+; fade up and down animation, bulb and frame are in opposite phase
464
+; input: -
465
+; output: -
466
+; changes: X, FRAME, CNT, DATA, BULB, BORDER, TMP, TMP2
467
+INVERTED_FADE:
468
+        ;rcall   CLEAR                   ; clear
469
+        ldi     DATA,0xf
470
+        sts     FRAME+41,DATA           ; set filament pixel
471
+
472
+        ldi     BORDER,15               ; start bright
473
+        ldi     BULB,0                  ; start dark
474
+INVERTED_FADE_BACK:;EVEN                     ; relative to the bulb
475
+        rcall   BORDER_COLOR            ; paint border (to darker)
476
+        rcall   BULB_COLOR              ; paint bulb (to brighter)
477
+        dec     BORDER                  ; fade down, 0-27
478
+        cpi     BORDER,255              ; loop until full off
479
+        inc     BULB                    ; fade up, 28-41
480
+        cpi     BULB,15                 ; loop until almost full on
481
+        brne    INVERTED_FADE_BACK
482
+        ldi     TMP,10                  ; show frame 60 ms
483
+        rcall   OUT_FRAME_TIME
484
+INVERTED_FADE_FORTH:;ODD
485
+        rcall   BORDER_COLOR            ; paint border (to brighter)
486
+        rcall   BULB_COLOR              ; paint bulb (to darker)
487
+        inc     BORDER                  ; fade up, 28-41
488
+        cpi     BORDER,15               ; loop until almost full on
489
+        dec     BULB                    ; fade down, 0-27
490
+        cpi     BULB,255                ; loop until full off
491
+        brne    INVERTED_FADE_FORTH
492
+        ldi     TMP,10                  ; show frame 60 ms
493
+        rcall   OUT_FRAME_TIME
494
+; done
495
+        ret
496
+
497
+
498
+; border (frame around bulb) blink animation
499
+; input: -
500
+; output: -
501
+; changes: X, FRAME, CNT, BORDER, TMP, TMP2
502
+ANIM_FRAMEBLINK:
503
+        rcall   CLEAR
504
+; off
505
+        ldi     BORDER,0                ; minimum color
506
+        rcall   BORDER_COLOR            ; paint
507
+        ldi     TMP,100                 ; show frame 600 ms
508
+        rcall   OUT_FRAME_TIME
509
+; on
510
+        ldi     BORDER,15               ; maximum color
511
+        rcall   BORDER_COLOR            ; paint
512
+        ldi     TMP,100                 ; show frame 600 ms
513
+        rcall   OUT_FRAME_TIME
514
+; done
515
+        ret
516
+
517
+; bulb blink animation, fast
518
+; input: -
519
+; output: -
520
+; changes: X, FRAME, CNT, BULB, TMP, TMP2
521
+ANIM_BULBFAST:
522
+        rcall   CLEAR
523
+        ldi     DATA,0xf
524
+        sts     FRAME+41,DATA           ; set filament pixel
525
+; off
526
+        ldi     BULB,0                ; minimum color
527
+        rcall   BULB_COLOR            ; paint
528
+        ldi     TMP,10                 ; show frame 20 ms
529
+        rcall   OUT_FRAME_TIME
530
+; on
531
+        ldi     BULB,15               ; maximum color
532
+        rcall   BULB_COLOR            ; paint
533
+        ldi     TMP,10                 ; show frame 20 ms
534
+        rcall   OUT_FRAME_TIME
535
+; done
536
+        ret
537
+
538
+; bulb blink animation, slow
539
+; input: -
540
+; output: -
541
+; changes: X, FRAME, CNT, BULB, TMP, TMP2
542
+ANIM_BULBSLOW:
543
+        rcall   CLEAR
544
+        ldi     DATA,0xf
545
+        sts     FRAME+41,DATA           ; set filament pixel
546
+; off
547
+        ldi     BULB,0                ; minimum color
548
+        rcall   BULB_COLOR            ; paint
549
+        ldi     TMP,200
550
+        rcall   OUT_FRAME_TIME
551
+; on
552
+        ldi     BULB,15               ; maximum color
553
+        rcall   BULB_COLOR            ; paint
554
+        ldi     TMP,200
555
+        rcall   OUT_FRAME_TIME
556
+; done
557
+        ret
558
+
559
+
560
+; flicker animation
561
+; input: -
562
+; output: -
563
+; changes: X, FRAME, CNT, DATA, TMP, TMP2
564
+ANIM_FLICKER:
565
+; even pixels
566
+        rcall   CLEAR                   ; clear
567
+        ldi     DATA,15                 ; even pixels to maximum
568
+        ldi     DATA,0xf
569
+        sts     FRAME+41,DATA                 ; set pixel, go back
570
+        ldi     CNT,0
571
+ANIM_FLICKER_EVEN:
572
+        rcall   SET_PIXEL
573
+        subi    CNT,-2                  ; move two pixels
574
+        cpi     CNT,42                  ; loop
575
+        brlo    ANIM_FLICKER_EVEN
576
+        ldi     TMP,20                  ; show frame 120 ms
577
+        rcall   OUT_FRAME_TIME
578
+; odd pixels
579
+        rcall   CLEAR                   ; clear
580
+        ldi     DATA,15                 ; odd pixels to maximum
581
+        ldi     CNT,1
582
+ANIM_FLICKER_ODD:
583
+        rcall   SET_PIXEL
584
+        subi    CNT,-2                  ; move two pixels
585
+        cpi     CNT,42                  ; loop
586
+        brlo    ANIM_FLICKER_ODD
587
+        ldi     TMP,20                  ; show frame 120 ms
588
+        rcall   OUT_FRAME_TIME
589
+; done
590
+        ret
591
+
592
+ANIM_IDLE:
593
+        rcall   CLEAR                   ; clear
594
+        ldi     TMP,500                 ; show frame 3000 ms
595
+        rcall   OUT_FRAME_TIME
596
+
597
+        ldi     DATA,0xf
598
+        sts     FRAME+41,DATA                 ; set pixel, go back
599
+
600
+        ldi     TMP,10                  ; show frame 60 ms
601
+        rcall   OUT_FRAME_TIME
602
+        ret
603
+
604
+
605
+
606
+
607
+; wobble animation
608
+; input: -
609
+; output: -
610
+; changes: X, FRAME, CNT, DATA, TMP, TMP2
611
+ANIM_WOBBLE:
612
+; even pixels up, odd pixels down
613
+        ldi     DATA,0                  ; even pixels start dark
614
+ANIM_WOBBLE_UP:
615
+        ldi     CNT,0
616
+ANIM_WOBBLE_UP_DRAW:
617
+        rcall   SET_PIXEL
618
+        inc     CNT                     ; next pixel
619
+        ldi     TMP,0x0F                ; invert color
620
+        eor     DATA,TMP
621
+        cpi     CNT,42                  ; loop
622
+        brlo    ANIM_WOBBLE_UP_DRAW
623
+        ldi     TMP,10                  ; show frame 60 ms
624
+        rcall   OUT_FRAME_TIME
625
+        inc     DATA                    ; next color: brighter
626
+        cpi     DATA,16
627
+        brlo    ANIM_WOBBLE_UP
628
+; even pixels down, odd pixels up
629
+        ldi     DATA,15                 ; even pixels start full
630
+ANIM_WOBBLE_DOWN:
631
+        ldi     CNT,0
632
+ANIM_WOBBLE_DOWN_DRAW:
633
+        rcall   SET_PIXEL
634
+        inc     CNT                     ; next pixel
635
+        ldi     TMP,0x0F                ; invert color
636
+        eor     DATA,TMP
637
+        cpi     CNT,42                  ; loop
638
+        brlo    ANIM_WOBBLE_DOWN_DRAW
639
+        ldi     TMP,10                  ; show frame 60 ms
640
+        rcall   OUT_FRAME_TIME
641
+        dec     DATA                    ; next color: darker
642
+        cpi     DATA,16
643
+        brlo    ANIM_WOBBLE_DOWN
644
+; done
645
+        ret
646
+
647
+
648
+
649
+; run animation
650
+; input: -
651
+; output: -
652
+; changes: X, FRAME, CNT, DATA, TMP, TMP2
653
+ANIM_RUN:
654
+        ldi     CNT,255                 ; start before 1st pixel
655
+ANIM_RUN_LOOP:
656
+        rcall   CLEAR                   ; clear
657
+        ldi     DATA,15                 ; current pixel full on
658
+        rcall   SET_PIXEL
659
+        ldi     TMP,10                  ; show frame 60 ms
660
+        rcall   OUT_FRAME_TIME
661
+        inc     CNT                     ; next pixel
662
+        cpi     CNT,41                  ; loop until after last pixel
663
+        brne    ANIM_RUN_LOOP
664
+; done
665
+        ret
666
+
667
+
668
+
669
+; backwards run animation
670
+; input: -
671
+; output: -
672
+; changes: X, FRAME, CNT, DATA, TMP, TMP2
673
+ANIM_BW_RUN:
674
+        ldi     CNT,40                  ; start after last pixel
675
+ANIM_BW_RUN_LOOP:
676
+        rcall   CLEAR                   ; clear
677
+        ldi     DATA,15                 ; current pixel full on
678
+        rcall   SET_PIXEL
679
+        ldi     TMP,10                  ; show frame 60 ms
680
+        rcall   OUT_FRAME_TIME
681
+        dec     CNT                     ; previous pixel
682
+        cpi     CNT,255                 ; loop until before 1st pixel
683
+        brne    ANIM_BW_RUN_LOOP
684
+; done
685
+        ret
686
+
687
+
688
+
689
+; worm animation
690
+; input: -
691
+; output: -
692
+; changes: X, FRAME, CNT, DATA, TMP, TMP2
693
+ANIM_WORM:
694
+        ldi     CNT,255                 ; worm starts before 1st pixel
695
+ANIM_WORM_LOOP:
696
+        rcall   CLEAR                   ; draw worm
697
+        rcall   DRAW_WORM
698
+        ldi     TMP,10                  ; show frame 60 ms
699
+        rcall   OUT_FRAME_TIME
700
+        inc     CNT                     ; advance worm
701
+        cpi     CNT,57                  ; loop until has exits
702
+        brne    ANIM_WORM_LOOP
703
+; done
704
+        ret
705
+
706
+
707
+
708
+; backwards worm animation
709
+; input: -
710
+; output: -
711
+; changes: X, FRAME, CNT, DATA, TMP, TMP2
712
+ANIM_BW_WORM:
713
+        ldi     CNT,56                  ; worm starts behind frame
714
+                                        ;   head not yet visible
715
+ANIM_BW_WORM_LOOP:
716
+        rcall   CLEAR                   ; draw backwards worm
717
+        rcall   DRAW_BW_WORM
718
+        ldi     TMP,10                  ; show frame 60 ms
719
+        rcall   OUT_FRAME_TIME
720
+        dec     CNT                     ; advance worm backwards
721
+        cpi     CNT,254                 ; loop until worm has exited
722
+        brne    ANIM_BW_WORM_LOOP
723
+; done
724
+        ret
725
+
726
+
727
+
728
+; read mode from switch and (store animation number)
729
+; input: MODE = old mode, CNT = animation number
730
+; output: MODE = new mode
731
+; changes: TMP, DATA
732
+MODE_READ:
733
+; read new mode (into DATA)
734
+        ldi     DATA,MODE_ALL
735
+        sbic    MODE_SW_PIN,MODE_SW_BIT
736
+        ldi     DATA,MODE_SINGLE
737
+; mode was changed from all to single -> save animation number
738
+        cpi     MODE,MODE_ALL           ; old mode not all -> do nothing
739
+        brne    MODE_READ_NOT_0_TO_1
740
+        cpi     DATA,MODE_SINGLE        ; new mode not single -> do nothing
741
+        brne    MODE_READ_NOT_0_TO_1
742
+        sbic    EECR,EEPE               ; EEPROM write ongoing -> do nothing
743
+        rjmp    MODE_READ_NOT_0_TO_1
744
+        ldi     TMP,0<<EEPM1|0<<EEPM0   ; set EEPROM programming mode
745
+        out     EECR,TMP
746
+        ldi     TMP,0                   ; set EEPROM address
747
+        out     EEARL,TMP
748
+        mov     TMP,CNT                 ; set EEPROM data to animation number
749
+        com     TMP                     ;   with NOTed number in upper nibble
750
+        swap    TMP
751
+        andi    TMP,0xF0
752
+        or      TMP,CNT
753
+        out     EEDR,TMP
754
+        sbi     EECR,EEMPE              ; begin writing EEPROM
755
+        sbi     EECR,EEPE
756
+MODE_READ_NOT_0_TO_1:
757
+; remember new mode (in MODE)
758
+        mov     MODE,DATA
759
+; done
760
+        ret
761
+
762
+
763
+
764
+; animation table: animation function, iteration count (<= 255)
765
+ANIM_TAB:
766
+        ;.dw     ANIM_FRAMEBLINK
767
+        ;.dw     5
768
+        ;.dw     ANIM_BULBSLOW
769
+        ;.dw     3
770
+        ;.dw     ANIM_WORM
771
+        ;.dw     1
772
+        ;.dw     ANIM_IDLE
773
+        ;.dw     5
774
+        ;.dw     ANIM_BW_WORM
775
+        ;.dw     1
776
+        ;.dw     ANIM_RUN
777
+        ;.dw     1
778
+        ;.dw     ANIM_BW_RUN
779
+        ;.dw     1
780
+        ;.dw     ANIM_WORM
781
+        ;.dw     1
782
+        ;.dw     ANIM_IDLE
783
+        ;.dw     1
784
+        .dw     INVERTED_FADE
785
+        .dw     5
786
+        ;.dw     ANIM_IDLE
787
+        ;.dw     2
788
+        ;.dw     ANIM_FLICKER
789
+        ;.dw     10
790
+        ;.dw     ANIM_IDLE
791
+        ;.dw     2
792
+        ;.dw     ANIM_FRAMEBLINK
793
+        ;.dw     1
794
+        ;.dw     ANIM_BULBFAST
795
+        ;.dw     5
796
+        ;.dw     ANIM_FRAMEBLINK
797
+        ;.dw     1
798
+        ;.dw     ANIM_IDLE
799
+        ;.dw     5
800
+        ;.dw     INVERTED_FADE
801
+        ;.dw     5
802
+        ;.dw     ANIM_IDLE
803
+        ;.dw     2
804
+        ;.dw     ANIM_WOBBLE
805
+        ;.dw     5
806
+ANIM_TAB_END:
807
+
808
+
809
+
810
+; main program
811
+MAIN:
812
+        wdr
813
+
814
+; initialization
815
+        ldi     MODE,MODE_UNKNOWN       ; unknown mode
816
+
817
+; get number of fist animation from EEPROM (into CNT)
818
+        ldi     TMP,0                   ; set EEPROM address
819
+        out     EEARL,TMP
820
+        sbi     EECR,EERE               ; start EEPROM read
821
+        in      ANI_NO,EEDR                ; get read value
822
+        mov     TMP,ANI_NO              ; check if high nibble contains NOTed
823
+        com     TMP                     ;   value
824
+        swap    TMP
825
+        cp      ANI_NO,TMP
826
+        brne    MAIN_FIRST_ANIM_INVALID
827
+        andi    ANI_NO,0x0F             ; throw away check value in high nibble
828
+        cpi     ANI_NO,(ANIM_TAB_END - ANIM_TAB) / 2
829
+        brlo    MAIN_FIRST_ANIM_OK
830
+MAIN_FIRST_ANIM_INVALID:
831
+        ldi     ANI_NO,0
832
+MAIN_FIRST_ANIM_OK:
833
+; first iteration of animation (into DATA)
834
+        ldi     ANI_IT,0
835
+
836
+; main loop
837
+MAIN_LOOP:
838
+        wdr
839
+
840
+; load pointer to animation function and repetition count from table
841
+        ldi     ZL,low(2 * ANIM_TAB)
842
+        ldi     ZH,high(2 * ANIM_TAB)
843
+        mov     TMP,ANI_NO
844
+        lsl     TMP
845
+        lsl     TMP
846
+        add     ZL,TMP
847
+        clr     TMP
848
+        adc     ZH,TMP
849
+        lpm     DATA,Z+                 ; address of function -> TMP:DATA
850
+        lpm     TMP,Z+
851
+        lpm     CNT,Z+                  ; iteration count -> CNT
852
+        mov     ZL,DATA                 ; address of function  -> Z
853
+        mov     ZH,TMP
854
+; save iteration count
855
+        push    CNT
856
+; call animation
857
+        icall
858
+; read new mode
859
+        mov     CNT,ANI_NO
860
+        rcall   MODE_READ
861
+; restore iteration count
862
+        pop     CNT
863
+
864
+; keep playing animation in single animation mode
865
+        cpi     MODE,MODE_SINGLE
866
+        breq    MAIN_NEXT_END
867
+; next iteration
868
+        inc     ANI_IT
869
+        cp      ANI_IT,CNT
870
+        brlo    MAIN_NEXT_END
871
+        clr     ANI_IT
872
+; next animation
873
+        inc     ANI_NO
874
+        cpi     ANI_NO,(ANIM_TAB_END - ANIM_TAB) / 2
875
+        brlo    MAIN_NEXT_END
876
+        clr     ANI_NO
877
+MAIN_NEXT_END:
878
+
879
+; bottom of main loop
880
+        rjmp     MAIN_LOOP
881
+
0 882