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_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; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 あく
						あく