esp8266 rtos sdk编译后flash镜像构成的方法是什么
这篇文章主要介绍"esp8266 rtos sdk编译后flash镜像构成的方法是什么",在日常操作中,相信很多人在esp8266 rtos sdk编译后flash镜像构成的方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"esp8266 rtos sdk编译后flash镜像构成的方法是什么"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
由于官方文件没有说明esp8266的启动特点,本文根据sdk内的flash map文档,sdk makefile, ld文件及flash image 生成的python脚本文件,简要分析esp8266的启动和运行,及flash镜像的构成特点。这里使用的sdk和编译时配置项见esp8266 rtos sdk在小黄板上的使用
##sdk生成的elf文件 这里主要分析sdk根目录下的makefile文件就可以得到elf相关信息。
在执行make前我们已经选择好编译的配置项,这里直接给出:
boot=none
app=0
freqdiv=0
mode=0
size_map=4
flash=4096
从makefile内可以分析到使用的ld文件是:
LD_FILE = $(LDDIR)/eagle.app.v6.ld
eagle.app.v6.ld可以看到
MEMORY{ dport0_0_seg : org = 0x3FF00000, len = 0x10 dram0_0_seg : org = 0x3FFE8000, len = 0x14000 iram1_0_seg : org = 0x40100000, len = 0x8000 irom0_0_seg : org = 0x40240000, len = 0x3C000}
sdk编译过程中会先生成eagle.app.v6.out,然后dump出段信息和符号文件
@$(RM) -r ../bin/eagle.S ../bin/eagle.dump@$(OBJDUMP) -x -s $< > ../bin/eagle.dump@$(OBJDUMP) -S $< > ../bin/eagle.S
从eagle.dump中可以找到对实际运行有效的5个section:
Idx Name Size VMA LMA File off Algn 0 .data 00000634 3ffe8000 3ffe8000 000000e0 2**4 1 .rodata 000008b0 3ffe8640 3ffe8640 00000720 2**4 2 .bss 00006bc8 3ffe8ef0 3ffe8ef0 00000fd0 2**4 3 .text 0000776a 40100000 40100000 00000fd0 2**2 4 .irom0.text 00030928 40240000 40240000 00008740 2**4
结合ld文件的memory信息可以看到 .data, .rodata, .bbs都是放到dram0_0_seg中,.text是放到iram1_0_seg中,.irom0.text是放到irom0_0_seg中。
##将elf文件转化为烧写镜像 ###makefile将以上各section copy成单个文件
$(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
###将section打包 然后使用gen_appbin.py脚本将eagle.app.v6.text.bin,eagle.app.v6.data.bin,eagle.app.v6.rodata.bin三个文件打包成一个eagle.app.flash.bin, 命令为:
python ../tools/gen_appbin.py $< 0 $(mode) $(freqdiv) $(size_map)
这里直接给出gen_appbin.py的各项参数
elf_file = sys.argv[1] >eagle.app.v6.outboot_mode = sys.argv[2] >0flash_mode = sys.argv[3] >0flash_clk_div = sys.argv[4] >0flash_size_map = sys.argv[5] >4BIN_MAGIC_IROM = 0xEATEXT_ADDRESS = 0x40100000
打包过程简要:
通过nm -g eagle.app.v6.out 产生eagle.app.sym,在sym文件中找出section地址和入口地址
call_user_start --> entry_addr >40100004 入口地址_data_start --> data_start_addr >3ffe8000 .data段开始地址_rodata_start --> rodata_start_addr >3ffe8640 .rodata段开始地址
按照如下格式打包成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.data.bin的文件长度4字节对齐
RODATA = eagle.app.v6.data.bin 的数据,4字节对齐,最后不对齐的补0
ALIGMENT = 对齐数据,保证sum前的数据16字节对齐,不对齐这里补0
CHKSUM = eagle.app.flash.bin的校验和
将生成的文件重命名为要烧写到flash的镜像名 @mv eagle.app.flash.bin ../bin/eagle.flash.bin @mv eagle.app.v6.irom0text.bin ../bin/eagle.irom0text.bin
##FLASH MAP 在数据下载后会写到SPI Flash内: eagle.flash.bin下载到0x00000处 eagle.irom0text.bin下载到0x40000处
##irom说明 从前面可以看.text放到idram0中执行,但指令内存空间有限32K,所以在C代码中,使用ICACHE_FLASH_ATTR定义的函数将会放到irom0内,最后也就是放到了eagle.irom0text.bin,被放到SPI flash上的0x40000处。
#define ICACHE_FLASH_ATTR __attribute__((section(".irom0.text")))
##启动和运行 现在可以来猜启动和运行的过程了:
芯片上电后会先运行片上的ROM,完成必要初始化
片上ROM读取SPI Flash 0x00000处的flash.bin,并解析出text,data,rodata在内存中的位置,并将这3部分加载到片上内存中
text加载到iram1上,因此text最大不能操过32K(0x8000), 可见内存加载的代码有限
data和rodata加载到dram0上,因此这二者和不能大于80K(0x14000)
在dram0上还有bbs,stack,heap,要注意使用量,在目前的状况下:data+rodata+bbs = 634+8b0+6bc8 = 7AAC,因此stack和heap能用的内存只有50K左右(0x14000-0x7AAC)
片上固化rom加载flash.bin完毕后跳到入口地址entry_addr处执行
当执行到irom1上的代码时(通过ICACHE_FLASH_ATTR定义的函数),会将它们从SPI Flash上读到 cache 中运行。**注意:**不要在 GPIO 或 UART 中断处理函数中调用带有 "ICACHE_FLASH_ATTR" 宏的函数,否则将进入异常。
由于片上ROM我们不能更改,因此编写代码时要遵循FLASH MAP地址和大小。
到此,关于"esp8266 rtos sdk编译后flash镜像构成的方法是什么"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!