学习STM32(二)之STM32启动流程

BOOT  的描述:

原文 : http://www.cnblogs.com/huanzxj/p/6273014.html

一、三种BOOT模式介绍

所谓启动,一般来说就是指我们下好程序后,重启芯片时,SYSCLK的第4个上升沿,BOOT引脚的值将被锁存。用户可以通过设置BOOT1和BOOT0引脚的状态,来选择在复位后的启动模式。

Main Flash memory
是STM32内置的Flash,一般我们使用JTAG或者SWD模式下载程序时,就是下载到这个里面,重启后也直接从这启动程序。

System memory(引导装载程序 为了把程序导入到FLash中)
从系统存储器启动,这种模式启动的程序功能是由厂家设置的。一般来说,这种启动方式用的比较少。系统存储器是芯片内部一块特定的区域,STM32在出厂时,由ST在这个区域内部预置了一段BootLoader, 也就是我们常说的ISP程序, 这是一块ROM,
出厂后无法修改。一般来说,我们选用这种启动模式时,是为了从串口下载程序,因为在厂家提供的BootLoader中,提供了串口下载程序的固件,可以通过这个BootLoader将程序下载到系统的Flash中。但是这个下载方式需要以下步骤:
Step1:将BOOT0设置为1,BOOT1设置为0,然后按下复位键,这样才能从系统存储器启动BootLoader
Step2:最后在BootLoader的帮助下,通过串口下载程序到Flash中
Step3:程序下载完成后,又有需要将BOOT0设置为GND,手动复位,这样,STM32才可以从Flash中启动可以看到, 利用串口下载程序还是比较的麻烦, 需要跳帽跳来跳去的,非常的不注重用户体验。

Embedded Memory
内置SRAM,既然是SRAM,自然也就没有程序存储的能力了,这个模式一般用于程序调试。假如我只修改了代码中一个小小的地方,然后就需要重新擦除整个Flash,比较的费时,可以考虑从这个模式启动代码(也就是STM32的内存中),用于快速的程序调试,等程序调试完成后,在将程序下载到SRAM中。

 二、开发BOOT模式选择。

1、通常使用程序代码存储在主闪存存储器,配置方式:BOOT0=0,BOOT1=X;

2、Flash锁死解决办法:

开发调试过程中,由于某种原因导致内部Flash锁死,无法连接SWD以及Jtag调试,无法读到设备,可以通过修改BOOT模式重新刷写代码。

修改为BOOT0=1,BOOT1=0即可从系统存储器启动,ST出厂时自带Bootloader程序,SWD以及JTAG调试接口都是专用的。重新烧写程序后,可将BOOT模式重新更换到BOOT0=0,BOOT1=X即可正常使用。

 

 

stm32初始化流程图解析:

原文 : http://www.elecfans.com/emb/app/20171116580420.html

 

  STM32启动流程分析:

  无论是STM32、ARM系列的单片机,还是简单的如51,PIC等,都以为上述原因,需要启动程序,只不过51,PIC等单片机的启动程序已经在相应的IDE编译、链接的时候隐含的编译了,故在写单片机程序的时候无需考虑。而STM32的启动有相应的启动文件,本文将采用KEIL MDK自带的启动文件STM32F10x.s进行分析。

  1 启动模式的选择

  STM32芯片自带的启动方式有3种如下表

stm32初始化流程图解析

  STM32的启动选择,通过设置BOOT1、BOOT0的引脚的高低电平即可选择。其中主闪存启动是将程序下载到内置的Flash进行启动(该flash可运行程序),该程序可以掉电保存,下次开机可自动启动;系统存储器启动是将程序写入到一快特定的区域,一般由厂家直接写入,不能被随意更改或擦除。内置SRAM启动,由于SRAM掉电丢失,不能保存程序,一般只用于程序的调试。

  就程序的启动而言,采用以上3种方式启动,但对于一个嵌入式系统的程序来说,如果程序执行文件很大,而STM32内置的存储空间有限,就需要外置Nand flash/Nor flash 和SDRAM,即程序存储在flash中,程序执行在SDRAM中,既节约了成本有提高了运行效率。如果采用外置的Flash+SDRAM的方式,就需要一个更加复杂的启动文件(bootloader),需要考虑flash的COPY,Flash的驱动,内存的管理,通信机制等,本文暂不涉及此内容,以后有机会专门讲述。

 

--------------------------------------------------------------------------------------------------------------------------------

上图:

向量表:所谓的中断向量表,其实是一个WORD(32位整数的数组),每个下标对应一个异常或者中断。向量表的存储地址是可以设置的,通过NVIC中的一个重定位寄存器来指出向量表的地址。复位默认为0。因此,地址0处必须包含一张向量表,用于初始化时的异常分配。

 

例: 中断向量名为EXTI0_IRQHandler,它其实是一个函数指针,指向的是中断服务函数void EXTI0_IRQHandler(void)
发生中断时,NVIC会计算出它的偏移量n*4 ,这个n = 6(n:为EXTI0_IRQHandler的异常类型号,这里不想再去找就直接用n代替),从而找到EXTI0_IRQHandler 并跳入。

 

 

复位第一条指令:Reset_Handler   PROC,这里指定为 LDR     R0, =__main。表示调用库函数__main,当然,我们可以在__main前做点事情,比如PLL初始化,例如执行下文的SystemInit()

可以不使用C库初始化函数__main()直接调用用户的main(),这个_main的函数可以随便改,不过要上下文一样
 

 

https://blog.csdn.net/ybhuangfugui/article/details/75948282

https://blog.csdn.net/lanmanck/article/details/8306045

 

 

 

 

 

 

 

 

 

 

STM32启动后系统初始化SystemInit()

原文 : https://blog.csdn.net/tianshi_1988/article/details/51085962


启动文件中复位异常相应函数如下:
; Reset handler
Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  __main
                IMPORT  SystemInit
                LDR     R0, =SystemInit
                BLX     R0               
                LDR     R0, =__main
                BX      R0
                ENDP

SystemInit()这个函数出现在main()函数的第一行,可以看出它的重要性。以前关于SystemInit()这个函数从来没有关心过,只知道这是进行STM32系统初始化的一个函数。今天决定仔细看看,重新开始STM32的学习。这个函数在system_stm32f10x.c中,此C文件主要就是干具体硬件配置相关的工作。

[cpp] view plain copy  
/** @addtogroup STM32F10x_System_Private_Functions 
  * @{ 
  */  
  
/** 
  * @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 SystemInit (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;  
  
  /* 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 */  
  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   
}  

从函数说明来看,此函数功能就是初始化内部FALSH,PLL并且更新系统时钟。此函数需在复位启动后调用。
[cpp] view plain copy  
RCC->CR |= (uint32_t)0x00000001;  

第一行代码操作时钟控制寄存器,将内部8M高速时钟使能,从这里可以看出系统启动后是首先依靠内部时钟源而工作的。
[cpp] view plain copy  
#ifndef STM32F10X_CL  
  RCC->CFGR &= (uint32_t)0xF8FF0000;  
#else  
  RCC->CFGR &= (uint32_t)0xF0FF0000;  

这两行代码则是操作时钟配置寄存器。其主要设置了MCO(微控制器时钟输出)PLL相关(PLL倍频系数,PLL输入时钟源),ADCPRE(ADC时钟),PPRE2(高速APB分频系数),PPRE1(低速APB分频系数),HPRE(AHB预分频系数),SW(系统时钟切换),开始时,系统时钟切换到HSI,由它作为系统初始时钟。宏STM32F10X_CL是跟具体STM32芯片相关的一个宏。
[cpp] view plain copy  
/* Reset HSEON, CSSON and PLLON bits */  
RCC->CR &= (uint32_t)0xFEF6FFFF;  
  
/* Reset HSEBYP bit */  
RCC->CR &= (uint32_t)0xFFFBFFFF;  
  
/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */  
RCC->CFGR &= (uint32_t)0xFF80FFFF;  

这几句话则是先在关闭HSE,CSS,,PLL等的情况下配置好与之相关参数然后开启,达到生效的目的。
[cpp] view plain copy  
#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 */  

这一段主要是跟中断设置有关。开始时,我们需要禁止所有中断并且清除所有中断标志位。不同硬件有不同之处。
[cpp] view plain copy  
#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)  
  #ifdef DATA_IN_ExtSRAM  
    SystemInit_ExtMemCtl();   
  #endif /* DATA_IN_ExtSRAM */  
#endif  

这段跟设置外部RAM有关吧,我用到的STM32F103RBT与此无关。
[cpp] view plain copy  
SetSysClock();  

此又是一个函数,主要是配置系统时钟频率。HCLK,PCLK2,PCLK1的分频值,分别代表AHB,APB2,和APB1。当然还干了其它的事情,配置FLASH延时周期和使能预取缓冲期。后面的这个配置具体还不了解。
[cpp] view plain copy  
#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   

这段代码主要是实现向量表的重定位。依据你想要将向量表定位在内部SRAM中还是内部FLASH中。这个SCB开始没在STM32参考手册中发现,原来它是跟Cortex-M3内核相关的东西。所以ST公司就没有把它包含进来吧。内核的东西后面再了解,这里给自己提个醒。

然后再看看SystemInit()中的那个函数SetClock()又做了什么吧。
[cpp] view plain copy  
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  
   
 /* If none of the define above is enabled, the HSI is used as System clock 
    source (default after reset) */   
}  

从中可以看出就是根据不同的宏来设置不同的系统时钟,这些宏就在跟此函数在同一个源文件里。官方很是考虑周到,我们只需要选择相应宏就能达到快速配置系统时钟的目的。
[cpp] view plain copy  
#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)  
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */  
 #define SYSCLK_FREQ_24MHz  24000000  
#else  
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */  
/* #define SYSCLK_FREQ_24MHz  24000000 */   
/* #define SYSCLK_FREQ_36MHz  36000000 */  
/* #define SYSCLK_FREQ_48MHz  48000000 */  
/* #define SYSCLK_FREQ_56MHz  56000000 */  
#define SYSCLK_FREQ_72MHz  72000000  
#endif  

比如这里我需要配置系统时钟为72MHZ,则只需要将#define SYSCLK_FREQ_72MHz  72000000两边的注释符去掉。
这个函数里面又有SetSysClockTo72()函数,这个函数就是具体操作寄存器进行配置了。
[cpp] view plain copy  
#elif defined SYSCLK_FREQ_72MHz  
/** 
  * @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 None 
  */  
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);  
   
  /* 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 */  
    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      
    /*  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 */  
    while((RCC->CR & RCC_CR_PLLRDY) == 0)  
    {  
    }  
      
    /* 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 */  
    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  

 

 

  • 0
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值