diff --git a/firmware/targets/f7/furi_hal/furi_hal_power.c b/firmware/targets/f7/furi_hal/furi_hal_power.c index 52bb7bcf..28e6cb05 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_power.c +++ b/firmware/targets/f7/furi_hal/furi_hal_power.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -299,6 +300,10 @@ void furi_hal_power_shutdown() { } void furi_hal_power_off() { + // Crutch: shutting down with ext 3V3 off is causing LSE to stop + furi_hal_power_enable_external_3_3v(); + furi_hal_delay_us(1000); + // Send poweroff to charger 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); @@ -482,11 +487,11 @@ void furi_hal_power_dump_state() { } void furi_hal_power_enable_external_3_3v() { - LL_GPIO_SetOutputPin(PERIPH_POWER_GPIO_Port, PERIPH_POWER_Pin); + furi_hal_gpio_write(&periph_power, 1); } void furi_hal_power_disable_external_3_3v() { - LL_GPIO_ResetOutputPin(PERIPH_POWER_GPIO_Port, PERIPH_POWER_Pin); + furi_hal_gpio_write(&periph_power, 0); } void furi_hal_power_suppress_charge_enter() { diff --git a/firmware/targets/f7/furi_hal/furi_hal_resources.c b/firmware/targets/f7/furi_hal/furi_hal_resources.c index 21fac834..c1238212 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_resources.c +++ b/firmware/targets/f7/furi_hal/furi_hal_resources.c @@ -58,7 +58,7 @@ const GpioPin gpio_i2c_power_scl = {.port = GPIOA, .pin = LL_GPIO_PIN_9}; const GpioPin gpio_speaker = {.port = GPIOB, .pin = LL_GPIO_PIN_8}; -const GpioPin periph_power = {.port = PERIPH_POWER_GPIO_Port, .pin = PERIPH_POWER_Pin}; +const GpioPin periph_power = {.port = GPIOA, .pin = LL_GPIO_PIN_3}; const GpioPin gpio_usb_dm = {.port = GPIOA, .pin = LL_GPIO_PIN_11}; const GpioPin gpio_usb_dp = {.port = GPIOA, .pin = LL_GPIO_PIN_12}; @@ -77,6 +77,10 @@ const size_t input_pins_count = sizeof(input_pins) / sizeof(InputPin); void furi_hal_resources_init_early() { furi_hal_gpio_init(&gpio_button_left, GpioModeInput, GpioPullUp, GpioSpeedLow); + // SD Card stepdown control + furi_hal_gpio_write(&periph_power, 1); + furi_hal_gpio_init(&periph_power, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); + // Display pins furi_hal_gpio_write(&gpio_display_rst_n, 1); furi_hal_gpio_init_simple(&gpio_display_rst_n, GpioModeOutputPushPull); @@ -142,8 +146,6 @@ void furi_hal_resources_init() { furi_hal_gpio_init(&gpio_rf_sw_0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - furi_hal_gpio_init(&periph_power, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); - NVIC_SetPriority(EXTI0_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); NVIC_EnableIRQ(EXTI0_IRQn); diff --git a/firmware/targets/f7/furi_hal/furi_hal_resources.h b/firmware/targets/f7/furi_hal/furi_hal_resources.h index 820760a1..d16c567e 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_resources.h +++ b/firmware/targets/f7/furi_hal/furi_hal_resources.h @@ -147,9 +147,6 @@ extern const GpioPin gpio_usb_dp; #define PC3_GPIO_Port GPIOC #define PC3_Pin LL_GPIO_PIN_3 -#define PERIPH_POWER_GPIO_Port GPIOA -#define PERIPH_POWER_Pin LL_GPIO_PIN_3 - #define QUARTZ_32MHZ_IN_GPIO_Port GPIOC #define QUARTZ_32MHZ_IN_Pin LL_GPIO_PIN_14 #define QUARTZ_32MHZ_OUT_GPIO_Port GPIOC diff --git a/firmware/targets/f7/furi_hal/furi_hal_rtc.c b/firmware/targets/f7/furi_hal/furi_hal_rtc.c index df410a9f..24dad38f 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_rtc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_rtc.c @@ -12,7 +12,9 @@ #define TAG "FuriHalRtc" -#define RTC_CLOCK_IS_READY() (LL_RCC_LSE_IsReady() && LL_RCC_LSI1_IsReady()) +#define FURI_HAL_RTC_LSE_STARTUP_TIME 300 + +#define FURI_HAL_RTC_CLOCK_IS_READY() (LL_RCC_LSE_IsReady() && LL_RCC_LSI1_IsReady()) #define FURI_HAL_RTC_HEADER_MAGIC 0x10F1 #define FURI_HAL_RTC_HEADER_VERSION 0 @@ -47,33 +49,83 @@ static const uint8_t furi_hal_rtc_days_per_month[][FURI_HAL_RTC_MONTHS_COUNT] = static const uint16_t furi_hal_rtc_days_per_year[] = {365, 366}; -void furi_hal_rtc_init_early() { - // LSE and RTC +static void furi_hal_rtc_reset() { + LL_RCC_ForceBackupDomainReset(); + LL_RCC_ReleaseBackupDomainReset(); +} + +static bool furi_hal_rtc_start_clock_and_switch() { + // Clock operation require access to Backup Domain LL_PWR_EnableBkUpAccess(); - if(!RTC_CLOCK_IS_READY()) { - LL_RCC_LSI1_Enable(); - // Try to start LSE normal way - LL_RCC_LSE_SetDriveCapability(LL_RCC_LSEDRIVE_HIGH); - LL_RCC_LSE_Enable(); - uint32_t c = 0; - while(!RTC_CLOCK_IS_READY() && c < 200) { - LL_mDelay(10); - c++; - } - // Plan B: reset backup domain - if(!RTC_CLOCK_IS_READY()) { - furi_hal_light_sequence("rgb R.r.R.r.R"); - LL_RCC_ForceBackupDomainReset(); - LL_RCC_ReleaseBackupDomainReset(); - NVIC_SystemReset(); - } - // Set RTC domain clock to LSE - LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSE); + + // Enable LSI and LSE + LL_RCC_LSI1_Enable(); + LL_RCC_LSE_SetDriveCapability(LL_RCC_LSEDRIVE_HIGH); + LL_RCC_LSE_Enable(); + + // Wait for LSI and LSE startup + uint32_t c = 0; + while(!FURI_HAL_RTC_CLOCK_IS_READY() && c < FURI_HAL_RTC_LSE_STARTUP_TIME) { + LL_mDelay(1); + c++; } - // Enable clocking - LL_RCC_EnableRTC(); + + if(FURI_HAL_RTC_CLOCK_IS_READY()) { + LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSE); + LL_RCC_EnableRTC(); + return LL_RCC_GetRTCClockSource() == LL_RCC_RTC_CLKSOURCE_LSE; + } else { + return false; + } +} + +static void furi_hal_rtc_recover() { + FuriHalRtcDateTime datetime = {0}; + + // Handle fixable LSE failure + if(LL_RCC_LSE_IsCSSDetected()) { + furi_hal_light_sequence("rgb B"); + // Shutdown LSE and LSECSS + LL_RCC_LSE_DisableCSS(); + LL_RCC_LSE_Disable(); + } else { + furi_hal_light_sequence("rgb R"); + } + + // Temporary switch to LSI + LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSI); + if(LL_RCC_GetRTCClockSource() == LL_RCC_RTC_CLKSOURCE_LSI) { + // Get datetime before RTC Domain reset + furi_hal_rtc_get_datetime(&datetime); + } + + // Reset RTC Domain + furi_hal_rtc_reset(); + + // Start Clock + if(!furi_hal_rtc_start_clock_and_switch()) { + // Plan C: reset RTC and restart + furi_hal_light_sequence("rgb R.r.R.r.R.r"); + furi_hal_rtc_reset(); + NVIC_SystemReset(); + } + + // Set date if it valid + if(datetime.year != 0) { + furi_hal_rtc_set_datetime(&datetime); + } +} + +void furi_hal_rtc_init_early() { + // Enable RTCAPB clock LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_RTCAPB); + // Prepare clock + if(!furi_hal_rtc_start_clock_and_switch()) { + // Plan B: try to recover + furi_hal_rtc_recover(); + } + // Verify header register uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterHeader); FuriHalRtcHeader* data = (FuriHalRtcHeader*)&data_reg; @@ -98,14 +150,6 @@ void furi_hal_rtc_deinit_early() { } void furi_hal_rtc_init() { - if(LL_RCC_GetRTCClockSource() != LL_RCC_RTC_CLKSOURCE_LSE) { - LL_RCC_ForceBackupDomainReset(); - LL_RCC_ReleaseBackupDomainReset(); - LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSE); - } - - LL_RCC_EnableRTC(); - LL_RTC_InitTypeDef RTC_InitStruct = {0}; RTC_InitStruct.HourFormat = LL_RTC_HOURFORMAT_24HOUR; RTC_InitStruct.AsynchPrescaler = 127;