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:
あく 2022-07-04 17:26:02 +03:00 committed by GitHub
parent b95cd2df14
commit c495677eb5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 88 additions and 40 deletions

View File

@ -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() {

View File

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

View File

@ -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

View File

@ -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_RCC_ForceBackupDomainReset();
LL_RCC_ReleaseBackupDomainReset();
}
static bool furi_hal_rtc_start_clock_and_switch() {
// Clock operation require access to Backup Domain
LL_PWR_EnableBkUpAccess(); LL_PWR_EnableBkUpAccess();
if(!RTC_CLOCK_IS_READY()) {
LL_RCC_LSI1_Enable(); // Enable LSI and LSE
// Try to start LSE normal way LL_RCC_LSI1_Enable();
LL_RCC_LSE_SetDriveCapability(LL_RCC_LSEDRIVE_HIGH); LL_RCC_LSE_SetDriveCapability(LL_RCC_LSEDRIVE_HIGH);
LL_RCC_LSE_Enable(); LL_RCC_LSE_Enable();
uint32_t c = 0;
while(!RTC_CLOCK_IS_READY() && c < 200) { // Wait for LSI and LSE startup
LL_mDelay(10); uint32_t c = 0;
c++; while(!FURI_HAL_RTC_CLOCK_IS_READY() && c < FURI_HAL_RTC_LSE_STARTUP_TIME) {
} LL_mDelay(1);
// Plan B: reset backup domain c++;
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 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); 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;