Saturday, December 5, 2020

0000 0000 0100 1100

What is better than one QX5252 chip?

I was musing about two recent but separate projects, one which sings the praises of the QX5252 chip and the other which throws the ATTiny13 chip into a watchdog role. What if the watchdog could effectively have endless energy via the big yellow in the sky, and so can run "forever" and be available to do watchdog-type activities?

I decided to test the addition of a second QX5252, one chip operating to "pump" out stable energy to the microcontroller, and the other to grab ergs from the sun when available.

Normally with the QX5252 and similar ICs the chip shuts down the output of the circuit if there is enough light, and all of the solar panel energy is shunted to the rechargeable battery for the next night of LED fun. If, however, you want the battery to simultaneously charge and discharge during the day (is that even possible?) then one variation worth exploring is to maybe employ a second QX5252 just for that purpose.

So the plan is:

  1. use the "normal" stable joule thief PCB and program an ATTiny13 to do something (probably blink), but do not connect a Solar Panel to the board so that the QX5252 is fooled into being always in "discharge" mode
  2. add another QX5252 to the rail, but have no output components such that it is charging the battery if there is any light available to do so
In part (1), above, I struggled to write the assembly code which initially seemed an easy variation on previous projects. All I wanted to do was use two LEDs and flash them alternatively for 2 seconds on then 8 seconds off - e.g. red on (2 seconds), all off (8 seconds), yellow on (2 seconds), all off (8 seconds), rinse and repeat...

Of course, if the states of the LEDs are not changing then the microcontroller can sleep to save power. Also the little fella should be running anaemically at 128kHz thus drawing minimum current.

Eventually the code worked, but if you can see a better way to more efficiently and/or clearly write these routines, please leave a comment on the YouTube channel.

.nolist
.include "tn13adef.inc" ; Define device ATtiny13A
.list
; **********************************
;        H A R D W A R E
; **********************************

; Device: ATtiny13A, Package: 8 - pin - PDIP_SOIC
;
;           ____________
;        1 /            | 8
;      o-- | RESET  VCC | --o
;      o-- | PB3    PB2 | --o
;      o-- | PB4    PB1 | --o
;      o-- | GND    PB0 | --o
;        4 |____________| 5
;

; **********************************
;         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        ; my interrupt
    reti ; ADCC

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

mytimer_ISR:

    ;  sleep is interrupted, program returns
    reti

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

    ldi r16, Low(RAMEND)
    out SPL, r16              ; Init LSB stack pointer

    ; output mode for PB3, PB4, input for the rest
    ldi r16, 0b00011000
    out DDRB, r16

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

    ; which LED is active?
    ldi r18, 0b00010000             ; start with PB4

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

Loop:

    rcall waitabit            ; 2 second (on)
    rcall waitalot            ; 8 seconds (off)
    rjmp loop

waitabit:

    ; reset watchdog timer
    wdr

    ; 2 second timer
    ldi r16, 0b01000111       ; see datasheet
    out WDTCR, r16

    rcall sleepnow
    rcall flipbit
    ret

waitalot:

    ; reset watchdog timer
    wdr

    ; 8 second timer
    ldi r16, 0b01100001      ; see datasheet
    out WDTCR, r16

    rcall sleepnow
    rcall flipbit
    ret


sleepnow:

    ; see datasheet MCUCR, ADCSRA, BODCR

    ; 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:

    cpi r18, 0b00010000    ; is pb4 active?
    brbs 1, workonpb4

workonpb3:

    in r16, portb
    andi r16, 0b00001000   ; mask all but PB3
    cpi r16, 0b00001000    ; is pb3 on?

    brbs 1, turnoffpb3

    in r16, portb          ; flip PB3
    ldi r17, 0b00001000
    eor r16, r17
    out portb, r16

    rjmp finishflip

turnoffpb3:

    in r16, portb          ; flip PB3
    ldi r17, 0b00001000
    eor r16, r17
    out portb, r16
    ldi r18, 0b00010000    ; make PB4 active

    rjmp finishflip

workonpb4:

    in r16, portb
    andi r16, 0b00010000
    cpi r16, 0b00010000    ; is PB4 on?

    brbs 1, turnoffpb4

    in r16, portb          ; flip PB4
    ldi r17, 0b00010000
    eor r16, r17
    out portb, r16

    rjmp finishflip

turnoffpb4:

    in r16, portb          ; flip PB4
    ldi r17, 0b00010000
    eor r16, r17
    out portb, r16
    ldi r18, 0b00001000    ; make PB3 active

finishflip:

ret

; End of source code


I was very stoked to see this circuit and code not only work as intended, but also hold its own over weeks of testing, oscillating between about 1.33V after a day of sunshine to 1.25V after a couple of days and nights of overcast misery. Nice one two QX5252 Frankenstein bloke!

The only question remaining is: should I add a couple of diodes going to the rail from each of the outputs so they don't interfere with each other? Are the losses so great (although they would probably be Schottky diodes for minimum forward voltage) that it's not worth the addition? There are more tests to be made, but for now enjoy the <usual> blinking madness. 







No comments:

Post a Comment