Skip to content

Commit

Permalink
Squashed commit of the following:
Browse files Browse the repository at this point in the history
commit 8dee15f
Author: Goostaf <[email protected]>
Date:   Mon Apr 1 00:22:32 2024 +0200

    Use pullup for VSS

commit 28c861a
Author: Goostaf <[email protected]>
Date:   Fri Mar 29 11:10:23 2024 +0100

    Use lower-level configuration

commit 4e7c173
Merge: 44e9908 7ec80c5
Author: Goostaf <[email protected]>
Date:   Sun Mar 24 11:54:55 2024 +0100

    Merge branch 'main' into feature/mcpwm-capture

    # Conflicts:
    #	src/fuel_economy_meter/config.h
    #	src/fuel_economy_meter/elm327.cpp
    #	src/fuel_economy_meter/trip.cpp
    #	src/fuel_economy_meter/trip.h

commit 44e9908
Author: Goostaf <[email protected]>
Date:   Mon Oct 23 14:47:40 2023 +0200

    Correct VSS MCPWM unit, attempt to fix overflow

commit d0ed833
Author: Goostaf <[email protected]>
Date:   Mon Oct 23 01:41:39 2023 +0200

    Fix watchdog timeouts in ISRs, correct timer config

commit 4aeda37
Author: Goostaf <[email protected]>
Date:   Thu Sep 28 01:08:47 2023 +0200

    Renaming and better comments

commit c84ea1e
Author: Goostaf <[email protected]>
Date:   Mon Sep 18 00:33:25 2023 +0200

    Convert timer ticks to microseconds

commit 669c473
Author: Goostaf <[email protected]>
Date:   Sun Sep 17 23:26:56 2023 +0200

    Remove extra comment

commit 29b477c
Author: Goostaf <[email protected]>
Date:   Sun Sep 17 23:24:50 2023 +0200

    Use MCPWM, velocity and injector timeouts

commit a1006e3
Author: Goostaf <[email protected]>
Date:   Sun Sep 17 15:21:44 2023 +0200

    Clearer documentation

commit 6c3c080
Author: Goostaf <[email protected]>
Date:   Sun Sep 17 15:14:00 2023 +0200

    Sample time immediately on interrupt
  • Loading branch information
GAsplund committed Mar 31, 2024
1 parent 7ec80c5 commit 4463e3c
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 70 deletions.
10 changes: 8 additions & 2 deletions src/fuel_economy_meter/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,21 @@
#define VSS_GPIO GPIO_NUM_19

// The maximum allowed time between opening and closing the injector
#define INJ_DELTA_MAX 500000
#define INJ_DELTA_MAX 0x80000000UL
// Amount of time for an injector to have injected 1 liter of fuel
#define INJ_USEC_LITER 53454766.0f
// Amount of time to consider the engine to be stopped
#define INJ_TICKS_TIMEOUT 1000000

// The maximum allowed time between VSS pulses to calculate velocity
#define VSS_DELTA_MAX 5000000
// Preferably below 0xFFFFFFFF, since that is the maximum value for uint32_t
#define VSS_DELTA_MAX 0x80000000UL

// Amount of VSS pulses to have travelled 1 Km
#define VSS_PULSE_KM 6840.0f
// Amount of time to consider the vehicle to be stopped
// Preferably below 0xFFFFFFFF, since that is the maximum value for uint32_t
#define VSS_TICKS_TIMEOUT 0x80000000UL

/*
* Bluetooth parameters
Expand Down
2 changes: 1 addition & 1 deletion src/fuel_economy_meter/elm327.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ void ELM327::poll(void)
}
else if (pid == "14")
{
OBDReturn = "61" + pid + converttohex(trip->latestInjectionTime, 4);
OBDReturn = "61" + pid + converttohex(trip->latestInjectionDutyTime, 4);
}
stream->println(OBDReturn);
}
Expand Down
15 changes: 8 additions & 7 deletions src/fuel_economy_meter/fuel_economy_meter.ino
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
#include "log_stream.h"

static Trip trip;
//static ELM327 elm327;
static LogStream logStream;
static ELM327 elm327;
//static LogStream logStream;

void setup()
{
Expand All @@ -14,15 +14,16 @@ void setup()
setupBT();
Serial.println("Trip");
trip.begin();
//elm327.begin(&SerialBT, &trip);
Serial.println("LogStream");
logStream.begin(&SerialBT, &trip);
elm327.begin(&SerialBT, &trip);
//Serial.println("LogStream");
//logStream.begin(&Serial, &trip);

Serial.println("Setup done");
}

void loop()
{
delay(1000);
logStream.log();
//delay(1000);
//logStream.log();
elm327.poll();
}
2 changes: 1 addition & 1 deletion src/fuel_economy_meter/log_stream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ void LogStream::log()
float lph = trip->getLph();
float eff = trip->getEfficiency();

stream->print(trip->latestInjectionTime);
stream->print(trip->latestInjectionDutyTime);
stream->print(" uS/inj ");
stream->print(trip->getRpm());
stream->print(" RPM ");
Expand Down
175 changes: 126 additions & 49 deletions src/fuel_economy_meter/trip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@
#include <arduino.h>
#include "esp_timer.h"
#include "config.h"
#include "soc/mcpwm_reg.h"
#include "soc/mcpwm_struct.h"
#include "driver/mcpwm.h"
#include "driver/timer.h"

Trip *Trip::sTrip = 0;
#define APB_TICK_US(ticks) ((ticks) / (APB_CLK_FREQ / 1000000))

Trip *sTrip = 0;

/**
* Starts the VSS interrupts and adds interrupts for the injector and VSS sensor
Expand All @@ -13,87 +19,154 @@ void Trip::begin(void)
{
sTrip = this;

Serial.println("Setting up timers");
timer_init(TIMER_GROUP_0, TIMER_0, &timeout_timer_conf);
timer_init(TIMER_GROUP_0, TIMER_1, &timeout_timer_conf);
timer_set_counter_value(TIMER_GROUP_0, TIMER_0, INJ_TICKS_TIMEOUT);
timer_set_counter_value(TIMER_GROUP_0, TIMER_1, VSS_TICKS_TIMEOUT);
timer_isr_callback_add(TIMER_GROUP_0, TIMER_0, &Trip::timeoutInjISR, NULL, 0);
timer_isr_callback_add(TIMER_GROUP_0, TIMER_1, &Trip::timeoutVssISR, NULL, 0);

Serial.println("Setting up injector ISR");
gpio_pad_select_gpio(INJ_GPIO);
gpio_set_direction(INJ_GPIO, GPIO_MODE_INPUT);
gpio_set_pull_mode(INJ_GPIO, GPIO_PULLUP_ONLY);
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM_CAP_0, INJ_GPIO);
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM_CAP_1, INJ_GPIO);
mcpwm_capture_enable(MCPWM_UNIT_0, MCPWM_SELECT_CAP0, MCPWM_NEG_EDGE, 0);
mcpwm_capture_enable(MCPWM_UNIT_0, MCPWM_SELECT_CAP1, MCPWM_POS_EDGE, 0);
mcpwm_isr_register(MCPWM_UNIT_0, Trip::tripInjISRHandler, NULL, ESP_INTR_FLAG_IRAM, NULL);

Serial.println("Setting up VSS ISR");
gpio_pad_select_gpio(VSS_GPIO);
gpio_set_direction(VSS_GPIO, GPIO_MODE_INPUT);
gpio_set_pull_mode(VSS_GPIO, GPIO_PULLUP_ONLY);

Serial.println("Enabling ISR");
gpio_install_isr_service(0);
gpio_set_intr_type(INJ_GPIO, GPIO_INTR_ANYEDGE);
gpio_set_intr_type(VSS_GPIO, GPIO_INTR_POSEDGE);

gpio_isr_handler_add(INJ_GPIO, Trip::updateTripInjISR, (void *)INJ_GPIO);
gpio_isr_handler_add(VSS_GPIO, Trip::updateTripVssISR, (void *)VSS_GPIO);
mcpwm_gpio_init(MCPWM_UNIT_1, MCPWM_CAP_0, VSS_GPIO);
mcpwm_gpio_init(MCPWM_UNIT_1, MCPWM_CAP_1, VSS_GPIO);
mcpwm_capture_enable(MCPWM_UNIT_1, MCPWM_SELECT_CAP0, MCPWM_NEG_EDGE, 0);
mcpwm_capture_enable(MCPWM_UNIT_1, MCPWM_SELECT_CAP1, MCPWM_POS_EDGE, 0);
mcpwm_isr_register(MCPWM_UNIT_1, Trip::tripVssISRHandler, NULL, ESP_INTR_FLAG_IRAM, NULL);

Serial.println("Starting timers");
timer_start(TIMER_GROUP_0, TIMER_0);
timer_start(TIMER_GROUP_0, TIMER_1);
}

/**
* @brief Handles a pulse change in the injector signal
* @brief Handles a pulse in the injector signal
*
* Used to calculate total and momentary injection time.
* Injector is considered open when the signal is low due to MOSFET pulling it down.
*
* ╭―(+ Inj -)―╮
* + o - pull-down signal
* - / - MOSFET
* | |
* - / - ECU MOSFET
* ╰―――――――――――╯
*/
void Trip::injChange()
void Trip::injPulse(uint32_t openCap, uint32_t closeCap)
{
uint64_t changeTimestamp = esp_timer_get_time();
if (gpio_get_level(INJ_GPIO) == 0)
timer_set_counter_value(TIMER_GROUP_0, TIMER_0, INJ_TICKS_TIMEOUT);

// Make sure that the injector has been open before
// We also don't know how many times we could have
// overflowed before, so we discard any additional captures
if (this->latestInjectionTimestamp == 0)
{
if (this->injOpenTimestamp > 0)
this->latestInjectionPeriod = changeTimestamp - this->injOpenTimestamp;
this->injOpenTimestamp = changeTimestamp;
this->totalInjectionPulses += 1;
this->latestInjectionTimestamp = openCap;
return;
}
else
{
uint32_t delta = changeTimestamp - this->injOpenTimestamp;

if (delta < INJ_DELTA_MAX)
{
this->latestInjectionTime = delta;
this->totalInjectionTime += this->latestInjectionTime;
}
uint32_t dutyTime = openCap > closeCap ?
(0xFFFFFFFF - openCap) + closeCap + 1:
closeCap - openCap;

if (dutyTime <= INJ_DELTA_MAX)
{
this->latestInjectionDutyTime = APB_TICK_US(dutyTime);
this->latestInjectionPeriod = APB_TICK_US(openCap - this->latestInjectionTimestamp);
}

this->latestInjectionTimestamp = openCap;
}

void IRAM_ATTR Trip::updateTripInjISR(void*)
void IRAM_ATTR Trip::tripInjISRHandler(void* arg)
{
if (sTrip != 0)
sTrip->injChange();
if (MCPWM0.int_st.cap1_int_st && sTrip != 0)
sTrip->injPulse(mcpwm_capture_signal_get_value(MCPWM_UNIT_0, MCPWM_SELECT_CAP0), mcpwm_capture_signal_get_value(MCPWM_UNIT_0, MCPWM_SELECT_CAP1));

MCPWM0.int_clr.val = MCPWM0.int_st.val;
}

/**
* @brief Handles a pulse in the VSS signal
*
* Gets the timestamp of the pulse and calculates the period between the current and the last pulse.
* If the period is not too long, it is stored as the latest period.
* Uses the length of the pulse to calculate the velocity of the vehicle.
* If the time since the last pulse isn't too long, the pulse is considered to be valid.
*/
void Trip::vssPulse(uint32_t upCap, uint32_t downCap)
{
timer_set_counter_value(TIMER_GROUP_0, TIMER_1, VSS_TICKS_TIMEOUT);
this->totalVssPulses++;

if(isStopped)
{
isStopped = false;
return;
}

// We assume that the HIGH time is always half a period
uint32_t period = 2 * (upCap > downCap ?
(0xFFFFFFFF - upCap) + downCap + 1:
downCap - upCap);

if (period < VSS_DELTA_MAX)
this->latestVssPeriod = APB_TICK_US(period);
}

void IRAM_ATTR Trip::tripVssISRHandler(void* arg)
{
if (MCPWM1.int_st.cap1_int_st && sTrip != 0)
sTrip->vssPulse(mcpwm_capture_signal_get_value(MCPWM_UNIT_1, MCPWM_SELECT_CAP0), mcpwm_capture_signal_get_value(MCPWM_UNIT_1, MCPWM_SELECT_CAP1));

MCPWM1.int_clr.val = MCPWM1.int_st.val;
}

/**
* @brief Handles a timeout in the injector signal
*
* Used to calculate the total RPM of the engine.
* If the injector has not opened for a long time, the engine is considered to be stopped.
*/
void Trip::timeoutInj()
{
this->latestInjectionPeriod = 0;
this->latestInjectionDutyTime = 0;
this->latestInjectionTimestamp = 0;
}

bool IRAM_ATTR Trip::timeoutInjISR(void*)
{
Serial.println("Inj timeout");
if (sTrip != 0)
sTrip->timeoutInj();
return false;
}

/**
* @brief Handles a timeout in the VSS signal
*
* Since the period is only used to calculate velocity, the delta is not needed when the period is
* too long. (i.e. when the vehicle is stopped)
* Used to calculate the total velocity of the vehicle.
* If the VSS signal has not pulsed for a long time, the vehicle is considered to be stopped.
*/
void Trip::vssPulse()
void Trip::timeoutVss()
{
uint64_t pulseTimestamp = esp_timer_get_time();
uint32_t delta = pulseTimestamp - this->latestVssTimestamp;
if (delta < VSS_DELTA_MAX)
this->latestVssPeriod = delta;
this->totalVssPulses += 1;
this->latestVssTimestamp = pulseTimestamp;
this->latestVssPeriod = 0;
this->isStopped = true;
}

void IRAM_ATTR Trip::updateTripVssISR(void*)
bool IRAM_ATTR Trip::timeoutVssISR(void*)
{
Serial.println("VSS timeout");
if (sTrip != 0)
sTrip->vssPulse();
sTrip->timeoutVss();
return false;
}

/**
Expand All @@ -110,6 +183,7 @@ void IRAM_ATTR Trip::updateTripVssISR(void*)
*
* @return the current engine RPM
*/
//uint16_t Trip::getRpm(void) { return (this->latestInjectionPeriod > 0) ? (60 * 1000000) / this->latestInjectionPeriod : 0; }
uint_fast16_t Trip::getRpm(void) { return (this->latestInjectionPeriod > 0) ? 60000000 / this->latestInjectionPeriod : 0; }

/**
Expand All @@ -120,11 +194,12 @@ float Trip::getLiters(void) { return this->totalInjectionTime * (1 / INJ_USEC_LI
/**
* @brief Calculates the duty cycle on the injector
*/
float Trip::getDuty(void) { return (this->latestInjectionPeriod > 0) ? (float) this->latestInjectionTime / (float) this->latestInjectionPeriod : 0; }
float Trip::getDuty(void) { return (this->latestInjectionPeriod > 0) ? (float) this->latestInjectionDutyTime / (float) this->latestInjectionPeriod : 0; }

/**
* @brief Calculates momentary fuel consumption
*/
//float Trip::getLph(void) { return (3.6E9 * getDuty()) / INJ_USEC_LITER; }
float Trip::getLph(void) { return (3600000000.0f / INJ_USEC_LITER) * getDuty(); }

/**
Expand All @@ -135,7 +210,8 @@ float Trip::getKm(void) { return this->totalVssPulses * (1 / VSS_PULSE_KM); }
/**
* Calculates the velocity in km/h
*/
float Trip::getKmh(void) { return (esp_timer_get_time() - this->latestVssTimestamp > VSS_DELTA_MAX) ? 0 : ( 3600/VSS_PULSE_KM ) * this->getVel(); }
float Trip::getKmh(void) { return (this->latestVssPeriod > 0) ? (this->getVel() / VSS_PULSE_KM) * 3600 : 0; }
//float Trip::getKmh(void) { return (esp_timer_get_time() - this->latestVssTimestamp > VSS_DELTA_MAX) ? 0 : ( 3600/VSS_PULSE_KM ) * this->getVel(); }

/**
* @brief Calculates the momentary fuel efficiency
Expand All @@ -158,4 +234,5 @@ float Trip::getEfficiency() {
*
* @return the amount of VSS pulses per second based on the latest period
*/
float Trip::getVel() { return (this->latestVssPeriod > 0) ? 1000000.0f / this->latestVssPeriod : 0; }
float Trip::getVel() { return this->isStopped ? 0 : 1000000.0 / this->latestVssPeriod; }
//float Trip::getVel() { return (this->latestVssPeriod > 0) ? 1000000.0f / this->latestVssPeriod : 0; }
40 changes: 30 additions & 10 deletions src/fuel_economy_meter/trip.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#define TRIP_H_

#include <Arduino.h>
#include "driver/mcpwm.h"
#include "driver/timer.h"

/**
* @brief Class for handling fuel and velocity calculations
Expand All @@ -18,31 +20,49 @@ class Trip
float getEfficiency();
float getLph(void);

volatile uint32_t latestInjectionTime = 0; /// The duty time of the last injection pulse
volatile uint32_t latestInjectionDutyTime = 0; /// The duty time of the last injection pulse

private:
static Trip *sTrip;

float getVel();
float getDuty(void);

static IRAM_ATTR void updateTripInjISR(void*);
static IRAM_ATTR void updateTripVssISR(void*);
void injChange();
void vssPulse();
//static IRAM_ATTR void tripInjISR(void*);
//static IRAM_ATTR void tripVssISR(void*);
//static IRAM_ATTR bool tripInjISR(mcpwm_unit_t, mcpwm_capture_channel_id_t, const cap_event_data_t *, void *);
//static IRAM_ATTR bool tripVssISR(mcpwm_unit_t, mcpwm_capture_channel_id_t, const cap_event_data_t *, void *);

static IRAM_ATTR void tripInjISRHandler(void *);
static IRAM_ATTR void tripVssISRHandler(void *);

static IRAM_ATTR bool timeoutInjISR(void*);
static IRAM_ATTR bool timeoutVssISR(void*);

void injPulse(uint32_t, uint32_t);
void vssPulse(uint32_t, uint32_t);
void timeoutInj();
void timeoutVss();

volatile uint32_t totalInjectionPulses = 0;
volatile uint64_t totalInjectionTime = 0;
volatile uint32_t totalRpmPulses = 0;

volatile uint32_t latestInjectionTimestamp = 0;
volatile uint32_t latestInjectionPeriod = 0;
volatile uint32_t latestRpmTime = 0;

volatile uint64_t injOpenTimestamp = 0;

volatile uint32_t totalVssPulses = 0;
volatile uint64_t latestVssTimestamp = 0;
volatile uint32_t latestVssPeriod = 0;
volatile bool isStopped = true;

const timer_config_t timeout_timer_conf = {
.alarm_en = TIMER_ALARM_EN,
.counter_en = TIMER_PAUSE,
.intr_type = TIMER_INTR_LEVEL,
.counter_dir = TIMER_COUNT_DOWN,
.auto_reload = TIMER_AUTORELOAD_DIS,
.divider = 2
};

};

#endif // TRIP_H_

0 comments on commit 4463e3c

Please sign in to comment.