diff --git a/.vscode/settings.json b/.vscode/settings.json index 957b308..4353d23 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -89,7 +89,8 @@ "sw7203.h": "c", "i2c.h": "c", "ios": "c", - "xiosbase": "c" + "xiosbase": "c", + "gpio.h": "c" }, "cmake.configureOnOpen": false } \ No newline at end of file diff --git a/include/sw7203/sw7203.c b/include/sw7203/sw7203.c index 24b3a45..eb7905e 100644 --- a/include/sw7203/sw7203.c +++ b/include/sw7203/sw7203.c @@ -1,10 +1,47 @@ #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; @@ -74,33 +111,93 @@ esp_err_t sw7203_reg_read(uint8_t reg_addr, uint8_t *data) vTaskDelay(50 / portTICK_PERIOD_MS); } SW7203_Mutex = 1; - errcode = i2c_master_transmit(SW7203_I2C_handle, data, 2, -1); + errcode = i2c_master_transmit_receive(SW7203_I2C_handle, reg_addr, 1, data, 1, -1); *SW7203_Mutex = 0; } else - errcode = i2c_master_transmit(SW7203_I2C_handle, data, 2, -1); + 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 == -1) + 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)); - if (sw7203_config->SW7203_control_mode.I2CBusBusyEnable == 0) - { - SW7203_Mutex = sw7203_config->Mutex; - __sw7203_driver_config__.I2CBusBusyEnable = 1; - } - else - __sw7203_driver_config__.I2CBusBusyEnable = 0; + 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 @@ -112,6 +209,10 @@ esp_err_t sw7203_driver_install(sw7203_config_t *sw7203_config, i2c_master_bus_h 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; @@ -211,6 +312,11 @@ esp_err_t sw7203_driver_install(sw7203_config_t *sw7203_config, i2c_master_bus_h } 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; } @@ -218,7 +324,7 @@ void sw7203SwitchOutput(sw7203_Vout_config_t *config) { uint8_t data_up, data_lb; int tmp; - if (config->VBUSVoltage_mV < 3000) + if ((__sw7203_current_output_voltage__ = config->VBUSVoltage_mV) < 3000) { data_up = 0; data_lb = 0; @@ -292,5 +398,154 @@ void sw7203SwitchOutput(sw7203_Vout_config_t *config) 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/include/sw7203/sw7203.h b/include/sw7203/sw7203.h index e2c8993..7dae485 100644 --- a/include/sw7203/sw7203.h +++ b/include/sw7203/sw7203.h @@ -4,35 +4,36 @@ #include "driver/i2c_master.h" #include "esp_log.h" -typedef sw7203_Vout_config_t *(*SW7203CallBack_t)(sw7203_I2C_port); +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; -int8_t *SW7203_Mutex = NULL; -static SW7203CallBack_t *__SW7203CallBack_; +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; - // 控制模式选择 - // 0: 被动模式 采取回调函数的方式进行运作,当检测到输入插入时调用回调函数,回调函数输入具体插入口,回调函数需返回输出配置的指针 - // 1: 主动模式 放弃中断中插入检测,直接用函数和配置文件进行设置 uint8_t INTGPIOEnable : 1; - // 中断GPIO模式使能 - // 0: 中断GPIO启动 - // 1: 轮询I2C代替中断GPIO - - uint8_t intMode : 1; - // 中断模式选择,在使用轮询I2C后无效 - // 0: 轮询模式 驱动程序自动加载中断轮询函数 - // 1: ESP32中断回调模式 需用户单独配置中断端口并中断后调用 函数 uint8_t voltageConflictSwitch : 1; - // 电压冲突选择,在设置为主动模式后无效 - // 0: 当A1 A2 任何一个已经插入且插入第二个时回调得到第二个不同的电压值,立刻切换到这个电压 - // 1: 当A1 A2 任何一个已经插入且插入第二个时回调得到第二个不同的电压值,等待第一个插入的拔出后再输出第二个电压 uint8_t I2CBusBusyEnable : 1; + uint8_t porta1enable : 1; + + uint8_t porta2enable : 1; + } __sw7203_driver_config__; typedef union @@ -54,12 +55,6 @@ typedef enum sw7203_I2c_0x18 = 3 } sw7203_I2C_address_t; -typedef enum -{ - sw7203_port_A1, - sw7203_port_A2 -} sw7203_I2C_port; - typedef struct { uint16_t VBUSVoltage_mV; // 放电 VBUS 输出电压设置 [3000,22000] 单位:毫伏(mV) @@ -76,7 +71,7 @@ typedef struct sw7203_I2C_address_t i2cAddress; void *Mutex; - SW7203CallBack_t CallBack; + SW7203OutputConfigCallBack_t CallBack; struct { @@ -91,9 +86,9 @@ typedef struct // 1: 轮询I2C代替中断GPIO uint8_t intMode : 1; - // 中断模式选择,在使用轮询I2C后无效 + // 中断模式选择 // 0: 轮询模式 驱动程序自动加载中断轮询函数 - // 1: ESP32中断回调模式 需用户单独配置中断端口并中断后调用 函数 + // 1: ESP32中断回调模式 需用户单独配置中断端口并中断后调用SW7203IntCallBack函数 uint8_t gpioInitMode : 1; // gpio初始化模式选择,在使用轮询I2C后无效 @@ -102,8 +97,8 @@ typedef struct uint8_t voltageConflictSwitch : 1; // 电压冲突选择,在设置为主动模式后无效 - // 0: 当A1 A2 任何一个已经插入且插入第二个时回调得到第二个不同的电压值,立刻切换到这个电压 - // 1: 当A1 A2 任何一个已经插入且插入第二个时回调得到第二个不同的电压值,等待第一个插入的拔出后再输出第二个电压 + // 0: 当A1 A2 任何一个已经插入且插入第二个时回调得到第二个不同的电压值,立刻切换到这个电压并直接打开第二个口 + // 1: 当A1 A2 任何一个已经插入且插入第二个时回调得到第二个不同的电压值,立刻关闭这个口切换到第二个口且切换到现在输入的电压 uint8_t I2CBusBusyEnable : 1; // I2C总线忙使能 @@ -425,6 +420,42 @@ esp_err_t sw7203_driver_install(sw7203_config_t *sw7023_config, i2c_master_bus_h */ 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 移除驱动程序 * @@ -462,6 +493,8 @@ const uint8_t SW7203RegAddress_bitmask[][2] = { {0x26, 0b01111111}, {0x27, 0b01111111}, {0x28, 0b00011111}, + {0x02, 0b01111111}, + {0x03, 0b11111111}, }; #endif \ No newline at end of file