PDA

View Full Version : Elm327 obd



mpgmike
- 4th March 2018, 17:22
I've spent about 2 years familiarizing myself with SAE OBD II communications protocols. I purchased the ELM327 OBD II CAN Interpreter, based on a PIC18F2480. As a test module, I printed a PCB board that uses a PIC18F25K50 for USB communication to my laptop. The initial goal is to send a command from the laptop to the K50 which is then sent serially to the ELM. I rigged an LCD screen to display (from the K50) communications both ways. I have the LCD verifying commands from the PC. However, the ELM327 Data Sheet claims it sends "ELM327 v2.1" when fired up, and when given "ATZ" command. I cannot seem to get the appropriate response from the ELM.

I rigged a logic analyzer to both Comm pins to see if it at least looked like it should. Sending "ATZ" from the PC is converted to 0x03 for the variable ByteCount (indicating 3 bytes of data to be transmitted; ATZ), 0x41 ("A"), 0x44 ("T), 0x5A ("Z"). The LCD confirms the K50 is receiving this from the PC via USB. From the K50 I send "ATZ" then $0D, which is the Carriage Return value. From the K50, the logic analyzer shows 0xA5, 0x8A, 0x96, 0xAC. Response from ELM is NULL, NULL. I tried MSB & LSB First, I tried Auto Baud Detect on the Logic Analyzer, I triple checked the 8 bits, 1 stop bit, no parity settings...

Next, the ELM327 has a couple BAUD rate options. Pin 6 tied to Vdd sets the initial baud at 38400, which is the option I chose. The punch line is I am unable to get the K50 talking with the ELM properly. I tried using the HSERIN/OUT commands setting the DEFINEs, but communication couldn't be verified. I then sent & received transmissions directly through the TXREG1 and RCREG1. Still no success. If I manually load values to represent an ELM transmission, the USB properly displays them, so the USB side seems fine. UART is not something I've worked with extensively. My inclinations are I'm not processing the data correctly between the K50 & ELM. Here is the pertinent code:



;Configurations:
#CONFIG
CONFIG PLLSEL = PLL3X ;3x clock multiplier
CONFIG CFGPLLEN = ON ;PLL Enabled
CONFIG CPUDIV = NOCLKDIV ;CPU uses system clock (no divide)
CONFIG LS48MHZ = SYS48X8 ;System clock at 48 MHz, USB clock divider is set to 8
CONFIG FOSC = INTOSCIO ;Internal oscillator
CONFIG PCLKEN = OFF ;Primary oscillator shutdown firmware controlled
CONFIG FCMEN = OFF ;Fail-Safe Clock Monitor disabled
CONFIG IESO = OFF ;Oscillator Switchover mode disabled
; CONFIG PWRTEN = OFF ;Power up timer disabled
CONFIG BOREN = ON ;BOR controlled by firmware (SBOREN is enabled)
CONFIG BORV = 190 ;BOR set to 1.9V nominal
; CONFIG LPBOR = OFF ;Low-Power Brown-out Reset disabled
CONFIG WDTEN = ON ;WDT enabled in hardware (SWDTEN ignored)
CONFIG WDTPS = 512 ;1:512
CONFIG CCP2MX = RC1 ;CCP2 input/output is multiplexed with RC1
CONFIG PBADEN = OFF ;PORTB<5:0> pins are configured as digital I/O on Reset
CONFIG T3CMX = RC0 ;T3CKI function is on RC0
CONFIG SDOMX = RB3 ;SDO function is on RB3
CONFIG MCLRE = OFF ;MCLR pin disabled; RE3 input enabled
CONFIG STVREN = ON ;Stack full/underflow will cause Reset
CONFIG LVP = OFF ;Single-Supply ICSP disabled
; CONFIG XINST = OFF ;Instruction set extension and Indexed Addressing mode disabled
#ENDCONFIG


INCLUDE "descript.bas" ' Include the USB & HID descriptors
INCLUDE "DT_INTS-18.bas"
INCLUDE "ReEnterPBP-18.bas"

Define OSC 48

;Interrupt Processor:
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler RX_INT, _Get_Elm, PBP, yes ;USART Transmission Received
endm
INT_CREATE ;Creates the interrupt processor
ENDASM

; --- *** Oscillator Related SFRs *** ----------------------------------------------------------------------------------
OSCCON = %01110000 ;INTOSC 16 MHz, PLL Defined
OSCCON2 = %10010010 ;PLL Enabled, HFINTOSC Running
OSCTUNE.7 = 1 ;3X PLL
; --- *** USB SFRs *** -------------------------------------------------------------------------------------------------
UCON = %00001110
UCFG = %00010100
; --- *** USART SFRs *** -----------------------------------------------------------------------------------------------
TXSTA1 = %00100100 ;24h, Yields 38400 Baud
;TXSTA1 = %00100000 ;20h, Yields 9600 Baud
RCSTA1 = %10010000 ;90h, .2 = FERR, .1 = OERR
BAUDCON1 = %01000000
SPBRG = 77 ;38400 Baud @ 48MHz, 0.16%
PIE1.5 = 1 ;RCIE
PIR1.5 = 0 ;RCIF
PIE1.4 = 0 ;TXIE
INTCON = %11000000

;Variables:
b0 VAR BYTE BANK0 SYSTEM ;Used for For/Next Loops
b1 VAR BYTE BANK0 SYSTEM ;Used for For/Next Loops
CmdCt VAR BYTE ;Similar to ByteCount, for ELM327
CmdSet VAR WORK.1 ;Indicates a Command has been received from the PC
ElmBuf VAR WORK.3 ;ELM Data Received before Init_LCD Completed
ElmSet VAR Work.0 ;End of Transmissions USART RX (Input from ELM), denoted by $D0 (CR)
Hin0 VAR BYTE BANK0 SYSTEM ;USART Input from ELM327, BYTE0
InBufIndex VAR BYTE BANK0 SYSTEM ;Index used to move BYTES from Hinx to InBuf[InBufIndex]
Work VAR BYTE ;Working Bits


' Alias for easy access to bit variables:
hmRptVarBitArray0 var byte


' Endpoint 1 IN variables:
' ========================
ElmData var byte[23]
OER var hmRptVarBitArray0.0
FER var hmRptVarBitArray0.1


' Endpoint 1 OUT variables:
' =========================
ByteCount var byte
CmdData var byte[23]

Goto start ' Skip around interrupt handler


' ************************************************** **********************
' Subroutines:
' ************************************************** **********************


; --- *** RX_INT Interrupt Handler from ELM327 *** ---------------------------------------------------------------------
Get_Elm:
Hin0 = RCREG1
; RCSTA1.4 = 0 ;CLOERR
; RCSTA1.4 = 1 ;CLOERR
IF (Hin0 <> $0D) AND (Hin0 <> $29) THEN ;CR or ">"
ElmData[InBufIndex] = Hin0
InBufIndex = InBufIndex + 1
;EP1XmtDataReady = TRUE
GOTO Leave
ELSEIF Hin0 = $0D THEN ;Carriage Return
b1 = InBufIndex - 1
ElmData[b1] = Hin0
FOR b0 = InBufIndex TO 22
ElmData[b0] = 0
NEXT b0
EP1XmtDataReady = TRUE
InBufIndex = 0
GOTO Leave
ENDIF
Leave:
; USBService
@ INT_RETURN

InitUSBVars:


USB_Enum_Complete = 0
return


' ************************************************** **********************
' USB Init Code:
' ************************************************** **********************


start:
gosub InitUSBVars
RTS = 1 ;Active Low, ELM Request To Send
Work = 0 ;Start all Working Bits at 0
InBufIndex = 0 ;Clear Input Buffer Index for ELM UART
USBW_On = 0
Pause 10
USBInit ' Init USB and wait until configured
HandleEp1Rcv = FALSE

MainLoop:
USBService ; Must service USB regularly
HandleEp1Rcv = FALSE
;HIDMaker created USB related code goes here next
DoHandleEp1Rcv:
HandleEp1Rcv = TRUE ' Indicate that we have data to handle
GOSUB Send_Elm ;We now have data from the USB to send to ELM

ExitEp1Rcv:
OER = RCSTA1.1 ;UART Over Run Error
FER = RCSTA1.2. ;UART Framing Error


EP1XmtDataReady = TRUE
;More HIDMaker generated USB code

Send_Elm:
RTS = 0
DO
LOOP WHILE PIR1.4 = 0
TXREG1 = $29
FOR b0 = 0 TO (ByteCount - 1)
DO
LOOP WHILE PIR1.4 = 0
TXREG1 = CmdData[b0]
NEXT b0
DO
LOOP WHILE PIR1.4 = 0
TXREG1 = $0D
HandleEp1Rcv = FALSE
RTS = 1
USBService
RETURN

tumbleweed
- 4th March 2018, 21:01
The PORTC UART pins on the K50 have analog capability, so try turning that off with ANSELC = 0

mpgmike
- 5th March 2018, 02:57
I skipped some of the code for brevity's sake; here is my PORT SFRs:


; --- *** PORT Related SFRs *** ----------------------------------------------------------------------------------------
TRISA = %01000000
TRISB = 0
TRISC = %11000000
ANSELA = 0
ANSELB = 0
ANSELC = 0

tumbleweed
- 5th March 2018, 10:13
Just to make sure I'm following you...
From the K50, the logic analyzer shows 0xA5, 0x8A, 0x96, 0xACSo the PC->K50 USB is ok... you see "ATZ", but the K50 uart TX is what's wrong? The above should have been "ATZ"?

I'll look back over the uart setup, but in the meantime try transmitting a "U" (0x55) on the uart and measure the bit times with a scope


txtest:
DO
LOOP WHILE PIR1.4 = 0
TXREG1 = $55
GOTO txtest

At 38400 bit times should be ~26us

mpgmike
- 9th March 2018, 14:40
I finally got it working. The big thing was it seems I missed traces on 2 of the ELM327 board that tie pins 5 & 6 to Vdd. Pin 5 holds the memory while pin 6 is the Baud selector. Ran a jumper on the bottom of the board and now it works.