-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
1,600 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,7 +34,7 @@ | |
*.app | ||
*.i*86 | ||
*.x86_64 | ||
*.hex | ||
#*.hex | ||
|
||
# Debug files | ||
*.dSYM/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
MAIN = ELM327SLCAN | ||
SRC = frontend.c init.c rbuf.c clock.c main.c can.c | ||
CC = C:\Program Files\Microchip\xc8\v1.42\bin\xc8.exe | ||
CHIP = 18F25K80 | ||
|
||
all: $(MAIN).hex | ||
|
||
$(MAIN).hex: $(SRC) | ||
$(CC) $(SRC) --chip=$(CHIP) --MODE=pro --OPT=+speed --OUTDIR=out -O$(MAIN) --ROM=default,-7cfc-7fff | ||
|
||
clean: | ||
rm -f $(MAIN).hex funclist $(MAIN).cof $(MAIN).hxl $(MAIN).p1 $(MAIN).sdb startup.* $(MAIN).lst $(MAIN).pre $(MAIN).sym | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
#### ELM327SLCAN | ||
|
||
The cheap vehicle's CAN bus sniffer based on ELM327, special [bootloader](https://fischl.de/usbtin/), and [USBtin](https://fischl.de/usbtin/). | ||
With this device you can monitor vehicle's CAN bus. Monitoring software – [CANHacker](https://cdn.hackaday.io/files/12644540960896/CANHackerV2.00.02.zip) or [similar](https://fischl.de/usbtin/#usbtinviewer). | ||
|
||
##### LEDs | ||
|
||
1. Red – power supply. | ||
2. Green – current connection status. If lights steady – connection is open. Flashes once in three seconds – connection is closed. | ||
3. Orange – error status. | ||
- If lights steady – serial port buffer overflow error. This error occurs when the MCU does not have time to read the next command from PC. You can reset this error only by turning off the power supply. | ||
- One flash in three seconds – CAN messages FIFO-buffer overflow in MCU. The depth of a FIFO-buffer is eight messages. Then the ninth message is received, this error is raised. | ||
- Double flash in three seconds – internal text buffer overflow in MCU. This error is raised then the rate of incoming CAN-messages is very high and MCU does not have time to send them to PC. | ||
- Triple flash in three seconds – internal text buffer overflow in MCU. This error is raised then the rate of incoming commands from PC is very high and MCU does not have time to process them all. | ||
|
||
The last three errors could be reset with f2 command. | ||
|
||
|
||
##### Switch to Bootloader mode for firmware update: | ||
|
||
1. Issue the command B10[CR] in RS232 terminal software (for instance, [termite](https://www.compuphase.com/software_termite.htm)). | ||
2. Disconnect the COM port in RS232 terminal software. | ||
3. Press the red button 'Bootloader Mode' in [Serial Bootloader AN1310](http://ww1.microchip.com/downloads/en/AppNotes/Serial%20Bootloader%20AN1310%20v1.05r.zip) software. | ||
4. Switching to Bootloader mode is reflected in the status bar. | ||
5. Update the firmware. | ||
6. To start the updated application it is need to turn off and on the power. | ||
|
||
|
||
 | ||
|
||
|
||
##### Filtering | ||
|
||
Implemented filtering 'Single filter mode' with three modifications as described in [SJA1000](https://www.nxp.com/docs/en/data-sheet/SJA1000.pdf) datasheet and [AN97076](https://www.nxp.com/docs/en/application-note/AN97076.pdf). The differences: | ||
|
||
1. RTR bit does not take part in filtering. | ||
2. Two message's bytes do not take part in filtering. LSB ACR3 must be zero in case of work in CAN bus with 11-bit IDs. | ||
3. LSB ACR3 is copied to EXIDEN bit of RXF0SIDL. LSB AMR3 is copied to EXIDEN bit of RXM0SIDL. See the PIC18FXXK80 datasheet. One mask (RXM0) and one filter (RXF0) are used. | ||
|
||
To activate the CANHacker Filter settings it is necessary that the connection has been already established (Connected to …). So - see the first Termite window: | ||
|
||
1. Establish connection. | ||
2. Click Filter button. | ||
3. Set Mask Filter in the upper group box. | ||
4. Click OK button. As a result, we get ‘close’, ‘set mask’, ‘set filter’, ‘open’ commands. | ||
|
||
Range Filter filtering (lower group box) works in software. Issued command allows all incoming messages (mFFFFFF). | ||
|
||
If you remove both checkboxes and press OK button, issued command allows all incoming messages (mFFFFFF). See the second Termite window. | ||
|
||
|
||
 | ||
|
||
##### Bluetooth | ||
|
||
Bluetooth name: OBDII | ||
Bluetooth PIN: 1234 | ||
Serial port settings: 38400, 8n1 | ||
|
||
|
||
##### To build new firmware, it is need to install Microchip XC8 Compiler and MinGW. | ||
|
||
 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,230 @@ | ||
#include <xc.h> | ||
#include "elm327slcan.h" | ||
#include "clock.h" | ||
#include "can.h" | ||
|
||
/** | ||
* \brief Write to given register | ||
* | ||
* \param address Register address | ||
* \param data Value to write to given register | ||
*/ | ||
void can_write_register(unsigned short address, unsigned char data) { | ||
FSR0 = address; | ||
INDF0 = data; | ||
} | ||
|
||
/** | ||
* \brief Read from given register | ||
* | ||
* \param address Register address | ||
* \return register value | ||
*/ | ||
unsigned char can_read_register(unsigned short address) { | ||
FSR0 = address; | ||
|
||
return INDF0; | ||
} | ||
|
||
/** | ||
* \brief Set filter mask of given SJA1000 register values | ||
* | ||
* \param amr0 Acceptence mask register 0 | ||
* \param amr1 Acceptence mask register 1 | ||
* \param amr2 Acceptence mask register 2 | ||
* \param amr3 Acceptence mask register 3 | ||
* | ||
* This function has only affect if can controller is in configuration mode. | ||
*/ | ||
void can_set_SJA1000_filter_mask(unsigned char amr0, unsigned char amr1, unsigned char amr2, unsigned char amr3) { | ||
|
||
// SJA1000 mask bit definition: 1 = accept without matching, 0 = do matching with acceptance code | ||
// Microchip mask bit definition: 0 = accept without matching, 1 = do matching with acceptance filter | ||
// -> invert mask | ||
|
||
RXM0SIDH = ~amr0; | ||
RXM0SIDL = ((~amr1) & 0xE0) | (((~amr1) >> 3) & 3); | ||
if (amr3 & 1) RXM0SIDL |= 8; | ||
RXM0EIDH = ((~amr2) >> 3) | ((~amr1) << 5); | ||
RXM0EIDL = ((~amr3) >> 3) | ((~amr2) << 5); | ||
/* | ||
// mask for filter 1 | ||
RXM0SIDH = ~amr0; | ||
RXM0SIDL = ((~amr1) & 0xE3) | 8; | ||
RXM0EIDH = ~amr2; | ||
RXM0EIDL = ~amr3; | ||
// mask for filter 2 | ||
RXM1SIDH = ~amr2; | ||
RXM1SIDL = (~amr3) & 0xE0; | ||
RXM1EIDH = 0x00; | ||
RXM1EIDL = 0x00; | ||
*/ | ||
} | ||
|
||
/** | ||
* \brief Set filter code of given SJA1000 register values | ||
* | ||
* \param amr0 Acceptence code register 0 | ||
* \param amr1 Acceptence code register 1 | ||
* \param amr2 Acceptence code register 2 | ||
* \param amr3 Acceptence code register 3 | ||
* | ||
* This function has only affect if controller is in configuration mode. | ||
*/ | ||
void can_set_SJA1000_filter_code(unsigned char acr0, unsigned char acr1, unsigned char acr2, unsigned char acr3) { | ||
RXF0SIDH = acr0; | ||
RXF0SIDL = (acr1 & 0xE0) | ((acr1 >> 3) & 3); | ||
if (acr3 & 1) RXF0SIDL |= 8; | ||
RXF0EIDH = (acr2 >> 3) | (acr1 << 5); | ||
RXF0EIDL = (acr3 >> 3) | (acr2 << 5); | ||
/* | ||
// acceptance code for filter 1 | ||
RXF0SIDH = acr0; | ||
RXF0SIDL = (acr1) & 0xE0; // standard | ||
RXF1SIDH = acr0; | ||
RXF1SIDL = ((acr1) & 0xE0) | 0x08; // extended | ||
// acceptance code for filter 2 | ||
RXF2SIDH = acr2; | ||
RXF2SIDL = (acr3) & 0xE0; // standard | ||
RXF3SIDH = acr2; | ||
RXF3SIDL = ((acr3) & 0xE0) | 0x08; // extended | ||
// fill remaining filters with zero | ||
// RXF4SIDH = 0x00; | ||
// RXF4SIDL = 0x00; | ||
// RXF5SIDH = 0x00; | ||
// RXF5SIDL = 0x00; | ||
*/ | ||
} | ||
|
||
/** | ||
* \brief Set bit timing registers | ||
* | ||
* \param cnf1 Configuration register 1 | ||
* \param cnf2 Configuration register 2 | ||
* \param cnf3 Configuration register 3 | ||
* | ||
* This function has only affect if controller is in configuration mode | ||
*/ | ||
void can_set_bittiming(unsigned char cnf1, unsigned char cnf2, unsigned char cnf3) { | ||
|
||
BRGCON1 = cnf1; | ||
BRGCON2 = cnf2; | ||
BRGCON3 = cnf3; | ||
} | ||
|
||
/** | ||
* \brief Send given CAN message | ||
* | ||
* \ p_canmsg Pointer to can message to send | ||
* \return 1 if transmitted successfully to transmit buffer, 0 on error (= no free buffer available) | ||
*/ | ||
unsigned char can_send_message(canmsg_t * p_canmsg) { | ||
ECANCON &= 0xE0; | ||
ECANCON |= 0x05; | ||
|
||
if (RXB0CON & 0x08) { | ||
ECANCON--; | ||
if (RXB0CON & 0x08) { | ||
ECANCON--; | ||
if (RXB0CON & 0x08) { | ||
return 0; //All TX buffers are busy | ||
} | ||
} | ||
} | ||
|
||
unsigned char length = p_canmsg->dlc; | ||
if (length > 8) length = 8; | ||
|
||
if (p_canmsg->flags.extended) { | ||
RXB0SIDH = p_canmsg->id >> 21; | ||
RXB0SIDL = ((p_canmsg->id >> 13) & 0xe0) | ((p_canmsg->id >> 16) & 0x03) | 0x08; | ||
RXB0EIDH = p_canmsg->id >> 8; | ||
RXB0EIDL = p_canmsg->id; | ||
} else { | ||
RXB0SIDH = p_canmsg->id >> 3; | ||
RXB0SIDL = p_canmsg->id << 5; | ||
} | ||
|
||
RXB0DLC = length; | ||
|
||
if (p_canmsg->flags.rtr) { | ||
RXB0DLC = length | 0x40; | ||
} else { | ||
if (length) { | ||
unsigned char *pTxBuf, i; | ||
|
||
pTxBuf = &RXB0D0; | ||
for (i = 0; i < length; i++) { | ||
*pTxBuf++ = p_canmsg->data[i]; | ||
} | ||
} | ||
} | ||
|
||
RXB0CON |= 8; | ||
|
||
return 1; | ||
} | ||
|
||
/* | ||
* \brief Read out one can message from controller | ||
* | ||
* \param p_canmsg Pointer to can message structure to fill | ||
* \return 1 on success, 0 if there is no message to read | ||
*/ | ||
unsigned char can_receive_message(canmsg_t * p_canmsg) { | ||
|
||
//unsigned char address; | ||
|
||
if (nFIFOEMPTY == 0) return 0; | ||
|
||
// store timestamp | ||
p_canmsg->timestamp = clock_getMS(); | ||
|
||
ECANCON &= 0xE0; | ||
ECANCON |= ((CANCON & 0x07) | 0x10); | ||
|
||
if (RXB0FUL == 0) return 0; | ||
|
||
unsigned char sidh = RXB0SIDH; | ||
unsigned char sidl = RXB0SIDL; | ||
|
||
if (sidl & 0x08) { | ||
// extended | ||
p_canmsg->flags.extended = 1; | ||
p_canmsg->id = (unsigned long) sidh << 21; | ||
p_canmsg->id |= (unsigned long)(sidl & 0xe0) << 13; | ||
p_canmsg->id |= (unsigned long)(sidl & 0x03) << 16; | ||
p_canmsg->id |= (unsigned long)(RXB0EIDH) << 8; | ||
p_canmsg->id |= (unsigned long) RXB0EIDL; | ||
unsigned char dlc = RXB0DLC; | ||
p_canmsg->dlc = dlc & 0x0f; | ||
p_canmsg->flags.rtr = (dlc >> 6) & 0x01; | ||
} else { | ||
// standard | ||
p_canmsg->flags.extended = 0; | ||
p_canmsg->flags.rtr = (sidl >> 4) & 0x01; | ||
p_canmsg->id = (unsigned long) sidh << 3; | ||
p_canmsg->id |= (unsigned long) sidl >> 5; | ||
p_canmsg->dlc = RXB0DLC & 0x0f; | ||
} | ||
|
||
// get data | ||
if (!p_canmsg->flags.rtr) { | ||
unsigned char i, *ptr; | ||
unsigned char length = p_canmsg->dlc; | ||
if (length > 8) length = 8; | ||
ptr = &RXB0D0; | ||
for (i = 0; i < length; i++) { | ||
p_canmsg->data[i] = *ptr++; | ||
} | ||
} | ||
|
||
RXB0FUL = 0; | ||
NOP(); | ||
RXBnIF = 0; | ||
|
||
return 1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
#ifndef _CAN_H_INC | ||
#define _CAN_H_INC | ||
|
||
// timing for Fosc = 16MHz // KVN | ||
#define CAN_TIMINGS_10K 0x00 | 49, 0x80 | ((4-1)<<3) | (7-1), 4-1 // Prop=7, PS1=4, PS2=4, SamplePoint=75% | ||
#define CAN_TIMINGS_20K 0x00 | 39, 0x80 | ((2-1)<<3) | (5-1), 2-1 // Prop=5, PS1=2, PS2=2, SamplePoint=80% | ||
#define CAN_TIMINGS_50K 0x00 | 15, 0x80 | ((2-1)<<3) | (5-1), 2-1 // Prop=5, PS1=2, PS2=2, SamplePoint=80% | ||
#define CAN_TIMINGS_100K 0x00 | 07, 0x80 | ((2-1)<<3) | (5-1), 2-1 // Prop=5, PS1=2, PS2=2, SamplePoint=80% | ||
#define CAN_TIMINGS_125K 0x00 | 07, 0x80 | ((2-1)<<3) | (3-1), 2-1 // Prop=3, PS1=2, PS2=2, SamplePoint=75% | ||
#define CAN_TIMINGS_250K 0x00 | 03, 0x80 | ((2-1)<<3) | (3-1), 2-1 // Prop=3, PS1=2, PS2=2, SamplePoint=75% | ||
#define CAN_TIMINGS_500K 0x00 | 01, 0x80 | ((2-1)<<3) | (3-1), 2-1 // Prop=3, PS1=2, PS2=2, SamplePoint=75% | ||
#define CAN_TIMINGS_800K 0x00 | 00, 0x80 | ((2-1)<<3) | (5-1), 2-1 // Prop=5, PS1=2, PS2=2, SamplePoint=80% | ||
#define CAN_TIMINGS_1M 0x00 | 00, 0x80 | ((2-1)<<3) | (3-1), 2-1 // Prop=3, PS1=2, PS2=2, SamplePoint=75% | ||
|
||
// can message data structure | ||
typedef struct | ||
{ | ||
unsigned long id; // identifier (11 or 29 bit) | ||
struct { | ||
unsigned char rtr : 1; // remote transmit request | ||
unsigned char extended : 1; // extended identifier | ||
} flags; | ||
|
||
unsigned char dlc; // data length code | ||
unsigned char data[8]; // payload data | ||
unsigned short timestamp; // timestamp | ||
} canmsg_t; | ||
|
||
// function prototypes | ||
//extern unsigned char can_init(); | ||
extern unsigned char can_read_register(unsigned short); | ||
extern void can_write_register(unsigned short, unsigned char); | ||
//extern void can_bit_modify(unsigned char address, unsigned char mask, unsigned char data); | ||
extern void can_set_SJA1000_filter_mask(unsigned char, unsigned char, unsigned char, unsigned char); | ||
extern void can_set_SJA1000_filter_code(unsigned char, unsigned char, unsigned char, unsigned char); | ||
extern unsigned char can_read_errorflags(void); | ||
extern void can_set_bittiming(unsigned char, unsigned char, unsigned char); | ||
extern unsigned char can_send_message(canmsg_t *); | ||
extern unsigned char can_receive_message(canmsg_t *); | ||
|
||
#endif |
Oops, something went wrong.