/************************************************************************* ************************************************************************** ** M E G A S Q U I R T II - 2 0 0 4 - V1.000 ** ** (C) 2003 - B. A. Bowling And A. C. Grippo ** ** This header must appear on all derivatives of this code. ** *************************************************************************** **************************************************************************/ /************************************************************************* ************************************************************************** ** GCC Port ** ** (C) 2004,2005 - Philip L Johnson ** ** This header must appear on all derivatives of this code. ** *************************************************************************** **************************************************************************/ /*------------------------ Version 1.000 This version has all the basic capabilities of MS, but much higher precision - in the usec range. It adds larger tuning tables (12x12), WBO2, IAC, dual tables, and ignition control which assumes 1 coil and a mechanical distributor to distribute spark or EDIS for multicoil wasted spark. Version 1.100 Made serial comms more robust: added one word read, write + verify commands, write to ram inhibit when overrun detection, receiver timeout check. Version 1.200 Fixed various problems with trigger offsets ATDC (charge time can occur after input capture at very low rpms and other related ignition timing problems.) Version 1.300 Changed tps, tpsdot units to % x 10; added accel tailoff algorithm. Version 2.000 This version works with the CAN v3 pcb and has a template for CAN comms. Additional changes: increased input area to 4 x 512 byte blocks; inhibit coil charge 2 sec after turning ign key on; changed ports for FP, Idle (but connect to same pins on motherboard); knock ADC input in Vx100; all unused ports initialized as inputs. Made IACstart, PrimeP, CWU,CWH, AWEV,AWC,asecount ints instead of bytes. PrimeP,AWEV,AWC made function of initial coolant temperature. Expanded IAC control options for cranking plus switch to time based after start; added pulse tolerance inputs for cranking and after start; IAC option(5) to always enable stepper motor chip for 15 minutes after start, then revert to option 2. Version 2.100 Added crank trigger mode.Ignition fires with only mech adv during cranking; added kpa to display outputs. Version 2.200 Modified/ added ADC averaging: provided lag filter averaging for all ADC inputs (also for rpm). Relocated VE tables in anticipation of Block Learn Mode. Version 2.300 Improved ego closed loop correction algorithms; flex fuel correction for alternative fuels; generic spare output ports;fixed logic error for IdleCtl=5; added fix to maintain coherence of inputs when changed thru serial port. Version 2.310, 2.320, 2.330, 2340, 2.350, 2.360 Fixed bug in ASE logic;set PW=0 in RevLimit mode;gcc compatibility changes; fixed bug in spare port hysteresis; changed some defaults; fixed bug in masking of TimerIn interrupts for dt/2; limited pw_open in case of battery spikes. Fixed stepper motor bug. Version 2.400 Added automatic mixture control;mod to AE;expanded warmup inputs; moved DoOnStack to permanent ram;added option for 2 NBs;added knock retard based on ADC7 sensor. Version 2.500 Added wheel decoding; added simple AE taper based on rpm;added time,% parameters to control tach input interrupt masking; 5 sec min for persistence of AS pulse tolerance; extended pulse tol range from 100 to 255. Version 2.510, 2.520, 2.530, 2.540 Added fix to extend rpm range for wheel decoding; fixed AMC logic. Version 2.600, 2.610, 2.620, 2.630, 2.640, 2.660, 2.670, 2.671, 2.672, 2.681-2.687 Added small model multi-page memory; added X-tau transient compensation; spark retard as function of manifold air temperature; added table fuel corrections for air density and barometric pressure; added spk retard correction for flex fuel; added injector test mode. Fixed bug in table burner; added ego volt outputs; shortened serial ISR time to expand wheel decoder range. Provided input for pwm stepper freq. Added check for serial overrun flag. Limit baro to 80-120 kPa for option 1. Put COP timeout in main loop. Made NB AFRtarget Vx100 in code. Reduced default tau table. Fixed burn in Inj Test mode. Added wheel decode improvements to check for lost synch, individual tooth timing correction.Omit check for xtra/ missing tach pulse if accelerating/ decelerating. Omit immed. f/p off. RPM limit for AMC burns. Made fixes to improve IAC performance. Version 2.700 Added dual spark outputs; allow alpha-N at lo rpm or at hi rpm. Version 2.800 Added MAF capability, including MAP/ MAF blend, 3-port selection for maf input; added option to multiply pw eq x AFRStoich / AFRtgt[map,rpm]; added option to use map/baro as index in ve,spk,afr tables. Set pw to 0 when ve = 0 to avoid any fuel dribble. Added option for wasted spark/ COP (requires external hw). For PredOpt=2, use 1st deriv ign prediction if slow rate of change. Allow tau=0. Fixed code to make all longs atomic. Put in AMCdve logic. Version 2.810, 2.820-2.823 Removed option for wasted spark/ COP with router chip (will be moved to router board). Added 2 cyl cop/ 4 cyl wasted spark using cam sync and/or toothed wheel. Changes to make starting faster.Shortened cpu time in TimerClock. -----------------------*/ #include "hcs12def.h" /* common defines and macros */ #include "flash.h" /* flashburner defines, structures */ #include //#define CAN_TEST #ifdef GCC_BUILD #define FAR_TEXT1_ATTR __attribute__ ((far)) __attribute__ ((section (".text1"))) #define TEXT1_ATTR __attribute__ ((section (".text1"))) #define EEPROM_ATTR __attribute__ ((section (".eeprom"))) #define INTERRUPT #define POST_INTERRUPT __attribute__((interrupt)) #define ENABLE_INTERRUPTS __asm__ __volatile__ ("cli"); #define DISABLE_INTERRUPTS __asm__ __volatile__ ("sei"); #define NEAR #define VECT_ATTR __attribute__ ((section (".vectors"))) extern void _start(void); /* Startup routine */ #else #define FAR_TEXT1_ATTR #define TEXT1_ATTR #define EEPROM_ATTR #define INTERRUPT interrupt #define POST_INTERRUPT #define ENABLE_INTERRUPTS asm cli; #define DISABLE_INTERRUPTS asm sei; #define NEAR near #define VECT_ATTR @0xFF80 #pragma CODE_SEG NON_BANKED /* Interrupt section for this module. Placement will be in NON_BANKED area. */ extern void near _Startup(void); /* Startup routine */ #endif INTERRUPT void UnimplementedISR(void) POST_INTERRUPT; INTERRUPT void ISR_Ign_TimerIn(void) POST_INTERRUPT; INTERRUPT void ISR_Ign_TimerOut(void) POST_INTERRUPT; INTERRUPT void ISR_Inj1_TimerOut(void) POST_INTERRUPT; INTERRUPT void ISR_Inj2_TimerOut(void) POST_INTERRUPT; INTERRUPT void ISR_TimerOverflow(void) POST_INTERRUPT; INTERRUPT void ISR_Timer_Clock(void) POST_INTERRUPT; INTERRUPT void ISR_SCI_Comm(void) POST_INTERRUPT; INTERRUPT void CanTxIsr(void) POST_INTERRUPT; INTERRUPT void CanRxIsr(void) POST_INTERRUPT; typedef void (* NEAR tIsrFunc)(void); const tIsrFunc _vect[] VECT_ATTR = { /* Interrupt table */ UnimplementedISR, /* vector 63 */ UnimplementedISR, /* vector 62 */ UnimplementedISR, /* vector 61 */ UnimplementedISR, /* vector 60 */ UnimplementedISR, /* vector 59 */ UnimplementedISR, /* vector 58 */ UnimplementedISR, /* vector 57 */ UnimplementedISR, /* vector 56 */ UnimplementedISR, /* vector 55 */ UnimplementedISR, /* vector 54 */ UnimplementedISR, /* vector 53 */ UnimplementedISR, /* vector 52 */ UnimplementedISR, /* vector 51 */ UnimplementedISR, /* vector 50 */ UnimplementedISR, /* vector 49 */ UnimplementedISR, /* vector 48 */ UnimplementedISR, /* vector 47 */ UnimplementedISR, /* vector 46 */ UnimplementedISR, /* vector 45 */ UnimplementedISR, /* vector 44 */ UnimplementedISR, /* vector 43 */ UnimplementedISR, /* vector 42 */ UnimplementedISR, /* vector 41 */ UnimplementedISR, /* vector 40 */ CanTxIsr, /* vector 39 */ CanRxIsr, /* vector 38 */ CanRxIsr, /* vector 37 */ UnimplementedISR, /* vector 36 */ UnimplementedISR, /* vector 35 */ UnimplementedISR, /* vector 34 */ UnimplementedISR, /* vector 33 */ UnimplementedISR, /* vector 32 */ UnimplementedISR, /* vector 31 */ UnimplementedISR, /* vector 30 */ UnimplementedISR, /* vector 29 */ UnimplementedISR, /* vector 28 */ UnimplementedISR, /* vector 27 */ UnimplementedISR, /* vector 26 */ UnimplementedISR, /* vector 25 */ UnimplementedISR, /* vector 24 */ UnimplementedISR, /* vector 23 */ UnimplementedISR, /* vector 22 */ UnimplementedISR, /* vector 21 */ ISR_SCI_Comm, /* vector 20 */ UnimplementedISR, /* vector 19 */ UnimplementedISR, /* vector 18 */ UnimplementedISR, /* vector 17 */ ISR_TimerOverflow, /* vector 16 */ UnimplementedISR, /* vector 15 */ UnimplementedISR, /* vector 14 */ ISR_Ign_TimerOut, /* vector 13 */ ISR_Ign_TimerOut, /* vector 12 */ ISR_Inj2_TimerOut, /* vector 11 */ ISR_Ign_TimerIn, /* vector 10 */ ISR_Inj1_TimerOut, /* vector 09 */ ISR_Ign_TimerIn, /* vector 08 */ ISR_Timer_Clock, /* vector 07 */ UnimplementedISR, /* vector 06 */ UnimplementedISR, /* vector 05 */ UnimplementedISR, /* vector 04 */ UnimplementedISR, /* vector 03 */ UnimplementedISR, /* vector 02 */ UnimplementedISR, /* vector 01 */ #ifdef GCC_BUILD _start /* Reset vector */ }; #else _Startup /* Reset vector */ }; #pragma CODE_SEG ROM_7400 void switch_page(unsigned char sub_no,char carg1,char carg2); int intrp_1dctable(char sgnx, int x, unsigned char n, int * x_table, char sgnz, unsigned char * z_table) TEXT1_ATTR; int intrp_2dctable(unsigned int x, int y, unsigned char nx, unsigned char ny, unsigned int * x_table, int * y_table, unsigned char * z_table) TEXT1_ATTR; int CW_table(int clt, int *table) TEXT1_ATTR; #pragma CODE_SEG DEFAULT #endif #include "cltfactor.inc" #include "matfactor.inc" #include "egofactor.inc" #include "maffactor.inc" #define NO_TBLES 7 #define NO_FMAPS 12 #define NO_SMAPS 12 #define NO_FRPMS 12 #define NO_SRPMS 12 #define NO_ARPMS 6 #define NO_ATPSS 6 #define NO_INJ 2 #define NO_TEMPS 10 #define NO_MAT_TEMPS 6 #define NO_BARS 6 #define NO_MATS 6 #define NO_TPS_DOTS 4 #define NO_MAP_DOTS 4 #define NO_MAFS 12 #define NO_KNKRPMS 6 #define NPORT 7 #define NO_COILCHG_PTS 5 #define EGODT 78 /* 78 .128 ms tics = 10 ms */ #define END_SYNCH 3 #define AMCBURN_RPM_THRESH 1200 #define MSG_CMD 0 #define MSG_REQ 1 #define MSG_RSP 2 #define MSG_XSUB 3 #define NO_VAR_BLKS 16 #define NO_CANMSG 10 #define NO_CANBOARDS 16 #define CANID_THIS_BOARD 0 // Error status words: // -bits 0-7 are current errors // -bits 8-15 are corresponding latched errors #define XMT_ERR 0x0101 #define CLR_XMT_ERR 0xFFFE #define XMT_TOUT 0x0202 #define CLR_XMT_TOUT 0xFFFD #define RCV_ERR 0x0404 #define CLR_RCV_ERR 0xFFFB #define SYS_ERR 0x0808 // User inputs - 1 set in flash, 1 in ram typedef struct { unsigned char no_cyl,no_skip_pulses, // skip >= n tach pulses at startup ICIgnOption, // Bit 0: Input capture: 0 = falling edge, 1 rising // Bit 1: 1= trigger return mode in cranking; for this // mode, set bit 0 to normal edge, then opp.edge used in cranking. // trigger return not applicable to EDIS // Bit 2: 1 = fire on tach trigger with no advance // while cranking; not applicable for EDIS. Bits 1,2 cannot both=1 // Bit 3: spare // Bits 4-7: 0 = standard - charge coil, spark // 1 = Ford EDIS option // 2 = EDIS with multispark spkout_hi_lo, // Ign Output compare: 0 = spark low (gnd) max_coil_dur,max_spk_dur,DurAcc; // ms x 10 char deltV_table[NO_COILCHG_PTS],deltDur_table[NO_COILCHG_PTS], // Vx10,msx10 RevLimOption, // 0=none, 1=spark retard, 2=fuel cut RevLimMaxRtd, // max amount of spark retard (degx10) (at Rpm2 below) PredOpt; // Option for prediction algorithm for next tach plse // 0=use last time interval // 1=use 1st deriv prediction; 2=use 1st deriv at hi // rpm, 2nd deriv prediction at lo rpm; // 3=use 2nd deriv prediction always. int crank_rpm; // rpm at which cranking is through (~300 - 400 rpm) int cold_adv_table[NO_TEMPS], adv_offset, // all in deg x 10 // adv_offset is no deg(x10) between trigger (Input Capture) and TDC. // It may be +btdc (IC1 to TDC) or -atdc (TDC to IC2). // // | | | // | | | // -|---------------|-----|- // IC1 TDC IC2 RevLimRpm1,RevLimRpm2; // Optn 1:Retard spk by 0 deg at Rpm1 and increase // to RevLimMaxRtd at Rpm2 // Optn 2:Cut fuel above Rpm2, restore below Rpm1 unsigned char afr_table[NO_INJ][NO_FMAPS][NO_FRPMS], // afr x 10 warmen_table[NO_TEMPS], // % enrichment vs temp tpsen_table[NO_TPS_DOTS], // accel enrichment pw in .1 ms units vs tpsdot mapen_table[NO_MAP_DOTS]; // accel enrichment pw in .1 ms units vs mapdot int iacstep_table[NO_TEMPS]; // iac steps vs temp unsigned int frpm_table[NO_FRPMS],srpm_table[NO_SRPMS]; // fuel, spk rpm tables int fmap_table[NO_FMAPS],smap_table[NO_SMAPS], // kpa x 10, temp_table[NO_TEMPS], // deg x 10 (C or F) tpsdot_table[NO_TPS_DOTS], // change in % x 10 per .1 sec mapdot_table[NO_MAP_DOTS]; // change in kPa x 10 per .1 sec int map0,mapmax,clt0,cltmult,mat0,matmult,tps0,tpsmax,batt0,battmax, // kPa x 10, deg F or C x 10, adc counts, volts x 10 ego0,egomult,baro0,baromax,bcor0,bcormult,knock0,knockmax; // afr x 10, kpa x 10, %, volts x 100 int Dtpred_Gain; // % unsigned char CrnkTol,ASTol,PulseTol, // % tolerance for next input pulse // timing during cranking, after start/warmup and normal running IdleCtl, // idle: 0 = none, 1= solenoid, 2= iac stepper motor // - enabled only when moving, 3 = iac motor - always enabled. // 4 = Ford pwm, 5 = 3 for 15 min, then = 2. IACtstep, // iac stepper motor nominal time between steps (.1 ms units) IACaccstep, // iac stepper motor accel/decel step time (.1 ms)-future use IACnaccstep, // iac stepper motor no. of accel/decel steps - future use IACpwm_step; // controls freq of pwm FIdle solenoid = 80 Hz * IACpwm_step. int IACStart, // no. of steps to send at startup to put stepper // motor at reference (wide open) position IdleHyst, // amount clt temp must move before Idle position is changed IACcrankpos, // IAC pos must be open(<) at least this much(steps) in cranking IACcrankxt, // no. seconds from end of cranking for IAC pos to blend into // coolant dependent pos. IACcoldtmp,IACcoldpos,IACcoldxt, // when startup coolant temp < IACcoldtmp, // then when reach (>=) IACcoldpos switch to time based ctl: interpolate // bet IACcoldpos and final table IAC pos for period IACcoldxt secs. PrimePU,PrimePH, // priming pulsewidths at min, max temps in temp_table (ms x 10) CWU,CWH, // crank pulsewidths at min, max temps in temp_table (ms x 10) AWEVU,AWEVH, // after start warmup % enrich add-on value at min,max temps in // temp_table AWCU,AWCH; // after start enrichment no. cycles at min,max temps in temp_table unsigned char Tpsacold, // cold (-40F) accel amount in .1 ms units AccMult, // cold (-40F) accel multiply factor (%) TpsThresh, // tpsdot threshhold for acc/decel enrichment(change in %x10 per .1 sec) MapThresh, // mapdot threshhold for acc/decel enrichment(change in kPax10 per .1 s) TpsAsync, // clock duration (in .1 sec tics) for accel enrichment TPSDQ; // deceleration fuel cut option (%) int TPSWOT, // TPS value at WOT (for flood clear) in %x10 TPSOXLimit; // Max tps value (%x10) where O2 closed loop active unsigned char Tps_acc_wght, // weight (0-100) to be given to tpsdot for accel enrichment. // 100 - Tps_acc_wght will then be given to mapdot. BaroOption, // 0=no baro, 1=baro is 1st reading of map (before cranking), // 2=independent barometer (=> EgoOption not 2 or 4) EgoOption, // 0 = no ego;1= nb o2;2=2 nb o2;3=single wbo2;4=dual wbo2. NOTE: // BaroOption MUST be < 2 if EgoOption = 2 or 4. EgoCountCmp, // Ign Pulse counts between when EGO corrections are made EgoStep, // % step change for EGO corrections EgoLimit, // Upper/Lower rail limit (egocorr inside 100 +/- limit) AFRTarget, // NBO2 AFR(Vx100) determining rich/ lean Temp_Units, // 0= coolant & mat in deg F; 1= deg C MAFOption, // MAF options. Bits 0-3: =0 is no MAF; =1 is MAF-only; =2 is MAF - // MAP blend. Bits 4-7: =0, MAF signal on ADC0=MAP pin. Must put MAF // here if MAFOption = 0. =1, MAF signal on ADC6=Baro/Ego2 pin; =2, // MAF signal on ADC7 (knock pin). DualSpkOptn; // Option = 1 for 2 ignition inputs and 2 outputs. Specifying this option // uses the 2 pwm1,2 pins (TC2,TC4) for the extra ignition in, out; // therefore ** NO injector PWM ** with this option.Also, NO trigger // return, NO wheel decode, NO EDIS. Also set ISR_tmask=0,_pmask < 20. // Option = 2,3 for 2 cyl COP/ 4 cyl wasted spark with normal tach pulse // on input 1, cam synch on input 2;option 2= falling, 3= rising edge for // cam synch. When cam synch occurs, fire Output 1, then fire O/P 2 on // next tach, etc. No inj pwm, NO trig_ret, No EDIS. Can have tooth wheel. // Option = 4 is same as 2,3 but 1 toothed wheel on input 1 (input 2 // is unused). On tooth after missing tooth(teeth) fire O/P 1, then // fire O/P 2 after skip teeth (= next tach), etc. int FastIdle, // fast idle Off temperature (idle_ctl = 1 only) EgoTemp, // min clt temp where ego active RPMOXLimit; // Min rpm where O2 closed loop is active unsigned int ReqFuel; // fuel pulsewidth (usec) at wide open throttle unsigned char Divider, // divide factor for input tach pulses Alternate, // option to alternate injector banks InjOpen, // Injector open time (.1 ms units) InjPWMTim, // Time (.1 ms units) after Inj opening to start pwm InjPWMPd, // Inj PWM period (us) - keep between 10-25 KHz (100-40 us) InjPWMDty, // Inj PWM duty cycle (%) BatFac, // Battery fuel pw correction factor (msx10) EngStroke, // 0 = 4 stroke // 1 = 2 stroke InjType, // 0 = port injection // 1 = throttle body NoInj, // no. of injectors (1-12) OddFire1, // > 0 = odd fire option - smaller angle bet firings (deg) OddFire2, // > 0 = odd fire option - larger angle bet firings (deg) rpmLF,mapLF,tpsLF, // Lag filter coefficient for Rpm,Map/ Maf,Tps. Acts like egoLF, // averager: xnew = xold + xLF * (xmeas - xold), so xLF=0 adcLF,knkLF, // means value will never change, xLF=100 means no filtering. // egoLF is coefficient for ego filter, adcLF is for clt,mat,batt, // knkLF is for knock. AMCOption, // Automatic Mixture Control Option: 0 = none; 1= automatic updates // to ram ve table(s); 2= also automatically updates flash ve tables. dual_tble_optn, // 1 = use dual table option - ve, afr tables for each inj FuelAlpha, // option for alpha-N mode: bits 0-3: 0=none;1=use map,tps blend // algorithm; 2=same as 1, but don't use kpa multiplier in pwidth eq; // bit 4 used to specify whether alphaN used below alpha_lorpm // or above alpha_hirpm. // Next two options can be implemented if needed. Presently Ign and afr table will // be handled as AlphaN if FuelAlpha selected, regardless of their settings. IgnAlpha, // option to use map,tps(alphaN) blend algorithm for ignition AfrAlpha, // option to use map,tps(alphaN) blend algorithm for WBO2 AFR AFRStoich; // stoich afr ratio (afrx10 or Vx100) for fuel used. If AFRMult=1, this // input used to normalize afrtgt or afr_table multiplier in fuel pw eq. int alpha_lorpm, // option to use map,tps(alphaN) blend algorithm for fuel alpha_hirpm, // use tps if < lorpm; use map if > hirpm; else blend, in which // case lo, hirpm should be consecutive entries in frpm_table. // set lorpm=hirpm =0 to use map enrichment only, // set lorpm =25K to use alpha-N enrichment only, // If bit 4 set in FuelAlpha, use tps if > hirpm,map if < lorpm. alpha_map_table[NO_ATPSS][NO_ARPMS], // Table of ave map values (kpa x 10) for // [tps][rpm] pairs. Used only for alpha-N algorithm. // Allows ve table to retain same ve values // whether in alpha-N mode or not, amap_tps[NO_ATPSS]; // Tps values (% x 10) for alpha_map table unsigned int amap_rpm[NO_ARPMS]; // Rpm values for alpha_map table unsigned long baud; // baud rate int MAPOXLimit; // Max map value (kPax10) where O2 closed loop active unsigned char board_id_type[NO_CANBOARDS]; // board type (1-255) of ith board; // type=0, no board present at ith slot. // type=1, ECU (MS II) // type=2. Router board // type=3, I/O board, ...... // Generic spare port parameters: spr_port = 0(don't use)/1(use),where // spr_port[0-7] = PM2 - PM5; PTT6,7; PORTA0; they are set as outs to main // pcb; out_offset,out_byte= byte offset from start of outpc structure and // size in bytes of 1st, 2nd variables to be tested for setting port; // condition='<', '>', '=';cond12 = '&','|',' ' connects the conditions for // the two variables with ' ' meaning only the first variable condition is // desired; thresh = value for the condition(e.g., var1 > thresh1); init_val, // port_val=value (0/1) to which the pin will be set at startup and when the // condition(s) is met; hyst is a hysteresis delta and works as ff: if a // setpoint condition is > and it is met, set port to val and leave until // variable is < thresh - hyst, then set pin back to 1 - val. Similarly if // condition is <, wait til var > thresh + hyst. For dual conditions, the // hysteresis conditions are evaluated the same way, but use the opposite // of cond12 to connect them (if cnd12 is &, use | and vice versa). char spr_port [NPORT], // NPORT == 7 condition1 [NPORT], condition2 [NPORT], cond12 [NPORT], init_val [NPORT], port_val [NPORT], out_byte1 [NPORT], out_byte2 [NPORT]; int out_offset1[NPORT], out_offset2[NPORT], thresh1 [NPORT], thresh2 [NPORT], hyst1 [NPORT], hyst2 [NPORT]; unsigned char TpsAsync2, // accel tailoff duration (sec x 10) AFRMult; // = 1 means multiply fuel pw eq by AFRStoich/AFRTgt(NB) // = 2 means multiply fuel pw eq by AFRStoich/afr_table(WB). int TpsAccel2; // end pulsewidth of accel enrichment (ms x 10) unsigned char EgoAlg, // 0=simple prop error algorithm; // 1=same algorithm with variable transport delay; // 2=full PID with Smith Pred correction. egoKP, egoKI, egoKD; // PID coefficients in %; egoKP also gain for // EgoAlg=0, with 100 = no gain; egoKD includes // 1/dt factor since fixed time step. unsigned int egoKdly1, // coefficients used to calculate ego transport egoKdly2; // delay (ms) = Kdly1 + Kdly2*120000 / (map(kPax10)*rpm) unsigned char FlexFuel, // Flex fuel option - modifies pw and spk adv based on % alcohol. cpad1, // pad byte fuelFreq[2], // Table of fuel sensor freq(Hz) vs %fuel corr; fuelCorr[2], AMCStep, // % of AMC correction to be applied when ramve updated. AMCdve; // AMC correction must be > AMCdve % to be applied in burn unsigned int AMCve_drpm,AMCve_dmap, // current rpm, map(kPax10) must be within this AMCramve_dt, // tolerance of a ve table vertex for AMCramve_dt secs // before AMC ve correction is applied AMCT_thresh, // Min time (secs) between flash burns of ram ve table AMCupdate_thresh;// Min number of AMC ram ve updates before burn table. unsigned char CWOption, // Cold warmup option - 0 = linear, 1 = custom table. knk_option, // Bits 0-3: 0=no knock detection;1=operate at table value or 1 // step below knock; 2=operate at table value or edge of knock. // Bits 4-7: 0/1 = knock signal < or > knk_thresh indicates knock occurred. knk_maxrtd, // max total retard when knock occurs, (degx10), knk_step1,knk_step2, // ign retard/ adv steps when 1st knock or after stopped, // (degx10); step1 large to quickly retard/ stop knock knk_trtd,knk_tadv, // time between knock retard, adv corrections, (secx10); // allows short time step to quickly retard, longer to try advancing. knk_dtble_adv, // change in table advance required to restart adv til knock or // reach table value (0 knock retard) process, deg x10. // This only applies with knk_option = 1. knk_ndet,cpad6; // number knock detects required for valid detection; pad byte. unsigned int knk_maxmap, // no knock retard above this map (kPax10). knk_lorpm,knk_hirpm, // no knock retard below, above these rpms. knk_rpm[NO_KNKRPMS], // tables of rpm vs knock threshhold(Vx100). knk_thresh[NO_KNKRPMS], No_Teeth; // Nominal (include missing) teeth for wheel decoding. (0= // no wheel decoding). unsigned char No_Miss_Teeth, // Number of consecutive missing teeth. No_Skip_Teeth, // Number of teeth (between tach pulses) to be skipped. Delay_Teeth, // Number of teeth to delay after 1st tooth after the missing // teeth before 1st tach synch declared(< No_Teeth- Miss_Teeth) // In this mode, for 16 - 2 wheel, 8 cyl,4 cycle, No_Skip_Teeth= 4,Delay_Teeth=0, // // \/ \/ \/ \/ // /\/\__ __/\/\/\/\/\/\/\/\/\/\/\/\ // // \/ => when the first tooth after all the missing teeth is input captured, // plus Delay_Teeth after, then we are at adv offset deg btdc, that is, this tooth // and every 'No_Skip_Teeth' thereafter mark the tach pulses. // Note: No_Miss_Teeth must be < No_Skip_Teeth. Also, Delay_Teeth must be such that // every tach pulse tooth is a real tooth - not a missing one. ICISR_tmask, // Time (msx10) after tach input capture during which further // interrupts are inhibited to mask coil ring or VR noise. ICISR_pmask, // % of dtpred after tach input capture during which further // interrupts are inhibited to mask coil ring or VR noise. // This and prior mask not applicable with wheel decoding. InjTestOption; // Puts program in injector test mode: program fires both // injectors according to parameters further below. when done // program halts until hard or soft reset issued. unsigned int ae_lorpm,ae_hirpm; // lorpm is rpm at which normal accel enrichment just starts // to scale down, and is reduced to 0 at ae_hirpm. To omit scaling, set _lorpm // = _hirpm= very large number. int ffSpkDel[2]; // Table of fuel sensor freq(Hz) vs spk corr (degx10); unsigned int InjTestNoSqrts, // No of squirts in test/clean mode. InjTestPW, // Pulse width(usec) for testing/ cleaning injectors. InjTestOff; // Time(msx10) between inj test squirts. unsigned int CID; // Engine cubic in displacement. } inputs1; typedef struct { unsigned char ve_table[NO_INJ][NO_FMAPS][NO_FRPMS]; int adv_table[NO_SMAPS][NO_SRPMS]; unsigned int AMCNBurns; int CWPrime[NO_TEMPS],CWCPW[NO_TEMPS],CWAWEV[NO_TEMPS],CWAWC[NO_TEMPS]; int MatTemps[NO_MAT_TEMPS]; // MAT temperatures for spark retard, degx10 F or C unsigned char MatSpkRtd[NO_MAT_TEMPS]; // degx10 of spark retard vs mfld air temp unsigned char XTauOption, // Bits 0-3: // 0 = no XTau algorithm; 1 = XTau for accel/ decel only; // 2 = XTau for warmup also, based on initial coolant temp. // This option presently incomplete - need to make 2nd inde- // pendent loop and add 2nd XTfcor for warmup, plus add uchar // array for XTX vs clt temps. Will be completed if real need. // Note X-Tau applies to both injectors. If needed (for // example with dual table option), Bit 4 (=1) can be used to // apply correction only to Inj1. XTDecel, // % change in XTauTable while in decel (tpsdot < -thresh) XTX,XTScl, // % fuel(1-99) going into wall puddling; tau scale factor, // 1-255, to scale XTauTable to larger values. XTauTable[NO_FMAPS][NO_FRPMS]; // time constant (secx100) for fuel puddle // dissipation vs map and rpm. int XTauClt[NO_TEMPS], // same tau, but % scale as function of coolant temp. XTauMat[NO_TEMPS]; // same tau, but % scale as function of mfld air temp int BaroVals[NO_BARS], // Barometric pressures (kPa x 10) for baro correction table MatVals[NO_MATS]; // air temperatures (degx10) for air density correction table char BaroCorDel[NO_BARS], // Barometric corrections (+/-%) - added to eq. value // to correct for varying exhaust size AirCorDel[NO_MATS]; // Air density orrections (+/-%) - added to eq. value // to correct for varying mat sensor location unsigned int MAFFlow[NO_MAFS]; // MAF flows (mg/ secx10) for below corrections. unsigned char MAFCor[NO_MAFS]; // Corrections to maf factor table (%) for real time tuning/ // intake mods.as function of MAFFlow. 100% = no correction. unsigned int MAFRPM1,MAFRPM2; // For MAFOption=2, if rpm < rpm1 use MAP only; > rpm2 use MAF // only. In between, use MAP/ MAF blend. unsigned char MAFDir, // If = 0, use above for MAP/ MAF blend; =1, reverse - use // MAF only below rpm1 and MAP only above rpm2. VEIXOptn; // =1 means use (kpa*1000)/baro instead of kpa as the index // into ve, afr, spk tables. (per Ben Strader (EFI Univ), verified // from Heywood, Aquino,Taylor, and Moskwa. When this done pw = // .....*kpa/1000... instead of *kpa/baro. } inputs2; #ifndef GCC_BUILD #pragma ROM_VAR INP_ROM #endif // flash copy of inputs - initialized #define SECTOR_BYTES 1024 // bytes #define SECTOR_WORDS ((int)(SECTOR_BYTES/2)) #define N_SECTORS(theStruct) ((int)((sizeof(theStruct)+SECTOR_BYTES-1)/SECTOR_BYTES)) #define N_PADDING(theStruct) ((int)(N_SECTORS(theStruct)*SECTOR_BYTES - sizeof(theStruct))) const inputs1 in1flash EEPROM_ATTR = { 8, // no_cyl (1-12) 3, // no_skip_pulses (tach pulses) 0x05, 1, // ICIgnOption,spkout_hi_lo, 31, 20, 6, // max_coil_dur,max_spk_dur,DurAcc msx10 {-40,-20,0,20,40}, // deltaV_table[], Vx10 = batt_voltx10 - 120 {24, 9, 0,-5,-9}, // deltaDur_table[], msx10 = correction for batt_volt 1, // RevLimOption:0,none; 1,retard spk; 2,fuel cut 120, // RevLimMaxRtd, deg x 10 1, // PredOpt (For EDIS, toothed wheel > 12 PredOpt=0 is sufficient) // For EDIS keep total adv (incl. offset & cold adv) < 60 deg 300, // rpm at which cranking through {60, // cold_adv_table[TEMP no = 0], deg x 10 50,40,30,20,10,0,0,0,0}, 0, // adv_offset, deg x 10 5500, 6000, // RevLimRpm1,2 {{{130, // afr_table[inj1][MAP/tps no =0][RPM no = 0], afrx10 135,160,160,160,149,143,132,131,132,131,130}, {132, // afr_table[inj1][MAP/tps no =1][RPM no = 0], afrx10 137,157,157,155,149,142,132,130,129,128,127}, {134, // afr_table[inj1][MAP/tps no =2][RPM no = 0], afrx10 139,155,155,154,149,141,130,129,128,127,127}, {135, // afr_table[inj1][MAP/tps no =3][RPM no = 0], afrx10 140,152,152,150,147,140,130,129,128,127,126}, {136, // afr_table[inj1][MAP/tps no =4][RPM no = 0], afrx10 141,150,149,147,147,140,129,128,127,126,126}, {135, // afr_table[inj1][MAP/tps no =5][RPM no = 0], afrx10 138,145,143,141,141,135,128,127,126,126,126}, {134, // afr_table[inj1][MAP/tps no =6][RPM no = 0], afrx10 134,139,137,136,136,131,127,126,126,126,126}, {132, // afr_table[inj1][MAP/tps no =7][RPM no = 0], afrx10 132,135,133,133,132,130,126,125,125,125,125}, {130, // afr_table[inj1][MAP/tps no =8][RPM no = 0], afrx10 130,131,130,130,129,130,125,125,125,125,125}, {130, // afr_table[inj1][MAP/tps no =9][RPM no = 0], afrx10 129,129,128,128,127,126,125,125,125,125,124}, {130, // afr_table[inj1][MAP/tps no =10][RPM no = 0], afrx10 129,129,128,128,127,126,125,125,125,123,123}, {130, // afr_table[inj1][MAP/tps no =11][RPM no = 0], afrx10 129,129,128,128,127,126,125,125,122,122,122}}, {{130, // afr_table[inj2][MAP/tps no =0][RPM no = 0], afrx10 135,160,160,160,149,143,132,131,132,131,130}, {132, // afr_table[inj2][MAP/tps no =1][RPM no = 0], afrx10 137,157,157,155,149,142,132,130,129,128,127}, {134, // afr_table[inj2][MAP/tps no =2][RPM no = 0], afrx10 139,155,155,154,149,141,130,129,128,127,127}, {135, // afr_table[inj2][MAP/tps no =3][RPM no = 0], afrx10 140,152,152,150,147,140,130,129,128,127,126}, {136, // afr_table[inj2][MAP/tps no =4][RPM no = 0], afrx10 141,150,149,147,147,140,129,128,127,126,126}, {135, // afr_table[inj2][MAP/tps no =5][RPM no = 0], afrx10 138,145,143,141,141,135,128,127,126,126,126}, {134, // afr_table[inj2][MAP/tps no =6][RPM no = 0], afrx10 134,139,137,136,136,131,127,126,126,126,126}, {132, // afr_table[inj2][MAP/tps no =7][RPM no = 0], afrx10 132,135,133,133,132,130,126,125,125,125,125}, {130, // afr_table[inj2][MAP/tps no =8][RPM no = 0], afrx10 130,131,130,130,129,130,125,125,125,125,125}, {130, // afr_table[inj2][MAP/tps no =9][RPM no = 0], afrx10 129,129,128,128,127,126,125,125,125,125,124}, {130, // afr_table[inj2][MAP/tps no =10][RPM no = 0], afrx10 129,129,128,128,127,126,125,125,125,123,123}, {130, // afr_table[inj2][MAP/tps no =11][RPM no = 0], afrx10 129,129,128,128,127,126,125,125,122,122,122}}}, {180, // warmen_table[TEMP no = 0], % enrichment vs temp 180,160,150,135,125,113,108,102,100}, {20, // tpsen_table[TPS_DOT no = 0], enrichment in .1ms vs tpsdot 50,105,150}, {0, // mapen_table[TPS_DOT no = 0], enrichment in .1ms vs mapdot 0,0,0}, {40, // iacstep_table[TEMP no = 0], 60,75,90,105,120,130,140,150,160}, {500, // frpm_table[RPM no = 0] , use in VE, AFR tables 800,1100,1400,2000,2600,3100,3700,4300,4900,5400,6000}, {700, // srpm_table[RPM no = 0] , use in spark advance table 900,1200,1500,2000,2600,3100,3700,4300,4900,5400,6000}, {300, // fmap_table[MAP/tps no = 0], kPa x 10 , use for VE, AFR 350,450,500,550,600,700,750,800,850,950,1000}, {200, // smap_table[MAP/tps no = 0], kPa x 10 , use for spk adv 250,300,350,400,450,500,600,700,800,900,1000}, {-400, // temp_table[TEMP no = 0], deg x 10 -200,0,200,400,600,800,1000,1300,1600}, {100, // tpsdot_table[TPS_DOT no =0], 400,800,1540}, // change in % x 10 per .1 sec {0, // mapdot_table[TPS_DOT no =0], 0,0,0}, // change in kPa x 10 per .1 sec 93, // map0, kPa x 10, value @ 0 ADC counts 2609, // mapmax, kPa x 10, value @ max(1023) ADC counts 0, // clt0, deg (C or F) x 10 100, // cltmult, % 0, // mat0, deg (C or F) x 10 100, // matmult, % 0, // tps0, adc counts 1023, // tpsmax, adc counts 1, // batt0, v x 10 297, // battmax, v x 10 0, // ego0, afr x 10 100, // egomult, % 93, // baro0, kPa x 10 2609, // baromax, kPa x 10 147, -47, // bcor0,bcormult %, slope 0, // knock0, v x 100 500, // knockmax, v x 100 0, // Dtpred_Gain, % 50,70,25, // PulseTol, % tolerance for next input pulse timing during // cranking, after start/ warmup, normal running 5, // IdleCtl, idle: 0 = none, 1= solenoid, 2= iac stepper motor // - enabled only when moving, 3 = iac motor - always enabled. // 4 = Ford PWM iac, 5 = 3 for 15 min, then = 2 25, // IACtstep, .1 ms units (25 gives pulse freq of 400 Hz) 0, // IACaccstep 0, // IACnaccstep 1, // IACpwm_step = freq of pwm FIdle solenoid= 80 Hz* IACpwm_step. 160, // IACStart, no. of steps to send at startup to put stepper // motor at reference (wide open) position 50, // IdleHyst amount (degx10) 100,5, // > IAC opening (< steps) during cranking and few secs after 0,120,40, // when startup coolant temp < IACcoldtmp (degx10), // then when reach (>=) IACcoldpos switch to time based ctl: interpolate // bet IACcoldpos and final table IAC pos for period IACcoldxt secs. 60, 20, // PrimePU,H priming pulsewidths at min, max temps in temp_table (ms x10) 120, 40, // CWU,CWH, crank pw at min, max temps in temp_table (ms x 10) 45,25, // AWEV, after start warmup % enrich add-on value at min, max clt temps, 350,150, // AWC, after start enrichment no. of cycles at min, max clt temps 30, // Tpsacold, cold (-40F) accel amount in .1 ms units 130, // AccMult, cold (-40F) accel multiply factor (%) 200, // TpsThresh, tpsdot threshhold for accel enrichment(change in %x10 per .1 s) 100, // MapThresh, mapdot threshhold for accel enrichment(change in kPax10 per .1 s) 2, // TpsAsync, clock duration (in .1 sec tics) for accel enrichment 90, // TPSDQ, deceleration fuel cut option (%) 700, // TPSWOT, TPS value at WOT (for flood clear), %x10 700, // TPSOXLimit, Max tps value (%x10) where O2 closed loop active 100, // Tps_acc_wght, weight to be given to tpsdot for accel enrichment. // 100 - Tps_acc_wght will then be given to mapdot. 1, // BaroOption, 0=no baro, 1=baro is 1st reading of map (before cranking), // 2=independent barometer 1, // 0 = no ego;1= nb o2;2=2 nb o2;3=single wbo2;4=dual wbo2. 16, // EgoCountCmp, Ign Pulse counts between when EGO corrections are made 1, // EgoStep, % step change for EGO corrections 15, // EgoLimit, Upper/Lower rail limit (egocorr inside 100 +/- limit) 45, // AFRTarget, NBO2 afr (Vx100) determining rich/ lean 0, // Temp_Units, 0= coolant & mat in deg F; 1= deg C 0, // MAFOption. Bits 0-3: =0 is no MAF; =1 is MAF-only; =2 is MAF - // MAP blend. Bits 4-7: =0, MAF signal on ADC0=MAP pin. Must put MAF // here if MAFOption = 0. =1, MAF signal on ADC6=Baro/Ego2 pin; =2, // MAF signal on ADC7 (knock pin). 0, // DualSpkOptn; Option = 1 for 2 ignition inputs and 2 outputs. This option // uses the 2 pwm1,2 pins (TC2,TC4) for the extra ignition in, out; // therefore ** NO injector PWM ** with this option.Also, NO trigger // return, NO wheel decode, NO EDIS. Also set ISR_tmask=0,_pmask < 20. // Option = 2,3 for 2 cyl COP/ 4 cyl wasted spark with normal tach pulse // on input 1, cam synch on input 2;option 2= falling, 3= rising edge for // cam synch. When cam synch occurs, fire Output 1, then fire O/P 2 on // next tach, etc. No inj pwm, NO trig_ret, No EDIS. Can have tooth wheel. // Option = 4 is same as 2,3 but 1 toothed wheel on input 1 (input 2 // is unused). On tooth after missing tooth(teeth) fire O/P 1, then // fire O/P 2 after skip teeth (= next tach), etc. 1400, // FastIdle, fast idle temperature (degx10) (idle_ctl = 1 only) 1600, // EgoTemp, min clt temp where ego active, degx10 1300, // RPMOXLimit, Min rpm where O2 closed loop is active 15500, // ReqFuel; fuel pulsewidth (usec) at wide open throttle 4, // Divider, divide factor for input tach pulses 1, // Alternate, option to alternate injector banks 10, // InjOpen, Injector open time (.1 ms units) 255, // InjPWMTim, Time (.1 ms units) after opening to start pwm 66, // InjPWMPd, Injector PWM period (us) 75, // InjPWMDty, Injector PWM duty cycle (%) 12, // BatFac, Battery fuel pw correction factor (msx10) 0, // EngStroke, 0 = 4 stroke, 1 = 2 stroke 0, // InjType, 0 = port injection, 1 = throttle body 8, // NoInj, no. of injectors (1-12) 0,0, // OddFire smaller, larger angle between firings 50,50,75, // Lag filter coefficients (1-100%) for Rpm,Map,Tps, 60, // ego1,2 50,80, // Lag filter coefficients for other adc(clt,mat,batt), knock. 0, // AMC option 0, // dual table option 0, // fuel alpha-N, map blend option 0, // ign alpha-N, map blend option(not implemented-always use // alphaN if FuelAlphaN=1, else don't). 0, // WBO2 AFR alpha-N, map blend option(same note as above); 45, // AFRStoich, stoich afr (afrx10 or Vx100) for fuel used. If AFRMult= // 1, this input used to normalize AFRtarget or afr_table multiplier // in fuel pw eq. 0, // lo rpm for alpha-N, map blend option 0, // alpha-N hi rpm {{1000,600,300,350,400,400}, // alpha_map_table[tps no =0][RPM nos 0-5] (kpa x 10) {1000,650,350,400,450,450}, // alpha_map_table[tps no =1][RPM nos 0-5] {1000,700,400,450,500,500}, // alpha_map_table[tps no =2][RPM nos 0-5] {1000,750,450,500,550,550}, // alpha_map_table[tps no =3][RPM nos 0-5] {1000,800,500,550,600,600}, // alpha_map_table[tps no =4][RPM nos 0-5] {1000,800,500,550,600,600}}, // alpha_map_table[tps no =5][RPM nos 0-5] {0,120,160,300,600,600}, // amap_tps[0 - 5] (% x 10); {0,500,1000,1500,2000,2000}, // amap_rpm[0 - 5] 115200, // baud rate 900, // MAPOXLimit, Max MAP value (kPax10) where O2 closed loop active {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // board types {0,0,0,0,0,0,0}, // spr_port {'<','<','<','<','<','<','<'}, // condition1 {'<','<','<','<','<','<','<'}, // condition2 {' ',' ',' ',' ',' ',' ',' '}, // cond12 {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0},{0,0,0,0,0,0,0},{0,0,0,0,0,0,0}, {0,0,0,0,0,0,0},{0,0,0,0,0,0,0}, {0,0,0,0,0,0,0},{0,0,0,0,0,0,0},{0,0,0,0,0,0,0},{0,0,0,0,0,0,0}, // spr pin params 1, // accel tail duration (sec x 10). 0, // AFRMult,= 1 means multiply fuel pw eq by AFRStoich/AFRTgt(NB) // = 2 means multiply fuel pw eq by AFRStoich/afr_table(WB). 20, // accel end pwidth enrichment (ms x 10) 0, // EgoAlg, 0=simple algorithm; 1=Prop err alg;2=PID w. Smith pred 100,20,0, // KP,KI,KD, PID coefficients in % 10,4000, // egoKdly1,2 = coefficients used to calculate ego transport // delay (ms) = Kdly1 + Kdly2*120000 / (map(kPax10)*rpm). // Defaults based on xpt delay of .1 s at wot, 1 s at idle 0, // Flex fuel option - modifies pw and spk adv based on freq signal // for % alcohol. 0, // cpad1, pad byte {50, 150}, // Table of fuel sensor freq(Hz) vs {100,163}, // fuel pw corr in %; 1st element is pure gas, 2nd is pure Alcohol. 10, // AMCStep, % of AMC correction to be applied when ramve updated. 2, // AMCdve, AMCcorrection must be > AMCdve % to be applied for burn 200,100, // AMCve_drpm,AMCve_dmap, current rpm, map(kPax10) must be within // this tolerance of a ve table vertex for 20, // AMCramve_dt secs before AMC correction is applied 1800, // AMCT_thresh, min time (secs) between flash burns of ram ve table 2, // AMCupdate_thresh, min number of AMC ram ve updates before burn table. 0, // CWOption, cold warmup option - 0 = linear, 1 = custom table. 0x00, // knk_option: Bits 0-3: 0=no knock detection;1=operate at table value or 1 // step below knock; 2=operate at table value or edge of knock. // Bits 4-7: 0/1 = knock signal < / > knk_thresh indicates knock occurred. 100, // knk_maxrtd, max total retard when knock, (degx10). 30,10, // knk_step1, _step2, ign retard/ adv steps when 1st knock or after stopped, // (degx10); step1 large to quickly retard/ stop knock 2,20, // knk_trtd,_tadv, time between knock retard, adv corrections, (secx10); // allows short time step to quickly retard, longer to try advancing. 30, // knk_dtble_adv, change in table advance required to restart adv til knock // or reach table value (0 knock retard) process, deg x10. // This only applies with knk_option = 1. 2,0, // knk_ndet, number of knock detects required for valid detection; pad byte. 700, // knk_maxmap, no knock retard above this map (kPax10). 700,3500, // knk_lorpm,knk_hirpm, no knock retard below, above these rpms. 500, // knk_rpm[0-NO_KNKRPMS], tables of rpm vs knock threshhold. 1000, 2000, 3000, 4000, 5000, 200, //knk_thresh[NO_KNKRPMS], Vx100 200, 200, 200, 200, 200, 0, // No_Teeth, nominal (include missing) teeth for wheel decoding. (0= // no wheel decoding). 2, // No_Miss_Teeth, number of consecutive missing teeth. 9, // No_Skip_Teeth, number of teeth (between tach pulses) to be skipped. 0, // Delay_Teeth, number of teeth to delay after 1st tooth after the missing // teeth before 1st tach synch declared (< No_Teeth- Miss_Teeth) 0, // ICISR_tmask, time (msx10) after tach input capture during which further // interrupts are inhibited to mask coil ring or VR noise. 50, // ICISR_pmask, % of dtpred after tach input capture during which further // interrupts are inhibited to mask coil ring or VR noise. // This and prior mask not applicable with wheel decoding. 0, // InjTestOption; Puts program in injector test mode: program fires both // injectors according to parameters further below. when done // program halts until hard or soft reset issued. 2500, 5000, // ae_lorpm,ae_hirpm, lorpm is rpm at which normal accel enrichment just // starts to scale down, and is reduced to 0 at ae_hirpm. To omit scaling, set // _lorpm = _hirpm= very large number. {0,-130}, // flex fuel spk corr (degx10); 1st element for pure gas, 2nd for pure // Alcohol; last is normally - to retard spk since Alch burns faster. 400, // InjTestNoSqrts, No of squirts in test/clean mode. 20000, // InjTestPW, Pulse width(usec) for testing/ cleaning injectors. 600, // InjTestOff, Time(msx10) between inj test squirts. 350 // CID, engine cubic in displacement. }; const unsigned char in1padding[N_PADDING(inputs1)] EEPROM_ATTR ={0}; const inputs2 in2flash EEPROM_ATTR = { {{{26, // ve_table[inj1][MAP/tps no =0][RPM no = 0] 26,29,34,40,46,50,55,58,61,61,60}, {29, // ve_table[inj1][MAP/tps no =1][RPM no = 0] 29,32,38,46,53,56,60,63,66,65,62}, {38, // ve_table[inj1][MAP/tps no =2][RPM no = 0] 37,39,44,53,61,65,67,69,73,71,66}, {43, // ve_table[inj1][MAP/tps no =3][RPM no = 0] 42,43,45,54,63,66,69,71,75,73,67}, {48, // ve_table[inj1][MAP/tps no =4][RPM no = 0] 46,48,50,58,65,69,71,73,77,75,69}, {52, // ve_table[inj1][MAP/tps no =5][RPM no = 0] 51,52,55,62,67,71,73,75,79,77,71}, {57, // ve_table[inj1][MAP/tps no =6][RPM no = 0] 59,61,65,69,72,76,78,81,85,85,80}, {61, // ve_table[inj1][MAP/tps no =7][RPM no = 0] 62,65,69,72,75,79,82,85,89,88,84}, {65, // ve_table[inj1][MAP/tps no =8][RPM no = 0] 66,69,73,76,78,82,86,90,93,92,88}, {68, // ve_table[inj1][MAP/tps no =9][RPM no = 0] 70,73,78,81,83,86,90,94,98,97,93}, {72, // ve_table[inj1][MAP/tps no =10][RPM no = 0] 77,82,87,90,93,95,100,105,109,108,103}, {74, // ve_table[inj1][MAP/tps no =11][RPM no = 0] 81,86,91,95,97,100,105,111,114,113,108}}, {{26, // ve_table[inj2][MAP/tps no =0][RPM no = 0] 26,29,34,40,46,50,55,58,61,61,60}, {29, // ve_table[inj2][MAP/tps no =1][RPM no = 0] 29,32,38,46,53,56,60,63,66,65,62}, {38, // ve_table[inj2][MAP/tps no =2][RPM no = 0] 37,39,44,53,61,65,67,69,73,71,66}, {43, // ve_table[inj2][MAP/tps no =3][RPM no = 0] 42,43,45,54,63,66,69,71,75,73,67}, {48, // ve_table[inj2][MAP/tps no =4][RPM no = 0] 46,48,50,58,65,69,71,73,77,75,69}, {52, // ve_table[inj2][MAP/tps no =5][RPM no = 0] 51,52,55,62,67,71,73,75,79,77,71}, {57, // ve_table[inj2][MAP/tps no =6][RPM no = 0] 59,61,65,69,72,76,78,81,85,85,80}, {61, // ve_table[inj2][MAP/tps no =7][RPM no = 0] 62,65,69,72,75,79,82,85,89,88,84}, {65, // ve_table[inj2][MAP/tps no =8][RPM no = 0] 66,69,73,76,78,82,86,90,93,92,88}, {68, // ve_table[inj2][MAP/tps no =9][RPM no = 0] 70,73,78,81,83,86,90,94,98,97,93}, {72, // ve_table[inj2][MAP/tps no =10][RPM no = 0] 77,82,87,90,93,95,100,105,109,108,103}, {74, // ve_table[inj2][MAP/tps no =11][RPM no = 0] 81,86,91,95,97,100,105,111,114,113,108}}}, {{157, // adv_table[MAP/tps no=0][RPM no=0], deg x 10 175,200,286,328,375,370,375,380,380,380,380}, {157, // adv_table[MAP/tps no=1][RPM no=0], deg x 10 178,201,282,324,370,370,370,375,380,380,380}, {156, // adv_table[MAP/tps no=2][RPM no=0], deg x 10 180,202,278,324,368,370,375,375,380,380,380}, {155, // adv_table[MAP/tps no=3][RPM no=0], deg x 10 182,204,274,323,364,370,370,375,375,380,380}, {155, // adv_table[MAP/tps no=4][RPM no=0], deg x 10 184,206,272,322,360,368,374,374,376,376,380}, {157, // adv_table[MAP/tps no=5][RPM no=0], deg x 10 186,207,268,321,360,366,372,375,375,375,375}, {158, // adv_table[MAP/tps no=6][RPM no=0], deg x 10 188,208,258,320,360,365,365,365,370,370,370}, {160, // adv_table[MAP/tps no=7][RPM no=0], deg x 10 185,205,250,317,358,360,362,362,362,362,362}, {160, // adv_table[MAP/tps no=8][RPM no=0], deg x 10 183,203,241,308,353,360,360,360,360,360,360}, {155, // adv_table[MAP/tps no=9][RPM no=0], deg x 10 175,200,235,299,348,360,360,360,360,360,360}, {151, // adv_table[MAP/tps no=10][RPM no=0], deg x 10 172,195,228,295,343,360,360,360,360,360,360}, {148, // adv_table[MAP/tps no=11][RPM no=0], deg x 10 168,190,216,282,335,360,360,360,360,360,360}}, 0, // AMCNBurns { 60, 56, 52, 48, 44, 40, 36, 32, 26, 20}, // CWPrime, (msx10) {120,112,104, 96, 88, 80, 72, 64, 52, 40}, // CWCPW, (msx10) { 45, 43, 41, 39, 37, 35, 33, 31, 28, 25}, // CWAWEV, % {350,330,310,290,270,250,230,210,180,150}, // CWAWC, cycles {1600,1800,2000,2200,2400,2600}, // MatTemps, degx10 F or C {0,0,20,40,60,80}, // MatSpkRtd, degx10 0, // XTauOption: 0 = no XTau algorithm; 1 = XTau for accel/ decel only; // 2 = XTau for warmup also, based on initial coolant temp. // This last option presently incomplete/ unused. 100, // XTDecel, % change in XTauTable while in decel (tpsdot < thresh) 30, // XTX = % fuel going into wall puddling; 1, // tau scale factor,1-255 to scale XTauTable. {{ 19, // XTauTable[MAP/tps no=0][RPM no=0], secx100 15, 12, 9, 6, 5, 4, 3, 3, 2, 2, 1}, { 21, // XTauTable[MAP/tps no=1][RPM no=0], secx100 19, 13, 10, 7, 6, 5, 4, 3, 3, 2, 1}, { 22, // XTauTable[MAP/tps no=2][RPM no=0], secx100 19, 15, 12, 9, 8, 6, 5, 4, 3, 2, 2}, { 23, // XTauTable[MAP/tps no=3][RPM no=0], secx100 20, 16, 13, 10, 9, 7, 5, 4, 3, 2, 2}, { 24, // XTauTable[MAP/tps no=4][RPM no=0], secx100 21, 17, 14, 11, 10, 8, 6, 4, 4, 3, 2}, { 26, // XTauTable[MAP/tps no=5][RPM no=0], secx100 23, 18, 15, 13, 11, 9, 7, 5, 4, 3, 2}, { 27, // XTauTable[MAP/tps no=6][RPM no=0], secx100 24, 19, 17, 14, 12, 10, 7, 5, 4, 3, 2}, { 28, // XTauTable[MAP/tps no=7][RPM no=0], secx100 25, 20, 18, 15, 13, 11, 8, 6, 5, 3, 3}, { 29, // XTauTable[MAP/tps no=8][RPM no=0], secx100 26, 21, 19, 16, 14, 12, 8, 6, 5, 4, 3}, { 30, // XTauTable[MAP/tps no=9][RPM no=0], secx100 27, 22, 21, 18, 15, 13, 9, 6, 5, 4, 3}, { 31, // XTauTable[MAP/tps no=10][RPM no=0], secx100 28, 23, 22, 19, 16, 14, 10, 7, 6, 4, 3}, { 33, // XTauTable[MAP/tps no=11][RPM no=0], secx100 29, 24, 23, 20, 17, 15, 10, 7, 6, 4, 3}}, {20000,15000,10000,8000,5800,4800,3600,2400,1200,100}, // XTauClt[NO_TEMPS], % {140,136,126,116,110,106,104,102,100,100}, // XTauMat[NO_TEMPS], % { // BaroVals[NO_BARS]: barometric pressures, (kPa x 10)) for baro correction table 800, 900, 1000, 1050, 1100, 1200 }, { // MatVals[NO_MATS]: air temperatures (degx10) for air density correction table 400, 600, 1000, 1300, 1600, 1800 }, { // BaroCorDel[NO_BARS], barometric correction table(%) - added to eq. value 0, 0, 0, 0, 0, 0 }, { // AirCorDel[NO_MATS], air density correction table(%) - added to eq. value 0, 0, 0, 0, 0, 0 }, { // MAFFlow[NO_MAFS], MAF flows (mg/ secx10) for below corrections. 100, 2000, 4000, 6000, 8000, 10000, 12000, 14000, 16000, 18000, 20000, 25000 }, { // MAFCor[NO_MAFS], Corrections to maf factor table (%) for real time tuning/ 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100 }, // intake mods.as // function of MAFFlow. 100% = no correction. 1200, 3000, // MAFRPM1,MAFRPM2. For MAFOption=2, if rpm < rpm1 use MAP only; // > rpm2 use MAF only. In between, use MAP/ MAF blend.(see next). 0, // MAFDir: If = 0, use above for MAP/ MAF blend; =1, reverse // - use MAF only below rpm1 and MAP only above rpm2. 0 // VEIXOptn =1 means use (map*1000)/baro instead of map as the index // into ve, afr, spk tables. }; const unsigned char in2padding[N_PADDING(inputs2)] EEPROM_ATTR ={0}; // 1024 bytes = 1 block flash #ifndef GCC_BUILD #pragma ROM_VAR DEFAULT #pragma ROM_VAR OVF_ROM #endif // IAC stepper motor sequence const unsigned char IACCoilA[8] = {0,0,1,1,0,0,1,1}; const unsigned char IACCoilB[8] = {1,0,0,1,1,0,0,1}; // array of TC overflow numbers at which to increment secs cntr. const unsigned int TC_ovfla[60] = { 23, 46, 69, 92, 114, 137, 160, 183, 206, 229, 252, 275, 298, 320, 343, 366, 389, 412, 435, 458, 481, 504, 526, 549, 572, 595, 618, 641, 664, 687, 710, 732, 755, 778, 801, 824, 847, 870, 893, 916, 938, 961, 984, 1007, 1030, 1053, 1076, 1099, 1122, 1144, 1167, 1190, 1213, 1236, 1259, 1282, 1305, 1328, 1350, 1373 }; const char RevNum[20] = { // revision no: // only change for major rev and/or interface change. "MSII Rev 2.80000 " }, Signature[32] = { // program title. // Change this every time you tweak a feature. "** V2.82Embedded Code by B&G **" }; #ifndef GCC_BUILD #pragma ROM_VAR DEFAULT #endif // ram copy of inputs inputs1 inpram; inputs2 in2ram; // sensor variables int last_tps,last_map,tpsdot_ltch,mapdot_ltch; // fuel variables unsigned int pwcalc1,pwcalc2,pw_open,PrimeP,AWEV,AWC; unsigned int Fl1OCt_overflow,Fl2OCt_overflow; unsigned long Fl1TimerComp,Fl2TimerComp; unsigned char pwm1_on,pwm2_on,cut_fuel; unsigned long pwm1_time,pwm2_time; int wrmtmp; // ignition variables char ICtt_ovflo; unsigned char SPK,CHG, pulse_no,ign_state[2],ign_setpin[2],ICintmask[2], OCintmask[2],IgnOCpinstate,first_edis,PulseTol,cyl_no,mask_teeth, last_tooth,tooth_no; char ICint,OCint,cam_sync; long adv_us,charge_time,coil_dur_set,coil_dur_out[2]; int ICt_overflow[2],IgnOCt_overflow[2],coil_dur,ic_adv_deg; volatile unsigned short *pTIC[2],*pTOC[2]; unsigned long IgnTimerComp[2],dtpred; // IAC variables unsigned long motor_time; int motor_step, IACmotor_pos,last_iacclt; char IAC_moving,IACmotor_reset,IdleCtl; // General variables unsigned int mms,millisec,burn_flag,iacpwmctr; unsigned int TC_ovflow,TC_ov_ix; unsigned long lmms,t_enable_IC[2],t_chgoff,Rpm_Coeff,ltch_lmms, rcv_timeout,adc_lmms; unsigned int asecount,mafraw; unsigned char flocker,tpsaclk,egocount,igncount,altcount,next_adc,first_adc, txmode,tble_idx,burn_idx,synch,trig_ret_mode,crank_trig_mode,reinit_flag, egopstat,afrSL, FSensStat,knk_clk,knk_clk_test,knk_stat,knk_count, amc_burn_flag,blend; int ego1err,ego1errm1,ego2err,ego2errm1,sego1err,sego2err,egoKPX, blendve1,blendve2; unsigned int afrdl1,afrdl2,afrtgt_skip, FSens_Pd,FSensFreq; unsigned long MAFCoef; /* Clocks: - igncount: counts up each tach pulse, cleared when hit Divider pulses (and injection occurs). - asecount: counts up each time igncount = 0 (each Divider pulses). - egocount: counts up each tach pulse, cleared when hits EgoCountCmp - tpsaclk: counts every .1 sec - altcount: flips 0,1,0,1... on each injection, resulting in firing alternate injector banks if Alternate option. */ unsigned int txcnt,txgoal,rxoffset,rxnbytes,rxcnt,tble_word,ntword; char AMCmode,AMCdve_change,ego_cloop,bad_ego_flag,bad_ego_ltch,XTcalc,first_clt, MAFPin; unsigned int AMCclk,AMCve_clk,AMCNSum,AMCburn_clk,AMCram_updates, XTau,XTm,XTf,burn_tooth_no; int knk_tble_adv,warmup_Tclt,ffspkdel,mafmap,kpaix,kpadiv; long XTM; // CAN variables unsigned long cansendclk; char *canvar_blkptr[NO_VAR_BLKS]; unsigned short can_status; unsigned char can_clr_stat,can_reset,can_id; struct canmsg { /* CAN Xmt mssge ring buffer: can[0] is to hold Rx,TxISR messages, can[1] for main loop messages */ unsigned char cxno,cxno_in,cxno_out; unsigned char cx_msg_type[NO_CANMSG], cx_varblk[NO_CANMSG], cx_dest[NO_CANMSG],cx_varbyt[NO_CANMSG]; unsigned short cx_varoff[NO_CANMSG]; unsigned char cx_datbuf[NO_CANMSG][8]; // max msg data = 8 bytes } can[2]; // pointers for spare port pins volatile unsigned char *pPTMpin[8], *pPTTpin[8], *pPTApin0; unsigned char dummyReg,lst_pval[NPORT]; // allocate space in ram for flash burner core volatile unsigned char RamBurnPgm[36]; // rs232 Outputs to pc typedef struct { unsigned int seconds,pw1,pw2,rpm; // pw in usec int adv_deg; // adv in deg x 10 unsigned char squirt,engine,afrtgt1,afrtgt2; // afrtgt in afr x 10 (or Vx100) /* ; Squirt Event Scheduling Variables - bit fields for "squirt" variable above inj1: equ 0 ; 0 = no squirt; 1 = inj squirting inj2: equ 1 ; Engine Operating/Status variables - bit fields for "engine" variable above ready: equ 0 ; 0 = engine not ready; 1 = ready to run (fuel pump on or ign plse) crank: equ 1 ; 0 = engine not cranking; 1 = engine cranking startw: equ 2 ; 0 = not in startup warmup; 1 = in startw enrichment warmup: equ 3 ; 0 = not in warmup; 1 = in warmup tpsaen: equ 4 ; 0 = not in TPS acceleration mode; 1 = TPS acceleration mode tpsden: equ 5 ; 0 = not in deacceleration mode; 1 = in deacceleration mode */ unsigned char wbo2_en1,wbo2_en2; // from wbo2 - indicates whether wb afr valid int baro,map,mat,clt,tps,batt,ego1,ego2,knock, // baro - kpa x 10 // map - kpa x 10 // mat, clt deg(C/F)x 10 // tps - % x 10 // batt - vlts x 10 // ego1,2 - afr x 10 // knock - volts x 100 egocor1,egocor2,aircor,warmcor, // all in % tpsaccel,tpsfuelcut,barocor,gammae, // tpsaccel - acc enrich(.1 ms units) // tpsfuelcut - % // barocor,gammae - % vecurr1,vecurr2,iacstep,cold_adv_deg, // vecurr - % // iacstep - steps // cold_adv_deg - deg x 10 tpsdot,mapdot, // tps, map rate of change - %x10/.1 sec, // kPax10 / .1 sec coil_dur; // msx10 coil chge set by ecu unsigned int maf; // maf (mg/secx10) int kpa, // kpa (=map,mafmap or tps) fuelcor; // fuel composition correction - % unsigned char port_status, // Bits indicating spare port status. knk_rtd; // amount of ign retard (degx10) subtracted from normal advance. int XTfcor; // X,tau fuel correction,%, to ensure correct amount of fuel gets // to the combustion chamber. int egoV1,egoV2; // ego sensor readbacks in Vx100 unsigned int amc_updates; int spare[14]; unsigned long dt3; // delta t bet. rpm pulses (us) } variables; variables outpc, txbuf; #ifndef GCC_BUILD #pragma ROM_VAR OVF_ROM #endif typedef struct { unsigned int *addrRam; unsigned int *addrFlash; unsigned int n_bytes; } tableDescriptor; const tableDescriptor tables[NO_TBLES] = { { NULL, (unsigned int *)cltfactor_table, sizeof(cltfactor_table) }, { NULL, (unsigned int *)matfactor_table, sizeof(matfactor_table) }, { NULL, (unsigned int *)egofactor_table, sizeof(egofactor_table) }, { NULL, (unsigned int *)maffactor_table, sizeof(maffactor_table) }, { (unsigned int *)&inpram, (unsigned int *)&in1flash, sizeof(inputs1) }, { (unsigned int *)&in2ram, (unsigned int *)&in2flash, sizeof(inputs2) }, { (unsigned int *)&txbuf, NULL, sizeof(txbuf) } }; #ifndef GCC_BUILD #pragma ROM_VAR DEFAULT #endif #define tableInit(iTable) (void)memcpy(tables[iTable].addrRam, tables[iTable].addrFlash, tables[iTable].n_bytes) #define tableByteRam(iTable, iByte) ((unsigned char *)tables[iTable].addrRam + iByte) #define tableWordRam(iTable, iWord) (tables[iTable].addrRam + iWord) #define tableByteFlash(iTable, iByte) ((unsigned char *)tables[iTable].addrFlash + iByte) #define tableWordFlash(iTable, iWord) (tables[iTable].addrFlash + iWord) #define tableBytes(iTable) (tables[iTable].n_bytes) #define tableWords(iTable) ((tables[iTable].n_bytes+1)/2) // Round up // Prototypes - Note: ISRs prototyped above. void main(void) FAR_TEXT1_ATTR; void ign_reset(void); void get_adc(char chan1, char chan2); int move_IACmotor(void) TEXT1_ATTR; void fburner(unsigned int* progAdr, unsigned int* bufferPtr, unsigned int no_words) TEXT1_ATTR; int barocor_eq(int baro) TEXT1_ATTR; int aircor_eq(int mat) TEXT1_ATTR; void set_spr_port(char port, char val) TEXT1_ATTR; int coil_dur_table(int delta_volt) TEXT1_ATTR; int knk_thresh_calc(unsigned int rpm) TEXT1_ATTR; int intrp_2ditable(unsigned int x, int y, unsigned char nx, unsigned char ny, unsigned int * x_table, int * y_table, int * z_table) TEXT1_ATTR; void CanInit(void) TEXT1_ATTR; void can_xsub01(void) FAR_TEXT1_ATTR; void Flash_Init(unsigned long oscclk) TEXT1_ATTR; void Flash_Erase_Sector(unsigned int *address) FAR_TEXT1_ATTR; void Flash_Write_Word(unsigned int *address, unsigned int data) TEXT1_ATTR; #ifndef GCC_BUILD #pragma CODE_SEG OTHER_ROM #endif void tpsaen(void); void ego_calc(void); void amc(void); unsigned char afrLF_calc(long t) TEXT1_ATTR; #ifndef GCC_BUILD #pragma CODE_SEG DEFAULT #endif extern void reboot(void) FAR_TEXT1_ATTR; extern void monitor(void) FAR_TEXT1_ATTR; extern void SpSub(void); extern void NoOp(void); void main(void) { int ix; int tmp1,tmp2,tmp3,tmp4; unsigned int utmp1,utmp2,utmp3,ppw[2]; long lsum,lsum1,lsum2,beta,ltmp; unsigned long ultmp; int start_clt; unsigned int tcrank_done,tcold_pos,tASTol; char ctmp1,ctmp2,XTau0; unsigned char uctmp,mx_bnk; PPAGE = 0x3C; // initalize PLL - reset default is Oscillator clock // 8 MHz oscillator, PLL freq = 48 MHz, 24 MHz bus, // divide by 16 for timer of 2/3 usec tic PLLCTL &= 0xBF; // Turn off PLL so can change freq SYNR = 0x02; // set PLL/ Bus freq to 48/ 24 MHz REFDV = 0x00; PLLCTL |= 0x40; // Turn on PLL // wait for PLL lock while (!(CRGFLG & 0x08)); CLKSEL = 0x80; // select PLL as clock // wait for clock transition to finish for (ix = 0; ix < 60; ix++); // open flash programming capability Flash_Init(8000); //inp_spare used to force inpflash, flashve_table into sectors. // Must use in program or it won't use up the entire sector. POS CW // ignores the pragma making this stupid statement necessary. ix = in1padding[0]; ix = in2padding[0]; if((int)RamBurnPgm & 0x0001) { // odd address - cpy to even one (void)memcpy((void *)RamBurnPgm,NoOp,1); // cpy noop to 1st location (void)memcpy((void *)&RamBurnPgm[1],SpSub,32); // cpy flashburn core pgm to ram } else (void)memcpy((void *)RamBurnPgm,SpSub,32); // cpy flashburn core pgm to ram // load all user inputs from Flash to RAM tableInit(4); tableInit(5); // set up i/o ports // - port M2 is fast idle solenoid // - port M3 is inj led // - port M4 is accel led // - port M5 is warmup led // - port E0 is flex fuel sensor input // - port E4 is fuel pump // - port P5 is bootload pin (input) // - port T6 is IAC Coil A // - port T7 is IAC Coil B // - port B4 is IAC Enable // - port A0 is Knock Enable (if set, means retard timing) DDRM |= 0xFC; // port M - all outputs, full drive by default DDRE |= 0x10; // port E4 - output, E0 is input DDRT |= 0xC0; // port T6-7 - outputs DDRB |= 0x10; // port B4 - output DDRA |= 0x01; // port A0 - output // Set pointers to real port addresses for(ix = 0; ix < 8; ix++) { pPTMpin[ix] = pPTM; pPTTpin[ix] = pPTT; } pPTApin0 = pPORTA; // reset those pointers to pins which are to be used as alternate outputs outpc.port_status = 0; for(ix = 0;ix < NPORT; ix++) { if(inpram.spr_port[ix]) { // pin output from normal function goes to dumy reg in ram if(ix < 4) pPTMpin[ix + 2] = &dummyReg; else if(ix < 6) pPTTpin[ix + 2] = &dummyReg; else pPTApin0 = &dummyReg; set_spr_port((char)ix, inpram.init_val[ix]); lst_pval[ix] = inpram.init_val[ix]; } } // turn off fidle solenoid, leds *pPTMpin[2] &= ~0x04; *pPTMpin[3] &= ~0x08; *pPTMpin[4] &= ~0x10; *pPTMpin[5] &= ~0x20; PORTE &= ~0x10; // turn off fuel pump *pPTTpin[6] &= ~0xC0; // turn off IAC coils (do both pins[6,7] in 1 cmd) if(inpram.IdleCtl == 2) { PORTB |= 0x10; // disable current to motor (set bit= 1) } else { // IdleCtl = 3, 5 or no stepper motor (set bit = 0) PORTB &= ~0x10; // enable current to motor always(set bit= 0) } *pPTApin0 &= ~0x01; // no knock signal // set all unused (even unbonded) ports to inputs with pullups DDRA &= 0x01; DDRB &= 0x10; DDRE &= 0x10; PUCR |= 0x13; // enable pullups for ports E, B and A DDRP = 0x00; PERP = 0xFF; // enable pullup resistance for port P DDRJ &= 0x3F; PERJ |= 0xC0; // enable pullup resistance for port J6,7 DDRS &= 0xF3; PERS |= 0x0C; // enable pullup resistance for port S2,3 reinit_flag = 0; // set up CRG RTI Interrupt for .128 ms clock. CRG from 8MHz oscillator. mms = 0; // .128 ms tics millisec = 0; // 1.024 ms clock (8 tics) for adcs lmms = 0; cansendclk = 7812; ltch_lmms = 0; outpc.seconds = 0; // (1.0035) secs burn_flag = 0; amc_burn_flag = 0; RTICTL = 0x10; // load timeout register for .128 ms (smallest possible) CRGINT |= 0x80; // enable interrupt CRGFLG = 0x80; // clear interrupt flag (0 writes have no effect) // Set up SCI (rs232): SCI BR reg= BusFreq(=24MHz)/16/baudrate //inpram.baud = 115200; // Use this for debugging corrupted flash sectors. SCI0BDL = (unsigned char)(1500000/inpram.baud); ltmp = (150000000/inpram.baud) - ((long)SCI0BDL*100); if(ltmp > 50)SCI0BDL++; // round up //inpram.baud = in1flash.baud; // See above. SCI0CR1 = 0x00; SCI0CR2 = 0x24; // TIE=0,RIE = 1; TE=0,RE =1 txcnt = 0; rxcnt = 0; txmode = 0; txgoal = 0; rcv_timeout = 0xFFFFFFFF; // Initialize timers: // Note: Inj OC and PWM are Nanded. // -when turn on inj1 i/o, also enable pwm1 @ 100 % duty & // set pwm1 timer = 0 (.1 ms units). // -When pwm1 timer = InjPWMTim, set duty cycle to InjPWMDty. // -when done injecting, turn off inj1 i/o and pwm1. // TC0: Input capture (tach) - no pullup (default) for MSII // TC1: Output compare for injector output - bank 1 // TC2: PWM2 for injector bank 1 (or IC for 2nd ignition input) // TC3: Output compare for injector output - bank 2 // TC4: PWM4 for injector bank 2 (or OC for 2nd ignition output) // TC5: Ouput compare for 1st ignition output SPK = 1 - inpram.spkout_hi_lo; // 0=spk low, but inverted logic CHG = 1 - SPK; // after transistor // Set prescaler to 16. This divides bus clk (= PLLCLK/2 = 24 MHz) // by 16. This gives 1.5 MHz timer, 1 tic = 2/3 us. TSCR2 = 0x04; TSCR2 |= 0x80; // enable timer overflow interrupt (TOI) pTIC[0] = pTC0; ICintmask[0] = 0x01; pTOC[0] = pTC5; OCintmask[0] = 0x20; if(!inpram.DualSpkOptn) { TIOS |= 0x3E; // Timer ch 0 = IC, ch 1-5 = OC & PWM, // ch 6,7 = I/O output TCTL2 |= 0x88; // bit OM1,3,5 = 1. OC output line high or // low iaw OL1,3,5 (not toggle or disable) TCTL1 |= 0x08; TSCR2 |= 0x80; // enable timer overflow interrupt (TOI) // ensure not charging ignition coil TCTL1 = (TCTL1 & 0xFB) | (SPK << 2); // set OC o/p in OL5 CFORC |= 0x20; // force output in OL5 onto OC pin // Set up injector PWMs - PWM2, 4 MODRR = 0x14; // Make Port T pins 2,4 be PWM PWME = 0; // disable pwms initially PWMPOL = 0x14; // polarity = 1, => go hi when start PWMCLK = 0x14; // select scaled clocks SB, SA PWMPRCLK = 0x00; // prescale A,B clocks = bus = 24 MHz PWMSCLA = 0x0C; // pwm clk = SA clk/(2*SCLA) = 24MHz/24 = 1 us clk PWMSCLB = 0x0C; // pwm clk = SB clk/(2*SCLB) = 24MHz/24 = 1 us clk PWMCAE = 0x00; // standard left align pulse: ----- // | |______ // duty // <---period---> PWMPER2 = inpram.InjPWMPd; // set PWM period (us) PWMPER4 = inpram.InjPWMPd; // set PWM period (us) pTIC[1] = pTC0; ICintmask[1] = ICintmask[0]; pTOC[1] = pTC5; OCintmask[1] = OCintmask[0]; } else { PWME = 0; // disable pwms with dual/wasted/COP spark option pwm1_time = 0xFFFFFFFF; pwm2_time = 0xFFFFFFFF; TIOS |= 0x3A; // Timer ch 0,2 = IC, ch 1,3,4,5 = OC, // ch 6,7 = I/O output TCTL2 |= 0x88; // bit OM1,3,4,5 = 1. OC output line high or // low iaw OL1,3,4,5 (not toggle or disable) TCTL1 |= 0x0A; // ensure not charging ignition coils TCTL1 = (TCTL1 & 0xFA) | SPK | (SPK << 2); // set OC o/p in OL4, OL5 CFORC |= 0x30; // force output in OL4,OL5 onto OC pin pTIC[1] = pTC2; if(inpram.DualSpkOptn != 4) ICintmask[1] = 0x04; else ICintmask[1] = ICintmask[0]; pTOC[1] = pTC4; OCintmask[1] = 0x10; } ign_reset(); first_edis = 1; // IACStart = enough steps to set IAC wide open. // Set current IAC position to IACStart (all way closed), then move // to the 0 position (wide open - fast idle) and zero out. After // this all subsequent IAC commands will gradually close air passage // as clt temp rises. // Note: Ignore all move commands until finished current move. IdleCtl = inpram.IdleCtl; IAC_moving = 0; motor_step = -1; if(IdleCtl == 4) IACmotor_reset = 1; else IACmotor_reset = 0; outpc.iacstep = inpram.IACStart; // set current motor step position // to closed since don't have actual position. IACmotor_pos = 0; // command motor step position to wide open if((IdleCtl > 1) && (IdleCtl != 4)) (void)move_IACmotor(); last_iacclt = -3200; iacpwmctr = 0; // set up ADC processing // ATD0 // - AN0 is MAP or MAF (MAFOption = 1, MAFPin = 0) // - AN1 is MAT // - AN2 is CLT // - AN3 is TPS // - AN4 is BAT // - AN5 is EGO1 (NB or WB) // - AN6 is Spare or BARO (BaroOption =2) or EGO2 (EgoOption = 2 or 4) // or MAF (MAFOption = 2, MAFPin = 1). // - AN7 is Spare or KNOCK or MAF (MAFOption = 2, MAFPin = 2). // Set up ADCs so they continuously convert, then read result registers // every millisecond MAFPin = (inpram.MAFOption & 0xF0) >> 4; next_adc = 0; // specifies next adc channel to be read ATD0CTL2 = 0x40; // leave interrupt disabled, set fast flag clear ATD0CTL3 = 0x00; // do 8 conversions/ sequence ATD0CTL4 = 0x67; // 10-bit resoln, 16 tic cnvsn (max accuracy), // prescaler divide by 16 => 2/3 us tic x 18 tics ATD0CTL5 = 0xB0; // right justified,unsigned, continuous cnvsn, // sample 8 channels starting with AN0 ATD0CTL2 |= 0x80; // turn on ADC0 // wait for ADC engine charge-up or P/S ramp-up for(ix = 0; ix < 160; ix++) { while(!(ATD0STAT0 >> 7)); // wait til conversion complete ATD0STAT0 = 0x80; } // get all adc values first_adc = 1; get_adc(0,7); first_adc = 0; if((inpram.BaroOption == 0) || (inpram.MAFOption == 1)) outpc.baro = 1000; // kPa x 10 else if(inpram.BaroOption == 1) { outpc.baro = outpc.map; // kPa x 10 // limit baro in case reset while car running if(outpc.baro < 800) outpc.baro = 800; else if(outpc.baro > 1200) outpc.baro = 1200; } adc_lmms = lmms; // Initialize variables flocker = 0; if(!inpram.DualSpkOptn) { if(inpram.EngStroke == 0) // 4 stroke Rpm_Coeff = 120000000; else // 2 stroke Rpm_Coeff = 60000000; } else { // Dual spark Rpm_Coeff = 120000000; } Rpm_Coeff /= inpram.no_cyl; pw_open = inpram.InjOpen; pwcalc1 = 0; // us outpc.pw1 = pwcalc1; pwcalc2 = 0; // us outpc.pw2 = pwcalc2; XTM = 0; XTcalc = 1; outpc.adv_deg = 0; // crank deg x 10 ic_adv_deg = outpc.adv_deg - inpram.adv_offset; coil_dur = inpram.max_coil_dur; // msx10 coil_dur_set = coil_dur * 100; // us outpc.coil_dur = coil_dur; // msx10 tASTol = 0; PulseTol = inpram.CrnkTol; outpc.kpa = outpc.map; // kPa x 10 kpaix = outpc.kpa; if(!in2ram.VEIXOptn) kpadiv = outpc.baro; else kpadiv = 1000; last_tps = outpc.tps; // % x 10 if((inpram.MAFOption & 0x0F) != 1) last_map = outpc.map; // kPa x 10 else last_map = 1000; // kpa x 10 if(inpram.EgoOption <= 2) outpc.afrtgt1 = 45; // Vx100 else outpc.afrtgt1 = 147; // afr x 10 outpc.afrtgt2 = outpc.afrtgt1; outpc.aircor = 100; outpc.vecurr1 = 100; outpc.vecurr2 = outpc.vecurr1; outpc.barocor = 100; outpc.warmcor = 100; outpc.cold_adv_deg = 0; // crank deg x 10 outpc.wbo2_en1 = 1; outpc.wbo2_en2 = 1; outpc.egocor1 = 100; outpc.egocor2 = 100; outpc.tpsfuelcut = 100; outpc.gammae = 100; outpc.XTfcor = 100; outpc.tpsaccel = 0; tcrank_done = 0xFFFF; tcold_pos = 0xFFFF; FSensStat = 0; FSens_Pd = 0; outpc.fuelcor = 100; // % ffspkdel = 0; // degx10 AMCmode = 0; AMCclk = 0; ego_cloop = 0; bad_ego_flag = 0; AMCram_updates = 0; outpc.amc_updates = 0; AMCburn_clk = outpc.seconds; tooth_no = 0; last_tooth = inpram.No_Teeth - inpram.No_Miss_Teeth; // best tooth to do flash erase if(inpram.No_Teeth > 30) burn_tooth_no = (3 * inpram.No_Teeth) / 4; else if(inpram.No_Teeth > 0) burn_tooth_no = last_tooth; else burn_tooth_no = 0; first_clt = 1; MAFCoef = 6184075; if(inpram.CID) MAFCoef /= inpram.CID; /* set variable block addresses to be used for CAN communications */ canvar_blkptr[0] = (char *)&inpram; canvar_blkptr[1] = (char *)&outpc; for(ix = 2;ix < NO_VAR_BLKS; ix++) { // rest spares for now canvar_blkptr[ix] = 0; } /* Initialize CAN comms */ can_reset = 0; can_id = 0; // MS-II is processor 0 CanInit(); // make IC highest priority interrupt HPRIO = 0xEE; // enable global interrupts ENABLE_INTERRUPTS // Check for Injector Test Mode: Squirt n pulses of duration pw us, then // wait until: MT repeat cmd (will repeat the squirts) or user clears // InjTestOption in MT, which will cause reboot back to normal operation. // To remain in test mode, leave Test Mode on, burn ecu, and turn off power. RESTRT_IT: if(inpram.InjTestOption) { utmp1 = 0; outpc.pw1 = inpram.InjTestPW; outpc.pw2 = outpc.pw1; outpc.engine = 0x01; PORTE |= 0x10; // Turn on fuel pump IT_SCHED: TIE &= 0xFE; // disable ign IC // Turn On Inj1 and 2 TCTL2 |= 0x44; // set output hi in OL1,OL3 CFORC |= 0x0A; // force high *pPTMpin[3] |= 0x08; // turn on inj led outpc.squirt |= 0x03; // inj1,2 squirting PWMPER2 = inpram.InjPWMPd; // set PWM period (us) PWMPER4 = inpram.InjPWMPd; // set PWM period (us) PWMDTY2 = PWMPER2; // set PWM duty to 100 % PWMDTY4 = PWMPER4; // set PWM duty to 100 % pwm1_on = 0; DISABLE_INTERRUPTS ultmp = lmms; ENABLE_INTERRUPTS pwm1_time = ultmp + ((inpram.InjPWMTim*8)/10); // .128 ms pwm2_on = 0; pwm2_time = ultmp + ((inpram.InjPWMTim*8)/10); // .128 ms PWMCNT2 = 0x00; // clear counter PWMCNT4 = 0x00; // clear counter PWME |= 0x14; // enable PWM2, 4 // Set up to turn Off Inj1,2 when get to pw us Fl1TimerComp = TCNT + ((3*(long)inpram.InjTestPW)>>1); // 2/3 us Fl2TimerComp = Fl1TimerComp; Fl1OCt_overflow = (unsigned short)(Fl1TimerComp >> 16); Fl2OCt_overflow = Fl1OCt_overflow; TC1 = (unsigned short)(Fl1TimerComp & 0xFFFF); // load OC compare reg TC3 = TC1; if(Fl1OCt_overflow <= 1) { // don't need to handle <= 1 overflow because TCNT will not // = TimerComp until after the overflow as long as pw < ~43 ms Fl1OCt_overflow = 0; Fl2OCt_overflow = 0; TCTL2 = TCTL2 & 0xBB; // set output lo in OL1, OL3 TIE |= 0x0A; // Enable Inj1,2 OC interrupt TFLG1 = 0x0A; // clear OC interrupt flags } else { // Disable Inj1,2 OC interrupt until ovflows done // do below to allow enough time to set OC pin in overflow isr if(TC1 < 30)TC1 = 30; if(TC3 < 30)TC3 = 30; TIE &= ~0x0A; } // wait til injections done - indicated when pins go low while((PTIT & 0x0A)); // wait specified time off DISABLE_INTERRUPTS ultmp = lmms; ENABLE_INTERRUPTS ltch_lmms = ultmp; for (;;) { while(lmms == ultmp); // wait til increments if((((lmms - ltch_lmms) * 128) / 100) > inpram.InjTestOff) // msx10 break; ultmp = lmms; } utmp1++; if(utmp1 < inpram.InjTestNoSqrts) goto IT_SCHED; PORTE &= ~0x10; // Turn off fuel pump while(inpram.InjTestOption == 1); // wait for user command if(inpram.InjTestOption > 1) { // repeat test inpram.InjTestOption = 1; goto RESTRT_IT; } else { // Test mode turned Off - want to reboot for norm operation // if flash changed, reburn to 0 which is the ram value if(in1flash.InjTestOption) { // burn flash 512 byte(256 word) sector(s) burn_flag = 1; flocker = 0xCC; while(burn_flag <= tableWords(4)) { fburner(tableWordFlash(4, 0), tableWordRam(4, 0), tableWords(4)); burn_flag++; } (void)reboot(); } } } // Set up COP timeout for main loop COPCTL = 0x44; // 131 ms timeout for reboot // Prime Pulse - shoot 1 prime pulse of length PrimeP ms x 10 start_clt = outpc.clt; if(!inpram.CWOption) { if(outpc.clt >= inpram.temp_table[NO_TEMPS-1]) { PrimeP = (unsigned short)inpram.PrimePH; AWEV = (unsigned short)inpram.AWEVH; AWC = (unsigned short)inpram.AWCH; } else if(outpc.clt <= inpram.temp_table[0]) { PrimeP = (unsigned short)inpram.PrimePU; AWEV = (unsigned short)inpram.AWEVU; AWC = (unsigned short)inpram.AWCU; } else { ltmp = (outpc.clt - inpram.temp_table[0]) * (long)(inpram.PrimePH - inpram.PrimePU); PrimeP = (unsigned short)(inpram.PrimePU + (ltmp / (inpram.temp_table[NO_TEMPS-1] - inpram.temp_table[0]))); // msx10 ltmp = (outpc.clt - inpram.temp_table[0]) * (long)(inpram.AWEVH - inpram.AWEVU); AWEV = (unsigned short)(inpram.AWEVU + (ltmp / (inpram.temp_table[NO_TEMPS-1] - inpram.temp_table[0]))); // % ltmp = (outpc.clt - inpram.temp_table[0]) * (long)(inpram.AWCH - inpram.AWCU); AWC = (unsigned short)(inpram.AWCU + (ltmp / (inpram.temp_table[NO_TEMPS-1] - inpram.temp_table[0]))); // cycles } } else { // custom warmup tables PrimeP = (unsigned short)CW_table(outpc.clt,in2ram.CWPrime); // msx10 AWEV = (unsigned short)CW_table(outpc.clt,in2ram.CWAWEV); // % AWC = (unsigned short)CW_table(outpc.clt,in2ram.CWAWC); // cycles } if(PrimeP) { outpc.pw1 = PrimeP * 100; // us outpc.pw2 = outpc.pw1; // Turn on fuel pump PORTE |= 0x10; // Turn On injectors & PWMs TCTL2 |= 0x44; // set outputs hi in OL1,3 CFORC |= 0x0A; // force high // set PWM duty (on time) to 100 % if(!inpram.DualSpkOptn) { PWMDTY2 = PWMPER2; PWMDTY4 = PWMDTY2; pwm1_on = 0; pwm1_time = 0; pwm2_on = 0; pwm2_time = 0; PWMCNT2 = 0x00; PWMCNT4 = 0x00; PWME |= 0x14; // enable PWMs } // Set up to turn Off injectors when get to pw us Fl1TimerComp = TCNT + ((3*(long)outpc.pw1)>>1); // 2/3 us TCTL2 &= ~0x44; // set outputs lo in OL1,3 Fl1OCt_overflow = Fl1TimerComp >> 16; Fl1TimerComp &= 0xFFFF; Fl2TimerComp = Fl1TimerComp; Fl2OCt_overflow = Fl1OCt_overflow; TC1 = (unsigned short)Fl1TimerComp; // load OC compare register TC3 = (unsigned short)Fl2TimerComp; // load OC compare register if(Fl1OCt_overflow <= 1) { Fl1OCt_overflow = 0; Fl2OCt_overflow = 0; // Enable OC interrupt TIE |= 0x0A; } else { // Disable OC interrupt TIE &= ~0x0A; TFLG1 = 0x0A; // clear OC interrupt flag } // turn on inj led *pPTMpin[3] |= 0x08; outpc.squirt |= 0x03; // both injectors squirting outpc.engine |= 0x01; // engine in ready to run status // Note: prime pulse should be over (65 ms max) before cranking starts } // main loop for (;;) { DISABLE_INTERRUPTS ultmp = lmms; ENABLE_INTERRUPTS if((ultmp - adc_lmms) > 78) { // every 10 ms (78 x .128 ms clk) adc_lmms = ultmp; // read 10-bit ADC results, convert to engineering units and filter next_adc++; if(next_adc > 7)next_adc = 1; switch(next_adc) { case 0: // skip map/ maf (in Timer_Clk Int) case 3: // skip tps (in Timer_Clk Int) case 5: // do ego1 in ego algorithm break; case 1: case 2: case 4: get_adc(next_adc,next_adc); // get one channel on each pass break; case 6: // do ego2 in ego algorithm, maf in Timer_Clk Int if(inpram.BaroOption == 2) get_adc(next_adc,next_adc); // get one channel on each pass break; case 7: // if knock option selected, do in knock algorithm, // do maf in Timer_Clk Int if(!(inpram.knk_option & 0x0F) && (inpram.MAFOption != 0x22)) get_adc(next_adc,next_adc); // get one channel on each pass } // end switch } if(inpram.BaroOption == 0) { outpc.barocor = 100; } else { // barometric correction (%) outpc.barocor = barocor_eq(outpc.baro) + intrp_1dctable(1, outpc.baro, NO_BARS, in2ram.BaroVals, 1, (unsigned char *)in2ram.BaroCorDel); } // airdensity correction (%) outpc.aircor = aircor_eq(outpc.mat) + intrp_1dctable(1, outpc.mat, NO_MATS, in2ram.MatVals, 1, (unsigned char *)in2ram.AirCorDel); // clear COP timeout counter ARMCOP = 0x55; ARMCOP = 0xAA; // If using MAF, calculate equivalent MAF pressure, mafmap (kpax10) if(inpram.MAFOption & 0x0F) { // calculate corrected maf here to avoid interp in ISR utmp1 = intrp_1dctable(0, (int)mafraw, NO_MAFS, (int *)in2ram.MAFFlow, 0, in2ram.MAFCor); asm { ldy mafraw ldd utmp1 EMUL ldx #100 EDIV sty outpc.maf }; if(outpc.rpm > 0) { mafmap = (int)(((MAFCoef / outpc.aircor) * outpc.maf) / outpc.rpm); if(mafmap < 100) mafmap = 100; } else { mafmap = 1000; } if((inpram.MAFOption & 0x0F) == 2) { if(in2ram.MAFDir == 0) { if(outpc.rpm <= in2ram.MAFRPM1) { mafmap = outpc.map; // use map at low rpm blend = 1; } else if(outpc.rpm < in2ram.MAFRPM2) { // use maf, map blend tmp1 = (in2ram.MAFRPM2 - outpc.rpm); tmp2 = (outpc.rpm - in2ram.MAFRPM1); tmp3 = (in2ram.MAFRPM2 - in2ram.MAFRPM1); mafmap = (int)((((long)tmp1 * outpc.map) + ((long)tmp2 * mafmap)) / tmp3); blend = 2; } else { // else leave mafmap as calculated blend = 3; } } else { if(outpc.rpm > in2ram.MAFRPM2) { mafmap = outpc.map; // use map at high rpm blend = 1; } else if(outpc.rpm > in2ram.MAFRPM1) { // use maf, map blend tmp1 = (outpc.rpm - in2ram.MAFRPM1); tmp2 = (in2ram.MAFRPM2 - outpc.rpm); tmp3 = (in2ram.MAFRPM2 - in2ram.MAFRPM1); mafmap = (int)((((long)tmp1 * outpc.map) + ((long)tmp2 * mafmap)) / tmp3); blend = 2; } else { // else leave mafmap as calculated blend = 3; } } } // end MAFOptn = 2 } // end MAFOptions else mafmap = outpc.map; // needed for alpha-N processing /* Determine if in Speed-density or Alpha-N mode. If in Alpha-N mode, set the variable "kpa" = "tps". This will not break anything, since this check is performed again when multiplying MAP against the enrichments, and the SCI version of the variable is MAP, not kpa. */ if(!(inpram.FuelAlpha & 0x0F)) { outpc.kpa = mafmap; // kpa x 10 } else { switch((inpram.FuelAlpha & 0xF0) >> 4) { case 0: // use alphaN if rpm < lorpm, map or maf if rpm > hirpm if(outpc.rpm < inpram.alpha_lorpm) { outpc.kpa = intrp_2ditable(outpc.rpm,outpc.tps, NO_ARPMS, NO_ATPSS, &inpram.amap_rpm[0],&inpram.amap_tps[0],&inpram.alpha_map_table[0][0]); // kpa x 10 } else if(outpc.rpm > inpram.alpha_hirpm) { outpc.kpa = mafmap; // kpa x 10 } else { beta = ((long)100 * (outpc.rpm - inpram.alpha_lorpm)) / (inpram.alpha_hirpm - inpram.alpha_lorpm); tmp4 = (short)((intrp_2ditable(inpram.alpha_lorpm,outpc.tps,NO_ARPMS, NO_ATPSS,&inpram.amap_rpm[0],&inpram.amap_tps[0], &inpram.alpha_map_table[0][0]) * (100 - beta)) / 100); outpc.kpa =(short)(tmp4 + ((mafmap * beta) / 100)); } break; case 1: // use alphaN if rpm > hirpm, map or maf if rpm < lorpm if(outpc.rpm > inpram.alpha_hirpm) { outpc.kpa = intrp_2ditable(outpc.rpm,outpc.tps, NO_ARPMS, NO_ATPSS, &inpram.amap_rpm[0],&inpram.amap_tps[0],&inpram.alpha_map_table[0][0]); // kpa x 10 } else if(outpc.rpm < inpram.alpha_lorpm) { outpc.kpa = mafmap; // kpa x 10 } else { beta = ((long)100 * (outpc.rpm - inpram.alpha_lorpm)) / (inpram.alpha_hirpm - inpram.alpha_lorpm); tmp4 = (short)((intrp_2ditable(inpram.alpha_hirpm,outpc.tps,NO_ARPMS, NO_ATPSS,&inpram.amap_rpm[0],&inpram.amap_tps[0], &inpram.alpha_map_table[0][0]) * beta) / 100); outpc.kpa =(short)(tmp4 + ((mafmap * (100 - beta)) / 100)); } break; } // end switch } if(!in2ram.VEIXOptn) { kpaix = outpc.kpa; // baro correction not in index switch(inpram.MAFOption & 0x0F) { case 0: // use pw= ...../baro kpadiv = outpc.baro; break; case 1: // maf only or baro, use pw= ..../1000 kpadiv = 1000; break; case 2: if(blend == 1) kpadiv = outpc.baro; else if(blend == 2) kpadiv = (int)((((long)tmp1 * outpc.baro) + ((long)tmp2 * 1000)) / tmp3); else kpadiv = 1000; break; }; } else { // baro correction in index asm { ldy outpc.kpa ldd #1000 EMULS ldx outpc.baro EDIVS sty tmp4 }; if(blend == 1) // use (kpa*1000)/baro as index to ve, spk, tau tbles + AMC indx kpaix = tmp4; else if(blend == 2) // blend (kpa*1000)/baro and kpa index kpaix = (int)((((long)tmp1 * tmp4) + ((long)tmp2 * outpc.kpa)) / tmp3); else kpaix = outpc.kpa; kpadiv = 1000; } // check rpm for stall condition (< 50 rpm) after engine synch DISABLE_INTERRUPTS tmp1 = (int)(lmms - ltch_lmms); ENABLE_INTERRUPTS if(synch == END_SYNCH) { if(tmp1 > (18750/inpram.no_cyl)) { // Engine is stalled, reset ign_reset(); // if coil charging, set flg to cease aft 1 s if no resynch // re-do this outside ign_reset so can force lmms is atomic DISABLE_INTERRUPTS t_chgoff = lmms + 7812; ENABLE_INTERRUPTS } } // if no tach pulse within 2 sec else if(tmp1 > 15625) { PORTE &= ~0x10; // Turn off fuel pump *pPTMpin[2] &= ~0x04; // Turn off fast idle ** Bug Fix By Guy Hill ** } // check idle control if(IdleCtl == 1) { if(outpc.clt < inpram.FastIdle) *pPTMpin[2] |= 0x04; // turn on fast idle solenoid if(outpc.clt < inpram.FastIdle - inpram.IdleHyst) *pPTMpin[2] |= 0x04; // turn on fast idle solenoid else if(outpc.clt > inpram.FastIdle) *pPTMpin[2] &= ~0x04; // turn off fast idle solenoid } else if(IACmotor_reset && ((IdleCtl >= 2) && (IdleCtl <= 5))) { // In cranking mode if((outpc.rpm > 0) && (outpc.rpm < inpram.crank_rpm)) { tmp1 = CW_table(outpc.clt,inpram.iacstep_table); if(tmp1 > inpram.IACcrankpos) { tmp1 = inpram.IACcrankpos; // want IAC open at // least this much during cranking regardless of temp } IACmotor_pos = tmp1; } // after cranking flare back to normal temperature dependent pos else if((outpc.seconds >= tcrank_done) && (outpc.seconds <= tcrank_done + inpram.IACcrankxt)) { // 0 steps is fully open (fast idle) and IACStart steps is fully closed tmp1 = CW_table(outpc.clt,inpram.iacstep_table); if(tmp1 > inpram.IACcrankpos) { tmp2 =(int)((long)(inpram.IACcrankpos - tmp1) * (tcrank_done + inpram.IACcrankxt - outpc.seconds) / inpram.IACcrankxt); tmp1 += tmp2; } IACmotor_pos = tmp1; } // switch to time based control if cold enough at startup else if((outpc.seconds >= tcold_pos) && (outpc.seconds <= tcold_pos + inpram.IACcoldxt)) { tmp1 = CW_table(outpc.clt,inpram.iacstep_table); if(tmp1 > inpram.IACcoldpos) { tmp2=(int)((long)(inpram.IACcoldpos - inpram.iacstep_table[NO_TEMPS-1]) *(tcold_pos + inpram.IACcoldxt - outpc.seconds) /inpram.IACcoldxt); tmp1 = inpram.iacstep_table[NO_TEMPS-1] + tmp2; } IACmotor_pos = tmp1; } // check if there has been a significant change in clt temp else if((outpc.clt < last_iacclt - inpram.IdleHyst) || (outpc.clt > last_iacclt)) { IACmotor_pos = CW_table(outpc.clt,inpram.iacstep_table); } if(outpc.iacstep != IACmotor_pos) { // move IAC motor to new step position if(IdleCtl != 4) { if(move_IACmotor()) last_iacclt = outpc.clt; } else last_iacclt = outpc.clt; } // check if/ when to start extended time-based idle control if(start_clt < inpram.IACcoldtmp) { if((outpc.seconds > tcrank_done) && (tcold_pos == 0xFFFF) && (IACmotor_pos > inpram.IACcoldpos)) tcold_pos = outpc.seconds; } if((inpram.IdleCtl == 5) && (outpc.seconds > 900)) { IdleCtl = 2; if(!IAC_moving) PORTB |= 0x10; // disable current to stepper motor(bit=1) } } // check for stall if(((outpc.engine & 0x01) == 0) || (outpc.rpm == 0))goto BURN_FLASH; /************************************************************************** ** ** Cranking Mode ** ** Pulsewidth is directly set by the coolant temperature to a value of ** CWU (at temp_table[0]) and CWH (at temp_table[NO_TEMPS -1]). ** The value is interpolated at clt. ** **************************************************************************/ if(outpc.rpm < inpram.crank_rpm) { PulseTol = inpram.CrnkTol; tcrank_done = 0xFFFF; outpc.engine |= 0x02; // set cranking bit outpc.engine &= ~0x0C; // clr starting warmup bit & warmup bit if(outpc.tps > inpram.TPSWOT) { pwcalc1 = 300; // usec (.3 ms for Flood Clear) pwcalc2 = pwcalc1; goto KNK; } if(!inpram.CWOption) { // KJW if outside the interpolation range, rail to CWU or CWH as // appropriate, else interpolate if(outpc.clt >= inpram.temp_table[NO_TEMPS-1]) pwcalc1 = (unsigned short)inpram.CWH * 100; else if(outpc.clt <= inpram.temp_table[0]) pwcalc1 = (unsigned short)inpram.CWU * 100; else { ltmp = (outpc.clt - inpram.temp_table[0]) * (long)(inpram.CWH - inpram.CWU) * 100; pwcalc1 = (unsigned short)(inpram.CWU * (long)100 + (ltmp / (inpram.temp_table[NO_TEMPS-1] - inpram.temp_table[0]))); // usec } } else { // custom warmup table pwcalc1 = (unsigned short)CW_table(outpc.clt,in2ram.CWCPW) * 100; // usec } pwcalc2 = pwcalc1; goto KNK; } else if(tcrank_done == 0xFFFF)tcrank_done = outpc.seconds; /************************************************************************** ** ** Warm-up and After-start Enrichment Section ** ** The Warm-up enrichment is a linear interpolated value for the current clt ** temperature from warmen_table[NO_TEMPS] vs temp_table[NO_TEMPS]. The ** interpolation is done in subroutine warmcor_table. ** ** Also, the after-start enrichment value is calculated and applied here - it ** is an added percent value on top of the warmup enrichment, and it is applied ** for the number of ignition cycles specified in AWC. This enrichment starts ** at a value of AWEV at first, then it linearly interpolates down to zero ** after AWC cycles. ** ** If (startw, engine is set) then: ** compare if (AWC > 0) then: ** interpolate for warmup enrichment ** else clear startw bit in engine ** **************************************************************************/ wrmtmp = outpc.warmcor; if(outpc.engine & 0x02) { // if engine cranking outpc.engine &= ~0x02; // clear crank bit outpc.engine |= 0x0C; // set starting warmup bit & warmup bit asecount = 0; PulseTol = inpram.ASTol; tASTol = outpc.seconds; } wrmtmp = intrp_1dctable(1, outpc.clt, NO_TEMPS, inpram.temp_table, 0, inpram.warmen_table); // % outpc.cold_adv_deg = CW_table(outpc.clt,inpram.cold_adv_table); // deg x 10 if(wrmtmp == 100) { // done warmup outpc.engine &= ~0x0C; // clear start warmup bit & warmup bit *pPTMpin[5] &= ~0x20; // clear warmup led if(outpc.seconds > tASTol + 5) PulseTol = inpram.PulseTol; goto END_WRM; } *pPTMpin[5] |= 0x20; // set warmup led outpc.engine |= 0x08; // set warmup bit if(!(outpc.engine & 0x04)) // if starting warmup bit clear goto END_WRM; if(asecount > AWC) { outpc.engine &= ~0x04; // clear start warmup bit if(outpc.seconds > tASTol + 5) PulseTol = inpram.PulseTol; goto END_WRM; } if(AWC > 0) { utmp1 = AWEV * asecount; wrmtmp += (AWEV - (utmp1 / AWC)); } END_WRM: outpc.warmcor = wrmtmp; /************************************************************************** ** ** Throttle Position Acceleration Enrichment ** **************************************************************************/ switch_page(3,0,0); // call tpsaen in page 3D /************************************************************************** ** ** Exhaust Gas Oxygen Sensor Measurement Section ** **************************************************************************/ switch_page(0,0,0); // call ego_calc in page 3D /************************************************************************** ** ** Automatic Mixture Control - enter once a second ** ***************************************************************************/ if(inpram.AMCOption) { switch_page(2,0,0); // call amc in page 3D } // AMC option selected /************************************************************************** ** ** Computation of Fuel Parameters ** Note that GAMMAE only includes Warm, Tpsfuelcut, Barocor, and Aircor ** (EGO no longer included) ** **************************************************************************/ lsum = ((outpc.warmcor * outpc.tpsfuelcut) / 100); lsum = (lsum * ((outpc.barocor * outpc.aircor) / 100)/100); outpc.gammae = (int)lsum; if((inpram.FuelAlpha & 0x0F) != 2) lsum2 = (long)outpc.kpa; else lsum2 = 1000; // normalizes to ~1 when divide by baro or 1000 if((inpram.MAFOption & 0x0F) == 1) { // pure maf blendve1 = 100; blendve2 = 100; } else { // pure map or maf/ map blend // Look up volumetric efficiency as function of rpm and map/ mafmap/ tps // (in alpha N mode) or (kpa * 1000) / baro blendve1 = intrp_2dctable(outpc.rpm, kpaix, NO_FRPMS, NO_FMAPS, &inpram.frpm_table[0], &inpram.fmap_table[0], &in2ram.ve_table[0][0][0]); // % if(inpram.dual_tble_optn) blendve2 = intrp_2dctable(outpc.rpm, kpaix, NO_FRPMS, NO_FMAPS, &inpram.frpm_table[0], &inpram.fmap_table[0], &in2ram.ve_table[1][0][0]); // % else blendve2 = blendve1; if((inpram.MAFOption & 0x0F) == 2) { // maf/ map blend ve if(in2ram.MAFDir == 0) { // map at lo rpm if((outpc.rpm > in2ram.MAFRPM1) && (outpc.rpm < in2ram.MAFRPM2)) { // use blend blendve1 = (int)((((long)(in2ram.MAFRPM2 - outpc.rpm) * blendve1) + ((long)(outpc.rpm - in2ram.MAFRPM1) * 100)) / (in2ram.MAFRPM2 - in2ram.MAFRPM1)); blendve2 = (int)((((long)(in2ram.MAFRPM2 - outpc.rpm) * blendve2) + ((long)(outpc.rpm - in2ram.MAFRPM1) * 100)) / (in2ram.MAFRPM2 - in2ram.MAFRPM1)); } else if(outpc.rpm > in2ram.MAFRPM2) { blendve1 = 100; blendve2 = 100; } } else { // map at hi rpm if(outpc.rpm < in2ram.MAFRPM1) { blendve1 = 100; blendve2 = 100; } else if((outpc.rpm > in2ram.MAFRPM1) && (outpc.rpm < in2ram.MAFRPM2)) { // use blend blendve1 = (int)((((long)(in2ram.MAFRPM2 - outpc.rpm) * 100) + ((long)(outpc.rpm - in2ram.MAFRPM1) * blendve1)) / (in2ram.MAFRPM2 - in2ram.MAFRPM1)); blendve2 = (int)((((long)(in2ram.MAFRPM2 - outpc.rpm) * 100) + ((long)(outpc.rpm - in2ram.MAFRPM1) * blendve2)) / (in2ram.MAFRPM2 - in2ram.MAFRPM1)); } } } // end maf/ map blendve } // end pure map or maf/ map blend outpc.vecurr1 = blendve1; outpc.vecurr2 = blendve2; lsum1 = (lsum * ((outpc.egocor1 * lsum2) / kpadiv)/100); lsum1 = (lsum1 * ((outpc.vecurr1 * (long)inpram.ReqFuel)/ 100)/ 100); // usec lsum2 = (lsum * ((outpc.egocor2 * lsum2) / kpadiv)/100); lsum2 = (lsum2 * ((outpc.vecurr2 * (long)inpram.ReqFuel)/ 100)/ 100); // usec if(inpram.AFRMult) { // factor in AFRTgt if this facilitates tuning lsum1 = (lsum1 * inpram.AFRStoich) / outpc.afrtgt1; lsum2 = (lsum2 * inpram.AFRStoich) / outpc.afrtgt2; } /************************************************************************** ** ** Calculation of Battery Voltage Correction for Injector Opening Time ** ** Injector open time is implemented as a linear function of ** battery voltage, from 7.2 volts to 19.2 volts, ** with 13.2 volts being the nominal operating voltage ** ** INJOPEN = injector open time at 13.2 volts in ms x 10 ** BATTFAC = injector open adjustment factor 6 volts from 13.2V in ms x 10 ** ** ** + (INJOPEN + BATTFAC) ** + * ** + (INJOPEN) ** + * ** + (INJOPEN - BATTFAC) ** + * ** + ** ++++++++++++++++++++++++++++++++++++++++++++++++++++++ ** 7.2V 13.2V 19.2 ** **************************************************************************/ tmp1 = (inpram.InjOpen + inpram.BatFac) - ((inpram.BatFac * (outpc.batt - 72)) / 60); // ms x 10 if(tmp1 > 0) pw_open = (unsigned int)tmp1; // if < 0, => bat spike, use prior val. /************************************************************************** ** ** Calc. of Flex Fuel Sensor %alcohol and PW,spk correction (fuelcor,ffspkdel) ** **************************************************************************/ if(inpram.FlexFuel && (FSens_Pd > 0)) { FSensFreq = (int)(7812 / FSens_Pd); // Hz, (FSens_Pd in .128 tics) if((FSensFreq >= 10) || (FSensFreq <= 300)) { outpc.fuelcor = inpram.fuelCorr[0] + (((short)(FSensFreq - inpram.fuelFreq[0]) * (inpram.fuelCorr[1] - inpram.fuelCorr[0])) / (inpram.fuelFreq[1] - inpram.fuelFreq[0])); // % ffspkdel = inpram.ffSpkDel[0] + (((char)(FSensFreq - inpram.fuelFreq[0]) * (inpram.ffSpkDel[1] - inpram.ffSpkDel[0])) / (inpram.fuelFreq[1] - inpram.fuelFreq[0])); // degx10 } else { // sensor reading bad - use default outpc.fuelcor = 100; // % ffspkdel = 0; // degx10 } lsum1 = (lsum1 * outpc.fuelcor)/ 100; // usec lsum2 = (lsum2 * outpc.fuelcor)/ 100; // usec } else { // no flex fuel or fuel sensor not yet ready/ broken outpc.fuelcor = 100; // % ffspkdel = 0; // degx10 } /************************************************************************** ** ** Calculation of Fuel Pulse Width ** **************************************************************************/ if(!in2ram.XTauOption || XTcalc) { lsum = (pw_open + outpc.tpsaccel) * 100; // usec if((lsum1 > 0) && !cut_fuel) { lsum1 += lsum; // usec if(lsum1 > 32000)lsum1 = 32000; // rail at 32 ms ppw[0] = (unsigned int)lsum1; } else { ppw[0] = 0; } if((lsum2 > 0) && !cut_fuel) { lsum2 += lsum; // usec if(lsum2 > 32000)lsum2 = 32000; ppw[1] = (unsigned int)lsum2; } else { ppw[1] = 0; } if(ppw[0] >= ppw[1]) mx_bnk = 0; else mx_bnk = 1; if(ppw[mx_bnk] == 0) { // no fuel - skip x-tau pwcalc1 = 0; pwcalc2 = 0; outpc.XTfcor = 100; if(XTcalc == 2) XTcalc = 0; // clear flag - will be reset on next tach pulse goto KNK; } } /************************************************************************** ** ** X,Tau Transient Enrichment Section: ** ** fi = [ mi - (Mi / (tau / dltau)) ] / (1 - X) ** ** Mi+1 = Mi + X * fi - (Mi / (tau / dltau)) ** ** where, ** fi = total fuel injected ** ** mi = total fuel going directly into combustion chamber (want this ** to be the calculated fuel) ** ** Mi = net fuel entering/leaving port wall puddling ** ** dltau = time (secx100) between tach pulses = dtpred in secx100 ** ** X = fraction of fuel injected which goes into port wall puddling ** tau = puddle fuel dissipation time constant (secx100) as function ** of map, rpm, coolant temp and air temp. ** ** XTfcor = % correction to calculated fuel to ensure the calculated ** amount gets into the comb chamber. ** **************************************************************************/ if(in2ram.XTauOption && (XTcalc == 2)) { // calculate tau as function of map,rpm,clt,mat (in secx100) tmp1 = in2ram.XTScl * intrp_2dctable(outpc.rpm, kpaix, NO_FRPMS, NO_FMAPS, &inpram.frpm_table[0], &inpram.fmap_table[0], &in2ram.XTauTable[0][0]); if(in2ram.XTauOption == 2) { // use X-Tau for warmup based on clt temp at startup if(first_clt) { warmup_Tclt = CW_table(outpc.clt,in2ram.XTauClt); // % first_clt = 0; } asm { ldy tmp1 ldd warmup_Tclt EMULS ldx #100 EDIVS sty tmp2 }; } else { // X-Tau for accel/ decel only tmp2 = tmp1; } tmp3 = CW_table(outpc.mat,in2ram.XTauMat); // % asm { ldy tmp2 ldd tmp3 EMULS ldx #100 EDIV sty XTau }; if((-tpsdot_ltch) > inpram.TpsThresh) { utmp1 = in2ram.XTDecel; asm { ldy XTau ldd utmp1 EMUL ldx #100 EDIV sty XTau }; } if(XTau < 1) { XTau = 1; XTau0 = 1; // continue x-tau calc with tau= 1, but make no correction. } else XTau0 = 0; utmp1 = pw_open * 100; XTm = ppw[mx_bnk] - utmp1; // just use max pw to get ratio & apply to both pw DISABLE_INTERRUPTS ultmp = dtpred; ENABLE_INTERRUPTS ltmp = (XTau * (unsigned long)10000) / ultmp; // tau / dltau if(ltmp < 1)ltmp = 1; ltmp = XTM / ltmp; if(ltmp > XTm) ltmp = XTm; // must leave beta and (int)cast below because of pos CW beta = ((XTm - ltmp) * 100) / (int)(100 - in2ram.XTX); if(beta > 65000)beta = 65000; XTf = (unsigned int)beta; utmp2 = in2ram.XTX; asm { ldy utmp2 ldd XTf EMUL ldx #100 EDIV sty utmp2 }; XTM = XTM + utmp2 - ltmp; if((XTm > 0) && !XTau0) { asm { ldy XTf ldd #100 EMUL ldx XTm EDIV sty outpc.XTfcor }; } else outpc.XTfcor = 100; if(!XTau0) ppw[mx_bnk] = XTf + utmp1; // X-tau done only on max bank - the correction is then applied to other. utmp2 = ppw[1-mx_bnk] - utmp1; if((utmp2 == XTm) || XTau0) ppw[1-mx_bnk] = ppw[mx_bnk]; else { utmp3 = (unsigned int)outpc.XTfcor; asm { ldy utmp3 ldd utmp2 EMUL ldx #100 EDIV sty utmp2 }; ppw[1-mx_bnk] = utmp2 + utmp1; } if(ppw[0] > 32000)ppw[0] = 32000; // rail at 32 ms if(ppw[1] > 32000)ppw[1] = 32000; // rail at 32 ms XTcalc = 0; // clear flag - will be reset on next tach pulse } pwcalc1 = ppw[0]; pwcalc2 = ppw[1]; /************************************************************************** ** ** Calculation of Knock retard, Distributor Advance & coil charge time correction ** **************************************************************************/ KNK: if(!(inpram.knk_option & 0x0F) || (outpc.map > inpram.knk_maxmap) || (outpc.rpm < inpram.knk_lorpm) || (outpc.rpm > inpram.knk_hirpm)) { // no knock correction outpc.knk_rtd = 0; goto DIST_ADV; } else { // latch any knocks that occur during the knk_clk_test interval // calculate knk_thresh get_adc(7,7); tmp1 = knk_thresh_calc(outpc.rpm); ix = (inpram.knk_option & 0xF0) >> 4; if(((ix == 0) && (outpc.knock < tmp1)) || ((ix == 1) && (outpc.knock > tmp1))) { // signal(Vx100) indicates knock occurred if(knk_count < 255) // don't want to overflow to 0 knk_count++; if((knk_stat == 0) && (knk_count > inpram.knk_ndet)) knk_clk = knk_clk_test; // just caught knock - force 1st retard // immediately (as fast as main loop allows) } if(knk_clk >= knk_clk_test) { // time to check for retard/ adv spark if(knk_count > inpram.knk_ndet) { // got valid knock. req ndet consec // knocks to be sure knk_clk_test = inpram.knk_trtd; if(knk_stat == 4) // thought had enough retard, but need more knk_stat = 2; if(knk_stat < 2) uctmp = inpram.knk_step1; // haven't stopped knock yet else uctmp = inpram.knk_step2; // stopped once - use smaller step uctmp = outpc.knk_rtd + uctmp; if(uctmp < inpram.knk_maxrtd) outpc.knk_rtd = uctmp; else outpc.knk_rtd = inpram.knk_maxrtd; if(knk_stat == 0) // 1st knock knk_stat = 1; else if(knk_stat == 2) { // this is knk returning due to too much adv if((inpram.knk_option & 0x0F) == 1) // operate one step below knock knk_stat = 3; } } else { // did not get unambiguous knock knk_clk_test = inpram.knk_tadv; // change time interval switch (knk_stat) { case 0: break; case 1: case 2: if((knk_stat == 2) && (outpc.knk_rtd == 0)) knk_stat = 0; // back to table value & no knock- restart process else { if(outpc.knk_rtd >= inpram.knk_step2) outpc.knk_rtd -= inpram.knk_step2; // remove some retard else outpc.knk_rtd = 0; knk_stat = 2; // had knock, eliminated it, now try get closer // to threshhold } break; case 3: // had knock, eliminated it, couldn't get closer to thresh // This is as good as can get; save tps, rpm knk_tble_adv = outpc.adv_deg; knk_stat = 4; break; case 4: // maintain status until knock or change in tps or map tmp1 = outpc.adv_deg - knk_tble_adv; if(tmp1 < 0)tmp1 = -tmp1; if(tmp1 > inpram.knk_dtble_adv) { outpc.knk_rtd = 0; // conditions changed- restart process knk_stat = 0; } break; } // end status switch } knk_count = 0; knk_clk = 0; } } DIST_ADV: // Calculate ignition advance lsum = intrp_2ditable(outpc.rpm, kpaix, NO_SRPMS, NO_SMAPS, &inpram.srpm_table[0], &inpram.smap_table[0], &in2ram.adv_table[0][0]) + outpc.cold_adv_deg - outpc.knk_rtd; // degx 10 // Subtract retard vs manifold air temp lsum -= intrp_1dctable(1, outpc.mat, NO_MAT_TEMPS, in2ram.MatTemps, 0, in2ram.MatSpkRtd); // % // correct for flex fuel; lsum += ffspkdel; // degx10 // rev limit if(inpram.RevLimOption == 1) { if(outpc.rpm > inpram.RevLimRpm2) lsum -= inpram.RevLimMaxRtd; // deg x 10 else if(outpc.rpm > inpram.RevLimRpm1) { lsum -= (((long)inpram.RevLimMaxRtd*(outpc.rpm- inpram.RevLimRpm1))/ (inpram.RevLimRpm2 - inpram.RevLimRpm1)); // deg x 10 } } // reference relative to IC ic_adv_deg = (int)(lsum - inpram.adv_offset); if((outpc.engine & 0x02) && // cranking & trigger rise/ return (crank_trig_mode || trig_ret_mode)) outpc.adv_deg = inpram.adv_offset; // relative to true TDC else outpc.adv_deg = (int)lsum; // relative to true TDC // Base dwell tmp1 = inpram.max_coil_dur; // Add correction if accelerating if((outpc.tpsaccel > 0) || (outpc.XTfcor > 101)) tmp1 += inpram.DurAcc; // Correct for battery voltage tmp1 += coil_dur_table(outpc.batt - 120); coil_dur = tmp1; // msx10, will be used in IC Isr. // following belongs in Input Capture ISR, but this saves long div in ISR DISABLE_INTERRUPTS ltmp = coil_dur_set; ENABLE_INTERRUPTS outpc.coil_dur = (int)(ltmp / 100); // msx10 /*************************************************************************** ** ** Check whether to burn flash ** **************************************************************************/ BURN_FLASH: if(amc_burn_flag && (outpc.rpm < AMCBURN_RPM_THRESH)) { amc_burn_flag = 0; burn_flag = 1; in2ram.AMCNBurns++; // increment cumulative no. of AMC flash burns flocker = 0xCC; // set sem to prevent burn flash thru runaway code } if(burn_flag) { // burn flash 512 byte(256 word) sector(s) if((burn_flag > 1) || (outpc.rpm <= 50) || (tooth_no == burn_tooth_no)) { fburner(tableWordFlash(burn_idx, 0), tableWordRam(burn_idx, 0), tableWords(burn_idx)); if(burn_flag >= tableWords(burn_idx)) { burn_flag = 0; flocker = 0; } else burn_flag++; } } /*************************************************************************** ** ** Check for reinit command ** **************************************************************************/ if(reinit_flag) { reinit_flag = 0; // update initialization of variables/ registers dependent on // user config inputs Rpm_Coeff = 120000000 / inpram.no_cyl; SPK = 1 - inpram.spkout_hi_lo; // 0=spk low, but inverted logic CHG = 1 - SPK; // after transistor if(!(inpram.ICIgnOption & 0x02)) trig_ret_mode = 0; else if(outpc.rpm < inpram.crank_rpm) trig_ret_mode = 2; TCTL4 &= ~0x33; // clear bits 0,1 and 4.5(won't hurt if not dual spk) if(inpram.DualSpkOptn < 2) { if(inpram.ICIgnOption & 0x01) { // normal rising edge input capture if(!trig_ret_mode) // not trig ret mode TCTL4 |= 0x11; // rising edge input capture else // reverse in trigger return mode TCTL4 |= 0x22; // falling edge input capture } else { // normal falling edge input capture if(!trig_ret_mode) // not trig ret mode TCTL4 |= 0x22; // falling edge input capture else // reverse in trigger return mode TCTL4 |= 0x11; // rising edge input capture } } else { if(inpram.ICIgnOption & 0x01) // tach in is rising edge TCTL4 |= 0x01; else // tach in is falling edge TCTL4 |= 0x02; if(inpram.DualSpkOptn == 3) // cam_sync is rising edge TCTL4 |= 0x10; else if(inpram.DualSpkOptn == 2) // cam_sync is falling edge TCTL4 |= 0x20; } if(!inpram.CWOption) { if(outpc.clt >= inpram.temp_table[NO_TEMPS-1]) { AWEV = (unsigned short)inpram.AWEVH; AWC = (unsigned short)inpram.AWCH; } else if(outpc.clt <= inpram.temp_table[0]) { AWEV = (unsigned short)inpram.AWEVU; AWC = (unsigned short)inpram.AWCU; } else { ltmp = (outpc.clt - inpram.temp_table[0]) * (long)(inpram.AWEVH - inpram.AWEVU); AWEV = (unsigned short)(inpram.AWEVU + (ltmp / (inpram.temp_table[NO_TEMPS-1] - inpram.temp_table[0]))); // % ltmp = (outpc.clt - inpram.temp_table[0]) * (long)(inpram.AWCH - inpram.AWCU); AWC = (unsigned short)(inpram.AWCU + (ltmp / (inpram.temp_table[NO_TEMPS-1] - inpram.temp_table[0]))); // cycles } } else { // custom warmup tables AWEV = (unsigned short)CW_table(outpc.clt,in2ram.CWAWEV); // % AWC = (unsigned short)CW_table(outpc.clt,in2ram.CWAWC); // cycles } crank_trig_mode = (inpram.ICIgnOption & 0x04) >> 2; // Set up SCI (rs232): SCI BR reg= BusFreq(=24MHz)/16/baudrate SCI0BDL = (unsigned char)(1500000/inpram.baud); ltmp = (150000000/inpram.baud) - ((long)SCI0BDL*100); if(ltmp > 50)SCI0BDL++; // round up } /*************************************************************************** ** ** Determine spare port settings ** **************************************************************************/ for(ix = 0;ix < NPORT; ix++) { if(inpram.spr_port[ix]) { // Evaluate first condition if(inpram.out_byte1[ix] == 1) tmp1 = *((char *)(&outpc) + inpram.out_offset1[ix]); else tmp1 = *( int *)((char *)(&outpc) + inpram.out_offset1[ix]); tmp1 = tmp1 - inpram.thresh1[ix]; if(inpram.condition1[ix] == '<') tmp1 = -tmp1; // convert < condition to same as > condition if(inpram.condition1[ix] == '=') { if((tmp1 >= -inpram.hyst1[ix]) && (tmp1 <= inpram.hyst1[ix])) ctmp1 = 1; // 1st condition true } else if(tmp1 > 0) ctmp1 = 1; // 1st condition true else ctmp1 = 0; // 1st condition false // Evaluate second condition if there is one if(inpram.cond12[ix] != ' ') { if(inpram.out_byte2[ix] == 1) tmp2 = *((char *)(&outpc) + inpram.out_offset2[ix]); else tmp2 = *( int *)((char *)(&outpc) + inpram.out_offset2[ix]); tmp2 = tmp2 - inpram.thresh2[ix]; if(inpram.condition2[ix] == '<') tmp2 = -tmp2; // convert < condition to same as > condition if(inpram.condition2[ix] == '=') { if((tmp2 >= -inpram.hyst2[ix]) && (tmp2 <= inpram.hyst2[ix])) ctmp2 = 1; // 2nd condition true } else if(tmp2 > 0) ctmp2 = 1; // 2nd condition true else ctmp2 = 0; // 2nd condition false } // Evaluate final condition if(((inpram.cond12[ix] == '&') && (ctmp1 && ctmp2)) || ((inpram.cond12[ix] == '|') && (ctmp1 || ctmp2)) || ((inpram.cond12[ix] == ' ') && ctmp1)) { if(lst_pval[ix] != inpram.port_val[ix]) { set_spr_port((char)ix, inpram.port_val[ix]); lst_pval[ix] = inpram.port_val[ix]; } } else { // Evaluate hysteresis conditions if((inpram.condition1[ix] == '>') || (inpram.condition1[ix] == '<')) tmp1 = -tmp1 - inpram.hyst1[ix]; if(inpram.condition1[ix] == '=') { ctmp1 = 1 - ctmp1; // 1st hyst. condition opposite of set cond } else if(tmp1 > 0) ctmp1 = 1; // 1st hysteresis condition true else ctmp1 = 0; // 1st hysteresis condition false if(inpram.cond12[ix] != ' ') { if((inpram.condition2[ix] == '>') || (inpram.condition2[ix] == '<')) tmp2 = -tmp2 - inpram.hyst2[ix]; if(inpram.condition2[ix] == '=') { ctmp2 = 1 - ctmp2; // 2nd hyst. condition opposite of set cond } else if(tmp2 > 0) ctmp2 = 1; // 2nd hysteresis condition true else ctmp2 = 0; // 2nd hysteresis condition false } // Evaluate final hysteresis condition if(((inpram.cond12[ix] == '&') && (ctmp1 || ctmp2)) || ((inpram.cond12[ix] == '|') && (ctmp1 && ctmp2)) || ((inpram.cond12[ix] == ' ') && ctmp1)) { if(lst_pval[ix] != 1 - inpram.port_val[ix]) { set_spr_port((char)ix, 1 - inpram.port_val[ix]); lst_pval[ix] = 1 - inpram.port_val[ix]; } } } // end eval of hysteresis conditions } // end if spr_port } // end for ix loop /*************************************************************************** ** ** Check for serial receiver timeout ** **************************************************************************/ DISABLE_INTERRUPTS ltmp = lmms; ultmp = rcv_timeout; ENABLE_INTERRUPTS if(ltmp > ultmp) { txmode = 0; // break out of current receive sequence rcv_timeout = 0xFFFFFFFF; } /*************************************************************************** ** ** Check for CAN reset ** **************************************************************************/ if(can_reset) { /* Re-initialize CAN comms */ CanInit(); can_reset = 0; } #ifdef CAN_TEST // sample code to send periodic messages DISABLE_INTERRUPTS ultmp = lmms; ENABLE_INTERRUPTS if(ultmp > cansendclk) { cansendclk = ultmp + 7812; // 1 sec(7812 x .128 ms) clk for(ix = 0;ix < 6;ix++) { /