Gen 3.2 PCS Firmware
From Seamonster
Gen 3.2
- General Microservers, Vexcel Microservers, Quick Reference, Data Acquisition, Middleware
- Components GPS, SBC
- Configuration Microserver, SBC, SD Card, Power
- Operation Communication Protocol (SBC <--> uc), SBC Operations, Agent
- Operation (background) Task Manager "milo", config files, MACRO
- Microcontroller Microcontroller, Firmware, Skeleton firmware
- Evaluation 2008 Cairn relay failure evaluation, Lab evaluation, Eval-Firmware, BPMS, Source notes
- PCS Board PCS Board Design, Voltage Monitoring Circuit
Gen 3.1
- Gen 3.1 Kernel Upgrade and Field Notes (Spring 2007)
- Gen 3.1 Microserver, README, Schematics
- Gen 3.1 Task Manager "milo", GPS, Firmware
Microcontroller-related
Other Microserver-Related
Introduction
The purpose of this page is to explicitly record the/a current version of the VuS Microcontroller firmware.
Version 4 Gen 3.2 Microcontroller Firmware
; Gen 3.2 microserver Power Conditioning Subsystem (PCS) uC code
; Device Vendor: Microchip
; MCU: PIC18F4520
; Start date: 5/15/2006
; Filename: PCS32.asm
; Authors: Dennis R. Fatland / Larry M. Brewster
; Company: Microsoft Corporation
; Last mod: 4/24/2008
; Version: 4 (second operational version)
;
; Version 4 Distinguishing Characteristics from Version 3
; edip001 turns on all peripherals before entering timing loop
; making it easier to configure the SBC since WiFi ON
;
; To Do:
; Ext-power off during operation: Does this reset the uc timing vars
; Re-check timing edip001: 5:00 min elapsed required 4:47 actual time
; Check WDT timeout edip010: About 121 seconds required to WDT timeout
; Check the batt mon ADC < 140: Sleep one hour and reset
;
; 'Antant' flags debug maneuvers
; 'Cassandra' flags warnings.
;
; Prelim version: 1
; Dev Version: 2
; Current version: 3
; see variable myVersion
;
; Note: Running in "Debug" mode on the ICD will disable a couple pins
;
; Op modes
; 000 All On Forever WDT Disabled Echo B7:4 to C7:4
; 001 All peripherals on, then infinite loop timing test
; 010 WDT enabled intentional reset test
; 011 Testing rapid drop dead
; 100 Operational NO Drop Dead WDT Enabled
; 101 Operational 4-Hr Drop Dead WDT Enabled
; 110 Operational 1-Day Drop Dead WDT Enabled
; 111 Operational 7-Day Drop Dead WDT Enabled
;
; Configuration Bit Settings
; OSCILLATOR: INT RC_CLKOUT on RA6, PORT on RA7
; Brown Out Detect: Disabled in hardware, SBOREN disabled
; Brown Out Voltage: 2.0V
; Watch Dog Timer Disable: Controlled by SWDTEN bit
; Watch Dog Postscaler: 1:32768
; CCP2 MUX: RC1
; PORTB A/D Enable: PORTB<4:0> configured as Digital I/O on Reset
; ??? Lower Power Timer1 OSC Enable: Enabled
; ??? Master Clear Enable: MCLR Disabled, RE3 Enabled
; Stack Overflow Reset: Enabled
; (The rest disabled)
;
; JP1 Source: SBC
; JP2 Source: AMP
; JP3 Sink: External Batt
; JP4 --------------------------> Batt Monitor line
; JP5 Source: Bridge
; JP6 Sink: Internal Batt
; JP7 Source: Internal 12
; JP8 Source: Internal 3.3
; JP9 30 pin test header
; J2 is the RJ45 programming port
; J7 4 pin Source to external power, 1-4: 3.3, 5, 12, Gd
;
; P1 LCD TO SBC pins 11, 12, 13, 14 -> RC4, 5, 6, 7
; (also on JP9 17, 18, 19, 20)
; P2 DIO1 FROM SBC pins 10, 12, 14, 16 -> RB4, 5, 6, 7
; (also on JP9 16, 15, 14, 13) note reverse order
;
; PORTB (readable) and LATC (writable) are not 8-bit accessible.
; PORTB and LATC work by means of bit operations on the four MSBs.
; This requires some delay tolerance on the part of the SBC.
; B is a 4-bit port from SBC, C is the return 4-bit port to SBC
; Bits are indexed PORTB7:4, PORTC7:4 in MSB to LSB order, etc.
;
; ADC and DIO spares
; Note that B2 and B3 are DIO lines A/GP-1 and A/GP-2 where B2 is
; dedicated to the BIG POWER MOSFET SWITCH while A0 and A1 are
; ADC lines A/GP-3 and A/GP-4. These are routed to one side of J4
; and one side of J5 so that they may be routed individually by
; jumpers either to J3 (useful for B2 to BPMS) or to J6 (useful
; for attaching an external analog signal).
;
; Code and configuration notes
; Error states are encoded as signature patterns
; on the 4 high LATC bits
;
; ADCON0 map:
; 7, 6 not used
; 5:2 4 bits to address one analog channel (0--12, 13--15 not implemented)
; 1 GO bit (set to enable, is clear when sample is acquired)
; 0 ON bit (set to enable the AD module)
;
; ADCON1 map
; 7, 6 not used
; 5 Vref- config: 0 means use Vss, 1 means use AN2 == RA2
; 4 Vref+ config: 0 means use Vdd, 1 means use AN3 == RA3 (our idea)
; 3:0 Config control bits; you have to use the lookup table but the basic idea is
; the higher this value the more ADC channels are enabled as such. The main
; value we care about are 1010 (which enables AN4:0, where AN4==RA5 is the
; voltage we want to see. (Note: If done using edip DIO input: Can also enable
; AN8 and AN9 (as well as 7:0) by setting ADCON1 bits3:0 to 0101.)
;
; ADCON2 map
; 7 Format bit: 1 is Rt-justified, 0 is Lt-justified
; 6 Not used
; 5:3 Set time of acquisition TAD
; 2:0 A/D Conversion Clock Select
;
; Steps to getting a digital value from an AD
; 1. Set up ADCON1: Analog pins, voltage ref xx011010
; 2. Select the AD input channel ADCON0 xx1001xx
; 3. Select the AD input time ADCON2 xx000xxx (I think, maybe 001...)
; 4. Select the AD clock source ADCON2 xxxxx000 (I think...)
; 5. Enable the AD module ADCON0 xxxxxxx1
; 6. --Skipped: Config AD Interrupt--
; 7. Wait acquisition time
; 8. Start the conversion (ADCON0 GO bit set) xxxxxx1x
; 9. Wait for conversion to finish ->0
; (poll the GO bit until 0)
; 10. Read result ADRESH:ADRESL
;
; analog in to pin mapping
; AN0 RA0 <- A/GP-3 configured as ADC
; AN1 RA1 <- A/GP-4 configured as ADC
; AN2 RA2 <- not used for V- reference voltage (Vss ground is)
; AN3 RA3 <- but used for V+ reference voltage (pin 22 E side S edge)
; (RA4 Dedicated DIO controls Internal_3p3)
; AN4 RA5 <- This is where the test voltage comes in (pin 24, 2nd one up on E side)
; AN5 RE0 <- used for edip (not ADC)
; AN6 RE1 <- edip
; AN7 RE2 <- edip
; AN8 RB2 <- available (temporarily until BPMS is installed)
; AN9 RB3 <- available
; AN10 RB1 <- not available (Ext5)
; AN11 RB4 <- not available (low bit of SBC input from DIO1)
; AN12 RB0 <- not available (Ext3p3)
;
; JP9 pinout:
; 1--4 A/GP_4,3,2,1
; 5 Ext 12V Out
; 6 Ext 5V Out
; 7 Ext 3.3V Out
; 8 Int 12V Out
; 9 Int 3.3V Out
; 10--11 Standalone voltage divider
; 12 Batt Monitor
; 13--16 PORTB7,6,5,4 from SBC DIO1
; 17--20 PORTC4,5,6,7 to SBC LCD (DIO)
; 21 Clock OSC2 PIC pin 31
; 22 1PPS
; 23 5V-B
; 24 3.3V --? to GSP ?--
; 25 5V-DQ Internal Batt to PIC
; 26 5V-P
; 27 12V W-AMP POWER
; 28 12V SBC POWER
; 29--30 Ground
;
; PORT MAPS
; Bit Pin Function
; RA0: 19: A/GP_3 fixed ADC
; RA1: 20: A/GP_4 fixed ADC
; RA2: 21: Gd(?)
; RA3: 22: ADC Reference Voltage In
; RA4: 23: Int3p3V Power
; RA5: 24: ADC4 Bat_Mon voltage divider input
;
; RB0: 8: Ext3p3V Power
; RB1: 9: Ext5V Power
; RB2: 10: A/GP_1, fixed DIO
; RB3: 11: A/GP_2, fixed DIO
; RB4: 14: SBC to uc Bit 0 (LSB)
; RB5: 15: SBC to uc Bit 1
; RB6: 16: SBC to uc Bit 2
; RB7: 17: SBC to uc Bit 3 (MSB)
;
; RC0: 32: EXT-Timer
; RC1: 35: EXT-Timer
; RC2: 36: Ext12V Power
; RC3: 37: Int12V Power
; RC4: 42: uc to SBC Bit 0 (LSB)
; RC5: 43: uc to SBC Bit 1
; RC6: 44: uc to SBC Bit 2
; RC7: 1: uc to SBC Bit 3 (MSB)
;
; RD0: 38: GPS Power via U9
; RD1: 39: 5V Power (General)
; RD2: 40: 12V_P Power
; RD3: 41: P_SEL Power (?)
; RD4: 2: SBC Power via U1
; RD5: 3: Amp Power via U2
; RD6: 4: Bridge Power via U11
; RD7: 5: 5V_P Power
;
; RE0: 25: edip bit 0
; RE1: 26: edip bit 1
; RE2: 27: edip bit 2 (MSB)
; RE3: 18: MCLR...
;
LIST P=PIC18F4520 ;directive to define processor and file format
#include p18f4520.inc ;processor specific variable definitions
vars udata
; Errors
myCommErrCounter res 1
; State variables
; Sleep interval is counted down during low power hibernation
; DropDead interval is counted down during normal operation
mySleepMinutes res 1
mySleepHours res 1
mySleepDays res 1
myDropDeadSeconds res 1
myDropDeadMinutes res 1
myDropDeadHours res 1
myDropDeadDays res 1
myNoDropDead res 1 ; Boolean for Mode 100
mySBCIsAwake res 1
myVersion res 1
; Message passing
mySBCChecksum res 1
myUcChecksum res 1
mySBCType res 1
mySBCData res 1
myUcType res 1
myUcData res 1
; Message processing
myToDoList res 1 ; Bit 0: Process SBC Message, Bit 1: Send Message, Bit 2: Go To Sleep Now
mySendMsgTypeLow res 1 ; 0: PowerState, 1: V, 2: GPIO State, 3:Sleep Alert, 4:NC, 5/6/7: Sleep Min/Hrs/Days
mySendMsgTypeHi res 1 ; 0/1/2/3: DropDead Sec/Min/Hrs/Days, 4--7:NC
myCaptureFailed res 1
; Timing loops
myDelaySec res 1
myDelayOuter res 1
myDelayInner res 1
myEdip res 1
; ADC
myADRESH res 1
pcs32 code
main
; Init power checking is done after edip switch in edip fns
nop
; set 32khz clock speed, internal (IRCF2:0 all zero)
bcf OSCCON, IRCF2
bsf OSCCON, IDLEN ;(LB 10/23/06)
; disable interrupts
; Regardless of RCON:IPEN setting INTCON:GIE=7 to ZERO disables all interrupts
clrf INTCON
; Version 1: Development version with positive logic on 5V-B supply U11
; Version 2: Development version, negative logic on 5V-B supply U11
; Version 3: First Operational Version for Build 1
; Version 4: Second Operational Version applied to PCS boards 8+ in Build 1
movlw 04h
movwf myVersion
; RCON Bit 3 is called TO and it is the Watchdog Timeout Flag Bit
; It is read-only and you want to keep it "High"
; Bit 3 = 0: A WDT has occurred
; Bit 3 = 1: Set by clrwdt or sleep or power-up
bcf WDTCON, SWDTEN
; Because the WDT Config is Disabled it can be set or disabled using
; SWDTEN so we begin by disabling that watchdog
; Use this as a basic pin toggle test
; bcf TRISC, 7
; tmpjump
; bsf LATC, 7
; bcf LATC, 7
; goto tmpjump
call PortConfigure ; Includes BIG POWER MOSFET SWITCH = ON
call PowerTransitionToFull
call InitAD
; Check the Batt Mon ADC value
; If it is identically ZERO: Assume wire not connected; continue normally
; If it is nonzero and >= decimal-140: Assume supply ok; continue normally
; If fallthrough: Nonzero on 1--139: Assume supply is low; sleep 1 hr, reset
nop
nop
call ReadVoltage
nop
nop
movff ADRESH, myADRESH ; make sure no write-result-to-register glitches
movlw 0h
addwf myADRESH ; add zero to the ADRESH value to get a testable result
bz ContinueStartup ; assume ADC = 0 means ADC wire not connected
; Cassandra: Should properly set a state value before
; branch to Continue
movlw 8ch ; 128 + 12 = 140 decimal
subwf myADRESH ; subtract WREG from myADRESH and
bnn ContinueStartup ; continue if result non-negative
clrf mySleepMinutes ; Fall-through means a low power supply;
movlw 01h ; Go sleep it off for another hour
movwf mySleepHours
clrf mySleepDays
goto DropDead
ContinueStartup
; SWITCH ON EDIP E0:2
;;;;;;;;;;;;;;;;;;;;;;;;
; In what follows we enumerate bits 2 = 1, 1 = 0, 0 = 0 as 100
btfss PORTE, 0
goto Exx0
btfss PORTE, 1 ; Before this instruction we know xx1
goto Ex01
btfss PORTE, 2 ; Before this instruction we know x11
goto edip011 ; Before this instruction we know 011
goto edip111 ; Before this instruction we know 111
Exx0
btfss PORTE, 1 ; Before this instruction we know xx0
goto Ex00 ; Before this instruction we know x00
btfss PORTE, 2 ; Before this instruction we know x10
goto edip010 ; Before this instruction we know 010
goto edip110 ; Before this instruction we know 110
Ex00
btfss PORTE, 2 ; Before this instruction we know x00
goto edip000 ; Before this instruction we know 000
goto edip100 ; Before this instruction we know 100
Ex01
btfss PORTE, 2 ; Before this instruction we know x01
goto edip001 ; Before this instruction we know 001
goto edip101 ; Before this instruction we know 101
; Can't get here
;;; EDIP 0 0 0: All on, echo B to C
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
edip000
call OnAllPeripherals
edip000_loop
movlw 01h
movwf mySleepMinutes
clrf mySleepHours
clrf mySleepDays
bsf LATC, 7
bsf LATC, 6
bsf LATC, 5
bsf LATC, 4
call DelayOneMinute
; can re-install a bit flip here in rvs order
nop
nop
nop
nop
nop
; goto edip000_loop
goto DropDead
;;; EDIP 0 0 1: Timing testing
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
edip001
call OnAllPeripherals
edip001_loop
bsf LATC, 4
bsf LATC, 5
bsf LATC, 6
bsf LATC, 7
call DelayOneMinute
bcf LATC, 7
call DelayOneMinute
bcf LATC, 6
call DelayOneMinute
bcf LATC, 5
call DelayOneMinute
bcf LATC, 4
call DelayOneMinute
goto edip001_loop
;;; EDIP 0 1 0: WDT timeout test
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
edip010
call OnSBC ; This works, requires 121 sec to timeout, roughly
bsf LATC, 4 ; PORTC starts HI
bsf LATC, 5
bsf LATC, 6
bsf LATC, 7
movlw 0ah
movwf myDelaySec
call DelayNSeconds
bcf LATC, 7 ; Kill 10 sec, extinguish 7, repeat for 6, 5, 4
movlw 0ah
movwf myDelaySec
call DelayNSeconds
bcf LATC, 6
movlw 0ah
movwf myDelaySec
call DelayNSeconds
bcf LATC, 5
movlw 0ah
movwf myDelaySec
call DelayNSeconds
bcf LATC, 4
movlw 0ah
movwf myDelaySec
call DelayNSeconds ; Wait 10 more sec, then enable WDT
bsf WDTCON, SWDTEN
clrwdt
edip010_loop
btfss RCON, 3
goto edip010_TO_Clear
bsf LATC, 4
bsf LATC, 5
bsf LATC, 6
bsf LATC, 7
goto edip010_loop
edip010_TO_Clear
bcf LATC, 4
bcf LATC, 5
bcf LATC, 6
bcf LATC, 7
goto edip010_loop
;;; EDIP 0 1 1: QUICK DROP DEAD for sleep testing
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
edip011
call operational_initialize
clrf myNoDropDead
clrf myDropDeadSeconds
movlw 3h
movwf myDropDeadMinutes
clrf myDropDeadHours
clrf myDropDeadDays
CLRWDT
goto operational_loop
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;
;;;;;;; OPERATIONAL MODES
;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Each edip1xx configures (initializes some timing) and jumps to
;; operational_loop. In particular what differentiates
edip100
call operational_initialize
setf myNoDropDead ; set myNoDropDead TRUE
goto operational_loop
edip101
call operational_initialize
clrf myNoDropDead
clrf myDropDeadSeconds
clrf myDropDeadMinutes
movlw 4h
movwf myDropDeadHours
clrf myDropDeadDays ; 4 Hours
goto operational_loop
edip110
call operational_initialize
clrf myNoDropDead
clrf myDropDeadSeconds
clrf myDropDeadMinutes
clrf myDropDeadHours
movlw 1h
movwf myDropDeadDays ; 1 Day
goto operational_loop
edip111
call operational_initialize
clrf myNoDropDead
clrf myDropDeadSeconds
clrf myDropDeadMinutes
clrf myDropDeadHours
movlw 7h
movwf myDropDeadDays ; 7 Days
goto operational_loop
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;
;;;;;;;;;; Operational-Mode Support Functions
;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
operational_initialize
call SetLATCFriendly
call OnSBC
call DelayOneMinute
call DelayOneMinute ; Ignore PORTB for awhile while system boots
call SetLATCFriendly
movlw 02h ; Default sleep interval is brief: 2 minutes
movwf mySleepMinutes
clrf mySleepHours
clrf mySleepDays
clrf myToDoList ; Nothing pending on the calendar
return
;;;;;;;;;;;;
;;; operational_loop uses parseB, power_check, and countdown
;;; These are listed in this order together with any dependent functions
;;;;;;;;;;;;
operational_loop
call ParseB ; Check for Alerts and process myToDoList:0 = 1
btfsc myToDoList, 1
call SendMessage
call countdown ; knocks 1 second off the drop dead clock
goto operational_loop
; SendMessage is "blind" (no intelligence); it simply pushes pre-loaded type and data
; through the 3-bit pipe using the PORTC MSB as a toggle-to-next.
SendMessage
bcf myToDoList, 1 ; whether or not this works it's off the ToDo list
bcf myToDoList, 0 ; also nothing to process from SBC; but don't touch the sleep-pending bit (2)
bcf LATC, 4 ; Set the Alert state on PORTC
bsf LATC, 5
bsf LATC, 6
bsf LATC, 7 ; LATC = 1110 0000 translation: uC message Alert
call PollPORTB765 ; Will return when B:765 bits are all set
btfsc PORTB, 4 ; Check bit 4: If Set: Bail out (and receive incoming)
return ; because the SBC has precedence between 1111 and 1110
call CalculateUcChecksum
call SetUcSignal1
clrwdt
call PollPORTB_MSBLo
call SetUcSignal2
clrwdt
call PollPORTB_MSBHi
call SetUcSignal3
clrwdt
call PollPORTB_MSBLo
call SetUcSignal4
clrwdt
call PollPORTB_MSBHi
call SetUcChecksum
clrwdt
call PollPORTB_MSBLo
call SetLATCFriendly
return
CalculateUcChecksum
; This uses myTmp as an accumulator
; movff myUcData, myUcChecksum
; movlw 07h
; AND WREG with myUcChecksum
; movf myUcData into WREG
; shift WREG right 3 bits
; andlw 07h
; addwf to myUcChecksum
; movf myUcData into WREG
; shift WREG right 6 bits
; andlw 03h
; addwf to myUcChecksum
; movff myUcType, WREG
; do the LSB as bit 3
; movff myUcType, WREG
; do bits 1:3 as bits 0:2
; mask result and 07h
return
; This should be ok
PollPORTB765
btfss PORTB, 7
goto PollPORTB765
btfss PORTB, 6
goto PollPORTB765
btfss PORTB, 5
goto PollPORTB765
return
; The following configure PORTC for signals 1, 2, 3, and 4 plus the checksum
SetUcSignal1
btfsc myUcType, 3 ; Low 4 bits of myUcType are used here
goto SUS1_Type3Hi
bcf LATC, 6
goto SUS1_Continue2
SUS1_Type3Hi
bsf LATC, 6
SUS1_Continue2
btfsc myUcType, 2
goto SUS1_Type2Hi
bcf LATC, 5
goto SUS1_Continue1
SUS1_Type2Hi
bsf LATC, 5
SUS1_Continue1
btfsc myUcType, 1
goto SUS1_Type1Hi
bcf LATC, 4
goto SUS1_ContinueDone
SUS1_Type1Hi
bsf LATC, 4
SUS1_ContinueDone
bcf LATC, 7 ; Hardcoded MSB toggles Lo for Signal 1 READY
return
SetUcSignal2
btfsc myUcType, 0
goto SUS2_Type0Hi
bcf LATC, 6
goto SUS2_Continue2
SUS2_Type0Hi
bsf LATC, 6
SUS2_Continue2
btfsc myUcData, 7
goto SUS2_Data7Hi
bcf LATC, 5
goto SUS2_Continue1
SUS2_Data7Hi
bsf LATC, 5
SUS2_Continue1
btfsc myUcData, 6
goto SUS2_Data6Hi
bcf LATC, 4
goto SUS2_ContinueDone
SUS2_Data6Hi
bsf LATC, 4
SUS2_ContinueDone
bsf LATC, 7 ; Hardcoded MSB toggles Hi for Signal 2 READY
return
SetUcSignal3
btfsc myUcData, 5
goto SUS3_Data5Hi
bcf LATC, 6
goto SUS3_Continue2
SUS3_Data5Hi
bsf LATC, 6
SUS3_Continue2
btfsc myUcData, 4
goto SUS3_Data4Hi
bcf LATC, 5
goto SUS3_Continue1
SUS3_Data4Hi
bsf LATC, 5
SUS3_Continue1
btfsc myUcData, 3
goto SUS3_Data3Hi
bcf LATC, 4
goto SUS3_ContinueDone
SUS3_Data3Hi
bsf LATC, 4
SUS3_ContinueDone
bcf LATC, 7 ; Hardcoded MSB toggles Lo for Signal 3 READY
return
SetUcSignal4
btfsc myUcData, 2
goto SUS4_Data2Hi
bcf LATC, 6
goto SUS4_Continue2
SUS4_Data2Hi
bsf LATC, 6
SUS4_Continue2
btfsc myUcData, 1
goto SUS4_Data1Hi
bcf LATC, 5
goto SUS4_Continue1
SUS4_Data1Hi
bsf LATC, 5
SUS4_Continue1
btfsc myUcData, 0
goto SUS4_Data0Hi
bcf LATC, 4
goto SUS4_ContinueDone
SUS4_Data0Hi
bsf LATC, 4
SUS4_ContinueDone
bsf LATC, 7 ; Hardcoded MSB toggles Hi for Signal 4 READY
return
SetUcChecksum
btfsc myUcChecksum, 2
goto SUC_Chksum2Hi
bcf LATC, 6
goto SUC_Continue2
SUC_Chksum2Hi
bsf LATC, 6
SUC_Continue2
btfsc myUcChecksum, 1
goto SUC_Chksum1Hi
bcf LATC, 5
goto SUC_Continue1
SUC_Chksum1Hi
bsf LATC, 5
SUC_Continue1
btfsc myUcChecksum, 0
goto SUC_Chksum0Hi
bcf LATC, 4
goto SUC_ContinueDone
SUC_Chksum0Hi
bsf LATC, 4
SUC_ContinueDone
bcf LATC, 7 ; Hardcoded MSB toggles Lo for Checksum signal set
return
; These should be ok, will reset on WDT or ... see notes
PollPORTB_MSBLo
btfsc PORTB, 7
goto PollPORTB_MSBLo
return
PollPORTB_MSBHi
btfss PORTB, 7
goto PollPORTB_MSBHi
return
; parsing happens in three stages
; 1. Check for an alert from the SBC = 1111 on PORTB7:4
; (If true we CaptureSBCSend to get all the message bits)
; 2. If myToDoList:0 is true: call ProcessMessage
; 3. Echo B to C
; 4. return
ParseB
call CheckAlertCaptureMsg
btfsc myToDoList, 0
call ProcessMessage
return
CheckAlertCaptureMsg
btfss PORTB, 7 ; Both Rest and SBC-Alert will have this bit set, therefore skip...
return ; MSB == 0 only possible inside message exchanges (signal toggle bit)
btfss PORTB, 6
return ; 10xx matches the Rest state 1000
btfss PORTB, 5
return ; 110x is only possible in response to IsSBCAwake handshake, not here
btfss PORTB, 4
return ; B=1110 is only possible when SBC ack's uC send
call CaptureSBCSend
return
IsSBCAwake
return
;;;;;;;;;;;;;;;;;;;;;;;;;
;; CaptureSBCSend
;;;;;;;;;;;;;;;;;;;;;;;;;
; Rapidly read a message from the SBC on B
; WDT is the only failsafe for much of this
; 6 signals will come across;
; Alert = 1111
; Sig1 = 0aaa
; Sig2 = 1bbb
; Sig3 = 0ccc
; Sig4 = 1ddd
; Chksum = 0jjj
;
; We arrived here because B=1111, C=1000
;
; Result: mySBCType = 0000 aaab
; mySBCData = bbcc cddd
; mySBCChksum = 0000 0jjj
; myUcChksum = 0000 0kkk (to be calculated)
;
; Procedure:
; 1. we echo 1111 on LATC
; 2. we step through MSB toggles to get the 12 type + data bits
; 3. calculate the checksum kkk
; 4. set PORTC = 0kkk
; 5. wait for last MSB toggle presumably to 1000
; 6. Set LATC = Rest state 1000
; 7. Set myToDoList:0 flag to 1
; return
;
CaptureSBCSend
clrf myCaptureFailed ; Provides a fall-out semaphor to Poll fns
bsf LATC, 4
bsf LATC, 5
bsf LATC, 6
bsf LATC, 7
call PollB7Clear
clrwdt
btfsc myCaptureFailed, 0
goto CaptureSBCSend_Fail
call GetMySBCTypeBits321
call EchoBC
call PollB7Set
clrwdt
btfsc myCaptureFailed, 0
goto CaptureSBCSend_Fail
call GetMySBCTypeBit0
call GetMySBCDataBits76
call EchoBC
call PollB7Clear
clrwdt
btfsc myCaptureFailed, 0
goto CaptureSBCSend_Fail
call GetMySBCDataBits543
call EchoBC
call PollB7Set
clrwdt
btfsc myCaptureFailed, 0
goto CaptureSBCSend_Fail
call GetMySBCDataBits210
call CalculateMyChecksum
call EchoBC
call PollB7Clear
clrwdt
call EchoBC
; call SetPORTCChecksum
call PollB7Set ; Last toggle should go to B = Rest state
clrwdt
btfsc myCaptureFailed, 0
goto CaptureSBCSend_Fail
bsf myToDoList, 0 ; Set Process Message bit
CaptureSBCSend_Fail ; Fall-through point on fail
call SetLATCFriendly ; Set Rest state on PORTC
return
; The message type is stored in the low 4 bits of mySBCType
; myB contains 0abc 0000 and we want
; myBType to read 0000 abc0
GetMySBCTypeBits321
clrf mySBCType ; all Zero
btfsc PORTB, 6
bsf mySBCType, 3 ; Set bit 3 if PORTB bit 6 is set
btfsc PORTB, 5
bsf mySBCType, 2 ; Set bit 2 if PORTB bit 5 is set
btfsc PORTB, 4
bsf mySBCType, 1 ; Set bit 1 if PORTB bit 4 is set
return
; This continues the previous mySBCType load...
; PORTB reads 1dxx 0000 and we want to improve mySBCType to 0000 abcd
GetMySBCTypeBit0
btfsc PORTB, 6
bsf mySBCType, 0
return
; PORTB reads 1dpq 0000 and we want mySBCData to read pq00 0000
GetMySBCDataBits76
clrf mySBCData
btfsc PORTB, 5
bsf mySBCData, 7
btfsc PORTB, 4
bsf mySBCData, 6
return
; PORTB contains 0rst 0000 and we want to improve mySBCData to pqrs t000
GetMySBCDataBits543
btfsc PORTB, 6
bsf mySBCData, 5
btfsc PORTB, 5
bsf mySBCData, 4
btfsc PORTB, 4
bsf mySBCData, 3
return
; PORTB contains 0uvw 0000 and we want to improve mySBCData to pqrs tuvw
GetMySBCDataBits210
btfsc PORTB, 6
bsf mySBCData, 2
btfsc PORTB, 5
bsf mySBCData, 1
btfsc PORTB, 4
bsf mySBCData, 0
return
CalculateMyChecksum
return
SetPORTCChecksum
; assign LATC, 4
; assign LATC, 5
; assign LATC, 6
bcf LATC, 7
return
; Toggle bit must persist in desired state through 5 reads
PollB7Clear
btfsc PORTB, 7
goto PollB7Clear
btfsc PORTB, 7
goto PollB7Clear
btfsc PORTB, 7
goto PollB7Clear
btfsc PORTB, 7
goto PollB7Clear
btfsc PORTB, 7
goto PollB7Clear
return
; Toggle bit must persist in desired state through 5 reads
PollB7Set
btfss PORTB, 7
goto PollB7Set
btfss PORTB, 7
goto PollB7Set
btfss PORTB, 7
goto PollB7Set
btfss PORTB, 7
goto PollB7Set
btfss PORTB, 7
goto PollB7Set
return
; Called upon receipt/load of an SBC Message
; mySBCType = 0000 tttt
; mySBCData = abcd efgh
; Sub-components will have prefix PM_
; Desire: logic fail-out hits a simple return with no harm
; 0000 NC
; 0001 Request state: PORTX, GPIO WDT etc
; 0010 Set Power State
; 0011 Request Power State
; 0100 Query external voltage
; 0101 Request Sleep
; 0110 Set: Drop Dead Active/Disable
; 0111 Echo test
; 1000 Set: Drop Dead Days (Should roll this up into a single, like sleep request)
; 1001 Set: Drop Dead Hours
; 1010 Set: Drop Dead Minutes
; 1011 NC
; 1100 NC
; 1101 NC
; 1110 NC
; 1111 NC
ProcessMessage
bcf myToDoList, 0 ; clear that bit, check that off
bcf myToDoList, 1 ; don't plan to do anything in response... yet
bcf myToDoList, 2 ; don't plan to go to sleep... yet
btfss mySBCType, 3 ; 16 possible messages on LSBs of mySBCType
goto PM_type0xxx
btfss mySBCType, 2
goto PM_type10xx ; Established: 10xx
btfss mySBCType, 1 ; Established: 11xx
goto PM_type110x
return ; Done: Established: 111x: 1111 and 1110 are currently NC
; Return to ParseB
PM_type110x
btfss mySBCType, 0
goto PM_ReportDropDeadHours ; Done: Established 1100: Report DropDead hours
goto PM_ReportDropDeadMinutes ; Done: Established 1101: Report DropDead minutes
PM_type10xx
btfss mySBCType, 1
goto PM_type100x
btfss mySBCType, 0 ; Established: 101x
goto PM_SetDropDeadMinutes ; Done: Established: 1010: Set DropDead minutes
goto PM_ReportDropDeadDays ; Done: Established: 1011: Report DropDead days
PM_type100x
btfss mySBCType, 0
goto PM_SetDropDeadDays ; Done: Established: 1000: Set DropDead Days
goto PM_SetDropDeadHours ; Done: Established: 1001: Set DropDead Hours
PM_type0xxx
btfss mySBCType, 2
goto PM_type00xx ; Established: 00xx
btfss mySBCType, 1 ; Established: 01xx
goto PM_type010x ; Established: 010x
btfss mySBCType, 0 ; Established: 011x
goto PM_SetDropDeadState ; Done: Established 0110: Set DropDead State
goto PM_TestEcho ; Done: Established 0111: NC (but actually a test echo)
PM_type010x
btfss mySBCType, 0
goto PM_ReportVoltage ; Done: Established 0100: Report voltage ADC value
goto PM_SleepRequest ; Done: Established 0101: Go to sleep by SBC request
PM_type00xx
btfss mySBCType, 1
goto PM_type000x ; Established: 000x
btfss mySBCType, 0 ; Established: 001x
goto PM_SetPowerState ; Done: Established: 0010: Set power state
goto PM_ReportPowerState ; Done: Established: 0011: Report power state
PM_type000x
btfss mySBCType, 0
return ; Done: Established: 0000: NC
goto PM_ReportState ; Done: Established: 0001: Report some PORTX / GPIO / etc state
PM_TestEcho
bsf myToDoList, 1
movff mySBCType, myUcType ; Will be 0000 0111
movff mySBCData, myUcData ; Will be whatever the SBC Data was
return ; Return to ParseB
PM_ReportDropDeadDays
bsf myToDoList, 1 ; Note to self: Send this message
movff myDropDeadDays, myUcData
movff mySBCType, myUcType
return ; Return to ParseB
PM_ReportDropDeadHours
bsf myToDoList, 1 ; Note to self: Send this message
movff myDropDeadHours, myUcData
movff mySBCType, myUcType
return ; Return to ParseB
PM_ReportDropDeadMinutes
bsf myToDoList, 1 ; Note to self: Send this message
movff myDropDeadMinutes, myUcData
movff mySBCType, myUcType
return ; Return to ParseB
PM_ReportVoltage
bsf myToDoList, 1 ; Note to self: Send this message
call ReadVoltage
movff ADRESH, myUcData ; myUcData = ADRESH
movff mySBCType, myUcType ; Type 4 gets a Type 4 reply
return ; Return to ParseB
; mySBCData bit 0: 0 means DropDead Disable, 1 means DropDead Enable
; This should be ok
PM_SetDropDeadState
bcf myToDoList, 1 ; Note to self: No messages to send
clrf myNoDropDead ; default is Enabled
btfss mySBCData, 0
setf myNoDropDead ; mySBCData bit 0 is clear so myNoDropDead is
; set and DropDead is therefore Disabled
return ; Return to ParseB
; This function uses the value of mySBCData to determine what to report:
; 0 PORTA low bits 0:5
; 1 PORTB
; 2 PORTC
; 3 PORTD
; 4 PORTE low bits 0:3
; 5 Hardcoded a5
; 6 myNoDropDead
; 7 mySBCIsAwake
; 8 ADRESH
; 9 ADRESL
; 10 OSCCON
; 11 INTCON
; 12 RCON
; 13 ADCON0
; 14 ADCON1
; 15 Drop Dead days
; 16 Drop Dead hours
; 17 Drop Dead minutes
; 18 Sleep days
; 19 Sleep hours
; 20 Sleep minutes
; 21 TRISA bits 0:5
; 22 TRISB
; 23 TRISC
; 24 TRISD
; 25 TRISE bits 0:3
; 26 WDT Enable
; 27 WDT Disable
; 28 A/GP-1 Set
; 29 A/GP-1 Clear
; 30 A/GP-2 Set
; 31 A/GP-2 Clear
; 32 Read AN0
; 33 Read AN1
PM_ReportState
bsf myToDoList, 1 ; Note to self: There is a message to send
movff mySBCType, myUcType ; Type 1 gets Type 1 in reply
movlw 0h
cpfseq mySBCData
goto PM_RS_GTZero
movff PORTA, myUcData
bcf myUcData, 6
bcf myUcData, 7
return
PM_RS_GTZero
decfsz mySBCData
goto PM_RS_GTOne
movff PORTB, myUcData
return
PM_RS_GTOne
decfsz mySBCData
goto PM_RS_GTTwo
movff PORTC, myUcData
return
PM_RS_GTTwo
decfsz mySBCData
goto PM_RS_GTThree
movff PORTD, myUcData
return
PM_RS_GTThree
decfsz mySBCData
goto PM_RS_GTFour
movff PORTE, myUcData
bcf myUcData, 4
bcf myUcData, 5
bcf myUcData, 6
bcf myUcData, 7
return
PM_RS_GTFour
decfsz mySBCData
goto PM_RS_GTFive
movlw 0a5h
movwf myUcData
return
PM_RS_GTFive
decfsz mySBCData
goto PM_RS_GTSix
movff myNoDropDead, myUcData
return
PM_RS_GTSix
decfsz mySBCData
goto PM_RS_GTSeven
movff mySBCIsAwake, myUcData
return
PM_RS_GTSeven
decfsz mySBCData
goto PM_RS_GTEight
movff ADRESH, myUcData
return
PM_RS_GTEight
decfsz mySBCData
goto PM_RS_GTNine
movff ADRESL, myUcData
return
PM_RS_GTNine
decfsz mySBCData
goto PM_RS_GTTen
movff OSCCON, myUcData
return
PM_RS_GTTen
decfsz mySBCData
goto PM_RS_GTEleven
movff INTCON, myUcData
return
PM_RS_GTEleven
decfsz mySBCData
goto PM_RS_GTTwelve
movff RCON, myUcData
return
PM_RS_GTTwelve
decfsz mySBCData
goto PM_RS_GTThirteen
movff ADCON0, myUcData
return
PM_RS_GTThirteen
decfsz mySBCData
goto PM_RS_GTFourteen
movff ADCON1, myUcData
return
PM_RS_GTFourteen
decfsz mySBCData
goto PM_RS_GTFifteen
movff myDropDeadDays, myUcData
return
PM_RS_GTFifteen
decfsz mySBCData
goto PM_RS_GTSixteen
movff myDropDeadHours, myUcData
return
PM_RS_GTSixteen
decfsz mySBCData
goto PM_RS_GTSeventeen
movff myDropDeadMinutes, myUcData
return
PM_RS_GTSeventeen
decfsz mySBCData
goto PM_RS_GTEighteen
movff mySleepDays, myUcData
return
PM_RS_GTEighteen
decfsz mySBCData
goto PM_RS_GTNineteen
movff mySleepHours, myUcData
return
PM_RS_GTNineteen
decfsz mySBCData
goto PM_RS_GTTwenty
movff mySleepMinutes, myUcData
return
PM_RS_GTTwenty
decfsz mySBCData
goto PM_RS_GTTwentyOne
movff TRISA, myUcData
return
PM_RS_GTTwentyOne
decfsz mySBCData
goto PM_RS_GTTwentyTwo
movff TRISB, myUcData
return
PM_RS_GTTwentyTwo
decfsz mySBCData
goto PM_RS_GTTwentyThree
movff TRISC, myUcData
return
PM_RS_GTTwentyThree
decfsz mySBCData
goto PM_RS_GTTwentyFour
movff TRISD, myUcData
return
PM_RS_GTTwentyFour
decfsz mySBCData
goto PM_RS_GTTwentyFive
movff TRISE, myUcData
return
PM_RS_GTTwentyFive
decfsz mySBCData
goto PM_RS_GTTwentySix
bsf WDTCON, SWDTEN
movff WDTCON, myUcData
return
PM_RS_GTTwentySix
decfsz mySBCData
goto PM_RS_GTTwentySeven
bcf WDTCON, SWDTEN
movff WDTCON, myUcData
return
PM_RS_GTTwentySeven
decfsz mySBCData
goto PM_RS_GTTwentyEight
bsf LATB, 2
movff PORTB, myUcData
return
PM_RS_GTTwentyEight
decfsz mySBCData
goto PM_RS_GTTwentyNine
bcf LATB, 2
movff PORTB, myUcData
return
PM_RS_GTTwentyNine
decfsz mySBCData
goto PM_RS_GTThirty
bsf LATB, 3
movff PORTB, myUcData
return
PM_RS_GTThirty
decfsz mySBCData
goto PM_RS_GTThirtyOne
bcf LATB, 3
movff PORTB, myUcData
return
PM_RS_GTThirtyOne
decfsz mySBCData
goto PM_RS_GTThirtyTwo
call ReadAN0
movff ADRESH, myUcData
return
PM_RS_GTThirtyTwo
decfsz mySBCData
goto PM_RS_NotImplemented
call ReadAN1
movff ADRESH, myUcData
return
PM_RS_NotImplemented
clrf myUcData
return ; Return to ParseB
; Bitwise parse of mySBCData into power switch values
PM_SetPowerState
bcf myToDoList, 1 ; Note to self: No messages to send
btfsc mySBCData, 7
goto PM_SPS_12InternalOn
call OffInternal12
goto PM_SPS_Continue6
PM_SPS_12InternalOn
call OnInternal12
PM_SPS_Continue6
btfsc mySBCData, 6
goto PM_SPS_3p3InternalOn
call OffInternal3p3
goto PM_SPS_Continue5
PM_SPS_3p3InternalOn
call OnInternal3p3
PM_SPS_Continue5
btfsc mySBCData, 5
goto PM_SPS_5ExternalOn
call OffExternal5
goto PM_SPS_Continue4
PM_SPS_5ExternalOn
call OnExternal5
PM_SPS_Continue4
btfsc mySBCData, 4
goto PM_SPS_12ExternalOn
call OffExternal12
goto PM_SPS_Continue3
PM_SPS_12ExternalOn
call OnExternal12
PM_SPS_Continue3
btfsc mySBCData, 3
goto PM_SPS_3p3ExternalOn
call OffExternal3p3
goto PM_SPS_Continue2
PM_SPS_3p3ExternalOn
call OnExternal3p3
PM_SPS_Continue2
btfsc mySBCData, 2
goto PM_SPS_AMPOn
call OffAmp
goto PM_SPS_Continue1
PM_SPS_AMPOn
call OnAmp
PM_SPS_Continue1
btfsc mySBCData, 1
goto PM_SPS_BridgeOn
call OffBridge
goto PM_SPS_Continue0
PM_SPS_BridgeOn
call OnBridge
PM_SPS_Continue0
btfsc mySBCData, 0
goto PM_SPS_GPSOn
call OffGPS
return
PM_SPS_GPSOn
call OnGPS
return ; Return to ParseB
PM_ReportPowerState
bsf myToDoList, 1 ; Note to self: Send message
clrf myUcData ; Clear then set bits for hot supplies
btfsc PORTC, 3
bsf myUcData, 7 ; 12 Internal
btfsc PORTA, 4
bsf myUcData, 6 ; 3p3 Internal
btfsc PORTB, 1
bsf myUcData, 5 ; 5 External
btfsc PORTC, 2
bsf myUcData, 4 ; 12 External
btfsc PORTB, 0
bsf myUcData, 3 ; 3p3 External
btfsc PORTD, 5
bsf myUcData, 2 ; AMP
btfsc PORTD, 6
bsf myUcData, 1 ; Bridge
btfsc PORTD, 0
bsf myUcData, 0 ; GPS
movff mySBCType, myUcType
return
; These should be ok although arguably could clear DropDeadSeconds when any of
; these are set to permit more accurate timing checks.
PM_SetDropDeadMinutes
bcf myToDoList, 1 ; Note to self: No messages to send
movff mySBCData, myDropDeadMinutes ; set low 6 bits
bcf myDropDeadMinutes, 6
bcf myDropDeadMinutes, 7
return
PM_SetDropDeadHours
bcf myToDoList, 1 ; Note to self: No messages to send
movff mySBCData, myDropDeadHours ; set low 6 bits
bcf myDropDeadHours, 6
bcf myDropDeadHours, 7
return
PM_SetDropDeadDays
bcf myToDoList, 1 ; Note to self: No messages to send
movff mySBCData, myDropDeadDays ; set low 6 bits
bcf myDropDeadDays, 6
bcf myDropDeadDays, 7
return
; Sleep Request machinery ONLY sets a sleep variable to 0--63 (Minutes or
; Hours or Days). It is important to realize that this operation
; does not INSTIGATE a sleep. That must be done through the four Drop Dead
; vars: myDropDeadMinutes, myDropDeadHours, myDropDeadDays, myNoDropDead.
; Once the Drop Dead timer goes to Zero (and presuming myNoDropDead is FALSE)
; the system will shut off all power except to the SBC, it will set PORTC
; to be 0000, and it will wait one minute. It will then shut off the SBC
; and go into a sleep for the requested time: Days + Hours + Minutes.
PM_SleepRequest
bsf myToDoList, 1 ; Note to self: Echo SBC Data back
movff mySBCType, myUcType
movff mySBCData, myUcData
btfss mySBCData, 7 ; Now parse bits 7 and 6 of mySBCData
goto PM_SR_Data7Clear ; Data76 = 0x
btfss mySBCData, 6
goto PM_SR_Days ; Data76 = 10 request Days of sleep
return ; Data76 = 11 is not used
PM_SR_Data7Clear
btfsc mySBCData, 6
goto PM_SR_Hours ; Data76 = 01 request Hours of sleep
movff mySBCData, mySleepMinutes ; Data76 = 00 request Minutes of sleep
return
PM_SR_Days
movff mySBCData, mySleepDays
bcf mySleepDays, 7
return
PM_SR_Hours
movff mySBCData, mySleepHours
bcf mySleepHours, 6
return
; This code carefully does not touch an output (LATC) bit until it knows what it should be
; This avoids jitter error over faster alternatives; Bit 7 set last since it is often used as
; as a toggle-latch.
EchoBC
btfss PORTB, 4
goto EchoBC_Clear4
bsf LATC, 4
goto EchoBC_Continue5
EchoBC_Clear4
bcf LATC, 4
EchoBC_Continue5
btfss PORTB, 5
goto EchoBC_Clear5
bsf LATC, 5
goto EchoBC_Continue6
EchoBC_Clear5
bcf LATC, 5
EchoBC_Continue6
btfss PORTB, 6
goto EchoBC_Clear6
bsf LATC, 6
goto EchoBC_Continue7
EchoBC_Clear6
bcf LATC, 6
EchoBC_Continue7
btfss PORTB, 7
goto EchoBC_Clear7
bsf LATC, 7
return
EchoBC_Clear7
bcf LATC, 7
return
countdown
clrwdt
call DelayOneSecond
; Using ShortTime accelerates the Drop Dead countdown
; call DelayShortTime
tstfsz myDropDeadSeconds ; if seconds == 0 skip next, else...
goto countdown_decrement_seconds ; jump to seconds decrement
; seconds == 0 so check if minutes == 0
tstfsz myDropDeadMinutes ; if minutes == 0 skip next, else...
goto countdown_decrement_minutes ; jump to minutes decrement
; minutes == 0 (sec also) so check if hours == 0
tstfsz myDropDeadHours ; if hours == 0 skip next, else...
goto countdown_decrement_hours ; jump to hours decrement
; hours == 0 (min, sec also) so check if days == 0
tstfsz myDropDeadDays ; if days == 0 skip next, else...
goto countdown_decrement_days ; jump to days decrement
; days == 0 (hrs, min, sec also) so time to sleep
tstfsz myNoDropDead ; if myNoDropDead is clear skip next, else...
return ; return to operational_loop
goto DropDead ; this culminates in a sleep and a reset
countdown_decrement_seconds
decf myDropDeadSeconds
return
countdown_decrement_minutes
decf myDropDeadMinutes
movlw 03ch
movwf myDropDeadSeconds ; put a full 60 sec back on the clock
return
countdown_decrement_hours
decf myDropDeadHours
movlw 03ch
movwf myDropDeadMinutes ; put a full 60 min back on the clock
return
countdown_decrement_days
decf myDropDeadDays
movlw 018h
movwf myDropDeadHours ; put a full 24 hours back on the clock
return
;;; Power switches
;;; peripherals power, power chain logic
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PortConfigure
; before anything else happens push all power to zero
clrf TRISD
clrf LATD
; This is a start but is incomplete:
; RD0 controls GPS 3.3V supply (1 = ON)
; RD1 controls 5V-B 5V supply (0 = ON) (Neg-logic)
; RD2 controls 12V_P_ON (1 = ON)
; RD3 controls P_SEL (1 = EXTERNAL power source)
; RD4 controls SBC 12V supply (1 = ON)
; RD5 controls WAMP 12V supply (1 = ON)
; RD6 controls BRIDGE 5V supply (1 = ON)
; RD7 controls 5V_P_ON (1 = ON)
; continue with remaining relevant port pins
; each case where TRIS bit is 0 == output the value is set in LAT
bsf TRISA, 5 ; Bat_Mon ADC voltage divider input
bcf TRISA, 4 ; GIO for internal 3p3 volts
bsf TRISA, 3 ; A/D reference voltage input
bsf TRISA, 2 ; Grounded; could be used as VREF-
bsf TRISA, 1 ; Spare A/GP-4 (implicitly available as ADC)
bsf TRISA, 0 ; Spare A/GP-3 (implicitly available as ADC)
; RA0 and RA1 could be used as DIO lines but the ADC configuration
; that establishes RA5 as AN4 also means that RA0 and RA1 are
; configured as Analog-to-Digital ports. See Chapter 19 on ADCON1.
bcf LATA, 4 ; Internal 3p3 OFF
bsf TRISB, 7 ; Input PORTB7 = B3
bsf TRISB, 6 ; Input PORTB6 = B2
bsf TRISB, 5 ; Input PORTB5 = B1
bsf TRISB, 4 ; Input PORTB4 = B0
bcf TRISB, 3 ; Spare DIO; set to output
bcf TRISB, 2 ; Spare DIO; set to output; will control BIG POWER MOSFET SWITCH
bcf TRISB, 1 ; DIO controls external 5V
bcf TRISB, 0 ; DIO controls external 3p3V
; 2 DIO lines Hi (A/GP1=RB2) and Lo (A/GP2=RB3), 2 external power lines off
bcf LATB, 3 ; Spare DIO Lo
bsf LATB, 2 ; Spare DIO Hi
bcf LATB, 1 ; External 5V OFF
bcf LATB, 0 ; External 3.3V OFF
bcf TRISC, 7 ; Output PORTC7 = C3
bcf TRISC, 6 ; Output PORTC6 = C2
bcf TRISC, 5 ; Output PORTC5 = C1
bcf TRISC, 4 ; Output PORTC4 = C0
bcf TRISC, 3 ; DIO controls internal 12V
bcf TRISC, 2 ; DIO controls external 12V
; RC0, RC1 involved in sleep external oscillator
; Output controlling
bcf LATC, 3 ; Internal 12V supply OFF (not working yet!)
bcf LATC, 2 ; External 12V supply OFF
; 1000 on RC7:4 == C3:0 and RC3 and RC2 both low
call SetLATCFriendly
bsf TRISE, 0 ; edip switch, PORTE0:2 Input
bsf TRISE, 1
bsf TRISE, 2
return
; RC7:4 = 1000
SetLATCFriendly
bcf LATC, 4
bcf LATC, 5
bcf LATC, 6
bsf LATC, 7
return
; IMPORTANT: In the PortConfigure function A/GP-1==RB2 has been set as
; Output and set Hi, meaning that the BIG POWER MOSFET SWITCH is ON
; and the off-PCS power components (SS6 and Voltage Reg) are hot. The
; 12V External supply is therefore engaged at this point, drawing about
; 0.45 watts.
PowerTransitionToFull
; Here is the old 3.1 LATD pin sequence: 7, 2, 1, 3
; From schematic this is 5V_P_ON, 12V_P_ON, U11/5V_B on, P_SEL on
; This matches to Gen 3.2 so we continue here the same way
bsf LATD, 7
bsf LATD, 2
call DelayOneSecond
bcf LATD, 1 ; Neg-logic on MiniLynx 5V VReg supplying 5V-B
; Set pin to Lo to enable supply
call DelayOneSecond
bsf LATD, 3 ; P_SEL
return
OnAllPeripherals
call OnSBC
call OnBridge
call OnAmp
call OnGPS
call OnInternal12
call OnInternal3p3
call OnExternal12
call OnExternal5
call OnExternal3p3
return
OnInternal12
bsf LATC, 3 ; Internal 12V supply
return
OnInternal3p3
bsf LATA, 4 ; Internal 3p3
return
OnExternal12
bsf LATC, 2 ; External 12V supplyOnInternal12
return
OnExternal5
bsf LATB, 1 ; External 5V
return
OnExternal3p3
bsf LATB, 0 ; External 3.3V
return
OnSBC
bsf LATD, 4
return
OnGPS
bsf LATD, 0
return
OnBridge
bsf LATD, 6
return
OnAmp
bsf LATD, 5
return
OffInternal12
bcf LATC, 3 ; Internal 12V supply
return
OffInternal3p3
bcf LATA, 4 ; Internal 3p3
return
OffExternal12
bcf LATC, 2 ; External 12V supplyOnInternal12
return
OffExternal5
bcf LATB, 1 ; External 5V
return
OffExternal3p3
bcf LATB, 0 ; External 3.3V
return
OffSBC
bcf LATD, 4
return
OffGPS
bcf LATD, 0
return
OffBridge
bcf LATD, 6
return
OffAmp
bcf LATD, 5
return
;;; DELAY TIMING
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Run at 31khz
; 4 cycles per instruction gives = 8000 delay inner-loops
; inner loop is DECFSZ (1) / goto (2), total of 3 instructions cycles
; Hence 4000 inner loop cycles
; Set this equal to A x B where A is the inner loop counter initialization
; and B is the outer loop. Diophantine equation.
; Setting inner loop to 136, outer to 20 runs at close to correct speed;
; a couple trials produced different results so this clock should be
; considered erratic. Knocking 20 back to 19 will probably
; ensure the clock "runs fast" by a bit.
;
DelayOneSecond
movlw 014h ; decimal 20
movwf myDelayOuter
DelayOneSecond_outer
movlw 088h ; decimal 136
movwf myDelayInner
DelayOneSecond_inner
decfsz myDelayInner
goto DelayOneSecond_inner
decfsz myDelayOuter
goto DelayOneSecond_outer
return
DelayShortTime
movlw 08h ; From 20 x 136 go to 8 x 10 so 34 times faster, roughly
movwf myDelayOuter
DelayShortTime_outer
movlw 0ah
movwf myDelayInner
DelayShortTime_inner
decfsz myDelayInner
goto DelayShortTime_inner
decfsz myDelayOuter
goto DelayShortTime_outer
return
DelayOneMinute
movlw 03ch ; 3ch = 60 decimal
movwf myDelaySec
call DelayNSeconds
return
DelayNSeconds
call DelayOneSecond
decfsz myDelaySec
goto DelayNSeconds
return
;;;;;;;;;;;;;;;;;;;;;;;;
; SLEEP TIMING
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; This extended comment will explain what is going on in the sleep delay
; functions IdleOneMinute and SleepLoop (below) which together elapse a
; time interval either self-directed or at the behest of the SBC.
; Time values are in mySleepMinutes, mySleepHours, and mySleepDays.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; The base time unit is 1 minute. The IdleOneMinute function is intended to idle away about
; 1 minute or a few milliseconds less than this, as accurately as possible.
;
; To accomplish this we use TIMER 1, a 16 bit register that is used as a counter.
; We have: TMR1 = { TMR1H TMR1L }, a 16 bit number that effectively counts up
; from its start value to a zero wraparound (or with carry to 0x10000). Starting
; TMR1 from a higher initial value shortens the sleep interval.
;
; This count-up happens during the sleep call, after which execution resumes on
; the next instruction.
;
; Using the internal clock the spec is 31,000 clock cycles per second, with 4
; cycles per instruction. A times-8 divider is implemented here so the sleep call
; does (in principle) 31,000 / 32 count-ups per second. We want this to go on for
; (60 - epsilon) seconds. Hence we have the theoretical calculation:
;
; Hex(0x10000 - TMR1) = Decimal(60 x (31,000 / 32)).
; This gives TMR1 = 0x1CF3 = Decimal(7411). 0x10000 = Decimal(65536). The difference
; is Decimal(58125) which is Decimal(60 x 31,000 / 32). So far so good.
;
; When running for a single 24 hour interval the elapsed (actual) time was 22 hours
; and 56 minutes using TMR1 = 0x10ef = Dec(4335). This means we are not very well
; calibrated since our elapsed time was only 94% of the desired. The gap above in
; terms of counting is Dec(65536) - Dec(4335) = Dec(61201). If we increase this by
; (1/0.94) = 1.0465 we get Dec(64048). This is less than 65536 so we can still
; hope to accomplish the 1 minute idle delay with one sleep call. The difference is
; Dec(1488) = 0x05D0.
;
; ...however (Gen 3.2 Version 3) this still seems to run a bit fast...
;
; So let's do the same thing again: 826 minutes elapse during 840 minutes of sleep-time
; where the ratio is 1.01694. 61201 x 1.01694 = 65133. 65536 - 65133 = 403 decimal,
; a new trial starting value for TMR1. I will hedge this by +3 to 406 decimal to
; try and keep the timer running just a little fast; I'd rather wake up a bit early.
; 406 = 256 + 128 + 16 + 4 + 2 = 0001 1001 0110 = 0196-hex.
;
IdleOneMinute ; 1 minute sleep timer (LB 10/25/06)
bcf PIR1,TMR1IF
movlw 001h ; Vary this value to adjust timing (LB 10/25/06)
movwf TMR1H
movlw 096h
movwf TMR1L
movlw b'00110001'
movwf T1CON
bsf IPR1,TMR1IP
bsf PIE1,TMR1IE
sleep
bcf PIR1,TMR1IF
return
; DropDead
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Operation Interval is OVER and myNoDropDead is FALSE so we're going to
; Drop Dead now. This function brings the system down HARD, initiates a sleep,
; and falls thru to the reset
DropDead
call OffInternal12
call OffInternal3p3
call OffExternal12
call OffExternal5
call OffExternal3p3
call OffGPS
call OffBridge
call OffAmp
bcf LATC, 7 ; Final 1 minute warning
bcf LATC, 6
bcf LATC, 5
bcf LATC, 4
clrwdt
call DelayOneMinute
clrwdt
call OffSBC
; Reverse the power-up sequence
bcf LATD, 3 ; P_SEL
bsf LATD, 1 ; 5V-B off (neg logic)
bcf LATD, 2 ; 12V_P
bcf LATD, 7 ; 5V_P
SleepLoop ; Timer using myDelay and call idle function
tstfsz mySleepMinutes
goto SleepLoop_Minutes
tstfsz mySleepHours
goto SleepLoop_Hours
tstfsz mySleepDays
goto SleepLoop_Days
goto DoneSleeping
SleepLoop_Minutes ; Minutes != 0
call IdleOneMinute ; this is an external-to-SleepLoop time killer
clrwdt ; found just up above SleepLoop
decf mySleepMinutes
goto SleepLoop
SleepLoop_Hours ; Minutes == 0, Hours != 0
movlw 03Ch ; 60 minutes
movwf mySleepMinutes
decf mySleepHours
goto SleepLoop
SleepLoop_Days ; Minutes == Hours == 0, Days != 0
movlw 018h ; 24 hours
movwf mySleepHours
decf mySleepDays
goto SleepLoop
DoneSleeping
reset
;
; InitAD configures ADCON0, ADCON1, and ADCON2 to handle analog input, in particular
; AN4 (PORTA pin 5 == RA5, package pin 24) which receives a voltage-divided version
; of the charge controller Load voltage.
; In this case we use Gd (Vss) as the low voltage reference source (VREF-) and a
; reference voltage from an external part directed to RA3 = AN3 as the high voltage
; reference source VREF+.
; "Managed A-to-D" has no interrupts enabled; rather we sample the ADC explicitly by
; setting a GO bit to 1 and waiting for the device to clear it. The result is a
; 10 bit value stored in two registers: ADRESH and ADRESL (A-to-D RESult High and Low).
;
InitAD
; 1. Set up ADCON0 which controls the operation of the A/D module
; Bits 6 and 7 are Unimplemented (not used)
; Bits 5:2 are Analog Channel Select Bits
; Choose 0100 which selects AN4
; 0000 is probably AN0, 0001 is probably AN1 which are
; the two spare ADC lines mapped to RA0 and RA1 resp.
; Bit 1 is GO/DONE: Set 1 means A/D conversion in progress
; Clr 0 means A/D conversion done
; Bit 0 is ADON: Set 1 means A/D converter module is enabled
; Clr 0 means A/D converter module is disabled
bcf ADCON0, 5 ; 0
bsf ADCON0, 4 ; 1
bcf ADCON0, 3 ; 0
bcf ADCON0, 2 ; 0
; (Do not touch Bit 1)
bsf ADCON0, 0 ; 1 (A/D enabled) (This is reinforced in the sampling loop)
; 2. Set up ADCON1 which controls the port configuration
; Bits 6 and 7 are Unimplemented (not used)
; Bit 5 is VREF- source. Want 0 -> Vss, do not want 1 -> AN2
; Bit 4 is VREF+ source. Want 1 -> AN3, do not want 0 -> Vdd
; Bits 3:0: Analog pin configuration bits PCFG3-0
; Set to 1010 to enable AN4 + AN3 + AN2 + AN1 + AN0
; RESULT: ADCON1 = xx011010
bcf ADCON1, 5 ; 0
bsf ADCON1, 4 ; 1
bsf ADCON1, 3 ; 1
bcf ADCON1, 2 ; 0
bsf ADCON1, 1 ; 1
bcf ADCON1, 0 ; 0
; 3. Set up ADCON2 which controls the A/D sampling method
; Bit 7: Format justify bit (1 = Right justify, 0 = Left justify)
; Bit 6: Unimplemented (not used)
; Bit 5:3: ACQT2:0 Acquisition time in units of TAD (originally 000 -> 0 TAD)
; Bit 2:0: ADCS2:0 A/D Clock Select (originally 000 -> Fosc/2)
; T-acquisition is (probably) very short required relative to this slow
; clock speed so it is set to minimum since a couple instructions will
; pass adequate time. The clock select is also set to minimal as this is
; the best strategy I can infer from reading so far.
bcf ADCON2, 7 ; 0 Left justify into ADRESH
bcf ADCON2, 5 ; 0
bcf ADCON2, 4 ; 0
bcf ADCON2, 3 ; 0
bcf ADCON2, 2 ; 0
bcf ADCON2, 1 ; 0
bcf ADCON2, 0 ; 0
return
ReadAN0
bcf ADCON0, 4 ; From 0100 to 0000
call ReadVoltage
bsf ADCON0, 4 ; Back to 0100 (Ext Voltage)
return
ReadAN1
bcf ADCON0, 4 ; From 0100 to 0001
bsf ADCON0, 2
call ReadVoltage
bsf ADCON0, 4 ; Back to 0100 (Ext Voltage)
bcf ADCON0, 2
return
; Read 8 high bits of ADC value
ReadVoltage
bsf ADCON0, 0 ; Enable the AD module
call DelayOneSecond ; "Charge caps": Both this delay and the next serve to
; let the sampling process stabilize. Visit ADCON2 bits 5:0
; and the Datasheet to look at making this work faster. In
; this configuration the supply voltage is sampled about
; once every two seconds, a bit slower than necessary.
bsf ADCON0, 1 ; Start the conversion by setting the GO bit
call DelayOneSecond ; Kill some time
ReadVoltage_POLL
nop
btfsc ADCON0, 1 ; The GO bit should be clear by now
goto ReadVoltage_POLL
return
end
