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