[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);
|
string_init_printf(fullname, "%s/%s", string_get_cstr(cur_dir), name);
|
||||||
FS_Error error = storage_common_remove(storage, string_get_cstr(fullname));
|
FS_Error error = storage_common_remove(storage, string_get_cstr(fullname));
|
||||||
furi_assert(error == FSE_OK);
|
furi_check(error == FSE_OK);
|
||||||
string_clear(fullname);
|
string_clear(fullname);
|
||||||
}
|
}
|
||||||
storage_dir_close(dir);
|
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));
|
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)) {
|
if(string_cmp(cur_dir, path)) {
|
||||||
size_t last_char = string_search_rchar(cur_dir, '/');
|
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);
|
clean_directory(fs_api, fullname);
|
||||||
}
|
}
|
||||||
FS_Error error = storage_common_remove(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(fullname);
|
||||||
}
|
}
|
||||||
free(name);
|
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-i2c.h>
|
||||||
|
#include <furi-hal-version.h>
|
||||||
|
|
||||||
#include <stm32wbxx_ll_bus.h>
|
|
||||||
#include <stm32wbxx_ll_i2c.h>
|
#include <stm32wbxx_ll_i2c.h>
|
||||||
#include <stm32wbxx_ll_rcc.h>
|
|
||||||
#include <stm32wbxx_ll_gpio.h>
|
#include <stm32wbxx_ll_gpio.h>
|
||||||
#include <stm32wbxx_ll_cortex.h>
|
#include <stm32wbxx_ll_cortex.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
void furi_hal_i2c_init() {
|
void furi_hal_i2c_init() {
|
||||||
LL_I2C_InitTypeDef I2C_InitStruct = {0};
|
furi_hal_i2c_bus_power.callback(&furi_hal_i2c_bus_power, FuriHalI2cBusEventInit);
|
||||||
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
|
}
|
||||||
|
|
||||||
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);
|
assert(handle->bus->current_handle == NULL);
|
||||||
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);
|
|
||||||
|
|
||||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);
|
handle->bus->current_handle = handle;
|
||||||
|
|
||||||
I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
|
handle->bus->callback(handle->bus, FuriHalI2cBusEventActivate);
|
||||||
I2C_InitStruct.Timing = POWER_I2C_TIMINGS;
|
|
||||||
I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
|
handle->callback(handle, FuriHalI2cBusHandleEventActivate);
|
||||||
I2C_InitStruct.DigitalFilter = 0;
|
}
|
||||||
I2C_InitStruct.OwnAddress1 = 0;
|
|
||||||
I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
|
void furi_hal_i2c_release(FuriHalI2cBusHandle* handle) {
|
||||||
I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
|
assert(handle->bus->current_handle == handle);
|
||||||
LL_I2C_Init(I2C1, &I2C_InitStruct);
|
|
||||||
LL_I2C_EnableAutoEndMode(I2C1);
|
handle->callback(handle, FuriHalI2cBusHandleEventDeactivate);
|
||||||
LL_I2C_SetOwnAddress2(I2C1, 0, LL_I2C_OWNADDRESS2_NOMASK);
|
|
||||||
LL_I2C_DisableOwnAddress2(I2C1);
|
handle->bus->callback(handle->bus, FuriHalI2cBusEventDeactivate);
|
||||||
LL_I2C_DisableGeneralCall(I2C1);
|
|
||||||
LL_I2C_EnableClockStretching(I2C1);
|
handle->bus->current_handle = NULL;
|
||||||
|
|
||||||
|
handle->bus->callback(handle->bus, FuriHalI2cBusEventUnlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool furi_hal_i2c_tx(
|
bool furi_hal_i2c_tx(
|
||||||
I2C_TypeDef* instance,
|
FuriHalI2cBusHandle* handle,
|
||||||
uint8_t address,
|
uint8_t address,
|
||||||
const uint8_t* data,
|
const uint8_t* data,
|
||||||
uint8_t size,
|
uint8_t size,
|
||||||
uint32_t timeout) {
|
uint32_t timeout) {
|
||||||
|
assert(handle->bus->current_handle == handle);
|
||||||
uint32_t time_left = timeout;
|
uint32_t time_left = timeout;
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
|
|
||||||
while(LL_I2C_IsActiveFlag_BUSY(instance))
|
while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
|
||||||
;
|
;
|
||||||
|
|
||||||
LL_I2C_HandleTransfer(
|
LL_I2C_HandleTransfer(
|
||||||
instance,
|
handle->bus->i2c,
|
||||||
address,
|
address,
|
||||||
LL_I2C_ADDRSLAVE_7BIT,
|
LL_I2C_ADDRSLAVE_7BIT,
|
||||||
size,
|
size,
|
||||||
LL_I2C_MODE_AUTOEND,
|
LL_I2C_MODE_AUTOEND,
|
||||||
LL_I2C_GENERATE_START_WRITE);
|
LL_I2C_GENERATE_START_WRITE);
|
||||||
|
|
||||||
while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
|
while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
|
||||||
if(LL_I2C_IsActiveFlag_TXIS(instance)) {
|
if(LL_I2C_IsActiveFlag_TXIS(handle->bus->i2c)) {
|
||||||
LL_I2C_TransmitData8(instance, (*data));
|
LL_I2C_TransmitData8(handle->bus->i2c, (*data));
|
||||||
data++;
|
data++;
|
||||||
size--;
|
size--;
|
||||||
time_left = timeout;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool furi_hal_i2c_rx(
|
bool furi_hal_i2c_rx(
|
||||||
I2C_TypeDef* instance,
|
FuriHalI2cBusHandle* handle,
|
||||||
uint8_t address,
|
uint8_t address,
|
||||||
uint8_t* data,
|
uint8_t* data,
|
||||||
uint8_t size,
|
uint8_t size,
|
||||||
uint32_t timeout) {
|
uint32_t timeout) {
|
||||||
|
assert(handle->bus->current_handle == handle);
|
||||||
uint32_t time_left = timeout;
|
uint32_t time_left = timeout;
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
|
|
||||||
while(LL_I2C_IsActiveFlag_BUSY(instance))
|
while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
|
||||||
;
|
;
|
||||||
|
|
||||||
LL_I2C_HandleTransfer(
|
LL_I2C_HandleTransfer(
|
||||||
instance,
|
handle->bus->i2c,
|
||||||
address,
|
address,
|
||||||
LL_I2C_ADDRSLAVE_7BIT,
|
LL_I2C_ADDRSLAVE_7BIT,
|
||||||
size,
|
size,
|
||||||
LL_I2C_MODE_AUTOEND,
|
LL_I2C_MODE_AUTOEND,
|
||||||
LL_I2C_GENERATE_START_READ);
|
LL_I2C_GENERATE_START_READ);
|
||||||
|
|
||||||
while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
|
while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
|
||||||
if(LL_I2C_IsActiveFlag_RXNE(instance)) {
|
if(LL_I2C_IsActiveFlag_RXNE(handle->bus->i2c)) {
|
||||||
*data = LL_I2C_ReceiveData8(instance);
|
*data = LL_I2C_ReceiveData8(handle->bus->i2c);
|
||||||
data++;
|
data++;
|
||||||
size--;
|
size--;
|
||||||
time_left = timeout;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool furi_hal_i2c_trx(
|
bool furi_hal_i2c_trx(
|
||||||
I2C_TypeDef* instance,
|
FuriHalI2cBusHandle* handle,
|
||||||
uint8_t address,
|
uint8_t address,
|
||||||
const uint8_t* tx_data,
|
const uint8_t* tx_data,
|
||||||
uint8_t tx_size,
|
uint8_t tx_size,
|
||||||
uint8_t* rx_data,
|
uint8_t* rx_data,
|
||||||
uint8_t rx_size,
|
uint8_t rx_size,
|
||||||
uint32_t timeout) {
|
uint32_t timeout) {
|
||||||
if(furi_hal_i2c_tx(instance, address, tx_data, tx_size, timeout) &&
|
if(furi_hal_i2c_tx(handle, address, tx_data, tx_size, timeout) &&
|
||||||
furi_hal_i2c_rx(instance, address, rx_data, rx_size, timeout)) {
|
furi_hal_i2c_rx(handle, address, rx_data, rx_size, timeout)) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -1,31 +1,82 @@
|
|||||||
|
/**
|
||||||
|
* @file furi-hal-i2c.h
|
||||||
|
* I2C HAL API
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <furi-hal-resources.h>
|
#include <furi-hal-i2c-config.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** Init I2C
|
||||||
|
*/
|
||||||
void furi_hal_i2c_init();
|
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(
|
bool furi_hal_i2c_tx(
|
||||||
I2C_TypeDef* instance,
|
FuriHalI2cBusHandle* handle,
|
||||||
const uint8_t address,
|
const uint8_t address,
|
||||||
const uint8_t* data,
|
const uint8_t* data,
|
||||||
const uint8_t size,
|
const uint8_t size,
|
||||||
uint32_t timeout);
|
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(
|
bool furi_hal_i2c_rx(
|
||||||
I2C_TypeDef* instance,
|
FuriHalI2cBusHandle* handle,
|
||||||
const uint8_t address,
|
const uint8_t address,
|
||||||
uint8_t* data,
|
uint8_t* data,
|
||||||
const uint8_t size,
|
const uint8_t size,
|
||||||
uint32_t timeout);
|
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(
|
bool furi_hal_i2c_trx(
|
||||||
I2C_TypeDef* instance,
|
FuriHalI2cBusHandle* handle,
|
||||||
const uint8_t address,
|
const uint8_t address,
|
||||||
const uint8_t* tx_data,
|
const uint8_t* tx_data,
|
||||||
const uint8_t tx_size,
|
const uint8_t tx_size,
|
||||||
@ -33,11 +84,6 @@ bool furi_hal_i2c_trx(
|
|||||||
const uint8_t rx_size,
|
const uint8_t rx_size,
|
||||||
uint32_t timeout);
|
uint32_t timeout);
|
||||||
|
|
||||||
#define with_furi_hal_i2c(type, pointer, function_body) \
|
|
||||||
{ \
|
|
||||||
*pointer = ({ type __fn__ function_body __fn__; })(); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -7,37 +7,43 @@
|
|||||||
#define LED_CURRENT_WHITE 150
|
#define LED_CURRENT_WHITE 150
|
||||||
|
|
||||||
void furi_hal_light_init() {
|
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_reset(&furi_hal_i2c_handle_power);
|
||||||
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_set_channel_value(LP5562ChannelRed, 0x00);
|
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelRed, LED_CURRENT_RED);
|
||||||
lp5562_set_channel_value(LP5562ChannelGreen, 0x00);
|
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelGreen, LED_CURRENT_GREEN);
|
||||||
lp5562_set_channel_value(LP5562ChannelBlue, 0x00);
|
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelBlue, LED_CURRENT_BLUE);
|
||||||
lp5562_set_channel_value(LP5562ChannelWhite, 0x00);
|
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelWhite, LED_CURRENT_WHITE);
|
||||||
|
|
||||||
lp5562_enable();
|
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, 0x00);
|
||||||
lp5562_configure();
|
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) {
|
void furi_hal_light_set(Light light, uint8_t value) {
|
||||||
|
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||||
switch(light) {
|
switch(light) {
|
||||||
case LightRed:
|
case LightRed:
|
||||||
lp5562_set_channel_value(LP5562ChannelRed, value);
|
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value);
|
||||||
break;
|
break;
|
||||||
case LightGreen:
|
case LightGreen:
|
||||||
lp5562_set_channel_value(LP5562ChannelGreen, value);
|
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value);
|
||||||
break;
|
break;
|
||||||
case LightBlue:
|
case LightBlue:
|
||||||
lp5562_set_channel_value(LP5562ChannelBlue, value);
|
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value);
|
||||||
break;
|
break;
|
||||||
case LightBacklight:
|
case LightBacklight:
|
||||||
lp5562_set_channel_value(LP5562ChannelWhite, value);
|
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
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_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_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" {
|
extern "C" {
|
||||||
#endif
|
#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 */
|
/* Input Keys */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
InputKeyUp,
|
InputKeyUp,
|
||||||
@ -77,6 +65,9 @@ extern const GpioPin gpio_irda_tx;
|
|||||||
extern const GpioPin gpio_usart_tx;
|
extern const GpioPin gpio_usart_tx;
|
||||||
extern const GpioPin gpio_usart_rx;
|
extern const GpioPin gpio_usart_rx;
|
||||||
|
|
||||||
|
extern const GpioPin gpio_i2c_power_sda;
|
||||||
|
extern const GpioPin gpio_i2c_power_scl;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#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-i2c.h>
|
||||||
|
#include <furi-hal-version.h>
|
||||||
|
|
||||||
#include <stm32wbxx_ll_bus.h>
|
|
||||||
#include <stm32wbxx_ll_i2c.h>
|
#include <stm32wbxx_ll_i2c.h>
|
||||||
#include <stm32wbxx_ll_rcc.h>
|
|
||||||
#include <stm32wbxx_ll_gpio.h>
|
#include <stm32wbxx_ll_gpio.h>
|
||||||
#include <stm32wbxx_ll_cortex.h>
|
#include <stm32wbxx_ll_cortex.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
void furi_hal_i2c_init() {
|
void furi_hal_i2c_init() {
|
||||||
LL_I2C_InitTypeDef I2C_InitStruct = {0};
|
furi_hal_i2c_bus_power.callback(&furi_hal_i2c_bus_power, FuriHalI2cBusEventInit);
|
||||||
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
|
}
|
||||||
|
|
||||||
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);
|
assert(handle->bus->current_handle == NULL);
|
||||||
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);
|
|
||||||
|
|
||||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);
|
handle->bus->current_handle = handle;
|
||||||
|
|
||||||
I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
|
handle->bus->callback(handle->bus, FuriHalI2cBusEventActivate);
|
||||||
I2C_InitStruct.Timing = POWER_I2C_TIMINGS;
|
|
||||||
I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
|
handle->callback(handle, FuriHalI2cBusHandleEventActivate);
|
||||||
I2C_InitStruct.DigitalFilter = 0;
|
}
|
||||||
I2C_InitStruct.OwnAddress1 = 0;
|
|
||||||
I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
|
void furi_hal_i2c_release(FuriHalI2cBusHandle* handle) {
|
||||||
I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
|
assert(handle->bus->current_handle == handle);
|
||||||
LL_I2C_Init(I2C1, &I2C_InitStruct);
|
|
||||||
LL_I2C_EnableAutoEndMode(I2C1);
|
handle->callback(handle, FuriHalI2cBusHandleEventDeactivate);
|
||||||
LL_I2C_SetOwnAddress2(I2C1, 0, LL_I2C_OWNADDRESS2_NOMASK);
|
|
||||||
LL_I2C_DisableOwnAddress2(I2C1);
|
handle->bus->callback(handle->bus, FuriHalI2cBusEventDeactivate);
|
||||||
LL_I2C_DisableGeneralCall(I2C1);
|
|
||||||
LL_I2C_EnableClockStretching(I2C1);
|
handle->bus->current_handle = NULL;
|
||||||
|
|
||||||
|
handle->bus->callback(handle->bus, FuriHalI2cBusEventUnlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool furi_hal_i2c_tx(
|
bool furi_hal_i2c_tx(
|
||||||
I2C_TypeDef* instance,
|
FuriHalI2cBusHandle* handle,
|
||||||
uint8_t address,
|
uint8_t address,
|
||||||
const uint8_t* data,
|
const uint8_t* data,
|
||||||
uint8_t size,
|
uint8_t size,
|
||||||
uint32_t timeout) {
|
uint32_t timeout) {
|
||||||
|
assert(handle->bus->current_handle == handle);
|
||||||
uint32_t time_left = timeout;
|
uint32_t time_left = timeout;
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
|
|
||||||
while(LL_I2C_IsActiveFlag_BUSY(instance))
|
while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
|
||||||
;
|
;
|
||||||
|
|
||||||
LL_I2C_HandleTransfer(
|
LL_I2C_HandleTransfer(
|
||||||
instance,
|
handle->bus->i2c,
|
||||||
address,
|
address,
|
||||||
LL_I2C_ADDRSLAVE_7BIT,
|
LL_I2C_ADDRSLAVE_7BIT,
|
||||||
size,
|
size,
|
||||||
LL_I2C_MODE_AUTOEND,
|
LL_I2C_MODE_AUTOEND,
|
||||||
LL_I2C_GENERATE_START_WRITE);
|
LL_I2C_GENERATE_START_WRITE);
|
||||||
|
|
||||||
while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
|
while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
|
||||||
if(LL_I2C_IsActiveFlag_TXIS(instance)) {
|
if(LL_I2C_IsActiveFlag_TXIS(handle->bus->i2c)) {
|
||||||
LL_I2C_TransmitData8(instance, (*data));
|
LL_I2C_TransmitData8(handle->bus->i2c, (*data));
|
||||||
data++;
|
data++;
|
||||||
size--;
|
size--;
|
||||||
time_left = timeout;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool furi_hal_i2c_rx(
|
bool furi_hal_i2c_rx(
|
||||||
I2C_TypeDef* instance,
|
FuriHalI2cBusHandle* handle,
|
||||||
uint8_t address,
|
uint8_t address,
|
||||||
uint8_t* data,
|
uint8_t* data,
|
||||||
uint8_t size,
|
uint8_t size,
|
||||||
uint32_t timeout) {
|
uint32_t timeout) {
|
||||||
|
assert(handle->bus->current_handle == handle);
|
||||||
uint32_t time_left = timeout;
|
uint32_t time_left = timeout;
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
|
|
||||||
while(LL_I2C_IsActiveFlag_BUSY(instance))
|
while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
|
||||||
;
|
;
|
||||||
|
|
||||||
LL_I2C_HandleTransfer(
|
LL_I2C_HandleTransfer(
|
||||||
instance,
|
handle->bus->i2c,
|
||||||
address,
|
address,
|
||||||
LL_I2C_ADDRSLAVE_7BIT,
|
LL_I2C_ADDRSLAVE_7BIT,
|
||||||
size,
|
size,
|
||||||
LL_I2C_MODE_AUTOEND,
|
LL_I2C_MODE_AUTOEND,
|
||||||
LL_I2C_GENERATE_START_READ);
|
LL_I2C_GENERATE_START_READ);
|
||||||
|
|
||||||
while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
|
while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
|
||||||
if(LL_I2C_IsActiveFlag_RXNE(instance)) {
|
if(LL_I2C_IsActiveFlag_RXNE(handle->bus->i2c)) {
|
||||||
*data = LL_I2C_ReceiveData8(instance);
|
*data = LL_I2C_ReceiveData8(handle->bus->i2c);
|
||||||
data++;
|
data++;
|
||||||
size--;
|
size--;
|
||||||
time_left = timeout;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool furi_hal_i2c_trx(
|
bool furi_hal_i2c_trx(
|
||||||
I2C_TypeDef* instance,
|
FuriHalI2cBusHandle* handle,
|
||||||
uint8_t address,
|
uint8_t address,
|
||||||
const uint8_t* tx_data,
|
const uint8_t* tx_data,
|
||||||
uint8_t tx_size,
|
uint8_t tx_size,
|
||||||
uint8_t* rx_data,
|
uint8_t* rx_data,
|
||||||
uint8_t rx_size,
|
uint8_t rx_size,
|
||||||
uint32_t timeout) {
|
uint32_t timeout) {
|
||||||
if(furi_hal_i2c_tx(instance, address, tx_data, tx_size, timeout) &&
|
if(furi_hal_i2c_tx(handle, address, tx_data, tx_size, timeout) &&
|
||||||
furi_hal_i2c_rx(instance, address, rx_data, rx_size, timeout)) {
|
furi_hal_i2c_rx(handle, address, rx_data, rx_size, timeout)) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -1,31 +1,82 @@
|
|||||||
|
/**
|
||||||
|
* @file furi-hal-i2c.h
|
||||||
|
* I2C HAL API
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <furi-hal-resources.h>
|
#include <furi-hal-i2c-config.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** Init I2C
|
||||||
|
*/
|
||||||
void furi_hal_i2c_init();
|
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(
|
bool furi_hal_i2c_tx(
|
||||||
I2C_TypeDef* instance,
|
FuriHalI2cBusHandle* handle,
|
||||||
const uint8_t address,
|
const uint8_t address,
|
||||||
const uint8_t* data,
|
const uint8_t* data,
|
||||||
const uint8_t size,
|
const uint8_t size,
|
||||||
uint32_t timeout);
|
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(
|
bool furi_hal_i2c_rx(
|
||||||
I2C_TypeDef* instance,
|
FuriHalI2cBusHandle* handle,
|
||||||
const uint8_t address,
|
const uint8_t address,
|
||||||
uint8_t* data,
|
uint8_t* data,
|
||||||
const uint8_t size,
|
const uint8_t size,
|
||||||
uint32_t timeout);
|
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(
|
bool furi_hal_i2c_trx(
|
||||||
I2C_TypeDef* instance,
|
FuriHalI2cBusHandle* handle,
|
||||||
const uint8_t address,
|
const uint8_t address,
|
||||||
const uint8_t* tx_data,
|
const uint8_t* tx_data,
|
||||||
const uint8_t tx_size,
|
const uint8_t tx_size,
|
||||||
@ -33,11 +84,6 @@ bool furi_hal_i2c_trx(
|
|||||||
const uint8_t rx_size,
|
const uint8_t rx_size,
|
||||||
uint32_t timeout);
|
uint32_t timeout);
|
||||||
|
|
||||||
#define with_furi_hal_i2c(type, pointer, function_body) \
|
|
||||||
{ \
|
|
||||||
*pointer = ({ type __fn__ function_body __fn__; })(); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -7,37 +7,43 @@
|
|||||||
#define LED_CURRENT_WHITE 150
|
#define LED_CURRENT_WHITE 150
|
||||||
|
|
||||||
void furi_hal_light_init() {
|
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_reset(&furi_hal_i2c_handle_power);
|
||||||
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_set_channel_value(LP5562ChannelRed, 0x00);
|
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelRed, LED_CURRENT_RED);
|
||||||
lp5562_set_channel_value(LP5562ChannelGreen, 0x00);
|
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelGreen, LED_CURRENT_GREEN);
|
||||||
lp5562_set_channel_value(LP5562ChannelBlue, 0x00);
|
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelBlue, LED_CURRENT_BLUE);
|
||||||
lp5562_set_channel_value(LP5562ChannelWhite, 0x00);
|
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelWhite, LED_CURRENT_WHITE);
|
||||||
|
|
||||||
lp5562_enable();
|
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, 0x00);
|
||||||
lp5562_configure();
|
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) {
|
void furi_hal_light_set(Light light, uint8_t value) {
|
||||||
|
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||||
switch(light) {
|
switch(light) {
|
||||||
case LightRed:
|
case LightRed:
|
||||||
lp5562_set_channel_value(LP5562ChannelRed, value);
|
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value);
|
||||||
break;
|
break;
|
||||||
case LightGreen:
|
case LightGreen:
|
||||||
lp5562_set_channel_value(LP5562ChannelGreen, value);
|
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value);
|
||||||
break;
|
break;
|
||||||
case LightBlue:
|
case LightBlue:
|
||||||
lp5562_set_channel_value(LP5562ChannelBlue, value);
|
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value);
|
||||||
break;
|
break;
|
||||||
case LightBacklight:
|
case LightBacklight:
|
||||||
lp5562_set_channel_value(LP5562ChannelWhite, value);
|
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
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_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_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" {
|
extern "C" {
|
||||||
#endif
|
#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 */
|
/* Input Keys */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
InputKeyUp,
|
InputKeyUp,
|
||||||
@ -77,6 +65,9 @@ extern const GpioPin gpio_irda_tx;
|
|||||||
extern const GpioPin gpio_usart_tx;
|
extern const GpioPin gpio_usart_tx;
|
||||||
extern const GpioPin gpio_usart_rx;
|
extern const GpioPin gpio_usart_rx;
|
||||||
|
|
||||||
|
extern const GpioPin gpio_i2c_power_sda;
|
||||||
|
extern const GpioPin gpio_i2c_power_scl;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#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"
|
#define TAG "FuriHalI2C"
|
||||||
|
|
||||||
osMutexId_t furi_hal_i2c_mutex = NULL;
|
|
||||||
|
|
||||||
void furi_hal_i2c_init() {
|
void furi_hal_i2c_init() {
|
||||||
furi_hal_i2c_mutex = osMutexNew(NULL);
|
furi_hal_i2c_bus_power.callback(&furi_hal_i2c_bus_power, FuriHalI2cBusEventInit);
|
||||||
furi_check(furi_hal_i2c_mutex);
|
furi_hal_i2c_bus_external.callback(&furi_hal_i2c_bus_external, FuriHalI2cBusEventInit);
|
||||||
|
|
||||||
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_LOG_I(TAG, "Init OK");
|
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(
|
bool furi_hal_i2c_tx(
|
||||||
I2C_TypeDef* instance,
|
FuriHalI2cBusHandle* handle,
|
||||||
uint8_t address,
|
uint8_t address,
|
||||||
const uint8_t* data,
|
const uint8_t* data,
|
||||||
uint8_t size,
|
uint8_t size,
|
||||||
uint32_t timeout) {
|
uint32_t timeout) {
|
||||||
|
furi_check(handle->bus->current_handle == handle);
|
||||||
uint32_t time_left = timeout;
|
uint32_t time_left = timeout;
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
|
|
||||||
while(LL_I2C_IsActiveFlag_BUSY(instance))
|
while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
|
||||||
;
|
;
|
||||||
|
|
||||||
LL_I2C_HandleTransfer(
|
LL_I2C_HandleTransfer(
|
||||||
instance,
|
handle->bus->i2c,
|
||||||
address,
|
address,
|
||||||
LL_I2C_ADDRSLAVE_7BIT,
|
LL_I2C_ADDRSLAVE_7BIT,
|
||||||
size,
|
size,
|
||||||
LL_I2C_MODE_AUTOEND,
|
LL_I2C_MODE_AUTOEND,
|
||||||
LL_I2C_GENERATE_START_WRITE);
|
LL_I2C_GENERATE_START_WRITE);
|
||||||
|
|
||||||
while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
|
while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
|
||||||
if(LL_I2C_IsActiveFlag_TXIS(instance)) {
|
if(LL_I2C_IsActiveFlag_TXIS(handle->bus->i2c)) {
|
||||||
LL_I2C_TransmitData8(instance, (*data));
|
LL_I2C_TransmitData8(handle->bus->i2c, (*data));
|
||||||
data++;
|
data++;
|
||||||
size--;
|
size--;
|
||||||
time_left = timeout;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool furi_hal_i2c_rx(
|
bool furi_hal_i2c_rx(
|
||||||
I2C_TypeDef* instance,
|
FuriHalI2cBusHandle* handle,
|
||||||
uint8_t address,
|
uint8_t address,
|
||||||
uint8_t* data,
|
uint8_t* data,
|
||||||
uint8_t size,
|
uint8_t size,
|
||||||
uint32_t timeout) {
|
uint32_t timeout) {
|
||||||
|
furi_check(handle->bus->current_handle == handle);
|
||||||
uint32_t time_left = timeout;
|
uint32_t time_left = timeout;
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
|
|
||||||
while(LL_I2C_IsActiveFlag_BUSY(instance))
|
while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
|
||||||
;
|
;
|
||||||
|
|
||||||
LL_I2C_HandleTransfer(
|
LL_I2C_HandleTransfer(
|
||||||
instance,
|
handle->bus->i2c,
|
||||||
address,
|
address,
|
||||||
LL_I2C_ADDRSLAVE_7BIT,
|
LL_I2C_ADDRSLAVE_7BIT,
|
||||||
size,
|
size,
|
||||||
LL_I2C_MODE_AUTOEND,
|
LL_I2C_MODE_AUTOEND,
|
||||||
LL_I2C_GENERATE_START_READ);
|
LL_I2C_GENERATE_START_READ);
|
||||||
|
|
||||||
while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
|
while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
|
||||||
if(LL_I2C_IsActiveFlag_RXNE(instance)) {
|
if(LL_I2C_IsActiveFlag_RXNE(handle->bus->i2c)) {
|
||||||
*data = LL_I2C_ReceiveData8(instance);
|
*data = LL_I2C_ReceiveData8(handle->bus->i2c);
|
||||||
data++;
|
data++;
|
||||||
size--;
|
size--;
|
||||||
time_left = timeout;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool furi_hal_i2c_trx(
|
bool furi_hal_i2c_trx(
|
||||||
I2C_TypeDef* instance,
|
FuriHalI2cBusHandle* handle,
|
||||||
uint8_t address,
|
uint8_t address,
|
||||||
const uint8_t* tx_data,
|
const uint8_t* tx_data,
|
||||||
uint8_t tx_size,
|
uint8_t tx_size,
|
||||||
uint8_t* rx_data,
|
uint8_t* rx_data,
|
||||||
uint8_t rx_size,
|
uint8_t rx_size,
|
||||||
uint32_t timeout) {
|
uint32_t timeout) {
|
||||||
if(furi_hal_i2c_tx(instance, address, tx_data, tx_size, timeout) &&
|
if(furi_hal_i2c_tx(handle, address, tx_data, tx_size, timeout) &&
|
||||||
furi_hal_i2c_rx(instance, address, rx_data, rx_size, timeout)) {
|
furi_hal_i2c_rx(handle, address, rx_data, rx_size, timeout)) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
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 <furi-hal-light.h>
|
||||||
#include <lp5562.h>
|
#include <lp5562.h>
|
||||||
|
|
||||||
#define TAG "FuriHalLight"
|
#define LED_CURRENT_RED 50
|
||||||
|
#define LED_CURRENT_GREEN 50
|
||||||
#define LED_CURRENT_RED 50
|
#define LED_CURRENT_BLUE 50
|
||||||
#define LED_CURRENT_GREEN 50
|
#define LED_CURRENT_WHITE 150
|
||||||
#define LED_CURRENT_BLUE 50
|
|
||||||
#define LED_CURRENT_WHITE 150
|
|
||||||
|
|
||||||
void furi_hal_light_init() {
|
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_reset(&furi_hal_i2c_handle_power);
|
||||||
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_set_channel_value(LP5562ChannelRed, 0x00);
|
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelRed, LED_CURRENT_RED);
|
||||||
lp5562_set_channel_value(LP5562ChannelGreen, 0x00);
|
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelGreen, LED_CURRENT_GREEN);
|
||||||
lp5562_set_channel_value(LP5562ChannelBlue, 0x00);
|
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelBlue, LED_CURRENT_BLUE);
|
||||||
lp5562_set_channel_value(LP5562ChannelWhite, 0x00);
|
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelWhite, LED_CURRENT_WHITE);
|
||||||
|
|
||||||
lp5562_enable();
|
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, 0x00);
|
||||||
lp5562_configure();
|
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, 0x00);
|
||||||
FURI_LOG_I(TAG, "Init OK");
|
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) {
|
void furi_hal_light_set(Light light, uint8_t value) {
|
||||||
|
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||||
switch(light) {
|
switch(light) {
|
||||||
case LightRed:
|
case LightRed:
|
||||||
lp5562_set_channel_value(LP5562ChannelRed, value);
|
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value);
|
||||||
break;
|
break;
|
||||||
case LightGreen:
|
case LightGreen:
|
||||||
lp5562_set_channel_value(LP5562ChannelGreen, value);
|
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value);
|
||||||
break;
|
break;
|
||||||
case LightBlue:
|
case LightBlue:
|
||||||
lp5562_set_channel_value(LP5562ChannelBlue, value);
|
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value);
|
||||||
break;
|
break;
|
||||||
case LightBacklight:
|
case LightBacklight:
|
||||||
lp5562_set_channel_value(LP5562ChannelWhite, value);
|
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||||
}
|
}
|
@ -74,8 +74,12 @@ void HAL_RCC_CSSCallback(void) {
|
|||||||
void furi_hal_power_init() {
|
void furi_hal_power_init() {
|
||||||
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
|
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
|
||||||
LL_PWR_SMPS_SetMode(LL_PWR_SMPS_STEP_DOWN);
|
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");
|
FURI_LOG_I(TAG, "Init OK");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,19 +165,30 @@ void furi_hal_power_sleep() {
|
|||||||
|
|
||||||
|
|
||||||
uint8_t furi_hal_power_get_pct() {
|
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() {
|
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() {
|
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() {
|
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() {
|
void furi_hal_power_reset() {
|
||||||
@ -181,66 +196,102 @@ void furi_hal_power_reset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void furi_hal_power_enable_otg() {
|
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() {
|
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() {
|
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() {
|
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() {
|
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 furi_hal_power_get_battery_voltage(FuriHalPowerIC ic) {
|
||||||
|
float ret = 0.0f;
|
||||||
|
|
||||||
|
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||||
if (ic == FuriHalPowerICCharger) {
|
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) {
|
} else if (ic == FuriHalPowerICFuelGauge) {
|
||||||
return (float)bq27220_get_voltage() / 1000.0f;
|
ret = (float)bq27220_get_voltage(&furi_hal_i2c_handle_power) / 1000.0f;
|
||||||
} else {
|
|
||||||
return 0.0f;
|
|
||||||
}
|
}
|
||||||
|
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
float furi_hal_power_get_battery_current(FuriHalPowerIC ic) {
|
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) {
|
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) {
|
} else if (ic == FuriHalPowerICFuelGauge) {
|
||||||
return (float)bq27220_get_current() / 1000.0f;
|
ret = (float)bq27220_get_current(&furi_hal_i2c_handle_power) / 1000.0f;
|
||||||
} else {
|
}
|
||||||
return 0.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) {
|
float furi_hal_power_get_battery_temperature(FuriHalPowerIC ic) {
|
||||||
if (ic == FuriHalPowerICCharger) {
|
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||||
// Linear approximation, +/- 5 C
|
float ret = furi_hal_power_get_battery_temperature_internal(ic);
|
||||||
return (71.0f - (float)bq25896_get_ntc_mpct()/1000) / 0.6f;
|
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||||
} else if (ic == FuriHalPowerICFuelGauge) {
|
|
||||||
return ((float)bq27220_get_temperature() - 2731.0f) / 10.0f;
|
return ret;
|
||||||
} else {
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float furi_hal_power_get_usb_voltage(){
|
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() {
|
void furi_hal_power_dump_state() {
|
||||||
BatteryStatus battery_status;
|
BatteryStatus battery_status;
|
||||||
OperationStatus operation_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");
|
printf("Failed to get bq27220 status. Communication error.\r\n");
|
||||||
} else {
|
} else {
|
||||||
printf(
|
printf(
|
||||||
@ -266,21 +317,23 @@ void furi_hal_power_dump_state() {
|
|||||||
// Voltage and current info
|
// Voltage and current info
|
||||||
printf(
|
printf(
|
||||||
"bq27220: Full capacity: %dmAh, Design capacity: %dmAh, Remaining capacity: %dmAh, State of Charge: %d%%, State of health: %d%%\r\n",
|
"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_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(), bq27220_get_state_of_health()
|
bq27220_get_state_of_charge(&furi_hal_i2c_handle_power), bq27220_get_state_of_health(&furi_hal_i2c_handle_power)
|
||||||
);
|
);
|
||||||
printf(
|
printf(
|
||||||
"bq27220: Voltage: %dmV, Current: %dmA, Temperature: %dC\r\n",
|
"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(
|
printf(
|
||||||
"bq25896: VBUS: %d, VSYS: %d, VBAT: %d, Current: %d, NTC: %ldm%%\r\n",
|
"bq25896: VBUS: %d, VSYS: %d, VBAT: %d, Current: %d, NTC: %ldm%%\r\n",
|
||||||
bq25896_get_vbus_voltage(), bq25896_get_vsys_voltage(),
|
bq25896_get_vbus_voltage(&furi_hal_i2c_handle_power), bq25896_get_vsys_voltage(&furi_hal_i2c_handle_power),
|
||||||
bq25896_get_vbat_voltage(), bq25896_get_vbat_current(),
|
bq25896_get_vbat_voltage(&furi_hal_i2c_handle_power), bq25896_get_vbat_current(&furi_hal_i2c_handle_power),
|
||||||
bq25896_get_ntc_mpct()
|
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(){
|
void furi_hal_power_enable_external_3_3v(){
|
||||||
@ -298,7 +351,9 @@ void furi_hal_power_suppress_charge_enter() {
|
|||||||
xTaskResumeAll();
|
xTaskResumeAll();
|
||||||
|
|
||||||
if (disable_charging) {
|
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();
|
xTaskResumeAll();
|
||||||
|
|
||||||
if (enable_charging) {
|
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_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_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" {
|
extern "C" {
|
||||||
#endif
|
#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 */
|
/* Input Related Constants */
|
||||||
#define INPUT_DEBOUNCE_TICKS 20
|
#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_tx;
|
||||||
extern const GpioPin gpio_usart_rx;
|
extern const GpioPin gpio_usart_rx;
|
||||||
|
extern const GpioPin gpio_i2c_power_sda;
|
||||||
|
extern const GpioPin gpio_i2c_power_scl;
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#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) {
|
static void vcp_on_cdc_rx(void* context) {
|
||||||
uint32_t ret = osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtRx);
|
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) {
|
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"
|
#define TAG "FuriHalI2C"
|
||||||
|
|
||||||
osMutexId_t furi_hal_i2c_mutex = NULL;
|
|
||||||
|
|
||||||
void furi_hal_i2c_init() {
|
void furi_hal_i2c_init() {
|
||||||
furi_hal_i2c_mutex = osMutexNew(NULL);
|
furi_hal_i2c_bus_power.callback(&furi_hal_i2c_bus_power, FuriHalI2cBusEventInit);
|
||||||
furi_check(furi_hal_i2c_mutex);
|
furi_hal_i2c_bus_external.callback(&furi_hal_i2c_bus_external, FuriHalI2cBusEventInit);
|
||||||
|
|
||||||
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_LOG_I(TAG, "Init OK");
|
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(
|
bool furi_hal_i2c_tx(
|
||||||
I2C_TypeDef* instance,
|
FuriHalI2cBusHandle* handle,
|
||||||
uint8_t address,
|
uint8_t address,
|
||||||
const uint8_t* data,
|
const uint8_t* data,
|
||||||
uint8_t size,
|
uint8_t size,
|
||||||
uint32_t timeout) {
|
uint32_t timeout) {
|
||||||
|
furi_check(handle->bus->current_handle == handle);
|
||||||
uint32_t time_left = timeout;
|
uint32_t time_left = timeout;
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
|
|
||||||
while(LL_I2C_IsActiveFlag_BUSY(instance))
|
while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
|
||||||
;
|
;
|
||||||
|
|
||||||
LL_I2C_HandleTransfer(
|
LL_I2C_HandleTransfer(
|
||||||
instance,
|
handle->bus->i2c,
|
||||||
address,
|
address,
|
||||||
LL_I2C_ADDRSLAVE_7BIT,
|
LL_I2C_ADDRSLAVE_7BIT,
|
||||||
size,
|
size,
|
||||||
LL_I2C_MODE_AUTOEND,
|
LL_I2C_MODE_AUTOEND,
|
||||||
LL_I2C_GENERATE_START_WRITE);
|
LL_I2C_GENERATE_START_WRITE);
|
||||||
|
|
||||||
while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
|
while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
|
||||||
if(LL_I2C_IsActiveFlag_TXIS(instance)) {
|
if(LL_I2C_IsActiveFlag_TXIS(handle->bus->i2c)) {
|
||||||
LL_I2C_TransmitData8(instance, (*data));
|
LL_I2C_TransmitData8(handle->bus->i2c, (*data));
|
||||||
data++;
|
data++;
|
||||||
size--;
|
size--;
|
||||||
time_left = timeout;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool furi_hal_i2c_rx(
|
bool furi_hal_i2c_rx(
|
||||||
I2C_TypeDef* instance,
|
FuriHalI2cBusHandle* handle,
|
||||||
uint8_t address,
|
uint8_t address,
|
||||||
uint8_t* data,
|
uint8_t* data,
|
||||||
uint8_t size,
|
uint8_t size,
|
||||||
uint32_t timeout) {
|
uint32_t timeout) {
|
||||||
|
furi_check(handle->bus->current_handle == handle);
|
||||||
uint32_t time_left = timeout;
|
uint32_t time_left = timeout;
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
|
|
||||||
while(LL_I2C_IsActiveFlag_BUSY(instance))
|
while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
|
||||||
;
|
;
|
||||||
|
|
||||||
LL_I2C_HandleTransfer(
|
LL_I2C_HandleTransfer(
|
||||||
instance,
|
handle->bus->i2c,
|
||||||
address,
|
address,
|
||||||
LL_I2C_ADDRSLAVE_7BIT,
|
LL_I2C_ADDRSLAVE_7BIT,
|
||||||
size,
|
size,
|
||||||
LL_I2C_MODE_AUTOEND,
|
LL_I2C_MODE_AUTOEND,
|
||||||
LL_I2C_GENERATE_START_READ);
|
LL_I2C_GENERATE_START_READ);
|
||||||
|
|
||||||
while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
|
while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
|
||||||
if(LL_I2C_IsActiveFlag_RXNE(instance)) {
|
if(LL_I2C_IsActiveFlag_RXNE(handle->bus->i2c)) {
|
||||||
*data = LL_I2C_ReceiveData8(instance);
|
*data = LL_I2C_ReceiveData8(handle->bus->i2c);
|
||||||
data++;
|
data++;
|
||||||
size--;
|
size--;
|
||||||
time_left = timeout;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool furi_hal_i2c_trx(
|
bool furi_hal_i2c_trx(
|
||||||
I2C_TypeDef* instance,
|
FuriHalI2cBusHandle* handle,
|
||||||
uint8_t address,
|
uint8_t address,
|
||||||
const uint8_t* tx_data,
|
const uint8_t* tx_data,
|
||||||
uint8_t tx_size,
|
uint8_t tx_size,
|
||||||
uint8_t* rx_data,
|
uint8_t* rx_data,
|
||||||
uint8_t rx_size,
|
uint8_t rx_size,
|
||||||
uint32_t timeout) {
|
uint32_t timeout) {
|
||||||
if(furi_hal_i2c_tx(instance, address, tx_data, tx_size, timeout) &&
|
if(furi_hal_i2c_tx(handle, address, tx_data, tx_size, timeout) &&
|
||||||
furi_hal_i2c_rx(instance, address, rx_data, rx_size, timeout)) {
|
furi_hal_i2c_rx(handle, address, rx_data, rx_size, timeout)) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
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 <furi-hal-light.h>
|
||||||
#include <lp5562.h>
|
#include <lp5562.h>
|
||||||
|
|
||||||
#define TAG "FuriHalLight"
|
#define LED_CURRENT_RED 50
|
||||||
|
#define LED_CURRENT_GREEN 50
|
||||||
#define LED_CURRENT_RED 50
|
#define LED_CURRENT_BLUE 50
|
||||||
#define LED_CURRENT_GREEN 50
|
#define LED_CURRENT_WHITE 150
|
||||||
#define LED_CURRENT_BLUE 50
|
|
||||||
#define LED_CURRENT_WHITE 150
|
|
||||||
|
|
||||||
void furi_hal_light_init() {
|
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_reset(&furi_hal_i2c_handle_power);
|
||||||
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_set_channel_value(LP5562ChannelRed, 0x00);
|
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelRed, LED_CURRENT_RED);
|
||||||
lp5562_set_channel_value(LP5562ChannelGreen, 0x00);
|
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelGreen, LED_CURRENT_GREEN);
|
||||||
lp5562_set_channel_value(LP5562ChannelBlue, 0x00);
|
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelBlue, LED_CURRENT_BLUE);
|
||||||
lp5562_set_channel_value(LP5562ChannelWhite, 0x00);
|
lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelWhite, LED_CURRENT_WHITE);
|
||||||
|
|
||||||
lp5562_enable();
|
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, 0x00);
|
||||||
lp5562_configure();
|
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, 0x00);
|
||||||
FURI_LOG_I(TAG, "Init OK");
|
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) {
|
void furi_hal_light_set(Light light, uint8_t value) {
|
||||||
|
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||||
switch(light) {
|
switch(light) {
|
||||||
case LightRed:
|
case LightRed:
|
||||||
lp5562_set_channel_value(LP5562ChannelRed, value);
|
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value);
|
||||||
break;
|
break;
|
||||||
case LightGreen:
|
case LightGreen:
|
||||||
lp5562_set_channel_value(LP5562ChannelGreen, value);
|
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value);
|
||||||
break;
|
break;
|
||||||
case LightBlue:
|
case LightBlue:
|
||||||
lp5562_set_channel_value(LP5562ChannelBlue, value);
|
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value);
|
||||||
break;
|
break;
|
||||||
case LightBacklight:
|
case LightBacklight:
|
||||||
lp5562_set_channel_value(LP5562ChannelWhite, value);
|
lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||||
}
|
}
|
@ -74,8 +74,12 @@ void HAL_RCC_CSSCallback(void) {
|
|||||||
void furi_hal_power_init() {
|
void furi_hal_power_init() {
|
||||||
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
|
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
|
||||||
LL_PWR_SMPS_SetMode(LL_PWR_SMPS_STEP_DOWN);
|
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");
|
FURI_LOG_I(TAG, "Init OK");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,19 +165,30 @@ void furi_hal_power_sleep() {
|
|||||||
|
|
||||||
|
|
||||||
uint8_t furi_hal_power_get_pct() {
|
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() {
|
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() {
|
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() {
|
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() {
|
void furi_hal_power_reset() {
|
||||||
@ -181,66 +196,102 @@ void furi_hal_power_reset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void furi_hal_power_enable_otg() {
|
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() {
|
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() {
|
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() {
|
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() {
|
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 furi_hal_power_get_battery_voltage(FuriHalPowerIC ic) {
|
||||||
|
float ret = 0.0f;
|
||||||
|
|
||||||
|
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||||
if (ic == FuriHalPowerICCharger) {
|
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) {
|
} else if (ic == FuriHalPowerICFuelGauge) {
|
||||||
return (float)bq27220_get_voltage() / 1000.0f;
|
ret = (float)bq27220_get_voltage(&furi_hal_i2c_handle_power) / 1000.0f;
|
||||||
} else {
|
|
||||||
return 0.0f;
|
|
||||||
}
|
}
|
||||||
|
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
float furi_hal_power_get_battery_current(FuriHalPowerIC ic) {
|
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) {
|
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) {
|
} else if (ic == FuriHalPowerICFuelGauge) {
|
||||||
return (float)bq27220_get_current() / 1000.0f;
|
ret = (float)bq27220_get_current(&furi_hal_i2c_handle_power) / 1000.0f;
|
||||||
} else {
|
}
|
||||||
return 0.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) {
|
float furi_hal_power_get_battery_temperature(FuriHalPowerIC ic) {
|
||||||
if (ic == FuriHalPowerICCharger) {
|
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||||
// Linear approximation, +/- 5 C
|
float ret = furi_hal_power_get_battery_temperature_internal(ic);
|
||||||
return (71.0f - (float)bq25896_get_ntc_mpct()/1000) / 0.6f;
|
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||||
} else if (ic == FuriHalPowerICFuelGauge) {
|
|
||||||
return ((float)bq27220_get_temperature() - 2731.0f) / 10.0f;
|
return ret;
|
||||||
} else {
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float furi_hal_power_get_usb_voltage(){
|
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() {
|
void furi_hal_power_dump_state() {
|
||||||
BatteryStatus battery_status;
|
BatteryStatus battery_status;
|
||||||
OperationStatus operation_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");
|
printf("Failed to get bq27220 status. Communication error.\r\n");
|
||||||
} else {
|
} else {
|
||||||
printf(
|
printf(
|
||||||
@ -266,21 +317,23 @@ void furi_hal_power_dump_state() {
|
|||||||
// Voltage and current info
|
// Voltage and current info
|
||||||
printf(
|
printf(
|
||||||
"bq27220: Full capacity: %dmAh, Design capacity: %dmAh, Remaining capacity: %dmAh, State of Charge: %d%%, State of health: %d%%\r\n",
|
"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_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(), bq27220_get_state_of_health()
|
bq27220_get_state_of_charge(&furi_hal_i2c_handle_power), bq27220_get_state_of_health(&furi_hal_i2c_handle_power)
|
||||||
);
|
);
|
||||||
printf(
|
printf(
|
||||||
"bq27220: Voltage: %dmV, Current: %dmA, Temperature: %dC\r\n",
|
"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(
|
printf(
|
||||||
"bq25896: VBUS: %d, VSYS: %d, VBAT: %d, Current: %d, NTC: %ldm%%\r\n",
|
"bq25896: VBUS: %d, VSYS: %d, VBAT: %d, Current: %d, NTC: %ldm%%\r\n",
|
||||||
bq25896_get_vbus_voltage(), bq25896_get_vsys_voltage(),
|
bq25896_get_vbus_voltage(&furi_hal_i2c_handle_power), bq25896_get_vsys_voltage(&furi_hal_i2c_handle_power),
|
||||||
bq25896_get_vbat_voltage(), bq25896_get_vbat_current(),
|
bq25896_get_vbat_voltage(&furi_hal_i2c_handle_power), bq25896_get_vbat_current(&furi_hal_i2c_handle_power),
|
||||||
bq25896_get_ntc_mpct()
|
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(){
|
void furi_hal_power_enable_external_3_3v(){
|
||||||
@ -298,7 +351,9 @@ void furi_hal_power_suppress_charge_enter() {
|
|||||||
xTaskResumeAll();
|
xTaskResumeAll();
|
||||||
|
|
||||||
if (disable_charging) {
|
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();
|
xTaskResumeAll();
|
||||||
|
|
||||||
if (enable_charging) {
|
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_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_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" {
|
extern "C" {
|
||||||
#endif
|
#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 */
|
/* Input Related Constants */
|
||||||
#define INPUT_DEBOUNCE_TICKS 20
|
#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_tx;
|
||||||
extern const GpioPin gpio_usart_rx;
|
extern const GpioPin gpio_usart_rx;
|
||||||
|
extern const GpioPin gpio_i2c_power_sda;
|
||||||
|
extern const GpioPin gpio_i2c_power_scl;
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#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) {
|
static void vcp_on_cdc_rx(void* context) {
|
||||||
uint32_t ret = osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtRx);
|
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) {
|
static void vcp_on_cdc_tx_complete(void* context) {
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <furi-hal-resources.h>
|
#include <furi-hal-i2c-config.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -17,18 +17,30 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
void furi_hal_i2c_init();
|
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
|
/** Perform I2C tx transfer
|
||||||
*
|
*
|
||||||
* @param instance I2C_TypeDef instance
|
* @param instance I2C_TypeDef instance
|
||||||
* @param address I2C slave address
|
* @param address I2C slave address
|
||||||
* @param data pointer to data buffer
|
* @param data pointer to data buffer
|
||||||
* @param size size of 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
|
* @return true on successful transfer, false otherwise
|
||||||
*/
|
*/
|
||||||
bool furi_hal_i2c_tx(
|
bool furi_hal_i2c_tx(
|
||||||
I2C_TypeDef* instance,
|
FuriHalI2cBusHandle* handle,
|
||||||
const uint8_t address,
|
const uint8_t address,
|
||||||
const uint8_t* data,
|
const uint8_t* data,
|
||||||
const uint8_t size,
|
const uint8_t size,
|
||||||
@ -40,12 +52,12 @@ bool furi_hal_i2c_tx(
|
|||||||
* @param address I2C slave address
|
* @param address I2C slave address
|
||||||
* @param data pointer to data buffer
|
* @param data pointer to data buffer
|
||||||
* @param size size of 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
|
* @return true on successful transfer, false otherwise
|
||||||
*/
|
*/
|
||||||
bool furi_hal_i2c_rx(
|
bool furi_hal_i2c_rx(
|
||||||
I2C_TypeDef* instance,
|
FuriHalI2cBusHandle* handle,
|
||||||
const uint8_t address,
|
const uint8_t address,
|
||||||
uint8_t* data,
|
uint8_t* data,
|
||||||
const uint8_t size,
|
const uint8_t size,
|
||||||
@ -59,12 +71,12 @@ bool furi_hal_i2c_rx(
|
|||||||
* @param tx_size size of tx data buffer
|
* @param tx_size size of tx data buffer
|
||||||
* @param rx_data pointer to rx data buffer
|
* @param rx_data pointer to rx data buffer
|
||||||
* @param rx_size size of 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
|
* @return true on successful transfer, false otherwise
|
||||||
*/
|
*/
|
||||||
bool furi_hal_i2c_trx(
|
bool furi_hal_i2c_trx(
|
||||||
I2C_TypeDef* instance,
|
FuriHalI2cBusHandle* handle,
|
||||||
const uint8_t address,
|
const uint8_t address,
|
||||||
const uint8_t* tx_data,
|
const uint8_t* tx_data,
|
||||||
const uint8_t tx_size,
|
const uint8_t tx_size,
|
||||||
@ -72,30 +84,6 @@ bool furi_hal_i2c_trx(
|
|||||||
const uint8_t rx_size,
|
const uint8_t rx_size,
|
||||||
uint32_t timeout);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -25,8 +25,7 @@ void furi_hal_spi_bus_lock(const FuriHalSpiBus* bus);
|
|||||||
*/
|
*/
|
||||||
void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus);
|
void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus);
|
||||||
|
|
||||||
/**
|
/** Configure SPI bus
|
||||||
* Configure SPI bus
|
|
||||||
* @param bus - spi bus handler
|
* @param bus - spi bus handler
|
||||||
* @param config - spi configuration structure
|
* @param config - spi configuration structure
|
||||||
*/
|
*/
|
@ -1,7 +1,6 @@
|
|||||||
#include "bq25896.h"
|
#include "bq25896.h"
|
||||||
#include "bq25896_reg.h"
|
#include "bq25896_reg.h"
|
||||||
|
|
||||||
#include <furi-hal-i2c.h>
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
uint8_t bit_reverse(uint8_t b) {
|
uint8_t bit_reverse(uint8_t b) {
|
||||||
@ -11,29 +10,17 @@ uint8_t bit_reverse(uint8_t b) {
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bq25896_read(uint8_t address, uint8_t* data, size_t size) {
|
bool bq25896_read(FuriHalI2cBusHandle* handle, uint8_t address, uint8_t* data, size_t size) {
|
||||||
bool ret;
|
return furi_hal_i2c_trx(handle, BQ25896_ADDRESS, &address, 1, data, size, BQ25896_I2C_TIMEOUT);
|
||||||
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_reg(uint8_t address, uint8_t* data) {
|
bool bq25896_read_reg(FuriHalI2cBusHandle* handle, uint8_t address, uint8_t* data) {
|
||||||
bq25896_read(address, data, 1);
|
return bq25896_read(handle, address, data, 1);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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};
|
uint8_t buffer[2] = {address, *data};
|
||||||
bool ret;
|
return furi_hal_i2c_tx(handle, BQ25896_ADDRESS, buffer, 2, BQ25896_I2C_TIMEOUT);
|
||||||
with_furi_hal_i2c(
|
|
||||||
bool, &ret, () {
|
|
||||||
return furi_hal_i2c_tx(POWER_I2C, BQ25896_ADDRESS, buffer, 2, BQ25896_I2C_TIMEOUT);
|
|
||||||
});
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -62,62 +49,62 @@ typedef struct {
|
|||||||
|
|
||||||
static bq25896_regs_t bq25896_regs;
|
static bq25896_regs_t bq25896_regs;
|
||||||
|
|
||||||
void bq25896_init() {
|
void bq25896_init(FuriHalI2cBusHandle* handle) {
|
||||||
bq25896_regs.r14.REG_RST = 1;
|
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
|
// 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
|
// Poll ADC forever
|
||||||
bq25896_regs.r02.CONV_START = 1;
|
bq25896_regs.r02.CONV_START = 1;
|
||||||
bq25896_regs.r02.CONV_RATE = 1;
|
bq25896_regs.r02.CONV_RATE = 1;
|
||||||
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_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_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() {
|
bool bq25896_is_charging(FuriHalI2cBusHandle* handle) {
|
||||||
bq25896_read(0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs));
|
bq25896_read(handle, 0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs));
|
||||||
bq25896_read_reg(0x0B, (uint8_t*)&bq25896_regs.r0B);
|
bq25896_read_reg(handle, 0x0B, (uint8_t*)&bq25896_regs.r0B);
|
||||||
return bq25896_regs.r0B.CHRG_STAT != ChrgStatNo;
|
return bq25896_regs.r0B.CHRG_STAT != ChrgStatNo;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bq25896_enable_charging() {
|
void bq25896_enable_charging(FuriHalI2cBusHandle* handle) {
|
||||||
bq25896_regs.r03.CHG_CONFIG = 1;
|
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_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_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_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() {
|
bool bq25896_is_otg_enabled(FuriHalI2cBusHandle* handle) {
|
||||||
bq25896_read_reg(0x03, (uint8_t*)&bq25896_regs.r03);
|
bq25896_read_reg(handle, 0x03, (uint8_t*)&bq25896_regs.r03);
|
||||||
return bq25896_regs.r03.OTG_CONFIG;
|
return bq25896_regs.r03.OTG_CONFIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t bq25896_get_vbus_voltage() {
|
uint16_t bq25896_get_vbus_voltage(FuriHalI2cBusHandle* handle) {
|
||||||
bq25896_read_reg(0x11, (uint8_t*)&bq25896_regs.r11);
|
bq25896_read_reg(handle, 0x11, (uint8_t*)&bq25896_regs.r11);
|
||||||
if(bq25896_regs.r11.VBUS_GD) {
|
if(bq25896_regs.r11.VBUS_GD) {
|
||||||
return (uint16_t)bq25896_regs.r11.VBUSV * 100 + 2600;
|
return (uint16_t)bq25896_regs.r11.VBUSV * 100 + 2600;
|
||||||
} else {
|
} else {
|
||||||
@ -125,22 +112,22 @@ uint16_t bq25896_get_vbus_voltage() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t bq25896_get_vsys_voltage() {
|
uint16_t bq25896_get_vsys_voltage(FuriHalI2cBusHandle* handle) {
|
||||||
bq25896_read_reg(0x0F, (uint8_t*)&bq25896_regs.r0F);
|
bq25896_read_reg(handle, 0x0F, (uint8_t*)&bq25896_regs.r0F);
|
||||||
return (uint16_t)bq25896_regs.r0F.SYSV * 20 + 2304;
|
return (uint16_t)bq25896_regs.r0F.SYSV * 20 + 2304;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t bq25896_get_vbat_voltage() {
|
uint16_t bq25896_get_vbat_voltage(FuriHalI2cBusHandle* handle) {
|
||||||
bq25896_read_reg(0x0E, (uint8_t*)&bq25896_regs.r0E);
|
bq25896_read_reg(handle, 0x0E, (uint8_t*)&bq25896_regs.r0E);
|
||||||
return (uint16_t)bq25896_regs.r0E.BATV * 20 + 2304;
|
return (uint16_t)bq25896_regs.r0E.BATV * 20 + 2304;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t bq25896_get_vbat_current() {
|
uint16_t bq25896_get_vbat_current(FuriHalI2cBusHandle* handle) {
|
||||||
bq25896_read_reg(0x12, (uint8_t*)&bq25896_regs.r12);
|
bq25896_read_reg(handle, 0x12, (uint8_t*)&bq25896_regs.r12);
|
||||||
return (uint16_t)bq25896_regs.r12.ICHGR * 50;
|
return (uint16_t)bq25896_regs.r12.ICHGR * 50;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t bq25896_get_ntc_mpct() {
|
uint32_t bq25896_get_ntc_mpct(FuriHalI2cBusHandle* handle) {
|
||||||
bq25896_read_reg(0x10, (uint8_t*)&bq25896_regs.r10);
|
bq25896_read_reg(handle, 0x10, (uint8_t*)&bq25896_regs.r10);
|
||||||
return (uint32_t)bq25896_regs.r10.TSPCT * 465 + 21000;
|
return (uint32_t)bq25896_regs.r10.TSPCT * 465 + 21000;
|
||||||
}
|
}
|
||||||
|
@ -2,42 +2,43 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <furi-hal-i2c.h>
|
||||||
|
|
||||||
/** Initialize Driver */
|
/** Initialize Driver */
|
||||||
void bq25896_init();
|
void bq25896_init(FuriHalI2cBusHandle* handle);
|
||||||
|
|
||||||
/** Send device into shipping mode */
|
/** Send device into shipping mode */
|
||||||
void bq25896_poweroff();
|
void bq25896_poweroff(FuriHalI2cBusHandle* handle);
|
||||||
|
|
||||||
/** Is currently charging */
|
/** Is currently charging */
|
||||||
bool bq25896_is_charging();
|
bool bq25896_is_charging(FuriHalI2cBusHandle* handle);
|
||||||
|
|
||||||
/** Enable charging */
|
/** Enable charging */
|
||||||
void bq25896_enable_charging();
|
void bq25896_enable_charging(FuriHalI2cBusHandle* handle);
|
||||||
|
|
||||||
/** Disable charging */
|
/** Disable charging */
|
||||||
void bq25896_disable_charging();
|
void bq25896_disable_charging(FuriHalI2cBusHandle* handle);
|
||||||
|
|
||||||
/** Enable otg */
|
/** Enable otg */
|
||||||
void bq25896_enable_otg();
|
void bq25896_enable_otg(FuriHalI2cBusHandle* handle);
|
||||||
|
|
||||||
/** Disable otg */
|
/** Disable otg */
|
||||||
void bq25896_disable_otg();
|
void bq25896_disable_otg(FuriHalI2cBusHandle* handle);
|
||||||
|
|
||||||
/** Is otg enabled */
|
/** Is otg enabled */
|
||||||
bool bq25896_is_otg_enabled();
|
bool bq25896_is_otg_enabled(FuriHalI2cBusHandle* handle);
|
||||||
|
|
||||||
/** Get VBUS Voltage in mV */
|
/** Get VBUS Voltage in mV */
|
||||||
uint16_t bq25896_get_vbus_voltage();
|
uint16_t bq25896_get_vbus_voltage(FuriHalI2cBusHandle* handle);
|
||||||
|
|
||||||
/** Get VSYS Voltage in mV */
|
/** Get VSYS Voltage in mV */
|
||||||
uint16_t bq25896_get_vsys_voltage();
|
uint16_t bq25896_get_vsys_voltage(FuriHalI2cBusHandle* handle);
|
||||||
|
|
||||||
/** Get VBAT Voltage in mV */
|
/** Get VBAT Voltage in mV */
|
||||||
uint16_t bq25896_get_vbat_voltage();
|
uint16_t bq25896_get_vbat_voltage(FuriHalI2cBusHandle* handle);
|
||||||
|
|
||||||
/** Get VBAT current in mA */
|
/** 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 */
|
/** 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.h"
|
||||||
#include "bq27220_reg.h"
|
#include "bq27220_reg.h"
|
||||||
|
|
||||||
#include <furi-hal-i2c.h>
|
|
||||||
#include <furi-hal-delay.h>
|
#include <furi-hal-delay.h>
|
||||||
|
#include <furi/log.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#define TAG "Gauge"
|
#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};
|
uint8_t buffer[2] = {address};
|
||||||
uint16_t ret;
|
uint16_t ret = 0;
|
||||||
with_furi_hal_i2c(
|
|
||||||
uint16_t, &ret, () {
|
if(furi_hal_i2c_trx(handle, BQ27220_ADDRESS, buffer, 1, buffer, 2, BQ27220_I2C_TIMEOUT)) {
|
||||||
if(furi_hal_i2c_trx(
|
ret = *(uint16_t*)buffer;
|
||||||
POWER_I2C, BQ27220_ADDRESS, buffer, 1, buffer, 2, BQ27220_I2C_TIMEOUT)) {
|
}
|
||||||
return *(uint16_t*)buffer;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bq27220_control(uint16_t control) {
|
bool bq27220_control(FuriHalI2cBusHandle* handle, uint16_t control) {
|
||||||
bool ret;
|
bool ret = false;
|
||||||
with_furi_hal_i2c(
|
uint8_t buffer[3];
|
||||||
bool, &ret, () {
|
|
||||||
uint8_t buffer[3];
|
buffer[0] = CommandControl;
|
||||||
buffer[0] = CommandControl;
|
buffer[1] = control & 0xFF;
|
||||||
buffer[1] = control & 0xFF;
|
buffer[2] = (control >> 8) & 0xFF;
|
||||||
buffer[2] = (control >> 8) & 0xFF;
|
ret = furi_hal_i2c_tx(handle, BQ27220_ADDRESS, buffer, 3, BQ27220_I2C_TIMEOUT);
|
||||||
return furi_hal_i2c_tx(POWER_I2C, BQ27220_ADDRESS, buffer, 3, BQ27220_I2C_TIMEOUT);
|
|
||||||
});
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,75 +38,73 @@ uint8_t bq27220_get_checksum(uint8_t* data, uint16_t len) {
|
|||||||
return 0xFF - ret;
|
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;
|
bool ret;
|
||||||
uint8_t buffer[5];
|
uint8_t buffer[5];
|
||||||
with_furi_hal_i2c(
|
|
||||||
bool, &ret, () {
|
buffer[0] = CommandSelectSubclass;
|
||||||
buffer[0] = CommandSelectSubclass;
|
buffer[1] = address & 0xFF;
|
||||||
buffer[1] = address & 0xFF;
|
buffer[2] = (address >> 8) & 0xFF;
|
||||||
buffer[2] = (address >> 8) & 0xFF;
|
buffer[3] = (value >> 8) & 0xFF;
|
||||||
buffer[3] = (value >> 8) & 0xFF;
|
buffer[4] = value & 0xFF;
|
||||||
buffer[4] = value & 0xFF;
|
ret = furi_hal_i2c_tx(handle, BQ27220_ADDRESS, buffer, 5, BQ27220_I2C_TIMEOUT);
|
||||||
return furi_hal_i2c_tx(POWER_I2C, BQ27220_ADDRESS, buffer, 5, BQ27220_I2C_TIMEOUT);
|
|
||||||
});
|
|
||||||
delay_us(10000);
|
delay_us(10000);
|
||||||
|
|
||||||
uint8_t checksum = bq27220_get_checksum(&buffer[1], 4);
|
uint8_t checksum = bq27220_get_checksum(&buffer[1], 4);
|
||||||
with_furi_hal_i2c(
|
buffer[0] = CommandMACDataSum;
|
||||||
bool, &ret, () {
|
buffer[1] = checksum;
|
||||||
buffer[0] = CommandMACDataSum;
|
buffer[2] = 6;
|
||||||
buffer[1] = checksum;
|
ret = furi_hal_i2c_tx(handle, BQ27220_ADDRESS, buffer, 3, BQ27220_I2C_TIMEOUT);
|
||||||
buffer[2] = 6;
|
|
||||||
return furi_hal_i2c_tx(POWER_I2C, BQ27220_ADDRESS, buffer, 3, BQ27220_I2C_TIMEOUT);
|
|
||||||
});
|
|
||||||
delay_us(10000);
|
delay_us(10000);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bq27220_init(const ParamCEDV* cedv) {
|
bool bq27220_init(FuriHalI2cBusHandle* handle, const ParamCEDV* cedv) {
|
||||||
uint32_t timeout = 100;
|
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) {
|
if(cedv->design_cap == design_cap) {
|
||||||
FURI_LOG_I(TAG, "Skip battery profile update");
|
FURI_LOG_I(TAG, "Skip battery profile update");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
FURI_LOG_I(TAG, "Start updating battery profile");
|
FURI_LOG_I(TAG, "Start updating battery profile");
|
||||||
OperationStatus status = {};
|
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");
|
FURI_LOG_E(TAG, "Can't configure update");
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
while((status.CFGUPDATE != 1) && (timeout-- > 0)) {
|
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(handle, AddressGaugingConfig, cedv->cedv_conf.gauge_conf_raw);
|
||||||
bq27220_set_parameter_u16(AddressFullChargeCapacity, cedv->full_charge_cap);
|
bq27220_set_parameter_u16(handle, AddressFullChargeCapacity, cedv->full_charge_cap);
|
||||||
bq27220_set_parameter_u16(AddressDesignCapacity, cedv->design_cap);
|
bq27220_set_parameter_u16(handle, AddressDesignCapacity, cedv->design_cap);
|
||||||
bq27220_set_parameter_u16(AddressEMF, cedv->EMF);
|
bq27220_set_parameter_u16(handle, AddressEMF, cedv->EMF);
|
||||||
bq27220_set_parameter_u16(AddressC0, cedv->C0);
|
bq27220_set_parameter_u16(handle, AddressC0, cedv->C0);
|
||||||
bq27220_set_parameter_u16(AddressR0, cedv->R0);
|
bq27220_set_parameter_u16(handle, AddressR0, cedv->R0);
|
||||||
bq27220_set_parameter_u16(AddressT0, cedv->T0);
|
bq27220_set_parameter_u16(handle, AddressT0, cedv->T0);
|
||||||
bq27220_set_parameter_u16(AddressR1, cedv->R1);
|
bq27220_set_parameter_u16(handle, AddressR1, cedv->R1);
|
||||||
bq27220_set_parameter_u16(AddressTC, (cedv->TC) << 8 | cedv->C1);
|
bq27220_set_parameter_u16(handle, AddressTC, (cedv->TC) << 8 | cedv->C1);
|
||||||
bq27220_set_parameter_u16(AddressStartDOD0, cedv->DOD0);
|
bq27220_set_parameter_u16(handle, AddressStartDOD0, cedv->DOD0);
|
||||||
bq27220_set_parameter_u16(AddressStartDOD10, cedv->DOD10);
|
bq27220_set_parameter_u16(handle, AddressStartDOD10, cedv->DOD10);
|
||||||
bq27220_set_parameter_u16(AddressStartDOD20, cedv->DOD20);
|
bq27220_set_parameter_u16(handle, AddressStartDOD20, cedv->DOD20);
|
||||||
bq27220_set_parameter_u16(AddressStartDOD30, cedv->DOD30);
|
bq27220_set_parameter_u16(handle, AddressStartDOD30, cedv->DOD30);
|
||||||
bq27220_set_parameter_u16(AddressStartDOD40, cedv->DOD40);
|
bq27220_set_parameter_u16(handle, AddressStartDOD40, cedv->DOD40);
|
||||||
bq27220_set_parameter_u16(AddressStartDOD50, cedv->DOD40);
|
bq27220_set_parameter_u16(handle, AddressStartDOD50, cedv->DOD40);
|
||||||
bq27220_set_parameter_u16(AddressStartDOD60, cedv->DOD60);
|
bq27220_set_parameter_u16(handle, AddressStartDOD60, cedv->DOD60);
|
||||||
bq27220_set_parameter_u16(AddressStartDOD70, cedv->DOD70);
|
bq27220_set_parameter_u16(handle, AddressStartDOD70, cedv->DOD70);
|
||||||
bq27220_set_parameter_u16(AddressStartDOD80, cedv->DOD80);
|
bq27220_set_parameter_u16(handle, AddressStartDOD80, cedv->DOD80);
|
||||||
bq27220_set_parameter_u16(AddressStartDOD90, cedv->DOD90);
|
bq27220_set_parameter_u16(handle, AddressStartDOD90, cedv->DOD90);
|
||||||
bq27220_set_parameter_u16(AddressStartDOD100, cedv->DOD100);
|
bq27220_set_parameter_u16(handle, AddressStartDOD100, cedv->DOD100);
|
||||||
bq27220_set_parameter_u16(AddressEDV0, cedv->EDV0);
|
bq27220_set_parameter_u16(handle, AddressEDV0, cedv->EDV0);
|
||||||
bq27220_set_parameter_u16(AddressEDV1, cedv->EDV1);
|
bq27220_set_parameter_u16(handle, AddressEDV1, cedv->EDV1);
|
||||||
bq27220_set_parameter_u16(AddressEDV2, cedv->EDV2);
|
bq27220_set_parameter_u16(handle, AddressEDV2, cedv->EDV2);
|
||||||
|
|
||||||
bq27220_control(Control_EXIT_CFG_UPDATE);
|
bq27220_control(handle, Control_EXIT_CFG_UPDATE);
|
||||||
delay_us(10000);
|
delay_us(10000);
|
||||||
design_cap = bq27220_get_design_capacity();
|
design_cap = bq27220_get_design_capacity(handle);
|
||||||
if(cedv->design_cap == design_cap) {
|
if(cedv->design_cap == design_cap) {
|
||||||
FURI_LOG_I(TAG, "Battery profile update success");
|
FURI_LOG_I(TAG, "Battery profile update success");
|
||||||
return true;
|
return true;
|
||||||
@ -121,16 +114,16 @@ bool bq27220_init(const ParamCEDV* cedv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t bq27220_get_voltage() {
|
uint16_t bq27220_get_voltage(FuriHalI2cBusHandle* handle) {
|
||||||
return bq27220_read_word(CommandVoltage);
|
return bq27220_read_word(handle, CommandVoltage);
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t bq27220_get_current() {
|
int16_t bq27220_get_current(FuriHalI2cBusHandle* handle) {
|
||||||
return bq27220_read_word(CommandCurrent);
|
return bq27220_read_word(handle, CommandCurrent);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t bq27220_get_battery_status(BatteryStatus* battery_status) {
|
uint8_t bq27220_get_battery_status(FuriHalI2cBusHandle* handle, BatteryStatus* battery_status) {
|
||||||
uint16_t data = bq27220_read_word(CommandBatteryStatus);
|
uint16_t data = bq27220_read_word(handle, CommandBatteryStatus);
|
||||||
if(data == BQ27220_ERROR) {
|
if(data == BQ27220_ERROR) {
|
||||||
return BQ27220_ERROR;
|
return BQ27220_ERROR;
|
||||||
} else {
|
} else {
|
||||||
@ -139,8 +132,8 @@ uint8_t bq27220_get_battery_status(BatteryStatus* battery_status) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t bq27220_get_operation_status(OperationStatus* operation_status) {
|
uint8_t bq27220_get_operation_status(FuriHalI2cBusHandle* handle, OperationStatus* operation_status) {
|
||||||
uint16_t data = bq27220_read_word(CommandOperationStatus);
|
uint16_t data = bq27220_read_word(handle, CommandOperationStatus);
|
||||||
if(data == BQ27220_ERROR) {
|
if(data == BQ27220_ERROR) {
|
||||||
return BQ27220_ERROR;
|
return BQ27220_ERROR;
|
||||||
} else {
|
} else {
|
||||||
@ -149,26 +142,26 @@ uint8_t bq27220_get_operation_status(OperationStatus* operation_status) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t bq27220_get_temperature() {
|
uint16_t bq27220_get_temperature(FuriHalI2cBusHandle* handle) {
|
||||||
return bq27220_read_word(CommandTemperature);
|
return bq27220_read_word(handle, CommandTemperature);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t bq27220_get_full_charge_capacity() {
|
uint16_t bq27220_get_full_charge_capacity(FuriHalI2cBusHandle* handle) {
|
||||||
return bq27220_read_word(CommandFullChargeCapacity);
|
return bq27220_read_word(handle, CommandFullChargeCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t bq27220_get_design_capacity() {
|
uint16_t bq27220_get_design_capacity(FuriHalI2cBusHandle* handle) {
|
||||||
return bq27220_read_word(CommandDesignCapacity);
|
return bq27220_read_word(handle, CommandDesignCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t bq27220_get_remaining_capacity() {
|
uint16_t bq27220_get_remaining_capacity(FuriHalI2cBusHandle* handle) {
|
||||||
return bq27220_read_word(CommandRemainingCapacity);
|
return bq27220_read_word(handle, CommandRemainingCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t bq27220_get_state_of_charge() {
|
uint16_t bq27220_get_state_of_charge(FuriHalI2cBusHandle* handle) {
|
||||||
return bq27220_read_word(CommandStateOfCharge);
|
return bq27220_read_word(handle, CommandStateOfCharge);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t bq27220_get_state_of_health() {
|
uint16_t bq27220_get_state_of_health(FuriHalI2cBusHandle* handle) {
|
||||||
return bq27220_read_word(CommandStateOfHealth);
|
return bq27220_read_word(handle, CommandStateOfHealth);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <furi-hal-i2c.h>
|
||||||
|
|
||||||
#define BQ27220_ERROR 0x0
|
#define BQ27220_ERROR 0x0
|
||||||
#define BQ27220_SUCCESS 0x1
|
#define BQ27220_SUCCESS 0x1
|
||||||
@ -95,36 +96,36 @@ typedef struct {
|
|||||||
/** Initialize Driver
|
/** Initialize Driver
|
||||||
* @return true on success, false otherwise
|
* @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 */
|
/** 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*/
|
/** Get current in mA or error*/
|
||||||
int16_t bq27220_get_current();
|
int16_t bq27220_get_current(FuriHalI2cBusHandle* handle);
|
||||||
|
|
||||||
/** Get battery status */
|
/** 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 */
|
/** 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 */
|
/** 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 */
|
/** 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 */
|
/** 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 */
|
/** 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 */
|
/** 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 */
|
/** 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.h"
|
||||||
#include "lp5562_reg.h"
|
#include "lp5562_reg.h"
|
||||||
|
|
||||||
#include <furi-hal-i2c.h>
|
|
||||||
#include <stdio.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};
|
uint8_t buffer[2] = {address, *data};
|
||||||
bool ret;
|
return furi_hal_i2c_tx(handle, LP5562_ADDRESS, buffer, 2, LP5562_I2C_TIMEOUT);
|
||||||
with_furi_hal_i2c(
|
|
||||||
bool, &ret, () {
|
|
||||||
return furi_hal_i2c_tx(POWER_I2C, LP5562_ADDRESS, buffer, 2, LP5562_I2C_TIMEOUT);
|
|
||||||
});
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lp5562_reset() {
|
void lp5562_reset(FuriHalI2cBusHandle* handle) {
|
||||||
Reg0D_Reset reg = {.value = 0xFF};
|
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};
|
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 = {
|
Reg70_LedMap map = {
|
||||||
.red = EngSelectI2C,
|
.red = EngSelectI2C,
|
||||||
@ -29,15 +23,15 @@ void lp5562_configure() {
|
|||||||
.blue = EngSelectI2C,
|
.blue = EngSelectI2C,
|
||||||
.white = 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};
|
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;
|
uint8_t reg_no;
|
||||||
if(channel == LP5562ChannelRed) {
|
if(channel == LP5562ChannelRed) {
|
||||||
reg_no = 0x07;
|
reg_no = 0x07;
|
||||||
@ -50,10 +44,10 @@ void lp5562_set_channel_current(LP5562Channel channel, uint8_t value) {
|
|||||||
} else {
|
} else {
|
||||||
return;
|
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;
|
uint8_t reg_no;
|
||||||
if(channel == LP5562ChannelRed) {
|
if(channel == LP5562ChannelRed) {
|
||||||
reg_no = 0x04;
|
reg_no = 0x04;
|
||||||
@ -66,5 +60,5 @@ void lp5562_set_channel_value(LP5562Channel channel, uint8_t value) {
|
|||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lp5562_write_reg(reg_no, &value);
|
lp5562_write_reg(handle, reg_no, &value);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <furi-hal-i2c.h>
|
||||||
|
|
||||||
/** Channel types */
|
/** Channel types */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -12,16 +13,16 @@ typedef enum {
|
|||||||
} LP5562Channel;
|
} LP5562Channel;
|
||||||
|
|
||||||
/** Initialize Driver */
|
/** Initialize Driver */
|
||||||
void lp5562_reset();
|
void lp5562_reset(FuriHalI2cBusHandle* handle);
|
||||||
|
|
||||||
/** Configure Driver */
|
/** Configure Driver */
|
||||||
void lp5562_configure();
|
void lp5562_configure(FuriHalI2cBusHandle* handle);
|
||||||
|
|
||||||
/** Enable Driver */
|
/** Enable Driver */
|
||||||
void lp5562_enable();
|
void lp5562_enable(FuriHalI2cBusHandle* handle);
|
||||||
|
|
||||||
/** Set channel current */
|
/** 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 */
|
/** 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…
x
Reference in New Issue
Block a user