stm32-内部时钟的使用

STM32-内部时钟

  • LSI:40kHz低速内部RC振荡器,驱动独立看门狗,或用程序选择驱动RTC
  • HSI:8MHz高速内部RC振荡器,可用于系统时钟;系统启动时默认使用该时钟为系统时钟,频率就是8MHz。
    另外,经过测试,得出几个结论点:
    1.如果调用了库的时钟初始化函数,初始化HSE外部高速时钟为PLL;当外部高速时钟有异常时,会导致PLL启动失败,会一直卡在某一个地方。
    2.当在运行过程中HSE出现异常(如用手触摸一个引脚),则会自动切换到HSI内部时钟;如果短路则不会切换,有看门狗会触发看门狗。
    3.如果可以开启时钟监视器,当HSE出现异常(任何异常)后产生一个CSSI中断,映射到NMI中断里;(NMI中断的处理可查阅文档后面,NMI中断处理函数@NMI_Handler)

示例代码

#include "system_clock.h"
#include "stm32f10x.h"

#define SYS_DEFAULT_COUNT_FREQ 285522 //系统上电后默认时钟计数频率Hz,测试得出

#define VECT_TAB_OFFSET  0x0 /*!< Vector Table base offset field. This value must be a multiple of 0x200. */

/**
 *@brief 设置内部高速时钟为系统时钟
 *@param[pll_mul] PLL倍频系数;参考 PLL_multiplication_factor
 *@note stm32f1中非互联型使用内部时钟,最大获得64MHz;互联型最大36MHz
*/
void set_sysclock_to_HSI(uint32_t pll_mul)
{
    RCC_DeInit();//重设RCC寄存器为缺省值
    RCC_HSICmd(ENABLE);//使能HSI内部高速晶振
    while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);//等待使能成功
    
    //配置AHB时钟频率与系统时钟频率一致    
    RCC_HCLKConfig(RCC_SYSCLK_Div1);
 
    //配置APB1低速时钟频率为AHB时钟频率的1/2                     	
    RCC_PCLK1Config(RCC_HCLK_Div2);
 
    //配置APB2高速时钟频率与AHB时钟频率一致                      
    RCC_PCLK2Config(RCC_HCLK_Div1);

    //配置ADC时钟频率为APB2时钟频率的1/4
    RCC_ADCCLKConfig(RCC_PCLK2_Div4);
 
    //将内部晶振时钟2分频后作为PLL时钟源,且配置PLL频系数(即系统时钟为(4*pll_mul)MHz)
    RCC_PLLConfig(RCC_PLLSource_HSI_Div2,pll_mul);
 
    //使能PLL(如果PLL被用于系统时钟,那么它不能被失能)                
    RCC_PLLCmd(ENABLE);
 
    //等待指定的RCC标志位设置成功,等待PLL初始化成功
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);

    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);//以PLL时钟作为系统时钟源
 
    //0x00:HSI作为系统时钟
    //0x04:HSE作为系统时钟
    //0x08:PLL作为系统时钟
    while(RCC_GetSYSCLKSource() != 0x08);//等待PLL时钟成功作为系统时钟源

}

void config_rcc_interrupt(void)
{
#ifdef STM32F10X_CL
    RCC_ITConfig(RCC_IT_LSIRDY, ENABLE);
    RCC_ITConfig(RCC_IT_LSERDY, ENABLE);
    RCC_ITConfig(RCC_IT_HSIRDY, ENABLE);
    RCC_ITConfig(RCC_IT_HSERDY, ENABLE);
    RCC_ITConfig(RCC_IT_PLLRDY, ENABLE);
    RCC_ITConfig(RCC_IT_PLL2RDY, ENABLE);
    RCC_ITConfig(RCC_IT_PLL3RDY, ENABLE);
#else
    RCC_ITConfig(RCC_IT_LSIRDY, ENABLE);
    RCC_ITConfig(RCC_IT_LSERDY, ENABLE);
    RCC_ITConfig(RCC_IT_HSIRDY, ENABLE);
    RCC_ITConfig(RCC_IT_HSERDY, ENABLE);
    RCC_ITConfig(RCC_IT_PLLRDY, ENABLE);
#endif
}

/**
  * @brief  Sets System clock frequency to 72MHz and configure HCLK, PCLK2 
  *         and PCLK1 prescalers. 
  * @note   This function should be used only after reset.
  * @param  None
  * @retval -1:HSE fails; -2:PLL2 fails; -3:PLL fails; -4:PLL fails switch to system clock
  */
static int set_sys_clock_to_72(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  
  /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    
  /* 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)
  {
    /* Enable Prefetch Buffer */
    FLASH->ACR |= FLASH_ACR_PRFTBE;

    /* Flash 2 wait state */
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    

 
    /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
      
    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    
    /* PCLK1 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

#ifdef STM32F10X_CL
    /* Configure PLLs ------------------------------------------------------*/
    /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
    /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */
        
    RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
                              RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
    RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
                             RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
  
    /* Enable PLL2 */
    RCC->CR |= RCC_CR_PLL2ON;
    /* Wait till PLL2 is ready */
    StartUpCounter = 0; 
    do{
        StartUpCounter++; 
    }while(((RCC->CR & RCC_CR_PLL2RDY) == 0) && (SYS_DEFAULT_COUNT_FREQ*5 != StartUpCounter))
    if((RCC->CR & RCC_CR_PLL2RDY) == 0){
        return -2;
    }
   
    /* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */ 
    RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | 
                            RCC_CFGR_PLLMULL9); 
#else    
    /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
                                        RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
#endif /* STM32F10X_CL */

    /* Enable PLL */
    RCC->CR |= RCC_CR_PLLON;

    /* Wait till PLL is ready */
    StartUpCounter = 0; 
    do{
        StartUpCounter++; 
    }while(((RCC->CR & RCC_CR_PLLRDY) == 0) && (SYS_DEFAULT_COUNT_FREQ*5 != StartUpCounter));
    if((RCC->CR & RCC_CR_PLLRDY) == 0){
        return -3;
    }
    /* Select PLL as system clock source */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    

    /* Wait till PLL is used as system clock source */
    uint32_t pll_sta = 0;
    StartUpCounter = 0; 
    do{
        pll_sta = (RCC->CFGR & (uint32_t)RCC_CFGR_SWS);
        StartUpCounter++;
    }while((pll_sta != (uint32_t)0x8) && (SYS_DEFAULT_COUNT_FREQ*5 != StartUpCounter));
    if(pll_sta != (uint32_t)0x8){
        return -4;
    }
  }
  else
  { /* If HSE fails to start-up, the application will have wrong clock 
         configuration. User can add here some code to deal with this error */
      return -1;
  }
  return 0;
}
/**
  * @brief  Setup the microcontroller system
  *         Initialize the Embedded Flash Interface, the PLL and update the 
  *         SystemCoreClock variable.
  * @note   This function should be used only after reset.
  * @param  None
  * @retval None
  */
void system_clock_init (void)
{
  /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
  /* Set HSION bit */
  RCC->CR |= (uint32_t)0x00000001;

  /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#ifndef STM32F10X_CL
  RCC->CFGR &= (uint32_t)0xF8FF0000;
#else
  RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */   
  
  /* Reset HSEON, CSSON and PLLON bits */
  RCC->CR &= (uint32_t)0xFEF6FFFF;
  //RCC_ClockSecuritySystemCmd(ENABLE);// ENABLE CSSON

  /* Reset HSEBYP bit */
  RCC->CR &= (uint32_t)0xFFFBFFFF;

  /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
  RCC->CFGR &= (uint32_t)0xFF80FFFF;

#ifdef STM32F10X_CL
  /* Reset PLL2ON and PLL3ON bits */
  RCC->CR &= (uint32_t)0xEBFFFFFF;

  /* Disable all interrupts and clear pending bits  */
//  RCC->CIR = 0x00FF0000;

  /* Reset CFGR2 register */
  RCC->CFGR2 = 0x00000000;
#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
  /* Disable all interrupts and clear pending bits  */
//  RCC->CIR = 0x009F0000;

  /* Reset CFGR2 register */
  RCC->CFGR2 = 0x00000000;      
#else
  /* Disable all interrupts and clear pending bits  */
//  RCC->CIR = 0x009F0000;
#endif /* STM32F10X_CL */
    
#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
  #ifdef DATA_IN_ExtSRAM
    SystemInit_ExtMemCtl(); 
  #endif /* DATA_IN_ExtSRAM */
#endif 

  /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
  /* Configure the Flash Latency cycles and enable prefetch buffer */
  int err = 0;
  err = set_sys_clock_to_72();
  if(err < 0)
  {
      set_sysclock_to_HSI(RCC_PLLMul_9); //设置PLL以内部RC振荡器为基准,系统时钟设置为PLL的9倍频,即36MHz
  }

#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif 
} 
/**
  * @brief  This function handles NMI exception.
  * @param  None
  * @retval None
  */
void NMI_Handler(void)
{
    /**
     * @brief 根据《stm32f10x参考手册6.2.7时钟安全系统》描述,且已经测试,得出结论:
     * 1.CSSI中断连接到该中断,若外部高速时钟HSE出现故障,则会触发该中断;
     * 2.如果在这里面没有清除CSS的中断挂起位,则会一直处在中断里。
     * 3.如果系统中有看门狗,则会触发看门狗复位,重启单片机系统。
     */
    if((RCC_GetITStatus(RCC_IT_CSS) != RESET) 
       && (RCC->CR | ((uint32_t)RCC_CR_HSEON))) 
    {
        RCC_ClearITPendingBit(RCC_IT_CSS);
        RCC_ClockSecuritySystemCmd(ENABLE);
        set_sysclock_to_HSI(RCC_PLLMul_9);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值