Sfoglia il codice sorgente

FuriHal: RTC recovery routine and ext3v3 enabled on start (#1357)

* FuriHal: leave ext3v3 enabled on start
* FuriHal: RTC recovery routine, cleanup resources

Co-authored-by: SG <who.just.the.doctor@gmail.com>
あく 3 anni fa
parent
commit
c495677eb5

+ 7 - 2
firmware/targets/f7/furi_hal/furi_hal_power.c

@@ -1,5 +1,6 @@
 #include <furi_hal_power.h>
 #include <furi_hal_clock.h>
+#include <furi_hal_delay.h>
 #include <furi_hal_bt.h>
 #include <furi_hal_resources.h>
 #include <furi_hal_uart.h>
@@ -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() {

+ 5 - 3
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);
 

+ 0 - 3
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

+ 75 - 31
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
+
+    // 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++;
+    }
+
+    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");
     }
-    // Enable clocking
-    LL_RCC_EnableRTC();
+
+    // 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;