New clock switch schema, fixes random core2 crashes (#3008)
* Updated stack to 1.17.0 * hal: ble: Fixed stack config * Bumped stack version in config * scripts: added validation of copro stack version in update bundles * Copro: update to 1.17.2 * FuriHal: adjust tick frequency for HSE as sys clk * FuriHal: adjust systick reload on sys clock change * Sync api and format sources * scripts: updated ob.data for newer stack * FuriHal: return core2 hse pll transition on deep sleep * FuriHal: cleanup ble glue * FuriHal: rework ble glue, allow shci_send in critical section * FuriHal: sync api symbols * FuriHal: cleanup BLE glue, remove unused garbage and duplicate declarations * FuriHal: BLE glue cleanup, 2nd iteration * FuriHal: hide tick drift reports under FURI_HAL_OS_DEBUG * Lib: sync stm32wb_copro with latest dev * FuriHal: ble-glue, slightly less editable device name and duplicate definition cleanup * FuriHal: update ble config options, enable some optimizations and ext adv * FuriHal: update clock switch method documentation * FuriHal: better SNBRSA bug workaround fix * FuriHal: complete comment about tick skew * FuriHal: proper condition in clock hsi2hse transition * FuriHal: move PLL start to hse2pll routine, fix lockup caused by core2 switching to HSE before us * FuriHal: explicit HSE start before switch * FuriHal: fix documentation and move flash latency change to later stage, remove duplicate LL_RCC_SetRFWKPClockSource call --------- Co-authored-by: hedger <hedger@nanode.su> Co-authored-by: hedger <hedger@users.noreply.github.com>
This commit is contained in:
@@ -2,7 +2,11 @@
|
||||
|
||||
#include <ble/ble.h>
|
||||
#include <interface/patterns/ble_thread/shci/shci.h>
|
||||
|
||||
#include <stm32wbxx.h>
|
||||
#include <stm32wbxx_ll_hsem.h>
|
||||
|
||||
#include <hsem_map.h>
|
||||
|
||||
#include <furi_hal_version.h>
|
||||
#include <furi_hal_bt_hid.h>
|
||||
|
||||
@@ -4,19 +4,26 @@
|
||||
|
||||
#include <stm32wbxx_ll_pwr.h>
|
||||
#include <stm32wbxx_ll_rcc.h>
|
||||
#include <stm32wbxx_ll_hsem.h>
|
||||
#include <stm32wbxx_ll_utils.h>
|
||||
#include <stm32wbxx_ll_cortex.h>
|
||||
|
||||
#include <hsem_map.h>
|
||||
#include <interface/patterns/ble_thread/shci/shci.h>
|
||||
|
||||
#define TAG "FuriHalClock"
|
||||
|
||||
#define CPU_CLOCK_HZ_EARLY 4000000
|
||||
#define CPU_CLOCK_HZ_MAIN 64000000
|
||||
#define CPU_CLOCK_EARLY_HZ 4000000
|
||||
#define CPU_CLOCK_HSI16_HZ 16000000
|
||||
#define CPU_CLOCK_HSE_HZ 32000000
|
||||
#define CPU_CLOCK_PLL_HZ 64000000
|
||||
|
||||
#define TICK_INT_PRIORITY 15U
|
||||
#define HS_CLOCK_IS_READY() (LL_RCC_HSE_IsReady() && LL_RCC_HSI_IsReady())
|
||||
#define LS_CLOCK_IS_READY() (LL_RCC_LSE_IsReady() && LL_RCC_LSI1_IsReady())
|
||||
|
||||
void furi_hal_clock_init_early() {
|
||||
LL_SetSystemCoreClock(CPU_CLOCK_HZ_EARLY);
|
||||
LL_SetSystemCoreClock(CPU_CLOCK_EARLY_HZ);
|
||||
LL_Init1msTick(SystemCoreClock);
|
||||
}
|
||||
|
||||
@@ -24,11 +31,6 @@ void furi_hal_clock_deinit_early() {
|
||||
}
|
||||
|
||||
void furi_hal_clock_init() {
|
||||
/* Prepare Flash memory for 64MHz system clock */
|
||||
LL_FLASH_SetLatency(LL_FLASH_LATENCY_3);
|
||||
while(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_3)
|
||||
;
|
||||
|
||||
/* HSE and HSI configuration and activation */
|
||||
LL_RCC_HSE_SetCapacitorTuning(0x26);
|
||||
LL_RCC_HSE_Enable();
|
||||
@@ -49,9 +51,6 @@ void furi_hal_clock_init() {
|
||||
while(!LS_CLOCK_IS_READY())
|
||||
;
|
||||
|
||||
/* RF wakeup */
|
||||
LL_RCC_SetRFWKPClockSource(LL_RCC_RFWKP_CLKSOURCE_LSE);
|
||||
|
||||
LL_EXTI_EnableIT_0_31(
|
||||
LL_EXTI_LINE_18); /* Why? Because that's why. See RM0434, Table 61. CPU1 vector table. */
|
||||
LL_EXTI_EnableRisingTrig_0_31(LL_EXTI_LINE_18);
|
||||
@@ -79,12 +78,17 @@ void furi_hal_clock_init() {
|
||||
;
|
||||
|
||||
/* Sysclk activation on the main PLL */
|
||||
/* Set CPU1 prescaler*/
|
||||
/* Set CPU1 prescaler */
|
||||
LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
|
||||
|
||||
/* Set CPU2 prescaler*/
|
||||
/* Set CPU2 prescaler, from this point we are not allowed to touch it. */
|
||||
LL_C2_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_2);
|
||||
|
||||
/* Prepare Flash memory for work on 64MHz system clock */
|
||||
LL_FLASH_SetLatency(LL_FLASH_LATENCY_3);
|
||||
while(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_3)
|
||||
;
|
||||
|
||||
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
|
||||
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL)
|
||||
;
|
||||
@@ -104,7 +108,7 @@ void furi_hal_clock_init() {
|
||||
;
|
||||
|
||||
/* Update CMSIS variable (which can be updated also through SystemCoreClockUpdate function) */
|
||||
LL_SetSystemCoreClock(CPU_CLOCK_HZ_MAIN);
|
||||
LL_SetSystemCoreClock(CPU_CLOCK_PLL_HZ);
|
||||
|
||||
/* Update the time base */
|
||||
LL_Init1msTick(SystemCoreClock);
|
||||
@@ -122,7 +126,7 @@ void furi_hal_clock_init() {
|
||||
FURI_LOG_I(TAG, "Init OK");
|
||||
}
|
||||
|
||||
void furi_hal_clock_switch_to_hsi() {
|
||||
void furi_hal_clock_switch_hse2hsi() {
|
||||
LL_RCC_HSI_Enable();
|
||||
|
||||
while(!LL_RCC_HSI_IsReady())
|
||||
@@ -134,38 +138,27 @@ void furi_hal_clock_switch_to_hsi() {
|
||||
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI)
|
||||
;
|
||||
|
||||
LL_C2_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
|
||||
|
||||
LL_FLASH_SetLatency(LL_FLASH_LATENCY_0);
|
||||
while(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_0)
|
||||
;
|
||||
}
|
||||
|
||||
void furi_hal_clock_switch_to_pll() {
|
||||
void furi_hal_clock_switch_hsi2hse() {
|
||||
#ifdef FURI_HAL_CLOCK_TRACK_STARTUP
|
||||
uint32_t clock_start_time = DWT->CYCCNT;
|
||||
#endif
|
||||
|
||||
LL_RCC_HSE_Enable();
|
||||
LL_RCC_PLL_Enable();
|
||||
LL_RCC_PLLSAI1_Enable();
|
||||
|
||||
while(!LL_RCC_HSE_IsReady())
|
||||
;
|
||||
while(!LL_RCC_PLL_IsReady())
|
||||
;
|
||||
while(!LL_RCC_PLLSAI1_IsReady())
|
||||
|
||||
LL_FLASH_SetLatency(LL_FLASH_LATENCY_1);
|
||||
while(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_1)
|
||||
;
|
||||
|
||||
LL_C2_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_2);
|
||||
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE);
|
||||
|
||||
LL_FLASH_SetLatency(LL_FLASH_LATENCY_3);
|
||||
while(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_3)
|
||||
;
|
||||
|
||||
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
|
||||
|
||||
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL)
|
||||
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE)
|
||||
;
|
||||
|
||||
#ifdef FURI_HAL_CLOCK_TRACK_STARTUP
|
||||
@@ -176,6 +169,48 @@ void furi_hal_clock_switch_to_pll() {
|
||||
#endif
|
||||
}
|
||||
|
||||
bool furi_hal_clock_switch_hse2pll() {
|
||||
furi_assert(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_HSE);
|
||||
|
||||
LL_RCC_PLL_Enable();
|
||||
LL_RCC_PLLSAI1_Enable();
|
||||
|
||||
while(!LL_RCC_PLL_IsReady())
|
||||
;
|
||||
while(!LL_RCC_PLLSAI1_IsReady())
|
||||
;
|
||||
|
||||
if(SHCI_C2_SetSystemClock(SET_SYSTEM_CLOCK_HSE_TO_PLL) != SHCI_Success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
furi_check(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_PLL);
|
||||
|
||||
LL_SetSystemCoreClock(CPU_CLOCK_PLL_HZ);
|
||||
SysTick->LOAD = (uint32_t)((SystemCoreClock / 1000) - 1UL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool furi_hal_clock_switch_pll2hse() {
|
||||
furi_assert(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_PLL);
|
||||
|
||||
LL_RCC_HSE_Enable();
|
||||
while(!LL_RCC_HSE_IsReady())
|
||||
;
|
||||
|
||||
if(SHCI_C2_SetSystemClock(SET_SYSTEM_CLOCK_PLL_ON_TO_HSE) != SHCI_Success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
furi_check(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_HSE);
|
||||
|
||||
LL_SetSystemCoreClock(CPU_CLOCK_HSE_HZ);
|
||||
SysTick->LOAD = (uint32_t)((SystemCoreClock / 1000) - 1UL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void furi_hal_clock_suspend_tick() {
|
||||
CLEAR_BIT(SysTick->CTRL, SysTick_CTRL_ENABLE_Msk);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <stm32wbxx_ll_rcc.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stm32wbxx_ll_rcc.h>
|
||||
|
||||
typedef enum {
|
||||
FuriHalClockMcoLse,
|
||||
FuriHalClockMcoSysclk,
|
||||
@@ -40,11 +41,23 @@ void furi_hal_clock_deinit_early();
|
||||
/** Initialize clocks */
|
||||
void furi_hal_clock_init();
|
||||
|
||||
/** Switch to HSI clock */
|
||||
void furi_hal_clock_switch_to_hsi();
|
||||
/** Switch clock from HSE to HSI */
|
||||
void furi_hal_clock_switch_hse2hsi();
|
||||
|
||||
/** Switch to PLL clock */
|
||||
void furi_hal_clock_switch_to_pll();
|
||||
/** Switch clock from HSI to HSE */
|
||||
void furi_hal_clock_switch_hsi2hse();
|
||||
|
||||
/** Switch clock from HSE to PLL
|
||||
*
|
||||
* @return true if changed, false if failed or not possible at this moment
|
||||
*/
|
||||
bool furi_hal_clock_switch_hse2pll();
|
||||
|
||||
/** Switch clock from PLL to HSE
|
||||
*
|
||||
* @return true if changed, false if failed or not possible at this moment
|
||||
*/
|
||||
bool furi_hal_clock_switch_pll2hse();
|
||||
|
||||
/** Stop SysTick counter without resetting */
|
||||
void furi_hal_clock_suspend_tick();
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
#include <stm32wbxx_ll_gpio.h>
|
||||
#include <stm32wbxx_ll_usart.h>
|
||||
|
||||
#include <utilities_conf.h>
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#define TAG "FuriHalConsole"
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
#include <interface/patterns/ble_thread/shci/shci.h>
|
||||
|
||||
#include <stm32wbxx.h>
|
||||
#include <stm32wbxx_ll_hsem.h>
|
||||
|
||||
#include <hsem_map.h>
|
||||
|
||||
#define TAG "FuriHalFlash"
|
||||
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
|
||||
#define TAG "FuriHalMemory"
|
||||
|
||||
// STM(TM) Copro(TM) bug(TM) workaround size
|
||||
#define RAM2B_COPRO_GAP_SIZE_KB 2
|
||||
|
||||
typedef enum {
|
||||
SRAM_A,
|
||||
SRAM_B,
|
||||
@@ -38,13 +35,20 @@ void furi_hal_memory_init() {
|
||||
uint32_t sbrsa = (FLASH->SRRVR & FLASH_SRRVR_SBRSA_Msk) >> FLASH_SRRVR_SBRSA_Pos;
|
||||
uint32_t snbrsa = (FLASH->SRRVR & FLASH_SRRVR_SNBRSA_Msk) >> FLASH_SRRVR_SNBRSA_Pos;
|
||||
|
||||
// STM(TM) Copro(TM) bug(TM): SNBRSA is incorrect if stack version is higher than 1.13 and lower than 1.17.2+
|
||||
// Radio core started, but not yet ready, so we'll try to guess
|
||||
// This will be true only if BLE light radio stack used,
|
||||
// 0x0D is known to be incorrect, 0x0B is known to be correct since 1.17.2+
|
||||
// Lower value by 2 pages to match real memory layout
|
||||
if(snbrsa > 0x0B) {
|
||||
FURI_LOG_E(TAG, "SNBRSA workaround");
|
||||
snbrsa -= 2;
|
||||
}
|
||||
|
||||
uint32_t sram2a_busy_size = (uint32_t)&__sram2a_free__ - (uint32_t)&__sram2a_start__;
|
||||
uint32_t sram2a_unprotected_size = (sbrsa)*1024;
|
||||
uint32_t sram2b_unprotected_size = (snbrsa)*1024;
|
||||
|
||||
// STM(TM) Copro(TM) bug(TM) workaround
|
||||
sram2b_unprotected_size -= 1024 * RAM2B_COPRO_GAP_SIZE_KB;
|
||||
|
||||
memory->region[SRAM_A].start = (uint8_t*)&__sram2a_free__;
|
||||
memory->region[SRAM_B].start = (uint8_t*)&__sram2b_start__;
|
||||
|
||||
|
||||
@@ -170,27 +170,35 @@ void vPortSuppressTicksAndSleep(TickType_t expected_idle_ticks) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Core2 shenanigans takes extra time, so we want to compensate tick skew by reducing sleep duration by 1 tick
|
||||
TickType_t unexpected_idle_ticks = expected_idle_ticks - 1;
|
||||
|
||||
// Limit amount of ticks to maximum that timer can count
|
||||
if(expected_idle_ticks > FURI_HAL_OS_MAX_SLEEP) {
|
||||
expected_idle_ticks = FURI_HAL_OS_MAX_SLEEP;
|
||||
if(unexpected_idle_ticks > FURI_HAL_OS_MAX_SLEEP) {
|
||||
unexpected_idle_ticks = FURI_HAL_OS_MAX_SLEEP;
|
||||
}
|
||||
|
||||
// Stop IRQ handling, no one should disturb us till we finish
|
||||
__disable_irq();
|
||||
do {
|
||||
// Confirm OS that sleep is still possible
|
||||
if(eTaskConfirmSleepModeStatus() == eAbortSleep || furi_hal_os_is_pending_irq()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Confirm OS that sleep is still possible
|
||||
if(eTaskConfirmSleepModeStatus() == eAbortSleep || furi_hal_os_is_pending_irq()) {
|
||||
__enable_irq();
|
||||
return;
|
||||
}
|
||||
|
||||
// Sleep and track how much ticks we spent sleeping
|
||||
uint32_t completed_ticks = furi_hal_os_sleep(expected_idle_ticks);
|
||||
// Notify system about time spent in sleep
|
||||
if(completed_ticks > 0) {
|
||||
vTaskStepTick(MIN(completed_ticks, expected_idle_ticks));
|
||||
}
|
||||
|
||||
// Sleep and track how much ticks we spent sleeping
|
||||
uint32_t completed_ticks = furi_hal_os_sleep(unexpected_idle_ticks);
|
||||
// Notify system about time spent in sleep
|
||||
if(completed_ticks > 0) {
|
||||
if(completed_ticks > expected_idle_ticks) {
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
furi_hal_console_printf(">%lu\r\n", completed_ticks - expected_idle_ticks);
|
||||
#endif
|
||||
completed_ticks = expected_idle_ticks;
|
||||
}
|
||||
vTaskStepTick(completed_ticks);
|
||||
}
|
||||
} while(0);
|
||||
// Reenable IRQ
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <stm32wbxx_ll_cortex.h>
|
||||
#include <stm32wbxx_ll_gpio.h>
|
||||
|
||||
#include <hw_conf.h>
|
||||
#include <hsem_map.h>
|
||||
#include <bq27220.h>
|
||||
#include <bq27220_data_memory.h>
|
||||
#include <bq25896.h>
|
||||
@@ -162,6 +162,11 @@ static inline void furi_hal_power_resume_aux_periphs() {
|
||||
static inline void furi_hal_power_deep_sleep() {
|
||||
furi_hal_power_suspend_aux_periphs();
|
||||
|
||||
if(!furi_hal_clock_switch_pll2hse()) {
|
||||
// Hello core2 my old friend
|
||||
return;
|
||||
}
|
||||
|
||||
while(LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID))
|
||||
;
|
||||
|
||||
@@ -171,13 +176,13 @@ static inline void furi_hal_power_deep_sleep() {
|
||||
LL_HSEM_ReleaseLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0);
|
||||
|
||||
// The switch on HSI before entering Stop Mode is required
|
||||
furi_hal_clock_switch_to_hsi();
|
||||
furi_hal_clock_switch_hse2hsi();
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* The switch on HSI before entering Stop Mode is required
|
||||
*/
|
||||
furi_hal_clock_switch_to_hsi();
|
||||
furi_hal_clock_switch_hse2hsi();
|
||||
}
|
||||
|
||||
/* Release RCC semaphore */
|
||||
@@ -201,12 +206,14 @@ static inline void furi_hal_power_deep_sleep() {
|
||||
while(LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID))
|
||||
;
|
||||
|
||||
if(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) {
|
||||
furi_hal_clock_switch_to_pll();
|
||||
if(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE) {
|
||||
furi_hal_clock_switch_hsi2hse();
|
||||
}
|
||||
|
||||
LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0);
|
||||
|
||||
furi_check(furi_hal_clock_switch_hse2pll());
|
||||
|
||||
furi_hal_power_resume_aux_periphs();
|
||||
furi_hal_rtc_sync_shadow();
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <stm32wbxx_ll_rcc.h>
|
||||
#include <stm32wbxx_ll_hsem.h>
|
||||
|
||||
#include <hw_conf.h>
|
||||
#include <hsem_map.h>
|
||||
|
||||
#define TAG "FuriHalRandom"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user