#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); }