[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

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