; ;************************************************************************ ; 1227747 ECU 160 Baud ALDL display / Juha Niinikoski ; Test code put together 11.9.2000 ; First working code 12.9.2000 v0.01 ; BLM Cell resolver & temperature conversion 13.9.2000 v0.02 ; O2 mV, MAP Kpa & TPs % conversion added 14.9.2000 ; PA3 display, knock warning & some bit indicators added 15.9.2000 ; VFD / LCD routine clean up & display format 26.9.2000 v1.00 ; Page & normal/diag switches. Diag display. 27.9.2000 v1.01 ; Display shows Wait until ALDL data is present. 29.3.2001 v1.02 ; Tested with 808 ECU. 808 needs more delay after clear screen. Additional ; delay makes display flicker. New display consept without clear ; screen commands. Assembly switch for knock warning 1.4.2001 v 1.10 ; assembly radix switch & false sync corrected 20.05.2002 v 1.11 ; P/N, Rich/Lean & low Bat display added 05.06.2002 v 1.12 ; PROM ID display at startup 05.07.2002 v 1.13 ; ; Test to convert code for 2k 16F628 part 25.07.2002 v 2.00 ; For correct PORTA operation CMCON register needs to be set. RAM origin changed. ; Label SYNC changed to ASYNC to avoid conflict with 628 predefined labels. ; __config changed for 16F628. ; Messages moved to RAM page 0x600. 0x700 reserved for additional messages. ; POINT6 & POINT7 Macros changed. Program memory from 0x300 to 0x5ff available for ; additional code. ; Error code logic added 26.07.2002 ; Display page select push button logic 28.07.2002 v2.01 ; ALDL receiver switched to TMR1. Watchdog enabled 07.08.2002 v2.02 ; Yet another ALDL sync problem corrected 07.08.2002 ; ;************************************************************************ ; LIST P = 16F628, R = HEX ; INCLUDE "p16f628.inc" ; __config _xt_osc & _wdt_on & _cp_off & _pwrte_on & _boden_on & _lvp_off ; ;************************************************************************ ; LCD I/O parameters ; lcddata equ porta ; Port A0:3 = LCD data lcdctr equ portb ; Port B6:7 = LCD control ; LCDRS EQU 6 ; Lcd register select output LCDEN EQU 7 ; Lcd enable output ; LCD commands LCDCLER EQU b'00000001' ; Clears display, resets curcor LCDCM EQU b'10000000' ; Sets cursor using bits 0 - 6 line1 equ .0 ; Line 1 range - 0 to 0x13 line2 equ 0x40 ; Line 2 range - 0x40 to 0x53 line3 equ 0x14 ; Line 3 range - 0x14 to 0x27 line4 equ 0x54 ; line 4 range - 0x54 to 0x67 ; diag equ 1 ; diagnostic I/O 1 = on, 0 = off #define diag_io portb, 3 ; diagnostic I/O for RX timing check ; kw_on equ 1 ; knock warning detection 1 = on, 0 = off ; ;************************ Data RAM Assignments ********************** ; ORG 0x20 ; Origin for 16F628 RAM ; ; Special variables ; s_status res 1 ; Startup status. Not cleared by clear RAM ; ; LCD I/O variables ; GP1 res 1 ; General purpose register chcnt ; map variables to save memory STRNUM res 1 CHPT res 1 ; Character string pointer in string. LCDCH res 1 ; Saves byte to be sent to lcd while ; it is processed DLYCNT res 1 COUNT res 1 TEMP res 1 TABOFF res 1 ; Table ofset pointer in lcd string lookup apu res 1 ; anotger gp register ; biglcd equ 0 ; size of lcd panel zsup equ 1 ; leading zero supress in 4 digit displays disp5d equ 0 ; # of digits displayed ; ;mulcnd res 1 ; 8 bit multiplicand ;mulplr res 1 ; 8 bit multiplier H_byte res 1 ; 16-bit register L_byte res 1 ; ; ; B2_BCD Bin to BCD conversion variables ; count res 1 ; ! already defined nflag res 1 ; negative number flag ; mulcnd ; map variables to save memory R0 res 1 ; hi order mulplr R1 res 1 ; 5 digit BCD output R2 res 1 ; A4 res 1 ; hi orde value A3 res 1 ; 5 byte ASCII output A2 res 1 A1 res 1 A0 res 1 ; lo order value ; ; Interrupt routine variables ; w_temp res 1 ; W save during interrupt status_temp res 1 ; status save during interrupt fsr_temp res 1 ; FSR save during interrupt ; ; ; Display page selector variables ; #define sw portb, 1 ; Page select switch IO bit #define swbit flags, 0 ; page select switch state bit. Stored in flags dpage res 1 ; page selector maxpage equ 3 ; Page numper steps between 0 and maxpage db_counter res 1 ; Debounce delay counter db_delay equ .50 ; switch debounce delay (rounds) ; ; ALDL variables ; oldpa3 res 1 ; incremental knock counter ; ; ALDL Error Code logic variables ; mfflag res 3 ; copy of MALFFLAGS 1 -3 msgidx res 1 ; index to messages bitctr res 1 ; bit counter ; ; 160 Baud receiver variables ; filter equ 1 ; switch for input filtering 1 = on fcount equ .3 ; filter delay ; rx_buff res 1 ; ALDL input shift register bit_count res 1 ; ALDL input bit counter rx_byte res 1 ; received ALDL data byte int_temp res 1 ; temp storage for int routines ; async equ 7 ; sync pattern received byte_rdy equ 6 ; byte ready in rx_byte flags res 1 ; ALDL receiver state flags ; rx_count res 1 ; characters received after last sync msg_num res 1 ; modulo 256 counter for aldl messages buff_ptr res 1 ; aldl buffer write pointer aldl_buff res .20 ; ALDL data storage aldl_buffe res 1 ; buffer end + 1. Junk byte for too long messages. aldl equ aldl_buff - 1 ; for data stream offsets (starts from 1) ; 1227747 ALDL data steream ; WORD BIT DESCRIPTION ; ---- --- --------------- ; 1 MODE WORD 2 ; 0 ROAD SPEED PULSE OCCURRED ; 1 ESC 43B READY FOR SECOND PE ; 2 REFERENCE PULSE OCCURRED ; 3 DIAGNOSTIC SWITCH IN FACTORY TEST POSITION (3.9K) ; 4 DIAGNOSTIC SWITCH IN DIAGNOSTIC POSITION (0 OHMS) ; 5 DIAGNOSTIC SWITCH IN ALDL POSITION (10k) ; 6 1ST TIME IDLE FLAG 0 = FIRST TIME ; 7 IDLE FLAG 1=TPS < KISTPSI & MPH < KIDLMPH ; 2 PROMID (MSB) ; 3 PROMID (LSB) PROMID = (MSB)*256 + (LSB) ; 4 IAC PRESENT POSITION N = COUNTS ; 5 COOLANT TEMPERATURE SEE TABLE 1 ; 6 VEHICLE SPEED MPH = N ; 7 MANIFOLD ABSOLUTE PRESSURE VOLTS = N * .0196 ; 8 ENGINE RPM RPM = N * 25 ; 9 THROTTLE POSITION SENSOR VOLTS = N * .0196 ; 10 CLOSED LOOP INTEGRATOR NONE ; 11 OXYGEN SENSOR MILLIVOLTS = N * 4.34 ; 12 MALFFLG1 ; 0 MALF CODE 24 VEHICLE SPEED SENSOR ; 1 (MALF CODE 23) ; 2 MALF CODE 22 THROTTLE POSITION SENSOR LOW ; 3 MALF CODE 21 THROTTLE POSITION SENSOR HIGH ; 4 MALF CODE 15 COOLANT SENSOR LOW ; 5 MALF CODE 14 COOLANT SENSOR HIGH ; 6 MALF CODE 13 OXYGEN SENSOR ; 7 MALF CODE 12 NO REFERENCE PULSES ; 13 MALFFLG2 ; 0 MALF CODE 42 ELECTRONIC SPARK TIMING MONITOR ERROR ; 1 (MALF CODE 41) ; 2 (MALF CODE 35) ; 3 MALF CODE 34 MAP SENSOR LOW ; 4 MALF CODE 33 MAP SENSOR HIGH ; 5 MALF CODE 32 EXHAUST GAS RECIRCULATION FAILURE ; 6 MALF CODE 31 GOVERNOR FAILURE ; 7 (MALF CODE 25) ; 14 MALFFLG3 ; 0 MALF CODE 55 ADU ERROR ; 1 MALF CODE 54 FUEL PUMP RELAY FAILURE ; 2 (MALF CODE 53) ; 3 MALF CODE 52 CAL PACK MISSING ; 4 MALF CODE 51 PROM ERROR ; 5 MALF CODE 45 OXYGEN SENSOR RICH ; 6 MALF CODE 44 OXYGEN SENSOR LEAN ; 7 MALF CODE 43 ELECTRONIC SPARK CONTROL FAILURE ; 15 MWAF1 ; 0 CLEAR FLOOD FLAG 1 = CRANKED IN C/FLOOD ; 1 LEARN CONTROL ENABLE FLAG 1 = ENABLE STORE ; 2 LOW BATTERY 1 = LOW ; 3 4-3 DOWNSHIFT FOR TCC UNLOCK ; 4 ASYNCHRONOUS FLAG ; 5 OLD HIGH GEAR FLAG 0 = HIGH GEAR LAST TIME ; 6 RICH LEAN FLAG 1 = RICH 0 = LEAN ; 7 CLOSED LOOP FLAG 1 = CLOSED LOOP ; 16 BATTERY VOLTAGE VOLTS = N * .1 ; 17 MCU2IO ; 0 AIR SWITCH 1 = SOLENOID ENGAGED ; 1 AIR DIVERT 1 = SOLENOID ENGAGED ; 2 OF3 A/C 1 = A/C DISABLED ; 3 TCC 1 = TCC LOCKED ; 4 PARK NEUTRAL 0 = DRIVE ; 5 HIGH GEAR 0 = SWITCH OPEN ; 6 FRTJ (NOT USED) ; 7 AIR CONDITIONER 0 = A/C REQUESTED ; 18 OLDPA3 N = COUNTS ; 19 BASE PULSE COURSE CORRECTION(BLM) ; 20 O2 CROSS COUNTS N = COUNTS ; ; ;*********************************************************************** ; ORG 0 ; Restart vector goto main0 ; ORG 4 ; INT vector goto irqserv ; serve interrupts ;*********************************************************************** ; Out 2 hex caharacters from W ; This routine must stay in page 0 ! ; out2hexs movwf temp movlw ' ' call putlcd goto o2h1 ; ; Out 2 hex withou space out2hex movwf temp ; o2h1 swapf temp, w andlw 0x0f call hextable nop call putlcd ; movf temp, w andlw 0x0f call hextable nop call putlcd ; return ; HexTable clrf pclath ; ! this routine must reside in page 0 addwf pcl retlw '0' ;0 retlw '1' ;1 retlw '2' ;2 retlw '3' ;3 retlw '4' ;4 retlw '5' ;5 retlw '6' ;6 retlw '7' ;7 retlw '8' ;8 retlw '9' ;9 retlw 'A' ;A retlw 'B' ;b retlw 'C' ;C retlw 'D' ;D retlw 'E' ;E retlw 'F' ;F ; ;*********************************************************************** ; main0 ;*********************************************************************** ; set up WDT prescaler ; movf status, w ; first save startup status movwf s_status clrwdt bsf status, rp0 ; select bank 1 bsf option_reg, psa ; take prescaler(default1:128) for WDT use clrwdt bcf option_reg, intedg ; RB0 interrupt with falling edge bcf option_reg, not_rbpu ; B-port pull ups on bsf pie1, tmr1ie ; enable TMR1 IRQ bcf status, rp0 ; back to bank 0 bsf intcon, peie ; enable peripheral IRQs ;*********************************************************************** ; 16F628 cpu Bank 0 RAM cleaning ; zeroes ram 0x21 - 0x7F ; movlw 0x21 ; start of 16F628 ram. s_status not cleared. movwf fsr ramc1 clrf indf ; clear indirect location incf fsr, f ; next location clrwdt btfss fsr, 7 ; cleans up to 0x7f goto ramc1 ; ;*********************************************************************** ; Set up lcd port & IRQ system. ; ; Outputs ; RA0 - 3 lcd data ; RB6 lcd register select ; RA7 lcd enable clrf lcddata clrf lcdctr movlw 0x07 ; turn comparators off movwf cmcon bsf status, rp0 ; select bank 1 movlw b'11110000' ; Set port A data directions, A0:3=outputs movwf trisa movlw b'00110111' ; Set port B data directions movwf trisb ; RB0 = int input bcf status, rp0 ; select bank 0 bsf swbit ; assume page select switch = open ; call initlcd ; init LCD routines clrwdt ; ; ; ;********************************************************************** ; ; Display banner messages ; btfsc s_status, not_to ; Watchdog bite ? goto ok_start movlw 'W' ; WDT bite call putlcd movlw 'D' call putlcd movlw 'T' call putlcd goto start_delay ; ok_start movlw .1 ; Hello message call string movlw line2 call lcdcur ; Position text on line 2 movlw .2 ; Version message call string ; start_delay movlw .30 ; wait about 3s call wait100 ; movlw line4 call lcdcur ; line 4 movlw .19 ; Wait message call string clrwdt ; ;************************************************************** ; ; Init ALDL application variables ; ; clrf rx_buff ; clrf bit_count ; clrf rx_byte ; clrf flags ; movlw aldl_buff ; init aldl buffer pointer movwf buff_ptr ; ; Enable interrupts = Let's go ; bsf intcon, gie ; enable interrupts bsf intcon, inte ; enable RB0 ALDL input interrupts ; wfs clrwdt btfss flags, async goto wfs ; wait for first sync ; ;************************************************************** ; ; Display PROM ID for few rounds ; movlw .10 ; # of ALDL frames while movwf H_byte ; PROM ID is shown ; dispid movlw line4 call lcdcur ; line 4 movlw 'I' ; ID call putlcd movlw 'D' call putlcd ; movf aldl+2, w ; get PROMID (MSB) call out2hexs movf aldl+3, w ; get PROMID (LSB) call out2hex movlw .10 call disp_wspaces ; clear rest of the line ; dispid1 clrwdt btfss flags, async goto dispid1 ; wait for sync bcf flags, async ; decfsz H_byte, f ; wait few rounds goto dispid ; ;************************************************************** ; ; Main loop is executed every time when sync pattern have occured at aldl bus. ; page variable defines page to be displayed ; main1 call pagesw ; handle page switch button btfss flags, async goto main1 ; wait for sync ; clrwdt ; if no sync received within 2s then restart(WDT bite) bcf flags, async incf msg_num, f ; increment message counter ;__________________________ ; ; select page to be displayed ; this routine must stay in page 0 ; clrf pclath ; page 0 movf dpage, w ; compute jump addwf pcl goto disp_page1 ; 0 page1 goto disp_page2 ; 1 page 2 goto disp_page3 ; 2 error codes goto disp_diag ; 3 diag diaplay ; ;__________________________ disp_page1 movlw line1 call lcdcur ; line 1 ; call disp_rpm call disp_space call disp_iac call disp_space call disp_a call disp_space ; if kw_on call knock ; this overrides line 1 if knock endif ;__________________________ movlw line2 call lcdcur ; line 2 ; call disp_tps call disp_space call disp_o2 call disp_space call disp_i call disp_space ;__________________________ movlw line3 call lcdcur ; line 3 ; call disp_map call disp_space call disp_int call disp_space call disp_c call disp_space ;__________________________ movlw line4 call lcdcur ; line 4 ; call disp_bcl call disp_space call disp_blm call disp_space call disp_l call disp_space ; goto main1 ; ;______________________________________________ ; ; second display page ; ; disp_page2 ; movlw line1 call lcdcur ; line 1 ; call disp_bat call disp_space call disp_tmp call disp_space call disp_lb call disp_space ;__________________________ movlw line2 call lcdcur ; line 2 ; call disp_spd call disp_space call disp_pa3 movlw .3 call disp_wspaces ;__________________________ movlw line3 call lcdcur ; line 3 ; call disp_occ call disp_space call disp_o2 call disp_space call disp_rl call disp_space ;__________________________ movlw line4 call lcdcur ; line 4 ; call disp_msg_num call disp_space call disp_rx_count call disp_space call disp_d call disp_space ; goto main1 ; ;______________________________________________ ; ; malfunction code display ; disp_page3 ; call disp_malf ; display malfunction codes goto main1 ;______________________________________________ ; ; diagnostics display = show raw aldl data ; hex display only. ; disp_diag ; disp_diag1 movlw aldl_buff ; set buffer pointer movwf chpt ; movlw line1 call lcdcur ; line 1 call disp_line movlw .5 ; fill rest of the line with spaces call disp_wspaces movlw line2 call lcdcur ; line 2 call disp_line movlw .5 call disp_wspaces movlw line3 call lcdcur ; line 3 call disp_line movlw .5 call disp_wspaces movlw line4 call lcdcur ; line 4 call disp_line movlw .5 call disp_wspaces goto main1 ; disp_line movlw .5 ; set character counter movwf chcnt ; disp_line1 movf chpt, w incf chpt, f ; uppdate character pointer movwf fsr ; set indirect pointer movf indf, w ; get data ; call out2hexs ; display in hex format ; decfsz chcnt, f goto disp_line1 ; continue this line return ; ;*************************************************************** ; ALDL parameter display routines ; Independent routines for each displayed paremeter ; disp_iac ; unit = count, range 0 - 255 movlw .3 ; display IAC call string movf aldl+4, w ; get IAC count goto disp_end ; ; ; do coarse ad value to temperature conversion ; tst10 macro ad1 movlw ad1 subwf aldl+5, w ; test if equal or less skpc call add10 ; 10 degrees increment endm ; tst5 macro ad2 movlw ad2 subwf aldl+5, w ; test if equal or less skpc call add5 ; 5 degrees increment endm ; add5 movlw .5 ; increnent temperature 5 deg addwf l_byte, f return add10 movlw .10 ; 10 deg addwf l_byte, f return ; disp_tmp ; unit = degrees Celcius, range 0 - 125 movlw .4 ; display Temp call string clrf h_byte clrf l_byte ; show 0 if .lt. 10 degrees ; ; do raw test and skip conversion ; tst10 .218 ; 10 tst10 .199 ; 20 tst10 .177 ; 30 tst10 .152 ; 40 tst10 .126 ; 50 tst10 .102 ; 60 tst5 .92 ; 65 tst5 .81 ; 70 tst5 .72 ; 75 tst5 .64 ; 80 tst5 .56 ; 85 tst5 .50 ; 90 tst5 .44 ; 95 tst5 .39 ; 100 tst5 .34 ; 105 tst10 .25 ; 115 tst10 .21 ; 125 stop testin now it is boiling anyway ; goto disp_end2 ; show conversion result from l_byte ; disp_spd ; unit = MPH or KPH, range = 0 - 255 movlw .5 ; display Vechicle Speed call string movf aldl+6, w ; get speed goto disp_end ; disp_map ; unit = Kpa, range = 10 - 104 movlw .6 ; display MAP call string movf aldl+7, w ; get MAP AD value count movwf mulcnd movlw .94 ; multiply by 94 movwf mulplr call mpy call div256 ; then divide by 256 movlw .10 ; offset addwf l_byte, f ; add offset goto disp_end2 ; disp_rpm ; unit = RPM, range = 0 - 6375 movlw .7 ; display RPM call string movf aldl+8, w ; get rpm data movwf mulcnd movlw .25 movwf mulplr ; multiply it by 25 call mpy goto disp_end2 ; disp_tps ; unit = %, range = 0- 100 movlw .8 ; display TPS call string movf aldl+9, w ; get TPS AD count movwf mulcnd movlw .100 ; multiply by 100 movwf mulplr call mpy call div256 ; then divide by 256 goto disp_end2 ; disp_int ; unit = unit, range = 0 - 255 movlw .9 ; display Integrator call string movf aldl+.10, w ; get Integrator goto disp_end ; disp_o2 ; unit = mV, range = 0 - 1115 movlw .10 ; display O2 volts call string movf aldl+.11, w ; get o2 raw value movwf mulcnd ; do conversion mV = ad*70/16 movlw .70 movwf mulplr ; multiply it by 70 call mpy call div16 ; divide by 16 goto disp_end2 ; show result ; disp_blm ; unit = unit, range = 0 - 255 movlw .11 ; display BLM call string movf aldl+.19, w ; get BLM value goto disp_end ; disp_occ ; unit = unit, range = 0 - 255 movlw .12 ; display O2 cross counts call string movf aldl+.20, w ; get o2 cross count goto disp_end ; disp_bat ; unit = 0.1V, ramge = 0 - 255 movlw .13 ; display battery voltage call string movf aldl+.16, w ; get battery voltage goto disp_end ; disp_bcl ; unit = cell #, range = 0 - 15 ; ; Resolve & display current BLM cell. Current BLM cell information ; does not come with ALDL data. You have to reconstruct it from MAp and RPM ; information. Cell border values are from ASDZ hack. Check yours ! ; hi_map equ .192 ; map cell border values mid_map equ .128 lo_map equ .20 hi_rpm equ .104 ; rpm cell border values mid_rpm equ .72 lo_rpm equ .30 ; map equ aldl+7 ; map data rpm equ aldl+8 ; rpm data ; movlw .14 ; resolve & display current blm cell call string ; movlw .15 movwf l_byte ; initial BLM value ; test_map movlw hi_map ; start testing from highest map value subwf map, w ; test skpnc goto test_rpm ; MAP is higher or equal movlw .4 subwf l_byte, f ; decrement MAP cell ; movlw mid_map subwf map, w ; test skpnc goto test_rpm ; MAP is higher or equal movlw .4 subwf l_byte, f ; decrement MAP cell ; movlw lo_map subwf map, w ; test skpnc goto test_rpm ; MAP is higher or equal movlw .4 subwf l_byte, f ; decrement MAP cell ; test_rpm movlw hi_rpm ; start testing from highest rpm value subwf rpm, w ; test skpnc goto test_end ; RPM is higher or equal decf l_byte, f ; decrement MAP cell ; movlw mid_rpm subwf rpm, w ; test skpnc goto test_end ; RPM is higher or equal decf l_byte, f ; decrement MAP cell ; movlw lo_rpm subwf rpm, w ; test skpnc goto test_end ; RPM is higher or equal decf l_byte, f ; decrement MAP cell ; ; l_byte on current BLM cell #, display it test_end goto disp_end1 ; l_byte already in place ; disp_pa3 ; unit = unit, range = 0 - 255 movlw .15 ; display OLDPA3 parameter call string movf aldl+.18, w ; get OLDPA3 value goto disp_end ; knock ; display if knock detected movf aldl+.18, w ; get OLDPA3 value xorwf oldpa3,w ; check is same as before skpnz return ; yes = no action movf aldl+.18, w ; get OLDPA3 value movwf oldpa3 ; store as old value call lcdclr ; write over what ever we have on the display movlw .16 ; display knock warning message call string movlw .8 ; fill rest of the line with spaces goto disp_wspaces ; disp_rx_count movlw .18 call string movf rx_count, w ; show how many bytes received since clrf rx_count ; reset character counter goto disp_end ; disp_msg_num movlw .17 call string movf msg_num, w ; show aldl message number goto disp_end ; disp_end movwf l_byte ; this is common part for almost disp_end1 clrf h_byte ; all parameter display routines disp_end2 call b2_bcd ; convert to decimal call disp5 ; show result movlw ' ' call putlcd return ; ; Display various flags ; disp_c ; display cloced loop flag movlw ' ' ; assume not set btfsc aldl+.15, 7 ; test closed loop flag MWAF1.7 movlw 'C' ; closed loop indicator call putlcd return ; disp_l ; display enable learn flag movlw ' ' ; assume not set btfsc aldl+.15, 1 ; test enable learn flag MWAF1.1 movlw 'L' ; learn indicator call putlcd return ; disp_a ; display async inj flag movlw ' ' ; assume not set btfsc aldl+.15, 4 ; test async inj flag flag MWAF1.4 movlw 'A' ; async indicator call putlcd return ; disp_i ; display idle flag movlw ' ' ; assume not set btfsc aldl+.1, 7 ; test idle flag MODE WORD 2.7 movlw 'I' ; Idle indicator call putlcd return ; ; disp_d ; display P/N flag, 0 = Drive movlw ' ' ; assume set btfss aldl+.17, 4 ; test P/N flag MCU2IO.4 movlw 'D' ; drive indicator call putlcd return ; disp_rl ; display rich / lean flag, 1 = Rich movlw 'R' ; assume set btfss aldl+.15, 6 ; test rich/lean MWAF1.6 movlw 'L' ; rich / lean indicators call putlcd return ; disp_lb ; display low battery flag movlw ' ' ; assume not set btfsc aldl+.15, 2 ; test low battery MWAF1.2 movlw 'B' ; low battery indicator call putlcd return ; disp_space movlw ' ' ; display one space goto putlcd ; disp_Wspaces movwf A0 ; display W number of spaces dws movlw ' ' ; display one space call putlcd decfsz A0, f goto dws return ; ; Display malfunction codes ; Not wery neat routine but it works ; disp_malf movf aldl+.12, w ; copy malfunction bytes to work register movwf mfflag movf aldl+.13, w movwf mfflag+1 movf aldl+.14, w movwf mfflag+2 clrf msgidx ; message index = 0 decf msgidx, f ; addjust index for first round movlw .24+1 ; set 3 bytes to bit counter movwf bitctr call lcdclr ; clear display movlw .20 ; print Code-message call string ; ; First LCD line malf1 decfsz bitctr, f ; test if all done goto malf2 goto malf99 ; yes, and no codes found malf2 incf msgidx ; uppdate message index clrc rlf mfflag+2, f ; test malfunction bits rlf mfflag+1, f ; starting from MALFFLAG1.7 rlf mfflag, f skpc goto malf1 ; continue error seek ; error found movf msgidx, w ; get current message index addlw emsg ; compute error message number call string ; display it movlw line2 ; change to second line and continue testing call lcdcur ; line 2 ; ; Second LCD line malf4 decfsz bitctr, f ; test if all done goto malf5 return ; yes malf5 incf msgidx ; uppdate message index clrc rlf mfflag+2, f ; test malfunction bits rlf mfflag+1, f rlf mfflag, f skpc goto malf4 ; continue error seek movlw .20 ; print Code-message call string movf msgidx, w ; get current message index addlw emsg ; compute error message number call string ; display it movlw line3 ; change to second line and continue testing call lcdcur ; line 3 ; ; Third LCD line malf7 decfsz bitctr, f ; test if all done goto malf8 return ; yes malf8 incf msgidx ; uppdate message index clrc rlf mfflag+2, f ; test malfunction bits rlf mfflag+1, f rlf mfflag, f skpc goto malf7 ; continue error seek movlw .20 ; print Code-message call string movf msgidx, w ; get current message index addlw emsg ; compute error message number call string ; display it movlw line4 ; change to second line and continue testing call lcdcur ; line 4 ; ; Fourth LCD line malf10 decfsz bitctr, f ; test if all done goto malf11 return ; yes malf11 incf msgidx ; uppdate message index clrc rlf mfflag+2, f ; test malfunction bits rlf mfflag+1, f rlf mfflag, f skpc goto malf10 ; continue error seek movlw .20 ; print Code-message call string movf msgidx, w ; get current message index addlw emsg ; compute error message number call string ; display it ; return ; We are out of display lines. Stop seeking error codes. ; malf99 movlw ' ' ; No codes found call putlcd movlw 'N' call putlcd movlw 'o' call putlcd return ; ;*************************************************************** ; ; Interrupt services. ; 160 Baud ALDL receiver ; flags.sync = 1 when sync pattern found. Bit must be cleared by application. ; flags.byte_rdy = 1 when character received. Bit must be cleared by application. ; rx_byte = received character. Must be read before next byte_rdy. ; Data is also stored in aldl_buff starting from sync. buff_ptr = buffer pointer. ; Rx_count shows # of characters received after last sync pattern (for diagnostics) ; ; irqserv ; movwf w_temp ; save W & status swapf status, w movwf status_temp movf fsr, w ; save fsr movwf fsr_temp ; ; test which interrupt bcf status, rp0 ; be shure we are in bank 0 btfss intcon, intf ; check if rb0 irq goto tmr1int ; was not rb0 irq, must be tmr1 ; ; ALDL data input RB0 interrupt at falling edge ; rb0int ; Data is sampled about 2 mS after start bit falling edge ; XTAL = 4.000 MHz => clock = 1.000 MHz, cycle = 1uS ; ; 2mS delay before sampling generated with TMR1 value 65536 - 2000 = 63536 0xF830. ; bcf intcon, intf ; reset irq flag movlw 0xF8 ; set TMR1 for 2 mS delay movwf tmr1H movlw 0x30 movwf tmr1L bcf pir1, tmr1if ; clear irq flag bsf t1con, tmr1on ; enable tmr1 goto irqret ; ; TMR1 interrupt do data sampling & receive bit ; tmr1int bcf pir1, tmr1if ; clear irq flag bcf t1con, tmr1on ; disable tmr1 ; if filter ; ; Do simple filtering for aldl (RB0) input line. ! very noicy input ; may lock this filter up ! ; test movlw fcount ; # of tests to determine B0 input state movwf int_temp btfss portb, 0 ; remember logical 1 = bit 0 ! goto test1 ; filter logical 1 test0 nop btfss portb, 0 ; check if still 0 goto test ; no restsrt filtering decfsz int_temp goto test0 clrc ; set 0 bit goto test9 test1 nop btfsc portb, 0 ; check if still 1 goto test ; no restart filtering decfsz int_temp goto test1 setc test9 ; it is 1 ; else ; ; simple aldl input line sampling without filtering ; clrc ; quess for 0 btfss portb, 0 ; check it setc ; data is 1 endif ; if diag bsf diag_io ; signal data sampling point endif ; rlf rx_buff, f ; shift bit in ; ; test if sync pattern received ; skpc goto rx_char incfsz rx_buff, w ; test if buffer was all ones goto rx_char ; ; sync received movlw .9 ; 160 baud character bit count movwf bit_count bsf flags, async ; set sync received flag ; movlw aldl_buff ; reset aldl buffer pointer movwf buff_ptr clrf rx_buff ; prevent false sync (first bit of first byte == 1) ; goto irqret ; rx_char decfsz bit_count, f ; test if all bits received goto irqret ; movlw .9 ; reset bit counter movwf bit_count movf buff_ptr, w ; set FSR movwf fsr movf rx_buff, w ; transfer ready character movwf rx_byte bsf flags, byte_rdy ; set byte ready flag ; incf rx_count, f ; increment character counter movwf indf ; store also to aldl buffer @ fsr ; movlw aldl_buffe ; one over xorwf buff_ptr, w ; do boundary check skpnz goto irqret ; stop at last buffer byte incf buff_ptr, f ; if not last byte increment buffer pointer clrf rx_buff ; prevent false sync (last bit of last byte == 1) ; irqret if diag bcf diag_io ; reset timing measurement output endif ; movf fsr_temp, w ; restore fsr movwf fsr swapf status_temp, w ; restore status & W movwf status swapf w_temp, f swapf w_temp, w ; retfie ; ;*************************************************************** ; ; LCD I/O routines ; ;****** ; CLKLCD clocks data/command to the lcd by making the EN line ; high then low. CLKLCD MACRO BSF lcdctr,LCDEN ; Lcd enable high BCF lcdctr,LCDEN ; Lcd enable low ENDM ;****** ; TABSET sets up the lcd table offset pointer before string output ; starts TABSET MACRO MOVLW b'11111111' ; Offset is incremented on each call to ; table - first call must generate zero value ; offset. MOVWF TABOFF ENDM ;****** ; POINT increments the string pointer offset and adds it to the ; PLC ready for string lookup POINT MACRO INCF TABOFF MOVFW TABOFF ADDWF PCL ENDM ;****** ; POINT6 increments the string pointer offset and adds it to the ; PLC ready for string lookup. Sets PCLATH to 3 POINT6 MACRO MOVLW .6 ; Page 6xx MOVWF PCLATH INCF TABOFF MOVFW TABOFF ADDWF PCL ENDM ;****** ; POINT4 increments the string pointer offset and adds it to the ; PLC ready for string lookup. Sets PCLATH to 4 ( for 16F877 etc) POINT7 MACRO MOVLW .7 MOVWF PCLATH INCF TABOFF MOVFW TABOFF ADDWF PCL ENDM ;-------------------------------------------------------------------------- ;****** ; STRING sends the string with number in W register - to the lcd STRING MOVWF STRNUM TABSET ; Xero the offset CALL DOSTR ; Character from string RETURN ;****** ; BCDLCD sends the bcd character in W to lcd BCDLCD IORLW b'00110000' ; Convert to ascii ;****** ; PUTLCD sends the ASCII character in W to lcd PUTLCD MOVWF LCDCH CALL CHALCD ; Character to lcd RETURN ; ;****** ; WAITGP waits for the number of ms in GP1 WAITGP MOVLW .74 ; 1ms DELAY CALL DL1 MOVLW .255 CALL DL1 DECF GP1 ; TOTAL DELAY N * 1 ms BNZ WAITGP ; Loop until delay is complete RETURN ; Exit from WAITGP ; wait100 movwf apu ; wait n * 100 ms W = delay wa101 movlw .100 movwf gp1 call waitgp ; wait 100 ms clrwdt ; feed watchdog during long delays decfsz apu goto wa101 return ;-------------------------------------------------------------------------- ; LCD Setup ;-------------------------------------------------------------------------- ; INITLCD ;****** ; Reset the lcd INITA MOVLW .20 ; Delay for 20 ms to let lcd settle MOVWF GP1 CALL WAITGP ; Wait for lcd MOVLW b'00000011' ; Reset MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW .6 ; Delay to let lcd settle MOVWF GP1 CALL WAITGP ; Wait for lcd MOVLW b'00000011' ; Reset MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW .5 ; Delay for 5 ms to let lcd settle MOVWF GP1 CALL WAITGP ; Wait for lcd MOVLW b'00000011' ; Reset MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW .5 ; Delay for 5 ms to let lcd settle MOVWF GP1 CALL WAITGP ; Wait for lcd MOVLW b'00000010' ; 4 bit interface MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW .5 ; Delay for 5 ms to let lcd settle MOVWF GP1 CALL WAITGP ; Wait for lcd MOVLW b'00000010' ; 4 bit interface MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW b'00001000' ; 2 LINES, 5*7 MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW .5 ; Delay for 5 ms to let lcd settle MOVWF GP1 CALL WAITGP ; Wait for lcd MOVLW b'00000000' ; Display OFF MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW b'00001000' ; MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW .5 ; Delay for 5 ms to let lcd settle MOVWF GP1 CALL WAITGP ; Wait for lcd MOVLW b'00000000' ; Display clear MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW b'00000001' ; MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW .5 ; Delay for 5 ms to let lcd settle MOVWF GP1 CALL WAITGP ; Wait for lcd MOVLW b'00000000' ; Entry mode set MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW b'00000110' ; MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW .5 ; Delay for 5 ms to let lcd settle MOVWF GP1 CALL WAITGP ; Wait for lcd MOVLW b'00000000' ; Display on MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW b'00001100' ; MOVWF lcddata ; Command to lcd port CLKLCD ; Clock the nibble to the lcd MOVLW .5 ; Delay for 5 ms to let lcd settle MOVWF GP1 CALL WAITGP ; Wait for lcd RETURN ; ;******************************************************************** ; Binary To BCD Conversion Routine ; The 16 bit binary number is input in locations H_byte and ; L_byte with the high byte in H_byte. ; The 5 digit BCD number is returned in R0, R1 and R2 with R0 ; containing the MSD in its right most nibble. ; B2_BCD bcf STATUS,0 ; clear the carry bit movlw .16 movwf count clrf R0 clrf R1 clrf R2 loop16 rlf L_byte, F rlf H_byte, F rlf R2, F rlf R1, F rlf R0, F ; decfsz count, F goto adjDEC goto bcdasc ; continue with ascii conv RETLW 0 ; adjDEC movlw R2 movwf FSR call adjBCD ; movlw R1 movwf FSR call adjBCD ; movlw R0 movwf FSR call adjBCD ; goto loop16 ; adjBCD movlw 3 addwf 0,W movwf temp btfsc temp,3 ; test if result > 7 movwf 0 movlw 0x30 addwf 0,W movwf temp btfsc temp,7 ; test if result > 7 movwf 0 ; save as MSD RETLW 0 ; ; continue with ASCII conversion bcdasc movf r2, w ; convert low order byte r0 movwf A1 andlw 0x0f addlw 0x30 ; low order nible = ASCII number movwf A0 swapf A1, w andlw 0x0f addlw 0x30 ; hi order nible = ASCII movwf A1 ; movf r1, w ; convert low order byte r1 movwf A3 andlw 0x0f addlw 0x30 ; low order nible = ASCII number movwf A2 swapf A3, w andlw 0x0f ; sets also Z-flag ; if zsup bz lzsup addlw 0x30 ; if non zero show number goto lz1 lzsup movlw 0x20 ; if zero replace with space lz1 movwf A3 else addlw 0x30 ; hi order nible = ASCII movwf A3 endif ; movf r0, w ; convert low order byte r2 andlw 0x0f addlw 0x30 ; hi order nible = ASCII movwf A4 ; save but dont care later ; retlw 0 ; ;************************************************************** ; display ascii result of bcd conversion ; disp5 if disp5d movf A4, w call putlcd endif movf A3, w ; display 4 digits call putlcd movf A2, w call putlcd movf A1, w call putlcd movf A0, w call putlcd retlw 0 ; ;************************************************************** ; Divide H_byte & L_byte by 16 or 8 ; div16 movlw .4 ; 4 * shift right = div by 16 goto div80 ; div8 movlw .3 ; 3 * shift right = div by 8 ; div80 movwf temp div81 clrc rrf h_byte, f rrf l_byte, f decfsz temp, f goto div81 retlw 0 ; div256 movf h_byte, w ; divide by 256 movwf l_byte clrf h_byte return ; ; 8 * 8 multiply. The 16 bit result is stored in 2 bytes ; Before calling the subroutine "mpy", the multiplier should ; be loaded in location "mulplr", and the multiplicand in ; "mulcnd". The 16 bit result is stored in locations ; H_byte & L_byte. mpy clrf H_byte clrf L_byte movlw 8 movwf count movf mulcnd, W bcf STATUS, C ; Clear the carry bit in the status Reg. loop rrf mulplr, F btfsc STATUS, C addwf H_byte, F rrf H_byte, F rrf L_byte, F decfsz count, F goto loop retlw 0 ; ;************************************ ; ; Part of LCD routine moved out from 0x300 page to get ; more room for messages ; ; LCD64/2 gives a delay of 64us or 1.6ms while the lcd accepts the ; data or command. LCD64 MOVLW .22 ; Gives 65 us delay GOTO DL1 ; LCD2 MOVLW .65 ; Gives 1.6ms delay CALL DL1 MOVLW .255 CALL DL1 MOVLW .255 GOTO DL1 ; DL1 MOVWF DLYCNT DL11 DECF DLYCNT, F BTFSS STATUS, Z GOTO DL11 RETLW .0 ; Exit from CHA/COMLCD routines ; ; ;-------------------------------------------------------------------------- ; Subroutines to handle the lcd ;-------------------------------------------------------------------------- ; CHALCD writes the character in W register to the lcd. ; On entry, the display character is in LCDCH. CHALCD ; Get the upper nibble and load to the lcd port SWAPF LCDCH,W ; Get the ms nibble to ls position ANDLW 07H ; Strip to ms nibble in ls position, ; and mask top bit in case this is the lset ; character in a string MOVWF lcddata ; Data to lcd port BSF lcdctr,LCDRS ; Select lcd data ; Clock the ms nibble to the lcd CLKLCD ; Get the lower nibble and load to the lcd port MOVFW LCDCH ; Get back the character ANDLW 0FH ; Strip to ms nibble in ls position MOVWF lcddata ; Data to lcd port BSF lcdctr,LCDRS ; Select lcd data ; Clock the ls nibble to the lcd. CLKLCD BCF lcdctr,LCDRS GOTO LCD64 ; Delay then exit from CHALCD ;***** ; COMLCD writes the command in W register to the lcd ; On entry, the command character is in LCDCH. COMLCD ; Get the upper nibble and load to the lcd port SWAPF LCDCH,W ; Get the ms nibble to ls position ANDLW 0FH ; Strip to ms nibble in ls position MOVWF lcddata ; Command to lcd port ; Clock the ms nibble to the lcd CLKLCD ; Get the lower nibble and load to the lcd port MOVFW LCDCH ; Get back the character ANDLW 0FH ; Strip to ms nibble in ls position MOVWF lcddata ; Command to lcd port ; Clock the ls nibble to the lcd. CLKLCD GOTO LCD2 ; Delay then exit from COMLCD ;****** ; LCDCL1R clears the display and resets the cursor LCDCLR MOVLW LCDCLER ; LCD clear command MOVWF LCDCH GOTO COMLCD ;****** ; LCDCUR sets cursor to position on using value in W register ; line1 - 4 are defined for 4 * 20 display ; LCDCUR IORLW LCDCM MOVWF LCDCH GOTO COMLCD ; ;-------------------------------------------------------------------------- ; ; Page select switch logic ; ;-------------------------------------------------------------------------- ; pagesw tstf db_counter ; debounce delay skpnz goto pagesw_test ; test switches only whwn dwlay expired decf db_counter, f ; do delay return ; pagesw_test btfsc sw ; check button pressed ? goto pagesw_open ; pagesw_closed ; 0 = button pressed = switch closed btfss swbit ; check if allready closed state ? return ; yes, do nothing. ; movlw db_delay ; set debounce delay movwf db_counter ; bcf swbit ; flag closed state movlw maxpage ; test if max reached xorwf dpage, w skpz ; yes goto pagesw_inc clrf dpage ; return to zero return ; pagesw_inc incf dpage, f ; increment counter return ; pagesw_open btfsc swbit ; check if allready open state ? return ; yes, do nothing. ; movlw db_delay ; set debounce delay movwf db_counter ; bsf swbit ; flag open state return ; ;-------------------------------------------------------------------------- ; ; 0x600 page of ROM ; ;-------------------------------------------------------------------------- ; Text strings and control subroutines must be stored on the correct ; page or this pcogram WILL NOT FUNCTION CORRECTLY. ; Only move code around if you are absoluteley clear as to what you ; are doing! ORG 0x600 ; First page for messages LAST EQU b'10000000' ; Value to add to last character in a string ;****** ; DOSTR uses CALLSTR table to direct flow to the correct lookup table ; for lcd strings. Gets string characters and outputs to lcd DOSTR MOVLW .6 ; 6xx Page MOVWF PCLATH ; Keep the pageing ok MOVFW STRNUM ; Get the string number CALL CALLSTR MOVWF LCDCH CALL CHALCD ; Character to lcd BTFSS LCDCH,7 ; Test if end of string flagged - bit 7 set GOTO DOSTR ; Loop until all sent RETURN ;****** ; CALLSTR is the dispatch table for lcd string lookup ; CALLSTR ADDWF PCL NOP ; 0 GOTO MSG1 ; 1'Banner display' GOTO MSG2 ; 2'version info' GOTO MSG3 ; 3'IAC' GOTO MSG4 ; 4'TMP' GOTO MSG5 ; 5'SPD' GOTO MSG6 ; 6'MAP' GOTO MSG7 ; 7'RPM' GOTO MSG8 ; 8'TPS' GOTO MSG9 ; 9'Int' GOTO MSG10 ; 10'O2 ' GOTO MSG11 ; 11'BLM' GOTO MSG12 ; 12'Occ' GOTO MSG13 ; 13'Bat' GOTO MSG14 ; 14'Cel' BLM cell GOTO MSG15 ; 15'PA3' GOTO MSG16 ; 16'Knock' GOTO MSG17 ; 17'Msg' ALDL message # GOTO MSG18 ; 18'Rxc' ALDL message character count GOTO MSG19 ; 19'Wait data' GOTO MSG20 ; 20'Code ' emsg equ .21 ; starting index for error messages ;aldl.12 / malfflg1 messages GOTO MSG27 ; 21'12 No ref pulse' GOTO MSG26 ; 22'13 oxygen sensor' GOTO MSG25 ; 23'14 coolant sensor high' GOTO MSG24 ; 24'15 coolant sensor low' GOTO MSG23 ; 25'21 TPS high' GOTO MSG22 ; 26'22 TPS low' GOTO MSG99 ; 27'23 xx' GOTO MSG24 ; 28'24 VSS' ; ;aldl.13 / malfflg2 messages GOTO MSG99 ; 29'25 xx' GOTO MSG32 ; 30'31 governor failure' GOTO MSG31 ; 31'32 EGR failure' GOTO MSG30 ; 32'33 MAP high' GOTO MSG29 ; 33'34 MAP low' GOTO MSG99 ; 34'35 xx' GOTO MSG99 ; 35'41 xx' GOTO MSG28 ; 36'42 EST monitor' ; ;aldl.14 / malfflg3 GOTO MSG39 ; 37'43 ESC failure' GOTO MSG38 ; 38'44 Oxy sensor lean' GOTO MSG37 ; 39'45 Oxy sensor rich' GOTO MSG36 ; 40'51 PROM Error' GOTO MSG35 ; 41'52 Cal Pack missing' GOTO MSG99 ; 42'53 xx' GOTO MSG34 ; 43'54 Fuel Pump Relay' GOTO MSG33 ; 44'55 ADU Error' ; GOTO MSG20 ; ; THE TEXT STRINGS! MSG1 POINT6 ; Use macro POINT6 when the string is in 0x600 ; address area RETLW '1' RETLW '6' RETLW '0' RETLW 'B' RETLW 'a' RETLW 'u' RETLW 'd' RETLW ' ' RETLW 'A' RETLW 'L' RETLW 'D' RETLW 'L' RETLW ' ' RETLW 'D' RETLW 'i' RETLW 's' RETLW 'p' RETLW 'l' RETLW 'a' RETLW 'y'+LAST ; MSG2 POINT6 RETLW 'v' RETLW ' ' RETLW '2' RETLW '.' RETLW '0' RETLW '2' RETLW ' ' RETLW 'J' RETLW 'N' RETLW 'i'+LAST ; MSG3 POINT6 RETLW 'I' RETLW 'A' RETLW 'C'+LAST ; MSG4 POINT6 RETLW 'T' RETLW 'M' RETLW 'P'+LAST ; MSG5 POINT6 RETLW 'S' RETLW 'P' RETLW 'D'+LAST ; MSG6 POINT6 RETLW 'M' RETLW 'A' RETLW 'P'+LAST ; MSG7 POINT6 RETLW 'R' RETLW 'p' RETLW 'm'+LAST ; MSG8 POINT6 RETLW 'T' RETLW 'P' RETLW 'S'+LAST ; MSG9 POINT6 RETLW 'I' RETLW 'n' RETLW 't'+LAST ; MSG10 POINT6 RETLW 'O' RETLW '2' RETLW ' '+LAST ; MSG11 POINT6 RETLW 'B' RETLW 'L' RETLW 'M'+LAST ; MSG12 POINT6 RETLW 'O' RETLW 'c' RETLW 'c'+LAST ; MSG13 POINT6 RETLW 'B' RETLW 'a' RETLW 't'+LAST ; MSG14 POINT6 RETLW 'C' RETLW 'e' RETLW 'l'+LAST MSG15 POINT6 RETLW 'P' RETLW 'A' RETLW '3'+LAST MSG16 POINT6 RETLW ' ' RETLW ' ' RETLW ' ' RETLW '!' RETLW ' ' RETLW 'K' RETLW 'n' RETLW 'o' RETLW 'c' RETLW 'k' RETLW ' ' RETLW '!'+LAST ; MSG17 POINT6 RETLW 'M' RETLW 's' RETLW 'g' + LAST ; MSG18 POINT6 RETLW 'R' RETLW 'x' RETLW 'c' + LAST ; MSG19 POINT6 RETLW 'W' RETLW 'a' RETLW 'i' RETLW 't' RETLW ' ' RETLW 'd' RETLW 'a' RETLW 't' RETLW 'a' + LAST ; MSG99 point6 dt "Er" ; General Error message dt 'r' + last ;-------------------------------------------------------------------------- ; 0x700 page of ROM ;-------------------------------------------------------------------------- org 0x700 ; Second page for messages ; MSG20 point7 dt "Code" dt 0x20 + last ; ; 12 MALFFLG1 ; 0 MALF CODE 24 VEHICLE SPEED SENSOR ; 1 (MALF CODE 23) ; 2 MALF CODE 22 THROTTLE POSITION SENSOR LOW ; 3 MALF CODE 21 THROTTLE POSITION SENSOR HIGH ; 4 MALF CODE 15 COOLANT SENSOR LOW ; 5 MALF CODE 14 COOLANT SENSOR HIGH ; 6 MALF CODE 13 OXYGEN SENSOR ; 7 MALF CODE 12 NO REFERENCE PULSES ; 13 MALFFLG2 ; 0 MALF CODE 42 ELECTRONIC SPARK TIMING MONITOR ERROR ; 1 (MALF CODE 41) ; 2 (MALF CODE 35) ; 3 MALF CODE 34 MAP SENSOR LOW ; 4 MALF CODE 33 MAP SENSOR HIGH ; 5 MALF CODE 32 EXHAUST GAS RECIRCULATION FAILURE ; 6 MALF CODE 31 GOVERNOR FAILURE ; 7 (MALF CODE 25) ; 14 MALFFLG3 ; 0 MALF CODE 55 ADU ERROR ; 1 MALF CODE 54 FUEL PUMP RELAY FAILURE ; 2 (MALF CODE 53) ; 3 MALF CODE 52 CAL PACK MISSING ; 4 MALF CODE 51 PROM ERROR ; 5 MALF CODE 45 OXYGEN SENSOR RICH ; 6 MALF CODE 44 OXYGEN SENSOR LEAN ; 7 MALF CODE 43 ELECTRONIC SPARK CONTROL FAILURE ; ; MALFFLG1 codes ; MSG21 point7 dt "24 VS" ; bit 0 dt 'S' + last ; MSG22 point7 dt "22 TPS " ; bit 2 dt 'L' + last ; MSG23 point7 dt "22 TPS " ; bit 3 dt 'H' + last ; MSG24 point7 dt "15 COOL " ; bit 4 dt 'L' + last ; MSG25 point7 dt "14 COOL " ; bit 5 dt 'H' + last ; MSG26 point7 dt "13 OX" ; bit 6 dt 'Y' + last ; MSG27 point7 dt "12 NO REF " ; bit 7 dt 'P' + last ; ; MALFFLG2 codes ; MSG28 point7 dt "42 ES" ; bit 0 dt 'T' + last ; MSG29 point7 dt "34 MAP " ; bit 3 dt 'L' + last ; MSG30 point7 dt "33 MAP " ; bit 4 dt 'H' + last ; MSG31 point7 dt "32 EG" ; bit 5 dt 'R' + last ; MSG32 point7 dt "31 GV" ; bit 6 dt 'R' + last ; ; MALFFLG3 codes ; MSG33 point7 dt "55 AD" ; bit 0 dt 'U' + last ; MSG34 point7 dt "54 FP RL" ; bit 1 dt 'Y' + last ; MSG35 point7 dt "52 CAL " ; bit 3 dt 'P' + last ; MSG36 point7 dt "51 PRO" ; bit 4 dt 'M' + last ; MSG37 point7 dt "45 OXY " ; bit 5 dt 'R' + last ; MSG38 point7 dt "44 OXY " ; bit 6 dt 'L' + last ; MSG39 point7 dt "43 ES" ; bit 7 dt 'C' + last ; END