CAN Bus Diagnostic Translator MANUAL
Kenneth Heck John Murphy
USE AND CARE I. USE First, decide in what manner you wish to use the device: Are you using it as a straightthrough from the car to the PC? Are you going to record from the car going around the track? Or are you going to play back a pre-recorded session from a Compact Flash card? STRAIGHT-THROUGH MODE Connect the device to the PC via the DB-9 connector, making sure to tighten the screws to reduce vibration. On the other side, connect the device to the CAN bus, locking the connector firmly for a good connection. Load the CAN translator software on the PC, and connect the device to power. The power LED will come on and the software will let you know when it is ready to proceed. Run the car's systems normally, being careful not to pull on the device's cables. When you are finished, disconnect the power and detach the device's cables, making sure not to get grease or motor oil in the connectors. If possible, wash your hands before handling the device, or use a clean cloth. RECORD MODE Open the device's case and insert a Compact Flash card into its connector, with its label side facing away from the circuit board. Close the case carefully. Connect the device to the CAN bus, locking its connector, and connect it to power. Secure the device carefully to avoid damaging it while the car is in motion. When you have finished, disconnect the device from power and from the CAN bus. Retrieve the card by opening the case again. DO NOT open the case with dirty hands. The Compact Flash card can remain in the device indefinitely, but on each new run the device begins writing from the beginning of the card, obliterating any data that may have been stored previously. Back up all data and keep logs, in possible, of whether a given card is safe to re-use. PLAYBACK MODE Open the device's case and insert the Compact Flash card into its socket. Connect the device to your PC via the DB-9 connector. Load the CAN translator software on your PC, then connect the device to power. When the program indicates that it is ready, push the playback button on the device.
Cards written to with the device are readable multiple times, provided that they are not written to by this device or any other in the meantime. See the manufacturer's information for your card to determine how long it will hold data.
I. CARE So long as the device is kept clean and dry, it should continue to operate normally. After use, the user should inspect all connectors to ensure that no dirt or oil has gotten in. Check internal cables periodically for cracks, especially around the headers. In choosing a location in the car to mount the device, consider the following things: ? Vibration – If the device is mounted to a moving part, or loosely mounted to a stable part, vibration can cause cables to come loose or disconnect competely. ? Heat – While the device itself is designed for average ambient temperatures inside an operating car, it is not designed to be placed directly on or near a heated element, such as the radiator or air conditioner. If possible, it is best to mount the device in the passenger space. ? Water and Oil – Do not mount the device in such a way that water or oil will fall on it during operation. Take special care when using the device in wet weather to avoid putting it in the path of water or steam.
TROUBLESHOOTING Power LED does not come on ? Check power connection. Make sure that the connector fits securely into the device and that the cable is free of defects such as cracks. Make sure that the cable is connected to either the car's power supply or a wall outlet. ? Examine the circuit board for damage or defects. Make sure that each chip is secure in its space and that none of the resistors or jumpers show scorch marks. Examine the LED itself to make sure that it has not been damaged. Check its connection to the board by gently probing it to see if has come loose. ? With a voltmeter, test pin 40 on the PIC chip when the device is powered to see if it is a logical high. If not, the problem may be the PIC itself, and it may need to be reprogrammed or replaced. CAN LEDs do not come on ? The CAN bus may not be active at all times. If possible, do something with the car that would ordinarily cause a message to be transferred. Starting the car, pumping the brakes, turning on the headlights or windshield wipers would all do this. ? Ensure that the device is connected to the CAN bus and locked securely to the connector. ? In playback mode, the LEDs may not come on, even though the device may be correctly attached to a working CAN bus. This is normal for playback mode. Disconnect it from power and reconnect it. Translator Software does not detect device, even though power LED is on ? Disconnect the device from power and reconnect it after checking to be sure that it is correctly attached to your computer. ? Make sure that the COM port on your computer is working properly. Unresolved IRQ conflicts will cause the serial communications on your computer to not work properly. ? Go to the Windows Control Panel, under System. Go to your COM port settings under Device Manager, and select the tab labelled Port Settings. Set the following values if they are not already set: Bits per second: 9600 Data bits: 8 Parity: None Stop Bits: 1 Flow control: None
APPENDIX B: SCHEMATIC
APPENDIX C: SOURCE CODE FOR PIC 16F877
;+===========================+ ;|John Murphy | ;|Kenneth Heck | ;| | ;|CAN bus adaptor | ;|28 November, 2001 | ;| | ;+===========================+ list p=16f877 ; Include file, change directory if needed include "p16f877.inc" __CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_OFF & _HS_OSC & _WRT_ENABLE_OFF & _LVP_ON & _DEBUG_OFF & _CPD_OFF #define debug ;#define echo ;+===========================+ ;| Variables | ;+===========================+ ;For the Interrupt Service Routines: W_TEMP equ STATUS_TEMP equ PCLATH_TEMP equ FSR_TEMP equ 0x74
0x71 0x72 0x73
;*************************************** ; DEVMODE ;Device's Mode/STATUS Byte ; Bit 0-2 MODE SELECT ; Bit 3 PC_buff overflow error ; Bit 4 CAN_buff overflow error ; Bit 5 CompactFlash full error ; Bit 6 PC_buff contains data ;*************************************** DEVMODE equ 0x75 #define PC_BUFF_OVERFLOW DEVMODE, #define CAN_BUFF_OVERFLOW DEVMODE, #define CF_INSERTED #define PC_BUFF_NOTEMPTY DEVMODE, #define CAN_BUFF_NOTEMPTY DEVMODE, DEVFLAG #define #define
equ CAN_RX0_READY CAN_RX1_READY
3 4 DEVMODE, 5 6 7
0x76 DEVFLAG, 0 DEVFLAG, 1
#define #define #define
SPI_IN_PROGRESS USART_IN_PROGRESS CF_IN_PROGRESS
DEVFLAG, 2 DEVFLAG, 3 DEVFLAG, 4
delay equ 0x21 rcv equ 0x22 loopctr0 equ 0x23 ;Whenever we write to the 2510, we write two bytes at a time. Load ;them into these first, then call SPI_Write ; And yes, these are all in the same bank as SSBUF. Makes life much easier later on. SPI1 SPI2 SPI3 SPIOUT
equ equ equ equ
0x26 0x27 0x28 0x29
CF_DATA_HIGH CD_DATA_LO equ
equ 0x2B
0x2A
POWER_ON_MSG INIT_MSG equ
equ 0x42
0x55
equ equ equ
0xE5 0xE6 0xE7
0x33 equ equ 0x36
0x34 0x35
;Here are our buffers: CAN_buff_in CAN_buff_out CAN_buff_ctr PC_buff_in equ PC_buff_out PC_buff_ctr outcounter equ
PC_buff equ 0x40 ;This ends at 0x50, for 16 bytes -- two CAN packets' worth PC_buff_end equ 0x51 CAN_buff equ 0xA0 ;This stretches out to 0xE0h -- 64 bytes CAN_buff_end equ 0xE1
;+===========================+ ;| Constants | ;+===========================+ #define #define #define
CAN_CS TXB0_TX TXB1_TX
;Compact Flash control lines #define CF_RESET #define CF_CD1 #define CF_OE #define CF_WE #define CF_RDY #define CF_CE1
PORTB, 2 PORTB, 6 PORTB, 5
PORTA, 5
;Output PORTA, 1 PORTA, 2 PORTA, 3 PORTA, 4 PORTA, 0
;Output ;Output ;Output ;Input ;Output
;+============================+ ; CANSTAT bits 3-1 ; Interrupt flag code ; 000 = No Interrupt ; 001 = Error Interrupt ; 010 = Wake Up Interrupt ; 011 = TXB0 Interrupt ; 100 = TXB1 Interrupt ; 101 = TXB2 Interrupt ; 110 = RXB0 Interrupt ; 111 = RXB1 Interrupt ;+============================+ CANCTRL CANSTAT CANINTE CANINTF CNF1 CNF2 CNF3
equ equ equ equ equ equ equ
SPI_RESET equ
B'11000000'
RXB0DLC RXBUF0 RXM0SIDH RXM0SIDL RXB1DLC RXBUF1 RXM1SIDH RXM1SIDL
equ equ 0x20 0x21 equ equ 0x24 0x25
equ equ
equ equ
TXBUF0 equ TXBUF1 equ Only one used by current code TXB1CTRL equ 0x40 TXBUF2 equ
0x0F 0x0E 0x2B 0x2C 0x2A 0x29 0x28 ;2510's RESET command
0x65 B'01100110'
;Start of RXB0
0x75 B'01110110'
;Start of RXB1
B'00100110' B'01000110'
;Start of TXB0 ;Start of TXB1 300
ns)
;No?
;Is there a card inserted? Go set up the 2510
;We have card! bsf CF_INSERTED banksel PORTA bsf CF_RESET nop nop bcf CF_RESET nop nop call wait call wait call wait call wait call wait call wait call wait call wait ;LONG wait. This may not be long enough, but it's probably OK
;+==========================+ ;| MCP2510 Config | ;+==========================+ CAN_INIT ;Initiate MCP2510 reset banksel PORTB bcf CAN_CS
;
movlw movwf
SPI_RESET SSPBUF
banksel movlw movwf call
TXREG 0x31 TXREG txwait
banksel movfw
SSPBUF SSPBUF
banksel bsf
PORTB CAN_CS
banksel
TXREG
;Hit the Chip Select
; ;
movfw movwf
0x43 TXREG
;And now -- we wait! call wait call wait call wait call wait ;This is probably excessive, but time is not ;critical at this point... ; Technically, this should be 128 Osc cycles from the 2510's point of view. ; It's running on the same clock that the PIC is, divided by four ; ; ; ;
banksel movlw movwf call
TXREG 0x32 TXREG txwait
; We need to set up the acceptance masks and filters here. ; For the demo, we're using RXBUF0, so let's set its mask to all 0's banksel movlw movwf movlw movwf call
SPI1 RXM0SIDH SPI1 0x00 SPI2 SPI_WRITE
banksel movlw movwf movlw movwf call
SPI1 RXM0SIDL SPI1 0x00 SPI2 SPI_WRITE
; For that matter, let's turn off RXBUF1 by setting its mask to all 1's, ; ensuring that nothing will match it. banksel movlw movwf movlw movwf call
SPI1 RXM1SIDH SPI1 0xFF SPI2 SPI_WRITE
banksel movlw movwf movlw movwf call
SPI1 RXM1SIDL SPI1 0xFF SPI2 SPI_WRITE
;The following settings I got from the sample code that
Microchip made available. banksel movlw movwf movlw movwf call
SPI1 CNF1 SPI1 0x03 SPI2 SPI_WRITE
banksel movlw movwf movlw movwf call
SPI1 CNF2 SPI1 0x90 SPI2 SPI_WRITE
banksel movlw movwf movlw movwf call ; Lastly, receipt in RXB0 banksel movlw movwf movlw movwf call
SPI1 CNF3 SPI1 0x02 SPI2 SPI_WRITE let's tell the 2510 to interrupt us upon message
SPI1 CANINTE SPI1 0x01 SPI2 SPI_WRITE
;******************************************************************** *******; ;+ Now that that's all done, let's set it up in loopback mode ;+ ;+ banksel SPI1 ;+ movlw CANCTRL ;+ movwf SPI1 ;+ movlw B'01000000' ; Loopback Mode ;+ movwf SPI2 ;+ call SPI_WRITE ;******************************************************************** ******** banksel SPI1 movlw CANCTRL movwf SPI1 movlw B'01110000' abort all pending transmissions movwf SPI2 call SPI_WRITE ; ; ; ;
banksel movlw movwf call
TXREG 0x33 TXREG txwait
; Listen-only mode, and
;+========================+ ;| Main Sequence | ;+========================+ banksel PORTB bsf PORTB, 7
;Hit the power indicator
clrf clrf
PIR1 PIR2
banksel movlw movwf call
TXREG INIT_MSG TXREG txwait
banksel bsf bsf
INTCON INTCON, 6 ;Enable peripheral interrupts INTCON, 7 ;Enable global interrupts
mainloop ; Okay, now let's take all those buffers we filled up and direct their data to where it ; needs to go btfsc call
CAN_RX0_READY READ_RXB0
;Is there anything in the transmit buffer? ;(I should really be using a flag for this instead!) banksel CAN_buff_ctr movf CAN_buff_ctr, F bz checkPCbuffer banksel movfw movwf banksel movfw movwf
CAN_buff_out CAN_buff_out FSR TXREG INDF TXREG
banksel CAN_buff_out movfw CAN_buff_out alloted space? addlw 0x1F we've overflowed bnc CANdecnormally movlw CAN_buff movwf CAN_buff_out decf CAN_buff_ctr goto endservice CANdecnormally incf CAN_buff_out decf CAN_buff_ctr underflow, since we already checked
;Data
;Have we read beyond our ; This will overflow if ;branch-no-carry
; I'm not checking for
checkPCbuffer ;Is there banksel movf bz banksel movfw movwf banksel movfw movwf
anything in the transmit buffer? PC_buff_ctr PC_buff_ctr, F endservice PC_buff_out PC_buff_out FSR TXREG INDF TXREG
movfw PC_buff_out alloted space? addlw 0xB0 we've overflowed bnc PCnormaldec movlw PC_buff movwf PC_buff_out decf PC_buff_ctr goto endservice PCnormaldec incf PC_buff_out decf PC_buff_ctr underflow, since we already checked
;Data
;Have we read beyond our ; This will overflow if ;branch-no-carry
; I'm not checking for
endservice ;Include any necessary clean-up here goto
mainloop
;+=========================+ ;| Function Calls | ;+=========================+ wait
del
banksel movlw movwf decf skpz goto return
delay B'11100000' delay delay
banksel btfss goto bcf return
PIR1 PIR1, TXIF txloop PIR1, TXIF
del
txwait txloop
SPI_WRITE ;Do NOT call until SPI has been configured!!! banksel PORTB bcf CAN_CS ;MCP2510's chip select line
#ifdef
debug movlw movwf
0x57 TXREG
;Debugging message
movlw
B'00000010'
;MCP2510 Write command
banksel movwf
SSPBUF SSPBUF
movf
SSPBUF, W
movfw banksel movwf
SPI1 SSPBUF SSPBUF
movf
SSPBUF, W
movfw banksel movwf
SPI2 SSPBUF SSPBUF
movf
SSPBUF, W
#endif
;We've moved our three bytes, now let's go home banksel PORTB bsf CAN_CS return BIT_MODIFY ;Do NOT call until SPI has been configured!!! banksel PORTB bcf CAN_CS ;MCP2510's chip select line
#ifdef
debug movlw movwf
0x42 TXREG
movlw banksel movwf
B'00000101' SSPBUF SSPBUF
movfw banksel movwf
SPI1 SSPBUF SSPBUF
movfw banksel movwf
SPI2 SSPBUF SSPBUF
movfw banksel movfw
SPI3 SSPBUF SSPBUF
;Debugging message
#endif
;We've edited the register, let's go back
;MCP2510 Bitwise Modify
banksel bsf return
PORTB CAN_CS
banksel bcf
PORTB CAN_CS
debug movlw movwf
0x52 TXREG
movlw banksel movwf
B'00000011' SSPBUF SSPBUF
movwf banksel movwf
SPI1 SSPBUF SSPBUF
SPI_READ
#ifdef
;Debugging message
#endif ;MCP2510 Read command
;The next thing that comes in is the contents of that register. ; At this stage, nothing that comes from the 2510 is used by the PIC -; it's just a straight pass-through
rgo2
banksel btfss goto
SSPSTAT SSPSTAT, BF rgo2
banksel movfw banksel movwf
SSPBUF SSPBUF SPIOUT SPIOUT
banksel bsf
PORTB CAN_CS
return
READ_RXB0 ;This function "calls up" the 2510, reads out the Data Length register, and loops that many ; times, feeding into the CAN_buff ring buffer. ;Right now, interrupts are turned OFF during the entire operation. This is ridiculous. ; I bet that turning interrupts back on during any wait periods, or just briefly in between ; cycles would help a lot. ; The CLEVER way to do this would be to externally load an offset, since adding 0x10 to each of ; these address bytes would select RXB1, instead. ; However, there is some doubt as to whether we will actually ever need RXB1. banksel
INTCON
bcf
INTCON, 7 ;OK, it's dumb, but it's temporary.
banksel bcf
PORTB CAN_CS
movlw banksel movwf
B'00000011' SSPBUF SSPBUF
;MCP2510 Read command
RXB0DLC
;Address of RX Buffer 0's
movwf Data Length Code movwf
;Poke the 2510
SSPBUF
;The next thing that comes in is the contents of that register. banksel btfss goto
SSPSTAT SSPSTAT, BF rxb01
banksel movfw andlw bottom four bits
SSPBUF SSPBUF B'00001111'
rxb01
;Mask out all but the ; creating a nice loop
timer banksel movwf bz don't waste time
loopctr0 loopctr0 rxb0done
; It may be empty, in which case,
banksel movlw movwf
SSPBUF B'00000011' SSPBUF
movlw movwf
RXBUF0 SSPBUF
banksel movfw movwf
PC_buff_in PC_buff_in FSR
;Address of start bit
rxb0loop
banksel rxb0loopinner btfss goto
SSPSTAT SSPSTAT, BF rxb0loopinner
banksel movfw
SSPBUF SSPBUF
banksel movwf incf movlw xorwf
CAN_buff INDF CAN_buff_in CAN_buff_end CAN_buff_in, W
skpz goto
rb0_rest
;Is the new address out of
bounds? ;If it is, loop around
movlw movwf
CAN_buff CAN_buff_in
;Loop around
rb0_rest incf movlw xorwf skpnz set the error bit bsf
CAN_buff_ctr 0x40 CAN_buff_ctr, W
banksel we're done. decf bnz
loopctr0
bsf
;64 bytes
-- HUGE counter
;If the counter overflows, CAN_BUFF_OVERFLOW ;Decrement our counter, and see if
loopctr0 rxb0loop CAN_BUFF_NOTEMPTY
rxb0done banksel PORTB bsf CAN_CS interrupts, to prevent overflows banksel bsf
;Do this before re-enabling
INTCON INTCON, 7
return CF_READY BTFSS goto return
CF_RDY CF_READY
CF_READ call CF_READY ;Input from data lines banksel TRISD movlw 0xFF movwf TRISD banksel PORTD clrf PORTD bsf
CF_OE
; ******************************** ; Handle incoming communications from the PC PC_SERVICE banksel movfw movwf
PC_buff_in PC_buff_in FSR
banksel movfw
RCREG RCREG
; The following code grabs that byte from RCREG and puts it into the PC_buff buffer ; When that buffer's counter is an integer multiple of eight, it gets flushed out
; onto the CAN bus. movwf incf movlw xorwf
INDF PC_buff_in PC_buff_end PC_buff_in, W
skpz goto movlw movwf
;If it is, loop around pc_rest PC_buff PC_buff_in ;Loop around
;Is the new address out of
bounds?
pc_rest incf movlw xorwf skpnz set the error bit bsf
PC_buff_ctr 0x10 PC_buff_ctr, W
;16 bytes ;If the counter overflows,
PC_BUFF_OVERFLOW
; At this point, we've loaded the new byte into the buffer, incremented the position ; and checked for overflow. We now indicate that the PC buffer contains data ; and head back to IntService bsf
PC_BUFF_NOTEMPTY
goto
CheckCAN
CAN_SERVICE ;Since the MCP2510 generates various things, ; This routine needs to read interrupt) ; Then poll the 2510 for the then a flag ; should be set for the MAIN Don't do it here
an external interrupt for off portb (To clear the error.
If it IS a message,
LOOP to read the buffer.
banksel movf bcf
PORTB PORTB, F CAN_CS
movlw banksel movwf
B'00000011' SSPBUF SSPBUF
;MCP2510 Read command
movwf banksel movwf
CANSTAT SSPBUF SSPBUF
;the 2510's status register
;Clear that interrupt
;The next thing that comes in is the contents of that register. ; We don't care about errors. They aren't processed in listen mode, anyhow. banksel
SSPSTAT
CS2
btfss goto
SSPSTAT, BF CS2
banksel movfw andlw
SSPBUF SSPBUF B'00001110'
banksel bsf
PORTB CAN_CS
xorlw bnz
B'00001100' NextISR
bsf
CAN_RX0_READY
goto
NextISR
;RXB0 Interrupt ;If anything else, then
forget it.
;+==========================+ ;| Interrupt Routines | ;+==========================+ IntService movwf
W_TEMP
swapf movwf movfw movwf movfw movwf
STATUS, W STATUS_TEMP FSR FSR_TEMP PCLATH PCLATH_TEMP
;save W, STATUS, PCLATH,
and FSR
banksel PIR1 ;Perform interrupt routines CheckPC btfsc goto
PIR1, RCIF PC_SERVICE
btfsc goto
PIR1, INTE CAN_SERVICE
CheckCAN
NextISR ;Clear Receive errors bcf RCREG, CREN bsf RCREG, CREN bcf PIR1, RCIF ;All done! Now let's put everything back where it was movfw PCLATH_TEMP movwf PCLATH movfw FSR_TEMP movwf FSR swapf STATUS_TEMP, W movwf STATUS swapf W_TEMP, F swapf W_TEMP, W retfie
end