/* ** OBD.c ** OBD interface from Suzuki SDL to PC comm port ** Version 1 ** J Holland ** 19th April 2008 ** ** SDL is single wire bi-directional interface ** implemented by resistors ** ** U1 is OBD is 15625bps??? ** U2 is COMM port is 115200bps ** U1_TX is implemented as open drain output ** RB5 is initialised as output (low) ** when U1_TX goes high SDL is connected and UART is initialised ** and LED6 (RA3) is switched off ** LED7 (RA4) indicates data reception error on U1 ** Comparator is used to clean up RX signal. */ #include #define RXFLG_SET_MSK 0x0001 #define RXFLG_CLR_MSK 0xFFFE #define RB14_DIG_MSK 0x4000 #define TRUE = 1; #define FALSE = 0; // timing and baud rate calculations (Fcy = 16MHz) -- note Fcy = Fosc/2 #define U1_BRATE 66 // 15126 baud (BREGH=0) #define U2_BRATE 34 // 115200 baud (BREGH=1) int U1_STATUS; int U2_STATUS; void obd_init() { //set up ports PORTA &= 0xFFFE; //turn off LED7 TRISA = 0xFFF3; //RA7,RA6 are LEDs PORTB = 0xFFDF; //RB5 inits low TRISB = 0xFFDF; //RB5 = output AD1PCFG = 0xFFFF; //PORTB all digital TRISC = 0xFFFF; TRISD = 0xFFFF; TRISE = 0xFFFF; // initialize the UART1 serial port PORTFbits.RF3=0; //set U1_TX low ODCF = 0x0008; //U1_Tx = open drain TRISF = 0xFFFF; //PORTF all inputs //clear (my) status registers U1_STATUS = 0x0000; //clear all status flags U2_STATUS = 0x0000; } void initComp1 (void) { TRISB = 0xFEFF; //init RB8=C1_OUT,RB5=C1_IN AD1PCFGbits.PCFG5=0; //RB5 is analogue in CMCON = 0x0512; //internal vref, input to -ve, inv output, enabled CVRCON = 0x00C6; //Vref = 1.44V, Vref on RB10 CMCONbits.C1EVT=0; } void initU1( void) //OBD interface { //set up interrupts for U1 IPC3bits.U1TXIP1 = 0; IPC3bits.U1TXIP0 = 0; IPC2bits.U1RXIP2 = 1; //Set Uart RX Interrupt Priority IPC2bits.U1RXIP1 = 0; IPC2bits.U1RXIP0 = 0; U1BRG = U1_BRATE; //set up baud rate U1MODEbits.BRGH = 0; //Use low speed mode - see errata!!! U1MODEbits.UARTEN = 1; //enable UART // U1STAbits.UTXINV = 1; //invert TX line U1STAbits.UTXEN = 1; //Enable Transmit IFS0bits.U1RXIF = 0; //clear interrupt flag before enabling IEC0bits.U1RXIE = 1; //Enable Receive Interrupt TRISFbits.TRISF3=0; } // initU1 void initU2( void) //PC Interface { // initialize the UART2 serial port IPC7bits.U2TXIP1 = 0; IPC7bits.U2TXIP0 = 0; IPC7bits.U2RXIP2 = 1; //Set Uart RX Interrupt Priority IPC7bits.U2RXIP1 = 0; IPC7bits.U2RXIP0 = 0; U2BRG = U2_BRATE; U2MODEbits.BRGH = 1; U2MODEbits.UARTEN = 1; U2STAbits.UTXEN = 1; //Enable Transmit IFS1bits.U2RXIF = 0; //clear interrupt flag before enabling IEC1bits.U2RXIE = 1; //Enable Receive Interrupt TRISFbits.TRISF5 = 0; } // initU2 // send a character to the UART1 serial port void putC_U1( int c) { while ( U1STAbits.UTXBF); // wait if Tx buffer full U1TXREG = c; } // putU1 // get a new character the UART1 serial port int getC_U1( void) { return U1RXREG; // read the character from the receive buffer }// getU1 // send a character to the UART2 serial port void putC_U2( int c) { while ( U2STAbits.UTXBF); // wait if Tx buffer full U2TXREG = c; } // putU2 // wait for a new character to arrive to the UART2 serial port int getC_U2( void) { return U2RXREG; // read the character from the receive buffer }// getU2 main() { obd_init(); //call initialisation code while((PORTFbits.RF3==0)) //wait till RF3 goes high { PORTAbits.RA3 = 1; //set 'not ready LED' } // ******************** add debounce delay initComp1(); //initialise comparator initU1(); //initialise UART1 initU2(); //initialise UART2 PORTAbits.RA3 = 0; //clear 'not ready LED' int c1; int c2; while (1) { if((U1_STATUS & RXFLG_SET_MSK) == 1){ c1 = getC_U1(); if((U1STAbits.FERR==1) | (U1STAbits.OERR ==1)) PORTA |= 0x08; //RA4 ON = error U1_STATUS = (U1_STATUS & RXFLG_CLR_MSK); //ONLY IF RX BUFFER EMPTY????? putC_U2(c1); } if((U2_STATUS & RXFLG_SET_MSK) == 1){ c2 = getC_U2(); U2_STATUS = (U2_STATUS & RXFLG_CLR_MSK); putC_U1(c2); } } }// main /****************************** Interrupt Service Routines ************************/ /* Fast context save (using push.s and pop.s) ????? */ void __attribute__ ((interrupt, no_auto_psv)) _U1RXInterrupt(void) { U1_STATUS = (U1_STATUS | RXFLG_SET_MSK); // set (polled) U1 status register rx flag IFS0bits.U1RXIF = 0; //clear interrupt flag before returning } void __attribute__ ((interrupt, no_auto_psv)) _U2RXInterrupt(void) { U2_STATUS = (U2_STATUS | RXFLG_SET_MSK); // set (polled) U2 status register rx flag IFS1bits.U2RXIF = 0; // clear interrupt flag before returning } /********* END OF INTERRUPT SERVICE ROUTINES ********/