技术笔记2023076 rBoot学习7

技术笔记2023076 rBoot学习7

  继续之前的学习。

代码分析:函数find_image()

// prevent this function being placed inline with main
// to keep main's stack size as small as possible
// don't mark as static or it'll be optimised out when
// using the assembler stub

  首先看一下作者给这个函数写下的注释。为了避免此函数内嵌入main函数而占用main函数的栈空间,此函数被关键字NOINLINE修饰。为了避免此函数在使用汇编存根(stub)时被优化,不能使用static来修饰此函数。

	uint8_t  flag;uint32_t  loadAddr;uint32_t  flashsize;int32_t  romToBoot;uint8_t  updateConfig  =  0;uint8_t  buffer[SECTOR_SIZE];rboot_config  *romconf  = (rboot_config*)buffer;rom_header  *header  = (rom_header*)buffer;

  此函数先声明了一些变量,其中的变量buffer数组的大小是SECTOR_SIZE,也就是Flash一个扇区的大小,此处为4KB

#ifdef BOOT_BAUDRATE// soft reset doesn't reset PLL/divider, so leave as configuredif (get_reset_reason() != REASON_SOFT_RESTART) {uart_div_modify( 0, UART_CLK_FREQ / BOOT_BAUDRATE);}
#endif

  此处建议在Makefile中定义变量RBOOT_BAUDRATE,因为ESP-12F模组上电默认的74880波特率太过奇怪。此处我将变量RBOOT_BAUDRATE定义在了变量RBOOT_FW_BASE的后面,并赋值为115200。

#if  defined  BOOT_DELAY_MICROS  &&  BOOT_DELAY_MICROS  >  0// delay to slow boot (help see messages when debugging)ets_delay_us(BOOT_DELAY_MICROS);
#endifets_printf("\r\nrBoot v1.4.2 - richardaburton@gmail.com\r\n");

  此处建议去掉rboot.h//#define BOOT_DELAY_MICROS 2000000的注释去掉,并给宏定义设置一个合适的值,我将其设置为20000(单位为us)。这样做可以做到等待系统稳定再进行后面的操作。如果我们想设置rBoot阶段串口输出的波特率,就需要在这里等待系统串口稳定。

	// read rom headerSPIRead(0, header, sizeof(rom_header));// print and get flash sizeets_printf("Flash Size: ");flag  =  header->flags2  >>  4;if (flag  ==  0) {ets_printf("4 Mbit\r\n");flashsize  =  0x80000;} else  if (flag  ==  1) {ets_printf("2 Mbit\r\n");flashsize  =  0x40000;} else  if (flag  ==  2) {ets_printf("8 Mbit\r\n");flashsize  =  0x100000;} else  if (flag  ==  3  ||  flag  ==  5) {ets_printf("16 Mbit\r\n");
#ifdef BOOT_BIG_FLASHflashsize =  0x200000;
#elseflashsize  =  0x100000; // limit to 8Mbit
#endif} else  if (flag  ==  4  ||  flag  ==  6) {ets_printf("32 Mbit\r\n");
#ifdef BOOT_BIG_FLASHflashsize =  0x400000;
#elseflashsize  =  0x100000; // limit to 8Mbit
#endif} else  if (flag  ==  8) {ets_printf("64 Mbit\r\n");
#ifdef BOOT_BIG_FLASHflashsize =  0x800000;
#elseflashsize  =  0x100000; // limit to 8Mbit
#endif} else  if (flag  ==  9) {ets_printf("128 Mbit\r\n");
#ifdef BOOT_BIG_FLASHflashsize =  0x1000000;
#elseflashsize  =  0x100000; // limit to 8Mbit
#endif} else {ets_printf("unknown\r\n");// assume at least 4mbitflashsize  =  0x80000;}// print spi modeets_printf("Flash Mode: ");if (header->flags1  ==  0) {ets_printf("QIO\r\n");} else  if (header->flags1  ==  1) {ets_printf("QOUT\r\n");} else  if (header->flags1  ==  2) {ets_printf("DIO\r\n");} else  if (header->flags1  ==  3) {ets_printf("DOUT\r\n");} else {ets_printf("unknown\r\n");}// print spi speedets_printf("Flash Speed: ");flag  =  header->flags2  &  0x0f;if (flag  ==  0) ets_printf("40 MHz\r\n");else  if (flag  ==  1) ets_printf("26.7 MHz\r\n");else  if (flag  ==  2) ets_printf("20 MHz\r\n");else  if (flag  ==  0x0f) ets_printf("80 MHz\r\n");else  ets_printf("unknown\r\n");

  这里使用SPI接口将Flash上的头部信息读出并保存在变量header中。其中包含有Flash大小、模式和速度信息。这些信息我们都可以在Makefile中设置,设置好以后会被编译进bin文件中。对于ESP-12F来说,应该这样设置:SPI_SIZE ?= 4MSPIMODE ?= DOUTSPI_SPEED ?= 40

	// read boot configSPIRead(BOOT_CONFIG_SECTOR  *  SECTOR_SIZE, buffer, SECTOR_SIZE);// fresh install or old version?if (romconf->magic  !=  BOOT_CONFIG_MAGIC  ||  romconf->version  !=  BOOT_CONFIG_VERSION) {// create a default config for a standard 2 rom setupets_printf("Writing default boot config.\r\n");ets_memset(romconf, 0x00, sizeof(rboot_config));romconf->magic  =  BOOT_CONFIG_MAGIC;romconf->version  =  BOOT_CONFIG_VERSION;default_config(romconf, flashsize);// write new config sectorSPIEraseSector(BOOT_CONFIG_SECTOR);SPIWrite(BOOT_CONFIG_SECTOR  *  SECTOR_SIZE, buffer, SECTOR_SIZE);}// try rom selected in the config, unless overriden by gpio/temp bootromToBoot  =  romconf->current_rom;

  这里先将Flash第一个扇区的数据读入缓冲区buffer中,而前面romconf指向了buffer。那么此时romconf就读出了rBoot的配置结构体信息。接着,我们比较magicversion是否与之前的宏定义相同。按照rBoot项目的readme中说的,我们在进行boot版本迭代时,可以通过修改version来区分新旧版本。如果此处if为真,则说明Flash中存在新的boot,此时要将Flash的第一个扇区覆盖。之后获取当前需要加载的rom的索引。

	// check valid rom number// gpio/temp boots will have already validated thisif (romconf->current_rom  >=  romconf->count) {// if invalid rom selected try rom 0ets_printf("Invalid rom selected, defaulting to 0.\r\n");romToBoot  =  0;romconf->current_rom  =  0;updateConfig  =  1;}// check rom is validloadAddr  =  check_image(romconf->roms[romToBoot]);// check we have a good romwhile (loadAddr  ==  0) {ets_printf("Rom %d at %x is bad.\r\n", romToBoot, romconf->roms[romToBoot]);// for normal mode try each previous rom// until we find a good one or run outupdateConfig  =  1;romToBoot--;if (romToBoot  <  0) romToBoot  =  romconf->count  -  1;if (romToBoot  ==  romconf->current_rom) {// tried them all and all are bad!ets_printf("No good rom available.\r\n");return  0;}loadAddr  =  check_image(romconf->roms[romToBoot]);
}

  之前拿到了当前需要加载的rom的索引。如果之前拿到的索引是否超出rom总数,则认为此索引是无效的,并默认加载第一个rom。之后再去获取rom的地址。如果获取rom地址失败,则说明此rom已经被损坏了。如果所有rom都已经损坏了,那么只能直接返回0,代表没有找到image了。

	// re-write config, if requiredif (updateConfig) {romconf->current_rom  =  romToBoot;SPIEraseSector(BOOT_CONFIG_SECTOR);SPIWrite(BOOT_CONFIG_SECTOR  *  SECTOR_SIZE, buffer, SECTOR_SIZE);}ets_printf("Booting rom %d at %x, load addr %x.\r\n", romToBoot, romconf->roms[romToBoot], loadAddr);// copy the loader to top of iramets_memcpy((void*)_text_addr, _text_data, _text_len);// return address to load fromreturn  loadAddr;

  获取到rom的地址后,将当前的rom的索引写入配置结构体中。随后将buffer写入boot所在的扇区,覆盖了之前的配置,在下次启动时将使用当前的配置。然后,将_text_data位置,长度为_text_len的数据加载到_text_addr中。最后返回rom的地址,find_image()函数就结束了。

const  uint32_t  entry_addr  =  0x4010fcb4;const  uint32_t  _text_addr  =  0x4010fc00;
const  uint32_t  _text_len  =  192;
const  uint8_t  _text_data[]  = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x10, 0x00, 0x00, 0x1c, 0x4b, 0x00, 0x40, 0x12, 0xc1, 0xc0, 0xc9, 0xe1, 0x8b, 0x31, 0xcd,
0x02, 0x0c, 0x84, 0xe9, 0xc1, 0xf9, 0xb1, 0x09, 0xf1, 0xd9, 0xd1, 0xc2, 0xcc, 0x08, 0x01, 0xf9,
0xff, 0xc0, 0x00, 0x00, 0xf8, 0x31, 0xe2, 0x01, 0x09, 0x86, 0x10, 0x00, 0x2d, 0x0c, 0x3d, 0x01,
0x0c, 0x84, 0x01, 0xf4, 0xff, 0xc0, 0x00, 0x00, 0x8b, 0xcc, 0x78, 0x01, 0xd8, 0x11, 0x46, 0x09,
0x00, 0x21, 0xef, 0xff, 0x5d, 0x0d, 0xd7, 0xb2, 0x02, 0x20, 0x52, 0x20, 0x2d, 0x0c, 0x3d, 0x07,
0x4d, 0x05, 0x59, 0x51, 0x79, 0x41, 0x01, 0xeb, 0xff, 0xc0, 0x00, 0x00, 0x58, 0x51, 0x78, 0x41,
0x5a, 0xcc, 0x5a, 0x77, 0x50, 0xdd, 0xc0, 0x56, 0x6d, 0xfd, 0x0b, 0x6e, 0x60, 0xe0, 0x74, 0x56,
0x9e, 0xfb, 0x08, 0xf1, 0x2d, 0x0f, 0xc8, 0xe1, 0xd8, 0xd1, 0xe8, 0xc1, 0xf8, 0xb1, 0x12, 0xc1,
0x40, 0x0d, 0xf0, 0x00, 0xfd, 0x00, 0x05, 0xf8, 0xff, 0x0d, 0x0f, 0xa0, 0x02, 0x00, 0x0d, 0xf0,
};

  _text_data_text_len_text_addr等变量都可以在build目录下的rboot-hex2a.h中找到。令人意外的是,此文件竟然处于build目录下,这就说明它不是写出来的,而是通过某种方式生成的。

$(RBOOT_BUILD_BASE)/rboot-hex2a.h: $(RBOOT_BUILD_BASE)/rboot-stage2a.elf@echo "E2 $@"$(Q)  $(ESPTOOL2) -quiet -header $<  $@ .text

  通过分析Makefile,我们可以看到,rboot-hex2a.h依赖于rboot-stage2a.elf,并通过esptool2生成的。关于生成rboot-hex2a.h的具体过程,可以参考这篇文章:ESP8266 Bootloader开源代码解析之rboot(一)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/12040.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

给APK签名—两种方式(flutter android 安装包)

前提&#xff1a;给未签名的apk签名&#xff0c;可以先检查下apk有没有签名 通过命令行查看&#xff1a;打开终端或命令行界面&#xff0c;导入包含APK文件的目录&#xff0c;并执行以下命令&#xff1a; keytool -printcert -jarfile your_app.apk 将 your_app.apk替换为要检查…

String 的 switch-case 实现原理

前面我们已经知道 String 的 switch-case 实现原理 依据 case 值的稀疏程度&#xff0c;分别由两个指令 - tableswitch 和 lookupswitch 实现&#xff0c;但是这两个指令都支持整型&#xff0c; 如何让 String 类型的值 也支持 String 的 switch-case 实现原理 public class T…

【数据结构】--189.轮转数组

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

Rethinking the Image Fusion(PMGI)

1.摘要 本文提出了一种基于梯度和强度比例维护&#xff08;PMGI&#xff09;的快速统一图像融合网络&#xff0c;可以端到端实现各种图像融合任务&#xff0c;包括红外和可见图像融合、多曝光图像融合、医学图像融合、多焦点图像融合和全色增强。我们将图像融合问题统一为源图…

保姆级系列教程-玩转Fiddler抓包教程(1)-HTTP和HTTPS基础知识

1.简介 有的小伙伴或者童鞋们可能会好奇地问&#xff0c;不是讲解和分享抓包工具了怎么这里开始讲解HTTP和HTTPS协议了。这是因为你对HTTP协议越了解&#xff0c;你就能越掌握Fiddler的使用方法&#xff0c;反过来你越使用Fiddler&#xff0c;就越能帮助你了解HTTP协议。 Fid…

Java | 继承、多态、抽象类与接口

目录 一、类的继承 二、Object类 2.1 getClass()方法 2.2 toString()方法 2.3 equals()方法 三 、对象类型的转换 3.1 向上转换 3.2 向下转型 四、使用instanceof关键字判断对象类型 五、方法的重载 六、final关键字 6.1 final变量 6.2 final方法 6.3 final类 七…

安装x265

一、编译libx265源码 libx265是用CMAKE编译的&#xff0c;故先下cmake&#xff0c;我是centos系统&#xff0c;命令&#xff1a; yum install cmake -y进入目录./x265_1.9/build/linux/下&#xff0c;执行脚本&#xff1a; sh make-Makefiles.bash选择好之后&#xff0c;输入…

【多模态】19、RegionCLIP | 基于 Region 来实现视觉语言模型预训练

文章目录 一、背景二、方法2.1 Region-based Language-Image Pretraining2.2 目标检测的迁移学习 三、效果3.1 数据集3.2 实现细节3.3 结果 论文&#xff1a; RegionCLIP: Region-based Language-Image Pretraining 代码&#xff1a;https://github.com/microsoft/RegionCLIP …

了解Unity编辑器之组件篇Playables和Rendering(十)

Playables 一、Playable Director&#xff1a;是一种用于控制和管理剧情、动画和音频的工具。它作为一个中央控制器&#xff0c;可以管理播放动画剧情、视频剧情和音频剧情&#xff0c;以及它们之间的时间、顺序和交互。 Playable Director组件具有以下作用&#xff1a; 剧情控…

Vue中使用echarts

1 安装 npm install -g cnpm --registryhttps://registry.npm.taobao.org cnpm install echarts -S 2 main.js引入 3 引入成功

perl 拼接字符串

在Perl中&#xff0c;你可以使用不同的方法来拼接字符串。以下是一些常用的方法&#xff1a; 使用.运算符拼接字符串&#xff1a; my $str1 "Hello, "; my $str2 "World!"; my $result $str1 . $str2; print $result; # 输出&#xff1a;Hello, Worl…

探索Java API学习路线:从基础到高级的全面指南

文章目录 第一阶段&#xff1a;入门基础1. 环境准备2. 学习Java基础 第二阶段&#xff1a;熟悉常用的Java API1. Java标准库2. Java API文档 第三阶段&#xff1a;深入学习特定领域的Java API1. Java GUI API2. Java数据库连接&#xff08;JDBC&#xff09;API3. Java多线程API…

【蓝图】p44简单解密机关

p44简单解密机关 p44简单解密机关文字提示开门文字提示开灯For Each Loop和For Each Loop With Break区别For Each LoopFor Each Loop With Break小操作&#xff1a;改变走线Execute Console Command(执行控制台命令) p44简单解密机关 文字提示开门 创建Actor蓝图类&#xff…

Python及PyCharm安装教程

1.Python安装教程 python官网下载windows64位python installer&#xff1b; 这里选择windows installer(64-bit) 打开下载完成的installer文件 记得勾选上Add python.exe to PATH&#xff0c;再点击Install Now&#xff1b; &#xff08;如果想要更改安装位置&#xff0c;需要…

【使用时空RBF-NN进行非线性系统识别】实现了 RBF、分数 RBF 和时空 RBF 神经网络,用于非线性系统识别研究(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 2.1 算例1 2.2 算例2 &#x1f389;3 参考文献 &#x1f308;4 Matlab代码实现 &#x1f4a5;1 概述 本文用于非线性系统识别任务的径向基函数神经网络&#xff08;RBF-NN&#xff09;的三种变体。特别是&#xff0c;我实现…

MYSQL DCL语句

MySQL DCL语句 简介 DQL是用于查询和检索数据库数据的重要工具。它具有丰富的功能和灵活性&#xff0c;可以根据不同的查询需求进行条件过滤、排序、聚合计算等操作。通过合理使用DQL&#xff0c;可以从数据库中提取有用的数据以进行数据分析和决策支持。 DCL语句的分类 DC…

Swoole协程系统HTTP服务

先启动宝塔 /etc/init.d/bt start 源码参考 https://github.com/zhangyue0503/swoole/tree/main/4.Swoole%E5%8D%8F%E7%A8%8B 对于异步来说&#xff0c;我们需要监听事件&#xff0c;并且监听的进程是并发的&#xff0c;所以会有一个问题&#xff0c;那就是无法保证前后顺…

33.Oracle的Sid重复问题

oracle安装sid重复问题 Oracle卸载后再次安装&#xff0c;设置的SID相同出现“指定的SID在本机上已经存在。请指定一个不同的SID。” 1. SID简介 SID也就是安全标识符&#xff08;Security Identifiers&#xff09;&#xff0c;是标识用户、组和计算机帐户的唯一的号码。在第…

redis到底几个线程?

通常我们说redis是单线程指的是从接收客户端请求->解析请求->读写->响应客户端这整个过程是由一个线程来完成的。这并不意味着redis在任何场景、任何版本下都只有一个线程 为何用单线程处理数据读写&#xff1f; 内存数据储存已经很快了 redis相比于mysql等数据库是…

宋浩高等数学笔记(八)向量代数与空间解析几何

本章知识点并不难理解&#xff0c;但是公式与名词属于非常多&#xff0c;记忆时需重点对待。