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:
authorあく <alleteam@gmail.com>2021-11-28 21:28:19 +0300
committerGitHub <noreply@github.com>2021-11-28 21:28:19 +0300
commitcf591ef7ebc024a0af74e26f4b645758e44ae4bb (patch)
tree5cf97006e777b94bca13b76256be075fab37abac /firmware
parent7c0943e7364b3d03e099654548ec9c264b58ef60 (diff)
[FL-1911] FuriHal: i2c refactoring (#847)
* Project: fix release build, replace asserts with checks. * FuriHal: i2c refactoring, new bus access model, flexible bus gpio configuration. * FuriHal: set i2c pins to high on detach. * FuriHal: more i2c bus events, put bus under reset when not used, move bus enable/disable routine to bus handler. * FuriHal: fix i2c deadlock in power api, add external i2c handle.
Diffstat (limited to 'firmware')
-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
21 files changed, 802 insertions, 427 deletions
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
*/