; multimode programmable four-wheel-steering controller ; controls two servos from one steering input plus one modeswitch channel ; ; copyright (c) 2008 Alexander Zangerl ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation (version 2 of the License). ; $Id: fourws.asm,v 1.11 2010/04/29 13:31:31 az Exp $ ; to build for a 12f635: no extra symbols required ; for a 12f683: define P12F683 IFDEF P12F683 processor p12f683 #include "p12f683.inc" ; some renamed register fields ; 635 vs. 683 NOT_RAPU equ NOT_GPPU WPUDA equ WPU RAIE equ GPIE RAIF equ GPIF ELSE processor p12f635 #include "p12f635.inc" ENDIF RADIX hex ERRORLEVEL -302 ; ignore the bank warnings, i know what i'm doing :-) ; default speed 4mhz, no clock out, no bod, no copyprotection, no watchdog, no wake-up reset IFDEF P12F683 ; 683 has no wakeup reset __CONFIG _INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOD_OFF & _IESO_OFF & _FCMEN_OFF ELSE __CONFIG _INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOD_OFF & _IESO_OFF & _FCMEN_OFF & _WUREN_OFF ENDIF ; defaults: mode and min and max acceptable pulse lengths MAXPULSE equ .2200 ; officially 2120us MINPULSE equ .840 ; officially 920us CTRPULSE equ .1520 ; us, official futaba value, jr say 1500 DEADBAND equ .160 ; us PROGMINP equ .1800 ; us. steer and mode must be above that to enter prog mode MAXDELTA equ 5 ; max # modecheck cycles (of 50ms) between transitions for double transition mode ; i/o pins STEER equ 3 ; gp3 steering pulses in (in-only anyway) MSWITCH equ 4 ; gp4 modeswitch pulses in FRONT equ 2 ; front steering out REAR equ 1 ; rear BEEP equ 5 ; buzzer LSWITCH equ 0 ; fws/rear lockout jumper ; config word bits REVBIT equ 0 ; 1 reverse rear channel, 0 f+r get same signal CYCBIT equ 1 ; 1 cyclic mode, 0 direct mode DM0BIT equ 2 ; direct mode assignments DM1BIT equ 3 RSCBIT equ 4 ; 1 rws is included in cycle CRCBIT equ 5 ; 1 crab is included in cycle TRNBIT equ 6 ; 1 cyclic on quick double transition, 0 on hi-lo ; mstate bits VALBIT equ 0 ; signal within ok range HIBIT equ 1 ; signal above center DBBIT equ 2 ; signal within deadband IFDEF P12F683 VARSTART equ 0x20 ELSE VARSTART equ 0x40 ENDIF cblock VARSTART scratch ; tempvar for delay routines foo ; tempvars bar baz ifoo ; inthandler tempvars ibar lateneutral opmode ; 1 4ws, 2 fws, 3 rws, 4 crab config ; configuration options, bit-encoded newconf lastpins ; to detect pin_changes_ mswitch ; modeswitch, pulse length in multiples of 16us. set by inthandler, read by decodestate mstate ; binary state of modeswitch prevmstate ; last binary state of modeswitch transcount ; signal counter for delta between transitions neutlo ; steering pulse length in us for neutral neuthi steerlo ; current steering pulse length in us steerhi endc cblock 0x70 ; bank-shared vars w_save ; interrupt context fsr_save status_save endc ; i dislike PAGESEL BANK0 macro bcf STATUS,RP0 endm BANK1 macro bsf STATUS,RP0 endm org 0 ; power-on or reset goto main org 0x4 ; interrupt vector movwf w_save ; save context swapf STATUS,W BANK0 movwf status_save movfw FSR movwf fsr_save ; can safely expect to run in bank0 call inthandler movfw fsr_save movwf FSR swapf status_save,W movwf STATUS swapf w_save,F swapf w_save,W retfie ; put the tables in low mem to avoid dealing with pclath and pcl arithmetic ; DM1BIT,DM0BIT affect direct modes, selected by hi-neutral-lo on mswitch: ; 00 4ws fws rws ; 01 4ws rws fws ; 10 4ws crab fws ; 11 4ws fws crab ; uses nibbles (hi when dm0 is set), arranged hi-n-lo ; two sets, second used when dm1 is set. d2mtable: addwf PCL,F ; dm1 clear dt 0x11 ; hi, always 4ws dt 0x32 ; n dt 0x23 ; lo ; dm1 set dt 0x11 ; hi, always 4ws dt 0x24 ; n dt 0x42 ; lo ; what channels get the direct signal? ; get the unchanged signal in which modes ; returns 0 if no direct outputs at all directmodes: movfw opmode btfsc config,REVBIT ; reverse rear? addlw 4 addwf PCL,F ; the non-reversed settings dt 0 ; non-mode 0 dt (1<lo transition wait: call decodestate movwf mstate ; a dud signal for either this or the last just makes us try again btfsc mstate,VALBIT btfss prevmstate,VALBIT goto morewait ; so, do we have previous=hi and now=low? btfss mstate,HIBIT ; skip if mstate is high btfss prevmstate,HIBIT; skip if mstate was high before goto morewait ; wohee, an answer. goto donewait morewait: movfw mstate ; move mstate to previous movwf prevmstate movlw .20 call delayXms goto wait ; and try again donewait: movfw mstate ; move mstate to previous movwf prevmstate ; capture steering now, low means OFF, high means ON ; slightly rough, as we miss changes if steering is overwritten right now movlw HIGH CTRPULSE subwf steerhi,W ; steer-neut should be positive for on skpnz ; hi steer-neut = 0? must check lo goto checklo skpc ; carry set = still positive goto wantzero ; below neut goto wantone ; hi already above neutral, lo irrelevant checklo: movlw LOW CTRPULSE subwf steerlo,W ; steer-neut should be positive for on skpc ; carry set = still positive goto wantzero ; below neut wantone: bsf newconf,7 movlw 1 goto next wantzero: bcf newconf,7 clrw ; sound new setting, sits in w next: call soundstate ; uses bar, nukes w call wait1s ; and wait one second until you continue ; next question incf foo,F movlw 8 ; 7 questions are to be asked subwf foo,W skpz goto nextquestion ; 7 questions: top-most 7 bits of newconf hold that ; one lower bit is zero and needs to go bcf STATUS,C rrf newconf,F ; write the new config word to eeprom movfw newconf BANK1 clrf EEADR ; statusword at offset 0 movwf EEDATA bsf EECON1,WREN BCF INTCON,GIE ; fixed sequence movlw 0x55 movwf EECON2 movlw 0xAA movwf EECON2 bsf EECON1,WR ; end sequence BANK0 ; sound done pattern: blip every 250ms, forever. done: call blip clrw call delayXms goto done ; uses bar, nukes w wait1s: movlw 4 movwf bar clrw call delayXms decfsz bar,F goto $-3 return ; calibrate neutral in 8 runs with 250ms delay each docal: movlw 8 movwf foo morecal: movlw .250 call delayXms ; 16b-add steering to neutral, works fine as max range is 2120 ; and we have 65k movfw steerlo addwf neutlo,F movfw steerhi skpnc incf steerhi,W ; skipped if no carry addwf neuthi,F ; no carry in high byte decfsz foo,F goto morecal ; now divide neutral by 8 (=3 rightshifts) movlw 3 movwf foo dodiv: bcf STATUS,C rrf neuthi,F rrf neutlo,F ; carry from hi moves down into lo decfsz foo,F goto dodiv btfsc T1CON,TMR1ON ; wait until tmr1 is off goto $-1 ; now check the calibration: too high or too low? movlw HIGH MAXPULSE subwf neuthi,W ; neut-max should be negative skpnz ; hi neut-max = 0? must check low byte goto cmaxlo skpnc ; carry set = still positive goto fault goto cmin ; high is already different, low irrelevant cmaxlo: movlw LOW MAXPULSE subwf neutlo,W ; neut-max should be negative skpnc ; carry set = still positive goto fault cmin: movlw HIGH MINPULSE subwf neuthi,W ; neut-min should be positive skpnz ; hi neut-min = 0? must check lo goto cminlo skpc ; carry set = still positive goto fault goto calok ; high is already different, low irrelevant cminlo: movlw LOW MINPULSE subwf neutlo,W ; neut-min should be positive skpc ; carry set = still positive goto fault ; one long beep, then show detected neutral for ~2s (100x~20ms) calok: call bleep movlw .100 ; show for 100x20ms = ~2s movwf foo bcf INTCON,RAIE ; disable pinchange int for the showing part clrf opmode ; no normal outputs! doshow: movlw (1<