STM32启动流程

发布者:和谐共融最新更新时间:2024-10-16 来源: cnblogs关键字:STM32  启动流程 手机看文章 扫描二维码
随时随地手机看文章

1、stm32初始化流程

void RCC_Configuration(void)

{

  /* RCC system reset(for debug purpose) */

  RCC_DeInit(); //时钟控制寄存器全部恢复默认值

  /* Enable HSE */

  RCC_HSEConfig(RCC_HSE_ON); //外部高速时钟源开启(8M晶振)

  /* Wait till HSE is ready */

  HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待外部时钟HSE就绪

  if(HSEStartUpStatus == SUCCESS) //如果时钟启动成功

  {

    /* HCLK = SYSCLK */

    RCC_HCLKConfig(RCC_SYSCLK_Div1); //定义AHB设备时钟为系统时钟1分频,AHB,系统时钟不分频

    /* PCLK2 = HCLK */

   RCC_PCLK2Config(RCC_HCLK_Div1); //定义AHB2设备时钟为HCLK时钟1分频

    /* PCLK1 = HCLK/2 */

   RCC_PCLK1Config(RCC_HCLK_Div2); //定义AHB1设备时钟为HCLK时钟2分频

    /* Flash 2 wait state */

    FLASH_SetLatency(FLASH_Latency_2); //设定内部FLASH的的延时周期为2周期

    /* Enable Prefetch Buffer */

    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //使能FLASH预存取缓冲区

    /* PLLCLK = 8MHz * 9 = 72 MHz */

    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //配置PLL时钟为外部高速时钟的9倍频,8MHz * 9 = 72 MHz

    /* Enable PLL */

    RCC_PLLCmd(ENABLE); //使能PLL时钟

    /* Wait till PLL is ready */

    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) //等待PLL时钟设置完成准备就绪

    {

    }

    /* Select PLL as system clock source */

    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //使用PLL时钟作为系统时钟源

    /* Wait till PLL is used as system clock source */

    while(RCC_GetSYSCLKSource() != 0x08) //返回系统所用时钟源确认为外部高速晶振,8M晶振。

    {

    }

  }

}

void RCC_DeInit(void)

{

  /* Set HSION bit,打开内部8M的HSI时钟 */

  RCC->CR |= (uint32_t)0x00000001;    //RCC结构体为RCC_TypeDef


  /* Reset SW[1:0], HPRE[3:0], PPRE1[2:0], PPRE2[2:0], ADCPRE[1:0] and MCO[2:0] bits */

  /*SW=00,SWS=00,设置HSI为系统时钟

   *HPRE=0000,AHB,即SYSCLK不分频

   *PPRE1=000,AHB1(PCLK1)不分频

   *PPRE2=000,AHB2 (PCLK2)不分频

   *ADCPRE=00,PCLK2 两分频后作为ADC时钟

   *MCO=000,没有时钟输出*/

  RCC->CFGR &= (uint32_t)0xF8FF0000;

 

  /* Reset HSEON, CSSON and PLLON bits */

/*HSEON=0,关闭HSE振荡器

CSSON=0,关闭时钟检测器

PLLON=0,PLL关闭*/

  RCC->CR &= (uint32_t)0xFEF6FFFF;


  /* Reset HSEBYP bit */

/*HSEBYP=0,外部4-16M振荡器没旁路*/

  RCC->CR &= (uint32_t)0xFFFBFFFF;


  /* Reset PLLSRC, PLLXTPRE, PLLMUL[3:0] and USBPRE bits */

/*PLLSRC=0,HSI经过2分频后作为PLL输入时钟

     PLLXTPRE=0.HSE不分频

    PLLMUL=0000,PLL 2倍频输出

USBPRE=0,PLL 1.5倍分频后作为USB时钟*/

  RCC->CFGR &= (uint32_t)0xFF80FFFF;


  /* Disable all interrupts */

//关闭所有时钟中断

  RCC->CIR = 0x00000000;

}


#define RCC                                    ((RCC_TypeDef *) RCC_BASE)

#define RCC_BASE                         (AHBPERIPH_BASE + 0x1000)    //RCC_BASE =  0x40021000

#define AHBPERIPH_BASE            (PERIPH_BASE + 0x20000)        //AHBPERIPH_BASE = 0x40020000

#define PERIPH_BASE                  ((uint32_t)0x40000000)                //PERIPH_BASE = 0x40000000

//所以RCC_BASE = 0x40021000,由上面寄存器表可知这个是复位和时钟控制器RCC


typedef struct

{

  __IO uint32_t CR;

  __IO uint32_t CFGR;

  __IO uint32_t CIR;

  __IO uint32_t APB2RSTR;

  __IO uint32_t APB1RSTR;

  __IO uint32_t AHBENR;

  __IO uint32_t APB2ENR;

  __IO uint32_t APB1ENR;

  __IO uint32_t BDCR;

  __IO uint32_t CSR;

} RCC_TypeDef;

这个结构体根据寄存器定义,如下图所示

总结:RCC_DeInit();  所做的工作就是在系统初始的时候关闭HSE时钟,打开HSI作为时钟,并关闭时钟中断

void RCC_HSEConfig(uint32_t RCC_HSE)

{

  /* Check the parameters */

/*不做实质上的操作*/

  assert_param(IS_RCC_HSE(RCC_HSE));

  /* Reset HSEON and HSEBYP bits before configuring the HSE ------------------*/

  /* Reset HSEON bit */

/*#define CR_HSEON_Reset ((uint32_t)0xFFFEFFFF)

#define CR_HSEBYP_Reset ((uint32_t)0xFFFBFFFF)

   设置HSE之前需要复位HSEON,HSEBYP,这两位写0*/

  RCC->CR &= CR_HSEON_Reset;

  /* Reset HSEBYP bit */

  RCC->CR &= CR_HSEBYP_Reset;


  /* Configure HSE (RCC_HSE_OFF is already covered by the code section above) */

  switch(RCC_HSE)

  {

    /*RCC_HSE= RCC_HSE_ON,所以执行这条

    #define CR_HSEON_Set ((uint32_t)0x00010000),开启HSE振荡器*/

    case RCC_HSE_ON:

      /* Set HSEON bit */

      RCC->CR |= CR_HSEON_Set;

      break;

     

    case RCC_HSE_Bypass:

      /* Set HSEBYP and HSEON bits */

      RCC->CR |= CR_HSEBYP_Set | CR_HSEON_Set;

      break;

     

    default:

      break;

  }

}

总结:打开HSE时钟

ErrorStatus RCC_WaitForHSEStartUp(void)

{

  __IO uint32_t StartUpCounter = 0;

  ErrorStatus status = ERROR;

  FlagStatus HSEStatus = RESET;

 

  /* Wait till HSE is ready and if Time out is reached exit */

  do

  {

    HSEStatus = RCC_GetFlagStatus(RCC_FLAG_HSERDY);         //#define RCC_FLAG_HSERDY ((uint8_t)0x31)

    StartUpCounter++;

  } while((HSEStatus == RESET) && (StartUpCounter != HSEStartUp_TimeOut));

  if (RCC_GetFlagStatus(RCC_FLAG_HSERDY) != RESET)

  {

    status = SUCCESS;

  }

  else

  {

    status = ERROR;

  }

  return (status);

}


FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG)

{

  uint32_t tmp = 0;

  uint32_t statusreg = 0;

  FlagStatus bitstatus = RESET;

  /* Check the parameters */

  assert_param(IS_RCC_FLAG(RCC_FLAG));

  /* Get the RCC register index */

  tmp = RCC_FLAG >> 5;        //RCC_FLAG = 0x31,tmp = 1

  if (tmp == 1) /* The flag to check is in CR register */

  {

    statusreg = RCC->CR;       // 读取RCC->CR寄存器

  }

  else if (tmp == 2) /* The flag to check is in BDCR register */

  {

    statusreg = RCC->BDCR;

  }

  else /* The flag to check is in CSR register */

  {

    statusreg = RCC->CSR;

  }

  /* Get the flag position */

  tmp = RCC_FLAG & FLAG_Mask;    //tmp = 0x31 & 1f = 0x11

  if ((statusreg & ((uint32_t)1 << tmp)) != (uint32_t)RESET)    //检测RCC->HSERDY,如果HSE准备好了,则bitstatus = SET,(RESET = 0, SET = !RESET)

  {

    bitstatus = SET;

  }

  else

  {

    bitstatus = RESET;

  }

  /* Return the flag status */

  return bitstatus;

}

总结:等待HSE时钟准备完毕,HSE准备完毕则返回SUCCES

void RCC_HCLKConfig(uint32_t RCC_SYSCLK)        //RCC_SYSCLK = RCC_SYSCLK_Div1    #define RCC_SYSCLK_Div1 ((uint32_t)0x00000000)

{

  uint32_t tmpreg = 0;

  /* Check the parameters */

  assert_param(IS_RCC_HCLK(RCC_SYSCLK));

  tmpreg = RCC->CFGR;

  /* Clear HPRE[3:0] bits,RCC->CFGR->HPRE清零,表示SYSCLK不分频 */

  tmpreg &= CFGR_HPRE_Reset_Mask;    //#define CFGR_HPRE_Reset_Mask ((uint32_t)0xFFFFFF0F)

  /* Set HPRE[3:0] bits according to RCC_SYSCLK value ,*/

  tmpreg |= RCC_SYSCLK;    //RCC_SYSCLK = RCC_SYSCLK_Div1    #define RCC_SYSCLK_Div1 ((uint32_t)0x00000000)

  /* Store the new value */

  RCC->CFGR = tmpreg;

}

void RCC_PCLK2Config(uint32_t RCC_HCLK)               //#define RCC_HCLK_Div1 ((uint32_t)0x00000000),    RCC_HCLK = RCC_HCLK_Div1

{

  uint32_t tmpreg = 0;

  /* Check the parameters */

  assert_param(IS_RCC_PCLK(RCC_HCLK));

  tmpreg = RCC->CFGR;

  /* Clear PPRE2[2:0] bits */

  tmpreg &= CFGR_PPRE2_Reset_Mask;    //#define CFGR_PPRE2_Reset_Mask ((uint32_t)0xFFFFC7FF)

  /* Set PPRE2[2:0] bits according to RCC_HCLK value */

  tmpreg |= RCC_HCLK << 3;

  /* Store the new value */

  RCC->CFGR = tmpreg;

}


void RCC_PCLK1Config(uint32_t RCC_HCLK)        //RCC_HCLK = #define RCC_HCLK_Div2 ((uint32_t)0x00000400)

{

  uint32_t tmpreg = 0;

  /* Check the parameters */

  assert_param(IS_RCC_PCLK(RCC_HCLK));

  tmpreg = RCC->CFGR;

  /* Clear PPRE1[2:0] bits ,PPRE1清零*/ 

  tmpreg &= CFGR_PPRE1_Reset_Mask;    //#define CFGR_PPRE1_Reset_Mask ((uint32_t)0xFFFFF8FF)

  /* Set PPRE1[2:0] bits according to RCC_HCLK value */

  tmpreg |= RCC_HCLK;   //2分频

  /* Store the new value */

  RCC->CFGR = tmpreg;

}

void FLASH_SetLatency(uint32_t FLASH_Latency)    //#define FLASH_Latency_2 ((uint32_t)0x00000002) 

{

  uint32_t tmpreg = 0;

 

  /* Check the parameters */

  assert_param(IS_FLASH_LATENCY(FLASH_Latency));

 

  /* Read the ACR register */

  tmpreg = FLASH->ACR;

 

  /* Sets the Latency value */

  tmpreg &= ACR_LATENCY_Mask;    //#define ACR_LATENCY_Mask ((uint32_t)0x00000038)

  tmpreg |= FLASH_Latency;        //2个等待状态

 

  /* Write the ACR register */

  FLASH->ACR = tmpreg;

}

void FLASH_PrefetchBufferCmd(uint32_t FLASH_PrefetchBuffer)    // //#define FLASH_PrefetchBuffer_Enable ((uint32_t)0x00000010)

{

  /* Check the parameters */

  assert_param(IS_FLASH_PREFETCHBUFFER_STATE(FLASH_PrefetchBuffer));

 

  /* Enable or disable the Prefetch Buffer */

  FLASH->ACR &= ACR_PRFTBE_Mask;

  FLASH->ACR |= FLASH_PrefetchBuffer;

}

void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t RCC_PLLMul)    //#define RCC_PLLSource_HSE_Div1 ((uint32_t)0x00010000),    #define RCC_PLLMul_9 ((uint32_t)0x001C0000)

{

  uint32_t tmpreg = 0;

  /* Check the parameters */

[1] [2]
关键字:STM32  启动流程 引用地址:STM32启动流程

上一篇:stm32常见错误与工程模板
下一篇:STM32自定义printf实现多串口互用

小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved