From eedc26d90d92102e94ea3584a95d024e3f9df9b3 Mon Sep 17 00:00:00 2001 From: mooiweertje Date: Thu, 13 Mar 2025 18:21:27 +0100 Subject: [PATCH 01/15] KirianLifePo4 base --- .github/workflows/main.yml | 28 +++------------------------- sdkconfig.supermini | 18 +++++++++--------- 2 files changed, 12 insertions(+), 34 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1d0075b..5c13586 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,31 +13,9 @@ 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 - display: cu2 - custom: dvjcodec - - target: esp32 - display: cu3 - custom: dvjcodec - - target: esp32c3 - display: cu2 - custom: supermini + target: [esp32c3] + display: [cu3] + custom: [supermini] steps: - name: Checkout repo uses: actions/checkout@v3 diff --git a/sdkconfig.supermini b/sdkconfig.supermini index 7b1ba63..c2623d4 100644 --- a/sdkconfig.supermini +++ b/sdkconfig.supermini @@ -20,13 +20,13 @@ CONFIG_ION_UART=1 CONFIG_ION_RXD=20 CONFIG_ION_TXD=21 -CONFIG_ION_LIGHT=n -CONFIG_ION_LIGHT_PIN=1 -CONFIG_ION_LIGHT_PIN_INVERTED=n - CONFIG_ION_RELAY=n CONFIG_ION_RELAY_PIN=0 -CONFIG_ION_RELAY_PIN_INVERTED=n +CONFIG_ION_RELAY_PIN_INVERTED=y + +CONFIG_ION_LIGHT=n +CONFIG_ION_LIGHT_PIN=1 +CONFIG_ION_LIGHT_PIN_INVERTED=y CONFIG_ESP32C3_DEFAULT_CPU_FREQ_160=y @@ -37,8 +37,8 @@ CONFIG_ION_ADC_CHAN=4 # The scale of the divider, times 1000, from APM power module CONFIG_ION_DIVIDER_SCALE=10829 -# Consider 18V (3.0V/cell for 6s) empty -CONFIG_ION_ADC_EMPTY_MV=18000 +# Consider 22V (3.0V/cell for 8s LifePo4) empty +CONFIG_ION_ADC_EMPTY_MV=21000 -# Consider 25.2V (4.2V/cell for 6s) full -CONFIG_ION_ADC_FULL_MV=25200 +# Consider 29.2V (4.2V/cell for 8s) full +CONFIG_ION_ADC_FULL_MV=28200 From f2dfaf1ee097c4b3e854ac0ad17e04b3a4a87fe2 Mon Sep 17 00:00:00 2001 From: mooiweertje Date: Mon, 6 Oct 2025 23:18:28 +0200 Subject: [PATCH 02/15] esp_idf_version --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5c13586..f4a5de0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -35,7 +35,7 @@ jobs: - name: esp-idf build uses: espressif/esp-idf-ci-action@v1 with: - esp_idf_version: latest + esp_idf_version: v5.1 target: ${{ matrix.target }} path: '' From c5deb27ddbe89e9d8093215e24071ac6b427a338 Mon Sep 17 00:00:00 2001 From: mooiweertje Date: Tue, 14 Oct 2025 15:37:02 +0200 Subject: [PATCH 03/15] LiFe8S --- .github/workflows/main.yml | 2 +- sdkconfig.supermini | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f4a5de0..88d994e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: target: [esp32c3] - display: [cu3] + display: [cu2, cu3] custom: [supermini] steps: - name: Checkout repo diff --git a/sdkconfig.supermini b/sdkconfig.supermini index c2623d4..f82d3a3 100644 --- a/sdkconfig.supermini +++ b/sdkconfig.supermini @@ -20,13 +20,13 @@ CONFIG_ION_UART=1 CONFIG_ION_RXD=20 CONFIG_ION_TXD=21 -CONFIG_ION_RELAY=n +CONFIG_ION_RELAY=y CONFIG_ION_RELAY_PIN=0 -CONFIG_ION_RELAY_PIN_INVERTED=y +CONFIG_ION_RELAY_PIN_INVERTED=n -CONFIG_ION_LIGHT=n +CONFIG_ION_LIGHT=y CONFIG_ION_LIGHT_PIN=1 -CONFIG_ION_LIGHT_PIN_INVERTED=y +CONFIG_ION_LIGHT_PIN_INVERTED=n CONFIG_ESP32C3_DEFAULT_CPU_FREQ_160=y @@ -37,8 +37,9 @@ CONFIG_ION_ADC_CHAN=4 # The scale of the divider, times 1000, from APM power module CONFIG_ION_DIVIDER_SCALE=10829 -# Consider 22V (3.0V/cell for 8s LifePo4) empty +# Consider 20V (2.5V/cell for 8s) empty CONFIG_ION_ADC_EMPTY_MV=21000 -# Consider 29.2V (4.2V/cell for 8s) full -CONFIG_ION_ADC_FULL_MV=28200 +# Consider 28V (3.5V/cell for 8s) full +CONFIG_ION_ADC_FULL_MV=27000 + From 5aeae5266f4e1e66c26ac5ae8a96a7d8fffefe2a Mon Sep 17 00:00:00 2001 From: mooiweertje Date: Fri, 7 Nov 2025 21:55:09 +0100 Subject: [PATCH 04/15] esp_idf_version_5.5.1 --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 88d994e..6846e47 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -35,7 +35,7 @@ jobs: - name: esp-idf build uses: espressif/esp-idf-ci-action@v1 with: - esp_idf_version: v5.1 + esp_idf_version: v5.5.1 target: ${{ matrix.target }} path: '' From 06250fea4d60782dee4caa2455145ffb5073421f Mon Sep 17 00:00:00 2001 From: mooiweertje Date: Thu, 6 Nov 2025 17:25:29 +0100 Subject: [PATCH 05/15] quickMotorOff --- main/states/motor_on.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/states/motor_on.cpp b/main/states/motor_on.cpp index 0e84440..6eb88ff 100644 --- a/main/states/motor_on.cpp +++ b/main/states/motor_on.cpp @@ -35,7 +35,7 @@ void handleMotorOnState(ion_state * state, bool modeShortPress, bool lightLongPr state->step++; } - if(now -lastMoving > 10 * 1000 * 1000 ) { + if(now -lastMoving > 3 * 1000 * 1000 ) { toTurnMotorOffState(state); return; } From 7117dd5f028e5b241a033580c73a356c3edbd773 Mon Sep 17 00:00:00 2001 From: mooiweertje Date: Tue, 11 Nov 2025 15:41:07 +0100 Subject: [PATCH 06/15] ADCOptimization --- main/bat.cpp | 28 +++++++++++++--------------- sdkconfig.supermini | 2 +- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/main/bat.cpp b/main/bat.cpp index ebc61a9..e262a30 100644 --- a/main/bat.cpp +++ b/main/bat.cpp @@ -20,9 +20,11 @@ static adc_cali_handle_t adc1_cali_handle = NULL; static uint32_t batMv = 27600; // 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; + +// static size_t historyIndex = 0; +// static size_t historySize = 0; static void adc_calibration_init(adc_unit_t unit, adc_atten_t atten) { esp_err_t ret = ESP_FAIL; @@ -130,11 +132,12 @@ 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++; - } + + history += batMv; + uint32_t avg = history >> 7; + history -= avg; + + batPercentage = batMvToPercentage(avg); } uint32_t getBatMv() { @@ -142,17 +145,12 @@ uint32_t getBatMv() { } uint8_t getBatPercentage() { - if(historySize == 0) { + if(batPercentage == 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 historyTotal / historySize; + return batPercentage; } void adc_teardown() { diff --git a/sdkconfig.supermini b/sdkconfig.supermini index f82d3a3..68347ab 100644 --- a/sdkconfig.supermini +++ b/sdkconfig.supermini @@ -32,7 +32,7 @@ CONFIG_ESP32C3_DEFAULT_CPU_FREQ_160=y CONFIG_ION_ADC=y # ADC channel 1 is pin 4 -CONFIG_ION_ADC_CHAN=4 +CONFIG_ION_ADC_CHAN=2 # The scale of the divider, times 1000, from APM power module CONFIG_ION_DIVIDER_SCALE=10829 From 7107f083f0326688f2c142ebd1e65a24bd508bd0 Mon Sep 17 00:00:00 2001 From: mooiweertje Date: Sat, 15 Nov 2025 13:26:39 +0100 Subject: [PATCH 07/15] AmpADC1 --- main/Kconfig.projbuild | 13 ++++++- main/bat.cpp | 57 +++++++++++++++++++++++------- main/bat.h | 10 +++++- main/charge.cpp | 65 +++++++++++++++++++++++++++++++++++ main/charge.h | 17 +++++++++ main/display.cpp | 10 ++++-- main/main.cpp | 39 +++++++++++++-------- main/states/motor_off.cpp | 2 ++ main/states/turn_motor_on.cpp | 9 +++-- sdkconfig.supermini | 18 +++++++++- 10 files changed, 206 insertions(+), 34 deletions(-) create mode 100644 main/charge.cpp create mode 100644 main/charge.h diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 085e674..c38534c 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -87,4 +87,15 @@ menu "Sparta Ion Config" int "The actual battery voltage in mv for full (=100%). For example 42000mv for a 10s battery" default 42000 -endmenu + 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 +endmenu \ No newline at end of file diff --git a/main/bat.cpp b/main/bat.cpp index e262a30..928ddf5 100644 --- a/main/bat.cpp +++ b/main/bat.cpp @@ -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. @@ -16,13 +18,20 @@ 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 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 size_t historyIndex = 0; // static size_t historySize = 0; @@ -87,8 +96,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); } @@ -108,20 +121,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; @@ -133,11 +156,15 @@ static uint8_t batMvToPercentage(uint32_t batMv) { void measureBat() { batMv = measureBatMv(); - history += batMv; - uint32_t avg = history >> 7; - history -= avg; + history += batMv; + uint32_t avg = history >> 7; + history -= avg; - batPercentage = batMvToPercentage(avg); + batPercentage = batMvToPercentage(avg); +} + +void measureCurrent() { + batMa = measureCurrentMv(); } uint32_t getBatMv() { @@ -145,7 +172,7 @@ uint32_t getBatMv() { } uint8_t getBatPercentage() { - if(batPercentage == 0) { + if(batMv == 0) { // Use a fake value of 50% when we don't have ADC. return 50; } @@ -153,6 +180,10 @@ uint8_t getBatPercentage() { return batPercentage; } +uint32_t getBatMa() { + return batMa; +} + void adc_teardown() { // Tear Down diff --git a/main/bat.h b/main/bat.h index 3e94de6..18dafcb 100644 --- a/main/bat.h +++ b/main/bat.h @@ -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(); \ No newline at end of file diff --git a/main/charge.cpp b/main/charge.cpp new file mode 100644 index 0000000..2d44b1c --- /dev/null +++ b/main/charge.cpp @@ -0,0 +1,65 @@ +#include "sdkconfig.h" +#include "storage.h" +#include "charge.h" + +#define CHARGE_FILE "/littlefs/charge.bin" +// note that the Ah is not real Ah but a relative Ah measurement based on ADC and timer. + +struct chargeStruct { + + uint32_t mv; + + uint32_t mah; +}; + +static chargeStruct charge; + +static uint32_t chargeFullMah = (CONFIG_ION_BAT_CHARGE * 2400); // increase * 2400 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; + return 100 - percentageUsed; //percentage left +} + +uint32_t getMv() { + return charge.mv; +} + +uint32_t getMah() { + return charge.mah; +} + +void chargeUpdate(uint32_t mv, uint32_t ma) { + /* + uint32_t diff = (charge.mv > mv) ? (charge.mv - mv) : (mv - charge.mv); + if (full) { + charge.mah = chargeFullMah; + } + */ + charge.mv = mv; + charge.mah += ma; + /* + if(charge.mah > chargeFullMah) { + charge.mah = 0; + } + */ +} + +void loadCharge() { + if(fileExists(CHARGE_FILE)) { + readData(CHARGE_FILE, &charge, sizeof(charge)); + } +} + +void saveCharge() { + writeData(CHARGE_FILE, &charge, sizeof(charge)); +} + +void resetCharge() { + charge.mv = 0; + charge.mah = 0; +} diff --git a/main/charge.h b/main/charge.h new file mode 100644 index 0000000..25b48a7 --- /dev/null +++ b/main/charge.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +uint8_t getChargePercentage(); + +uint32_t getMv(); + +uint32_t getMah(); + +void chargeUpdate(uint32_t mv, uint32_t mah); + +void loadCharge(); + +void saveCharge(); + +void resetCharge(); diff --git a/main/display.cpp b/main/display.cpp index 6f61d9f..ea16ddc 100644 --- a/main/display.cpp +++ b/main/display.cpp @@ -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" @@ -41,7 +42,12 @@ void stopDisplayUpdates() { static void displayUpdate(ion_state * state) { #if CONFIG_ION_CU2 uint16_t numTop = digits(state->speed, 3, 2); - uint32_t numBottom = digits(getTrip1() / 100, 5, 1); + // 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 @@ -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 diff --git a/main/main.cpp b/main/main.cpp index d319148..f62991c 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -31,6 +31,7 @@ #include "motor.h" #include "relays.h" #include "trip.h" +#include "charge.h" #include "states/states.h" #include "storage.h" @@ -53,14 +54,14 @@ static const char *TAG = "app"; #define CHARGE_PIN ((gpio_num_t)CONFIG_ION_CHARGE_PIN) #endif -static const int BUTTON_MODE_SHORT_PRESS_BIT = BIT0; -static const int BUTTON_MODE_LONG_PRESS_BIT = BIT1; -static const int BUTTON_LIGHT_SHORT_PRESS_BIT = BIT2; -static const int BUTTON_LIGHT_LONG_PRESS_BIT = BIT3; -static const int IGNORE_HELD_BIT = BIT4; -static const int WAKEUP_BIT = BIT5; -static const int CALIBRATE_BIT = BIT6; -static const int MEASURE_BAT_BIT = BIT7; +static const int BUTTON_MODE_SHORT_PRESS_BIT = BIT0; +static const int BUTTON_MODE_LONG_PRESS_BIT = BIT1; +static const int BUTTON_LIGHT_SHORT_PRESS_BIT = BIT2; +static const int BUTTON_LIGHT_LONG_PRESS_BIT = BIT3; +static const int IGNORE_HELD_BIT = BIT4; +static const int WAKEUP_BIT = BIT5; +static const int CALIBRATE_BIT = BIT6; +static const int MEASURE_BAT_BIT = BIT7; static EventGroupHandle_t controlEventGroup; @@ -234,6 +235,7 @@ static void my_task(void *pvParameter) { initUart(); loadDistances(); + loadCharge(); #if CONFIG_ION_CU2 initCu2(controlEventGroup, @@ -285,12 +287,12 @@ static void my_task(void *pvParameter) { #endif EventBits_t buttonBits = xEventGroupWaitBits(controlEventGroup, BUTTON_MODE_SHORT_PRESS_BIT | BUTTON_MODE_LONG_PRESS_BIT | BUTTON_LIGHT_SHORT_PRESS_BIT | BUTTON_LIGHT_LONG_PRESS_BIT | WAKEUP_BIT | CALIBRATE_BIT, true, false, 0); - const bool modeShortPress = (buttonBits & BUTTON_MODE_SHORT_PRESS_BIT) != 0; - const bool modeLongPress = (buttonBits & BUTTON_MODE_LONG_PRESS_BIT) != 0; + const bool modeShortPress = (buttonBits & BUTTON_MODE_SHORT_PRESS_BIT) != 0; + const bool modeLongPress = (buttonBits & BUTTON_MODE_LONG_PRESS_BIT) != 0; const bool lightShortPress = (buttonBits & BUTTON_LIGHT_SHORT_PRESS_BIT) != 0; - const bool lightLongPress = (buttonBits & BUTTON_LIGHT_LONG_PRESS_BIT) != 0; - const bool wakeup = (buttonBits & WAKEUP_BIT) != 0; - const bool calibrate = (buttonBits & CALIBRATE_BIT) != 0; + const bool lightLongPress = (buttonBits & BUTTON_LIGHT_LONG_PRESS_BIT) != 0; + const bool wakeup = (buttonBits & WAKEUP_BIT) != 0; + const bool calibrate = (buttonBits & CALIBRATE_BIT) != 0; if(lightShortPress) { toggleLight(); @@ -299,6 +301,7 @@ static void my_task(void *pvParameter) { if(modeLongPress) { resetTrip1(0); + resetCharge(); requestDisplayUpdate(); } @@ -307,7 +310,15 @@ static void my_task(void *pvParameter) { EventBits_t bits = xEventGroupWaitBits(controlEventGroup, bitsToCheck, false, false, 0); if((bits & MEASURE_BAT_BIT) != 0) { xEventGroupClearBits(controlEventGroup, MEASURE_BAT_BIT); + + // Batterij meten measureBat(); + +#if CONFIG_ION_CURR_ADC + // Stroom meten tegelijk + measureCurrent(); + chargeUpdate(getBatMv(), getBatMa()); +#endif } else #endif if(handleDisplayUpdate(&state)) { @@ -381,4 +392,4 @@ extern "C" void app_main() { } } #endif -} +} \ No newline at end of file diff --git a/main/states/motor_off.cpp b/main/states/motor_off.cpp index 364e2e0..e429e3f 100644 --- a/main/states/motor_off.cpp +++ b/main/states/motor_off.cpp @@ -4,6 +4,7 @@ #include "esp_log.h" #include "blink.h" #include "trip.h" +#include "charge.h" #include "states.h" void toMotorOffState(ion_state * state) { @@ -11,6 +12,7 @@ void toMotorOffState(ion_state * state) { queueBlink(4, 100, 300); saveDistances(); + saveCharge(); state->state = MOTOR_OFF; state->step = 0; diff --git a/main/states/turn_motor_on.cpp b/main/states/turn_motor_on.cpp index 03e0f25..64f7056 100644 --- a/main/states/turn_motor_on.cpp +++ b/main/states/turn_motor_on.cpp @@ -11,6 +11,8 @@ #include "cu3.h" #include "motor.h" #include "states.h" +#include "trip.h" +#include "charge.h" static const char *TAG = "turn_motor_on_state"; @@ -56,7 +58,8 @@ void handleTurnMotorOnState(ion_state * state) { readResult result = exchange(cmdReq(MSG_DISPLAY, MSG_BMS, CMD_BUTTON_POLL, payload, sizeof(payload)), &message, 225 / portTICK_PERIOD_MS ); } else if(state->step == 1) { // Update display - displayUpdateCu2(false, ASS_OFF, BLNK_SOLID, BLNK_OFF, BLNK_SOLID, BLNK_OFF, BLNK_OFF, BLNK_SOLID, BLNK_OFF, BLNK_SOLID, BLNK_SOLID, BLNK_SOLID, true, 25, 0xccc, 0xccccc); + // assistLevel assistBlink wrench total trip light bars comma km top bottom miles batPercentage topVal bottomVal + displayUpdateCu2(false, ASS_OFF, BLNK_SOLID, BLNK_OFF, BLNK_OFF, BLNK_OFF, BLNK_OFF, BLNK_SOLID, BLNK_OFF, BLNK_SOLID, BLNK_SOLID, BLNK_SOLID, false, getChargePercentage(), 0xccc, 0xa0a0a); } else if(state->step == 2) { // Unknown command which is always the same and always sent to the // display at this point. @@ -69,7 +72,9 @@ void handleTurnMotorOnState(ion_state * state) { startButtonCheck(); } else if(state->step == 4) { // Set default display, which is shown if the display isn't updated for a bit (?) - displayUpdateCu2(true, ASS_OFF, BLNK_SOLID, BLNK_OFF, BLNK_SOLID, BLNK_OFF, BLNK_OFF, BLNK_SOLID, BLNK_OFF, BLNK_SOLID, BLNK_OFF, BLNK_SOLID, false, 10, 0xccc, 0xccccc); + // setDefault assistLevel assistBlink wrench total trip light bars comma km top bottom miles batPercentage topVal bottomVal + // displayUpdateCu2(f, ASS_OFF, BLNK_SOLID, BLNK_OFF, BLNK_SOLID, BLNK_OFF, BLNK_OFF, BLNK_SOLID, BLNK_OFF, BLNK_SOLID, BLNK_SOLID, BLNK_SOLID, true, 100, 0xccc, 0xccccc); + displayUpdateCu2(true, ASS_OFF, BLNK_SOLID, BLNK_OFF, BLNK_SOLID, BLNK_OFF, BLNK_OFF, BLNK_SOLID, BLNK_OFF, BLNK_SOLID, BLNK_OFF, BLNK_SOLID, false, getChargePercentage(), 0xccc, digits(getTotal(), 5, 1)); } else #else const uint8_t nextStep = 0; diff --git a/sdkconfig.supermini b/sdkconfig.supermini index 68347ab..73386d4 100644 --- a/sdkconfig.supermini +++ b/sdkconfig.supermini @@ -30,8 +30,16 @@ CONFIG_ION_LIGHT_PIN_INVERTED=n CONFIG_ESP32C3_DEFAULT_CPU_FREQ_160=y +# --- ADC measuring --- +# For ESP32-C3 +# ADC channel 0 is pin 0 +# ADC channel 1 is pin 1 +# ADC channel 2 is pin 2 +# ADC channel 3 is pin 3 +# ADC channel 4 is pin 4 CONFIG_ION_ADC=y -# ADC channel 1 is pin 4 +# --- Voltage measuring --- +# ADC channel 1 is pin 2 CONFIG_ION_ADC_CHAN=2 # The scale of the divider, times 1000, from APM power module @@ -43,3 +51,11 @@ CONFIG_ION_ADC_EMPTY_MV=21000 # Consider 28V (3.5V/cell for 8s) full CONFIG_ION_ADC_FULL_MV=27000 +# --- Current measuring --- +CONFIG_ION_CURR_ADC=y + +# ADC channel 2 is pin 1 +CONFIG_ION_CURR_ADC_CHAN=1 + +# Full battery charge in mAh. +CONFIG_ION_BAT_CHARGE=15000 From 3355c3163bdcfd7f4dc167f1ac345658d97d0cd1 Mon Sep 17 00:00:00 2001 From: mooiweertje Date: Sat, 15 Nov 2025 19:53:16 +0100 Subject: [PATCH 08/15] heartBeat --- main/main.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/main/main.cpp b/main/main.cpp index f62991c..7dc0571 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -65,6 +65,8 @@ static const int MEASURE_BAT_BIT = BIT7; static EventGroupHandle_t controlEventGroup; +volatile bool myTaskAlive = false; + enum messageHandlingResult { // We got a handoff back, so we get to send the next message CONTROL_TO_US, @@ -75,9 +77,17 @@ enum messageHandlingResult { }; static TimerHandle_t measureBatTimer; +TimerHandle_t healthCheckTimer ; static void measureBatTimerCallback(TimerHandle_t xTimer) { xEventGroupSetBits(controlEventGroup, MEASURE_BAT_BIT); } +static void checkMyTaskHealth(TimerHandle_t xTimer) { + if (!myTaskAlive) { + esp_restart(); + } + myTaskAlive = false; // Reset voor volgende check +} + static messageHandlingResult handleMotorMessage(ion_state * state) { messageType message = {}; readResult result; @@ -251,8 +261,10 @@ static void my_task(void *pvParameter) { initMotor(); measureBatTimer = xTimerCreate("measureBatTimer", (100 / portTICK_PERIOD_MS), pdTRUE, (void *)0, measureBatTimerCallback); - xTimerStart(measureBatTimer, 0); + + healthCheckTimer = xTimerCreate("healthCheckTimer", 60000 / portTICK_PERIOD_MS, pdTRUE, NULL, checkMyTaskHealth); + xTimerStart(healthCheckTimer, 0); ion_state state = { .state = IDLE, @@ -268,6 +280,8 @@ static void my_task(void *pvParameter) { while(true) { + myTaskAlive = true; // Teken van leven + // TODO: // More use of timeouts // See if we really need 8k stack (copying message structure a lot I guess) From b1ce64042a9820efe799a6d2b348c358a9348233 Mon Sep 17 00:00:00 2001 From: mooiweertje Date: Fri, 21 Nov 2025 16:39:02 +0100 Subject: [PATCH 09/15] AmpADC2 --- main/charge.cpp | 30 +++++++++++++++--------------- main/display.cpp | 4 ++-- main/main.cpp | 6 ++++-- main/states/calibrate.cpp | 6 ++++++ main/states/motor_on.cpp | 2 +- main/states/turn_motor_on.cpp | 4 ++-- sdkconfig.supermini | 2 +- 7 files changed, 31 insertions(+), 23 deletions(-) diff --git a/main/charge.cpp b/main/charge.cpp index 2d44b1c..77397f0 100644 --- a/main/charge.cpp +++ b/main/charge.cpp @@ -3,10 +3,13 @@ #include "charge.h" #define CHARGE_FILE "/littlefs/charge.bin" -// note that the Ah is not real Ah but a relative Ah measurement based on ADC and timer. + +// 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; @@ -14,15 +17,22 @@ struct chargeStruct { static chargeStruct charge; -static uint32_t chargeFullMah = (CONFIG_ION_BAT_CHARGE * 2400); // increase * 2400 to conform to the relative current measurement. +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; - return 100 - percentageUsed; //percentage left + uint8_t percentage = 100 - percentageUsed; //percentage left; + + if(percentage != charge.percentage){ + charge.percentage = percentage; + saveCharge(); + } + + return charge.percentage; } uint32_t getMv() { @@ -34,19 +44,8 @@ uint32_t getMah() { } void chargeUpdate(uint32_t mv, uint32_t ma) { - /* - uint32_t diff = (charge.mv > mv) ? (charge.mv - mv) : (mv - charge.mv); - if (full) { - charge.mah = chargeFullMah; - } - */ charge.mv = mv; charge.mah += ma; - /* - if(charge.mah > chargeFullMah) { - charge.mah = 0; - } - */ } void loadCharge() { @@ -60,6 +59,7 @@ void saveCharge() { } void resetCharge() { + charge.percentage = 100; charge.mv = 0; charge.mah = 0; } diff --git a/main/display.cpp b/main/display.cpp index ea16ddc..6192098 100644 --- a/main/display.cpp +++ b/main/display.cpp @@ -44,9 +44,9 @@ static void displayUpdate(ion_state * state) { 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(getTrip1() / 100, 5, 1); // uint32_t numBottom = digits(getBatMa(), 5, 1); - uint32_t numBottom = digits(getMah() / 1000, 5, 1); + // uint32_t numBottom = digits(getMah() / 1000, 5, 1); uint8_t batPercentage = getChargePercentage(); displayUpdateCu2(false, // setDefault (assist_level)state->level, // assistLevel diff --git a/main/main.cpp b/main/main.cpp index 7dc0571..a9816cb 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -65,7 +65,7 @@ static const int MEASURE_BAT_BIT = BIT7; static EventGroupHandle_t controlEventGroup; -volatile bool myTaskAlive = false; +volatile bool myTaskAlive = true; enum messageHandlingResult { // We got a handoff back, so we get to send the next message @@ -83,6 +83,8 @@ static void measureBatTimerCallback(TimerHandle_t xTimer) { xEventGroupSetBits(c static void checkMyTaskHealth(TimerHandle_t xTimer) { if (!myTaskAlive) { + saveDistances(); + saveCharge(); esp_restart(); } myTaskAlive = false; // Reset voor volgende check @@ -280,7 +282,7 @@ static void my_task(void *pvParameter) { while(true) { - myTaskAlive = true; // Teken van leven + myTaskAlive = true; // sign of life // TODO: // More use of timeouts diff --git a/main/states/calibrate.cpp b/main/states/calibrate.cpp index 50147c1..ed6313c 100644 --- a/main/states/calibrate.cpp +++ b/main/states/calibrate.cpp @@ -2,6 +2,8 @@ #include "freertos/event_groups.h" #include "esp_log.h" #include "blink.h" +#include "display.h" +#include "cu2.h" #include "cmds.h" #include "bow.h" #include "states.h" @@ -22,6 +24,10 @@ void handleCalibrateState(ion_state * state) { // >> cal: almost directly after cal cmd (35) // XXX handoffs later DP(CU3) pings motor, and starts to include it in handoffs // Motor does get data 2a +#if CONFIG_ION_CU2 + displayUpdateCu2(false, ASS_OFF, BLNK_SOLID, BLNK_OFF, BLNK_OFF, BLNK_OFF, BLNK_OFF, BLNK_SOLID, BLNK_OFF, BLNK_SOLID, BLNK_SOLID, BLNK_SOLID, false, 0, 0xccc, 0xa0a0a); + requestDisplayUpdate(); +#endif if(state->step == 0) { exchange(cmdReq(MSG_MOTOR, MSG_BMS, CMD_CALIBRATE)); } else if (state->step == 1) { diff --git a/main/states/motor_on.cpp b/main/states/motor_on.cpp index 6eb88ff..0e84440 100644 --- a/main/states/motor_on.cpp +++ b/main/states/motor_on.cpp @@ -35,7 +35,7 @@ void handleMotorOnState(ion_state * state, bool modeShortPress, bool lightLongPr state->step++; } - if(now -lastMoving > 3 * 1000 * 1000 ) { + if(now -lastMoving > 10 * 1000 * 1000 ) { toTurnMotorOffState(state); return; } diff --git a/main/states/turn_motor_on.cpp b/main/states/turn_motor_on.cpp index 64f7056..b943df1 100644 --- a/main/states/turn_motor_on.cpp +++ b/main/states/turn_motor_on.cpp @@ -59,7 +59,7 @@ void handleTurnMotorOnState(ion_state * state) { } else if(state->step == 1) { // Update display // assistLevel assistBlink wrench total trip light bars comma km top bottom miles batPercentage topVal bottomVal - displayUpdateCu2(false, ASS_OFF, BLNK_SOLID, BLNK_OFF, BLNK_OFF, BLNK_OFF, BLNK_OFF, BLNK_SOLID, BLNK_OFF, BLNK_SOLID, BLNK_SOLID, BLNK_SOLID, false, getChargePercentage(), 0xccc, 0xa0a0a); + displayUpdateCu2(false, ASS_OFF, BLNK_SOLID, BLNK_OFF, BLNK_OFF, BLNK_OFF, BLNK_OFF, BLNK_SOLID, BLNK_OFF, BLNK_SOLID, BLNK_SOLID, BLNK_SOLID, false, getChargePercentage(), 0xccc, digits(getTotal() / 100, 5, 1)); } else if(state->step == 2) { // Unknown command which is always the same and always sent to the // display at this point. @@ -74,7 +74,7 @@ void handleTurnMotorOnState(ion_state * state) { // Set default display, which is shown if the display isn't updated for a bit (?) // setDefault assistLevel assistBlink wrench total trip light bars comma km top bottom miles batPercentage topVal bottomVal // displayUpdateCu2(f, ASS_OFF, BLNK_SOLID, BLNK_OFF, BLNK_SOLID, BLNK_OFF, BLNK_OFF, BLNK_SOLID, BLNK_OFF, BLNK_SOLID, BLNK_SOLID, BLNK_SOLID, true, 100, 0xccc, 0xccccc); - displayUpdateCu2(true, ASS_OFF, BLNK_SOLID, BLNK_OFF, BLNK_SOLID, BLNK_OFF, BLNK_OFF, BLNK_SOLID, BLNK_OFF, BLNK_SOLID, BLNK_OFF, BLNK_SOLID, false, getChargePercentage(), 0xccc, digits(getTotal(), 5, 1)); + displayUpdateCu2(true, ASS_OFF, BLNK_SOLID, BLNK_OFF, BLNK_SOLID, BLNK_OFF, BLNK_OFF, BLNK_SOLID, BLNK_OFF, BLNK_SOLID, BLNK_OFF, BLNK_SOLID, false, getChargePercentage(), 0xccc, digits(getTotal() / 100, 5, 1)); } else #else const uint8_t nextStep = 0; diff --git a/sdkconfig.supermini b/sdkconfig.supermini index 73386d4..2b71a8f 100644 --- a/sdkconfig.supermini +++ b/sdkconfig.supermini @@ -58,4 +58,4 @@ CONFIG_ION_CURR_ADC=y CONFIG_ION_CURR_ADC_CHAN=1 # Full battery charge in mAh. -CONFIG_ION_BAT_CHARGE=15000 +CONFIG_ION_BAT_CHARGE=20000 From c7b2d8ca0c245e45d7b0c1da4b1b14ea0b29d831 Mon Sep 17 00:00:00 2001 From: mooiweertje Date: Fri, 21 Nov 2025 16:50:21 +0100 Subject: [PATCH 10/15] AmpADC2 --- main/states/calibrate.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/main/states/calibrate.cpp b/main/states/calibrate.cpp index ed6313c..56858c6 100644 --- a/main/states/calibrate.cpp +++ b/main/states/calibrate.cpp @@ -27,6 +27,7 @@ void handleCalibrateState(ion_state * state) { #if CONFIG_ION_CU2 displayUpdateCu2(false, ASS_OFF, BLNK_SOLID, BLNK_OFF, BLNK_OFF, BLNK_OFF, BLNK_OFF, BLNK_SOLID, BLNK_OFF, BLNK_SOLID, BLNK_SOLID, BLNK_SOLID, false, 0, 0xccc, 0xa0a0a); requestDisplayUpdate(); + vTaskDelay(pdMS_TO_TICKS(1000)); #endif if(state->step == 0) { exchange(cmdReq(MSG_MOTOR, MSG_BMS, CMD_CALIBRATE)); From 79452553e43e6f278679dd75f457052e2fc313e2 Mon Sep 17 00:00:00 2001 From: mooiweertje Date: Sat, 15 Nov 2025 20:23:16 +0100 Subject: [PATCH 11/15] heartBeat --- main/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main/main.cpp b/main/main.cpp index a9816cb..9956db3 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -83,7 +83,7 @@ static void measureBatTimerCallback(TimerHandle_t xTimer) { xEventGroupSetBits(c static void checkMyTaskHealth(TimerHandle_t xTimer) { if (!myTaskAlive) { - saveDistances(); + saveDistances(); saveCharge(); esp_restart(); } @@ -265,8 +265,8 @@ static void my_task(void *pvParameter) { measureBatTimer = xTimerCreate("measureBatTimer", (100 / portTICK_PERIOD_MS), pdTRUE, (void *)0, measureBatTimerCallback); xTimerStart(measureBatTimer, 0); - healthCheckTimer = xTimerCreate("healthCheckTimer", 60000 / portTICK_PERIOD_MS, pdTRUE, NULL, checkMyTaskHealth); - xTimerStart(healthCheckTimer, 0); + healthCheckTimer = xTimerCreate("healthCheckTimer", 60000 / portTICK_PERIOD_MS, pdTRUE, NULL, checkMyTaskHealth); + xTimerStart(healthCheckTimer, 0); ion_state state = { .state = IDLE, From b42612185ecfef65b8c4f114f4aaa8351fde7bcf Mon Sep 17 00:00:00 2001 From: void-spark <81029971+void-spark@users.noreply.github.com> Date: Sun, 16 Nov 2025 16:46:55 +0100 Subject: [PATCH 12/15] Add a bit of comments on the new adc code --- main/bat.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/main/bat.cpp b/main/bat.cpp index 928ddf5..87ab8b0 100644 --- a/main/bat.cpp +++ b/main/bat.cpp @@ -24,17 +24,12 @@ 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 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 size_t historyIndex = 0; -// static size_t historySize = 0; - static void adc_calibration_init(adc_unit_t unit, adc_atten_t atten) { esp_err_t ret = ESP_FAIL; @@ -156,9 +151,20 @@ static uint8_t batMvToPercentage(uint32_t batMv) { void measureBat() { batMv = measureBatMv(); +<<<<<<< HEAD history += batMv; uint32_t avg = history >> 7; history -= avg; +======= + // 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; +>>>>>>> 9e922f8 (Add a bit of comments on the new adc code) batPercentage = batMvToPercentage(avg); } From ecd2030904395d41b63eab9566a77a50618fe238 Mon Sep 17 00:00:00 2001 From: mooiweertje Date: Wed, 17 Dec 2025 18:26:29 +0100 Subject: [PATCH 13/15] heartBeat --- main/Kconfig.projbuild | 8 +++++++- main/main.cpp | 13 ++++++++++--- sdkconfig.supermini | 4 ++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index c38534c..c8b7b0a 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -98,4 +98,10 @@ menu "Sparta Ion Config" config ION_BAT_CHARGE int "Full battery charge in mAh." default 10000 -endmenu \ No newline at end of file + + 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 + diff --git a/main/main.cpp b/main/main.cpp index 9956db3..3fb7354 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -65,8 +65,6 @@ static const int MEASURE_BAT_BIT = BIT7; static EventGroupHandle_t controlEventGroup; -volatile bool myTaskAlive = true; - enum messageHandlingResult { // We got a handoff back, so we get to send the next message CONTROL_TO_US, @@ -77,10 +75,13 @@ enum messageHandlingResult { }; static TimerHandle_t measureBatTimer; -TimerHandle_t healthCheckTimer ; static void measureBatTimerCallback(TimerHandle_t xTimer) { xEventGroupSetBits(controlEventGroup, MEASURE_BAT_BIT); } +#if CONFIG_ION_KEEPALIVE +volatile bool myTaskAlive = false; +TimerHandle_t healthCheckTimer ; + static void checkMyTaskHealth(TimerHandle_t xTimer) { if (!myTaskAlive) { saveDistances(); @@ -89,6 +90,8 @@ static void checkMyTaskHealth(TimerHandle_t xTimer) { } myTaskAlive = false; // Reset voor volgende check } +#endif + static messageHandlingResult handleMotorMessage(ion_state * state) { messageType message = {}; @@ -265,8 +268,10 @@ static void my_task(void *pvParameter) { measureBatTimer = xTimerCreate("measureBatTimer", (100 / portTICK_PERIOD_MS), pdTRUE, (void *)0, measureBatTimerCallback); xTimerStart(measureBatTimer, 0); +#if CONFIG_ION_KEEPALIVE healthCheckTimer = xTimerCreate("healthCheckTimer", 60000 / portTICK_PERIOD_MS, pdTRUE, NULL, checkMyTaskHealth); xTimerStart(healthCheckTimer, 0); +#endif ion_state state = { .state = IDLE, @@ -282,7 +287,9 @@ static void my_task(void *pvParameter) { while(true) { +#if CONFIG_ION_KEEPALIVE myTaskAlive = true; // sign of life +#endif // TODO: // More use of timeouts diff --git a/sdkconfig.supermini b/sdkconfig.supermini index 2b71a8f..2a6ad0a 100644 --- a/sdkconfig.supermini +++ b/sdkconfig.supermini @@ -59,3 +59,7 @@ CONFIG_ION_CURR_ADC_CHAN=1 # Full battery charge in mAh. CONFIG_ION_BAT_CHARGE=20000 + +# keepalive +CONFIG_ION_KEEPALIVE=y + From dd0bbd17278917c3964c2d29283e60bf6a065739 Mon Sep 17 00:00:00 2001 From: mooiweertje Date: Thu, 18 Dec 2025 10:57:18 +0100 Subject: [PATCH 14/15] Tesla config split --- .github/workflows/main.yml | 13 +++-- sdkconfig.Tesla | 65 +++++++++++++++++++++++++ sdkconfig.supermini => sdkconfig.TeslaS | 4 ++ sdkconfig.TeslaTour | 65 +++++++++++++++++++++++++ 4 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 sdkconfig.Tesla rename sdkconfig.supermini => sdkconfig.TeslaS (92%) create mode 100644 sdkconfig.TeslaTour diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6846e47..49d36ee 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,9 +13,16 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - target: [esp32c3] - display: [cu2, cu3] - custom: [supermini] + include: + - target: esp32c3 + display: cu2 + custom: Tesla + - target: esp32c3 + display: cu2 + custom: TeslaS + - target: esp32c3 + display: cu3 + custom: TeslaTour steps: - name: Checkout repo uses: actions/checkout@v3 diff --git a/sdkconfig.Tesla b/sdkconfig.Tesla new file mode 100644 index 0000000..bc720d6 --- /dev/null +++ b/sdkconfig.Tesla @@ -0,0 +1,65 @@ +# Configuration for use with ESP32 C3 supermini and APM power module +# https://nl.aliexpress.com/item/1005006170575141.html +# https://nl.aliexpress.com/item/1005005831224524.html + +# Pins: +# 1(06) - GND - GND +# 2(04) - GP4 - IO4 > Optional ADC use for battery level, voltage +# 3(06) - GP5 - IO5 > Optional ADC use for battery level, current +# 4(00) - GP0 - IO0 > Motor on/off (active low) +# 5(01) - GP1 - IO1 > Light on/off (active high) + jumper for debug +# 6(20) - RXD - RX > Bus send +# 7(21) - TXD - TX > Bus receive +# 8(07) - VCC - 5V + + +CONFIG_ION_BUTTON=n +CONFIG_ION_LED_PIN=8 + +CONFIG_ION_UART=1 +CONFIG_ION_RXD=20 +CONFIG_ION_TXD=21 + +CONFIG_ION_LIGHT=y +CONFIG_ION_LIGHT_PIN=3 +CONFIG_ION_LIGHT_PIN_INVERTED=n + +CONFIG_ION_RELAY=y +CONFIG_ION_RELAY_PIN=0 +CONFIG_ION_RELAY_PIN_INVERTED=n + +CONFIG_ESP32C3_DEFAULT_CPU_FREQ_160=y + +# --- ADC measuring --- +# For ESP32-C3 +# ADC channel 0 is pin 0 +# ADC channel 1 is pin 1 +# ADC channel 2 is pin 2 +# ADC channel 3 is pin 3 +# ADC channel 4 is pin 4 +CONFIG_ION_ADC=y + +# --- Voltage measuring --- +# ADC channel 1 is pin 2 +CONFIG_ION_ADC_CHAN=2 + +# The scale of the divider, times 1000, from APM power module +CONFIG_ION_DIVIDER_SCALE=10829 + +# Consider 22V (2.5V/cell for 8s LiFePo4) empty +CONFIG_ION_ADC_EMPTY_MV=21000 + +# Consider 27V (3.5V/cell for 8s LiFePo4) full +CONFIG_ION_ADC_FULL_MV=27000 + +# --- Current measuring --- +CONFIG_ION_CURR_ADC=y + +# ADC channel 2 is pin 1 +CONFIG_ION_CURR_ADC_CHAN=1 + +# Full battery charge in mAh. +CONFIG_ION_BAT_CHARGE=15000 + +# keepalive +CONFIG_ION_KEEPALIVE=y diff --git a/sdkconfig.supermini b/sdkconfig.TeslaS similarity index 92% rename from sdkconfig.supermini rename to sdkconfig.TeslaS index 2a6ad0a..b2a1af5 100644 --- a/sdkconfig.supermini +++ b/sdkconfig.TeslaS @@ -61,5 +61,9 @@ CONFIG_ION_CURR_ADC_CHAN=1 CONFIG_ION_BAT_CHARGE=20000 # keepalive +<<<<<<< HEAD:sdkconfig.supermini CONFIG_ION_KEEPALIVE=y +======= +CONFIG_ION_KEEPALIVE=n +>>>>>>> 8796a39 (Tesla config split):sdkconfig.TeslaS diff --git a/sdkconfig.TeslaTour b/sdkconfig.TeslaTour new file mode 100644 index 0000000..bc720d6 --- /dev/null +++ b/sdkconfig.TeslaTour @@ -0,0 +1,65 @@ +# Configuration for use with ESP32 C3 supermini and APM power module +# https://nl.aliexpress.com/item/1005006170575141.html +# https://nl.aliexpress.com/item/1005005831224524.html + +# Pins: +# 1(06) - GND - GND +# 2(04) - GP4 - IO4 > Optional ADC use for battery level, voltage +# 3(06) - GP5 - IO5 > Optional ADC use for battery level, current +# 4(00) - GP0 - IO0 > Motor on/off (active low) +# 5(01) - GP1 - IO1 > Light on/off (active high) + jumper for debug +# 6(20) - RXD - RX > Bus send +# 7(21) - TXD - TX > Bus receive +# 8(07) - VCC - 5V + + +CONFIG_ION_BUTTON=n +CONFIG_ION_LED_PIN=8 + +CONFIG_ION_UART=1 +CONFIG_ION_RXD=20 +CONFIG_ION_TXD=21 + +CONFIG_ION_LIGHT=y +CONFIG_ION_LIGHT_PIN=3 +CONFIG_ION_LIGHT_PIN_INVERTED=n + +CONFIG_ION_RELAY=y +CONFIG_ION_RELAY_PIN=0 +CONFIG_ION_RELAY_PIN_INVERTED=n + +CONFIG_ESP32C3_DEFAULT_CPU_FREQ_160=y + +# --- ADC measuring --- +# For ESP32-C3 +# ADC channel 0 is pin 0 +# ADC channel 1 is pin 1 +# ADC channel 2 is pin 2 +# ADC channel 3 is pin 3 +# ADC channel 4 is pin 4 +CONFIG_ION_ADC=y + +# --- Voltage measuring --- +# ADC channel 1 is pin 2 +CONFIG_ION_ADC_CHAN=2 + +# The scale of the divider, times 1000, from APM power module +CONFIG_ION_DIVIDER_SCALE=10829 + +# Consider 22V (2.5V/cell for 8s LiFePo4) empty +CONFIG_ION_ADC_EMPTY_MV=21000 + +# Consider 27V (3.5V/cell for 8s LiFePo4) full +CONFIG_ION_ADC_FULL_MV=27000 + +# --- Current measuring --- +CONFIG_ION_CURR_ADC=y + +# ADC channel 2 is pin 1 +CONFIG_ION_CURR_ADC_CHAN=1 + +# Full battery charge in mAh. +CONFIG_ION_BAT_CHARGE=15000 + +# keepalive +CONFIG_ION_KEEPALIVE=y From 429bd680c1d0913f7f7a3cc91fcbef2f8ed37054 Mon Sep 17 00:00:00 2001 From: mooiweertje Date: Mon, 22 Dec 2025 16:53:13 +0100 Subject: [PATCH 15/15] backToSpiffsMergeFixes --- .github/workflows/main.yml | 4 ++-- main/Kconfig.projbuild | 1 - main/bat.cpp | 6 ------ main/charge.cpp | 2 -- main/main.cpp | 2 +- main/storage.cpp | 4 +--- main/storage.h | 8 +++++++- main/trip.cpp | 2 -- sdkconfig.Tesla | 14 +++++++------- sdkconfig.TeslaS | 16 ++++++---------- sdkconfig.TeslaTour | 14 +++++++------- sdkconfig.defaults | 2 +- sdkconfig.defaults.esp32c3 | 1 - 13 files changed, 32 insertions(+), 44 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 49d36ee..202df80 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -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: diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index c8b7b0a..1344c98 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -104,4 +104,3 @@ menu "Sparta Ion Config" default n endmenu - diff --git a/main/bat.cpp b/main/bat.cpp index 87ab8b0..cd9c50a 100644 --- a/main/bat.cpp +++ b/main/bat.cpp @@ -151,11 +151,6 @@ static uint8_t batMvToPercentage(uint32_t batMv) { void measureBat() { batMv = measureBatMv(); -<<<<<<< HEAD - history += batMv; - uint32_t avg = history >> 7; - history -= avg; -======= // 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. @@ -164,7 +159,6 @@ void measureBat() { history += batMv; uint32_t avg = history >> 7; history -= avg; ->>>>>>> 9e922f8 (Add a bit of comments on the new adc code) batPercentage = batMvToPercentage(avg); } diff --git a/main/charge.cpp b/main/charge.cpp index 77397f0..fac7ae0 100644 --- a/main/charge.cpp +++ b/main/charge.cpp @@ -2,8 +2,6 @@ #include "storage.h" #include "charge.h" -#define CHARGE_FILE "/littlefs/charge.bin" - // note that Ah is not real Ah but a relative Ah measurement based on ADC and timer. struct chargeStruct { diff --git a/main/main.cpp b/main/main.cpp index 3fb7354..0412dfc 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -245,7 +245,7 @@ static void my_task(void *pvParameter) { adc_init(); #endif - init_spiffs(); + init_fs(); initUart(); diff --git a/main/storage.cpp b/main/storage.cpp index 8c9570d..710422e 100644 --- a/main/storage.cpp +++ b/main/storage.cpp @@ -5,9 +5,7 @@ static const char *TAG = "storage"; -#define CALIBRATION_FILE "/spiffs/calibration.bin" - -void init_spiffs() { +void init_fs() { ESP_LOGI(TAG, "Initializing SPIFFS"); esp_vfs_spiffs_conf_t spiffs_conf = {}; diff --git a/main/storage.h b/main/storage.h index 65c3a42..c8223a5 100644 --- a/main/storage.h +++ b/main/storage.h @@ -2,7 +2,13 @@ #include -void init_spiffs(); +#define CALIBRATION_FILE "/spiffs/calibration.bin" + +#define DISTANCE_FILE "/spiffs/distance.bin" + +#define CHARGE_FILE "/spiffs/charge.bin" + +void init_fs(); // Is a calibration file stored? bool calibrationFileExists(); diff --git a/main/trip.cpp b/main/trip.cpp index 2e555dd..23a2e91 100644 --- a/main/trip.cpp +++ b/main/trip.cpp @@ -1,8 +1,6 @@ #include "storage.h" #include "trip.h" -#define DISTANCE_FILE "/spiffs/distance.bin" - struct distancesStruct { // Trip-1 in 10m increments uint32_t trip1; diff --git a/sdkconfig.Tesla b/sdkconfig.Tesla index bc720d6..c6ffe83 100644 --- a/sdkconfig.Tesla +++ b/sdkconfig.Tesla @@ -20,14 +20,14 @@ CONFIG_ION_UART=1 CONFIG_ION_RXD=20 CONFIG_ION_TXD=21 -CONFIG_ION_LIGHT=y -CONFIG_ION_LIGHT_PIN=3 -CONFIG_ION_LIGHT_PIN_INVERTED=n - CONFIG_ION_RELAY=y CONFIG_ION_RELAY_PIN=0 CONFIG_ION_RELAY_PIN_INVERTED=n +CONFIG_ION_LIGHT=y +CONFIG_ION_LIGHT_PIN=3 +CONFIG_ION_LIGHT_PIN_INVERTED=n + CONFIG_ESP32C3_DEFAULT_CPU_FREQ_160=y # --- ADC measuring --- @@ -46,10 +46,10 @@ CONFIG_ION_ADC_CHAN=2 # The scale of the divider, times 1000, from APM power module CONFIG_ION_DIVIDER_SCALE=10829 -# Consider 22V (2.5V/cell for 8s LiFePo4) empty -CONFIG_ION_ADC_EMPTY_MV=21000 +# Consider 23V (2,875V/cell for 8s LiFePo4) empty +CONFIG_ION_ADC_EMPTY_MV=23000 -# Consider 27V (3.5V/cell for 8s LiFePo4) full +# Consider 27V (3,375V/cell for 8s LiFePo4) full CONFIG_ION_ADC_FULL_MV=27000 # --- Current measuring --- diff --git a/sdkconfig.TeslaS b/sdkconfig.TeslaS index b2a1af5..a0369f3 100644 --- a/sdkconfig.TeslaS +++ b/sdkconfig.TeslaS @@ -25,7 +25,7 @@ CONFIG_ION_RELAY_PIN=0 CONFIG_ION_RELAY_PIN_INVERTED=n CONFIG_ION_LIGHT=y -CONFIG_ION_LIGHT_PIN=1 +CONFIG_ION_LIGHT_PIN=3 CONFIG_ION_LIGHT_PIN_INVERTED=n CONFIG_ESP32C3_DEFAULT_CPU_FREQ_160=y @@ -37,6 +37,7 @@ CONFIG_ESP32C3_DEFAULT_CPU_FREQ_160=y # ADC channel 2 is pin 2 # ADC channel 3 is pin 3 # ADC channel 4 is pin 4 + CONFIG_ION_ADC=y # --- Voltage measuring --- # ADC channel 1 is pin 2 @@ -45,10 +46,10 @@ CONFIG_ION_ADC_CHAN=2 # The scale of the divider, times 1000, from APM power module CONFIG_ION_DIVIDER_SCALE=10829 -# Consider 20V (2.5V/cell for 8s) empty -CONFIG_ION_ADC_EMPTY_MV=21000 +# Consider 23V (2,875V/cell for 8s LiFePo4) empty +CONFIG_ION_ADC_EMPTY_MV=23000 -# Consider 28V (3.5V/cell for 8s) full +# Consider 27V (3,375V/cell for 8s LiFePo4) full CONFIG_ION_ADC_FULL_MV=27000 # --- Current measuring --- @@ -61,9 +62,4 @@ CONFIG_ION_CURR_ADC_CHAN=1 CONFIG_ION_BAT_CHARGE=20000 # keepalive -<<<<<<< HEAD:sdkconfig.supermini -CONFIG_ION_KEEPALIVE=y - -======= -CONFIG_ION_KEEPALIVE=n ->>>>>>> 8796a39 (Tesla config split):sdkconfig.TeslaS +CONFIG_ION_KEEPALIVE=y \ No newline at end of file diff --git a/sdkconfig.TeslaTour b/sdkconfig.TeslaTour index bc720d6..c6ffe83 100644 --- a/sdkconfig.TeslaTour +++ b/sdkconfig.TeslaTour @@ -20,14 +20,14 @@ CONFIG_ION_UART=1 CONFIG_ION_RXD=20 CONFIG_ION_TXD=21 -CONFIG_ION_LIGHT=y -CONFIG_ION_LIGHT_PIN=3 -CONFIG_ION_LIGHT_PIN_INVERTED=n - CONFIG_ION_RELAY=y CONFIG_ION_RELAY_PIN=0 CONFIG_ION_RELAY_PIN_INVERTED=n +CONFIG_ION_LIGHT=y +CONFIG_ION_LIGHT_PIN=3 +CONFIG_ION_LIGHT_PIN_INVERTED=n + CONFIG_ESP32C3_DEFAULT_CPU_FREQ_160=y # --- ADC measuring --- @@ -46,10 +46,10 @@ CONFIG_ION_ADC_CHAN=2 # The scale of the divider, times 1000, from APM power module CONFIG_ION_DIVIDER_SCALE=10829 -# Consider 22V (2.5V/cell for 8s LiFePo4) empty -CONFIG_ION_ADC_EMPTY_MV=21000 +# Consider 23V (2,875V/cell for 8s LiFePo4) empty +CONFIG_ION_ADC_EMPTY_MV=23000 -# Consider 27V (3.5V/cell for 8s LiFePo4) full +# Consider 27V (3,375V/cell for 8s LiFePo4) full CONFIG_ION_ADC_FULL_MV=27000 # --- Current measuring --- diff --git a/sdkconfig.defaults b/sdkconfig.defaults index 6d5b1e8..9a07c8f 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -4,7 +4,7 @@ CONFIG_ION_CU3=y # My chips are 4MB flash, once you use OTA this settings matters CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y -# Set up partitions for SPIFFS +# Set up partitions CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" diff --git a/sdkconfig.defaults.esp32c3 b/sdkconfig.defaults.esp32c3 index 1a90b98..e5bd942 100644 --- a/sdkconfig.defaults.esp32c3 +++ b/sdkconfig.defaults.esp32c3 @@ -11,7 +11,6 @@ # 7(--) - RST - RST # 8(--) - VCC - 3.3V - CONFIG_ION_BUTTON=n CONFIG_ION_LED_PIN=3 CONFIG_ION_UART=1