STM32F072从零配置工程-自定义时钟配置详解

从自己的板子STM32F407入手,参考官方的SystemInit()函数:

       核心在SetSysClock()这个函数,官方默认是采用HSE(设定为8MHz)作为PLL锁相环的输入输出168MHz的SYSCLK;

/*** @brief  Setup the microcontroller system*         Initialize the Embedded Flash Interface, the PLL and update the *         SystemFrequency variable.* @param  None* @retval None*/
void SystemInit(void)
{/* Reset the RCC clock configuration to the default reset state ------------*//* Set HSION bit */RCC->CR |= (uint32_t)0x00000001;/* Reset CFGR register */RCC->CFGR = 0x00000000;/* Reset HSEON, CSSON and PLLON bits */RCC->CR &= (uint32_t)0xFEF6FFFF;/* Reset PLLCFGR register */RCC->PLLCFGR = 0x24003010;/* Reset HSEBYP bit */RCC->CR &= (uint32_t)0xFFFBFFFF;/* Disable all interrupts */RCC->CIR = 0x00000000;/* Configure the System clock source, PLL Multiplier and Divider factors, AHB/APBx prescalers and Flash settings ----------------------------------*/SetSysClock();}

 

这里大致分析一下官方默认的SetSysClock()配置:

由于我个人采用的是STM32F407型号的芯片,因此精简一下函数;

总体思路的话:

        使能HSE;

        等待HSE初始化完毕,进行下一步设置;

        设置HCLK、PCLK1、PCLK2的分频系数;

        配置PLL,使能PLL,等待PLL初始化完毕;

        选择PLL作为SYSCLK,等待SYSCLK时钟设置完毕;

/*** @brief  Configures the System clock source, PLL Multiplier and Divider factors, *         AHB/APBx prescalers and Flash settings* @Note   This function should be called only once the RCC clock configuration  *         is reset to the default reset state (done in SystemInit() function).   * @param  None* @retval None*/
static void SetSysClock(void)
{
/******************************************************************************/
/*            PLL (clocked by HSE) used as System clock source                */
/******************************************************************************/__IO uint32_t StartUpCounter = 0, HSEStatus = 0;/* Enable HSE */RCC->CR |= ((uint32_t)RCC_CR_HSEON);/* Wait till HSE is ready and if Time out is reached exit */do{HSEStatus = RCC->CR & RCC_CR_HSERDY;StartUpCounter++;} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));if ((RCC->CR & RCC_CR_HSERDY) != RESET){HSEStatus = (uint32_t)0x01;}else{HSEStatus = (uint32_t)0x00;}if (HSEStatus == (uint32_t)0x01){/* Select regulator voltage output Scale 1 mode */RCC->APB1ENR |= RCC_APB1ENR_PWREN;PWR->CR |= PWR_CR_VOS;/* HCLK = SYSCLK / 1*/RCC->CFGR |= RCC_CFGR_HPRE_DIV1;/* PCLK2 = HCLK / 2*/RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;/* PCLK1 = HCLK / 4*/RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;/* PCLK2 = HCLK / 1*/RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;/* PCLK1 = HCLK / 2*/RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;/* Configure the main PLL */RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);/* Enable the main PLL */RCC->CR |= RCC_CR_PLLON;/* Wait till the main PLL is ready */while((RCC->CR & RCC_CR_PLLRDY) == 0){}/* Configure Flash prefetch, Instruction cache, Data cache and wait state */FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;/* Configure Flash prefetch, Instruction cache, Data cache and wait state */FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;/* Select the main PLL as system clock source */RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));RCC->CFGR |= RCC_CFGR_SW_PLL;/* Wait till the main PLL is used as system clock source */while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);{}}else{ /* If HSE fails to start-up, the application will have wrong clockconfiguration. User can add here some code to deal with this error */}
}

 

在官方的基础上,直接设定HSE作为SYSCLK时钟:

       初始化HSE;

       等待HSE初始化成功后再继续;

       设置调压器电压输出级别为1以便使器件在最大频率工作;

       设置HCLK、PCLK1、PCLK2分频系数;

       设置HSE作为系统时钟;

void HSE_SetSysClock(void)
{__IO uint32_t HSEStartUpStatus = 0;/* 开启HSE时钟 *//* 此函数从stm32f0xx_rcc.c获取,用于配置外部时钟HSE:*   有三个配置:RCC_HSE_OFF关闭外部HSE时钟*         RCC_HSE_ON开始外部HSE晶振*         RCC_HSE_Bypass开始HSE旁路设置*/RCC_HSEConfig(RCC_HSE_ON);/* 等待HSE开启设置成功,并获取到时钟配置状态 */HSEStartUpStatus = RCC_WaitForHSEStartUp();/* 若时钟配置成功 */if(HSEStartUpStatus == SUCCESS){RCC->APB1ENR |= RCC_APB1ENR_PWREN;PWR->CR |= PWR_CR_VOS;RCC_HCLKConfig(RCC_SYSCLK_Div1);RCC_PCLK2Config(RCC_HCLK_Div1);RCC_PCLK1Config(RCC_HCLK_Div1);/* 将SYSCLK系统时钟设置为HSE */RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);/* 等待SYSCLK系统时钟设置成功 */while(RCC_GetSYSCLKSource() != 0x04){}}else{while(1);}
}

 

 

使用HSI经过PLL配置系统时钟:

       使能HSI时钟;

       获取HSI状态并等待HSI稳定;

       设置调节器电压输出级别配置为1;

       设置HCLK、PCLK1/2分频系数;

       设置PLL时钟分频系数;

       使能PLL并等待PLL稳定后配置PLL状态;

       设置PLL作为SYSCLK时钟并等待设置完成;

void HSI_SetSysClock(uint32_t m, uint32_t n, uint32_t p, uint32_t q)
{__IO uint32_t HSIStartUpStatus = 0;/* 去初始化RCC */RCC_DeInit();/* 使能HSI时钟 */RCC_HSICmd(ENABLE);/* 从RCC的CR寄存器中获取HSI配置状态 */HSIStartUpStatus = RCC->CR & RCC_CR_HSIRDY;/* 若HSI配置成功 */if(HSIStartUpStatus == RCC_CR_HSIRDY){/* 配置调节器电压输出级别为1 */RCC->APB1ENR |= RCC_APB1ENR_PWREN;PWR->CR |= PWR_CR_VOS;/* 配置SYSCLK到HCLK的分频系数为1 */RCC_HCLKConfig(RCC_SYSCLK_Div1);/* 配置HCLK到PCLK1/2的分频系数为2/4 */RCC_PCLK2Config(RCC_HCLK_Div2);RCC_PCLK1Config(RCC_HCLK_Div4);/* 配置PLL参数,选用HSI作为PLL参数,同时使能PLL */RCC_PLLConfig(RCC_PLLSource_HSI, m, n, p, q);RCC_PLLCmd(ENABLE);/* 等待PLL设置完成 */while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN| FLASH_ACR_DCEN| FLASH_ACR_LATENCY_5WS;RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);while(RCC_GetSYSCLKSource() != 0x08);}else{while(1);}
}

 

HAL时钟配置分析:

与STM32标准外设库不同,HAL库来实现时钟配置需要重新适应配置方式,但是本质的寄存器调动是类似不变的,且配置的过程也和STM32标准外设库相似;

参考使用STMCube生成的代码,时钟树如图所示:

 

在STM32Cube中设置:

HSE设置为Crystal/Ceramic Resonator,Input Frequency设置为16MHz;

在工程中要配置的参数:

        第一个HSE_VALUE参数位于stm32f0xx_hal_conf.h中,此参数与在STMCube时钟树上定义的一致,需要手动设置为实际的参数值

        第二个HSE_VALUE参数位于system_stm32f0xx.c中,此参数默认为8MHz,可以通过用户程序来提供和调整;

        第三个SystemCoreClock参数位于system_stm32f0xx.c中,其默认值也是8MHz,可以根据以下三种方式来更新:

    调用CMSIS函数SystemCoreClockUpdate()、

    调用HAL API函数HAL_RCC_GetHCLKFreq()、

    调用HAL_RCC_ClockConfig();

/*** @brief Adjust the value of External High Speed oscillator (HSE) used in your application.*        This value is used by the RCC HAL module to compute the system frequency*        (when HSE is used as system clock source, directly or through the PLL).  */
#if !defined  (HSE_VALUE) #define HSE_VALUE    ((uint32_t)16000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */#if !defined  (HSE_VALUE) #define HSE_VALUE    ((uint32_t)8000000) 
/*!< Default value of the External oscillator in Hz.This value can be provided and adapted by the user application. */
#endif /* HSE_VALUE *//** @addtogroup STM32F0xx_System_Private_Variables* @{*//* This variable is updated in three ways:1) by calling CMSIS function SystemCoreClockUpdate()2) by calling HAL API function HAL_RCC_GetHCLKFreq()3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequencyNote: If you use this function to configure the system clock there is no need to call the 2 first functions listed above, since SystemCoreClock variable is updated automatically.*/
uint32_t SystemCoreClock = 8000000;

 

实际的时钟配置函数如下图:

使用了三个参数来配置:

        RCC_OscInitStruct用来配置外部时钟参数,这里设置晶振类型为HSE、设置HSE的状态为开启状态、不使用PLL;

        RCC_ClkInitStruct用来配置系统时钟内的参数(如Sys CLK、HCLK、PCLK1),这里设置要配置的时钟类型为HCLK、SYSCLK、PCLK1,选择HSE时钟作为SYSCLK的时钟源,并设置系统时钟SYSCLK分频系数为0、HCLK的分频系数为4;

        PeriphClkInit用来配置外设时钟的时钟源,这里设置USART1/2的时钟源为PCLK1;

/*** @brief System Clock Configuration* @retval None*/
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};/** Initializes the CPU, AHB and APB busses clocks */RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB busses clocks */RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK){Error_Handler();}PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_USART2;PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1;PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK){Error_Handler();}HAL_SYSTICK_Config(SystemCoreClock / 1000);HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

这里加入了对SysTick的时钟配置,参考HAL库本身的设置:

        HAL_SYSTICK_Config()用来配置使能和配置SysTick寄存器;

        HAL_SYSTICK_CLKSourceConfig()选择AHB时钟(或AHB时钟除以8)作为SysTick时钟源;

        HAL_NVIC_SetPriority()配置SysTick_IRQn的中断优先级为0,默认为最高;

 

转载于:https://www.cnblogs.com/lpfdezh/p/10948817.html


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部