Saturday, December 19, 2020

0000 0000 0100 1110

Christmas supercomputer

Note: it is the summer holidays DownUnder, so this blog (and YT channel) will be taking a little break for a month - see you in 2021!

Who doesn't love red and green flashing LEDs at Christmas? For the last couple of years we have had these little CR2032 driven ATTiny13 chips flashing a couple of 5mm LEDs strewn throughout the house (and outside).

The microcontrollers are running at 1MHz and they are mostly sleep, just pumping out alternate 1/8th second blips to the LEDs followed by a 4 second gap. In this guise the coin cells last around 6-9 months (!!), although they do get a bit dim towards the end of that run.


This year I decided to update the project, again using ATTiny13a chips, but this time ambling along at 128kHz (less power) which switch 1206 SMD LEDs (less power at 1/4W), but flashing more frequently (1/8th second on, 1/2 second off). So it will be very interesting to see how they last through the festive season and beyond. I can't remember if the original was coded in assembly or not, but this one sure is:

;
; Device: ATtiny13A, Package: 8-pin-PDIP_SOIC
;
;            ______
;         1 /      |8
; RESET o--|       |--o VCC
;         2|       |7
;   PB3 o--|       |--o PB2
;         3|       |6
;   PB4 o--|       |--o PB1
;         4|       |5
;   GND o--|       |--o PB0
;          |_______|
;

.nolist
.include "tn13adef.inc"         ; Define device ATtiny13A
.list

; **********************************
;       R E G I S T E R S
; **********************************

.def rSreg = R15                   ; Save/Restore status port
.def rmp = R16                     ; Define multipurpose register
.def colour = R1

; **********************************
;           S R A M
; **********************************

.dseg
.org SRAM_START

; **********************************
;         C O D E
; **********************************

.cseg
.org 000000

; **********************************
; R E S E T  &  I N T - V E C T O R S
; **********************************
    rjmp Main                        ; Reset vector
    reti ; INT0
    reti ; PCI0
    reti ; OVF0
    reti ; ERDY
    reti ; ACI
    reti ; OC0A
    reti ; OC0B
    rjmp mytimer_ISR                 ; watchdog timer interrupt
    reti ; ADCC

; **********************************
;  I N T - S E R V I C E   R O U T .
; **********************************

; Add all interrupt service routines

mytimer_ISR:

     ; as I understand it, cli and sei are automatic on
     ; entry and exit respectively of ISR

     in r16, SREG      ; save SREG
     push r16          ; do this if you want to use

finishisr:

     pop r16           ; do this if you pushed SREG above
     out SREG, r16     ; restore SREG

     reti

; **********************************
;  M A I N   P R O G R A M   I N I T
; **********************************

Main:
    ldi rmp,Low(RAMEND)
    out SPL,rmp                    ; Init LSB stack pointer

    ldi r16, 0b00011000            ; output mode for PB3/4
    out DDRB, r16
    ldi r16, 0b00010000
    mov colour, r16                 ; red is on

    ; turn on PB4, enable internal pullups
    ; on the rest of the pins except PB3
    ldi r16, 0b11110111
    out PORTB, r16

; **********************************
;    P R O G R A M   L O O P
; **********************************

Loop:

    rcall waitabit                 ; 1/16 second subroutine
    rcall waitalot                 ; 1/2 second subroutine

    rjmp Loop

waitabit:

    wdr                      ; reset watchdog timer
    ldi r16, 0b01000010      ; 1/8 second timer
    out WDTCR, r16
    rcall sleepnow           ; sleep subroutine
    rcall flipbit            ; flip the led, if off then on, etc.
    ret

waitalot:

    wdr                      ; reset watchdog timer
    ldi r16, 0b01000101      ; 1/2 second timer
    out WDTCR, r16
    rcall sleepnow           ; sleep subroutine
    rcall flipbit            ; flip the leds
    ret

sleepnow:

    ; sleep enable, power down mode
    ldi r16, 0b00110000
    out MCUCR, r16

    ; disable ADC
    ldi r16, 0b00010000
    out ADCSRA, r16

    ; disable interrupts to make sure the following
    ; timed sequence is not interrupted
    cli

    ; disable BOD - must be done in a timed sequence
    ; as follows, write 1 to BODS and BODSE then within
    ; four clock cycles write 1 to BODS and 0 to BODSE
    ; then within three clock cycles enable sleep
    ; page 33 on the datasheet

    ldi r16, 0b00000011
    ldi r17, 0b00000010
    out BODCR, r16
    out BODCR, r17

    sei
    sleep

    ; sleep disable
    ldi r16, 0b00000000
    out MCUCR, r16

    ret

flipbit:

    in r16, pinb              ; what is the state of the pins?
    andi r16, 0b00011000      ; load red or green on
    brbc 1, turnoff

testred:
    mov r16, colour
    ldi r17, 0b00001000
    cp r16, r17
    brbs 1, greenon

redon:
    ldi r16, 0b00001000       ; set colour red
    mov colour, r16           ; and make it so
    ldi r16, 0b00001000
    out portb, r16
    rjmp finishflip

greenon:
    ldi r16, 0b00010000       ; set colour green
    mov colour, r16           ; and make it so
    ldi r16, 0b00010000
    out portb, r16
    rjmp finishflip

turnoff:
    ldi r16, 0b00000000
    out portb, r16

finishflip:

    ret

; End of source code


The only downside is that with the frantic flashing the place looks like an alien landing site or a Christmas super computer - good one!

In line with some other current projects, it is my solemn promise to make next year's batch from Pesky Padauk microcontrollers, probably the PMS150C.




No comments:

Post a Comment