diff options
Diffstat (limited to 'firmware')
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 */ |