Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 9 additions & 24 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name: CI
on:
push:
branches: [ "master" ]
branches: [ "**" ]
pull_request:
branches: [ "master" ]
branches: [ "**" ]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
Expand All @@ -13,31 +13,16 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
target: [esp32, esp32c3]
display: [cu2, cu3]
custom: [std]
include:
- target: esp32
display: cu3
custom: mike
- target: esp32
display: cu3
custom: wroom2xrelay
- target: esp32
display: cu2
custom: gpu7990
- target: esp32
display: cu3
custom: gpu7990
- target: esp32
- target: esp32c3
display: cu2
custom: dvjcodec
- target: esp32
display: cu3
custom: dvjcodec
custom: Tesla
- target: esp32c3
display: cu2
custom: supermini
custom: TeslaS
- target: esp32c3
display: cu3
custom: TeslaTour
steps:
- name: Checkout repo
uses: actions/checkout@v3
Expand All @@ -57,7 +42,7 @@ jobs:
- name: esp-idf build
uses: espressif/esp-idf-ci-action@v1
with:
esp_idf_version: latest
esp_idf_version: v5.5.1
target: ${{ matrix.target }}
path: ''

Expand Down
16 changes: 16 additions & 0 deletions main/Kconfig.projbuild
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,20 @@ menu "Sparta Ion Config"
int "The actual battery voltage in mv for full (=100%). For example 42000mv for a 10s battery"
default 42000

config ION_CURR_ADC
bool "Enable ADC for current measurement"
default n

config ION_CURR_ADC_CHAN
int "ADC channel to use for current measurement"
default 6

config ION_BAT_CHARGE
int "Full battery charge in mAh."
default 10000

config CONFIG_ION_KEEPALIVE
bool "Enable keepalive heartbeat. Will reset the ESP32 when main loop is stuck for more than a minute."
default n

endmenu
75 changes: 52 additions & 23 deletions main/bat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

static const char *TAG = "bat";

static uint32_t chargeFullMah = (CONFIG_ION_BAT_CHARGE * 3);

// ADC Attenuation
// 11DB = 3.55 voltage gain, reference voltage should be around 1100mv,
// so max theoretical measurement would be 3905mv, actual/recommended(?) is a lot lower.
Expand All @@ -16,14 +18,18 @@ static bool cali_enable = false;
static adc_oneshot_unit_handle_t adc1_handle = NULL;
static adc_cali_handle_t adc1_cali_handle = NULL;

// Use a fake value of 27.6v when we don't have ADC.
// Batterij en stroomwaarden
// Use a fake value of CONFIG_ION_ADC_FULL_MVv when we don't have ADC.
static uint32_t batMv = 27600;
static uint32_t batMa = 0;
static uint32_t historyMa = 0;

// We try to measure every 100ms, so 100 points gives us 10 seconds history.
static uint8_t history[100];
static size_t historyIndex = 0;
static size_t historySize = 0;
static uint32_t history;
static uint8_t batPercentage;

// Get lower/upper limit from configuration
static uint32_t emptyMv = CONFIG_ION_ADC_EMPTY_MV;
static uint32_t fullMv = CONFIG_ION_ADC_FULL_MV;
static void adc_calibration_init(adc_unit_t unit, adc_atten_t atten) {
esp_err_t ret = ESP_FAIL;

Expand Down Expand Up @@ -85,8 +91,12 @@ void adc_init() {
config.atten = ADC_ATTEN;
config.bitwidth = ADC_BITWIDTH_DEFAULT;

// Voltage channel
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, (adc_channel_t)CONFIG_ION_ADC_CHAN, &config));

// Current Channel
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, (adc_channel_t)CONFIG_ION_CURR_ADC_CHAN, &config));

adc_calibration_init(ADC_UNIT_1, ADC_ATTEN);
}

Expand All @@ -106,20 +116,30 @@ uint32_t measureBatMv() {
return (adcVoltageMv * CONFIG_ION_DIVIDER_SCALE) / 1000;
}

static uint8_t batMvToPercentage(uint32_t batMv) {
uint32_t measureCurrentMv() {
int adc_raw = 0;
ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, (adc_channel_t)CONFIG_ION_CURR_ADC_CHAN, &adc_raw));
int adcCurrentMv = 0;
if (cali_enable) {
ESP_ERROR_CHECK(adc_cali_raw_to_voltage(adc1_cali_handle, adc_raw, &adcCurrentMv));
} else {
adcCurrentMv = (adc_raw * 3550) / (1 << SOC_ADC_RTC_MAX_BITWIDTH);
}
historyMa += adcCurrentMv;
uint32_t avg = historyMa >> 5;
historyMa -= avg;

// Get lower/upper limit from configuration
uint32_t emptyMv = CONFIG_ION_ADC_EMPTY_MV;
uint32_t fullMv = CONFIG_ION_ADC_FULL_MV;
return avg;
}

static uint8_t batMvToPercentage(uint32_t batMv) {

// Calculate the percentage
uint32_t percentage = (batMv < emptyMv) ? 0 : ((batMv - emptyMv) * 100) / (fullMv - emptyMv);

// Limit to 0-100
uint8_t batterypercentage = 0;
if (percentage < 0) {
batterypercentage = 0;
} else if (percentage > 100) {
if (percentage > 100) {
batterypercentage = 100;
} else {
batterypercentage = (uint8_t)percentage;
Expand All @@ -130,29 +150,38 @@ static uint8_t batMvToPercentage(uint32_t batMv) {

void measureBat() {
batMv = measureBatMv();
history[historyIndex] = batMvToPercentage(batMv);
historyIndex = (historyIndex + 1) % sizeof(history);
if(historySize < sizeof(history)) {
historySize++;
}

// This is provided by 'mooiweertje' and is pretty much similar to Simple Exponential Smoothing (https://en.wikipedia.org/wiki/Exponential_smoothing).
// By using an alpha of 1/128, and storing the smoothed value scaled by 128 in history, this can be written very efficiently though,
// and the scaled value allows us to work with integers instead of floating point.
// It should take about 5 x 128 (640) calls to settle on a value (at 99.3%), and we try to measure every 100ms,
// which puts us a bit over 60 seconds. That's quite slow, but for a battery indicator should be ok.
history += batMv;
uint32_t avg = history >> 7;
history -= avg;

batPercentage = batMvToPercentage(avg);
}

void measureCurrent() {
batMa = measureCurrentMv();
}

uint32_t getBatMv() {
return batMv;
}

uint8_t getBatPercentage() {
if(historySize == 0) {
if(batMv == 0) {
// Use a fake value of 50% when we don't have ADC.
return 50;
}

uint32_t historyTotal = 0;
for(int index = 0; index < historySize; index++) {
historyTotal += history[index];
}
return batPercentage;
}

return historyTotal / historySize;
uint32_t getBatMa() {
return batMa;
}

void adc_teardown() {
Expand Down
10 changes: 9 additions & 1 deletion main/bat.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
#pragma once

// Initialisatie en teardown
void adc_init();
void adc_teardown();

// Voltage measurement
void measureBat();
uint32_t getBatMv();
uint8_t getBatPercentage();
void adc_teardown();

// Current Measurement
void measureCurrent();
uint32_t getBatMa();
uint32_t getBatMah();
63 changes: 63 additions & 0 deletions main/charge.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include "sdkconfig.h"
#include "storage.h"
#include "charge.h"

// note that Ah is not real Ah but a relative Ah measurement based on ADC and timer.

struct chargeStruct {

uint8_t percentage;

uint32_t mv;

uint32_t mah;
};

static chargeStruct charge;

static uint32_t chargeFullMah = (CONFIG_ION_BAT_CHARGE * 1800); // increase * 1800 to conform to the relative current measurement.

bool full = true;

uint8_t getChargePercentage() {

uint8_t percentageUsed = (uint8_t) (((float)charge.mah / (float)chargeFullMah) * 100.0f);
if(percentageUsed > 100) percentageUsed = 100;
uint8_t percentage = 100 - percentageUsed; //percentage left;

if(percentage != charge.percentage){
charge.percentage = percentage;
saveCharge();
}

return charge.percentage;
}

uint32_t getMv() {
return charge.mv;
}

uint32_t getMah() {
return charge.mah;
}

void chargeUpdate(uint32_t mv, uint32_t ma) {
charge.mv = mv;
charge.mah += ma;
}

void loadCharge() {
if(fileExists(CHARGE_FILE)) {
readData(CHARGE_FILE, &charge, sizeof(charge));
}
}

void saveCharge() {
writeData(CHARGE_FILE, &charge, sizeof(charge));
}

void resetCharge() {
charge.percentage = 100;
charge.mv = 0;
charge.mah = 0;
}
17 changes: 17 additions & 0 deletions main/charge.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include <sys/unistd.h>

uint8_t getChargePercentage();

uint32_t getMv();

uint32_t getMah();

void chargeUpdate(uint32_t mv, uint32_t mah);

void loadCharge();

void saveCharge();

void resetCharge();
8 changes: 7 additions & 1 deletion main/display.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "freertos/timers.h"
#include "states/states.h"
#include "trip.h"
#include "charge.h"
#include "relays.h"
#include "bat.h"
#include "cu2.h"
Expand Down Expand Up @@ -41,7 +42,12 @@ void stopDisplayUpdates() {
static void displayUpdate(ion_state * state) {
#if CONFIG_ION_CU2
uint16_t numTop = digits(state->speed, 3, 2);
// uint16_t numTop = digits(getChargePercentage(), 3, 2);
//uint16_t numTop = digits(getBatMv(), 3, 2);
uint32_t numBottom = digits(getTrip1() / 100, 5, 1);
// uint32_t numBottom = digits(getBatMa(), 5, 1);
// uint32_t numBottom = digits(getMah() / 1000, 5, 1);
uint8_t batPercentage = getChargePercentage();
displayUpdateCu2(false, // setDefault
(assist_level)state->level, // assistLevel
BLNK_SOLID, // assistBlink
Expand All @@ -55,7 +61,7 @@ static void displayUpdate(ion_state * state) {
BLNK_SOLID, // top
BLNK_SOLID, // bottom
false, // miles
getBatPercentage(), // batPercentage
batPercentage, // batPercentage
numTop, // topVal
numBottom); // bottomVal
#elif CONFIG_ION_CU3
Expand Down
Loading