2024-03-06 06:09:49 +08:00
// I2C设置
# define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
# define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
# define I2C0_NUM I2C_NUM_0
# define I2C0_SCL_IO 42
# define I2C0_SDA_IO 41
# define I2C0_FREQ_HZ 40000
# define I2C_MASTER_TIMEOUT_MS 14000
# define SW7203_ADDR 0x3C
# include <cstdlib>
# include <iostream>
# include <string>
# include "driver/i2c.h"
# include "freertos/FreeRTOS.h"
# include "freertos/task.h"
# include "driver/uart.h"
# include "driver/gpio.h"
# include "sdkconfig.h"
# include "esp_log.h"
# include "bq4050.h"
# include "driver/gpio.h"
# include <thread>
# define SetBitTrue(a, b) a |= (1 << b)
# define SetBitFalse(a, b) a &= ~(1 << b)
# define GetBit(a, b) a & (1 << b)
2024-03-06 09:32:15 +08:00
static esp_err_t i2c0_master_init ( )
2024-03-06 06:09:49 +08:00
{
i2c_config_t conf = {
. mode = I2C_MODE_MASTER ,
2024-03-06 09:32:15 +08:00
. sda_io_num = I2C0_SDA_IO ,
. scl_io_num = I2C0_SCL_IO ,
2024-03-06 06:09:49 +08:00
. sda_pullup_en = GPIO_PULLUP_ENABLE ,
. scl_pullup_en = GPIO_PULLUP_ENABLE ,
. master {
2024-03-06 09:32:15 +08:00
. clk_speed = I2C_MASTER_TIMEOUT_MS } ,
2024-03-06 06:09:49 +08:00
} ;
2024-03-06 09:32:15 +08:00
i2c_param_config ( I2C0_NUM , & conf ) ;
return i2c_driver_install ( I2C0_NUM , conf . mode , I2C_MASTER_RX_BUF_DISABLE , I2C_MASTER_TX_BUF_DISABLE , 0 ) ;
2024-03-06 06:09:49 +08:00
}
esp_err_t sw7203_register_read ( uint8_t reg_addr , uint8_t * data )
{
return i2c_master_write_read_device ( SW7203_I2C_MASTER_NUM , SW7203_ADDR , & reg_addr , 1 , data , 1 , SW7203_I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS ) ;
}
esp_err_t sw7203_register_write ( uint8_t * data )
{
return i2c_master_write_to_device ( SW7203_I2C_MASTER_NUM , SW7203_ADDR , data , 2 , SW7203_I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS ) ;
}
void sw7203_check_error ( esp_err_t errcode )
{
if ( errcode ! = ESP_OK )
{
ESP_LOGI ( TAG , " SW7203 I2C error \n :) " ) ;
ESP_ERROR_CHECK_WITHOUT_ABORT ( err_code ) ;
while ( 1 )
{
ErrLED . set_high ( ) ;
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
ErrLED . set_low ( ) ;
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
}
}
}
# ifndef __SW7203_DEBUG__
void sw7203_start_charge ( )
{
unsigned int VBUS_Voltage = 0 ;
uint8_t data = 0 ;
sw7203_check_error ( sw7203_register_read ( 0x11 , & data ) ) ;
VBUS_Voltage = data ;
VBUS_Voltage = VBUS_Voltage < < 4 ;
sw7203_check_error ( sw7203_register_read ( 0x12 , & data ) ) ;
VBUS_Voltage & = ( data & 0 b00001111 ) ;
VBUS_Voltage * = 75 ;
VBUS_Voltage - = 7500 ;
VBUS_Voltage = ( VBUS_Voltage - 40000 ) / 1000 ;
uint8_t VBUS_BitMask = 0 b01111111 , VBUS_Limit = VBUS_Voltage ;
uint8_t cmd [ 3 ] [ 2 ] = { { 0x38 , uint8_t ( VBUS_Limit & VBUS_BitMask ) } , { 0x19 , 0 b00000100 } , { 0x0D , 0 b00010000 } } ;
sw7203_register_write ( cmd [ 0 ] ) ;
sw7203_register_write ( cmd [ 1 ] ) ;
sw7203_register_write ( cmd [ 2 ] ) ;
}
void sw7203_stop_charge ( )
{
uint8_t cmd [ 2 ] [ 2 ] = { { 0x04 , 0 b00000100 } , { 0x19 , 0 b00000000 } } ;
sw7203_register_write ( cmd [ 0 ] ) ;
sw7203_register_write ( cmd [ 1 ] ) ;
}
void sw7203_irq_func ( void * arg )
{
while ( 1 )
{
if ( gpio_get_level ( GPIO_NUM_47 ) = = 1 )
{
ESP_LOGI ( TAG , " SW 7203 INT ARG " ) ;
uint8_t data = 0 ;
sw7203_check_error ( sw7203_register_read ( 0x04 , & data ) ) ;
if ( data & 0x40 )
{
ESP_LOGI ( TAG , " VSYS voltage limit exceeded " ) ;
}
if ( data & 0x20 )
{
ESP_LOGI ( TAG , " Battery charge time limit exceeded " ) ;
}
if ( data & 0x10 )
{
ESP_LOGI ( TAG , " Battery fullcharged " ) ;
}
if ( data & 0x08 )
{
ESP_LOGI ( TAG , " DCIN moved in " ) ;
AC_IN = true ;
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
sw7203_start_charge ( ) ;
}
if ( data & 0x04 )
{
ESP_LOGI ( TAG , " DCIN moved out " ) ;
AC_IN = false ;
sw7203_stop_charge ( ) ;
}
sw7203_check_error ( sw7203_register_read ( 0x05 , & data ) ) ;
if ( data & 0x80 )
{
ESP_LOGI ( TAG , " SW7203 over temperature " ) ;
}
if ( data & 0x10 )
{
ESP_LOGI ( TAG , " VBAT voltage limit exceeded " ) ;
}
if ( data & 0x08 )
{
ESP_LOGI ( TAG , " VBAT voltage limit subceeded " ) ;
}
if ( data & 0x01 )
{
ESP_LOGI ( TAG , " VBUS power limit exceeded " ) ;
}
sw7203_check_error ( sw7203_register_read ( 0x06 , & data ) ) ;
if ( data & 0x02 )
{
NVDC_BAT_charge = true ;
}
else
{
NVDC_BAT_charge = false ;
}
uint8_t cmd [ 2 ] [ 2 ] = { { 0x04 , 0 b11111111 } , { 0x05 , 0 b11111111 } } ;
sw7203_register_write ( cmd [ 0 ] ) ;
sw7203_register_write ( cmd [ 1 ] ) ;
}
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
}
}
# endif
extern " C " void app_main ( )
{
ErrLED . set_high ( ) ;
# ifdef __USB_HID_ENABLE__
ESP_LOGI ( TAG , " USB initialization " ) ;
const tinyusb_config_t tusb_cfg = {
. device_descriptor = & descriptor_config ,
. string_descriptor = string_descriptor ,
. string_descriptor_count = sizeof ( string_descriptor ) / sizeof ( string_descriptor [ 0 ] ) ,
. external_phy = false ,
. configuration_descriptor = desc_configuration ,
. self_powered = false ,
} ;
if ( ( err_code = tinyusb_driver_install ( & tusb_cfg ) ) ! = ESP_OK )
{
ESP_LOGI ( TAG , " TinyUSB driver error \n :) " ) ;
ESP_ERROR_CHECK_WITHOUT_ABORT ( err_code ) ;
while ( 1 )
{
ErrLED . set_high ( ) ;
vTaskDelay ( 1000 / portTICK_PERIOD_MS ) ;
ErrLED . set_low ( ) ;
vTaskDelay ( 1000 / portTICK_PERIOD_MS ) ;
}
}
ESP_LOGI ( TAG , " USB initialization DONE " ) ;
# endif
uint8_t sw7203_config_data [ ] [ 2 ] = {
{ 0x02 , 0 b00000011 } ,
// 中断使能1 0使能 1禁止 7:NULL 6:VSYS过压中断 5:充电超时中断 4:充电充满中断
// 3: 适配器插入中断 2:适配器移出中断 1:A2负载接入中断 0:A1负载接入中断
{ 0x03 , 0 b01000110 } ,
// {0x04, 0b11111111},
// {0x05, 0b11111111},
{ 0x0D , 0 b00000000 } ,
{ 0x0F , 0 b00000001 } ,
{ 0x10 , 0 b01000001 } ,
{ 0x18 , 0 b00000011 } ,
{ 0x19 , 0 b00000000 } ,
{ 0x20 , 0 b10000100 } ,
{ 0x21 , 0 b11111111 } ,
{ 0x22 , 0 b10100000 } ,
{ 0x26 , 0 b01011001 } ,
{ 0x27 , 0 b01010101 } ,
{ 0x28 , 0 b00000100 } ,
{ 0x30 , 0 b00000011 } ,
{ 0x31 , 0 b00000000 } ,
{ 0x32 , 0 b11010000 } ,
{ 0x34 , 0 b10101010 } ,
{ 0x35 , 0 b00000000 } ,
{ 0x36 , 0 b01011111 } ,
{ 0x37 , 0 b00001111 } ,
{ 0x38 , 0 b00000100 } ,
{ 0x39 , 0 b01111111 } ,
{ 0x3A , 0 b00010011 } ,
# ifdef __SW7203_DEBUG__
{ 0x40 , 0 b01000011 } ,
# else
{ 0x40 , 0 b00000011 } ,
# endif
{ 0x41 , 0 b00000100 } ,
{ 0x42 , 0 b00100101 } } ;
if ( ( err_code = bq4050_i2c_master_init ( ) ) ! = ESP_OK )
{
ESP_LOGI ( TAG , " BQ4050 driver error \n :) " ) ;
ESP_ERROR_CHECK_WITHOUT_ABORT ( err_code ) ;
while ( 1 )
{
ErrLED . set_high ( ) ;
vTaskDelay ( 1000 / portTICK_PERIOD_MS ) ;
ErrLED . set_low ( ) ;
vTaskDelay ( 1000 / portTICK_PERIOD_MS ) ;
}
}
BatteryVoltage = bq_GetVoltage ( ) ;
BatteryCurrentCapacity = bq_GetRSOC ( ) ;
BatteryRunTimeToEmpty = bq_GetT2E ( ) ;
BatteryRunTimeToFull = bq_GetT2F ( ) ;
ESP_LOGI ( TAG , " BQ4050 initialization DONE! \n :) " ) ;
if ( ( err_code = sw7203_i2c_master_init ( ) ) ! = ESP_OK )
{
ESP_LOGI ( TAG , " SW7203 driver error \n :) " ) ;
ESP_ERROR_CHECK_WITHOUT_ABORT ( err_code ) ;
while ( 1 )
{
ErrLED . set_high ( ) ;
vTaskDelay ( 1000 / portTICK_PERIOD_MS ) ;
ErrLED . set_low ( ) ;
vTaskDelay ( 1000 / portTICK_PERIOD_MS ) ;
}
}
for ( int i = 0 ; i < 27 ; i + + )
{
if ( ( err_code = sw7203_register_write ( sw7203_config_data [ i ] ) ) ! = ESP_OK )
{
ESP_LOGI ( TAG , " SW7203 I2C error \n :) " ) ;
ESP_ERROR_CHECK_WITHOUT_ABORT ( err_code ) ;
while ( 1 )
{
ErrLED . set_high ( ) ;
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
ErrLED . set_low ( ) ;
vTaskDelay ( 100 / portTICK_PERIOD_MS ) ;
}
}
}
ESP_LOGI ( TAG , " SW7203 initialization DONE! \n :) " ) ;
# ifndef __SW7203_DEBUG__
gpio_config_t SW7203_IRQ_gpio_config = {
. pin_bit_mask = 1ull < < 47 ,
. mode = GPIO_MODE_INPUT ,
. pull_up_en = GPIO_PULLUP_ENABLE ,
. pull_down_en = GPIO_PULLDOWN_DISABLE ,
} ;
gpio_config ( & SW7203_IRQ_gpio_config ) ;
xTaskCreate ( sw7203_irq_func , " SW7203IRQ " , 10240 , NULL , 20 , NULL ) ;
ESP_LOGI ( TAG , " SW7203 intrupt initialization DONE! \n :) " ) ;
# endif
ESP_LOGI ( TAG , " initialization DONE! \n :) " ) ;
ErrLED . set_low ( ) ;
while ( 1 )
{
BatteryCurrentCapacity = bq_GetRSOC ( ) ;
BatteryRunTimeToEmpty = bq_GetT2E ( ) ;
BatteryCurrentStatus = bq_BattState_u16 ( AC_IN , NVDC_BAT_charge ) ;
# ifdef __USB_HID_ENABLE__
if ( ( BatteryCurrentCapacity ! = BatteryPrevCapacity ) | | ( BatteryCurrentStatus ! = BatteryPrevStatus ) )
{
tud_hid_report ( HID_PD_REMAININGCAPACITY , & BatteryCurrentCapacity , sizeof ( BatteryCurrentCapacity ) ) ;
tud_hid_report ( HID_PD_PRESENTSTATUS , & BatteryCurrentStatus , sizeof ( BatteryCurrentStatus ) ) ;
if ( BatteryCurrentStatus & ( 1 < < PRESENTSTATUS_DISCHARGING ) )
tud_hid_report ( HID_PD_RUNTIMETOEMPTY , & BatteryRunTimeToEmpty , sizeof ( BatteryRunTimeToEmpty ) ) ;
BatteryPrevCapacity = BatteryCurrentCapacity ;
BatteryPrevStatus = BatteryCurrentStatus ;
}
# endif
if ( BatteryCurrentCapacity < 10 )
PowerlossLED . set_high ( ) ;
else
PowerlossLED . set_low ( ) ;
if ( BatteryCurrentStatus & ( 1 < < PRESENTSTATUS_CHARGING ) )
ChargingLED . set_high ( ) ;
else
ChargingLED . set_low ( ) ;
ESP_LOGI ( TAG , " Battery Current Capacity :%d \n Battery Current Status :%d \n Battery RunTime To Empty :%d \n " , BatteryCurrentCapacity , BatteryCurrentStatus , BatteryRunTimeToEmpty ) ;
vTaskDelay ( 2000 / portTICK_PERIOD_MS ) ;
}
}
# ifdef __USB_HID_ENABLE__
uint16_t tud_hid_get_report_cb ( uint8_t instance , uint8_t report_id , hid_report_type_t report_type , uint8_t * buffer , uint16_t reqlen )
{
switch ( int ( report_type ) )
{
case HID_REPORT_TYPE_FEATURE :
{
switch ( report_id )
{
case HID_PD_PRESENTSTATUS :
{
# ifdef __SK_BQ4050_HID__
BatteryCurrentStatus = bq_BattState_u16 ( AC_IN , NVDC_BAT_charge ) ;
buffer [ 0 ] = BatteryCurrentStatus & 0x00ff ;
buffer [ 1 ] = BatteryCurrentStatus > > 8 & 0x00ff ;
return 2 ;
# else
buffer [ 0 ] = BatteryCurrentStatus & 0x00ff ;
buffer [ 1 ] = BatteryCurrentStatus > > 8 & 0x00ff ;
return 2 ;
# endif
}
case HID_PD_VOLTAGE :
{
# ifdef __SK_BQ4050_HID__
BatteryVoltage = bq_GetVoltage ( ) ;
buffer [ 0 ] = BatteryVoltage & 0x00ff ;
buffer [ 1 ] = BatteryVoltage > > 8 & 0x00ff ;
return 2 ;
# else
buffer [ 0 ] = BatteryVoltage & 0x00ff ;
buffer [ 1 ] = BatteryVoltage > > 8 & 0x00ff ;
return 2 ;
# endif
}
case HID_PD_DESIGNCAPACITY :
{
buffer [ 0 ] = BatteryDesignCapacity ;
return 1 ;
}
case HID_PD_IDEVICECHEMISTRY :
{
buffer [ 0 ] = BatteryDeviceChemistry ;
return 1 ;
}
case HID_PD_SERIAL :
{
buffer [ 0 ] = 3 ;
return 1 ;
}
case HID_PD_IOEMINFORMATION :
{
buffer [ 0 ] = BatteryOEMVendor ;
return 1 ;
}
case HID_PD_IPRODUCT :
{
buffer [ 0 ] = IPRODUCT ;
return 1 ;
}
case HID_PD_MANUFACTURER :
{
buffer [ 0 ] = IMANUFACTURER ;
return 1 ;
}
case HID_PD_MANUFACTUREDATE :
{
buffer [ 0 ] = ManufactureDate & 0x00ff ;
buffer [ 1 ] = ManufactureDate > > 8 & 0x00ff ;
return 2 ;
}
case HID_PD_FULLCHRGECAPACITY :
{
buffer [ 0 ] = BatteryFullChargeCapacity ;
return 1 ;
}
case HID_PD_WARNCAPACITYLIMIT :
{
buffer [ 0 ] = BatteryWarnCapacityLimit ;
return 1 ;
}
case HID_PD_REMNCAPACITYLIMIT :
{
buffer [ 0 ] = BatteryRemnCapacityLimit ;
return 1 ;
}
case HID_PD_REMAININGCAPACITY :
{
BatteryCurrentCapacity = bq_GetRSOC ( ) ;
buffer [ 0 ] = BatteryCurrentCapacity ;
return 1 ;
}
case HID_PD_RUNTIMETOEMPTY :
{
BatteryRunTimeToEmpty = bq_GetT2E ( ) ;
buffer [ 0 ] = BatteryRunTimeToEmpty & 0x00ff ;
buffer [ 1 ] = BatteryRunTimeToEmpty > > 8 & 0x00ff ;
return 2 ;
}
case HID_PD_CPCTYGRANULARITY1 :
{
buffer [ 0 ] = BatteryCapacityGranularity1 ;
return 1 ;
}
case HID_PD_CPCTYGRANULARITY2 :
{
buffer [ 0 ] = BatteryCapacityGranularity2 ;
return 1 ;
}
case HID_PD_CAPACITYMODE :
{
buffer [ 0 ] = BatteryCapacityMode ;
return 1 ;
}
}
}
}
ESP_LOGI ( TAG , " Get_report Request: %d, type=%s , id: %d , len:%d \n " ,
instance ,
( report_type = = HID_REPORT_TYPE_INVALID ? " HID_REPORT_TYPE_INVALID " : ( report_type = = HID_REPORT_TYPE_INPUT ? " HID_REPORT_TYPE_INPUT " : ( report_type = = HID_REPORT_TYPE_OUTPUT ? " HID_REPORT_TYPE_OUTPUT " : " HID_REPORT_TYPE_FEATURE " ) ) ) ,
report_id ,
reqlen ) ;
for ( int i = 0 ; i < reqlen ; i + + )
{
ESP_LOGI ( TAG , " Report %d:%d \n " , i , buffer [ - i ] ) ;
}
ESP_LOGI ( TAG , " end REQUSET \n " ) ;
return 0 ;
}
uint8_t const * tud_hid_descriptor_report_cb ( uint8_t instance )
{
// We use only one interface and one HID report descriptor, so we can ignore parameter 'instance'
return ESP32UPS : : desc_hid_report ;
}
void tud_hid_set_report_cb ( uint8_t instance , uint8_t report_id , hid_report_type_t report_type , uint8_t const * buffer , uint16_t bufsize )
{
// ESP_LOGI(TAG, "Get_report Request: %d, type=%s , id: %d , len:%d\n",
// instance,
// (report_type == HID_REPORT_TYPE_INVALID ? "HID_REPORT_TYPE_INVALID" : (report_type == HID_REPORT_TYPE_INPUT ? "HID_REPORT_TYPE_INPUT" : (report_type == HID_REPORT_TYPE_OUTPUT ? "HID_REPORT_TYPE_OUTPUT" : "HID_REPORT_TYPE_FEATURE"))),
// report_id,
// bufsize);
// for (int i = 0; i < bufsize; i++)
// {
// ESP_LOGI(TAG, "Report %d:%d\n", i, buffer[i]);
// }
// ESP_LOGI(TAG, "end REQUSET\n");
}
# endif