2019年6月27日 星期四

MicroPython on ESP32 學習筆記 (一) : 燒錄韌體

上週末購買的兩塊 NodeMCU-32S 昨天到貨, 這兩天才有時間開封測試. 但因為沒有事先研究而做了許多白工, 先說結論好了 :
  1. NodeMCU 的 USB 晶片用的是 CP2102, 必須下載安裝驅動程式才能抓到 COM port. 
  2. ESP32 要用 pip3 install esptool 安裝 esptool 這個 Python 套件燒錄韌體, 不要用以前 ESP8266 的 Espflasher.exe 程式. 
  3. 清除 flash 與燒錄韌體指令執行前必須按住板子右下角的 flash 按鈕, 等指令開始執行後再放開, 否則無法正常開機. 
ESP32 開發板內建藍芽與 WiFi, 是 ESP8266 模組的進階版, 擁有更多 ADC 接腳, CP 值更高, 因為一塊藍芽模組也要 100~300 元左右. Arduino, ESP8266, ESP32 這三塊開發板的主要功能比較如下表 :


 功能 Arduino ESP8266 ESP32
 CPU AVR ATMega328P Tensilica Xtensa LX106 Tensilica Xtensa LX6
 資料寬度 8 位元 32 位元 32 位元
 核心數 單核心 單核心 雙核心
 操作頻率 20MHz 80/160MHz 160/240MHz
 SRAM 16KB 160KB 512KB
 Flash 32KB 1-4MB 4-16MB
 WiFi 無 802.11 b/g/n 802.11 b/g/n/a/c
 Bluetooth 無 無 Bluetooth 5.0 LE
 DIO 有 (13 個) 有 (8 個) 有 (18 個)
 ADC 有 (8 個) 有 (1 個) 有 (18 個)
 DAC 無 無 有 (2 個)
 UART 有 (1 組, D0, D1) 有 (1 組) 有 (3 組)
 I2C 有 (1 組, A4, A5) 有 (1 組) 有 (2 組)
 I2S 有 (1 組) 有 (1 組) 有 (2 組)
 SPI 有 (1 組) 有 (1 組) 有 (3 組)
 PWM 有 (6 個, 3/5/6/9/10/11) 有 (8 個) 有 (16 個)
 電容觸控輸入 無 無 有 (10 個)


參考 :

https://nick.zoic.org/talk/lca2017/

我手上目前有三種 ESP32 開發板 : NodeMCU 32S, rpi:bit, 以及 ESP-CAM, 它們都是 4MB Flash 的板子, 相關教學資料參考 :

https://docs.micropython.org/en/latest/ (官方文件)

以下紀錄這兩天的測試過程, 都是在我的 Acer Swift 5 筆電的 Win10 下進行, 主要是依照 Randomnerd 的教學網頁, 參考 :

Flashing MicroPython Firmware with esptool.py on ESP32 and ESP8266

如果一開始就找到此網頁應該就可少走許多冤枉路.

除了 esptool 外,  還有一個 GUI 軟體 uPyCraft 可以燒錄 ESP32 韌體, 參考 :

Flash/Upload MicroPython Firmware to ESP32 and ESP8266

但我覺得 esptool 的 CLI 介面就很好用了.


1. 安裝 CP2102 驅動程式 : 

剛拆封的 NodeMCU 板子用 micro USB 線接上 PC 時, 開啟裝置管理員, 在連接埠 (COM 與 PRT) 項下會找不到 COM 埠. 因為此板內建的 USB 晶片不是常見的 CH340 (D1 mini 採用此晶片), 而是 Silicon Labs 的 CP2102, Windows 10 沒有內建, 必須下載安裝驅動程式 (CH340 在 Win10 就有, 毋須安裝), 參考 :

Arduino ESP32 精簡型開發板 安裝教學
https://cityos-air.readme.io/docs/1-usb-drivers-for-nodemcu-v10

CP2102 的下載位址 :

https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers

我下載的是 WINDOWS 10 Universal 版 (zip 檔) :




解開後執行 x64 那個 .exe 檔安裝驅動程式 :




然後開啟控制台的裝置管理員, 在連接埠項下就會出現 CP210X 的 COM 埠了 :




這時再次將 NodeMCU-32S 板子連接電腦 USB 埠, 開啟 Putty 以 115200 bps 速率 Serial 連線此 COM 埠 :




連線 NodeMCU 成功後 Putty 出現如下訊息, 此乃出廠時預燒的 Lua 程式, 會讓板子上的 LED 燈閃爍 :

ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0x00
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3ffc0000,len:0
load:0x3ffc0000,len:920
load:0x40078000,len:2624
load:0x40098000,len:508
entry 0x40098118
I (73) heap_alloc_caps: Initializing heap allocator:
I (73) heap_alloc_caps: Region 19: 3FFC03A0 len 0001FC60 tag 0
I (73) heap_alloc_caps: Region 23: 3FFE8000 len 00010000 tag 1
check b=0x3ffc03ac size=130116 ok
check b=0x3ffdfff0 size=0 ok
check b=0x3ffe800c size=65508 ok
I (92) cpu_start: Pro cpu up.
I (96) cpu_start: Single core mode
I (100) cpu_start: Pro cpu start user code
rtc v112 Sep 22 2016 16:08:39
XTAL 40M
I (133) cpu_start: Starting scheduler on PRO CPU.
D (135) nvs: init start=6 count=3
D (138) nvs: nvs_open misc 1
D (139) nvs: nvs_get_str_or_blob log
frc2_timer_task_hdl:3ffc4224, prio:22, stack:2048
tcpip_task_hdlxxx : 3ffc4e58, prio:18,stack:2048
phy_version: 123, Sep 13 2016, 20:01:58, 0
D (268) nvs: nvs_open nvs.net80211 1
D (268) nvs: nvs_get opmode 1
D (268) nvs: nvs_get country 1
D (269) nvs: nvs_get_str_or_blob sta.ssid
D (273) nvs: nvs_get_str_or_blob sta.mac
D (276) nvs: nvs_get sta.authmode 1
D (280) nvs: nvs_get_str_or_blob sta.pswd
D (283) nvs: nvs_get_str_or_blob sta.pmk
D (287) nvs: nvs_get sta.chan 1
D (290) nvs: nvs_get auto.conn 1
D (293) nvs: nvs_get bssid.set 1
D (296) nvs: nvs_get_str_or_blob sta.bssid
D (300) nvs: nvs_get sta.phym 1
D (302) nvs: nvs_get sta.phybw 1
D (305) nvs: nvs_get_str_or_blob sta.apsw
D (309) nvs: nvs_get_str_or_blob sta.apinfo
D (313) nvs: nvs_get_str_or_blob ap.ssid
D (317) nvs: nvs_get_str_or_blob ap.mac
D (320) nvs: nvs_get_str_or_blob ap.passwd
D (324) nvs: nvs_get_str_or_blob ap.pmk
D (328) nvs: nvs_get ap.chan 1
D (330) nvs: nvs_get ap.authmode 1
D (333) nvs: nvs_get ap.hidden 1
D (336) nvs: nvs_get ap.max.conn 1
D (340) nvs: nvs_get bcn.interval 2
D (343) nvs: nvs_get ap.phym 1
D (346) nvs: nvs_get ap.phybw 1
D (348) nvs: nvs_get ap.sndchan 1
D (352) nvs: nvs_set_blob sta.mac 6
D (355) nvs: nvs_set_blob ap.mac 6
pp_task_hdl : 3ffc8710, prio:23, stack:8192
get wifi mode: 2
set wifi mode
get wifi ap mac: 7D:3A:B7:B7:A7:5C
get wifi ap ssid: ESP_B7A75C
get wifi ap password:
set wifi ap ...
get wifi sta ssid:
get wifi sta password:
set wifi sta ...
wifi start
mode : sta(80:7d:3a:b7:a7:5c) + softAP(82:7d:3a:b7:a7:5c)
D (387) event: SYSTEM_EVENT_STA_START
V (390) event: enter default callback
V (393) event: exit default callback
D (396) event: SYSTEM_EVENT_AP_START
V (400) event: enter default callback
dhcp server start:(ip: 192.168.4.1, mask: 255.255.255.0, gw: 192.168.4.1)
V (410) event: exit default callback
mode : softAP(82:7d:3a:b7:a7:5c)
D (416) event: SYSTEM_EVENT_STA_STOP
V (419) event: enter default callback
V (423) event: exit default callback
start led blink task.
start http server task.

接下來要安裝 esptool 套件, 將板子 flash 裡面的既有程式清除掉, 再燒錄我們要的 MicroPython 韌體.


2. 安裝 esptool 套件 :

去年 Tim 大哥給了我一塊 rpi:bit ESP32 開發板, 當時燒錄 MicroPython 的經驗是 ESP32 不能用之前燒錄 ESP8266 (例如 ESP-01 或 D1 mini) 板子的 ESPflasher.exe 這個程式, 而是要用 Python 的 esptool 套件, 參考 :

# rpi:bit ESP32 開發板測試 (一) : 燒錄 MicroPython 韌體

Randomnerd 寫的教學文件裡也是用 esptool, 可以用 pip 直接安裝 :


C:\Users\User> pip3 install esptool 

完畢後檢視 Python 安裝目錄的 Scripts 資料夾, 會發現多了幾個 esp 開頭的檔案, 其中的 esptool.py 或 esptool.py.exe 就是我們要用來清除 flash 以及燒錄韌體的程式. 如果安裝 Python 時有勾選自動加入 path 環境變數, 那麼在任何目錄下都可執行 esptool.py.exe, 否則就要手動將 Scripts 目錄自行加入 path 中了.




注意, 在 Randomnerd 寫的教學文件裡是用 esptool.py, 這兩個都可以用. 執行 esptool.py 或  esptool.py.exe 會顯示指令說明 :

D:\test>esptool.py 
esptool.py v2.6
usage: esptool [-h] [--chip {auto,esp8266,esp32}] [--port PORT] [--baud BAUD]
               [--before {default_reset,no_reset,no_reset_no_sync}]
               [--after {hard_reset,soft_reset,no_reset}] [--no-stub]
               [--trace] [--override-vddsdio [{1.8V,1.9V,OFF}]]
               {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}
               ...

esptool.py v2.6 - ESP8266 ROM Bootloader Utility

positional arguments:
  {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}
                        Run esptool {command} -h for additional help
    load_ram            Download an image to RAM and execute
    dump_mem            Dump arbitrary memory to disk
    read_mem            Read arbitrary memory location
    write_mem           Read-modify-write to arbitrary memory location
    write_flash         Write a binary blob to flash
    run                 Run application code in flash
    image_info          Dump headers from an application image
    make_image          Create an application image from binary files
    elf2image           Create an application image from ELF file
    read_mac            Read MAC address from OTP ROM
    chip_id             Read Chip ID from OTP ROM
    flash_id            Read SPI flash manufacturer and device ID
    read_flash_status   Read SPI flash status register
    write_flash_status  Write SPI flash status register
    read_flash          Read SPI flash content
    verify_flash        Verify a binary blob against flash
    erase_flash         Perform Chip Erase on SPI flash
    erase_region        Erase a region of the flash
    version             Print esptool version

optional arguments:
  -h, --help            show this help message and exit
  --chip {auto,esp8266,esp32}, -c {auto,esp8266,esp32}
                        Target chip type
  --port PORT, -p PORT  Serial port device
  --baud BAUD, -b BAUD  Serial port baud rate used when flashing/reading
  --before {default_reset,no_reset,no_reset_no_sync}
                        What to do before connecting to the chip
  --after {hard_reset,soft_reset,no_reset}, -a {hard_reset,soft_reset,no_reset}
                        What to do after esptool.py is finished
  --no-stub             Disable launching the flasher stub, only talk to ROM
                        bootloader. Some features will not be available.
  --trace, -t           Enable trace-level output of esptool.py interactions.
  --override-vddsdio [{1.8V,1.9V,OFF}]
                        Override ESP32 VDDSDIO internal voltage regulator (use
                        with care)



3. 清除 flash 內容 :

在燒錄 MicroPython 韌體之前須先清空裡面的程式與資料, 指令如下 :

esptool.py --chip esp32 --port COM8 erase_flash

但是要注意, 在按下 ENTER 鍵之前要按住右下角的 IO0 (即 flash) 按鈕 :




直到 Connecting ... 後面的 Chip 編號出來, 如果沒有按的話會可能會出現如下 "Failed to connect to Espressif device" 錯誤 :

D:\test>esptool.py --chip esp32 --port COM8 erase_flash
esptool.py v2.6
Serial port COM8
Connecting........_____....._____....._____....._____....._____....._____....._____

A fatal error occurred: Failed to connect to Espressif device: Timed out waiting for packet header

我搜尋了網路發現有非常多人遇到這問題, 其原因除了沒按下 flash 按鈕外, 還有一個原因是 USB 線不對, 有可能只是充電線而已而不是資料傳輸線, 只要更換好一點的線即可.

按住 flash 鍵後再執行清除指令的話很快就與晶片連線了 :

D:\test>esptool.py --chip esp32 --port COM8 erase_flash 
esptool.py v2.6
Serial port COM8
Connecting.....
Chip is ESP32D0WDQ6 (revision 1) 
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
MAC: 80:7d:3a:b7:c0:8c
Uploading stub...
Running stub...
Stub running...
Erasing flash (this may take a while)...
Chip erase completed successfully in 3.0s
Hard resetting via RTS pin...


4. 查詢 flash 資訊 : 

指令如下 :

esptool.py --port COM8 flash_id

與上面清除 flash 一樣, 下達查詢指令前按住 flash 鈕 (即 IO0) 才會順利連線 :

D:\test>esptool.py --port COM8 flash_id 
esptool.py v2.6
Serial port COM8
Connecting....
Detecting chip type... ESP32 
Chip is ESP32D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
MAC: 80:7d:3a:b7:c0:8c
Uploading stub...
Running stub...
Stub running...
Manufacturer: 68
Device: 4016
Detected flash size: 4MB
Hard resetting via RTS pin...

可見 CPU 是 240 MHz 雙核心, 具備 WiFi 與藍芽功能, flash 容量為 4MB PSRAM, 關於 PSRAM 參考 :

PSRAM偽靜態隨機存取記憶體


5. 下載並燒錄 MicroPython 韌體 :

ESP32 版的 MicroPython 韌體可在下列網址下載,  有 Standard 與 SPIRAM 兩種版本, Standard 版本可在任何一種 ESP32 板子上運作, 但 SPIRAM 版本只能在配備 4MB 外部 PSRAM (SPI RAM) 的板子上跑. NodeMCU-32S 沒有 SPI RAM, 雖然兩種版本都可以跑, 但燒錄 SPIRAM 版韌體事實上無法啟動 SPI RAM (因為沒有), 故此處下載 Standard 版本 :

https://micropython.org/download/esp32/

先切換到下載韌體所在目錄, 與上面清除與查詢 flash 一樣, 在下達燒錄指令前需按住 flash 鍵 (即 IO0) 直到 Connecting ... 後面的 Chip 編號出來才放掉 :

D:\ESP32>esptool.py --chip esp32 --port COM8 write_flash -z 0x1000 esp32-20190711-v1.11-142-ga73859d5a.bin
esptool.py v2.6
Serial port COM8
Connecting....
Chip is ESP32D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
MAC: 80:7d:3a:b7:c0:8c
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Auto-detected Flash size: 4MB
Compressed 1167312 bytes to 729739...
Wrote 1167312 bytes (729739 compressed) at 0x00001000 in 65.1 seconds (effective 143.4 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...

這樣就燒錄完成了. 接著開啟 PuTTY 以 Serial 115200 速率連線 COM port, 應該馬上就進入 REPL 介面了 :

ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:4928
ho 0 tail 12 room 4
load:0x40078000,len:9404
load:0x40080400,len:6228
entry 0x400806ec
I (439) cpu_start: Pro cpu up.
I (439) cpu_start: Application information:
I (439) cpu_start: Compile time:     Jun 25 2019 12:38:11
I (443) cpu_start: ELF file SHA256:  0000000000000000...
I (449) cpu_start: ESP-IDF:          v3.3-beta1-694-g6b3da6b18
I (455) cpu_start: Starting app cpu, entry point is 0x40082b54
I (0) cpu_start: App cpu up.
I (466) heap_init: Initializing. RAM available for dynamic allocation:
I (473) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (479) heap_init: At 3FFB9ED0 len 00026130 (152 KiB): DRAM
I (485) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (491) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (498) heap_init: At 400921FC len 0000DE04 (55 KiB): IRAM
I (504) cpu_start: Pro cpu start user code
I (75) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
MicroPython v1.11-63-gd889def06 on 2019-06-25; ESP32 module with ESP32
Type "help()" for more information.
>>> import sys
>>> print("Version Python ", sys.version) 
Version Python  3.4.0   

可見 v1.11-63 版韌體是實作 Python v3.4.0.

雖然 NodeMCU 32S 這塊開發板沒有外部 SPI RAM, 但也可以燒錄 SPI RAM 版本的韌體, 只是開機時會顯示 "SPI RAM enabled but initialization failed" 以及 "Failed to init external RAM" 等訊息, 雖然都能正常運作, 還是燒錄 Standard 版本吧!

ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:4928
ho 0 tail 12 room 4
load:0x40078000,len:10264
ho 0 tail 12 room 4
load:0x40080400,len:6740
entry 0x400806ec
E (509) spiram: SPI RAM enabled but initialization failed. Bailing out.
I (510) cpu_start: Failed to init external RAM; continuing without it.
I (513) cpu_start: Pro cpu up.
I (516) cpu_start: Application information:
I (521) cpu_start: Compile time:     Jun 25 2019 00:44:35
I (527) cpu_start: ELF file SHA256:  0000000000000000...
I (533) cpu_start: ESP-IDF:          v3.3-beta1-694-g6b3da6b18
I (540) cpu_start: Starting app cpu, entry point is 0x40083014
I (0) cpu_start: App cpu up.
I (550) heap_init: Initializing. RAM available for dynamic allocation:
I (557) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (563) heap_init: At 3FFBA098 len 00025F68 (151 KiB): DRAM
I (570) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (576) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (582) heap_init: At 40096438 len 00009BC8 (38 KiB): IRAM
I (588) cpu_start: Pro cpu start user code
I (159) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
E (20) spiram: SPI RAM not initialized
I (40) modsocket: Initializing
I (60) wifi: wifi driver task: 3ffe2f08, prio:23, stack:3584, core=0
I (283) wifi: wifi firmware version: 7240fb7
I (283) wifi: config NVS flash: enabled
I (283) wifi: config nano formating: disabled
I (283) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
I (293) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
I (323) wifi: Init dynamic tx buffer num: 32
I (323) wifi: Init data frame dynamic rx buffer num: 32
I (323) wifi: Init management frame dynamic rx buffer num: 32
I (323) wifi: Init management short buffer num: 32
I (333) wifi: Init static rx buffer size: 1600
I (333) wifi: Init static rx buffer num: 10
I (343) wifi: Init dynamic rx buffer num: 32
Started webrepl in normal mode
MicroPython v1.11-52-g205c6d0dc on 2019-06-25; ESP32 module with ESP32
Type "help()" for more information.

如果買的是 ESP32 WROVER 開發板就有 4MB 的外部 SPI RAM, 需要用到 SPI RAM 的話就可以燒錄 SPI RAM 版韌體, 但 SPI RAM 運作速度較低, 不需要 SPI RAM 的話就安裝 Standard 版. 關於 SPI RAM 參考 :

  1. SPIRAM 速度較慢, 理論上是 40MB/s, 實際應用大約 14MB/s
  2. 如果燒錄的韌體是 SPI 版, 則系統會自動使用 SPIRAM 而非較快的 SRAM. 


6. 檢查硬體與韌體狀態 :

MicroPython v1.11-63-gd889def06 on 2019-06-25; ESP32 module with ESP32
Type "help()" for more information.
>>> import esp   
>>> esp.check_fw()    
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'check_fw'
>>> import port_diag   
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: no module named 'port_diag'
>>> dir()
['uos', '__name__', 'gc', 'bdev', 'esp']
>>> dir(esp)
['__class__', '__name__', 'LOG_DEBUG', 'LOG_ERROR', 'LOG_INFO', 'LOG_NONE', 'LOG_VERBOSE', 'LOG_WARNING', 'dht_readinto', 'flash_erase', 'flash_read', 'flash_size', 'flash_user_start', 'flash_write', 'gpio_matrix_in', 'gpio_matrix_out', 'neopixel_write', 'osdebug']
>>> esp.flash_size()   
4194304   

可見 ESP32 版本的 MicroPython 雖然有 esp 模組, 但已經移除 check_fw() 方法, 而且也沒有 port_diag 模組了. 利用 esp.flash_size() 查詢記憶體容量確實有 4MB. 


7. 檢查檔案系統 :

>>> dir()
['uos', 'gc', '__name__', 'bdev']

注意, 上面是 SPIRAM 版的預載模組, 如果是 Standard 版則不同 :

>>> dir()
['bdev', 'gc', '__name__', 'os', 'uos', 'f', 'webrepl', 'line']

檔案系統根目錄下只有一個 boot.py :

>>> import os 
>>> os.uname()
(sysname='esp32', nodename='esp32', release='1.11.0', version='v1.11-52-g205c6d0dc on 2019-06-25', machine='ESP32 module with ESP32')
>>> os.listdir() 
['boot.py']
>>> f=open('boot.py','r') 
>>> for line in f.readlines(): 
...     print(line)
...
...
...
# This file is executed on every boot (including wake-boot from deepsleep

#import esp

#esp.osdebug(None)

#import webrepl

#webrepl.start()

>>> f.close() 

可見預設載入了 os, gc, webrepl 等模組, 但 webrepl 並未開啟. 其中 esp.osdebug(None) 用來關閉系統偵錯訊息, 在開發階段要像這樣用 # 註解掉以利程式錯誤時有資訊可用來除錯,


8. 開啟 webrepl 功能 :

>>> import webrepl_setup 
WebREPL daemon auto-start status: disabled 

Would you like to (E)nable or (D)isable it running on boot?
(Empty line to quit)
> E
To enable WebREPL, you must set password for it
New password (4-9 chars): 123456
Confirm password: 123456
Changes will be activated after reboot
Would you like to reboot now? (y/n)y

重新讀取 boot.py  :

>>> f=open('boot.py','r') 
>>> for line in f.readlines(): 
...     print(line) 
...
...
...
# This file is executed on every boot (including wake-boot from deepsleep)

#import esp

#esp.osdebug(None)

import webrepl

webrepl.start()   

>>> f.close()

可見 webrepl 已開啟.

完成上面的燒錄作業, 就可以開始測試 ESP32 開發板的功能了. 上面讀取檔案可用 with, 這樣讀取完畢會自動關檔, 不須呼叫 close() :

>>> with open('boot.py','r') as lines: 
...     for line in lines: 
...         print(line) 
...
...
...
# This file is executed on every boot (including wake-boot from deepsleep)

#import esp

#esp.osdebug(None)

import webrepl

webrepl.start()



9. 系統內建模組 :

呼叫內建函數 dir() 可以檢視 MicroPython 內建模組 :

>>> dir() 
['bdev', 'gc', '__name__', 'esp', 'uos', 'machine', 'webrepl']

其中 uos 是 CPython 的 os 模組在 MicroPython 上實作的子集合, 可以用 import os 或 import uos 引入模組 (用 os 其實會被轉成 uos), 主要是檔案管理函數, 參考 :

https://docs.micropython.org/en/latest/library/uos.html#module-uos

>>> import uos 
>>> dir(uos) 
['__class__', '__name__', 'remove', 'VfsFat', 'chdir', 'dupterm', 'dupterm_notify', 'getcwd', 'ilistdir', 'listdir', 'mkdir', 'mount', 'rename', 'rmdir', 'stat', 'statvfs', 'umount', 'uname', 'urandom']
nique_id']

其次是 esp 模組, 此為 ESP8266 與 ESP32 特有的模組, 大部分是與 flash 記憶體與 GPIO 操作有關, 參考 :

https://docs.micropython.org/en/latest/library/esp.html#module-esp

>>> dir(esp) 
['__class__', '__name__', 'LOG_DEBUG', 'LOG_ERROR', 'LOG_INFO', 'LOG_NONE', 'LOG_VERBOSE', 'LOG_WARNING', 'dht_readinto', 'flash_erase', 'flash_read', 'flash_size', 'flash_user_start', 'flash_write', 'gpio_matrix_in', 'gpio_matrix_out', 'neopixel_write', 'osdebug']

另外還有一個 ESP32 特有的模組 esp32, 主要是與睡眠及喚醒功能有關之函數, 參考 :

https://docs.micropython.org/en/latest/library/esp32.html#module-esp32

>>> import esp32 
>>> dir(esp32) 
['__class__', '__name__', 'ULP', 'WAKEUP_ALL_LOW', 'WAKEUP_ANY_HIGH', 'hall_sensor', 'raw_temperature', 'wake_on_ext0', 'wake_on_ext1', 'wake_on_touch']

最後是 machine 模組, 包含重啟, 中斷, 計時器, 看門狗等硬體功能相關之函數與屬性, 參考 :

https://docs.micropython.org/en/latest/library/machine.html#module-machine

>>> import machine 
>>> dir(machine) 
['__class__', '__name__', 'ADC', 'DAC', 'DEEPSLEEP', 'DEEPSLEEP_RESET', 'EXT0_WAKE', 'EXT1_WAKE', 'HARD_RESET', 'I2C', 'PIN_WAKE', 'PWM', 'PWRON_RESET', 'Pin', 'RTC', 'SDCard', 'SLEEP', 'SOFT_RESET', 'SPI', 'Signal', 'TIMER_WAKE', 'TOUCHPAD_WAKE', 'Timer', 'TouchPad', 'UART', 'ULP_WAKE', 'WDT', 'WDT_RESET', 'deepsleep', 'disable_irq', 'enable_irq', 'freq', 'idle', 'lightsleep', 'mem16', 'mem32', 'mem8', 'reset', 'reset_cause', 'sleep', 'time_pulse_us', 'unique_id', 'wake_reason']


參考 :

[SOLVED] Failed to connect to ESP32: Timed out waiting for packet header
Flash/Upload MicroPython Firmware to ESP32 and ESP8266
[芸庭樹]安信可原廠 NodeMCU-32S Lua ESP32S開發板Arduino MicroPython

12 則留言 :

David Wang 提到...

您寫得非常詳細!
我使用chip原廠的esp32 devkit board, 之前燒錄micropython前erase flash都沒有按boot按鍵,不知道會不會有後遺症...

小狐狸事務所 提到...

Hi, 不同廠出的板子也許操作不同, 如果沒按 flash 鍵也能正常燒錄使用就不用擔心了. 我這是副廠出的板子.

xxx 開發團隊 提到...

假設我有一塊esp32
他的參數如下
SRAM 512KB
Flash 4-16MB

1.我若要燒錄把我的程式燒錄在esp32
那他就是寫入flash??有看文章,想再一次確認
2.SRAM是指我要程式,需要要記錄的值??所寫入的地方

小狐狸事務所 提到...

燒錄是指將 MicroPython 韌體寫進 flash 記憶體中以便 ESP32 有一個 Python 操作環境 (OS), 燒錄完畢後此 pYTHON OS 就有一個檔案系統了, 再用 AMPY 程式把 .PY 應用程式傳到他根目錄下執行, 主程式名稱必須為 main.py

SJ 提到...

版主您好:
最近我也正在學習ESP32 的板子用microPython 撰寫,但燒錄完microPython 的韌體後 用Putty 卻無法連線, 一直連續跑出以下的回應(按RST後還是一樣):

rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
flash read err, 1000
ets_main.c 371
ets Jun 8 2016 00:22:57

按IO0(flash) 後就停在這行
rst:0x10 (RTCWDT_RTC_RESET),boot:0x3 (DOWNLOAD_BOOT(UART0/UART1/SDIO_REI_REO_V2))
waiting for download

不知版主有經驗這是什麼情況嗎?

小狐狸事務所 提到...

應該是不穩, 不要下載最新的開發版, 下載穩定的 1.12 版試試看.

SJ 提到...

感謝版主回覆, 我找到原因了,因為ESP32的burn address 須設定為 0x1000, 但是我直接設定成跟ESP8266一樣的 0X0, 所以造成韌體燒在錯誤的位置,PuTTY 連線後,就無法正確完成開機程序了(但是燒錄時Python互動視窗還提示"燒錄成功" 真奇怪?)

想再請教版大,下方燒錄指令裡的 "-z 參數" 在哪裡可以查到? 我key in "esptool help"都沒看到相關的說明?
" esptool.py --chip esp32 --port COM8 write_flash -z 0x1000 esp32-20190711-v1.11-142-ga73859d5a.bin "

第二個問題是burn address的設定, ESP32: 0x1000, ESP8266: 0X0 在哪裡可以查詢的到呢?

THX.

小狐狸事務所 提到...

燒錯位址這個錯誤我也犯過, 但我遇到的好像是開機後出現一堆怪碼, 可能是 1.10 版之類的. 燒錯位址還是可以燒進去的, 只是載入時會出問題而已. 燒錄指令的參數我沒有深入研究, 因為我的目標只要能成功燒錄韌體, 可以馬上開始進行應用測試即可. 希望多交流!

Unknown 提到...

折腾好几天,看了你这个文章,很快烧进去了,谢谢

小狐狸事務所 提到...

謝謝留言, 其實過一段時間再玩 ESP 我也會忘記一些細節, 能幫到您我也很高興!

Spake 提到...

請問Micropython可以在ESP32中,寫入log嗎?

小狐狸事務所 提到...

MicroPython 1.12 沒有內建 logging 模組, 須用 upip 安裝. 我在 ESP8266 的 D1 Mini 上測試可用, 但不支援 filename 參數無法紀錄到檔案中, 參考 :
http://yhhuang1966.blogspot.com/2020/12/micropython-on-esp8266-logging.html