乐鑫ESP8266开发入门
Arduino方式开发
NonOS开发
FreeRTOS开发
ESP-AT开发
乐鑫已经停止了对8266 AT开发的支持, 后续只维护BUG. 现在乐鑫推荐 ESP32-C3也即是RISC-V平台.
ESP-AT Git项目能找到8266最后版本的技术文档
ESP-IDF开发
官方文档是这个: ESP8266 SDK的开发指南, 目前只有英文
CSDN上半颗心脏同学的8266开发笔记
乐鑫关于8266和32开发用IDF的区别, 8266 SDK从V3.0开始与IDF风格统一, 但由于不是完全兼容, 所以名称没有改为IDF.
ESP8266 SDK的GIT库
ESP-IDF的GIT库
环境搭建
还挺费劲, 下载的东西还挺多
准备工作
- 大多数人可能还是用windows 环境吧
- 需要下载3个包, 1个是msys2模拟linux环境, 1个是8266 编译器, 1个是8266项目包
- 需要用到github,所以准备好梯子
具体步骤
- 下载并解压 toolchain: https://dl.espressif.com/dl/esp32_win32_msys2_environment_and_toolchain-20181001.zip, 解压缩后把里面的
msys32
放到一个简短点儿的目录里比较好, 如D:\msys32
- 双击里面的
mingw32.exe
, 这就是以后的主要工作环境了. 先在home\用户名\
也就是~
目录下建立一个esp
目录, 把开发支持工具(等会儿会有2个), 放在这儿.home
目录就在D:\msys32
下面. - 下载第一个开发支持工具: esp8266 toolchain, https://dl.espressif.com/dl/xtensa-lx106-elf-gcc8_4_0-esp-2020r3-win32.zip, 解压缩到
esp
目录里面. mingw32
里面用vim .bashrc
增加一句话export PATH="$PATH:$HOME/esp/xtensa-lx106-elf/bin"
- 在
esp
目录里下载第二个支持工具. 这儿要用git
和github
. 所以你可能要先在.bashrc
里面设置个代理export http_proxy="192.168.0.1:8080"
, 然后重启mingw32, 进入esp
目录运行:git clone https://github.com/espressif/ESP8266_RTOS_SDK.git
, 也可以下载zip包https://github.com/espressif/ESP8266_RTOS_SDK/releases/download/v3.4/ESP8266_RTOS_SDK-v3.4.zip直接解压, 然后把clone后的路径设置为系统变量IDF_PATH
. 可以在.bashrc
里面设置, 增加一行:export IDF_PATH="$HOME/esp/ESP8266_RTOS_SDK"
,也可以再windows系统的环境变量里面设置, 如果在winows环境变量设置, 值要设置为/home/用户名/esp/ESP8266_RTOS_SDK
这样的形式. 似乎~
符号不认. 重启mingw32使设置生效. - 运行
python -m pip install --user -r $IDF_PATH/requirements.txt
- 复制一个
hello world
出来cp -r $IDF_PATH/examples/get-started/hello_world
- 进到
hello_world
目录运行make menuconfig
, 出来个UI界面配置一下串口名称如COM18
, 保存退出. 注意这个是ESP8266的烧录串口, 波特率74880
- 运行
make flash
, 会检查环境, 并且从github
下载项目, 编译, 挺花时间, 没个十几分钟搞不定. 可以增加一个-j8
参数, 使用8核编译,速度会快很多 - 运行
make monitor
可以监控串口输出.
好了, 看起来终于可以开始了.
其他有用的命令
make all
只编译而不烧录, 也会在最后显示烧录命令.
make print_flash_cmd
打印烧录命令, 可以用在其他地方
make partition_table
打印分区表, 一般分为两种: 非OTA的分区表Single factory app, no OTA
和OTA分区表Two OTA app
, 可以在make menuconfig
中选择.
分区表
分区表烧录在0x8000位置, 长度为0xC00
非OTA的分区表:
# Espressif ESP8266 Partition Table
# Name, Type, SubType, Offset, Size
nvs, data, nvs, 0x9000, 0x6000
phy_init, data, phy, 0xf000, 0x1000
factory, app, factory, 0x10000, 0xF0000
NVS是非易失存储, PHY似乎是物理什么的
OTA的分区表
# Espressif ESP8266 Partition Table
# Name, Type, SubType, Offset, Size
nvs, data, nvs, 0x9000, 0x4000
otadata, data, ota, 0xd000, 0x2000
phy_init, data, phy, 0xf000, 0x1000
ota_0, 0, ota_0, 0x10000, 0xF0000
ota_1, 0, ota_1, 0x110000, 0xF0000
可以看到OTA分区表是兼容非OTA分区表的, 兼容性明显比以前的8266项目好多了. 网上有很多介绍以前的8266分区表的, OTA分为user0/user1, user0起始于0x1000而不是现在的0x10000, 现在应该已经不适用了.
otadata
是指示启动那个app的, 如果为空就启动ota_0
分区表可以自定义, 不过我感觉一般是没必要了
系统任务
大写T
在最后面的是IDF的任务, 其他的是FREERTOS的任务.
uiT
用户初始化任务, 初始化完以后调用app_main
再销毁自己
IDLE
FREERTOS的空闲任务, 在其钩子vApplicationIdleHook
中调用sleep
和喂狗任务
Tmr
FREERTOS的软时钟
ppT
处理WIFI硬件驱动,我猜是process protocol的缩写
ppT
系统电源管理, power managerment.
rtT
高优先级的硬时钟中断任务. 主要处理WIFI实时事件. 基于这个组件的程序不要在应用(application)里面调用,以免影响WIFI收发.
tiT
Tcp-Ip协议栈的任务(LwIP), 处理TCP-IP包.
esp_event_loop_task
处理系统事件
优先级从低到高依次是:
0 IDLE
2 Tmr
8 tiT
10 esp_event_loop_task
11 pmT
12 rtT
13 ppT
14 uiT
用户任务的优先级要低于rtT
也就是12.
如果要加快 TCP/UDP 吞吐量,可以尝试将发送/接收任务的优先级设置为高于“tiT”任务的优先级(8)
PWM和嗅探器Sniffer共存问题
SmartConfig应该属于一种Sniffer.
8266是没有硬件PWM的, 它是用硬时钟模拟的软件PWM. 硬时钟同时用于WIFI, 所以WIFI sniffer和PWM同时用会出现资源争用的问题.
N个通道的PWM每次翻转GPIO将占用6+8N ns的时长. 例如一个通道PWM就是14ns.
占用期间, 如果收到了必须要实时处理的LPDC或HT40包, 这些包就会被丢弃.
同时使用PWM和smartconfig会使得配网时间更长. 而且调整PWM的频率/duty cycle/phase都会影响smartconfig的速度.
如果要同时使用, 需要:
- PWM 的频率不能太高,最多 2KHz。
- 修改PWM的占空比和相位,使每个通道反相之间的时间间隔(Tn)等于0或大于50us(Tn = 0,或Tn > 50)
这样看起来这个软件PWM似乎不太适合用于LED驱动~~
使用API-Reference文档
非常神奇的, 8266仿照IDF风格的API编程手册, 乐鑫已经放弃治疗了, 8266 RTOS SDK 编程指南最后版本V3.4中, 居然只是把每个函数罗列了一遍, 有个球用. 找了网上各种指南, 发现只能参考ESP32的手册, 在同样的目录结构下, Uart的使用就有非常详细的描述.
使用 make menuconfig
工具
感觉有些操蛋~ 很多在程序里面定义的参数还要再menuconfig里面预先定义一下, 否则程序编译后运行得总有些问题. 而且make menuconfig
重新定义以后,这个编译速度就慢的惊人了
使用linux服务器或者使用docker中加载linux环境, make的速度可以快好几倍.
menuconfig主要是在根目录下生成sdkconfig
文件作为编译依据. 同时会把旧的文件改名为sdkconfig.old
. 如果熟练的情况可以直接修改sdkconfig文件.
是否要重新编译, 似乎是根据sdkconfig
有没有更新决定的. 所以即使修改了一个和编译完全无关的项目, 如PC烧录串口, 也会导致全部重新编译.
IDF版本兼容性
IDF各个版本兼容性不佳, 如8266 v3.4和v3.1是不兼容的. 发现的就有 uart_driver_install
在v3.4比v3.1多一个参数,导致编译不能通过.
8266的串口输出
8266只有1.5个串口, 也就是1个完整串口UART0和1个只有TX的串口. 所谓有时候看到的UART2(IO13/15)是UART0交换(swap)过去的.
基于idf, 函数中直接使用printf
函数将直接从uart0口输出, 不需要串口初始化的步骤.
-
在menuconfig中将
Swap UART0 I/O pins
选上, 编译烧录后, 刚刚启动打印的boot信息在UART0输出, 后面printf的信息都在UART2上输出. 如果使用了软重启esp_restart();
, 软重启后的boot信息也将在UART2上输出. -
在menuconfig中将
Uart for console output
选项改为Custom
, 如果UART peripheral to use for console output (0-1)
仍然为UART0
, 结果和上面的一样不变. -
如果将
UART peripheral to use for console output (0-1)
改为UART1
, 那么第一次启动的boot信息在UART0输出, printf的信息在UART1输出, 软重启后的boot信息在UART2输出. -
在meunconfig中将
Partition Table
改为Factory app, two OTA definitions
不会对运行结果有什么影响, 但是flash烧录的固件名称会改为partitions_two_ota.bin
如果是单文件, 烧录命令是(project_template是项目的目录名):D:\r\esp\esp-idf\components\esptool_py\esptool\esptool.py --chip esp8266 --port COM18 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size 2MB 0x0000 build/bootloader/bootloader.bin 0x10000 build/project_template.bin 0x8000 build/partitions_singleapp.bin
如果是ota,烧录命令是:
D:\r\esp\esp-idf\components\esptool_py\esptool\esptool.py --chip esp8266 --port COM18 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size 2MB 0x0000 build/bootloader/bootloader.bin 0x10000 build/project_template.bin 0x8000 build/partitions_two_ota.bin
-
menuconfig只能控制所谓console的uart设置, 如果要使用uart,还是要自己通过程序进行uart初始化设置.
-
uart初始化使用uart0的影子uart2, 如果在menuconfig中已经设置了
swap
, 在初始化中就不需要再次调用swap函数了.static void uartInit() { // Configure parameters of an UART driver, // communication pins and install the driver uart_config_t uart_config = { .baud_rate = 115200, .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, .flow_ctrl = UART_HW_FLOWCTRL_DISABLE }; uart_param_config(UART_NUM_0, &uart_config); uart_driver_install(UART_NUM_0, BUF_SIZE * 2, 0, 0, NULL); }
-
v3.1
printf
的问题: 有时候不会及时输出, 尤其是在使用了格式化符号%d%x
等等后, 必须要用fflush(stdout)
后才能输出.
include顺序
idf头文件#include
是有顺序的,否则编译不通过.
感觉顺序似乎应该是标准库文件->freertos头文件->esp系统文件->驱动文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "driver/uart.h"