/*** Megaview v1.2 --- B.A.Bowling And A.C.Grippo ***/ // v1.1 - first release version // v1.2 - identical to v1.1 but provides a #define for converting // coolant and MAT to Celsius #include #include #include "defs.h" #include "Gp32.h" #pragma DATA_SEG _DATA_ZEROPAGE // To use Celsius instead of Farenheit, define below as 1 // and change the DispVarUpperStrng to CLT(C) and MAT(C) #define CELSIUS 0 #define DISPLAY 0 #define CONTROL 1 #define NO_DISP_BYTES_FROM_ECU 22 #define NO_CTRL_BYTES_FROM_ECU 125 #define NUM_CTL_VARIABLES 122 #define CHR 0 #define UCH 1 #define SHT 2 #define USH 3 #define ULG 4 #define FLT 5 #define MAX_COLS 20 #define MAX_VFD_STRLEN strlen(DispVarUpperStrng) /*============================ PORT VARIABLES ================================*/ /* The Address of all Ports Data Registers */ volatile U8* PortDataReg[] = { pPTA, pPTB, pPTC, pPTD, pPTE }; /* The Address of all Ports Data Registers */ volatile U8* PortDirecReg[] = { pDDRA, pDDRB, pDDRC, pDDRD, pDDRE }; /****************************************************************************** * Macro : PortRead * Description : Reads a data bit from a port. * * Input Parameters: U8 PortId * port identifier : PORT_A,PORT_B,PORT_C,PORT_D * PORT_E,PORT_F,PORT_G,PORT_H * U8 Bit * The Bit of the port to read from * * Return Value : U8 Value * The value of the port bit * ******************************************************************************/ #define PortRead(PortId, Bit) (((*PortDataReg[PortId]) & (0x1 << Bit)) >> Bit) /****************************************************************************** * Macro : PortSetDir * Description : Configures all the Port's Direction pins as input or output pins. * * Input Parameters : * 1. U8 PortId Port Identifier: * PORT_A,PORT_B,PORT_C,PORT_D * PORT_E,PORT_F,POR_G,PORT_H * 2. U8 IoMode: * The mode (INPUT/OUTPUT) of the port * * Return Value : None * * Example : Port a configure as an input: * PortSetDir(PORT_A,INPUT); * Port a configure as an output: * PortSetDir(PORT_A,OUTPUT_PORT); * ******************************************************************************/ #define PortSetDir(PortId,IoMode) (*PortDirecReg[PortId]) = IoMode /****************************************************************************** * Macro : PortWrite * Description : Write a data bit to a port. * * Input Parameters: 1. U8 PortId Port Identifier: * PORT_A,PORT_B,PORT_C,PORT_D * PORT_E,PORT_F,PORT_G,PORT_H * 2. U8 Bit * The bit # of the port to write to * ******************************************************************************/ #define PortSet(PortId, Bit) (*PortDataReg[PortId]) |= (0x1 << Bit) #define PortClr(PortId, Bit) (*PortDataReg[PortId]) &= ~(0x1 << Bit) U8 select,freeze,mode,modeChange; U8 ibyte,no_xbytes,xmtbuf[6],no_rbytes,rcvbuf[NO_DISP_BYTES_FROM_ECU + 2]; U8 controlRcv,curr_var_no; U8 irpm,ikpa,VFDDisp_flg; // display variables U8 secl,secl_last; unsigned short seconds; U8 alarm_alt; short colix; union all_types { char chr; U8 uch; short sht; float flt; } control_var_val; U8 ctl_var_ecu_val, ctl_var_ecu_val2; U8 kparnge[8],rpmrnge[8]; U8 debounce,map_type,get_config; short changed_ctl_var; U8 incr_count,decr_count; U8 dim,rcv_timeout,sem; #pragma DATA_SEG DEFAULT #include "table.h" #include "asc_table.h" const U8 DispVarUpperStrng[] = { " SECS ENGINE WRMENRCH ACCENRCH RPM PW(MS) MAP(KPA) BARO(KPA)\ CLT(F) MAT(F) TPS(V) BAT(V) EGO(V) EGOCOR(%) AIRCOR(%)\ BARCOR(%) VECOR(%) WRMCOR(%) ACCOR(MS) GAMMA(%)" }; const U8 DispVarLowerStrng[] = { " 00 \ \ " }; const U8 SelectStrng[MAX_COLS + 1] = {" Selected: "}; const U8 BlnkStrng[MAX_COLS + 1] = {" "}; const U8 CtlVarStrng[NUM_CTL_VARIABLES - 64][MAX_COLS + 2] = { "CRNK ENRCH_L=%4.1f ms", "CRNK ENRCH_H=%4.1f ms", " AFT WRM PCT=%3u ", " AFT WRM EVTS=%3u ", " WRMUP[-40]PCT=%3u ", " WRMUP[-20]PCT=%3u ", " WRMUP[ 0]PCT=%3u ", " WRMUP[ 20]PCT=%3u ", " WRMUP[ 40]PCT=%3u ", " WRMUP[ 60]PCT=%3u ", " WRMUP[ 80]PCT=%3u ", " WRMUP[100]PCT=%3u ", " WRMUP[130]PCT=%3u ", " WRMUP[160]PCT=%3u ", "TPSAQ[1 V/S]=%4.1f ms", "TPSAQ[4 V/S]=%4.1f ms", "TPSAQ[8 V/S]=%4.1f ms", "TPSAQ[15V/S]=%4.1f ms", " TPSACOLD=%4.1f ms ", " TPSTHRESH=%3u ", " TPSASYNC=%4.1f sec ", " TPSDECEL=%3u ", " EGOTEMP=%4d F ", " EGOCOUNTCMP=%3u ", " EGODELTA=%3u ", " EGOLIMIT=%3u ", " REQFUEL=%4.1f ms ", " DIVIDER=%3u ", " ALTERNATE=%3s ", " INJOPEN=%4.1f ms ", " INJPWM=%3u ", " INJPWMT=%4.1f ms ", " BATTFAC=%4.1f ms ", " RPMK=%5d ", " RPM FOR VE[1]=%5d ", " RPM FOR VE[2]=%5d ", " RPM FOR VE[3]=%5d ", " RPM FOR VE[4]=%5d ", " RPM FOR VE[5]=%5d ", " RPM FOR VE[6]=%5d ", " RPM FOR VE[7]=%5d ", " RPM FOR VE[8]=%5d ", " KPA FOR VE[1]=%3u ", " KPA FOR VE[2]=%3u ", " KPA FOR VE[3]=%3u ", " KPA FOR VE[4]=%3u ", " KPA FOR VE[5]=%3u ", " KPA FOR VE[6]=%3u ", " KPA FOR VE[7]=%3u ", " KPA FOR VE[8]=%3u ", " CONFIG1=%3u ", " CONFIG2=%3u ", " CONFIG3=%3u ", " PRIME PLSE=%4.1f ms ", " RPM OXLIM=%5d rpm ", " FAST IDLE=%4d F ", " VOLT OXTGT=%4.1f V ", " ACC CLD MULT=%3u " }; const U8 ctl_var_offset[NUM_CTL_VARIABLES] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 95, 96, 97, 98, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123 }; const U8 ctl_var_type[NUM_CTL_VARIABLES] = { UCH,UCH,UCH,UCH, UCH,UCH,UCH,UCH, UCH,UCH,UCH,UCH, UCH,UCH,UCH,UCH, UCH,UCH,UCH,UCH, UCH,UCH,UCH,UCH, UCH,UCH,UCH,UCH, UCH,UCH,UCH,UCH, UCH,UCH,UCH,UCH, UCH,UCH,UCH,UCH, UCH,UCH,UCH,UCH, UCH,UCH,UCH,UCH, UCH,UCH,UCH,UCH, UCH,UCH,UCH,UCH, UCH,UCH,UCH,UCH, UCH,UCH,UCH,UCH, FLT,FLT,UCH,UCH, UCH,UCH,UCH,UCH, UCH,UCH,UCH,UCH, UCH,UCH,FLT,FLT, FLT,FLT,FLT,UCH, FLT,UCH,SHT,UCH, UCH,UCH,FLT,UCH, UCH,FLT,UCH,FLT, FLT,SHT,SHT,SHT, SHT,SHT,SHT,SHT, SHT,SHT,UCH,UCH, UCH,UCH,UCH,UCH, UCH,UCH,UCH,UCH, UCH,FLT,SHT,SHT, FLT,UCH }; U8 VFDLower[sizeof(DispVarLowerStrng)]; // Prototypes void SystemInit(void); void SciInit(void); interrupt void SciTxIntHand(void); interrupt void SciRxIntHand(void); void PortAInit(void); void PortBInit(void); void PortCInit(void); void PortDInit(void); void KbiInit(void); interrupt void KbiHand(void); void ModeIsr(void); void ModeChange(void); void SelectIsr(void); void IncrIsr(void); void DecrIsr(void); interrupt void GetDispIsr(void); void VFDInit(void); void VFDDisplay(void); void VFDConvert(char sw); void VFDsprintf(U8 *bufo, U8 type, U8 neg, U8 width, U8 *bufi, U8 alarm); void VFDSend(char line, char col, char value); void VFDData(char value); void main(void) { U8 ix,jx,kx; // Configure system and set up clock SystemInit(); // Set up rs232 SciInit(); // Initialize variables modeChange = 0; select = 0; freeze = 0; colix = 0; secl_last = 0; seconds = 0; strcpy(VFDLower, DispVarLowerStrng); VFDDisp_flg = 0; debounce = 0; alarm_alt = 0; rcv_timeout = 0; sem = 0; // Set up VFD control line I/O PortBInit(); PortCInit(); PortDInit(); // Delay while power stabilizes, allow MS and VFD to come up for(ix=0;ix<5;ix++) { for(jx=0;jx<200;jx++) { for(kx=0;kx<200;kx++) { asm nop; } } } // Enable CPU Global Interrupts asm CLI; // Set up VFD dim = PortRead(PORT_B,0); VFDInit(); // Set up buttons (Inputs - enable pullups) PortAInit(); KbiInit(); // enable interrupts mode = CONTROL; // Set up and turn on 4 Hz interrupt timer (Timebase Module) TBCR = 0x10; // set 4 Hz TBCR |= 0x06; // turn on and enable interrupt // Get config data from ECU get_config = 1; curr_var_no = 0; incr_count = 0; decr_count = 0; ibyte = 0; xmtbuf[0] = 'V'; no_xbytes = 1; SCC2 |= SCI_Tx_INT_ENABLE; // enable xmt interrupt register ix = SCS1; SCDR = xmtbuf[0]; while(get_config); mode = DISPLAY; // idle while(1) { if(VFDDisp_flg) { VFDDisplay(); VFDDisp_flg = 0; } if(mode == CONTROL) { // incr/scroll button auto repeat if(incr_count >= 2) { incr_count = 1; if(!select) { debounce = 0; sem = 1; IncrIsr(); sem = 0; } } if(decr_count >= 2) { decr_count = 1; if(!select) { debounce = 0; sem = 1; DecrIsr(); sem = 0; } } } } // end while(1) } interrupt void SwiHand(void) { } interrupt void NullHand(void) { } /*================================== VARIABLES ================================*/ /* gPllLockState - Global Var that hold the PLL lock state PLL_LOCKED or PLL_UNLOCKED; */ static char gPllLockState = PLL_UNLOCKED; /****************************************************************************** * FUNCTION : SystemInit * System Initialization ******************************************************************************/ void SystemInit(void) { #define DELAY_TIME 10 U8 i; /* Set the CONFIG1 Option Register */ CONFIG1 = ( COP_TIMOUT_LONG | /* Set the COP rate */ LVI_DISABLE_IN_STOP | /* Set the LVI mode during stop mode */ LVI_RESET_DISABLE | /* (MOR=CONFIG1) Set the LVI Reset Enable Bit */ LVI_POWERD_DISABLE | /* (MOR=CONFIG1) Set the LVI Power Enable Bit */ LVI_IN_5_V | /* Set the LVI to 5v/3v operating voltage */ SLOW_RECOVERY_FROM_STOP | /* Set fast/slow recover time from stop mode */ MOR_STOP_ENABLE | /* (MOR=CONFIG1) Set the stop mode */ DISABLE_COP_MODULE ); /* (MOR=CONFIG1) Set the COP module */ /* Set oscillator mode during stop mode */ CONFIG2 = ( OSCI_IN_STOP_DISABLE | SCI_INTERNAL_BUS_CLOCK ); /* set the baud rate source for the sci */ /* Initialize the IRQ Status and Control Register */ ISCR = ( IRQ1_ENABLE | /* Enable/disable IRQ */ IRQ_FALLING_EDGE_AND_LEVEL /* IRQ signal Sensitivity */ ); /* Init the PLL Bandwidth Control Register */ PBWC = ( PLL_AUTOMATIC_CONTROL /* Set The AUTO - Automatic Bandwidth Control Bit */ ); /* The PLL control register (PCTL) contains the interrupt enable and flag bits, the on/off switch, and the base clock selector bit. */ PCTL &= ~PLL_ON; /* Turn off to set up bus freq = 7.3728 MHz */ PCTL |= 0x2; PMSH =0x3; PMSL = 0x84; PMRS = 0xC0; PMDS = 0x1; PCTL = ( PLL_INTERRUPT_DISABLED | /* Set PLLIE - PLL Interrupt Enable Bit */ PLL_ON ); /* Set PLLON - PLL On/Off Bit */ /* After toggling BCS, it may take up to three CGMXCLK and three CGMVCLK cycles to complete the transition from one source clock to the other. */ for ( i = 0 ; i < DELAY_TIME ; i++ ); /* Delay */ PCTL |= PLL_VCO_ENABLE ; /* Set BCS - Base Clock Select Bit */ for ( i = 0 ; i < DELAY_TIME ; i++ ); /* Delay */ /* Break Module */ /* Init the SIM Break Flag Control Register */ SBFCR = STATUS_BITS_NOT_CLEARABLE; return; } /****************************************************************************** * FUNCTION : SciInit * Initial for the Sci module ******************************************************************************/ void SciInit(void) { CONFIG2 |= SCI_INTERNAL_BUS_CLOCK; /* set the clock source for the baud rate */ SCC1 = ENABLE_SCI; /* Enable the sci module */ SCC1 |= ( SCI_LOOP_DISABLE | /* Enable/disable loop mode */ SCI_TRANSMIT_UNINVERTED | /* Transmit character inverted/not inverted */ SCI_8_BIT_DATA | /* Set character length to 8/9 bits */ SCI_IDLE_WAKEUP | /* Wakeup by address mark/idle line */ SCI_IDLE_AFTER_START | /* Begin idle character bit count after stop/start bit */ SCI_DISABLE_PARITY | /* Enable/disable parity function */ SCI_ODD_PARITY ); /* Select odd/even as parity */ /* This register initialize interrupts request activate the transmitter and receiver and wakeup mode */ SCC2 = ( SCI_Tx_INT_DISABLE | /* Enable/disable transmitter empty interrupt */ SCI_INT_TRAN_COMP_DISABLE | /* Enable/disable transmitter complete interrupt */ SCI_Rx_INT_DISABLE | /* Enable/disable receiver full interrupt */ SCI_INT_IDLE_DISABLE | /* Enable/disable receiver idle interrupt */ SCI_TRANSMITTER_ENABLE | /* Enable/disable transmitter */ SCI_RECEIVER_ENABLE | /* Enable/disable receiver */ SCI_RWU_NORMAL ); /* Enable/disable wakeup mode */ /* This register initialize the DMA services and error interrupts */ SCC3 = ( SCI_DMA_FOR_REC_DISABLE | /* Enable/disable receive DMA service */ SCI_DMA_FOR_TRAN_DISABLE | /* Enable/disable transfer DMA service */ SCI_INT_REC_OVERUN_DISABLE | /* Enable/disable receiver overrun interrupt */ SCI_INT_REC_NOISE_DISABLE | /* Enable/disable receiver noise error interrupt */ SCI_INT_REC_FRAME_DISABLE | /* Enable/disable receiver frame error interrupt */ SCI_INT_REC_PARITY_DISABLE ); /* Enable/disable receiver parity error interrupt */ /* This register sets baud rate to 9600 at bus freq = 7.3728 MHz */ SCBR = ( SCI_PD_DIV_BY_3 | SCI_BD_DIV_BY_4 ); } /****************************************************************************** * FUNCTION : SciTxIntHand * Transmitter interrupt handler, cpu will get here when TEIE bit set in * SCC2 ******************************************************************************/ interrupt void SciTxIntHand(void) { // Enter here when the rs232 transmit buffer is empty U8 Status ; ibyte++; if(ibyte < no_xbytes) { // clear status register (by read) to allow next interrupt Status=SCS1; // transfer transmit byte from buffer to register SCDR = xmtbuf[ibyte]; } else { // Done transmitting - kill transmit buffer empty interrupt SCC2 &= (~SCI_Tx_INT_ENABLE); if(mode == DISPLAY) { // Display mode // Set up to receive the requested display data ibyte = 0; no_rbytes = NO_DISP_BYTES_FROM_ECU; SCC2 |= SCI_Rx_INT_ENABLE; // enable receiver full interrupt } else if(xmtbuf[0] != 'B') { // Control mode // Set up to receive the requested control data ibyte = 0; no_rbytes = NO_CTRL_BYTES_FROM_ECU; rcv_timeout = 1; SCC2 |= SCI_Rx_INT_ENABLE; // enable receiver full interrupt } } return; } /****************************************************************************** * FUNCTION : SciRxIntHand * Receiver interrupt handler ******************************************************************************/ interrupt void SciRxIntHand(void) { U8 Status,readbuf; // Enter here when have received rs232 byte // clear status register to allow next interrupt Status = SCS1; // transfer received byte from register to buffer readbuf = SCDR; if(get_config) { if(ibyte == 116) { map_type = readbuf & 0x03; } } else if(mode == DISPLAY) rcvbuf[ibyte] = readbuf; else { if (ibyte == ctl_var_offset[curr_var_no]) rcvbuf[0] = readbuf; if (ibyte == 99) rcvbuf[1] = readbuf; // 2nd half of rpm coeff (for ncyl) if((ibyte >= 100) && (ibyte <= 107)) rpmrnge[ibyte - 100] = readbuf; if((ibyte >= 108) && (ibyte <= 115)) kparnge[ibyte - 108] = readbuf; } ibyte++; if(ibyte < no_rbytes) { return; } else { // Done receiving - kill receive interrupt enable SCC2 &= (~SCI_Rx_INT_ENABLE); rcv_timeout = 0; if(get_config) { get_config = 0; return; } if(mode == CONTROL) controlRcv = 1; // Check if mode change desired. If so, can change mode now // without getting ecu comms out of synch if(modeChange) { ModeChange(); } else { // convert data to engineering units, put in VFD // display string, and write/ scroll across VFD VFDDisp_flg = 1; } } return; } /****************************************************************************** * FUNCTION : PortAInit * Port A Initialization ******************************************************************************/ void PortAInit(void) { /* Set global Var with Registers Address */ PortDirecReg[PORT_A] = pDDRA ; PortDataReg[PORT_A] = pPTA ; /* Set all Data Pin to 0 */ PTA = 0; /* Set Data direction Port to input for bits 0-3 */ DDRA = 0xF0; /* Set Pullup Enables for bits 0 - 3 (buttons) Bit 0 Scroll Left/ Decrease Bit 1 Scroll Right/ Increase Bit 2 Select/ Freeze Bit 3 Mode Button */ PTAPUE = 0x0F; } /****************************************************************************** * FUNCTION : PortBInit * Port B Initialization ******************************************************************************/ void PortBInit(void) { /* Set global Var with Registers Address */ PortDirecReg[PORT_B] = pDDRB ; PortDataReg[PORT_B] = pPTB ; /* Set all Data Pin to 0 */ PTB = 0; /* Set Data direction Port to: input for bit 0; outputs for bits 4-6 VFD Control lines: Bit 0 Dimming Bit 4 Enable Bit 5 R/W Bit 6 RS */ DDRB = 0xFE; } /****************************************************************************** * FUNCTION : PortCInit * Port C Initialization ******************************************************************************/ void PortCInit(void) { /* Set global Var with Registers Address */ PortDirecReg[PORT_C] = pDDRC ; PortDataReg[PORT_C] = pPTC ; /* Set all Data Pin to 0 */ PTC = 0; /* Set Data direction Port to ouputs for bits 0-3 VFD data bits: Bit 0 DB4 Bit 1 DB5 Bit 2 DB6 Bit 3 DB7 */ DDRC = 0xFF; } /****************************************************************************** * FUNCTION : PortDInit * Port D Initialization ******************************************************************************/ void PortDInit(void) { /* Set global Var with Registers Address */ PortDirecReg[PORT_D] = pDDRD ; PortDataReg[PORT_D] = pPTD ; /* Set all Data Pin to 0 */ PTD = 0; /* Set Data direction Port to output for bit 4 */ DDRD = 0xFF; // LCD contrast } /****************************************************************************** * FUNCTION : KbiInit * Kbi initialization ******************************************************************************/ #define KbiWriteAcknowledge() INTKBSCR |= ( KBI_ACKNOWLEDGE ) void KbiInit(void) { /* Initialize status and control register */ INTKBSCR = ( DISABLE_KBI_INT | /* Set the musk interrupt bit */ KBI_INT_ON_FALLING); /* Set the sensitivity of the keyboard */ /* Initialize the keyboard interrupt register */ INTKBIER = ( ENABLE_KBI_INT_0 | /* Enable/Disable keyboard interrupt 0 */ ENABLE_KBI_INT_1 | /* Enable/Disable keyboard interrupt 1 */ ENABLE_KBI_INT_2 | /* Enable/Disable keyboard interrupt 2 */ ENABLE_KBI_INT_3 | /* Enable/Disable keyboard interrupt 3 */ DISABLE_KBI_INT_4 | /* Enable/Disable keyboard interrupt 4 */ DISABLE_KBI_INT_5 | /* Enable/Disable keyboard interrupt 5 */ DISABLE_KBI_INT_6 | /* Enable/Disable keyboard interrupt 6 */ DISABLE_KBI_INT_7 ); /* Enable/Disable keyboard interrupt 7 */ KbiWriteAcknowledge(); /* Enable the keyboard interrupts */ INTKBSCR &= ~( DISABLE_KBI_INT ); /* clear the musk interrupt bit */ return; } /****************************************************************************** * FUNCTION : KbiHand * KBI interrupt Handler ******************************************************************************/ interrupt void KbiHand(void) { U8 Status; if(!debounce) { debounce = 2; /* Determine which button pushed */ if(PortRead(PORT_A,3) == 0) ModeIsr(); else if(PortRead(PORT_A,2) == 0) SelectIsr(); else if(PortRead(PORT_A,1) == 0) { if(!sem)IncrIsr(); } else if(PortRead(PORT_A,0) == 0) { if(!sem)DecrIsr(); } } else Status = PortRead(PORT_A,0); // read to clear /* Write an Acknowledge to clear the interrupt flag */ KbiWriteAcknowledge(); return; } void ModeIsr(void) { // Enter here when push Mode button if(mode == DISPLAY) { // Set flag so when current rs232 rcv transaction done, will // call ModeChange modeChange = 1; } else { if(!controlRcv) { // havn't got ctl data yet from ecu // Set flag so when current rs232 rcv transaction done, will // call ModeChange modeChange = 1; } else { ModeChange(); } } return; } void ModeChange(void) { U8 Status; modeChange = 0; if(mode == DISPLAY) { // Switch to Control Mode mode = CONTROL; select = 0; controlRcv = 0; // havn't got ctl data yet from ecu // Transmit request for all control variable values ibyte = 0; xmtbuf[0] = 'V'; no_xbytes = 1; SCC2 |= SCI_Tx_INT_ENABLE; // enable xmt interrupt register Status = SCS1; SCDR = xmtbuf[0]; } else { // Switch to Display Mode mode = DISPLAY; if(!freeze) colix = 0; strcpy(VFDLower, DispVarLowerStrng); VFDDisp_flg = 0; } return; } void SelectIsr(void) { char col; U8 Status; // Enter here when push freeze/select button' if(mode == DISPLAY) { freeze = 1 - freeze; } else { // Control Mode select = 1 - select; if(select) { changed_ctl_var = 0; // Indicate Control is Selected, so // incr/decr will change value. // send out top line for(col=0; col < MAX_COLS; col++) { VFDSend(0,col,SelectStrng[col]); } } else { // Have just unselected - check if have made a net change if(changed_ctl_var) { // Burn change into flash ibyte = 0; xmtbuf[0] = 'B'; no_xbytes = 1; SCC2 |= SCI_Tx_INT_ENABLE; // enable xmt interrupt register Status = SCS1; SCDR = xmtbuf[0]; } // Indicate Control is Not Selected, so // incr/decr will cause scrolling // send out top line for(col=0; col < MAX_COLS; col++) { VFDSend(0,col,BlnkStrng[col]); } } } return; } void IncrIsr(void) { // Enter here when push incr or scroll right button short test; long testl; float testf; U8 Status; if(mode == DISPLAY)return; if(select && !rcv_timeout) { // control variable has been selected, // therefore want to increase value changed_ctl_var++; if(ctl_var_type[curr_var_no] == UCH) { test = control_var_val.uch + 1; if((curr_var_no == 92) && (test > 1))test = 0; if((curr_var_no == 94) && (test > 100))test = 100; if(test < 256) control_var_val.uch = test; } else if(ctl_var_type[curr_var_no] == SHT) { if((curr_var_no < 97) || (curr_var_no == 119)) { // temps testl = control_var_val.sht + 1; if(testl > 215)testl = 215; } else if(curr_var_no == 97) { // rpmk testl = control_var_val.sht + 1; if(testl > 24000)testl = 24000; } else { // rpms for ve table testl = control_var_val.sht + 100; if(curr_var_no != 118) { if(testl > 25500)testl = 25500; } else { if(testl > 10000)testl = 10000; // rpmoxlimit } } control_var_val.sht = testl; } else if(ctl_var_type[curr_var_no] == FLT) { testf = control_var_val.flt + 0.1; if(curr_var_no != 120) { if(testf > 25.5)testf = 25.5; } else { if(testf > 5.0)testf = 5.0; // voltoxtgt } control_var_val.flt = testf; } controlRcv = 0; // havn't got ctl data yet from ecu // Transmit request to write, then rdbk all ctl vars ibyte = 0; xmtbuf[0] = 'W'; xmtbuf[1] = ctl_var_offset[curr_var_no]; VFDConvert(2); // This takes control_var_val and converts // to ECU units (ctl_var_ecu_val) xmtbuf[2] = ctl_var_ecu_val; if(curr_var_no != 97) { no_xbytes = 3; } else { xmtbuf[3] = ctl_var_ecu_val2; no_xbytes = 4; } xmtbuf[no_xbytes] = 'V'; no_xbytes++; SCC2 |= SCI_Tx_INT_ENABLE; // enable xmt interrupt register Status = SCS1; SCDR = xmtbuf[0]; } else { // control variable not selected, therefore want // to scroll right if(!rcv_timeout) { curr_var_no++; // disallow rpmk, configs if(curr_var_no == 97)curr_var_no++; if(curr_var_no == 114)curr_var_no = 117; if(curr_var_no >= NUM_CTL_VARIABLES) curr_var_no = 0; controlRcv = 0; // havn't got ctl data yet from ecu // Transmit request for all control variable values ibyte = 0; xmtbuf[0] = 'V'; no_xbytes = 1; SCC2 |= SCI_Tx_INT_ENABLE; // enable xmt interrupt register Status = SCS1; SCDR = xmtbuf[0]; } } return; } void DecrIsr(void) { // Enter here when push decr or scroll left button short test; long testl; float testf; U8 Status; if(mode == DISPLAY)return; if(select && !rcv_timeout) { // control variable has been selected, // therefore want to decrease value changed_ctl_var--; if(ctl_var_type[curr_var_no] == UCH) { test = control_var_val.uch - 1; if((curr_var_no == 92) && (test < 0))test = 1; if(test >= 0) control_var_val.uch = test; } else if(ctl_var_type[curr_var_no] == SHT) { if((curr_var_no < 97) || (curr_var_no == 119)) { // temps testl = control_var_val.sht - 1; if(testl < -40)testl = -40; } else if(curr_var_no == 97) { // rpmk testl = control_var_val.sht - 1; if(testl < 325)testl = 325; } else { // rpms for ve table,rpmoxlim testl = control_var_val.sht - 100; if(testl < 0)testl = 0; } control_var_val.sht = testl; } else if(ctl_var_type[curr_var_no] == FLT) { testf = control_var_val.flt - 0.1; if(testf < 0.0)testf = 0.0; control_var_val.flt = testf; } controlRcv = 0; // havn't got ctl data yet from ecu // Transmit request to write, then rdbk all ctl vars ibyte = 0; xmtbuf[0] = 'W'; xmtbuf[1] = ctl_var_offset[curr_var_no]; VFDConvert(2); // This takes control_var_val and converts // to ECU units (ctl_var_ecu_val) xmtbuf[2] = ctl_var_ecu_val; if(curr_var_no != 97) { no_xbytes = 3; } else { xmtbuf[3] = ctl_var_ecu_val2; no_xbytes = 4; } xmtbuf[no_xbytes] = 'V'; no_xbytes++; SCC2 |= SCI_Tx_INT_ENABLE; // enable xmt interrupt register Status = SCS1; SCDR = xmtbuf[0]; } else { // control variable not selected, therefore want // to scroll left if(!rcv_timeout) { if(curr_var_no == 0) curr_var_no = NUM_CTL_VARIABLES; curr_var_no--; // disallow rpmk, configs if(curr_var_no == 97)curr_var_no--; if(curr_var_no == 116)curr_var_no = 113; controlRcv = 0; // havn't got ctl data yet from ecu // Transmit request for all control variable values ibyte = 0; xmtbuf[0] = 'V'; no_xbytes = 1; SCC2 |= SCI_Tx_INT_ENABLE; // enable xmt interrupt register Status = SCS1; SCDR = xmtbuf[0]; } } return; } interrupt void GetDispIsr(void) { U8 Status; // Enter here every 0.25 seconds // acknowledge TBM interrupt (to clear interrupt flag) TBCR |= 0x08; if(debounce > 0)debounce--; // incr/scroll button auto repeat if(mode == CONTROL) { if(PortRead(PORT_A,1) == 0) incr_count++; else incr_count = 0; if(PortRead(PORT_A,0) == 0) decr_count++; else decr_count = 0; } // Check for receiver timeout if(rcv_timeout) { rcv_timeout++; if(rcv_timeout > 8) { // 2 sec timeout // Re-transmit ibyte = 0; SCC2 |= SCI_Tx_INT_ENABLE; Status = SCS1; SCDR = xmtbuf[0]; } } if(mode != DISPLAY) return; // Set up to transmit request for all display data. // At end of transmit, will automatically set up for // receiving the data, then displaying it. ibyte = 0; xmtbuf[0] = 'A'; no_xbytes = 1; // enable transmit interrupt register SCC2 |= SCI_Tx_INT_ENABLE; Status = SCS1; SCDR = xmtbuf[0]; return; } void VFDInit(void) { // RS = R/W = EN = 0 PortClr(PORT_B, 4); // EN PortClr(PORT_B, 5); // R/W PortClr(PORT_B, 6); // RS VFDData(0x33); // check if want to dim if(dim) { PortSet(PORT_B,6); // set RS=1 VFDData(0x02); // 50% brightness PortClr(PORT_B,6); // restore RS=0 } VFDData(0x32); // 4 bit data, 2 lines, 5x7 dots VFDData(0x28); // ??????? VFDData(0x06); // Turn on cursor VFDData(0x0C); // Clear display VFDData(0x01); return; } void VFDDisplay(void) { // This subroutine converts receive buffer data from ECU // to engineering data, formats it into VFD display strings, // and writes/ scrolls it across the VFD display. char col; short coljx; if(mode == DISPLAY) { // Display mode VFDConvert(0); // This takes rcvbuf and converts to // display variable values, then puts in VFDLower if(!freeze) { colix++; if(colix >= MAX_VFD_STRLEN)colix=0; } coljx = colix; for(col=0; col < MAX_COLS; col++) { VFDSend(0,col,DispVarUpperStrng[coljx]); VFDSend(1,col,VFDLower[coljx]); coljx++; if(coljx >= MAX_VFD_STRLEN)coljx=0; } } else { // Control mode VFDConvert(1); // This takes rcvbuf and converts/sets // value of current control variable // Display the control variable if(curr_var_no < 64) { // ve table ikpa = curr_var_no / 8; irpm = curr_var_no - (ikpa * 8); sprintf(VFDLower, " VE[%3u][%5u]=%3u ", kparnge[ikpa], rpmrnge[irpm]*100, control_var_val.uch); } else if(curr_var_no == 92) { // alternate if(control_var_val.uch) sprintf(VFDLower, &CtlVarStrng[curr_var_no - 64][0], "Yes"); else sprintf(VFDLower, &CtlVarStrng[curr_var_no - 64][0], " No"); } else if(ctl_var_type[curr_var_no] == UCH) sprintf(VFDLower, &CtlVarStrng[curr_var_no - 64][0], control_var_val.uch); else if(ctl_var_type[curr_var_no] == SHT) sprintf(VFDLower, &CtlVarStrng[curr_var_no - 64][0], control_var_val.sht); else if(ctl_var_type[curr_var_no] == FLT) sprintf(VFDLower, &CtlVarStrng[curr_var_no - 64][0], control_var_val.flt); // Send out VFD lines for(col=0; col < MAX_COLS; col++) { if(select) VFDSend(0,col,SelectStrng[col]); else VFDSend(0,col,BlnkStrng[col]); VFDSend(1,col,VFDLower[col]); } } return; } void VFDConvert(char sw) { short ix; U8 status,neg,kx,lz,itmp,itmp1,alarm; unsigned short div,tmp1,tmp2; if(sw == 0) { // convert ECU data to display (engineering) units alarm_alt = 1 - alarm_alt; secl = rcvbuf[0]; // time if(secl != secl_last) seconds++; secl_last = secl; div = 10000; tmp2 = seconds; lz = 1; for(ix=4; ix >= 0; ix--) { tmp1 = tmp2 / div; // leading digit tmp2 = tmp2 % div; // remainder kx = 1 + (4-ix); if((tmp1 == 0) && lz) // blank leading zeros VFDLower[kx] = ' '; else { VFDLower[kx] = 48 + tmp1; lz = 0; } div /= 10; } status = rcvbuf[2]; if((status & 0x03) == 0) // engine (bits 0,1) VFDsprintf(&VFDLower[9], 0, 0, 5, " OFF ",0); else if((status & 0x03) == 1) VFDsprintf(&VFDLower[9], 0, 0, 5, " RUN ",0); else VFDsprintf(&VFDLower[9], 0, 0, 5, "CRANK",0); if((status & 0x0C) == 0) // warm enrich (bits 2,3) VFDsprintf(&VFDLower[18], 0, 0, 5, " OFF ",0); else if(((status & 0x0C) >> 2) == 1) VFDsprintf(&VFDLower[18], 0, 0, 5, "START",0); else VFDsprintf(&VFDLower[18], 0, 0, 5, " ON ",0); if((status & 0x30) == 0) // accel enrich (bits 4,5) VFDsprintf(&VFDLower[27], 0, 0, 5, " OFF ",0); else if(((status & 0x30) >> 4) == 1) VFDsprintf(&VFDLower[27], 0, 0, 5, "ACCEL",0); else VFDsprintf(&VFDLower[27], 0, 0, 5, "DECEL",0); VFDsprintf(&VFDLower[36], 1, 0, 3, &rcvbuf[13],0); // rpm VFDsprintf(&VFDLower[44], 2, 0, 4, &rcvbuf[14],0); // pw in ms x 10 if(map_type == 0) { // map, baro itmp = map_table[rcvbuf[4]]; itmp1 = baro_table[rcvbuf[3]]; } else { itmp = map_trbo_table[rcvbuf[4]]; itmp1 = baro_trbo_table[rcvbuf[3]]; } if(alarm_alt && ((rcvbuf[4] == 0) || (rcvbuf[4] == 255))) // railed alarm = 1; else alarm = 0; VFDsprintf(&VFDLower[52], 1, 0, 3, &itmp,alarm); if(alarm_alt && ((itmp1 < 70) || (itmp1 > 130))) // baro out of range alarm = 1; else alarm = 0; VFDsprintf(&VFDLower[63], 1, 0, 3, &itmp1,alarm); itmp = therm_table[rcvbuf[6]]; // clt if(itmp < 40) { neg =1; itmp = 40 - itmp; } else { neg = 0; itmp = itmp - 40; } if(CELSIUS) { if(neg) itmp = (5 * (itmp + 32)) / 9; else if(itmp < 32) itmp = (5 * (32 - itmp)) / 9; else itmp = (5 * (itmp - 32)) / 9; } if(alarm_alt && ((rcvbuf[6] == 0) || (rcvbuf[6] == 255) || // railed (!CELSIUS && (itmp > 230)) || (CELSIUS && (itmp > 110)))) // overheat alarm = 1; else alarm = 0; VFDsprintf(&VFDLower[73], 1, neg, 3, &itmp, alarm); itmp = therm_table[rcvbuf[5]]; // mat if(itmp < 40) { neg =1; itmp = 40 - itmp; } else { neg = 0; itmp = itmp - 40; } if(CELSIUS) { if(neg) itmp = (5 * (itmp + 32)) / 9; else if(itmp < 32) itmp = (5 * (32 - itmp)) / 9; else itmp = (5 * (itmp - 32)) / 9; } if(alarm_alt && ((rcvbuf[5] == 0) || (rcvbuf[5] == 255))) // railed alarm = 1; else alarm = 0; VFDsprintf(&VFDLower[81], 1, neg, 3, &itmp, alarm); itmp = (rcvbuf[7] * 50) / 255; // tps in V x 10 VFDsprintf(&VFDLower[89], 2, 0, 4, &itmp,0); itmp = (rcvbuf[8] * 50) * 6 / 255; // bat in V x 10 if(alarm_alt && ((itmp < 90) || (itmp > 160))) // out of range alarm = 1; else alarm = 0; VFDsprintf(&VFDLower[97], 2, 0, 4, &itmp,alarm); itmp = (rcvbuf[9] * 50) / 255; // ego in V x 10 if(alarm_alt && ((rcvbuf[9] == 0) || (rcvbuf[9] == 255))) // railed alarm = 1; else alarm = 0; VFDsprintf(&VFDLower[105], 2, 0, 4, &itmp, alarm); VFDsprintf(&VFDLower[114], 1, 0, 3, &rcvbuf[10],0); // egocor VFDsprintf(&VFDLower[125], 1, 0, 3, &rcvbuf[11],0); // aircor VFDsprintf(&VFDLower[136], 1, 0, 3, &rcvbuf[16],0); // barcor VFDsprintf(&VFDLower[145], 1, 0, 3, &rcvbuf[18],0); // vecorr VFDsprintf(&VFDLower[155], 1, 0, 3, &rcvbuf[12],0); // wrmcor VFDsprintf(&VFDLower[165], 2, 0, 4, &rcvbuf[15],0); // tpsacc (ms x 10) VFDsprintf(&VFDLower[175], 1, 0, 3, &rcvbuf[17],0); // gamma } else if(sw == 1) { // convert control data from ecu to display data if(curr_var_no < 64) { // ve[kpa][rpm] table control_var_val.uch = rcvbuf[0]; } else { switch(curr_var_no) { case 64: case 65: control_var_val.flt = (float)rcvbuf[0] * 0.1; // cwu,cwh break; case 66: case 67: case 68: case 69: case 70: case 71: case 72: case 73: case 74: case 75: case 76: case 77: control_var_val.uch = rcvbuf[0]; // awev,avc, wwu break; case 78: case 79: case 80: case 81: case 82: control_var_val.flt = (float)rcvbuf[0] * 0.1; // tpsaq tble or break; //tpsacold case 83: control_var_val.uch = rcvbuf[0]; // tpsthresh break; case 84: control_var_val.flt = (float)rcvbuf[0] * 0.1; //tpsasync break; case 85: control_var_val.uch = rcvbuf[0]; // tpsdq break; case 86: control_var_val.sht = rcvbuf[0] - 40; // egotemp break; case 87: case 88: case 89: control_var_val.uch = rcvbuf[0]; // egocountcmp, egodelta, egolimit break; case 90: control_var_val.flt = (float)rcvbuf[0] * 0.1; //reqfuel break; case 91: case 92: control_var_val.uch = rcvbuf[0]; // divider, alternate break; case 93: control_var_val.flt = (float)rcvbuf[0] * 0.1; //injopen break; case 94: control_var_val.uch = rcvbuf[0]; // injpwm break; case 95: case 96: control_var_val.flt = (float)rcvbuf[0] * 0.1; //injpwmt, battfac break; case 97: // rpmk (= 12000/ncyl) control_var_val.sht = (unsigned short)rcvbuf[1] + ((unsigned short)rcvbuf[0] << 8); break; case 98: case 99: case 100: case 101: case 102: case 103: case 104: case 105: control_var_val.sht = rcvbuf[0] * 100; // rpmve table break; case 106: case 107: case 108: case 109: case 110: case 111: case 112: case 113: case 114: case 115: case 116: control_var_val.uch = rcvbuf[0]; // kpave table, configs break; case 117: control_var_val.flt = (float)rcvbuf[0] * 0.1; // primep break; case 118: control_var_val.sht = rcvbuf[0] * 100; //rpmoxlimit break; case 119: control_var_val.sht = rcvbuf[0] - 40; // fastidle break; case 120: control_var_val.flt = (5.0/255.) * (float)rcvbuf[0]; // voltoxtgt break; case 121: control_var_val.uch = rcvbuf[0]; // ACC cold mult } // end switch } // end else } else if(sw == 2) { // convert display control data to ecu data if(curr_var_no < 64) { ikpa = curr_var_no / 8; irpm = curr_var_no - (ikpa*8); ctl_var_ecu_val = control_var_val.uch; } else { switch(curr_var_no) { case 64: case 65: //cwu,h ctl_var_ecu_val = (U8)(control_var_val.flt * 10.001); break; case 66: case 67: case 68: case 69: case 70: case 71: case 72: case 73: case 74: case 75: case 76: case 77: //awev, awc, or wwu table ctl_var_ecu_val = control_var_val.uch; break; case 78: case 79: case 80: case 81: case 82: //tpsaq table or tpsacold ctl_var_ecu_val = (U8)(control_var_val.flt * 10.001); break; case 83: //tpsthresh ctl_var_ecu_val = control_var_val.uch; break; case 84: //tpsasync ctl_var_ecu_val = (U8)(control_var_val.flt * 10.001); break; case 85: //tpsdq ctl_var_ecu_val = control_var_val.uch; break; case 86: //egotemp ctl_var_ecu_val = (U8)(control_var_val.sht + 40); break; case 87: case 88: case 89: // egocountcmp, egodelta, or egolimit ctl_var_ecu_val = control_var_val.uch; break; case 90: // reqfuel ctl_var_ecu_val = (U8)(control_var_val.flt * 10.001); break; case 91: case 92: // divider or alternate ctl_var_ecu_val = control_var_val.uch; break; case 93: // injopen ctl_var_ecu_val = (U8)(control_var_val.flt * 10.001); break; case 94: // injpwm ctl_var_ecu_val = control_var_val.uch; break; case 95: case 96: // injpwmt or battfac ctl_var_ecu_val = (U8)(control_var_val.flt * 10.001); break; case 97: // rpmk ctl_var_ecu_val = (U8)(control_var_val.sht >> 8); ctl_var_ecu_val2 = (U8)(control_var_val.sht & 0x00FF); break; case 98: case 99: case 100: case 101: case 102: case 103: case 104: case 105: // rpmve table ctl_var_ecu_val = control_var_val.sht / 100; break; case 106: case 107: case 108: case 109: case 110: case 111: case 112: case 113: case 114: case 115: case 116: // kpave table, configs ctl_var_ecu_val = control_var_val.uch; break; case 117: // primep ctl_var_ecu_val = (U8)(control_var_val.flt * 10.001); break; case 118: // rpmoxlimit ctl_var_ecu_val = control_var_val.sht / 100; break; case 119: // fastidle ctl_var_ecu_val = (U8)(control_var_val.sht + 40); break; case 120: // voltoxtgt ctl_var_ecu_val = (U8)(control_var_val.flt * 51.001); break; case 121: // acc cold mult ctl_var_ecu_val = control_var_val.uch; } // end switch } // end else } // end main else return; } void VFDsprintf(U8 *bufo, U8 type, U8 neg, U8 width, U8 *bufi, U8 alarm) { U8 ix; if(!alarm) { if(type == 0) { // string for(ix=0;ix < width; ix++) { bufo[ix] = bufi[ix]; } } else if (type == 1) { // char if(neg) { bufo[0] = '-'; bufo[1] = asc_cnvt_tbl2[bufi[0]]; bufo[2] = asc_cnvt_tbl1[bufi[0]]; } else { bufo[0] = asc_cnvt_tbl3[bufi[0]]; bufo[1] = asc_cnvt_tbl2[bufi[0]]; bufo[2] = asc_cnvt_tbl1[bufi[0]]; } } else if (type == 2) { // float bufo[0] = asc_cnvt_tbl3[bufi[0]]; bufo[1] = asc_cnvt_tbl2[bufi[0]]; bufo[2] = '.'; bufo[3] = asc_cnvt_tbl1[bufi[0]]; } } else { bufo[0] = ' '; bufo[1] = ' '; bufo[2] = ' '; if(type == 2) bufo[3] = ' '; } return; } void VFDSend(char line, char col, char value) { // Set up to send a byte to VFD character RAM PortClr(PORT_B, 4); // EN = 0 PortClr(PORT_B, 5); // R/~W = 0 (write operation) PortClr(PORT_B, 6); // RS = 0 (sending an instruction) // send address of where cursor/ data byte will go // format of byte is 0x1lcccccc where l = line # (0,1) // and cccccc = 6-bit col #. VFDData(0x80 | (line << 6) | col); // Send position // Send data byte PortSet(PORT_B, 6); // RS = 1 (sending a data byte) VFDData(value); return; } void VFDData(char value) { U8 ix; // data bit 4 (PTC0) if(value & 0x10) PortSet(PORT_C, 0); else PortClr(PORT_C, 0); // data bit 5 (PTC1) if(value & 0x20) PortSet(PORT_C, 1); else PortClr(PORT_C, 1); // data bit 6 (PTC2) if(value & 0x40) PortSet(PORT_C, 2); else PortClr(PORT_C, 2); // data bit 7 (PTC3) if(value & 0x80) PortSet(PORT_C, 3); else PortClr(PORT_C, 3); for(ix=0; ix < 245; ix++); //delay to let data settle PortSet(PORT_B, 4); // set enable line to send over // delay > .5 us to satisfy VFD timing reqts. for(ix=0; ix < 5; ix++) { asm nop; } PortClr(PORT_B, 4); // unset enable to set up for next xmt // delay > .5 us to satisfy VFD timing reqts. for(ix=0; ix < 5; ix++) { asm nop; } // data bit 0 (PTC0) if(value & 0x01) PortSet(PORT_C, 0); else PortClr(PORT_C, 0); // data bit 1 (PTC1) if(value & 0x02) PortSet(PORT_C, 1); else PortClr(PORT_C, 1); // data bit 2 (PTC2) if(value & 0x04) PortSet(PORT_C, 2); else PortClr(PORT_C, 2); // data bit 3 (PTC3) if(value & 0x08) PortSet(PORT_C, 3); else PortClr(PORT_C, 3); for(ix=0; ix < 245; ix++); //delay to let data settle PortSet(PORT_B, 4); // set enable line to send over // delay > .5 us to satisfy VFD timing reqts. for(ix=0; ix < 5; ix++) { asm nop; } PortClr(PORT_B, 4); // unset enable to set up for next xmt // delay > .5 us to satisfy VFD timing reqts. for(ix=0; ix < 5; ix++) { asm nop; } return; }