diff --git a/applications/storage/storage-external-api.c b/applications/storage/storage-external-api.c index 6c61f707..05d1fc28 100644 --- a/applications/storage/storage-external-api.c +++ b/applications/storage/storage-external-api.c @@ -427,7 +427,7 @@ bool storage_simply_remove_recursive(Storage* storage, const char* path) { string_init_printf(fullname, "%s/%s", string_get_cstr(cur_dir), name); FS_Error error = storage_common_remove(storage, string_get_cstr(fullname)); - furi_assert(error == FSE_OK); + furi_check(error == FSE_OK); string_clear(fullname); } storage_dir_close(dir); @@ -438,7 +438,7 @@ bool storage_simply_remove_recursive(Storage* storage, const char* path) { } FS_Error error = storage_common_remove(storage, string_get_cstr(cur_dir)); - furi_assert(error == FSE_OK); + furi_check(error == FSE_OK); if(string_cmp(cur_dir, path)) { size_t last_char = string_search_rchar(cur_dir, '/'); diff --git a/applications/tests/rpc/rpc_test.c b/applications/tests/rpc/rpc_test.c index af99be4a..dbe1a324 100644 --- a/applications/tests/rpc/rpc_test.c +++ b/applications/tests/rpc/rpc_test.c @@ -115,7 +115,7 @@ static void clean_directory(Storage* fs_api, const char* clean_dir) { clean_directory(fs_api, fullname); } FS_Error error = storage_common_remove(fs_api, fullname); - furi_assert(error == FSE_OK); + furi_check(error == FSE_OK); free(fullname); } free(name); diff --git a/bootloader/targets/f6/furi-hal/furi-hal-i2c-config.c b/bootloader/targets/f6/furi-hal/furi-hal-i2c-config.c new file mode 100644 index 00000000..afaab237 --- /dev/null +++ b/bootloader/targets/f6/furi-hal/furi-hal-i2c-config.c @@ -0,0 +1,149 @@ +#include "furi-hal-i2c-config.h" +#include +#include + +#include +#include + +/** Timing register value is computed with the STM32CubeMX Tool, + * Standard Mode @100kHz with I2CCLK = 64 MHz, + * rise time = 0ns, fall time = 0ns + */ +#define FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100 0x10707DBC + +/** Timing register value is computed with the STM32CubeMX Tool, + * Fast Mode @400kHz with I2CCLK = 64 MHz, + * rise time = 0ns, fall time = 0ns + */ +#define FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_400 0x00602173 + +static void furi_hal_i2c_bus_power_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) { + if(event == FuriHalI2cBusEventInit) { + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); + LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); + LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1); + bus->current_handle = NULL; + } else if(event == FuriHalI2cBusEventDeinit) { + } else if(event == FuriHalI2cBusEventLock) { + } else if(event == FuriHalI2cBusEventUnlock) { + } else if(event == FuriHalI2cBusEventActivate) { + LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C1); + } else if(event == FuriHalI2cBusEventDeactivate) { + LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1); + } +} + +FuriHalI2cBus furi_hal_i2c_bus_power = { + .i2c = I2C1, + .current_handle = NULL, + .callback = furi_hal_i2c_bus_power_event, +}; + +static void furi_hal_i2c_bus_external_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) { + if(event == FuriHalI2cBusEventActivate) { + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C3); + LL_RCC_SetI2CClockSource(LL_RCC_I2C3_CLKSOURCE_PCLK1); + LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C3); + } else if(event == FuriHalI2cBusEventDeactivate) { + LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C3); + } +} + +FuriHalI2cBus furi_hal_i2c_bus_external = { + .i2c = I2C3, + .current_handle = NULL, + .callback = furi_hal_i2c_bus_external_event, +}; + +void furi_hal_i2c_bus_handle_power_event( + FuriHalI2cBusHandle* handle, + FuriHalI2cBusHandleEvent event) { + if(event == FuriHalI2cBusHandleEventActivate) { + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); + hal_gpio_init_ex( + &gpio_i2c_power_sda, + GpioModeAltFunctionOpenDrain, + GpioPullNo, + GpioSpeedLow, + GpioAltFn4I2C1); + hal_gpio_init_ex( + &gpio_i2c_power_scl, + GpioModeAltFunctionOpenDrain, + GpioPullNo, + GpioSpeedLow, + GpioAltFn4I2C1); + + LL_I2C_InitTypeDef I2C_InitStruct = {0}; + I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C; + I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE; + I2C_InitStruct.DigitalFilter = 0; + I2C_InitStruct.OwnAddress1 = 0; + I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK; + I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT; + if(furi_hal_version_get_hw_version() > 10) { + I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_400; + } else { + I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100; + } + LL_I2C_Init(handle->bus->i2c, &I2C_InitStruct); + + LL_I2C_EnableAutoEndMode(handle->bus->i2c); + LL_I2C_SetOwnAddress2(handle->bus->i2c, 0, LL_I2C_OWNADDRESS2_NOMASK); + LL_I2C_DisableOwnAddress2(handle->bus->i2c); + LL_I2C_DisableGeneralCall(handle->bus->i2c); + LL_I2C_EnableClockStretching(handle->bus->i2c); + LL_I2C_Enable(handle->bus->i2c); + } else if(event == FuriHalI2cBusHandleEventDeactivate) { + LL_I2C_Disable(handle->bus->i2c); + hal_gpio_write(&gpio_i2c_power_sda, 1); + hal_gpio_write(&gpio_i2c_power_scl, 1); + hal_gpio_init_ex( + &gpio_i2c_power_sda, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused); + hal_gpio_init_ex( + &gpio_i2c_power_scl, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused); + } +} + +FuriHalI2cBusHandle furi_hal_i2c_handle_power = { + .bus = &furi_hal_i2c_bus_power, + .callback = furi_hal_i2c_bus_handle_power_event, +}; + +void furi_hal_i2c_bus_handle_external_event( + FuriHalI2cBusHandle* handle, + FuriHalI2cBusHandleEvent event) { + if(event == FuriHalI2cBusHandleEventActivate) { + hal_gpio_init_ex( + &gpio_ext_pc0, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C3); + hal_gpio_init_ex( + &gpio_ext_pc1, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C3); + + LL_I2C_InitTypeDef I2C_InitStruct = {0}; + I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C; + I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE; + I2C_InitStruct.DigitalFilter = 0; + I2C_InitStruct.OwnAddress1 = 0; + I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK; + I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT; + I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100; + LL_I2C_Init(handle->bus->i2c, &I2C_InitStruct); + + LL_I2C_EnableAutoEndMode(handle->bus->i2c); + LL_I2C_SetOwnAddress2(handle->bus->i2c, 0, LL_I2C_OWNADDRESS2_NOMASK); + LL_I2C_DisableOwnAddress2(handle->bus->i2c); + LL_I2C_DisableGeneralCall(handle->bus->i2c); + LL_I2C_EnableClockStretching(handle->bus->i2c); + LL_I2C_Enable(handle->bus->i2c); + } else if(event == FuriHalI2cBusHandleEventDeactivate) { + LL_I2C_Disable(handle->bus->i2c); + hal_gpio_write(&gpio_ext_pc0, 1); + hal_gpio_write(&gpio_ext_pc1, 1); + hal_gpio_init_ex(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused); + hal_gpio_init_ex(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused); + } +} + +FuriHalI2cBusHandle furi_hal_i2c_handle_external = { + .bus = &furi_hal_i2c_bus_external, + .callback = furi_hal_i2c_bus_handle_external_event, +}; diff --git a/bootloader/targets/f6/furi-hal/furi-hal-i2c-config.h b/bootloader/targets/f6/furi-hal/furi-hal-i2c-config.h new file mode 100644 index 00000000..2094dca3 --- /dev/null +++ b/bootloader/targets/f6/furi-hal/furi-hal-i2c-config.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Internal(power) i2c bus, I2C1, under reset when not used */ +extern FuriHalI2cBus furi_hal_i2c_bus_power; + +/** External i2c bus, I2C3, under reset when not used */ +extern FuriHalI2cBus furi_hal_i2c_bus_external; + +/** Handle for internal(power) i2c bus + * Bus: furi_hal_i2c_bus_external + * Pins: PA9(SCL) / PA10(SDA), float on release + * Params: 400khz + */ +extern FuriHalI2cBusHandle furi_hal_i2c_handle_power; + +/** Handle for external i2c bus + * Bus: furi_hal_i2c_bus_external + * Pins: PC0(SCL) / PC1(SDA), float on release + * Params: 100khz + */ +extern FuriHalI2cBusHandle furi_hal_i2c_handle_external; + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/bootloader/targets/f6/furi-hal/furi-hal-i2c-types.h b/bootloader/targets/f6/furi-hal/furi-hal-i2c-types.h new file mode 100644 index 00000000..0f2b735e --- /dev/null +++ b/bootloader/targets/f6/furi-hal/furi-hal-i2c-types.h @@ -0,0 +1,51 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct FuriHalI2cBus FuriHalI2cBus; +typedef struct FuriHalI2cBusHandle FuriHalI2cBusHandle; + +/** FuriHal i2c bus states */ +typedef enum { + FuriHalI2cBusEventInit, /**< Bus initialization event, called on system start */ + FuriHalI2cBusEventDeinit, /**< Bus deinitialization event, called on system stop */ + FuriHalI2cBusEventLock, /**< Bus lock event, called before activation */ + FuriHalI2cBusEventUnlock, /**< Bus unlock event, called after deactivation */ + FuriHalI2cBusEventActivate, /**< Bus activation event, called before handle activation */ + FuriHalI2cBusEventDeactivate, /**< Bus deactivation event, called after handle deactivation */ +} FuriHalI2cBusEvent; + +/** FuriHal i2c bus event callback */ +typedef void (*FuriHalI2cBusEventCallback)(FuriHalI2cBus* bus, FuriHalI2cBusEvent event); + +/** FuriHal i2c bus */ +struct FuriHalI2cBus { + I2C_TypeDef* i2c; + FuriHalI2cBusHandle* current_handle; + FuriHalI2cBusEventCallback callback; +}; + +/** FuriHal i2c handle states */ +typedef enum { + FuriHalI2cBusHandleEventActivate, /**< Handle activate: connect gpio and apply bus config */ + FuriHalI2cBusHandleEventDeactivate, /**< Handle deactivate: disconnect gpio and reset bus config */ +} FuriHalI2cBusHandleEvent; + +/** FuriHal i2c handle event callback */ +typedef void (*FuriHalI2cBusHandleEventCallback)( + FuriHalI2cBusHandle* handle, + FuriHalI2cBusHandleEvent event); + +/** FuriHal i2c handle */ +struct FuriHalI2cBusHandle { + FuriHalI2cBus* bus; + FuriHalI2cBusHandleEventCallback callback; +}; + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/bootloader/targets/f6/furi-hal/furi-hal-i2c.c b/bootloader/targets/f6/furi-hal/furi-hal-i2c.c index c40a70af..f276ff75 100644 --- a/bootloader/targets/f6/furi-hal/furi-hal-i2c.c +++ b/bootloader/targets/f6/furi-hal/furi-hal-i2c.c @@ -1,66 +1,64 @@ #include +#include -#include #include -#include #include #include +#include + void furi_hal_i2c_init() { - LL_I2C_InitTypeDef I2C_InitStruct = {0}; - LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; + furi_hal_i2c_bus_power.callback(&furi_hal_i2c_bus_power, FuriHalI2cBusEventInit); +} - LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); +void furi_hal_i2c_acquire(FuriHalI2cBusHandle* handle) { + handle->bus->callback(handle->bus, FuriHalI2cBusEventLock); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); - GPIO_InitStruct.Pin = POWER_I2C_SCL_Pin | POWER_I2C_SDA_Pin; - GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; - GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW; - GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN; - GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; - GPIO_InitStruct.Alternate = LL_GPIO_AF_4; - LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + assert(handle->bus->current_handle == NULL); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); + handle->bus->current_handle = handle; - I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C; - I2C_InitStruct.Timing = POWER_I2C_TIMINGS; - I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE; - I2C_InitStruct.DigitalFilter = 0; - I2C_InitStruct.OwnAddress1 = 0; - I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK; - I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT; - LL_I2C_Init(I2C1, &I2C_InitStruct); - LL_I2C_EnableAutoEndMode(I2C1); - LL_I2C_SetOwnAddress2(I2C1, 0, LL_I2C_OWNADDRESS2_NOMASK); - LL_I2C_DisableOwnAddress2(I2C1); - LL_I2C_DisableGeneralCall(I2C1); - LL_I2C_EnableClockStretching(I2C1); + handle->bus->callback(handle->bus, FuriHalI2cBusEventActivate); + + handle->callback(handle, FuriHalI2cBusHandleEventActivate); +} + +void furi_hal_i2c_release(FuriHalI2cBusHandle* handle) { + assert(handle->bus->current_handle == handle); + + handle->callback(handle, FuriHalI2cBusHandleEventDeactivate); + + handle->bus->callback(handle->bus, FuriHalI2cBusEventDeactivate); + + handle->bus->current_handle = NULL; + + handle->bus->callback(handle->bus, FuriHalI2cBusEventUnlock); } bool furi_hal_i2c_tx( - I2C_TypeDef* instance, + FuriHalI2cBusHandle* handle, uint8_t address, const uint8_t* data, uint8_t size, uint32_t timeout) { + assert(handle->bus->current_handle == handle); uint32_t time_left = timeout; bool ret = true; - while(LL_I2C_IsActiveFlag_BUSY(instance)) + while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c)) ; LL_I2C_HandleTransfer( - instance, + handle->bus->i2c, address, LL_I2C_ADDRSLAVE_7BIT, size, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_WRITE); - while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) { - if(LL_I2C_IsActiveFlag_TXIS(instance)) { - LL_I2C_TransmitData8(instance, (*data)); + while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) { + if(LL_I2C_IsActiveFlag_TXIS(handle->bus->i2c)) { + LL_I2C_TransmitData8(handle->bus->i2c, (*data)); data++; size--; time_left = timeout; @@ -74,34 +72,35 @@ bool furi_hal_i2c_tx( } } - LL_I2C_ClearFlag_STOP(instance); + LL_I2C_ClearFlag_STOP(handle->bus->i2c); return ret; } bool furi_hal_i2c_rx( - I2C_TypeDef* instance, + FuriHalI2cBusHandle* handle, uint8_t address, uint8_t* data, uint8_t size, uint32_t timeout) { + assert(handle->bus->current_handle == handle); uint32_t time_left = timeout; bool ret = true; - while(LL_I2C_IsActiveFlag_BUSY(instance)) + while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c)) ; LL_I2C_HandleTransfer( - instance, + handle->bus->i2c, address, LL_I2C_ADDRSLAVE_7BIT, size, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_READ); - while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) { - if(LL_I2C_IsActiveFlag_RXNE(instance)) { - *data = LL_I2C_ReceiveData8(instance); + while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) { + if(LL_I2C_IsActiveFlag_RXNE(handle->bus->i2c)) { + *data = LL_I2C_ReceiveData8(handle->bus->i2c); data++; size--; time_left = timeout; @@ -115,21 +114,21 @@ bool furi_hal_i2c_rx( } } - LL_I2C_ClearFlag_STOP(instance); + LL_I2C_ClearFlag_STOP(handle->bus->i2c); return ret; } bool furi_hal_i2c_trx( - I2C_TypeDef* instance, + FuriHalI2cBusHandle* handle, uint8_t address, const uint8_t* tx_data, uint8_t tx_size, uint8_t* rx_data, uint8_t rx_size, uint32_t timeout) { - if(furi_hal_i2c_tx(instance, address, tx_data, tx_size, timeout) && - furi_hal_i2c_rx(instance, address, rx_data, rx_size, timeout)) { + if(furi_hal_i2c_tx(handle, address, tx_data, tx_size, timeout) && + furi_hal_i2c_rx(handle, address, rx_data, rx_size, timeout)) { return true; } else { return false; diff --git a/bootloader/targets/f6/furi-hal/furi-hal-i2c.h b/bootloader/targets/f6/furi-hal/furi-hal-i2c.h index 5db562e0..7ef1db44 100644 --- a/bootloader/targets/f6/furi-hal/furi-hal-i2c.h +++ b/bootloader/targets/f6/furi-hal/furi-hal-i2c.h @@ -1,31 +1,82 @@ +/** + * @file furi-hal-i2c.h + * I2C HAL API + */ + #pragma once #include #include -#include +#include #ifdef __cplusplus extern "C" { #endif +/** Init I2C + */ void furi_hal_i2c_init(); +/** Acquire i2c bus handle + * + * @return Instance of FuriHalI2cBus + */ +void furi_hal_i2c_acquire(FuriHalI2cBusHandle* handle); + +/** Release i2c bus handle + * + * @param bus instance of FuriHalI2cBus aquired in `furi_hal_i2c_acquire` + */ +void furi_hal_i2c_release(FuriHalI2cBusHandle* handle); + +/** Perform I2C tx transfer + * + * @param instance I2C_TypeDef instance + * @param address I2C slave address + * @param data pointer to data buffer + * @param size size of data buffer + * @param timeout timeout in ticks + * + * @return true on successful transfer, false otherwise + */ bool furi_hal_i2c_tx( - I2C_TypeDef* instance, + FuriHalI2cBusHandle* handle, const uint8_t address, const uint8_t* data, const uint8_t size, uint32_t timeout); +/** Perform I2C rx transfer + * + * @param instance I2C_TypeDef instance + * @param address I2C slave address + * @param data pointer to data buffer + * @param size size of data buffer + * @param timeout timeout in ticks + * + * @return true on successful transfer, false otherwise + */ bool furi_hal_i2c_rx( - I2C_TypeDef* instance, + FuriHalI2cBusHandle* handle, const uint8_t address, uint8_t* data, const uint8_t size, uint32_t timeout); +/** Perform I2C tx and rx transfers + * + * @param instance I2C_TypeDef instance + * @param address I2C slave address + * @param tx_data pointer to tx data buffer + * @param tx_size size of tx data buffer + * @param rx_data pointer to rx data buffer + * @param rx_size size of rx data buffer + * @param timeout timeout in ticks + * + * @return true on successful transfer, false otherwise + */ bool furi_hal_i2c_trx( - I2C_TypeDef* instance, + FuriHalI2cBusHandle* handle, const uint8_t address, const uint8_t* tx_data, const uint8_t tx_size, @@ -33,11 +84,6 @@ bool furi_hal_i2c_trx( const uint8_t rx_size, uint32_t timeout); -#define with_furi_hal_i2c(type, pointer, function_body) \ - { \ - *pointer = ({ type __fn__ function_body __fn__; })(); \ - } - #ifdef __cplusplus } #endif diff --git a/bootloader/targets/f6/furi-hal/furi-hal-light.c b/bootloader/targets/f6/furi-hal/furi-hal-light.c index d5f54f6d..15a69f09 100644 --- a/bootloader/targets/f6/furi-hal/furi-hal-light.c +++ b/bootloader/targets/f6/furi-hal/furi-hal-light.c @@ -7,37 +7,43 @@ #define LED_CURRENT_WHITE 150 void furi_hal_light_init() { - lp5562_reset(); + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); - lp5562_set_channel_current(LP5562ChannelRed, LED_CURRENT_RED); - lp5562_set_channel_current(LP5562ChannelGreen, LED_CURRENT_GREEN); - lp5562_set_channel_current(LP5562ChannelBlue, LED_CURRENT_BLUE); - lp5562_set_channel_current(LP5562ChannelWhite, LED_CURRENT_WHITE); + lp5562_reset(&furi_hal_i2c_handle_power); - lp5562_set_channel_value(LP5562ChannelRed, 0x00); - lp5562_set_channel_value(LP5562ChannelGreen, 0x00); - lp5562_set_channel_value(LP5562ChannelBlue, 0x00); - lp5562_set_channel_value(LP5562ChannelWhite, 0x00); + lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelRed, LED_CURRENT_RED); + lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelGreen, LED_CURRENT_GREEN); + lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelBlue, LED_CURRENT_BLUE); + lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelWhite, LED_CURRENT_WHITE); - lp5562_enable(); - lp5562_configure(); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, 0x00); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, 0x00); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, 0x00); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, 0x00); + + lp5562_enable(&furi_hal_i2c_handle_power); + lp5562_configure(&furi_hal_i2c_handle_power); + + furi_hal_i2c_release(&furi_hal_i2c_handle_power); } void furi_hal_light_set(Light light, uint8_t value) { + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); switch(light) { case LightRed: - lp5562_set_channel_value(LP5562ChannelRed, value); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value); break; case LightGreen: - lp5562_set_channel_value(LP5562ChannelGreen, value); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value); break; case LightBlue: - lp5562_set_channel_value(LP5562ChannelBlue, value); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value); break; case LightBacklight: - lp5562_set_channel_value(LP5562ChannelWhite, value); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, value); break; default: break; } + furi_hal_i2c_release(&furi_hal_i2c_handle_power); } \ No newline at end of file diff --git a/bootloader/targets/f6/furi-hal/furi-hal-resources.c b/bootloader/targets/f6/furi-hal/furi-hal-resources.c index 1260a485..3af9ba03 100644 --- a/bootloader/targets/f6/furi-hal/furi-hal-resources.c +++ b/bootloader/targets/f6/furi-hal/furi-hal-resources.c @@ -39,3 +39,6 @@ const GpioPin gpio_irda_tx = {.port = IR_TX_GPIO_Port, .pin = IR_TX_Pin}; const GpioPin gpio_usart_tx = {.port = USART1_TX_Port, .pin = USART1_TX_Pin}; const GpioPin gpio_usart_rx = {.port = USART1_RX_Port, .pin = USART1_RX_Pin}; + +const GpioPin gpio_i2c_power_sda = {.port = GPIOA, .pin = LL_GPIO_PIN_10}; +const GpioPin gpio_i2c_power_scl = {.port = GPIOA, .pin = LL_GPIO_PIN_9}; diff --git a/bootloader/targets/f6/furi-hal/furi-hal-resources.h b/bootloader/targets/f6/furi-hal/furi-hal-resources.h index 95bb4d0d..42b9b315 100644 --- a/bootloader/targets/f6/furi-hal/furi-hal-resources.h +++ b/bootloader/targets/f6/furi-hal/furi-hal-resources.h @@ -8,18 +8,6 @@ extern "C" { #endif -#define POWER_I2C_SCL_Pin LL_GPIO_PIN_9 -#define POWER_I2C_SCL_GPIO_Port GPIOA -#define POWER_I2C_SDA_Pin LL_GPIO_PIN_10 -#define POWER_I2C_SDA_GPIO_Port GPIOA - -#define POWER_I2C I2C1 -/* Timing register value is computed with the STM32CubeMX Tool, - * Fast Mode @100kHz with I2CCLK = 64 MHz, - * rise time = 0ns, fall time = 0ns - */ -#define POWER_I2C_TIMINGS 0x10707DBC - /* Input Keys */ typedef enum { InputKeyUp, @@ -77,6 +65,9 @@ extern const GpioPin gpio_irda_tx; extern const GpioPin gpio_usart_tx; extern const GpioPin gpio_usart_rx; +extern const GpioPin gpio_i2c_power_sda; +extern const GpioPin gpio_i2c_power_scl; + #ifdef __cplusplus } #endif diff --git a/bootloader/targets/f7/furi-hal/furi-hal-i2c-config.c b/bootloader/targets/f7/furi-hal/furi-hal-i2c-config.c new file mode 100644 index 00000000..afaab237 --- /dev/null +++ b/bootloader/targets/f7/furi-hal/furi-hal-i2c-config.c @@ -0,0 +1,149 @@ +#include "furi-hal-i2c-config.h" +#include +#include + +#include +#include + +/** Timing register value is computed with the STM32CubeMX Tool, + * Standard Mode @100kHz with I2CCLK = 64 MHz, + * rise time = 0ns, fall time = 0ns + */ +#define FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100 0x10707DBC + +/** Timing register value is computed with the STM32CubeMX Tool, + * Fast Mode @400kHz with I2CCLK = 64 MHz, + * rise time = 0ns, fall time = 0ns + */ +#define FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_400 0x00602173 + +static void furi_hal_i2c_bus_power_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) { + if(event == FuriHalI2cBusEventInit) { + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); + LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); + LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1); + bus->current_handle = NULL; + } else if(event == FuriHalI2cBusEventDeinit) { + } else if(event == FuriHalI2cBusEventLock) { + } else if(event == FuriHalI2cBusEventUnlock) { + } else if(event == FuriHalI2cBusEventActivate) { + LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C1); + } else if(event == FuriHalI2cBusEventDeactivate) { + LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1); + } +} + +FuriHalI2cBus furi_hal_i2c_bus_power = { + .i2c = I2C1, + .current_handle = NULL, + .callback = furi_hal_i2c_bus_power_event, +}; + +static void furi_hal_i2c_bus_external_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) { + if(event == FuriHalI2cBusEventActivate) { + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C3); + LL_RCC_SetI2CClockSource(LL_RCC_I2C3_CLKSOURCE_PCLK1); + LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C3); + } else if(event == FuriHalI2cBusEventDeactivate) { + LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C3); + } +} + +FuriHalI2cBus furi_hal_i2c_bus_external = { + .i2c = I2C3, + .current_handle = NULL, + .callback = furi_hal_i2c_bus_external_event, +}; + +void furi_hal_i2c_bus_handle_power_event( + FuriHalI2cBusHandle* handle, + FuriHalI2cBusHandleEvent event) { + if(event == FuriHalI2cBusHandleEventActivate) { + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); + hal_gpio_init_ex( + &gpio_i2c_power_sda, + GpioModeAltFunctionOpenDrain, + GpioPullNo, + GpioSpeedLow, + GpioAltFn4I2C1); + hal_gpio_init_ex( + &gpio_i2c_power_scl, + GpioModeAltFunctionOpenDrain, + GpioPullNo, + GpioSpeedLow, + GpioAltFn4I2C1); + + LL_I2C_InitTypeDef I2C_InitStruct = {0}; + I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C; + I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE; + I2C_InitStruct.DigitalFilter = 0; + I2C_InitStruct.OwnAddress1 = 0; + I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK; + I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT; + if(furi_hal_version_get_hw_version() > 10) { + I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_400; + } else { + I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100; + } + LL_I2C_Init(handle->bus->i2c, &I2C_InitStruct); + + LL_I2C_EnableAutoEndMode(handle->bus->i2c); + LL_I2C_SetOwnAddress2(handle->bus->i2c, 0, LL_I2C_OWNADDRESS2_NOMASK); + LL_I2C_DisableOwnAddress2(handle->bus->i2c); + LL_I2C_DisableGeneralCall(handle->bus->i2c); + LL_I2C_EnableClockStretching(handle->bus->i2c); + LL_I2C_Enable(handle->bus->i2c); + } else if(event == FuriHalI2cBusHandleEventDeactivate) { + LL_I2C_Disable(handle->bus->i2c); + hal_gpio_write(&gpio_i2c_power_sda, 1); + hal_gpio_write(&gpio_i2c_power_scl, 1); + hal_gpio_init_ex( + &gpio_i2c_power_sda, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused); + hal_gpio_init_ex( + &gpio_i2c_power_scl, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused); + } +} + +FuriHalI2cBusHandle furi_hal_i2c_handle_power = { + .bus = &furi_hal_i2c_bus_power, + .callback = furi_hal_i2c_bus_handle_power_event, +}; + +void furi_hal_i2c_bus_handle_external_event( + FuriHalI2cBusHandle* handle, + FuriHalI2cBusHandleEvent event) { + if(event == FuriHalI2cBusHandleEventActivate) { + hal_gpio_init_ex( + &gpio_ext_pc0, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C3); + hal_gpio_init_ex( + &gpio_ext_pc1, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C3); + + LL_I2C_InitTypeDef I2C_InitStruct = {0}; + I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C; + I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE; + I2C_InitStruct.DigitalFilter = 0; + I2C_InitStruct.OwnAddress1 = 0; + I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK; + I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT; + I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100; + LL_I2C_Init(handle->bus->i2c, &I2C_InitStruct); + + LL_I2C_EnableAutoEndMode(handle->bus->i2c); + LL_I2C_SetOwnAddress2(handle->bus->i2c, 0, LL_I2C_OWNADDRESS2_NOMASK); + LL_I2C_DisableOwnAddress2(handle->bus->i2c); + LL_I2C_DisableGeneralCall(handle->bus->i2c); + LL_I2C_EnableClockStretching(handle->bus->i2c); + LL_I2C_Enable(handle->bus->i2c); + } else if(event == FuriHalI2cBusHandleEventDeactivate) { + LL_I2C_Disable(handle->bus->i2c); + hal_gpio_write(&gpio_ext_pc0, 1); + hal_gpio_write(&gpio_ext_pc1, 1); + hal_gpio_init_ex(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused); + hal_gpio_init_ex(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused); + } +} + +FuriHalI2cBusHandle furi_hal_i2c_handle_external = { + .bus = &furi_hal_i2c_bus_external, + .callback = furi_hal_i2c_bus_handle_external_event, +}; diff --git a/bootloader/targets/f7/furi-hal/furi-hal-i2c-config.h b/bootloader/targets/f7/furi-hal/furi-hal-i2c-config.h new file mode 100644 index 00000000..2094dca3 --- /dev/null +++ b/bootloader/targets/f7/furi-hal/furi-hal-i2c-config.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Internal(power) i2c bus, I2C1, under reset when not used */ +extern FuriHalI2cBus furi_hal_i2c_bus_power; + +/** External i2c bus, I2C3, under reset when not used */ +extern FuriHalI2cBus furi_hal_i2c_bus_external; + +/** Handle for internal(power) i2c bus + * Bus: furi_hal_i2c_bus_external + * Pins: PA9(SCL) / PA10(SDA), float on release + * Params: 400khz + */ +extern FuriHalI2cBusHandle furi_hal_i2c_handle_power; + +/** Handle for external i2c bus + * Bus: furi_hal_i2c_bus_external + * Pins: PC0(SCL) / PC1(SDA), float on release + * Params: 100khz + */ +extern FuriHalI2cBusHandle furi_hal_i2c_handle_external; + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/bootloader/targets/f7/furi-hal/furi-hal-i2c-types.h b/bootloader/targets/f7/furi-hal/furi-hal-i2c-types.h new file mode 100644 index 00000000..0f2b735e --- /dev/null +++ b/bootloader/targets/f7/furi-hal/furi-hal-i2c-types.h @@ -0,0 +1,51 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct FuriHalI2cBus FuriHalI2cBus; +typedef struct FuriHalI2cBusHandle FuriHalI2cBusHandle; + +/** FuriHal i2c bus states */ +typedef enum { + FuriHalI2cBusEventInit, /**< Bus initialization event, called on system start */ + FuriHalI2cBusEventDeinit, /**< Bus deinitialization event, called on system stop */ + FuriHalI2cBusEventLock, /**< Bus lock event, called before activation */ + FuriHalI2cBusEventUnlock, /**< Bus unlock event, called after deactivation */ + FuriHalI2cBusEventActivate, /**< Bus activation event, called before handle activation */ + FuriHalI2cBusEventDeactivate, /**< Bus deactivation event, called after handle deactivation */ +} FuriHalI2cBusEvent; + +/** FuriHal i2c bus event callback */ +typedef void (*FuriHalI2cBusEventCallback)(FuriHalI2cBus* bus, FuriHalI2cBusEvent event); + +/** FuriHal i2c bus */ +struct FuriHalI2cBus { + I2C_TypeDef* i2c; + FuriHalI2cBusHandle* current_handle; + FuriHalI2cBusEventCallback callback; +}; + +/** FuriHal i2c handle states */ +typedef enum { + FuriHalI2cBusHandleEventActivate, /**< Handle activate: connect gpio and apply bus config */ + FuriHalI2cBusHandleEventDeactivate, /**< Handle deactivate: disconnect gpio and reset bus config */ +} FuriHalI2cBusHandleEvent; + +/** FuriHal i2c handle event callback */ +typedef void (*FuriHalI2cBusHandleEventCallback)( + FuriHalI2cBusHandle* handle, + FuriHalI2cBusHandleEvent event); + +/** FuriHal i2c handle */ +struct FuriHalI2cBusHandle { + FuriHalI2cBus* bus; + FuriHalI2cBusHandleEventCallback callback; +}; + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/bootloader/targets/f7/furi-hal/furi-hal-i2c.c b/bootloader/targets/f7/furi-hal/furi-hal-i2c.c index c40a70af..f276ff75 100644 --- a/bootloader/targets/f7/furi-hal/furi-hal-i2c.c +++ b/bootloader/targets/f7/furi-hal/furi-hal-i2c.c @@ -1,66 +1,64 @@ #include +#include -#include #include -#include #include #include +#include + void furi_hal_i2c_init() { - LL_I2C_InitTypeDef I2C_InitStruct = {0}; - LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; + furi_hal_i2c_bus_power.callback(&furi_hal_i2c_bus_power, FuriHalI2cBusEventInit); +} - LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); +void furi_hal_i2c_acquire(FuriHalI2cBusHandle* handle) { + handle->bus->callback(handle->bus, FuriHalI2cBusEventLock); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); - GPIO_InitStruct.Pin = POWER_I2C_SCL_Pin | POWER_I2C_SDA_Pin; - GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; - GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW; - GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN; - GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; - GPIO_InitStruct.Alternate = LL_GPIO_AF_4; - LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + assert(handle->bus->current_handle == NULL); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); + handle->bus->current_handle = handle; - I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C; - I2C_InitStruct.Timing = POWER_I2C_TIMINGS; - I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE; - I2C_InitStruct.DigitalFilter = 0; - I2C_InitStruct.OwnAddress1 = 0; - I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK; - I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT; - LL_I2C_Init(I2C1, &I2C_InitStruct); - LL_I2C_EnableAutoEndMode(I2C1); - LL_I2C_SetOwnAddress2(I2C1, 0, LL_I2C_OWNADDRESS2_NOMASK); - LL_I2C_DisableOwnAddress2(I2C1); - LL_I2C_DisableGeneralCall(I2C1); - LL_I2C_EnableClockStretching(I2C1); + handle->bus->callback(handle->bus, FuriHalI2cBusEventActivate); + + handle->callback(handle, FuriHalI2cBusHandleEventActivate); +} + +void furi_hal_i2c_release(FuriHalI2cBusHandle* handle) { + assert(handle->bus->current_handle == handle); + + handle->callback(handle, FuriHalI2cBusHandleEventDeactivate); + + handle->bus->callback(handle->bus, FuriHalI2cBusEventDeactivate); + + handle->bus->current_handle = NULL; + + handle->bus->callback(handle->bus, FuriHalI2cBusEventUnlock); } bool furi_hal_i2c_tx( - I2C_TypeDef* instance, + FuriHalI2cBusHandle* handle, uint8_t address, const uint8_t* data, uint8_t size, uint32_t timeout) { + assert(handle->bus->current_handle == handle); uint32_t time_left = timeout; bool ret = true; - while(LL_I2C_IsActiveFlag_BUSY(instance)) + while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c)) ; LL_I2C_HandleTransfer( - instance, + handle->bus->i2c, address, LL_I2C_ADDRSLAVE_7BIT, size, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_WRITE); - while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) { - if(LL_I2C_IsActiveFlag_TXIS(instance)) { - LL_I2C_TransmitData8(instance, (*data)); + while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) { + if(LL_I2C_IsActiveFlag_TXIS(handle->bus->i2c)) { + LL_I2C_TransmitData8(handle->bus->i2c, (*data)); data++; size--; time_left = timeout; @@ -74,34 +72,35 @@ bool furi_hal_i2c_tx( } } - LL_I2C_ClearFlag_STOP(instance); + LL_I2C_ClearFlag_STOP(handle->bus->i2c); return ret; } bool furi_hal_i2c_rx( - I2C_TypeDef* instance, + FuriHalI2cBusHandle* handle, uint8_t address, uint8_t* data, uint8_t size, uint32_t timeout) { + assert(handle->bus->current_handle == handle); uint32_t time_left = timeout; bool ret = true; - while(LL_I2C_IsActiveFlag_BUSY(instance)) + while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c)) ; LL_I2C_HandleTransfer( - instance, + handle->bus->i2c, address, LL_I2C_ADDRSLAVE_7BIT, size, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_READ); - while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) { - if(LL_I2C_IsActiveFlag_RXNE(instance)) { - *data = LL_I2C_ReceiveData8(instance); + while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) { + if(LL_I2C_IsActiveFlag_RXNE(handle->bus->i2c)) { + *data = LL_I2C_ReceiveData8(handle->bus->i2c); data++; size--; time_left = timeout; @@ -115,21 +114,21 @@ bool furi_hal_i2c_rx( } } - LL_I2C_ClearFlag_STOP(instance); + LL_I2C_ClearFlag_STOP(handle->bus->i2c); return ret; } bool furi_hal_i2c_trx( - I2C_TypeDef* instance, + FuriHalI2cBusHandle* handle, uint8_t address, const uint8_t* tx_data, uint8_t tx_size, uint8_t* rx_data, uint8_t rx_size, uint32_t timeout) { - if(furi_hal_i2c_tx(instance, address, tx_data, tx_size, timeout) && - furi_hal_i2c_rx(instance, address, rx_data, rx_size, timeout)) { + if(furi_hal_i2c_tx(handle, address, tx_data, tx_size, timeout) && + furi_hal_i2c_rx(handle, address, rx_data, rx_size, timeout)) { return true; } else { return false; diff --git a/bootloader/targets/f7/furi-hal/furi-hal-i2c.h b/bootloader/targets/f7/furi-hal/furi-hal-i2c.h index 5db562e0..7ef1db44 100644 --- a/bootloader/targets/f7/furi-hal/furi-hal-i2c.h +++ b/bootloader/targets/f7/furi-hal/furi-hal-i2c.h @@ -1,31 +1,82 @@ +/** + * @file furi-hal-i2c.h + * I2C HAL API + */ + #pragma once #include #include -#include +#include #ifdef __cplusplus extern "C" { #endif +/** Init I2C + */ void furi_hal_i2c_init(); +/** Acquire i2c bus handle + * + * @return Instance of FuriHalI2cBus + */ +void furi_hal_i2c_acquire(FuriHalI2cBusHandle* handle); + +/** Release i2c bus handle + * + * @param bus instance of FuriHalI2cBus aquired in `furi_hal_i2c_acquire` + */ +void furi_hal_i2c_release(FuriHalI2cBusHandle* handle); + +/** Perform I2C tx transfer + * + * @param instance I2C_TypeDef instance + * @param address I2C slave address + * @param data pointer to data buffer + * @param size size of data buffer + * @param timeout timeout in ticks + * + * @return true on successful transfer, false otherwise + */ bool furi_hal_i2c_tx( - I2C_TypeDef* instance, + FuriHalI2cBusHandle* handle, const uint8_t address, const uint8_t* data, const uint8_t size, uint32_t timeout); +/** Perform I2C rx transfer + * + * @param instance I2C_TypeDef instance + * @param address I2C slave address + * @param data pointer to data buffer + * @param size size of data buffer + * @param timeout timeout in ticks + * + * @return true on successful transfer, false otherwise + */ bool furi_hal_i2c_rx( - I2C_TypeDef* instance, + FuriHalI2cBusHandle* handle, const uint8_t address, uint8_t* data, const uint8_t size, uint32_t timeout); +/** Perform I2C tx and rx transfers + * + * @param instance I2C_TypeDef instance + * @param address I2C slave address + * @param tx_data pointer to tx data buffer + * @param tx_size size of tx data buffer + * @param rx_data pointer to rx data buffer + * @param rx_size size of rx data buffer + * @param timeout timeout in ticks + * + * @return true on successful transfer, false otherwise + */ bool furi_hal_i2c_trx( - I2C_TypeDef* instance, + FuriHalI2cBusHandle* handle, const uint8_t address, const uint8_t* tx_data, const uint8_t tx_size, @@ -33,11 +84,6 @@ bool furi_hal_i2c_trx( const uint8_t rx_size, uint32_t timeout); -#define with_furi_hal_i2c(type, pointer, function_body) \ - { \ - *pointer = ({ type __fn__ function_body __fn__; })(); \ - } - #ifdef __cplusplus } #endif diff --git a/bootloader/targets/f7/furi-hal/furi-hal-light.c b/bootloader/targets/f7/furi-hal/furi-hal-light.c index d5f54f6d..15a69f09 100644 --- a/bootloader/targets/f7/furi-hal/furi-hal-light.c +++ b/bootloader/targets/f7/furi-hal/furi-hal-light.c @@ -7,37 +7,43 @@ #define LED_CURRENT_WHITE 150 void furi_hal_light_init() { - lp5562_reset(); + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); - lp5562_set_channel_current(LP5562ChannelRed, LED_CURRENT_RED); - lp5562_set_channel_current(LP5562ChannelGreen, LED_CURRENT_GREEN); - lp5562_set_channel_current(LP5562ChannelBlue, LED_CURRENT_BLUE); - lp5562_set_channel_current(LP5562ChannelWhite, LED_CURRENT_WHITE); + lp5562_reset(&furi_hal_i2c_handle_power); - lp5562_set_channel_value(LP5562ChannelRed, 0x00); - lp5562_set_channel_value(LP5562ChannelGreen, 0x00); - lp5562_set_channel_value(LP5562ChannelBlue, 0x00); - lp5562_set_channel_value(LP5562ChannelWhite, 0x00); + lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelRed, LED_CURRENT_RED); + lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelGreen, LED_CURRENT_GREEN); + lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelBlue, LED_CURRENT_BLUE); + lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelWhite, LED_CURRENT_WHITE); - lp5562_enable(); - lp5562_configure(); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, 0x00); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, 0x00); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, 0x00); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, 0x00); + + lp5562_enable(&furi_hal_i2c_handle_power); + lp5562_configure(&furi_hal_i2c_handle_power); + + furi_hal_i2c_release(&furi_hal_i2c_handle_power); } void furi_hal_light_set(Light light, uint8_t value) { + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); switch(light) { case LightRed: - lp5562_set_channel_value(LP5562ChannelRed, value); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value); break; case LightGreen: - lp5562_set_channel_value(LP5562ChannelGreen, value); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value); break; case LightBlue: - lp5562_set_channel_value(LP5562ChannelBlue, value); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value); break; case LightBacklight: - lp5562_set_channel_value(LP5562ChannelWhite, value); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, value); break; default: break; } + furi_hal_i2c_release(&furi_hal_i2c_handle_power); } \ No newline at end of file diff --git a/bootloader/targets/f7/furi-hal/furi-hal-resources.c b/bootloader/targets/f7/furi-hal/furi-hal-resources.c index 1260a485..3af9ba03 100644 --- a/bootloader/targets/f7/furi-hal/furi-hal-resources.c +++ b/bootloader/targets/f7/furi-hal/furi-hal-resources.c @@ -39,3 +39,6 @@ const GpioPin gpio_irda_tx = {.port = IR_TX_GPIO_Port, .pin = IR_TX_Pin}; const GpioPin gpio_usart_tx = {.port = USART1_TX_Port, .pin = USART1_TX_Pin}; const GpioPin gpio_usart_rx = {.port = USART1_RX_Port, .pin = USART1_RX_Pin}; + +const GpioPin gpio_i2c_power_sda = {.port = GPIOA, .pin = LL_GPIO_PIN_10}; +const GpioPin gpio_i2c_power_scl = {.port = GPIOA, .pin = LL_GPIO_PIN_9}; diff --git a/bootloader/targets/f7/furi-hal/furi-hal-resources.h b/bootloader/targets/f7/furi-hal/furi-hal-resources.h index 95bb4d0d..42b9b315 100644 --- a/bootloader/targets/f7/furi-hal/furi-hal-resources.h +++ b/bootloader/targets/f7/furi-hal/furi-hal-resources.h @@ -8,18 +8,6 @@ extern "C" { #endif -#define POWER_I2C_SCL_Pin LL_GPIO_PIN_9 -#define POWER_I2C_SCL_GPIO_Port GPIOA -#define POWER_I2C_SDA_Pin LL_GPIO_PIN_10 -#define POWER_I2C_SDA_GPIO_Port GPIOA - -#define POWER_I2C I2C1 -/* Timing register value is computed with the STM32CubeMX Tool, - * Fast Mode @100kHz with I2CCLK = 64 MHz, - * rise time = 0ns, fall time = 0ns - */ -#define POWER_I2C_TIMINGS 0x10707DBC - /* Input Keys */ typedef enum { InputKeyUp, @@ -77,6 +65,9 @@ extern const GpioPin gpio_irda_tx; extern const GpioPin gpio_usart_tx; extern const GpioPin gpio_usart_rx; +extern const GpioPin gpio_i2c_power_sda; +extern const GpioPin gpio_i2c_power_scl; + #ifdef __cplusplus } #endif diff --git a/firmware/targets/f6/furi-hal/furi-hal-i2c-config.c b/firmware/targets/f6/furi-hal/furi-hal-i2c-config.c new file mode 100644 index 00000000..273d46b1 --- /dev/null +++ b/firmware/targets/f6/furi-hal/furi-hal-i2c-config.c @@ -0,0 +1,133 @@ +#include "furi-hal-i2c-config.h" +#include +#include + +/** 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 + +#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 + +#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 #include -#define TAG "FuriHalLight" - -#define LED_CURRENT_RED 50 -#define LED_CURRENT_GREEN 50 -#define LED_CURRENT_BLUE 50 -#define LED_CURRENT_WHITE 150 +#define LED_CURRENT_RED 50 +#define LED_CURRENT_GREEN 50 +#define LED_CURRENT_BLUE 50 +#define LED_CURRENT_WHITE 150 void furi_hal_light_init() { - lp5562_reset(); + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); - lp5562_set_channel_current(LP5562ChannelRed, LED_CURRENT_RED); - lp5562_set_channel_current(LP5562ChannelGreen, LED_CURRENT_GREEN); - lp5562_set_channel_current(LP5562ChannelBlue, LED_CURRENT_BLUE); - lp5562_set_channel_current(LP5562ChannelWhite, LED_CURRENT_WHITE); + lp5562_reset(&furi_hal_i2c_handle_power); - lp5562_set_channel_value(LP5562ChannelRed, 0x00); - lp5562_set_channel_value(LP5562ChannelGreen, 0x00); - lp5562_set_channel_value(LP5562ChannelBlue, 0x00); - lp5562_set_channel_value(LP5562ChannelWhite, 0x00); + lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelRed, LED_CURRENT_RED); + lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelGreen, LED_CURRENT_GREEN); + lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelBlue, LED_CURRENT_BLUE); + lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelWhite, LED_CURRENT_WHITE); - lp5562_enable(); - lp5562_configure(); - FURI_LOG_I(TAG, "Init OK"); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, 0x00); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, 0x00); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, 0x00); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, 0x00); + + lp5562_enable(&furi_hal_i2c_handle_power); + lp5562_configure(&furi_hal_i2c_handle_power); + + furi_hal_i2c_release(&furi_hal_i2c_handle_power); } void furi_hal_light_set(Light light, uint8_t value) { + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); switch(light) { - case LightRed: - lp5562_set_channel_value(LP5562ChannelRed, value); + case LightRed: + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value); break; - case LightGreen: - lp5562_set_channel_value(LP5562ChannelGreen, value); + case LightGreen: + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value); break; - case LightBlue: - lp5562_set_channel_value(LP5562ChannelBlue, value); + case LightBlue: + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value); break; - case LightBacklight: - lp5562_set_channel_value(LP5562ChannelWhite, value); + case LightBacklight: + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, value); break; - default: + default: break; } + furi_hal_i2c_release(&furi_hal_i2c_handle_power); } \ 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; +} + +static float furi_hal_power_get_battery_temperature_internal(FuriHalPowerIC ic) { + float ret = 0.0f; + + if (ic == FuriHalPowerICCharger) { + // Linear approximation, +/- 5 C + ret = (71.0f - (float)bq25896_get_ntc_mpct(&furi_hal_i2c_handle_power)/1000) / 0.6f; + } else if (ic == FuriHalPowerICFuelGauge) { + ret = ((float)bq27220_get_temperature(&furi_hal_i2c_handle_power) - 2731.0f) / 10.0f; } + + return ret; } float furi_hal_power_get_battery_temperature(FuriHalPowerIC ic) { - if (ic == FuriHalPowerICCharger) { - // Linear approximation, +/- 5 C - return (71.0f - (float)bq25896_get_ntc_mpct()/1000) / 0.6f; - } else if (ic == FuriHalPowerICFuelGauge) { - return ((float)bq27220_get_temperature() - 2731.0f) / 10.0f; - } else { - return 0.0f; - } - + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); + float ret = furi_hal_power_get_battery_temperature_internal(ic); + furi_hal_i2c_release(&furi_hal_i2c_handle_power); + + return ret; } float furi_hal_power_get_usb_voltage(){ - return (float)bq25896_get_vbus_voltage() / 1000.0f; + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); + float ret = (float)bq25896_get_vbus_voltage(&furi_hal_i2c_handle_power) / 1000.0f; + furi_hal_i2c_release(&furi_hal_i2c_handle_power); + return ret; } void furi_hal_power_dump_state() { BatteryStatus battery_status; OperationStatus operation_status; - if (bq27220_get_battery_status(&battery_status) == BQ27220_ERROR - || bq27220_get_operation_status(&operation_status) == BQ27220_ERROR) { + + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); + + if (bq27220_get_battery_status(&furi_hal_i2c_handle_power, &battery_status) == BQ27220_ERROR + || bq27220_get_operation_status(&furi_hal_i2c_handle_power, &operation_status) == BQ27220_ERROR) { printf("Failed to get bq27220 status. Communication error.\r\n"); } else { printf( @@ -266,21 +317,23 @@ void furi_hal_power_dump_state() { // Voltage and current info printf( "bq27220: Full capacity: %dmAh, Design capacity: %dmAh, Remaining capacity: %dmAh, State of Charge: %d%%, State of health: %d%%\r\n", - bq27220_get_full_charge_capacity(), bq27220_get_design_capacity(), bq27220_get_remaining_capacity(), - bq27220_get_state_of_charge(), bq27220_get_state_of_health() + bq27220_get_full_charge_capacity(&furi_hal_i2c_handle_power), bq27220_get_design_capacity(&furi_hal_i2c_handle_power), bq27220_get_remaining_capacity(&furi_hal_i2c_handle_power), + bq27220_get_state_of_charge(&furi_hal_i2c_handle_power), bq27220_get_state_of_health(&furi_hal_i2c_handle_power) ); printf( "bq27220: Voltage: %dmV, Current: %dmA, Temperature: %dC\r\n", - bq27220_get_voltage(), bq27220_get_current(), (int)furi_hal_power_get_battery_temperature(FuriHalPowerICFuelGauge) + bq27220_get_voltage(&furi_hal_i2c_handle_power), bq27220_get_current(&furi_hal_i2c_handle_power), (int)furi_hal_power_get_battery_temperature_internal(FuriHalPowerICFuelGauge) ); } printf( "bq25896: VBUS: %d, VSYS: %d, VBAT: %d, Current: %d, NTC: %ldm%%\r\n", - bq25896_get_vbus_voltage(), bq25896_get_vsys_voltage(), - bq25896_get_vbat_voltage(), bq25896_get_vbat_current(), - bq25896_get_ntc_mpct() + bq25896_get_vbus_voltage(&furi_hal_i2c_handle_power), bq25896_get_vsys_voltage(&furi_hal_i2c_handle_power), + bq25896_get_vbat_voltage(&furi_hal_i2c_handle_power), bq25896_get_vbat_current(&furi_hal_i2c_handle_power), + bq25896_get_ntc_mpct(&furi_hal_i2c_handle_power) ); + + furi_hal_i2c_release(&furi_hal_i2c_handle_power); } void furi_hal_power_enable_external_3_3v(){ @@ -298,7 +351,9 @@ void furi_hal_power_suppress_charge_enter() { xTaskResumeAll(); if (disable_charging) { - bq25896_disable_charging(); + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); + bq25896_disable_charging(&furi_hal_i2c_handle_power); + furi_hal_i2c_release(&furi_hal_i2c_handle_power); } } @@ -309,6 +364,8 @@ void furi_hal_power_suppress_charge_exit() { xTaskResumeAll(); if (enable_charging) { - bq25896_enable_charging(); + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); + bq25896_enable_charging(&furi_hal_i2c_handle_power); + furi_hal_i2c_release(&furi_hal_i2c_handle_power); } } \ 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 +#include + +/** 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 + +#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 + +#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 #include -#define TAG "FuriHalLight" - -#define LED_CURRENT_RED 50 -#define LED_CURRENT_GREEN 50 -#define LED_CURRENT_BLUE 50 -#define LED_CURRENT_WHITE 150 +#define LED_CURRENT_RED 50 +#define LED_CURRENT_GREEN 50 +#define LED_CURRENT_BLUE 50 +#define LED_CURRENT_WHITE 150 void furi_hal_light_init() { - lp5562_reset(); + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); - lp5562_set_channel_current(LP5562ChannelRed, LED_CURRENT_RED); - lp5562_set_channel_current(LP5562ChannelGreen, LED_CURRENT_GREEN); - lp5562_set_channel_current(LP5562ChannelBlue, LED_CURRENT_BLUE); - lp5562_set_channel_current(LP5562ChannelWhite, LED_CURRENT_WHITE); + lp5562_reset(&furi_hal_i2c_handle_power); - lp5562_set_channel_value(LP5562ChannelRed, 0x00); - lp5562_set_channel_value(LP5562ChannelGreen, 0x00); - lp5562_set_channel_value(LP5562ChannelBlue, 0x00); - lp5562_set_channel_value(LP5562ChannelWhite, 0x00); + lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelRed, LED_CURRENT_RED); + lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelGreen, LED_CURRENT_GREEN); + lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelBlue, LED_CURRENT_BLUE); + lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelWhite, LED_CURRENT_WHITE); - lp5562_enable(); - lp5562_configure(); - FURI_LOG_I(TAG, "Init OK"); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, 0x00); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, 0x00); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, 0x00); + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, 0x00); + + lp5562_enable(&furi_hal_i2c_handle_power); + lp5562_configure(&furi_hal_i2c_handle_power); + + furi_hal_i2c_release(&furi_hal_i2c_handle_power); } void furi_hal_light_set(Light light, uint8_t value) { + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); switch(light) { - case LightRed: - lp5562_set_channel_value(LP5562ChannelRed, value); + case LightRed: + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value); break; - case LightGreen: - lp5562_set_channel_value(LP5562ChannelGreen, value); + case LightGreen: + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value); break; - case LightBlue: - lp5562_set_channel_value(LP5562ChannelBlue, value); + case LightBlue: + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value); break; - case LightBacklight: - lp5562_set_channel_value(LP5562ChannelWhite, value); + case LightBacklight: + lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, value); break; - default: + default: break; } + furi_hal_i2c_release(&furi_hal_i2c_handle_power); } \ 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; +} + +static float furi_hal_power_get_battery_temperature_internal(FuriHalPowerIC ic) { + float ret = 0.0f; + + if (ic == FuriHalPowerICCharger) { + // Linear approximation, +/- 5 C + ret = (71.0f - (float)bq25896_get_ntc_mpct(&furi_hal_i2c_handle_power)/1000) / 0.6f; + } else if (ic == FuriHalPowerICFuelGauge) { + ret = ((float)bq27220_get_temperature(&furi_hal_i2c_handle_power) - 2731.0f) / 10.0f; } + + return ret; } float furi_hal_power_get_battery_temperature(FuriHalPowerIC ic) { - if (ic == FuriHalPowerICCharger) { - // Linear approximation, +/- 5 C - return (71.0f - (float)bq25896_get_ntc_mpct()/1000) / 0.6f; - } else if (ic == FuriHalPowerICFuelGauge) { - return ((float)bq27220_get_temperature() - 2731.0f) / 10.0f; - } else { - return 0.0f; - } - + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); + float ret = furi_hal_power_get_battery_temperature_internal(ic); + furi_hal_i2c_release(&furi_hal_i2c_handle_power); + + return ret; } float furi_hal_power_get_usb_voltage(){ - return (float)bq25896_get_vbus_voltage() / 1000.0f; + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); + float ret = (float)bq25896_get_vbus_voltage(&furi_hal_i2c_handle_power) / 1000.0f; + furi_hal_i2c_release(&furi_hal_i2c_handle_power); + return ret; } void furi_hal_power_dump_state() { BatteryStatus battery_status; OperationStatus operation_status; - if (bq27220_get_battery_status(&battery_status) == BQ27220_ERROR - || bq27220_get_operation_status(&operation_status) == BQ27220_ERROR) { + + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); + + if (bq27220_get_battery_status(&furi_hal_i2c_handle_power, &battery_status) == BQ27220_ERROR + || bq27220_get_operation_status(&furi_hal_i2c_handle_power, &operation_status) == BQ27220_ERROR) { printf("Failed to get bq27220 status. Communication error.\r\n"); } else { printf( @@ -266,21 +317,23 @@ void furi_hal_power_dump_state() { // Voltage and current info printf( "bq27220: Full capacity: %dmAh, Design capacity: %dmAh, Remaining capacity: %dmAh, State of Charge: %d%%, State of health: %d%%\r\n", - bq27220_get_full_charge_capacity(), bq27220_get_design_capacity(), bq27220_get_remaining_capacity(), - bq27220_get_state_of_charge(), bq27220_get_state_of_health() + bq27220_get_full_charge_capacity(&furi_hal_i2c_handle_power), bq27220_get_design_capacity(&furi_hal_i2c_handle_power), bq27220_get_remaining_capacity(&furi_hal_i2c_handle_power), + bq27220_get_state_of_charge(&furi_hal_i2c_handle_power), bq27220_get_state_of_health(&furi_hal_i2c_handle_power) ); printf( "bq27220: Voltage: %dmV, Current: %dmA, Temperature: %dC\r\n", - bq27220_get_voltage(), bq27220_get_current(), (int)furi_hal_power_get_battery_temperature(FuriHalPowerICFuelGauge) + bq27220_get_voltage(&furi_hal_i2c_handle_power), bq27220_get_current(&furi_hal_i2c_handle_power), (int)furi_hal_power_get_battery_temperature_internal(FuriHalPowerICFuelGauge) ); } printf( "bq25896: VBUS: %d, VSYS: %d, VBAT: %d, Current: %d, NTC: %ldm%%\r\n", - bq25896_get_vbus_voltage(), bq25896_get_vsys_voltage(), - bq25896_get_vbat_voltage(), bq25896_get_vbat_current(), - bq25896_get_ntc_mpct() + bq25896_get_vbus_voltage(&furi_hal_i2c_handle_power), bq25896_get_vsys_voltage(&furi_hal_i2c_handle_power), + bq25896_get_vbat_voltage(&furi_hal_i2c_handle_power), bq25896_get_vbat_current(&furi_hal_i2c_handle_power), + bq25896_get_ntc_mpct(&furi_hal_i2c_handle_power) ); + + furi_hal_i2c_release(&furi_hal_i2c_handle_power); } void furi_hal_power_enable_external_3_3v(){ @@ -298,7 +351,9 @@ void furi_hal_power_suppress_charge_enter() { xTaskResumeAll(); if (disable_charging) { - bq25896_disable_charging(); + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); + bq25896_disable_charging(&furi_hal_i2c_handle_power); + furi_hal_i2c_release(&furi_hal_i2c_handle_power); } } @@ -309,6 +364,8 @@ void furi_hal_power_suppress_charge_exit() { xTaskResumeAll(); if (enable_charging) { - bq25896_enable_charging(); + furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); + bq25896_enable_charging(&furi_hal_i2c_handle_power); + furi_hal_i2c_release(&furi_hal_i2c_handle_power); } } \ 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 -#include - -#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 #include -#include +#include #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 similarity index 98% rename from firmware/targets/f6/furi-hal/furi-hal-spi.h rename to firmware/targets/furi-hal-include/furi-hal-spi.h index 638e713a..e42dcdc4 100644 --- a/firmware/targets/f6/furi-hal/furi-hal-spi.h +++ b/firmware/targets/furi-hal-include/furi-hal-spi.h @@ -25,8 +25,7 @@ void furi_hal_spi_bus_lock(const FuriHalSpiBus* bus); */ void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus); -/** - * Configure SPI bus +/** Configure SPI bus * @param bus - spi bus handler * @param config - spi configuration structure */ diff --git a/lib/drivers/bq25896.c b/lib/drivers/bq25896.c index 9062653b..3f923b97 100644 --- a/lib/drivers/bq25896.c +++ b/lib/drivers/bq25896.c @@ -1,7 +1,6 @@ #include "bq25896.h" #include "bq25896_reg.h" -#include #include uint8_t bit_reverse(uint8_t b) { @@ -11,29 +10,17 @@ uint8_t bit_reverse(uint8_t b) { return b; } -bool bq25896_read(uint8_t address, uint8_t* data, size_t size) { - bool ret; - with_furi_hal_i2c( - bool, &ret, () { - return furi_hal_i2c_trx( - POWER_I2C, BQ25896_ADDRESS, &address, 1, data, size, BQ25896_I2C_TIMEOUT); - }); - return ret; +bool bq25896_read(FuriHalI2cBusHandle* handle, uint8_t address, uint8_t* data, size_t size) { + return furi_hal_i2c_trx(handle, BQ25896_ADDRESS, &address, 1, data, size, BQ25896_I2C_TIMEOUT); } -bool bq25896_read_reg(uint8_t address, uint8_t* data) { - bq25896_read(address, data, 1); - return true; +bool bq25896_read_reg(FuriHalI2cBusHandle* handle, uint8_t address, uint8_t* data) { + return bq25896_read(handle, address, data, 1); } -bool bq25896_write_reg(uint8_t address, uint8_t* data) { +bool bq25896_write_reg(FuriHalI2cBusHandle* handle, uint8_t address, uint8_t* data) { uint8_t buffer[2] = {address, *data}; - bool ret; - with_furi_hal_i2c( - bool, &ret, () { - return furi_hal_i2c_tx(POWER_I2C, BQ25896_ADDRESS, buffer, 2, BQ25896_I2C_TIMEOUT); - }); - return ret; + return furi_hal_i2c_tx(handle, BQ25896_ADDRESS, buffer, 2, BQ25896_I2C_TIMEOUT); } typedef struct { @@ -62,62 +49,62 @@ typedef struct { static bq25896_regs_t bq25896_regs; -void bq25896_init() { +void bq25896_init(FuriHalI2cBusHandle* handle) { bq25896_regs.r14.REG_RST = 1; - bq25896_write_reg(0x14, (uint8_t*)&bq25896_regs.r14); + bq25896_write_reg(handle, 0x14, (uint8_t*)&bq25896_regs.r14); // Readout all registers - bq25896_read(0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs)); + bq25896_read(handle, 0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs)); // Poll ADC forever bq25896_regs.r02.CONV_START = 1; bq25896_regs.r02.CONV_RATE = 1; - bq25896_write_reg(0x02, (uint8_t*)&bq25896_regs.r02); + bq25896_write_reg(handle, 0x02, (uint8_t*)&bq25896_regs.r02); bq25896_regs.r07.WATCHDOG = WatchdogDisable; - bq25896_write_reg(0x07, (uint8_t*)&bq25896_regs.r07); + bq25896_write_reg(handle, 0x07, (uint8_t*)&bq25896_regs.r07); - bq25896_read(0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs)); + bq25896_read(handle, 0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs)); } -void bq25896_poweroff() { +void bq25896_poweroff(FuriHalI2cBusHandle* handle) { bq25896_regs.r09.BATFET_DIS = 1; - bq25896_write_reg(0x09, (uint8_t*)&bq25896_regs.r09); + bq25896_write_reg(handle, 0x09, (uint8_t*)&bq25896_regs.r09); } -bool bq25896_is_charging() { - bq25896_read(0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs)); - bq25896_read_reg(0x0B, (uint8_t*)&bq25896_regs.r0B); +bool bq25896_is_charging(FuriHalI2cBusHandle* handle) { + bq25896_read(handle, 0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs)); + bq25896_read_reg(handle, 0x0B, (uint8_t*)&bq25896_regs.r0B); return bq25896_regs.r0B.CHRG_STAT != ChrgStatNo; } -void bq25896_enable_charging() { +void bq25896_enable_charging(FuriHalI2cBusHandle* handle) { bq25896_regs.r03.CHG_CONFIG = 1; - bq25896_write_reg(0x03, (uint8_t*)&bq25896_regs.r03); + bq25896_write_reg(handle, 0x03, (uint8_t*)&bq25896_regs.r03); } -void bq25896_disable_charging() { +void bq25896_disable_charging(FuriHalI2cBusHandle* handle) { bq25896_regs.r03.CHG_CONFIG = 0; - bq25896_write_reg(0x03, (uint8_t*)&bq25896_regs.r03); + bq25896_write_reg(handle, 0x03, (uint8_t*)&bq25896_regs.r03); } -void bq25896_enable_otg() { +void bq25896_enable_otg(FuriHalI2cBusHandle* handle) { bq25896_regs.r03.OTG_CONFIG = 1; - bq25896_write_reg(0x03, (uint8_t*)&bq25896_regs.r03); + bq25896_write_reg(handle, 0x03, (uint8_t*)&bq25896_regs.r03); } -void bq25896_disable_otg() { +void bq25896_disable_otg(FuriHalI2cBusHandle* handle) { bq25896_regs.r03.OTG_CONFIG = 0; - bq25896_write_reg(0x03, (uint8_t*)&bq25896_regs.r03); + bq25896_write_reg(handle, 0x03, (uint8_t*)&bq25896_regs.r03); } -bool bq25896_is_otg_enabled() { - bq25896_read_reg(0x03, (uint8_t*)&bq25896_regs.r03); +bool bq25896_is_otg_enabled(FuriHalI2cBusHandle* handle) { + bq25896_read_reg(handle, 0x03, (uint8_t*)&bq25896_regs.r03); return bq25896_regs.r03.OTG_CONFIG; } -uint16_t bq25896_get_vbus_voltage() { - bq25896_read_reg(0x11, (uint8_t*)&bq25896_regs.r11); +uint16_t bq25896_get_vbus_voltage(FuriHalI2cBusHandle* handle) { + bq25896_read_reg(handle, 0x11, (uint8_t*)&bq25896_regs.r11); if(bq25896_regs.r11.VBUS_GD) { return (uint16_t)bq25896_regs.r11.VBUSV * 100 + 2600; } else { @@ -125,22 +112,22 @@ uint16_t bq25896_get_vbus_voltage() { } } -uint16_t bq25896_get_vsys_voltage() { - bq25896_read_reg(0x0F, (uint8_t*)&bq25896_regs.r0F); +uint16_t bq25896_get_vsys_voltage(FuriHalI2cBusHandle* handle) { + bq25896_read_reg(handle, 0x0F, (uint8_t*)&bq25896_regs.r0F); return (uint16_t)bq25896_regs.r0F.SYSV * 20 + 2304; } -uint16_t bq25896_get_vbat_voltage() { - bq25896_read_reg(0x0E, (uint8_t*)&bq25896_regs.r0E); +uint16_t bq25896_get_vbat_voltage(FuriHalI2cBusHandle* handle) { + bq25896_read_reg(handle, 0x0E, (uint8_t*)&bq25896_regs.r0E); return (uint16_t)bq25896_regs.r0E.BATV * 20 + 2304; } -uint16_t bq25896_get_vbat_current() { - bq25896_read_reg(0x12, (uint8_t*)&bq25896_regs.r12); +uint16_t bq25896_get_vbat_current(FuriHalI2cBusHandle* handle) { + bq25896_read_reg(handle, 0x12, (uint8_t*)&bq25896_regs.r12); return (uint16_t)bq25896_regs.r12.ICHGR * 50; } -uint32_t bq25896_get_ntc_mpct() { - bq25896_read_reg(0x10, (uint8_t*)&bq25896_regs.r10); +uint32_t bq25896_get_ntc_mpct(FuriHalI2cBusHandle* handle) { + bq25896_read_reg(handle, 0x10, (uint8_t*)&bq25896_regs.r10); return (uint32_t)bq25896_regs.r10.TSPCT * 465 + 21000; } diff --git a/lib/drivers/bq25896.h b/lib/drivers/bq25896.h index 03bf7ba2..c6c9a30b 100644 --- a/lib/drivers/bq25896.h +++ b/lib/drivers/bq25896.h @@ -2,42 +2,43 @@ #include #include +#include /** Initialize Driver */ -void bq25896_init(); +void bq25896_init(FuriHalI2cBusHandle* handle); /** Send device into shipping mode */ -void bq25896_poweroff(); +void bq25896_poweroff(FuriHalI2cBusHandle* handle); /** Is currently charging */ -bool bq25896_is_charging(); +bool bq25896_is_charging(FuriHalI2cBusHandle* handle); /** Enable charging */ -void bq25896_enable_charging(); +void bq25896_enable_charging(FuriHalI2cBusHandle* handle); /** Disable charging */ -void bq25896_disable_charging(); +void bq25896_disable_charging(FuriHalI2cBusHandle* handle); /** Enable otg */ -void bq25896_enable_otg(); +void bq25896_enable_otg(FuriHalI2cBusHandle* handle); /** Disable otg */ -void bq25896_disable_otg(); +void bq25896_disable_otg(FuriHalI2cBusHandle* handle); /** Is otg enabled */ -bool bq25896_is_otg_enabled(); +bool bq25896_is_otg_enabled(FuriHalI2cBusHandle* handle); /** Get VBUS Voltage in mV */ -uint16_t bq25896_get_vbus_voltage(); +uint16_t bq25896_get_vbus_voltage(FuriHalI2cBusHandle* handle); /** Get VSYS Voltage in mV */ -uint16_t bq25896_get_vsys_voltage(); +uint16_t bq25896_get_vsys_voltage(FuriHalI2cBusHandle* handle); /** Get VBAT Voltage in mV */ -uint16_t bq25896_get_vbat_voltage(); +uint16_t bq25896_get_vbat_voltage(FuriHalI2cBusHandle* handle); /** Get VBAT current in mA */ -uint16_t bq25896_get_vbat_current(); +uint16_t bq25896_get_vbat_current(FuriHalI2cBusHandle* handle); /** Get NTC voltage in mpct of REGN */ -uint32_t bq25896_get_ntc_mpct(); +uint32_t bq25896_get_ntc_mpct(FuriHalI2cBusHandle* handle); diff --git a/lib/drivers/bq27220.c b/lib/drivers/bq27220.c index 578e3849..8689db4a 100644 --- a/lib/drivers/bq27220.c +++ b/lib/drivers/bq27220.c @@ -1,37 +1,32 @@ #include "bq27220.h" #include "bq27220_reg.h" -#include #include +#include #include #define TAG "Gauge" -uint16_t bq27220_read_word(uint8_t address) { +uint16_t bq27220_read_word(FuriHalI2cBusHandle* handle, uint8_t address) { uint8_t buffer[2] = {address}; - uint16_t ret; - with_furi_hal_i2c( - uint16_t, &ret, () { - if(furi_hal_i2c_trx( - POWER_I2C, BQ27220_ADDRESS, buffer, 1, buffer, 2, BQ27220_I2C_TIMEOUT)) { - return *(uint16_t*)buffer; - } else { - return 0; - } - }); + uint16_t ret = 0; + + if(furi_hal_i2c_trx(handle, BQ27220_ADDRESS, buffer, 1, buffer, 2, BQ27220_I2C_TIMEOUT)) { + ret = *(uint16_t*)buffer; + } + return ret; } -bool bq27220_control(uint16_t control) { - bool ret; - with_furi_hal_i2c( - bool, &ret, () { - uint8_t buffer[3]; - buffer[0] = CommandControl; - buffer[1] = control & 0xFF; - buffer[2] = (control >> 8) & 0xFF; - return furi_hal_i2c_tx(POWER_I2C, BQ27220_ADDRESS, buffer, 3, BQ27220_I2C_TIMEOUT); - }); +bool bq27220_control(FuriHalI2cBusHandle* handle, uint16_t control) { + bool ret = false; + uint8_t buffer[3]; + + buffer[0] = CommandControl; + buffer[1] = control & 0xFF; + buffer[2] = (control >> 8) & 0xFF; + ret = furi_hal_i2c_tx(handle, BQ27220_ADDRESS, buffer, 3, BQ27220_I2C_TIMEOUT); + return ret; } @@ -43,75 +38,73 @@ uint8_t bq27220_get_checksum(uint8_t* data, uint16_t len) { return 0xFF - ret; } -bool bq27220_set_parameter_u16(uint16_t address, uint16_t value) { +bool bq27220_set_parameter_u16(FuriHalI2cBusHandle* handle, uint16_t address, uint16_t value) { bool ret; uint8_t buffer[5]; - with_furi_hal_i2c( - bool, &ret, () { - buffer[0] = CommandSelectSubclass; - buffer[1] = address & 0xFF; - buffer[2] = (address >> 8) & 0xFF; - buffer[3] = (value >> 8) & 0xFF; - buffer[4] = value & 0xFF; - return furi_hal_i2c_tx(POWER_I2C, BQ27220_ADDRESS, buffer, 5, BQ27220_I2C_TIMEOUT); - }); + + buffer[0] = CommandSelectSubclass; + buffer[1] = address & 0xFF; + buffer[2] = (address >> 8) & 0xFF; + buffer[3] = (value >> 8) & 0xFF; + buffer[4] = value & 0xFF; + ret = furi_hal_i2c_tx(handle, BQ27220_ADDRESS, buffer, 5, BQ27220_I2C_TIMEOUT); + delay_us(10000); + uint8_t checksum = bq27220_get_checksum(&buffer[1], 4); - with_furi_hal_i2c( - bool, &ret, () { - buffer[0] = CommandMACDataSum; - buffer[1] = checksum; - buffer[2] = 6; - return furi_hal_i2c_tx(POWER_I2C, BQ27220_ADDRESS, buffer, 3, BQ27220_I2C_TIMEOUT); - }); + buffer[0] = CommandMACDataSum; + buffer[1] = checksum; + buffer[2] = 6; + ret = furi_hal_i2c_tx(handle, BQ27220_ADDRESS, buffer, 3, BQ27220_I2C_TIMEOUT); + delay_us(10000); return ret; } -bool bq27220_init(const ParamCEDV* cedv) { +bool bq27220_init(FuriHalI2cBusHandle* handle, const ParamCEDV* cedv) { uint32_t timeout = 100; - uint16_t design_cap = bq27220_get_design_capacity(); + uint16_t design_cap = bq27220_get_design_capacity(handle); if(cedv->design_cap == design_cap) { FURI_LOG_I(TAG, "Skip battery profile update"); return true; } FURI_LOG_I(TAG, "Start updating battery profile"); OperationStatus status = {}; - if(!bq27220_control(Control_ENTER_CFG_UPDATE)) { + if(!bq27220_control(handle, Control_ENTER_CFG_UPDATE)) { FURI_LOG_E(TAG, "Can't configure update"); return false; }; while((status.CFGUPDATE != 1) && (timeout-- > 0)) { - bq27220_get_operation_status(&status); + bq27220_get_operation_status(handle, &status); } - bq27220_set_parameter_u16(AddressGaugingConfig, cedv->cedv_conf.gauge_conf_raw); - bq27220_set_parameter_u16(AddressFullChargeCapacity, cedv->full_charge_cap); - bq27220_set_parameter_u16(AddressDesignCapacity, cedv->design_cap); - bq27220_set_parameter_u16(AddressEMF, cedv->EMF); - bq27220_set_parameter_u16(AddressC0, cedv->C0); - bq27220_set_parameter_u16(AddressR0, cedv->R0); - bq27220_set_parameter_u16(AddressT0, cedv->T0); - bq27220_set_parameter_u16(AddressR1, cedv->R1); - bq27220_set_parameter_u16(AddressTC, (cedv->TC) << 8 | cedv->C1); - bq27220_set_parameter_u16(AddressStartDOD0, cedv->DOD0); - bq27220_set_parameter_u16(AddressStartDOD10, cedv->DOD10); - bq27220_set_parameter_u16(AddressStartDOD20, cedv->DOD20); - bq27220_set_parameter_u16(AddressStartDOD30, cedv->DOD30); - bq27220_set_parameter_u16(AddressStartDOD40, cedv->DOD40); - bq27220_set_parameter_u16(AddressStartDOD50, cedv->DOD40); - bq27220_set_parameter_u16(AddressStartDOD60, cedv->DOD60); - bq27220_set_parameter_u16(AddressStartDOD70, cedv->DOD70); - bq27220_set_parameter_u16(AddressStartDOD80, cedv->DOD80); - bq27220_set_parameter_u16(AddressStartDOD90, cedv->DOD90); - bq27220_set_parameter_u16(AddressStartDOD100, cedv->DOD100); - bq27220_set_parameter_u16(AddressEDV0, cedv->EDV0); - bq27220_set_parameter_u16(AddressEDV1, cedv->EDV1); - bq27220_set_parameter_u16(AddressEDV2, cedv->EDV2); + bq27220_set_parameter_u16(handle, AddressGaugingConfig, cedv->cedv_conf.gauge_conf_raw); + bq27220_set_parameter_u16(handle, AddressFullChargeCapacity, cedv->full_charge_cap); + bq27220_set_parameter_u16(handle, AddressDesignCapacity, cedv->design_cap); + bq27220_set_parameter_u16(handle, AddressEMF, cedv->EMF); + bq27220_set_parameter_u16(handle, AddressC0, cedv->C0); + bq27220_set_parameter_u16(handle, AddressR0, cedv->R0); + bq27220_set_parameter_u16(handle, AddressT0, cedv->T0); + bq27220_set_parameter_u16(handle, AddressR1, cedv->R1); + bq27220_set_parameter_u16(handle, AddressTC, (cedv->TC) << 8 | cedv->C1); + bq27220_set_parameter_u16(handle, AddressStartDOD0, cedv->DOD0); + bq27220_set_parameter_u16(handle, AddressStartDOD10, cedv->DOD10); + bq27220_set_parameter_u16(handle, AddressStartDOD20, cedv->DOD20); + bq27220_set_parameter_u16(handle, AddressStartDOD30, cedv->DOD30); + bq27220_set_parameter_u16(handle, AddressStartDOD40, cedv->DOD40); + bq27220_set_parameter_u16(handle, AddressStartDOD50, cedv->DOD40); + bq27220_set_parameter_u16(handle, AddressStartDOD60, cedv->DOD60); + bq27220_set_parameter_u16(handle, AddressStartDOD70, cedv->DOD70); + bq27220_set_parameter_u16(handle, AddressStartDOD80, cedv->DOD80); + bq27220_set_parameter_u16(handle, AddressStartDOD90, cedv->DOD90); + bq27220_set_parameter_u16(handle, AddressStartDOD100, cedv->DOD100); + bq27220_set_parameter_u16(handle, AddressEDV0, cedv->EDV0); + bq27220_set_parameter_u16(handle, AddressEDV1, cedv->EDV1); + bq27220_set_parameter_u16(handle, AddressEDV2, cedv->EDV2); - bq27220_control(Control_EXIT_CFG_UPDATE); + bq27220_control(handle, Control_EXIT_CFG_UPDATE); delay_us(10000); - design_cap = bq27220_get_design_capacity(); + design_cap = bq27220_get_design_capacity(handle); if(cedv->design_cap == design_cap) { FURI_LOG_I(TAG, "Battery profile update success"); return true; @@ -121,16 +114,16 @@ bool bq27220_init(const ParamCEDV* cedv) { } } -uint16_t bq27220_get_voltage() { - return bq27220_read_word(CommandVoltage); +uint16_t bq27220_get_voltage(FuriHalI2cBusHandle* handle) { + return bq27220_read_word(handle, CommandVoltage); } -int16_t bq27220_get_current() { - return bq27220_read_word(CommandCurrent); +int16_t bq27220_get_current(FuriHalI2cBusHandle* handle) { + return bq27220_read_word(handle, CommandCurrent); } -uint8_t bq27220_get_battery_status(BatteryStatus* battery_status) { - uint16_t data = bq27220_read_word(CommandBatteryStatus); +uint8_t bq27220_get_battery_status(FuriHalI2cBusHandle* handle, BatteryStatus* battery_status) { + uint16_t data = bq27220_read_word(handle, CommandBatteryStatus); if(data == BQ27220_ERROR) { return BQ27220_ERROR; } else { @@ -139,8 +132,8 @@ uint8_t bq27220_get_battery_status(BatteryStatus* battery_status) { } } -uint8_t bq27220_get_operation_status(OperationStatus* operation_status) { - uint16_t data = bq27220_read_word(CommandOperationStatus); +uint8_t bq27220_get_operation_status(FuriHalI2cBusHandle* handle, OperationStatus* operation_status) { + uint16_t data = bq27220_read_word(handle, CommandOperationStatus); if(data == BQ27220_ERROR) { return BQ27220_ERROR; } else { @@ -149,26 +142,26 @@ uint8_t bq27220_get_operation_status(OperationStatus* operation_status) { } } -uint16_t bq27220_get_temperature() { - return bq27220_read_word(CommandTemperature); +uint16_t bq27220_get_temperature(FuriHalI2cBusHandle* handle) { + return bq27220_read_word(handle, CommandTemperature); } -uint16_t bq27220_get_full_charge_capacity() { - return bq27220_read_word(CommandFullChargeCapacity); +uint16_t bq27220_get_full_charge_capacity(FuriHalI2cBusHandle* handle) { + return bq27220_read_word(handle, CommandFullChargeCapacity); } -uint16_t bq27220_get_design_capacity() { - return bq27220_read_word(CommandDesignCapacity); +uint16_t bq27220_get_design_capacity(FuriHalI2cBusHandle* handle) { + return bq27220_read_word(handle, CommandDesignCapacity); } -uint16_t bq27220_get_remaining_capacity() { - return bq27220_read_word(CommandRemainingCapacity); +uint16_t bq27220_get_remaining_capacity(FuriHalI2cBusHandle* handle) { + return bq27220_read_word(handle, CommandRemainingCapacity); } -uint16_t bq27220_get_state_of_charge() { - return bq27220_read_word(CommandStateOfCharge); +uint16_t bq27220_get_state_of_charge(FuriHalI2cBusHandle* handle) { + return bq27220_read_word(handle, CommandStateOfCharge); } -uint16_t bq27220_get_state_of_health() { - return bq27220_read_word(CommandStateOfHealth); +uint16_t bq27220_get_state_of_health(FuriHalI2cBusHandle* handle) { + return bq27220_read_word(handle, CommandStateOfHealth); } diff --git a/lib/drivers/bq27220.h b/lib/drivers/bq27220.h index 312d46fd..4c97c48e 100644 --- a/lib/drivers/bq27220.h +++ b/lib/drivers/bq27220.h @@ -2,6 +2,7 @@ #include #include +#include #define BQ27220_ERROR 0x0 #define BQ27220_SUCCESS 0x1 @@ -95,36 +96,36 @@ typedef struct { /** Initialize Driver * @return true on success, false otherwise */ -bool bq27220_init(const ParamCEDV* cedv); +bool bq27220_init(FuriHalI2cBusHandle* handle, const ParamCEDV* cedv); /** Get battery voltage in mV or error */ -uint16_t bq27220_get_voltage(); +uint16_t bq27220_get_voltage(FuriHalI2cBusHandle* handle); /** Get current in mA or error*/ -int16_t bq27220_get_current(); +int16_t bq27220_get_current(FuriHalI2cBusHandle* handle); /** Get battery status */ -uint8_t bq27220_get_battery_status(BatteryStatus* battery_status); +uint8_t bq27220_get_battery_status(FuriHalI2cBusHandle* handle, BatteryStatus* battery_status); /** Get operation status */ -uint8_t bq27220_get_operation_status(OperationStatus* operation_status); +uint8_t bq27220_get_operation_status(FuriHalI2cBusHandle* handle, OperationStatus* operation_status); /** Get temperature in units of 0.1°K */ -uint16_t bq27220_get_temperature(); +uint16_t bq27220_get_temperature(FuriHalI2cBusHandle* handle); /** Get compensated full charge capacity in in mAh */ -uint16_t bq27220_get_full_charge_capacity(); +uint16_t bq27220_get_full_charge_capacity(FuriHalI2cBusHandle* handle); /** Get design capacity in mAh */ -uint16_t bq27220_get_design_capacity(); +uint16_t bq27220_get_design_capacity(FuriHalI2cBusHandle* handle); /** Get remaining capacity in in mAh */ -uint16_t bq27220_get_remaining_capacity(); +uint16_t bq27220_get_remaining_capacity(FuriHalI2cBusHandle* handle); /** Get predicted remaining battery capacity in percents */ -uint16_t bq27220_get_state_of_charge(); +uint16_t bq27220_get_state_of_charge(FuriHalI2cBusHandle* handle); /** Get ratio of full charge capacity over design capacity in percents */ -uint16_t bq27220_get_state_of_health(); +uint16_t bq27220_get_state_of_health(FuriHalI2cBusHandle* handle); -void bq27220_change_design_capacity(uint16_t capacity); +void bq27220_change_design_capacity(FuriHalI2cBusHandle* handle, uint16_t capacity); diff --git a/lib/drivers/lp5562.c b/lib/drivers/lp5562.c index 954fa65e..8535f3ac 100644 --- a/lib/drivers/lp5562.c +++ b/lib/drivers/lp5562.c @@ -1,27 +1,21 @@ #include "lp5562.h" #include "lp5562_reg.h" -#include #include -bool lp5562_write_reg(uint8_t address, uint8_t* data) { +static bool lp5562_write_reg(FuriHalI2cBusHandle* handle, uint8_t address, uint8_t* data) { uint8_t buffer[2] = {address, *data}; - bool ret; - with_furi_hal_i2c( - bool, &ret, () { - return furi_hal_i2c_tx(POWER_I2C, LP5562_ADDRESS, buffer, 2, LP5562_I2C_TIMEOUT); - }); - return ret; + return furi_hal_i2c_tx(handle, LP5562_ADDRESS, buffer, 2, LP5562_I2C_TIMEOUT); } -void lp5562_reset() { +void lp5562_reset(FuriHalI2cBusHandle* handle) { Reg0D_Reset reg = {.value = 0xFF}; - lp5562_write_reg(0x0D, (uint8_t*)®); + lp5562_write_reg(handle, 0x0D, (uint8_t*)®); } -void lp5562_configure() { +void lp5562_configure(FuriHalI2cBusHandle* handle) { Reg08_Config config = {.INT_CLK_EN = true, .PS_EN = true, .PWM_HF = true}; - lp5562_write_reg(0x08, (uint8_t*)&config); + lp5562_write_reg(handle, 0x08, (uint8_t*)&config); Reg70_LedMap map = { .red = EngSelectI2C, @@ -29,15 +23,15 @@ void lp5562_configure() { .blue = EngSelectI2C, .white = EngSelectI2C, }; - lp5562_write_reg(0x70, (uint8_t*)&map); + lp5562_write_reg(handle, 0x70, (uint8_t*)&map); } -void lp5562_enable() { +void lp5562_enable(FuriHalI2cBusHandle* handle) { Reg00_Enable reg = {.CHIP_EN = true, .LOG_EN = true}; - lp5562_write_reg(0x00, (uint8_t*)®); + lp5562_write_reg(handle, 0x00, (uint8_t*)®); } -void lp5562_set_channel_current(LP5562Channel channel, uint8_t value) { +void lp5562_set_channel_current(FuriHalI2cBusHandle* handle, LP5562Channel channel, uint8_t value) { uint8_t reg_no; if(channel == LP5562ChannelRed) { reg_no = 0x07; @@ -50,10 +44,10 @@ void lp5562_set_channel_current(LP5562Channel channel, uint8_t value) { } else { return; } - lp5562_write_reg(reg_no, &value); + lp5562_write_reg(handle, reg_no, &value); } -void lp5562_set_channel_value(LP5562Channel channel, uint8_t value) { +void lp5562_set_channel_value(FuriHalI2cBusHandle* handle, LP5562Channel channel, uint8_t value) { uint8_t reg_no; if(channel == LP5562ChannelRed) { reg_no = 0x04; @@ -66,5 +60,5 @@ void lp5562_set_channel_value(LP5562Channel channel, uint8_t value) { } else { return; } - lp5562_write_reg(reg_no, &value); + lp5562_write_reg(handle, reg_no, &value); } diff --git a/lib/drivers/lp5562.h b/lib/drivers/lp5562.h index b58e2ee0..7af6ae6f 100644 --- a/lib/drivers/lp5562.h +++ b/lib/drivers/lp5562.h @@ -2,6 +2,7 @@ #include #include +#include /** Channel types */ typedef enum { @@ -12,16 +13,16 @@ typedef enum { } LP5562Channel; /** Initialize Driver */ -void lp5562_reset(); +void lp5562_reset(FuriHalI2cBusHandle* handle); /** Configure Driver */ -void lp5562_configure(); +void lp5562_configure(FuriHalI2cBusHandle* handle); /** Enable Driver */ -void lp5562_enable(); +void lp5562_enable(FuriHalI2cBusHandle* handle); /** Set channel current */ -void lp5562_set_channel_current(LP5562Channel channel, uint8_t value); +void lp5562_set_channel_current(FuriHalI2cBusHandle* handle, LP5562Channel channel, uint8_t value); /** Set channel current */ -void lp5562_set_channel_value(LP5562Channel channel, uint8_t value); +void lp5562_set_channel_value(FuriHalI2cBusHandle* handle, LP5562Channel channel, uint8_t value);