diff --git a/applications/gui/canvas.c b/applications/gui/canvas.c index d3394413..31e6499f 100644 --- a/applications/gui/canvas.c +++ b/applications/gui/canvas.c @@ -120,9 +120,9 @@ void canvas_font_set(CanvasApi* api, Font font) { Canvas* canvas = (Canvas*)api; u8g2_SetFontMode(&canvas->fb, 1); if(font == FontPrimary) { - u8g2_SetFont(&canvas->fb, u8g2_font_Born2bSportyV2_tr); + u8g2_SetFont(&canvas->fb, u8g2_font_helvB08_tf); } else if(font == FontSecondary) { - u8g2_SetFont(&canvas->fb, u8g2_font_HelvetiPixel_tr); + u8g2_SetFont(&canvas->fb, u8g2_font_haxrcorp4089_tr); } else { furi_check(0); } diff --git a/applications/power/power.c b/applications/power/power.c index 665e9881..3bbd5142 100644 --- a/applications/power/power.c +++ b/applications/power/power.c @@ -1,15 +1,13 @@ #include "power.h" #include + +#include +#include #include #include #include - -#define BATTERY_MIN_VOLTAGE 3.2f -#define BATTERY_MAX_VOLTAGE 4.0f -#define BATTERY_INIT 0xFFAACCEE - -extern ADC_HandleTypeDef hadc1; +#include struct Power { Icon* usb_icon; @@ -18,7 +16,10 @@ struct Power { Icon* battery_icon; Widget* battery_widget; - uint32_t charge; + ValueMutex* menu_vm; + MenuItem* menu; + + uint8_t charge; }; void power_draw_usb_callback(CanvasApi* canvas, void* context) { @@ -32,40 +33,40 @@ void power_draw_battery_callback(CanvasApi* canvas, void* context) { Power* power = context; canvas->draw_icon(canvas, 0, 0, power->battery_icon); - - if(power->charge != BATTERY_INIT) { - float charge = ((float)power->charge / 1000 * 2 - BATTERY_MIN_VOLTAGE) / - (BATTERY_MAX_VOLTAGE - BATTERY_MIN_VOLTAGE); - if(charge > 1) { - charge = 1; - } - canvas->draw_box(canvas, 2, 2, charge * 14, 4); - } + canvas->draw_box(canvas, 2, 2, (float)power->charge / 100 * 14, 4); } -void power_input_events_callback(const void* value, void* ctx) { - assert(ctx); - Power* power = ctx; - const InputEvent* event = value; +void power_off_callback(void* context) { + api_hal_power_off(); +} - if(event->input != InputCharging) return; +void power_enable_otg_callback(void* context) { + api_hal_power_enable_otg(); +} - widget_enabled_set(power->usb_widget, event->state); - widget_update(power->usb_widget); +void power_disable_otg_callback(void* context) { + api_hal_power_disable_otg(); } Power* power_alloc() { Power* power = furi_alloc(sizeof(Power)); + power->menu_vm = furi_open("menu"); + furi_check(power->menu_vm); + + power->menu = menu_item_alloc_menu("Power", NULL); + menu_item_subitem_add( + power->menu, menu_item_alloc_function("Poweroff", NULL, power_off_callback, power)); + menu_item_subitem_add( + power->menu, + menu_item_alloc_function("Enable OTG", NULL, power_enable_otg_callback, power)); + menu_item_subitem_add( + power->menu, + menu_item_alloc_function("Disable OTG", NULL, power_disable_otg_callback, power)); + power->usb_icon = assets_icons_get(I_USBConnected_15x8); power->usb_widget = widget_alloc(); widget_set_width(power->usb_widget, icon_get_width(power->usb_icon)); - - ValueManager* input_state_manager = furi_open("input_state"); - InputState input_state; - read_mutex_block(&input_state_manager->value, &input_state, sizeof(input_state)); - widget_enabled_set(power->usb_widget, input_state.charging); - widget_draw_callback_set(power->usb_widget, power_draw_usb_callback, power); power->battery_icon = assets_icons_get(I_Battery_19x8); @@ -73,12 +74,6 @@ Power* power_alloc() { widget_set_width(power->battery_widget, icon_get_width(power->battery_icon)); widget_draw_callback_set(power->battery_widget, power_draw_battery_callback, power); - PubSub* input_event_record = furi_open("input_events"); - assert(input_event_record); - subscribe_pubsub(input_event_record, power_input_events_callback, power); - - power->charge = BATTERY_INIT; - return power; } @@ -99,19 +94,21 @@ void power_task(void* p) { gui->add_widget(gui, power->battery_widget, GuiLayerStatusBarRight); furi_commit(gui_record); + with_value_mutex( + power->menu_vm, (Menu * menu) { menu_item_add(menu, power->menu); }); + if(!furi_create("power", power)) { printf("[power_task] unable to create power record\n"); furiac_exit(NULL); } + api_hal_power_init(); + furiac_ready(); while(1) { - HAL_ADC_Start(&hadc1); - if(HAL_ADC_PollForConversion(&hadc1, 1000) != HAL_TIMEOUT) { - power->charge = HAL_ADC_GetValue(&hadc1); - widget_update(power->battery_widget); - } + power->charge = api_hal_power_get_pct(); + widget_enabled_set(power->usb_widget, api_hal_power_is_charging()); osDelay(1000); } } diff --git a/firmware/Makefile b/firmware/Makefile index 926972d7..eec67bf3 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -14,6 +14,7 @@ include $(PROJECT_ROOT)/lib/lib.mk TARGET ?= f2 TARGET_DIR = targets/$(TARGET) include $(TARGET_DIR)/target.mk +CFLAGS += -Itargets/Inc include $(PROJECT_ROOT)/make/git.mk include $(PROJECT_ROOT)/make/toolchain.mk diff --git a/firmware/targets/Inc/api-hal-power.h b/firmware/targets/Inc/api-hal-power.h new file mode 100644 index 00000000..2b90dc61 --- /dev/null +++ b/firmware/targets/Inc/api-hal-power.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +/* Initialize drivers */ +void api_hal_power_init(); + +/* Get predicted remaining battery capacity in percents */ +uint8_t api_hal_power_get_pct(); + +/* Get charging status */ +bool api_hal_power_is_charging(); + +/* Poweroff system */ +void api_hal_power_off(); + +/* OTG enable */ +void api_hal_power_enable_otg(); + +/* OTG disable */ +void api_hal_power_disable_otg(); diff --git a/firmware/targets/f2/api-hal/api-hal-power.c b/firmware/targets/f2/api-hal/api-hal-power.c new file mode 100644 index 00000000..17db66d1 --- /dev/null +++ b/firmware/targets/f2/api-hal/api-hal-power.c @@ -0,0 +1,34 @@ +#include +#include + +#define BATTERY_MIN_VOLTAGE 3.2f +#define BATTERY_MAX_VOLTAGE 4.0f + +void api_hal_power_init() {} + +uint8_t api_hal_power_get_pct() { + float value; + HAL_ADC_Start(&hadc1); + if(HAL_ADC_PollForConversion(&hadc1, 1000) != HAL_TIMEOUT) { + value = HAL_ADC_GetValue(&hadc1); + } + + value = ((float)value / 10 * 2 - BATTERY_MIN_VOLTAGE) / + (BATTERY_MAX_VOLTAGE - BATTERY_MIN_VOLTAGE); + + if(value > 100) { + value = 100; + } + + return value; +} + +bool api_hal_power_is_charging() { + return false; +} + +void api_hal_power_off() {} + +void api_hal_power_enable_otg() {} + +void api_hal_power_disable_otg() {} diff --git a/firmware/targets/f3/Inc/bq25896.h b/firmware/targets/f3/Inc/bq25896.h new file mode 100644 index 00000000..9ba80362 --- /dev/null +++ b/firmware/targets/f3/Inc/bq25896.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +/* Initialize Driver */ +void bq25896_init(); + +/* Send device into shipping mode */ +void bq25896_poweroff(); + +/* Is currently charging */ +bool bq25896_is_charging(); + +/* Enable otg */ +void bq25896_enable_otg(); + +/* Disable otg */ +void bq25896_disable_otg(); diff --git a/firmware/targets/f3/Inc/bq25896_reg.h b/firmware/targets/f3/Inc/bq25896_reg.h new file mode 100644 index 00000000..97b06461 --- /dev/null +++ b/firmware/targets/f3/Inc/bq25896_reg.h @@ -0,0 +1,263 @@ +#pragma once + +#include +#include + +#if BITS_BIG_ENDIAN == 1 +#error Bit structures defined in this file is not portable to BE +#endif + +#define BQ25896_ADDRESS 0xD6 + +typedef struct { + uint8_t IINLIM:6; // Input Current Limit, mA, offset: +100mA + bool EN_ILIM:1; // Enable ILIM Pin + bool EN_HIZ:1; // Enable HIZ Mode +} REG00; + +#define IILIM_1600 (1<<5) +#define IILIM_800 (1<<4) +#define IILIM_400 (1<<3) +#define IILIM_200 (1<<2) +#define IILIM_100 (1<<1) +#define IILIM_50 (1<<0) + +typedef struct { + uint8_t VINDPM_OS:5; // Input Voltage Limit Offset, mV + bool BCOLD:1; // Boost Mode Cold Temperature Monitor Threshold + uint8_t BHOT:2; // Boost Mode Hot Temperature Monitor Threshold +} REG01; + +#define VINDPM_OS_1600 (1<<4) +#define VINDPM_OS_800 (1<<3) +#define VINDPM_OS_400 (1<<2) +#define VINDPM_OS_200 (1<<1) +#define VINDPM_OS_100 (1<<0) + + +typedef struct { + bool AUTO_DPDM_EN:1; // Automatic Input Detection Enable + bool FORCE_DPDM:1; // Force Input Detection + uint8_t RES:2; // Reserved + bool ICO_EN:1; // Input Current Optimizer (ICO) Enable + bool BOOST_FREQ:1; // Boost Mode Frequency Selection + bool CONV_RATE:1; // ADC Conversion Rate Selection + bool CONV_START:1; // ADC Conversion Start Control +} REG02; + + +typedef struct { + bool MIN_VBAT_SEL:1; // Minimum Battery Voltage (falling) to exit boost mode + uint8_t SYS_MIN:3; // Minimum System Voltage Limit, mV, offset: +3000mV + bool CHG_CONFIG:1; // Charge Enable Configuration + bool OTG_CONFIG:1; // Boost (OTG) Mode Configuration + bool WD_RST:1; // I2C Watchdog Timer Reset + bool BAT_LOADEN:1; // Battery Load (IBATLOAD) Enable +} REG03; + +#define SYS_MIN_400 (1<<2) +#define SYS_MIN_200 (1<<1) +#define SYS_MIN_100 (1<<0) + +typedef struct { + uint8_t ICHG:7; // Fast Charge Current Limit, mA + bool EN_PUMPX:1; // Current pulse control Enable +} REG04; + +#define ICHG_4096 (1<<6) +#define ICHG_2048 (1<<5) +#define ICHG_1024 (1<<4) +#define ICHG_512 (1<<3) +#define ICHG_256 (1<<2) +#define ICHG_128 (1<<1) +#define ICHG_64 (1<<0) + +typedef struct { + uint8_t ITERM:4; // Termination Current Limit, offset: +64mA + uint8_t IPRECHG:4; // Precharge Current Limit, offset: +64mA +} REG05; + +#define IPRETERM_512 (1<<3) +#define IPRETERM_256 (1<<2) +#define IPRETERM_128 (1<<1) +#define IPRETERM_64 (1<<0) + +typedef struct { + bool VRECHG:1; // Battery Recharge Threshold Offset + bool BATLOWV:1; // Battery Precharge to Fast Charge Threshold + uint8_t VREG:6; // Charge Voltage Limit, offset: +3840mV +} REG06; + +#define VREG_512 (1<<5) +#define VREG_256 (1<<4) +#define VREG_128 (1<<3) +#define VREG_64 (1<<2) +#define VREG_32 (1<<1) +#define VREG_16 (1<<0) + +typedef struct { + bool JEITA_ISET:1; // JEITA Low Temperature Current Setting + uint8_t CHG_TIMER:2; // Fast Charge Timer Setting + bool EN_TIMER:1; // Charging Safety Timer Enable + uint8_t WATCHDOG:2; // I2C Watchdog Timer Setting + bool STAT_DIS:1; // STAT Pin Disable + bool EN_TERM:1; // Charging Termination Enable +} REG07; + +#define WATCHDOG_DIS (0b00) +#define WATCHDOG_40 (0b01) +#define WATCHDOG_80 (0b10) +#define WATCHDOG_160 (0b11) + +#define CHG_TIMER_5 (0b00) +#define CHG_TIMER_8 (0b01) +#define CHG_TIMER_12 (0b10) +#define CHG_TIMER_20 (0b11) + +typedef struct { + uint8_t TREG:2; // Thermal Regulation Threshold + uint8_t VCLAMP:3; // IR Compensation Voltage Clamp + uint8_t BAT_COMP:3; // IR Compensation Resistor Setting +} REG08; + +#define BAT_COMP_80 (1<<2) +#define BAT_COMP_40 (1<<1) +#define BAT_COMP_20 (1<<0) + +#define VCLAMP_128 (1<<2) +#define VCLAMP_64 (1<<1) +#define VCLAMP_32 (1<<0) + +#define TREG_60 (0b00) +#define TREG_80 (0b01) +#define TREG_100 (0b10) +#define TREG_120 (0b11) + +typedef struct { + bool PUMPX_DN:1; // Current pulse control voltage down enable + bool PUMPX_UP:1; // Current pulse control voltage up enable + bool BATFET_RST_EN:1; // BATFET full system reset enable + bool BATFET_DLY:1; // BATFET turn off delay control + bool JEITA_VSET:1; // JEITA High Temperature Voltage Setting + bool BATFET_DIS:1; // Force BATFET off to enable ship mode + bool TMR2X_EN:1; // Safety Timer Setting during DPM or Thermal Regulation + bool FORCE_ICO:1; // Force Start Input Current Optimizer +} REG09; + +typedef struct { + uint8_t BOOST_LIM:3; // Boost Mode Current Limit + bool PFM_OTG_DIS:1; // PFM mode allowed in boost mode + uint8_t BOOSTV:4; // Boost Mode Voltage Regulation, offset: +4550mV +} REG0A; + +#define BOOSTV_512 (1<<3) +#define BOOSTV_256 (1<<2) +#define BOOSTV_128 (1<<1) +#define BOOSTV_64 (1<<0) + +#define BOOST_LIM_500 (0b000) +#define BOOST_LIM_750 (0b001) +#define BOOST_LIM_1200 (0b010) +#define BOOST_LIM_1400 (0b011) +#define BOOST_LIM_1650 (0b100) +#define BOOST_LIM_1875 (0b101) +#define BOOST_LIM_2150 (0b110) +#define BOOST_LIM_RSVD (0b111) + + +typedef enum { + VBusStatNo = 0b000, + VBusStatUSB = 0b001, + VBusStatExternal = 0b010, + VBusStatOTG = 0b111, +} VBusStat; + +typedef enum { + ChrgStatNo = 0b00, + ChrgStatPre = 0b01, + ChrgStatFast = 0b10, + ChrgStatDone = 0b11, +} ChrgStat; + +typedef struct { + bool VSYS_STAT:1; // VSYS Regulation Status + bool RES:1; // Reserved: Always reads 1 + bool PG_STAT:1; // Power Good Status + ChrgStat CHRG_STAT:2; // Charging Status + VBusStat VBUS_STAT:3; // VBUS Status register +} REG0B; + +typedef enum { + ChrgFaultNO = 0b00, + ChrgFaultIN = 0b01, + ChrgFaultTH = 0b10, + ChrgFaultTIM = 0b11, +} ChrgFault; + +typedef enum { + NtcFaultNo = 0b000, + NtcFaultWarm = 0b010, + NtcFaultCool = 0b011, + NtcFaultCold = 0b101, + NtcFaultHot = 0b110, +} NtcFault; + +typedef struct { + NtcFault NTC_FAULT:3; // NTC Fault Status + bool BAT_FAULT:1; // Battery Fault Status + ChrgFault CHRG_FAULT:2; // Charge Fault Status + bool BOOST_FAULT:1; // Boost Mode Fault Status + bool WATCHDOG_FAULT:1; // Watchdog Fault Status +} REG0C; + +typedef struct { + uint8_t VINDPM:7; // Absolute VINDPM Threshold, offset: +2600mV + bool FORCE_VINDPM:1; // VINDPM Threshold Setting Method +} REG0D; + +#define VINDPM_6400 (1<<6) +#define VINDPM_3200 (1<<5) +#define VINDPM_1600 (1<<4) +#define VINDPM_800 (1<<3) +#define VINDPM_400 (1<<2) +#define VINDPM_200 (1<<1) +#define VINDPM_100 (1<<0) + +typedef struct { + uint8_t BATV:7; // ADC conversion of Battery Voltage (VBAT), offset: +2304mV + bool THERM_STAT:1; // Thermal Regulation Status +} REG0E; + +typedef struct { + uint8_t SYSV:7; // ADDC conversion of System Voltage (VSYS), offset: +2304mV + uint8_t RES:1; // Reserved: Always reads 0 +} REG0F; + +typedef struct { + uint8_t TSPCT:7; // ADC conversion of TS Voltage (TS) as percentage of REGN, offset: +21% + uint8_t RES:1; // Reserved: Always reads 0 +} REG10; + +typedef struct { + uint8_t VBUSV:7; // ADC conversion of VBUS voltage (VBUS), offset: +2600mV + bool VBUS_GD:1; // VBUS Good Status +} REG11; + +typedef struct { + uint8_t ICHGR:7; // ADC conversion of Charge Current (IBAT) when VBAT > VBATSHORT + uint8_t RES:1; // Reserved: Always reads 0 +} REG12; + +typedef struct { + uint8_t IDPM_LIM:6; // Input Current Limit in effect while Input Current Optimizer (ICO) is enabled, offset: 100mA (default) + bool IDPM_STAT:1; // IINDPM Status + bool VDPM_STAT:1; // VINDPM Status +} REG13; + +typedef struct { + uint8_t DEV_REV:2; // Device Revision + bool TS_PROFILE:1; // Temperature Profile + uint8_t PN:3; // Device Configuration + bool ICO_OPTIMIZED:1; // Input Current Optimizer (ICO) Status + bool REG_RST:1; // Register Reset +} REG14; diff --git a/firmware/targets/f3/Inc/bq27220.h b/firmware/targets/f3/Inc/bq27220.h new file mode 100644 index 00000000..941c42a9 --- /dev/null +++ b/firmware/targets/f3/Inc/bq27220.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +/* Initialize Driver */ +void bq27220_init(); + +/* Get battery voltage in mV */ +uint16_t bq27220_get_voltage(); + +/* Get current in mA */ +int16_t bq27220_get_current(); + +/* Get compensated full charge capacity in in mAh */ +uint16_t bq27220_get_full_charge_capacity(); + +/* Get remaining capacity in in mAh */ +uint16_t bq27220_get_remaining_capacity(); + +/* Get predicted remaining battery capacity in percents */ +uint16_t bq27220_get_state_of_charge(); diff --git a/firmware/targets/f3/Inc/bq27220_reg.h b/firmware/targets/f3/Inc/bq27220_reg.h new file mode 100644 index 00000000..daa1c184 --- /dev/null +++ b/firmware/targets/f3/Inc/bq27220_reg.h @@ -0,0 +1,66 @@ +#pragma once + +#define BQ27220_ADDRESS 0xAA + +#define CommandControl 0x00 +#define CommandAtRate 0x02 +#define CommandAtRateTimeToEmpty 0x04 +#define CommandTemperature 0x06 +#define CommandVoltage 0x08 +#define CommandBatteryStatus 0x0A +#define CommandCurrent 0x0C +#define CommandRemainingCapacity 0x10 +#define CommandFullChargeCapacity 0x12 +#define CommandAverageCurrent 0x14 +#define CommandTimeToEmpty 0x16 +#define CommandTimeToFull 0x18 +#define CommandStandbyCurrent 0x1A +#define CommandStandbyTimeToEmpty 0x1C +#define CommandMaxLoadCurrent 0x1E +#define CommandMaxLoadTimeToEmpty 0x20 +#define CommandRawCoulombCount 0x22 +#define CommandAveragePower 0x24 +#define CommandInternalTemperature 0x28 +#define CommandCycleCount 0x2A +#define CommandStateOfCharge 0x2C +#define CommandStateOfHealth 0x2E +#define CommandChargeVoltage 0x30 +#define CommandChargeCurrent 0x32 +#define CommandBTPDischargeSet 0x34 +#define CommandBTPChargeSet 0x36 +#define CommandOperationStatus 0x3A +#define CommandDesignCapacity 0x3C +#define CommandMACData 0x40 +#define CommandMACDataSum 0x60 +#define CommandMACDataLen 0x61 +#define CommandAnalogCount 0x79 +#define CommandRawCurrent 0x7A +#define CommandRawVoltage 0x7C +#define CommandRawIntTemp 0x7E + +#define Control_CONTROL_STATUS 0x0000 +#define Control_DEVICE_NUMBER 0x0001 +#define Control_FW_VERSION 0x0002 +#define Control_BOARD_OFFSET 0x0009 +#define Control_CC_OFFSET 0x000A +#define Control_CC_OFFSET_SAVE 0x000B +#define Control_OCV_CMD 0x000C +#define Control_BAT_INSERT 0x000D +#define Control_BAT_REMOVE 0x000E +#define Control_SET_SNOOZE 0x0013 +#define Control_CLEAR_SNOOZE 0x0014 +#define Control_SET_PROFILE_1 0x0015 +#define Control_SET_PROFILE_2 0x0016 +#define Control_SET_PROFILE_3 0x0017 +#define Control_SET_PROFILE_4 0x0018 +#define Control_SET_PROFILE_5 0x0019 +#define Control_SET_PROFILE_6 0x001A +#define Control_CAL_TOGGLE 0x002D +#define Control_SEALED 0x0030 +#define Control_RESET 0x0041 +#define Control_EXIT_CAL 0x0080 +#define Control_ENTER_CAL 0x0081 +#define Control_ENTER_CFG_UPDATE 0x0090 +#define Control_EXIT_CFG_UPDATE_REINIT 0x0091 +#define Control_EXIT_CFG_UPDATE 0x0092 +#define Control_RETURN_TO_ROM 0x0F00 diff --git a/firmware/targets/f3/Inc/i2c.h b/firmware/targets/f3/Inc/i2c.h index 9fa519cf..89392e4e 100644 --- a/firmware/targets/f3/Inc/i2c.h +++ b/firmware/targets/f3/Inc/i2c.h @@ -34,6 +34,8 @@ extern I2C_HandleTypeDef hi2c1; /* USER CODE BEGIN Private defines */ +#define POWER_I2C hi2c1 + /* USER CODE END Private defines */ void MX_I2C1_Init(void); diff --git a/firmware/targets/f3/Src/bq25896.c b/firmware/targets/f3/Src/bq25896.c new file mode 100644 index 00000000..25e7bf5d --- /dev/null +++ b/firmware/targets/f3/Src/bq25896.c @@ -0,0 +1,99 @@ + +#include +#include +#include + +uint8_t bit_reverse(uint8_t b) { + b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; + b = (b & 0xCC) >> 2 | (b & 0x33) << 2; + b = (b & 0xAA) >> 1 | (b & 0x55) << 1; + return b; +} + +bool bq25896_read(uint8_t address, uint8_t* data, size_t size) { + if (HAL_I2C_Master_Transmit(&POWER_I2C, BQ25896_ADDRESS, &address, 1, 2000) != HAL_OK) { + return false; + } + if (HAL_I2C_Master_Receive(&POWER_I2C, BQ25896_ADDRESS, data, size, 2000) != HAL_OK) { + return false; + } + return true; +} + +bool bq25896_read_reg(uint8_t address, uint8_t* data) { + bq25896_read(address, data, 1); + return true; +} + +bool bq25896_write_reg(uint8_t address, uint8_t* data) { + uint8_t buffer[2] = { address, *data }; + + if (HAL_I2C_Master_Transmit(&POWER_I2C, BQ25896_ADDRESS, buffer, 2, 2000) != HAL_OK) { + return false; + } + return true; +} + +typedef struct { + REG00 r00; + REG01 r01; + REG02 r02; + REG03 r03; + REG04 r04; + REG05 r05; + REG06 r06; + REG07 r07; + REG08 r08; + REG09 r09; + REG0A r0A; + REG0B r0B; + REG0C r0C; + REG0D r0D; + REG0E r0E; + REG0F r0F; + REG10 r10; + REG11 r11; + REG12 r12; + REG13 r13; + REG14 r14; +} bq25896_regs_t; + +static bq25896_regs_t bq25896_regs; + +void bq25896_init() { + bq25896_read(0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs)); + + bq25896_regs.r09.BATFET_DIS = 0; + bq25896_write_reg(0x09, (uint8_t*)&bq25896_regs.r09); + + bq25896_regs.r14.REG_RST = 1; + bq25896_write_reg(0x14, (uint8_t*)&bq25896_regs.r14); + + // bq25896_regs.r07.WATCHDOG = 0b00; + // bq25896_write_reg(0x07, (uint8_t*)&bq25896_regs.r07); + + bq25896_read(0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs)); +} + +void bq25896_poweroff() { + bq25896_regs.r09.BATFET_DIS=1; + bq25896_write_reg(0x09, (uint8_t*)&bq25896_regs.r09); +} + +bool bq25896_is_charging() { + bq25896_regs.r03.WD_RST = 1; + bq25896_write_reg(0x03, (uint8_t*)&bq25896_regs.r03); + + bq25896_read_reg(0x0B, (uint8_t*)&bq25896_regs.r0B); + return bq25896_regs.r0B.CHRG_STAT != ChrgStatNo; +} + +void bq25896_enable_otg() { + bq25896_regs.r03.OTG_CONFIG = 1; + bq25896_write_reg(0x09, (uint8_t*)&bq25896_regs.r03); +} + +void bq25896_disable_otg() { + bq25896_regs.r03.OTG_CONFIG = 0; + bq25896_write_reg(0x09, (uint8_t*)&bq25896_regs.r03); +} diff --git a/firmware/targets/f3/Src/bq27220.c b/firmware/targets/f3/Src/bq27220.c new file mode 100644 index 00000000..a988ed1d --- /dev/null +++ b/firmware/targets/f3/Src/bq27220.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include + +uint16_t bq27220_read_word(uint8_t address) { + uint8_t data[2] = { address }; + if (HAL_I2C_Master_Transmit(&POWER_I2C, BQ27220_ADDRESS, data, 1, 2000) != HAL_OK) { + return 0; + } + + if (HAL_I2C_Master_Receive(&POWER_I2C, BQ27220_ADDRESS, data, 2, 2000) != HAL_OK) { + return 0; + } + return *(uint16_t*)data; +} + +bool bq27220_control(uint16_t control) { + uint8_t data[3] = { CommandControl }; + data[1] = (control>>8) & 0xFF; + data[2] = control & 0xFF; + if (HAL_I2C_Master_Transmit(&POWER_I2C, BQ27220_ADDRESS, data, 3, 2000) != HAL_OK) { + return false; + } + + return true; +} + +void bq27220_init() { + bq27220_control(Control_ENTER_CFG_UPDATE); + bq27220_control(Control_SET_PROFILE_2); + bq27220_control(Control_EXIT_CFG_UPDATE); +} + +uint16_t bq27220_get_voltage() { + return bq27220_read_word(CommandVoltage); +} + +int16_t bq27220_get_current() { + return (int16_t)bq27220_read_word(CommandCurrent); +} + +uint16_t bq27220_get_full_charge_capacity() { + return bq27220_read_word(CommandFullChargeCapacity); +} + +uint16_t bq27220_get_remaining_capacity() { + return bq27220_read_word(CommandRemainingCapacity); +} + +uint16_t bq27220_get_state_of_charge() { + return bq27220_read_word(CommandStateOfCharge); +} diff --git a/firmware/targets/f3/api-hal/api-hal-power.c b/firmware/targets/f3/api-hal/api-hal-power.c new file mode 100644 index 00000000..25e153d1 --- /dev/null +++ b/firmware/targets/f3/api-hal/api-hal-power.c @@ -0,0 +1,28 @@ +#include +#include +#include + +void api_hal_power_init() { + bq27220_init(); + bq25896_init(); +} + +uint8_t api_hal_power_get_pct() { + return bq27220_get_state_of_charge(); +} + +bool api_hal_power_is_charging() { + return bq25896_is_charging(); +} + +void api_hal_power_off() { + bq25896_poweroff(); +} + +void api_hal_power_enable_otg() { + bq25896_enable_otg(); +} + +void api_hal_power_disable_otg() { + bq25896_disable_otg(); +}