██████╗ ███████╗██████╗ ██╗ ██╗███████╗
██╔═══██╗██╔════╝██╔══██╗╚██╗ ██╔╝██╔════╝
██║ ██║███████╗██████╔╝ ╚████╔╝ █████╗
██║▄▄ ██║╚════██║██╔══██╗ ╚██╔╝ ██╔══╝
╚██████╔╝███████║██████╔╝ ██║ ███████╗
╚══▀▀═╝ ╚══════╝╚═════╝ ╚═╝ ╚══════╝
保命声明:笔者代码能力有限,若行文中有错漏之处欢迎大家指出。
ESP32S3通过USB下载和调试(不用USB转TTL芯片)
[https://www.cnblogs.com/Spin-jump/p/16884302.html]
目前 ESP32-S3 进行下载和调试有两种方式,一种是通过串口(UART),
另一种是通过USB。如果使用串口的话,还需要一个额外的串口芯片-CP2102。使用USB就可以直接连接、下载。
BOOT 键(GPIO0)是必须要有的,进入下载模式的时候需要用到。
复位键可以不用,直接使用上电复位配合上 BOOT 键也能进入下载模式。
GPIO19 和 GPIO20 是需要连接的USB引脚。
进入下载模式:
- 在通电的情况下,按住 BOOT 键不松开,然后在按一下复位键,然后再松开 BOOT 就能进入下载模式了。
- 在按住 BOOT 键不松的情况下上电。
esp32分区表
ESP32的FLASH可以包含多个应用程序以及不同类型的数据,因此在FLASH默认偏移地址的0x8000处烧写了一个分区表,长度为0xC00字节,分区表数据后还保存着该表的 MD5 校验和,用于验证分区表的完整性。此外,如果芯片使能了 安全启动 功能,则该分区表后还会保存签名信息。
分别代表什么意思呢?4M FLASH默认分区方案为1.2MB的应用程序空间,1.2MB为OTA保留,1.5MB为SPIFFS文件系统保留的,我们找到这个描述文件,在SDK下tools下的partitions,我们打开default.csv,对应默认的分区表.
表格描述的很清楚,各个分区名字,对应的偏移地址,以及占用大小,比如,nvs分区,从0x9000地址处开始,大小为0x5000,也就是20480字节的大小,具体每个分区的作用,我们下面细说。我们这里知道的就是,在0x9000处放了一个nvs表,决定我们整个存储区域怎么划分的,每个分区分别分配多大的存储空间,系统就根据这个表来划分,可以根据我们的程序大小等灵活配置。
分区表说明:
- 0-0x1000 保留
- 0x1000-0x8000 Bootloader分区
- 0x8000-0x9000 Partition Table分区,保存着分区表
- 0x9000-0xD000 NVS分区,可以存储一些PHY初始化数据,也可以存储其他数据,一些断电存储的数据建议放在这里
- 0xD000-0xF000 OTA data分区,系统从哪个app分区启动由这里存储的数据决定
- 0xF000-0x10000 PHy_init分区,用于存储的PHY初始化数据
- 0x10000-0x3FFFFF Factory APP分区,保存出厂应用程序,分区表有工厂应用程序就会启动这个分区的程序
- Core dump分区,查找系统崩溃时的软件错误,以便开发者分析原因
- OTA0/OTA1分区,保存OTA下载固件,交替保存在这两个分区,镜像验证无误之后,会更新OTA data分区,分配好下一次应该从哪里启动。
- fctry分区,保存阿里云四元组,这个就是私有数据了,可以在存储空间的最后分配一些空间用于保存一些APP的激活数据之类的,没有用到就可以忽略。
代码烧录就是把上面的每个分区的文件分别烧录进FLASH芯片中.
esptool.py简介
当前支持命令: load_ram,dump_mem,read_mem,write_mem,write_flash,run,image_info,make_image,elf2image,read_mac,chip_id,flash_id,read_flash_status,write_flash_status,read_flash,verify_flash,erase_flash,erase_region,version,get_security_info
支持写入/读取flash,即可以提取固件;
通过 esptool.py -h 查看所有命令和通用参数详细说明
通过 esptool.py <command> -h 查看每条命令对应的参数详细说明
写入flash:
esptool.py --chip esp8266 --port /dev/ttyUSB0 --baud 115200 --before default_reset --after hard_reset write_flash -z --flash_mode dout --flash_freq 80m --flash_size 2MB 0x0 build/bootloader/bootloader.bin 0x10000 build/sntp.bin 0x8000 build/partitions.bin
读取flash:
#指定串口 USB1, 波特率 460800, 从 0x10000 地址读取 1MB 内容到 dump.bin 文件
esptool.py -p /dev/ttyUSB1 -b 460800 read_flash 0x10000 0x100000 dump.bin
flash spi mode
- DIO
- DOUT
QIO/QOUT: use /HOLD and /WP pin as SPI data2/data3, make sure your flash support Quad instructions before select.(Almost the same but "QIO" will send address in quad mode, but "QOUT" will not.)
- QIO
- QOUT
DIO/DOUT: use Dual mode instructions to read/write flash. (Almost the same but "DIO" will send address in Dual mode but "DOUT" will not.)
Most of the flashes support DIO/DOUT mode operations.
Most of the flashes have their "QE" bit on the 9th bit of status register.
For those flashes whose "QE" bit are the 6th bit of status register, we can use DIO/DOUT mode.
The configure byte is in the 3rd byte from flash address 0x0. So the downlaod tool will overwrite the 3rd byte of bin file which is to be written to 0x0 address.
串口打印测试
代码目录结构
.proj_hello
├── CMakeLists.txt
├── Makefile
├── README.md
├── build
│ ├── 1.bin
│ ├── 1.hello_world.elf
│ ├── 1.hello_world.map
│ ├── CMakeCache.txt
│ ├── CMakeFiles
│ ├── app-flash_args
│ ├── bootloader
│ ├── bootloader-flash_args
│ ├── bootloader-prefix
│ ├── build.ninja
│ ├── cmake_install.cmake
│ ├── compile_commands.json
│ ├── config
│ ├── config.env
│ ├── esp-idf
│ ├── flash_app_args
│ ├── flash_args
│ ├── flash_args.in
│ ├── flash_bootloader_args
│ ├── flash_project_args
│ ├── flasher_args.json
│ ├── kconfigs.in
│ ├── kconfigs_projbuild.in
│ ├── ldgen_libraries
│ ├── ldgen_libraries.in
│ ├── partition-table-flash_args
│ ├── partition_table
│ ├── project_description.json
│ ├── project_elf_src_esp32s3.c
│ └── x509_crt_bundle.S
├── dependencies.lock
├── example_test.py
├── main
│ ├── CMakeLists.txt
│ ├── component.mk
│ └── hello_world_main.c
├── partitions.csv
└── sdkconfig
代码
hello_world_main.c
/*原作者:Kevincoooool*/
#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
/*
ESP32工作的时候是以app_main来作为主入口,STM32是main
*/
void app_main(void)
{
printf("Hello world!\n");
// uint8_t buff =heap_caps_malloc(1*1523 * 7541, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
/* Print chip information */
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);//获取当前的芯片参数
printf("This is %s chip with %d CPU core(s), WiFi%s%s, ",
CONFIG_IDF_TARGET,
chip_info.cores,
(chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");
printf("silicon revision %d, ", chip_info.revision);
printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024),
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
printf("Minimum free heap size: %d bytes\n", esp_get_minimum_free_heap_size());
for (int i = 10; i >= 0; i--) {
printf("Restarting in %d seconds...\n", i);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
printf("Restarting now.\n");
fflush(stdout);//把所有数据都输出出去
esp_restart();//复位芯片
}
编译
cd ESP32_S3_Screen_ksdiy
alias esp-idf='docker run --rm --privileged -v $PWD:/project -w /project -it espressif/idf:v4.4 bash -c'
esp-idf "cd /project/proj_hello && idf.py build"
烧录
#擦除原有程序(改成自己的串口号,可能要sudo)
ls /dev/cu*
esptool.py --chip auto --port /dev/cu.usbmodem143301 erase_flash
#烧入bin文件(注意匹配你的 bin文件名、串口号、flash大小与速率、传输波特率等)
cd ./proj_hello/build
esptool.py --chip auto --port /dev/cu.usbmodem143301 -b 961200 --before=default_reset --after=hard_reset write_flash --flash_mode qio --flash_freq 40m --flash_size 8MB 0x0000 bootloader/bootloader.bin 0x10000 1.bin 0x8000 partition_table/partition-table.bin
注意区分Flash SPI Mode不然烧录会失败的。
效果