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>
This commit is contained in:
		@@ -1,5 +1,6 @@
 | 
				
			|||||||
#include <furi_hal_power.h>
 | 
					#include <furi_hal_power.h>
 | 
				
			||||||
#include <furi_hal_clock.h>
 | 
					#include <furi_hal_clock.h>
 | 
				
			||||||
 | 
					#include <furi_hal_delay.h>
 | 
				
			||||||
#include <furi_hal_bt.h>
 | 
					#include <furi_hal_bt.h>
 | 
				
			||||||
#include <furi_hal_resources.h>
 | 
					#include <furi_hal_resources.h>
 | 
				
			||||||
#include <furi_hal_uart.h>
 | 
					#include <furi_hal_uart.h>
 | 
				
			||||||
@@ -299,6 +300,10 @@ void furi_hal_power_shutdown() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void furi_hal_power_off() {
 | 
					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);
 | 
					    furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
 | 
				
			||||||
    bq25896_poweroff(&furi_hal_i2c_handle_power);
 | 
					    bq25896_poweroff(&furi_hal_i2c_handle_power);
 | 
				
			||||||
    furi_hal_i2c_release(&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() {
 | 
					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() {
 | 
					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() {
 | 
					void furi_hal_power_suppress_charge_enter() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 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_dm = {.port = GPIOA, .pin = LL_GPIO_PIN_11};
 | 
				
			||||||
const GpioPin gpio_usb_dp = {.port = GPIOA, .pin = LL_GPIO_PIN_12};
 | 
					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() {
 | 
					void furi_hal_resources_init_early() {
 | 
				
			||||||
    furi_hal_gpio_init(&gpio_button_left, GpioModeInput, GpioPullUp, GpioSpeedLow);
 | 
					    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
 | 
					    // Display pins
 | 
				
			||||||
    furi_hal_gpio_write(&gpio_display_rst_n, 1);
 | 
					    furi_hal_gpio_write(&gpio_display_rst_n, 1);
 | 
				
			||||||
    furi_hal_gpio_init_simple(&gpio_display_rst_n, GpioModeOutputPushPull);
 | 
					    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(&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_SetPriority(EXTI0_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0));
 | 
				
			||||||
    NVIC_EnableIRQ(EXTI0_IRQn);
 | 
					    NVIC_EnableIRQ(EXTI0_IRQn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -147,9 +147,6 @@ extern const GpioPin gpio_usb_dp;
 | 
				
			|||||||
#define PC3_GPIO_Port GPIOC
 | 
					#define PC3_GPIO_Port GPIOC
 | 
				
			||||||
#define PC3_Pin LL_GPIO_PIN_3
 | 
					#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_GPIO_Port GPIOC
 | 
				
			||||||
#define QUARTZ_32MHZ_IN_Pin LL_GPIO_PIN_14
 | 
					#define QUARTZ_32MHZ_IN_Pin LL_GPIO_PIN_14
 | 
				
			||||||
#define QUARTZ_32MHZ_OUT_GPIO_Port GPIOC
 | 
					#define QUARTZ_32MHZ_OUT_GPIO_Port GPIOC
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define TAG "FuriHalRtc"
 | 
					#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_MAGIC 0x10F1
 | 
				
			||||||
#define FURI_HAL_RTC_HEADER_VERSION 0
 | 
					#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};
 | 
					static const uint16_t furi_hal_rtc_days_per_year[] = {365, 366};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void furi_hal_rtc_init_early() {
 | 
					static void furi_hal_rtc_reset() {
 | 
				
			||||||
    // LSE and RTC
 | 
					 | 
				
			||||||
    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_ForceBackupDomainReset();
 | 
				
			||||||
    LL_RCC_ReleaseBackupDomainReset();
 | 
					    LL_RCC_ReleaseBackupDomainReset();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool furi_hal_rtc_start_clock_and_switch() {
 | 
				
			||||||
 | 
					    // Clock operation require access to Backup Domain
 | 
				
			||||||
 | 
					    LL_PWR_EnableBkUpAccess();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 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");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 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();
 | 
					        NVIC_SystemReset();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
        // Set RTC domain clock to LSE
 | 
					
 | 
				
			||||||
        LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSE);
 | 
					    // Set date if it valid
 | 
				
			||||||
 | 
					    if(datetime.year != 0) {
 | 
				
			||||||
 | 
					        furi_hal_rtc_set_datetime(&datetime);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    // Enable clocking
 | 
					}
 | 
				
			||||||
    LL_RCC_EnableRTC();
 | 
					
 | 
				
			||||||
 | 
					void furi_hal_rtc_init_early() {
 | 
				
			||||||
 | 
					    // Enable RTCAPB clock
 | 
				
			||||||
    LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_RTCAPB);
 | 
					    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
 | 
					    // Verify header register
 | 
				
			||||||
    uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterHeader);
 | 
					    uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterHeader);
 | 
				
			||||||
    FuriHalRtcHeader* data = (FuriHalRtcHeader*)&data_reg;
 | 
					    FuriHalRtcHeader* data = (FuriHalRtcHeader*)&data_reg;
 | 
				
			||||||
@@ -98,14 +150,6 @@ void furi_hal_rtc_deinit_early() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void furi_hal_rtc_init() {
 | 
					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};
 | 
					    LL_RTC_InitTypeDef RTC_InitStruct = {0};
 | 
				
			||||||
    RTC_InitStruct.HourFormat = LL_RTC_HOURFORMAT_24HOUR;
 | 
					    RTC_InitStruct.HourFormat = LL_RTC_HOURFORMAT_24HOUR;
 | 
				
			||||||
    RTC_InitStruct.AsynchPrescaler = 127;
 | 
					    RTC_InitStruct.AsynchPrescaler = 127;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user