From 4481a22f6b5feb223ffff8073bcfbe7d57287a39 Mon Sep 17 00:00:00 2001 From: pulipakaa24 Date: Sun, 22 Feb 2026 23:00:10 -0600 Subject: [PATCH] groundwork for BMS --- include/batteryManagement.hpp | 0 include/i2c.h | 26 +++++++++++ include/max17048.h | 38 +++++++++++++++ sdkconfig.seeed_xiao_esp32c6 | 8 ---- {include => src}/BLE.cpp | 1 - src/CMakeLists.txt | 2 +- {include => src}/WiFi.cpp | 0 src/batteryManagement.cpp | 10 ++++ {include => src}/bmHTTP.cpp | 0 {include => src}/calibration.cpp | 0 {include => src}/encoder.cpp | 0 src/i2c.c | 75 ++++++++++++++++++++++++++++++ {include => src}/mainEventLoop.cpp | 0 src/max17048.c | 44 ++++++++++++++++++ {include => src}/servo.cpp | 0 {include => src}/setup.cpp | 0 {include => src}/socketIO.cpp | 0 17 files changed, 194 insertions(+), 10 deletions(-) create mode 100644 include/batteryManagement.hpp create mode 100644 include/i2c.h create mode 100644 include/max17048.h rename {include => src}/BLE.cpp (99%) rename {include => src}/WiFi.cpp (100%) create mode 100644 src/batteryManagement.cpp rename {include => src}/bmHTTP.cpp (100%) rename {include => src}/calibration.cpp (100%) rename {include => src}/encoder.cpp (100%) create mode 100644 src/i2c.c rename {include => src}/mainEventLoop.cpp (100%) create mode 100644 src/max17048.c rename {include => src}/servo.cpp (100%) rename {include => src}/setup.cpp (100%) rename {include => src}/socketIO.cpp (100%) diff --git a/include/batteryManagement.hpp b/include/batteryManagement.hpp new file mode 100644 index 0000000..e69de29 diff --git a/include/i2c.h b/include/i2c.h new file mode 100644 index 0000000..274b7e3 --- /dev/null +++ b/include/i2c.h @@ -0,0 +1,26 @@ +#ifndef I2C_HELPER_H +#define I2C_HELPER_H +#include "driver/gpio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// I2C Configuration (Match your schematic) +#define I2C_MASTER_SCL_IO GPIO_NUM_23 // Example GPIO for C6 +#define I2C_MASTER_SDA_IO GPIO_NUM_22 // Example GPIO for C6 +#define I2C_MASTER_NUM 0 +#define I2C_MASTER_FREQ_HZ 100000 // use standard freq +#define I2C_MASTER_TIMEOUT_MS 1000 + +esp_err_t i2c_init(); +esp_err_t max17048_read_reg(uint8_t reg_addr, uint8_t *MSB, uint8_t *LSB); +esp_err_t max17048_write_reg(uint8_t reg_addr, uint8_t MSB, uint8_t LSB); +esp_err_t max17048_friendly_write_reg(uint8_t reg_addr, uint8_t MSB, uint8_t LSB, + uint8_t MSBmask, uint8_t LSBmask); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/include/max17048.h b/include/max17048.h new file mode 100644 index 0000000..763d4c9 --- /dev/null +++ b/include/max17048.h @@ -0,0 +1,38 @@ +#ifndef MAX_17_H +#define MAX_17_H + +#define MAX17048_ADDR 0x36 +#define MAX17048_REG_VCELL 0x02 // Voltage +#define MAX17048_REG_SOC 0x04 // State of Charge (%) +#define MAX17048_REG_MODE 0x06 +#define MAX17048_REG_VERSION 0x08 +#define MAX17048_REG_CONFIG 0x0C +#define MAX17048_REG_CMD 0xFE // Command (Reset) +#define MAX17048_REG_STATUS 0x1A +#define MAX17048_REG_VALRT 0x14 +#define MAX17048_REG_VRST_ID 0x18 + +// Commands +#define MAX17048_CMD_POR 0x5400 // Power On Reset command +#define MAX17048_CMD_QSTRT 0x4000 // Quick Start command + + +#ifdef __cplusplus +extern "C" { +#endif +#include "driver/i2c.h" + +esp_err_t max17048_init(); +uint8_t bms_get_soc(); +esp_err_t bms_set_alert_bound_voltages(float min, float max); +esp_err_t bms_set_reset_voltage(float vreset); +esp_err_t bms_clear_status(); + +#define bms_set_alsc() max17048_friendly_write_reg(MAX17048_REG_CONFIG, 0, 1<<6, 0, 1<<6) +#define bms_clear_status() max17048_write_reg(MAX17048_REG_STATUS, 0, 0) + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/sdkconfig.seeed_xiao_esp32c6 b/sdkconfig.seeed_xiao_esp32c6 index dbe3ede..f5eebb8 100644 --- a/sdkconfig.seeed_xiao_esp32c6 +++ b/sdkconfig.seeed_xiao_esp32c6 @@ -132,7 +132,6 @@ CONFIG_SOC_GPIO_DEEP_SLEEP_WAKE_VALID_GPIO_MASK=0 CONFIG_SOC_GPIO_DEEP_SLEEP_WAKE_SUPPORTED_PIN_CNT=8 CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0x000000007FFFFF00 CONFIG_SOC_GPIO_SUPPORT_FORCE_HOLD=y -CONFIG_SOC_GPIO_SUPPORT_HOLD_IO_IN_DSLP=y CONFIG_SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP=y CONFIG_SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX=y CONFIG_SOC_CLOCKOUT_HAS_SOURCE_GATE=y @@ -2357,13 +2356,6 @@ CONFIG_LIBC_TIME_SYSCALL_USE_RTC_HRT=y # # CONFIG_OPENTHREAD_ENABLED is not set -# -# Thread Console -# -CONFIG_OPENTHREAD_CLI=y -CONFIG_OPENTHREAD_CONSOLE_COMMAND_PREFIX="ot" -# end of Thread Console - # # OpenThread Spinel # diff --git a/include/BLE.cpp b/src/BLE.cpp similarity index 99% rename from include/BLE.cpp rename to src/BLE.cpp index 5a2908f..d42ac98 100644 --- a/include/BLE.cpp +++ b/src/BLE.cpp @@ -2,7 +2,6 @@ #include "freertos/queue.h" #include "freertos/task.h" #include "BLE.hpp" -#include "NimBLEDevice.h" #include "WiFi.hpp" #include "nvs_flash.h" #include "socketIO.hpp" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0848ada..e3e1ef0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ # This file was automatically generated for projects # without default 'CMakeLists.txt' file. -FILE(GLOB_RECURSE app_sources ${CMAKE_SOURCE_DIR}/src/*.* ${CMAKE_SOURCE_DIR}/include/*.cpp) +FILE(GLOB_RECURSE app_sources ${CMAKE_SOURCE_DIR}/src/*.*) idf_component_register(SRCS ${app_sources} INCLUDE_DIRS "." diff --git a/include/WiFi.cpp b/src/WiFi.cpp similarity index 100% rename from include/WiFi.cpp rename to src/WiFi.cpp diff --git a/src/batteryManagement.cpp b/src/batteryManagement.cpp new file mode 100644 index 0000000..0596538 --- /dev/null +++ b/src/batteryManagement.cpp @@ -0,0 +1,10 @@ + + // 3. Post Event to System Loop + battery_data_t data = { .soc = soc, .voltage = voltage }; + + esp_event_post(BATTERY_EVENTS, BATTERY_EVENT_UPDATE, &data, sizeof(data), 0); + + // Optional: Post warnings + if (soc < 20.0) { + esp_event_post(BATTERY_EVENTS, BATTERY_EVENT_LOW, NULL, 0, 0); + } \ No newline at end of file diff --git a/include/bmHTTP.cpp b/src/bmHTTP.cpp similarity index 100% rename from include/bmHTTP.cpp rename to src/bmHTTP.cpp diff --git a/include/calibration.cpp b/src/calibration.cpp similarity index 100% rename from include/calibration.cpp rename to src/calibration.cpp diff --git a/include/encoder.cpp b/src/encoder.cpp similarity index 100% rename from include/encoder.cpp rename to src/encoder.cpp diff --git a/src/i2c.c b/src/i2c.c new file mode 100644 index 0000000..00bcad6 --- /dev/null +++ b/src/i2c.c @@ -0,0 +1,75 @@ +#include "i2c.h" +#include "driver/i2c.h" +#include "esp_log.h" +#include "max17048.h" + +// Helper: Initializes I2C controller at 100kHz, returns 0=success +esp_err_t i2c_init() { + // 1. Initialize I2C + i2c_config_t conf = { + .mode = I2C_MODE_MASTER, + .sda_io_num = I2C_MASTER_SDA_IO, + .scl_io_num = I2C_MASTER_SCL_IO, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master.clk_speed = I2C_MASTER_FREQ_HZ, + }; + + return (i2c_param_config(I2C_MASTER_NUM, &conf) || + i2c_driver_install(I2C_MASTER_NUM, conf.mode, 0, 0, 0)); +} + +// Helper: Read 16-bit register to 2-byte array (MSB first big endian) +esp_err_t max17048_read_reg(uint8_t reg_addr, uint8_t *MSB, uint8_t *LSB) { + // this is better than converting to little endian for my application + // since I usually need to handle bytes individually. + uint8_t data[2]; + // Write register address + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (MAX17048_ADDR << 1) | I2C_MASTER_WRITE, true); + i2c_master_write_byte(cmd, reg_addr, true); + + // Restart and Read 2 bytes + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (MAX17048_ADDR << 1) | I2C_MASTER_READ, true); + i2c_master_read(cmd, data, 2, I2C_MASTER_LAST_NACK); + i2c_master_stop(cmd); + + esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, pdMS_TO_TICKS(I2C_MASTER_TIMEOUT_MS)); + i2c_cmd_link_delete(cmd); + + if (ret == ESP_OK) { + *MSB = data[0]; + *LSB = data[1]; + } + + return ret; +} + +// Write big endian 2-byte array to a 16-bit register +esp_err_t max17048_write_reg(uint8_t reg_addr, uint8_t MSB, uint8_t LSB) { + // Write register address + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (MAX17048_ADDR << 1) | I2C_MASTER_WRITE, true); + i2c_master_write_byte(cmd, reg_addr, true); + i2c_master_write_byte(cmd, MSB, true); + i2c_master_write_byte(cmd, LSB, true); + i2c_master_stop(cmd); + + esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, pdMS_TO_TICKS(I2C_MASTER_TIMEOUT_MS)); + i2c_cmd_link_delete(cmd); + return ret; +} + +esp_err_t max17048_friendly_write_reg(uint8_t reg_addr, uint8_t MSB, uint8_t LSB, + uint8_t MSBmask, uint8_t LSBmask) { + uint8_t origMSB, origLSB; + esp_err_t err = max17048_read_reg(reg_addr, origMSB, origLSB); + MSB &= MSBmask; + LSB &= LSBmask; + MSB |= origMSB & ~MSBmask; + LSB |= origLSB & ~LSBmask; + return err | max17048_write_reg(reg_addr, MSB, LSB); +} diff --git a/include/mainEventLoop.cpp b/src/mainEventLoop.cpp similarity index 100% rename from include/mainEventLoop.cpp rename to src/mainEventLoop.cpp diff --git a/src/max17048.c b/src/max17048.c new file mode 100644 index 0000000..7a43ecf --- /dev/null +++ b/src/max17048.c @@ -0,0 +1,44 @@ +#include "max17048.h" +#include "esp_err.h" +#include "i2c.h" +#include "esp_timer.h" + +static const char *TAG = "BATTERY"; +uint8_t established_soc; + +esp_err_t max17048_init() { + esp_err_t err = ESP_OK; + uint8_t status, _; + err |= i2c_init(); + err |= max17048_read_reg(MAX17048_REG_STATUS, &status, &_); + err |= bms_set_alert_bound_voltages(3.3, 4.2); + err |= bms_set_reset_voltage(3.25); + err |= bms_set_alsc(); + err |= bms_clear_status(); + +} + +// Helper: Function reading MAX17048 SOC register, returning battery percentage +uint8_t bms_get_soc() { + // uint16_t raw_soc, raw_vcell; + uint16_t raw_soc; + + // Read SOC (Register 0x04) + if (max17048_read_reg(MAX17048_REG_SOC, ((uint8_t*)&raw_soc)+1, (uint8_t*)&raw_soc) == ESP_OK) { + return (raw_soc >> 8) + raw_soc & 0x80; // round to the nearest percent + } else { + ESP_LOGE(TAG, "Failed to read MAX17048"); + return 0; + } +} + +esp_err_t bms_set_alert_bound_voltages(float min, float max) { + uint8_t minVal = (uint16_t)((float)min * 1000.0) / 20; + uint8_t maxVal = (uint16_t)((float)max * 1000.0) / 20; + return max17048_write_reg(MAX17048_REG_VALRT, minVal, maxVal); +} + +esp_err_t bms_set_reset_voltage(float vreset) { + uint8_t maxVal = (uint16_t)((float)vreset * 1000.0) / 40; + max17048_write_reg(MAX17048_REG_VRST_ID, vreset, 0); +} \ No newline at end of file diff --git a/include/servo.cpp b/src/servo.cpp similarity index 100% rename from include/servo.cpp rename to src/servo.cpp diff --git a/include/setup.cpp b/src/setup.cpp similarity index 100% rename from include/setup.cpp rename to src/setup.cpp diff --git a/include/socketIO.cpp b/src/socketIO.cpp similarity index 100% rename from include/socketIO.cpp rename to src/socketIO.cpp