PIC Code

A project log for Single SuperCapacitor UPS for Raspberry Pi

A last gasp Uninterruptible Power Supply for any Raspberry Pi computer.

bud-bennettBud Bennett 01/06/2019 at 14:590 Comments

The assembler code for the PIC10F202 is below. I will also place the hex file for programming it in the files section of this project. The main body is only 21 lines of code. The comments should clearly document what is going on, but here's an overview:

  1. Setup I/O and watchdog timer.
  2. Sample SHUTDN pin every 10ms.
  3. SHUTDN must be high for 5 consecutive samples to be considered "HIGH". This is a noise filter.
  4. If SHUTDN is high, then delay for 20 seconds and set the GP1 high for 750µs, which disables the LTC4041.
  5. Loop forever until power is cut by the LTC4041.
; WARNING!!! Don't erase this part before programming. It will erase the
; calibration value stored in 0x01ff.

; PIC10F202 Configuration Bit Settings

; Assembly source line config statements

#include ""

; __config 0xFFFB

 ; General Notes:
 ; Internal oscillator is 4MHz (1MHz system clock). No external
 ; oscillator needed. 
 ; Watchdog timer is set for 18ms x 16 = 288ms.
 ; Only 2 stack registers. Can't call more than 1 nested subroutine.
 ; Pin Assignments:
 ;  1 - GP0: SHUTDN input
 ;  2 - VSS
 ;  3 - GP1: Shutdown output to the base of Q1
 ;  4 - GP2: unused. Set as output.
 ;  5 - VDD
 ;  6 - MCLR_, GP3: unused. tied to VDD in circuit.

;***** Define addresses of the General Purpose Registers ****
; 24 general purpose registers available starting at 0x08
COUNT1    equ 0x08    ;First counter for delay loops
COUNT2    equ 0x09    ;Second counter for delay loops
COUNT3    equ 0x0a    ;Third counter for delay loops
SCRATCH    equ 0x0b    ;Scratchpad variable for everthing else.
    org    0x0000          ; processor reset vector

    movwf    OSCCAL        ; load the calibration value into the OSCCAL reg.
;**** Disable unused peripherals ****
    movlw    b'11001100' ; disable Wake on Change, disable Weak pullups, 
    OPTION                ; internal clk -> Timer0, Timer0 source edge don't care,
                ; Prescaler Assignment -> WDT, Prescaler = 16
;**** Setup GPIO inputs/outputs ****
    movlw    b'00000000' ; load GPIO register before TRIS assignment
    movwf    GPIO
    movlw    b'00001001' ; set GP1 & GP2 as output, all others are inputs
    TRIS    GPIO

    clrwdt            ; reset watchdog
    call    Delay10ms   
    btfss    GPIO, 0        ; sample SHUTDN input every 10ms
    goto    Start        ; back to START if SHUTDN = 0
    movlw    d'5'        ; number of samples to deglitch SHUTDN input.
    movwf    COUNT3
Sample    call    Delay10ms
    btfss    GPIO, 0
    goto    Start        ; back to START if SHUTDN = 0
    decfsz    COUNT3, 1   ; SHUTDN must be high 5x in a row
    goto    Sample
    clrwdt            ; clear the watchdog
    call    Delay20        ; commit to shutdown at this point. Wait 20 sec.
    bsf    GPIO, 1        ; set the shutdown output high
Stuck    clrwdt            ; reset watchdog    
    goto Stuck        ; infinite loop until power is cut

;**** subroutines begin here ****    
Delay1                ; total count = 1Meg = 1 second
    movlw    d'8'        ; put 8 into COUNT3
    movwf    COUNT3        ; COUNT3 x (COUNT1 x 3 + 3)(COUNT2 + 5) = 1001472
    movlw    d'255'        ; put 255 
    movwf    COUNT1        ; into COUNT1
Loop2    movlw    d'158'        ; put 158
    movwf    COUNT2        ; into COUNT2        
Loop1    decfsz    COUNT1,1    ; counts down from 255
        goto    Loop1       ;
        decfsz    COUNT2,1    ; counts down from 158
    goto    Loop1        ;
    clrwdt            ; clear the watchdog timer every 125ms
    decfsz    COUNT3,1    ; counts down from 8
    goto    Loop2        ; 
    RETLW    0

Delay10ms            ; delay = 1us x (255x3+3) x (8 + 5) = 9.98ms
    movlw    d'255'
    movwf    COUNT1
    movlw    d'8'
    movwf    COUNT2        
    decfsz    COUNT1,1    
        goto    Loop10       
        decfsz    COUNT2,1    
    goto    Loop10        
    RETLW    0    
    movlw    d'20'        ; 20 x 1 = 20 seconds
    movwf    SCRATCH        ; into SCRATCH reg.
    call    Delay1        ; 1 sec delay
    decfsz    SCRATCH,1   ;
        goto    Loop20       ;
    RETLW    0

Edit 2019-01-18: I change the shutdown output from a 750µs pulse to just a high value after the 20 second delay. Apparently, the pulse was too short to accomplish the task and it works fine with the step output. I updated the hex code in the files section to match.