【ESP8266】ESP8266_NONOS_SDK开发包生成的镜像文件构建步骤分析
2016-05-11 15:50
483 查看
ESP8266有官方提供的软件开发包。下面是对该开发包ESP8266_NONOS_SDK生成的镜像文件构建步骤分析。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201605/b96f6e7f64c3645940b7984c0182142f)
User
Data区域:当程序(flash.bin和irom0text.bin)未占满整个空间时,空闲区域均可用于存放用户数据。
上图irom0text.bin默认最大为200KB;ESP8266目前程序最大支持1024 KB,因此对于4096 KB Flash,用户可修改编译,使其最大支持到 1024 - 256 = 768 KB。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201605/70a3f2e538baf0c38d3306cba5137ba7)
ld文件夹的eagle.app.v6.ld文件,其中irom0_0_seg的len为设置irom0text.bin上限值。对于4096 KB Flash,此len最大可修改为0xC0000,irom0text.bin最大支持到 768 KB。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201605/41b7b27d15152b50ccfd4039a09b96b0)
题外话:编译官方的AT固件时,如果出现irom0_0seg的报错信息,可能就是因为irom0_0seg的大小空间不够,增大irom0_0seg的len就好。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201605/ad6f54d0cf1fa54edc30bdbd658f1368)
23~27行:
BOOT?=none
APP?=0
SPI_SPEED?=40
SPI_MODE?=QIO
SPI_SIZE_MAP?=0
说明:Makefile已经默认配置好了的选项
131行:
LD_FILE = $(LDDIR)/eagle.app.v6.ld
说明:使用的链接文件是\esp_iot_sdk\ld\eagle.app.v6.ld
238~240行:
@$(RM) -r ../bin/eagle.S ../bin/eagle.dump
@$(OBJDUMP) -x -s $< > ../bin/eagle.dump
@$(OBJDUMP) -S $< > ../bin/eagle.S
说明:sdk编译过程中会先生成eagle.app.v6.out,然后dump出段信息和符号文件。下面用一小节介绍一下生成ELF文件的步骤:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201605/81ad5508097f1ad9a09a75b1fe964896)
从bin\eagle.dump中摘取部分有有用的信息,为了方便阅读,转换为表格格式。
Sections:
结合ld文件的memory信息(本文第一节有图片)可以看到
.data的LMA(Load Memory Address,装载内存地址)为3ffe8000,正好是dram0_0_seg的org;
.rodata的LMA为3ffe8b40,.bss是3ffe98b0,在dram0_0_seg的大小内;
.text是40100000,正好对应iram1_0_seg;
.irom0.text是40240000,正好对应irom0_0_seg;
因此,data、rodata、bbs段都是放到dram0_0_seg中,text段是放到iram1_0_seg中,.irom0.text段是放到irom0_0_seg中。
由于iram1_0_seg大小为0x8000,即32KB,因此,程序段(.text)不能超过32KB;同理,数据段(.data+.rodata)不能超过0x14000,即80KB。
第248到251行:
@$(OBJCOPY) --only-section .text -O binary $< eagle.app.v6.text.bin
@$(OBJCOPY) --only-section .data -O binary $< eagle.app.v6.data.bin
@$(OBJCOPY) --only-section .rodata -O binary $< eagle.app.v6.rodata.bin
@$(OBJCOPY) --only-section .irom0.text -O binary $< eagle.app.v6.irom0text.bin
说明:Makefile将以上各个section copy成单个文件。
257行:
@python ../tools/gen_appbin.py $< 0 $(mode) $(freqdiv) $(size_map) $(app)
说明:使用tools/gen_appbin.py脚本文件将eagle.app.v6.text.bin、eagle.app.v6.data.bin和eagle.app.v6.rodata.bin三个文件打包成一个eagle.app.flash.bin。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201605/aca10c498ea7c0f24402cf9ac6f76d90)
在toos/gen_appbin.py脚本文件中,需要给之各项参数,由
@python
../tools/gen_appbin.py $< 0 $(mode) $(freqdiv) $(size_map) $(app)
这条语句可知给了什么参数,源文件如下(121~126行):
elf_file = sys.argv[1]# < eagle.app.v6.out
boot_mode = sys.argv[2] # < 0
flash_mode = sys.argv[3] # < mode=0
flash_clk_div = sys.argv[4] # < freqdiv=0
flash_size_map = sys.argv[5] # < size_map=0
user_bin = sys.argv[6] # < app=0
之后使用nm -g eagle.app.v6.out产生eagle.app.sym文件,并在sym文件中找出section地址和入口地址。
(cmd = 'xt-nm -g ' + elf_file + ' > eagle.app.sym')
最后按照如下格式打包成eagle.app.flash.bin。(代码略)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201605/b9cda962ca2d5b02d7056a3a8a9a77a7)
HEAD0 = BIN_MAGIC_FLASH
HEAD1 = 3
HEAD2 = flash_mode
HEAD3 = flash_size_map<<4 | flash_clk_div
ENTRY = entry_addr 入口地址
TEXTADDR = TEXT_ADDRESS
TEXTLEN = eagle.app.v6.text.bin的文件长度4字节对齐
TEXT = eagle.app.v6.text.bin 的数据,4字节对齐,最后不对齐的补0
DATAADDR = data_start_addr
DATALEN = eagle.app.v6.data.bin的文件长度4字节对齐
DATA = eagle.app.v6.data.bin 的数据,4字节对齐,最后不对齐的补0
RODATAADDR = data_start_addr
RODATALEN = eagle.app.v6.rodata.bin的文件长度4字节对齐
RODATA = eagle.app.v6.rodata.bin 的数据,4字节对齐,最后不对齐的补0
ALIGMENT = 对齐数据,保证sum前的数据16字节对齐,不对齐这里补0
CHKSUM = eagle.app.flash.bin的校验和
@mv eagle.app.flash.bin ../bin/eagle.flash.bin
@mv eagle.app.v6.irom0text.bin ../bin/eagle.irom0text.bin
说明:最后两个mv指令是把生成的两个bin文件,改成相应的名字并移动到esp_iot_sdk/bin/目录下。
自此,整个Makefile执行结束,生成eagle.flash.bin和eagle.irom0text.bin文件。
2、片上ROM读取SPI Flash 0x00000处的flash.bin,并解析出text、data、rodata在内存中的位置,并将这3部分加载到片上内存中
- text会加载到iram1上,因此text最大不能超过32KB(0x8000);(解决方法参见注意事项和建议的第一条)
- data和rodata加载到dram0上,因此这二者和不能大于80KB(0x14000);
- 在dram0上还有bbs、stack、heap,要注意使用量。以IoT_Demo固件来看:data+rodata+bbs = 0xb34+0xd70+0x6cd0 = 0x8574,因此stack和heap能用的内存只有46K左右(0x14000-0x8574),如果是空白的固件,则大约有50KB左右;
3、片上固化rom加载flash.bin完毕后跳到入口地址entry_addr处执行;
4、当执行到irom1上的代码时(通过ICACHE_FLASH_ATTR定义的函数),会将它们从SPI Flash上加载到cache中运行;
运行;
没有标注的会放在iram1里面,iram1大小只有32KB,IoT_Demo固件使用了大约27KB,还剩下5KB,而irom0最大支持768KB。所以如果自己用SDK开发,请尽量给函数都标注该宏,不然会出现内存不够用的错误信息:「.output/eagle/debug/image/eagle.app.v6.out
section `.text' will not fit in region `iram1_0_seg'」
2、不要在GPIO或UART中断处理函数中调用带有「ICACHE_FLASH_ATTR」宏的函数,否则可能会进入异常导致重启。
3、上电时会以串口波特率76800bps(和晶振有关)打印「ets Jan 8 2013,rst cause:2, boot mode:(1,7)」等信息,这一上电信息是保存在片上固化ROM的,无法屏蔽。
参考资料:
1、esp8266 rtos sdk编译后flash镜像构成
2、[Resolved]section `.text' will not fit in region `iram1_0_seg' 编译出错,怎么调整段空间划分
一、Flash布局
首先参考官方提供编号为2A的文档,对于4MB(32Mbit) SPI Flash,其布局如下:User
Data区域:当程序(flash.bin和irom0text.bin)未占满整个空间时,空闲区域均可用于存放用户数据。
上图irom0text.bin默认最大为200KB;ESP8266目前程序最大支持1024 KB,因此对于4096 KB Flash,用户可修改编译,使其最大支持到 1024 - 256 = 768 KB。
ld文件夹的eagle.app.v6.ld文件,其中irom0_0_seg的len为设置irom0text.bin上限值。对于4096 KB Flash,此len最大可修改为0xC0000,irom0text.bin最大支持到 768 KB。
题外话:编译官方的AT固件时,如果出现irom0_0seg的报错信息,可能就是因为irom0_0seg的大小空间不够,增大irom0_0seg的len就好。
二、Makefile
这里简单分析一下主目录里的Makefile内容:23~27行:
BOOT?=none
APP?=0
SPI_SPEED?=40
SPI_MODE?=QIO
SPI_SIZE_MAP?=0
说明:Makefile已经默认配置好了的选项
131行:
LD_FILE = $(LDDIR)/eagle.app.v6.ld
说明:使用的链接文件是\esp_iot_sdk\ld\eagle.app.v6.ld
238~240行:
@$(RM) -r ../bin/eagle.S ../bin/eagle.dump
@$(OBJDUMP) -x -s $< > ../bin/eagle.dump
@$(OBJDUMP) -S $< > ../bin/eagle.S
说明:sdk编译过程中会先生成eagle.app.v6.out,然后dump出段信息和符号文件。下面用一小节介绍一下生成ELF文件的步骤:
生成ELF文件
从bin\eagle.dump中摘取部分有有用的信息,为了方便阅读,转换为表格格式。
Sections:
Idx | Name | Size | VMA | LMA | File off | Algn |
0 | .data | 00000b34 | 3ffe8000 | 3ffe8000 | 000000e0 | 2**4 |
1 | .rodata | 00000d70 | 3ffe8b40 | 3ffe8b40 | 00000c20 | 2**4 |
2 | .bss | 00006cd0 | 3ffe98b0 | 3ffe98b0 | 00001990 | 2**4 |
3 | .text | 00006d6e | 40100000 | 40100000 | 00001990 | 2**2 |
4 | .irom0.text | 00033230 | 40240000 | 40240000 | 00008700 | 2**4 |
.data的LMA(Load Memory Address,装载内存地址)为3ffe8000,正好是dram0_0_seg的org;
.rodata的LMA为3ffe8b40,.bss是3ffe98b0,在dram0_0_seg的大小内;
.text是40100000,正好对应iram1_0_seg;
.irom0.text是40240000,正好对应irom0_0_seg;
因此,data、rodata、bbs段都是放到dram0_0_seg中,text段是放到iram1_0_seg中,.irom0.text段是放到irom0_0_seg中。
由于iram1_0_seg大小为0x8000,即32KB,因此,程序段(.text)不能超过32KB;同理,数据段(.data+.rodata)不能超过0x14000,即80KB。
将ELF文件转化为烧写镜像
下面回到对Makefile的分析。第248到251行:
@$(OBJCOPY) --only-section .text -O binary $< eagle.app.v6.text.bin
@$(OBJCOPY) --only-section .data -O binary $< eagle.app.v6.data.bin
@$(OBJCOPY) --only-section .rodata -O binary $< eagle.app.v6.rodata.bin
@$(OBJCOPY) --only-section .irom0.text -O binary $< eagle.app.v6.irom0text.bin
说明:Makefile将以上各个section copy成单个文件。
257行:
@python ../tools/gen_appbin.py $< 0 $(mode) $(freqdiv) $(size_map) $(app)
说明:使用tools/gen_appbin.py脚本文件将eagle.app.v6.text.bin、eagle.app.v6.data.bin和eagle.app.v6.rodata.bin三个文件打包成一个eagle.app.flash.bin。
打包过程简要
在toos/gen_appbin.py脚本文件中,需要给之各项参数,由
@python
../tools/gen_appbin.py $< 0 $(mode) $(freqdiv) $(size_map) $(app)
这条语句可知给了什么参数,源文件如下(121~126行):
elf_file = sys.argv[1]# < eagle.app.v6.out
boot_mode = sys.argv[2] # < 0
flash_mode = sys.argv[3] # < mode=0
flash_clk_div = sys.argv[4] # < freqdiv=0
flash_size_map = sys.argv[5] # < size_map=0
user_bin = sys.argv[6] # < app=0
之后使用nm -g eagle.app.v6.out产生eagle.app.sym文件,并在sym文件中找出section地址和入口地址。
(cmd = 'xt-nm -g ' + elf_file + ' > eagle.app.sym')
最后按照如下格式打包成eagle.app.flash.bin。(代码略)
HEAD0 = BIN_MAGIC_FLASH
HEAD1 = 3
HEAD2 = flash_mode
HEAD3 = flash_size_map<<4 | flash_clk_div
ENTRY = entry_addr 入口地址
TEXTADDR = TEXT_ADDRESS
TEXTLEN = eagle.app.v6.text.bin的文件长度4字节对齐
TEXT = eagle.app.v6.text.bin 的数据,4字节对齐,最后不对齐的补0
DATAADDR = data_start_addr
DATALEN = eagle.app.v6.data.bin的文件长度4字节对齐
DATA = eagle.app.v6.data.bin 的数据,4字节对齐,最后不对齐的补0
RODATAADDR = data_start_addr
RODATALEN = eagle.app.v6.rodata.bin的文件长度4字节对齐
RODATA = eagle.app.v6.rodata.bin 的数据,4字节对齐,最后不对齐的补0
ALIGMENT = 对齐数据,保证sum前的数据16字节对齐,不对齐这里补0
CHKSUM = eagle.app.flash.bin的校验和
其他
回到Makefile,258~259行:@mv eagle.app.flash.bin ../bin/eagle.flash.bin
@mv eagle.app.v6.irom0text.bin ../bin/eagle.irom0text.bin
说明:最后两个mv指令是把生成的两个bin文件,改成相应的名字并移动到esp_iot_sdk/bin/目录下。
自此,整个Makefile执行结束,生成eagle.flash.bin和eagle.irom0text.bin文件。
三、启动运行过程
1、芯片上电后会先运行片上的ROM,完成必要初始化;2、片上ROM读取SPI Flash 0x00000处的flash.bin,并解析出text、data、rodata在内存中的位置,并将这3部分加载到片上内存中
- text会加载到iram1上,因此text最大不能超过32KB(0x8000);(解决方法参见注意事项和建议的第一条)
- data和rodata加载到dram0上,因此这二者和不能大于80KB(0x14000);
- 在dram0上还有bbs、stack、heap,要注意使用量。以IoT_Demo固件来看:data+rodata+bbs = 0xb34+0xd70+0x6cd0 = 0x8574,因此stack和heap能用的内存只有46K左右(0x14000-0x8574),如果是空白的固件,则大约有50KB左右;
3、片上固化rom加载flash.bin完毕后跳到入口地址entry_addr处执行;
4、当执行到irom1上的代码时(通过ICACHE_FLASH_ATTR定义的函数),会将它们从SPI Flash上加载到cache中运行;
四、注意事项和建议
1、标注「ICACHE_FLASH_ATTR」宏的函数存储在irom0里面(Flash里面),表示将其存放在Flash中,仅调用时才加载到cache运行;
没有标注的会放在iram1里面,iram1大小只有32KB,IoT_Demo固件使用了大约27KB,还剩下5KB,而irom0最大支持768KB。所以如果自己用SDK开发,请尽量给函数都标注该宏,不然会出现内存不够用的错误信息:「.output/eagle/debug/image/eagle.app.v6.out
section `.text' will not fit in region `iram1_0_seg'」
2、不要在GPIO或UART中断处理函数中调用带有「ICACHE_FLASH_ATTR」宏的函数,否则可能会进入异常导致重启。
3、上电时会以串口波特率76800bps(和晶振有关)打印「ets Jan 8 2013,rst cause:2, boot mode:(1,7)」等信息,这一上电信息是保存在片上固化ROM的,无法屏蔽。
参考资料:
1、esp8266 rtos sdk编译后flash镜像构成
2、[Resolved]section `.text' will not fit in region `iram1_0_seg' 编译出错,怎么调整段空间划分
相关文章推荐
- 给hexo个人博客 next主题添加背景图片
- atoi()
- Eclipse 注释模板
- Mysql 中间件 oneProxy总结
- 1、hadoop环境搭建
- Android--高德地图自动定位
- 推送服务
- ios开发开发之:关于时间戳转化成时间
- VR设备介绍
- ehcache memcache redis -- java中的三大缓存
- 我的书单mybooklist
- PHP 安装 redis、memcached、openssl、pdo_mysql等
- sqlDevelopor客户端操作MySQL数据库
- gitlab怎么删除创建的项目
- 关于C语言调用Unity3d C#函数的方法
- stm32F4学习笔记序言
- Levmar使用小结(一)
- iOS GCD的使用
- 微信浏览器禁止页面下拉查看网址
- MySQL5.6 GTID方式,配置主从