[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:
		
							parent
							
								
									7c0943e736
								
							
						
					
					
						commit
						cf591ef7eb
					
				| @ -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); |             string_init_printf(fullname, "%s/%s", string_get_cstr(cur_dir), name); | ||||||
|             FS_Error error = storage_common_remove(storage, string_get_cstr(fullname)); |             FS_Error error = storage_common_remove(storage, string_get_cstr(fullname)); | ||||||
|             furi_assert(error == FSE_OK); |             furi_check(error == FSE_OK); | ||||||
|             string_clear(fullname); |             string_clear(fullname); | ||||||
|         } |         } | ||||||
|         storage_dir_close(dir); |         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)); |         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)) { |         if(string_cmp(cur_dir, path)) { | ||||||
|             size_t last_char = string_search_rchar(cur_dir, '/'); |             size_t last_char = string_search_rchar(cur_dir, '/'); | ||||||
|  | |||||||
| @ -115,7 +115,7 @@ static void clean_directory(Storage* fs_api, const char* clean_dir) { | |||||||
|                 clean_directory(fs_api, fullname); |                 clean_directory(fs_api, fullname); | ||||||
|             } |             } | ||||||
|             FS_Error error = storage_common_remove(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(fullname); | ||||||
|         } |         } | ||||||
|         free(name); |         free(name); | ||||||
|  | |||||||
							
								
								
									
										149
									
								
								bootloader/targets/f6/furi-hal/furi-hal-i2c-config.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								bootloader/targets/f6/furi-hal/furi-hal-i2c-config.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,149 @@ | |||||||
|  | #include "furi-hal-i2c-config.h" | ||||||
|  | #include <furi-hal-resources.h> | ||||||
|  | #include <furi-hal-version.h> | ||||||
|  | 
 | ||||||
|  | #include <stm32wbxx_ll_rcc.h> | ||||||
|  | #include <stm32wbxx_ll_bus.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 | ||||||
|  | 
 | ||||||
|  | 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, | ||||||
|  | }; | ||||||
							
								
								
									
										31
									
								
								bootloader/targets/f6/furi-hal/furi-hal-i2c-config.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								bootloader/targets/f6/furi-hal/furi-hal-i2c-config.h
									
									
									
									
									
										Normal 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 | ||||||
							
								
								
									
										51
									
								
								bootloader/targets/f6/furi-hal/furi-hal-i2c-types.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								bootloader/targets/f6/furi-hal/furi-hal-i2c-types.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | |||||||
|  | #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 | ||||||
| @ -1,66 +1,64 @@ | |||||||
| #include <furi-hal-i2c.h> | #include <furi-hal-i2c.h> | ||||||
|  | #include <furi-hal-version.h> | ||||||
| 
 | 
 | ||||||
| #include <stm32wbxx_ll_bus.h> |  | ||||||
| #include <stm32wbxx_ll_i2c.h> | #include <stm32wbxx_ll_i2c.h> | ||||||
| #include <stm32wbxx_ll_rcc.h> |  | ||||||
| #include <stm32wbxx_ll_gpio.h> | #include <stm32wbxx_ll_gpio.h> | ||||||
| #include <stm32wbxx_ll_cortex.h> | #include <stm32wbxx_ll_cortex.h> | ||||||
| 
 | 
 | ||||||
|  | #include <assert.h> | ||||||
|  | 
 | ||||||
| void furi_hal_i2c_init() { | void furi_hal_i2c_init() { | ||||||
|     LL_I2C_InitTypeDef I2C_InitStruct = {0}; |     furi_hal_i2c_bus_power.callback(&furi_hal_i2c_bus_power, FuriHalI2cBusEventInit); | ||||||
|     LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; | } | ||||||
| 
 | 
 | ||||||
|     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); |     assert(handle->bus->current_handle == NULL); | ||||||
|     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); |  | ||||||
| 
 | 
 | ||||||
|     LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); |     handle->bus->current_handle = handle; | ||||||
| 
 | 
 | ||||||
|     I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C; |     handle->bus->callback(handle->bus, FuriHalI2cBusEventActivate); | ||||||
|     I2C_InitStruct.Timing = POWER_I2C_TIMINGS; | 
 | ||||||
|     I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE; |     handle->callback(handle, FuriHalI2cBusHandleEventActivate); | ||||||
|     I2C_InitStruct.DigitalFilter = 0; | } | ||||||
|     I2C_InitStruct.OwnAddress1 = 0; | 
 | ||||||
|     I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK; | void furi_hal_i2c_release(FuriHalI2cBusHandle* handle) { | ||||||
|     I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT; |     assert(handle->bus->current_handle == handle); | ||||||
|     LL_I2C_Init(I2C1, &I2C_InitStruct); | 
 | ||||||
|     LL_I2C_EnableAutoEndMode(I2C1); |     handle->callback(handle, FuriHalI2cBusHandleEventDeactivate); | ||||||
|     LL_I2C_SetOwnAddress2(I2C1, 0, LL_I2C_OWNADDRESS2_NOMASK); | 
 | ||||||
|     LL_I2C_DisableOwnAddress2(I2C1); |     handle->bus->callback(handle->bus, FuriHalI2cBusEventDeactivate); | ||||||
|     LL_I2C_DisableGeneralCall(I2C1); | 
 | ||||||
|     LL_I2C_EnableClockStretching(I2C1); |     handle->bus->current_handle = NULL; | ||||||
|  | 
 | ||||||
|  |     handle->bus->callback(handle->bus, FuriHalI2cBusEventUnlock); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool furi_hal_i2c_tx( | bool furi_hal_i2c_tx( | ||||||
|     I2C_TypeDef* instance, |     FuriHalI2cBusHandle* handle, | ||||||
|     uint8_t address, |     uint8_t address, | ||||||
|     const uint8_t* data, |     const uint8_t* data, | ||||||
|     uint8_t size, |     uint8_t size, | ||||||
|     uint32_t timeout) { |     uint32_t timeout) { | ||||||
|  |     assert(handle->bus->current_handle == handle); | ||||||
|     uint32_t time_left = timeout; |     uint32_t time_left = timeout; | ||||||
|     bool ret = true; |     bool ret = true; | ||||||
| 
 | 
 | ||||||
|     while(LL_I2C_IsActiveFlag_BUSY(instance)) |     while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c)) | ||||||
|         ; |         ; | ||||||
| 
 | 
 | ||||||
|     LL_I2C_HandleTransfer( |     LL_I2C_HandleTransfer( | ||||||
|         instance, |         handle->bus->i2c, | ||||||
|         address, |         address, | ||||||
|         LL_I2C_ADDRSLAVE_7BIT, |         LL_I2C_ADDRSLAVE_7BIT, | ||||||
|         size, |         size, | ||||||
|         LL_I2C_MODE_AUTOEND, |         LL_I2C_MODE_AUTOEND, | ||||||
|         LL_I2C_GENERATE_START_WRITE); |         LL_I2C_GENERATE_START_WRITE); | ||||||
| 
 | 
 | ||||||
|     while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) { |     while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) { | ||||||
|         if(LL_I2C_IsActiveFlag_TXIS(instance)) { |         if(LL_I2C_IsActiveFlag_TXIS(handle->bus->i2c)) { | ||||||
|             LL_I2C_TransmitData8(instance, (*data)); |             LL_I2C_TransmitData8(handle->bus->i2c, (*data)); | ||||||
|             data++; |             data++; | ||||||
|             size--; |             size--; | ||||||
|             time_left = timeout; |             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; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool furi_hal_i2c_rx( | bool furi_hal_i2c_rx( | ||||||
|     I2C_TypeDef* instance, |     FuriHalI2cBusHandle* handle, | ||||||
|     uint8_t address, |     uint8_t address, | ||||||
|     uint8_t* data, |     uint8_t* data, | ||||||
|     uint8_t size, |     uint8_t size, | ||||||
|     uint32_t timeout) { |     uint32_t timeout) { | ||||||
|  |     assert(handle->bus->current_handle == handle); | ||||||
|     uint32_t time_left = timeout; |     uint32_t time_left = timeout; | ||||||
|     bool ret = true; |     bool ret = true; | ||||||
| 
 | 
 | ||||||
|     while(LL_I2C_IsActiveFlag_BUSY(instance)) |     while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c)) | ||||||
|         ; |         ; | ||||||
| 
 | 
 | ||||||
|     LL_I2C_HandleTransfer( |     LL_I2C_HandleTransfer( | ||||||
|         instance, |         handle->bus->i2c, | ||||||
|         address, |         address, | ||||||
|         LL_I2C_ADDRSLAVE_7BIT, |         LL_I2C_ADDRSLAVE_7BIT, | ||||||
|         size, |         size, | ||||||
|         LL_I2C_MODE_AUTOEND, |         LL_I2C_MODE_AUTOEND, | ||||||
|         LL_I2C_GENERATE_START_READ); |         LL_I2C_GENERATE_START_READ); | ||||||
| 
 | 
 | ||||||
|     while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) { |     while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) { | ||||||
|         if(LL_I2C_IsActiveFlag_RXNE(instance)) { |         if(LL_I2C_IsActiveFlag_RXNE(handle->bus->i2c)) { | ||||||
|             *data = LL_I2C_ReceiveData8(instance); |             *data = LL_I2C_ReceiveData8(handle->bus->i2c); | ||||||
|             data++; |             data++; | ||||||
|             size--; |             size--; | ||||||
|             time_left = timeout; |             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; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool furi_hal_i2c_trx( | bool furi_hal_i2c_trx( | ||||||
|     I2C_TypeDef* instance, |     FuriHalI2cBusHandle* handle, | ||||||
|     uint8_t address, |     uint8_t address, | ||||||
|     const uint8_t* tx_data, |     const uint8_t* tx_data, | ||||||
|     uint8_t tx_size, |     uint8_t tx_size, | ||||||
|     uint8_t* rx_data, |     uint8_t* rx_data, | ||||||
|     uint8_t rx_size, |     uint8_t rx_size, | ||||||
|     uint32_t timeout) { |     uint32_t timeout) { | ||||||
|     if(furi_hal_i2c_tx(instance, address, tx_data, tx_size, timeout) && |     if(furi_hal_i2c_tx(handle, address, tx_data, tx_size, timeout) && | ||||||
|        furi_hal_i2c_rx(instance, address, rx_data, rx_size, timeout)) { |        furi_hal_i2c_rx(handle, address, rx_data, rx_size, timeout)) { | ||||||
|         return true; |         return true; | ||||||
|     } else { |     } else { | ||||||
|         return false; |         return false; | ||||||
|  | |||||||
| @ -1,31 +1,82 @@ | |||||||
|  | /**
 | ||||||
|  |  * @file furi-hal-i2c.h | ||||||
|  |  * I2C HAL API | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <furi-hal-resources.h> | #include <furi-hal-i2c-config.h> | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | /** Init I2C
 | ||||||
|  |  */ | ||||||
| void furi_hal_i2c_init(); | 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( | bool furi_hal_i2c_tx( | ||||||
|     I2C_TypeDef* instance, |     FuriHalI2cBusHandle* handle, | ||||||
|     const uint8_t address, |     const uint8_t address, | ||||||
|     const uint8_t* data, |     const uint8_t* data, | ||||||
|     const uint8_t size, |     const uint8_t size, | ||||||
|     uint32_t timeout); |     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( | bool furi_hal_i2c_rx( | ||||||
|     I2C_TypeDef* instance, |     FuriHalI2cBusHandle* handle, | ||||||
|     const uint8_t address, |     const uint8_t address, | ||||||
|     uint8_t* data, |     uint8_t* data, | ||||||
|     const uint8_t size, |     const uint8_t size, | ||||||
|     uint32_t timeout); |     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( | bool furi_hal_i2c_trx( | ||||||
|     I2C_TypeDef* instance, |     FuriHalI2cBusHandle* handle, | ||||||
|     const uint8_t address, |     const uint8_t address, | ||||||
|     const uint8_t* tx_data, |     const uint8_t* tx_data, | ||||||
|     const uint8_t tx_size, |     const uint8_t tx_size, | ||||||
| @ -33,11 +84,6 @@ bool furi_hal_i2c_trx( | |||||||
|     const uint8_t rx_size, |     const uint8_t rx_size, | ||||||
|     uint32_t timeout); |     uint32_t timeout); | ||||||
| 
 | 
 | ||||||
| #define with_furi_hal_i2c(type, pointer, function_body)       \ |  | ||||||
|     {                                                         \ |  | ||||||
|         *pointer = ({ type __fn__ function_body __fn__; })(); \ |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -7,37 +7,43 @@ | |||||||
| #define LED_CURRENT_WHITE 150 | #define LED_CURRENT_WHITE 150 | ||||||
| 
 | 
 | ||||||
| void furi_hal_light_init() { | 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_reset(&furi_hal_i2c_handle_power); | ||||||
|     lp5562_set_channel_current(LP5562ChannelGreen, LED_CURRENT_GREEN); |  | ||||||
|     lp5562_set_channel_current(LP5562ChannelBlue, LED_CURRENT_BLUE); |  | ||||||
|     lp5562_set_channel_current(LP5562ChannelWhite, LED_CURRENT_WHITE); |  | ||||||
| 
 | 
 | ||||||
|     lp5562_set_channel_value(LP5562ChannelRed, 0x00); |     lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelRed, LED_CURRENT_RED); | ||||||
|     lp5562_set_channel_value(LP5562ChannelGreen, 0x00); |     lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelGreen, LED_CURRENT_GREEN); | ||||||
|     lp5562_set_channel_value(LP5562ChannelBlue, 0x00); |     lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelBlue, LED_CURRENT_BLUE); | ||||||
|     lp5562_set_channel_value(LP5562ChannelWhite, 0x00); |     lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelWhite, LED_CURRENT_WHITE); | ||||||
| 
 | 
 | ||||||
|     lp5562_enable(); |     lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, 0x00); | ||||||
|     lp5562_configure(); |     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) { | void furi_hal_light_set(Light light, uint8_t value) { | ||||||
|  |     furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); | ||||||
|     switch(light) { |     switch(light) { | ||||||
|     case LightRed: |     case LightRed: | ||||||
|         lp5562_set_channel_value(LP5562ChannelRed, value); |         lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value); | ||||||
|         break; |         break; | ||||||
|     case LightGreen: |     case LightGreen: | ||||||
|         lp5562_set_channel_value(LP5562ChannelGreen, value); |         lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value); | ||||||
|         break; |         break; | ||||||
|     case LightBlue: |     case LightBlue: | ||||||
|         lp5562_set_channel_value(LP5562ChannelBlue, value); |         lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value); | ||||||
|         break; |         break; | ||||||
|     case LightBacklight: |     case LightBacklight: | ||||||
|         lp5562_set_channel_value(LP5562ChannelWhite, value); |         lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, value); | ||||||
|         break; |         break; | ||||||
|     default: |     default: | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|  |     furi_hal_i2c_release(&furi_hal_i2c_handle_power); | ||||||
| } | } | ||||||
| @ -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_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_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}; | ||||||
|  | |||||||
| @ -8,18 +8,6 @@ | |||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #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 */ | /* Input Keys */ | ||||||
| typedef enum { | typedef enum { | ||||||
|     InputKeyUp, |     InputKeyUp, | ||||||
| @ -77,6 +65,9 @@ extern const GpioPin gpio_irda_tx; | |||||||
| extern const GpioPin gpio_usart_tx; | extern const GpioPin gpio_usart_tx; | ||||||
| extern const GpioPin gpio_usart_rx; | extern const GpioPin gpio_usart_rx; | ||||||
| 
 | 
 | ||||||
|  | extern const GpioPin gpio_i2c_power_sda; | ||||||
|  | extern const GpioPin gpio_i2c_power_scl; | ||||||
|  | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
							
								
								
									
										149
									
								
								bootloader/targets/f7/furi-hal/furi-hal-i2c-config.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								bootloader/targets/f7/furi-hal/furi-hal-i2c-config.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,149 @@ | |||||||
|  | #include "furi-hal-i2c-config.h" | ||||||
|  | #include <furi-hal-resources.h> | ||||||
|  | #include <furi-hal-version.h> | ||||||
|  | 
 | ||||||
|  | #include <stm32wbxx_ll_rcc.h> | ||||||
|  | #include <stm32wbxx_ll_bus.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 | ||||||
|  | 
 | ||||||
|  | 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, | ||||||
|  | }; | ||||||
							
								
								
									
										31
									
								
								bootloader/targets/f7/furi-hal/furi-hal-i2c-config.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								bootloader/targets/f7/furi-hal/furi-hal-i2c-config.h
									
									
									
									
									
										Normal 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 | ||||||
							
								
								
									
										51
									
								
								bootloader/targets/f7/furi-hal/furi-hal-i2c-types.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								bootloader/targets/f7/furi-hal/furi-hal-i2c-types.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | |||||||
|  | #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 | ||||||
| @ -1,66 +1,64 @@ | |||||||
| #include <furi-hal-i2c.h> | #include <furi-hal-i2c.h> | ||||||
|  | #include <furi-hal-version.h> | ||||||
| 
 | 
 | ||||||
| #include <stm32wbxx_ll_bus.h> |  | ||||||
| #include <stm32wbxx_ll_i2c.h> | #include <stm32wbxx_ll_i2c.h> | ||||||
| #include <stm32wbxx_ll_rcc.h> |  | ||||||
| #include <stm32wbxx_ll_gpio.h> | #include <stm32wbxx_ll_gpio.h> | ||||||
| #include <stm32wbxx_ll_cortex.h> | #include <stm32wbxx_ll_cortex.h> | ||||||
| 
 | 
 | ||||||
|  | #include <assert.h> | ||||||
|  | 
 | ||||||
| void furi_hal_i2c_init() { | void furi_hal_i2c_init() { | ||||||
|     LL_I2C_InitTypeDef I2C_InitStruct = {0}; |     furi_hal_i2c_bus_power.callback(&furi_hal_i2c_bus_power, FuriHalI2cBusEventInit); | ||||||
|     LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; | } | ||||||
| 
 | 
 | ||||||
|     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); |     assert(handle->bus->current_handle == NULL); | ||||||
|     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); |  | ||||||
| 
 | 
 | ||||||
|     LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); |     handle->bus->current_handle = handle; | ||||||
| 
 | 
 | ||||||
|     I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C; |     handle->bus->callback(handle->bus, FuriHalI2cBusEventActivate); | ||||||
|     I2C_InitStruct.Timing = POWER_I2C_TIMINGS; | 
 | ||||||
|     I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE; |     handle->callback(handle, FuriHalI2cBusHandleEventActivate); | ||||||
|     I2C_InitStruct.DigitalFilter = 0; | } | ||||||
|     I2C_InitStruct.OwnAddress1 = 0; | 
 | ||||||
|     I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK; | void furi_hal_i2c_release(FuriHalI2cBusHandle* handle) { | ||||||
|     I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT; |     assert(handle->bus->current_handle == handle); | ||||||
|     LL_I2C_Init(I2C1, &I2C_InitStruct); | 
 | ||||||
|     LL_I2C_EnableAutoEndMode(I2C1); |     handle->callback(handle, FuriHalI2cBusHandleEventDeactivate); | ||||||
|     LL_I2C_SetOwnAddress2(I2C1, 0, LL_I2C_OWNADDRESS2_NOMASK); | 
 | ||||||
|     LL_I2C_DisableOwnAddress2(I2C1); |     handle->bus->callback(handle->bus, FuriHalI2cBusEventDeactivate); | ||||||
|     LL_I2C_DisableGeneralCall(I2C1); | 
 | ||||||
|     LL_I2C_EnableClockStretching(I2C1); |     handle->bus->current_handle = NULL; | ||||||
|  | 
 | ||||||
|  |     handle->bus->callback(handle->bus, FuriHalI2cBusEventUnlock); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool furi_hal_i2c_tx( | bool furi_hal_i2c_tx( | ||||||
|     I2C_TypeDef* instance, |     FuriHalI2cBusHandle* handle, | ||||||
|     uint8_t address, |     uint8_t address, | ||||||
|     const uint8_t* data, |     const uint8_t* data, | ||||||
|     uint8_t size, |     uint8_t size, | ||||||
|     uint32_t timeout) { |     uint32_t timeout) { | ||||||
|  |     assert(handle->bus->current_handle == handle); | ||||||
|     uint32_t time_left = timeout; |     uint32_t time_left = timeout; | ||||||
|     bool ret = true; |     bool ret = true; | ||||||
| 
 | 
 | ||||||
|     while(LL_I2C_IsActiveFlag_BUSY(instance)) |     while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c)) | ||||||
|         ; |         ; | ||||||
| 
 | 
 | ||||||
|     LL_I2C_HandleTransfer( |     LL_I2C_HandleTransfer( | ||||||
|         instance, |         handle->bus->i2c, | ||||||
|         address, |         address, | ||||||
|         LL_I2C_ADDRSLAVE_7BIT, |         LL_I2C_ADDRSLAVE_7BIT, | ||||||
|         size, |         size, | ||||||
|         LL_I2C_MODE_AUTOEND, |         LL_I2C_MODE_AUTOEND, | ||||||
|         LL_I2C_GENERATE_START_WRITE); |         LL_I2C_GENERATE_START_WRITE); | ||||||
| 
 | 
 | ||||||
|     while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) { |     while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) { | ||||||
|         if(LL_I2C_IsActiveFlag_TXIS(instance)) { |         if(LL_I2C_IsActiveFlag_TXIS(handle->bus->i2c)) { | ||||||
|             LL_I2C_TransmitData8(instance, (*data)); |             LL_I2C_TransmitData8(handle->bus->i2c, (*data)); | ||||||
|             data++; |             data++; | ||||||
|             size--; |             size--; | ||||||
|             time_left = timeout; |             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; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool furi_hal_i2c_rx( | bool furi_hal_i2c_rx( | ||||||
|     I2C_TypeDef* instance, |     FuriHalI2cBusHandle* handle, | ||||||
|     uint8_t address, |     uint8_t address, | ||||||
|     uint8_t* data, |     uint8_t* data, | ||||||
|     uint8_t size, |     uint8_t size, | ||||||
|     uint32_t timeout) { |     uint32_t timeout) { | ||||||
|  |     assert(handle->bus->current_handle == handle); | ||||||
|     uint32_t time_left = timeout; |     uint32_t time_left = timeout; | ||||||
|     bool ret = true; |     bool ret = true; | ||||||
| 
 | 
 | ||||||
|     while(LL_I2C_IsActiveFlag_BUSY(instance)) |     while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c)) | ||||||
|         ; |         ; | ||||||
| 
 | 
 | ||||||
|     LL_I2C_HandleTransfer( |     LL_I2C_HandleTransfer( | ||||||
|         instance, |         handle->bus->i2c, | ||||||
|         address, |         address, | ||||||
|         LL_I2C_ADDRSLAVE_7BIT, |         LL_I2C_ADDRSLAVE_7BIT, | ||||||
|         size, |         size, | ||||||
|         LL_I2C_MODE_AUTOEND, |         LL_I2C_MODE_AUTOEND, | ||||||
|         LL_I2C_GENERATE_START_READ); |         LL_I2C_GENERATE_START_READ); | ||||||
| 
 | 
 | ||||||
|     while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) { |     while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) { | ||||||
|         if(LL_I2C_IsActiveFlag_RXNE(instance)) { |         if(LL_I2C_IsActiveFlag_RXNE(handle->bus->i2c)) { | ||||||
|             *data = LL_I2C_ReceiveData8(instance); |             *data = LL_I2C_ReceiveData8(handle->bus->i2c); | ||||||
|             data++; |             data++; | ||||||
|             size--; |             size--; | ||||||
|             time_left = timeout; |             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; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool furi_hal_i2c_trx( | bool furi_hal_i2c_trx( | ||||||
|     I2C_TypeDef* instance, |     FuriHalI2cBusHandle* handle, | ||||||
|     uint8_t address, |     uint8_t address, | ||||||
|     const uint8_t* tx_data, |     const uint8_t* tx_data, | ||||||
|     uint8_t tx_size, |     uint8_t tx_size, | ||||||
|     uint8_t* rx_data, |     uint8_t* rx_data, | ||||||
|     uint8_t rx_size, |     uint8_t rx_size, | ||||||
|     uint32_t timeout) { |     uint32_t timeout) { | ||||||
|     if(furi_hal_i2c_tx(instance, address, tx_data, tx_size, timeout) && |     if(furi_hal_i2c_tx(handle, address, tx_data, tx_size, timeout) && | ||||||
|        furi_hal_i2c_rx(instance, address, rx_data, rx_size, timeout)) { |        furi_hal_i2c_rx(handle, address, rx_data, rx_size, timeout)) { | ||||||
|         return true; |         return true; | ||||||
|     } else { |     } else { | ||||||
|         return false; |         return false; | ||||||
|  | |||||||
| @ -1,31 +1,82 @@ | |||||||
|  | /**
 | ||||||
|  |  * @file furi-hal-i2c.h | ||||||
|  |  * I2C HAL API | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <furi-hal-resources.h> | #include <furi-hal-i2c-config.h> | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | /** Init I2C
 | ||||||
|  |  */ | ||||||
| void furi_hal_i2c_init(); | 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( | bool furi_hal_i2c_tx( | ||||||
|     I2C_TypeDef* instance, |     FuriHalI2cBusHandle* handle, | ||||||
|     const uint8_t address, |     const uint8_t address, | ||||||
|     const uint8_t* data, |     const uint8_t* data, | ||||||
|     const uint8_t size, |     const uint8_t size, | ||||||
|     uint32_t timeout); |     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( | bool furi_hal_i2c_rx( | ||||||
|     I2C_TypeDef* instance, |     FuriHalI2cBusHandle* handle, | ||||||
|     const uint8_t address, |     const uint8_t address, | ||||||
|     uint8_t* data, |     uint8_t* data, | ||||||
|     const uint8_t size, |     const uint8_t size, | ||||||
|     uint32_t timeout); |     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( | bool furi_hal_i2c_trx( | ||||||
|     I2C_TypeDef* instance, |     FuriHalI2cBusHandle* handle, | ||||||
|     const uint8_t address, |     const uint8_t address, | ||||||
|     const uint8_t* tx_data, |     const uint8_t* tx_data, | ||||||
|     const uint8_t tx_size, |     const uint8_t tx_size, | ||||||
| @ -33,11 +84,6 @@ bool furi_hal_i2c_trx( | |||||||
|     const uint8_t rx_size, |     const uint8_t rx_size, | ||||||
|     uint32_t timeout); |     uint32_t timeout); | ||||||
| 
 | 
 | ||||||
| #define with_furi_hal_i2c(type, pointer, function_body)       \ |  | ||||||
|     {                                                         \ |  | ||||||
|         *pointer = ({ type __fn__ function_body __fn__; })(); \ |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -7,37 +7,43 @@ | |||||||
| #define LED_CURRENT_WHITE 150 | #define LED_CURRENT_WHITE 150 | ||||||
| 
 | 
 | ||||||
| void furi_hal_light_init() { | 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_reset(&furi_hal_i2c_handle_power); | ||||||
|     lp5562_set_channel_current(LP5562ChannelGreen, LED_CURRENT_GREEN); |  | ||||||
|     lp5562_set_channel_current(LP5562ChannelBlue, LED_CURRENT_BLUE); |  | ||||||
|     lp5562_set_channel_current(LP5562ChannelWhite, LED_CURRENT_WHITE); |  | ||||||
| 
 | 
 | ||||||
|     lp5562_set_channel_value(LP5562ChannelRed, 0x00); |     lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelRed, LED_CURRENT_RED); | ||||||
|     lp5562_set_channel_value(LP5562ChannelGreen, 0x00); |     lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelGreen, LED_CURRENT_GREEN); | ||||||
|     lp5562_set_channel_value(LP5562ChannelBlue, 0x00); |     lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelBlue, LED_CURRENT_BLUE); | ||||||
|     lp5562_set_channel_value(LP5562ChannelWhite, 0x00); |     lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelWhite, LED_CURRENT_WHITE); | ||||||
| 
 | 
 | ||||||
|     lp5562_enable(); |     lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, 0x00); | ||||||
|     lp5562_configure(); |     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) { | void furi_hal_light_set(Light light, uint8_t value) { | ||||||
|  |     furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); | ||||||
|     switch(light) { |     switch(light) { | ||||||
|     case LightRed: |     case LightRed: | ||||||
|         lp5562_set_channel_value(LP5562ChannelRed, value); |         lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value); | ||||||
|         break; |         break; | ||||||
|     case LightGreen: |     case LightGreen: | ||||||
|         lp5562_set_channel_value(LP5562ChannelGreen, value); |         lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value); | ||||||
|         break; |         break; | ||||||
|     case LightBlue: |     case LightBlue: | ||||||
|         lp5562_set_channel_value(LP5562ChannelBlue, value); |         lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value); | ||||||
|         break; |         break; | ||||||
|     case LightBacklight: |     case LightBacklight: | ||||||
|         lp5562_set_channel_value(LP5562ChannelWhite, value); |         lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, value); | ||||||
|         break; |         break; | ||||||
|     default: |     default: | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|  |     furi_hal_i2c_release(&furi_hal_i2c_handle_power); | ||||||
| } | } | ||||||
| @ -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_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_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}; | ||||||
|  | |||||||
| @ -8,18 +8,6 @@ | |||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #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 */ | /* Input Keys */ | ||||||
| typedef enum { | typedef enum { | ||||||
|     InputKeyUp, |     InputKeyUp, | ||||||
| @ -77,6 +65,9 @@ extern const GpioPin gpio_irda_tx; | |||||||
| extern const GpioPin gpio_usart_tx; | extern const GpioPin gpio_usart_tx; | ||||||
| extern const GpioPin gpio_usart_rx; | extern const GpioPin gpio_usart_rx; | ||||||
| 
 | 
 | ||||||
|  | extern const GpioPin gpio_i2c_power_sda; | ||||||
|  | extern const GpioPin gpio_i2c_power_scl; | ||||||
|  | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
							
								
								
									
										133
									
								
								firmware/targets/f6/furi-hal/furi-hal-i2c-config.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								firmware/targets/f6/furi-hal/furi-hal-i2c-config.c
									
									
									
									
									
										Normal 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, | ||||||
|  | }; | ||||||
							
								
								
									
										31
									
								
								firmware/targets/f6/furi-hal/furi-hal-i2c-config.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								firmware/targets/f6/furi-hal/furi-hal-i2c-config.h
									
									
									
									
									
										Normal 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 | ||||||
							
								
								
									
										49
									
								
								firmware/targets/f6/furi-hal/furi-hal-i2c-types.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								firmware/targets/f6/furi-hal/furi-hal-i2c-types.h
									
									
									
									
									
										Normal 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 | ||||||
| @ -8,68 +8,62 @@ | |||||||
| 
 | 
 | ||||||
| #define TAG "FuriHalI2C" | #define TAG "FuriHalI2C" | ||||||
| 
 | 
 | ||||||
| osMutexId_t furi_hal_i2c_mutex = NULL; |  | ||||||
| 
 |  | ||||||
| void furi_hal_i2c_init() { | void furi_hal_i2c_init() { | ||||||
|     furi_hal_i2c_mutex = osMutexNew(NULL); |     furi_hal_i2c_bus_power.callback(&furi_hal_i2c_bus_power, FuriHalI2cBusEventInit); | ||||||
|     furi_check(furi_hal_i2c_mutex); |     furi_hal_i2c_bus_external.callback(&furi_hal_i2c_bus_external, FuriHalI2cBusEventInit); | ||||||
| 
 |  | ||||||
|     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_LOG_I(TAG, "Init OK"); |     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( | bool furi_hal_i2c_tx( | ||||||
|     I2C_TypeDef* instance, |     FuriHalI2cBusHandle* handle, | ||||||
|     uint8_t address, |     uint8_t address, | ||||||
|     const uint8_t* data, |     const uint8_t* data, | ||||||
|     uint8_t size, |     uint8_t size, | ||||||
|     uint32_t timeout) { |     uint32_t timeout) { | ||||||
|  |     furi_check(handle->bus->current_handle == handle); | ||||||
|     uint32_t time_left = timeout; |     uint32_t time_left = timeout; | ||||||
|     bool ret = true; |     bool ret = true; | ||||||
| 
 | 
 | ||||||
|     while(LL_I2C_IsActiveFlag_BUSY(instance)) |     while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c)) | ||||||
|         ; |         ; | ||||||
| 
 | 
 | ||||||
|     LL_I2C_HandleTransfer( |     LL_I2C_HandleTransfer( | ||||||
|         instance, |         handle->bus->i2c, | ||||||
|         address, |         address, | ||||||
|         LL_I2C_ADDRSLAVE_7BIT, |         LL_I2C_ADDRSLAVE_7BIT, | ||||||
|         size, |         size, | ||||||
|         LL_I2C_MODE_AUTOEND, |         LL_I2C_MODE_AUTOEND, | ||||||
|         LL_I2C_GENERATE_START_WRITE); |         LL_I2C_GENERATE_START_WRITE); | ||||||
| 
 | 
 | ||||||
|     while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) { |     while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) { | ||||||
|         if(LL_I2C_IsActiveFlag_TXIS(instance)) { |         if(LL_I2C_IsActiveFlag_TXIS(handle->bus->i2c)) { | ||||||
|             LL_I2C_TransmitData8(instance, (*data)); |             LL_I2C_TransmitData8(handle->bus->i2c, (*data)); | ||||||
|             data++; |             data++; | ||||||
|             size--; |             size--; | ||||||
|             time_left = timeout; |             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; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool furi_hal_i2c_rx( | bool furi_hal_i2c_rx( | ||||||
|     I2C_TypeDef* instance, |     FuriHalI2cBusHandle* handle, | ||||||
|     uint8_t address, |     uint8_t address, | ||||||
|     uint8_t* data, |     uint8_t* data, | ||||||
|     uint8_t size, |     uint8_t size, | ||||||
|     uint32_t timeout) { |     uint32_t timeout) { | ||||||
|  |     furi_check(handle->bus->current_handle == handle); | ||||||
|     uint32_t time_left = timeout; |     uint32_t time_left = timeout; | ||||||
|     bool ret = true; |     bool ret = true; | ||||||
| 
 | 
 | ||||||
|     while(LL_I2C_IsActiveFlag_BUSY(instance)) |     while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c)) | ||||||
|         ; |         ; | ||||||
| 
 | 
 | ||||||
|     LL_I2C_HandleTransfer( |     LL_I2C_HandleTransfer( | ||||||
|         instance, |         handle->bus->i2c, | ||||||
|         address, |         address, | ||||||
|         LL_I2C_ADDRSLAVE_7BIT, |         LL_I2C_ADDRSLAVE_7BIT, | ||||||
|         size, |         size, | ||||||
|         LL_I2C_MODE_AUTOEND, |         LL_I2C_MODE_AUTOEND, | ||||||
|         LL_I2C_GENERATE_START_READ); |         LL_I2C_GENERATE_START_READ); | ||||||
| 
 | 
 | ||||||
|     while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) { |     while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) { | ||||||
|         if(LL_I2C_IsActiveFlag_RXNE(instance)) { |         if(LL_I2C_IsActiveFlag_RXNE(handle->bus->i2c)) { | ||||||
|             *data = LL_I2C_ReceiveData8(instance); |             *data = LL_I2C_ReceiveData8(handle->bus->i2c); | ||||||
|             data++; |             data++; | ||||||
|             size--; |             size--; | ||||||
|             time_left = timeout; |             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; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool furi_hal_i2c_trx( | bool furi_hal_i2c_trx( | ||||||
|     I2C_TypeDef* instance, |     FuriHalI2cBusHandle* handle, | ||||||
|     uint8_t address, |     uint8_t address, | ||||||
|     const uint8_t* tx_data, |     const uint8_t* tx_data, | ||||||
|     uint8_t tx_size, |     uint8_t tx_size, | ||||||
|     uint8_t* rx_data, |     uint8_t* rx_data, | ||||||
|     uint8_t rx_size, |     uint8_t rx_size, | ||||||
|     uint32_t timeout) { |     uint32_t timeout) { | ||||||
|     if(furi_hal_i2c_tx(instance, address, tx_data, tx_size, timeout) && |     if(furi_hal_i2c_tx(handle, address, tx_data, tx_size, timeout) && | ||||||
|        furi_hal_i2c_rx(instance, address, rx_data, rx_size, timeout)) { |        furi_hal_i2c_rx(handle, address, rx_data, rx_size, timeout)) { | ||||||
|         return true; |         return true; | ||||||
|     } else { |     } else { | ||||||
|         return false; |         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); |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -1,46 +1,49 @@ | |||||||
| #include <furi-hal-light.h> | #include <furi-hal-light.h> | ||||||
| #include <lp5562.h> | #include <lp5562.h> | ||||||
| 
 | 
 | ||||||
| #define TAG "FuriHalLight" | #define LED_CURRENT_RED 50 | ||||||
| 
 | #define LED_CURRENT_GREEN 50 | ||||||
| #define LED_CURRENT_RED     50 | #define LED_CURRENT_BLUE 50 | ||||||
| #define LED_CURRENT_GREEN   50 | #define LED_CURRENT_WHITE 150 | ||||||
| #define LED_CURRENT_BLUE    50 |  | ||||||
| #define LED_CURRENT_WHITE   150 |  | ||||||
| 
 | 
 | ||||||
| void furi_hal_light_init() { | 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_reset(&furi_hal_i2c_handle_power); | ||||||
|     lp5562_set_channel_current(LP5562ChannelGreen, LED_CURRENT_GREEN); |  | ||||||
|     lp5562_set_channel_current(LP5562ChannelBlue, LED_CURRENT_BLUE); |  | ||||||
|     lp5562_set_channel_current(LP5562ChannelWhite, LED_CURRENT_WHITE); |  | ||||||
| 
 | 
 | ||||||
|     lp5562_set_channel_value(LP5562ChannelRed, 0x00); |     lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelRed, LED_CURRENT_RED); | ||||||
|     lp5562_set_channel_value(LP5562ChannelGreen, 0x00); |     lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelGreen, LED_CURRENT_GREEN); | ||||||
|     lp5562_set_channel_value(LP5562ChannelBlue, 0x00); |     lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelBlue, LED_CURRENT_BLUE); | ||||||
|     lp5562_set_channel_value(LP5562ChannelWhite, 0x00); |     lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelWhite, LED_CURRENT_WHITE); | ||||||
| 
 | 
 | ||||||
|     lp5562_enable(); |     lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, 0x00); | ||||||
|     lp5562_configure(); |     lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, 0x00); | ||||||
|     FURI_LOG_I(TAG, "Init OK"); |     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) { | void furi_hal_light_set(Light light, uint8_t value) { | ||||||
|  |     furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); | ||||||
|     switch(light) { |     switch(light) { | ||||||
|         case LightRed: |     case LightRed: | ||||||
|             lp5562_set_channel_value(LP5562ChannelRed, value); |         lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value); | ||||||
|         break; |         break; | ||||||
|         case LightGreen: |     case LightGreen: | ||||||
|             lp5562_set_channel_value(LP5562ChannelGreen, value); |         lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value); | ||||||
|         break; |         break; | ||||||
|         case LightBlue: |     case LightBlue: | ||||||
|             lp5562_set_channel_value(LP5562ChannelBlue, value); |         lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value); | ||||||
|         break; |         break; | ||||||
|         case LightBacklight: |     case LightBacklight: | ||||||
|             lp5562_set_channel_value(LP5562ChannelWhite, value); |         lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, value); | ||||||
|         break; |         break; | ||||||
|         default: |     default: | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|  |     furi_hal_i2c_release(&furi_hal_i2c_handle_power); | ||||||
| } | } | ||||||
| @ -74,8 +74,12 @@ void HAL_RCC_CSSCallback(void) { | |||||||
| void furi_hal_power_init() { | void furi_hal_power_init() { | ||||||
|     LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); |     LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); | ||||||
|     LL_PWR_SMPS_SetMode(LL_PWR_SMPS_STEP_DOWN); |     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"); |     FURI_LOG_I(TAG, "Init OK"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -161,19 +165,30 @@ void furi_hal_power_sleep() { | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| uint8_t furi_hal_power_get_pct() { | 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() { | 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() { | 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() { | 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() { | void furi_hal_power_reset() { | ||||||
| @ -181,66 +196,102 @@ void furi_hal_power_reset() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_power_enable_otg() { | 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() { | 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() { | 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() { | 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() { | 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 furi_hal_power_get_battery_voltage(FuriHalPowerIC ic) { | ||||||
|  |     float ret = 0.0f; | ||||||
|  | 
 | ||||||
|  |     furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); | ||||||
|     if (ic == FuriHalPowerICCharger) { |     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) { |     } else if (ic == FuriHalPowerICFuelGauge) { | ||||||
|         return (float)bq27220_get_voltage() / 1000.0f; |         ret = (float)bq27220_get_voltage(&furi_hal_i2c_handle_power) / 1000.0f; | ||||||
|     } else { |  | ||||||
|         return 0.0f; |  | ||||||
|     } |     } | ||||||
|  |     furi_hal_i2c_release(&furi_hal_i2c_handle_power); | ||||||
|  | 
 | ||||||
|  |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| float furi_hal_power_get_battery_current(FuriHalPowerIC ic) { | 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) { |     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) { |     } else if (ic == FuriHalPowerICFuelGauge) { | ||||||
|         return (float)bq27220_get_current() / 1000.0f; |         ret = (float)bq27220_get_current(&furi_hal_i2c_handle_power) / 1000.0f; | ||||||
|     } else { |  | ||||||
|         return 0.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) { | float furi_hal_power_get_battery_temperature(FuriHalPowerIC ic) { | ||||||
|     if (ic == FuriHalPowerICCharger) { |     furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); | ||||||
|         // Linear approximation, +/- 5 C
 |     float ret = furi_hal_power_get_battery_temperature_internal(ic); | ||||||
|         return (71.0f - (float)bq25896_get_ntc_mpct()/1000) / 0.6f; |     furi_hal_i2c_release(&furi_hal_i2c_handle_power); | ||||||
|     } else if (ic == FuriHalPowerICFuelGauge) { |  | ||||||
|         return ((float)bq27220_get_temperature() - 2731.0f) / 10.0f; |  | ||||||
|     } else { |  | ||||||
|         return 0.0f; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|  |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| float furi_hal_power_get_usb_voltage(){ | 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() { | void furi_hal_power_dump_state() { | ||||||
|     BatteryStatus battery_status; |     BatteryStatus battery_status; | ||||||
|     OperationStatus operation_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"); |         printf("Failed to get bq27220 status. Communication error.\r\n"); | ||||||
|     } else { |     } else { | ||||||
|         printf( |         printf( | ||||||
| @ -266,21 +317,23 @@ void furi_hal_power_dump_state() { | |||||||
|         // Voltage and current info
 |         // Voltage and current info
 | ||||||
|         printf( |         printf( | ||||||
|             "bq27220: Full capacity: %dmAh, Design capacity: %dmAh, Remaining capacity: %dmAh, State of Charge: %d%%, State of health: %d%%\r\n", |             "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_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(), bq27220_get_state_of_health() |             bq27220_get_state_of_charge(&furi_hal_i2c_handle_power), bq27220_get_state_of_health(&furi_hal_i2c_handle_power) | ||||||
|         ); |         ); | ||||||
|         printf( |         printf( | ||||||
|             "bq27220: Voltage: %dmV, Current: %dmA, Temperature: %dC\r\n", |             "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( |     printf( | ||||||
|         "bq25896: VBUS: %d, VSYS: %d, VBAT: %d, Current: %d, NTC: %ldm%%\r\n", |         "bq25896: VBUS: %d, VSYS: %d, VBAT: %d, Current: %d, NTC: %ldm%%\r\n", | ||||||
|         bq25896_get_vbus_voltage(), bq25896_get_vsys_voltage(), |         bq25896_get_vbus_voltage(&furi_hal_i2c_handle_power), bq25896_get_vsys_voltage(&furi_hal_i2c_handle_power), | ||||||
|         bq25896_get_vbat_voltage(), bq25896_get_vbat_current(), |         bq25896_get_vbat_voltage(&furi_hal_i2c_handle_power), bq25896_get_vbat_current(&furi_hal_i2c_handle_power), | ||||||
|         bq25896_get_ntc_mpct() |         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(){ | void furi_hal_power_enable_external_3_3v(){ | ||||||
| @ -298,7 +351,9 @@ void furi_hal_power_suppress_charge_enter() { | |||||||
|     xTaskResumeAll(); |     xTaskResumeAll(); | ||||||
| 
 | 
 | ||||||
|     if (disable_charging) { |     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(); |     xTaskResumeAll(); | ||||||
| 
 | 
 | ||||||
|     if (enable_charging) { |     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); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -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_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_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}; | ||||||
|  | |||||||
| @ -10,24 +10,6 @@ | |||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #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 */ | /* Input Related Constants */ | ||||||
| #define INPUT_DEBOUNCE_TICKS 20 | #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_tx; | ||||||
| extern const GpioPin gpio_usart_rx; | extern const GpioPin gpio_usart_rx; | ||||||
|  | extern const GpioPin gpio_i2c_power_sda; | ||||||
|  | extern const GpioPin gpio_i2c_power_scl; | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
|  | |||||||
| @ -280,7 +280,7 @@ static void vcp_on_cdc_control_line(void* context, uint8_t state) { | |||||||
| 
 | 
 | ||||||
| static void vcp_on_cdc_rx(void* context) { | static void vcp_on_cdc_rx(void* context) { | ||||||
|     uint32_t ret = osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtRx); |     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) { | static void vcp_on_cdc_tx_complete(void* context) { | ||||||
|  | |||||||
							
								
								
									
										133
									
								
								firmware/targets/f7/furi-hal/furi-hal-i2c-config.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								firmware/targets/f7/furi-hal/furi-hal-i2c-config.c
									
									
									
									
									
										Normal 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, | ||||||
|  | }; | ||||||
							
								
								
									
										31
									
								
								firmware/targets/f7/furi-hal/furi-hal-i2c-config.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								firmware/targets/f7/furi-hal/furi-hal-i2c-config.h
									
									
									
									
									
										Normal 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 | ||||||
							
								
								
									
										49
									
								
								firmware/targets/f7/furi-hal/furi-hal-i2c-types.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								firmware/targets/f7/furi-hal/furi-hal-i2c-types.h
									
									
									
									
									
										Normal 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 | ||||||
| @ -8,68 +8,62 @@ | |||||||
| 
 | 
 | ||||||
| #define TAG "FuriHalI2C" | #define TAG "FuriHalI2C" | ||||||
| 
 | 
 | ||||||
| osMutexId_t furi_hal_i2c_mutex = NULL; |  | ||||||
| 
 |  | ||||||
| void furi_hal_i2c_init() { | void furi_hal_i2c_init() { | ||||||
|     furi_hal_i2c_mutex = osMutexNew(NULL); |     furi_hal_i2c_bus_power.callback(&furi_hal_i2c_bus_power, FuriHalI2cBusEventInit); | ||||||
|     furi_check(furi_hal_i2c_mutex); |     furi_hal_i2c_bus_external.callback(&furi_hal_i2c_bus_external, FuriHalI2cBusEventInit); | ||||||
| 
 |  | ||||||
|     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_LOG_I(TAG, "Init OK"); |     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( | bool furi_hal_i2c_tx( | ||||||
|     I2C_TypeDef* instance, |     FuriHalI2cBusHandle* handle, | ||||||
|     uint8_t address, |     uint8_t address, | ||||||
|     const uint8_t* data, |     const uint8_t* data, | ||||||
|     uint8_t size, |     uint8_t size, | ||||||
|     uint32_t timeout) { |     uint32_t timeout) { | ||||||
|  |     furi_check(handle->bus->current_handle == handle); | ||||||
|     uint32_t time_left = timeout; |     uint32_t time_left = timeout; | ||||||
|     bool ret = true; |     bool ret = true; | ||||||
| 
 | 
 | ||||||
|     while(LL_I2C_IsActiveFlag_BUSY(instance)) |     while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c)) | ||||||
|         ; |         ; | ||||||
| 
 | 
 | ||||||
|     LL_I2C_HandleTransfer( |     LL_I2C_HandleTransfer( | ||||||
|         instance, |         handle->bus->i2c, | ||||||
|         address, |         address, | ||||||
|         LL_I2C_ADDRSLAVE_7BIT, |         LL_I2C_ADDRSLAVE_7BIT, | ||||||
|         size, |         size, | ||||||
|         LL_I2C_MODE_AUTOEND, |         LL_I2C_MODE_AUTOEND, | ||||||
|         LL_I2C_GENERATE_START_WRITE); |         LL_I2C_GENERATE_START_WRITE); | ||||||
| 
 | 
 | ||||||
|     while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) { |     while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) { | ||||||
|         if(LL_I2C_IsActiveFlag_TXIS(instance)) { |         if(LL_I2C_IsActiveFlag_TXIS(handle->bus->i2c)) { | ||||||
|             LL_I2C_TransmitData8(instance, (*data)); |             LL_I2C_TransmitData8(handle->bus->i2c, (*data)); | ||||||
|             data++; |             data++; | ||||||
|             size--; |             size--; | ||||||
|             time_left = timeout; |             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; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool furi_hal_i2c_rx( | bool furi_hal_i2c_rx( | ||||||
|     I2C_TypeDef* instance, |     FuriHalI2cBusHandle* handle, | ||||||
|     uint8_t address, |     uint8_t address, | ||||||
|     uint8_t* data, |     uint8_t* data, | ||||||
|     uint8_t size, |     uint8_t size, | ||||||
|     uint32_t timeout) { |     uint32_t timeout) { | ||||||
|  |     furi_check(handle->bus->current_handle == handle); | ||||||
|     uint32_t time_left = timeout; |     uint32_t time_left = timeout; | ||||||
|     bool ret = true; |     bool ret = true; | ||||||
| 
 | 
 | ||||||
|     while(LL_I2C_IsActiveFlag_BUSY(instance)) |     while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c)) | ||||||
|         ; |         ; | ||||||
| 
 | 
 | ||||||
|     LL_I2C_HandleTransfer( |     LL_I2C_HandleTransfer( | ||||||
|         instance, |         handle->bus->i2c, | ||||||
|         address, |         address, | ||||||
|         LL_I2C_ADDRSLAVE_7BIT, |         LL_I2C_ADDRSLAVE_7BIT, | ||||||
|         size, |         size, | ||||||
|         LL_I2C_MODE_AUTOEND, |         LL_I2C_MODE_AUTOEND, | ||||||
|         LL_I2C_GENERATE_START_READ); |         LL_I2C_GENERATE_START_READ); | ||||||
| 
 | 
 | ||||||
|     while(!LL_I2C_IsActiveFlag_STOP(instance) || size > 0) { |     while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) { | ||||||
|         if(LL_I2C_IsActiveFlag_RXNE(instance)) { |         if(LL_I2C_IsActiveFlag_RXNE(handle->bus->i2c)) { | ||||||
|             *data = LL_I2C_ReceiveData8(instance); |             *data = LL_I2C_ReceiveData8(handle->bus->i2c); | ||||||
|             data++; |             data++; | ||||||
|             size--; |             size--; | ||||||
|             time_left = timeout; |             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; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool furi_hal_i2c_trx( | bool furi_hal_i2c_trx( | ||||||
|     I2C_TypeDef* instance, |     FuriHalI2cBusHandle* handle, | ||||||
|     uint8_t address, |     uint8_t address, | ||||||
|     const uint8_t* tx_data, |     const uint8_t* tx_data, | ||||||
|     uint8_t tx_size, |     uint8_t tx_size, | ||||||
|     uint8_t* rx_data, |     uint8_t* rx_data, | ||||||
|     uint8_t rx_size, |     uint8_t rx_size, | ||||||
|     uint32_t timeout) { |     uint32_t timeout) { | ||||||
|     if(furi_hal_i2c_tx(instance, address, tx_data, tx_size, timeout) && |     if(furi_hal_i2c_tx(handle, address, tx_data, tx_size, timeout) && | ||||||
|        furi_hal_i2c_rx(instance, address, rx_data, rx_size, timeout)) { |        furi_hal_i2c_rx(handle, address, rx_data, rx_size, timeout)) { | ||||||
|         return true; |         return true; | ||||||
|     } else { |     } else { | ||||||
|         return false; |         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); |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -1,46 +1,49 @@ | |||||||
| #include <furi-hal-light.h> | #include <furi-hal-light.h> | ||||||
| #include <lp5562.h> | #include <lp5562.h> | ||||||
| 
 | 
 | ||||||
| #define TAG "FuriHalLight" | #define LED_CURRENT_RED 50 | ||||||
| 
 | #define LED_CURRENT_GREEN 50 | ||||||
| #define LED_CURRENT_RED     50 | #define LED_CURRENT_BLUE 50 | ||||||
| #define LED_CURRENT_GREEN   50 | #define LED_CURRENT_WHITE 150 | ||||||
| #define LED_CURRENT_BLUE    50 |  | ||||||
| #define LED_CURRENT_WHITE   150 |  | ||||||
| 
 | 
 | ||||||
| void furi_hal_light_init() { | 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_reset(&furi_hal_i2c_handle_power); | ||||||
|     lp5562_set_channel_current(LP5562ChannelGreen, LED_CURRENT_GREEN); |  | ||||||
|     lp5562_set_channel_current(LP5562ChannelBlue, LED_CURRENT_BLUE); |  | ||||||
|     lp5562_set_channel_current(LP5562ChannelWhite, LED_CURRENT_WHITE); |  | ||||||
| 
 | 
 | ||||||
|     lp5562_set_channel_value(LP5562ChannelRed, 0x00); |     lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelRed, LED_CURRENT_RED); | ||||||
|     lp5562_set_channel_value(LP5562ChannelGreen, 0x00); |     lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelGreen, LED_CURRENT_GREEN); | ||||||
|     lp5562_set_channel_value(LP5562ChannelBlue, 0x00); |     lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelBlue, LED_CURRENT_BLUE); | ||||||
|     lp5562_set_channel_value(LP5562ChannelWhite, 0x00); |     lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelWhite, LED_CURRENT_WHITE); | ||||||
| 
 | 
 | ||||||
|     lp5562_enable(); |     lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, 0x00); | ||||||
|     lp5562_configure(); |     lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, 0x00); | ||||||
|     FURI_LOG_I(TAG, "Init OK"); |     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) { | void furi_hal_light_set(Light light, uint8_t value) { | ||||||
|  |     furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); | ||||||
|     switch(light) { |     switch(light) { | ||||||
|         case LightRed: |     case LightRed: | ||||||
|             lp5562_set_channel_value(LP5562ChannelRed, value); |         lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value); | ||||||
|         break; |         break; | ||||||
|         case LightGreen: |     case LightGreen: | ||||||
|             lp5562_set_channel_value(LP5562ChannelGreen, value); |         lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value); | ||||||
|         break; |         break; | ||||||
|         case LightBlue: |     case LightBlue: | ||||||
|             lp5562_set_channel_value(LP5562ChannelBlue, value); |         lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value); | ||||||
|         break; |         break; | ||||||
|         case LightBacklight: |     case LightBacklight: | ||||||
|             lp5562_set_channel_value(LP5562ChannelWhite, value); |         lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, value); | ||||||
|         break; |         break; | ||||||
|         default: |     default: | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|  |     furi_hal_i2c_release(&furi_hal_i2c_handle_power); | ||||||
| } | } | ||||||
| @ -74,8 +74,12 @@ void HAL_RCC_CSSCallback(void) { | |||||||
| void furi_hal_power_init() { | void furi_hal_power_init() { | ||||||
|     LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); |     LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); | ||||||
|     LL_PWR_SMPS_SetMode(LL_PWR_SMPS_STEP_DOWN); |     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"); |     FURI_LOG_I(TAG, "Init OK"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -161,19 +165,30 @@ void furi_hal_power_sleep() { | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| uint8_t furi_hal_power_get_pct() { | 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() { | 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() { | 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() { | 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() { | void furi_hal_power_reset() { | ||||||
| @ -181,66 +196,102 @@ void furi_hal_power_reset() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_power_enable_otg() { | 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() { | 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() { | 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() { | 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() { | 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 furi_hal_power_get_battery_voltage(FuriHalPowerIC ic) { | ||||||
|  |     float ret = 0.0f; | ||||||
|  | 
 | ||||||
|  |     furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); | ||||||
|     if (ic == FuriHalPowerICCharger) { |     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) { |     } else if (ic == FuriHalPowerICFuelGauge) { | ||||||
|         return (float)bq27220_get_voltage() / 1000.0f; |         ret = (float)bq27220_get_voltage(&furi_hal_i2c_handle_power) / 1000.0f; | ||||||
|     } else { |  | ||||||
|         return 0.0f; |  | ||||||
|     } |     } | ||||||
|  |     furi_hal_i2c_release(&furi_hal_i2c_handle_power); | ||||||
|  | 
 | ||||||
|  |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| float furi_hal_power_get_battery_current(FuriHalPowerIC ic) { | 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) { |     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) { |     } else if (ic == FuriHalPowerICFuelGauge) { | ||||||
|         return (float)bq27220_get_current() / 1000.0f; |         ret = (float)bq27220_get_current(&furi_hal_i2c_handle_power) / 1000.0f; | ||||||
|     } else { |  | ||||||
|         return 0.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) { | float furi_hal_power_get_battery_temperature(FuriHalPowerIC ic) { | ||||||
|     if (ic == FuriHalPowerICCharger) { |     furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); | ||||||
|         // Linear approximation, +/- 5 C
 |     float ret = furi_hal_power_get_battery_temperature_internal(ic); | ||||||
|         return (71.0f - (float)bq25896_get_ntc_mpct()/1000) / 0.6f; |     furi_hal_i2c_release(&furi_hal_i2c_handle_power); | ||||||
|     } else if (ic == FuriHalPowerICFuelGauge) { |  | ||||||
|         return ((float)bq27220_get_temperature() - 2731.0f) / 10.0f; |  | ||||||
|     } else { |  | ||||||
|         return 0.0f; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|  |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| float furi_hal_power_get_usb_voltage(){ | 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() { | void furi_hal_power_dump_state() { | ||||||
|     BatteryStatus battery_status; |     BatteryStatus battery_status; | ||||||
|     OperationStatus operation_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"); |         printf("Failed to get bq27220 status. Communication error.\r\n"); | ||||||
|     } else { |     } else { | ||||||
|         printf( |         printf( | ||||||
| @ -266,21 +317,23 @@ void furi_hal_power_dump_state() { | |||||||
|         // Voltage and current info
 |         // Voltage and current info
 | ||||||
|         printf( |         printf( | ||||||
|             "bq27220: Full capacity: %dmAh, Design capacity: %dmAh, Remaining capacity: %dmAh, State of Charge: %d%%, State of health: %d%%\r\n", |             "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_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(), bq27220_get_state_of_health() |             bq27220_get_state_of_charge(&furi_hal_i2c_handle_power), bq27220_get_state_of_health(&furi_hal_i2c_handle_power) | ||||||
|         ); |         ); | ||||||
|         printf( |         printf( | ||||||
|             "bq27220: Voltage: %dmV, Current: %dmA, Temperature: %dC\r\n", |             "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( |     printf( | ||||||
|         "bq25896: VBUS: %d, VSYS: %d, VBAT: %d, Current: %d, NTC: %ldm%%\r\n", |         "bq25896: VBUS: %d, VSYS: %d, VBAT: %d, Current: %d, NTC: %ldm%%\r\n", | ||||||
|         bq25896_get_vbus_voltage(), bq25896_get_vsys_voltage(), |         bq25896_get_vbus_voltage(&furi_hal_i2c_handle_power), bq25896_get_vsys_voltage(&furi_hal_i2c_handle_power), | ||||||
|         bq25896_get_vbat_voltage(), bq25896_get_vbat_current(), |         bq25896_get_vbat_voltage(&furi_hal_i2c_handle_power), bq25896_get_vbat_current(&furi_hal_i2c_handle_power), | ||||||
|         bq25896_get_ntc_mpct() |         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(){ | void furi_hal_power_enable_external_3_3v(){ | ||||||
| @ -298,7 +351,9 @@ void furi_hal_power_suppress_charge_enter() { | |||||||
|     xTaskResumeAll(); |     xTaskResumeAll(); | ||||||
| 
 | 
 | ||||||
|     if (disable_charging) { |     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(); |     xTaskResumeAll(); | ||||||
| 
 | 
 | ||||||
|     if (enable_charging) { |     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); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -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_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_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}; | ||||||
|  | |||||||
| @ -10,24 +10,6 @@ | |||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #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 */ | /* Input Related Constants */ | ||||||
| #define INPUT_DEBOUNCE_TICKS 20 | #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_tx; | ||||||
| extern const GpioPin gpio_usart_rx; | extern const GpioPin gpio_usart_rx; | ||||||
|  | extern const GpioPin gpio_i2c_power_sda; | ||||||
|  | extern const GpioPin gpio_i2c_power_scl; | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
|  | |||||||
| @ -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 |  | ||||||
| @ -280,7 +280,7 @@ static void vcp_on_cdc_control_line(void* context, uint8_t state) { | |||||||
| 
 | 
 | ||||||
| static void vcp_on_cdc_rx(void* context) { | static void vcp_on_cdc_rx(void* context) { | ||||||
|     uint32_t ret = osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtRx); |     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) { | static void vcp_on_cdc_tx_complete(void* context) { | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ | |||||||
| 
 | 
 | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <furi-hal-resources.h> | #include <furi-hal-i2c-config.h> | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" { | extern "C" { | ||||||
| @ -17,18 +17,30 @@ extern "C" { | |||||||
|  */ |  */ | ||||||
| void furi_hal_i2c_init(); | 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
 | /** Perform I2C tx transfer
 | ||||||
|  * |  * | ||||||
|  * @param      instance  I2C_TypeDef instance |  * @param      instance  I2C_TypeDef instance | ||||||
|  * @param      address   I2C slave address |  * @param      address   I2C slave address | ||||||
|  * @param      data      pointer to data buffer |  * @param      data      pointer to data buffer | ||||||
|  * @param      size      size of 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 |  * @return     true on successful transfer, false otherwise | ||||||
|  */ |  */ | ||||||
| bool furi_hal_i2c_tx( | bool furi_hal_i2c_tx( | ||||||
|     I2C_TypeDef* instance, |     FuriHalI2cBusHandle* handle, | ||||||
|     const uint8_t address, |     const uint8_t address, | ||||||
|     const uint8_t* data, |     const uint8_t* data, | ||||||
|     const uint8_t size, |     const uint8_t size, | ||||||
| @ -40,12 +52,12 @@ bool furi_hal_i2c_tx( | |||||||
|  * @param      address   I2C slave address |  * @param      address   I2C slave address | ||||||
|  * @param      data      pointer to data buffer |  * @param      data      pointer to data buffer | ||||||
|  * @param      size      size of 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 |  * @return     true on successful transfer, false otherwise | ||||||
|  */ |  */ | ||||||
| bool furi_hal_i2c_rx( | bool furi_hal_i2c_rx( | ||||||
|     I2C_TypeDef* instance, |     FuriHalI2cBusHandle* handle, | ||||||
|     const uint8_t address, |     const uint8_t address, | ||||||
|     uint8_t* data, |     uint8_t* data, | ||||||
|     const uint8_t size, |     const uint8_t size, | ||||||
| @ -59,12 +71,12 @@ bool furi_hal_i2c_rx( | |||||||
|  * @param      tx_size   size of tx data buffer |  * @param      tx_size   size of tx data buffer | ||||||
|  * @param      rx_data   pointer to rx data buffer |  * @param      rx_data   pointer to rx data buffer | ||||||
|  * @param      rx_size   size of 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 |  * @return     true on successful transfer, false otherwise | ||||||
|  */ |  */ | ||||||
| bool furi_hal_i2c_trx( | bool furi_hal_i2c_trx( | ||||||
|     I2C_TypeDef* instance, |     FuriHalI2cBusHandle* handle, | ||||||
|     const uint8_t address, |     const uint8_t address, | ||||||
|     const uint8_t* tx_data, |     const uint8_t* tx_data, | ||||||
|     const uint8_t tx_size, |     const uint8_t tx_size, | ||||||
| @ -72,30 +84,6 @@ bool furi_hal_i2c_trx( | |||||||
|     const uint8_t rx_size, |     const uint8_t rx_size, | ||||||
|     uint32_t timeout); |     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 | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -25,8 +25,7 @@ void furi_hal_spi_bus_lock(const FuriHalSpiBus* bus); | |||||||
|  */ |  */ | ||||||
| void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus); | void furi_hal_spi_bus_unlock(const FuriHalSpiBus* bus); | ||||||
| 
 | 
 | ||||||
| /**
 | /** Configure SPI bus
 | ||||||
|  * Configure SPI bus |  | ||||||
|  * @param bus - spi bus handler |  * @param bus - spi bus handler | ||||||
|  * @param config - spi configuration structure |  * @param config - spi configuration structure | ||||||
|  */ |  */ | ||||||
| @ -1,7 +1,6 @@ | |||||||
| #include "bq25896.h" | #include "bq25896.h" | ||||||
| #include "bq25896_reg.h" | #include "bq25896_reg.h" | ||||||
| 
 | 
 | ||||||
| #include <furi-hal-i2c.h> |  | ||||||
| #include <stddef.h> | #include <stddef.h> | ||||||
| 
 | 
 | ||||||
| uint8_t bit_reverse(uint8_t b) { | uint8_t bit_reverse(uint8_t b) { | ||||||
| @ -11,29 +10,17 @@ uint8_t bit_reverse(uint8_t b) { | |||||||
|     return b; |     return b; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool bq25896_read(uint8_t address, uint8_t* data, size_t size) { | bool bq25896_read(FuriHalI2cBusHandle* handle, uint8_t address, uint8_t* data, size_t size) { | ||||||
|     bool ret; |     return furi_hal_i2c_trx(handle, BQ25896_ADDRESS, &address, 1, data, size, BQ25896_I2C_TIMEOUT); | ||||||
|     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_reg(uint8_t address, uint8_t* data) { | bool bq25896_read_reg(FuriHalI2cBusHandle* handle, uint8_t address, uint8_t* data) { | ||||||
|     bq25896_read(address, data, 1); |     return bq25896_read(handle, address, data, 1); | ||||||
|     return true; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 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}; |     uint8_t buffer[2] = {address, *data}; | ||||||
|     bool ret; |     return furi_hal_i2c_tx(handle, BQ25896_ADDRESS, buffer, 2, BQ25896_I2C_TIMEOUT); | ||||||
|     with_furi_hal_i2c( |  | ||||||
|         bool, &ret, () { |  | ||||||
|             return furi_hal_i2c_tx(POWER_I2C, BQ25896_ADDRESS, buffer, 2, BQ25896_I2C_TIMEOUT); |  | ||||||
|         }); |  | ||||||
|     return ret; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
| @ -62,62 +49,62 @@ typedef struct { | |||||||
| 
 | 
 | ||||||
| static bq25896_regs_t bq25896_regs; | static bq25896_regs_t bq25896_regs; | ||||||
| 
 | 
 | ||||||
| void bq25896_init() { | void bq25896_init(FuriHalI2cBusHandle* handle) { | ||||||
|     bq25896_regs.r14.REG_RST = 1; |     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
 |     // 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
 |     // Poll ADC forever
 | ||||||
|     bq25896_regs.r02.CONV_START = 1; |     bq25896_regs.r02.CONV_START = 1; | ||||||
|     bq25896_regs.r02.CONV_RATE = 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_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_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() { | bool bq25896_is_charging(FuriHalI2cBusHandle* handle) { | ||||||
|     bq25896_read(0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs)); |     bq25896_read(handle, 0x00, (uint8_t*)&bq25896_regs, sizeof(bq25896_regs)); | ||||||
|     bq25896_read_reg(0x0B, (uint8_t*)&bq25896_regs.r0B); |     bq25896_read_reg(handle, 0x0B, (uint8_t*)&bq25896_regs.r0B); | ||||||
|     return bq25896_regs.r0B.CHRG_STAT != ChrgStatNo; |     return bq25896_regs.r0B.CHRG_STAT != ChrgStatNo; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void bq25896_enable_charging() { | void bq25896_enable_charging(FuriHalI2cBusHandle* handle) { | ||||||
|     bq25896_regs.r03.CHG_CONFIG = 1; |     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_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_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_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() { | bool bq25896_is_otg_enabled(FuriHalI2cBusHandle* handle) { | ||||||
|     bq25896_read_reg(0x03, (uint8_t*)&bq25896_regs.r03); |     bq25896_read_reg(handle, 0x03, (uint8_t*)&bq25896_regs.r03); | ||||||
|     return bq25896_regs.r03.OTG_CONFIG; |     return bq25896_regs.r03.OTG_CONFIG; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint16_t bq25896_get_vbus_voltage() { | uint16_t bq25896_get_vbus_voltage(FuriHalI2cBusHandle* handle) { | ||||||
|     bq25896_read_reg(0x11, (uint8_t*)&bq25896_regs.r11); |     bq25896_read_reg(handle, 0x11, (uint8_t*)&bq25896_regs.r11); | ||||||
|     if(bq25896_regs.r11.VBUS_GD) { |     if(bq25896_regs.r11.VBUS_GD) { | ||||||
|         return (uint16_t)bq25896_regs.r11.VBUSV * 100 + 2600; |         return (uint16_t)bq25896_regs.r11.VBUSV * 100 + 2600; | ||||||
|     } else { |     } else { | ||||||
| @ -125,22 +112,22 @@ uint16_t bq25896_get_vbus_voltage() { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint16_t bq25896_get_vsys_voltage() { | uint16_t bq25896_get_vsys_voltage(FuriHalI2cBusHandle* handle) { | ||||||
|     bq25896_read_reg(0x0F, (uint8_t*)&bq25896_regs.r0F); |     bq25896_read_reg(handle, 0x0F, (uint8_t*)&bq25896_regs.r0F); | ||||||
|     return (uint16_t)bq25896_regs.r0F.SYSV * 20 + 2304; |     return (uint16_t)bq25896_regs.r0F.SYSV * 20 + 2304; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint16_t bq25896_get_vbat_voltage() { | uint16_t bq25896_get_vbat_voltage(FuriHalI2cBusHandle* handle) { | ||||||
|     bq25896_read_reg(0x0E, (uint8_t*)&bq25896_regs.r0E); |     bq25896_read_reg(handle, 0x0E, (uint8_t*)&bq25896_regs.r0E); | ||||||
|     return (uint16_t)bq25896_regs.r0E.BATV * 20 + 2304; |     return (uint16_t)bq25896_regs.r0E.BATV * 20 + 2304; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint16_t bq25896_get_vbat_current() { | uint16_t bq25896_get_vbat_current(FuriHalI2cBusHandle* handle) { | ||||||
|     bq25896_read_reg(0x12, (uint8_t*)&bq25896_regs.r12); |     bq25896_read_reg(handle, 0x12, (uint8_t*)&bq25896_regs.r12); | ||||||
|     return (uint16_t)bq25896_regs.r12.ICHGR * 50; |     return (uint16_t)bq25896_regs.r12.ICHGR * 50; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint32_t bq25896_get_ntc_mpct() { | uint32_t bq25896_get_ntc_mpct(FuriHalI2cBusHandle* handle) { | ||||||
|     bq25896_read_reg(0x10, (uint8_t*)&bq25896_regs.r10); |     bq25896_read_reg(handle, 0x10, (uint8_t*)&bq25896_regs.r10); | ||||||
|     return (uint32_t)bq25896_regs.r10.TSPCT * 465 + 21000; |     return (uint32_t)bq25896_regs.r10.TSPCT * 465 + 21000; | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,42 +2,43 @@ | |||||||
| 
 | 
 | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
|  | #include <furi-hal-i2c.h> | ||||||
| 
 | 
 | ||||||
| /** Initialize Driver */ | /** Initialize Driver */ | ||||||
| void bq25896_init(); | void bq25896_init(FuriHalI2cBusHandle* handle); | ||||||
| 
 | 
 | ||||||
| /** Send device into shipping mode */ | /** Send device into shipping mode */ | ||||||
| void bq25896_poweroff(); | void bq25896_poweroff(FuriHalI2cBusHandle* handle); | ||||||
| 
 | 
 | ||||||
| /** Is currently charging */ | /** Is currently charging */ | ||||||
| bool bq25896_is_charging(); | bool bq25896_is_charging(FuriHalI2cBusHandle* handle); | ||||||
| 
 | 
 | ||||||
| /** Enable charging */ | /** Enable charging */ | ||||||
| void bq25896_enable_charging(); | void bq25896_enable_charging(FuriHalI2cBusHandle* handle); | ||||||
| 
 | 
 | ||||||
| /** Disable charging */ | /** Disable charging */ | ||||||
| void bq25896_disable_charging(); | void bq25896_disable_charging(FuriHalI2cBusHandle* handle); | ||||||
| 
 | 
 | ||||||
| /** Enable otg */ | /** Enable otg */ | ||||||
| void bq25896_enable_otg(); | void bq25896_enable_otg(FuriHalI2cBusHandle* handle); | ||||||
| 
 | 
 | ||||||
| /** Disable otg */ | /** Disable otg */ | ||||||
| void bq25896_disable_otg(); | void bq25896_disable_otg(FuriHalI2cBusHandle* handle); | ||||||
| 
 | 
 | ||||||
| /** Is otg enabled */ | /** Is otg enabled */ | ||||||
| bool bq25896_is_otg_enabled(); | bool bq25896_is_otg_enabled(FuriHalI2cBusHandle* handle); | ||||||
| 
 | 
 | ||||||
| /** Get VBUS Voltage in mV */ | /** Get VBUS Voltage in mV */ | ||||||
| uint16_t bq25896_get_vbus_voltage(); | uint16_t bq25896_get_vbus_voltage(FuriHalI2cBusHandle* handle); | ||||||
| 
 | 
 | ||||||
| /** Get VSYS Voltage in mV */ | /** Get VSYS Voltage in mV */ | ||||||
| uint16_t bq25896_get_vsys_voltage(); | uint16_t bq25896_get_vsys_voltage(FuriHalI2cBusHandle* handle); | ||||||
| 
 | 
 | ||||||
| /** Get VBAT Voltage in mV */ | /** Get VBAT Voltage in mV */ | ||||||
| uint16_t bq25896_get_vbat_voltage(); | uint16_t bq25896_get_vbat_voltage(FuriHalI2cBusHandle* handle); | ||||||
| 
 | 
 | ||||||
| /** Get VBAT current in mA */ | /** 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 */ | /** Get NTC voltage in mpct of REGN */ | ||||||
| uint32_t bq25896_get_ntc_mpct(); | uint32_t bq25896_get_ntc_mpct(FuriHalI2cBusHandle* handle); | ||||||
|  | |||||||
| @ -1,37 +1,32 @@ | |||||||
| #include "bq27220.h" | #include "bq27220.h" | ||||||
| #include "bq27220_reg.h" | #include "bq27220_reg.h" | ||||||
| 
 | 
 | ||||||
| #include <furi-hal-i2c.h> |  | ||||||
| #include <furi-hal-delay.h> | #include <furi-hal-delay.h> | ||||||
|  | #include <furi/log.h> | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| 
 | 
 | ||||||
| #define TAG "Gauge" | #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}; |     uint8_t buffer[2] = {address}; | ||||||
|     uint16_t ret; |     uint16_t ret = 0; | ||||||
|     with_furi_hal_i2c( | 
 | ||||||
|         uint16_t, &ret, () { |     if(furi_hal_i2c_trx(handle, BQ27220_ADDRESS, buffer, 1, buffer, 2, BQ27220_I2C_TIMEOUT)) { | ||||||
|             if(furi_hal_i2c_trx( |         ret = *(uint16_t*)buffer; | ||||||
|                    POWER_I2C, BQ27220_ADDRESS, buffer, 1, buffer, 2, BQ27220_I2C_TIMEOUT)) { |     } | ||||||
|                 return *(uint16_t*)buffer; | 
 | ||||||
|             } else { |  | ||||||
|                 return 0; |  | ||||||
|             } |  | ||||||
|         }); |  | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool bq27220_control(uint16_t control) { | bool bq27220_control(FuriHalI2cBusHandle* handle, uint16_t control) { | ||||||
|     bool ret; |     bool ret = false; | ||||||
|     with_furi_hal_i2c( |     uint8_t buffer[3]; | ||||||
|         bool, &ret, () { | 
 | ||||||
|             uint8_t buffer[3]; |     buffer[0] = CommandControl; | ||||||
|             buffer[0] = CommandControl; |     buffer[1] = control & 0xFF; | ||||||
|             buffer[1] = control & 0xFF; |     buffer[2] = (control >> 8) & 0xFF; | ||||||
|             buffer[2] = (control >> 8) & 0xFF; |     ret = furi_hal_i2c_tx(handle, BQ27220_ADDRESS, buffer, 3, BQ27220_I2C_TIMEOUT); | ||||||
|             return furi_hal_i2c_tx(POWER_I2C, BQ27220_ADDRESS, buffer, 3, BQ27220_I2C_TIMEOUT); | 
 | ||||||
|         }); |  | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -43,75 +38,73 @@ uint8_t bq27220_get_checksum(uint8_t* data, uint16_t len) { | |||||||
|     return 0xFF - ret; |     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; |     bool ret; | ||||||
|     uint8_t buffer[5]; |     uint8_t buffer[5]; | ||||||
|     with_furi_hal_i2c( | 
 | ||||||
|         bool, &ret, () { |     buffer[0] = CommandSelectSubclass; | ||||||
|             buffer[0] = CommandSelectSubclass; |     buffer[1] = address & 0xFF; | ||||||
|             buffer[1] = address & 0xFF; |     buffer[2] = (address >> 8) & 0xFF; | ||||||
|             buffer[2] = (address >> 8) & 0xFF; |     buffer[3] = (value >> 8) & 0xFF; | ||||||
|             buffer[3] = (value >> 8) & 0xFF; |     buffer[4] = value & 0xFF; | ||||||
|             buffer[4] = value & 0xFF; |     ret = furi_hal_i2c_tx(handle, BQ27220_ADDRESS, buffer, 5, BQ27220_I2C_TIMEOUT); | ||||||
|             return furi_hal_i2c_tx(POWER_I2C, BQ27220_ADDRESS, buffer, 5, BQ27220_I2C_TIMEOUT); | 
 | ||||||
|         }); |  | ||||||
|     delay_us(10000); |     delay_us(10000); | ||||||
|  | 
 | ||||||
|     uint8_t checksum = bq27220_get_checksum(&buffer[1], 4); |     uint8_t checksum = bq27220_get_checksum(&buffer[1], 4); | ||||||
|     with_furi_hal_i2c( |     buffer[0] = CommandMACDataSum; | ||||||
|         bool, &ret, () { |     buffer[1] = checksum; | ||||||
|             buffer[0] = CommandMACDataSum; |     buffer[2] = 6; | ||||||
|             buffer[1] = checksum; |     ret = furi_hal_i2c_tx(handle, BQ27220_ADDRESS, buffer, 3, BQ27220_I2C_TIMEOUT); | ||||||
|             buffer[2] = 6; | 
 | ||||||
|             return furi_hal_i2c_tx(POWER_I2C, BQ27220_ADDRESS, buffer, 3, BQ27220_I2C_TIMEOUT); |  | ||||||
|         }); |  | ||||||
|     delay_us(10000); |     delay_us(10000); | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool bq27220_init(const ParamCEDV* cedv) { | bool bq27220_init(FuriHalI2cBusHandle* handle, const ParamCEDV* cedv) { | ||||||
|     uint32_t timeout = 100; |     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) { |     if(cedv->design_cap == design_cap) { | ||||||
|         FURI_LOG_I(TAG, "Skip battery profile update"); |         FURI_LOG_I(TAG, "Skip battery profile update"); | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|     FURI_LOG_I(TAG, "Start updating battery profile"); |     FURI_LOG_I(TAG, "Start updating battery profile"); | ||||||
|     OperationStatus status = {}; |     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"); |         FURI_LOG_E(TAG, "Can't configure update"); | ||||||
|         return false; |         return false; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     while((status.CFGUPDATE != 1) && (timeout-- > 0)) { |     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(handle, AddressGaugingConfig, cedv->cedv_conf.gauge_conf_raw); | ||||||
|     bq27220_set_parameter_u16(AddressFullChargeCapacity, cedv->full_charge_cap); |     bq27220_set_parameter_u16(handle, AddressFullChargeCapacity, cedv->full_charge_cap); | ||||||
|     bq27220_set_parameter_u16(AddressDesignCapacity, cedv->design_cap); |     bq27220_set_parameter_u16(handle, AddressDesignCapacity, cedv->design_cap); | ||||||
|     bq27220_set_parameter_u16(AddressEMF, cedv->EMF); |     bq27220_set_parameter_u16(handle, AddressEMF, cedv->EMF); | ||||||
|     bq27220_set_parameter_u16(AddressC0, cedv->C0); |     bq27220_set_parameter_u16(handle, AddressC0, cedv->C0); | ||||||
|     bq27220_set_parameter_u16(AddressR0, cedv->R0); |     bq27220_set_parameter_u16(handle, AddressR0, cedv->R0); | ||||||
|     bq27220_set_parameter_u16(AddressT0, cedv->T0); |     bq27220_set_parameter_u16(handle, AddressT0, cedv->T0); | ||||||
|     bq27220_set_parameter_u16(AddressR1, cedv->R1); |     bq27220_set_parameter_u16(handle, AddressR1, cedv->R1); | ||||||
|     bq27220_set_parameter_u16(AddressTC, (cedv->TC) << 8 | cedv->C1); |     bq27220_set_parameter_u16(handle, AddressTC, (cedv->TC) << 8 | cedv->C1); | ||||||
|     bq27220_set_parameter_u16(AddressStartDOD0, cedv->DOD0); |     bq27220_set_parameter_u16(handle, AddressStartDOD0, cedv->DOD0); | ||||||
|     bq27220_set_parameter_u16(AddressStartDOD10, cedv->DOD10); |     bq27220_set_parameter_u16(handle, AddressStartDOD10, cedv->DOD10); | ||||||
|     bq27220_set_parameter_u16(AddressStartDOD20, cedv->DOD20); |     bq27220_set_parameter_u16(handle, AddressStartDOD20, cedv->DOD20); | ||||||
|     bq27220_set_parameter_u16(AddressStartDOD30, cedv->DOD30); |     bq27220_set_parameter_u16(handle, AddressStartDOD30, cedv->DOD30); | ||||||
|     bq27220_set_parameter_u16(AddressStartDOD40, cedv->DOD40); |     bq27220_set_parameter_u16(handle, AddressStartDOD40, cedv->DOD40); | ||||||
|     bq27220_set_parameter_u16(AddressStartDOD50, cedv->DOD40); |     bq27220_set_parameter_u16(handle, AddressStartDOD50, cedv->DOD40); | ||||||
|     bq27220_set_parameter_u16(AddressStartDOD60, cedv->DOD60); |     bq27220_set_parameter_u16(handle, AddressStartDOD60, cedv->DOD60); | ||||||
|     bq27220_set_parameter_u16(AddressStartDOD70, cedv->DOD70); |     bq27220_set_parameter_u16(handle, AddressStartDOD70, cedv->DOD70); | ||||||
|     bq27220_set_parameter_u16(AddressStartDOD80, cedv->DOD80); |     bq27220_set_parameter_u16(handle, AddressStartDOD80, cedv->DOD80); | ||||||
|     bq27220_set_parameter_u16(AddressStartDOD90, cedv->DOD90); |     bq27220_set_parameter_u16(handle, AddressStartDOD90, cedv->DOD90); | ||||||
|     bq27220_set_parameter_u16(AddressStartDOD100, cedv->DOD100); |     bq27220_set_parameter_u16(handle, AddressStartDOD100, cedv->DOD100); | ||||||
|     bq27220_set_parameter_u16(AddressEDV0, cedv->EDV0); |     bq27220_set_parameter_u16(handle, AddressEDV0, cedv->EDV0); | ||||||
|     bq27220_set_parameter_u16(AddressEDV1, cedv->EDV1); |     bq27220_set_parameter_u16(handle, AddressEDV1, cedv->EDV1); | ||||||
|     bq27220_set_parameter_u16(AddressEDV2, cedv->EDV2); |     bq27220_set_parameter_u16(handle, AddressEDV2, cedv->EDV2); | ||||||
| 
 | 
 | ||||||
|     bq27220_control(Control_EXIT_CFG_UPDATE); |     bq27220_control(handle, Control_EXIT_CFG_UPDATE); | ||||||
|     delay_us(10000); |     delay_us(10000); | ||||||
|     design_cap = bq27220_get_design_capacity(); |     design_cap = bq27220_get_design_capacity(handle); | ||||||
|     if(cedv->design_cap == design_cap) { |     if(cedv->design_cap == design_cap) { | ||||||
|         FURI_LOG_I(TAG, "Battery profile update success"); |         FURI_LOG_I(TAG, "Battery profile update success"); | ||||||
|         return true; |         return true; | ||||||
| @ -121,16 +114,16 @@ bool bq27220_init(const ParamCEDV* cedv) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint16_t bq27220_get_voltage() { | uint16_t bq27220_get_voltage(FuriHalI2cBusHandle* handle) { | ||||||
|     return bq27220_read_word(CommandVoltage); |     return bq27220_read_word(handle, CommandVoltage); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int16_t bq27220_get_current() { | int16_t bq27220_get_current(FuriHalI2cBusHandle* handle) { | ||||||
|     return bq27220_read_word(CommandCurrent); |     return bq27220_read_word(handle, CommandCurrent); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint8_t bq27220_get_battery_status(BatteryStatus* battery_status) { | uint8_t bq27220_get_battery_status(FuriHalI2cBusHandle* handle, BatteryStatus* battery_status) { | ||||||
|     uint16_t data = bq27220_read_word(CommandBatteryStatus); |     uint16_t data = bq27220_read_word(handle, CommandBatteryStatus); | ||||||
|     if(data == BQ27220_ERROR) { |     if(data == BQ27220_ERROR) { | ||||||
|         return BQ27220_ERROR; |         return BQ27220_ERROR; | ||||||
|     } else { |     } else { | ||||||
| @ -139,8 +132,8 @@ uint8_t bq27220_get_battery_status(BatteryStatus* battery_status) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint8_t bq27220_get_operation_status(OperationStatus* operation_status) { | uint8_t bq27220_get_operation_status(FuriHalI2cBusHandle* handle, OperationStatus* operation_status) { | ||||||
|     uint16_t data = bq27220_read_word(CommandOperationStatus); |     uint16_t data = bq27220_read_word(handle, CommandOperationStatus); | ||||||
|     if(data == BQ27220_ERROR) { |     if(data == BQ27220_ERROR) { | ||||||
|         return BQ27220_ERROR; |         return BQ27220_ERROR; | ||||||
|     } else { |     } else { | ||||||
| @ -149,26 +142,26 @@ uint8_t bq27220_get_operation_status(OperationStatus* operation_status) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint16_t bq27220_get_temperature() { | uint16_t bq27220_get_temperature(FuriHalI2cBusHandle* handle) { | ||||||
|     return bq27220_read_word(CommandTemperature); |     return bq27220_read_word(handle, CommandTemperature); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint16_t bq27220_get_full_charge_capacity() { | uint16_t bq27220_get_full_charge_capacity(FuriHalI2cBusHandle* handle) { | ||||||
|     return bq27220_read_word(CommandFullChargeCapacity); |     return bq27220_read_word(handle, CommandFullChargeCapacity); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint16_t bq27220_get_design_capacity() { | uint16_t bq27220_get_design_capacity(FuriHalI2cBusHandle* handle) { | ||||||
|     return bq27220_read_word(CommandDesignCapacity); |     return bq27220_read_word(handle, CommandDesignCapacity); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint16_t bq27220_get_remaining_capacity() { | uint16_t bq27220_get_remaining_capacity(FuriHalI2cBusHandle* handle) { | ||||||
|     return bq27220_read_word(CommandRemainingCapacity); |     return bq27220_read_word(handle, CommandRemainingCapacity); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint16_t bq27220_get_state_of_charge() { | uint16_t bq27220_get_state_of_charge(FuriHalI2cBusHandle* handle) { | ||||||
|     return bq27220_read_word(CommandStateOfCharge); |     return bq27220_read_word(handle, CommandStateOfCharge); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint16_t bq27220_get_state_of_health() { | uint16_t bq27220_get_state_of_health(FuriHalI2cBusHandle* handle) { | ||||||
|     return bq27220_read_word(CommandStateOfHealth); |     return bq27220_read_word(handle, CommandStateOfHealth); | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
| 
 | 
 | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
|  | #include <furi-hal-i2c.h> | ||||||
| 
 | 
 | ||||||
| #define BQ27220_ERROR 0x0 | #define BQ27220_ERROR 0x0 | ||||||
| #define BQ27220_SUCCESS 0x1 | #define BQ27220_SUCCESS 0x1 | ||||||
| @ -95,36 +96,36 @@ typedef struct { | |||||||
| /** Initialize Driver
 | /** Initialize Driver
 | ||||||
|  * @return true on success, false otherwise |  * @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 */ | /** 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*/ | /** Get current in mA or error*/ | ||||||
| int16_t bq27220_get_current(); | int16_t bq27220_get_current(FuriHalI2cBusHandle* handle); | ||||||
| 
 | 
 | ||||||
| /** Get battery status */ | /** 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 */ | /** 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 */ | /** 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 */ | /** 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 */ | /** 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 */ | /** 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 */ | /** 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 */ | /** 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); | ||||||
|  | |||||||
| @ -1,27 +1,21 @@ | |||||||
| #include "lp5562.h" | #include "lp5562.h" | ||||||
| #include "lp5562_reg.h" | #include "lp5562_reg.h" | ||||||
| 
 | 
 | ||||||
| #include <furi-hal-i2c.h> |  | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| 
 | 
 | ||||||
| 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}; |     uint8_t buffer[2] = {address, *data}; | ||||||
|     bool ret; |     return furi_hal_i2c_tx(handle, LP5562_ADDRESS, buffer, 2, LP5562_I2C_TIMEOUT); | ||||||
|     with_furi_hal_i2c( |  | ||||||
|         bool, &ret, () { |  | ||||||
|             return furi_hal_i2c_tx(POWER_I2C, LP5562_ADDRESS, buffer, 2, LP5562_I2C_TIMEOUT); |  | ||||||
|         }); |  | ||||||
|     return ret; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void lp5562_reset() { | void lp5562_reset(FuriHalI2cBusHandle* handle) { | ||||||
|     Reg0D_Reset reg = {.value = 0xFF}; |     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}; |     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 = { |     Reg70_LedMap map = { | ||||||
|         .red = EngSelectI2C, |         .red = EngSelectI2C, | ||||||
| @ -29,15 +23,15 @@ void lp5562_configure() { | |||||||
|         .blue = EngSelectI2C, |         .blue = EngSelectI2C, | ||||||
|         .white = 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}; |     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; |     uint8_t reg_no; | ||||||
|     if(channel == LP5562ChannelRed) { |     if(channel == LP5562ChannelRed) { | ||||||
|         reg_no = 0x07; |         reg_no = 0x07; | ||||||
| @ -50,10 +44,10 @@ void lp5562_set_channel_current(LP5562Channel channel, uint8_t value) { | |||||||
|     } else { |     } else { | ||||||
|         return; |         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; |     uint8_t reg_no; | ||||||
|     if(channel == LP5562ChannelRed) { |     if(channel == LP5562ChannelRed) { | ||||||
|         reg_no = 0x04; |         reg_no = 0x04; | ||||||
| @ -66,5 +60,5 @@ void lp5562_set_channel_value(LP5562Channel channel, uint8_t value) { | |||||||
|     } else { |     } else { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     lp5562_write_reg(reg_no, &value); |     lp5562_write_reg(handle, reg_no, &value); | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
| 
 | 
 | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
|  | #include <furi-hal-i2c.h> | ||||||
| 
 | 
 | ||||||
| /** Channel types */ | /** Channel types */ | ||||||
| typedef enum { | typedef enum { | ||||||
| @ -12,16 +13,16 @@ typedef enum { | |||||||
| } LP5562Channel; | } LP5562Channel; | ||||||
| 
 | 
 | ||||||
| /** Initialize Driver */ | /** Initialize Driver */ | ||||||
| void lp5562_reset(); | void lp5562_reset(FuriHalI2cBusHandle* handle); | ||||||
| 
 | 
 | ||||||
| /** Configure Driver */ | /** Configure Driver */ | ||||||
| void lp5562_configure(); | void lp5562_configure(FuriHalI2cBusHandle* handle); | ||||||
| 
 | 
 | ||||||
| /** Enable Driver */ | /** Enable Driver */ | ||||||
| void lp5562_enable(); | void lp5562_enable(FuriHalI2cBusHandle* handle); | ||||||
| 
 | 
 | ||||||
| /** Set channel current */ | /** 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 */ | /** 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); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 あく
						あく