ESP32是近年很火的國產低成本MCU系列。
買了晶片ESP32-C3
的模組安信可 ESP-C3-32S
的開發板安信可 NodeMCU ESP-C3-32S-Kit
。開發板很小,沒有任何多餘的東西,還不如叫它「最小系統+最小連線板」。
燒錄只需要以上加一條microUSB線就可以,不用買任何的232 TTL、燒錄器之類的,開發板上有USB轉串列埠的晶片。
另外,看檔案說,改變接線後,可以啟用USB JTAG(無需任何額外晶片),然後可以單步偵錯、看暫存器之類的(有對應的開源跨平臺軟體openocd)。這一開發板也引出了USB資料的兩個pin
便宜是便宜,但買得不夠好。不好的原因及造成的限制:
ESP32-C3
這個晶片型號是RISC-V架構。若使用MicroPython,那麼MicroPython的native code或viper(這兩個東西能讓python寫的東西執行更快)都尚未支援。ESP32-Cx屬於ESP32系列中的便宜精簡系列。要求高的建議買ESP32系列的其他架構的型號。
這個模組配的Flash只有2M。MicroPython官方提供的bin檔案(1.4M左右)雖然足夠燒進去,但功能有問題。建議至少選4M Flash的。
不過還好
- 這裡有個老外編譯了2M Flash版本的ESP32C3的MicroPython的bin。版本號
1.16.0 210824 v1.16-236-gb51e7e9d0
,python 3.4.0。其中也包括他修改自己的安信可開發板,焊上缺失的兩個開關管的說明。- (建議)我自己編譯了MicroPython 1.19 for ESP32-C3 2M Flash
若選CircuitPython: 這是MicroPython的衍生版。它提供針對這一開發板的2M Flash韌體adafruit-circuitpython-ai_thinker_esp32-c3s-2m-en_US-7.3.3.bin
。Python 3.4.0
這個開發板買回來缺少兩開關管,和幾個0402的電阻電容。可能就是這個原因,導致ampy(一個PC上的與MicroPython通訊的工具,非必須)無法使用。不過我也試出了補救方法。你可以像上面那個老外那樣自己焊上去,也可以用我這裡將要介紹的經驗,在不用ampy的情況下使用
以下描述都是在Linux下進行。Windows使用者請將串列埠
/dev/ttyUSB0
自行替換為Windows的COM
使用esptool.py
清除整個Flash(必須)。其中的esptool.py
來自ESP官方IDF
燒錄:
esptool.py --chip esp32c3 --port /dev/ttyUSB0 write_flash -z 0x0 firmware_gereric_c3_2mb_210824.bin
(下載上面連結的老外提供的MicroPython .bin
檔案。(你若願意自己編譯更好).bin
或選擇CircuitPython
esptool.py --chip esp32c3 --port /dev/ttyUSB0 write_flash -z 0x0 adafruit-circuitpython-ai_thinker_esp32-c3s-2m-en_US-7.3.3.bin
使用Linux上picocom這個串列埠工具
picocom -b 115200 --lower-dtr --lower-rts /dev/ttyUSB0
連路由器的wifi也可以。若是想在Linux電腦上設個專門的wifi也行:
sudo lnxrouter --ap wlan0 ssid -p 密碼 -g 192.168.5.1
我們想要在Flash上建立wifi.py
、main.py
(在boot.py
之後韌體會自動呼叫main.py
),實現啟動後自動連線wifi。由於目前ampy不可用,所以,在python shell中利用檔案讀寫函數來建立檔案
fileContent = """
import network
nic = network.WLAN(network.STA_IF)
nic.active(True)
nic.ifconfig( [ "192.168.5.20", "255.255.255.0", "192.168.5.1", "192.168.5.1" ])
nic.connect("ssid", "密碼")
"""
wfile = open('wifi.py','w')
wfile.write(fileContent)
wfile.flush()
wfile.close()
fileContent = """
import wifi
"""
wfile = open('main.py','w')
wfile.write(fileContent)
wfile.flush()
wfile.close()
以上是MicroPython的。CircuitPython的wifi函數都不一樣,略
webREPL是MicroPython帶的東西,可以在電腦和ESP的Flash之間傳檔案上傳、下載檔案,也可以提供無線python shell。有了這個就能夠快速更新.py
程式碼,相當於可以OTA。(它是通過websocket協定通訊的。)
用python shell時還是串列埠線好用,無線webREPL的輸入和回顯有延時
CircuitPython那邊,似乎還沒有這樣完整的一套無線shell和無線傳檔案的東西。有相關討論、有一些檔案,略看了一下,還不完整不易用。
在MicroPython的python shell中:
>>> import webrepl_setup
WebREPL daemon auto-start status: enabled
Would you like to (E)nable or (D)isable it running on boot?
輸入E
。然後會讓你設定密碼。完成之後它會改寫boot.py
,並建立webrepl_cfg.py
用於記錄密碼
用來當OTA升級程式真的快。
把webREPL倉庫裡的檔案下載下來。裡面的HTML可以用瀏覽器開啟(Firefox不支援),即可以獲得一個GUI介面。
雖然有web GUI,但頻繁的上傳.py
檔案當然是用CLI更快:
./webrepl_cli.py -p 密碼 /電腦上的路徑/test.py 192.168.5.20:test.py
上傳了test.py
後,平時就可以在python shell裡使用
exec(open('test.py').read())
(用
import test
也會執行,但與exec
不一樣)
來直接執行該檔案
import machine
pin5 = machine.Pin(5, machine.Pin.OUT)
pin5.value(0)
pin5.value(1)
from machine import Pin
from machine import ADC
pin0 = Pin(0, Pin.IN)
ad0 = ADC(pin0)
ad0.read_u16()
串列埠的預設115200的baud很慢。在有大量文字輸出時,不如電腦用wifi UDP接收。經測試,電腦顯示最快達到過1MB/s接收速度。
在電腦上:
nc -k -u -l 0.0.0.0 9995
在MicroPython那邊:
import socket
u = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
def log(s) :
u.sendto(str(s)+'\n' , ('192.168.5.1', 9995) )
log("xxxxxx")
但要注意:
while
連續地使用UDP的sendto()
函數,有時會出現ENOMEM
錯誤(有時換個wifi ap可以避免)。要try
處理一下gc.collect()
、time.sleep_ms()
、重發。ESP32C3手冊說支援5M baud。開發板上的CH340C串列埠轉USB晶片說支援2M baud。實測調成2M(即200kB/s)在連續傳送時有位元組丟失。調成1M baud(即100kB/s)則無問題。
記憶體:經測試,gc.mem_free()
顯示的可用記憶體,MicroPython最大時有約110kB(在gc.collect()
過之後)。據說自己編譯MicroPython,改些引數,就可以讓使用者可分配的記憶體更多。而CircuitPython有87kB。這一晶片的實際記憶體是300kB+。
速度:Python解析執行起來肯定比C慢(據說慢100倍)。
MicroPython的time
模組裡有一些可以用於記錄時間的函數:
import time
time.ticks_cpu() # 據說最精確
time.ticks_us() # 微秒
time.ticks_ms() # 毫秒
經試驗,每通過python語句執行一個與硬體有關的操作,至少需要30us。
而CircuitPython則是用
import time
time.monotonic_ns()
可以看時間。
這速度,在有實時性高的需求時,不啟用DMA或native code或viper肯定是不行的。但risc-v架構還不能使用MicroPython的native或viper。(所以目前ESP32的「C3」這個型號在這種情況下不建議選用)
另外,測試了MicroPython的長時間執行一個有實時性要求的任務。剛開始10分鐘內沒什麼問題的,但幾分鐘後,開始有多次時不時的定時器中斷不能及時響應的現象。所以,它還算不上一個可靠的實時系統。
MicroPython只對部分的型號新增了DMA模組,我們這個還沒有支援DMA。
但MicroPython支援用mem32
,mem16
,mem8
來直接讀寫任何地址,也就可以設定MCU暫存器,來讓DMA工作。也可以操作任何的硬體模組。
CircuitPython目前未實現直接讀寫任何地址。
由於樂鑫官方ESP-IDF提供了大量example,多於MicroPython已支援的。
MicroPython的韌體本身就是C寫的,用ESP-IDF編譯出來的。為了不浪費ESP官方的example,應該學習一下如何搞自己的python韌體編譯進MicroPython裡。
官方檔案:
或者參考上面我自己編譯的例子
官方晶片手冊檔案寫得不夠完整,不如ESP-IDF完整。手冊中會出現某部分篇章未完成(已是極少量了)之類的提示。
試過自己設定暫存器,結果出現過這樣的狀況:1. 發現過手冊中的錯誤。 2. 按照手冊裡的軟體流程做,失敗。利用ESP-IDF裡的examples才成功。
子曰,玩而予賞,善莫大焉?
又曰,玩而不賞,良心安焉?
寫作不易,感謝支援!
雖然,小小玩意,不足掛齒;
亦是,卅年老刀,獻醜於此。
其實,多賞非求,少許亦可。
進者,參觀主頁,玩物更多。