Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ClusterM/flipperzero-firmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--applications/storage/storage-external-api.c4
-rw-r--r--applications/tests/rpc/rpc_test.c2
-rw-r--r--bootloader/targets/f6/furi-hal/furi-hal-i2c-config.c149
-rw-r--r--bootloader/targets/f6/furi-hal/furi-hal-i2c-config.h31
-rw-r--r--bootloader/targets/f6/furi-hal/furi-hal-i2c-types.h51
-rw-r--r--bootloader/targets/f6/furi-hal/furi-hal-i2c.c95
-rw-r--r--bootloader/targets/f6/furi-hal/furi-hal-i2c.h64
-rw-r--r--bootloader/targets/f6/furi-hal/furi-hal-light.c36
-rw-r--r--bootloader/targets/f6/furi-hal/furi-hal-resources.c3
-rw-r--r--bootloader/targets/f6/furi-hal/furi-hal-resources.h15
-rw-r--r--bootloader/targets/f7/furi-hal/furi-hal-i2c-config.c149
-rw-r--r--bootloader/targets/f7/furi-hal/furi-hal-i2c-config.h31
-rw-r--r--bootloader/targets/f7/furi-hal/furi-hal-i2c-types.h51
-rw-r--r--bootloader/targets/f7/furi-hal/furi-hal-i2c.c95
-rw-r--r--bootloader/targets/f7/furi-hal/furi-hal-i2c.h64
-rw-r--r--bootloader/targets/f7/furi-hal/furi-hal-light.c36
-rw-r--r--bootloader/targets/f7/furi-hal/furi-hal-resources.c3
-rw-r--r--bootloader/targets/f7/furi-hal/furi-hal-resources.h15
-rw-r--r--firmware/targets/f6/furi-hal/furi-hal-i2c-config.c133
-rw-r--r--firmware/targets/f6/furi-hal/furi-hal-i2c-config.h31
-rw-r--r--firmware/targets/f6/furi-hal/furi-hal-i2c-types.h49
-rw-r--r--firmware/targets/f6/furi-hal/furi-hal-i2c.c107
-rw-r--r--firmware/targets/f6/furi-hal/furi-hal-light.c57
-rw-r--r--firmware/targets/f6/furi-hal/furi-hal-power.c131
-rw-r--r--firmware/targets/f6/furi-hal/furi-hal-resources.c3
-rw-r--r--firmware/targets/f6/furi-hal/furi-hal-resources.h21
-rw-r--r--firmware/targets/f6/furi-hal/furi-hal-vcp.c2
-rw-r--r--firmware/targets/f7/furi-hal/furi-hal-i2c-config.c133
-rw-r--r--firmware/targets/f7/furi-hal/furi-hal-i2c-config.h31
-rw-r--r--firmware/targets/f7/furi-hal/furi-hal-i2c-types.h49
-rw-r--r--firmware/targets/f7/furi-hal/furi-hal-i2c.c107
-rw-r--r--firmware/targets/f7/furi-hal/furi-hal-light.c57
-rw-r--r--firmware/targets/f7/furi-hal/furi-hal-power.c131
-rw-r--r--firmware/targets/f7/furi-hal/furi-hal-resources.c3
-rw-r--r--firmware/targets/f7/furi-hal/furi-hal-resources.h21
-rw-r--r--firmware/targets/f7/furi-hal/furi-hal-spi.h108
-rw-r--r--firmware/targets/f7/furi-hal/furi-hal-vcp.c2
-rw-r--r--firmware/targets/furi-hal-include/furi-hal-i2c.h50
-rw-r--r--firmware/targets/furi-hal-include/furi-hal-spi.h (renamed from firmware/targets/f6/furi-hal/furi-hal-spi.h)3
-rw-r--r--lib/drivers/bq25896.c87
-rw-r--r--lib/drivers/bq25896.h27
-rw-r--r--lib/drivers/bq27220.c171
-rw-r--r--lib/drivers/bq27220.h25
-rw-r--r--lib/drivers/lp5562.c32
-rw-r--r--lib/drivers/lp5562.h11
45 files changed, 1690 insertions, 786 deletions
diff --git a/applications/storage/storage-external-api.c b/applications/storage/storage-external-api.c
index 6c61f707..05d1fc28 100644
--- a/applications/storage/storage-external-api.c
+++ b/applications/storage/storage-external-api.c
@@ -427,7 +427,7 @@ bool storage_simply_remove_recursive(Storage* storage, const char* path) {
string_init_printf(fullname, "%s/%s", string_get_cstr(cur_dir), name);
FS_Error error = storage_common_remove(storage, string_get_cstr(fullname));
- furi_assert(error == FSE_OK);
+ furi_check(error == FSE_OK);
string_clear(fullname);
}
storage_dir_close(dir);
@@ -438,7 +438,7 @@ bool storage_simply_remove_recursive(Storage* storage, const char* path) {
}
FS_Error error = storage_common_remove(storage, string_get_cstr(cur_dir));
- furi_assert(error == FSE_OK);
+ furi_check(error == FSE_OK);
if(string_cmp(cur_dir, path)) {
size_t last_char = string_search_rchar(cur_dir, '/');
diff --git a/applications/tests/rpc/rpc_test.c b/applications/tests/rpc/rpc_test.c
index af99be4a..dbe1a324 100644
--- a/applications/tests/rpc/rpc_test.c
+++ b/applications/tests/rpc/rpc_test.c
@@ -115,7 +115,7 @@ static void clean_directory(Storage* fs_api, const char* clean_dir) {
clean_directory(fs_api, fullname);
}
FS_Error error = storage_common_remove(fs_api, fullname);
- furi_assert(error == FSE_OK);
+ furi_check(error == FSE_OK);
free(fullname);
}
free(name);
diff --git a/bootloader/targets/f6/furi-hal/furi-hal-i2c-config.c b/bootloader/targets/f6/furi-hal/furi-hal-i2c-config.c
new file mode 100644
index 00000000..afaab237
--- /dev/null
+++ b/bootloader/targets/f6/furi-hal/furi-hal-i2c-config.c
@@ -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,
+};
diff --git a/bootloader/targets/f6/furi-hal/furi-hal-i2c-config.h b/bootloader/targets/f6/furi-hal/furi-hal-i2c-config.h
new file mode 100644
index 00000000..2094dca3
--- /dev/null
+++ b/bootloader/targets/f6/furi-hal/furi-hal-i2c-config.h
@@ -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 \ No newline at end of file
diff --git a/bootloader/targets/f6/furi-hal/furi-hal-i2c-types.h b/bootloader/targets/f6/furi-hal/furi-hal-i2c-types.h
new file mode 100644
index 00000000..0f2b735e
--- /dev/null
+++ b/bootloader/targets/f6/furi-hal/furi-hal-i2c-types.h
@@ -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 \ No newline at end of file
diff --git a/bootloader/targets/f6/furi-hal/furi-hal-i2c.c b/bootloader/targets/f6/furi-hal/furi-hal-i2c.c
index c40a70af..f276ff75 100644
--- a/bootloader/targets/f6/furi-hal/furi-hal-i2c.c
+++ b/bootloader/targets/f6/furi-hal/furi-hal-i2c.c
@@ -1,66 +1,64 @@
#include <furi-hal-i2c.h>
+#include <furi-hal-version.h>
-#include <stm32wbxx_ll_bus.h>
#include <stm32wbxx_ll_i2c.h>
-#include <stm32wbxx_ll_rcc.h>
#include <stm32wbxx_ll_gpio.h>
#include <stm32wbxx_ll_cortex.h>
+#include <assert.h>
+
void furi_hal_i2c_init() {
- LL_I2C_InitTypeDef I2C_InitStruct = {0};
- LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
-
- LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);
-
- LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
- GPIO_InitStruct.Pin = POWER_I2C_SCL_Pin | POWER_I2C_SDA_Pin;
- GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
- GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
- GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
- GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
- GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
- LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
-
- LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);
-
- I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
- I2C_InitStruct.Timing = POWER_I2C_TIMINGS;
- I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
- I2C_InitStruct.DigitalFilter = 0;
- I2C_InitStruct.OwnAddress1 = 0;
- I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
- I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
- LL_I2C_Init(I2C1, &I2C_InitStruct);
- LL_I2C_EnableAutoEndMode(I2C1);
- LL_I2C_SetOwnAddress2(I2C1, 0, LL_I2C_OWNADDRESS2_NOMASK);
- LL_I2C_DisableOwnAddress2(I2C1);
- LL_I2C_DisableGeneralCall(I2C1);
- LL_I2C_EnableClockStretching(I2C1);
+ furi_hal_i2c_bus_power.callback(&furi_hal_i2c_bus_power, FuriHalI2cBusEventInit);
+}
+
+void furi_hal_i2c_acquire(FuriHalI2cBusHandle* handle) {
+ handle->bus->callback(handle->bus, FuriHalI2cBusEventLock);
+
+ assert(handle->bus->current_handle == NULL);
+
+ handle->bus->current_handle = handle;
+
+ handle->bus->callback(handle->bus, FuriHalI2cBusEventActivate);
+
+ handle->callback(handle, FuriHalI2cBusHandleEventActivate);
+}
+
+void furi_hal_i2c_release(FuriHalI2cBusHandle* handle) {
+ assert(handle->bus->current_handle == handle);
+
+ handle->callback(handle, FuriHalI2cBusHandleEventDeactivate);
+
+ handle->bus->callback(handle->bus, FuriHalI2cBusEventDeactivate);
+
+ handle->bus->current_handle = NULL;
+
+ handle->bus->callback(handle->bus, FuriHalI2cBusEventUnlock);
}
bool furi_hal_i2c_tx(
- I2C_TypeDef* instance,
+ FuriHalI2cBusHandle* handle,
uint8_t address,
const uint8_t* data,
uint8_t size,
uint32_t timeout) {
+ assert(handle->bus->current_handle == handle);
uint32_t time_left = timeout;
bool ret = true;
- while(LL_I2C_IsActiveFlag_BUSY(instance))
+ while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
;
LL_I2C_HandleTransfer(
- instance,
+ handle->bus->i2c,
address,
LL_I2C_ADDRSLAVE_7BIT,
size,
LL_I2C_MODE_AUTOEND,
LL_I2C_GENERATE_START_WRITE);
- while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
- if(LL_I2C_IsActiveFlag_TXIS(instance)) {
- LL_I2C_TransmitData8(instance, (*data));
+ while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
+ if(LL_I2C_IsActiveFlag_TXIS(handle->bus->i2c)) {
+ LL_I2C_TransmitData8(handle->bus->i2c, (*data));
data++;
size--;
time_left = timeout;
@@ -74,34 +72,35 @@ bool furi_hal_i2c_tx(
}
}
- LL_I2C_ClearFlag_STOP(instance);
+ LL_I2C_ClearFlag_STOP(handle->bus->i2c);
return ret;
}
bool furi_hal_i2c_rx(
- I2C_TypeDef* instance,
+ FuriHalI2cBusHandle* handle,
uint8_t address,
uint8_t* data,
uint8_t size,
uint32_t timeout) {
+ assert(handle->bus->current_handle == handle);
uint32_t time_left = timeout;
bool ret = true;
- while(LL_I2C_IsActiveFlag_BUSY(instance))
+ while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
;
LL_I2C_HandleTransfer(
- instance,
+ handle->bus->i2c,
address,
LL_I2C_ADDRSLAVE_7BIT,
size,
LL_I2C_MODE_AUTOEND,
LL_I2C_GENERATE_START_READ);
- while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
- if(LL_I2C_IsActiveFlag_RXNE(instance)) {
- *data = LL_I2C_ReceiveData8(instance);
+ while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
+ if(LL_I2C_IsActiveFlag_RXNE(handle->bus->i2c)) {
+ *data = LL_I2C_ReceiveData8(handle->bus->i2c);
data++;
size--;
time_left = timeout;
@@ -115,21 +114,21 @@ bool furi_hal_i2c_rx(
}
}
- LL_I2C_ClearFlag_STOP(instance);
+ LL_I2C_ClearFlag_STOP(handle->bus->i2c);
return ret;
}
bool furi_hal_i2c_trx(
- I2C_TypeDef* instance,
+ FuriHalI2cBusHandle* handle,
uint8_t address,
const uint8_t* tx_data,
uint8_t tx_size,
uint8_t* rx_data,
uint8_t rx_size,
uint32_t timeout) {
- if(furi_hal_i2c_tx(instance, address, tx_data, tx_size, timeout) &&
- furi_hal_i2c_rx(instance, address, rx_data, rx_size, timeout)) {
+ if(furi_hal_i2c_tx(handle, address, tx_data, tx_size, timeout) &&
+ furi_hal_i2c_rx(handle, address, rx_data, rx_size, timeout)) {
return true;
} else {
return false;
diff --git a/bootloader/targets/f6/furi-hal/furi-hal-i2c.h b/bootloader/targets/f6/furi-hal/furi-hal-i2c.h
index 5db562e0..7ef1db44 100644
--- a/bootloader/targets/f6/furi-hal/furi-hal-i2c.h
+++ b/bootloader/targets/f6/furi-hal/furi-hal-i2c.h
@@ -1,31 +1,82 @@
+/**
+ * @file furi-hal-i2c.h
+ * I2C HAL API
+ */
+
#pragma once
#include <stdbool.h>
#include <stdint.h>
-#include <furi-hal-resources.h>
+#include <furi-hal-i2c-config.h>
#ifdef __cplusplus
extern "C" {
#endif
+/** Init I2C
+ */
void furi_hal_i2c_init();
+/** Acquire i2c bus handle
+ *
+ * @return Instance of FuriHalI2cBus
+ */
+void furi_hal_i2c_acquire(FuriHalI2cBusHandle* handle);
+
+/** Release i2c bus handle
+ *
+ * @param bus instance of FuriHalI2cBus aquired in `furi_hal_i2c_acquire`
+ */
+void furi_hal_i2c_release(FuriHalI2cBusHandle* handle);
+
+/** Perform I2C tx transfer
+ *
+ * @param instance I2C_TypeDef instance
+ * @param address I2C slave address
+ * @param data pointer to data buffer
+ * @param size size of data buffer
+ * @param timeout timeout in ticks
+ *
+ * @return true on successful transfer, false otherwise
+ */
bool furi_hal_i2c_tx(
- I2C_TypeDef* instance,
+ FuriHalI2cBusHandle* handle,
const uint8_t address,
const uint8_t* data,
const uint8_t size,
uint32_t timeout);
+/** Perform I2C rx transfer
+ *
+ * @param instance I2C_TypeDef instance
+ * @param address I2C slave address
+ * @param data pointer to data buffer
+ * @param size size of data buffer
+ * @param timeout timeout in ticks
+ *
+ * @return true on successful transfer, false otherwise
+ */
bool furi_hal_i2c_rx(
- I2C_TypeDef* instance,
+ FuriHalI2cBusHandle* handle,
const uint8_t address,
uint8_t* data,
const uint8_t size,
uint32_t timeout);
+/** Perform I2C tx and rx transfers
+ *
+ * @param instance I2C_TypeDef instance
+ * @param address I2C slave address
+ * @param tx_data pointer to tx data buffer
+ * @param tx_size size of tx data buffer
+ * @param rx_data pointer to rx data buffer
+ * @param rx_size size of rx data buffer
+ * @param timeout timeout in ticks
+ *
+ * @return true on successful transfer, false otherwise
+ */
bool furi_hal_i2c_trx(
- I2C_TypeDef* instance,
+ FuriHalI2cBusHandle* handle,
const uint8_t address,
const uint8_t* tx_data,
const uint8_t tx_size,
@@ -33,11 +84,6 @@ bool furi_hal_i2c_trx(
const uint8_t rx_size,
uint32_t timeout);
-#define with_furi_hal_i2c(type, pointer, function_body) \
- { \
- *pointer = ({ type __fn__ function_body __fn__; })(); \
- }
-
#ifdef __cplusplus
}
#endif
diff --git a/bootloader/targets/f6/furi-hal/furi-hal-light.c b/bootloader/targets/f6/furi-hal/furi-hal-light.c
index d5f54f6d..15a69f09 100644
--- a/bootloader/targets/f6/furi-hal/furi-hal-light.c
+++ b/bootloader/targets/f6/furi-hal/furi-hal-light.c
@@ -7,37 +7,43 @@
#define LED_CURRENT_WHITE 150
void furi_hal_light_init() {
- lp5562_reset();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
- lp5562_set_channel_current(LP5562ChannelRed, LED_CURRENT_RED);
- lp5562_set_channel_current(LP5562ChannelGreen, LED_CURRENT_GREEN);
- lp5562_set_channel_current(LP5562ChannelBlue, LED_CURRENT_BLUE);
- lp5562_set_channel_current(LP5562ChannelWhite, LED_CURRENT_WHITE);
+ lp5562_reset(&furi_hal_i2c_handle_power);
- lp5562_set_channel_value(LP5562ChannelRed, 0x00);
- lp5562_set_channel_value(LP5562ChannelGreen, 0x00);
- lp5562_set_channel_value(LP5562ChannelBlue, 0x00);
- lp5562_set_channel_value(LP5562ChannelWhite, 0x00);
+ lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelRed, LED_CURRENT_RED);
+ lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelGreen, LED_CURRENT_GREEN);
+ lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelBlue, LED_CURRENT_BLUE);
+ lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelWhite, LED_CURRENT_WHITE);
- lp5562_enable();
- lp5562_configure();
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, 0x00);
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, 0x00);
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, 0x00);
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, 0x00);
+
+ lp5562_enable(&furi_hal_i2c_handle_power);
+ lp5562_configure(&furi_hal_i2c_handle_power);
+
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
}
void furi_hal_light_set(Light light, uint8_t value) {
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
switch(light) {
case LightRed:
- lp5562_set_channel_value(LP5562ChannelRed, value);
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value);
break;
case LightGreen:
- lp5562_set_channel_value(LP5562ChannelGreen, value);
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value);
break;
case LightBlue:
- lp5562_set_channel_value(LP5562ChannelBlue, value);
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value);
break;
case LightBacklight:
- lp5562_set_channel_value(LP5562ChannelWhite, value);
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, value);
break;
default:
break;
}
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
} \ No newline at end of file
diff --git a/bootloader/targets/f6/furi-hal/furi-hal-resources.c b/bootloader/targets/f6/furi-hal/furi-hal-resources.c
index 1260a485..3af9ba03 100644
--- a/bootloader/targets/f6/furi-hal/furi-hal-resources.c
+++ b/bootloader/targets/f6/furi-hal/furi-hal-resources.c
@@ -39,3 +39,6 @@ const GpioPin gpio_irda_tx = {.port = IR_TX_GPIO_Port, .pin = IR_TX_Pin};
const GpioPin gpio_usart_tx = {.port = USART1_TX_Port, .pin = USART1_TX_Pin};
const GpioPin gpio_usart_rx = {.port = USART1_RX_Port, .pin = USART1_RX_Pin};
+
+const GpioPin gpio_i2c_power_sda = {.port = GPIOA, .pin = LL_GPIO_PIN_10};
+const GpioPin gpio_i2c_power_scl = {.port = GPIOA, .pin = LL_GPIO_PIN_9};
diff --git a/bootloader/targets/f6/furi-hal/furi-hal-resources.h b/bootloader/targets/f6/furi-hal/furi-hal-resources.h
index 95bb4d0d..42b9b315 100644
--- a/bootloader/targets/f6/furi-hal/furi-hal-resources.h
+++ b/bootloader/targets/f6/furi-hal/furi-hal-resources.h
@@ -8,18 +8,6 @@
extern "C" {
#endif
-#define POWER_I2C_SCL_Pin LL_GPIO_PIN_9
-#define POWER_I2C_SCL_GPIO_Port GPIOA
-#define POWER_I2C_SDA_Pin LL_GPIO_PIN_10
-#define POWER_I2C_SDA_GPIO_Port GPIOA
-
-#define POWER_I2C I2C1
-/* Timing register value is computed with the STM32CubeMX Tool,
- * Fast Mode @100kHz with I2CCLK = 64 MHz,
- * rise time = 0ns, fall time = 0ns
- */
-#define POWER_I2C_TIMINGS 0x10707DBC
-
/* Input Keys */
typedef enum {
InputKeyUp,
@@ -77,6 +65,9 @@ extern const GpioPin gpio_irda_tx;
extern const GpioPin gpio_usart_tx;
extern const GpioPin gpio_usart_rx;
+extern const GpioPin gpio_i2c_power_sda;
+extern const GpioPin gpio_i2c_power_scl;
+
#ifdef __cplusplus
}
#endif
diff --git a/bootloader/targets/f7/furi-hal/furi-hal-i2c-config.c b/bootloader/targets/f7/furi-hal/furi-hal-i2c-config.c
new file mode 100644
index 00000000..afaab237
--- /dev/null
+++ b/bootloader/targets/f7/furi-hal/furi-hal-i2c-config.c
@@ -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,
+};
diff --git a/bootloader/targets/f7/furi-hal/furi-hal-i2c-config.h b/bootloader/targets/f7/furi-hal/furi-hal-i2c-config.h
new file mode 100644
index 00000000..2094dca3
--- /dev/null
+++ b/bootloader/targets/f7/furi-hal/furi-hal-i2c-config.h
@@ -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 \ No newline at end of file
diff --git a/bootloader/targets/f7/furi-hal/furi-hal-i2c-types.h b/bootloader/targets/f7/furi-hal/furi-hal-i2c-types.h
new file mode 100644
index 00000000..0f2b735e
--- /dev/null
+++ b/bootloader/targets/f7/furi-hal/furi-hal-i2c-types.h
@@ -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 \ No newline at end of file
diff --git a/bootloader/targets/f7/furi-hal/furi-hal-i2c.c b/bootloader/targets/f7/furi-hal/furi-hal-i2c.c
index c40a70af..f276ff75 100644
--- a/bootloader/targets/f7/furi-hal/furi-hal-i2c.c
+++ b/bootloader/targets/f7/furi-hal/furi-hal-i2c.c
@@ -1,66 +1,64 @@
#include <furi-hal-i2c.h>
+#include <furi-hal-version.h>
-#include <stm32wbxx_ll_bus.h>
#include <stm32wbxx_ll_i2c.h>
-#include <stm32wbxx_ll_rcc.h>
#include <stm32wbxx_ll_gpio.h>
#include <stm32wbxx_ll_cortex.h>
+#include <assert.h>
+
void furi_hal_i2c_init() {
- LL_I2C_InitTypeDef I2C_InitStruct = {0};
- LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
-
- LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);
-
- LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
- GPIO_InitStruct.Pin = POWER_I2C_SCL_Pin | POWER_I2C_SDA_Pin;
- GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
- GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
- GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
- GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
- GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
- LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
-
- LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);
-
- I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
- I2C_InitStruct.Timing = POWER_I2C_TIMINGS;
- I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
- I2C_InitStruct.DigitalFilter = 0;
- I2C_InitStruct.OwnAddress1 = 0;
- I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
- I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
- LL_I2C_Init(I2C1, &I2C_InitStruct);
- LL_I2C_EnableAutoEndMode(I2C1);
- LL_I2C_SetOwnAddress2(I2C1, 0, LL_I2C_OWNADDRESS2_NOMASK);
- LL_I2C_DisableOwnAddress2(I2C1);
- LL_I2C_DisableGeneralCall(I2C1);
- LL_I2C_EnableClockStretching(I2C1);
+ furi_hal_i2c_bus_power.callback(&furi_hal_i2c_bus_power, FuriHalI2cBusEventInit);
+}
+
+void furi_hal_i2c_acquire(FuriHalI2cBusHandle* handle) {
+ handle->bus->callback(handle->bus, FuriHalI2cBusEventLock);
+
+ assert(handle->bus->current_handle == NULL);
+
+ handle->bus->current_handle = handle;
+
+ handle->bus->callback(handle->bus, FuriHalI2cBusEventActivate);
+
+ handle->callback(handle, FuriHalI2cBusHandleEventActivate);
+}
+
+void furi_hal_i2c_release(FuriHalI2cBusHandle* handle) {
+ assert(handle->bus->current_handle == handle);
+
+ handle->callback(handle, FuriHalI2cBusHandleEventDeactivate);
+
+ handle->bus->callback(handle->bus, FuriHalI2cBusEventDeactivate);
+
+ handle->bus->current_handle = NULL;
+
+ handle->bus->callback(handle->bus, FuriHalI2cBusEventUnlock);
}
bool furi_hal_i2c_tx(
- I2C_TypeDef* instance,
+ FuriHalI2cBusHandle* handle,
uint8_t address,
const uint8_t* data,
uint8_t size,
uint32_t timeout) {
+ assert(handle->bus->current_handle == handle);
uint32_t time_left = timeout;
bool ret = true;
- while(LL_I2C_IsActiveFlag_BUSY(instance))
+ while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
;
LL_I2C_HandleTransfer(
- instance,
+ handle->bus->i2c,
address,
LL_I2C_ADDRSLAVE_7BIT,
size,
LL_I2C_MODE_AUTOEND,
LL_I2C_GENERATE_START_WRITE);
- while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
- if(LL_I2C_IsActiveFlag_TXIS(instance)) {
- LL_I2C_TransmitData8(instance, (*data));
+ while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
+ if(LL_I2C_IsActiveFlag_TXIS(handle->bus->i2c)) {
+ LL_I2C_TransmitData8(handle->bus->i2c, (*data));
data++;
size--;
time_left = timeout;
@@ -74,34 +72,35 @@ bool furi_hal_i2c_tx(
}
}
- LL_I2C_ClearFlag_STOP(instance);
+ LL_I2C_ClearFlag_STOP(handle->bus->i2c);
return ret;
}
bool furi_hal_i2c_rx(
- I2C_TypeDef* instance,
+ FuriHalI2cBusHandle* handle,
uint8_t address,
uint8_t* data,
uint8_t size,
uint32_t timeout) {
+ assert(handle->bus->current_handle == handle);
uint32_t time_left = timeout;
bool ret = true;
- while(LL_I2C_IsActiveFlag_BUSY(instance))
+ while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
;
LL_I2C_HandleTransfer(
- instance,
+ handle->bus->i2c,
address,
LL_I2C_ADDRSLAVE_7BIT,
size,
LL_I2C_MODE_AUTOEND,
LL_I2C_GENERATE_START_READ);
- while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
- if(LL_I2C_IsActiveFlag_RXNE(instance)) {
- *data = LL_I2C_ReceiveData8(instance);
+ while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
+ if(LL_I2C_IsActiveFlag_RXNE(handle->bus->i2c)) {
+ *data = LL_I2C_ReceiveData8(handle->bus->i2c);
data++;
size--;
time_left = timeout;
@@ -115,21 +114,21 @@ bool furi_hal_i2c_rx(
}
}
- LL_I2C_ClearFlag_STOP(instance);
+ LL_I2C_ClearFlag_STOP(handle->bus->i2c);
return ret;
}
bool furi_hal_i2c_trx(
- I2C_TypeDef* instance,
+ FuriHalI2cBusHandle* handle,
uint8_t address,
const uint8_t* tx_data,
uint8_t tx_size,
uint8_t* rx_data,
uint8_t rx_size,
uint32_t timeout) {
- if(furi_hal_i2c_tx(instance, address, tx_data, tx_size, timeout) &&
- furi_hal_i2c_rx(instance, address, rx_data, rx_size, timeout)) {
+ if(furi_hal_i2c_tx(handle, address, tx_data, tx_size, timeout) &&
+ furi_hal_i2c_rx(handle, address, rx_data, rx_size, timeout)) {
return true;
} else {
return false;
diff --git a/bootloader/targets/f7/furi-hal/furi-hal-i2c.h b/bootloader/targets/f7/furi-hal/furi-hal-i2c.h
index 5db562e0..7ef1db44 100644
--- a/bootloader/targets/f7/furi-hal/furi-hal-i2c.h
+++ b/bootloader/targets/f7/furi-hal/furi-hal-i2c.h
@@ -1,31 +1,82 @@
+/**
+ * @file furi-hal-i2c.h
+ * I2C HAL API
+ */
+
#pragma once
#include <stdbool.h>
#include <stdint.h>
-#include <furi-hal-resources.h>
+#include <furi-hal-i2c-config.h>
#ifdef __cplusplus
extern "C" {
#endif
+/** Init I2C
+ */
void furi_hal_i2c_init();
+/** Acquire i2c bus handle
+ *
+ * @return Instance of FuriHalI2cBus
+ */
+void furi_hal_i2c_acquire(FuriHalI2cBusHandle* handle);
+
+/** Release i2c bus handle
+ *
+ * @param bus instance of FuriHalI2cBus aquired in `furi_hal_i2c_acquire`
+ */
+void furi_hal_i2c_release(FuriHalI2cBusHandle* handle);
+
+/** Perform I2C tx transfer
+ *
+ * @param instance I2C_TypeDef instance
+ * @param address I2C slave address
+ * @param data pointer to data buffer
+ * @param size size of data buffer
+ * @param timeout timeout in ticks
+ *
+ * @return true on successful transfer, false otherwise
+ */
bool furi_hal_i2c_tx(
- I2C_TypeDef* instance,
+ FuriHalI2cBusHandle* handle,
const uint8_t address,
const uint8_t* data,
const uint8_t size,
uint32_t timeout);
+/** Perform I2C rx transfer
+ *
+ * @param instance I2C_TypeDef instance
+ * @param address I2C slave address
+ * @param data pointer to data buffer
+ * @param size size of data buffer
+ * @param timeout timeout in ticks
+ *
+ * @return true on successful transfer, false otherwise
+ */
bool furi_hal_i2c_rx(
- I2C_TypeDef* instance,
+ FuriHalI2cBusHandle* handle,
const uint8_t address,
uint8_t* data,
const uint8_t size,
uint32_t timeout);
+/** Perform I2C tx and rx transfers
+ *
+ * @param instance I2C_TypeDef instance
+ * @param address I2C slave address
+ * @param tx_data pointer to tx data buffer
+ * @param tx_size size of tx data buffer
+ * @param rx_data pointer to rx data buffer
+ * @param rx_size size of rx data buffer
+ * @param timeout timeout in ticks
+ *
+ * @return true on successful transfer, false otherwise
+ */
bool furi_hal_i2c_trx(
- I2C_TypeDef* instance,
+ FuriHalI2cBusHandle* handle,
const uint8_t address,
const uint8_t* tx_data,
const uint8_t tx_size,
@@ -33,11 +84,6 @@ bool furi_hal_i2c_trx(
const uint8_t rx_size,
uint32_t timeout);
-#define with_furi_hal_i2c(type, pointer, function_body) \
- { \
- *pointer = ({ type __fn__ function_body __fn__; })(); \
- }
-
#ifdef __cplusplus
}
#endif
diff --git a/bootloader/targets/f7/furi-hal/furi-hal-light.c b/bootloader/targets/f7/furi-hal/furi-hal-light.c
index d5f54f6d..15a69f09 100644
--- a/bootloader/targets/f7/furi-hal/furi-hal-light.c
+++ b/bootloader/targets/f7/furi-hal/furi-hal-light.c
@@ -7,37 +7,43 @@
#define LED_CURRENT_WHITE 150
void furi_hal_light_init() {
- lp5562_reset();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
- lp5562_set_channel_current(LP5562ChannelRed, LED_CURRENT_RED);
- lp5562_set_channel_current(LP5562ChannelGreen, LED_CURRENT_GREEN);
- lp5562_set_channel_current(LP5562ChannelBlue, LED_CURRENT_BLUE);
- lp5562_set_channel_current(LP5562ChannelWhite, LED_CURRENT_WHITE);
+ lp5562_reset(&furi_hal_i2c_handle_power);
- lp5562_set_channel_value(LP5562ChannelRed, 0x00);
- lp5562_set_channel_value(LP5562ChannelGreen, 0x00);
- lp5562_set_channel_value(LP5562ChannelBlue, 0x00);
- lp5562_set_channel_value(LP5562ChannelWhite, 0x00);
+ lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelRed, LED_CURRENT_RED);
+ lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelGreen, LED_CURRENT_GREEN);
+ lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelBlue, LED_CURRENT_BLUE);
+ lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelWhite, LED_CURRENT_WHITE);
- lp5562_enable();
- lp5562_configure();
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, 0x00);
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, 0x00);
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, 0x00);
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, 0x00);
+
+ lp5562_enable(&furi_hal_i2c_handle_power);
+ lp5562_configure(&furi_hal_i2c_handle_power);
+
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
}
void furi_hal_light_set(Light light, uint8_t value) {
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
switch(light) {
case LightRed:
- lp5562_set_channel_value(LP5562ChannelRed, value);
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value);
break;
case LightGreen:
- lp5562_set_channel_value(LP5562ChannelGreen, value);
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value);
break;
case LightBlue:
- lp5562_set_channel_value(LP5562ChannelBlue, value);
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value);
break;
case LightBacklight:
- lp5562_set_channel_value(LP5562ChannelWhite, value);
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, value);
break;
default:
break;
}
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
} \ No newline at end of file
diff --git a/bootloader/targets/f7/furi-hal/furi-hal-resources.c b/bootloader/targets/f7/furi-hal/furi-hal-resources.c
index 1260a485..3af9ba03 100644
--- a/bootloader/targets/f7/furi-hal/furi-hal-resources.c
+++ b/bootloader/targets/f7/furi-hal/furi-hal-resources.c
@@ -39,3 +39,6 @@ const GpioPin gpio_irda_tx = {.port = IR_TX_GPIO_Port, .pin = IR_TX_Pin};
const GpioPin gpio_usart_tx = {.port = USART1_TX_Port, .pin = USART1_TX_Pin};
const GpioPin gpio_usart_rx = {.port = USART1_RX_Port, .pin = USART1_RX_Pin};
+
+const GpioPin gpio_i2c_power_sda = {.port = GPIOA, .pin = LL_GPIO_PIN_10};
+const GpioPin gpio_i2c_power_scl = {.port = GPIOA, .pin = LL_GPIO_PIN_9};
diff --git a/bootloader/targets/f7/furi-hal/furi-hal-resources.h b/bootloader/targets/f7/furi-hal/furi-hal-resources.h
index 95bb4d0d..42b9b315 100644
--- a/bootloader/targets/f7/furi-hal/furi-hal-resources.h
+++ b/bootloader/targets/f7/furi-hal/furi-hal-resources.h
@@ -8,18 +8,6 @@
extern "C" {
#endif
-#define POWER_I2C_SCL_Pin LL_GPIO_PIN_9
-#define POWER_I2C_SCL_GPIO_Port GPIOA
-#define POWER_I2C_SDA_Pin LL_GPIO_PIN_10
-#define POWER_I2C_SDA_GPIO_Port GPIOA
-
-#define POWER_I2C I2C1
-/* Timing register value is computed with the STM32CubeMX Tool,
- * Fast Mode @100kHz with I2CCLK = 64 MHz,
- * rise time = 0ns, fall time = 0ns
- */
-#define POWER_I2C_TIMINGS 0x10707DBC
-
/* Input Keys */
typedef enum {
InputKeyUp,
@@ -77,6 +65,9 @@ extern const GpioPin gpio_irda_tx;
extern const GpioPin gpio_usart_tx;
extern const GpioPin gpio_usart_rx;
+extern const GpioPin gpio_i2c_power_sda;
+extern const GpioPin gpio_i2c_power_scl;
+
#ifdef __cplusplus
}
#endif
diff --git a/firmware/targets/f6/furi-hal/furi-hal-i2c-config.c b/firmware/targets/f6/furi-hal/furi-hal-i2c-config.c
new file mode 100644
index 00000000..273d46b1
--- /dev/null
+++ b/firmware/targets/f6/furi-hal/furi-hal-i2c-config.c
@@ -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,
+};
diff --git a/firmware/targets/f6/furi-hal/furi-hal-i2c-config.h b/firmware/targets/f6/furi-hal/furi-hal-i2c-config.h
new file mode 100644
index 00000000..2094dca3
--- /dev/null
+++ b/firmware/targets/f6/furi-hal/furi-hal-i2c-config.h
@@ -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 \ No newline at end of file
diff --git a/firmware/targets/f6/furi-hal/furi-hal-i2c-types.h b/firmware/targets/f6/furi-hal/furi-hal-i2c-types.h
new file mode 100644
index 00000000..4f7aab91
--- /dev/null
+++ b/firmware/targets/f6/furi-hal/furi-hal-i2c-types.h
@@ -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 \ No newline at end of file
diff --git a/firmware/targets/f6/furi-hal/furi-hal-i2c.c b/firmware/targets/f6/furi-hal/furi-hal-i2c.c
index b1ec4711..2fd5c5e3 100644
--- a/firmware/targets/f6/furi-hal/furi-hal-i2c.c
+++ b/firmware/targets/f6/furi-hal/furi-hal-i2c.c
@@ -8,68 +8,62 @@
#define TAG "FuriHalI2C"
-osMutexId_t furi_hal_i2c_mutex = NULL;
-
void furi_hal_i2c_init() {
- furi_hal_i2c_mutex = osMutexNew(NULL);
- furi_check(furi_hal_i2c_mutex);
-
- LL_I2C_InitTypeDef I2C_InitStruct = {0};
- LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
-
- LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);
-
- GPIO_InitStruct.Pin = POWER_I2C_SCL_Pin | POWER_I2C_SDA_Pin;
- GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
- GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
- GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
- GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
- GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
- LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
-
- I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
- I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
- I2C_InitStruct.DigitalFilter = 0;
- I2C_InitStruct.OwnAddress1 = 0;
- I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
- I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
- if (furi_hal_version_get_hw_version() > 10) {
- I2C_InitStruct.Timing = POWER_I2C_TIMINGS_400;
- } else {
- I2C_InitStruct.Timing = POWER_I2C_TIMINGS_100;
- }
- LL_I2C_Init(POWER_I2C, &I2C_InitStruct);
- LL_I2C_EnableAutoEndMode(POWER_I2C);
- LL_I2C_SetOwnAddress2(POWER_I2C, 0, LL_I2C_OWNADDRESS2_NOMASK);
- LL_I2C_DisableOwnAddress2(POWER_I2C);
- LL_I2C_DisableGeneralCall(POWER_I2C);
- LL_I2C_EnableClockStretching(POWER_I2C);
+ furi_hal_i2c_bus_power.callback(&furi_hal_i2c_bus_power, FuriHalI2cBusEventInit);
+ furi_hal_i2c_bus_external.callback(&furi_hal_i2c_bus_external, FuriHalI2cBusEventInit);
FURI_LOG_I(TAG, "Init OK");
}
+void furi_hal_i2c_acquire(FuriHalI2cBusHandle* handle) {
+ // Lock bus access
+ handle->bus->callback(handle->bus, FuriHalI2cBusEventLock);
+ // Ensuree that no active handle set
+ furi_check(handle->bus->current_handle == NULL);
+ // Set current handle
+ handle->bus->current_handle = handle;
+ // Activate bus
+ handle->bus->callback(handle->bus, FuriHalI2cBusEventActivate);
+ // Activate handle
+ handle->callback(handle, FuriHalI2cBusHandleEventActivate);
+}
+
+void furi_hal_i2c_release(FuriHalI2cBusHandle* handle) {
+ // Ensure that current handle is our handle
+ furi_check(handle->bus->current_handle == handle);
+ // Deactivate handle
+ handle->callback(handle, FuriHalI2cBusHandleEventDeactivate);
+ // Deactivate bus
+ handle->bus->callback(handle->bus, FuriHalI2cBusEventDeactivate);
+ // Reset current handle
+ handle->bus->current_handle = NULL;
+ // Unlock bus
+ handle->bus->callback(handle->bus, FuriHalI2cBusEventUnlock);
+}
+
bool furi_hal_i2c_tx(
- I2C_TypeDef* instance,
+ FuriHalI2cBusHandle* handle,
uint8_t address,
const uint8_t* data,
uint8_t size,
uint32_t timeout) {
+ furi_check(handle->bus->current_handle == handle);
uint32_t time_left = timeout;
bool ret = true;
- while(LL_I2C_IsActiveFlag_BUSY(instance))
+ while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
;
LL_I2C_HandleTransfer(
- instance,
+ handle->bus->i2c,
address,
LL_I2C_ADDRSLAVE_7BIT,
size,
LL_I2C_MODE_AUTOEND,
LL_I2C_GENERATE_START_WRITE);
- while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
- if(LL_I2C_IsActiveFlag_TXIS(instance)) {
- LL_I2C_TransmitData8(instance, (*data));
+ while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
+ if(LL_I2C_IsActiveFlag_TXIS(handle->bus->i2c)) {
+ LL_I2C_TransmitData8(handle->bus->i2c, (*data));
data++;
size--;
time_left = timeout;
@@ -83,34 +77,35 @@ bool furi_hal_i2c_tx(
}
}
- LL_I2C_ClearFlag_STOP(instance);
+ LL_I2C_ClearFlag_STOP(handle->bus->i2c);
return ret;
}
bool furi_hal_i2c_rx(
- I2C_TypeDef* instance,
+ FuriHalI2cBusHandle* handle,
uint8_t address,
uint8_t* data,
uint8_t size,
uint32_t timeout) {
+ furi_check(handle->bus->current_handle == handle);
uint32_t time_left = timeout;
bool ret = true;
- while(LL_I2C_IsActiveFlag_BUSY(instance))
+ while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
;
LL_I2C_HandleTransfer(
- instance,
+ handle->bus->i2c,
address,
LL_I2C_ADDRSLAVE_7BIT,
size,
LL_I2C_MODE_AUTOEND,
LL_I2C_GENERATE_START_READ);
- while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
- if(LL_I2C_IsActiveFlag_RXNE(instance)) {
- *data = LL_I2C_ReceiveData8(instance);
+ while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
+ if(LL_I2C_IsActiveFlag_RXNE(handle->bus->i2c)) {
+ *data = LL_I2C_ReceiveData8(handle->bus->i2c);
data++;
size--;
time_left = timeout;
@@ -124,31 +119,23 @@ bool furi_hal_i2c_rx(
}
}
- LL_I2C_ClearFlag_STOP(instance);
+ LL_I2C_ClearFlag_STOP(handle->bus->i2c);
return ret;
}
bool furi_hal_i2c_trx(
- I2C_TypeDef* instance,
+ FuriHalI2cBusHandle* handle,
uint8_t address,
const uint8_t* tx_data,
uint8_t tx_size,
uint8_t* rx_data,
uint8_t rx_size,
uint32_t timeout) {
- if(furi_hal_i2c_tx(instance, address, tx_data, tx_size, timeout) &&
- furi_hal_i2c_rx(instance, address, rx_data, rx_size, timeout)) {
+ if(furi_hal_i2c_tx(handle, address, tx_data, tx_size, timeout) &&
+ furi_hal_i2c_rx(handle, address, rx_data, rx_size, timeout)) {
return true;
} else {
return false;
}
}
-
-void furi_hal_i2c_lock() {
- furi_check(osMutexAcquire(furi_hal_i2c_mutex, osWaitForever) == osOK);
-}
-
-void furi_hal_i2c_unlock() {
- furi_check(osMutexRelease(furi_hal_i2c_mutex) == osOK);
-}
diff --git a/firmware/targets/f6/furi-hal/furi-hal-light.c b/firmware/targets/f6/furi-hal/furi-hal-light.c
index ecf0d4f2..15a69f09 100644
--- a/firmware/targets/f6/furi-hal/furi-hal-light.c
+++ b/firmware/targets/f6/furi-hal/furi-hal-light.c
@@ -1,46 +1,49 @@
#include <furi-hal-light.h>
#include <lp5562.h>
-#define TAG "FuriHalLight"
-
-#define LED_CURRENT_RED 50
-#define LED_CURRENT_GREEN 50
-#define LED_CURRENT_BLUE 50
-#define LED_CURRENT_WHITE 150
+#define LED_CURRENT_RED 50
+#define LED_CURRENT_GREEN 50
+#define LED_CURRENT_BLUE 50
+#define LED_CURRENT_WHITE 150
void furi_hal_light_init() {
- lp5562_reset();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+
+ lp5562_reset(&furi_hal_i2c_handle_power);
+
+ lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelRed, LED_CURRENT_RED);
+ lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelGreen, LED_CURRENT_GREEN);
+ lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelBlue, LED_CURRENT_BLUE);
+ lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelWhite, LED_CURRENT_WHITE);
- lp5562_set_channel_current(LP5562ChannelRed, LED_CURRENT_RED);
- lp5562_set_channel_current(LP5562ChannelGreen, LED_CURRENT_GREEN);
- lp5562_set_channel_current(LP5562ChannelBlue, LED_CURRENT_BLUE);
- lp5562_set_channel_current(LP5562ChannelWhite, LED_CURRENT_WHITE);
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, 0x00);
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, 0x00);
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, 0x00);
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, 0x00);
- lp5562_set_channel_value(LP5562ChannelRed, 0x00);
- lp5562_set_channel_value(LP5562ChannelGreen, 0x00);
- lp5562_set_channel_value(LP5562ChannelBlue, 0x00);
- lp5562_set_channel_value(LP5562ChannelWhite, 0x00);
+ lp5562_enable(&furi_hal_i2c_handle_power);
+ lp5562_configure(&furi_hal_i2c_handle_power);
- lp5562_enable();
- lp5562_configure();
- FURI_LOG_I(TAG, "Init OK");
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
}
void furi_hal_light_set(Light light, uint8_t value) {
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
switch(light) {
- case LightRed:
- lp5562_set_channel_value(LP5562ChannelRed, value);
+ case LightRed:
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value);
break;
- case LightGreen:
- lp5562_set_channel_value(LP5562ChannelGreen, value);
+ case LightGreen:
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value);
break;
- case LightBlue:
- lp5562_set_channel_value(LP5562ChannelBlue, value);
+ case LightBlue:
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value);
break;
- case LightBacklight:
- lp5562_set_channel_value(LP5562ChannelWhite, value);
+ case LightBacklight:
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, value);
break;
- default:
+ default:
break;
}
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
} \ No newline at end of file
diff --git a/firmware/targets/f6/furi-hal/furi-hal-power.c b/firmware/targets/f6/furi-hal/furi-hal-power.c
index 870cbda6..ad333b5d 100644
--- a/firmware/targets/f6/furi-hal/furi-hal-power.c
+++ b/firmware/targets/f6/furi-hal/furi-hal-power.c
@@ -74,8 +74,12 @@ void HAL_RCC_CSSCallback(void) {
void furi_hal_power_init() {
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
LL_PWR_SMPS_SetMode(LL_PWR_SMPS_STEP_DOWN);
- bq27220_init(&cedv);
- bq25896_init();
+
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ bq27220_init(&furi_hal_i2c_handle_power, &cedv);
+ bq25896_init(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
+
FURI_LOG_I(TAG, "Init OK");
}
@@ -161,19 +165,30 @@ void furi_hal_power_sleep() {
uint8_t furi_hal_power_get_pct() {
- return bq27220_get_state_of_charge();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ uint8_t ret = bq27220_get_state_of_charge(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
+ return ret;
}
uint8_t furi_hal_power_get_bat_health_pct() {
- return bq27220_get_state_of_health();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ uint8_t ret = bq27220_get_state_of_health(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
+ return ret;
}
bool furi_hal_power_is_charging() {
- return bq25896_is_charging();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ bool ret = bq25896_is_charging(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
+ return ret;
}
void furi_hal_power_off() {
- bq25896_poweroff();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ bq25896_poweroff(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
}
void furi_hal_power_reset() {
@@ -181,66 +196,102 @@ void furi_hal_power_reset() {
}
void furi_hal_power_enable_otg() {
- bq25896_enable_otg();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ bq25896_enable_otg(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
}
void furi_hal_power_disable_otg() {
- bq25896_disable_otg();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ bq25896_disable_otg(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
}
bool furi_hal_power_is_otg_enabled() {
- return bq25896_is_otg_enabled();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ bool ret = bq25896_is_otg_enabled(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
+ return ret;
}
uint32_t furi_hal_power_get_battery_remaining_capacity() {
- return bq27220_get_remaining_capacity();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ uint32_t ret = bq27220_get_remaining_capacity(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
+ return ret;
}
uint32_t furi_hal_power_get_battery_full_capacity() {
- return bq27220_get_full_charge_capacity();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ uint32_t ret = bq27220_get_full_charge_capacity(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
+ return ret;
}
float furi_hal_power_get_battery_voltage(FuriHalPowerIC ic) {
+ float ret = 0.0f;
+
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
if (ic == FuriHalPowerICCharger) {
- return (float)bq25896_get_vbat_voltage() / 1000.0f;
+ ret = (float)bq25896_get_vbat_voltage(&furi_hal_i2c_handle_power) / 1000.0f;
} else if (ic == FuriHalPowerICFuelGauge) {
- return (float)bq27220_get_voltage() / 1000.0f;
- } else {
- return 0.0f;
+ ret = (float)bq27220_get_voltage(&furi_hal_i2c_handle_power) / 1000.0f;
}
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
+
+ return ret;
}
float furi_hal_power_get_battery_current(FuriHalPowerIC ic) {
+ float ret = 0.0f;
+
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
if (ic == FuriHalPowerICCharger) {
- return (float)bq25896_get_vbat_current() / 1000.0f;
+ ret = (float)bq25896_get_vbat_current(&furi_hal_i2c_handle_power) / 1000.0f;
} else if (ic == FuriHalPowerICFuelGauge) {
- return (float)bq27220_get_current() / 1000.0f;
- } else {
- return 0.0f;
- }
+ ret = (float)bq27220_get_current(&furi_hal_i2c_handle_power) / 1000.0f;
+ }
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
+
+ return ret;
}
-float furi_hal_power_get_battery_temperature(FuriHalPowerIC ic) {
+static float furi_hal_power_get_battery_temperature_internal(FuriHalPowerIC ic) {
+ float ret = 0.0f;
+
if (ic == FuriHalPowerICCharger) {
// Linear approximation, +/- 5 C
- return (71.0f - (float)bq25896_get_ntc_mpct()/1000) / 0.6f;
+ ret = (71.0f - (float)bq25896_get_ntc_mpct(&furi_hal_i2c_handle_power)/1000) / 0.6f;
} else if (ic == FuriHalPowerICFuelGauge) {
- return ((float)bq27220_get_temperature() - 2731.0f) / 10.0f;
- } else {
- return 0.0f;
+ 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) {
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ float ret = furi_hal_power_get_battery_temperature_internal(ic);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
+
+ return ret;
}
float furi_hal_power_get_usb_voltage(){
- return (float)bq25896_get_vbus_voltage() / 1000.0f;
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ float ret = (float)bq25896_get_vbus_voltage(&furi_hal_i2c_handle_power) / 1000.0f;
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
+ return ret;
}
void furi_hal_power_dump_state() {
BatteryStatus battery_status;
OperationStatus operation_status;
- if (bq27220_get_battery_status(&battery_status) == BQ27220_ERROR
- || bq27220_get_operation_status(&operation_status) == BQ27220_ERROR) {
+
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+
+ if (bq27220_get_battery_status(&furi_hal_i2c_handle_power, &battery_status) == BQ27220_ERROR
+ || bq27220_get_operation_status(&furi_hal_i2c_handle_power, &operation_status) == BQ27220_ERROR) {
printf("Failed to get bq27220 status. Communication error.\r\n");
} else {
printf(
@@ -266,21 +317,23 @@ void furi_hal_power_dump_state() {
// Voltage and current info
printf(
"bq27220: Full capacity: %dmAh, Design capacity: %dmAh, Remaining capacity: %dmAh, State of Charge: %d%%, State of health: %d%%\r\n",
- bq27220_get_full_charge_capacity(), bq27220_get_design_capacity(), bq27220_get_remaining_capacity(),
- bq27220_get_state_of_charge(), bq27220_get_state_of_health()
+ bq27220_get_full_charge_capacity(&furi_hal_i2c_handle_power), bq27220_get_design_capacity(&furi_hal_i2c_handle_power), bq27220_get_remaining_capacity(&furi_hal_i2c_handle_power),
+ bq27220_get_state_of_charge(&furi_hal_i2c_handle_power), bq27220_get_state_of_health(&furi_hal_i2c_handle_power)
);
printf(
"bq27220: Voltage: %dmV, Current: %dmA, Temperature: %dC\r\n",
- bq27220_get_voltage(), bq27220_get_current(), (int)furi_hal_power_get_battery_temperature(FuriHalPowerICFuelGauge)
+ bq27220_get_voltage(&furi_hal_i2c_handle_power), bq27220_get_current(&furi_hal_i2c_handle_power), (int)furi_hal_power_get_battery_temperature_internal(FuriHalPowerICFuelGauge)
);
}
printf(
"bq25896: VBUS: %d, VSYS: %d, VBAT: %d, Current: %d, NTC: %ldm%%\r\n",
- bq25896_get_vbus_voltage(), bq25896_get_vsys_voltage(),
- bq25896_get_vbat_voltage(), bq25896_get_vbat_current(),
- bq25896_get_ntc_mpct()
+ bq25896_get_vbus_voltage(&furi_hal_i2c_handle_power), bq25896_get_vsys_voltage(&furi_hal_i2c_handle_power),
+ bq25896_get_vbat_voltage(&furi_hal_i2c_handle_power), bq25896_get_vbat_current(&furi_hal_i2c_handle_power),
+ bq25896_get_ntc_mpct(&furi_hal_i2c_handle_power)
);
+
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
}
void furi_hal_power_enable_external_3_3v(){
@@ -298,7 +351,9 @@ void furi_hal_power_suppress_charge_enter() {
xTaskResumeAll();
if (disable_charging) {
- bq25896_disable_charging();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ bq25896_disable_charging(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
}
}
@@ -309,6 +364,8 @@ void furi_hal_power_suppress_charge_exit() {
xTaskResumeAll();
if (enable_charging) {
- bq25896_enable_charging();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ bq25896_enable_charging(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
}
} \ No newline at end of file
diff --git a/firmware/targets/f6/furi-hal/furi-hal-resources.c b/firmware/targets/f6/furi-hal/furi-hal-resources.c
index 6d7f8a0b..21f6f3fa 100644
--- a/firmware/targets/f6/furi-hal/furi-hal-resources.c
+++ b/firmware/targets/f6/furi-hal/furi-hal-resources.c
@@ -54,3 +54,6 @@ const GpioPin gpio_irda_tx = {.port = IR_TX_GPIO_Port, .pin = IR_TX_Pin};
const GpioPin gpio_usart_tx = {.port = USART1_TX_Port, .pin = USART1_TX_Pin};
const GpioPin gpio_usart_rx = {.port = USART1_RX_Port, .pin = USART1_RX_Pin};
+
+const GpioPin gpio_i2c_power_sda = {.port = GPIOA, .pin = LL_GPIO_PIN_10};
+const GpioPin gpio_i2c_power_scl = {.port = GPIOA, .pin = LL_GPIO_PIN_9};
diff --git a/firmware/targets/f6/furi-hal/furi-hal-resources.h b/firmware/targets/f6/furi-hal/furi-hal-resources.h
index bec183ef..feec0451 100644
--- a/firmware/targets/f6/furi-hal/furi-hal-resources.h
+++ b/firmware/targets/f6/furi-hal/furi-hal-resources.h
@@ -10,24 +10,6 @@
extern "C" {
#endif
-#define POWER_I2C_SCL_Pin LL_GPIO_PIN_9
-#define POWER_I2C_SCL_GPIO_Port GPIOA
-#define POWER_I2C_SDA_Pin LL_GPIO_PIN_10
-#define POWER_I2C_SDA_GPIO_Port GPIOA
-
-#define POWER_I2C I2C1
-/** Timing register value is computed with the STM32CubeMX Tool,
- * Standard Mode @100kHz with I2CCLK = 64 MHz,
- * rise time = 0ns, fall time = 0ns
- */
-#define POWER_I2C_TIMINGS_100 0x10707DBC
-
-/** Timing register value is computed with the STM32CubeMX Tool,
- * Fast Mode @400kHz with I2CCLK = 64 MHz,
- * rise time = 0ns, fall time = 0ns
- */
-#define POWER_I2C_TIMINGS_400 0x00602173
-
/* Input Related Constants */
#define INPUT_DEBOUNCE_TICKS 20
@@ -98,6 +80,9 @@ extern const GpioPin gpio_irda_tx;
extern const GpioPin gpio_usart_tx;
extern const GpioPin gpio_usart_rx;
+extern const GpioPin gpio_i2c_power_sda;
+extern const GpioPin gpio_i2c_power_scl;
+
#ifdef __cplusplus
}
diff --git a/firmware/targets/f6/furi-hal/furi-hal-vcp.c b/firmware/targets/f6/furi-hal/furi-hal-vcp.c
index ce3cda49..05033817 100644
--- a/firmware/targets/f6/furi-hal/furi-hal-vcp.c
+++ b/firmware/targets/f6/furi-hal/furi-hal-vcp.c
@@ -280,7 +280,7 @@ static void vcp_on_cdc_control_line(void* context, uint8_t state) {
static void vcp_on_cdc_rx(void* context) {
uint32_t ret = osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtRx);
- furi_assert((ret & osFlagsError) == 0);
+ furi_check((ret & osFlagsError) == 0);
}
static void vcp_on_cdc_tx_complete(void* context) {
diff --git a/firmware/targets/f7/furi-hal/furi-hal-i2c-config.c b/firmware/targets/f7/furi-hal/furi-hal-i2c-config.c
new file mode 100644
index 00000000..273d46b1
--- /dev/null
+++ b/firmware/targets/f7/furi-hal/furi-hal-i2c-config.c
@@ -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,
+};
diff --git a/firmware/targets/f7/furi-hal/furi-hal-i2c-config.h b/firmware/targets/f7/furi-hal/furi-hal-i2c-config.h
new file mode 100644
index 00000000..2094dca3
--- /dev/null
+++ b/firmware/targets/f7/furi-hal/furi-hal-i2c-config.h
@@ -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 \ No newline at end of file
diff --git a/firmware/targets/f7/furi-hal/furi-hal-i2c-types.h b/firmware/targets/f7/furi-hal/furi-hal-i2c-types.h
new file mode 100644
index 00000000..4f7aab91
--- /dev/null
+++ b/firmware/targets/f7/furi-hal/furi-hal-i2c-types.h
@@ -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 \ No newline at end of file
diff --git a/firmware/targets/f7/furi-hal/furi-hal-i2c.c b/firmware/targets/f7/furi-hal/furi-hal-i2c.c
index b1ec4711..2fd5c5e3 100644
--- a/firmware/targets/f7/furi-hal/furi-hal-i2c.c
+++ b/firmware/targets/f7/furi-hal/furi-hal-i2c.c
@@ -8,68 +8,62 @@
#define TAG "FuriHalI2C"
-osMutexId_t furi_hal_i2c_mutex = NULL;
-
void furi_hal_i2c_init() {
- furi_hal_i2c_mutex = osMutexNew(NULL);
- furi_check(furi_hal_i2c_mutex);
-
- LL_I2C_InitTypeDef I2C_InitStruct = {0};
- LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
-
- LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);
-
- GPIO_InitStruct.Pin = POWER_I2C_SCL_Pin | POWER_I2C_SDA_Pin;
- GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
- GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
- GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
- GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
- GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
- LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
-
- I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
- I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
- I2C_InitStruct.DigitalFilter = 0;
- I2C_InitStruct.OwnAddress1 = 0;
- I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
- I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
- if (furi_hal_version_get_hw_version() > 10) {
- I2C_InitStruct.Timing = POWER_I2C_TIMINGS_400;
- } else {
- I2C_InitStruct.Timing = POWER_I2C_TIMINGS_100;
- }
- LL_I2C_Init(POWER_I2C, &I2C_InitStruct);
- LL_I2C_EnableAutoEndMode(POWER_I2C);
- LL_I2C_SetOwnAddress2(POWER_I2C, 0, LL_I2C_OWNADDRESS2_NOMASK);
- LL_I2C_DisableOwnAddress2(POWER_I2C);
- LL_I2C_DisableGeneralCall(POWER_I2C);
- LL_I2C_EnableClockStretching(POWER_I2C);
+ furi_hal_i2c_bus_power.callback(&furi_hal_i2c_bus_power, FuriHalI2cBusEventInit);
+ furi_hal_i2c_bus_external.callback(&furi_hal_i2c_bus_external, FuriHalI2cBusEventInit);
FURI_LOG_I(TAG, "Init OK");
}
+void furi_hal_i2c_acquire(FuriHalI2cBusHandle* handle) {
+ // Lock bus access
+ handle->bus->callback(handle->bus, FuriHalI2cBusEventLock);
+ // Ensuree that no active handle set
+ furi_check(handle->bus->current_handle == NULL);
+ // Set current handle
+ handle->bus->current_handle = handle;
+ // Activate bus
+ handle->bus->callback(handle->bus, FuriHalI2cBusEventActivate);
+ // Activate handle
+ handle->callback(handle, FuriHalI2cBusHandleEventActivate);
+}
+
+void furi_hal_i2c_release(FuriHalI2cBusHandle* handle) {
+ // Ensure that current handle is our handle
+ furi_check(handle->bus->current_handle == handle);
+ // Deactivate handle
+ handle->callback(handle, FuriHalI2cBusHandleEventDeactivate);
+ // Deactivate bus
+ handle->bus->callback(handle->bus, FuriHalI2cBusEventDeactivate);
+ // Reset current handle
+ handle->bus->current_handle = NULL;
+ // Unlock bus
+ handle->bus->callback(handle->bus, FuriHalI2cBusEventUnlock);
+}
+
bool furi_hal_i2c_tx(
- I2C_TypeDef* instance,
+ FuriHalI2cBusHandle* handle,
uint8_t address,
const uint8_t* data,
uint8_t size,
uint32_t timeout) {
+ furi_check(handle->bus->current_handle == handle);
uint32_t time_left = timeout;
bool ret = true;
- while(LL_I2C_IsActiveFlag_BUSY(instance))
+ while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
;
LL_I2C_HandleTransfer(
- instance,
+ handle->bus->i2c,
address,
LL_I2C_ADDRSLAVE_7BIT,
size,
LL_I2C_MODE_AUTOEND,
LL_I2C_GENERATE_START_WRITE);
- while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
- if(LL_I2C_IsActiveFlag_TXIS(instance)) {
- LL_I2C_TransmitData8(instance, (*data));
+ while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
+ if(LL_I2C_IsActiveFlag_TXIS(handle->bus->i2c)) {
+ LL_I2C_TransmitData8(handle->bus->i2c, (*data));
data++;
size--;
time_left = timeout;
@@ -83,34 +77,35 @@ bool furi_hal_i2c_tx(
}
}
- LL_I2C_ClearFlag_STOP(instance);
+ LL_I2C_ClearFlag_STOP(handle->bus->i2c);
return ret;
}
bool furi_hal_i2c_rx(
- I2C_TypeDef* instance,
+ FuriHalI2cBusHandle* handle,
uint8_t address,
uint8_t* data,
uint8_t size,
uint32_t timeout) {
+ furi_check(handle->bus->current_handle == handle);
uint32_t time_left = timeout;
bool ret = true;
- while(LL_I2C_IsActiveFlag_BUSY(instance))
+ while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c))
;
LL_I2C_HandleTransfer(
- instance,
+ handle->bus->i2c,
address,
LL_I2C_ADDRSLAVE_7BIT,
size,
LL_I2C_MODE_AUTOEND,
LL_I2C_GENERATE_START_READ);
- while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) {
- if(LL_I2C_IsActiveFlag_RXNE(instance)) {
- *data = LL_I2C_ReceiveData8(instance);
+ while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) {
+ if(LL_I2C_IsActiveFlag_RXNE(handle->bus->i2c)) {
+ *data = LL_I2C_ReceiveData8(handle->bus->i2c);
data++;
size--;
time_left = timeout;
@@ -124,31 +119,23 @@ bool furi_hal_i2c_rx(
}
}
- LL_I2C_ClearFlag_STOP(instance);
+ LL_I2C_ClearFlag_STOP(handle->bus->i2c);
return ret;
}
bool furi_hal_i2c_trx(
- I2C_TypeDef* instance,
+ FuriHalI2cBusHandle* handle,
uint8_t address,
const uint8_t* tx_data,
uint8_t tx_size,
uint8_t* rx_data,
uint8_t rx_size,
uint32_t timeout) {
- if(furi_hal_i2c_tx(instance, address, tx_data, tx_size, timeout) &&
- furi_hal_i2c_rx(instance, address, rx_data, rx_size, timeout)) {
+ if(furi_hal_i2c_tx(handle, address, tx_data, tx_size, timeout) &&
+ furi_hal_i2c_rx(handle, address, rx_data, rx_size, timeout)) {
return true;
} else {
return false;
}
}
-
-void furi_hal_i2c_lock() {
- furi_check(osMutexAcquire(furi_hal_i2c_mutex, osWaitForever) == osOK);
-}
-
-void furi_hal_i2c_unlock() {
- furi_check(osMutexRelease(furi_hal_i2c_mutex) == osOK);
-}
diff --git a/firmware/targets/f7/furi-hal/furi-hal-light.c b/firmware/targets/f7/furi-hal/furi-hal-light.c
index ecf0d4f2..15a69f09 100644
--- a/firmware/targets/f7/furi-hal/furi-hal-light.c
+++ b/firmware/targets/f7/furi-hal/furi-hal-light.c
@@ -1,46 +1,49 @@
#include <furi-hal-light.h>
#include <lp5562.h>
-#define TAG "FuriHalLight"
-
-#define LED_CURRENT_RED 50
-#define LED_CURRENT_GREEN 50
-#define LED_CURRENT_BLUE 50
-#define LED_CURRENT_WHITE 150
+#define LED_CURRENT_RED 50
+#define LED_CURRENT_GREEN 50
+#define LED_CURRENT_BLUE 50
+#define LED_CURRENT_WHITE 150
void furi_hal_light_init() {
- lp5562_reset();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+
+ lp5562_reset(&furi_hal_i2c_handle_power);
+
+ lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelRed, LED_CURRENT_RED);
+ lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelGreen, LED_CURRENT_GREEN);
+ lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelBlue, LED_CURRENT_BLUE);
+ lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelWhite, LED_CURRENT_WHITE);
- lp5562_set_channel_current(LP5562ChannelRed, LED_CURRENT_RED);
- lp5562_set_channel_current(LP5562ChannelGreen, LED_CURRENT_GREEN);
- lp5562_set_channel_current(LP5562ChannelBlue, LED_CURRENT_BLUE);
- lp5562_set_channel_current(LP5562ChannelWhite, LED_CURRENT_WHITE);
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, 0x00);
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, 0x00);
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, 0x00);
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, 0x00);
- lp5562_set_channel_value(LP5562ChannelRed, 0x00);
- lp5562_set_channel_value(LP5562ChannelGreen, 0x00);
- lp5562_set_channel_value(LP5562ChannelBlue, 0x00);
- lp5562_set_channel_value(LP5562ChannelWhite, 0x00);
+ lp5562_enable(&furi_hal_i2c_handle_power);
+ lp5562_configure(&furi_hal_i2c_handle_power);
- lp5562_enable();
- lp5562_configure();
- FURI_LOG_I(TAG, "Init OK");
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
}
void furi_hal_light_set(Light light, uint8_t value) {
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
switch(light) {
- case LightRed:
- lp5562_set_channel_value(LP5562ChannelRed, value);
+ case LightRed:
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value);
break;
- case LightGreen:
- lp5562_set_channel_value(LP5562ChannelGreen, value);
+ case LightGreen:
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value);
break;
- case LightBlue:
- lp5562_set_channel_value(LP5562ChannelBlue, value);
+ case LightBlue:
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value);
break;
- case LightBacklight:
- lp5562_set_channel_value(LP5562ChannelWhite, value);
+ case LightBacklight:
+ lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, value);
break;
- default:
+ default:
break;
}
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
} \ No newline at end of file
diff --git a/firmware/targets/f7/furi-hal/furi-hal-power.c b/firmware/targets/f7/furi-hal/furi-hal-power.c
index 870cbda6..ad333b5d 100644
--- a/firmware/targets/f7/furi-hal/furi-hal-power.c
+++ b/firmware/targets/f7/furi-hal/furi-hal-power.c
@@ -74,8 +74,12 @@ void HAL_RCC_CSSCallback(void) {
void furi_hal_power_init() {
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
LL_PWR_SMPS_SetMode(LL_PWR_SMPS_STEP_DOWN);
- bq27220_init(&cedv);
- bq25896_init();
+
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ bq27220_init(&furi_hal_i2c_handle_power, &cedv);
+ bq25896_init(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
+
FURI_LOG_I(TAG, "Init OK");
}
@@ -161,19 +165,30 @@ void furi_hal_power_sleep() {
uint8_t furi_hal_power_get_pct() {
- return bq27220_get_state_of_charge();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ uint8_t ret = bq27220_get_state_of_charge(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
+ return ret;
}
uint8_t furi_hal_power_get_bat_health_pct() {
- return bq27220_get_state_of_health();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ uint8_t ret = bq27220_get_state_of_health(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
+ return ret;
}
bool furi_hal_power_is_charging() {
- return bq25896_is_charging();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ bool ret = bq25896_is_charging(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
+ return ret;
}
void furi_hal_power_off() {
- bq25896_poweroff();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ bq25896_poweroff(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
}
void furi_hal_power_reset() {
@@ -181,66 +196,102 @@ void furi_hal_power_reset() {
}
void furi_hal_power_enable_otg() {
- bq25896_enable_otg();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ bq25896_enable_otg(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
}
void furi_hal_power_disable_otg() {
- bq25896_disable_otg();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ bq25896_disable_otg(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
}
bool furi_hal_power_is_otg_enabled() {
- return bq25896_is_otg_enabled();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ bool ret = bq25896_is_otg_enabled(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
+ return ret;
}
uint32_t furi_hal_power_get_battery_remaining_capacity() {
- return bq27220_get_remaining_capacity();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ uint32_t ret = bq27220_get_remaining_capacity(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
+ return ret;
}
uint32_t furi_hal_power_get_battery_full_capacity() {
- return bq27220_get_full_charge_capacity();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ uint32_t ret = bq27220_get_full_charge_capacity(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
+ return ret;
}
float furi_hal_power_get_battery_voltage(FuriHalPowerIC ic) {
+ float ret = 0.0f;
+
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
if (ic == FuriHalPowerICCharger) {
- return (float)bq25896_get_vbat_voltage() / 1000.0f;
+ ret = (float)bq25896_get_vbat_voltage(&furi_hal_i2c_handle_power) / 1000.0f;
} else if (ic == FuriHalPowerICFuelGauge) {
- return (float)bq27220_get_voltage() / 1000.0f;
- } else {
- return 0.0f;
+ ret = (float)bq27220_get_voltage(&furi_hal_i2c_handle_power) / 1000.0f;
}
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
+
+ return ret;
}
float furi_hal_power_get_battery_current(FuriHalPowerIC ic) {
+ float ret = 0.0f;
+
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
if (ic == FuriHalPowerICCharger) {
- return (float)bq25896_get_vbat_current() / 1000.0f;
+ ret = (float)bq25896_get_vbat_current(&furi_hal_i2c_handle_power) / 1000.0f;
} else if (ic == FuriHalPowerICFuelGauge) {
- return (float)bq27220_get_current() / 1000.0f;
- } else {
- return 0.0f;
- }
+ ret = (float)bq27220_get_current(&furi_hal_i2c_handle_power) / 1000.0f;
+ }
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
+
+ return ret;
}
-float furi_hal_power_get_battery_temperature(FuriHalPowerIC ic) {
+static float furi_hal_power_get_battery_temperature_internal(FuriHalPowerIC ic) {
+ float ret = 0.0f;
+
if (ic == FuriHalPowerICCharger) {
// Linear approximation, +/- 5 C
- return (71.0f - (float)bq25896_get_ntc_mpct()/1000) / 0.6f;
+ ret = (71.0f - (float)bq25896_get_ntc_mpct(&furi_hal_i2c_handle_power)/1000) / 0.6f;
} else if (ic == FuriHalPowerICFuelGauge) {
- return ((float)bq27220_get_temperature() - 2731.0f) / 10.0f;
- } else {
- return 0.0f;
+ 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) {
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ float ret = furi_hal_power_get_battery_temperature_internal(ic);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
+
+ return ret;
}
float furi_hal_power_get_usb_voltage(){
- return (float)bq25896_get_vbus_voltage() / 1000.0f;
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ float ret = (float)bq25896_get_vbus_voltage(&furi_hal_i2c_handle_power) / 1000.0f;
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
+ return ret;
}
void furi_hal_power_dump_state() {
BatteryStatus battery_status;
OperationStatus operation_status;
- if (bq27220_get_battery_status(&battery_status) == BQ27220_ERROR
- || bq27220_get_operation_status(&operation_status) == BQ27220_ERROR) {
+
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+
+ if (bq27220_get_battery_status(&furi_hal_i2c_handle_power, &battery_status) == BQ27220_ERROR
+ || bq27220_get_operation_status(&furi_hal_i2c_handle_power, &operation_status) == BQ27220_ERROR) {
printf("Failed to get bq27220 status. Communication error.\r\n");
} else {
printf(
@@ -266,21 +317,23 @@ void furi_hal_power_dump_state() {
// Voltage and current info
printf(
"bq27220: Full capacity: %dmAh, Design capacity: %dmAh, Remaining capacity: %dmAh, State of Charge: %d%%, State of health: %d%%\r\n",
- bq27220_get_full_charge_capacity(), bq27220_get_design_capacity(), bq27220_get_remaining_capacity(),
- bq27220_get_state_of_charge(), bq27220_get_state_of_health()
+ bq27220_get_full_charge_capacity(&furi_hal_i2c_handle_power), bq27220_get_design_capacity(&furi_hal_i2c_handle_power), bq27220_get_remaining_capacity(&furi_hal_i2c_handle_power),
+ bq27220_get_state_of_charge(&furi_hal_i2c_handle_power), bq27220_get_state_of_health(&furi_hal_i2c_handle_power)
);
printf(
"bq27220: Voltage: %dmV, Current: %dmA, Temperature: %dC\r\n",
- bq27220_get_voltage(), bq27220_get_current(), (int)furi_hal_power_get_battery_temperature(FuriHalPowerICFuelGauge)
+ bq27220_get_voltage(&furi_hal_i2c_handle_power), bq27220_get_current(&furi_hal_i2c_handle_power), (int)furi_hal_power_get_battery_temperature_internal(FuriHalPowerICFuelGauge)
);
}
printf(
"bq25896: VBUS: %d, VSYS: %d, VBAT: %d, Current: %d, NTC: %ldm%%\r\n",
- bq25896_get_vbus_voltage(), bq25896_get_vsys_voltage(),
- bq25896_get_vbat_voltage(), bq25896_get_vbat_current(),
- bq25896_get_ntc_mpct()
+ bq25896_get_vbus_voltage(&furi_hal_i2c_handle_power), bq25896_get_vsys_voltage(&furi_hal_i2c_handle_power),
+ bq25896_get_vbat_voltage(&furi_hal_i2c_handle_power), bq25896_get_vbat_current(&furi_hal_i2c_handle_power),
+ bq25896_get_ntc_mpct(&furi_hal_i2c_handle_power)
);
+
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
}
void furi_hal_power_enable_external_3_3v(){
@@ -298,7 +351,9 @@ void furi_hal_power_suppress_charge_enter() {
xTaskResumeAll();
if (disable_charging) {
- bq25896_disable_charging();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ bq25896_disable_charging(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
}
}
@@ -309,6 +364,8 @@ void furi_hal_power_suppress_charge_exit() {
xTaskResumeAll();
if (enable_charging) {
- bq25896_enable_charging();
+ furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
+ bq25896_enable_charging(&furi_hal_i2c_handle_power);
+ furi_hal_i2c_release(&furi_hal_i2c_handle_power);
}
} \ No newline at end of file
diff --git a/firmware/targets/f7/furi-hal/furi-hal-resources.c b/firmware/targets/f7/furi-hal/furi-hal-resources.c
index 52ea3cf7..3f7fe36c 100644
--- a/firmware/targets/f7/furi-hal/furi-hal-resources.c
+++ b/firmware/targets/f7/furi-hal/furi-hal-resources.c
@@ -55,3 +55,6 @@ const GpioPin gpio_irda_tx = {.port = IR_TX_GPIO_Port, .pin = IR_TX_Pin};
const GpioPin gpio_usart_tx = {.port = USART1_TX_Port, .pin = USART1_TX_Pin};
const GpioPin gpio_usart_rx = {.port = USART1_RX_Port, .pin = USART1_RX_Pin};
+
+const GpioPin gpio_i2c_power_sda = {.port = GPIOA, .pin = LL_GPIO_PIN_10};
+const GpioPin gpio_i2c_power_scl = {.port = GPIOA, .pin = LL_GPIO_PIN_9};
diff --git a/firmware/targets/f7/furi-hal/furi-hal-resources.h b/firmware/targets/f7/furi-hal/furi-hal-resources.h
index 09af7532..aed61372 100644
--- a/firmware/targets/f7/furi-hal/furi-hal-resources.h
+++ b/firmware/targets/f7/furi-hal/furi-hal-resources.h
@@ -10,24 +10,6 @@
extern "C" {
#endif
-#define POWER_I2C_SCL_Pin LL_GPIO_PIN_9
-#define POWER_I2C_SCL_GPIO_Port GPIOA
-#define POWER_I2C_SDA_Pin LL_GPIO_PIN_10
-#define POWER_I2C_SDA_GPIO_Port GPIOA
-
-#define POWER_I2C I2C1
-/** Timing register value is computed with the STM32CubeMX Tool,
- * Standard Mode @100kHz with I2CCLK = 64 MHz,
- * rise time = 0ns, fall time = 0ns
- */
-#define POWER_I2C_TIMINGS_100 0x10707DBC
-
-/** Timing register value is computed with the STM32CubeMX Tool,
- * Fast Mode @400kHz with I2CCLK = 64 MHz,
- * rise time = 0ns, fall time = 0ns
- */
-#define POWER_I2C_TIMINGS_400 0x00602173
-
/* Input Related Constants */
#define INPUT_DEBOUNCE_TICKS 20
@@ -99,6 +81,9 @@ extern const GpioPin gpio_irda_tx;
extern const GpioPin gpio_usart_tx;
extern const GpioPin gpio_usart_rx;
+extern const GpioPin gpio_i2c_power_sda;
+extern const GpioPin gpio_i2c_power_scl;
+
#ifdef __cplusplus
}
diff --git a/firmware/targets/f7/furi-hal/furi-hal-spi.h b/firmware/targets/f7/furi-hal/furi-hal-spi.h
deleted file mode 100644
index 638e713a..00000000
--- a/firmware/targets/f7/furi-hal/furi-hal-spi.h
+++ /dev/null
@@ -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 \ No newline at end of file
diff --git a/firmware/targets/f7/furi-hal/furi-hal-vcp.c b/firmware/targets/f7/furi-hal/furi-hal-vcp.c
index ce3cda49..05033817 100644
--- a/firmware/targets/f7/furi-hal/furi-hal-vcp.c
+++ b/firmware/targets/f7/furi-hal/furi-hal-vcp.c
@@ -280,7 +280,7 @@ static void vcp_on_cdc_control_line(void* context, uint8_t state) {
static void vcp_on_cdc_rx(void* context) {
uint32_t ret = osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtRx);
- furi_assert((ret & osFlagsError) == 0);
+ furi_check((ret & osFlagsError) == 0);
}
static void vcp_on_cdc_tx_complete(void* context) {
diff --git a/firmware/targets/furi-hal-include/furi-hal-i2c.h b/firmware/targets/furi-hal-include/furi-hal-i2c.h
index db61aea8..7ef1db44 100644
--- a/firmware/targets/furi-hal-include/furi-hal-i2c.h
+++ b/firmware/targets/furi-hal-include/furi-hal-i2c.h
@@ -7,7 +7,7 @@
#include <stdbool.h>
#include <stdint.h>
-#include <furi-hal-resources.h>
+#include <furi-hal-i2c-config.h>
#ifdef __cplusplus
extern "C" {
@@ -17,18 +17,30 @@ extern "C" {
*/
void furi_hal_i2c_init();
+/** Acquire i2c bus handle
+ *
+ * @return Instance of FuriHalI2cBus
+ */
+void furi_hal_i2c_acquire(FuriHalI2cBusHandle* handle);
+
+/** Release i2c bus handle
+ *
+ * @param bus instance of FuriHalI2cBus aquired in `furi_hal_i2c_acquire`
+ */
+void furi_hal_i2c_release(FuriHalI2cBusHandle* handle);
+
/** Perform I2C tx transfer
*
* @param instance I2C_TypeDef instance
* @param address I2C slave address
* @param data pointer to data buffer
* @param size size of data buffer
- * @param timeout timeout in CPU ticks
+ * @param timeout timeout in ticks
*
* @return true on successful transfer, false otherwise
*/
bool furi_hal_i2c_tx(
- I2C_TypeDef* instance,
+ FuriHalI2cBusHandle* handle,
const uint8_t address,
const uint8_t* data,
const uint8_t size,
@@ -40,12 +52,12 @@ bool furi_hal_i2c_tx(
* @param address I2C slave address
* @param data pointer to data buffer
* @param size size of data buffer
- * @param timeout timeout in CPU ticks
+ * @param timeout timeout in ticks
*
* @return true on successful transfer, false otherwise
*/
bool furi_hal_i2c_rx(
- I2C_TypeDef* instance,
+ FuriHalI2cBusHandle* handle,
const uint8_t address,
uint8_t* data,
const uint8_t size,
@@ -59,12 +71,12 @@ bool furi_hal_i2c_rx(
* @param tx_size size of tx data buffer
* @param rx_data pointer to rx data buffer
* @param rx_size size of rx data buffer
- * @param timeout timeout in CPU ticks
+ * @param timeout timeout in ticks
*
* @return true on successful transfer, false otherwise
*/
bool furi_hal_i2c_trx(
- I2C_TypeDef* instance,
+ FuriHalI2cBusHandle* handle,
const uint8_t address,
const uint8_t* tx_data,
const uint8_t tx_size,
@@ -72,30 +84,6 @@ bool furi_hal_i2c_trx(
const uint8_t rx_size,
uint32_t timeout);
-/** Acquire I2C mutex
- */
-void furi_hal_i2c_lock();
-
-/** Release I2C mutex
- */
-void furi_hal_i2c_unlock();
-
-/** With clause for I2C peripheral
- *
- * @param type type of function_body
- * @param pointer pointer to return of function_body
- * @param function_body a (){} lambda declaration, executed with I2C mutex
- * acquired
- *
- * @return Nothing
- */
-#define with_furi_hal_i2c(type, pointer, function_body) \
- { \
- furi_hal_i2c_lock(); \
- *pointer = ({ type __fn__ function_body __fn__; })(); \
- furi_hal_i2c_unlock(); \
- }
-
#ifdef __cplusplus
}
#endif
diff --git a/firmware/targets/f6/furi-hal/furi-hal-spi.h b/firmware/targets/furi-hal-include/furi-hal-spi.h
index 638e713a..e42dcdc4 100644
--- a/firmware/targets/f6/furi-hal/furi-hal-spi.h
+++ b/firmware/targets/furi-hal-include/furi-hal-spi.h
@@ -25,8 +25,7 @@ void furi_hal_spi_bus_lock(const FuriHalSpiBus* bus);
*/
void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus);
-/**
- * Configure SPI bus
+/** Configure SPI bus
* @param bus - spi bus handler
* @param config - spi configuration structure
*/
diff --git a/lib/drivers/bq25896.c b/lib/drivers/bq25896.c
index 9062653b..3f923b97 100644
--- a/lib/drivers/bq25896.c
+++ b/lib/drivers/bq25896.c
@@ -1,7 +1,6 @@
#include "bq25896.h"
#include "bq25896_reg.h"
-#include <furi-hal-i2c.h>
#include <stddef.h>
uint8_t bit_reverse(uint8_t b) {
@@ -11,29 +10,17 @@ uint8_t bit_reverse(uint8_t b) {
return b;
}
-bool bq25896_read(uint8_t address, uint8_t* data, size_t size) {
- bool ret;
- with_furi_hal_i2c(
- bool, &ret, () {
- return furi_hal_i2c_trx(
- POWER_I2C, BQ25896_ADDRESS, &address, 1, data, size, BQ25896_I2C_TIMEOUT);
- });
- return ret;
+bool bq25896_read(FuriHalI2cBusHandle* handle, uint8_t address, uint8_t* data, size_t size) {
+ return furi_hal_i2c_trx(handle, BQ25896_ADDRESS, &address, 1, data, size, BQ25896_I2C_TIMEOUT);
}
-bool bq25896_read_reg(uint8_t address, uint8_t* data) {
- bq25896_read(address, data, 1);
- return true;
+bool bq25896_read_reg(FuriHalI2cBusHandle* handle, uint8_t address, uint8_t* data) {
+ return bq25896_read(handle, address, data, 1);
}
-bool bq25896_write_reg(uint8_t address, uint8_t* data) {
+bool bq25896_write_reg(FuriHalI2cBusHandle* handle, uint8_t address, uint8_t* data) {
uint8_t buffer[2] = {address, *data};
- bool ret;
- with_furi_hal_i2c(
- bool, &ret, () {
- return furi_hal_i2c_tx(POWER_I2C, BQ25896_ADDRESS, buffer, 2, BQ25896_I2C_TIMEOUT);
- });
- return ret;
+ return furi_hal_i2c_tx(handle, BQ25896_ADDRESS, buffer, 2, BQ25896_I2C_TIMEOUT);
}
typedef struct {
@@ -62,62 +49,62 @@ typedef struct {
static bq25896_regs_t bq25896_regs;
-void bq25896_init() {
+void bq25896_init(FuriHalI2cBusHandle* handle) {
bq25896_regs.r14.REG_RST = 1;
- bq25896_write_reg(0x14, (uint8_t*)&bq25896_regs.r14);
+ bq25896_write_reg(handle, 0x14, (uint8_t*)&bq25896_regs.r14);
// Readout all registers
- bq25896_read(0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs));
+ bq25896_read(handle, 0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs));
// Poll ADC forever
bq25896_regs.r02.CONV_START = 1;
bq25896_regs.r02.CONV_RATE = 1;
- bq25896_write_reg(0x02, (uint8_t*)&bq25896_regs.r02);
+ bq25896_write_reg(handle, 0x02, (uint8_t*)&bq25896_regs.r02);
bq25896_regs.r07.WATCHDOG = WatchdogDisable;
- bq25896_write_reg(0x07, (uint8_t*)&bq25896_regs.r07);
+ bq25896_write_reg(handle, 0x07, (uint8_t*)&bq25896_regs.r07);
- bq25896_read(0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs));
+ bq25896_read(handle, 0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs));
}
-void bq25896_poweroff() {
+void bq25896_poweroff(FuriHalI2cBusHandle* handle) {
bq25896_regs.r09.BATFET_DIS = 1;
- bq25896_write_reg(0x09, (uint8_t*)&bq25896_regs.r09);
+ bq25896_write_reg(handle, 0x09, (uint8_t*)&bq25896_regs.r09);
}
-bool bq25896_is_charging() {
- bq25896_read(0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs));
- bq25896_read_reg(0x0B, (uint8_t*)&bq25896_regs.r0B);
+bool bq25896_is_charging(FuriHalI2cBusHandle* handle) {
+ bq25896_read(handle, 0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs));
+ bq25896_read_reg(handle, 0x0B, (uint8_t*)&bq25896_regs.r0B);
return bq25896_regs.r0B.CHRG_STAT != ChrgStatNo;
}
-void bq25896_enable_charging() {
+void bq25896_enable_charging(FuriHalI2cBusHandle* handle) {
bq25896_regs.r03.CHG_CONFIG = 1;
- bq25896_write_reg(0x03, (uint8_t*)&bq25896_regs.r03);
+ bq25896_write_reg(handle, 0x03, (uint8_t*)&bq25896_regs.r03);
}
-void bq25896_disable_charging() {
+void bq25896_disable_charging(FuriHalI2cBusHandle* handle) {
bq25896_regs.r03.CHG_CONFIG = 0;
- bq25896_write_reg(0x03, (uint8_t*)&bq25896_regs.r03);
+ bq25896_write_reg(handle, 0x03, (uint8_t*)&bq25896_regs.r03);
}
-void bq25896_enable_otg() {
+void bq25896_enable_otg(FuriHalI2cBusHandle* handle) {
bq25896_regs.r03.OTG_CONFIG = 1;
- bq25896_write_reg(0x03, (uint8_t*)&bq25896_regs.r03);
+ bq25896_write_reg(handle, 0x03, (uint8_t*)&bq25896_regs.r03);
}
-void bq25896_disable_otg() {
+void bq25896_disable_otg(FuriHalI2cBusHandle* handle) {
bq25896_regs.r03.OTG_CONFIG = 0;
- bq25896_write_reg(0x03, (uint8_t*)&bq25896_regs.r03);
+ bq25896_write_reg(handle, 0x03, (uint8_t*)&bq25896_regs.r03);
}
-bool bq25896_is_otg_enabled() {
- bq25896_read_reg(0x03, (uint8_t*)&bq25896_regs.r03);
+bool bq25896_is_otg_enabled(FuriHalI2cBusHandle* handle) {
+ bq25896_read_reg(handle, 0x03, (uint8_t*)&bq25896_regs.r03);
return bq25896_regs.r03.OTG_CONFIG;
}
-uint16_t bq25896_get_vbus_voltage() {
- bq25896_read_reg(0x11, (uint8_t*)&bq25896_regs.r11);
+uint16_t bq25896_get_vbus_voltage(FuriHalI2cBusHandle* handle) {
+ bq25896_read_reg(handle, 0x11, (uint8_t*)&bq25896_regs.r11);
if(bq25896_regs.r11.VBUS_GD) {
return (uint16_t)bq25896_regs.r11.VBUSV * 100 + 2600;
} else {
@@ -125,22 +112,22 @@ uint16_t bq25896_get_vbus_voltage() {
}
}
-uint16_t bq25896_get_vsys_voltage() {
- bq25896_read_reg(0x0F, (uint8_t*)&bq25896_regs.r0F);
+uint16_t bq25896_get_vsys_voltage(FuriHalI2cBusHandle* handle) {
+ bq25896_read_reg(handle, 0x0F, (uint8_t*)&bq25896_regs.r0F);
return (uint16_t)bq25896_regs.r0F.SYSV * 20 + 2304;
}
-uint16_t bq25896_get_vbat_voltage() {
- bq25896_read_reg(0x0E, (uint8_t*)&bq25896_regs.r0E);
+uint16_t bq25896_get_vbat_voltage(FuriHalI2cBusHandle* handle) {
+ bq25896_read_reg(handle, 0x0E, (uint8_t*)&bq25896_regs.r0E);
return (uint16_t)bq25896_regs.r0E.BATV * 20 + 2304;
}
-uint16_t bq25896_get_vbat_current() {
- bq25896_read_reg(0x12, (uint8_t*)&bq25896_regs.r12);
+uint16_t bq25896_get_vbat_current(FuriHalI2cBusHandle* handle) {
+ bq25896_read_reg(handle, 0x12, (uint8_t*)&bq25896_regs.r12);
return (uint16_t)bq25896_regs.r12.ICHGR * 50;
}
-uint32_t bq25896_get_ntc_mpct() {
- bq25896_read_reg(0x10, (uint8_t*)&bq25896_regs.r10);
+uint32_t bq25896_get_ntc_mpct(FuriHalI2cBusHandle* handle) {
+ bq25896_read_reg(handle, 0x10, (uint8_t*)&bq25896_regs.r10);
return (uint32_t)bq25896_regs.r10.TSPCT * 465 + 21000;
}
diff --git a/lib/drivers/bq25896.h b/lib/drivers/bq25896.h
index 03bf7ba2..c6c9a30b 100644
--- a/lib/drivers/bq25896.h
+++ b/lib/drivers/bq25896.h
@@ -2,42 +2,43 @@
#include <stdbool.h>
#include <stdint.h>
+#include <furi-hal-i2c.h>
/** Initialize Driver */
-void bq25896_init();
+void bq25896_init(FuriHalI2cBusHandle* handle);
/** Send device into shipping mode */
-void bq25896_poweroff();
+void bq25896_poweroff(FuriHalI2cBusHandle* handle);
/** Is currently charging */
-bool bq25896_is_charging();
+bool bq25896_is_charging(FuriHalI2cBusHandle* handle);
/** Enable charging */
-void bq25896_enable_charging();
+void bq25896_enable_charging(FuriHalI2cBusHandle* handle);
/** Disable charging */
-void bq25896_disable_charging();
+void bq25896_disable_charging(FuriHalI2cBusHandle* handle);
/** Enable otg */
-void bq25896_enable_otg();
+void bq25896_enable_otg(FuriHalI2cBusHandle* handle);
/** Disable otg */
-void bq25896_disable_otg();
+void bq25896_disable_otg(FuriHalI2cBusHandle* handle);
/** Is otg enabled */
-bool bq25896_is_otg_enabled();
+bool bq25896_is_otg_enabled(FuriHalI2cBusHandle* handle);
/** Get VBUS Voltage in mV */
-uint16_t bq25896_get_vbus_voltage();
+uint16_t bq25896_get_vbus_voltage(FuriHalI2cBusHandle* handle);
/** Get VSYS Voltage in mV */
-uint16_t bq25896_get_vsys_voltage();
+uint16_t bq25896_get_vsys_voltage(FuriHalI2cBusHandle* handle);
/** Get VBAT Voltage in mV */
-uint16_t bq25896_get_vbat_voltage();
+uint16_t bq25896_get_vbat_voltage(FuriHalI2cBusHandle* handle);
/** Get VBAT current in mA */
-uint16_t bq25896_get_vbat_current();
+uint16_t bq25896_get_vbat_current(FuriHalI2cBusHandle* handle);
/** Get NTC voltage in mpct of REGN */
-uint32_t bq25896_get_ntc_mpct();
+uint32_t bq25896_get_ntc_mpct(FuriHalI2cBusHandle* handle);
diff --git a/lib/drivers/bq27220.c b/lib/drivers/bq27220.c
index 578e3849..8689db4a 100644
--- a/lib/drivers/bq27220.c
+++ b/lib/drivers/bq27220.c
@@ -1,37 +1,32 @@
#include "bq27220.h"
#include "bq27220_reg.h"
-#include <furi-hal-i2c.h>
#include <furi-hal-delay.h>
+#include <furi/log.h>
#include <stdbool.h>
#define TAG "Gauge"
-uint16_t bq27220_read_word(uint8_t address) {
+uint16_t bq27220_read_word(FuriHalI2cBusHandle* handle, uint8_t address) {
uint8_t buffer[2] = {address};
- uint16_t ret;
- with_furi_hal_i2c(
- uint16_t, &ret, () {
- if(furi_hal_i2c_trx(
- POWER_I2C, BQ27220_ADDRESS, buffer, 1, buffer, 2, BQ27220_I2C_TIMEOUT)) {
- return *(uint16_t*)buffer;
- } else {
- return 0;
- }
- });
+ uint16_t ret = 0;
+
+ if(furi_hal_i2c_trx(handle, BQ27220_ADDRESS, buffer, 1, buffer, 2, BQ27220_I2C_TIMEOUT)) {
+ ret = *(uint16_t*)buffer;
+ }
+
return ret;
}
-bool bq27220_control(uint16_t control) {
- bool ret;
- with_furi_hal_i2c(
- bool, &ret, () {
- uint8_t buffer[3];
- buffer[0] = CommandControl;
- buffer[1] = control & 0xFF;
- buffer[2] = (control >> 8) & 0xFF;
- return furi_hal_i2c_tx(POWER_I2C, BQ27220_ADDRESS, buffer, 3, BQ27220_I2C_TIMEOUT);
- });
+bool bq27220_control(FuriHalI2cBusHandle* handle, uint16_t control) {
+ bool ret = false;
+ uint8_t buffer[3];
+
+ buffer[0] = CommandControl;
+ buffer[1] = control & 0xFF;
+ buffer[2] = (control >> 8) & 0xFF;
+ ret = furi_hal_i2c_tx(handle, BQ27220_ADDRESS, buffer, 3, BQ27220_I2C_TIMEOUT);
+
return ret;
}
@@ -43,75 +38,73 @@ uint8_t bq27220_get_checksum(uint8_t* data, uint16_t len) {
return 0xFF - ret;
}
-bool bq27220_set_parameter_u16(uint16_t address, uint16_t value) {
+bool bq27220_set_parameter_u16(FuriHalI2cBusHandle* handle, uint16_t address, uint16_t value) {
bool ret;
uint8_t buffer[5];
- with_furi_hal_i2c(
- bool, &ret, () {
- buffer[0] = CommandSelectSubclass;
- buffer[1] = address & 0xFF;
- buffer[2] = (address >> 8) & 0xFF;
- buffer[3] = (value >> 8) & 0xFF;
- buffer[4] = value & 0xFF;
- return furi_hal_i2c_tx(POWER_I2C, BQ27220_ADDRESS, buffer, 5, BQ27220_I2C_TIMEOUT);
- });
+
+ buffer[0] = CommandSelectSubclass;
+ buffer[1] = address & 0xFF;
+ buffer[2] = (address >> 8) & 0xFF;
+ buffer[3] = (value >> 8) & 0xFF;
+ buffer[4] = value & 0xFF;
+ ret = furi_hal_i2c_tx(handle, BQ27220_ADDRESS, buffer, 5, BQ27220_I2C_TIMEOUT);
+
delay_us(10000);
+
uint8_t checksum = bq27220_get_checksum(&buffer[1], 4);
- with_furi_hal_i2c(
- bool, &ret, () {
- buffer[0] = CommandMACDataSum;
- buffer[1] = checksum;
- buffer[2] = 6;
- return furi_hal_i2c_tx(POWER_I2C, BQ27220_ADDRESS, buffer, 3, BQ27220_I2C_TIMEOUT);
- });
+ buffer[0] = CommandMACDataSum;
+ buffer[1] = checksum;
+ buffer[2] = 6;
+ ret = furi_hal_i2c_tx(handle, BQ27220_ADDRESS, buffer, 3, BQ27220_I2C_TIMEOUT);
+
delay_us(10000);
return ret;
}
-bool bq27220_init(const ParamCEDV* cedv) {
+bool bq27220_init(FuriHalI2cBusHandle* handle, const ParamCEDV* cedv) {
uint32_t timeout = 100;
- uint16_t design_cap = bq27220_get_design_capacity();
+ uint16_t design_cap = bq27220_get_design_capacity(handle);
if(cedv->design_cap == design_cap) {
FURI_LOG_I(TAG, "Skip battery profile update");
return true;
}
FURI_LOG_I(TAG, "Start updating battery profile");
OperationStatus status = {};
- if(!bq27220_control(Control_ENTER_CFG_UPDATE)) {
+ if(!bq27220_control(handle, Control_ENTER_CFG_UPDATE)) {
FURI_LOG_E(TAG, "Can't configure update");
return false;
};
while((status.CFGUPDATE != 1) && (timeout-- > 0)) {
- bq27220_get_operation_status(&status);
+ bq27220_get_operation_status(handle, &status);
}
- bq27220_set_parameter_u16(AddressGaugingConfig, cedv->cedv_conf.gauge_conf_raw);
- bq27220_set_parameter_u16(AddressFullChargeCapacity, cedv->full_charge_cap);
- bq27220_set_parameter_u16(AddressDesignCapacity, cedv->design_cap);
- bq27220_set_parameter_u16(AddressEMF, cedv->EMF);
- bq27220_set_parameter_u16(AddressC0, cedv->C0);
- bq27220_set_parameter_u16(AddressR0, cedv->R0);
- bq27220_set_parameter_u16(AddressT0, cedv->T0);
- bq27220_set_parameter_u16(AddressR1, cedv->R1);
- bq27220_set_parameter_u16(AddressTC, (cedv->TC) << 8 | cedv->C1);
- bq27220_set_parameter_u16(AddressStartDOD0, cedv->DOD0);
- bq27220_set_parameter_u16(AddressStartDOD10, cedv->DOD10);
- bq27220_set_parameter_u16(AddressStartDOD20, cedv->DOD20);
- bq27220_set_parameter_u16(AddressStartDOD30, cedv->DOD30);
- bq27220_set_parameter_u16(AddressStartDOD40, cedv->DOD40);
- bq27220_set_parameter_u16(AddressStartDOD50, cedv->DOD40);
- bq27220_set_parameter_u16(AddressStartDOD60, cedv->DOD60);
- bq27220_set_parameter_u16(AddressStartDOD70, cedv->DOD70);
- bq27220_set_parameter_u16(AddressStartDOD80, cedv->DOD80);
- bq27220_set_parameter_u16(AddressStartDOD90, cedv->DOD90);
- bq27220_set_parameter_u16(AddressStartDOD100, cedv->DOD100);
- bq27220_set_parameter_u16(AddressEDV0, cedv->EDV0);
- bq27220_set_parameter_u16(AddressEDV1, cedv->EDV1);
- bq27220_set_parameter_u16(AddressEDV2, cedv->EDV2);
-
- bq27220_control(Control_EXIT_CFG_UPDATE);
+ bq27220_set_parameter_u16(handle, AddressGaugingConfig, cedv->cedv_conf.gauge_conf_raw);
+ bq27220_set_parameter_u16(handle, AddressFullChargeCapacity, cedv->full_charge_cap);
+ bq27220_set_parameter_u16(handle, AddressDesignCapacity, cedv->design_cap);
+ bq27220_set_parameter_u16(handle, AddressEMF, cedv->EMF);
+ bq27220_set_parameter_u16(handle, AddressC0, cedv->C0);
+ bq27220_set_parameter_u16(handle, AddressR0, cedv->R0);
+ bq27220_set_parameter_u16(handle, AddressT0, cedv->T0);
+ bq27220_set_parameter_u16(handle, AddressR1, cedv->R1);
+ bq27220_set_parameter_u16(handle, AddressTC, (cedv->TC) << 8 | cedv->C1);
+ bq27220_set_parameter_u16(handle, AddressStartDOD0, cedv->DOD0);
+ bq27220_set_parameter_u16(handle, AddressStartDOD10, cedv->DOD10);
+ bq27220_set_parameter_u16(handle, AddressStartDOD20, cedv->DOD20);
+ bq27220_set_parameter_u16(handle, AddressStartDOD30, cedv->DOD30);
+ bq27220_set_parameter_u16(handle, AddressStartDOD40, cedv->DOD40);
+ bq27220_set_parameter_u16(handle, AddressStartDOD50, cedv->DOD40);
+ bq27220_set_parameter_u16(handle, AddressStartDOD60, cedv->DOD60);
+ bq27220_set_parameter_u16(handle, AddressStartDOD70, cedv->DOD70);
+ bq27220_set_parameter_u16(handle, AddressStartDOD80, cedv->DOD80);
+ bq27220_set_parameter_u16(handle, AddressStartDOD90, cedv->DOD90);
+ bq27220_set_parameter_u16(handle, AddressStartDOD100, cedv->DOD100);
+ bq27220_set_parameter_u16(handle, AddressEDV0, cedv->EDV0);
+ bq27220_set_parameter_u16(handle, AddressEDV1, cedv->EDV1);
+ bq27220_set_parameter_u16(handle, AddressEDV2, cedv->EDV2);
+
+ bq27220_control(handle, Control_EXIT_CFG_UPDATE);
delay_us(10000);
- design_cap = bq27220_get_design_capacity();
+ design_cap = bq27220_get_design_capacity(handle);
if(cedv->design_cap == design_cap) {
FURI_LOG_I(TAG, "Battery profile update success");
return true;
@@ -121,16 +114,16 @@ bool bq27220_init(const ParamCEDV* cedv) {
}
}
-uint16_t bq27220_get_voltage() {
- return bq27220_read_word(CommandVoltage);
+uint16_t bq27220_get_voltage(FuriHalI2cBusHandle* handle) {
+ return bq27220_read_word(handle, CommandVoltage);
}
-int16_t bq27220_get_current() {
- return bq27220_read_word(CommandCurrent);
+int16_t bq27220_get_current(FuriHalI2cBusHandle* handle) {
+ return bq27220_read_word(handle, CommandCurrent);
}
-uint8_t bq27220_get_battery_status(BatteryStatus* battery_status) {
- uint16_t data = bq27220_read_word(CommandBatteryStatus);
+uint8_t bq27220_get_battery_status(FuriHalI2cBusHandle* handle, BatteryStatus* battery_status) {
+ uint16_t data = bq27220_read_word(handle, CommandBatteryStatus);
if(data == BQ27220_ERROR) {
return BQ27220_ERROR;
} else {
@@ -139,8 +132,8 @@ uint8_t bq27220_get_battery_status(BatteryStatus* battery_status) {
}
}
-uint8_t bq27220_get_operation_status(OperationStatus* operation_status) {
- uint16_t data = bq27220_read_word(CommandOperationStatus);
+uint8_t bq27220_get_operation_status(FuriHalI2cBusHandle* handle, OperationStatus* operation_status) {
+ uint16_t data = bq27220_read_word(handle, CommandOperationStatus);
if(data == BQ27220_ERROR) {
return BQ27220_ERROR;
} else {
@@ -149,26 +142,26 @@ uint8_t bq27220_get_operation_status(OperationStatus* operation_status) {
}
}
-uint16_t bq27220_get_temperature() {
- return bq27220_read_word(CommandTemperature);
+uint16_t bq27220_get_temperature(FuriHalI2cBusHandle* handle) {
+ return bq27220_read_word(handle, CommandTemperature);
}
-uint16_t bq27220_get_full_charge_capacity() {
- return bq27220_read_word(CommandFullChargeCapacity);
+uint16_t bq27220_get_full_charge_capacity(FuriHalI2cBusHandle* handle) {
+ return bq27220_read_word(handle, CommandFullChargeCapacity);
}
-uint16_t bq27220_get_design_capacity() {
- return bq27220_read_word(CommandDesignCapacity);
+uint16_t bq27220_get_design_capacity(FuriHalI2cBusHandle* handle) {
+ return bq27220_read_word(handle, CommandDesignCapacity);
}
-uint16_t bq27220_get_remaining_capacity() {
- return bq27220_read_word(CommandRemainingCapacity);
+uint16_t bq27220_get_remaining_capacity(FuriHalI2cBusHandle* handle) {
+ return bq27220_read_word(handle, CommandRemainingCapacity);
}
-uint16_t bq27220_get_state_of_charge() {
- return bq27220_read_word(CommandStateOfCharge);
+uint16_t bq27220_get_state_of_charge(FuriHalI2cBusHandle* handle) {
+ return bq27220_read_word(handle, CommandStateOfCharge);
}
-uint16_t bq27220_get_state_of_health() {
- return bq27220_read_word(CommandStateOfHealth);
+uint16_t bq27220_get_state_of_health(FuriHalI2cBusHandle* handle) {
+ return bq27220_read_word(handle, CommandStateOfHealth);
}
diff --git a/lib/drivers/bq27220.h b/lib/drivers/bq27220.h
index 312d46fd..4c97c48e 100644
--- a/lib/drivers/bq27220.h
+++ b/lib/drivers/bq27220.h
@@ -2,6 +2,7 @@
#include <stdint.h>
#include <stdbool.h>
+#include <furi-hal-i2c.h>
#define BQ27220_ERROR 0x0
#define BQ27220_SUCCESS 0x1
@@ -95,36 +96,36 @@ typedef struct {
/** Initialize Driver
* @return true on success, false otherwise
*/
-bool bq27220_init(const ParamCEDV* cedv);
+bool bq27220_init(FuriHalI2cBusHandle* handle, const ParamCEDV* cedv);
/** Get battery voltage in mV or error */
-uint16_t bq27220_get_voltage();
+uint16_t bq27220_get_voltage(FuriHalI2cBusHandle* handle);
/** Get current in mA or error*/
-int16_t bq27220_get_current();
+int16_t bq27220_get_current(FuriHalI2cBusHandle* handle);
/** Get battery status */
-uint8_t bq27220_get_battery_status(BatteryStatus* battery_status);
+uint8_t bq27220_get_battery_status(FuriHalI2cBusHandle* handle, BatteryStatus* battery_status);
/** Get operation status */
-uint8_t bq27220_get_operation_status(OperationStatus* operation_status);
+uint8_t bq27220_get_operation_status(FuriHalI2cBusHandle* handle, OperationStatus* operation_status);
/** Get temperature in units of 0.1°K */
-uint16_t bq27220_get_temperature();
+uint16_t bq27220_get_temperature(FuriHalI2cBusHandle* handle);
/** Get compensated full charge capacity in in mAh */
-uint16_t bq27220_get_full_charge_capacity();
+uint16_t bq27220_get_full_charge_capacity(FuriHalI2cBusHandle* handle);
/** Get design capacity in mAh */
-uint16_t bq27220_get_design_capacity();
+uint16_t bq27220_get_design_capacity(FuriHalI2cBusHandle* handle);
/** Get remaining capacity in in mAh */
-uint16_t bq27220_get_remaining_capacity();
+uint16_t bq27220_get_remaining_capacity(FuriHalI2cBusHandle* handle);
/** Get predicted remaining battery capacity in percents */
-uint16_t bq27220_get_state_of_charge();
+uint16_t bq27220_get_state_of_charge(FuriHalI2cBusHandle* handle);
/** Get ratio of full charge capacity over design capacity in percents */
-uint16_t bq27220_get_state_of_health();
+uint16_t bq27220_get_state_of_health(FuriHalI2cBusHandle* handle);
-void bq27220_change_design_capacity(uint16_t capacity);
+void bq27220_change_design_capacity(FuriHalI2cBusHandle* handle, uint16_t capacity);
diff --git a/lib/drivers/lp5562.c b/lib/drivers/lp5562.c
index 954fa65e..8535f3ac 100644
--- a/lib/drivers/lp5562.c
+++ b/lib/drivers/lp5562.c
@@ -1,27 +1,21 @@
#include "lp5562.h"
#include "lp5562_reg.h"
-#include <furi-hal-i2c.h>
#include <stdio.h>
-bool lp5562_write_reg(uint8_t address, uint8_t* data) {
+static bool lp5562_write_reg(FuriHalI2cBusHandle* handle, uint8_t address, uint8_t* data) {
uint8_t buffer[2] = {address, *data};
- bool ret;
- with_furi_hal_i2c(
- bool, &ret, () {
- return furi_hal_i2c_tx(POWER_I2C, LP5562_ADDRESS, buffer, 2, LP5562_I2C_TIMEOUT);
- });
- return ret;
+ return furi_hal_i2c_tx(handle, LP5562_ADDRESS, buffer, 2, LP5562_I2C_TIMEOUT);
}
-void lp5562_reset() {
+void lp5562_reset(FuriHalI2cBusHandle* handle) {
Reg0D_Reset reg = {.value = 0xFF};
- lp5562_write_reg(0x0D, (uint8_t*)&reg);
+ lp5562_write_reg(handle, 0x0D, (uint8_t*)&reg);
}
-void lp5562_configure() {
+void lp5562_configure(FuriHalI2cBusHandle* handle) {
Reg08_Config config = {.INT_CLK_EN = true, .PS_EN = true, .PWM_HF = true};
- lp5562_write_reg(0x08, (uint8_t*)&config);
+ lp5562_write_reg(handle, 0x08, (uint8_t*)&config);
Reg70_LedMap map = {
.red = EngSelectI2C,
@@ -29,15 +23,15 @@ void lp5562_configure() {
.blue = EngSelectI2C,
.white = EngSelectI2C,
};
- lp5562_write_reg(0x70, (uint8_t*)&map);
+ lp5562_write_reg(handle, 0x70, (uint8_t*)&map);
}
-void lp5562_enable() {
+void lp5562_enable(FuriHalI2cBusHandle* handle) {
Reg00_Enable reg = {.CHIP_EN = true, .LOG_EN = true};
- lp5562_write_reg(0x00, (uint8_t*)&reg);
+ lp5562_write_reg(handle, 0x00, (uint8_t*)&reg);
}
-void lp5562_set_channel_current(LP5562Channel channel, uint8_t value) {
+void lp5562_set_channel_current(FuriHalI2cBusHandle* handle, LP5562Channel channel, uint8_t value) {
uint8_t reg_no;
if(channel == LP5562ChannelRed) {
reg_no = 0x07;
@@ -50,10 +44,10 @@ void lp5562_set_channel_current(LP5562Channel channel, uint8_t value) {
} else {
return;
}
- lp5562_write_reg(reg_no, &value);
+ lp5562_write_reg(handle, reg_no, &value);
}
-void lp5562_set_channel_value(LP5562Channel channel, uint8_t value) {
+void lp5562_set_channel_value(FuriHalI2cBusHandle* handle, LP5562Channel channel, uint8_t value) {
uint8_t reg_no;
if(channel == LP5562ChannelRed) {
reg_no = 0x04;
@@ -66,5 +60,5 @@ void lp5562_set_channel_value(LP5562Channel channel, uint8_t value) {
} else {
return;
}
- lp5562_write_reg(reg_no, &value);
+ lp5562_write_reg(handle, reg_no, &value);
}
diff --git a/lib/drivers/lp5562.h b/lib/drivers/lp5562.h
index b58e2ee0..7af6ae6f 100644
--- a/lib/drivers/lp5562.h
+++ b/lib/drivers/lp5562.h
@@ -2,6 +2,7 @@
#include <stdint.h>
#include <stdbool.h>
+#include <furi-hal-i2c.h>
/** Channel types */
typedef enum {
@@ -12,16 +13,16 @@ typedef enum {
} LP5562Channel;
/** Initialize Driver */
-void lp5562_reset();
+void lp5562_reset(FuriHalI2cBusHandle* handle);
/** Configure Driver */
-void lp5562_configure();
+void lp5562_configure(FuriHalI2cBusHandle* handle);
/** Enable Driver */
-void lp5562_enable();
+void lp5562_enable(FuriHalI2cBusHandle* handle);
/** Set channel current */
-void lp5562_set_channel_current(LP5562Channel channel, uint8_t value);
+void lp5562_set_channel_current(FuriHalI2cBusHandle* handle, LP5562Channel channel, uint8_t value);
/** Set channel current */
-void lp5562_set_channel_value(LP5562Channel channel, uint8_t value);
+void lp5562_set_channel_value(FuriHalI2cBusHandle* handle, LP5562Channel channel, uint8_t value);