PowerBroker2 / ELMduino

Arduino OBD-II Bluetooth Scanner Interface Library for Car Hacking Projects
MIT License
677 stars 125 forks source link

ELM_TIMEOUT only when using eSPI library for TFT Display #210

Closed edwardcorke closed 11 months ago

edwardcorke commented 11 months ago

Hi. I've successfully used the ELMduino Bluetooth example to connect an ESP32 to a Bluetooth ELM327 and receive the RPM and MPH values. I simply want to display these on a TFT SPI display and tried merging the code for each.

Since adding the TFT library, specifically the eSPI library, I stripped back my code until the only difference was I included 2 libraries (SPI and eSPI) and created an instance. Just with these 3 lines I get an ELM TIMEOUT when waiting to receive new read values.

I'm wondering if there is some sort of interference when using ELMDuino over Bluetooth and SPI for a TFT display. Any help would be appreciated please.

Source Code:

#include "ELMduino.h"

BluetoothSerial SerialBT;
#define ELM_PORT   SerialBT
#define DEBUG_PORT Serial
uint8_t address[6] = {0x00,0x10,0xCC,0x4F,0x36,0x03};
ELM327 myELM327;

// TFT Display (3 lines of code that 'cause' the ELM TIMEOUT)
#include <SPI.h>
#include <TFT_eSPI.h>       // Hardware-specific library
TFT_eSPI tft = TFT_eSPI();  // Invoke custom library

const bool DEBUG        = true;
const int  TIMEOUT      = 2000;
const bool HALT_ON_FAIL = false;

typedef enum { ENG_RPM,
               SPEED } obd_pid_states;
obd_pid_states obd_state = ENG_RPM;

float rpm = 0;
float mph = 0;

void setup() {
  DEBUG_PORT.begin(38400);
  SerialBT.setPin("0000");
  ELM_PORT.begin("ArduHUD", true);

  if (!ELM_PORT.connect(address)) {
    DEBUG_PORT.println("Couldn't connect to OBD scanner - Phase 1");
    while(1);
  }

  if (!myELM327.begin(ELM_PORT, true, 2000, '5', 2000)) {
    Serial.println("Couldn't connect to OBD scanner - Phase 2");
    while (1);
  }
  Serial.println("Connected to ELM327");
}

void loop() {
  switch (obd_state) {
    case ENG_RPM: {
      rpm = myELM327.rpm();

      if (myELM327.nb_rx_state == ELM_SUCCESS) {
        Serial.print("rpm: ");
        Serial.println(rpm);
        obd_state = SPEED;
      }
      else if (myELM327.nb_rx_state != ELM_GETTING_MSG) {
        myELM327.printError();
        obd_state = SPEED;
      }  
      break;
    }

    case SPEED: {
      mph = myELM327.mph();

      if (myELM327.nb_rx_state == ELM_SUCCESS) {
        Serial.print("mph: ");
        Serial.println(mph);
        obd_state = ENG_RPM;
      }
      else if (myELM327.nb_rx_state != ELM_GETTING_MSG) {
        myELM327.printError();
        obd_state = ENG_RPM;
      }
      break;
    }
  }   
} ```

**Serial Output:**
``` Connected to ELM327
Service: 1
PID: 12
Normal length query detected
Query string: 010C1
Clearing input serial buffer
Sending the following command/query: 010C1
    Received char: 0
    Received char: 1
    Received char: 0
    Received char: C
    Received char: 1
    Received char: \r
    Received char: \r
Timeout detected with overflow of 0ms
Received: 010C1
ERROR: ELM_TIMEOUT
Service: 1
PID: 13
Normal length query detected
Query string: 010D1
Clearing input serial buffer
Sending the following command/query: 010D1
    Received char: 0
    Received char: 1
    Received char: 0
    Received char: D
    Received char: 1
    Received char: \r
    Received char: \r
Timeout detected with overflow of 0ms
Received: 010D1
ERROR: ELM_TIMEOUT
Service: 1
PID: 12
Normal length query detected
Query string: 010C1
Clearing input serial buffer
Sending the following command/query: 010C1
    Received char: 0
    Received char: 1
    Received char: 0
    Received char: C
    Received char: 1
    Received char: \r
Timeout detected with overflow of 0ms
Received: 010C1
ERROR: ELM_TIMEOUT
Service: 1
PID: 13
Normal length query detected
Query string: 010D1
Clearing input serial buffer
Sending the following command/query: 010D1
    Received char: 0
    Received char: 1
    Received char: 0
    Received char: D
    Received char: 1
    Received char: \r
    Received char: \r
Timeout detected with overflow of 0ms
Received: 010D1
ERROR: ELM_TIMEOUT

ESP32 Pins Used for TFT: MOSI - 21 (SDA) SCLK - 22 CS - 15 DC - 2 RST - 4

edwardcorke commented 11 months ago

Apologies, this was an error on my behalf - something in my code I'm trying to work out that is now working. Feel free to delete this issue. Thanks.

molotovec commented 5 months ago

Hi @PowerBroker2 ! Thanks a lot for the library ! I have the same ERROR: ELM_TIMEOUT . Value received for a while and then error happens. Code below

 // ga9a01 esp32 2424s012
#include <WiFi.h>
#include "ELMduino.h"
#include <TFT_eSPI.h>
#include <SPI.h>
#include <SoftwareSerial.h>
#include "SerpentineBoldItalic.h"
#include "pin_config.h"

#include "CST816D.h"
#define I2C_SDA 4
#define I2C_SCL 5
#define TP_RST 1
#define TP_INT 0

CST816D touch(I2C_SDA, I2C_SCL, TP_RST, TP_INT);
uint8_t gesture;
uint16_t touchX, touchY;

TFT_eSPI tft = TFT_eSPI();
TFT_eSprite testSprite = TFT_eSprite(&tft);

const char* ssid = "V-LINK";
const char* host = "192.168.0.10";
const int port = 35000;

// IP Address of your ELM327 Dongle
IPAddress server(192, 168, 0, 10);
WiFiClient client;
ELM327 myELM327;

const int ledPin = TFT_BL;  // 3 corresponds to GPIO3

const int freq = 2000;
const int ledChannel = 0;
const int resolution = 8;
const int dutyCycle = 255;  // LED brightness

float rpm = 0;
float volts = 0;

void setup() {
  Serial.begin(115200);

  touch.begin();  // Display init and touch

  tft.init();
  tft.setRotation(4);
  testSprite.setColorDepth(8);
  testSprite.createSprite(240, 240);

  ledcSetup(ledChannel, freq, resolution);  // migration from 2.x to 3.x
  ledcAttachPin(ledPin, ledChannel);        // Attach the LED pin to the channel
  ledcWrite(ledChannel, dutyCycle);         // Set the LED brightness

  // Clear the screen
  tft.fillScreen(TFT_BLACK);

  // Connecting to ELM327 WiFi
  Serial.print("Connecting to ");
  Serial.println(ssid);
  tft.setTextColor(TFT_WHITE);
  tft.drawCentreString("Connecting...", 120, 80, 2);

  WiFi.mode(WIFI_AP);
  WiFi.begin(ssid);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("Connected to Wifi ");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  IPAddress ip = WiFi.localIP();
  char ipChar[16];
  sprintf(ipChar, "%u.%u.%u.%u", ip & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, (ip >> 24) & 0xFF);
  String ipStr(ipChar);  // convert char array to string here.
  tft.setTextColor(TFT_CYAN);
  tft.drawCentreString("Connected to Wifi " + ipStr, 120, 120, 2);

  if (client.connect(server, 35000)) {
    Serial.println("Connected!");
    tft.drawCentreString("Connected", 120, 160, 2);
  } else {
    Serial.println(">>>> Connection failed!!! <<<<");
    tft.fillScreen(TFT_BLACK);
    tft.setTextColor(TFT_CYAN);
    tft.drawCentreString("Connection failed!", 120, 80, 2);
    delay(1000);
    resetDraw();
    delay(500);
    ESP.restart();
  }

  myELM327.begin(client, true, 5000, ISO_15765_29_BIT_500_KBAUD);
}

void draw(float value) {
  testSprite.fillSprite(TFT_BLACK);

  testSprite.setTextColor(TFT_CYAN);
  testSprite.loadFont(SerpentineBoldItalic68pt);
  testSprite.setTextDatum(CC_DATUM);
  testSprite.drawFloat(value, 2, 120, 130);

  testSprite.setTextColor(TFT_GOLD);
  testSprite.loadFont(SerpentineBoldItalic18pt);
  //testSprite.drawString("RPM", 120, 180);
  testSprite.drawString("Volts", 120, 180);

  testSprite.pushSprite(0, 0);
}

void resetDraw() {
  testSprite.fillSprite(TFT_RED);
  testSprite.pushSprite(0, 0);
  Serial.println("Resetting ESP32...");
  delay(500);  // Small delay to allow serial message to be sent
  ESP.restart();
}

void loop() {
  //float tempRPM = myELM327.rpm();
float tempVolts = myELM327.batteryVoltage();
  if (myELM327.nb_rx_state == ELM_SUCCESS) {
    //rpm = tempRPM;
    volts=tempVolts;
  } else {
    Serial.println("Failed to receive data from ELM327.");
    myELM327.printError();
  }

  //draw(rpm);
  draw(volts);

  if (myELM327.nb_rx_state == ELM_TIMEOUT) {
    Serial.print("Reset by: ELM_TIMEOUT");
    resetDraw();
  }
}

void printError() {
  Serial.print("Received: ");
  for (byte i = 0; i < myELM327.recBytes; i++)
    Serial.write(myELM327.payload[i]);
  Serial.println();

  if (myELM327.nb_rx_state == ELM_SUCCESS)
    Serial.println(F("\tELM_SUCCESS"));
  else if (myELM327.nb_rx_state == ELM_NO_RESPONSE)
    Serial.println(F("\tERROR: ELM_NO_RESPONSE"));
  else if (myELM327.nb_rx_state == ELM_BUFFER_OVERFLOW)
    Serial.println(F("\tERROR: ELM_BUFFER_OVERFLOW"));
  else if (myELM327.nb_rx_state == ELM_UNABLE_TO_CONNECT)
    Serial.println(F("\tERROR: ELM_UNABLE_TO_CONNECT"));
  else if (myELM327.nb_rx_state == ELM_NO_DATA)
    Serial.println(F("\tERROR: ELM_NO_DATA"));
  else if (myELM327.nb_rx_state == ELM_STOPPED)
    Serial.println(F("\tERROR: ELM_STOPPED"));
  else if (myELM327.nb_rx_state == ELM_TIMEOUT)
    Serial.println(F("\tERROR: ELM_TIMEOUT"));
  else if (myELM327.nb_rx_state == ELM_GENERAL_ERROR)
    Serial.println(F("\tERROR: ELM_GENERAL_ERROR"));

  delay(100);
}

Log below ELM_timeout_LOG.txt

Thanks in advance!

Update: No tft (plain) wifi example also shows timeout issue (library 3.3.0, esp32C3, ELM327 v2.3 VGATE iCar Pro)

jimwhitelaw commented 5 months ago

@molotovec You've commented on a closed issue that isn't quite related to yours. I've moved your comment to a new issue here.