当前位置: 首页 > article >正文

STM32F103 MCU 上电启动流程分析实现

STM32F10x上电启动流程概述

STM32F10x上电后执行的第一条指令是存储在ROM中的,这部分ROM通常被称为系统存储器(System Memory)或引导存储器(Boot ROM)。这个区域包含了启动代码(Boot Code),其主要任务是初始化微控制器的基本功能,并且决定从哪里加载程序来执行。

系统存储器中的启动代码会执行以下操作:

  • 电源和时钟系统初始化:设置内部时钟系统,确保微控制器以正确的频率运行。
  • 外设初始化:对必要的外设进行基本配置,例如GPIO、复位外设等。
  • 启动模式选择:根据BOOT0和BOOT1引脚的状态以及其他启动配置选项(如启动模式选择引脚),决定是从内部Flash、外部存储器还是通过其他接口(如串行通信)加载程序。

  • 跳转到主程序:一旦系统初始化完成,启动代码会跳转到主程序的入口点,这个入口点通常是内部Flash中的中断向量表的起始地址。

若BOOT0和BOOT1引脚被配置为从系统存储器启动,那么启动代码会从系统存储器的固定地址(通常是0x1FFF0000)开始执行。

注:系统存储器区域是只读的,它在微控制器出厂时被编程,并且通常不会被用户修改。这个区域的代码是微控制器正常启动和运行的关键部分。

若BOOT0和BOOT1引脚被配置为从内部Flash启动,那么它会跳转到内部Flash的起始地址(通常是0x08000000)去执行第一条指令。

当调到主程序执行时,默认使用的是STM32F10x自带的时钟源(HSI:高速内部时钟,由内部RC振荡器产生),然而 HSI 精度较差,对时钟频率精度要求较高的场合,需要切换精度较高的高速外部时钟(HSE:高速外部时钟,由外部晶振或时钟源提供,常见的频率为8MHz)。

以下对HSE的时钟配置进行说明

HSE 时钟配置

当使用外部晶振(以8M晶振为例)作为时钟源时,对应的STM32F10x的时钟树配置如下图所示

主要由RCC_CRRCC_CFGR寄存器进行控制

代码实现

主程序中断向量表实现

#include <stdint.h>

#define SRAM_START_ADDR             (0x20000000U)
#define SRAM_SIZE                   (64U * 1024U)
#define SRAM_END_ADDR               (SRAM_START_ADDR + SRAM_SIZE)

#define STACK_INIT_ADDR             (SRAM_END_ADDR)

#define ISR_EXCEPTION_NUM           16
#define ISR_STM32_SPECIFIC_NUM      60
#define ISR_VECTOR_SIZE             (ISR_EXCEPTION_NUM + ISR_STM32_SPECIFIC_NUM)

void reset_handler(void);
void default_handler(void);

// Cortex-M system exceptions
void nmi_handler(void) __attribute__((weak, alias("default_handler")));
void hard_fault_handler(void) __attribute__((weak, alias("default_handler")));
void mem_manage_handler(void) __attribute__((weak, alias("default_handler")));
void bus_fault_handler(void) __attribute__((weak, alias("default_handler")));
void usage_fault_handler(void) __attribute__((weak, alias("default_handler")));
void svc_handler(void) __attribute__((weak, alias("default_handler")));
void debug_mon_handler(void) __attribute__((weak, alias("default_handler")));
void pendsv_handler(void) __attribute__((weak, alias("default_handler")));
void systick_handler(void) __attribute__((weak, alias("default_handler")));

// STM32F103ZET interrupt handlers
void wwdg_handler(void) __attribute__((weak, alias("default_handler")));
void pvd_handler(void) __attribute__((weak, alias("default_handler")));
void tamper_handler(void) __attribute__((weak, alias("default_handler")));
void rtc_handler(void) __attribute__((weak, alias("default_handler")));
void flash_handler(void) __attribute__((weak, alias("default_handler")));
void rcc_handler(void) __attribute__((weak, alias("default_handler")));
void exti0_handler(void) __attribute__((weak, alias("default_handler")));
void exti1_handler(void) __attribute__((weak, alias("default_handler")));
void exti2_handler(void) __attribute__((weak, alias("default_handler")));
void exti3_handler(void) __attribute__((weak, alias("default_handler")));
void exti4_handler(void) __attribute__((weak, alias("default_handler")));
void dma1_channel1_handler(void) __attribute__((weak, alias("default_handler")));
void dma1_channel2_handler(void) __attribute__((weak, alias("default_handler")));
void dma1_channel3_handler(void) __attribute__((weak, alias("default_handler")));
void dma1_channel4_handler(void) __attribute__((weak, alias("default_handler")));
void dma1_channel5_handler(void) __attribute__((weak, alias("default_handler")));
void dma1_channel6_handler(void) __attribute__((weak, alias("default_handler")));
void dma1_channel7_handler(void) __attribute__((weak, alias("default_handler")));
void adc1_2_handler(void) __attribute__((weak, alias("default_handler")));
void usb_hp_can1_tx_handler(void) __attribute__((weak, alias("default_handler")));
void usb_lp_can1_rx0_handler(void) __attribute__((weak, alias("default_handler")));
void can1_rx1_handler(void) __attribute__((weak, alias("default_handler")));
void can1_sce_handler(void) __attribute__((weak, alias("default_handler")));
void exti9_5_handler(void) __attribute__((weak, alias("default_handler")));
void tim1_brk_handler(void) __attribute__((weak, alias("default_handler")));
void tim1_up_handler(void) __attribute__((weak, alias("default_handler")));
void tim1_trg_com_handler(void) __attribute__((weak, alias("default_handler")));
void tim1_cc_handler(void) __attribute__((weak, alias("default_handler")));
void tim2_handler(void) __attribute__((weak, alias("default_handler")));
void tim3_handler(void) __attribute__((weak, alias("default_handler")));
void tim4_handler(void) __attribute__((weak, alias("default_handler")));
void i2c1_ev_handler(void) __attribute__((weak, alias("default_handler")));
void i2c1_er_handler(void) __attribute__((weak, alias("default_handler")));
void i2c2_ev_handler(void) __attribute__((weak, alias("default_handler")));
void i2c2_er_handler(void) __attribute__((weak, alias("default_handler")));
void spi1_handler(void) __attribute__((weak, alias("default_handler")));
void spi2_handler(void) __attribute__((weak, alias("default_handler")));
void usart1_handler(void) __attribute__((weak, alias("default_handler")));
void usart2_handler(void) __attribute__((weak, alias("default_handler")));
void usart3_handler(void) __attribute__((weak, alias("default_handler")));
void exti15_10_handler(void) __attribute__((weak, alias("default_handler")));
void rtc_alarm_handler(void) __attribute__((weak, alias("default_handler")));
void usbwakeup_handler(void) __attribute__((weak, alias("default_handler")));
void tim8_brk_handler(void) __attribute__((weak, alias("default_handler")));
void tim8_up_handler(void) __attribute__((weak, alias("default_handler")));
void tim8_trg_com_handler(void) __attribute__((weak, alias("default_handler")));
void tim8_cc_handler(void) __attribute__((weak, alias("default_handler")));
void adc3_handler(void) __attribute__((weak, alias("default_handler")));
void fsmc_handler(void) __attribute__((weak, alias("default_handler")));
void sdio_handler(void) __attribute__((weak, alias("default_handler")));
void tim5_handler(void) __attribute__((weak, alias("default_handler")));
void spi3_handler(void) __attribute__((weak, alias("default_handler")));
void uart4_handler(void) __attribute__((weak, alias("default_handler")));
void uart5_handler(void) __attribute__((weak, alias("default_handler")));
void tim6_handler(void) __attribute__((weak, alias("default_handler")));
void tim7_handler(void) __attribute__((weak, alias("default_handler")));
void dma2_channel1_handler(void) __attribute__((weak, alias("default_handler")));
void dma2_channel2_handler(void) __attribute__((weak, alias("default_handler")));
void dma2_channel3_handler(void) __attribute__((weak, alias("default_handler")));
void dma2_channel4_5_handler(void) __attribute__((weak, alias("default_handler")));

uint32_t isr_vector[ISR_VECTOR_SIZE] __attribute__((section(".isr_vector"))) = {
    STACK_INIT_ADDR,

    // Cortex-M3 Processor Exceptions
    (uint32_t)&reset_handler,           // Reset Handler

    (uint32_t)&nmi_handler,             // NMI Handler
    (uint32_t)&hard_fault_handler,      // Hard Fault Handler
    (uint32_t)&mem_manage_handler,      // MPU Fault Handler
    (uint32_t)&bus_fault_handler,       // Bus Fault Handler
    (uint32_t)&usage_fault_handler,     // Usage Fault Handler
    (uint32_t)0,                        // Reserved
    (uint32_t)0,                        // Reserved
    (uint32_t)0,                        // Reserved
    (uint32_t)0,                        // Reserved
    (uint32_t)&svc_handler,             // SVCall Handler
    (uint32_t)&debug_mon_handler,       // Debug Monitor Handler
    (uint32_t)0,                        // Reserved
    (uint32_t)&pendsv_handler,          // PendSV Handler
    (uint32_t)&systick_handler,         // SysTick Handler

    // external interrupts
    (uint32_t)&wwdg_handler,            // Window Watchdog
    (uint32_t)&pvd_handler,             // PVD through EXTI Line detect
    (uint32_t)&tamper_handler,          // Tamper
    (uint32_t)&rtc_handler,             // RTC
    (uint32_t)&flash_handler,           // Flash
    (uint32_t)&rcc_handler,             // RCC
    (uint32_t)&exti0_handler,           // EXTI Line 0
    (uint32_t)&exti1_handler,           // EXTI Line 1
    (uint32_t)&exti2_handler,           // EXTI Line 2
    (uint32_t)&exti3_handler,           // EXTI Line 3
    (uint32_t)&exti4_handler,           // EXTI Line 4
    (uint32_t)&dma1_channel1_handler,   // DMA1 Channel 1
    (uint32_t)&dma1_channel2_handler,   // DMA1 Channel 2
    (uint32_t)&dma1_channel3_handler,   // DMA1 Channel 3
    (uint32_t)&dma1_channel4_handler,   // DMA1 Channel 4
    (uint32_t)&dma1_channel5_handler,   // DMA1 Channel 5
    (uint32_t)&dma1_channel6_handler,   // DMA1 Channel 6
    (uint32_t)&dma1_channel7_handler,   // DMA1 Channel 7
    (uint32_t)&adc1_2_handler,          // ADC1 & ADC2
    (uint32_t)&usb_hp_can1_tx_handler,  // USB High Priority or CAN1 TX
    (uint32_t)&usb_lp_can1_rx0_handler, // USB Low  Priority or CAN1 RX0
    (uint32_t)&can1_rx1_handler,        // CAN1 RX1
    (uint32_t)&can1_sce_handler,        // CAN1 SCE
    (uint32_t)&exti9_5_handler,         // EXTI Line 9..5
    (uint32_t)&tim1_brk_handler,        // TIM1 Break
    (uint32_t)&tim1_up_handler,         // TIM1 Update
    (uint32_t)&tim1_trg_com_handler,    // TIM1 Trigger and Commutation
    (uint32_t)&tim1_cc_handler,         // TIM1 Capture Compare
    (uint32_t)&tim2_handler,            // TIM2
    (uint32_t)&tim3_handler,            // TIM3
    (uint32_t)&tim4_handler,            // TIM4
    (uint32_t)&i2c1_ev_handler,         // I2C1 Event
    (uint32_t)&i2c1_er_handler,         // I2C1 Error
    (uint32_t)&i2c2_ev_handler,         // I2C2 Event
    (uint32_t)&i2c2_er_handler,         // I2C2 Error
    (uint32_t)&spi1_handler,            // SPI1
    (uint32_t)&spi2_handler,            // SPI2
    (uint32_t)&usart1_handler,          // USART1
    (uint32_t)&usart2_handler,          // USART2
    (uint32_t)&usart3_handler,          // USART3
    (uint32_t)&exti15_10_handler,       // EXTI Line 15..10
    (uint32_t)&rtc_alarm_handler,       // RTC Alarm through EXTI Line
    (uint32_t)&usbwakeup_handler,       // USB Wakeup from suspend
    (uint32_t)&tim8_brk_handler,        // TIM8 Break
    (uint32_t)&tim8_up_handler,         // TIM8 Update
    (uint32_t)&tim8_trg_com_handler,    // TIM8 Trigger and Commutation
    (uint32_t)&tim8_cc_handler,         // TIM8 Capture Compare
    (uint32_t)&adc3_handler,            // ADC3
    (uint32_t)&fsmc_handler,            // FSMC
    (uint32_t)&sdio_handler,            // SDIO
    (uint32_t)&tim5_handler,            // TIM5
    (uint32_t)&spi3_handler,            // SPI3
    (uint32_t)&uart4_handler,           // UART4
    (uint32_t)&uart5_handler,           // UART5
    (uint32_t)&tim6_handler,            // TIM6
    (uint32_t)&tim7_handler,            // TIM7
    (uint32_t)&dma2_channel1_handler,   // DMA2 Channel1
    (uint32_t)&dma2_channel2_handler,   // DMA2 Channel2
    (uint32_t)&dma2_channel3_handler,   // DMA2 Channel3
    (uint32_t)&dma2_channel4_5_handler, // DMA2 Channel4 & Channel5
};

extern uint32_t _etext, _sdata, _edata, _sbss, _ebss, _sidata;
void app_main(void);

void reset_handler(void)
{
    // Copy .data from FLASH to SRAM
    uint32_t data_size = (uint32_t)&_edata - (uint32_t)&_sdata;
    uint8_t *flash_data = (uint8_t*)&_sidata; // Data load address (in flash)
    uint8_t *sram_data = (uint8_t*)&_sdata; // Data virtual address (in sram)

    for (uint32_t i = 0; i < data_size; i++) {
        sram_data[i] = flash_data[i];
    }

    // Zero-fill .bss section in SRAM
    uint32_t bss_size = (uint32_t)&_ebss - (uint32_t)&_sbss;
    uint8_t *bss = (uint8_t*) &_sbss;

    for (uint32_t i = 0; i < bss_size; i++) {
        bss[i] = 0;
    }

    app_main();
}

void default_handler(void)
{
    while(1);
}

HSE时钟配置代码

void system_clock_init(uint8_t PLL)
{
    unsigned char temp=0;

    rcc_deinit();         //复位并配置向量表

    RCC->CR|=0x00010000;    //外部高速时钟使能HSEON
    while(!(RCC->CR>>17));  //等待外部时钟就绪

    RCC->CFGR=0X00000400;   //APB1=DIV2;APB2=DIV1;AHB=DIV1;
    PLL-=2;                 //抵消2个单位(因为是从2开始的,设置0就是2)
    RCC->CFGR|=PLL<<18;     //设置PLL值 2~16
    RCC->CFGR|=1<<16;       //PLLSRC ON
    FLASH->ACR|=0x32;       //FLASH 2个延时周期
    RCC->CR|=0x01000000;    //PLLON
    while(!(RCC->CR>>25));  //等待PLL锁定

    RCC->CFGR|=0x00000002;  //PLL作为系统时钟
    while(temp!=0x02) {     //等待PLL作为系统时钟设置成功
        temp=RCC->CFGR>>2;
        temp&=0x03;
    }
}


http://www.kler.cn/a/468249.html

相关文章:

  • 打包部署若依(RuoYi)SpringBoot后端和Vue前端图文教程
  • 【AI落地】AI生成测试用例,claude or gpt?(提效至少 50%)
  • 图漾相机基础操作
  • 资源分享:gpts、kaggle、paperswithcode
  • 常用的数据结构API概览
  • SQL使用游标
  • 从 TiDB 学习分布式数据库测试
  • 构建JS全栈开发的CMS系统——从零开始搭建前后端
  • kafka使用常见问题
  • 【机器学习篇】交通革命:机器学习如何引领未来的道路创新
  • 仓颉笔记——windows11安装启用cangjie语言,并使用vscode编写“你好,世界”
  • 面试经典150题——矩阵
  • 《数据结构》期末考试测试题【中】
  • 在PostgreSQL中,函数调用是一个非常重要的操作
  • deepseek v3模型为啥要开源
  • Eplan 项目结构(高层代号、安装地点、位置代号)
  • 初识C语言之函数的递归
  • 【linux基础I/O(1)】文件描述符的本质重定向的本质
  • 解决HBuilderX报错:未安装内置终端插件,是否下载?或使用外部命令行打开。
  • SQL Server 的备份机制及其恢复实现
  • 利用轮换IP的强大功能
  • CSS系列(49)-- Relative Color Syntax详解
  • Postgresql中clog与xid对应关系计算方法(速查表)
  • lua库介绍:数据处理与操作工具库 - leo
  • k8s 镜像拉取策略
  • 计算机组成原理——控制单元设计