moonglow / pcan_pro_x

:alien: XCAN PRO/PRO FD/FD USB2CAN firmware implementation for cheap STM32F4 hardware
Do What The F*ck You Want To Public License
240 stars 148 forks source link

HSE frequency auto-detect? #15

Closed rusefillc closed 2 years ago

rusefillc commented 2 years ago

Any chance for HSE frequency auto detect in light of https://rusefi.com/forum/viewtopic.php?f=13&t=2243?

rusEFI has that like this

static constexpr float rtcpreDivider = 31;

// This only works if you're using the PLL as the configured clock source!
static_assert(STM32_SW == RCC_CFGR_SW_PLL);

static void enableTimer() {
    RCC->APB2ENR |= RCC_APB2ENR_TIM11EN;
}

static void disableTimer() {
    RCC->APB2ENR &= ~RCC_APB2ENR_TIM11EN;
}

static void reprogramPll(uint8_t roundedHseMhz) {
    // Switch back to HSI to configure PLL
    // clear SW to use HSI
    RCC->CFGR &= ~RCC_CFGR_SW;

    // Stop the PLL
    RCC->CR &= ~RCC_CR_PLLON;

    // Mask out the old PLLM and PLLSRC
    RCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLM_Msk | RCC_PLLCFGR_PLLSRC_Msk);

    // Stick in the new PLLM value
    RCC->PLLCFGR |= (roundedHseMhz << RCC_PLLCFGR_PLLM_Pos) & RCC_PLLCFGR_PLLM_Msk;
    // Set PLLSRC to HSE
    RCC->PLLCFGR |= RCC_PLLCFGR_PLLSRC_HSE;

    // Reenable PLL, wait for lock
    RCC->CR |= RCC_CR_PLLON;
    while (!(RCC->CR & RCC_CR_PLLRDY));

    // Switch clock source back to PLL
    RCC->CFGR &= ~RCC_CFGR_SW;
    RCC->CFGR |= RCC_CFGR_SW_PLL;
    while ((RCC->CFGR & RCC_CFGR_SWS) != (STM32_SW << 2));
}

// __late_init runs after bss/zero initialziation, but before static constructors and main
extern "C" void __late_init() {
    // Set RTCPRE to /31 - just set all the bits
    RCC->CFGR |= RCC_CFGR_RTCPRE_Msk;

    // Turn on timer
    enableTimer();

    // Remap to connect HSERTC to CH1
#ifdef STM32H7XX
    // TI1SEL = 2, HSE_1MHz
    TIMER->TISEL = TIM_TISEL_TI1SEL_1;
#elif defined(STM32F4XX)
    TIMER->OR = TIM_OR_TI1_RMP_1;
#else
    // the definition has a different name on F7 for whatever reason
    TIMER->OR = TIM11_OR_TI1_RMP_1;
#endif

    // Enable capture on channel 1
    TIMER->CCMR1 = TIM_CCMR1_CC1S_0;
    TIMER->CCER = TIM_CCER_CC1E;

    // Start timer
    TIMER->CR1 |= TIM_CR1_CEN;

    // Measure HSE against SYSCLK
    auto hseCounts = getTimerCounts(10);

    // Turn off timer now that we're done with it
    disableTimer();

    float hseFrequencyHz = 10 * rtcpreDivider * STM32_TIMCLK2 / hseCounts;

    hseFrequencyMhz = hseFrequencyHz / 1e6;
    autoDetectedRoundedMhz = efiRound(hseFrequencyMhz, 1);

    reprogramPll(autoDetectedRoundedMhz);
}
moonglow commented 2 years ago

It useless for many cases, as examples your hardware is not used same LIN/CAN/USB/LED pins and so on. Automatic HSE detection is nice feature ,but it does not solve others problem.