; ***************************************************************
; * Copyright (C) 2007, Embed Inc (http://www.embedinc.com) *
; * *
; * Permission to copy this file is granted as long as this *
; * copyright notice is included in its entirety at the *
; * beginning of the file, whether the file is copied in whole *
; * or in part and regardless of whether other information is *
; * added to the copy. *
; * *
; * The contents of this file may be used in any way, *
; * commercial or otherwise. This file is provided "as is", *
; * and Embed Inc makes no claims of suitability for a *
; * particular purpose nor assumes any liability resulting from *
; * its use. *
; ***************************************************************
;
; Controller for KnurdLight LED headlamp.
;
/const processor string = "10F204"
processor [chars processor]
include [str "p" [lcase processor] ".inc"]
/include "(cog)src/pic/std_def.ins.aspic"
freq_osc equ 4000000 ;CPU oscillator frequency in Hz
stacksize set 0 ;no software stack in use
/include "(cog)src/pic/std.ins.aspic"
;
; Set the static processor configuration bits.
;
.config code
data b'111111111111'
; XXXXXXX---XX unused
; -------1---- MCLR pin configured to MCLR role
; --------1--- disable code protection
; ---------1-- enable watchdog timer
;
; Application configuration parameters.
;
/const wdtms real = 18 ;mS nominal watchdog timer timeout
/const startms real = 250 ;mS button must be up for startup
/const onminms real = 250 ;minimum mS button pressed/released for turn on
/const onmaxms real = 750 ;maximum mS button pressed/released for turn on
;
; Derived constants.
;
startwd equ [rnd [/ startms wdtms]] ;WDT ticks button up for startup
onminwd equ [rnd [/ onminms wdtms]] ;WDT ticks min button time for turn on
onmaxwd equ [rnd [/ onmaxms wdtms]] ;WDT ticks max button time for turn on
;
; Flag bits. Each /FLAG directive allocates a single new bit. The minimum
; number GFL0 - GFLn variables are created to hold all the flag bits. See
; the PREPIC preprocessor documentation for details of the /FLAG directive.
;
;
; Variables.
;
udata
wakeadr res 1 ;address to resume at after watchdog timer reset
reg0 res 1 ;scratch registers with no dedicated purpose
reg1 res 1
reg2 res 1
reg3 res 1
flags_define ;define GFL0-GFLn to hold all the flag bits
;
; I/O pin declarations. See the PREPIC preprocessor documentation for
; details of the /OUTBIT and /INBIT directives.
;
/inbit outcurr porta 0 ;analog input, proportional to output current
/outbit butt porta 1 0 ;pulled low when user button is pressed
/outbit sw porta 2 0 ;high enables buck switching element
/inbit mclr porta 3 ;dedicated MCLR line, low holds processor in reset
tris_butt equ val_trisa | (1 << butt_bit) ;TRIS value for reading button pin
;
;***********************************************************************
;
; Macro SW_ON
;
; Turn on the switching power supply switching element.
;
sw_on macro
bsf sw_pin
endm
;
;***********************************************************************
;
; Macro SW_OFF
;
; Turn off the switching power supply switching element.
;
sw_off macro
bcf sw_pin
endm
;
;***********************************************************************
;
; Macro SKIP_VLO
;
; Skip the next instruction if the output voltage is below its
; regulation threshold.
;
skip_vlo macro
btfsc cmcon0, cmpout
endm
;
;***********************************************************************
;
; Macro SKIP_VHI
;
; Skip the next instruction if the output voltage is above its
; regulation threshold.
;
skip_vhi macro
btfss cmcon0, cmpout
endm
;
;***********************************************************************
;
; Macro BUTT_DISABLE
;
; Disable the button input. This minimizes current drain, but disables
; the ability to read the button.
;
; W is trashed.
;
butt_disable macro
movlw val_trisa
tris gpio
endm
;
;***********************************************************************
;
; Macro BUTT_ENABLE
;
; Enable reading the button, although this can cause more current drain.
;
; W is trashed.
;
butt_enable macro
movlw tris_butt
tris gpio
endm
;
;***********************************************************************
;
; Macro WAIT_WDT
;
; Put the processor to sleep and continue after this macro on the next
; watchdog timer tick. The processor performs a reset on watchdog
; timer timeout and therefore does not continue after the sleep
; instruction. The code at reset detects a watchdog timer timeout as
; apposed to a power up reset. On a watchdog timer timeout, the startup
; code jumps to the address in WAKEADR, which is set by this macro before
; the processor sleep is started.
;
wait_wdt macro
local restart
movlw restart ;save restart address
movwf wakeadr
sleep ;power down until WDT timeout
nop ;prefetched instruction that is always executed
restart ;startup code will resume here on watchdog wakeup
endm
;
;***********************************************************************
;
; Macro WAIT_UP N, ABORT
;
; Wait for the button to be up for at least N watchdog timer ticks. This
; macro jumps to ABORT if the button is ever found pressed. The supply
; current drain is minimized during this time, both from the processor
; itself and from current for checking the button.
;
; N must be from 1 to 255.
;
; REG0, REG1 are trashed.
;
wait_up macro n, abort
local loop
if (n < 1) || (n > 255)
error N parameter to WAIT_UP macro out of range.
endif
movlw n ;init number of watchdog wakeups left
movwf reg1
loop ;back here for each new watchdog wakeup
wait_wdt ;sleep for one watchdog timer tick
mcall butt_read ;get button I/O pin into REG0
btfss reg0, butt_bit ;button is up ?
jump abort ;button is down
decfsz reg1 ;count one less timer tick left to do
jump loop ;back to do next timer tick
endm
;
;***********************************************************************
;
; Macro WAIT_DOWN N, ABORT
;
; Wait for the button to be down for at least N watchdog timer ticks. This
; macro jumps to ABORT if the button is ever found up. The supply
; current drain is minimized during this time, both from the processor
; itself and from current for checking the button.
;
; N must be from 1 to 255.
;
; REG0, REG1 are trashed.
;
wait_down macro n, abort
local loop
if (n < 1) || (n > 255)
error N parameter to WAIT_UP macro out of range.
endif
movlw n ;init number of watchdog wakeups left
movwf reg1
loop ;back here for each new watchdog wakeup
wait_wdt ;sleep for one watchdog timer tick
mcall butt_read ;get button I/O pin into REG0
btfsc reg0, butt_bit ;button is down ?
jump abort ;button is up
decfsz reg1 ;count one less timer tick left to do
jump loop ;back to do next timer tick
endm
;
;***********************************************************************
;
; Executable code.
;
.reset code 0 ;execution starts here on a reset
andlw b'11111110' ;mask off Fosc/4 driven onto GP2 control bit
movwf osccal ;set oscillator to calibrated value
movlw b'10000111' ;set up OPTION register
; 1------- disable wakeup on pin change
; -0------ enable passive pullups on input pins
; --0----- timer 0 clock source is instruction clock
; ---X---- timer 0 edge select, not used with instr clock source
; ----0--- prescaler assigned to timer 0
; -----111 prescaler divide value of 256
option
;
; Set up the I/O pins according to the /INBIT and /OUTBIT preprocessor
; commands above.
;
if val_trisa & ~15
error Non-existent I/O bit set as input.
endif
if (val_trisa ^ 8) & 8
error GPIO 3 declared as output, can only be input.
endif
movlw val_porta
movwf porta ;set initial values for output pins
movlw val_trisa
tris porta ;set pins to input or output as specified
ifdef adcon0 ;disable A/D if there is one
movlw b'00000000'
; 0------- configure GP1 for digital I/O
; -0------ configure GP0 for digital I/O
; --XX---- unused
; ----XX-- A/D channel select
; ------0- do not start A/D conversion now
; -------0 keep the A/D off
movwf adcon0
endif
clrf cmcon0 ;comparator off for now to minimize current drain
;
; Check for watchdog timer versus power up reset. We assume a watchdog timer
; reset is really a wakeup after a delay, and execution is resumed after the
; sleep point.
;
btfsc status, not_to ;this reset is due to watchdog timer timeout ?
jump powerup ;no, due to power up
;
; Watchdog timer reset.
;
; Restart after the SLEEP instruction that was used to wait for this
; watchdog timer tick. The WAIT_WDT macro is used to wait for a watchdog
; timeout tick. It sets WAKEADR to the address to resume execution at
; on a watchdog timer restart.
;
movf wakeadr, w ;get the execution restart address
movwf pcl ;jump to it
;
;***********************************************************************
;
; Subroutine BUTT_READ
;
; Read the external button and put the result in bit BUTT_BIT of REG0.
; This bit will be 0 if the button is pressed and 1 if released. The
; BUTT I/O line will be set to a input with internal pullup, the line
; will be given sufficient time to rise if the button is not pressed,
; the line read, and then the pin restored to a output driven low to
; conserve supply curent.
;
butt_read
butt_enable ;set up hardware to enable button read
waitus 10, 1 ;give button line a chance to settle
movf butt_reg, w ;read the port containing button pin
movwf reg0 ;pass back result
butt_disable ;set button hardware to lowest current drain
retlw 0
;
;***********************************************************************
;
; Power up reset. The code jumps here from the reset vector if the
; reset is due to power up instead of a watchdog timer timeout.
;
powerup
flags_clear ;init all the 1-bit flags to zero
;
; Wait for the user button to be up continuously for about STARTMS
; milliseconds before startup up. The timeout is restarted whenever
; the button is found pressed.
;
pwrup_up ;back here until button up long enough
ton0 ;abort back here on invalid turn on sequence
wait_up startwd, pwrup_up ;wait for the minimum button up time
;
;********************
;
; Wait for command to turn on.
;
ton1 ;wait for button press
wait_down onminwd, ton1 ;wait for minimum button down time
wait_down onmaxwd - onminwd, ton2 ;button must be released during this time
jump ton0 ;button down too long, abort
ton2 ;valid button press just ended
wait_up onminwd, ton0 ;wait for minimum required up time
wait_up onmaxwd - onminwd, ton3 ;button must be pressed during this time
jump ton0 ;button not pressed in time, abort
ton3 ;second button press just started
wait_down onminwd, ton0 ;wait for minimum button down time
wait_down onmaxwd - onminwd, ton4 ;button must be released during this time
jump ton0 ;button down too long, abort
ton4 ;second button press just ended
;
;********************
;
; Normal operation. Keep the output around its regulation threshold
; but abort to the reset vector if the button is pressed.
;
movlw b'01111011' ;turn on the compartor for sensing the current
; X------- comparator output, read only
; -1------ comparator output not driven to COUT pin
; --1----- do not invert comparator output
; ---1---- comparator output is not timer 0 clock
; ----1--- enable the comparator
; -----0-- negative input is internal 600mV reference
; ------1- positive input is CIN+ pin (GP0)
; -------1 disable wakeup on comparator change
movwf cmcon0
butt_enable ;enable reading external button
;
; Wait for the output to fall below the regulation threshold.
;
ishigh ;jump here when the output is high
sw_off ;turn off the switching element
loop_high ;back here while the output is high
clrwdt
skip_vlo ;output is now low ?
goto loop_high ;no, go back and check again
;
; The output is low. Do switching pulses until the output goes high.
;
sw_on
pulse ;back here after starting a new pulse
skip_vlo ;output still low ?
jump ishigh ;no, abort pulse
btfss butt_pin ;button not pressed ?
goto abort ;button is pressed, abort normal operation
clrwdt
sw_off ;turn off switch for one cycle
sw_on
jump pulse
;
; The button was found pressed during normal operation.
;
abort
sw_off ;turn off the switching element
movlw powerup ;treat next reset like powerup
movwf wakeadr
goto 255 ;jump to the reset vector, re-initialize system
end