首页 > 其他分享 >史上最简单的bootloader【STM32F767】[【二】

史上最简单的bootloader【STM32F767】[【二】

时间:2024-06-15 14:31:38浏览次数:23  
标签:Reset RW Image unsigned long STM32F767 bootloader IRAM1 史上

继上一篇史上最简单的bootloader【STM32F767】后,最近进一步研究了下bootloader。

任务:bootloader不变,app自我复制,将app搬运到sram中运行。

目的:1)学习bootloader;

          2)没什么大用处,主要是学习---->看资料说是代码在sram中运行会快一点,本人没有测试过

学习过程有点曲折,虽然实验现象符合预期,还是有很多不明白的地方,话多不表,开始!!!

bootloader代码参考史上最简单的bootloader【STM32F767】

app文件中增加了拷贝复制的函数:

void copymyself(void)
{
  extern unsigned long Image$$ER_IROM1$$Base;
  extern unsigned long Image$$ER_IROM1$$Length;
  extern unsigned long Load$$ER_IROM1$$Base;
  //拷贝代码
  volatile unsigned long TXTSize_volatile =
 ( unsigned long )&Image$$ER_IROM1$$Length;
  memcpy(&Image$$ER_IROM1$$Base,&Load$$ER_IROM1$$Base,TXTSize_volatile);
  
  //拷贝数据段
  extern unsigned long Image$$RW_IRAM1$$Base;
  extern unsigned long Load$$RW_IRAM1$$Base;
  extern unsigned long Image$$RW_IRAM1$$Length;
  volatile unsigned long DATSize_volatile=( unsigned long )&Image$$RW_IRAM1$$Length;
  memcpy(&Image$$RW_IRAM1$$Base,&Load$$RW_IRAM1$$Base,DATSize_volatile);
  //BSS段清零
  extern unsigned long Image$$RW_IRAM1$$ZI$$Base;
  extern unsigned long Image$$RW_IRAM1$$ZI$$Length;
  volatile unsigned long ZISize_volatile=( unsigned long )&Image$$RW_IRAM1$$ZI$$Length;
  memset(&Image$$RW_IRAM1$$ZI$$Base,0,ZISize_volatile);
}

散列文件改动了一点,一个一个说明!

LR_IROM1 0x08030000 0x00a0000  {    ; load region size_region
  ER_IROM1 0x20000000 0x00080000  {  ; load address = execution address
   *.o (RESET, +First)
   .ANY (+RO)
   .ANY (+XO)
  }
  RW_IRAM1 +0  {  ; RW data
   .ANY (+RW +ZI)
  }
}

解释:
 1) ER_IROM1 0x20000000 0x00080000    运行域的地址放在sram中,因为加载地址和链接地址不一致,所 
     以需要代码、数据、BSS都需要重新定位(其实就是代码复制,将相关的数据复制到链接地址,比如本次
     加载地址是0x08030000,链接地址0x20000000 ,就需要把0x08030000开始的相关代码和数据复制到链接        
     地址0x20000000)
 2) RW_IRAM1 +0   +0代表紧接着上一个加载域(同一个空间中,都是在sram中。为什么可读可写,未初始化 
     变量要放在sram,自行查找资料,个人认为就是sram中可以对某个字节,类似nandflash norflahs就需要 
     以块或者扇区为单位进行读写,不怎么灵活)

启动文件改动的地方比较多,里面有很多不太明白的地方!!!

__Vectors       ;DCD     __initial_sp               ; Top of Stack
				DCD		(0x20000000+0x00080000)
                ;DCD     Reset_Handler              ; Reset Handler 0x200001f8
				DCD     0x080301f9             ; Reset Handler
                DCD     NMI_Handler                ; NMI Handler
                ……
                ……
                ……
说明:
1)DCD		(0x20000000+0x00080000)   指定栈,虽然我知道栈空间地址是向下的,对于这一句,我不是 
   很明白,如果是默认的 -> DCD     __initial_sp   ,程序无法运行
2)DCD     0x080301f9             ; Reset Handler 这一句很奇怪是不是。因为必须要这么做!!! 
   目的:app自我复制,然后再跳到sram中运行相关代码。
   解释:
        在跳转到sram中执行代码前(重定位后的代码),实现app自我复制的代码(函数copymyself)  必                    
        须、一定、肯定、100%要“运行”flash中的。因为此时的链接地址处   app自我复制的代码(函数 
        copymyself)   还没被搬运到这里。
        下面是反汇编文件,可以看到Reset_Handler段链接地址:0x200001f8,可以确定Reset_Handler 
        段在flash上地址在0x080301f8(0x080301f9是因为用的是thumb指令集)

       $d.realdata
    RESET
    __Vectors
        0x20000000:    20080000    ...     DCD    537395200
        0x20000004:    080301f9    ....    DCD    134414841
        0x20000008:    2000a901    ...     DCD    536914177
        0x2000000c:    20008ff1    ...     DCD    536907761
        0x20000010:    2000a8f9    ...     DCD    536914169
        0x20000014:    20000301    ...     DCD    536871681
        0x20000018:    2000bc21    !..     DCD    536919073
        0x2000001c:    00000000    ....    DCD    0
        0x20000020:    00000000    ....    DCD    0
        0x20000024:    00000000    ....    DCD    0
        0x20000028:    00000000    ....    DCD    0

    .text
    $v0
    Reset_Handler
    __Vectors_End
        0x200001f8:    f00bfd2e    ....    BL       copymyself ; 0x2000bc58
        0x200001fc:    f00bfd6c    ..l.    BL       mymain ; 0x2000bcd8
        0x20000200:    e7fe        ..      B        0x20000200 ; Reset_Handler + 8
        0x20000202:    e7fe        ..      B        0x20000202 ; Reset_Handler + 10
        0x20000204:    e7fe        ..      B        0x20000204 ; Reset_Handler + 12
        0x20000206:    e7fe        ..      B        0x20000206 ; Reset_Handler + 14
        0x20000208:    e7fe        ..      B        0x20000208 ; Reset_Handler + 16
        0x2000020a:    e7fe        ..      B        0x2000020a ; Reset_Handler + 18
        0x2000020c:    e7fe        ..      B        0x2000020c ; Reset_Handler + 20
        0x2000020e:    e7fe        ..      B        0x2000020e ; Reset_Handler + 22
        0x20000210:    e7fe        ..      B        0x20000210 ; Reset_Handler + 24
             


上面理解不了,可以看.map文件,map文件也能说明。

下面是 Reset_Handler段,实现功能:

1)调用void copymyself(void)函数实现app自我复制

2)初始化stm32环境

3)跳转到sram中的APP运行

__Vectors_End

__Vectors_Size  EQU  __Vectors_End - __Vectors

                AREA    |.text|, CODE, READONLY
; Reset handler
Reset_Handler    PROC	
                 EXPORT  Reset_Handler             [WEAK]
				 IMPORT  copymyself
			     IMPORT  mymain
				 IMPORT  SystemInit
				 ;LDR     SP,=(0x20000000+0x00080000)
				 BL 	 copymyself
				 ;BL 	 mymain
				 BL 	 SystemInit
			     ;LDR     R0, =SystemInit
                 ;BLX     R0
				 LDR     R0, =mymain
                 BLX     R0
                 ENDP
说明:
    1) BL 	 copymyself   这个是相对跳转的指令,因为此时代码还没跳到SRAM中运行,所以用BL相对跳转 
       指令 
    2)BL 	 SystemInit   这个是初始化stm32运行环境,至于为什么还需要初始化,我也不明白,如果不重 
       新初始化环境printf函数不能用,但是led反转功能是正常的,很无语,个人猜测应该是uart重定向的代 
       码没有被复制到sram中也就是c运行库的问题。
    3) LDR     R0, =mymain
        BLX     R0         位置有关的跳转,跳转到sram中的mymain()运行

 app的实现

/* USER CODE BEGIN 0 */

void copymyself(void)
{
  extern unsigned long Image$$ER_IROM1$$Base;
  extern unsigned long Image$$ER_IROM1$$Length;
  extern unsigned long Load$$ER_IROM1$$Base;
  //拷贝代码
  volatile unsigned long TXTSize_volatile =
 ( unsigned long )&Image$$ER_IROM1$$Length;
  memcpy(&Image$$ER_IROM1$$Base,&Load$$ER_IROM1$$Base,TXTSize_volatile);
  
  //拷贝数据段
  extern unsigned long Image$$RW_IRAM1$$Base;
  extern unsigned long Load$$RW_IRAM1$$Base;
  extern unsigned long Image$$RW_IRAM1$$Length;
  volatile unsigned long DATSize_volatile=( unsigned long )&Image$$RW_IRAM1$$Length;
  memcpy(&Image$$RW_IRAM1$$Base,&Load$$RW_IRAM1$$Base,DATSize_volatile);
  //BSS段清零
  extern unsigned long Image$$RW_IRAM1$$ZI$$Base;
  extern unsigned long Image$$RW_IRAM1$$ZI$$Length;
  volatile unsigned long ZISize_volatile=( unsigned long )&Image$$RW_IRAM1$$ZI$$Length;
  memset(&Image$$RW_IRAM1$$ZI$$Base,0,ZISize_volatile);
}
/* USER CODE END 0 */
/**
  * @brief  The application entry point.
  * @retval int
  */
int mymain(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MPU Configuration--------------------------------------------------------*/
  MPU_Config();

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
    HAL_GPIO_TogglePin(led01_GPIO_Port,led01_Pin);
    HAL_GPIO_TogglePin(led01_GPIO_Port,led00_Pin);
    printf("this is app program \r\n");
    HAL_Delay(1200);
  }
  /* USER CODE END 3 */
}

至此,通过app的自我复制,将代码搬运到sram中运行功能就实现了!!!

那些不明白的地方,如果哪天搞明白了,会在文中更新,同时也希望有知道的大佬能留言指导下小弟!!!

标签:Reset,RW,Image,unsigned,long,STM32F767,bootloader,IRAM1,史上
From: https://blog.csdn.net/Mr1sky/article/details/139700883

相关文章

  • PIC18 bootloader之RS485 bootloader
                   了解更多关于bootloader的C语言实现,请加我Q扣:1273623966(验证信息请填bootloader),欢迎咨询或定制bootloader(在线升级程序)。    不知道为什么,现在工业控制领域也向汽车领域学习,产品需要带bootloader,产品出货后也要可......
  • 【408精华知识】史上最全的数据结构代码题总结!三万字长文!!!
    关于数据结构代码题,可以说是让很多同学感到头疼了,书上的代码太繁琐、网上的总结不全面让大家对代码题感到云里雾里,那么这篇文章可能会给大家带来一点启发,因为我自己也是深受代码题的折磨,所以一直想写一篇有关它的总结,希望能够做到全面、简洁,让大家用最快的速度记住代码书......
  • 史上最强!华为交换机常用命令大全,网络工程师收藏!
    华为作为全球领先的信息与通信解决方案供应商,其交换机产品在全球市场占据了重要位置。华为交换机以高性能、高可靠性和丰富的功能著称,广泛应用于企业、数据中心、运营商网络等各类环境中。无论是中小企业的局域网,还是大型数据中心的核心网络,华为交换机都能提供灵活、稳定的......
  • CDH详解(史上最全)
    工作记录知识研究CDH概览CDH(ClouderaDistributionIncludingApacheHadoop)是由Cloudera公司提供的一个集成了ApacheHadoop以及相关生态系统的发行版本。CDH是一个大数据平台,简化和加速了大数据处理分析的部署和管理。CDH提供Hadoop的核心元素-可伸缩存储和分布式计算-以......
  • 史上最强 AI 翻译诞生了!拳打谷歌,脚踢 DeepL
    CoT推理范式默认情况下,大语言模型通常是直接给出问题的最终答案,中间推理过程是隐含的、不透明的,无法发挥出大模型最极致的理解能力。如果你用它来充当翻译,可能效果和传统的机器翻译也差不了太多。如果我们给大模型设计一个合理的提示词,控制大模型的思考方式,就能发挥出大模型的......
  • STM32F767+LWIP+CubeMX配置
    一、环境准备电脑系统:Windows10专业版 20H2IDE:Keilv5.35、STM32CubeMXv6.5.0测试硬件:STM32F767二、测试步骤1、测试目的通过CubeMX配置lwip,ping通STM32F7672、新建工程3、配置sys不使用操作系统,那么时基源直接使用Systick,SWD调试。4、配置RCC高速时钟为电路......
  • JAVA:实际工作中,项目上线——打包war,并部署到Tomcat中运行(史上最详细教程)
    每日一讲希望每天叫醒你的不是闹钟,而是梦想!目录每日一讲1.部署原因1.1Tomcat介绍 2.Tomcat下载及安装2.1Tomcat下载2.2Tomcat在IDEA上部署​2.3解决Tomcat乱码问题3.打包war文件,并在Tomcat目录下运行3.1打包文件3.2Tomcat环境配置3.3Tomcat运行1.部署原因......
  • 7 | 史上最全大数据笔记-Hive函数
    第八章Hive函数在Hive中,函数主要分两大类型,一种是内置函数,一种是用户自定义函数。8.1Hive内置函数8.1.1函数查看 showfunctions; descfunctionfunctionName;8.1.2日期函数1)当前系统时间函数:current_date()、current_timestamp()、unix_timestamp() --函......
  • 史上最全Docker教程,从容器发展史到实操(一)
    前言:今天我们所说的容器是一种IT技术。容器其实是一种沙盒技术。顾名思义,沙盒就是能够像一个集装箱一样,把你的应用装起来。这样,应用与应用之间就有了边界而不会相互干扰;同时装在沙盒里面的应用,也可以很方便的被搬来搬去,这也是PaaS想要的最理想的状态(可移植性,标准化,隔离性)......
  • 面试必问:MySQL死锁 是什么,如何解决?(史上最全)
    MySQL死锁接触少,但面试又经常被问到怎么办?最近有小伙伴在面试的时候,被问了MySQL死锁,如何解决?虽然也回答出来了,但是不够全面体系化,所以,小北给大家做一下系统化、体系化的梳理,帮助大家在面试过程中能够脱颖而出,拿到自己心仪的Offer插播一条:如果你近期准备面试跳槽,建议在http:......