在得到一份代码后我们最先应当了解一下它的目录结构,这里用ESP8266_RTOS_SDK_V1.5.0为例:

app:用户代码主目录,用户代码都将放在这里
bin :编译生成和SDK提供的bin文件,用于下载到Flash中
driver_lib : RTOS驱动示例代码
examples:示例代码
extra_include:Xtensa编译器头文件(使用XCC编译时使用,一般用GCC)
include:SDK头文件(包含可用的 API函数和相关的宏定义)
ld:链接时所需的脚本文件,如无特殊需求无需修改
lib:SDK的库文件
third_party:第三方开源库(源码),编译后会放到lib目录
tools:编译bin文件所需的工具,无需修改
Makefile:编译入口脚本(执行make时所执行的文件)
bin文件
文件列表 是否必选 说明 Non-FOTA FOTA
master_device_key.bin 可选 乐鑫云服务,在Espressif Cloud申请 ☑ ☑
esp_init_data_default.bin 必选 初始化射频参数,SDK提供 ☑ ☑
blank.bin 必选 初始化系统参数,SDK提供 ☑ ☑
eagle.flash.bin 必选 主程序,编译生成(app=0) ☑ ❌
eagle.irom0text.bin 必选 主程序,编译生成(app=0) ☑ ❌
user1.bin 初次必选 主程序,编译生成(app=1) ❌ ☑
user2.bin FOTA升级 主程序,编译生成(app=2) ❌ ☑
(文件名不一定相同)
注:user1.bin和user2.bin实际上除了烧录位置不同其它是几乎是一样的,因为在线升级时没有数据缓存位置,所以下载的数据是直接写入flash的,但又不能覆盖当前程序(否则升级一半掉电就无法开机了),所以user1.bin程序FOTA升级使用user2.bin,user2.bin程序FOTA升级使用user1.bin。第一次烧录使用user1.bin。

Flash布局
以下为Flash使用布局,可以根据需要进行修改,这里大致了解一下就可以。

Flash布局
系统程序:程序固件
用户数据:未使用的Flash部分可以给用户自行存储用户数据
用户参数:地址可自定义,IOT_Demo设置为0x3C000开始的4个扇区(master_device_key.bin放在第三个扇区)
系统参数:固定为Flash最后的4个扇区(blank.bin放在倒数第2、1扇区,esp_init_data_default.bin放在倒数第4、3扇区)
Boot信息:FOTA升级相关信息
预留:与Boot信息区对应的预留部分
注:一个扇区为4kb(Byte)
编译过程
如果要了解一个工程的结构,那么从工程的编译来看是最为深刻的,那么了解这个编译过程有什么用?老实说,并没有什么卵用。那为什么还要写这部分?因为我就想把文章写的长一点,啊哈哈哈哈。。。

入口脚本
看过官方的文档都知道,我们编译项目是要进入app这个目录然后执行gen_misc.bat这个文件(Linux下是gen_misc.sh)来编译的,那么我们就从这个文件下刀吧:

@echo off

Rem NOTICE
Rem MUST set SDK_PATH & BIN_PATH firstly!!!
Rem example:
Rem set SDK_PATH=/c/esp_iot_sdk_freertos
Rem set BIN_PATH=/c/esp8266_bin

set SDK_PATH=/c/ESP8266_RTOS_SDK
set BIN_PATH=/c/ESP8266_BIN

echo gen_misc.bat version 20150911
echo .

if not %SDK_PATH% == “” (
echo SDK_PATH: %SDK_PATH%
) else (
echo ERROR: Please set SDK_PATH in gen_misc.bat firstly, exit!!!
goto end
)

if not %BIN_PATH% == “” (
echo BIN_PATH: %BIN_PATH%
) else (
echo ERROR: Please set BIN_PATH in gen_misc.bat firstly, exit!!!
goto end
)

echo .
echo Please check SDK_PATH/BIN_PATH, enter (Y/y) to continue:
set input=default
set /p input=

if not %input% == Y (
if not %input% == y (
goto end
)
)
文件开头这部分,很简单,这里设置SDK_PATH和BIN_PATH两个变量(官方文档也会叫你先改这两个值后在编译),如果没设置就报错,结束编译。什么?你问我Rem是什么意思?那只是注释啦(好学的孩子可以出门左拐看看windows批处理,这里就简单带过了)。

echo .
echo Please follow below steps(1-5) to generate specific bin(s):
echo STEP 1: use boot_v1.2+ by default
set boot=new

echo boot mode: %boot%
echo.

echo STEP 2: choose bin generate(0=eagle.flash.bin+eagle.irom0text.bin, 1=user1.bin, 2=user2.bin)
set input=default
set /p input=enter (0/1/2, default 0):

-----------------------------------这里省略部分代码---------------------------------------

echo.
echo start…
echo.
这部分有点长,中间略写了,就是分5步用选择的方式定义了boot、app、spi_speed、spi_mode和spi_size_map这五个变量。

make clean

make COMPILE=xcc BOOT=%boot% APP=%app% SPI_SPEED=%spi_speed% SPI_MODE=%spi_mode% SPI_SIZE_MAP=%spi_size_map%

:end
看结尾这部分,首先先执行了make clean清除构建,然后进行make编译,把上面五个变量传递进去,make执行的即当前目录下的Makefile文件。
啥?你说:end又是啥?这还是一个注释啦,啊哈哈哈哈哈哈哈哈
最后这一小部分则是这个文件最关键的,给后面make操作提供了参数(COMPILE、BOOT、APP、SPI_SPEED、SPI_MODE和SPI_SIZE_MAP)。gen_misc.sh类似区别在于使用的脚本语音不同,最后参数就COMPILE不一样(用于选择编译器的)。

入口Makefile
看Makefile可以对照《跟我一起写Makefile》或者我的一起来看神奇的Makefile

TARGET = eagle
#FLAVOR = release
FLAVOR = debug

#EXTRA_CCFLAGS += -u
parent_dir:=$(abspath ( s h e l l p w d ) / (shell pwd)/ (shellpwd)/(lastword ( M A K E F I L E L I S T ) ) ) p a r e n t d i r : = (MAKEFILE_LIST))) parent_dir:= (MAKEFILEL​IST)))parentd​ir:=(shell dirname ( p a r e n t d i r ) ) p a r e n t d i r : = (parent_dir)) parent_dir:= (parentd​ir))parentd​ir:=(shell dirname $(parent_dir))

SDK_PATH= ( p a r e n t d i r ) B I N P A T H = (parent_dir) BIN_PATH= (parentd​ir)BINP​ATH=(SDK_PATH)/bin
开头定义了两个变量TARGET和FLAVOR表示编译的目标和版本,接下来的parent_dir比较有意思,从字面上看是父路径的意思,猜测就是当前的上一级也就是工程根目录,但这里采用了一个很复杂的方式取得:先从MAKEFILE_LIST取最后一个词(也就是当前Makefile的文件名),加上pwd取得当前路径,然后再取绝对路径。而后又连续取两次目录名(去掉两级路径)也就是当前目录的上一级,可绕脑了,这是想让看Makefile的小朋友望而怯步吗。。。
接下来主要的还是定义SDK_PATH和BIN_PATH两个目录(工程根目录和bin目录)

ifndef PDIR # {
GEN_IMAGES= eagle.app.v6.out
GEN_BINS= eagle.app.v6.bin
SPECIAL_MKTARGETS=$(APP_MKTARGETS)
SUBDIRS=
user
driver

endif # } PDIR
这里PDIR没有定义,为什么?因为我们一路看下来并没有发现哪里有定义啊!
这里定义了SUBDIRS变量,记住它。

LDDIR = $(SDK_PATH)/ld

CCFLAGS += -Os

TARGET_LDFLAGS =
-nostdlib
-Wl,-EL
–longcalls
–text-section-literals

ifeq ($(FLAVOR),debug)
TARGET_LDFLAGS += -g -O2
endif

ifeq ($(FLAVOR),release)
TARGET_LDFLAGS += -g -O0
endif
定义了几个变量LDDIR(ld文件目录)、CCFLAGS(编译参数)和TARGET_LDFLAGS(链接参数),这里上面定义的FLAVOR变量已经使用上了。

COMPONENTS_eagle.app.v6 =
user/libuser.a
driver/libdriver.a

LINKFLAGS_eagle.app.v6 =
-LKaTeX parse error: Expected 'EOF', got '#' at position 24: …H)/lib \ #̲ 定义链接库的搜索路径是 SD…(LD_FILE) \ # 读取链接描述脚本,以确定符号等的定位地址
-Wl,–no-check-sections \ # Do not check section addresses for overlaps 不检查重叠地址
-u call_user_start \ # 取消定义的宏(call_user_start)
-Wl,-static \ # 使用静态链接
-Wl,–start-group \ #库列表开始
-lcirom
-lcrypto
-lespconn
-lespnow
-lfreertos
-lgcc
-lhal
-ljson
-llwip
-lmain
-lmesh
-lmirom
-lnet80211
-lnopoll
-lphy
-lpp
-lpwm
-lsmartconfig
-lspiffs
-lssl
-lwpa
-lwps
$(DEP_LIBS_eagle.app.v6)
-Wl,–end-group # 库列表结束

DEPENDS_eagle.app.v6 =
$(LD_FILE)
$(LDDIR)/eagle.rom.addr.v6.ld
定义三个变量COMPONENTS_eagle.app.v6(需要生成的目标)、LINKFLAGS_eagle.app.v6(链接库)和DEPENDS_eagle.app.v6(ld文件)。LINKFLAGS_eagle.app.v6中-Wl,–start-group前面的为链接参数和-Wl,–end-group间为链接库,可以根据需要进行删减。

CONFIGURATION_DEFINES = -DICACHE_FLASH

DEFINES +=
$(UNIVERSAL_TARGET_DEFINES)
$(CONFIGURATION_DEFINES)

DDEFINES +=
$(UNIVERSAL_TARGET_DEFINES)
$(CONFIGURATION_DEFINES)
定义DEFINES和DDEFINES,给编译用。两个值都是"-DICACHE_FLASH"具体做啥用我也不清楚,字面上看应该是Flash的cache缓存相关的。

INCLUDES := $(INCLUDES) -I $(PDIR)include
sinclude $(SDK_PATH)/Makefile

.PHONY: FORCE
FORCE:
最后给INCLUDES添加了"include"目录然后调用根目录的Makefile文件(这里只是展开文件并没有切换目录,还是在app目录下执行),最后两行是定义了一个FORCE的伪目标,啥都没做。
这里只要记住这个Makefile文件定义了SUBDIRS、COMPONENTS_eagle.app.v6、LINKFLAGS_eagle.app.v6和DEPENDS_eagle.app.v6这几个变量即可。

主Makefile
这个文件是主要的编译文件,主要是具体的编译,比较长,这里只取较为关键的部分。

ifeq ($(COMPILE), xcc)
AR = xt-ar
CC = xt-xcc
NM = xt-nm
CPP = xt-xt++
OBJCOPY = xt-objcopy
OBJDUMP = xt-objdump
else
AR = xtensa-lx106-elf-ar
CC = xtensa-lx106-elf-gcc
NM = xtensa-lx106-elf-nm
CPP = xtensa-lx106-elf-g++
OBJCOPY = xtensa-lx106-elf-objcopy
OBJDUMP = xtensa-lx106-elf-objdump
endif
根据COMPILE选择编译器,从开头的脚本克制Windows使用xcc,Linux使用gcc。实际测试在windows下使用gcc也似乎并没有问题。

BOOT?=new
APP?=1
SPI_SPEED?=40
SPI_MODE?=QIO
SPI_SIZE_MAP?=2
设置参数的默认值,这里说一下上一节我们编译机智云的工程为啥使用不一样的方式,原因就是机智云的工程里这里的默认值是不一样的,我们直接使用了make而没有传入参数,所以会导致编辑结果不一样,事实上也无需关心这部分,我们只要给它传参就可以了,开篇只是作为验证编译器是否正常而已。
后续一百多行的脚本根据这几个变量定义了boot、app、freqdiv、mode、addr、size_map、flash、LD_FILE以及BIN_NAME,比较简单这里不赘述。

CSRCS ?= $(wildcard *.c) # $(wildcard xxx)这个意思是在当前目录下使用通配符列出所有文件
CPPSRCS ?= $(wildcard *.cpp)
ASRCs ?= $(wildcard *.s)
ASRCS ?= $(wildcard *.S)
SUBDIRS ?= ( p a t s u b s t (patsubst %/,%, (patsubst(dir $(wildcard */Makefile)))

ODIR := .output
OBJODIR := ( O D I R ) / (ODIR)/ (ODIR)/(TARGET)/$(FLAVOR)/obj

OBJS := ( C S R C S : (CSRCS:%.c= (CSRCS:(OBJODIR)/%.o)
( C P P S R C S : (CPPSRCS:%.cpp= (CPPSRCS:(OBJODIR)/%.o)
( A S R C s : (ASRCs:%.s= (ASRCs:(OBJODIR)/%.o)
( A S R C S : (ASRCS:%.S= (ASRCS:(OBJODIR)/%.o)

DEPS := ( C S R C S : (CSRCS:%.c= (CSRCS:(OBJODIR)/%.d)
( C P P S R C S : (CPPSRCS:%.cpp= (CPPSRCS:(OBJODIR)/%.d)
( A S R C s : (ASRCs:%.s= (ASRCs:(OBJODIR)/%.d)
( A S R C S : (ASRCS:%.S= (ASRCS:(OBJODIR)/%.d)

LIBODIR := ( O D I R ) / (ODIR)/ (ODIR)/(TARGET)/$(FLAVOR)/lib
OLIBS := ( G E N L I B S : (GEN_LIBS:%= (GENL​IBS:(LIBODIR)/%)

IMAGEODIR := ( O D I R ) / (ODIR)/ (ODIR)/(TARGET)/$(FLAVOR)/image
OIMAGES := ( G E N I M A G E S : (GEN_IMAGES:%= (GENI​MAGES:(IMAGEODIR)/%)

BINODIR := ( O D I R ) / (ODIR)/ (ODIR)/(TARGET)/$(FLAVOR)/bin
OBINS := ( G E N B I N S : (GEN_BINS:%= (GENB​INS:(BINODIR)/%)
定义了一些变量,后续会反复使用的一些文件,这里将文件赋值给变量后续操作就方便了比如说编译跟clean就会用到一大堆相同的.o文件。
这里有一个有趣的地方,就是SUBDIRS ?= ( p a t s u b s t (patsubst %/,%, (patsubst(dir $(wildcard */Makefile)))如果你是在app目录进行make,那么app目录下的make文件会定义SUBDIRS,如果在根目录下直接make这个不会定义,然后就会执行这一句,接着就会把app这个目录包含进来,最后编译的时候就会编译到app目录的Makefile定义SUBDIRS最后又会回到这里。
( C S R C S : (CSRCS:%.c= (CSRCS:(OBJODIR)/%.d)意思是把CSRCS中的.c全部替换成$(OBJODIR)/.d具体为什么是这样写的,我只能说:你猜。Makefile真是一个神奇的东西。

CCFLAGS +=
-g
-Wpointer-arith
-Wundef
-Werror
-Wl,-EL
-fno-inline-functions
-nostdlib
-mlongcalls
-mtext-section-literals
-ffunction-sections
-fdata-sections
-fno-builtin-printf

-Wall

CFLAGS = $(CCFLAGS) $(DEFINES) $(EXTRA_CCFLAGS) $(INCLUDES)
DFLAGS = $(CCFLAGS) $(DDEFINES) $(EXTRA_CCFLAGS) $(INCLUDES)
一堆编译参数放到CFLAGS和DFLAGS这两个变量里面。
接下来就是关键的编译部分的代码,这里先跳过编译的代码回头再来看,先看脚本

ifneq ( ( M A K E C M D G O A L S ) , c l e a n ) i f n e q ( (MAKECMDGOALS),clean) ifneq ( (MAKECMDGOALS),clean)ifneq((MAKECMDGOALS),clobber)
ifdef DEPS
sinclude $(DEPS)
endif
endif
endif
这段代码比较典型,MAKECMDGOALS并没有定义,所以会执行sinclude $(DEPS),DEPS根据前面的定义可以知道是当前目录下的源文件(.c .cpp .s)生成的.d,根据.d文件的生成规则可以知道是使用gcc -M编译得到,即对应.o的依赖关系,包括包含的.h(新建a.c文件仅写一个a.h,新建a.h放空,编译后的a.d为.output/eagle/debug/obj/a.o .output/eagle/debug/obj/a.d : a.c a.h),sinclude $(DEPS)就是将这个.d文件展开,意义在于我们写依赖关系的时候我们并不能把源文件里面引用的.h文件都加到依赖关系里面,如果不加进来,那么仅修改.h的不会重新生成.o文件的。
简单一句话就是.c文件中包含的.h发生改变的时候重新生成对应的.o

define ShortcutRule
$(1): .subdirs ( 2 ) / (2)/ (2)/(1)
endef

define MakeLibrary
DEP_LIBS_$(1) = ( f o r e a c h l i b , (foreach lib, (foreachlib,(filter %.a,KaTeX parse error: Got function '$' with no arguments as subscript at position 13: (COMPONENTS_$̲(1))),(dir ( l i b ) ) (lib)) (lib))(LIBODIR)/ ( n o t d i r (notdir (notdir(lib)))
DEP_OBJS_$(1) = ( f o r e a c h o b j , (foreach obj, (foreachobj,(filter %.o,KaTeX parse error: Got function '$' with no arguments as subscript at position 13: (COMPONENTS_$̲(1))),(dir ( o b j ) ) (obj)) (obj))(OBJODIR)/ ( n o t d i r (notdir (notdir(obj)))
KaTeX parse error: Can't use function '$' in math mode at position 11: (LIBODIR)/$̲(1).a: (OBJS) KaTeX parse error: Got function '$' with no arguments as subscript at position 11: (DEP_OBJS_$̲(1)) (DEP_LIBS_$(1)) KaTeX parse error: Got function '$' with no arguments as subscript at position 10: (DEPENDS_$̲(1)) @mkdir…(LIBODIR)
( i f (if (if(filter %.a, ? ) , m k d i r − p ?),mkdir -p ?),mkdir−p(EXTRACT_DIR)$(1))
( i f (if (if(filter %.a, ? ) , c d ?),cd ?),cd(EXTRACT_DIR)
$(1); ( f o r e a c h l i b , (foreach lib, (foreachlib,(filter %.a, ? ) , ?), ?),(AR) xo ( U P E X T R A C T D I R ) / (UP_EXTRACT_DIR)/ (UPE​XTRACTD​IR)/(lib)

ESP8266入门学习(一)相关推荐

  1. RT-Thread Nano入门学习笔记(2)

    RT-Thread系列 Keil模拟器 STM32F103上手指南学习笔记 RT-Thread Studio快速上手 RT-Thread Nano入门学习笔记(1) 项目实战:快速打造一个桌面mini ...

  2. 【STM32F411RE和L610物联网入门学习笔记】

    [STM32F411RE和L610物联网入门学习笔记] 配置MX生成代码并在KEIL中添加串口通信代码: 粗浅的学习文章,仅供参考: 广和通资料群里面的移植示例个人感觉没什么用处:毕竟粗看过去用到了t ...

  3. 入门学习C语言需要使用vc++6.0吗?

    提到VC++便会顺带提一下网上吐槽最多到谭浩强的C语言教材,回顾我以前入门学习C语言到的时候,看的第一本书也是这一本. 这么多年过去了,尽管网上吐槽得很多,但很多大学还是使用这一本教材,还在使用VC+ ...

  4. 【腾讯连连 腾讯物联网入门学习 第3篇】安信可IoT微信小程序全面开源,小程序上实现一键配网+控制+绑定!(源码开放)

    文章目录 一.简介 二.开发指导 2.1 腾讯物联开发平台配置 2.2 微信小程序导入步骤 三.设备开发 3.1 AT直连对接 3.2 SDK二次开发 四.本人开源微信物联网控制 一览表 另外,不要把 ...

  5. python速成要多久2019-8-28_2019最全Python入门学习路线,不是我吹,绝对是最全

    近几年Python的受欢迎程度可谓是扶摇直上,当然了学习的人也是愈来愈多.一些学习Python的小白在学习初期,总希望能够得到一份Python学习路线图,小编经过多方汇总为大家汇总了一份Python学 ...

  6. MAYA 2022基础入门学习教程

    流派:电子学习| MP4 |视频:h264,1280×720 |音频:AAC,48.0 KHz 语言:英语+中英文字幕(根据原英文字幕机译更准确)|大小解压后:3.41 GB |时长:4.5小时 包含 ...

  7. 3dmax Vray建筑可视化入门学习教程

    面向初学者的3Ds Max Vray最佳Archviz可视化课程 从安装到最终图像的一切都将从头开始教授,不需要任何经验 大小解压后:3.25G 时长4h 6m 1280X720 MP4 语言:英语+ ...

  8. Blender 3.0基础入门学习教程 Introduction to Blender 3.0

    成为Blender通才,通过这个基于项目的循序渐进课程学习所有主题的基础知识. 你会学到什么 教程获取:Blender 3.0基础入门学习教程 Introduction to Blender 3.0- ...

  9. Maya游戏角色绑定入门学习教程 Game Character Rigging for Beginners in Maya

    准备好开始为游戏制作自己的角色动画了吗? 你会学到什么 了解Maya的界面 优化并准备好你的模型,为游戏做准备 了解关节以及如何使用它们来构建健壮的角色骨骼,以便在任何游戏引擎中制作动画 了解IK和F ...

最新文章

  1. Oracle Lsnrctl - 关于oracle监听器的命令和解释
  2. 《C++ 开发从入门到精通》——1.3 使用Visual Studio 2010
  3. Struts2--DomainModel接收参数---使用广泛!!!
  4. 抽象代数的抽象方法本质
  5. 利用SCCM 2007 软件分发
  6. airflow部署和使用示例
  7. php微信二次分享出错,解决微信二次分享bug
  8. ubuntu下C语言编程的注意点
  9. 一些控件中的属性。(未完)
  10. PAIP.通过公共网络传递秘密信息.txt (包括语音和文字)
  11. melodic版本ROS使用anaconda中的python
  12. 支持向量机原理与实现
  13. could not find driver (SQL: select * from information_schema.tables where table_schema = oliver and
  14. IRS2110S+IGBT半桥驱动调试问题记录
  15. 多视图信息瓶颈表征学习
  16. 如何通过移动广告平台实现手游推广
  17. 闸门机制(Gate Mechanism)
  18. 优雅的进行线上数据订正
  19. 【笔记】IP地址详解、Linux网络及常用命令
  20. 浏览器历史大事记和JavaScript的诞生

热门文章

  1. java除法不显示小数/andriod studio判断edittext是否为空值
  2. 2020 双节假期后的感悟
  3. 完全彻底卸载Oracle
  4. xp iis mysql php,XP下IIS配置PHP 和MySQL
  5. hive经典指标:最近7天连续3天活跃用户数
  6. 免费为网站配置ssl证书, 使网站变成https.半小时搞定
  7. intellij IDEA配置php环境
  8. 云计算服务:有标准才可信
  9. 星空极速密码破解算法
  10. 介绍MenuDrawer这个牛x的控件,实现左右出菜单,上下出菜单