[FL-3051] Gauge initialization routine refactoring, new DataMemory layout, configuration update (#2887)
* FuriHal: refactor power gauge config * Format sources and move gauge DM load to separate method * FuriHal: bq27220 refactoring part 1 * Power: use SYSDWN battery status flag for system shutdown * Libs: bq27220 read DM before write, fix incorrect shift * FuriHal: cleanup gauge config, add flags, add ptr DM type, update symbols * FuriHal: 2 stage gauge DM verification and update, better detection routine * FuriHal: update gauge configuration, lower sleep current and deadband * FuriHal: gauge and charger health reporting * Lib: cleanup bq27220 sources * FuriHal: correct documentation for furi_hal_power_is_shutdown_requested * FuriHal: proper gauge config for f7
This commit is contained in:
		
							parent
							
								
									309f65e401
								
							
						
					
					
						commit
						76e97b8d35
					
				@ -117,6 +117,7 @@ static bool power_update_info(Power* power) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    info.is_charging = furi_hal_power_is_charging();
 | 
					    info.is_charging = furi_hal_power_is_charging();
 | 
				
			||||||
    info.gauge_is_ok = furi_hal_power_gauge_is_ok();
 | 
					    info.gauge_is_ok = furi_hal_power_gauge_is_ok();
 | 
				
			||||||
 | 
					    info.is_shutdown_requested = furi_hal_power_is_shutdown_requested();
 | 
				
			||||||
    info.charge = furi_hal_power_get_pct();
 | 
					    info.charge = furi_hal_power_get_pct();
 | 
				
			||||||
    info.health = furi_hal_power_get_bat_health_pct();
 | 
					    info.health = furi_hal_power_get_bat_health_pct();
 | 
				
			||||||
    info.capacity_remaining = furi_hal_power_get_battery_remaining_capacity();
 | 
					    info.capacity_remaining = furi_hal_power_get_battery_remaining_capacity();
 | 
				
			||||||
@ -145,7 +146,7 @@ static void power_check_low_battery(Power* power) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Check battery charge and vbus voltage
 | 
					    // Check battery charge and vbus voltage
 | 
				
			||||||
    if((power->info.charge == 0) && (power->info.voltage_vbus < 4.0f) &&
 | 
					    if((power->info.is_shutdown_requested) && (power->info.voltage_vbus < 4.0f) &&
 | 
				
			||||||
       power->show_low_bat_level_message) {
 | 
					       power->show_low_bat_level_message) {
 | 
				
			||||||
        if(!power->battery_low) {
 | 
					        if(!power->battery_low) {
 | 
				
			||||||
            view_dispatcher_send_to_front(power->view_dispatcher);
 | 
					            view_dispatcher_send_to_front(power->view_dispatcher);
 | 
				
			||||||
 | 
				
			|||||||
@ -37,6 +37,7 @@ typedef struct {
 | 
				
			|||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    bool gauge_is_ok;
 | 
					    bool gauge_is_ok;
 | 
				
			||||||
    bool is_charging;
 | 
					    bool is_charging;
 | 
				
			||||||
 | 
					    bool is_shutdown_requested;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    float current_charger;
 | 
					    float current_charger;
 | 
				
			||||||
    float current_gauge;
 | 
					    float current_gauge;
 | 
				
			||||||
 | 
				
			|||||||
@ -54,8 +54,7 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) {
 | 
				
			|||||||
            (uint32_t)(data->vbus_voltage * 10) % 10,
 | 
					            (uint32_t)(data->vbus_voltage * 10) % 10,
 | 
				
			||||||
            current);
 | 
					            current);
 | 
				
			||||||
    } else if(current < -5) {
 | 
					    } else if(current < -5) {
 | 
				
			||||||
        // Often gauge reports anything in the range 1~5ma as 5ma
 | 
					        // 0-5ma deadband
 | 
				
			||||||
        // That brings confusion, so we'll treat it as Napping
 | 
					 | 
				
			||||||
        snprintf(
 | 
					        snprintf(
 | 
				
			||||||
            emote,
 | 
					            emote,
 | 
				
			||||||
            sizeof(emote),
 | 
					            sizeof(emote),
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
entry,status,name,type,params
 | 
					entry,status,name,type,params
 | 
				
			||||||
Version,+,34.2,,
 | 
					Version,+,34.3,,
 | 
				
			||||||
Header,+,applications/services/bt/bt_service/bt.h,,
 | 
					Header,+,applications/services/bt/bt_service/bt.h,,
 | 
				
			||||||
Header,+,applications/services/cli/cli.h,,
 | 
					Header,+,applications/services/cli/cli.h,,
 | 
				
			||||||
Header,+,applications/services/cli/cli_vcp.h,,
 | 
					Header,+,applications/services/cli/cli_vcp.h,,
 | 
				
			||||||
@ -36,7 +36,6 @@ Header,+,applications/services/notification/notification_messages.h,,
 | 
				
			|||||||
Header,+,applications/services/power/power_service/power.h,,
 | 
					Header,+,applications/services/power/power_service/power.h,,
 | 
				
			||||||
Header,+,applications/services/rpc/rpc_app.h,,
 | 
					Header,+,applications/services/rpc/rpc_app.h,,
 | 
				
			||||||
Header,+,applications/services/storage/storage.h,,
 | 
					Header,+,applications/services/storage/storage.h,,
 | 
				
			||||||
Header,-,firmware/targets/f18/furi_hal/furi_hal_power_calibration.h,,
 | 
					 | 
				
			||||||
Header,+,firmware/targets/f18/furi_hal/furi_hal_resources.h,,
 | 
					Header,+,firmware/targets/f18/furi_hal/furi_hal_resources.h,,
 | 
				
			||||||
Header,+,firmware/targets/f18/furi_hal/furi_hal_spi_config.h,,
 | 
					Header,+,firmware/targets/f18/furi_hal/furi_hal_spi_config.h,,
 | 
				
			||||||
Header,+,firmware/targets/f18/furi_hal/furi_hal_target_hw.h,,
 | 
					Header,+,firmware/targets/f18/furi_hal/furi_hal_target_hw.h,,
 | 
				
			||||||
@ -1149,6 +1148,7 @@ Function,-,furi_hal_power_insomnia_level,uint16_t,
 | 
				
			|||||||
Function,+,furi_hal_power_is_charging,_Bool,
 | 
					Function,+,furi_hal_power_is_charging,_Bool,
 | 
				
			||||||
Function,+,furi_hal_power_is_charging_done,_Bool,
 | 
					Function,+,furi_hal_power_is_charging_done,_Bool,
 | 
				
			||||||
Function,+,furi_hal_power_is_otg_enabled,_Bool,
 | 
					Function,+,furi_hal_power_is_otg_enabled,_Bool,
 | 
				
			||||||
 | 
					Function,+,furi_hal_power_is_shutdown_requested,_Bool,
 | 
				
			||||||
Function,+,furi_hal_power_off,void,
 | 
					Function,+,furi_hal_power_off,void,
 | 
				
			||||||
Function,+,furi_hal_power_reset,void,
 | 
					Function,+,furi_hal_power_reset,void,
 | 
				
			||||||
Function,+,furi_hal_power_set_battery_charge_voltage_limit,void,float
 | 
					Function,+,furi_hal_power_set_battery_charge_voltage_limit,void,float
 | 
				
			||||||
 | 
				
			|||||||
		
		
			
  | 
@ -1,37 +0,0 @@
 | 
				
			|||||||
const ParamCEDV cedv = {
 | 
					 | 
				
			||||||
    .cedv_conf.gauge_conf =
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            .CCT = 1,
 | 
					 | 
				
			||||||
            .CSYNC = 0,
 | 
					 | 
				
			||||||
            .EDV_CMP = 0,
 | 
					 | 
				
			||||||
            .SC = 1,
 | 
					 | 
				
			||||||
            .FIXED_EDV0 = 1,
 | 
					 | 
				
			||||||
            .FCC_LIM = 1,
 | 
					 | 
				
			||||||
            .FC_FOR_VDQ = 1,
 | 
					 | 
				
			||||||
            .IGNORE_SD = 1,
 | 
					 | 
				
			||||||
            .SME0 = 0,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    .full_charge_cap = 1300,
 | 
					 | 
				
			||||||
    .design_cap = 1300,
 | 
					 | 
				
			||||||
    .EDV0 = 3300,
 | 
					 | 
				
			||||||
    .EDV1 = 3321,
 | 
					 | 
				
			||||||
    .EDV2 = 3355,
 | 
					 | 
				
			||||||
    .EMF = 3679,
 | 
					 | 
				
			||||||
    .C0 = 430,
 | 
					 | 
				
			||||||
    .C1 = 0,
 | 
					 | 
				
			||||||
    .R1 = 408,
 | 
					 | 
				
			||||||
    .R0 = 334,
 | 
					 | 
				
			||||||
    .T0 = 4626,
 | 
					 | 
				
			||||||
    .TC = 11,
 | 
					 | 
				
			||||||
    .DOD0 = 4044,
 | 
					 | 
				
			||||||
    .DOD10 = 3905,
 | 
					 | 
				
			||||||
    .DOD20 = 3807,
 | 
					 | 
				
			||||||
    .DOD30 = 3718,
 | 
					 | 
				
			||||||
    .DOD40 = 3642,
 | 
					 | 
				
			||||||
    .DOD50 = 3585,
 | 
					 | 
				
			||||||
    .DOD60 = 3546,
 | 
					 | 
				
			||||||
    .DOD70 = 3514,
 | 
					 | 
				
			||||||
    .DOD80 = 3477,
 | 
					 | 
				
			||||||
    .DOD90 = 3411,
 | 
					 | 
				
			||||||
    .DOD100 = 3299,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
							
								
								
									
										149
									
								
								firmware/targets/f18/furi_hal/furi_hal_power_config.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								firmware/targets/f18/furi_hal/furi_hal_power_config.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,149 @@
 | 
				
			|||||||
 | 
					#include <bq27220_data_memory.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const BQ27220DMGaugingConfig furi_hal_power_gauge_data_memory_gauging_config = {
 | 
				
			||||||
 | 
					    .CCT = 1,
 | 
				
			||||||
 | 
					    .CSYNC = 0,
 | 
				
			||||||
 | 
					    .EDV_CMP = 0,
 | 
				
			||||||
 | 
					    .SC = 1,
 | 
				
			||||||
 | 
					    .FIXED_EDV0 = 1,
 | 
				
			||||||
 | 
					    .FCC_LIM = 1,
 | 
				
			||||||
 | 
					    .FC_FOR_VDQ = 1,
 | 
				
			||||||
 | 
					    .IGNORE_SD = 1,
 | 
				
			||||||
 | 
					    .SME0 = 0,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const BQ27220DMData furi_hal_power_gauge_data_memory[] = {
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1GaugingConfig,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypePtr16,
 | 
				
			||||||
 | 
					        .value.u32 = (uint32_t)&furi_hal_power_gauge_data_memory_gauging_config,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1FullChargeCapacity,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 1300,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1DesignCapacity,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 1300,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1EMF,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3679,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1C0,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 430,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1R0,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 334,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1T0,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 4626,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1R1,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 408,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1TC,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU8,
 | 
				
			||||||
 | 
					        .value.u8 = 11,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1C1,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU8,
 | 
				
			||||||
 | 
					        .value.u8 = 0,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD0,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 4044,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD10,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3905,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD20,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3807,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD30,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3718,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD40,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3642,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD50,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3585,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD60,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3546,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD70,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3514,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD80,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3477,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD90,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3411,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD100,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3299,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1EDV0,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3300,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1EDV1,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3321,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1EDV2,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3355,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressCalibrationCurrentDeadband,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU8,
 | 
				
			||||||
 | 
					        .value.u8 = 1,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressConfigurationPowerSleepCurrent,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeI16,
 | 
				
			||||||
 | 
					        .value.i16 = 1,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeEnd,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
entry,status,name,type,params
 | 
					entry,status,name,type,params
 | 
				
			||||||
Version,+,34.2,,
 | 
					Version,+,34.3,,
 | 
				
			||||||
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
 | 
					Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
 | 
				
			||||||
Header,+,applications/services/bt/bt_service/bt.h,,
 | 
					Header,+,applications/services/bt/bt_service/bt.h,,
 | 
				
			||||||
Header,+,applications/services/cli/cli.h,,
 | 
					Header,+,applications/services/cli/cli.h,,
 | 
				
			||||||
@ -50,7 +50,6 @@ Header,+,firmware/targets/f7/furi_hal/furi_hal_idle_timer.h,,
 | 
				
			|||||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_interrupt.h,,
 | 
					Header,+,firmware/targets/f7/furi_hal/furi_hal_interrupt.h,,
 | 
				
			||||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_nfc.h,,
 | 
					Header,+,firmware/targets/f7/furi_hal/furi_hal_nfc.h,,
 | 
				
			||||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_os.h,,
 | 
					Header,+,firmware/targets/f7/furi_hal/furi_hal_os.h,,
 | 
				
			||||||
Header,-,firmware/targets/f7/furi_hal/furi_hal_power_calibration.h,,
 | 
					 | 
				
			||||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_pwm.h,,
 | 
					Header,+,firmware/targets/f7/furi_hal/furi_hal_pwm.h,,
 | 
				
			||||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_resources.h,,
 | 
					Header,+,firmware/targets/f7/furi_hal/furi_hal_resources.h,,
 | 
				
			||||||
Header,+,firmware/targets/f7/furi_hal/furi_hal_rfid.h,,
 | 
					Header,+,firmware/targets/f7/furi_hal/furi_hal_rfid.h,,
 | 
				
			||||||
@ -1270,6 +1269,7 @@ Function,-,furi_hal_power_insomnia_level,uint16_t,
 | 
				
			|||||||
Function,+,furi_hal_power_is_charging,_Bool,
 | 
					Function,+,furi_hal_power_is_charging,_Bool,
 | 
				
			||||||
Function,+,furi_hal_power_is_charging_done,_Bool,
 | 
					Function,+,furi_hal_power_is_charging_done,_Bool,
 | 
				
			||||||
Function,+,furi_hal_power_is_otg_enabled,_Bool,
 | 
					Function,+,furi_hal_power_is_otg_enabled,_Bool,
 | 
				
			||||||
 | 
					Function,+,furi_hal_power_is_shutdown_requested,_Bool,
 | 
				
			||||||
Function,+,furi_hal_power_off,void,
 | 
					Function,+,furi_hal_power_off,void,
 | 
				
			||||||
Function,+,furi_hal_power_reset,void,
 | 
					Function,+,furi_hal_power_reset,void,
 | 
				
			||||||
Function,+,furi_hal_power_set_battery_charge_voltage_limit,void,float
 | 
					Function,+,furi_hal_power_set_battery_charge_voltage_limit,void,float
 | 
				
			||||||
 | 
				
			|||||||
		
		
			
  | 
@ -15,6 +15,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <hw_conf.h>
 | 
					#include <hw_conf.h>
 | 
				
			||||||
#include <bq27220.h>
 | 
					#include <bq27220.h>
 | 
				
			||||||
 | 
					#include <bq27220_data_memory.h>
 | 
				
			||||||
#include <bq25896.h>
 | 
					#include <bq25896.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <furi.h>
 | 
					#include <furi.h>
 | 
				
			||||||
@ -37,16 +38,18 @@ typedef struct {
 | 
				
			|||||||
    volatile uint8_t insomnia;
 | 
					    volatile uint8_t insomnia;
 | 
				
			||||||
    volatile uint8_t suppress_charge;
 | 
					    volatile uint8_t suppress_charge;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t gauge_initialized;
 | 
					    bool gauge_ok;
 | 
				
			||||||
    uint8_t charger_initialized;
 | 
					    bool charger_ok;
 | 
				
			||||||
} FuriHalPower;
 | 
					} FuriHalPower;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static volatile FuriHalPower furi_hal_power = {
 | 
					static volatile FuriHalPower furi_hal_power = {
 | 
				
			||||||
    .insomnia = 0,
 | 
					    .insomnia = 0,
 | 
				
			||||||
    .suppress_charge = 0,
 | 
					    .suppress_charge = 0,
 | 
				
			||||||
 | 
					    .gauge_ok = false,
 | 
				
			||||||
 | 
					    .charger_ok = false,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <furi_hal_power_calibration.h>
 | 
					extern const BQ27220DMData furi_hal_power_gauge_data_memory[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void furi_hal_power_init() {
 | 
					void furi_hal_power_init() {
 | 
				
			||||||
#ifdef FURI_HAL_POWER_DEBUG
 | 
					#ifdef FURI_HAL_POWER_DEBUG
 | 
				
			||||||
@ -63,8 +66,13 @@ void furi_hal_power_init() {
 | 
				
			|||||||
    LL_C2_PWR_SetPowerMode(FURI_HAL_POWER_STOP_MODE);
 | 
					    LL_C2_PWR_SetPowerMode(FURI_HAL_POWER_STOP_MODE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
 | 
					    furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
 | 
				
			||||||
    bq27220_init(&furi_hal_i2c_handle_power, &cedv);
 | 
					    // Find and init gauge
 | 
				
			||||||
    bq25896_init(&furi_hal_i2c_handle_power);
 | 
					    if(bq27220_init(&furi_hal_i2c_handle_power)) {
 | 
				
			||||||
 | 
					        furi_hal_power.gauge_ok = bq27220_apply_data_memory(
 | 
				
			||||||
 | 
					            &furi_hal_i2c_handle_power, furi_hal_power_gauge_data_memory);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // Find and init charger
 | 
				
			||||||
 | 
					    furi_hal_power.charger_ok = bq25896_init(&furi_hal_i2c_handle_power);
 | 
				
			||||||
    furi_hal_i2c_release(&furi_hal_i2c_handle_power);
 | 
					    furi_hal_i2c_release(&furi_hal_i2c_handle_power);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    FURI_LOG_I(TAG, "Init OK");
 | 
					    FURI_LOG_I(TAG, "Init OK");
 | 
				
			||||||
@ -78,14 +86,29 @@ bool furi_hal_power_gauge_is_ok() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
 | 
					    furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(bq27220_get_battery_status(&furi_hal_i2c_handle_power, &battery_status) == BQ27220_ERROR ||
 | 
					    if(!bq27220_get_battery_status(&furi_hal_i2c_handle_power, &battery_status) ||
 | 
				
			||||||
       bq27220_get_operation_status(&furi_hal_i2c_handle_power, &operation_status) ==
 | 
					       !bq27220_get_operation_status(&furi_hal_i2c_handle_power, &operation_status)) {
 | 
				
			||||||
           BQ27220_ERROR) {
 | 
					 | 
				
			||||||
        ret = false;
 | 
					        ret = false;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        ret &= battery_status.BATTPRES;
 | 
					        ret &= battery_status.BATTPRES;
 | 
				
			||||||
        ret &= operation_status.INITCOMP;
 | 
					        ret &= operation_status.INITCOMP;
 | 
				
			||||||
        ret &= (cedv.design_cap == bq27220_get_design_capacity(&furi_hal_i2c_handle_power));
 | 
					        ret &= furi_hal_power.gauge_ok;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    furi_hal_i2c_release(&furi_hal_i2c_handle_power);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool furi_hal_power_is_shutdown_requested() {
 | 
				
			||||||
 | 
					    bool ret = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    BatteryStatus battery_status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(bq27220_get_battery_status(&furi_hal_i2c_handle_power, &battery_status) != BQ27220_ERROR) {
 | 
				
			||||||
 | 
					        ret = battery_status.SYSDWN;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    furi_hal_i2c_release(&furi_hal_i2c_handle_power);
 | 
					    furi_hal_i2c_release(&furi_hal_i2c_handle_power);
 | 
				
			||||||
@ -576,9 +599,8 @@ void furi_hal_power_debug_get(PropertyValueCallback out, void* context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const uint32_t ntc_mpct = bq25896_get_ntc_mpct(&furi_hal_i2c_handle_power);
 | 
					    const uint32_t ntc_mpct = bq25896_get_ntc_mpct(&furi_hal_i2c_handle_power);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(bq27220_get_battery_status(&furi_hal_i2c_handle_power, &battery_status) != BQ27220_ERROR &&
 | 
					    if(bq27220_get_battery_status(&furi_hal_i2c_handle_power, &battery_status) &&
 | 
				
			||||||
       bq27220_get_operation_status(&furi_hal_i2c_handle_power, &operation_status) !=
 | 
					       bq27220_get_operation_status(&furi_hal_i2c_handle_power, &operation_status)) {
 | 
				
			||||||
           BQ27220_ERROR) {
 | 
					 | 
				
			||||||
        property_value_out(&property_context, "%lu", 2, "charger", "ntc", ntc_mpct);
 | 
					        property_value_out(&property_context, "%lu", 2, "charger", "ntc", ntc_mpct);
 | 
				
			||||||
        property_value_out(&property_context, "%d", 2, "gauge", "calmd", operation_status.CALMD);
 | 
					        property_value_out(&property_context, "%d", 2, "gauge", "calmd", operation_status.CALMD);
 | 
				
			||||||
        property_value_out(&property_context, "%d", 2, "gauge", "sec", operation_status.SEC);
 | 
					        property_value_out(&property_context, "%d", 2, "gauge", "sec", operation_status.SEC);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,37 +0,0 @@
 | 
				
			|||||||
const ParamCEDV cedv = {
 | 
					 | 
				
			||||||
    .cedv_conf.gauge_conf =
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            .CCT = 1,
 | 
					 | 
				
			||||||
            .CSYNC = 0,
 | 
					 | 
				
			||||||
            .EDV_CMP = 0,
 | 
					 | 
				
			||||||
            .SC = 1,
 | 
					 | 
				
			||||||
            .FIXED_EDV0 = 1,
 | 
					 | 
				
			||||||
            .FCC_LIM = 1,
 | 
					 | 
				
			||||||
            .FC_FOR_VDQ = 1,
 | 
					 | 
				
			||||||
            .IGNORE_SD = 1,
 | 
					 | 
				
			||||||
            .SME0 = 0,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    .full_charge_cap = 2101,
 | 
					 | 
				
			||||||
    .design_cap = 2101,
 | 
					 | 
				
			||||||
    .EDV0 = 3300,
 | 
					 | 
				
			||||||
    .EDV1 = 3321,
 | 
					 | 
				
			||||||
    .EDV2 = 3355,
 | 
					 | 
				
			||||||
    .EMF = 3679,
 | 
					 | 
				
			||||||
    .C0 = 430,
 | 
					 | 
				
			||||||
    .C1 = 0,
 | 
					 | 
				
			||||||
    .R1 = 408,
 | 
					 | 
				
			||||||
    .R0 = 334,
 | 
					 | 
				
			||||||
    .T0 = 4626,
 | 
					 | 
				
			||||||
    .TC = 11,
 | 
					 | 
				
			||||||
    .DOD0 = 4044,
 | 
					 | 
				
			||||||
    .DOD10 = 3905,
 | 
					 | 
				
			||||||
    .DOD20 = 3807,
 | 
					 | 
				
			||||||
    .DOD30 = 3718,
 | 
					 | 
				
			||||||
    .DOD40 = 3642,
 | 
					 | 
				
			||||||
    .DOD50 = 3585,
 | 
					 | 
				
			||||||
    .DOD60 = 3546,
 | 
					 | 
				
			||||||
    .DOD70 = 3514,
 | 
					 | 
				
			||||||
    .DOD80 = 3477,
 | 
					 | 
				
			||||||
    .DOD90 = 3411,
 | 
					 | 
				
			||||||
    .DOD100 = 3299,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
							
								
								
									
										149
									
								
								firmware/targets/f7/furi_hal/furi_hal_power_config.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								firmware/targets/f7/furi_hal/furi_hal_power_config.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,149 @@
 | 
				
			|||||||
 | 
					#include <bq27220_data_memory.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const BQ27220DMGaugingConfig furi_hal_power_gauge_data_memory_gauging_config = {
 | 
				
			||||||
 | 
					    .CCT = 1,
 | 
				
			||||||
 | 
					    .CSYNC = 0,
 | 
				
			||||||
 | 
					    .EDV_CMP = 0,
 | 
				
			||||||
 | 
					    .SC = 1,
 | 
				
			||||||
 | 
					    .FIXED_EDV0 = 1,
 | 
				
			||||||
 | 
					    .FCC_LIM = 1,
 | 
				
			||||||
 | 
					    .FC_FOR_VDQ = 1,
 | 
				
			||||||
 | 
					    .IGNORE_SD = 1,
 | 
				
			||||||
 | 
					    .SME0 = 0,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const BQ27220DMData furi_hal_power_gauge_data_memory[] = {
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1GaugingConfig,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypePtr16,
 | 
				
			||||||
 | 
					        .value.u32 = (uint32_t)&furi_hal_power_gauge_data_memory_gauging_config,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1FullChargeCapacity,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 2100,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1DesignCapacity,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 2100,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1EMF,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3679,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1C0,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 430,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1R0,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 334,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1T0,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 4626,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1R1,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 408,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1TC,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU8,
 | 
				
			||||||
 | 
					        .value.u8 = 11,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1C1,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU8,
 | 
				
			||||||
 | 
					        .value.u8 = 0,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD0,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 4044,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD10,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3905,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD20,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3807,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD30,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3718,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD40,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3642,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD50,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3585,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD60,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3546,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD70,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3514,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD80,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3477,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD90,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3411,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1StartDOD100,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3299,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1EDV0,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3300,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1EDV1,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3321,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressGasGaugingCEDVProfile1EDV2,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					        .value.u16 = 3355,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressCalibrationCurrentDeadband,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeU8,
 | 
				
			||||||
 | 
					        .value.u8 = 1,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .address = BQ27220DMAddressConfigurationPowerSleepCurrent,
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeI16,
 | 
				
			||||||
 | 
					        .value.i16 = 1,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        .type = BQ27220DMTypeEnd,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -34,6 +34,12 @@ void furi_hal_power_init();
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
bool furi_hal_power_gauge_is_ok();
 | 
					bool furi_hal_power_gauge_is_ok();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Check if gauge requests system shutdown
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @return true if system shutdown requested
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool furi_hal_power_is_shutdown_requested();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Get current insomnia level
 | 
					/** Get current insomnia level
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @return     insomnia level: 0 - no insomnia, >0 - insomnia, bearer count.
 | 
					 * @return     insomnia level: 0 - no insomnia, >0 - insomnia, bearer count.
 | 
				
			||||||
 | 
				
			|||||||
@ -35,13 +35,15 @@ typedef struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static bq25896_regs_t bq25896_regs;
 | 
					static bq25896_regs_t bq25896_regs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void bq25896_init(FuriHalI2cBusHandle* handle) {
 | 
					bool bq25896_init(FuriHalI2cBusHandle* handle) {
 | 
				
			||||||
 | 
					    bool result = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bq25896_regs.r14.REG_RST = 1;
 | 
					    bq25896_regs.r14.REG_RST = 1;
 | 
				
			||||||
    furi_hal_i2c_write_reg_8(
 | 
					    result &= furi_hal_i2c_write_reg_8(
 | 
				
			||||||
        handle, BQ25896_ADDRESS, 0x14, *(uint8_t*)&bq25896_regs.r14, BQ25896_I2C_TIMEOUT);
 | 
					        handle, BQ25896_ADDRESS, 0x14, *(uint8_t*)&bq25896_regs.r14, BQ25896_I2C_TIMEOUT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Readout all registers
 | 
					    // Readout all registers
 | 
				
			||||||
    furi_hal_i2c_read_mem(
 | 
					    result &= furi_hal_i2c_read_mem(
 | 
				
			||||||
        handle,
 | 
					        handle,
 | 
				
			||||||
        BQ25896_ADDRESS,
 | 
					        BQ25896_ADDRESS,
 | 
				
			||||||
        0x00,
 | 
					        0x00,
 | 
				
			||||||
@ -52,26 +54,28 @@ void bq25896_init(FuriHalI2cBusHandle* handle) {
 | 
				
			|||||||
    // Poll ADC forever
 | 
					    // Poll ADC forever
 | 
				
			||||||
    bq25896_regs.r02.CONV_START = 1;
 | 
					    bq25896_regs.r02.CONV_START = 1;
 | 
				
			||||||
    bq25896_regs.r02.CONV_RATE = 1;
 | 
					    bq25896_regs.r02.CONV_RATE = 1;
 | 
				
			||||||
    furi_hal_i2c_write_reg_8(
 | 
					    result &= furi_hal_i2c_write_reg_8(
 | 
				
			||||||
        handle, BQ25896_ADDRESS, 0x02, *(uint8_t*)&bq25896_regs.r02, BQ25896_I2C_TIMEOUT);
 | 
					        handle, BQ25896_ADDRESS, 0x02, *(uint8_t*)&bq25896_regs.r02, BQ25896_I2C_TIMEOUT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bq25896_regs.r07.WATCHDOG = WatchdogDisable;
 | 
					    bq25896_regs.r07.WATCHDOG = WatchdogDisable;
 | 
				
			||||||
    furi_hal_i2c_write_reg_8(
 | 
					    result &= furi_hal_i2c_write_reg_8(
 | 
				
			||||||
        handle, BQ25896_ADDRESS, 0x07, *(uint8_t*)&bq25896_regs.r07, BQ25896_I2C_TIMEOUT);
 | 
					        handle, BQ25896_ADDRESS, 0x07, *(uint8_t*)&bq25896_regs.r07, BQ25896_I2C_TIMEOUT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // OTG power configuration
 | 
					    // OTG power configuration
 | 
				
			||||||
    bq25896_regs.r0A.BOOSTV = 0x8; // BOOST Voltage: 5.062V
 | 
					    bq25896_regs.r0A.BOOSTV = 0x8; // BOOST Voltage: 5.062V
 | 
				
			||||||
    bq25896_regs.r0A.BOOST_LIM = BoostLim_1400; // BOOST Current limit: 1.4A
 | 
					    bq25896_regs.r0A.BOOST_LIM = BoostLim_1400; // BOOST Current limit: 1.4A
 | 
				
			||||||
    furi_hal_i2c_write_reg_8(
 | 
					    result &= furi_hal_i2c_write_reg_8(
 | 
				
			||||||
        handle, BQ25896_ADDRESS, 0x0A, *(uint8_t*)&bq25896_regs.r0A, BQ25896_I2C_TIMEOUT);
 | 
					        handle, BQ25896_ADDRESS, 0x0A, *(uint8_t*)&bq25896_regs.r0A, BQ25896_I2C_TIMEOUT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    furi_hal_i2c_read_mem(
 | 
					    result &= furi_hal_i2c_read_mem(
 | 
				
			||||||
        handle,
 | 
					        handle,
 | 
				
			||||||
        BQ25896_ADDRESS,
 | 
					        BQ25896_ADDRESS,
 | 
				
			||||||
        0x00,
 | 
					        0x00,
 | 
				
			||||||
        (uint8_t*)&bq25896_regs,
 | 
					        (uint8_t*)&bq25896_regs,
 | 
				
			||||||
        sizeof(bq25896_regs),
 | 
					        sizeof(bq25896_regs),
 | 
				
			||||||
        BQ25896_I2C_TIMEOUT);
 | 
					        BQ25896_I2C_TIMEOUT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void bq25896_set_boost_lim(FuriHalI2cBusHandle* handle, BoostLim boost_lim) {
 | 
					void bq25896_set_boost_lim(FuriHalI2cBusHandle* handle, BoostLim boost_lim) {
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,7 @@
 | 
				
			|||||||
#include <furi_hal_i2c.h>
 | 
					#include <furi_hal_i2c.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Initialize Driver */
 | 
					/** Initialize Driver */
 | 
				
			||||||
void bq25896_init(FuriHalI2cBusHandle* handle);
 | 
					bool bq25896_init(FuriHalI2cBusHandle* handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Set boost lim*/
 | 
					/** Set boost lim*/
 | 
				
			||||||
void bq25896_set_boost_lim(FuriHalI2cBusHandle* handle, BoostLim boost_lim);
 | 
					void bq25896_set_boost_lim(FuriHalI2cBusHandle* handle, BoostLim boost_lim);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,12 +1,16 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "bq27220.h"
 | 
					#include "bq27220.h"
 | 
				
			||||||
#include "bq27220_reg.h"
 | 
					#include "bq27220_reg.h"
 | 
				
			||||||
 | 
					#include "bq27220_data_memory.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_Static_assert(sizeof(BQ27220DMGaugingConfig) == 2, "Incorrect structure size");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <furi.h>
 | 
					#include <furi.h>
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TAG "Gauge"
 | 
					#define TAG "Gauge"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint16_t bq27220_read_word(FuriHalI2cBusHandle* handle, uint8_t address) {
 | 
					static uint16_t bq27220_read_word(FuriHalI2cBusHandle* handle, uint8_t address) {
 | 
				
			||||||
    uint16_t buf = 0;
 | 
					    uint16_t buf = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    furi_hal_i2c_read_mem(
 | 
					    furi_hal_i2c_read_mem(
 | 
				
			||||||
@ -15,14 +19,14 @@ uint16_t bq27220_read_word(FuriHalI2cBusHandle* handle, uint8_t address) {
 | 
				
			|||||||
    return buf;
 | 
					    return buf;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool bq27220_control(FuriHalI2cBusHandle* handle, uint16_t control) {
 | 
					static bool bq27220_control(FuriHalI2cBusHandle* handle, uint16_t control) {
 | 
				
			||||||
    bool ret = furi_hal_i2c_write_mem(
 | 
					    bool ret = furi_hal_i2c_write_mem(
 | 
				
			||||||
        handle, BQ27220_ADDRESS, CommandControl, (uint8_t*)&control, 2, BQ27220_I2C_TIMEOUT);
 | 
					        handle, BQ27220_ADDRESS, CommandControl, (uint8_t*)&control, 2, BQ27220_I2C_TIMEOUT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint8_t bq27220_get_checksum(uint8_t* data, uint16_t len) {
 | 
					static uint8_t bq27220_get_checksum(uint8_t* data, uint16_t len) {
 | 
				
			||||||
    uint8_t ret = 0;
 | 
					    uint8_t ret = 0;
 | 
				
			||||||
    for(uint16_t i = 0; i < len; i++) {
 | 
					    for(uint16_t i = 0; i < len; i++) {
 | 
				
			||||||
        ret += data[i];
 | 
					        ret += data[i];
 | 
				
			||||||
@ -30,80 +34,181 @@ uint8_t bq27220_get_checksum(uint8_t* data, uint16_t len) {
 | 
				
			|||||||
    return 0xFF - ret;
 | 
					    return 0xFF - ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool bq27220_set_parameter_u16(FuriHalI2cBusHandle* handle, uint16_t address, uint16_t value) {
 | 
					static bool bq27220_parameter_check(
 | 
				
			||||||
    bool ret;
 | 
					    FuriHalI2cBusHandle* handle,
 | 
				
			||||||
    uint8_t buffer[4];
 | 
					    uint16_t address,
 | 
				
			||||||
 | 
					    uint32_t value,
 | 
				
			||||||
 | 
					    size_t size,
 | 
				
			||||||
 | 
					    bool update) {
 | 
				
			||||||
 | 
					    furi_assert(size == 1 || size == 2 || size == 4);
 | 
				
			||||||
 | 
					    bool ret = false;
 | 
				
			||||||
 | 
					    uint8_t buffer[6] = {0};
 | 
				
			||||||
 | 
					    uint8_t old_data[4] = {0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    buffer[0] = address & 0xFF;
 | 
					    do {
 | 
				
			||||||
    buffer[1] = (address >> 8) & 0xFF;
 | 
					        buffer[0] = address & 0xFF;
 | 
				
			||||||
    buffer[2] = (value >> 8) & 0xFF;
 | 
					        buffer[1] = (address >> 8) & 0xFF;
 | 
				
			||||||
    buffer[3] = value & 0xFF;
 | 
					 | 
				
			||||||
    ret = furi_hal_i2c_write_mem(
 | 
					 | 
				
			||||||
        handle, BQ27220_ADDRESS, CommandSelectSubclass, buffer, 4, BQ27220_I2C_TIMEOUT);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    furi_delay_us(10000);
 | 
					        for(size_t i = 0; i < size; i++) {
 | 
				
			||||||
 | 
					            buffer[1 + size - i] = (value >> (i * 8)) & 0xFF;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t checksum = bq27220_get_checksum(buffer, 4);
 | 
					        if(update) {
 | 
				
			||||||
    buffer[0] = checksum;
 | 
					            if(!furi_hal_i2c_write_mem(
 | 
				
			||||||
    buffer[1] = 6;
 | 
					                   handle,
 | 
				
			||||||
    ret &= furi_hal_i2c_write_mem(
 | 
					                   BQ27220_ADDRESS,
 | 
				
			||||||
        handle, BQ27220_ADDRESS, CommandMACDataSum, buffer, 2, BQ27220_I2C_TIMEOUT);
 | 
					                   CommandSelectSubclass,
 | 
				
			||||||
 | 
					                   buffer,
 | 
				
			||||||
 | 
					                   size + 2,
 | 
				
			||||||
 | 
					                   BQ27220_I2C_TIMEOUT)) {
 | 
				
			||||||
 | 
					                FURI_LOG_I(TAG, "DM write failed");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            furi_delay_us(10000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            uint8_t checksum = bq27220_get_checksum(buffer, size + 2);
 | 
				
			||||||
 | 
					            buffer[0] = checksum;
 | 
				
			||||||
 | 
					            buffer[1] = 4 + size; // TODO: why 4?
 | 
				
			||||||
 | 
					            if(!furi_hal_i2c_write_mem(
 | 
				
			||||||
 | 
					                   handle, BQ27220_ADDRESS, CommandMACDataSum, buffer, 2, BQ27220_I2C_TIMEOUT)) {
 | 
				
			||||||
 | 
					                FURI_LOG_I(TAG, "CRC write failed");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            furi_delay_us(10000);
 | 
				
			||||||
 | 
					            ret = true;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            if(!furi_hal_i2c_write_mem(
 | 
				
			||||||
 | 
					                   handle, BQ27220_ADDRESS, CommandSelectSubclass, buffer, 2, BQ27220_I2C_TIMEOUT)) {
 | 
				
			||||||
 | 
					                FURI_LOG_I(TAG, "DM SelectSubclass for read failed");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(!furi_hal_i2c_rx(handle, BQ27220_ADDRESS, old_data, size, BQ27220_I2C_TIMEOUT)) {
 | 
				
			||||||
 | 
					                FURI_LOG_I(TAG, "DM read failed");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(*(uint32_t*)&(old_data[0]) != *(uint32_t*)&(buffer[2])) {
 | 
				
			||||||
 | 
					                FURI_LOG_W( //-V641
 | 
				
			||||||
 | 
					                    TAG,
 | 
				
			||||||
 | 
					                    "Data at 0x%04x(%zu): 0x%08lx!=0x%08lx",
 | 
				
			||||||
 | 
					                    address,
 | 
				
			||||||
 | 
					                    size,
 | 
				
			||||||
 | 
					                    *(uint32_t*)&(old_data[0]),
 | 
				
			||||||
 | 
					                    *(uint32_t*)&(buffer[2]));
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                ret = true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } while(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    furi_delay_us(10000);
 | 
					 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool bq27220_init(FuriHalI2cBusHandle* handle, const ParamCEDV* cedv) {
 | 
					static bool bq27220_data_memory_check(
 | 
				
			||||||
    uint32_t timeout = 100;
 | 
					    FuriHalI2cBusHandle* handle,
 | 
				
			||||||
    uint16_t design_cap = bq27220_get_design_capacity(handle);
 | 
					    const BQ27220DMData* data_memory,
 | 
				
			||||||
    if(cedv->design_cap == design_cap) {
 | 
					    bool update) {
 | 
				
			||||||
        FURI_LOG_I(TAG, "Skip battery profile update");
 | 
					    if(update) {
 | 
				
			||||||
        return true;
 | 
					        if(!bq27220_control(handle, Control_ENTER_CFG_UPDATE)) {
 | 
				
			||||||
 | 
					            FURI_LOG_E(TAG, "ENTER_CFG_UPDATE command failed");
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Wait for enter CFG update mode
 | 
				
			||||||
 | 
					        uint32_t timeout = 100;
 | 
				
			||||||
 | 
					        OperationStatus status = {0};
 | 
				
			||||||
 | 
					        while((status.CFGUPDATE != true) && (timeout-- > 0)) {
 | 
				
			||||||
 | 
					            bq27220_get_operation_status(handle, &status);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(timeout == 0) {
 | 
				
			||||||
 | 
					            FURI_LOG_E(TAG, "CFGUPDATE mode failed");
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    FURI_LOG_I(TAG, "Start updating battery profile");
 | 
					
 | 
				
			||||||
    OperationStatus status = {0};
 | 
					    // Process data memory records
 | 
				
			||||||
    if(!bq27220_control(handle, Control_ENTER_CFG_UPDATE)) {
 | 
					    bool result = true;
 | 
				
			||||||
        FURI_LOG_E(TAG, "Can't configure update");
 | 
					    while(data_memory->type != BQ27220DMTypeEnd) {
 | 
				
			||||||
 | 
					        if(data_memory->type == BQ27220DMTypeWait) {
 | 
				
			||||||
 | 
					            furi_delay_us(data_memory->value.u32);
 | 
				
			||||||
 | 
					        } else if(data_memory->type == BQ27220DMTypeU8) {
 | 
				
			||||||
 | 
					            result &= bq27220_parameter_check(
 | 
				
			||||||
 | 
					                handle, data_memory->address, data_memory->value.u8, 1, update);
 | 
				
			||||||
 | 
					        } else if(data_memory->type == BQ27220DMTypeU16) {
 | 
				
			||||||
 | 
					            result &= bq27220_parameter_check(
 | 
				
			||||||
 | 
					                handle, data_memory->address, data_memory->value.u16, 2, update);
 | 
				
			||||||
 | 
					        } else if(data_memory->type == BQ27220DMTypeU32) {
 | 
				
			||||||
 | 
					            result &= bq27220_parameter_check(
 | 
				
			||||||
 | 
					                handle, data_memory->address, data_memory->value.u32, 4, update);
 | 
				
			||||||
 | 
					        } else if(data_memory->type == BQ27220DMTypeI8) {
 | 
				
			||||||
 | 
					            result &= bq27220_parameter_check(
 | 
				
			||||||
 | 
					                handle, data_memory->address, data_memory->value.i8, 1, update);
 | 
				
			||||||
 | 
					        } else if(data_memory->type == BQ27220DMTypeI16) {
 | 
				
			||||||
 | 
					            result &= bq27220_parameter_check(
 | 
				
			||||||
 | 
					                handle, data_memory->address, data_memory->value.i16, 2, update);
 | 
				
			||||||
 | 
					        } else if(data_memory->type == BQ27220DMTypeI32) {
 | 
				
			||||||
 | 
					            result &= bq27220_parameter_check(
 | 
				
			||||||
 | 
					                handle, data_memory->address, data_memory->value.i32, 4, update);
 | 
				
			||||||
 | 
					        } else if(data_memory->type == BQ27220DMTypeF32) {
 | 
				
			||||||
 | 
					            result &= bq27220_parameter_check(
 | 
				
			||||||
 | 
					                handle, data_memory->address, data_memory->value.u32, 4, update);
 | 
				
			||||||
 | 
					        } else if(data_memory->type == BQ27220DMTypePtr8) {
 | 
				
			||||||
 | 
					            result &= bq27220_parameter_check(
 | 
				
			||||||
 | 
					                handle, data_memory->address, *(uint8_t*)data_memory->value.u32, 1, update);
 | 
				
			||||||
 | 
					        } else if(data_memory->type == BQ27220DMTypePtr16) {
 | 
				
			||||||
 | 
					            result &= bq27220_parameter_check(
 | 
				
			||||||
 | 
					                handle, data_memory->address, *(uint16_t*)data_memory->value.u32, 2, update);
 | 
				
			||||||
 | 
					        } else if(data_memory->type == BQ27220DMTypePtr32) {
 | 
				
			||||||
 | 
					            result &= bq27220_parameter_check(
 | 
				
			||||||
 | 
					                handle, data_memory->address, *(uint32_t*)data_memory->value.u32, 4, update);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            furi_crash("Invalid DM Type");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        data_memory++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Finalize configuration update
 | 
				
			||||||
 | 
					    if(update) {
 | 
				
			||||||
 | 
					        bq27220_control(handle, Control_EXIT_CFG_UPDATE_REINIT);
 | 
				
			||||||
 | 
					        furi_delay_us(10000);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool bq27220_init(FuriHalI2cBusHandle* handle) {
 | 
				
			||||||
 | 
					    // Request device number(chip PN)
 | 
				
			||||||
 | 
					    if(!bq27220_control(handle, Control_DEVICE_NUMBER)) {
 | 
				
			||||||
 | 
					        FURI_LOG_E(TAG, "Device is not present");
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    // Check control response
 | 
				
			||||||
 | 
					    uint16_t data = 0;
 | 
				
			||||||
 | 
					    data = bq27220_read_word(handle, CommandControl);
 | 
				
			||||||
 | 
					    if(data != 0xFF00) {
 | 
				
			||||||
 | 
					        FURI_LOG_E(TAG, "Invalid control response: %x", data);
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while((status.CFGUPDATE != true) && (timeout-- > 0)) {
 | 
					    data = bq27220_read_word(handle, CommandMACData);
 | 
				
			||||||
        bq27220_get_operation_status(handle, &status);
 | 
					    FURI_LOG_I(TAG, "Device Number %04x", data);
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    bq27220_set_parameter_u16(handle, AddressGaugingConfig, cedv->cedv_conf.gauge_conf_raw);
 | 
					 | 
				
			||||||
    bq27220_set_parameter_u16(handle, AddressFullChargeCapacity, cedv->full_charge_cap);
 | 
					 | 
				
			||||||
    bq27220_set_parameter_u16(handle, AddressDesignCapacity, cedv->design_cap);
 | 
					 | 
				
			||||||
    bq27220_set_parameter_u16(handle, AddressEMF, cedv->EMF);
 | 
					 | 
				
			||||||
    bq27220_set_parameter_u16(handle, AddressC0, cedv->C0);
 | 
					 | 
				
			||||||
    bq27220_set_parameter_u16(handle, AddressR0, cedv->R0);
 | 
					 | 
				
			||||||
    bq27220_set_parameter_u16(handle, AddressT0, cedv->T0);
 | 
					 | 
				
			||||||
    bq27220_set_parameter_u16(handle, AddressR1, cedv->R1);
 | 
					 | 
				
			||||||
    bq27220_set_parameter_u16(handle, AddressTC, (cedv->TC) << 8 | cedv->C1);
 | 
					 | 
				
			||||||
    bq27220_set_parameter_u16(handle, AddressStartDOD0, cedv->DOD0);
 | 
					 | 
				
			||||||
    bq27220_set_parameter_u16(handle, AddressStartDOD10, cedv->DOD10);
 | 
					 | 
				
			||||||
    bq27220_set_parameter_u16(handle, AddressStartDOD20, cedv->DOD20);
 | 
					 | 
				
			||||||
    bq27220_set_parameter_u16(handle, AddressStartDOD30, cedv->DOD30);
 | 
					 | 
				
			||||||
    bq27220_set_parameter_u16(handle, AddressStartDOD40, cedv->DOD40);
 | 
					 | 
				
			||||||
    bq27220_set_parameter_u16(handle, AddressStartDOD50, cedv->DOD40);
 | 
					 | 
				
			||||||
    bq27220_set_parameter_u16(handle, AddressStartDOD60, cedv->DOD60);
 | 
					 | 
				
			||||||
    bq27220_set_parameter_u16(handle, AddressStartDOD70, cedv->DOD70);
 | 
					 | 
				
			||||||
    bq27220_set_parameter_u16(handle, AddressStartDOD80, cedv->DOD80);
 | 
					 | 
				
			||||||
    bq27220_set_parameter_u16(handle, AddressStartDOD90, cedv->DOD90);
 | 
					 | 
				
			||||||
    bq27220_set_parameter_u16(handle, AddressStartDOD100, cedv->DOD100);
 | 
					 | 
				
			||||||
    bq27220_set_parameter_u16(handle, AddressEDV0, cedv->EDV0);
 | 
					 | 
				
			||||||
    bq27220_set_parameter_u16(handle, AddressEDV1, cedv->EDV1);
 | 
					 | 
				
			||||||
    bq27220_set_parameter_u16(handle, AddressEDV2, cedv->EDV2);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bq27220_control(handle, Control_EXIT_CFG_UPDATE_REINIT);
 | 
					    return data == 0x0220;
 | 
				
			||||||
    furi_delay_us(10000);
 | 
					}
 | 
				
			||||||
    design_cap = bq27220_get_design_capacity(handle);
 | 
					
 | 
				
			||||||
    if(cedv->design_cap == design_cap) {
 | 
					bool bq27220_apply_data_memory(FuriHalI2cBusHandle* handle, const BQ27220DMData* data_memory) {
 | 
				
			||||||
        FURI_LOG_I(TAG, "Battery profile update success");
 | 
					    FURI_LOG_I(TAG, "Verifying data memory");
 | 
				
			||||||
        return true;
 | 
					    if(!bq27220_data_memory_check(handle, data_memory, false)) {
 | 
				
			||||||
    } else {
 | 
					        FURI_LOG_I(TAG, "Updating data memory");
 | 
				
			||||||
        FURI_LOG_E(TAG, "Battery profile update failed");
 | 
					        bq27220_data_memory_check(handle, data_memory, true);
 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    FURI_LOG_I(TAG, "Data memory verification complete");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint16_t bq27220_get_voltage(FuriHalI2cBusHandle* handle) {
 | 
					uint16_t bq27220_get_voltage(FuriHalI2cBusHandle* handle) {
 | 
				
			||||||
@ -114,24 +219,23 @@ int16_t bq27220_get_current(FuriHalI2cBusHandle* handle) {
 | 
				
			|||||||
    return bq27220_read_word(handle, CommandCurrent);
 | 
					    return bq27220_read_word(handle, CommandCurrent);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint8_t bq27220_get_battery_status(FuriHalI2cBusHandle* handle, BatteryStatus* battery_status) {
 | 
					bool bq27220_get_battery_status(FuriHalI2cBusHandle* handle, BatteryStatus* battery_status) {
 | 
				
			||||||
    uint16_t data = bq27220_read_word(handle, CommandBatteryStatus);
 | 
					    uint16_t data = bq27220_read_word(handle, CommandBatteryStatus);
 | 
				
			||||||
    if(data == BQ27220_ERROR) {
 | 
					    if(data == BQ27220_ERROR) {
 | 
				
			||||||
        return BQ27220_ERROR;
 | 
					        return false;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        *(uint16_t*)battery_status = data;
 | 
					        *(uint16_t*)battery_status = data;
 | 
				
			||||||
        return BQ27220_SUCCESS;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint8_t
 | 
					bool bq27220_get_operation_status(FuriHalI2cBusHandle* handle, OperationStatus* operation_status) {
 | 
				
			||||||
    bq27220_get_operation_status(FuriHalI2cBusHandle* handle, OperationStatus* operation_status) {
 | 
					 | 
				
			||||||
    uint16_t data = bq27220_read_word(handle, CommandOperationStatus);
 | 
					    uint16_t data = bq27220_read_word(handle, CommandOperationStatus);
 | 
				
			||||||
    if(data == BQ27220_ERROR) {
 | 
					    if(data == BQ27220_ERROR) {
 | 
				
			||||||
        return BQ27220_ERROR;
 | 
					        return false;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        *(uint16_t*)operation_status = data;
 | 
					        *(uint16_t*)operation_status = data;
 | 
				
			||||||
        return BQ27220_SUCCESS;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -47,60 +47,17 @@ typedef struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
_Static_assert(sizeof(OperationStatus) == 2, "Incorrect structure size");
 | 
					_Static_assert(sizeof(OperationStatus) == 2, "Incorrect structure size");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct BQ27220DMData BQ27220DMData;
 | 
				
			||||||
    // Low byte, Low bit first
 | 
					 | 
				
			||||||
    bool CCT : 1;
 | 
					 | 
				
			||||||
    bool CSYNC : 1;
 | 
					 | 
				
			||||||
    bool RSVD0 : 1;
 | 
					 | 
				
			||||||
    bool EDV_CMP : 1;
 | 
					 | 
				
			||||||
    bool SC : 1;
 | 
					 | 
				
			||||||
    bool FIXED_EDV0 : 1;
 | 
					 | 
				
			||||||
    uint8_t RSVD1 : 2;
 | 
					 | 
				
			||||||
    // High byte, Low bit first
 | 
					 | 
				
			||||||
    bool FCC_LIM : 1;
 | 
					 | 
				
			||||||
    bool RSVD2 : 1;
 | 
					 | 
				
			||||||
    bool FC_FOR_VDQ : 1;
 | 
					 | 
				
			||||||
    bool IGNORE_SD : 1;
 | 
					 | 
				
			||||||
    bool SME0 : 1;
 | 
					 | 
				
			||||||
    uint8_t RSVD3 : 3;
 | 
					 | 
				
			||||||
} GaugingConfig;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
_Static_assert(sizeof(GaugingConfig) == 2, "Incorrect structure size");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct {
 | 
					 | 
				
			||||||
    union {
 | 
					 | 
				
			||||||
        GaugingConfig gauge_conf;
 | 
					 | 
				
			||||||
        uint16_t gauge_conf_raw;
 | 
					 | 
				
			||||||
    } cedv_conf;
 | 
					 | 
				
			||||||
    uint16_t full_charge_cap;
 | 
					 | 
				
			||||||
    uint16_t design_cap;
 | 
					 | 
				
			||||||
    uint16_t EDV0;
 | 
					 | 
				
			||||||
    uint16_t EDV1;
 | 
					 | 
				
			||||||
    uint16_t EDV2;
 | 
					 | 
				
			||||||
    uint16_t EMF;
 | 
					 | 
				
			||||||
    uint16_t C0;
 | 
					 | 
				
			||||||
    uint16_t R0;
 | 
					 | 
				
			||||||
    uint16_t T0;
 | 
					 | 
				
			||||||
    uint16_t R1;
 | 
					 | 
				
			||||||
    uint8_t TC;
 | 
					 | 
				
			||||||
    uint8_t C1;
 | 
					 | 
				
			||||||
    uint16_t DOD0;
 | 
					 | 
				
			||||||
    uint16_t DOD10;
 | 
					 | 
				
			||||||
    uint16_t DOD20;
 | 
					 | 
				
			||||||
    uint16_t DOD30;
 | 
					 | 
				
			||||||
    uint16_t DOD40;
 | 
					 | 
				
			||||||
    uint16_t DOD50;
 | 
					 | 
				
			||||||
    uint16_t DOD60;
 | 
					 | 
				
			||||||
    uint16_t DOD70;
 | 
					 | 
				
			||||||
    uint16_t DOD80;
 | 
					 | 
				
			||||||
    uint16_t DOD90;
 | 
					 | 
				
			||||||
    uint16_t DOD100;
 | 
					 | 
				
			||||||
} ParamCEDV;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Initialize Driver
 | 
					/** Initialize Driver
 | 
				
			||||||
 * @return true on success, false otherwise
 | 
					 * @return true on success, false otherwise
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
bool bq27220_init(FuriHalI2cBusHandle* handle, const ParamCEDV* cedv);
 | 
					bool bq27220_init(FuriHalI2cBusHandle* handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Initialize Driver
 | 
				
			||||||
 | 
					 * @return true on success, false otherwise
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool bq27220_apply_data_memory(FuriHalI2cBusHandle* handle, const BQ27220DMData* data_memory);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Get battery voltage in mV or error */
 | 
					/** Get battery voltage in mV or error */
 | 
				
			||||||
uint16_t bq27220_get_voltage(FuriHalI2cBusHandle* handle);
 | 
					uint16_t bq27220_get_voltage(FuriHalI2cBusHandle* handle);
 | 
				
			||||||
@ -109,11 +66,10 @@ uint16_t bq27220_get_voltage(FuriHalI2cBusHandle* handle);
 | 
				
			|||||||
int16_t bq27220_get_current(FuriHalI2cBusHandle* handle);
 | 
					int16_t bq27220_get_current(FuriHalI2cBusHandle* handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Get battery status */
 | 
					/** Get battery status */
 | 
				
			||||||
uint8_t bq27220_get_battery_status(FuriHalI2cBusHandle* handle, BatteryStatus* battery_status);
 | 
					bool bq27220_get_battery_status(FuriHalI2cBusHandle* handle, BatteryStatus* battery_status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Get operation status */
 | 
					/** Get operation status */
 | 
				
			||||||
uint8_t
 | 
					bool bq27220_get_operation_status(FuriHalI2cBusHandle* handle, OperationStatus* operation_status);
 | 
				
			||||||
    bq27220_get_operation_status(FuriHalI2cBusHandle* handle, OperationStatus* operation_status);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Get temperature in units of 0.1°K */
 | 
					/** Get temperature in units of 0.1°K */
 | 
				
			||||||
uint16_t bq27220_get_temperature(FuriHalI2cBusHandle* handle);
 | 
					uint16_t bq27220_get_temperature(FuriHalI2cBusHandle* handle);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										84
									
								
								lib/drivers/bq27220_data_memory.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								lib/drivers/bq27220_data_memory.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,84 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					    BQ27220DMTypeEnd,
 | 
				
			||||||
 | 
					    BQ27220DMTypeWait,
 | 
				
			||||||
 | 
					    BQ27220DMTypeU8,
 | 
				
			||||||
 | 
					    BQ27220DMTypeU16,
 | 
				
			||||||
 | 
					    BQ27220DMTypeU32,
 | 
				
			||||||
 | 
					    BQ27220DMTypeI8,
 | 
				
			||||||
 | 
					    BQ27220DMTypeI16,
 | 
				
			||||||
 | 
					    BQ27220DMTypeI32,
 | 
				
			||||||
 | 
					    BQ27220DMTypeF32,
 | 
				
			||||||
 | 
					    BQ27220DMTypePtr8,
 | 
				
			||||||
 | 
					    BQ27220DMTypePtr16,
 | 
				
			||||||
 | 
					    BQ27220DMTypePtr32,
 | 
				
			||||||
 | 
					} BQ27220DMType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1GaugingConfig = 0x929B,
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1FullChargeCapacity = 0x929D,
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1DesignCapacity = 0x929F,
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1EMF = 0x92A3,
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1C0 = 0x92A9,
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1R0 = 0x92AB,
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1T0 = 0x92AD,
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1R1 = 0x92AF,
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1TC = 0x92B1,
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1C1 = 0x92B2,
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1EDV0 = 0x92B4,
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1EDV1 = 0x92B7,
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1EDV2 = 0x92BA,
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1StartDOD0 = 0x92BD,
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1StartDOD10 = 0x92BF,
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1StartDOD20 = 0x92C1,
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1StartDOD30 = 0x92C3,
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1StartDOD40 = 0x92C5,
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1StartDOD50 = 0x92C7,
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1StartDOD60 = 0x92C9,
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1StartDOD70 = 0x92CB,
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1StartDOD80 = 0x92CD,
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1StartDOD90 = 0x92CF,
 | 
				
			||||||
 | 
					    BQ27220DMAddressGasGaugingCEDVProfile1StartDOD100 = 0x92D1,
 | 
				
			||||||
 | 
					    BQ27220DMAddressCalibrationCurrentDeadband = 0x91DE,
 | 
				
			||||||
 | 
					    BQ27220DMAddressConfigurationPowerSleepCurrent = 0x9217,
 | 
				
			||||||
 | 
					    BQ27220DMAddressConfigurationCurrentThresholdsDischargeDetectionThreshold = 0x9228,
 | 
				
			||||||
 | 
					    BQ27220DMAddressConfigurationDataInitialStandby = 0x923C,
 | 
				
			||||||
 | 
					} BQ27220DMAddress;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct BQ27220DMData BQ27220DMData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct BQ27220DMData {
 | 
				
			||||||
 | 
					    uint16_t type;
 | 
				
			||||||
 | 
					    uint16_t address;
 | 
				
			||||||
 | 
					    union {
 | 
				
			||||||
 | 
					        uint8_t u8;
 | 
				
			||||||
 | 
					        uint16_t u16;
 | 
				
			||||||
 | 
					        uint32_t u32;
 | 
				
			||||||
 | 
					        int8_t i8;
 | 
				
			||||||
 | 
					        int16_t i16;
 | 
				
			||||||
 | 
					        int32_t i32;
 | 
				
			||||||
 | 
					        float f32;
 | 
				
			||||||
 | 
					    } value;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    // Low byte, Low bit first
 | 
				
			||||||
 | 
					    const bool CCT : 1;
 | 
				
			||||||
 | 
					    const bool CSYNC : 1;
 | 
				
			||||||
 | 
					    const bool RSVD0 : 1;
 | 
				
			||||||
 | 
					    const bool EDV_CMP : 1;
 | 
				
			||||||
 | 
					    const bool SC : 1;
 | 
				
			||||||
 | 
					    const bool FIXED_EDV0 : 1;
 | 
				
			||||||
 | 
					    const uint8_t RSVD1 : 2;
 | 
				
			||||||
 | 
					    // High byte, Low bit first
 | 
				
			||||||
 | 
					    const bool FCC_LIM : 1;
 | 
				
			||||||
 | 
					    const bool RSVD2 : 1;
 | 
				
			||||||
 | 
					    const bool FC_FOR_VDQ : 1;
 | 
				
			||||||
 | 
					    const bool IGNORE_SD : 1;
 | 
				
			||||||
 | 
					    const bool SME0 : 1;
 | 
				
			||||||
 | 
					    const uint8_t RSVD3 : 3;
 | 
				
			||||||
 | 
					} BQ27220DMGaugingConfig;
 | 
				
			||||||
@ -66,28 +66,3 @@
 | 
				
			|||||||
#define Control_EXIT_CFG_UPDATE_REINIT 0x0091
 | 
					#define Control_EXIT_CFG_UPDATE_REINIT 0x0091
 | 
				
			||||||
#define Control_EXIT_CFG_UPDATE 0x0092
 | 
					#define Control_EXIT_CFG_UPDATE 0x0092
 | 
				
			||||||
#define Control_RETURN_TO_ROM 0x0F00
 | 
					#define Control_RETURN_TO_ROM 0x0F00
 | 
				
			||||||
 | 
					 | 
				
			||||||
#define AddressGaugingConfig 0x929B
 | 
					 | 
				
			||||||
#define AddressFullChargeCapacity 0x929D
 | 
					 | 
				
			||||||
#define AddressDesignCapacity 0x929F
 | 
					 | 
				
			||||||
#define AddressEMF 0x92A3
 | 
					 | 
				
			||||||
#define AddressC0 0x92A9
 | 
					 | 
				
			||||||
#define AddressR0 0x92AB
 | 
					 | 
				
			||||||
#define AddressT0 0x92AD
 | 
					 | 
				
			||||||
#define AddressR1 0x92AF
 | 
					 | 
				
			||||||
#define AddressTC 0x92B1
 | 
					 | 
				
			||||||
#define AddressC1 0x92B2
 | 
					 | 
				
			||||||
#define AddressEDV0 0x92B4
 | 
					 | 
				
			||||||
#define AddressEDV1 0x92B7
 | 
					 | 
				
			||||||
#define AddressEDV2 0x92BA
 | 
					 | 
				
			||||||
#define AddressStartDOD0 0x92BD
 | 
					 | 
				
			||||||
#define AddressStartDOD10 0x92BF
 | 
					 | 
				
			||||||
#define AddressStartDOD20 0x92C1
 | 
					 | 
				
			||||||
#define AddressStartDOD30 0x92C3
 | 
					 | 
				
			||||||
#define AddressStartDOD40 0x92C5
 | 
					 | 
				
			||||||
#define AddressStartDOD50 0x92C7
 | 
					 | 
				
			||||||
#define AddressStartDOD60 0x92C9
 | 
					 | 
				
			||||||
#define AddressStartDOD70 0x92CB
 | 
					 | 
				
			||||||
#define AddressStartDOD80 0x92CD
 | 
					 | 
				
			||||||
#define AddressStartDOD90 0x92CF
 | 
					 | 
				
			||||||
#define AddressStartDOD100 0x92D1
 | 
					 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user