[FL-1911] FuriHal: i2c refactoring (#847)
* Project: fix release build, replace asserts with checks. * FuriHal: i2c refactoring, new bus access model, flexible bus gpio configuration. * FuriHal: set i2c pins to high on detach. * FuriHal: more i2c bus events, put bus under reset when not used, move bus enable/disable routine to bus handler. * FuriHal: fix i2c deadlock in power api, add external i2c handle.
This commit is contained in:
parent
7c0943e736
commit
cf591ef7eb
@ -427,7 +427,7 @@ bool storage_simply_remove_recursive(Storage* storage, const char* path) {
|
||||
|
||||
string_init_printf(fullname, "%s/%s", string_get_cstr(cur_dir), name);
|
||||
FS_Error error = storage_common_remove(storage, string_get_cstr(fullname));
|
||||
furi_assert(error == FSE_OK);
|
||||
furi_check(error == FSE_OK);
|
||||
string_clear(fullname);
|
||||
}
|
||||
storage_dir_close(dir);
|
||||
@ -438,7 +438,7 @@ bool storage_simply_remove_recursive(Storage* storage, const char* path) {
|
||||
}
|
||||
|
||||
FS_Error error = storage_common_remove(storage, string_get_cstr(cur_dir));
|
||||
furi_assert(error == FSE_OK);
|
||||
furi_check(error == FSE_OK);
|
||||
|
||||
if(string_cmp(cur_dir, path)) {
|
||||
size_t last_char = string_search_rchar(cur_dir, '/');
|
||||
|
@ -115,7 +115,7 @@ static void clean_directory(Storage* fs_api, const char* clean_dir) {
|
||||
clean_directory(fs_api, fullname);
|
||||
}
|
||||
FS_Error error = storage_common_remove(fs_api, fullname);
|
||||
furi_assert(error == FSE_OK);
|
||||
furi_check(error == FSE_OK);
|
||||
free(fullname);
|
||||
}
|
||||
free(name);
|
||||
|
149
bootloader/targets/f6/furi-hal/furi-hal-i2c-config.c
Normal file
149
bootloader/targets/f6/furi-hal/furi-hal-i2c-config.c
Normal file
@ -0,0 +1,149 @@
|
||||
#include "furi-hal-i2c-config.h"
|
||||
#include <furi-hal-resources.h>
|
||||
#include <furi-hal-version.h>
|
||||
|
||||
#include <stm32wbxx_ll_rcc.h>
|
||||
#include <stm32wbxx_ll_bus.h>
|
||||
|
||||
/** Timing register value is computed with the STM32CubeMX Tool,
|
||||
* Standard Mode @100kHz with I2CCLK = 64 MHz,
|
||||
* rise time = 0ns, fall time = 0ns
|
||||
*/
|
||||
#define FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100 0x10707DBC
|
||||
|
||||
/** Timing register value is computed with the STM32CubeMX Tool,
|
||||
* Fast Mode @400kHz with I2CCLK = 64 MHz,
|
||||
* rise time = 0ns, fall time = 0ns
|
||||
*/
|
||||
#define FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_400 0x00602173
|
||||
|
||||
static void furi_hal_i2c_bus_power_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) {
|
||||
if(event == FuriHalI2cBusEventInit) {
|
||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);
|
||||
LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);
|
||||
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1);
|
||||
bus->current_handle = NULL;
|
||||
} else if(event == FuriHalI2cBusEventDeinit) {
|
||||
} else if(event == FuriHalI2cBusEventLock) {
|
||||
} else if(event == FuriHalI2cBusEventUnlock) {
|
||||
} else if(event == FuriHalI2cBusEventActivate) {
|
||||
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C1);
|
||||
} else if(event == FuriHalI2cBusEventDeactivate) {
|
||||
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1);
|
||||
}
|
||||
}
|
||||
|
||||
FuriHalI2cBus furi_hal_i2c_bus_power = {
|
||||
.i2c = I2C1,
|
||||
.current_handle = NULL,
|
||||
.callback = furi_hal_i2c_bus_power_event,
|
||||
};
|
||||
|
||||
static void furi_hal_i2c_bus_external_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) {
|
||||
if(event == FuriHalI2cBusEventActivate) {
|
||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C3);
|
||||
LL_RCC_SetI2CClockSource(LL_RCC_I2C3_CLKSOURCE_PCLK1);
|
||||
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C3);
|
||||
} else if(event == FuriHalI2cBusEventDeactivate) {
|
||||
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C3);
|
||||
}
|
||||
}
|
||||
|
||||
FuriHalI2cBus furi_hal_i2c_bus_external = {
|
||||
.i2c = I2C3,
|
||||
.current_handle = NULL,
|
||||
.callback = furi_hal_i2c_bus_external_event,
|
||||
};
|
||||
|
||||
void furi_hal_i2c_bus_handle_power_event(
|
||||
FuriHalI2cBusHandle* handle,
|
||||
FuriHalI2cBusHandleEvent event) {
|
||||
if(event == FuriHalI2cBusHandleEventActivate) {
|
||||
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
|
||||
hal_gpio_init_ex(
|
||||
&gpio_i2c_power_sda,
|
||||
GpioModeAltFunctionOpenDrain,
|
||||
GpioPullNo,
|
||||
GpioSpeedLow,
|
||||
GpioAltFn4I2C1);
|
||||
hal_gpio_init_ex(
|
||||
&gpio_i2c_power_scl,
|
||||
GpioModeAltFunctionOpenDrain,
|
||||
GpioPullNo,
|
||||
GpioSpeedLow,
|
||||
GpioAltFn4I2C1);
|
||||
|
||||
LL_I2C_InitTypeDef I2C_InitStruct = {0};
|
||||
I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
|
||||
I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
|
||||
I2C_InitStruct.DigitalFilter = 0;
|
||||
I2C_InitStruct.OwnAddress1 = 0;
|
||||
I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
|
||||
I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
|
||||
if(furi_hal_version_get_hw_version() > 10) {
|
||||
I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_400;
|
||||
} else {
|
||||
I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100;
|
||||
}
|
||||
LL_I2C_Init(handle->bus->i2c, &I2C_InitStruct);
|
||||
|
||||
LL_I2C_EnableAutoEndMode(handle->bus->i2c);
|
||||
LL_I2C_SetOwnAddress2(handle->bus->i2c, 0, LL_I2C_OWNADDRESS2_NOMASK);
|
||||
LL_I2C_DisableOwnAddress2(handle->bus->i2c);
|
||||
LL_I2C_DisableGeneralCall(handle->bus->i2c);
|
||||
LL_I2C_EnableClockStretching(handle->bus->i2c);
|
||||
LL_I2C_Enable(handle->bus->i2c);
|
||||
} else if(event == FuriHalI2cBusHandleEventDeactivate) {
|
||||
LL_I2C_Disable(handle->bus->i2c);
|
||||
hal_gpio_write(&gpio_i2c_power_sda, 1);
|
||||
hal_gpio_write(&gpio_i2c_power_scl, 1);
|
||||
hal_gpio_init_ex(
|
||||
&gpio_i2c_power_sda, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
|
||||
hal_gpio_init_ex(
|
||||
&gpio_i2c_power_scl, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
|
||||
}
|
||||
}
|
||||
|
||||
FuriHalI2cBusHandle furi_hal_i2c_handle_power = {
|
||||
.bus = &furi_hal_i2c_bus_power,
|
||||
.callback = furi_hal_i2c_bus_handle_power_event,
|
||||
};
|
||||
|
||||
void furi_hal_i2c_bus_handle_external_event(
|
||||
FuriHalI2cBusHandle* handle,
|
||||
FuriHalI2cBusHandleEvent event) {
|
||||
if(event == FuriHalI2cBusHandleEventActivate) {
|
||||
hal_gpio_init_ex(
|
||||
&gpio_ext_pc0, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C3);
|
||||
hal_gpio_init_ex(
|
||||
&gpio_ext_pc1, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C3);
|
||||
|
||||
LL_I2C_InitTypeDef I2C_InitStruct = {0};
|
||||
I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
|
||||
I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
|
||||
I2C_InitStruct.DigitalFilter = 0;
|
||||
I2C_InitStruct.OwnAddress1 = 0;
|
||||
I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
|
||||
I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
|
||||
I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100;
|
||||
LL_I2C_Init(handle->bus->i2c, &I2C_InitStruct);
|
||||
|
||||
LL_I2C_EnableAutoEndMode(handle->bus->i2c);
|
||||
LL_I2C_SetOwnAddress2(handle->bus->i2c, 0, LL_I2C_OWNADDRESS2_NOMASK);
|
||||
LL_I2C_DisableOwnAddress2(handle->bus->i2c);
|
||||
LL_I2C_DisableGeneralCall(handle->bus->i2c);
|
||||
LL_I2C_EnableClockStretching(handle->bus->i2c);
|
||||
LL_I2C_Enable(handle->bus->i2c);
|
||||
} else if(event == FuriHalI2cBusHandleEventDeactivate) {
|
||||
LL_I2C_Disable(handle->bus->i2c);
|
||||
hal_gpio_write(&gpio_ext_pc0, 1);
|
||||
hal_gpio_write(&gpio_ext_pc1, 1);
|
||||
hal_gpio_init_ex(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
|
||||
hal_gpio_init_ex(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
|
||||
}
|
||||
}
|
||||
|
||||
FuriHalI2cBusHandle furi_hal_i2c_handle_external = {
|
||||
.bus = &furi_hal_i2c_bus_external,
|
||||
.callback = furi_hal_i2c_bus_handle_external_event,
|
||||
};
|
31
bootloader/targets/f6/furi-hal/furi-hal-i2c-config.h
Normal file
31
bootloader/targets/f6/furi-hal/furi-hal-i2c-config.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi-hal-i2c-types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Internal(power) i2c bus, I2C1, under reset when not used */
|
||||
extern FuriHalI2cBus furi_hal_i2c_bus_power;
|
||||
|
||||
/** External i2c bus, I2C3, under reset when not used */
|
||||
extern FuriHalI2cBus furi_hal_i2c_bus_external;
|
||||
|
||||
/** Handle for internal(power) i2c bus
|
||||
* Bus: furi_hal_i2c_bus_external
|
||||
* Pins: PA9(SCL) / PA10(SDA), float on release
|
||||
* Params: 400khz
|
||||
*/
|
||||
extern FuriHalI2cBusHandle furi_hal_i2c_handle_power;
|
||||
|
||||
/** Handle for external i2c bus
|
||||
* Bus: furi_hal_i2c_bus_external
|
||||
* Pins: PC0(SCL) / PC1(SDA), float on release
|
||||
* Params: 100khz
|
||||
*/
|
||||
extern FuriHalI2cBusHandle furi_hal_i2c_handle_external;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
51
bootloader/targets/f6/furi-hal/furi-hal-i2c-types.h
Normal file
51
bootloader/targets/f6/furi-hal/furi-hal-i2c-types.h
Normal file
@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include <stm32wbxx_ll_i2c.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct FuriHalI2cBus FuriHalI2cBus;
|
||||
typedef struct FuriHalI2cBusHandle FuriHalI2cBusHandle;
|
||||
|
||||
/** FuriHal i2c bus states */
|
||||
typedef enum {
|
||||
FuriHalI2cBusEventInit, /**< Bus initialization event, called on system start */
|
||||
FuriHalI2cBusEventDeinit, /**< Bus deinitialization event, called on system stop */
|
||||
FuriHalI2cBusEventLock, /**< Bus lock event, called before activation */
|
||||
FuriHalI2cBusEventUnlock, /**< Bus unlock event, called after deactivation */
|
||||
FuriHalI2cBusEventActivate, /**< Bus activation event, called before handle activation */
|
||||
FuriHalI2cBusEventDeactivate, /**< Bus deactivation event, called after handle deactivation */
|
||||
} FuriHalI2cBusEvent;
|
||||
|
||||
/** FuriHal i2c bus event callback */
|
||||
typedef void (*FuriHalI2cBusEventCallback)(FuriHalI2cBus* bus, FuriHalI2cBusEvent event);
|
||||
|
||||
/** FuriHal i2c bus */
|
||||
struct FuriHalI2cBus {
|
||||
I2C_TypeDef* i2c;
|
||||
FuriHalI2cBusHandle* current_handle;
|
||||
FuriHalI2cBusEventCallback callback;
|
||||
};
|
||||
|
||||
/** FuriHal i2c handle states */
|
||||
typedef enum {
|
||||
FuriHalI2cBusHandleEventActivate, /**< Handle activate: connect gpio and apply bus config */
|
||||
FuriHalI2cBusHandleEventDeactivate, /**< Handle deactivate: disconnect gpio and reset bus config */
|
||||
} FuriHalI2cBusHandleEvent;
|
||||
|
||||
/** FuriHal i2c handle event callback */
|
||||
typedef void (*FuriHalI2cBusHandleEventCallback)(
|
||||
FuriHalI2cBusHandle* handle,
|
||||
FuriHalI2cBusHandleEvent event);
|
||||
|
||||
/** FuriHal i2c handle */
|
||||
struct FuriHalI2cBusHandle {
|
||||
FuriHalI2cBus* bus;
|
||||
FuriHalI2cBusHandleEventCallback callback;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,66 +1,64 @@
|
||||
#include <furi-hal-i2c.h>
|
||||
#include <furi-hal-version.h>
|
||||
|
||||
#include <stm32wbxx_ll_bus.h>
|
||||
#include <stm32wbxx_ll_i2c.h>
|
||||
#include <stm32wbxx_ll_rcc.h>
|
||||
#include <stm32wbxx_ll_gpio.h>
|
||||
#include <stm32wbxx_ll_cortex.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
void furi_hal_i2c_init() {
|
||||
LL_I2C_InitTypeDef I2C_InitStruct = {0};
|
||||
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
furi_hal_i2c_bus_power.callback(&furi_hal_i2c_bus_power, FuriHalI2cBusEventInit);
|
||||
}
|
||||
|
||||
LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);
|
||||
void furi_hal_i2c_acquire(FuriHalI2cBusHandle* handle) {
|
||||
handle->bus->callback(handle->bus, FuriHalI2cBusEventLock);
|
||||
|
||||
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
|
||||
GPIO_InitStruct.Pin = POWER_I2C_SCL_Pin | POWER_I2C_SDA_Pin;
|
||||
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
|
||||
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
|
||||
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
|
||||
GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
|
||||
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
assert(handle->bus->current_handle == NULL);
|
||||
|
||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);
|
||||
handle->bus->current_handle = handle;
|
||||
|
||||
I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
|
||||
I2C_InitStruct.Timing = POWER_I2C_TIMINGS;
|
||||
I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
|
||||
I2C_InitStruct.DigitalFilter = 0;
|
||||
I2C_InitStruct.OwnAddress1 = 0;
|
||||
I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
|
||||
I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
|
||||
LL_I2C_Init(I2C1, &I2C_InitStruct);
|
||||
LL_I2C_EnableAutoEndMode(I2C1);
|
||||
LL_I2C_SetOwnAddress2(I2C1, 0, LL_I2C_OWNADDRESS2_NOMASK);
|
||||
LL_I2C_DisableOwnAddress2(I2C1);
|
||||
LL_I2C_DisableGeneralCall(I2C1);
|
||||
LL_I2C_EnableClockStretching(I2C1);
|
||||
handle->bus->callback(handle->bus, FuriHalI2cBusEventActivate);
|
||||
|
||||
handle->callback(handle, FuriHalI2cBusHandleEventActivate);
|
||||
}
|
||||
|
||||
void furi_hal_i2c_release(FuriHalI2cBusHandle* handle) {
|
||||
assert(handle->bus->current_handle == handle);
|
||||
|
||||
handle->callback(handle, FuriHalI2cBusHandleEventDeactivate);
|
||||
|
||||
handle->bus->callback(handle->bus, FuriHalI2cBusEventDeactivate);
|
||||
|
||||
handle->bus->current_handle = NULL;
|
||||
|
||||
handle->bus->callback(handle->bus, FuriHalI2cBusEventUnlock);
|
||||
}
|
||||
|
||||
bool furi_hal_i2c_tx(
|
||||
I2C_TypeDef* instance,
|
||||
FuriHalI2cBusHandle* handle,
|
||||
uint8_t address,
|
||||
const uint8_t* data,
|
||||
uint8_t size,
|
||||
uint32_t timeout) {
|
||||
assert(handle->bus->current_handle == handle);
|
||||
uint32_t time_left = timeout;
|
||||
bool ret = true;
|
||||
|
||||
while(LL_I2C_IsActiveFlag_BUSY(instance))
|
||||
while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
|
||||
;
|
||||
|
||||
LL_I2C_HandleTransfer(
|
||||
instance,
|
||||
handle->bus->i2c,
|
||||
address,
|
||||
LL_I2C_ADDRSLAVE_7BIT,
|
||||
size,
|
||||
LL_I2C_MODE_AUTOEND,
|
||||
LL_I2C_GENERATE_START_WRITE);
|
||||
|
||||
while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
|
||||
if(LL_I2C_IsActiveFlag_TXIS(instance)) {
|
||||
LL_I2C_TransmitData8(instance, (*data));
|
||||
while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
|
||||
if(LL_I2C_IsActiveFlag_TXIS(handle->bus->i2c)) {
|
||||
LL_I2C_TransmitData8(handle->bus->i2c, (*data));
|
||||
data++;
|
||||
size--;
|
||||
time_left = timeout;
|
||||
@ -74,34 +72,35 @@ bool furi_hal_i2c_tx(
|
||||
}
|
||||
}
|
||||
|
||||
LL_I2C_ClearFlag_STOP(instance);
|
||||
LL_I2C_ClearFlag_STOP(handle->bus->i2c);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool furi_hal_i2c_rx(
|
||||
I2C_TypeDef* instance,
|
||||
FuriHalI2cBusHandle* handle,
|
||||
uint8_t address,
|
||||
uint8_t* data,
|
||||
uint8_t size,
|
||||
uint32_t timeout) {
|
||||
assert(handle->bus->current_handle == handle);
|
||||
uint32_t time_left = timeout;
|
||||
bool ret = true;
|
||||
|
||||
while(LL_I2C_IsActiveFlag_BUSY(instance))
|
||||
while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
|
||||
;
|
||||
|
||||
LL_I2C_HandleTransfer(
|
||||
instance,
|
||||
handle->bus->i2c,
|
||||
address,
|
||||
LL_I2C_ADDRSLAVE_7BIT,
|
||||
size,
|
||||
LL_I2C_MODE_AUTOEND,
|
||||
LL_I2C_GENERATE_START_READ);
|
||||
|
||||
while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
|
||||
if(LL_I2C_IsActiveFlag_RXNE(instance)) {
|
||||
*data = LL_I2C_ReceiveData8(instance);
|
||||
while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
|
||||
if(LL_I2C_IsActiveFlag_RXNE(handle->bus->i2c)) {
|
||||
*data = LL_I2C_ReceiveData8(handle->bus->i2c);
|
||||
data++;
|
||||
size--;
|
||||
time_left = timeout;
|
||||
@ -115,21 +114,21 @@ bool furi_hal_i2c_rx(
|
||||
}
|
||||
}
|
||||
|
||||
LL_I2C_ClearFlag_STOP(instance);
|
||||
LL_I2C_ClearFlag_STOP(handle->bus->i2c);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool furi_hal_i2c_trx(
|
||||
I2C_TypeDef* instance,
|
||||
FuriHalI2cBusHandle* handle,
|
||||
uint8_t address,
|
||||
const uint8_t* tx_data,
|
||||
uint8_t tx_size,
|
||||
uint8_t* rx_data,
|
||||
uint8_t rx_size,
|
||||
uint32_t timeout) {
|
||||
if(furi_hal_i2c_tx(instance, address, tx_data, tx_size, timeout) &&
|
||||
furi_hal_i2c_rx(instance, address, rx_data, rx_size, timeout)) {
|
||||
if(furi_hal_i2c_tx(handle, address, tx_data, tx_size, timeout) &&
|
||||
furi_hal_i2c_rx(handle, address, rx_data, rx_size, timeout)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -1,31 +1,82 @@
|
||||
/**
|
||||
* @file furi-hal-i2c.h
|
||||
* I2C HAL API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <furi-hal-resources.h>
|
||||
#include <furi-hal-i2c-config.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Init I2C
|
||||
*/
|
||||
void furi_hal_i2c_init();
|
||||
|
||||
/** Acquire i2c bus handle
|
||||
*
|
||||
* @return Instance of FuriHalI2cBus
|
||||
*/
|
||||
void furi_hal_i2c_acquire(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Release i2c bus handle
|
||||
*
|
||||
* @param bus instance of FuriHalI2cBus aquired in `furi_hal_i2c_acquire`
|
||||
*/
|
||||
void furi_hal_i2c_release(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Perform I2C tx transfer
|
||||
*
|
||||
* @param instance I2C_TypeDef instance
|
||||
* @param address I2C slave address
|
||||
* @param data pointer to data buffer
|
||||
* @param size size of data buffer
|
||||
* @param timeout timeout in ticks
|
||||
*
|
||||
* @return true on successful transfer, false otherwise
|
||||
*/
|
||||
bool furi_hal_i2c_tx(
|
||||
I2C_TypeDef* instance,
|
||||
FuriHalI2cBusHandle* handle,
|
||||
const uint8_t address,
|
||||
const uint8_t* data,
|
||||
const uint8_t size,
|
||||
uint32_t timeout);
|
||||
|
||||
/** Perform I2C rx transfer
|
||||
*
|
||||
* @param instance I2C_TypeDef instance
|
||||
* @param address I2C slave address
|
||||
* @param data pointer to data buffer
|
||||
* @param size size of data buffer
|
||||
* @param timeout timeout in ticks
|
||||
*
|
||||
* @return true on successful transfer, false otherwise
|
||||
*/
|
||||
bool furi_hal_i2c_rx(
|
||||
I2C_TypeDef* instance,
|
||||
FuriHalI2cBusHandle* handle,
|
||||
const uint8_t address,
|
||||
uint8_t* data,
|
||||
const uint8_t size,
|
||||
uint32_t timeout);
|
||||
|
||||
/** Perform I2C tx and rx transfers
|
||||
*
|
||||
* @param instance I2C_TypeDef instance
|
||||
* @param address I2C slave address
|
||||
* @param tx_data pointer to tx data buffer
|
||||
* @param tx_size size of tx data buffer
|
||||
* @param rx_data pointer to rx data buffer
|
||||
* @param rx_size size of rx data buffer
|
||||
* @param timeout timeout in ticks
|
||||
*
|
||||
* @return true on successful transfer, false otherwise
|
||||
*/
|
||||
bool furi_hal_i2c_trx(
|
||||
I2C_TypeDef* instance,
|
||||
FuriHalI2cBusHandle* handle,
|
||||
const uint8_t address,
|
||||
const uint8_t* tx_data,
|
||||
const uint8_t tx_size,
|
||||
@ -33,11 +84,6 @@ bool furi_hal_i2c_trx(
|
||||
const uint8_t rx_size,
|
||||
uint32_t timeout);
|
||||
|
||||
#define with_furi_hal_i2c(type, pointer, function_body) \
|
||||
{ \
|
||||
*pointer = ({ type __fn__ function_body __fn__; })(); \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -7,37 +7,43 @@
|
||||
#define LED_CURRENT_WHITE 150
|
||||
|
||||
void furi_hal_light_init() {
|
||||
lp5562_reset();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
|
||||
lp5562_set_channel_current(LP5562ChannelRed, LED_CURRENT_RED);
|
||||
lp5562_set_channel_current(LP5562ChannelGreen, LED_CURRENT_GREEN);
|
||||
lp5562_set_channel_current(LP5562ChannelBlue, LED_CURRENT_BLUE);
|
||||
lp5562_set_channel_current(LP5562ChannelWhite, LED_CURRENT_WHITE);
|
||||
lp5562_reset(&furi_hal_i2c_handle_power);
|
||||
|
||||
lp5562_set_channel_value(LP5562ChannelRed, 0x00);
|
||||
lp5562_set_channel_value(LP5562ChannelGreen, 0x00);
|
||||
lp5562_set_channel_value(LP5562ChannelBlue, 0x00);
|
||||
lp5562_set_channel_value(LP5562ChannelWhite, 0x00);
|
||||
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelRed, LED_CURRENT_RED);
|
||||
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelGreen, LED_CURRENT_GREEN);
|
||||
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelBlue, LED_CURRENT_BLUE);
|
||||
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelWhite, LED_CURRENT_WHITE);
|
||||
|
||||
lp5562_enable();
|
||||
lp5562_configure();
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, 0x00);
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, 0x00);
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, 0x00);
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, 0x00);
|
||||
|
||||
lp5562_enable(&furi_hal_i2c_handle_power);
|
||||
lp5562_configure(&furi_hal_i2c_handle_power);
|
||||
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
||||
|
||||
void furi_hal_light_set(Light light, uint8_t value) {
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
switch(light) {
|
||||
case LightRed:
|
||||
lp5562_set_channel_value(LP5562ChannelRed, value);
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value);
|
||||
break;
|
||||
case LightGreen:
|
||||
lp5562_set_channel_value(LP5562ChannelGreen, value);
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value);
|
||||
break;
|
||||
case LightBlue:
|
||||
lp5562_set_channel_value(LP5562ChannelBlue, value);
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value);
|
||||
break;
|
||||
case LightBacklight:
|
||||
lp5562_set_channel_value(LP5562ChannelWhite, value);
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
@ -39,3 +39,6 @@ const GpioPin gpio_irda_tx = {.port = IR_TX_GPIO_Port, .pin = IR_TX_Pin};
|
||||
|
||||
const GpioPin gpio_usart_tx = {.port = USART1_TX_Port, .pin = USART1_TX_Pin};
|
||||
const GpioPin gpio_usart_rx = {.port = USART1_RX_Port, .pin = USART1_RX_Pin};
|
||||
|
||||
const GpioPin gpio_i2c_power_sda = {.port = GPIOA, .pin = LL_GPIO_PIN_10};
|
||||
const GpioPin gpio_i2c_power_scl = {.port = GPIOA, .pin = LL_GPIO_PIN_9};
|
||||
|
@ -8,18 +8,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define POWER_I2C_SCL_Pin LL_GPIO_PIN_9
|
||||
#define POWER_I2C_SCL_GPIO_Port GPIOA
|
||||
#define POWER_I2C_SDA_Pin LL_GPIO_PIN_10
|
||||
#define POWER_I2C_SDA_GPIO_Port GPIOA
|
||||
|
||||
#define POWER_I2C I2C1
|
||||
/* Timing register value is computed with the STM32CubeMX Tool,
|
||||
* Fast Mode @100kHz with I2CCLK = 64 MHz,
|
||||
* rise time = 0ns, fall time = 0ns
|
||||
*/
|
||||
#define POWER_I2C_TIMINGS 0x10707DBC
|
||||
|
||||
/* Input Keys */
|
||||
typedef enum {
|
||||
InputKeyUp,
|
||||
@ -77,6 +65,9 @@ extern const GpioPin gpio_irda_tx;
|
||||
extern const GpioPin gpio_usart_tx;
|
||||
extern const GpioPin gpio_usart_rx;
|
||||
|
||||
extern const GpioPin gpio_i2c_power_sda;
|
||||
extern const GpioPin gpio_i2c_power_scl;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
149
bootloader/targets/f7/furi-hal/furi-hal-i2c-config.c
Normal file
149
bootloader/targets/f7/furi-hal/furi-hal-i2c-config.c
Normal file
@ -0,0 +1,149 @@
|
||||
#include "furi-hal-i2c-config.h"
|
||||
#include <furi-hal-resources.h>
|
||||
#include <furi-hal-version.h>
|
||||
|
||||
#include <stm32wbxx_ll_rcc.h>
|
||||
#include <stm32wbxx_ll_bus.h>
|
||||
|
||||
/** Timing register value is computed with the STM32CubeMX Tool,
|
||||
* Standard Mode @100kHz with I2CCLK = 64 MHz,
|
||||
* rise time = 0ns, fall time = 0ns
|
||||
*/
|
||||
#define FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100 0x10707DBC
|
||||
|
||||
/** Timing register value is computed with the STM32CubeMX Tool,
|
||||
* Fast Mode @400kHz with I2CCLK = 64 MHz,
|
||||
* rise time = 0ns, fall time = 0ns
|
||||
*/
|
||||
#define FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_400 0x00602173
|
||||
|
||||
static void furi_hal_i2c_bus_power_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) {
|
||||
if(event == FuriHalI2cBusEventInit) {
|
||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);
|
||||
LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);
|
||||
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1);
|
||||
bus->current_handle = NULL;
|
||||
} else if(event == FuriHalI2cBusEventDeinit) {
|
||||
} else if(event == FuriHalI2cBusEventLock) {
|
||||
} else if(event == FuriHalI2cBusEventUnlock) {
|
||||
} else if(event == FuriHalI2cBusEventActivate) {
|
||||
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C1);
|
||||
} else if(event == FuriHalI2cBusEventDeactivate) {
|
||||
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1);
|
||||
}
|
||||
}
|
||||
|
||||
FuriHalI2cBus furi_hal_i2c_bus_power = {
|
||||
.i2c = I2C1,
|
||||
.current_handle = NULL,
|
||||
.callback = furi_hal_i2c_bus_power_event,
|
||||
};
|
||||
|
||||
static void furi_hal_i2c_bus_external_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) {
|
||||
if(event == FuriHalI2cBusEventActivate) {
|
||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C3);
|
||||
LL_RCC_SetI2CClockSource(LL_RCC_I2C3_CLKSOURCE_PCLK1);
|
||||
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C3);
|
||||
} else if(event == FuriHalI2cBusEventDeactivate) {
|
||||
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C3);
|
||||
}
|
||||
}
|
||||
|
||||
FuriHalI2cBus furi_hal_i2c_bus_external = {
|
||||
.i2c = I2C3,
|
||||
.current_handle = NULL,
|
||||
.callback = furi_hal_i2c_bus_external_event,
|
||||
};
|
||||
|
||||
void furi_hal_i2c_bus_handle_power_event(
|
||||
FuriHalI2cBusHandle* handle,
|
||||
FuriHalI2cBusHandleEvent event) {
|
||||
if(event == FuriHalI2cBusHandleEventActivate) {
|
||||
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
|
||||
hal_gpio_init_ex(
|
||||
&gpio_i2c_power_sda,
|
||||
GpioModeAltFunctionOpenDrain,
|
||||
GpioPullNo,
|
||||
GpioSpeedLow,
|
||||
GpioAltFn4I2C1);
|
||||
hal_gpio_init_ex(
|
||||
&gpio_i2c_power_scl,
|
||||
GpioModeAltFunctionOpenDrain,
|
||||
GpioPullNo,
|
||||
GpioSpeedLow,
|
||||
GpioAltFn4I2C1);
|
||||
|
||||
LL_I2C_InitTypeDef I2C_InitStruct = {0};
|
||||
I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
|
||||
I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
|
||||
I2C_InitStruct.DigitalFilter = 0;
|
||||
I2C_InitStruct.OwnAddress1 = 0;
|
||||
I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
|
||||
I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
|
||||
if(furi_hal_version_get_hw_version() > 10) {
|
||||
I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_400;
|
||||
} else {
|
||||
I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100;
|
||||
}
|
||||
LL_I2C_Init(handle->bus->i2c, &I2C_InitStruct);
|
||||
|
||||
LL_I2C_EnableAutoEndMode(handle->bus->i2c);
|
||||
LL_I2C_SetOwnAddress2(handle->bus->i2c, 0, LL_I2C_OWNADDRESS2_NOMASK);
|
||||
LL_I2C_DisableOwnAddress2(handle->bus->i2c);
|
||||
LL_I2C_DisableGeneralCall(handle->bus->i2c);
|
||||
LL_I2C_EnableClockStretching(handle->bus->i2c);
|
||||
LL_I2C_Enable(handle->bus->i2c);
|
||||
} else if(event == FuriHalI2cBusHandleEventDeactivate) {
|
||||
LL_I2C_Disable(handle->bus->i2c);
|
||||
hal_gpio_write(&gpio_i2c_power_sda, 1);
|
||||
hal_gpio_write(&gpio_i2c_power_scl, 1);
|
||||
hal_gpio_init_ex(
|
||||
&gpio_i2c_power_sda, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
|
||||
hal_gpio_init_ex(
|
||||
&gpio_i2c_power_scl, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
|
||||
}
|
||||
}
|
||||
|
||||
FuriHalI2cBusHandle furi_hal_i2c_handle_power = {
|
||||
.bus = &furi_hal_i2c_bus_power,
|
||||
.callback = furi_hal_i2c_bus_handle_power_event,
|
||||
};
|
||||
|
||||
void furi_hal_i2c_bus_handle_external_event(
|
||||
FuriHalI2cBusHandle* handle,
|
||||
FuriHalI2cBusHandleEvent event) {
|
||||
if(event == FuriHalI2cBusHandleEventActivate) {
|
||||
hal_gpio_init_ex(
|
||||
&gpio_ext_pc0, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C3);
|
||||
hal_gpio_init_ex(
|
||||
&gpio_ext_pc1, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C3);
|
||||
|
||||
LL_I2C_InitTypeDef I2C_InitStruct = {0};
|
||||
I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
|
||||
I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
|
||||
I2C_InitStruct.DigitalFilter = 0;
|
||||
I2C_InitStruct.OwnAddress1 = 0;
|
||||
I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
|
||||
I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
|
||||
I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100;
|
||||
LL_I2C_Init(handle->bus->i2c, &I2C_InitStruct);
|
||||
|
||||
LL_I2C_EnableAutoEndMode(handle->bus->i2c);
|
||||
LL_I2C_SetOwnAddress2(handle->bus->i2c, 0, LL_I2C_OWNADDRESS2_NOMASK);
|
||||
LL_I2C_DisableOwnAddress2(handle->bus->i2c);
|
||||
LL_I2C_DisableGeneralCall(handle->bus->i2c);
|
||||
LL_I2C_EnableClockStretching(handle->bus->i2c);
|
||||
LL_I2C_Enable(handle->bus->i2c);
|
||||
} else if(event == FuriHalI2cBusHandleEventDeactivate) {
|
||||
LL_I2C_Disable(handle->bus->i2c);
|
||||
hal_gpio_write(&gpio_ext_pc0, 1);
|
||||
hal_gpio_write(&gpio_ext_pc1, 1);
|
||||
hal_gpio_init_ex(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
|
||||
hal_gpio_init_ex(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
|
||||
}
|
||||
}
|
||||
|
||||
FuriHalI2cBusHandle furi_hal_i2c_handle_external = {
|
||||
.bus = &furi_hal_i2c_bus_external,
|
||||
.callback = furi_hal_i2c_bus_handle_external_event,
|
||||
};
|
31
bootloader/targets/f7/furi-hal/furi-hal-i2c-config.h
Normal file
31
bootloader/targets/f7/furi-hal/furi-hal-i2c-config.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi-hal-i2c-types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Internal(power) i2c bus, I2C1, under reset when not used */
|
||||
extern FuriHalI2cBus furi_hal_i2c_bus_power;
|
||||
|
||||
/** External i2c bus, I2C3, under reset when not used */
|
||||
extern FuriHalI2cBus furi_hal_i2c_bus_external;
|
||||
|
||||
/** Handle for internal(power) i2c bus
|
||||
* Bus: furi_hal_i2c_bus_external
|
||||
* Pins: PA9(SCL) / PA10(SDA), float on release
|
||||
* Params: 400khz
|
||||
*/
|
||||
extern FuriHalI2cBusHandle furi_hal_i2c_handle_power;
|
||||
|
||||
/** Handle for external i2c bus
|
||||
* Bus: furi_hal_i2c_bus_external
|
||||
* Pins: PC0(SCL) / PC1(SDA), float on release
|
||||
* Params: 100khz
|
||||
*/
|
||||
extern FuriHalI2cBusHandle furi_hal_i2c_handle_external;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
51
bootloader/targets/f7/furi-hal/furi-hal-i2c-types.h
Normal file
51
bootloader/targets/f7/furi-hal/furi-hal-i2c-types.h
Normal file
@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include <stm32wbxx_ll_i2c.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct FuriHalI2cBus FuriHalI2cBus;
|
||||
typedef struct FuriHalI2cBusHandle FuriHalI2cBusHandle;
|
||||
|
||||
/** FuriHal i2c bus states */
|
||||
typedef enum {
|
||||
FuriHalI2cBusEventInit, /**< Bus initialization event, called on system start */
|
||||
FuriHalI2cBusEventDeinit, /**< Bus deinitialization event, called on system stop */
|
||||
FuriHalI2cBusEventLock, /**< Bus lock event, called before activation */
|
||||
FuriHalI2cBusEventUnlock, /**< Bus unlock event, called after deactivation */
|
||||
FuriHalI2cBusEventActivate, /**< Bus activation event, called before handle activation */
|
||||
FuriHalI2cBusEventDeactivate, /**< Bus deactivation event, called after handle deactivation */
|
||||
} FuriHalI2cBusEvent;
|
||||
|
||||
/** FuriHal i2c bus event callback */
|
||||
typedef void (*FuriHalI2cBusEventCallback)(FuriHalI2cBus* bus, FuriHalI2cBusEvent event);
|
||||
|
||||
/** FuriHal i2c bus */
|
||||
struct FuriHalI2cBus {
|
||||
I2C_TypeDef* i2c;
|
||||
FuriHalI2cBusHandle* current_handle;
|
||||
FuriHalI2cBusEventCallback callback;
|
||||
};
|
||||
|
||||
/** FuriHal i2c handle states */
|
||||
typedef enum {
|
||||
FuriHalI2cBusHandleEventActivate, /**< Handle activate: connect gpio and apply bus config */
|
||||
FuriHalI2cBusHandleEventDeactivate, /**< Handle deactivate: disconnect gpio and reset bus config */
|
||||
} FuriHalI2cBusHandleEvent;
|
||||
|
||||
/** FuriHal i2c handle event callback */
|
||||
typedef void (*FuriHalI2cBusHandleEventCallback)(
|
||||
FuriHalI2cBusHandle* handle,
|
||||
FuriHalI2cBusHandleEvent event);
|
||||
|
||||
/** FuriHal i2c handle */
|
||||
struct FuriHalI2cBusHandle {
|
||||
FuriHalI2cBus* bus;
|
||||
FuriHalI2cBusHandleEventCallback callback;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,66 +1,64 @@
|
||||
#include <furi-hal-i2c.h>
|
||||
#include <furi-hal-version.h>
|
||||
|
||||
#include <stm32wbxx_ll_bus.h>
|
||||
#include <stm32wbxx_ll_i2c.h>
|
||||
#include <stm32wbxx_ll_rcc.h>
|
||||
#include <stm32wbxx_ll_gpio.h>
|
||||
#include <stm32wbxx_ll_cortex.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
void furi_hal_i2c_init() {
|
||||
LL_I2C_InitTypeDef I2C_InitStruct = {0};
|
||||
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
furi_hal_i2c_bus_power.callback(&furi_hal_i2c_bus_power, FuriHalI2cBusEventInit);
|
||||
}
|
||||
|
||||
LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);
|
||||
void furi_hal_i2c_acquire(FuriHalI2cBusHandle* handle) {
|
||||
handle->bus->callback(handle->bus, FuriHalI2cBusEventLock);
|
||||
|
||||
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
|
||||
GPIO_InitStruct.Pin = POWER_I2C_SCL_Pin | POWER_I2C_SDA_Pin;
|
||||
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
|
||||
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
|
||||
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
|
||||
GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
|
||||
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
assert(handle->bus->current_handle == NULL);
|
||||
|
||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);
|
||||
handle->bus->current_handle = handle;
|
||||
|
||||
I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
|
||||
I2C_InitStruct.Timing = POWER_I2C_TIMINGS;
|
||||
I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
|
||||
I2C_InitStruct.DigitalFilter = 0;
|
||||
I2C_InitStruct.OwnAddress1 = 0;
|
||||
I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
|
||||
I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
|
||||
LL_I2C_Init(I2C1, &I2C_InitStruct);
|
||||
LL_I2C_EnableAutoEndMode(I2C1);
|
||||
LL_I2C_SetOwnAddress2(I2C1, 0, LL_I2C_OWNADDRESS2_NOMASK);
|
||||
LL_I2C_DisableOwnAddress2(I2C1);
|
||||
LL_I2C_DisableGeneralCall(I2C1);
|
||||
LL_I2C_EnableClockStretching(I2C1);
|
||||
handle->bus->callback(handle->bus, FuriHalI2cBusEventActivate);
|
||||
|
||||
handle->callback(handle, FuriHalI2cBusHandleEventActivate);
|
||||
}
|
||||
|
||||
void furi_hal_i2c_release(FuriHalI2cBusHandle* handle) {
|
||||
assert(handle->bus->current_handle == handle);
|
||||
|
||||
handle->callback(handle, FuriHalI2cBusHandleEventDeactivate);
|
||||
|
||||
handle->bus->callback(handle->bus, FuriHalI2cBusEventDeactivate);
|
||||
|
||||
handle->bus->current_handle = NULL;
|
||||
|
||||
handle->bus->callback(handle->bus, FuriHalI2cBusEventUnlock);
|
||||
}
|
||||
|
||||
bool furi_hal_i2c_tx(
|
||||
I2C_TypeDef* instance,
|
||||
FuriHalI2cBusHandle* handle,
|
||||
uint8_t address,
|
||||
const uint8_t* data,
|
||||
uint8_t size,
|
||||
uint32_t timeout) {
|
||||
assert(handle->bus->current_handle == handle);
|
||||
uint32_t time_left = timeout;
|
||||
bool ret = true;
|
||||
|
||||
while(LL_I2C_IsActiveFlag_BUSY(instance))
|
||||
while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
|
||||
;
|
||||
|
||||
LL_I2C_HandleTransfer(
|
||||
instance,
|
||||
handle->bus->i2c,
|
||||
address,
|
||||
LL_I2C_ADDRSLAVE_7BIT,
|
||||
size,
|
||||
LL_I2C_MODE_AUTOEND,
|
||||
LL_I2C_GENERATE_START_WRITE);
|
||||
|
||||
while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
|
||||
if(LL_I2C_IsActiveFlag_TXIS(instance)) {
|
||||
LL_I2C_TransmitData8(instance, (*data));
|
||||
while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
|
||||
if(LL_I2C_IsActiveFlag_TXIS(handle->bus->i2c)) {
|
||||
LL_I2C_TransmitData8(handle->bus->i2c, (*data));
|
||||
data++;
|
||||
size--;
|
||||
time_left = timeout;
|
||||
@ -74,34 +72,35 @@ bool furi_hal_i2c_tx(
|
||||
}
|
||||
}
|
||||
|
||||
LL_I2C_ClearFlag_STOP(instance);
|
||||
LL_I2C_ClearFlag_STOP(handle->bus->i2c);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool furi_hal_i2c_rx(
|
||||
I2C_TypeDef* instance,
|
||||
FuriHalI2cBusHandle* handle,
|
||||
uint8_t address,
|
||||
uint8_t* data,
|
||||
uint8_t size,
|
||||
uint32_t timeout) {
|
||||
assert(handle->bus->current_handle == handle);
|
||||
uint32_t time_left = timeout;
|
||||
bool ret = true;
|
||||
|
||||
while(LL_I2C_IsActiveFlag_BUSY(instance))
|
||||
while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
|
||||
;
|
||||
|
||||
LL_I2C_HandleTransfer(
|
||||
instance,
|
||||
handle->bus->i2c,
|
||||
address,
|
||||
LL_I2C_ADDRSLAVE_7BIT,
|
||||
size,
|
||||
LL_I2C_MODE_AUTOEND,
|
||||
LL_I2C_GENERATE_START_READ);
|
||||
|
||||
while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
|
||||
if(LL_I2C_IsActiveFlag_RXNE(instance)) {
|
||||
*data = LL_I2C_ReceiveData8(instance);
|
||||
while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
|
||||
if(LL_I2C_IsActiveFlag_RXNE(handle->bus->i2c)) {
|
||||
*data = LL_I2C_ReceiveData8(handle->bus->i2c);
|
||||
data++;
|
||||
size--;
|
||||
time_left = timeout;
|
||||
@ -115,21 +114,21 @@ bool furi_hal_i2c_rx(
|
||||
}
|
||||
}
|
||||
|
||||
LL_I2C_ClearFlag_STOP(instance);
|
||||
LL_I2C_ClearFlag_STOP(handle->bus->i2c);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool furi_hal_i2c_trx(
|
||||
I2C_TypeDef* instance,
|
||||
FuriHalI2cBusHandle* handle,
|
||||
uint8_t address,
|
||||
const uint8_t* tx_data,
|
||||
uint8_t tx_size,
|
||||
uint8_t* rx_data,
|
||||
uint8_t rx_size,
|
||||
uint32_t timeout) {
|
||||
if(furi_hal_i2c_tx(instance, address, tx_data, tx_size, timeout) &&
|
||||
furi_hal_i2c_rx(instance, address, rx_data, rx_size, timeout)) {
|
||||
if(furi_hal_i2c_tx(handle, address, tx_data, tx_size, timeout) &&
|
||||
furi_hal_i2c_rx(handle, address, rx_data, rx_size, timeout)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -1,31 +1,82 @@
|
||||
/**
|
||||
* @file furi-hal-i2c.h
|
||||
* I2C HAL API
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <furi-hal-resources.h>
|
||||
#include <furi-hal-i2c-config.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Init I2C
|
||||
*/
|
||||
void furi_hal_i2c_init();
|
||||
|
||||
/** Acquire i2c bus handle
|
||||
*
|
||||
* @return Instance of FuriHalI2cBus
|
||||
*/
|
||||
void furi_hal_i2c_acquire(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Release i2c bus handle
|
||||
*
|
||||
* @param bus instance of FuriHalI2cBus aquired in `furi_hal_i2c_acquire`
|
||||
*/
|
||||
void furi_hal_i2c_release(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Perform I2C tx transfer
|
||||
*
|
||||
* @param instance I2C_TypeDef instance
|
||||
* @param address I2C slave address
|
||||
* @param data pointer to data buffer
|
||||
* @param size size of data buffer
|
||||
* @param timeout timeout in ticks
|
||||
*
|
||||
* @return true on successful transfer, false otherwise
|
||||
*/
|
||||
bool furi_hal_i2c_tx(
|
||||
I2C_TypeDef* instance,
|
||||
FuriHalI2cBusHandle* handle,
|
||||
const uint8_t address,
|
||||
const uint8_t* data,
|
||||
const uint8_t size,
|
||||
uint32_t timeout);
|
||||
|
||||
/** Perform I2C rx transfer
|
||||
*
|
||||
* @param instance I2C_TypeDef instance
|
||||
* @param address I2C slave address
|
||||
* @param data pointer to data buffer
|
||||
* @param size size of data buffer
|
||||
* @param timeout timeout in ticks
|
||||
*
|
||||
* @return true on successful transfer, false otherwise
|
||||
*/
|
||||
bool furi_hal_i2c_rx(
|
||||
I2C_TypeDef* instance,
|
||||
FuriHalI2cBusHandle* handle,
|
||||
const uint8_t address,
|
||||
uint8_t* data,
|
||||
const uint8_t size,
|
||||
uint32_t timeout);
|
||||
|
||||
/** Perform I2C tx and rx transfers
|
||||
*
|
||||
* @param instance I2C_TypeDef instance
|
||||
* @param address I2C slave address
|
||||
* @param tx_data pointer to tx data buffer
|
||||
* @param tx_size size of tx data buffer
|
||||
* @param rx_data pointer to rx data buffer
|
||||
* @param rx_size size of rx data buffer
|
||||
* @param timeout timeout in ticks
|
||||
*
|
||||
* @return true on successful transfer, false otherwise
|
||||
*/
|
||||
bool furi_hal_i2c_trx(
|
||||
I2C_TypeDef* instance,
|
||||
FuriHalI2cBusHandle* handle,
|
||||
const uint8_t address,
|
||||
const uint8_t* tx_data,
|
||||
const uint8_t tx_size,
|
||||
@ -33,11 +84,6 @@ bool furi_hal_i2c_trx(
|
||||
const uint8_t rx_size,
|
||||
uint32_t timeout);
|
||||
|
||||
#define with_furi_hal_i2c(type, pointer, function_body) \
|
||||
{ \
|
||||
*pointer = ({ type __fn__ function_body __fn__; })(); \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -7,37 +7,43 @@
|
||||
#define LED_CURRENT_WHITE 150
|
||||
|
||||
void furi_hal_light_init() {
|
||||
lp5562_reset();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
|
||||
lp5562_set_channel_current(LP5562ChannelRed, LED_CURRENT_RED);
|
||||
lp5562_set_channel_current(LP5562ChannelGreen, LED_CURRENT_GREEN);
|
||||
lp5562_set_channel_current(LP5562ChannelBlue, LED_CURRENT_BLUE);
|
||||
lp5562_set_channel_current(LP5562ChannelWhite, LED_CURRENT_WHITE);
|
||||
lp5562_reset(&furi_hal_i2c_handle_power);
|
||||
|
||||
lp5562_set_channel_value(LP5562ChannelRed, 0x00);
|
||||
lp5562_set_channel_value(LP5562ChannelGreen, 0x00);
|
||||
lp5562_set_channel_value(LP5562ChannelBlue, 0x00);
|
||||
lp5562_set_channel_value(LP5562ChannelWhite, 0x00);
|
||||
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelRed, LED_CURRENT_RED);
|
||||
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelGreen, LED_CURRENT_GREEN);
|
||||
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelBlue, LED_CURRENT_BLUE);
|
||||
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelWhite, LED_CURRENT_WHITE);
|
||||
|
||||
lp5562_enable();
|
||||
lp5562_configure();
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, 0x00);
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, 0x00);
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, 0x00);
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, 0x00);
|
||||
|
||||
lp5562_enable(&furi_hal_i2c_handle_power);
|
||||
lp5562_configure(&furi_hal_i2c_handle_power);
|
||||
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
||||
|
||||
void furi_hal_light_set(Light light, uint8_t value) {
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
switch(light) {
|
||||
case LightRed:
|
||||
lp5562_set_channel_value(LP5562ChannelRed, value);
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value);
|
||||
break;
|
||||
case LightGreen:
|
||||
lp5562_set_channel_value(LP5562ChannelGreen, value);
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value);
|
||||
break;
|
||||
case LightBlue:
|
||||
lp5562_set_channel_value(LP5562ChannelBlue, value);
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value);
|
||||
break;
|
||||
case LightBacklight:
|
||||
lp5562_set_channel_value(LP5562ChannelWhite, value);
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
@ -39,3 +39,6 @@ const GpioPin gpio_irda_tx = {.port = IR_TX_GPIO_Port, .pin = IR_TX_Pin};
|
||||
|
||||
const GpioPin gpio_usart_tx = {.port = USART1_TX_Port, .pin = USART1_TX_Pin};
|
||||
const GpioPin gpio_usart_rx = {.port = USART1_RX_Port, .pin = USART1_RX_Pin};
|
||||
|
||||
const GpioPin gpio_i2c_power_sda = {.port = GPIOA, .pin = LL_GPIO_PIN_10};
|
||||
const GpioPin gpio_i2c_power_scl = {.port = GPIOA, .pin = LL_GPIO_PIN_9};
|
||||
|
@ -8,18 +8,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define POWER_I2C_SCL_Pin LL_GPIO_PIN_9
|
||||
#define POWER_I2C_SCL_GPIO_Port GPIOA
|
||||
#define POWER_I2C_SDA_Pin LL_GPIO_PIN_10
|
||||
#define POWER_I2C_SDA_GPIO_Port GPIOA
|
||||
|
||||
#define POWER_I2C I2C1
|
||||
/* Timing register value is computed with the STM32CubeMX Tool,
|
||||
* Fast Mode @100kHz with I2CCLK = 64 MHz,
|
||||
* rise time = 0ns, fall time = 0ns
|
||||
*/
|
||||
#define POWER_I2C_TIMINGS 0x10707DBC
|
||||
|
||||
/* Input Keys */
|
||||
typedef enum {
|
||||
InputKeyUp,
|
||||
@ -77,6 +65,9 @@ extern const GpioPin gpio_irda_tx;
|
||||
extern const GpioPin gpio_usart_tx;
|
||||
extern const GpioPin gpio_usart_rx;
|
||||
|
||||
extern const GpioPin gpio_i2c_power_sda;
|
||||
extern const GpioPin gpio_i2c_power_scl;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
133
firmware/targets/f6/furi-hal/furi-hal-i2c-config.c
Normal file
133
firmware/targets/f6/furi-hal/furi-hal-i2c-config.c
Normal file
@ -0,0 +1,133 @@
|
||||
#include "furi-hal-i2c-config.h"
|
||||
#include <furi-hal-resources.h>
|
||||
#include <furi-hal-version.h>
|
||||
|
||||
/** Timing register value is computed with the STM32CubeMX Tool,
|
||||
* Standard Mode @100kHz with I2CCLK = 64 MHz,
|
||||
* rise time = 0ns, fall time = 0ns
|
||||
*/
|
||||
#define FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100 0x10707DBC
|
||||
|
||||
/** Timing register value is computed with the STM32CubeMX Tool,
|
||||
* Fast Mode @400kHz with I2CCLK = 64 MHz,
|
||||
* rise time = 0ns, fall time = 0ns
|
||||
*/
|
||||
#define FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_400 0x00602173
|
||||
|
||||
osMutexId_t furi_hal_i2c_bus_power_mutex = NULL;
|
||||
|
||||
static void furi_hal_i2c_bus_power_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) {
|
||||
if (event == FuriHalI2cBusEventInit) {
|
||||
furi_hal_i2c_bus_power_mutex = osMutexNew(NULL);
|
||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);
|
||||
LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);
|
||||
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1);
|
||||
bus->current_handle = NULL;
|
||||
} else if (event == FuriHalI2cBusEventDeinit) {
|
||||
osMutexDelete(furi_hal_i2c_bus_power_mutex);
|
||||
} else if (event == FuriHalI2cBusEventLock) {
|
||||
furi_check(osMutexAcquire(furi_hal_i2c_bus_power_mutex, osWaitForever) == osOK);
|
||||
} else if (event == FuriHalI2cBusEventUnlock) {
|
||||
furi_check(osMutexRelease(furi_hal_i2c_bus_power_mutex) == osOK);
|
||||
} else if (event == FuriHalI2cBusEventActivate) {
|
||||
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C1);
|
||||
} else if (event == FuriHalI2cBusEventDeactivate) {
|
||||
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1);
|
||||
}
|
||||
}
|
||||
|
||||
FuriHalI2cBus furi_hal_i2c_bus_power = {
|
||||
.i2c=I2C1,
|
||||
.callback=furi_hal_i2c_bus_power_event,
|
||||
};
|
||||
|
||||
osMutexId_t furi_hal_i2c_bus_external_mutex = NULL;
|
||||
|
||||
static void furi_hal_i2c_bus_external_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) {
|
||||
if (event == FuriHalI2cBusEventActivate) {
|
||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C3);
|
||||
LL_RCC_SetI2CClockSource(LL_RCC_I2C3_CLKSOURCE_PCLK1);
|
||||
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C3);
|
||||
} else if (event == FuriHalI2cBusEventDeactivate) {
|
||||
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C3);
|
||||
}
|
||||
}
|
||||
|
||||
FuriHalI2cBus furi_hal_i2c_bus_external = {
|
||||
.i2c=I2C3,
|
||||
.callback=furi_hal_i2c_bus_external_event,
|
||||
};
|
||||
|
||||
void furi_hal_i2c_bus_handle_power_event(FuriHalI2cBusHandle* handle, FuriHalI2cBusHandleEvent event) {
|
||||
if (event == FuriHalI2cBusHandleEventActivate) {
|
||||
hal_gpio_init_ex(&gpio_i2c_power_sda, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C1);
|
||||
hal_gpio_init_ex(&gpio_i2c_power_scl, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C1);
|
||||
|
||||
LL_I2C_InitTypeDef I2C_InitStruct = {0};
|
||||
I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
|
||||
I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
|
||||
I2C_InitStruct.DigitalFilter = 0;
|
||||
I2C_InitStruct.OwnAddress1 = 0;
|
||||
I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
|
||||
I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
|
||||
if (furi_hal_version_get_hw_version() > 10) {
|
||||
I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_400;
|
||||
} else {
|
||||
I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100;
|
||||
}
|
||||
LL_I2C_Init(handle->bus->i2c, &I2C_InitStruct);
|
||||
|
||||
LL_I2C_EnableAutoEndMode(handle->bus->i2c);
|
||||
LL_I2C_SetOwnAddress2(handle->bus->i2c, 0, LL_I2C_OWNADDRESS2_NOMASK);
|
||||
LL_I2C_DisableOwnAddress2(handle->bus->i2c);
|
||||
LL_I2C_DisableGeneralCall(handle->bus->i2c);
|
||||
LL_I2C_EnableClockStretching(handle->bus->i2c);
|
||||
LL_I2C_Enable(handle->bus->i2c);
|
||||
} else if (event == FuriHalI2cBusHandleEventDeactivate) {
|
||||
LL_I2C_Disable(handle->bus->i2c);
|
||||
hal_gpio_write(&gpio_i2c_power_sda, 1);
|
||||
hal_gpio_write(&gpio_i2c_power_scl, 1);
|
||||
hal_gpio_init_ex(&gpio_i2c_power_sda, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
|
||||
hal_gpio_init_ex(&gpio_i2c_power_scl, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
|
||||
}
|
||||
}
|
||||
|
||||
FuriHalI2cBusHandle furi_hal_i2c_handle_power = {
|
||||
.bus = &furi_hal_i2c_bus_power,
|
||||
.callback = furi_hal_i2c_bus_handle_power_event,
|
||||
};
|
||||
|
||||
void furi_hal_i2c_bus_handle_external_event(FuriHalI2cBusHandle* handle, FuriHalI2cBusHandleEvent event) {
|
||||
if (event == FuriHalI2cBusHandleEventActivate) {
|
||||
hal_gpio_init_ex(&gpio_ext_pc0, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C3);
|
||||
hal_gpio_init_ex(&gpio_ext_pc1, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C3);
|
||||
|
||||
LL_I2C_InitTypeDef I2C_InitStruct = {0};
|
||||
I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
|
||||
I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
|
||||
I2C_InitStruct.DigitalFilter = 0;
|
||||
I2C_InitStruct.OwnAddress1 = 0;
|
||||
I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
|
||||
I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
|
||||
I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100;
|
||||
LL_I2C_Init(handle->bus->i2c, &I2C_InitStruct);
|
||||
|
||||
LL_I2C_EnableAutoEndMode(handle->bus->i2c);
|
||||
LL_I2C_SetOwnAddress2(handle->bus->i2c, 0, LL_I2C_OWNADDRESS2_NOMASK);
|
||||
LL_I2C_DisableOwnAddress2(handle->bus->i2c);
|
||||
LL_I2C_DisableGeneralCall(handle->bus->i2c);
|
||||
LL_I2C_EnableClockStretching(handle->bus->i2c);
|
||||
LL_I2C_Enable(handle->bus->i2c);
|
||||
} else if (event == FuriHalI2cBusHandleEventDeactivate) {
|
||||
LL_I2C_Disable(handle->bus->i2c);
|
||||
hal_gpio_write(&gpio_ext_pc0, 1);
|
||||
hal_gpio_write(&gpio_ext_pc1, 1);
|
||||
hal_gpio_init_ex(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
|
||||
hal_gpio_init_ex(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
|
||||
}
|
||||
}
|
||||
|
||||
FuriHalI2cBusHandle furi_hal_i2c_handle_external = {
|
||||
.bus = &furi_hal_i2c_bus_external,
|
||||
.callback = furi_hal_i2c_bus_handle_external_event,
|
||||
};
|
31
firmware/targets/f6/furi-hal/furi-hal-i2c-config.h
Normal file
31
firmware/targets/f6/furi-hal/furi-hal-i2c-config.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi-hal-i2c-types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Internal(power) i2c bus, I2C1, under reset when not used */
|
||||
extern FuriHalI2cBus furi_hal_i2c_bus_power;
|
||||
|
||||
/** External i2c bus, I2C3, under reset when not used */
|
||||
extern FuriHalI2cBus furi_hal_i2c_bus_external;
|
||||
|
||||
/** Handle for internal(power) i2c bus
|
||||
* Bus: furi_hal_i2c_bus_external
|
||||
* Pins: PA9(SCL) / PA10(SDA), float on release
|
||||
* Params: 400khz
|
||||
*/
|
||||
extern FuriHalI2cBusHandle furi_hal_i2c_handle_power;
|
||||
|
||||
/** Handle for external i2c bus
|
||||
* Bus: furi_hal_i2c_bus_external
|
||||
* Pins: PC0(SCL) / PC1(SDA), float on release
|
||||
* Params: 100khz
|
||||
*/
|
||||
extern FuriHalI2cBusHandle furi_hal_i2c_handle_external;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
49
firmware/targets/f6/furi-hal/furi-hal-i2c-types.h
Normal file
49
firmware/targets/f6/furi-hal/furi-hal-i2c-types.h
Normal file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <stm32wbxx_ll_i2c.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct FuriHalI2cBus FuriHalI2cBus;
|
||||
typedef struct FuriHalI2cBusHandle FuriHalI2cBusHandle;
|
||||
|
||||
/** FuriHal i2c bus states */
|
||||
typedef enum {
|
||||
FuriHalI2cBusEventInit, /**< Bus initialization event, called on system start */
|
||||
FuriHalI2cBusEventDeinit, /**< Bus deinitialization event, called on system stop */
|
||||
FuriHalI2cBusEventLock, /**< Bus lock event, called before activation */
|
||||
FuriHalI2cBusEventUnlock, /**< Bus unlock event, called after deactivation */
|
||||
FuriHalI2cBusEventActivate, /**< Bus activation event, called before handle activation */
|
||||
FuriHalI2cBusEventDeactivate, /**< Bus deactivation event, called after handle deactivation */
|
||||
} FuriHalI2cBusEvent;
|
||||
|
||||
/** FuriHal i2c bus event callback */
|
||||
typedef void (*FuriHalI2cBusEventCallback)(FuriHalI2cBus* bus, FuriHalI2cBusEvent event);
|
||||
|
||||
/** FuriHal i2c bus */
|
||||
struct FuriHalI2cBus {
|
||||
I2C_TypeDef* i2c;
|
||||
FuriHalI2cBusHandle* current_handle;
|
||||
FuriHalI2cBusEventCallback callback;
|
||||
};
|
||||
|
||||
/** FuriHal i2c handle states */
|
||||
typedef enum {
|
||||
FuriHalI2cBusHandleEventActivate, /**< Handle activate: connect gpio and apply bus config */
|
||||
FuriHalI2cBusHandleEventDeactivate, /**< Handle deactivate: disconnect gpio and reset bus config */
|
||||
} FuriHalI2cBusHandleEvent;
|
||||
|
||||
/** FuriHal i2c handle event callback */
|
||||
typedef void (*FuriHalI2cBusHandleEventCallback)(FuriHalI2cBusHandle* handle, FuriHalI2cBusHandleEvent event);
|
||||
|
||||
/** FuriHal i2c handle */
|
||||
struct FuriHalI2cBusHandle {
|
||||
FuriHalI2cBus* bus;
|
||||
FuriHalI2cBusHandleEventCallback callback;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -8,68 +8,62 @@
|
||||
|
||||
#define TAG "FuriHalI2C"
|
||||
|
||||
osMutexId_t furi_hal_i2c_mutex = NULL;
|
||||
|
||||
void furi_hal_i2c_init() {
|
||||
furi_hal_i2c_mutex = osMutexNew(NULL);
|
||||
furi_check(furi_hal_i2c_mutex);
|
||||
|
||||
LL_I2C_InitTypeDef I2C_InitStruct = {0};
|
||||
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
|
||||
LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);
|
||||
|
||||
GPIO_InitStruct.Pin = POWER_I2C_SCL_Pin | POWER_I2C_SDA_Pin;
|
||||
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
|
||||
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
|
||||
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
|
||||
GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
|
||||
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
|
||||
I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
|
||||
I2C_InitStruct.DigitalFilter = 0;
|
||||
I2C_InitStruct.OwnAddress1 = 0;
|
||||
I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
|
||||
I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
|
||||
if (furi_hal_version_get_hw_version() > 10) {
|
||||
I2C_InitStruct.Timing = POWER_I2C_TIMINGS_400;
|
||||
} else {
|
||||
I2C_InitStruct.Timing = POWER_I2C_TIMINGS_100;
|
||||
}
|
||||
LL_I2C_Init(POWER_I2C, &I2C_InitStruct);
|
||||
LL_I2C_EnableAutoEndMode(POWER_I2C);
|
||||
LL_I2C_SetOwnAddress2(POWER_I2C, 0, LL_I2C_OWNADDRESS2_NOMASK);
|
||||
LL_I2C_DisableOwnAddress2(POWER_I2C);
|
||||
LL_I2C_DisableGeneralCall(POWER_I2C);
|
||||
LL_I2C_EnableClockStretching(POWER_I2C);
|
||||
furi_hal_i2c_bus_power.callback(&furi_hal_i2c_bus_power, FuriHalI2cBusEventInit);
|
||||
furi_hal_i2c_bus_external.callback(&furi_hal_i2c_bus_external, FuriHalI2cBusEventInit);
|
||||
FURI_LOG_I(TAG, "Init OK");
|
||||
}
|
||||
|
||||
void furi_hal_i2c_acquire(FuriHalI2cBusHandle* handle) {
|
||||
// Lock bus access
|
||||
handle->bus->callback(handle->bus, FuriHalI2cBusEventLock);
|
||||
// Ensuree that no active handle set
|
||||
furi_check(handle->bus->current_handle == NULL);
|
||||
// Set current handle
|
||||
handle->bus->current_handle = handle;
|
||||
// Activate bus
|
||||
handle->bus->callback(handle->bus, FuriHalI2cBusEventActivate);
|
||||
// Activate handle
|
||||
handle->callback(handle, FuriHalI2cBusHandleEventActivate);
|
||||
}
|
||||
|
||||
void furi_hal_i2c_release(FuriHalI2cBusHandle* handle) {
|
||||
// Ensure that current handle is our handle
|
||||
furi_check(handle->bus->current_handle == handle);
|
||||
// Deactivate handle
|
||||
handle->callback(handle, FuriHalI2cBusHandleEventDeactivate);
|
||||
// Deactivate bus
|
||||
handle->bus->callback(handle->bus, FuriHalI2cBusEventDeactivate);
|
||||
// Reset current handle
|
||||
handle->bus->current_handle = NULL;
|
||||
// Unlock bus
|
||||
handle->bus->callback(handle->bus, FuriHalI2cBusEventUnlock);
|
||||
}
|
||||
|
||||
bool furi_hal_i2c_tx(
|
||||
I2C_TypeDef* instance,
|
||||
FuriHalI2cBusHandle* handle,
|
||||
uint8_t address,
|
||||
const uint8_t* data,
|
||||
uint8_t size,
|
||||
uint32_t timeout) {
|
||||
furi_check(handle->bus->current_handle == handle);
|
||||
uint32_t time_left = timeout;
|
||||
bool ret = true;
|
||||
|
||||
while(LL_I2C_IsActiveFlag_BUSY(instance))
|
||||
while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
|
||||
;
|
||||
|
||||
LL_I2C_HandleTransfer(
|
||||
instance,
|
||||
handle->bus->i2c,
|
||||
address,
|
||||
LL_I2C_ADDRSLAVE_7BIT,
|
||||
size,
|
||||
LL_I2C_MODE_AUTOEND,
|
||||
LL_I2C_GENERATE_START_WRITE);
|
||||
|
||||
while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
|
||||
if(LL_I2C_IsActiveFlag_TXIS(instance)) {
|
||||
LL_I2C_TransmitData8(instance, (*data));
|
||||
while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
|
||||
if(LL_I2C_IsActiveFlag_TXIS(handle->bus->i2c)) {
|
||||
LL_I2C_TransmitData8(handle->bus->i2c, (*data));
|
||||
data++;
|
||||
size--;
|
||||
time_left = timeout;
|
||||
@ -83,34 +77,35 @@ bool furi_hal_i2c_tx(
|
||||
}
|
||||
}
|
||||
|
||||
LL_I2C_ClearFlag_STOP(instance);
|
||||
LL_I2C_ClearFlag_STOP(handle->bus->i2c);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool furi_hal_i2c_rx(
|
||||
I2C_TypeDef* instance,
|
||||
FuriHalI2cBusHandle* handle,
|
||||
uint8_t address,
|
||||
uint8_t* data,
|
||||
uint8_t size,
|
||||
uint32_t timeout) {
|
||||
furi_check(handle->bus->current_handle == handle);
|
||||
uint32_t time_left = timeout;
|
||||
bool ret = true;
|
||||
|
||||
while(LL_I2C_IsActiveFlag_BUSY(instance))
|
||||
while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
|
||||
;
|
||||
|
||||
LL_I2C_HandleTransfer(
|
||||
instance,
|
||||
handle->bus->i2c,
|
||||
address,
|
||||
LL_I2C_ADDRSLAVE_7BIT,
|
||||
size,
|
||||
LL_I2C_MODE_AUTOEND,
|
||||
LL_I2C_GENERATE_START_READ);
|
||||
|
||||
while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
|
||||
if(LL_I2C_IsActiveFlag_RXNE(instance)) {
|
||||
*data = LL_I2C_ReceiveData8(instance);
|
||||
while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
|
||||
if(LL_I2C_IsActiveFlag_RXNE(handle->bus->i2c)) {
|
||||
*data = LL_I2C_ReceiveData8(handle->bus->i2c);
|
||||
data++;
|
||||
size--;
|
||||
time_left = timeout;
|
||||
@ -124,31 +119,23 @@ bool furi_hal_i2c_rx(
|
||||
}
|
||||
}
|
||||
|
||||
LL_I2C_ClearFlag_STOP(instance);
|
||||
LL_I2C_ClearFlag_STOP(handle->bus->i2c);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool furi_hal_i2c_trx(
|
||||
I2C_TypeDef* instance,
|
||||
FuriHalI2cBusHandle* handle,
|
||||
uint8_t address,
|
||||
const uint8_t* tx_data,
|
||||
uint8_t tx_size,
|
||||
uint8_t* rx_data,
|
||||
uint8_t rx_size,
|
||||
uint32_t timeout) {
|
||||
if(furi_hal_i2c_tx(instance, address, tx_data, tx_size, timeout) &&
|
||||
furi_hal_i2c_rx(instance, address, rx_data, rx_size, timeout)) {
|
||||
if(furi_hal_i2c_tx(handle, address, tx_data, tx_size, timeout) &&
|
||||
furi_hal_i2c_rx(handle, address, rx_data, rx_size, timeout)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_i2c_lock() {
|
||||
furi_check(osMutexAcquire(furi_hal_i2c_mutex, osWaitForever) == osOK);
|
||||
}
|
||||
|
||||
void furi_hal_i2c_unlock() {
|
||||
furi_check(osMutexRelease(furi_hal_i2c_mutex) == osOK);
|
||||
}
|
||||
|
@ -1,46 +1,49 @@
|
||||
#include <furi-hal-light.h>
|
||||
#include <lp5562.h>
|
||||
|
||||
#define TAG "FuriHalLight"
|
||||
|
||||
#define LED_CURRENT_RED 50
|
||||
#define LED_CURRENT_GREEN 50
|
||||
#define LED_CURRENT_BLUE 50
|
||||
#define LED_CURRENT_WHITE 150
|
||||
#define LED_CURRENT_RED 50
|
||||
#define LED_CURRENT_GREEN 50
|
||||
#define LED_CURRENT_BLUE 50
|
||||
#define LED_CURRENT_WHITE 150
|
||||
|
||||
void furi_hal_light_init() {
|
||||
lp5562_reset();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
|
||||
lp5562_set_channel_current(LP5562ChannelRed, LED_CURRENT_RED);
|
||||
lp5562_set_channel_current(LP5562ChannelGreen, LED_CURRENT_GREEN);
|
||||
lp5562_set_channel_current(LP5562ChannelBlue, LED_CURRENT_BLUE);
|
||||
lp5562_set_channel_current(LP5562ChannelWhite, LED_CURRENT_WHITE);
|
||||
lp5562_reset(&furi_hal_i2c_handle_power);
|
||||
|
||||
lp5562_set_channel_value(LP5562ChannelRed, 0x00);
|
||||
lp5562_set_channel_value(LP5562ChannelGreen, 0x00);
|
||||
lp5562_set_channel_value(LP5562ChannelBlue, 0x00);
|
||||
lp5562_set_channel_value(LP5562ChannelWhite, 0x00);
|
||||
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelRed, LED_CURRENT_RED);
|
||||
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelGreen, LED_CURRENT_GREEN);
|
||||
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelBlue, LED_CURRENT_BLUE);
|
||||
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelWhite, LED_CURRENT_WHITE);
|
||||
|
||||
lp5562_enable();
|
||||
lp5562_configure();
|
||||
FURI_LOG_I(TAG, "Init OK");
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, 0x00);
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, 0x00);
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, 0x00);
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, 0x00);
|
||||
|
||||
lp5562_enable(&furi_hal_i2c_handle_power);
|
||||
lp5562_configure(&furi_hal_i2c_handle_power);
|
||||
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
||||
|
||||
void furi_hal_light_set(Light light, uint8_t value) {
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
switch(light) {
|
||||
case LightRed:
|
||||
lp5562_set_channel_value(LP5562ChannelRed, value);
|
||||
case LightRed:
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value);
|
||||
break;
|
||||
case LightGreen:
|
||||
lp5562_set_channel_value(LP5562ChannelGreen, value);
|
||||
case LightGreen:
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value);
|
||||
break;
|
||||
case LightBlue:
|
||||
lp5562_set_channel_value(LP5562ChannelBlue, value);
|
||||
case LightBlue:
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value);
|
||||
break;
|
||||
case LightBacklight:
|
||||
lp5562_set_channel_value(LP5562ChannelWhite, value);
|
||||
case LightBacklight:
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, value);
|
||||
break;
|
||||
default:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
@ -74,8 +74,12 @@ void HAL_RCC_CSSCallback(void) {
|
||||
void furi_hal_power_init() {
|
||||
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
|
||||
LL_PWR_SMPS_SetMode(LL_PWR_SMPS_STEP_DOWN);
|
||||
bq27220_init(&cedv);
|
||||
bq25896_init();
|
||||
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
bq27220_init(&furi_hal_i2c_handle_power, &cedv);
|
||||
bq25896_init(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
|
||||
FURI_LOG_I(TAG, "Init OK");
|
||||
}
|
||||
|
||||
@ -161,19 +165,30 @@ void furi_hal_power_sleep() {
|
||||
|
||||
|
||||
uint8_t furi_hal_power_get_pct() {
|
||||
return bq27220_get_state_of_charge();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
uint8_t ret = bq27220_get_state_of_charge(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t furi_hal_power_get_bat_health_pct() {
|
||||
return bq27220_get_state_of_health();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
uint8_t ret = bq27220_get_state_of_health(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool furi_hal_power_is_charging() {
|
||||
return bq25896_is_charging();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
bool ret = bq25896_is_charging(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void furi_hal_power_off() {
|
||||
bq25896_poweroff();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
bq25896_poweroff(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
||||
|
||||
void furi_hal_power_reset() {
|
||||
@ -181,66 +196,102 @@ void furi_hal_power_reset() {
|
||||
}
|
||||
|
||||
void furi_hal_power_enable_otg() {
|
||||
bq25896_enable_otg();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
bq25896_enable_otg(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
||||
|
||||
void furi_hal_power_disable_otg() {
|
||||
bq25896_disable_otg();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
bq25896_disable_otg(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
||||
|
||||
bool furi_hal_power_is_otg_enabled() {
|
||||
return bq25896_is_otg_enabled();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
bool ret = bq25896_is_otg_enabled(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t furi_hal_power_get_battery_remaining_capacity() {
|
||||
return bq27220_get_remaining_capacity();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
uint32_t ret = bq27220_get_remaining_capacity(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t furi_hal_power_get_battery_full_capacity() {
|
||||
return bq27220_get_full_charge_capacity();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
uint32_t ret = bq27220_get_full_charge_capacity(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
return ret;
|
||||
}
|
||||
|
||||
float furi_hal_power_get_battery_voltage(FuriHalPowerIC ic) {
|
||||
float ret = 0.0f;
|
||||
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
if (ic == FuriHalPowerICCharger) {
|
||||
return (float)bq25896_get_vbat_voltage() / 1000.0f;
|
||||
ret = (float)bq25896_get_vbat_voltage(&furi_hal_i2c_handle_power) / 1000.0f;
|
||||
} else if (ic == FuriHalPowerICFuelGauge) {
|
||||
return (float)bq27220_get_voltage() / 1000.0f;
|
||||
} else {
|
||||
return 0.0f;
|
||||
ret = (float)bq27220_get_voltage(&furi_hal_i2c_handle_power) / 1000.0f;
|
||||
}
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
float furi_hal_power_get_battery_current(FuriHalPowerIC ic) {
|
||||
float ret = 0.0f;
|
||||
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
if (ic == FuriHalPowerICCharger) {
|
||||
return (float)bq25896_get_vbat_current() / 1000.0f;
|
||||
ret = (float)bq25896_get_vbat_current(&furi_hal_i2c_handle_power) / 1000.0f;
|
||||
} else if (ic == FuriHalPowerICFuelGauge) {
|
||||
return (float)bq27220_get_current() / 1000.0f;
|
||||
} else {
|
||||
return 0.0f;
|
||||
ret = (float)bq27220_get_current(&furi_hal_i2c_handle_power) / 1000.0f;
|
||||
}
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static float furi_hal_power_get_battery_temperature_internal(FuriHalPowerIC ic) {
|
||||
float ret = 0.0f;
|
||||
|
||||
if (ic == FuriHalPowerICCharger) {
|
||||
// Linear approximation, +/- 5 C
|
||||
ret = (71.0f - (float)bq25896_get_ntc_mpct(&furi_hal_i2c_handle_power)/1000) / 0.6f;
|
||||
} else if (ic == FuriHalPowerICFuelGauge) {
|
||||
ret = ((float)bq27220_get_temperature(&furi_hal_i2c_handle_power) - 2731.0f) / 10.0f;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
float furi_hal_power_get_battery_temperature(FuriHalPowerIC ic) {
|
||||
if (ic == FuriHalPowerICCharger) {
|
||||
// Linear approximation, +/- 5 C
|
||||
return (71.0f - (float)bq25896_get_ntc_mpct()/1000) / 0.6f;
|
||||
} else if (ic == FuriHalPowerICFuelGauge) {
|
||||
return ((float)bq27220_get_temperature() - 2731.0f) / 10.0f;
|
||||
} else {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
float ret = furi_hal_power_get_battery_temperature_internal(ic);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
float furi_hal_power_get_usb_voltage(){
|
||||
return (float)bq25896_get_vbus_voltage() / 1000.0f;
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
float ret = (float)bq25896_get_vbus_voltage(&furi_hal_i2c_handle_power) / 1000.0f;
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void furi_hal_power_dump_state() {
|
||||
BatteryStatus battery_status;
|
||||
OperationStatus operation_status;
|
||||
if (bq27220_get_battery_status(&battery_status) == BQ27220_ERROR
|
||||
|| bq27220_get_operation_status(&operation_status) == BQ27220_ERROR) {
|
||||
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
|
||||
if (bq27220_get_battery_status(&furi_hal_i2c_handle_power, &battery_status) == BQ27220_ERROR
|
||||
|| bq27220_get_operation_status(&furi_hal_i2c_handle_power, &operation_status) == BQ27220_ERROR) {
|
||||
printf("Failed to get bq27220 status. Communication error.\r\n");
|
||||
} else {
|
||||
printf(
|
||||
@ -266,21 +317,23 @@ void furi_hal_power_dump_state() {
|
||||
// Voltage and current info
|
||||
printf(
|
||||
"bq27220: Full capacity: %dmAh, Design capacity: %dmAh, Remaining capacity: %dmAh, State of Charge: %d%%, State of health: %d%%\r\n",
|
||||
bq27220_get_full_charge_capacity(), bq27220_get_design_capacity(), bq27220_get_remaining_capacity(),
|
||||
bq27220_get_state_of_charge(), bq27220_get_state_of_health()
|
||||
bq27220_get_full_charge_capacity(&furi_hal_i2c_handle_power), bq27220_get_design_capacity(&furi_hal_i2c_handle_power), bq27220_get_remaining_capacity(&furi_hal_i2c_handle_power),
|
||||
bq27220_get_state_of_charge(&furi_hal_i2c_handle_power), bq27220_get_state_of_health(&furi_hal_i2c_handle_power)
|
||||
);
|
||||
printf(
|
||||
"bq27220: Voltage: %dmV, Current: %dmA, Temperature: %dC\r\n",
|
||||
bq27220_get_voltage(), bq27220_get_current(), (int)furi_hal_power_get_battery_temperature(FuriHalPowerICFuelGauge)
|
||||
bq27220_get_voltage(&furi_hal_i2c_handle_power), bq27220_get_current(&furi_hal_i2c_handle_power), (int)furi_hal_power_get_battery_temperature_internal(FuriHalPowerICFuelGauge)
|
||||
);
|
||||
}
|
||||
|
||||
printf(
|
||||
"bq25896: VBUS: %d, VSYS: %d, VBAT: %d, Current: %d, NTC: %ldm%%\r\n",
|
||||
bq25896_get_vbus_voltage(), bq25896_get_vsys_voltage(),
|
||||
bq25896_get_vbat_voltage(), bq25896_get_vbat_current(),
|
||||
bq25896_get_ntc_mpct()
|
||||
bq25896_get_vbus_voltage(&furi_hal_i2c_handle_power), bq25896_get_vsys_voltage(&furi_hal_i2c_handle_power),
|
||||
bq25896_get_vbat_voltage(&furi_hal_i2c_handle_power), bq25896_get_vbat_current(&furi_hal_i2c_handle_power),
|
||||
bq25896_get_ntc_mpct(&furi_hal_i2c_handle_power)
|
||||
);
|
||||
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
||||
|
||||
void furi_hal_power_enable_external_3_3v(){
|
||||
@ -298,7 +351,9 @@ void furi_hal_power_suppress_charge_enter() {
|
||||
xTaskResumeAll();
|
||||
|
||||
if (disable_charging) {
|
||||
bq25896_disable_charging();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
bq25896_disable_charging(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
||||
}
|
||||
|
||||
@ -309,6 +364,8 @@ void furi_hal_power_suppress_charge_exit() {
|
||||
xTaskResumeAll();
|
||||
|
||||
if (enable_charging) {
|
||||
bq25896_enable_charging();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
bq25896_enable_charging(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
||||
}
|
@ -54,3 +54,6 @@ const GpioPin gpio_irda_tx = {.port = IR_TX_GPIO_Port, .pin = IR_TX_Pin};
|
||||
|
||||
const GpioPin gpio_usart_tx = {.port = USART1_TX_Port, .pin = USART1_TX_Pin};
|
||||
const GpioPin gpio_usart_rx = {.port = USART1_RX_Port, .pin = USART1_RX_Pin};
|
||||
|
||||
const GpioPin gpio_i2c_power_sda = {.port = GPIOA, .pin = LL_GPIO_PIN_10};
|
||||
const GpioPin gpio_i2c_power_scl = {.port = GPIOA, .pin = LL_GPIO_PIN_9};
|
||||
|
@ -10,24 +10,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define POWER_I2C_SCL_Pin LL_GPIO_PIN_9
|
||||
#define POWER_I2C_SCL_GPIO_Port GPIOA
|
||||
#define POWER_I2C_SDA_Pin LL_GPIO_PIN_10
|
||||
#define POWER_I2C_SDA_GPIO_Port GPIOA
|
||||
|
||||
#define POWER_I2C I2C1
|
||||
/** Timing register value is computed with the STM32CubeMX Tool,
|
||||
* Standard Mode @100kHz with I2CCLK = 64 MHz,
|
||||
* rise time = 0ns, fall time = 0ns
|
||||
*/
|
||||
#define POWER_I2C_TIMINGS_100 0x10707DBC
|
||||
|
||||
/** Timing register value is computed with the STM32CubeMX Tool,
|
||||
* Fast Mode @400kHz with I2CCLK = 64 MHz,
|
||||
* rise time = 0ns, fall time = 0ns
|
||||
*/
|
||||
#define POWER_I2C_TIMINGS_400 0x00602173
|
||||
|
||||
/* Input Related Constants */
|
||||
#define INPUT_DEBOUNCE_TICKS 20
|
||||
|
||||
@ -98,6 +80,9 @@ extern const GpioPin gpio_irda_tx;
|
||||
|
||||
extern const GpioPin gpio_usart_tx;
|
||||
extern const GpioPin gpio_usart_rx;
|
||||
extern const GpioPin gpio_i2c_power_sda;
|
||||
extern const GpioPin gpio_i2c_power_scl;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -280,7 +280,7 @@ static void vcp_on_cdc_control_line(void* context, uint8_t state) {
|
||||
|
||||
static void vcp_on_cdc_rx(void* context) {
|
||||
uint32_t ret = osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtRx);
|
||||
furi_assert((ret & osFlagsError) == 0);
|
||||
furi_check((ret & osFlagsError) == 0);
|
||||
}
|
||||
|
||||
static void vcp_on_cdc_tx_complete(void* context) {
|
||||
|
133
firmware/targets/f7/furi-hal/furi-hal-i2c-config.c
Normal file
133
firmware/targets/f7/furi-hal/furi-hal-i2c-config.c
Normal file
@ -0,0 +1,133 @@
|
||||
#include "furi-hal-i2c-config.h"
|
||||
#include <furi-hal-resources.h>
|
||||
#include <furi-hal-version.h>
|
||||
|
||||
/** Timing register value is computed with the STM32CubeMX Tool,
|
||||
* Standard Mode @100kHz with I2CCLK = 64 MHz,
|
||||
* rise time = 0ns, fall time = 0ns
|
||||
*/
|
||||
#define FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100 0x10707DBC
|
||||
|
||||
/** Timing register value is computed with the STM32CubeMX Tool,
|
||||
* Fast Mode @400kHz with I2CCLK = 64 MHz,
|
||||
* rise time = 0ns, fall time = 0ns
|
||||
*/
|
||||
#define FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_400 0x00602173
|
||||
|
||||
osMutexId_t furi_hal_i2c_bus_power_mutex = NULL;
|
||||
|
||||
static void furi_hal_i2c_bus_power_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) {
|
||||
if (event == FuriHalI2cBusEventInit) {
|
||||
furi_hal_i2c_bus_power_mutex = osMutexNew(NULL);
|
||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);
|
||||
LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);
|
||||
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1);
|
||||
bus->current_handle = NULL;
|
||||
} else if (event == FuriHalI2cBusEventDeinit) {
|
||||
osMutexDelete(furi_hal_i2c_bus_power_mutex);
|
||||
} else if (event == FuriHalI2cBusEventLock) {
|
||||
furi_check(osMutexAcquire(furi_hal_i2c_bus_power_mutex, osWaitForever) == osOK);
|
||||
} else if (event == FuriHalI2cBusEventUnlock) {
|
||||
furi_check(osMutexRelease(furi_hal_i2c_bus_power_mutex) == osOK);
|
||||
} else if (event == FuriHalI2cBusEventActivate) {
|
||||
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C1);
|
||||
} else if (event == FuriHalI2cBusEventDeactivate) {
|
||||
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1);
|
||||
}
|
||||
}
|
||||
|
||||
FuriHalI2cBus furi_hal_i2c_bus_power = {
|
||||
.i2c=I2C1,
|
||||
.callback=furi_hal_i2c_bus_power_event,
|
||||
};
|
||||
|
||||
osMutexId_t furi_hal_i2c_bus_external_mutex = NULL;
|
||||
|
||||
static void furi_hal_i2c_bus_external_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) {
|
||||
if (event == FuriHalI2cBusEventActivate) {
|
||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C3);
|
||||
LL_RCC_SetI2CClockSource(LL_RCC_I2C3_CLKSOURCE_PCLK1);
|
||||
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C3);
|
||||
} else if (event == FuriHalI2cBusEventDeactivate) {
|
||||
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C3);
|
||||
}
|
||||
}
|
||||
|
||||
FuriHalI2cBus furi_hal_i2c_bus_external = {
|
||||
.i2c=I2C3,
|
||||
.callback=furi_hal_i2c_bus_external_event,
|
||||
};
|
||||
|
||||
void furi_hal_i2c_bus_handle_power_event(FuriHalI2cBusHandle* handle, FuriHalI2cBusHandleEvent event) {
|
||||
if (event == FuriHalI2cBusHandleEventActivate) {
|
||||
hal_gpio_init_ex(&gpio_i2c_power_sda, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C1);
|
||||
hal_gpio_init_ex(&gpio_i2c_power_scl, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C1);
|
||||
|
||||
LL_I2C_InitTypeDef I2C_InitStruct = {0};
|
||||
I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
|
||||
I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
|
||||
I2C_InitStruct.DigitalFilter = 0;
|
||||
I2C_InitStruct.OwnAddress1 = 0;
|
||||
I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
|
||||
I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
|
||||
if (furi_hal_version_get_hw_version() > 10) {
|
||||
I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_400;
|
||||
} else {
|
||||
I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100;
|
||||
}
|
||||
LL_I2C_Init(handle->bus->i2c, &I2C_InitStruct);
|
||||
|
||||
LL_I2C_EnableAutoEndMode(handle->bus->i2c);
|
||||
LL_I2C_SetOwnAddress2(handle->bus->i2c, 0, LL_I2C_OWNADDRESS2_NOMASK);
|
||||
LL_I2C_DisableOwnAddress2(handle->bus->i2c);
|
||||
LL_I2C_DisableGeneralCall(handle->bus->i2c);
|
||||
LL_I2C_EnableClockStretching(handle->bus->i2c);
|
||||
LL_I2C_Enable(handle->bus->i2c);
|
||||
} else if (event == FuriHalI2cBusHandleEventDeactivate) {
|
||||
LL_I2C_Disable(handle->bus->i2c);
|
||||
hal_gpio_write(&gpio_i2c_power_sda, 1);
|
||||
hal_gpio_write(&gpio_i2c_power_scl, 1);
|
||||
hal_gpio_init_ex(&gpio_i2c_power_sda, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
|
||||
hal_gpio_init_ex(&gpio_i2c_power_scl, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
|
||||
}
|
||||
}
|
||||
|
||||
FuriHalI2cBusHandle furi_hal_i2c_handle_power = {
|
||||
.bus = &furi_hal_i2c_bus_power,
|
||||
.callback = furi_hal_i2c_bus_handle_power_event,
|
||||
};
|
||||
|
||||
void furi_hal_i2c_bus_handle_external_event(FuriHalI2cBusHandle* handle, FuriHalI2cBusHandleEvent event) {
|
||||
if (event == FuriHalI2cBusHandleEventActivate) {
|
||||
hal_gpio_init_ex(&gpio_ext_pc0, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C3);
|
||||
hal_gpio_init_ex(&gpio_ext_pc1, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C3);
|
||||
|
||||
LL_I2C_InitTypeDef I2C_InitStruct = {0};
|
||||
I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
|
||||
I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
|
||||
I2C_InitStruct.DigitalFilter = 0;
|
||||
I2C_InitStruct.OwnAddress1 = 0;
|
||||
I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
|
||||
I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
|
||||
I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100;
|
||||
LL_I2C_Init(handle->bus->i2c, &I2C_InitStruct);
|
||||
|
||||
LL_I2C_EnableAutoEndMode(handle->bus->i2c);
|
||||
LL_I2C_SetOwnAddress2(handle->bus->i2c, 0, LL_I2C_OWNADDRESS2_NOMASK);
|
||||
LL_I2C_DisableOwnAddress2(handle->bus->i2c);
|
||||
LL_I2C_DisableGeneralCall(handle->bus->i2c);
|
||||
LL_I2C_EnableClockStretching(handle->bus->i2c);
|
||||
LL_I2C_Enable(handle->bus->i2c);
|
||||
} else if (event == FuriHalI2cBusHandleEventDeactivate) {
|
||||
LL_I2C_Disable(handle->bus->i2c);
|
||||
hal_gpio_write(&gpio_ext_pc0, 1);
|
||||
hal_gpio_write(&gpio_ext_pc1, 1);
|
||||
hal_gpio_init_ex(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
|
||||
hal_gpio_init_ex(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
|
||||
}
|
||||
}
|
||||
|
||||
FuriHalI2cBusHandle furi_hal_i2c_handle_external = {
|
||||
.bus = &furi_hal_i2c_bus_external,
|
||||
.callback = furi_hal_i2c_bus_handle_external_event,
|
||||
};
|
31
firmware/targets/f7/furi-hal/furi-hal-i2c-config.h
Normal file
31
firmware/targets/f7/furi-hal/furi-hal-i2c-config.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi-hal-i2c-types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Internal(power) i2c bus, I2C1, under reset when not used */
|
||||
extern FuriHalI2cBus furi_hal_i2c_bus_power;
|
||||
|
||||
/** External i2c bus, I2C3, under reset when not used */
|
||||
extern FuriHalI2cBus furi_hal_i2c_bus_external;
|
||||
|
||||
/** Handle for internal(power) i2c bus
|
||||
* Bus: furi_hal_i2c_bus_external
|
||||
* Pins: PA9(SCL) / PA10(SDA), float on release
|
||||
* Params: 400khz
|
||||
*/
|
||||
extern FuriHalI2cBusHandle furi_hal_i2c_handle_power;
|
||||
|
||||
/** Handle for external i2c bus
|
||||
* Bus: furi_hal_i2c_bus_external
|
||||
* Pins: PC0(SCL) / PC1(SDA), float on release
|
||||
* Params: 100khz
|
||||
*/
|
||||
extern FuriHalI2cBusHandle furi_hal_i2c_handle_external;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
49
firmware/targets/f7/furi-hal/furi-hal-i2c-types.h
Normal file
49
firmware/targets/f7/furi-hal/furi-hal-i2c-types.h
Normal file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <stm32wbxx_ll_i2c.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct FuriHalI2cBus FuriHalI2cBus;
|
||||
typedef struct FuriHalI2cBusHandle FuriHalI2cBusHandle;
|
||||
|
||||
/** FuriHal i2c bus states */
|
||||
typedef enum {
|
||||
FuriHalI2cBusEventInit, /**< Bus initialization event, called on system start */
|
||||
FuriHalI2cBusEventDeinit, /**< Bus deinitialization event, called on system stop */
|
||||
FuriHalI2cBusEventLock, /**< Bus lock event, called before activation */
|
||||
FuriHalI2cBusEventUnlock, /**< Bus unlock event, called after deactivation */
|
||||
FuriHalI2cBusEventActivate, /**< Bus activation event, called before handle activation */
|
||||
FuriHalI2cBusEventDeactivate, /**< Bus deactivation event, called after handle deactivation */
|
||||
} FuriHalI2cBusEvent;
|
||||
|
||||
/** FuriHal i2c bus event callback */
|
||||
typedef void (*FuriHalI2cBusEventCallback)(FuriHalI2cBus* bus, FuriHalI2cBusEvent event);
|
||||
|
||||
/** FuriHal i2c bus */
|
||||
struct FuriHalI2cBus {
|
||||
I2C_TypeDef* i2c;
|
||||
FuriHalI2cBusHandle* current_handle;
|
||||
FuriHalI2cBusEventCallback callback;
|
||||
};
|
||||
|
||||
/** FuriHal i2c handle states */
|
||||
typedef enum {
|
||||
FuriHalI2cBusHandleEventActivate, /**< Handle activate: connect gpio and apply bus config */
|
||||
FuriHalI2cBusHandleEventDeactivate, /**< Handle deactivate: disconnect gpio and reset bus config */
|
||||
} FuriHalI2cBusHandleEvent;
|
||||
|
||||
/** FuriHal i2c handle event callback */
|
||||
typedef void (*FuriHalI2cBusHandleEventCallback)(FuriHalI2cBusHandle* handle, FuriHalI2cBusHandleEvent event);
|
||||
|
||||
/** FuriHal i2c handle */
|
||||
struct FuriHalI2cBusHandle {
|
||||
FuriHalI2cBus* bus;
|
||||
FuriHalI2cBusHandleEventCallback callback;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -8,68 +8,62 @@
|
||||
|
||||
#define TAG "FuriHalI2C"
|
||||
|
||||
osMutexId_t furi_hal_i2c_mutex = NULL;
|
||||
|
||||
void furi_hal_i2c_init() {
|
||||
furi_hal_i2c_mutex = osMutexNew(NULL);
|
||||
furi_check(furi_hal_i2c_mutex);
|
||||
|
||||
LL_I2C_InitTypeDef I2C_InitStruct = {0};
|
||||
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
|
||||
LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);
|
||||
|
||||
GPIO_InitStruct.Pin = POWER_I2C_SCL_Pin | POWER_I2C_SDA_Pin;
|
||||
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
|
||||
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
|
||||
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
|
||||
GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
|
||||
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
|
||||
I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
|
||||
I2C_InitStruct.DigitalFilter = 0;
|
||||
I2C_InitStruct.OwnAddress1 = 0;
|
||||
I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
|
||||
I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
|
||||
if (furi_hal_version_get_hw_version() > 10) {
|
||||
I2C_InitStruct.Timing = POWER_I2C_TIMINGS_400;
|
||||
} else {
|
||||
I2C_InitStruct.Timing = POWER_I2C_TIMINGS_100;
|
||||
}
|
||||
LL_I2C_Init(POWER_I2C, &I2C_InitStruct);
|
||||
LL_I2C_EnableAutoEndMode(POWER_I2C);
|
||||
LL_I2C_SetOwnAddress2(POWER_I2C, 0, LL_I2C_OWNADDRESS2_NOMASK);
|
||||
LL_I2C_DisableOwnAddress2(POWER_I2C);
|
||||
LL_I2C_DisableGeneralCall(POWER_I2C);
|
||||
LL_I2C_EnableClockStretching(POWER_I2C);
|
||||
furi_hal_i2c_bus_power.callback(&furi_hal_i2c_bus_power, FuriHalI2cBusEventInit);
|
||||
furi_hal_i2c_bus_external.callback(&furi_hal_i2c_bus_external, FuriHalI2cBusEventInit);
|
||||
FURI_LOG_I(TAG, "Init OK");
|
||||
}
|
||||
|
||||
void furi_hal_i2c_acquire(FuriHalI2cBusHandle* handle) {
|
||||
// Lock bus access
|
||||
handle->bus->callback(handle->bus, FuriHalI2cBusEventLock);
|
||||
// Ensuree that no active handle set
|
||||
furi_check(handle->bus->current_handle == NULL);
|
||||
// Set current handle
|
||||
handle->bus->current_handle = handle;
|
||||
// Activate bus
|
||||
handle->bus->callback(handle->bus, FuriHalI2cBusEventActivate);
|
||||
// Activate handle
|
||||
handle->callback(handle, FuriHalI2cBusHandleEventActivate);
|
||||
}
|
||||
|
||||
void furi_hal_i2c_release(FuriHalI2cBusHandle* handle) {
|
||||
// Ensure that current handle is our handle
|
||||
furi_check(handle->bus->current_handle == handle);
|
||||
// Deactivate handle
|
||||
handle->callback(handle, FuriHalI2cBusHandleEventDeactivate);
|
||||
// Deactivate bus
|
||||
handle->bus->callback(handle->bus, FuriHalI2cBusEventDeactivate);
|
||||
// Reset current handle
|
||||
handle->bus->current_handle = NULL;
|
||||
// Unlock bus
|
||||
handle->bus->callback(handle->bus, FuriHalI2cBusEventUnlock);
|
||||
}
|
||||
|
||||
bool furi_hal_i2c_tx(
|
||||
I2C_TypeDef* instance,
|
||||
FuriHalI2cBusHandle* handle,
|
||||
uint8_t address,
|
||||
const uint8_t* data,
|
||||
uint8_t size,
|
||||
uint32_t timeout) {
|
||||
furi_check(handle->bus->current_handle == handle);
|
||||
uint32_t time_left = timeout;
|
||||
bool ret = true;
|
||||
|
||||
while(LL_I2C_IsActiveFlag_BUSY(instance))
|
||||
while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
|
||||
;
|
||||
|
||||
LL_I2C_HandleTransfer(
|
||||
instance,
|
||||
handle->bus->i2c,
|
||||
address,
|
||||
LL_I2C_ADDRSLAVE_7BIT,
|
||||
size,
|
||||
LL_I2C_MODE_AUTOEND,
|
||||
LL_I2C_GENERATE_START_WRITE);
|
||||
|
||||
while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
|
||||
if(LL_I2C_IsActiveFlag_TXIS(instance)) {
|
||||
LL_I2C_TransmitData8(instance, (*data));
|
||||
while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
|
||||
if(LL_I2C_IsActiveFlag_TXIS(handle->bus->i2c)) {
|
||||
LL_I2C_TransmitData8(handle->bus->i2c, (*data));
|
||||
data++;
|
||||
size--;
|
||||
time_left = timeout;
|
||||
@ -83,34 +77,35 @@ bool furi_hal_i2c_tx(
|
||||
}
|
||||
}
|
||||
|
||||
LL_I2C_ClearFlag_STOP(instance);
|
||||
LL_I2C_ClearFlag_STOP(handle->bus->i2c);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool furi_hal_i2c_rx(
|
||||
I2C_TypeDef* instance,
|
||||
FuriHalI2cBusHandle* handle,
|
||||
uint8_t address,
|
||||
uint8_t* data,
|
||||
uint8_t size,
|
||||
uint32_t timeout) {
|
||||
furi_check(handle->bus->current_handle == handle);
|
||||
uint32_t time_left = timeout;
|
||||
bool ret = true;
|
||||
|
||||
while(LL_I2C_IsActiveFlag_BUSY(instance))
|
||||
while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
|
||||
;
|
||||
|
||||
LL_I2C_HandleTransfer(
|
||||
instance,
|
||||
handle->bus->i2c,
|
||||
address,
|
||||
LL_I2C_ADDRSLAVE_7BIT,
|
||||
size,
|
||||
LL_I2C_MODE_AUTOEND,
|
||||
LL_I2C_GENERATE_START_READ);
|
||||
|
||||
while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
|
||||
if(LL_I2C_IsActiveFlag_RXNE(instance)) {
|
||||
*data = LL_I2C_ReceiveData8(instance);
|
||||
while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
|
||||
if(LL_I2C_IsActiveFlag_RXNE(handle->bus->i2c)) {
|
||||
*data = LL_I2C_ReceiveData8(handle->bus->i2c);
|
||||
data++;
|
||||
size--;
|
||||
time_left = timeout;
|
||||
@ -124,31 +119,23 @@ bool furi_hal_i2c_rx(
|
||||
}
|
||||
}
|
||||
|
||||
LL_I2C_ClearFlag_STOP(instance);
|
||||
LL_I2C_ClearFlag_STOP(handle->bus->i2c);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool furi_hal_i2c_trx(
|
||||
I2C_TypeDef* instance,
|
||||
FuriHalI2cBusHandle* handle,
|
||||
uint8_t address,
|
||||
const uint8_t* tx_data,
|
||||
uint8_t tx_size,
|
||||
uint8_t* rx_data,
|
||||
uint8_t rx_size,
|
||||
uint32_t timeout) {
|
||||
if(furi_hal_i2c_tx(instance, address, tx_data, tx_size, timeout) &&
|
||||
furi_hal_i2c_rx(instance, address, rx_data, rx_size, timeout)) {
|
||||
if(furi_hal_i2c_tx(handle, address, tx_data, tx_size, timeout) &&
|
||||
furi_hal_i2c_rx(handle, address, rx_data, rx_size, timeout)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_i2c_lock() {
|
||||
furi_check(osMutexAcquire(furi_hal_i2c_mutex, osWaitForever) == osOK);
|
||||
}
|
||||
|
||||
void furi_hal_i2c_unlock() {
|
||||
furi_check(osMutexRelease(furi_hal_i2c_mutex) == osOK);
|
||||
}
|
||||
|
@ -1,46 +1,49 @@
|
||||
#include <furi-hal-light.h>
|
||||
#include <lp5562.h>
|
||||
|
||||
#define TAG "FuriHalLight"
|
||||
|
||||
#define LED_CURRENT_RED 50
|
||||
#define LED_CURRENT_GREEN 50
|
||||
#define LED_CURRENT_BLUE 50
|
||||
#define LED_CURRENT_WHITE 150
|
||||
#define LED_CURRENT_RED 50
|
||||
#define LED_CURRENT_GREEN 50
|
||||
#define LED_CURRENT_BLUE 50
|
||||
#define LED_CURRENT_WHITE 150
|
||||
|
||||
void furi_hal_light_init() {
|
||||
lp5562_reset();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
|
||||
lp5562_set_channel_current(LP5562ChannelRed, LED_CURRENT_RED);
|
||||
lp5562_set_channel_current(LP5562ChannelGreen, LED_CURRENT_GREEN);
|
||||
lp5562_set_channel_current(LP5562ChannelBlue, LED_CURRENT_BLUE);
|
||||
lp5562_set_channel_current(LP5562ChannelWhite, LED_CURRENT_WHITE);
|
||||
lp5562_reset(&furi_hal_i2c_handle_power);
|
||||
|
||||
lp5562_set_channel_value(LP5562ChannelRed, 0x00);
|
||||
lp5562_set_channel_value(LP5562ChannelGreen, 0x00);
|
||||
lp5562_set_channel_value(LP5562ChannelBlue, 0x00);
|
||||
lp5562_set_channel_value(LP5562ChannelWhite, 0x00);
|
||||
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelRed, LED_CURRENT_RED);
|
||||
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelGreen, LED_CURRENT_GREEN);
|
||||
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelBlue, LED_CURRENT_BLUE);
|
||||
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelWhite, LED_CURRENT_WHITE);
|
||||
|
||||
lp5562_enable();
|
||||
lp5562_configure();
|
||||
FURI_LOG_I(TAG, "Init OK");
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, 0x00);
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, 0x00);
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, 0x00);
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, 0x00);
|
||||
|
||||
lp5562_enable(&furi_hal_i2c_handle_power);
|
||||
lp5562_configure(&furi_hal_i2c_handle_power);
|
||||
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
||||
|
||||
void furi_hal_light_set(Light light, uint8_t value) {
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
switch(light) {
|
||||
case LightRed:
|
||||
lp5562_set_channel_value(LP5562ChannelRed, value);
|
||||
case LightRed:
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value);
|
||||
break;
|
||||
case LightGreen:
|
||||
lp5562_set_channel_value(LP5562ChannelGreen, value);
|
||||
case LightGreen:
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value);
|
||||
break;
|
||||
case LightBlue:
|
||||
lp5562_set_channel_value(LP5562ChannelBlue, value);
|
||||
case LightBlue:
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value);
|
||||
break;
|
||||
case LightBacklight:
|
||||
lp5562_set_channel_value(LP5562ChannelWhite, value);
|
||||
case LightBacklight:
|
||||
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, value);
|
||||
break;
|
||||
default:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
@ -74,8 +74,12 @@ void HAL_RCC_CSSCallback(void) {
|
||||
void furi_hal_power_init() {
|
||||
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
|
||||
LL_PWR_SMPS_SetMode(LL_PWR_SMPS_STEP_DOWN);
|
||||
bq27220_init(&cedv);
|
||||
bq25896_init();
|
||||
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
bq27220_init(&furi_hal_i2c_handle_power, &cedv);
|
||||
bq25896_init(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
|
||||
FURI_LOG_I(TAG, "Init OK");
|
||||
}
|
||||
|
||||
@ -161,19 +165,30 @@ void furi_hal_power_sleep() {
|
||||
|
||||
|
||||
uint8_t furi_hal_power_get_pct() {
|
||||
return bq27220_get_state_of_charge();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
uint8_t ret = bq27220_get_state_of_charge(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t furi_hal_power_get_bat_health_pct() {
|
||||
return bq27220_get_state_of_health();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
uint8_t ret = bq27220_get_state_of_health(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool furi_hal_power_is_charging() {
|
||||
return bq25896_is_charging();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
bool ret = bq25896_is_charging(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void furi_hal_power_off() {
|
||||
bq25896_poweroff();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
bq25896_poweroff(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
||||
|
||||
void furi_hal_power_reset() {
|
||||
@ -181,66 +196,102 @@ void furi_hal_power_reset() {
|
||||
}
|
||||
|
||||
void furi_hal_power_enable_otg() {
|
||||
bq25896_enable_otg();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
bq25896_enable_otg(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
||||
|
||||
void furi_hal_power_disable_otg() {
|
||||
bq25896_disable_otg();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
bq25896_disable_otg(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
||||
|
||||
bool furi_hal_power_is_otg_enabled() {
|
||||
return bq25896_is_otg_enabled();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
bool ret = bq25896_is_otg_enabled(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t furi_hal_power_get_battery_remaining_capacity() {
|
||||
return bq27220_get_remaining_capacity();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
uint32_t ret = bq27220_get_remaining_capacity(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t furi_hal_power_get_battery_full_capacity() {
|
||||
return bq27220_get_full_charge_capacity();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
uint32_t ret = bq27220_get_full_charge_capacity(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
return ret;
|
||||
}
|
||||
|
||||
float furi_hal_power_get_battery_voltage(FuriHalPowerIC ic) {
|
||||
float ret = 0.0f;
|
||||
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
if (ic == FuriHalPowerICCharger) {
|
||||
return (float)bq25896_get_vbat_voltage() / 1000.0f;
|
||||
ret = (float)bq25896_get_vbat_voltage(&furi_hal_i2c_handle_power) / 1000.0f;
|
||||
} else if (ic == FuriHalPowerICFuelGauge) {
|
||||
return (float)bq27220_get_voltage() / 1000.0f;
|
||||
} else {
|
||||
return 0.0f;
|
||||
ret = (float)bq27220_get_voltage(&furi_hal_i2c_handle_power) / 1000.0f;
|
||||
}
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
float furi_hal_power_get_battery_current(FuriHalPowerIC ic) {
|
||||
float ret = 0.0f;
|
||||
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
if (ic == FuriHalPowerICCharger) {
|
||||
return (float)bq25896_get_vbat_current() / 1000.0f;
|
||||
ret = (float)bq25896_get_vbat_current(&furi_hal_i2c_handle_power) / 1000.0f;
|
||||
} else if (ic == FuriHalPowerICFuelGauge) {
|
||||
return (float)bq27220_get_current() / 1000.0f;
|
||||
} else {
|
||||
return 0.0f;
|
||||
ret = (float)bq27220_get_current(&furi_hal_i2c_handle_power) / 1000.0f;
|
||||
}
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static float furi_hal_power_get_battery_temperature_internal(FuriHalPowerIC ic) {
|
||||
float ret = 0.0f;
|
||||
|
||||
if (ic == FuriHalPowerICCharger) {
|
||||
// Linear approximation, +/- 5 C
|
||||
ret = (71.0f - (float)bq25896_get_ntc_mpct(&furi_hal_i2c_handle_power)/1000) / 0.6f;
|
||||
} else if (ic == FuriHalPowerICFuelGauge) {
|
||||
ret = ((float)bq27220_get_temperature(&furi_hal_i2c_handle_power) - 2731.0f) / 10.0f;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
float furi_hal_power_get_battery_temperature(FuriHalPowerIC ic) {
|
||||
if (ic == FuriHalPowerICCharger) {
|
||||
// Linear approximation, +/- 5 C
|
||||
return (71.0f - (float)bq25896_get_ntc_mpct()/1000) / 0.6f;
|
||||
} else if (ic == FuriHalPowerICFuelGauge) {
|
||||
return ((float)bq27220_get_temperature() - 2731.0f) / 10.0f;
|
||||
} else {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
float ret = furi_hal_power_get_battery_temperature_internal(ic);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
float furi_hal_power_get_usb_voltage(){
|
||||
return (float)bq25896_get_vbus_voltage() / 1000.0f;
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
float ret = (float)bq25896_get_vbus_voltage(&furi_hal_i2c_handle_power) / 1000.0f;
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void furi_hal_power_dump_state() {
|
||||
BatteryStatus battery_status;
|
||||
OperationStatus operation_status;
|
||||
if (bq27220_get_battery_status(&battery_status) == BQ27220_ERROR
|
||||
|| bq27220_get_operation_status(&operation_status) == BQ27220_ERROR) {
|
||||
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
|
||||
if (bq27220_get_battery_status(&furi_hal_i2c_handle_power, &battery_status) == BQ27220_ERROR
|
||||
|| bq27220_get_operation_status(&furi_hal_i2c_handle_power, &operation_status) == BQ27220_ERROR) {
|
||||
printf("Failed to get bq27220 status. Communication error.\r\n");
|
||||
} else {
|
||||
printf(
|
||||
@ -266,21 +317,23 @@ void furi_hal_power_dump_state() {
|
||||
// Voltage and current info
|
||||
printf(
|
||||
"bq27220: Full capacity: %dmAh, Design capacity: %dmAh, Remaining capacity: %dmAh, State of Charge: %d%%, State of health: %d%%\r\n",
|
||||
bq27220_get_full_charge_capacity(), bq27220_get_design_capacity(), bq27220_get_remaining_capacity(),
|
||||
bq27220_get_state_of_charge(), bq27220_get_state_of_health()
|
||||
bq27220_get_full_charge_capacity(&furi_hal_i2c_handle_power), bq27220_get_design_capacity(&furi_hal_i2c_handle_power), bq27220_get_remaining_capacity(&furi_hal_i2c_handle_power),
|
||||
bq27220_get_state_of_charge(&furi_hal_i2c_handle_power), bq27220_get_state_of_health(&furi_hal_i2c_handle_power)
|
||||
);
|
||||
printf(
|
||||
"bq27220: Voltage: %dmV, Current: %dmA, Temperature: %dC\r\n",
|
||||
bq27220_get_voltage(), bq27220_get_current(), (int)furi_hal_power_get_battery_temperature(FuriHalPowerICFuelGauge)
|
||||
bq27220_get_voltage(&furi_hal_i2c_handle_power), bq27220_get_current(&furi_hal_i2c_handle_power), (int)furi_hal_power_get_battery_temperature_internal(FuriHalPowerICFuelGauge)
|
||||
);
|
||||
}
|
||||
|
||||
printf(
|
||||
"bq25896: VBUS: %d, VSYS: %d, VBAT: %d, Current: %d, NTC: %ldm%%\r\n",
|
||||
bq25896_get_vbus_voltage(), bq25896_get_vsys_voltage(),
|
||||
bq25896_get_vbat_voltage(), bq25896_get_vbat_current(),
|
||||
bq25896_get_ntc_mpct()
|
||||
bq25896_get_vbus_voltage(&furi_hal_i2c_handle_power), bq25896_get_vsys_voltage(&furi_hal_i2c_handle_power),
|
||||
bq25896_get_vbat_voltage(&furi_hal_i2c_handle_power), bq25896_get_vbat_current(&furi_hal_i2c_handle_power),
|
||||
bq25896_get_ntc_mpct(&furi_hal_i2c_handle_power)
|
||||
);
|
||||
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
||||
|
||||
void furi_hal_power_enable_external_3_3v(){
|
||||
@ -298,7 +351,9 @@ void furi_hal_power_suppress_charge_enter() {
|
||||
xTaskResumeAll();
|
||||
|
||||
if (disable_charging) {
|
||||
bq25896_disable_charging();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
bq25896_disable_charging(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
||||
}
|
||||
|
||||
@ -309,6 +364,8 @@ void furi_hal_power_suppress_charge_exit() {
|
||||
xTaskResumeAll();
|
||||
|
||||
if (enable_charging) {
|
||||
bq25896_enable_charging();
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
bq25896_enable_charging(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
}
|
||||
}
|
@ -55,3 +55,6 @@ const GpioPin gpio_irda_tx = {.port = IR_TX_GPIO_Port, .pin = IR_TX_Pin};
|
||||
|
||||
const GpioPin gpio_usart_tx = {.port = USART1_TX_Port, .pin = USART1_TX_Pin};
|
||||
const GpioPin gpio_usart_rx = {.port = USART1_RX_Port, .pin = USART1_RX_Pin};
|
||||
|
||||
const GpioPin gpio_i2c_power_sda = {.port = GPIOA, .pin = LL_GPIO_PIN_10};
|
||||
const GpioPin gpio_i2c_power_scl = {.port = GPIOA, .pin = LL_GPIO_PIN_9};
|
||||
|
@ -10,24 +10,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define POWER_I2C_SCL_Pin LL_GPIO_PIN_9
|
||||
#define POWER_I2C_SCL_GPIO_Port GPIOA
|
||||
#define POWER_I2C_SDA_Pin LL_GPIO_PIN_10
|
||||
#define POWER_I2C_SDA_GPIO_Port GPIOA
|
||||
|
||||
#define POWER_I2C I2C1
|
||||
/** Timing register value is computed with the STM32CubeMX Tool,
|
||||
* Standard Mode @100kHz with I2CCLK = 64 MHz,
|
||||
* rise time = 0ns, fall time = 0ns
|
||||
*/
|
||||
#define POWER_I2C_TIMINGS_100 0x10707DBC
|
||||
|
||||
/** Timing register value is computed with the STM32CubeMX Tool,
|
||||
* Fast Mode @400kHz with I2CCLK = 64 MHz,
|
||||
* rise time = 0ns, fall time = 0ns
|
||||
*/
|
||||
#define POWER_I2C_TIMINGS_400 0x00602173
|
||||
|
||||
/* Input Related Constants */
|
||||
#define INPUT_DEBOUNCE_TICKS 20
|
||||
|
||||
@ -99,6 +81,9 @@ extern const GpioPin gpio_irda_tx;
|
||||
|
||||
extern const GpioPin gpio_usart_tx;
|
||||
extern const GpioPin gpio_usart_rx;
|
||||
extern const GpioPin gpio_i2c_power_sda;
|
||||
extern const GpioPin gpio_i2c_power_scl;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -1,108 +0,0 @@
|
||||
#pragma once
|
||||
#include "main.h"
|
||||
#include "furi-hal-spi-config.h"
|
||||
#include <furi-hal-gpio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Init SPI API
|
||||
*/
|
||||
void furi_hal_spi_init();
|
||||
|
||||
/* Bus Level API */
|
||||
|
||||
/** Lock SPI bus
|
||||
* Takes bus mutex, if used
|
||||
*/
|
||||
void furi_hal_spi_bus_lock(const FuriHalSpiBus* bus);
|
||||
|
||||
/** Unlock SPI bus
|
||||
* Releases BUS mutex, if used
|
||||
*/
|
||||
void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus);
|
||||
|
||||
/**
|
||||
* Configure SPI bus
|
||||
* @param bus - spi bus handler
|
||||
* @param config - spi configuration structure
|
||||
*/
|
||||
void furi_hal_spi_bus_configure(const FuriHalSpiBus* bus, const LL_SPI_InitTypeDef* config);
|
||||
|
||||
/** SPI Receive
|
||||
* @param bus - spi bus handler
|
||||
* @param buffer - receive buffer
|
||||
* @param size - transaction size
|
||||
* @param timeout - bus operation timeout in ms
|
||||
*/
|
||||
bool furi_hal_spi_bus_rx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout);
|
||||
|
||||
/** SPI Transmit
|
||||
* @param bus - spi bus handler
|
||||
* @param buffer - transmit buffer
|
||||
* @param size - transaction size
|
||||
* @param timeout - bus operation timeout in ms
|
||||
*/
|
||||
bool furi_hal_spi_bus_tx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout);
|
||||
|
||||
/** SPI Transmit and Receive
|
||||
* @param bus - spi bus handlere
|
||||
* @param tx_buffer - device handle
|
||||
* @param rx_buffer - device handle
|
||||
* @param size - transaction size
|
||||
* @param timeout - bus operation timeout in ms
|
||||
*/
|
||||
bool furi_hal_spi_bus_trx(const FuriHalSpiBus* bus, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout);
|
||||
|
||||
/* Device Level API */
|
||||
|
||||
/** Reconfigure SPI bus for device
|
||||
* @param device - device description
|
||||
*/
|
||||
void furi_hal_spi_device_configure(const FuriHalSpiDevice* device);
|
||||
|
||||
/** Get Device handle
|
||||
* And lock access to the corresponding SPI BUS
|
||||
* @param device_id - device identifier
|
||||
* @return device handle
|
||||
*/
|
||||
const FuriHalSpiDevice* furi_hal_spi_device_get(FuriHalSpiDeviceId device_id);
|
||||
|
||||
/** Return Device handle
|
||||
* And unlock access to the corresponding SPI BUS
|
||||
* @param device - device handle
|
||||
*/
|
||||
void furi_hal_spi_device_return(const FuriHalSpiDevice* device);
|
||||
|
||||
/** SPI Recieve
|
||||
* @param device - device handle
|
||||
* @param buffer - receive buffer
|
||||
* @param size - transaction size
|
||||
* @param timeout - bus operation timeout in ms
|
||||
*/
|
||||
bool furi_hal_spi_device_rx(const FuriHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout);
|
||||
|
||||
/** SPI Transmit
|
||||
* @param device - device handle
|
||||
* @param buffer - transmit buffer
|
||||
* @param size - transaction size
|
||||
* @param timeout - bus operation timeout in ms
|
||||
*/
|
||||
bool furi_hal_spi_device_tx(const FuriHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout);
|
||||
|
||||
/** SPI Transmit and Receive
|
||||
* @param device - device handle
|
||||
* @param tx_buffer - device handle
|
||||
* @param rx_buffer - device handle
|
||||
* @param size - transaction size
|
||||
* @param timeout - bus operation timeout in ms
|
||||
*/
|
||||
bool furi_hal_spi_device_trx(const FuriHalSpiDevice* device, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -280,7 +280,7 @@ static void vcp_on_cdc_control_line(void* context, uint8_t state) {
|
||||
|
||||
static void vcp_on_cdc_rx(void* context) {
|
||||
uint32_t ret = osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtRx);
|
||||
furi_assert((ret & osFlagsError) == 0);
|
||||
furi_check((ret & osFlagsError) == 0);
|
||||
}
|
||||
|
||||
static void vcp_on_cdc_tx_complete(void* context) {
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <furi-hal-resources.h>
|
||||
#include <furi-hal-i2c-config.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -17,18 +17,30 @@ extern "C" {
|
||||
*/
|
||||
void furi_hal_i2c_init();
|
||||
|
||||
/** Acquire i2c bus handle
|
||||
*
|
||||
* @return Instance of FuriHalI2cBus
|
||||
*/
|
||||
void furi_hal_i2c_acquire(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Release i2c bus handle
|
||||
*
|
||||
* @param bus instance of FuriHalI2cBus aquired in `furi_hal_i2c_acquire`
|
||||
*/
|
||||
void furi_hal_i2c_release(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Perform I2C tx transfer
|
||||
*
|
||||
* @param instance I2C_TypeDef instance
|
||||
* @param address I2C slave address
|
||||
* @param data pointer to data buffer
|
||||
* @param size size of data buffer
|
||||
* @param timeout timeout in CPU ticks
|
||||
* @param timeout timeout in ticks
|
||||
*
|
||||
* @return true on successful transfer, false otherwise
|
||||
*/
|
||||
bool furi_hal_i2c_tx(
|
||||
I2C_TypeDef* instance,
|
||||
FuriHalI2cBusHandle* handle,
|
||||
const uint8_t address,
|
||||
const uint8_t* data,
|
||||
const uint8_t size,
|
||||
@ -40,12 +52,12 @@ bool furi_hal_i2c_tx(
|
||||
* @param address I2C slave address
|
||||
* @param data pointer to data buffer
|
||||
* @param size size of data buffer
|
||||
* @param timeout timeout in CPU ticks
|
||||
* @param timeout timeout in ticks
|
||||
*
|
||||
* @return true on successful transfer, false otherwise
|
||||
*/
|
||||
bool furi_hal_i2c_rx(
|
||||
I2C_TypeDef* instance,
|
||||
FuriHalI2cBusHandle* handle,
|
||||
const uint8_t address,
|
||||
uint8_t* data,
|
||||
const uint8_t size,
|
||||
@ -59,12 +71,12 @@ bool furi_hal_i2c_rx(
|
||||
* @param tx_size size of tx data buffer
|
||||
* @param rx_data pointer to rx data buffer
|
||||
* @param rx_size size of rx data buffer
|
||||
* @param timeout timeout in CPU ticks
|
||||
* @param timeout timeout in ticks
|
||||
*
|
||||
* @return true on successful transfer, false otherwise
|
||||
*/
|
||||
bool furi_hal_i2c_trx(
|
||||
I2C_TypeDef* instance,
|
||||
FuriHalI2cBusHandle* handle,
|
||||
const uint8_t address,
|
||||
const uint8_t* tx_data,
|
||||
const uint8_t tx_size,
|
||||
@ -72,30 +84,6 @@ bool furi_hal_i2c_trx(
|
||||
const uint8_t rx_size,
|
||||
uint32_t timeout);
|
||||
|
||||
/** Acquire I2C mutex
|
||||
*/
|
||||
void furi_hal_i2c_lock();
|
||||
|
||||
/** Release I2C mutex
|
||||
*/
|
||||
void furi_hal_i2c_unlock();
|
||||
|
||||
/** With clause for I2C peripheral
|
||||
*
|
||||
* @param type type of function_body
|
||||
* @param pointer pointer to return of function_body
|
||||
* @param function_body a (){} lambda declaration, executed with I2C mutex
|
||||
* acquired
|
||||
*
|
||||
* @return Nothing
|
||||
*/
|
||||
#define with_furi_hal_i2c(type, pointer, function_body) \
|
||||
{ \
|
||||
furi_hal_i2c_lock(); \
|
||||
*pointer = ({ type __fn__ function_body __fn__; })(); \
|
||||
furi_hal_i2c_unlock(); \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -25,8 +25,7 @@ void furi_hal_spi_bus_lock(const FuriHalSpiBus* bus);
|
||||
*/
|
||||
void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus);
|
||||
|
||||
/**
|
||||
* Configure SPI bus
|
||||
/** Configure SPI bus
|
||||
* @param bus - spi bus handler
|
||||
* @param config - spi configuration structure
|
||||
*/
|
@ -1,7 +1,6 @@
|
||||
#include "bq25896.h"
|
||||
#include "bq25896_reg.h"
|
||||
|
||||
#include <furi-hal-i2c.h>
|
||||
#include <stddef.h>
|
||||
|
||||
uint8_t bit_reverse(uint8_t b) {
|
||||
@ -11,29 +10,17 @@ uint8_t bit_reverse(uint8_t b) {
|
||||
return b;
|
||||
}
|
||||
|
||||
bool bq25896_read(uint8_t address, uint8_t* data, size_t size) {
|
||||
bool ret;
|
||||
with_furi_hal_i2c(
|
||||
bool, &ret, () {
|
||||
return furi_hal_i2c_trx(
|
||||
POWER_I2C, BQ25896_ADDRESS, &address, 1, data, size, BQ25896_I2C_TIMEOUT);
|
||||
});
|
||||
return ret;
|
||||
bool bq25896_read(FuriHalI2cBusHandle* handle, uint8_t address, uint8_t* data, size_t size) {
|
||||
return furi_hal_i2c_trx(handle, BQ25896_ADDRESS, &address, 1, data, size, BQ25896_I2C_TIMEOUT);
|
||||
}
|
||||
|
||||
bool bq25896_read_reg(uint8_t address, uint8_t* data) {
|
||||
bq25896_read(address, data, 1);
|
||||
return true;
|
||||
bool bq25896_read_reg(FuriHalI2cBusHandle* handle, uint8_t address, uint8_t* data) {
|
||||
return bq25896_read(handle, address, data, 1);
|
||||
}
|
||||
|
||||
bool bq25896_write_reg(uint8_t address, uint8_t* data) {
|
||||
bool bq25896_write_reg(FuriHalI2cBusHandle* handle, uint8_t address, uint8_t* data) {
|
||||
uint8_t buffer[2] = {address, *data};
|
||||
bool ret;
|
||||
with_furi_hal_i2c(
|
||||
bool, &ret, () {
|
||||
return furi_hal_i2c_tx(POWER_I2C, BQ25896_ADDRESS, buffer, 2, BQ25896_I2C_TIMEOUT);
|
||||
});
|
||||
return ret;
|
||||
return furi_hal_i2c_tx(handle, BQ25896_ADDRESS, buffer, 2, BQ25896_I2C_TIMEOUT);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
@ -62,62 +49,62 @@ typedef struct {
|
||||
|
||||
static bq25896_regs_t bq25896_regs;
|
||||
|
||||
void bq25896_init() {
|
||||
void bq25896_init(FuriHalI2cBusHandle* handle) {
|
||||
bq25896_regs.r14.REG_RST = 1;
|
||||
bq25896_write_reg(0x14, (uint8_t*)&bq25896_regs.r14);
|
||||
bq25896_write_reg(handle, 0x14, (uint8_t*)&bq25896_regs.r14);
|
||||
|
||||
// Readout all registers
|
||||
bq25896_read(0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs));
|
||||
bq25896_read(handle, 0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs));
|
||||
|
||||
// Poll ADC forever
|
||||
bq25896_regs.r02.CONV_START = 1;
|
||||
bq25896_regs.r02.CONV_RATE = 1;
|
||||
bq25896_write_reg(0x02, (uint8_t*)&bq25896_regs.r02);
|
||||
bq25896_write_reg(handle, 0x02, (uint8_t*)&bq25896_regs.r02);
|
||||
|
||||
bq25896_regs.r07.WATCHDOG = WatchdogDisable;
|
||||
bq25896_write_reg(0x07, (uint8_t*)&bq25896_regs.r07);
|
||||
bq25896_write_reg(handle, 0x07, (uint8_t*)&bq25896_regs.r07);
|
||||
|
||||
bq25896_read(0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs));
|
||||
bq25896_read(handle, 0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs));
|
||||
}
|
||||
|
||||
void bq25896_poweroff() {
|
||||
void bq25896_poweroff(FuriHalI2cBusHandle* handle) {
|
||||
bq25896_regs.r09.BATFET_DIS = 1;
|
||||
bq25896_write_reg(0x09, (uint8_t*)&bq25896_regs.r09);
|
||||
bq25896_write_reg(handle, 0x09, (uint8_t*)&bq25896_regs.r09);
|
||||
}
|
||||
|
||||
bool bq25896_is_charging() {
|
||||
bq25896_read(0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs));
|
||||
bq25896_read_reg(0x0B, (uint8_t*)&bq25896_regs.r0B);
|
||||
bool bq25896_is_charging(FuriHalI2cBusHandle* handle) {
|
||||
bq25896_read(handle, 0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs));
|
||||
bq25896_read_reg(handle, 0x0B, (uint8_t*)&bq25896_regs.r0B);
|
||||
return bq25896_regs.r0B.CHRG_STAT != ChrgStatNo;
|
||||
}
|
||||
|
||||
void bq25896_enable_charging() {
|
||||
void bq25896_enable_charging(FuriHalI2cBusHandle* handle) {
|
||||
bq25896_regs.r03.CHG_CONFIG = 1;
|
||||
bq25896_write_reg(0x03, (uint8_t*)&bq25896_regs.r03);
|
||||
bq25896_write_reg(handle, 0x03, (uint8_t*)&bq25896_regs.r03);
|
||||
}
|
||||
|
||||
void bq25896_disable_charging() {
|
||||
void bq25896_disable_charging(FuriHalI2cBusHandle* handle) {
|
||||
bq25896_regs.r03.CHG_CONFIG = 0;
|
||||
bq25896_write_reg(0x03, (uint8_t*)&bq25896_regs.r03);
|
||||
bq25896_write_reg(handle, 0x03, (uint8_t*)&bq25896_regs.r03);
|
||||
}
|
||||
|
||||
void bq25896_enable_otg() {
|
||||
void bq25896_enable_otg(FuriHalI2cBusHandle* handle) {
|
||||
bq25896_regs.r03.OTG_CONFIG = 1;
|
||||
bq25896_write_reg(0x03, (uint8_t*)&bq25896_regs.r03);
|
||||
bq25896_write_reg(handle, 0x03, (uint8_t*)&bq25896_regs.r03);
|
||||
}
|
||||
|
||||
void bq25896_disable_otg() {
|
||||
void bq25896_disable_otg(FuriHalI2cBusHandle* handle) {
|
||||
bq25896_regs.r03.OTG_CONFIG = 0;
|
||||
bq25896_write_reg(0x03, (uint8_t*)&bq25896_regs.r03);
|
||||
bq25896_write_reg(handle, 0x03, (uint8_t*)&bq25896_regs.r03);
|
||||
}
|
||||
|
||||
bool bq25896_is_otg_enabled() {
|
||||
bq25896_read_reg(0x03, (uint8_t*)&bq25896_regs.r03);
|
||||
bool bq25896_is_otg_enabled(FuriHalI2cBusHandle* handle) {
|
||||
bq25896_read_reg(handle, 0x03, (uint8_t*)&bq25896_regs.r03);
|
||||
return bq25896_regs.r03.OTG_CONFIG;
|
||||
}
|
||||
|
||||
uint16_t bq25896_get_vbus_voltage() {
|
||||
bq25896_read_reg(0x11, (uint8_t*)&bq25896_regs.r11);
|
||||
uint16_t bq25896_get_vbus_voltage(FuriHalI2cBusHandle* handle) {
|
||||
bq25896_read_reg(handle, 0x11, (uint8_t*)&bq25896_regs.r11);
|
||||
if(bq25896_regs.r11.VBUS_GD) {
|
||||
return (uint16_t)bq25896_regs.r11.VBUSV * 100 + 2600;
|
||||
} else {
|
||||
@ -125,22 +112,22 @@ uint16_t bq25896_get_vbus_voltage() {
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t bq25896_get_vsys_voltage() {
|
||||
bq25896_read_reg(0x0F, (uint8_t*)&bq25896_regs.r0F);
|
||||
uint16_t bq25896_get_vsys_voltage(FuriHalI2cBusHandle* handle) {
|
||||
bq25896_read_reg(handle, 0x0F, (uint8_t*)&bq25896_regs.r0F);
|
||||
return (uint16_t)bq25896_regs.r0F.SYSV * 20 + 2304;
|
||||
}
|
||||
|
||||
uint16_t bq25896_get_vbat_voltage() {
|
||||
bq25896_read_reg(0x0E, (uint8_t*)&bq25896_regs.r0E);
|
||||
uint16_t bq25896_get_vbat_voltage(FuriHalI2cBusHandle* handle) {
|
||||
bq25896_read_reg(handle, 0x0E, (uint8_t*)&bq25896_regs.r0E);
|
||||
return (uint16_t)bq25896_regs.r0E.BATV * 20 + 2304;
|
||||
}
|
||||
|
||||
uint16_t bq25896_get_vbat_current() {
|
||||
bq25896_read_reg(0x12, (uint8_t*)&bq25896_regs.r12);
|
||||
uint16_t bq25896_get_vbat_current(FuriHalI2cBusHandle* handle) {
|
||||
bq25896_read_reg(handle, 0x12, (uint8_t*)&bq25896_regs.r12);
|
||||
return (uint16_t)bq25896_regs.r12.ICHGR * 50;
|
||||
}
|
||||
|
||||
uint32_t bq25896_get_ntc_mpct() {
|
||||
bq25896_read_reg(0x10, (uint8_t*)&bq25896_regs.r10);
|
||||
uint32_t bq25896_get_ntc_mpct(FuriHalI2cBusHandle* handle) {
|
||||
bq25896_read_reg(handle, 0x10, (uint8_t*)&bq25896_regs.r10);
|
||||
return (uint32_t)bq25896_regs.r10.TSPCT * 465 + 21000;
|
||||
}
|
||||
|
@ -2,42 +2,43 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <furi-hal-i2c.h>
|
||||
|
||||
/** Initialize Driver */
|
||||
void bq25896_init();
|
||||
void bq25896_init(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Send device into shipping mode */
|
||||
void bq25896_poweroff();
|
||||
void bq25896_poweroff(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Is currently charging */
|
||||
bool bq25896_is_charging();
|
||||
bool bq25896_is_charging(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Enable charging */
|
||||
void bq25896_enable_charging();
|
||||
void bq25896_enable_charging(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Disable charging */
|
||||
void bq25896_disable_charging();
|
||||
void bq25896_disable_charging(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Enable otg */
|
||||
void bq25896_enable_otg();
|
||||
void bq25896_enable_otg(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Disable otg */
|
||||
void bq25896_disable_otg();
|
||||
void bq25896_disable_otg(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Is otg enabled */
|
||||
bool bq25896_is_otg_enabled();
|
||||
bool bq25896_is_otg_enabled(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Get VBUS Voltage in mV */
|
||||
uint16_t bq25896_get_vbus_voltage();
|
||||
uint16_t bq25896_get_vbus_voltage(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Get VSYS Voltage in mV */
|
||||
uint16_t bq25896_get_vsys_voltage();
|
||||
uint16_t bq25896_get_vsys_voltage(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Get VBAT Voltage in mV */
|
||||
uint16_t bq25896_get_vbat_voltage();
|
||||
uint16_t bq25896_get_vbat_voltage(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Get VBAT current in mA */
|
||||
uint16_t bq25896_get_vbat_current();
|
||||
uint16_t bq25896_get_vbat_current(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Get NTC voltage in mpct of REGN */
|
||||
uint32_t bq25896_get_ntc_mpct();
|
||||
uint32_t bq25896_get_ntc_mpct(FuriHalI2cBusHandle* handle);
|
||||
|
@ -1,37 +1,32 @@
|
||||
#include "bq27220.h"
|
||||
#include "bq27220_reg.h"
|
||||
|
||||
#include <furi-hal-i2c.h>
|
||||
#include <furi-hal-delay.h>
|
||||
#include <furi/log.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define TAG "Gauge"
|
||||
|
||||
uint16_t bq27220_read_word(uint8_t address) {
|
||||
uint16_t bq27220_read_word(FuriHalI2cBusHandle* handle, uint8_t address) {
|
||||
uint8_t buffer[2] = {address};
|
||||
uint16_t ret;
|
||||
with_furi_hal_i2c(
|
||||
uint16_t, &ret, () {
|
||||
if(furi_hal_i2c_trx(
|
||||
POWER_I2C, BQ27220_ADDRESS, buffer, 1, buffer, 2, BQ27220_I2C_TIMEOUT)) {
|
||||
return *(uint16_t*)buffer;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
uint16_t ret = 0;
|
||||
|
||||
if(furi_hal_i2c_trx(handle, BQ27220_ADDRESS, buffer, 1, buffer, 2, BQ27220_I2C_TIMEOUT)) {
|
||||
ret = *(uint16_t*)buffer;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool bq27220_control(uint16_t control) {
|
||||
bool ret;
|
||||
with_furi_hal_i2c(
|
||||
bool, &ret, () {
|
||||
uint8_t buffer[3];
|
||||
buffer[0] = CommandControl;
|
||||
buffer[1] = control & 0xFF;
|
||||
buffer[2] = (control >> 8) & 0xFF;
|
||||
return furi_hal_i2c_tx(POWER_I2C, BQ27220_ADDRESS, buffer, 3, BQ27220_I2C_TIMEOUT);
|
||||
});
|
||||
bool bq27220_control(FuriHalI2cBusHandle* handle, uint16_t control) {
|
||||
bool ret = false;
|
||||
uint8_t buffer[3];
|
||||
|
||||
buffer[0] = CommandControl;
|
||||
buffer[1] = control & 0xFF;
|
||||
buffer[2] = (control >> 8) & 0xFF;
|
||||
ret = furi_hal_i2c_tx(handle, BQ27220_ADDRESS, buffer, 3, BQ27220_I2C_TIMEOUT);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -43,75 +38,73 @@ uint8_t bq27220_get_checksum(uint8_t* data, uint16_t len) {
|
||||
return 0xFF - ret;
|
||||
}
|
||||
|
||||
bool bq27220_set_parameter_u16(uint16_t address, uint16_t value) {
|
||||
bool bq27220_set_parameter_u16(FuriHalI2cBusHandle* handle, uint16_t address, uint16_t value) {
|
||||
bool ret;
|
||||
uint8_t buffer[5];
|
||||
with_furi_hal_i2c(
|
||||
bool, &ret, () {
|
||||
buffer[0] = CommandSelectSubclass;
|
||||
buffer[1] = address & 0xFF;
|
||||
buffer[2] = (address >> 8) & 0xFF;
|
||||
buffer[3] = (value >> 8) & 0xFF;
|
||||
buffer[4] = value & 0xFF;
|
||||
return furi_hal_i2c_tx(POWER_I2C, BQ27220_ADDRESS, buffer, 5, BQ27220_I2C_TIMEOUT);
|
||||
});
|
||||
|
||||
buffer[0] = CommandSelectSubclass;
|
||||
buffer[1] = address & 0xFF;
|
||||
buffer[2] = (address >> 8) & 0xFF;
|
||||
buffer[3] = (value >> 8) & 0xFF;
|
||||
buffer[4] = value & 0xFF;
|
||||
ret = furi_hal_i2c_tx(handle, BQ27220_ADDRESS, buffer, 5, BQ27220_I2C_TIMEOUT);
|
||||
|
||||
delay_us(10000);
|
||||
|
||||
uint8_t checksum = bq27220_get_checksum(&buffer[1], 4);
|
||||
with_furi_hal_i2c(
|
||||
bool, &ret, () {
|
||||
buffer[0] = CommandMACDataSum;
|
||||
buffer[1] = checksum;
|
||||
buffer[2] = 6;
|
||||
return furi_hal_i2c_tx(POWER_I2C, BQ27220_ADDRESS, buffer, 3, BQ27220_I2C_TIMEOUT);
|
||||
});
|
||||
buffer[0] = CommandMACDataSum;
|
||||
buffer[1] = checksum;
|
||||
buffer[2] = 6;
|
||||
ret = furi_hal_i2c_tx(handle, BQ27220_ADDRESS, buffer, 3, BQ27220_I2C_TIMEOUT);
|
||||
|
||||
delay_us(10000);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool bq27220_init(const ParamCEDV* cedv) {
|
||||
bool bq27220_init(FuriHalI2cBusHandle* handle, const ParamCEDV* cedv) {
|
||||
uint32_t timeout = 100;
|
||||
uint16_t design_cap = bq27220_get_design_capacity();
|
||||
uint16_t design_cap = bq27220_get_design_capacity(handle);
|
||||
if(cedv->design_cap == design_cap) {
|
||||
FURI_LOG_I(TAG, "Skip battery profile update");
|
||||
return true;
|
||||
}
|
||||
FURI_LOG_I(TAG, "Start updating battery profile");
|
||||
OperationStatus status = {};
|
||||
if(!bq27220_control(Control_ENTER_CFG_UPDATE)) {
|
||||
if(!bq27220_control(handle, Control_ENTER_CFG_UPDATE)) {
|
||||
FURI_LOG_E(TAG, "Can't configure update");
|
||||
return false;
|
||||
};
|
||||
|
||||
while((status.CFGUPDATE != 1) && (timeout-- > 0)) {
|
||||
bq27220_get_operation_status(&status);
|
||||
bq27220_get_operation_status(handle, &status);
|
||||
}
|
||||
bq27220_set_parameter_u16(AddressGaugingConfig, cedv->cedv_conf.gauge_conf_raw);
|
||||
bq27220_set_parameter_u16(AddressFullChargeCapacity, cedv->full_charge_cap);
|
||||
bq27220_set_parameter_u16(AddressDesignCapacity, cedv->design_cap);
|
||||
bq27220_set_parameter_u16(AddressEMF, cedv->EMF);
|
||||
bq27220_set_parameter_u16(AddressC0, cedv->C0);
|
||||
bq27220_set_parameter_u16(AddressR0, cedv->R0);
|
||||
bq27220_set_parameter_u16(AddressT0, cedv->T0);
|
||||
bq27220_set_parameter_u16(AddressR1, cedv->R1);
|
||||
bq27220_set_parameter_u16(AddressTC, (cedv->TC) << 8 | cedv->C1);
|
||||
bq27220_set_parameter_u16(AddressStartDOD0, cedv->DOD0);
|
||||
bq27220_set_parameter_u16(AddressStartDOD10, cedv->DOD10);
|
||||
bq27220_set_parameter_u16(AddressStartDOD20, cedv->DOD20);
|
||||
bq27220_set_parameter_u16(AddressStartDOD30, cedv->DOD30);
|
||||
bq27220_set_parameter_u16(AddressStartDOD40, cedv->DOD40);
|
||||
bq27220_set_parameter_u16(AddressStartDOD50, cedv->DOD40);
|
||||
bq27220_set_parameter_u16(AddressStartDOD60, cedv->DOD60);
|
||||
bq27220_set_parameter_u16(AddressStartDOD70, cedv->DOD70);
|
||||
bq27220_set_parameter_u16(AddressStartDOD80, cedv->DOD80);
|
||||
bq27220_set_parameter_u16(AddressStartDOD90, cedv->DOD90);
|
||||
bq27220_set_parameter_u16(AddressStartDOD100, cedv->DOD100);
|
||||
bq27220_set_parameter_u16(AddressEDV0, cedv->EDV0);
|
||||
bq27220_set_parameter_u16(AddressEDV1, cedv->EDV1);
|
||||
bq27220_set_parameter_u16(AddressEDV2, cedv->EDV2);
|
||||
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(Control_EXIT_CFG_UPDATE);
|
||||
bq27220_control(handle, Control_EXIT_CFG_UPDATE);
|
||||
delay_us(10000);
|
||||
design_cap = bq27220_get_design_capacity();
|
||||
design_cap = bq27220_get_design_capacity(handle);
|
||||
if(cedv->design_cap == design_cap) {
|
||||
FURI_LOG_I(TAG, "Battery profile update success");
|
||||
return true;
|
||||
@ -121,16 +114,16 @@ bool bq27220_init(const ParamCEDV* cedv) {
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t bq27220_get_voltage() {
|
||||
return bq27220_read_word(CommandVoltage);
|
||||
uint16_t bq27220_get_voltage(FuriHalI2cBusHandle* handle) {
|
||||
return bq27220_read_word(handle, CommandVoltage);
|
||||
}
|
||||
|
||||
int16_t bq27220_get_current() {
|
||||
return bq27220_read_word(CommandCurrent);
|
||||
int16_t bq27220_get_current(FuriHalI2cBusHandle* handle) {
|
||||
return bq27220_read_word(handle, CommandCurrent);
|
||||
}
|
||||
|
||||
uint8_t bq27220_get_battery_status(BatteryStatus* battery_status) {
|
||||
uint16_t data = bq27220_read_word(CommandBatteryStatus);
|
||||
uint8_t bq27220_get_battery_status(FuriHalI2cBusHandle* handle, BatteryStatus* battery_status) {
|
||||
uint16_t data = bq27220_read_word(handle, CommandBatteryStatus);
|
||||
if(data == BQ27220_ERROR) {
|
||||
return BQ27220_ERROR;
|
||||
} else {
|
||||
@ -139,8 +132,8 @@ uint8_t bq27220_get_battery_status(BatteryStatus* battery_status) {
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t bq27220_get_operation_status(OperationStatus* operation_status) {
|
||||
uint16_t data = bq27220_read_word(CommandOperationStatus);
|
||||
uint8_t bq27220_get_operation_status(FuriHalI2cBusHandle* handle, OperationStatus* operation_status) {
|
||||
uint16_t data = bq27220_read_word(handle, CommandOperationStatus);
|
||||
if(data == BQ27220_ERROR) {
|
||||
return BQ27220_ERROR;
|
||||
} else {
|
||||
@ -149,26 +142,26 @@ uint8_t bq27220_get_operation_status(OperationStatus* operation_status) {
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t bq27220_get_temperature() {
|
||||
return bq27220_read_word(CommandTemperature);
|
||||
uint16_t bq27220_get_temperature(FuriHalI2cBusHandle* handle) {
|
||||
return bq27220_read_word(handle, CommandTemperature);
|
||||
}
|
||||
|
||||
uint16_t bq27220_get_full_charge_capacity() {
|
||||
return bq27220_read_word(CommandFullChargeCapacity);
|
||||
uint16_t bq27220_get_full_charge_capacity(FuriHalI2cBusHandle* handle) {
|
||||
return bq27220_read_word(handle, CommandFullChargeCapacity);
|
||||
}
|
||||
|
||||
uint16_t bq27220_get_design_capacity() {
|
||||
return bq27220_read_word(CommandDesignCapacity);
|
||||
uint16_t bq27220_get_design_capacity(FuriHalI2cBusHandle* handle) {
|
||||
return bq27220_read_word(handle, CommandDesignCapacity);
|
||||
}
|
||||
|
||||
uint16_t bq27220_get_remaining_capacity() {
|
||||
return bq27220_read_word(CommandRemainingCapacity);
|
||||
uint16_t bq27220_get_remaining_capacity(FuriHalI2cBusHandle* handle) {
|
||||
return bq27220_read_word(handle, CommandRemainingCapacity);
|
||||
}
|
||||
|
||||
uint16_t bq27220_get_state_of_charge() {
|
||||
return bq27220_read_word(CommandStateOfCharge);
|
||||
uint16_t bq27220_get_state_of_charge(FuriHalI2cBusHandle* handle) {
|
||||
return bq27220_read_word(handle, CommandStateOfCharge);
|
||||
}
|
||||
|
||||
uint16_t bq27220_get_state_of_health() {
|
||||
return bq27220_read_word(CommandStateOfHealth);
|
||||
uint16_t bq27220_get_state_of_health(FuriHalI2cBusHandle* handle) {
|
||||
return bq27220_read_word(handle, CommandStateOfHealth);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <furi-hal-i2c.h>
|
||||
|
||||
#define BQ27220_ERROR 0x0
|
||||
#define BQ27220_SUCCESS 0x1
|
||||
@ -95,36 +96,36 @@ typedef struct {
|
||||
/** Initialize Driver
|
||||
* @return true on success, false otherwise
|
||||
*/
|
||||
bool bq27220_init(const ParamCEDV* cedv);
|
||||
bool bq27220_init(FuriHalI2cBusHandle* handle, const ParamCEDV* cedv);
|
||||
|
||||
/** Get battery voltage in mV or error */
|
||||
uint16_t bq27220_get_voltage();
|
||||
uint16_t bq27220_get_voltage(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Get current in mA or error*/
|
||||
int16_t bq27220_get_current();
|
||||
int16_t bq27220_get_current(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Get battery status */
|
||||
uint8_t bq27220_get_battery_status(BatteryStatus* battery_status);
|
||||
uint8_t bq27220_get_battery_status(FuriHalI2cBusHandle* handle, BatteryStatus* battery_status);
|
||||
|
||||
/** Get operation status */
|
||||
uint8_t bq27220_get_operation_status(OperationStatus* operation_status);
|
||||
uint8_t bq27220_get_operation_status(FuriHalI2cBusHandle* handle, OperationStatus* operation_status);
|
||||
|
||||
/** Get temperature in units of 0.1°K */
|
||||
uint16_t bq27220_get_temperature();
|
||||
uint16_t bq27220_get_temperature(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Get compensated full charge capacity in in mAh */
|
||||
uint16_t bq27220_get_full_charge_capacity();
|
||||
uint16_t bq27220_get_full_charge_capacity(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Get design capacity in mAh */
|
||||
uint16_t bq27220_get_design_capacity();
|
||||
uint16_t bq27220_get_design_capacity(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Get remaining capacity in in mAh */
|
||||
uint16_t bq27220_get_remaining_capacity();
|
||||
uint16_t bq27220_get_remaining_capacity(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Get predicted remaining battery capacity in percents */
|
||||
uint16_t bq27220_get_state_of_charge();
|
||||
uint16_t bq27220_get_state_of_charge(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Get ratio of full charge capacity over design capacity in percents */
|
||||
uint16_t bq27220_get_state_of_health();
|
||||
uint16_t bq27220_get_state_of_health(FuriHalI2cBusHandle* handle);
|
||||
|
||||
void bq27220_change_design_capacity(uint16_t capacity);
|
||||
void bq27220_change_design_capacity(FuriHalI2cBusHandle* handle, uint16_t capacity);
|
||||
|
@ -1,27 +1,21 @@
|
||||
#include "lp5562.h"
|
||||
#include "lp5562_reg.h"
|
||||
|
||||
#include <furi-hal-i2c.h>
|
||||
#include <stdio.h>
|
||||
|
||||
bool lp5562_write_reg(uint8_t address, uint8_t* data) {
|
||||
static bool lp5562_write_reg(FuriHalI2cBusHandle* handle, uint8_t address, uint8_t* data) {
|
||||
uint8_t buffer[2] = {address, *data};
|
||||
bool ret;
|
||||
with_furi_hal_i2c(
|
||||
bool, &ret, () {
|
||||
return furi_hal_i2c_tx(POWER_I2C, LP5562_ADDRESS, buffer, 2, LP5562_I2C_TIMEOUT);
|
||||
});
|
||||
return ret;
|
||||
return furi_hal_i2c_tx(handle, LP5562_ADDRESS, buffer, 2, LP5562_I2C_TIMEOUT);
|
||||
}
|
||||
|
||||
void lp5562_reset() {
|
||||
void lp5562_reset(FuriHalI2cBusHandle* handle) {
|
||||
Reg0D_Reset reg = {.value = 0xFF};
|
||||
lp5562_write_reg(0x0D, (uint8_t*)®);
|
||||
lp5562_write_reg(handle, 0x0D, (uint8_t*)®);
|
||||
}
|
||||
|
||||
void lp5562_configure() {
|
||||
void lp5562_configure(FuriHalI2cBusHandle* handle) {
|
||||
Reg08_Config config = {.INT_CLK_EN = true, .PS_EN = true, .PWM_HF = true};
|
||||
lp5562_write_reg(0x08, (uint8_t*)&config);
|
||||
lp5562_write_reg(handle, 0x08, (uint8_t*)&config);
|
||||
|
||||
Reg70_LedMap map = {
|
||||
.red = EngSelectI2C,
|
||||
@ -29,15 +23,15 @@ void lp5562_configure() {
|
||||
.blue = EngSelectI2C,
|
||||
.white = EngSelectI2C,
|
||||
};
|
||||
lp5562_write_reg(0x70, (uint8_t*)&map);
|
||||
lp5562_write_reg(handle, 0x70, (uint8_t*)&map);
|
||||
}
|
||||
|
||||
void lp5562_enable() {
|
||||
void lp5562_enable(FuriHalI2cBusHandle* handle) {
|
||||
Reg00_Enable reg = {.CHIP_EN = true, .LOG_EN = true};
|
||||
lp5562_write_reg(0x00, (uint8_t*)®);
|
||||
lp5562_write_reg(handle, 0x00, (uint8_t*)®);
|
||||
}
|
||||
|
||||
void lp5562_set_channel_current(LP5562Channel channel, uint8_t value) {
|
||||
void lp5562_set_channel_current(FuriHalI2cBusHandle* handle, LP5562Channel channel, uint8_t value) {
|
||||
uint8_t reg_no;
|
||||
if(channel == LP5562ChannelRed) {
|
||||
reg_no = 0x07;
|
||||
@ -50,10 +44,10 @@ void lp5562_set_channel_current(LP5562Channel channel, uint8_t value) {
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
lp5562_write_reg(reg_no, &value);
|
||||
lp5562_write_reg(handle, reg_no, &value);
|
||||
}
|
||||
|
||||
void lp5562_set_channel_value(LP5562Channel channel, uint8_t value) {
|
||||
void lp5562_set_channel_value(FuriHalI2cBusHandle* handle, LP5562Channel channel, uint8_t value) {
|
||||
uint8_t reg_no;
|
||||
if(channel == LP5562ChannelRed) {
|
||||
reg_no = 0x04;
|
||||
@ -66,5 +60,5 @@ void lp5562_set_channel_value(LP5562Channel channel, uint8_t value) {
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
lp5562_write_reg(reg_no, &value);
|
||||
lp5562_write_reg(handle, reg_no, &value);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <furi-hal-i2c.h>
|
||||
|
||||
/** Channel types */
|
||||
typedef enum {
|
||||
@ -12,16 +13,16 @@ typedef enum {
|
||||
} LP5562Channel;
|
||||
|
||||
/** Initialize Driver */
|
||||
void lp5562_reset();
|
||||
void lp5562_reset(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Configure Driver */
|
||||
void lp5562_configure();
|
||||
void lp5562_configure(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Enable Driver */
|
||||
void lp5562_enable();
|
||||
void lp5562_enable(FuriHalI2cBusHandle* handle);
|
||||
|
||||
/** Set channel current */
|
||||
void lp5562_set_channel_current(LP5562Channel channel, uint8_t value);
|
||||
void lp5562_set_channel_current(FuriHalI2cBusHandle* handle, LP5562Channel channel, uint8_t value);
|
||||
|
||||
/** Set channel current */
|
||||
void lp5562_set_channel_value(LP5562Channel channel, uint8_t value);
|
||||
void lp5562_set_channel_value(FuriHalI2cBusHandle* handle, LP5562Channel channel, uint8_t value);
|
||||
|
Loading…
Reference in New Issue
Block a user