espflash --- ตัวแฟลชเฟิร์มแวร์ ESP32 ROM bootloader

โมดูลนี้ให้การใช้งาน ESPFlash แบบย่อที่สื่อสารกับ ESP32 ROM bootloader ผ่าน UART โดยมีจุดประสงค์เพื่ออัปเดตเฟิร์มแวร์ ESP32 บนโมดูลคู่หูแบบ in-system (เช่น โมดูล U-blox NINA-W10 ที่ใช้บนบอร์ด Arduino) และไม่ได้เป็นตัวแทนของยูทิลิตี้ esptool แบบสมบูรณ์ คุณสมบัติขั้นสูงต่าง ๆ (stub loader, ชิป ESP อื่น ๆ, deflate, secure boot เป็นต้น) จงใจไม่รองรับ

ไดรเวอร์สลับ RESET และ GPIO0 เพื่อนำ ESP32 เข้าสู่โหมดดาวน์โหลด จากนั้นส่งคำสั่ง SLIP-framed เพื่ออ่านขนาดแฟลช, กำหนดค่าอินเตอร์เฟส SPI, เขียนอิมเมจเฟิร์มแวร์ และตรวจสอบผ่าน MD5 digest

ตัวอย่างสำหรับ Arduino Nano RP2040 Connect (บอร์ดที่รองรับ OpenMV เพียงบอร์ดเดียวซึ่งมีการ freeze espflash ไว้อยู่) พิน reset และ boot-strap ของ NINA-W102 คือ RP2040 GPIO 3 และ GPIO 2 ตามลำดับ และ UART0 ของ NINA เชื่อมต่อกับ RP2040 UART1 (TX = GPIO 8, RX = GPIO 9):

from machine import Pin, UART
from espflash import ESPFlash

reset = Pin(3, Pin.OUT)                                    # NINA RESET
gpio0 = Pin(2, Pin.OUT)                                    # NINA GPIO0
uart = UART(1, 115200, timeout=1000)

esp = ESPFlash(reset, gpio0, uart)
esp.bootloader()
esp.set_baudrate(921600)
size = esp.flash_read_size()
esp.flash_attach()
esp.flash_config(size)
esp.flash_write_file("NINA_FW.bin")
esp.flash_verify_file("NINA_FW.bin")
esp.reboot()

class ESPFlash

class espflash.ESPFlash(reset: 'machine.Pin', gpio0: 'machine.Pin', uart: 'machine.UART', log_enabled: bool = False)

สร้างออบเจ็กต์ ESPFlash ที่ขับเคลื่อน ESP32 ROM bootloader

  • reset คือ instance ของ machine.Pin ที่เชื่อมต่อกับสาย RESET ของ ESP32 ซึ่งกำหนดค่าเป็น output

  • gpio0 คือ instance ของ machine.Pin ที่เชื่อมต่อกับสาย GPIO0 ของ ESP32 ซึ่งกำหนดค่าเป็น output

  • uart คือ instance ของ machine.UART ที่เชื่อมต่อกับพิน UART0 ของ ESP32 โดยต้องถูก initialize ที่ 115200 baud พร้อม read timeout ที่ไม่เป็นศูนย์

  • log_enabled เปิดใช้งานการ logging แบบละเอียดสำหรับ SLIP frames ที่แลกเปลี่ยนกับ bootloader ใช้สำหรับการ debug เท่านั้น

constructor จะพยายาม import hashlib หาก hashlib.md5 พร้อมใช้งาน MD5 digest แบบรันไปเรื่อย ๆ ที่ใช้โดย ESPFlash.flash_verify_file() จะถูกคำนวณโดยอัตโนมัติระหว่างการเขียน

set_baudrate(baudrate: int, timeout: int = 350) None

เปลี่ยนอัตราบอดของ UART ใน bootloader

  • baudrate คืออัตราบอดใหม่ที่จะสลับไปใช้ หากต่างจากอัตราบอดที่ใช้อยู่ในปัจจุบัน คำสั่ง CHANGE_BAUDRATE จะถูกส่งไปยัง bootloader ก่อนที่จะกำหนดค่า UART ในเครื่องใหม่

  • timeout สงวนไว้และยังไม่ได้ใช้งานในปัจจุบัน

ไม่มีผลใด ๆ หากออบเจ็กต์ UART ที่อยู่เบื้องหลังไม่มีเมธอด init()

bootloader(retry: int = 6) bool

ขับเคลื่อน RESET และ GPIO0 เพื่อเข้าสู่ ESP32 ROM download mode และซิงค์กับ bootloader

  • retry คือจำนวนครั้งที่พยายาม reset/sync ก่อนยอมแพ้

คืนค่า True หากสำเร็จ หรือ raise Exception ในกรณีอื่น

flash_read_size() int

อ่าน JEDEC ID ของ SPI flash และคืนค่าขนาด flash เป็นไบต์

raise Exception หากบิตขนาดที่รายงานอยู่นอกช่วง 0x12-0x19 ที่คาดไว้

flash_attach() None

เชื่อมต่อกับ SPI flash ต้องเรียกใช้ครั้งเดียวหลังจาก bootloader() และก่อนการอ่าน/เขียน flash ใด ๆ

flash_config(flash_size: int = 2 * 1024 * 1024) None

กำหนดค่าพารามิเตอร์ SPI flash

  • flash_size คือขนาด flash รวมทั้งหมดเป็นไบต์ โดยปกติคือค่าที่คืนมาจาก flash_read_size()

ขนาด block, sector และ page ถูกกำหนดไว้ที่ 64 KiB, 4 KiB และ 256 ไบต์ตามลำดับ

flash_write_file(path: str, blksize: int = 0x1000) None

เขียนอิมเมจเฟิร์มแวร์ไปยัง flash เริ่มต้นที่ offset 0

  • path คือ path ของระบบไฟล์ของไฟล์ binary เฟิร์มแวร์ที่จะแฟลช

  • blksize คือขนาดเป็นไบต์ของแต่ละ data block ที่ส่งไปยัง bootloader ต้องเป็นทวีคูณของขนาด sector

block สุดท้ายจะถูก pad ด้วย 0xFF ให้ครบ blksize หากมีการรองรับ MD5 MD5 digest แบบรันไปเรื่อย ๆ จะถูกอัปเดตระหว่างการเขียน เพื่อให้สามารถเรียก flash_verify_file() ได้โดยไม่ต้องใส่อาร์กิวเมนต์

flash_verify_file(path: str, digest: bytes | None = None, offset: int = 0) None

ตรวจสอบเนื้อหาของ flash เทียบกับไฟล์เฟิร์มแวร์

  • path คือ path ของระบบไฟล์ของไฟล์เฟิร์มแวร์อ้างอิง ขนาดของมันกำหนดจำนวนไบต์ที่จะตรวจสอบ

  • digest คือ MD5 digest ที่ encode เป็น hex ที่คำนวณล่วงหน้าแบบ optional สำหรับไฟล์นั้น หากเป็น None จะใช้ digest ที่คำนวณระหว่างการเรียก flash_write_file() ครั้งล่าสุด

  • offset คือ flash offset เป็นไบต์ที่การตรวจสอบเริ่มต้น

raise Exception หากไม่มี digest พร้อมใช้งาน หรือหากเนื้อหา flash ไม่ตรงกับ reference digest

reboot() None

ส่งคำสั่ง FLASH_END ที่สั่งให้ ROM bootloader รีบูต ESP32 และรันเฟิร์มแวร์ที่แฟลชใหม่ ไม่มีการอ่าน response ใด ๆ