OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 22532|回复: 14

STM32启动过程相关代码分析

[复制链接]

3

主题

6

帖子

0

精华

新手上路

积分
38
金钱
38
注册时间
2011-4-24
在线时间
0 小时
发表于 2012-9-8 21:57:02 | 显示全部楼层 |阅读模式
      之前从张洋网店买了2个板(可惜老同学了,都没给我打折),这几天需要用到了,就搭了个环境。
      我用的编译环境:Eclipse + CDT +  Code Sourcery Lite Arm GNU Tool chain
      由于库中的startup_stm32f10x_md.s与编译环境有关,所以针对的是库中的
STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\TrueSTUDIO路径下的文件进行分析。对了,我用的库是3.5的。

system_stm32f10x.c

SystemInit(): 在"startup_stm32f10x_xx.s"文件中被调用,功能是设置系统时钟(包括时钟源,PLL系数,AHB/APBx的预分频系数还有 flash的设定),这个函数
会在系统复位之后首先被执行。文件中默认的一些设置:允许HSE(外部时钟),FLASH(允许预取缓冲区,设置2个等待周 期),PLL系数为9,开启PLL并选择PLL
输出作为时钟源(SYSCLK),后续设置SYSCLK = HCLK = APB2 = 72MHz,APB1 = HCLK/2 = 36MHz,HCLK即AHB的时钟。

SystemCoreClockUpdate():在系统时钟HCLK变化的时候调用,以更新一个全局变量SystemCoreClock,这个变量可以为应用程序使用,必须保证正确。默认不用
调用这个函数,因为SystemCoreClock默认被设置为设定的频率了(72MHz)

另外,下面这种设置寄存器的方法值得借鉴,先用位名清除相应的位,再进行设置,例如:

 #define  RCC_CFGR_PLLSRC                     ((uint32_t)0x00010000)        /*!< PLL entry clock source */
 #define  RCC_CFGR_PLLXTPRE                   ((uint32_t)0x00020000)        /*!< HSE divider for PLL entry */

 #define  RCC_CFGR_PLLMULL                    ((uint32_t)0x003C0000)        /*!< PLLMUL[3:0] bits (PLL multiplication factor) */

 #define  RCC_CFGR_PLLSRC_HSE                ((uint32_t)0x00010000)        /*!< HSE clock selected as PLL entry clock source */

 #define  RCC_CFGR_PLLMULL9                  ((uint32_t)0x001C0000)        /*!< PLL input clock*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);[/mw_shl_code] 

 

startup_stm32f10x_md.s:(开发板的F103RBT6是中容量的产品)

这个文件里面首先定义了复位中断(复位入口矢量被硬件固定在地址0x0000_0004)的处理函数:Reset_Handler,它的作用就是将保存于flash中的初始化数据复
制到sram中,调用上面说到的SystemInit来初始化时钟,接着跳转到main执行。

接着定义了Default_Handler, 这个是作为其他所有中断的默认处理函数,作用就是死循环,所以你假如开启了某个中断,请按照这里面的中断函数名给它写中断
处理函数,例如串口中断处理函数名是 USART1_IRQHandler,你开了串口中断,如果不重写USART1_IRQHandler,就默认执行Default_Handler,死循环了。而如
果你有重写,那么中断向量表中的处理函数的地址就会更新为你自己写的那个函数的地址了。为什么会这样呢?因为此文件的末尾用了类似这样的语句:

    .weak    USART1_IRQHandler
    .thumb_set USART1_IRQHandler,Default_Handler[/mw_shl_code] 

它给中断处理函数提供了弱(weak)别名(Default_Handler),如果不重写,中断了默认执行Default_Handler,如果重写了,因为是弱别名,所以会被你写的同名
函数
覆盖。


最后定义了一个中断向量表的段.section    .isr_vector,"a",%progbits),这个表将会放置在0x0000 0000那里,第二个字(0x0000 0004)是复位向量,复位之后
重这地址所指的函数执行。

 

那么,如何保证.isr_vector这个段将放在flash的最开始(0x08000000)呢?这就需要链接脚本了,即我们用的那个stm32_flash.ld文件了,查看一下就知道了,里面
先定义了堆栈的地址:_estack

/* Highest address of the user mode stack */
_estack = 0x20005000;    /* end of 20K RAM */[/mw_shl_code] 

接着定义了堆和栈的大小:

/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0;      /* required amount of heap  */
_Min_Stack_Size = 0x100; /* required amount of stack */[/mw_shl_code] 

接着声明了各个内存的区域(定义了几个代表某个线性空间的名字,如下面的FLASH):

/* Specify the memory areas */
MEMORY
{
  FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 128K   
  RAM (xrw)       : ORIGIN = 0x20000000, LENGTH = 20K   
  MEMORY_B1 (rx)  : ORIGIN = 0x60000000, LENGTH = 0K }[/mw_shl_code] 

接着下面再介绍上面这三个名字里面都放了什么东西,首先是FLASH的:

/* Define output sections */
SECTIONS
{
  /* The startup code goes first into FLASH */
  .isr_vector :
  {
    . = ALIGN(4);    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);  } >FLASH

  /* The program code and other data goes into FLASH */
  .text :
  {
    . = ALIGN(4);    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */

    KEEP (*(.init))
    KEEP (*(.fini))

    . = ALIGN(4);    _etext = .;        /* define a global symbols at end of code */   
} >FLASH[/mw_shl_code] 

可以看到startup_stm32f10x_md.s中定义的这个段.isr_vector确实放在了最开头的位置。下面其他的内容就不分析了可查看下面地址获取更多信息
http://www.stf12.org/developers/freerots_ec-linker_script.html)。

     但是我们前面说复位向量在0x0000 0004,现在其地址是在flash中,所以地址是0x0800 0004,这个怎么回事呢?原来,stm32可以通过boot0、boot1引脚的配置
将flash映射到0x0000 0000处。具体可参考stm32的用户手册2.4节:

从主闪存存储器启动(BOOT0 = 0,BOOT1 = X):主闪存存储器被映射到启动空间(0x0000 0000),但仍然能够在它原有的地址(0x0800 0000)访问它,即闪存存
储器的内容可以在两个地址区域访问,0x0000 0000或0x0800 0000。

至此,整个STM32的启动过程以及程序结构都可以比较清晰了。至于使用MDK-ARM 环境的情况,也差不多的。

Ps:开始是在blogcn里面写的,那里编辑器好一些,写完直接复制过来了。有兴趣可以过去look look:http://www.cnblogs.com/TrueElement/ 只是更新频率很慢就
是了。
focus on what you want!
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

6

帖子

0

精华

新手上路

积分
38
金钱
38
注册时间
2011-4-24
在线时间
0 小时
 楼主| 发表于 2012-9-8 21:59:12 | 显示全部楼层
Oh,这个排版⊙﹏⊙b汗
怎么不会自动换行?
focus on what you want!
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2012-9-8 23:52:29 | 显示全部楼层
回复【2楼】TrueElement:
---------------------------------
你和张洋是同学?
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

3

主题

6

帖子

0

精华

新手上路

积分
38
金钱
38
注册时间
2011-4-24
在线时间
0 小时
 楼主| 发表于 2012-9-10 08:07:18 | 显示全部楼层
回复【3楼】正点原子:
---------------------------------
恩,不过他应该猜不出我是谁~~~
focus on what you want!
回复 支持 反对

使用道具 举报

3

主题

6

帖子

0

精华

新手上路

积分
38
金钱
38
注册时间
2011-4-24
在线时间
0 小时
 楼主| 发表于 2012-9-16 17:28:51 | 显示全部楼层
看来没人有兴趣讨论这些不实际的问题,飘过了~~~
focus on what you want!
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2012-9-16 18:02:41 | 显示全部楼层
呵呵
回复 支持 反对

使用道具 举报

20

主题

122

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
222
金钱
222
注册时间
2013-9-21
在线时间
0 小时
发表于 2013-11-27 17:56:32 | 显示全部楼层
回复【5楼】TrueElement:
---------------------------------
受教了,楼主讲的很好啊。
回复 支持 反对

使用道具 举报

20

主题

122

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
222
金钱
222
注册时间
2013-9-21
在线时间
0 小时
发表于 2013-11-27 18:00:52 | 显示全部楼层
回复【3楼】正点原子:
---------------------------------
原子哥,我想问下:
1.stm32的引导文件(即.s文件)会烧录到flash里面吗?这算是一个bootloader吗?
2.flash里面生产厂家固化的启动程序和这个一样吗?这个是不是不能改啊?
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2013-11-27 23:32:07 | 显示全部楼层
回复【8楼】jikaishihuaidan:
---------------------------------
1,会,不是.
2,是,不能.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

20

主题

122

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
222
金钱
222
注册时间
2013-9-21
在线时间
0 小时
发表于 2013-11-28 14:27:38 | 显示全部楼层
回复【9楼】正点原子:
---------------------------------
2.flash里面生产厂家固化的启动程序和这个一样吗?这个是不是不能改啊?
2,是,不能.

如果一样的话,为什么.s文件还能修改呢?
stm32在执行main()函数之前,要进行一系列的准备工作,包括将RW和ZI DATA从ROM复制到RAM中,把ZI DATA在RAM地址清0等,这些工作也是stm32f10x_hd.s文件完成的吗?
stm32f10x_hd.s文件不是只开辟了堆和栈并初始化,设置了中断向量表吗?
stm32f10x_hd.s文件里的_main()是在哪定义的呢?
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2013-11-28 16:00:47 | 显示全部楼层
回复【10楼】jikaishihuaidan:
---------------------------------
论坛搜索:.s
有详细分析.自己慢慢拜读吧.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

20

主题

122

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
222
金钱
222
注册时间
2013-9-21
在线时间
0 小时
发表于 2013-11-28 17:53:17 | 显示全部楼层
回复【11楼】正点原子:
---------------------------------
终于找到答案了,
首先,_main()是C语言的入口函数,它是由编译器给出的,在编译过程中放进去。

其次stm32的flash里固化的程序和引导程序(.s)文件是不一样的。


stm32的flash里固化的程序存在flash的system memory,也就是启动程序代码0X1FFFF000~0X1FFFF7FF,这部分的主要任务就是通过uart1下载程序到内置flash中去 。
而引导程序(.s文件)的作用则是上面所说的。

回复 支持 反对

使用道具 举报

16

主题

253

帖子

0

精华

高级会员

Rank: 4

积分
565
金钱
565
注册时间
2013-10-16
在线时间
52 小时
发表于 2014-12-20 10:26:47 | 显示全部楼层
现在也在看SystemCoreClockUpdate(),怎么没有调用的,我改成SystemCoreClockUpdate1(),也不出问题,不出警告的。
如果按照楼主说的 == 在系统时钟HCLK变化的时候调用。
那我改变了,应该会出错的。
回复 支持 反对

使用道具 举报

0

主题

11

帖子

0

精华

初级会员

Rank: 2

积分
69
金钱
69
注册时间
2013-8-26
在线时间
5 小时
发表于 2016-9-5 23:49:33 | 显示全部楼层
很有启发性,多谢指教。
回复 支持 反对

使用道具 举报

33

主题

218

帖子

0

精华

高级会员

Rank: 4

积分
568
金钱
568
注册时间
2015-1-12
在线时间
75 小时
发表于 2021-8-5 13:25:24 | 显示全部楼层
本帖最后由 yuanzinpl 于 2021-8-18 15:12 编辑

SystemCoreClockUpdate()普通程序确实没发现调用。关于引导程序讲的很好,受教了,多谢
能举个例子  什么时候才调用这个函数吗?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-26 00:20

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表