之前的文章 讲了如何烧录 ESP32 程序. 本篇讲一下如何生产烧录
通常生产使用的使用 , 固件都会有一个唯一ID , 我们这里叫序列号 (SN). 有多种方式可以烧录进去,这里主要讲两种方式
编译时注入
这种方式是直接在运行脚本中注入一个唯一ID , 优点是一次注入,终身不变. 缺点是每次烧录都得走编译流程 , 虽然代码没有改变 , 但是还是会重新执行一次 , 速度略慢.
首先修改项目的 platformio.ini
增加构建脚本 build_flags = -DDEVICE_ID="\"${sysenv.DEVICE_ID}\""
然后准备生产序列号文件 devices_ids.txt
, 里面每行一个序列号
1 2
| TESTU23110003 TESTU23110004
|
然后是执行脚本 generate_id_and_upload.bat
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| @echo off setlocal enabledelayedexpansion
:: 定义 ID 文件路径 set ID_FILE=device_ids.txt
:: 检查文件是否存在 if not exist %ID_FILE% ( echo Error: %ID_FILE% does not exist. exit /b 1 )
:: 读取第一行作为 DEVICE_ID set /p DEVICE_ID=<%ID_FILE%
:: 如果没有 DEVICE_ID,则退出 if "%DEVICE_ID%"=="" ( echo Error: No available IDs in %ID_FILE%. exit /b 1 )
:: 显示当前烧录的 ID echo Flashing device with ID: %DEVICE_ID%
:: 删除第一行并更新文件 (for /f "tokens=*" %%i in (%ID_FILE%) do ( if "%%i" neq "%DEVICE_ID%" echo %%i )) > temp.txt move /y temp.txt %ID_FILE% >nul
:: 运行 PlatformIO 烧录,传递 DEVICE_ID set DEVICE_ID=%DEVICE_ID% C:\Users\Administrator\.platformio\penv\Scripts\platformio.exe run --target upload --environment esp32-s3-devkitc-1 --upload-port COM7
endlocal
|
直接命令行执行或者双击 , 代码中 DEVICE_ID
即是烧录进去的ID
存储分区文件写入
首先 , 先准备好程序的固件程序以及支持项, 具体细节参考 之前的文章
bootloader.bin
firmware.bin
partitions.bin
boot_app0.bin
custom_partitions.csv
这个就是烧录一个空程序需要的文件 , 我们在此基础上要写入一个ID到存储文件中然后一起烧录
这里写入nvs要用一个 python 工具类 NVS Partition Generator Utility 下载下来放到准备烧录的目录
然后准备烧录脚本 burn_app.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| import os import subprocess
PORT = "COM7" BAUD = "115200"
ID_FILE = "device_ids.txt" if not os.path.exists(ID_FILE): print(f"Error: {ID_FILE} does not exist.") exit(1)
with open(ID_FILE, 'r') as file: DEVICE_ID = file.readline().strip()
if not DEVICE_ID: print(f"Error: No available IDs in {ID_FILE}.") exit(1)
csv_file = "nvs.csv" with open(csv_file, 'w', newline='') as file: file.write("key,type,encoding,value\n") file.write("nvs,namespace,,\n") file.write(f"serial_id,data,string,\"{DEVICE_ID}\"\n")
nvs_bin_file = "nvs.bin" command = ["python", "nvs_partition_gen.py", "generate", csv_file, nvs_bin_file, "0x5000"] try: subprocess.run(command, check=True) print(f"Generated NVS binary file: {nvs_bin_file}") except subprocess.CalledProcessError as e: print(f"Error generating NVS files: {e}") exit(1)
flash_command = [ "esptool", "--chip", "esp32s3", "--port", PORT, "--baud", BAUD, "--before", "default_reset", "--after", "hard_reset", "write_flash", "-z", "--flash_mode", "dio", "--flash_freq", "80m", "--flash_size", "8MB", "0x0000", "bootloader.bin", "0x8000", "partitions.bin", "0xe000", "boot_app0.bin", "0x10000", "firmware.bin", "0x9000", nvs_bin_file ]
try: subprocess.run(flash_command, check=True) print(f"Device flashed successfully with ID: {DEVICE_ID}") except subprocess.CalledProcessError as e: print(f"Error flashing device: {e}") exit(1)
with open(ID_FILE, 'r') as file: lines = file.readlines()
with open(ID_FILE, 'w') as file: for line in lines: if line.strip() != DEVICE_ID: file.write(line)
os.remove(csv_file) os.remove(nvs_bin_file)
print(f"Successfully flashed device with ID: {DEVICE_ID}")
|
这里参考我的分区配置
1 2 3 4 5 6 7
| # Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 0x9000, 0x5000, otadata, data, ota, 0xe000, 0x2000, app0, app, ota_0, 0x10000, 0x180000, app1, app, ota_1, 0x190000, 0x180000, spiffs, data, spiffs, 0x310000, 0xCE000, coredump, data, coredump, 0x3DF000, 0x10000
|
最终烧录前目录文件是
bootloader.bin
firmware.bin
partitions.bin
boot_app0.bin
custom_partitions.csv
device_ids.txt
burn_app.py
可自行修改脚本文件配置. 这里是读取txt文件中的每行ID号 ,然后写入文件 , 烧录 . 实际情况中可以接多个串口一次烧录, 提高效率 .自定一个 pyqt 工具烧录 ,会相当不错.
我们会发现这个方法是最适合生产的 , 因为只需要一次编译 , 然后将烧录工具和程序文件一起交给生产人员 ,高效便捷还不会泄露源码 . 用 idf
开发的项目也可以如此烧录