auto detect HSE clock speed (#2952)
* detect hse * implementation * these boards don't need to set their own HSECLK * assertions * name * tweaks * how did this compile? * s * biiiig comment * this script doesn't need to set 25mhz any more * ....or PLLM Co-authored-by: Matthew Kennedy <makenne@microsoft.com>
This commit is contained in:
parent
c465997bd8
commit
15353ae3b2
|
@ -5,7 +5,7 @@ rem TODO: somehow this -DDUMMY is helping us to not mess up the parameters, why?
|
|||
rem https://github.com/rusefi/rusefi/issues/684
|
||||
rem this board has only 512K flash so using custom FLASH_ADDR
|
||||
rem You probably want "flash0 : org = 0x08000000, len = 450K" in the .ld file
|
||||
set EXTRA_PARAMS=-DDUMMY -DEFI_COMMUNICATION_PIN=GPIOB_9 -DSTM32_HSECLK=25000000U -DSTM32_PLLM_VALUE=25 -DSTM32_RTCPRE_VALUE=25 -DDEFAULT_ENGINE_TYPE=MINIMAL_PINS^
|
||||
set EXTRA_PARAMS=-DDUMMY -DEFI_COMMUNICATION_PIN=GPIOB_9 -DSTM32_RTCPRE_VALUE=25 -DDEFAULT_ENGINE_TYPE=MINIMAL_PINS^
|
||||
-DEFI_INTERNAL_FLASH=FALSE ^
|
||||
-DHAL_USE_RTC=FALSE ^
|
||||
-DBOARD_OTG_NOVBUSSENS ^
|
||||
|
|
|
@ -57,10 +57,6 @@
|
|||
#define STM32_LSECLK 32768U
|
||||
#endif
|
||||
|
||||
#if !defined(STM32_HSECLK)
|
||||
#define STM32_HSECLK 8000000U
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Board voltages.
|
||||
* Required for performance limits calculation.
|
||||
|
|
|
@ -57,10 +57,6 @@
|
|||
#define STM32_LSECLK 32768U
|
||||
#endif
|
||||
|
||||
#if !defined(STM32_HSECLK)
|
||||
#define STM32_HSECLK 8000000U
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Board voltages.
|
||||
* Required for performance limits calculation.
|
||||
|
|
|
@ -57,10 +57,6 @@
|
|||
#define STM32_LSECLK 32768U
|
||||
#endif
|
||||
|
||||
#if !defined(STM32_HSECLK)
|
||||
#define STM32_HSECLK 8000000U
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Board voltages.
|
||||
* Required for performance limits calculation.
|
||||
|
|
|
@ -57,10 +57,6 @@
|
|||
#define STM32_LSECLK 32768U
|
||||
#endif
|
||||
|
||||
#if !defined(STM32_HSECLK)
|
||||
#define STM32_HSECLK 8000000U
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Board voltages.
|
||||
* Required for performance limits calculation.
|
||||
|
|
|
@ -57,10 +57,6 @@
|
|||
#define STM32_LSECLK 32768U
|
||||
#endif
|
||||
|
||||
#if !defined(STM32_HSECLK)
|
||||
#define STM32_HSECLK 8000000U
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Board voltages.
|
||||
* Required for performance limits calculation.
|
||||
|
|
|
@ -41,10 +41,6 @@
|
|||
#define STM32_LSECLK 32768U
|
||||
#endif
|
||||
|
||||
#if !defined(STM32_HSECLK)
|
||||
#define STM32_HSECLK 8000000U
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Board voltages.
|
||||
* Required for performance limits calculation.
|
||||
|
|
|
@ -28,10 +28,6 @@
|
|||
|
||||
#define STM32_LSEDRV (3U << 3U)
|
||||
|
||||
#if !defined(STM32_HSECLK)
|
||||
#define STM32_HSECLK 25000000U
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Board voltages.
|
||||
* Required for performance limits calculation.
|
||||
|
|
|
@ -11,10 +11,6 @@
|
|||
|
||||
#include "../../../hw_layer/ports/stm32/stm32f7/cfg/mcuconf.h"
|
||||
|
||||
/* clocks adjust for 25 MHz ocs */
|
||||
#undef STM32_PLLM_VALUE
|
||||
#define STM32_PLLM_VALUE 25
|
||||
|
||||
//#undef STM32_LSE_ENABLED
|
||||
//#define STM32_LSE_ENABLED FALSE
|
||||
|
||||
|
|
|
@ -323,3 +323,15 @@
|
|||
* WDG driver system settings.
|
||||
*/
|
||||
#define STM32_WDG_USE_IWDG FALSE
|
||||
|
||||
// We auto detect the value of HSE, so set the default PLLM value to the maximum,
|
||||
// so we don't accidentially overclock to processor before we know how fast HSE is
|
||||
#define STM32_PLLM_VALUE 25
|
||||
|
||||
// This also means we have to pretend (for now) we have a 25MHz HSE fitted
|
||||
#define STM32_HSECLK 25000000
|
||||
|
||||
// After boot, we will detect the real frequency, and adjust the PLL M value to suit
|
||||
|
||||
#define ENABLE_AUTO_DETECT_HSE
|
||||
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
/**
|
||||
* @file osc_detector.cpp
|
||||
* @brief This logic automatically detects the speed of the
|
||||
* oscillator or crystal connected to HSE.
|
||||
* @date 12 July 2021
|
||||
*
|
||||
* It works by first using the reasonably-precise HSI oscillator (16MHz) to measure LSI (nominally 32khz, but wide tolerance).
|
||||
* Then, it switches the system clock source to HSE, and repeats the same measurement. The inaccurate LSI will not drift
|
||||
* significantly in the short period of time between these two measurements, so use it as a transfer standard to compare the speed
|
||||
* of HSI and HSE. The ratio between the measured speed of LSI when running on HSE vs. HSI will give the ratio of speeds of HSE
|
||||
* and HSI themselves. Since we know the value of HSI (16mhz), we can compute the speed of HSE.
|
||||
*
|
||||
* Lastly, the PLL is reconfigured to use the correct input divider such that the input frequency is 1MHz
|
||||
* (PLLM is set to N for an N-MHz HSE crystal).
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
#include "efilib.h"
|
||||
|
||||
#ifdef ENABLE_AUTO_DETECT_HSE
|
||||
|
||||
static void useHsi() {
|
||||
// clear SW to use HSI
|
||||
RCC->CFGR &= ~RCC_CFGR_SW;
|
||||
}
|
||||
|
||||
static void useHse() {
|
||||
// Switch to HSE clock
|
||||
RCC->CFGR &= ~RCC_CFGR_SW;
|
||||
RCC->CFGR |= RCC_CFGR_SW_HSE;
|
||||
}
|
||||
|
||||
static void usePll() {
|
||||
RCC->CFGR &= ~RCC_CFGR_SW;
|
||||
RCC->CFGR |= RCC_CFGR_SW_PLL;
|
||||
while ((RCC->CFGR & RCC_CFGR_SWS) != (STM32_SW << 2));
|
||||
}
|
||||
|
||||
static uint32_t getOneCapture() {
|
||||
// wait for input capture
|
||||
while ((TIM5->SR & TIM_SR_CC4IF) == 0);
|
||||
|
||||
// Return captured count
|
||||
return TIM5->CCR4;
|
||||
}
|
||||
|
||||
static uint32_t getAverageLsiCounts() {
|
||||
// Burn one count
|
||||
getOneCapture();
|
||||
|
||||
uint32_t lastCapture = getOneCapture();
|
||||
uint32_t sum = 0;
|
||||
|
||||
for (size_t i = 0; i < 20; i++)
|
||||
{
|
||||
auto capture = getOneCapture();
|
||||
sum += (capture - lastCapture);
|
||||
lastCapture = capture;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
// This only works if you're using the PLL as the configured clock source!
|
||||
static_assert(STM32_SW == RCC_CFGR_SW_PLL);
|
||||
|
||||
// These clocks must all be enabled for this to work
|
||||
static_assert(STM32_HSI_ENABLED);
|
||||
static_assert(STM32_LSI_ENABLED);
|
||||
static_assert(STM32_HSE_ENABLED);
|
||||
|
||||
static void reprogramPll(uint8_t pllM) {
|
||||
// Switch back to HSI to configure PLL
|
||||
useHsi();
|
||||
|
||||
// Stop the PLL
|
||||
RCC->CR &= ~RCC_CR_PLLON;
|
||||
|
||||
// Mask out the old PLLM val
|
||||
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLM_Msk;
|
||||
|
||||
// Stick in the new PLLM value
|
||||
RCC->PLLCFGR |= (pllM << RCC_PLLCFGR_PLLM_Pos) & RCC_PLLCFGR_PLLM_Msk;
|
||||
|
||||
// Reenable PLL, wait for lock
|
||||
RCC->CR |= RCC_CR_PLLON;
|
||||
while (!(RCC->CR & RCC_CR_PLLRDY));
|
||||
|
||||
// Switch clock source back to PLL
|
||||
usePll();
|
||||
}
|
||||
|
||||
// __late_init runs after bss/zero initialziation, but before static constructors and main
|
||||
extern "C" void __late_init() {
|
||||
// Turn on timer 5
|
||||
RCC->APB1ENR |= RCC_APB1ENR_TIM5EN;
|
||||
|
||||
// Remap to connect LSI to input capture channel 4
|
||||
TIM5->OR = TIM_OR_TI4_RMP_0;
|
||||
|
||||
// Enable capture on channel 4
|
||||
TIM5->CCMR2 = TIM_CCMR2_CC4S_0;
|
||||
TIM5->CCER = TIM_CCER_CC4E;
|
||||
|
||||
// Start TIM5
|
||||
TIM5->CR1 |= TIM_CR1_CEN;
|
||||
|
||||
// Use HSI
|
||||
useHsi();
|
||||
|
||||
// Measure LSI against HSI
|
||||
auto hsiCounts = getAverageLsiCounts();
|
||||
|
||||
useHse();
|
||||
|
||||
// Measure LSI against HSE
|
||||
auto hseCounts = getAverageLsiCounts();
|
||||
|
||||
// Turn off timer 5 now that we're done with it
|
||||
RCC->APB1ENR &= ~RCC_APB1ENR_TIM5EN;
|
||||
|
||||
// The external clocks's frequency is the ratio of the measured LSI speed, times HSI's speed (16MHz)
|
||||
float hseFrequencyMhz = 16.0f * hseCounts / hsiCounts;
|
||||
|
||||
uint8_t pllMValue = efiRound(hseFrequencyMhz, 1);
|
||||
|
||||
reprogramPll(pllMValue);
|
||||
}
|
||||
|
||||
#endif // defined ENABLE_AUTO_DETECT_HSE
|
|
@ -7,6 +7,7 @@ HW_LAYER_EMS_CPP += \
|
|||
$(PROJECT_DIR)/hw_layer/ports/stm32/stm32_common.cpp \
|
||||
$(PROJECT_DIR)/hw_layer/ports/stm32/backup_ram.cpp \
|
||||
$(PROJECT_DIR)/hw_layer/ports/stm32/microsecond_timer_stm32.cpp \
|
||||
$(PROJECT_DIR)/hw_layer/ports/stm32/osc_detector.cpp \
|
||||
|
||||
RUSEFIASM = $(PROJECT_DIR)/hw_layer/ports/stm32/rusEfiStartup.S
|
||||
|
||||
|
|
|
@ -56,10 +56,6 @@
|
|||
#define STM32_LSECLK 32768U
|
||||
#endif
|
||||
|
||||
#if !defined(STM32_HSECLK)
|
||||
#define STM32_HSECLK 8000000U
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Board voltages.
|
||||
* Required for performance limits calculation.
|
||||
|
|
|
@ -53,9 +53,6 @@
|
|||
#define STM32_SW STM32_SW_PLL
|
||||
#define STM32_PLLSRC STM32_PLLSRC_HSE
|
||||
|
||||
#ifndef STM32_PLLM_VALUE
|
||||
#define STM32_PLLM_VALUE 8
|
||||
#endif
|
||||
#define STM32_PLLN_VALUE 336
|
||||
#define STM32_PLLP_VALUE 2
|
||||
#define STM32_PLLQ_VALUE 7
|
||||
|
|
|
@ -58,10 +58,6 @@
|
|||
|
||||
#define STM32_LSEDRV (3U << 3U)
|
||||
|
||||
#if !defined(STM32_HSECLK)
|
||||
#define STM32_HSECLK 8000000U
|
||||
#endif
|
||||
|
||||
// Nucleo boards use MCO signal from St-Link and NOT oscillator - these need STM32_HSE_BYPASS
|
||||
// if you do not have Sl-Link and MCO on your board, you need EFI_USE_OSC
|
||||
|
||||
|
|
|
@ -73,7 +73,6 @@
|
|||
#define STM32_CLOCK48_REQUIRED TRUE
|
||||
#define STM32_SW STM32_SW_PLL
|
||||
#define STM32_PLLSRC STM32_PLLSRC_HSE
|
||||
#define STM32_PLLM_VALUE 8
|
||||
#define STM32_PLLN_VALUE 432
|
||||
#define STM32_PLLP_VALUE 2
|
||||
#define STM32_PLLQ_VALUE 9
|
||||
|
|
Loading…
Reference in New Issue