static uint32_t pll_start(uint32_t crystal, uint32_t frequency) { uint32_t div, mul, div_core, vco_input_frequency, vco_output_frequency, frequency_core; uint32_t best_div = 0, best_mul = 0, best_div_core = 0, best_frequency_core = 0; RCC_CR_HSEON_bb = 1; // enable HSE clock flash_latency(frequency); // configure Flash latency for desired frequency for (div = 2; div <= 63; div++) // PLLM in [2; 63] { vco_input_frequency = crystal / div; if ((vco_input_frequency < 1000000ul) || (vco_input_frequency > 2000000)) // skip invalid settings continue; for (mul = 64; mul <= 432; mul++) // PLLN in [64; 432] { vco_output_frequency = vco_input_frequency * mul; if ((vco_output_frequency < 64000000ul) || (vco_output_frequency > 432000000ul)) // skip invalid settings continue; for (div_core = 2; div_core <= 8; div_core += 2) // PLLP in {2, 4, 6, 8} { frequency_core = vco_output_frequency / div_core; if (frequency_core > frequency) // skip values over desired frequency continue; if (frequency_core > best_frequency_core) // is this configuration better than previous one? { best_frequency_core = frequency_core; // yes - save values best_div = div; best_mul = mul; best_div_core = div_core; } } } } RCC->PLLCFGR = (best_div << RCC_PLLCFGR_PLLM_bit) | (best_mul << RCC_PLLCFGR_PLLN_bit) | ((best_div_core / 2 - 1) << RCC_PLLCFGR_PLLP_bit) | RCC_PLLCFGR_PLLQ_DIV7 | RCC_PLLCFGR_PLLSRC_HSE; // configure PLL factors, always divide USB clock by 9 RCC->CFGR = RCC_CFGR_PPRE2_DIV2 | RCC_CFGR_PPRE1_DIV4 | RCC_CFGR_HPRE_DIV1; // AHB - no prescaler, APB1 - divide by 4, APB2 - divide by 2 while (!RCC_CR_HSERDY_bb); // wait for stable clock RCC_CR_PLLON_bb = 1; // enable PLL while (!RCC_CR_PLLRDY_bb); // wait for PLL lock RCC->CFGR |= RCC_CFGR_SW_PLL; // change SYSCLK to PLL while (((RCC->CFGR) & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); // wait for switch return best_frequency_core; }
/** * @brief Starts the PLL * @details Configure and enable PLL to achieve some frequency with some crystal. * Before the speed change Flash latency is configured via flash_latency(). PLL * parameters are based on both function parameters. The PLL is set up, * started and connected. AHB clock ratio is set to 1:1 with core clock, APB1 - * 1:2 (max 36MHz), APB2 - 1:1 (max 72MHz). * * @param [in] crystal is the frequency of the crystal resonator connected to the * STM32F334X8 * @param [in] frequency is the desired target frequency after enabling the PLL (max 72MHz) * * @return real frequency that was set **/ uint32_t pll_start(uint32_t crystal, uint32_t frequency){ volatile uint32_t mul, pll_in, pll_out; volatile uint32_t best_mul=0, pll_out_best=0; #ifdef OSC_EXTERNAL volatile uint32_t div; volatile uint32_t best_div=0; RCC->CR |= RCC_CR_HSEON; // enable HSE flash_latency(frequency); // configure Flash latency for desired frequency for(div =1; div<=16; div+=1) { //PREDIV [0:16] pll_in = crystal/div; for(mul=2; mul<=16; mul+=1){ //PLLMUL[2:16] pll_out = pll_in * mul; if((pll_out > 72000000ul) || (pll_out < 16000000ul)) // skip invalid value continue; if(pll_out > frequency) // skip value over desired frequnecy continue; if(pll_out > pll_out_best){ pll_out_best = pll_out; best_mul = mul; best_div = div; } } } // configure PLL factors RCC->CFGR |= ((best_mul-2) << RCC_CFGR_PLLMUL_bit); // set PLL multification factor RCC->CFGR2 |= ((best_div-1) << RCC_CFGR2_PREDIV_bit); // set HSE divider to PLL RCC->CFGR |= RCC_CFGR_PLLSRC; // HSE/PRESCALER clk source while(!(RCC->CR & RCC_CR_HSERDY)); // wait for stable clock RCC->CFGR |= RCC_CFGR_PPRE2_DIV1 | RCC_CFGR_PPRE1_DIV4 | RCC_CFGR_HPRE_DIV1; /// AHB - no prescaler, APB1 - divide by 4, APB2 - divide by 1 RCC->CR |= RCC_CR_PLLON; // enable PLL while(!(RCC->CR & RCC_CR_PLLRDY)); // wait for PLL lock RCC->CFGR |= RCC_CFGR_SW_PLL; // change SYSCLK to PLL while (((RCC->CFGR) & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); // wait for switch return pll_out_best; #else RCC->CR |= RCC_CR_HSION; // enable HSI flash_latency(frequency); // configure Flash latency for desired frequency pll_in = crystal/2; for(mul=2; mul<=16; mul+=1){ //PLLMUL[2:16] pll_out = pll_in * mul; if((pll_out > 72000000ul) || (pll_out < 16000000ul)) // skip invalid value continue; if(pll_out > frequency) // skip value over desired frequnecy continue; if(pll_out > pll_out_best){ pll_out_best = pll_out; best_mul = mul; } } // configure PLL factors RCC->CFGR |= ((best_mul-2) << RCC_CFGR_PLLMUL_bit); // set PLL multification factor RCC->CFGR |= RCC_CFGR_PPRE2_DIV1 | RCC_CFGR_PPRE1_DIV4 | RCC_CFGR_HPRE_DIV1; /// AHB - no prescaler, APB1 - divide by 4, APB2 - divide by 1 RCC->CR |= RCC_CR_PLLON; // enable PLL while(!(RCC->CR & RCC_CR_PLLRDY)); // wait for PLL lock RCC->CFGR |= RCC_CFGR_SW_PLL; // change SYSCLK to PLL while (((RCC->CFGR) & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); // wait for switch return pll_out_best; #endif }