STM32:RCC

1 STM32F1的复位方式

  1.1 系统复位

    作用:将RCC_CSR的复位标志、备份区域除外的所有reg值复位为复位值;

       备份区域:LSE后备寄存器、RCC_BDCR、RTC的相关寄存器;

            如果使用备用电池Vbat,那么VDD断电后,备份区域会使用Vbat备份;

    1.1.1  NRST引脚上的低电平(外部复位)

    1.1.2 窗口看门狗计数终止(WWDG复位)

    1.1.3 独立看门狗计数终止(IWDG复位)

    1.1.4 低功耗管理复位

    1.1.5 软件复位(SW复位)

        配置CM3内核中的"中断应用和复位控制寄存器"中的SYSRESETREQ位置’1’,可实现软件复位;

  1.2 电源复位

    1.2.1 芯片上电/掉电复位;

    1.2.2 从待机模式返回;

  1.3 备份域复位

    1.3.1 只针对备份区域的备份域复位,详见参考手册章节7.1

2 RCC

  RCC全称 reset clock controller 复位和时钟控制器;

  作用是控制芯片的复位信号,内核及外设的时钟;由于芯片的外设时钟较多,参考手册对其进行了树形图整理;

  2.1 寄存器

    

    rcc_CR控制寄存器:              配置HSE,HSI,PLL的使能,复位默认使能HSI时钟;

    rcc_CFGR时钟配置寄存器:   配置HSE,HSI,PLL的参数,搭配时钟树使用清晰易懂,时钟树已标注出;

    rcc_xxx外设复位寄存器:       复位对应的外设寄存器为复位值;

    rcc_xxx外设时钟使能寄存器:使能对应的外设时钟,每个外设都有一个独立的时钟使能bit,外设使用前需要使能时钟;

    rcc_CIR时钟中断寄存器:       目测不相关,懒得写;

    rcc_CSR控制状态寄存器:      目测不相关,懒得写;

    rcc_BDSR备份域控制寄存器:目测用不上,懒得写;

  2.2 时钟树

    2.2.1 晶振时钟源

      HSI:8MHz的内部低速晶振时钟,可作为系统时钟源、PLL时钟源;

      HSE:4-16MHz的外部高速晶振时钟,可作为系统时钟源、PLL时钟源,f1战舰版的HSE为8MHz;

      LSI :约40kHz的内部低速低功耗晶振时钟,为IWDG独立看门狗时钟源、待机停机模式下的自动唤醒单元时钟源;

      LSE:32.768kHz的外部低速低功耗晶振时钟,为RTC实时时钟源;

    以系统时钟sysclk举例可知,sysclk时钟可以通过HSI,HSE或PLLCLK生成;

    PLLCLK由HSI或HSE分频倍频而来;如果HSI输入pll作为系统时钟源,那么sysclk最大64MHz;2分频后倍频max16倍可不就是64M嘛;

    

  2.2 AHB,APB1,APB2外设连接;

    下图来自STM32F103ZET6数据手册,为器件功能概览,挂在总线上的外设部分作为时钟树外设的补充;

    使用外设不仅需要使能该外设时钟,还要使能外设所在IO的IO_port时钟;每个外设时钟源都可以单独开关来优化功耗;

    

3 标准库函数

void RCC_DeInit(void);//复位CR,CFGR,CIR;
void RCC_HSEConfig(uint32_t RCC_HSE);//CR_HSEON,CR_HSEBYP;
ErrorStatus RCC_WaitForHSEStartUp(void);//CR_HSERDY;
void RCC_AdjustHSICalibrationValue(uint8_t HSICalibrationValue);
void RCC_HSICmd(FunctionalState NewState);//位带操作CR_HSION;
void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t RCC_PLLMul);
void RCC_PLLCmd(FunctionalState NewState);//位带操作CR_PLLON;

//顾名思义,懒得看了;
void RCC_SYSCLKConfig(uint32_t RCC_SYSCLKSource);
uint8_t RCC_GetSYSCLKSource(void);
void RCC_HCLKConfig(uint32_t RCC_SYSCLK);
void RCC_PCLK1Config(uint32_t RCC_HCLK);
void RCC_PCLK2Config(uint32_t RCC_HCLK);
void RCC_ITConfig(uint8_t RCC_IT, FunctionalState NewState);

void RCC_USBCLKConfig(uint32_t RCC_USBCLKSource);

void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);

void RCC_LSEConfig(uint8_t RCC_LSE);
void RCC_LSICmd(FunctionalState NewState);
void RCC_RTCCLKConfig(uint32_t RCC_RTCCLKSource);
void RCC_RTCCLKCmd(FunctionalState NewState);
void RCC_GetClocksFreq(RCC_ClocksTypeDef* RCC_Clocks);
void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);

void RCC_APB2PeriphResetCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
void RCC_APB1PeriphResetCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
void RCC_BackupResetCmd(FunctionalState NewState);
void RCC_ClockSecuritySystemCmd(FunctionalState NewState);
void RCC_MCOConfig(uint8_t RCC_MCO);
FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG);
void RCC_ClearFlag(void);
ITStatus RCC_GetITStatus(uint8_t RCC_IT);
void RCC_ClearITPendingBit(uint8_t RCC_IT);
/***以下HSI,PLL的配置,使用的是bit-band位带操作;
***位带操作:将目标寄存器的特定bit映射到bit-band位带区域的特定地址;
*************对位带地址的数据操作映射到目标寄存器的对应位数据;
*******公式:STM32_GPIO_3.3;
***/
RCC_HSICmd(FunctionalState NewState)
/***以下HSI的配置,使用的是bit-band位带操作;***/
#define HSION_BitNumber           0x00

#define PERIPH_BASE           ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region */
#define AHBPERIPH_BASE        (PERIPH_BASE + 0x20000)
#define RCC_BASE              (AHBPERIPH_BASE + 0x1000)
#define RCC_OFFSET                (RCC_BASE - PERIPH_BASE)
#define CR_OFFSET                 (RCC_OFFSET + 0x00)

#define PERIPH_BB_BASE        ((uint32_t)0x42000000) /*!< Peripheral base address in the bit-band region */

#define CR_HSION_BB               (PERIPH_BB_BASE + (CR_OFFSET * 32) + (HSION_BitNumber * 4))
/**
  * @brief  Enables or disables the Internal High Speed oscillator (HSI).
  * @note   HSI can not be stopped if it is used directly or through the PLL as system clock.
  * @param  NewState: new state of the HSI. This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void RCC_HSICmd(FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_FUNCTIONAL_STATE(NewState));
  *(__IO uint32_t *) CR_HSION_BB = (uint32_t)NewState;
}
RCC_PLLCmd(FunctionalState NewState)
/***PLLON_BitNumber为什么是0x18,怎么对应上的不理解;这个问题很简单,结合“STM32:GPIO”3.3小结解析就可以了;***/

/* Alias word address of PLLON bit */
#define PLLON_BitNumber           0x18
#define CR_PLLON_BB               (PERIPH_BB_BASE + (CR_OFFSET * 32) + (PLLON_BitNumber * 4))

void RCC_PLLCmd(FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_FUNCTIONAL_STATE(NewState));

  *(__IO uint32_t *) CR_PLLON_BB = (uint32_t)NewState;
}

4 rcc默认配置

  在启动文件中,Reset_Handler中断调用了__main函数来对软件进行初始化,__mian函数具体执行了什么主要是mdk的事,内容太长我就不看了;

  但是__main函数调用了SystemInit()函数来配置程序rcc的初始化,这个很重要,所以这里我们来看一下SystemInit()函数;

  rcc一开始首先使用HSI时钟,然后修改成HSE时钟通过pll倍频9倍作为sysclk时钟;f1战舰版外部晶振8M;

//system_stm32f10x.c   STM32F10X_HD的SystemInit()实际只配置了下面5个中文注释部分,然后调用SetSysClock();
void SystemInit (void)
{
  RCC->CR |= (uint32_t)0x00000001;		//使能HSI时钟;

#ifndef STM32F10X_CL
  RCC->CFGR &= (uint32_t)0xF8FF0000;	//sysclk选HSI,AHB,APB1,APB2不分频;ADC2分频;
#else
  RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */   

  RCC->CR &= (uint32_t)0xFEF6FFFF;		//HSE,PLL,CSS时钟安全系统不使能;
  RCC->CR &= (uint32_t)0xFFFBFFFF;		//[18]HSEEBYP正常接线;
  RCC->CFGR &= (uint32_t)0xFF80FFFF;    //[22:16]与0,配置了PLLCLK,可是没使能PLL时钟哟;

#ifdef STM32F10X_CL
  RCC->CR &= (uint32_t)0xEBFFFFFF;
  RCC->CIR = 0x00FF0000;
  RCC->CFGR2 = 0x00000000;
#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
  RCC->CIR = 0x009F0000;
  RCC->CFGR2 = 0x00000000;      
#else
  RCC->CIR = 0x009F0000;				//Disable all interrupts and clear pending bits
#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 */
  SetSysClock();

#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 
}
//system_stm32f10x.c  这个函数下面的宏只定义了SYSCLK_FREQ_72MHz,所以调用SetSysClockTo72();
static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
  SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
  SetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHz
  SetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHz
  SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
  SetSysClockTo56();  
#elif defined SYSCLK_FREQ_72MHz
  SetSysClockTo72();
#endif
#elif defined SYSCLK_FREQ_72MHz
/***下面这个函数执行步骤如下3步,搭配时钟树和寄存器分析非常清晰;作为本文的巩固和联系非常适合,方便理解;
	1 使能CR_HSE时钟,先配置好CFGR_[13:7]总线时钟;
	2 先配置时钟树中HSE时钟到PLLCLK的CFGR_[21:16],然后使能CR_PLL时钟;
	3 清0SW[1:0],然后配置为10b,配置sysclk时钟来自pllclk;
***/
static void SetSysClockTo72(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  
  /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    
  /* Enable HSE */    
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);//[16]使能HSE
 
  /* 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 [7:4]不分频 */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
      
    /* PCLK2 = HCLK  [13:11]不分频 */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    
    /* PCLK1 = HCLK  [10:8]2分频*/
    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 */
    while((RCC->CR & RCC_CR_PLL2RDY) == 0)
    {
    }
    
   
    /* 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 
	//执行代码;清0[21:16],然后使能[16],[21:18]0111b倍频7+2=9倍;
    /*  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 [24]*/
    RCC->CR |= RCC_CR_PLLON;

    /* Wait till PLL is ready */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }
    
    /*先清0[1:0],然后赋值10b,选sysclk时钟为pll;*/
    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 */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    {
    }
  }
  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 */
  }
}
#endif

 

posted @ 2023-04-12 16:26  caesura_k  阅读(176)  评论(0编辑  收藏  举报