diff --git a/Firmware/main/include/bat_mon.hpp b/Firmware/main/include/bat_mon.hpp index fce9e5e..8814ca4 100644 --- a/Firmware/main/include/bat_mon.hpp +++ b/Firmware/main/include/bat_mon.hpp @@ -21,7 +21,7 @@ public: private: static inline i2c_device_config_t _dev_cfg = { .dev_addr_length = I2C_ADDR_BIT_LEN_7, - .device_address = 0x70, + .device_address = 0x36, .scl_speed_hz = 100000, }; diff --git a/Firmware/main/include/buttons.hpp b/Firmware/main/include/buttons.hpp index 7cd3953..aa7e406 100644 --- a/Firmware/main/include/buttons.hpp +++ b/Firmware/main/include/buttons.hpp @@ -9,14 +9,14 @@ #include "freertos/task.h" typedef enum { - L1 = 1 << 1, - L2 = 1 << 6, - L3 = 1 << 0, - L4 = 1 << 7, - R1 = 1 << 5, - R2 = 1 << 2, - R3 = 1 << 4, - R4 = 1 << 3, + BTN_START = 1 << 1, + BTN_DOWN = 1 << 6, + BTN_SELECT = 1 << 0, + BTN_LEFT = 1 << 7, + BTN_UP = 1 << 5, + BTN_B = 1 << 2, + BTN_RIGHT = 1 << 4, + BTN_A = 1 << 3, } btn_num; class Buttons { diff --git a/Firmware/main/include/config.hpp b/Firmware/main/include/config.hpp index 0e15b6e..abd7bde 100644 --- a/Firmware/main/include/config.hpp +++ b/Firmware/main/include/config.hpp @@ -7,10 +7,11 @@ #define I2C_SCL GPIO_NUM_8 #define I2C_SDA GPIO_NUM_9 -#define SPI_MOSI GPIO_NUM_5 -#define SPI_MISO GPIO_NUM_0 -#define SPI_SCK GPIO_NUM_4 -#define SPI_DISP_CS GPIO_NUM_11 +#define SPI_MOSI GPIO_NUM_5 +#define SPI_MISO GPIO_NUM_0 +#define SPI_SCK GPIO_NUM_4 +#define SPI_DISP_CS GPIO_NUM_24 +#define SPI_DISP_DISP GPIO_NUM_11 #define SPI_BUS SPI2_HOST @@ -20,10 +21,6 @@ #define PWR_INT GPIO_NUM_10 #define PWR_KILL GPIO_NUM_12 -#define SHR_OUT GPIO_NUM_23 -#define SHR_CLK GPIO_NUM_3 -#define SHR_SH GPIO_NUM_2 - -#define DIRECT_BTN GPIO_NUM_1 +#define EXP_INT GPIO_NUM_1 #endif diff --git a/Firmware/main/src/bat_mon.cpp b/Firmware/main/src/bat_mon.cpp index 87ff535..c6f6491 100644 --- a/Firmware/main/src/bat_mon.cpp +++ b/Firmware/main/src/bat_mon.cpp @@ -20,25 +20,78 @@ BatMon& BatMon::get() { static void start_pooler(void* arg) { static_cast(arg)->pooler(); } +void WriteRegister(uint8_t reg, uint16_t value) { + uint8_t buf2[3]; + buf2[0] = reg; + buf2[1] = value & 0xFF; + buf2[2] = value >> 8; + ESP_ERROR_CHECK(i2c_master_transmit(dev_handle, buf2, sizeof(buf2), -1)); +} + +uint16_t ReadRegister(uint8_t reg) { + uint16_t buffer; + ESP_ERROR_CHECK( + i2c_master_transmit_receive(dev_handle, ®, sizeof(reg), reinterpret_cast(&buffer), 2, -1)); + return buffer; +} +void WriteAndVerifyRegister(char RegisterAddress, int RegisterValueToWrite) { + int attempt = 0; + uint16_t RegisterValueRead; + do { + WriteRegister(RegisterAddress, RegisterValueToWrite); + vTaskDelay(1 / portTICK_PERIOD_MS); + RegisterValueRead = ReadRegister(RegisterAddress); + } while (RegisterValueToWrite != RegisterValueRead && attempt++ < 3); +} + +static constexpr float RSense = 0.1; // 100mOhm +static constexpr uint16_t DesignCapMah = 180; // 100mOhm + +constexpr float mahToCap(float mah) { return mah * (1000.0 / 5.0) * RSense; } +constexpr float capToMah(uint16_t cap) { return cap * (5.0 / 1000.0) / RSense; } +constexpr float regToCurrent(uint16_t reg) { + return static_cast(static_cast(reg)) * 0.0015625f / RSense; // Convert to mA +} +constexpr uint16_t currentToReg(float current) { return static_cast(current * RSense / 0.0015625f); } +constexpr float regToVoltage(uint16_t reg) { + return reg * 0.078125f * 0.001f; // Convert to volts +} +constexpr uint16_t voltageToReg(float voltage) { + return static_cast(voltage / (0.078125f * 0.001f)); // Convert to register value +} +static constexpr uint16_t DesignCap = mahToCap(DesignCapMah); +static constexpr uint16_t IchgTerm = currentToReg(25); +static constexpr uint16_t VEmpty = 0xA561; // (3.3V/3.88V) +static constexpr uint16_t dQAcc = (DesignCap / 32); + BatMon::BatMon() { ESP_ERROR_CHECK(i2c_master_bus_add_device(I2cGlobal::get().get_bus_handle(), &_dev_cfg, &dev_handle)); - uint8_t reg = 1; - uint8_t buffer; - uint8_t buf2[2]; - - ESP_ERROR_CHECK( - i2c_master_transmit_receive(dev_handle, ®, sizeof(reg), reinterpret_cast(&buffer), 1, -1)); - if (buffer & (1 << 4)) // POR reset + bool StatusPOR = ReadRegister(0x00) & 0x0002; + if (StatusPOR) // POR reset { printf("Gas gauge reset!\n"); - buf2[0] = 1; - buf2[1] = 0 << 4; - ESP_ERROR_CHECK(i2c_master_transmit(dev_handle, buf2, sizeof(buf2), -1)); + while (ReadRegister(0x3D) & 1) + vTaskDelay(10 / portTICK_PERIOD_MS); - buf2[0] = 0; - buf2[1] = 1 << 4 | 1 << 2; // 10 bit adc - ESP_ERROR_CHECK(i2c_master_transmit(dev_handle, buf2, sizeof(buf2), -1)); + uint16_t HibCFG = ReadRegister(0xBA); // Store original HibCFG value + WriteRegister(0x60, 0x90); // Exit Hibernate Mode step 1 + WriteRegister(0xBA, 0x0); // Exit Hibernate Mode step 2 + WriteRegister(0x60, 0x0); // Exit Hibernate Mode step 3 + WriteRegister(0x18, DesignCap); // Write DesignCap + WriteRegister(0x45, DesignCap / 32); // Write dQAcc + WriteRegister(0x1E, IchgTerm); // Write IchgTerm + WriteRegister(0x3A, VEmpty); // Write VEmpty + WriteRegister(0x46, dQAcc * 44138 / DesignCap); // Write dPAcc + WriteRegister(0xDB, 0x8000); // Write ModelCFG + + // Poll ModelCFG.Refresh(highest bit), proceed to Step 4 when ModelCFG.Refresh = 0. + while (ReadRegister(0xDB) & 0x8000) + vTaskDelay(10 / portTICK_PERIOD_MS); // 10ms wait loop. Do not continue until ModelCFG.Refresh == 0. + WriteRegister(0xBA, HibCFG); // Restore Original HibCFG value + + uint16_t Status = ReadRegister(0x00); // Read Status + WriteAndVerifyRegister(0x00, Status & 0xFFFD); // Write and Verify Status with POR bit cleared } xTaskCreate(&start_pooler, "BatMon", 2048, this, tskIDLE_PRIORITY, &_pooler_task); @@ -48,27 +101,9 @@ void BatMon::pooler() { while (true) { uint8_t reg = 8; uint16_t buffer; - ESP_ERROR_CHECK( - i2c_master_transmit_receive(dev_handle, ®, sizeof(reg), reinterpret_cast(&buffer), 2, -1)); - float voltage = buffer; - voltage *= 2.44f; - voltage /= 1000; - _voltage = voltage; - reg = 2; - ESP_ERROR_CHECK( - i2c_master_transmit_receive(dev_handle, ®, sizeof(reg), reinterpret_cast(&buffer), 2, -1)); - float charge = *reinterpret_cast(&buffer); - charge *= 6.70f; - charge /= 50; - _charge = charge; - reg = 6; - ESP_ERROR_CHECK( - i2c_master_transmit_receive(dev_handle, ®, sizeof(reg), reinterpret_cast(&buffer), 2, -1)); - float current = static_cast(buffer << 2); - current *= 11.77f; - current /= 50; - current /= 4; - _current = current; + _charge = capToMah(ReadRegister(0x05)); + _current = regToCurrent(ReadRegister(0x0B)); + _voltage = regToVoltage(ReadRegister(0x09)); PowerHelper::get().delay(10000, 1000); } } diff --git a/Firmware/main/src/buttons.cpp b/Firmware/main/src/buttons.cpp index d03bce9..d932da0 100644 --- a/Firmware/main/src/buttons.cpp +++ b/Firmware/main/src/buttons.cpp @@ -13,6 +13,14 @@ #include "freertos/task.h" #include "config.hpp" +#include "i2c_global.hpp" + +static i2c_master_dev_handle_t dev_handle; +static inline i2c_device_config_t dev_cfg = { + .dev_addr_length = I2C_ADDR_BIT_LEN_7, + .device_address = 0x20, + .scl_speed_hz = 100000, +}; Buttons& Buttons::get() { static Buttons buttons; @@ -22,14 +30,15 @@ Buttons& Buttons::get() { static void start_pooler(void* arg) { static_cast(arg)->pooler(); } Buttons::Buttons() { - ESP_ERROR_CHECK(gpio_reset_pin(SHR_OUT)); - ESP_ERROR_CHECK(gpio_reset_pin(SHR_CLK)); - ESP_ERROR_CHECK(gpio_reset_pin(SHR_SH)); - ESP_ERROR_CHECK(gpio_set_direction(SHR_OUT, GPIO_MODE_INPUT)); - ESP_ERROR_CHECK(gpio_set_pull_mode(SHR_OUT, GPIO_FLOATING)); - ESP_ERROR_CHECK(gpio_set_direction(SHR_SH, GPIO_MODE_OUTPUT)); - ESP_ERROR_CHECK(gpio_set_direction(SHR_CLK, GPIO_MODE_OUTPUT)); + ESP_ERROR_CHECK(i2c_master_bus_add_device(I2cGlobal::get().get_bus_handle(), &dev_cfg, &dev_handle)); + uint8_t buf2[2]; + // Config + buf2[0] = 6; + buf2[1] = 0xFF; + ESP_ERROR_CHECK(i2c_master_transmit(dev_handle, buf2, sizeof(buf2), -1)); + buf2[0] = 7; + ESP_ERROR_CHECK(i2c_master_transmit(dev_handle, buf2, sizeof(buf2), -1)); xTaskCreate(&start_pooler, "ButtonsPooler", 2048, this, 1, &_pooler_task); } @@ -42,18 +51,12 @@ static void delay(unsigned long long loop) { void Buttons::pooler() { while (true) { - ESP_ERROR_CHECK(gpio_set_level(SHR_SH, 0)); - ESP_ERROR_CHECK(gpio_set_level(SHR_SH, 1)); - - uint8_t new_val = 0; - - for (int i = 0; i < 8; i++) { - ESP_ERROR_CHECK(gpio_set_level(SHR_CLK, 0)); - new_val |= gpio_get_level(SHR_OUT) << i; - ESP_ERROR_CHECK(gpio_set_level(SHR_CLK, 1)); - } - _current = new_val; - PowerHelper::get().delay(10000, 100); + uint8_t reg = 0; + uint8_t buffer; + ESP_ERROR_CHECK( + i2c_master_transmit_receive(dev_handle, ®, sizeof(reg), reinterpret_cast(&buffer), 1, -1)); + _current = buffer; + PowerHelper::get().delay(10000, 200); } } uint8_t Buttons::get_pressed() { return _current; } diff --git a/Firmware/main/src/display.cpp b/Firmware/main/src/display.cpp index 92ebeaf..9dd8eaf 100644 --- a/Firmware/main/src/display.cpp +++ b/Firmware/main/src/display.cpp @@ -6,6 +6,7 @@ #include +#include #include "driver/spi_master.h" // This solution is attributed to Rich Schroeppel in the Programming Hacks section @@ -28,7 +29,14 @@ SMD& SMD::get() { return smd; } -SMD::SMD() { spi_bus_add_device(SPI_BUS, &_devcfg, &_spi); } +SMD::SMD() { + spi_bus_add_device(SPI_BUS, &_devcfg, &_spi); + ESP_ERROR_CHECK(gpio_reset_pin(SPI_DISP_DISP)); + + ESP_ERROR_CHECK(gpio_set_direction(SPI_DISP_DISP, GPIO_MODE_OUTPUT)); + ESP_ERROR_CHECK(gpio_set_level(SPI_DISP_DISP, 1)); + ESP_ERROR_CHECK(gpio_hold_en(SPI_DISP_DISP)); +} void SMD::clear() { std::array buf{}; diff --git a/Firmware/main/src/hello_world_main.cpp b/Firmware/main/src/hello_world_main.cpp index 9301158..0fad828 100644 --- a/Firmware/main/src/hello_world_main.cpp +++ b/Firmware/main/src/hello_world_main.cpp @@ -39,7 +39,7 @@ FbTty tty; extern "C" void app_main() { esp_pm_config_t pm_config = { .max_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ, .min_freq_mhz = 16, .light_sleep_enable = true}; - ESP_ERROR_CHECK(esp_pm_configure(&pm_config)); + // ESP_ERROR_CHECK(esp_pm_configure(&pm_config)); printf("Hello world!\n"); // TODO: Where to put that? ESP_ERROR_CHECK(esp_sleep_enable_gpio_wakeup()); @@ -74,13 +74,13 @@ extern "C" void app_main() { tty.reset(); uint8_t pressed = Buttons::get().get_pressed(); - if (pressed & L3) + if (pressed & BTN_LEFT) rx -= 5; - if (pressed & L4) + if (pressed & BTN_DOWN) ry += 5; - if (pressed & R3) + if (pressed & BTN_UP) ry -= 5; - if (pressed & R4) + if (pressed & BTN_RIGHT) rx += 5; if (pressed == 0 && !PowerHelper::get().is_slow()) @@ -99,6 +99,8 @@ extern "C" void app_main() { tty.fmt("{:.1f}mA {:.1f}V {:.1f}mAh {}", BatMon::get().get_current(), BatMon::get().get_voltage(), BatMon::get().get_charge(), slow ? "S" : ""); + tty.fmt("Buttons: {:08b}", pressed); + if (rx < 30) rx = 30; if (rx > 370) diff --git a/Firmware/main/src/power_helper.cpp b/Firmware/main/src/power_helper.cpp index b8deb56..fab86a9 100644 --- a/Firmware/main/src/power_helper.cpp +++ b/Firmware/main/src/power_helper.cpp @@ -17,6 +17,7 @@ PowerHelper& PowerHelper::get() { } bool PowerHelper::is_slow() const { return _slow; } void PowerHelper::set_slow(bool slow) { + return; _slow = slow; if (_slow) { xEventGroupClearBits(_event_group, 1); @@ -41,13 +42,13 @@ void PowerHelper::reset_slow_isr() { static void wakeup(void* arg) { static_cast(arg)->reset_slow_isr(); } PowerHelper::PowerHelper() : _event_group(xEventGroupCreate()) { - ESP_ERROR_CHECK(gpio_reset_pin(DIRECT_BTN)); - ESP_ERROR_CHECK(gpio_set_direction(DIRECT_BTN, GPIO_MODE_INPUT)); - ESP_ERROR_CHECK(gpio_set_pull_mode(DIRECT_BTN, GPIO_FLOATING)); - ESP_ERROR_CHECK(gpio_set_intr_type(DIRECT_BTN, GPIO_INTR_HIGH_LEVEL)); - ESP_ERROR_CHECK(gpio_wakeup_enable(DIRECT_BTN, GPIO_INTR_HIGH_LEVEL)); + // ESP_ERROR_CHECK(gpio_reset_pin(EXP_INT)); + // ESP_ERROR_CHECK(gpio_set_direction(EXP_INT, GPIO_MODE_INPUT)); + // ESP_ERROR_CHECK(gpio_set_pull_mode(EXP_INT, GPIO_FLOATING)); + // ESP_ERROR_CHECK(gpio_set_intr_type(EXP_INT, GPIO_INTR_HIGH_LEVEL)); + // ESP_ERROR_CHECK(gpio_wakeup_enable(EXP_INT, GPIO_INTR_HIGH_LEVEL)); // ESP_ERROR_CHECK(gpio_install_isr_service(0)); - // gpio_isr_handler_add(DIRECT_BTN, wakeup, this); + // gpio_isr_handler_add(EXP_INT, wakeup, this); set_slow(false); } @@ -67,4 +68,6 @@ void PowerHelper::delay(int slow_ms, int normal_ms) { vTaskDelay(normal_ms / portTICK_PERIOD_MS); } } -void PowerHelper::install_isr() { gpio_isr_handler_add(DIRECT_BTN, wakeup, this); } +void PowerHelper::install_isr() { + // gpio_isr_handler_add(EXP_INT, wakeup, this); +} diff --git a/Firmware/main/src/shutdowner.cpp b/Firmware/main/src/shutdowner.cpp index 372a823..7011d98 100644 --- a/Firmware/main/src/shutdowner.cpp +++ b/Firmware/main/src/shutdowner.cpp @@ -21,18 +21,18 @@ static void IRAM_ATTR shutdown(void* arg) { } Shutdowner::Shutdowner() { - ESP_ERROR_CHECK(gpio_reset_pin(PWR_INT)); ESP_ERROR_CHECK(gpio_reset_pin(PWR_KILL)); - - ESP_ERROR_CHECK(gpio_set_direction(PWR_INT, GPIO_MODE_INPUT)); ESP_ERROR_CHECK(gpio_set_direction(PWR_KILL, GPIO_MODE_OUTPUT)); ESP_ERROR_CHECK(gpio_set_level(PWR_KILL, 1)); + ESP_ERROR_CHECK(gpio_hold_en(PWR_KILL)); + + ESP_ERROR_CHECK(gpio_reset_pin(PWR_INT)); + ESP_ERROR_CHECK(gpio_set_direction(PWR_INT, GPIO_MODE_INPUT)); ESP_ERROR_CHECK(gpio_set_pull_mode(PWR_INT, GPIO_FLOATING)); ESP_ERROR_CHECK(gpio_set_intr_type(PWR_INT, GPIO_INTR_LOW_LEVEL)); // ESP_ERROR_CHECK(esp_sleep_enable_gpio_wakeup()); ESP_ERROR_CHECK(gpio_wakeup_enable(PWR_INT, GPIO_INTR_LOW_LEVEL)); // ESP_ERROR_CHECK(gpio_install_isr_service(0)); - ESP_ERROR_CHECK(gpio_hold_en(PWR_KILL)); // gpio_isr_handler_add(PWR_INT, shutdown, nullptr); }