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:
		
							parent
							
								
									b95cd2df14
								
							
						
					
					
						commit
						c495677eb5
					
				| @ -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() { | ||||
|  | ||||
| @ -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); | ||||
| 
 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 あく
						あく