From 5db75e3ae38915c6c3c2f3cdd841617bf0453f04 Mon Sep 17 00:00:00 2001 From: alex04130 Date: Mon, 18 Mar 2024 20:46:57 -0500 Subject: [PATCH] first commit --- CMakeLists.txt | 3 + sw7203.c | 551 +++++++++++++++++++++++++++++++++++++++++++++++++ sw7203.h | 500 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1054 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 sw7203.c create mode 100644 sw7203.h diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..673bbec --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "sw7203.c" + INCLUDE_DIRS "." + REQUIRES driver) \ No newline at end of file diff --git a/sw7203.c b/sw7203.c new file mode 100644 index 0000000..eb7905e --- /dev/null +++ b/sw7203.c @@ -0,0 +1,551 @@ + +#include +#include "driver/gpio.h" +#include "driver/i2c_master.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +static const char *SW7203_TAG = "SW7203"; + +void sw7203_register_change_bitmask_nonpoint(uint8_t reg_addr, uint8_t data, uint8_t bitmask) +{ + uint8_t original_reg; + if (__sw7203_driver_config__.I2CBusBusyEnable == 1) + { + while (*SW7203_Mutex != 0) + { + vTaskDelay(50 / portTICK_PERIOD_MS); + } + *SW7203_Mutex = 1; + ESP_ERROR_CHECK(i2c_master_transmit_receive(SW7203_I2C_handle, ®_addr, 1, &original_reg, 1, -1)); + *SW7203_Mutex = 0; + } + else + ESP_ERROR_CHECK(i2c_master_transmit_receive(SW7203_I2C_handle, ®_addr, 1, &original_reg, 1, -1)); + uint8_t diff = (original_reg ^ (data)) & (bitmask); + if (diff) + { + uint16_t write_data = (reg_addr) << 8 | (diff ^ original_reg); + if (__sw7203_driver_config__.I2CBusBusyEnable == 1) + { + while (SW7203_Mutex != 0) + { + vTaskDelay(50 / portTICK_PERIOD_MS); + } + SW7203_Mutex = 1; + ESP_ERROR_CHECK(i2c_master_transmit(SW7203_I2C_handle, &write_data, 2, -1)); + *SW7203_Mutex = 0; + } + else + ESP_ERROR_CHECK(i2c_master_transmit(SW7203_I2C_handle, &write_data, 2, -1)); + } +} + +uint8_t sw7203_I2C_address_find(i2c_master_bus_handle_t I2C_bus_handle) +{ + esp_err_t errcode; + errcode = i2c_master_probe(I2C_bus_handle, sw7203_I2c_0x3C, -1); + if (errcode == ESP_OK) + { + return 0x3C; + } + errcode = i2c_master_probe(I2C_bus_handle, sw7203_I2c_0x1C, -1); + if (errcode == ESP_OK) + { + return 0x1C; + } + errcode = i2c_master_probe(I2C_bus_handle, sw7203_I2c_0x18, -1); + if (errcode == ESP_OK) + { + return 0x18; + } + errcode = i2c_master_probe(I2C_bus_handle, sw7203_I2c_0x38, -1); + if (errcode == ESP_OK) + { + return 0x38; + } + return -1; +} + +void sw7203_register_change_bitmask(uint8_t *reg_addr, uint8_t *data, uint8_t *bitmask) +{ + uint8_t original_reg; + if (__sw7203_driver_config__.I2CBusBusyEnable == 1) + { + while (*SW7203_Mutex != 0) + { + vTaskDelay(50 / portTICK_PERIOD_MS); + } + *SW7203_Mutex = 1; + ESP_ERROR_CHECK(i2c_master_transmit_receive(SW7203_I2C_handle, reg_addr, 1, &original_reg, 1, -1)); + *SW7203_Mutex = 0; + } + else + ESP_ERROR_CHECK(i2c_master_transmit_receive(SW7203_I2C_handle, reg_addr, 1, &original_reg, 1, -1)); + uint8_t diff = (original_reg ^ (*data)) & (*bitmask); + if (diff) + { + uint16_t write_data = (*reg_addr) << 8 | (diff ^ original_reg); + if (__sw7203_driver_config__.I2CBusBusyEnable == 1) + { + while (SW7203_Mutex != 0) + { + vTaskDelay(50 / portTICK_PERIOD_MS); + } + SW7203_Mutex = 1; + ESP_ERROR_CHECK(i2c_master_transmit(SW7203_I2C_handle, &write_data, 2, -1)); + *SW7203_Mutex = 0; + } + else + ESP_ERROR_CHECK(i2c_master_transmit(SW7203_I2C_handle, &write_data, 2, -1)); + } +} +esp_err_t sw7203_reg_read(uint8_t reg_addr, uint8_t *data) +{ + esp_err_t errcode; + if (__sw7203_driver_config__.I2CBusBusyEnable == 1) + { + while (SW7203_Mutex != 0) + { + vTaskDelay(50 / portTICK_PERIOD_MS); + } + SW7203_Mutex = 1; + errcode = i2c_master_transmit_receive(SW7203_I2C_handle, reg_addr, 1, data, 1, -1); + *SW7203_Mutex = 0; + } + else + errcode = i2c_master_transmit_receive(SW7203_I2C_handle, reg_addr, 1, data, 1, -1); + return errcode; +} +esp_err_t sw7203_reg_write(uint8_t reg_addr, uint8_t *data) +{ + uint8_t tran_data[2]; + tran_data[0] = reg_addr; + tran_data[1] = *data; + esp_err_t errcode; + if (__sw7203_driver_config__.I2CBusBusyEnable == 1) + { + while (SW7203_Mutex != 0) + { + vTaskDelay(50 / portTICK_PERIOD_MS); + } + SW7203_Mutex = 1; + errcode = i2c_master_transmit(SW7203_I2C_handle, tran_data, 2, -1); + *SW7203_Mutex = 0; + } + else + errcode = i2c_master_transmit(SW7203_I2C_handle, tran_data, 2, -1); + return errcode; +} + +void sw7203_int() +{ + if (__sw7203_driver_config__.INTGPIOEnable == 1) + { + while (1) + { + vTaskDelay(50 / portTICK_PERIOD_MS); + SW7203IntCallBack(); + } + } + else + { + while (1) + { + if (gpio_get_level(sw7203_INT_gpio_num) == 0) + { + SW7203IntCallBack(); + } + vTaskDelay(50 / portTICK_PERIOD_MS); + } + } +} + +esp_err_t sw7203_driver_install(sw7203_config_t *sw7203_config, i2c_master_bus_handle_t I2C_bus_handle, uint8_t I2C_address) +{ + if (I2C_address != 0x18 && I2C_address != 0x1C && I2C_address != 0x38 && I2C_address != 0x3C) + { + return ESP_ERR_NOT_ALLOWED; + } + if (sw7203_config->SW7203_control_mode.mode == 1 && (sw7203_config->connectDetect.config.a1PortDetectEnable == 1 || sw7203_config->connectDetect.config.a2PortDetectEnable == 1)) + { + return ESP_ERR_INVALID_RESPONSE; + } + if ((__sw7203_driver_config__.INTGPIOEnable = sw7203_config->SW7203_control_mode.INTGPIOEnable) == 0) + { + sw7203_INT_gpio_num = sw7203_config->INT_gpio_num; + if (sw7203_config->SW7203_control_mode.gpioInitMode == 0) + { + gpio_config_t sw7203_int_gpio_config = { + .pin_bit_mask = 1ull << sw7203_INT_gpio_num, + .mode = GPIO_MODE_INPUT, + .pull_down_en = gpio_pulldown_dis, + .pull_up_en = gpio_pullup_en, + }; + gpio_config(&sw7203_int_gpio_config); + } + } + __sw7203_driver_config__.mode = sw7203_config->SW7203_control_mode.mode; + __sw7203_driver_config__.I2CBusBusyEnable = sw7203_config->SW7203_control_mode.I2CBusBusyEnable; + __sw7203_driver_config__.voltageConflictSwitch = sw7203_config->SW7203_control_mode.voltageConflictSwitch; + __sw7203_driver_config__.porta1enable = sw7203_config->connectDetect.config.a1PortDetectEnable; + __sw7203_driver_config__.porta2enable = sw7203_config->connectDetect.config.a2PortDetectEnable; + esp_err_t errcode; + i2c_device_config_t sw7203_i2c_dev_config = { + .dev_addr_length = I2C_ADDR_BIT_LEN_7, + .device_address = I2C_address, + .scl_speed_hz = 100000}; + ESP_ERROR_CHECK(errcode = i2c_master_bus_add_device(I2C_bus_handle, &sw7203_i2c_dev_config, &SW7203_I2C_handle)); + SW7203_Mutex = sw7203_config->Mutex; + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[0][0], &sw7203_config->connectDetect.hex, &SW7203RegAddress_bitmask[0][1]); // {0x18, 0b00010011}, 0 + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[1][0], &sw7203_config->i2cAddress, &SW7203RegAddress_bitmask[1][1]); // {0x1A, 0b00000011}, 1 + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[2][0], &sw7203_config->funcConfig1.hex, &SW7203RegAddress_bitmask[2][1]); // {0x20, 0b11100111}, 2 + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[3][0], &sw7203_config->funcConfig2.hex, &SW7203RegAddress_bitmask[3][1]); // {0x21, 0b11111111}, 3 + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[4][0], &sw7203_config->funcConfig3.hex, &SW7203RegAddress_bitmask[4][1]); // {0x22, 0b11110000}, 4 + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[5][0], &sw7203_config->funcConfig4.hex, &SW7203RegAddress_bitmask[5][1]); // {0x30, 0b11001111}, 5 + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[6][0], &sw7203_config->funcConfig5.hex, &SW7203RegAddress_bitmask[6][1]); // {0x31, 0b00001111}, 6 + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[7][0], &sw7203_config->funcConfig6.hex, &SW7203RegAddress_bitmask[7][1]); // {0x32, 0b11011111}, 7 + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[8][0], &sw7203_config->funcConfig7.hex, &SW7203RegAddress_bitmask[8][1]); // {0x33, 0b11111111}, 8 + uint8_t data_up, data_lb; + int tmp; + data_up = 0b01111100 & (sw7203_config->connectDetect.config.a1PortDetectEnable) & ((sw7203_config->connectDetect.config.a1PortDetectEnable) ? 2 : 0); + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[26][0], &data_up, &SW7203RegAddress_bitmask[26][1]); // {0x02, 0b01111111} 26 + data_up = 0b10111111 & ((sw7203_config->funcConfig1.config.NTCProtectEnable) ? 0 : 64); + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[27][0], &data_up, &SW7203RegAddress_bitmask[27][1]); // {0x28, 0b00011111} 27 + if (sw7203_config->chargeVoltage_mV < 3000) + { + data_up = 0; + data_lb = 0; + } + else if (sw7203_config->chargeVoltage_mV > 19200) + { + data_up = 0b11001010; + data_lb = 0b00000100; + } + else + { + tmp = ((sw7203_config->chargeVoltage_mV - 3000) / 10); + data_up = (uint8_t)(tmp >> 3) & 0xff; + data_lb = (tmp) & 0b0000000000000111; + } + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[9][0], &data_up, &SW7203RegAddress_bitmask[9][1]); // {0x34, 0b11111111}, 9 + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[10][0], &data_lb, &SW7203RegAddress_bitmask[10][1]); // {0x35, 0b00000111}, 10 + if (sw7203_config->trickleVoltage_mV < 2500) + { + data_up = 0; + } + else if (sw7203_config->trickleVoltage_mV > 13200) + { + data_up = 107; + } + else + { + data_up = ((sw7203_config->trickleVoltage_mV - 2500) / 100); + } + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[11][0], &data_up, &SW7203RegAddress_bitmask[11][1]); // {0x36, 0b01111111}, 11 + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[12][0], &sw7203_config->trickleConfig.hex, &SW7203RegAddress_bitmask[12][1]); // {0x37, 0b00001111}, 12 + if (sw7203_config->chargeVBUSVoltageLimit_mV < 4000) + { + data_up = 0; + } + else if (sw7203_config->chargeVBUSVoltageLimit_mV > 20000) + { + data_up = 160; + } + else + { + data_up = ((sw7203_config->chargeVBUSVoltageLimit_mV - 4000) / 100); + } + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[13][0], &data_up, &SW7203RegAddress_bitmask[13][1]); // {0x38, 0b11111111}, 13 + if (sw7203_config->chargeVBUSCurrentLimit_mA < 500) + { + data_up = 0; + } + else if (sw7203_config->chargeVBUSCurrentLimit_mA > 6850) + { + data_up = 127; + } + else + { + data_up = ((sw7203_config->chargeVBUSCurrentLimit_mA - 500) / 50); + } + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[14][0], &data_up, &SW7203RegAddress_bitmask[14][1]); // {0x39, 0b01111111}, 14 + if (sw7203_config->chargeVBATCurrentLimit_mA < 100) + { + data_up = 0; + } + else if (sw7203_config->chargeVBATCurrentLimit_mA > 12000) + { + data_up = 119; + } + else + { + data_up = ((sw7203_config->chargeVBATCurrentLimit_mA - 100) / 100); + } + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[15][0], &data_up, &SW7203RegAddress_bitmask[15][1]); // {0x3A, 0b01111111}, 15 + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[16][0], &sw7203_config->NVDCConfig1.hex, &SW7203RegAddress_bitmask[16][1]); // {0x40, 0b01000011}, 16 + if (sw7203_config->chargeLDOCurrentLimit_mA < 100) + { + data_up = 0; + } + else if (sw7203_config->chargeLDOCurrentLimit_mA > 2000) + { + data_up = 19; + } + else + { + data_up = ((sw7203_config->chargeLDOCurrentLimit_mA - 100) / 100); + } + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[17][0], &data_up, &SW7203RegAddress_bitmask[17][1]); // {0x41, 0b00011111}, 17 + if (sw7203_config->VSYSMinVoltage_mV < 3000) + { + data_up = 0; + } + else if (sw7203_config->VSYSMinVoltage_mV > 16600) + { + data_up = 68; + } + else + { + data_up = ((sw7203_config->VSYSMinVoltage_mV - 3000) / 200); + } + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[18][0], &data_up, &SW7203RegAddress_bitmask[18][1]); // {0x42, 0b01111111}, 18 + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[19][0], &sw7203_config->NTCConfig.hex, &SW7203RegAddress_bitmask[19][1]); // {0x43, 0b11111111}, 19 + + if (sw7203_config->SW7203_control_mode.intMode == 0) + { + xTaskCreate(sw7203_int, "sw7203 int driver func", 1024, NULL, 5, &__sw7203_int_rtos_handle__); + } + return ESP_OK; +} + +void sw7203SwitchOutput(sw7203_Vout_config_t *config) +{ + uint8_t data_up, data_lb; + int tmp; + if ((__sw7203_current_output_voltage__ = config->VBUSVoltage_mV) < 3000) + { + data_up = 0; + data_lb = 0; + } + else if (config->VBUSVoltage_mV > 22000) + { + data_up = 0b11101101; + data_lb = 0b00000100; + } + else + { + tmp = ((config->VBUSVoltage_mV - 3000) / 10); + data_up = (uint8_t)(tmp >> 3) & 0xff; + data_lb = (tmp) & 0b0000000000000111; + } + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[20][0], &data_up, &SW7203RegAddress_bitmask[20][1]); // {0x23, 0b11111111} 20 + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[21][0], &data_lb, &SW7203RegAddress_bitmask[21][1]); // {0x24, 0b00000111} 21 + if (config->VBUSCurrentLimit_mA < 500) + { + data_up = 0; + } + else if (config->VBUSCurrentLimit_mA > 6850) + { + data_up = 127; + } + else + { + data_up = (uint8_t)((config->VBUSCurrentLimit_mA - 500) / 50); + } + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[22][0], &data_up, &SW7203RegAddress_bitmask[22][1]); // {0x25, 0b01111111} 22 + if (config->VBATCurrentLimit_mA < 100) + { + data_up = 0; + } + else if (config->VBATCurrentLimit_mA > 12000) + { + data_up = 119; + } + else + { + data_up = (uint8_t)((config->VBUSCurrentLimit_mA - 100) / 100); + } + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[23][0], &data_up, &SW7203RegAddress_bitmask[23][1]); // {0x26, 0b01111111} 23 + if (config->VBATVoltageLimit_mV < 2700) + { + data_up = 0; + } + else if (config->VBATVoltageLimit_mV > 13200) + { + data_up = 105; + } + else + { + data_up = (uint8_t)((config->VBATVoltageLimit_mV - 2700) / 100); + } + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[24][0], &data_up, &SW7203RegAddress_bitmask[24][1]); // {0x27, 0b01111111} 24 + if (config->VBATVoltageLimitHysteresis_mV < 400) + { + data_up = 0; + } + else if (config->VBATVoltageLimitHysteresis_mV > 2000) + { + data_up = 16; + } + else + { + data_up = (uint8_t)((config->VBATVoltageLimitHysteresis_mV - 400) / 100); + } + sw7203_register_change_bitmask(&SW7203RegAddress_bitmask[25][0], &data_up, &SW7203RegAddress_bitmask[25][1]); // {0x28, 0b00011111} 25 +} + +esp_err_t sw7203_driver_uninstall(i2c_master_bus_handle_t I2C_bus_handle) +{ + if (__sw7203_int_rtos_handle__ != NULL) + vTaskDelete(__sw7203_int_rtos_handle__); + return i2c_master_bus_rm_device(SW7203_I2C_handle); +} + +void SW7203IntCallBack() +{ + uint8_t buffer; + sw7203_reg_read(0x04, buffer); + if (buffer & 0x40) + { + ESP_LOGW(SW7203_TAG, "VSYS Over Voltage!"); + } + if (buffer & 0x20) + { + ESP_LOGW(SW7203_TAG, "Charge Time Out!"); + } + if (buffer & 0x10) + { + ESP_LOGI(SW7203_TAG, "Charge Full!"); + } + if (buffer & 0x08) + { + ESP_LOGI(SW7203_TAG, "Port B pluged in!"); + sw7203OutputDisable(); + sw7203_register_change_bitmask_nonpoint(0x19, 0b00000100, 0b00000100); + sw7203_register_change_bitmask_nonpoint(0x0d, 0b00010000, 0b00010000); + } + if (buffer & 0x04) + { + ESP_LOGI(SW7203_TAG, "Port B removed!"); + sw7203_register_change_bitmask_nonpoint(0x19, 0, 0b00000100); + if (__sw7203_driver_config__.porta1enable == 1) + { + sw7203_register_change_bitmask_nonpoint(0x0c, 0b00000010, 0b00000010); + vTaskDelay(300 / portTICK_PERIOD_MS); + sw7203_register_change_bitmask_nonpoint(0x0c, 0b00000000, 0b00000010); + } + if (__sw7203_driver_config__.porta2enable == 1) + { + sw7203_register_change_bitmask_nonpoint(0x0c, 0b00000001, 0b00000001); + vTaskDelay(300 / portTICK_PERIOD_MS); + sw7203_register_change_bitmask_nonpoint(0x0c, 0b00000000, 0b00000001); + } + } + if (__sw7203_driver_config__.porta2enable == 1 && buffer & 0x02) + { + ESP_LOGI(SW7203_TAG, "A2 pluged in!"); + if (__sw7203_driver_config__.mode == 0) + { + sw7203_Vout_config_t *tmp = (*__SW7203CallBack_)(sw7203_port_A2); + if (tmp->VBUSVoltage_mV != __sw7203_current_output_voltage__) + { + sw7203SwitchOutput(tmp); + } + sw7203_register_change_bitmask_nonpoint(0x19, 0b00000001, 0b00000001); + } + } + if (__sw7203_driver_config__.porta1enable == 1 && buffer & 0x01) + { + ESP_LOGI(SW7203_TAG, "A1 pluged in!"); + if (__sw7203_driver_config__.mode == 0) + { + sw7203_Vout_config_t *tmp = (*__SW7203CallBack_)(sw7203_port_A1); + if (tmp->VBUSVoltage_mV != __sw7203_current_output_voltage__) + { + sw7203SwitchOutput(tmp); + } + sw7203_register_change_bitmask_nonpoint(0x19, 0b00000010, 0b00000010); + } + } + buffer = 0x7f; + sw7203_reg_write(0x04, &buffer); + sw7203_reg_read(0x05, buffer); + if (buffer & 0x80) + { + ESP_LOGW(SW7203_TAG, "Chip Over Temperature!"); + } + if (buffer & 0x40) + { + ESP_LOGW(SW7203_TAG, "NTC Over Temperature!"); + } + if (buffer & 0x20) + { + ESP_LOGW(SW7203_TAG, "VBUS Over Voltage!"); + } + if (buffer & 0x10) + { + ESP_LOGW(SW7203_TAG, "VBAT Over Voltage!"); + } + if (buffer & 0x08) + { + ESP_LOGW(SW7203_TAG, "VBAT Under Voltage!"); + } + if (buffer & 0x04) + { + ESP_LOGW(SW7203_TAG, "VBUS Short-Cutted!"); + } + if (buffer & 0x02) + { + ESP_LOGW(SW7203_TAG, "VBUS Over Power!"); + } + if (buffer & 0x01) + { + ESP_LOGW(SW7203_TAG, "VSYS Over Power!"); + } + buffer = 0xff; + sw7203_reg_write(0x05, &buffer); +} + +void sw7203OutputEnable() +{ + sw7203_register_change_bitmask_nonpoint(0x0d, 0b00000001, 0b00000001); +} + +void sw7203OutputDisable() +{ + sw7203_register_change_bitmask_nonpoint(0x0d, 0, 0b00000001); + if (__sw7203_driver_config__.porta1enable == 1) + { + sw7203_register_change_bitmask_nonpoint(0x0c, 0b00000010, 0b00000010); + vTaskDelay(300 / portTICK_PERIOD_MS); + sw7203_register_change_bitmask_nonpoint(0x0c, 0b00000000, 0b00000010); + } + if (__sw7203_driver_config__.porta2enable == 1) + { + sw7203_register_change_bitmask_nonpoint(0x0c, 0b00000001, 0b00000001); + vTaskDelay(300 / portTICK_PERIOD_MS); + sw7203_register_change_bitmask_nonpoint(0x0c, 0b00000000, 0b00000001); + } +} + +void sw7203A1PortOpen() +{ + sw7203_register_change_bitmask_nonpoint(0x19, 0b00000010, 0b00000010); +} + +void sw7203A2PortOpen() +{ + sw7203_register_change_bitmask_nonpoint(0x19, 0b00000001, 0b00000001); +} + +void sw7203A1PortClose() +{ + sw7203_register_change_bitmask_nonpoint(0x19, 0, 0b00000010); +} + +void sw7203A2PortClose() +{ + sw7203_register_change_bitmask_nonpoint(0x19, 0, 0b00000001); +} \ No newline at end of file diff --git a/sw7203.h b/sw7203.h new file mode 100644 index 0000000..7dae485 --- /dev/null +++ b/sw7203.h @@ -0,0 +1,500 @@ +#ifndef __SW7203_H__ +#define __SW7203_H__ + +#include "driver/i2c_master.h" +#include "esp_log.h" + +typedef enum +{ + sw7203_port_A1, + sw7203_port_A2 +} sw7203_I2C_port; + +typedef sw7203_Vout_config_t *(*SW7203OutputConfigCallBack_t)(sw7203_I2C_port); +void SW7203IntCallBack(); + +uint8_t sw7203_INT_gpio_num; +static i2c_master_dev_handle_t SW7203_I2C_handle; +uint8_t *SW7203_Mutex = NULL; +static SW7203OutputConfigCallBack_t *__SW7203CallBack_; +TaskHandle_t __sw7203_int_rtos_handle__ = NULL; +int __sw7203_current_output_voltage__; + +struct +{ + uint8_t mode : 1; + + uint8_t INTGPIOEnable : 1; + + uint8_t voltageConflictSwitch : 1; + + uint8_t I2CBusBusyEnable : 1; + + uint8_t porta1enable : 1; + + uint8_t porta2enable : 1; + +} __sw7203_driver_config__; + +typedef union +{ + uint8_t hex; + struct + { + uint8_t adc_filter_time : 2; // 0: 10mS 1:20mS 2:40mS 4: 80mS + uint8_t : 2; + uint8_t adc_data : 4; // 0: VBAT电压 1: VBUS电压 4: VBAT充电电流 5: VBUS 充电电流 6: VBAT 放电电流 7:VBUS 放电电流 8: 芯片温度 9: NTC电压 10: VSYS电压 + } config; +} adc_config; + +typedef enum +{ + sw7203_I2c_0x3C = 0, + sw7203_I2c_0x38 = 1, + sw7203_I2c_0x1C = 2, + sw7203_I2c_0x18 = 3 +} sw7203_I2C_address_t; + +typedef struct +{ + uint16_t VBUSVoltage_mV; // 放电 VBUS 输出电压设置 [3000,22000] 单位:毫伏(mV) + uint16_t VBATVoltageLimit_mV; // 放电 VBAT 欠压设置 [2700,13200] 单位:毫伏(mV) + uint16_t VBATVoltageLimitHysteresis_mV; // 放电 VBAT 欠压迟滞设置 [400,2000] 单位:毫伏(mV) + uint16_t VBUSCurrentLimit_mA; // 放电 VBUS 输出限流设置 [500,6850] 单位:毫安(mA) + uint16_t VBATCurrentLimit_mA; // 放电 VBAT 输出限流设置 [100,12000] 单位:毫安(mA) +} sw7203_Vout_config_t; + +typedef struct +{ + + uint8_t INT_gpio_num; + + sw7203_I2C_address_t i2cAddress; + void *Mutex; + SW7203OutputConfigCallBack_t CallBack; + + struct + { + uint8_t mode : 1; + // 控制模式选择 + // 0: 被动模式 采取回调函数的方式进行运作,当检测到输入插入时调用回调函数,回调函数输入具体插入口,回调函数需返回输出配置的指针 + // 1: 主动模式 放弃中断中插入检测,直接用函数和配置文件进行设置 + + uint8_t INTGPIOEnable : 1; + // 中断GPIO模式使能 + // 0: 中断GPIO启动 + // 1: 轮询I2C代替中断GPIO + + uint8_t intMode : 1; + // 中断模式选择 + // 0: 轮询模式 驱动程序自动加载中断轮询函数 + // 1: ESP32中断回调模式 需用户单独配置中断端口并中断后调用SW7203IntCallBack函数 + + uint8_t gpioInitMode : 1; + // gpio初始化模式选择,在使用轮询I2C后无效 + // 0: 驱动程序初始化时自动初始化中断gpio + // 1: 用户自己初始化中断gpio后初始化sw7203 + + uint8_t voltageConflictSwitch : 1; + // 电压冲突选择,在设置为主动模式后无效 + // 0: 当A1 A2 任何一个已经插入且插入第二个时回调得到第二个不同的电压值,立刻切换到这个电压并直接打开第二个口 + // 1: 当A1 A2 任何一个已经插入且插入第二个时回调得到第二个不同的电压值,立刻关闭这个口切换到第二个口且切换到现在输入的电压 + + uint8_t I2CBusBusyEnable : 1; + // I2C总线忙使能 + // 0: Mutex指针为I2C进程锁,为1时表示总线正忙 + // 1: 关闭总线防冲突功能 + + } SW7203_control_mode; + + uint16_t chargeVoltage_mV; // 充电目标电压设置 [3000,19200] 单位:毫伏(mV) + uint16_t trickleVoltage_mV; // 涓流电压设置 [2500,13200] 单位:毫伏(mV) + uint16_t chargeVBUSVoltageLimit_mV; // 防拉挂电压设置 [4000,20000] 单位:毫伏(mV) + uint16_t VSYSMinVoltage_mV; // VSYMIN 电压设置 [3000,16600] 单位:毫伏(mV) + uint16_t chargeVBUSCurrentLimit_mA; // 充电 VBUS 输入限流设置 [500,6850] 单位:毫安(mA) + uint16_t chargeVBATCurrentLimit_mA; // 充电 VBAT 输入限流设置 [100,12000] 单位:毫安(mA) + uint16_t chargeLDOCurrentLimit_mA; // LDO 充电电流设置 [100,2000] 单位:毫安(mA) + + union + { + uint8_t hex; // 8位无符号整数,用于将位域组合成一个字节方便程序读取 + + struct + { + uint8_t : 3; // 未定义的 bit 不能被改写 + + uint8_t shutdownLowPowerModeEnable : 1; + // 关机低功耗模式使能标志位: + // 0: 启用关机低功耗模式,1: 禁用关机低功耗模式 + + uint8_t : 2; // 未定义的 bit 不能被改写 + + uint8_t a1PortDetectEnable : 1; + // A1端口检测使能标志位: + // 0: 禁用A1端口检测,1: 启用A1端口检测 + + uint8_t a2PortDetectEnable : 1; + // A2端口检测使能标志位: + // 0: 禁用A2端口检测,1: 启用A2端口检测 + } config; + } connectDetect; // 负载接入检测及低功耗模式控制 + + union + { + uint8_t hex; // 8位无符号整数,用于将位域组合成一个字节方便程序读取 + + struct + { + uint8_t switchFrequency : 2; + // 开关频率选项: + // 0: 300KHz,1: 200KHz,2: 400KHz,3: 800KHz + + uint8_t forcePWMModeEnable : 1; + // 强制 PWM 模式使能: + // 0: 禁用,1: 启用 + + uint8_t : 2; // 未定义的 bit 不能被改写 + + uint8_t NTCProtectEnable : 1; + // NTC 过温保护使能 + // 0: 启用,1: 禁用 + + uint8_t PowerMOSMinConductTime : 1; + // 功率管最小导通时间设置: + // 0: 下管最小导通时间 112nS,上管最小导通时间 133nS + // 1: 下管最小导通时间 58nS,上管最小导通时间 81nS + + uint8_t VBUSVoltageRegulationMethod : 1; + // VBUS 输出调压方式选择: + // 0: I2C 调压,1: FB 调压 + } config; + } funcConfig1; + + union + { + uint8_t hex; // 8位无符号整数,用于将位域组合成一个字节方便程序读取 + + struct + { + uint8_t deadzoneM1OpenM2Closed : 2; + // M2 关 M1 开死区设置: + // 0: 60nS,1: 20nS,2: 40nS,3: 80nS + + uint8_t deadzoneM1ClosedM2Open : 2; + // M2 关 M1 开死区设置: + // 0: 60nS,1: 20nS,2: 40nS,3: 60nS + + uint8_t deadzoneM3ClosedM4Open : 2; + // M3 关 M4 开死区设置: + // 0: 60nS,1: 20nS,2: 40nS,3: 80nS + + uint8_t deadzoneM3OpenM4Closed : 2; + // M4 关 M3 开死区设置: + // 0: 60nS,1: 20nS,2: 40nS,3: 60nS + } config; + } funcConfig2; + + union + { + uint8_t hex; // 8位无符号整数,用于将位域组合成一个字节方便程序读取 + + struct + { + uint8_t M2MOSRdsOn : 2; + // M2 功率管内阻设置: + // 0: 2.5mR,1: 5mR,2: 7.5mR,3: 10mR + + uint8_t nductanceValue : 2; + // 电感感值设置: + // 0: 1uH,1: 2.2uH,2: 3.3uH,3: 4.7uH + + uint8_t : 4; // 未定义的 bit 不能被改写 + } config; + } funcConfig3; + + union + { + uint8_t hex; // 8位无符号整数,用于将位域组合成一个字节方便程序读取 + + struct + { + uint8_t ACOutRegResetControl : 1; + // 适配器移出是否清除充电开关控制位: + // 0: 清除,1: 不清除 + + uint8_t stopChargingOnFullEnable : 1; + // 充满停充使能: + // 0: 使能,1: 禁止 + + uint8_t : 2; // 未定义的 bit 不能被改写 + + uint8_t fullChargeCurrent : 2; + // 充满截止电流设置: + // 0: 100mA,1: 200mA, 3: 300mA,4: 400mA + + uint8_t batteryCellNum : 2; + // 电池节数设置: + // 0: 1节,1: 2节, 3: 3节,4: 4节 + } config; + } funcConfig4; + + union + { + uint8_t hex; // 8位无符号整数,用于将位域组合成一个字节方便程序读取 + + struct + { + uint8_t : 4; // 未定义的 bit 不能被改写 + + uint8_t chipOverTemp : 2; + // 芯片过温温度设置: + // 0: 120℃,1: 130℃, 3: 140℃,4: 150℃ + + uint8_t peakCurrentLimit : 2; + // 峰值限流设置,充放电共用此设置: + // 0: 12A,1: 14A, 3: 16A,4: 18A + } config; + } funcConfig5; + + union + { + uint8_t hex; // 8位无符号整数,用于将位域组合成一个字节方便程序读取 + + struct + { + uint8_t func62368Enable : 1; + // 62368 功能使能: + // 0: 使能,1: 禁止 + + uint8_t func62368IBUSLimitEnable : 1; + // 处于 62368 的高低温状态,降低 IBUS 限流功能使能: + // 0: 使能,1: 禁止 + + uint8_t : 1; // 未定义的 bit 不能被改写 + + uint8_t chargeOverTimeEnable : 1; + // 充电超时使能: + // 0: 使能,1: 禁止 + + uint8_t trickleChargeTimeout : 2; + // 涓流充电超时时间设置: + // 0: 30分钟,1: 1小时, 3: 2小时,4: 4小时 + + uint8_t constantCurrentChargeTimeout : 2; + // 恒流充电超时时间设置: + // 0: 12小时,1: 24小时, 3: 48小时,4: 72小时 + } config; + } funcConfig6; + + union + { + uint8_t hex; // 8位无符号整数,用于将位域组合成一个字节方便程序读取 + + struct + { + uint8_t func62368LowTempCurrentLimit : 2; + // 处于 62368 的低温状态,降低限流设置: + // 当 funcConfig6.func62368IBUSLimitEnable=0 时,同时降低 IBUS 和 IBAT 的限流值 + // funcConfig6.func62368IBUSLimitEnable=1 时,只降低 IBAT 的限流值 + // 0: 降低到设置值的 1/2,1: 降低到设置值的 1/4, 3: 不降低,4: 保留(不可选) + + uint8_t func62368HighTempCurrentLimit : 2; + // 处于 62368 的高温状态,降低限流设置: + // 当 funcConfig6.func62368IBUSLimitEnable=0 时,同时降低 IBUS 和 IBAT 的限流值 + // funcConfig6.func62368IBUSLimitEnable=1 时,只降低 IBAT 的限流值 + // 0: 降低到设置值的 1/2,1: 降低到设置值的 1/4, 3: 不降低,4: 保留(不可选) + + uint8_t func62368LowTempVoltageLimit : 1; + // 处于 62368 的低温状态,降低充电目标电压设置: + // 0: 充电目标电压降低电池节数设置值*0.1V,1: 不降低充电目标电压 + + uint8_t func62368HighTempVoltageLimit : 1; + // 处于 62368 的高温状态,降低充电目标电压设置: + // 0: 充电目标电压降低电池节数设置值*0.1V,1: 不降低充电目标电压 + + uint8_t func62368LowTempHysteresis : 1; + // 62368 低温迟滞: + // 0: 5℃,1: 10℃ + + uint8_t func62368HighTempHysteresis : 1; + // 62368 高温迟滞: + // 0: 5℃,1: 10℃ + } config; + } funcConfig7; + + union + { + uint8_t hex; // 8位无符号整数,用于将位域组合成一个字节方便程序读取 + + struct + { + uint8_t dischargeNTCHighLimit : 2; + // 放电 NTC 高温门限: + // 0: 50℃,1: 55℃,2: 60℃,3: 65℃ + + uint8_t dischargeNTCLowLimit : 2; + // 放电 NTC 低温门限: + // 0: -10℃,1: -5℃,2: 0℃,3: -20℃ + + uint8_t chargeNTCHighLimit : 2; + // 充电 NTC 高温门限: + // 0: 50℃,1: 55℃,2: 60℃,3: 65℃ + + uint8_t chargeNTCLowLimit : 2; + // 充电 NTC 低温门限: + // 0: -10℃,1: -5℃,2: 0℃,3: -20℃ + } config; + } NTCConfig; + + union + { + uint8_t hex; // 8位无符号整数,用于将位域组合成一个字节方便程序读取 + + struct + { + uint8_t : 1; // 未定义的 bit 不能被改写 + + uint8_t NVDCLearnModeEnable : 1; + // 学习模式使能: + // 适配器接入时,关闭充放电,NVDC 处于全打开状态 + // 0: 禁止,1: 使能 + + uint8_t : 4; // 未定义的 bit 不能被改写 + + uint8_t VSYSOverVoltage : 2; + // VSYS 过载门限: + // 电池节数为 2~4 节时 + // 0: 6V,1: 5.75V,2: 6.25V,3: 6.5V + // 电池节数为 1 节时 + // 0: 3.1V,1: 2.85V,2: 3.35V,3: 3.6V + } config; + } NVDCConfig1; + + union + { + uint8_t hex; // 8位无符号整数,用于将位域组合成一个字节方便程序读取 + + struct + { + uint8_t : 4; // 未定义的 bit 不能被改写 + + uint8_t trickleCurrent : 2; + // 涓流电流设置: + // 0: 100mA,1: 200mA,2: 300mA,3: 400mA + + uint8_t trickleCurrentHysteresis : 2; + // 涓流电压迟滞设置: + // 默认值根据 BSSET 电阻设置的电池节数,设置为电池节数*0.1V + // 0: 0.1V,1: 0.2V,2: 0.3V,3: 0.4V + } config; + } trickleConfig; // 涓流电流设置 +} sw7203_config_t; + +/** + * @brief SW7203 I2C 地址查询 + * + * @param handle i2c device handle + * @return + * - 一个8位二进制数: 查找到的地址,如果没有找到就返回-1 + */ +uint8_t sw7203_I2C_address_find(i2c_master_bus_handle_t I2C_bus_handle); + +/** + * @brief SW7203 驱动程序安装 + * + * @param[in] sw7203_config sw7203的配置文件 + * @param handle I2C_bus_handle I2C 总线的handle + * @param[in] I2C_address sw7203的I2C地址 + * + * @return + * - ESP_OK: 驱动程序安装正常. + * - ESP_ERR_NOT_ALLOWED: SW7203 I2C地址不存在. + */ +esp_err_t sw7203_driver_install(sw7203_config_t *sw7023_config, i2c_master_bus_handle_t I2C_bus_handle, uint8_t I2C_address); + +/** + * @brief SW7203 切换输出 + * + * @param[in] config sw7203的输出配置文件 + * + */ +void sw7203SwitchOutput(sw7203_Vout_config_t *config); + +/** + * @brief SW7203 开启输出 + * + */ +void sw7203OutputEnable(); + +/** + * @brief SW7203 关闭输出 + * + */ +void sw7203OutputDisable(); + +/** + * @brief SW7203 开启A1端口 + * + */ +void sw7203A1PortOpen(); + +/** + * @brief SW7203 开启A2端口 + * + */ +void sw7203A2PortOpen(); + +/** + * @brief SW7203 关闭A1端口 + * + */ +void sw7203A1PortClose(); + +/** + * @brief SW7203 关闭A2端口 + * + */ +void sw7203A2PortClose(); + +/** + * @brief SW7203 移除驱动程序 + * + * @param handle I2C_bus_handle I2C 总线的handle + * + * @return + * - ESP_OK: 驱动程序移除成功. + */ +esp_err_t sw7203_driver_uninstall(i2c_master_bus_handle_t I2C_bus_handle); + +const uint8_t SW7203RegAddress_bitmask[][2] = { + {0x18, 0b00010011}, + {0x1A, 0b00000011}, + {0x20, 0b11100111}, + {0x21, 0b11111111}, + {0x22, 0b11110000}, + {0x30, 0b11001111}, + {0x31, 0b00001111}, + {0x32, 0b11011111}, + {0x33, 0b11111111}, + {0x34, 0b11111111}, + {0x35, 0b00000111}, + {0x36, 0b01111111}, + {0x37, 0b00001111}, + {0x38, 0b11111111}, + {0x39, 0b01111111}, + {0x3A, 0b01111111}, + {0x40, 0b01000011}, + {0x41, 0b00011111}, + {0x42, 0b01111111}, + {0x43, 0b11111111}, + {0x23, 0b11111111}, + {0x24, 0b00000111}, + {0x25, 0b01111111}, + {0x26, 0b01111111}, + {0x27, 0b01111111}, + {0x28, 0b00011111}, + {0x02, 0b01111111}, + {0x03, 0b11111111}, +}; + +#endif \ No newline at end of file