[FL-1911] FuriHal: i2c refactoring (#847)

* Project: fix release build, replace asserts with checks.
* FuriHal: i2c refactoring, new bus access model, flexible bus gpio configuration.
* FuriHal: set i2c pins to high on detach.
* FuriHal: more i2c bus events, put bus under reset when not used, move bus enable/disable routine to bus handler.
* FuriHal: fix i2c deadlock in power api, add external i2c handle.
This commit is contained in:
あく
2021-11-28 21:28:19 +03:00
committed by GitHub
parent 7c0943e736
commit cf591ef7eb
45 changed files with 1685 additions and 781 deletions

View File

@@ -0,0 +1,133 @@
#include "furi-hal-i2c-config.h"
#include <furi-hal-resources.h>
#include <furi-hal-version.h>
/** Timing register value is computed with the STM32CubeMX Tool,
* Standard Mode @100kHz with I2CCLK = 64 MHz,
* rise time = 0ns, fall time = 0ns
*/
#define FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100 0x10707DBC
/** Timing register value is computed with the STM32CubeMX Tool,
* Fast Mode @400kHz with I2CCLK = 64 MHz,
* rise time = 0ns, fall time = 0ns
*/
#define FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_400 0x00602173
osMutexId_t furi_hal_i2c_bus_power_mutex = NULL;
static void furi_hal_i2c_bus_power_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) {
if (event == FuriHalI2cBusEventInit) {
furi_hal_i2c_bus_power_mutex = osMutexNew(NULL);
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);
LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1);
bus->current_handle = NULL;
} else if (event == FuriHalI2cBusEventDeinit) {
osMutexDelete(furi_hal_i2c_bus_power_mutex);
} else if (event == FuriHalI2cBusEventLock) {
furi_check(osMutexAcquire(furi_hal_i2c_bus_power_mutex, osWaitForever) == osOK);
} else if (event == FuriHalI2cBusEventUnlock) {
furi_check(osMutexRelease(furi_hal_i2c_bus_power_mutex) == osOK);
} else if (event == FuriHalI2cBusEventActivate) {
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C1);
} else if (event == FuriHalI2cBusEventDeactivate) {
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1);
}
}
FuriHalI2cBus furi_hal_i2c_bus_power = {
.i2c=I2C1,
.callback=furi_hal_i2c_bus_power_event,
};
osMutexId_t furi_hal_i2c_bus_external_mutex = NULL;
static void furi_hal_i2c_bus_external_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) {
if (event == FuriHalI2cBusEventActivate) {
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C3);
LL_RCC_SetI2CClockSource(LL_RCC_I2C3_CLKSOURCE_PCLK1);
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C3);
} else if (event == FuriHalI2cBusEventDeactivate) {
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C3);
}
}
FuriHalI2cBus furi_hal_i2c_bus_external = {
.i2c=I2C3,
.callback=furi_hal_i2c_bus_external_event,
};
void furi_hal_i2c_bus_handle_power_event(FuriHalI2cBusHandle* handle, FuriHalI2cBusHandleEvent event) {
if (event == FuriHalI2cBusHandleEventActivate) {
hal_gpio_init_ex(&gpio_i2c_power_sda, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C1);
hal_gpio_init_ex(&gpio_i2c_power_scl, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C1);
LL_I2C_InitTypeDef I2C_InitStruct = {0};
I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
I2C_InitStruct.DigitalFilter = 0;
I2C_InitStruct.OwnAddress1 = 0;
I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
if (furi_hal_version_get_hw_version() > 10) {
I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_400;
} else {
I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100;
}
LL_I2C_Init(handle->bus->i2c, &I2C_InitStruct);
LL_I2C_EnableAutoEndMode(handle->bus->i2c);
LL_I2C_SetOwnAddress2(handle->bus->i2c, 0, LL_I2C_OWNADDRESS2_NOMASK);
LL_I2C_DisableOwnAddress2(handle->bus->i2c);
LL_I2C_DisableGeneralCall(handle->bus->i2c);
LL_I2C_EnableClockStretching(handle->bus->i2c);
LL_I2C_Enable(handle->bus->i2c);
} else if (event == FuriHalI2cBusHandleEventDeactivate) {
LL_I2C_Disable(handle->bus->i2c);
hal_gpio_write(&gpio_i2c_power_sda, 1);
hal_gpio_write(&gpio_i2c_power_scl, 1);
hal_gpio_init_ex(&gpio_i2c_power_sda, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
hal_gpio_init_ex(&gpio_i2c_power_scl, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
}
}
FuriHalI2cBusHandle furi_hal_i2c_handle_power = {
.bus = &furi_hal_i2c_bus_power,
.callback = furi_hal_i2c_bus_handle_power_event,
};
void furi_hal_i2c_bus_handle_external_event(FuriHalI2cBusHandle* handle, FuriHalI2cBusHandleEvent event) {
if (event == FuriHalI2cBusHandleEventActivate) {
hal_gpio_init_ex(&gpio_ext_pc0, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C3);
hal_gpio_init_ex(&gpio_ext_pc1, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C3);
LL_I2C_InitTypeDef I2C_InitStruct = {0};
I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
I2C_InitStruct.DigitalFilter = 0;
I2C_InitStruct.OwnAddress1 = 0;
I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100;
LL_I2C_Init(handle->bus->i2c, &I2C_InitStruct);
LL_I2C_EnableAutoEndMode(handle->bus->i2c);
LL_I2C_SetOwnAddress2(handle->bus->i2c, 0, LL_I2C_OWNADDRESS2_NOMASK);
LL_I2C_DisableOwnAddress2(handle->bus->i2c);
LL_I2C_DisableGeneralCall(handle->bus->i2c);
LL_I2C_EnableClockStretching(handle->bus->i2c);
LL_I2C_Enable(handle->bus->i2c);
} else if (event == FuriHalI2cBusHandleEventDeactivate) {
LL_I2C_Disable(handle->bus->i2c);
hal_gpio_write(&gpio_ext_pc0, 1);
hal_gpio_write(&gpio_ext_pc1, 1);
hal_gpio_init_ex(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
hal_gpio_init_ex(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
}
}
FuriHalI2cBusHandle furi_hal_i2c_handle_external = {
.bus = &furi_hal_i2c_bus_external,
.callback = furi_hal_i2c_bus_handle_external_event,
};

View File

@@ -0,0 +1,31 @@
#pragma once
#include <furi-hal-i2c-types.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Internal(power) i2c bus, I2C1, under reset when not used */
extern FuriHalI2cBus furi_hal_i2c_bus_power;
/** External i2c bus, I2C3, under reset when not used */
extern FuriHalI2cBus furi_hal_i2c_bus_external;
/** Handle for internal(power) i2c bus
* Bus: furi_hal_i2c_bus_external
* Pins: PA9(SCL) / PA10(SDA), float on release
* Params: 400khz
*/
extern FuriHalI2cBusHandle furi_hal_i2c_handle_power;
/** Handle for external i2c bus
* Bus: furi_hal_i2c_bus_external
* Pins: PC0(SCL) / PC1(SDA), float on release
* Params: 100khz
*/
extern FuriHalI2cBusHandle furi_hal_i2c_handle_external;
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,49 @@
#pragma once
#include <stm32wbxx_ll_i2c.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct FuriHalI2cBus FuriHalI2cBus;
typedef struct FuriHalI2cBusHandle FuriHalI2cBusHandle;
/** FuriHal i2c bus states */
typedef enum {
FuriHalI2cBusEventInit, /**< Bus initialization event, called on system start */
FuriHalI2cBusEventDeinit, /**< Bus deinitialization event, called on system stop */
FuriHalI2cBusEventLock, /**< Bus lock event, called before activation */
FuriHalI2cBusEventUnlock, /**< Bus unlock event, called after deactivation */
FuriHalI2cBusEventActivate, /**< Bus activation event, called before handle activation */
FuriHalI2cBusEventDeactivate, /**< Bus deactivation event, called after handle deactivation */
} FuriHalI2cBusEvent;
/** FuriHal i2c bus event callback */
typedef void (*FuriHalI2cBusEventCallback)(FuriHalI2cBus* bus, FuriHalI2cBusEvent event);
/** FuriHal i2c bus */
struct FuriHalI2cBus {
I2C_TypeDef* i2c;
FuriHalI2cBusHandle* current_handle;
FuriHalI2cBusEventCallback callback;
};
/** FuriHal i2c handle states */
typedef enum {
FuriHalI2cBusHandleEventActivate, /**< Handle activate: connect gpio and apply bus config */
FuriHalI2cBusHandleEventDeactivate, /**< Handle deactivate: disconnect gpio and reset bus config */
} FuriHalI2cBusHandleEvent;
/** FuriHal i2c handle event callback */
typedef void (*FuriHalI2cBusHandleEventCallback)(FuriHalI2cBusHandle* handle, FuriHalI2cBusHandleEvent event);
/** FuriHal i2c handle */
struct FuriHalI2cBusHandle {
FuriHalI2cBus* bus;
FuriHalI2cBusHandleEventCallback callback;
};
#ifdef __cplusplus
}
#endif

View File

@@ -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);
}

View File

@@ -1,46 +1,49 @@
#include <furi-hal-light.h>
#include <lp5562.h>
#define TAG "FuriHalLight"
#define LED_CURRENT_RED 50
#define LED_CURRENT_GREEN 50
#define LED_CURRENT_BLUE 50
#define LED_CURRENT_WHITE 150
#define LED_CURRENT_RED 50
#define LED_CURRENT_GREEN 50
#define LED_CURRENT_BLUE 50
#define LED_CURRENT_WHITE 150
void furi_hal_light_init() {
lp5562_reset();
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
lp5562_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);
}

View File

@@ -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);
}
}

View File

@@ -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};

View File

@@ -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
}

View File

@@ -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) {

View File

@@ -0,0 +1,133 @@
#include "furi-hal-i2c-config.h"
#include <furi-hal-resources.h>
#include <furi-hal-version.h>
/** Timing register value is computed with the STM32CubeMX Tool,
* Standard Mode @100kHz with I2CCLK = 64 MHz,
* rise time = 0ns, fall time = 0ns
*/
#define FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100 0x10707DBC
/** Timing register value is computed with the STM32CubeMX Tool,
* Fast Mode @400kHz with I2CCLK = 64 MHz,
* rise time = 0ns, fall time = 0ns
*/
#define FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_400 0x00602173
osMutexId_t furi_hal_i2c_bus_power_mutex = NULL;
static void furi_hal_i2c_bus_power_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) {
if (event == FuriHalI2cBusEventInit) {
furi_hal_i2c_bus_power_mutex = osMutexNew(NULL);
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);
LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1);
bus->current_handle = NULL;
} else if (event == FuriHalI2cBusEventDeinit) {
osMutexDelete(furi_hal_i2c_bus_power_mutex);
} else if (event == FuriHalI2cBusEventLock) {
furi_check(osMutexAcquire(furi_hal_i2c_bus_power_mutex, osWaitForever) == osOK);
} else if (event == FuriHalI2cBusEventUnlock) {
furi_check(osMutexRelease(furi_hal_i2c_bus_power_mutex) == osOK);
} else if (event == FuriHalI2cBusEventActivate) {
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C1);
} else if (event == FuriHalI2cBusEventDeactivate) {
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1);
}
}
FuriHalI2cBus furi_hal_i2c_bus_power = {
.i2c=I2C1,
.callback=furi_hal_i2c_bus_power_event,
};
osMutexId_t furi_hal_i2c_bus_external_mutex = NULL;
static void furi_hal_i2c_bus_external_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) {
if (event == FuriHalI2cBusEventActivate) {
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C3);
LL_RCC_SetI2CClockSource(LL_RCC_I2C3_CLKSOURCE_PCLK1);
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C3);
} else if (event == FuriHalI2cBusEventDeactivate) {
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C3);
}
}
FuriHalI2cBus furi_hal_i2c_bus_external = {
.i2c=I2C3,
.callback=furi_hal_i2c_bus_external_event,
};
void furi_hal_i2c_bus_handle_power_event(FuriHalI2cBusHandle* handle, FuriHalI2cBusHandleEvent event) {
if (event == FuriHalI2cBusHandleEventActivate) {
hal_gpio_init_ex(&gpio_i2c_power_sda, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C1);
hal_gpio_init_ex(&gpio_i2c_power_scl, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C1);
LL_I2C_InitTypeDef I2C_InitStruct = {0};
I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
I2C_InitStruct.DigitalFilter = 0;
I2C_InitStruct.OwnAddress1 = 0;
I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
if (furi_hal_version_get_hw_version() > 10) {
I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_400;
} else {
I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100;
}
LL_I2C_Init(handle->bus->i2c, &I2C_InitStruct);
LL_I2C_EnableAutoEndMode(handle->bus->i2c);
LL_I2C_SetOwnAddress2(handle->bus->i2c, 0, LL_I2C_OWNADDRESS2_NOMASK);
LL_I2C_DisableOwnAddress2(handle->bus->i2c);
LL_I2C_DisableGeneralCall(handle->bus->i2c);
LL_I2C_EnableClockStretching(handle->bus->i2c);
LL_I2C_Enable(handle->bus->i2c);
} else if (event == FuriHalI2cBusHandleEventDeactivate) {
LL_I2C_Disable(handle->bus->i2c);
hal_gpio_write(&gpio_i2c_power_sda, 1);
hal_gpio_write(&gpio_i2c_power_scl, 1);
hal_gpio_init_ex(&gpio_i2c_power_sda, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
hal_gpio_init_ex(&gpio_i2c_power_scl, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
}
}
FuriHalI2cBusHandle furi_hal_i2c_handle_power = {
.bus = &furi_hal_i2c_bus_power,
.callback = furi_hal_i2c_bus_handle_power_event,
};
void furi_hal_i2c_bus_handle_external_event(FuriHalI2cBusHandle* handle, FuriHalI2cBusHandleEvent event) {
if (event == FuriHalI2cBusHandleEventActivate) {
hal_gpio_init_ex(&gpio_ext_pc0, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C3);
hal_gpio_init_ex(&gpio_ext_pc1, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C3);
LL_I2C_InitTypeDef I2C_InitStruct = {0};
I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
I2C_InitStruct.DigitalFilter = 0;
I2C_InitStruct.OwnAddress1 = 0;
I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100;
LL_I2C_Init(handle->bus->i2c, &I2C_InitStruct);
LL_I2C_EnableAutoEndMode(handle->bus->i2c);
LL_I2C_SetOwnAddress2(handle->bus->i2c, 0, LL_I2C_OWNADDRESS2_NOMASK);
LL_I2C_DisableOwnAddress2(handle->bus->i2c);
LL_I2C_DisableGeneralCall(handle->bus->i2c);
LL_I2C_EnableClockStretching(handle->bus->i2c);
LL_I2C_Enable(handle->bus->i2c);
} else if (event == FuriHalI2cBusHandleEventDeactivate) {
LL_I2C_Disable(handle->bus->i2c);
hal_gpio_write(&gpio_ext_pc0, 1);
hal_gpio_write(&gpio_ext_pc1, 1);
hal_gpio_init_ex(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
hal_gpio_init_ex(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
}
}
FuriHalI2cBusHandle furi_hal_i2c_handle_external = {
.bus = &furi_hal_i2c_bus_external,
.callback = furi_hal_i2c_bus_handle_external_event,
};

View File

@@ -0,0 +1,31 @@
#pragma once
#include <furi-hal-i2c-types.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Internal(power) i2c bus, I2C1, under reset when not used */
extern FuriHalI2cBus furi_hal_i2c_bus_power;
/** External i2c bus, I2C3, under reset when not used */
extern FuriHalI2cBus furi_hal_i2c_bus_external;
/** Handle for internal(power) i2c bus
* Bus: furi_hal_i2c_bus_external
* Pins: PA9(SCL) / PA10(SDA), float on release
* Params: 400khz
*/
extern FuriHalI2cBusHandle furi_hal_i2c_handle_power;
/** Handle for external i2c bus
* Bus: furi_hal_i2c_bus_external
* Pins: PC0(SCL) / PC1(SDA), float on release
* Params: 100khz
*/
extern FuriHalI2cBusHandle furi_hal_i2c_handle_external;
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,49 @@
#pragma once
#include <stm32wbxx_ll_i2c.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct FuriHalI2cBus FuriHalI2cBus;
typedef struct FuriHalI2cBusHandle FuriHalI2cBusHandle;
/** FuriHal i2c bus states */
typedef enum {
FuriHalI2cBusEventInit, /**< Bus initialization event, called on system start */
FuriHalI2cBusEventDeinit, /**< Bus deinitialization event, called on system stop */
FuriHalI2cBusEventLock, /**< Bus lock event, called before activation */
FuriHalI2cBusEventUnlock, /**< Bus unlock event, called after deactivation */
FuriHalI2cBusEventActivate, /**< Bus activation event, called before handle activation */
FuriHalI2cBusEventDeactivate, /**< Bus deactivation event, called after handle deactivation */
} FuriHalI2cBusEvent;
/** FuriHal i2c bus event callback */
typedef void (*FuriHalI2cBusEventCallback)(FuriHalI2cBus* bus, FuriHalI2cBusEvent event);
/** FuriHal i2c bus */
struct FuriHalI2cBus {
I2C_TypeDef* i2c;
FuriHalI2cBusHandle* current_handle;
FuriHalI2cBusEventCallback callback;
};
/** FuriHal i2c handle states */
typedef enum {
FuriHalI2cBusHandleEventActivate, /**< Handle activate: connect gpio and apply bus config */
FuriHalI2cBusHandleEventDeactivate, /**< Handle deactivate: disconnect gpio and reset bus config */
} FuriHalI2cBusHandleEvent;
/** FuriHal i2c handle event callback */
typedef void (*FuriHalI2cBusHandleEventCallback)(FuriHalI2cBusHandle* handle, FuriHalI2cBusHandleEvent event);
/** FuriHal i2c handle */
struct FuriHalI2cBusHandle {
FuriHalI2cBus* bus;
FuriHalI2cBusHandleEventCallback callback;
};
#ifdef __cplusplus
}
#endif

View File

@@ -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);
}

View File

@@ -1,46 +1,49 @@
#include <furi-hal-light.h>
#include <lp5562.h>
#define TAG "FuriHalLight"
#define LED_CURRENT_RED 50
#define LED_CURRENT_GREEN 50
#define LED_CURRENT_BLUE 50
#define LED_CURRENT_WHITE 150
#define LED_CURRENT_RED 50
#define LED_CURRENT_GREEN 50
#define LED_CURRENT_BLUE 50
#define LED_CURRENT_WHITE 150
void furi_hal_light_init() {
lp5562_reset();
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
lp5562_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);
}

View File

@@ -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);
}
}

View File

@@ -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};

View File

@@ -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
}

View File

@@ -1,108 +0,0 @@
#pragma once
#include "main.h"
#include "furi-hal-spi-config.h"
#include <furi-hal-gpio.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Init SPI API
*/
void furi_hal_spi_init();
/* Bus Level API */
/** Lock SPI bus
* Takes bus mutex, if used
*/
void furi_hal_spi_bus_lock(const FuriHalSpiBus* bus);
/** Unlock SPI bus
* Releases BUS mutex, if used
*/
void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus);
/**
* Configure SPI bus
* @param bus - spi bus handler
* @param config - spi configuration structure
*/
void furi_hal_spi_bus_configure(const FuriHalSpiBus* bus, const LL_SPI_InitTypeDef* config);
/** SPI Receive
* @param bus - spi bus handler
* @param buffer - receive buffer
* @param size - transaction size
* @param timeout - bus operation timeout in ms
*/
bool furi_hal_spi_bus_rx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout);
/** SPI Transmit
* @param bus - spi bus handler
* @param buffer - transmit buffer
* @param size - transaction size
* @param timeout - bus operation timeout in ms
*/
bool furi_hal_spi_bus_tx(const FuriHalSpiBus* bus, uint8_t* buffer, size_t size, uint32_t timeout);
/** SPI Transmit and Receive
* @param bus - spi bus handlere
* @param tx_buffer - device handle
* @param rx_buffer - device handle
* @param size - transaction size
* @param timeout - bus operation timeout in ms
*/
bool furi_hal_spi_bus_trx(const FuriHalSpiBus* bus, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout);
/* Device Level API */
/** Reconfigure SPI bus for device
* @param device - device description
*/
void furi_hal_spi_device_configure(const FuriHalSpiDevice* device);
/** Get Device handle
* And lock access to the corresponding SPI BUS
* @param device_id - device identifier
* @return device handle
*/
const FuriHalSpiDevice* furi_hal_spi_device_get(FuriHalSpiDeviceId device_id);
/** Return Device handle
* And unlock access to the corresponding SPI BUS
* @param device - device handle
*/
void furi_hal_spi_device_return(const FuriHalSpiDevice* device);
/** SPI Recieve
* @param device - device handle
* @param buffer - receive buffer
* @param size - transaction size
* @param timeout - bus operation timeout in ms
*/
bool furi_hal_spi_device_rx(const FuriHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout);
/** SPI Transmit
* @param device - device handle
* @param buffer - transmit buffer
* @param size - transaction size
* @param timeout - bus operation timeout in ms
*/
bool furi_hal_spi_device_tx(const FuriHalSpiDevice* device, uint8_t* buffer, size_t size, uint32_t timeout);
/** SPI Transmit and Receive
* @param device - device handle
* @param tx_buffer - device handle
* @param rx_buffer - device handle
* @param size - transaction size
* @param timeout - bus operation timeout in ms
*/
bool furi_hal_spi_device_trx(const FuriHalSpiDevice* device, uint8_t* tx_buffer, uint8_t* rx_buffer, size_t size, uint32_t timeout);
#ifdef __cplusplus
}
#endif

View File

@@ -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) {

View File

@@ -7,7 +7,7 @@
#include <stdbool.h>
#include <stdint.h>
#include <furi-hal-resources.h>
#include <furi-hal-i2c-config.h>
#ifdef __cplusplus
extern "C" {
@@ -17,18 +17,30 @@ extern "C" {
*/
void furi_hal_i2c_init();
/** Acquire i2c bus handle
*
* @return Instance of FuriHalI2cBus
*/
void furi_hal_i2c_acquire(FuriHalI2cBusHandle* handle);
/** Release i2c bus handle
*
* @param bus instance of FuriHalI2cBus aquired in `furi_hal_i2c_acquire`
*/
void furi_hal_i2c_release(FuriHalI2cBusHandle* handle);
/** Perform I2C tx transfer
*
* @param instance I2C_TypeDef instance
* @param address I2C slave address
* @param data pointer to data buffer
* @param size size of data buffer
* @param timeout timeout in CPU ticks
* @param timeout timeout in ticks
*
* @return true on successful transfer, false otherwise
*/
bool furi_hal_i2c_tx(
I2C_TypeDef* instance,
FuriHalI2cBusHandle* handle,
const uint8_t address,
const uint8_t* data,
const uint8_t size,
@@ -40,12 +52,12 @@ bool furi_hal_i2c_tx(
* @param address I2C slave address
* @param data pointer to data buffer
* @param size size of data buffer
* @param timeout timeout in CPU ticks
* @param timeout timeout in ticks
*
* @return true on successful transfer, false otherwise
*/
bool furi_hal_i2c_rx(
I2C_TypeDef* instance,
FuriHalI2cBusHandle* handle,
const uint8_t address,
uint8_t* data,
const uint8_t size,
@@ -59,12 +71,12 @@ bool furi_hal_i2c_rx(
* @param tx_size size of tx data buffer
* @param rx_data pointer to rx data buffer
* @param rx_size size of rx data buffer
* @param timeout timeout in CPU ticks
* @param timeout timeout in ticks
*
* @return true on successful transfer, false otherwise
*/
bool furi_hal_i2c_trx(
I2C_TypeDef* instance,
FuriHalI2cBusHandle* handle,
const uint8_t address,
const uint8_t* tx_data,
const uint8_t tx_size,
@@ -72,30 +84,6 @@ bool furi_hal_i2c_trx(
const uint8_t rx_size,
uint32_t timeout);
/** Acquire I2C mutex
*/
void furi_hal_i2c_lock();
/** Release I2C mutex
*/
void furi_hal_i2c_unlock();
/** With clause for I2C peripheral
*
* @param type type of function_body
* @param pointer pointer to return of function_body
* @param function_body a (){} lambda declaration, executed with I2C mutex
* acquired
*
* @return Nothing
*/
#define with_furi_hal_i2c(type, pointer, function_body) \
{ \
furi_hal_i2c_lock(); \
*pointer = ({ type __fn__ function_body __fn__; })(); \
furi_hal_i2c_unlock(); \
}
#ifdef __cplusplus
}
#endif

View File

@@ -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
*/