如何為 esp32 編譯和配置及燒寫 MicroPython 固件。


MicroPython 在 esp-idf (esp32) 上編譯固件

esp32 編譯 micropython 的固件相關的資料應該很多吧,我也會出一篇,但會額外講一些 linux 的東西的。

資料將按照以下順序進行說明。

  • 什么是 esp-idf ?
  • 配置 esp32 工具鏈
  • 准備 micropython 倉庫
  • 建立 micropython for esp32 固件

注意,以下操作截圖全部在 linux 下完成(but 我在虛擬機,方便截圖),順便一提,我寫的資料,並不會考慮開發新手,如果有問題可以評論解答,但我是不會在寫的內容中照顧他人的,隨心所欲,但是有問題歡迎來提。

什么是 esp-idf ?

esp-idf 就是 esp32 的官方標准 SDK 支持,進入倉庫看下 readme 即可,但在這里並非必要了解的知識。

往下看前請先准備 esp-idf 的官方文檔,進入 快速開始 一章,按步驟開始部署開發環境。

配置 esp32 交叉編譯工具鏈

因為在電腦上寫的程序將要編譯運行在 esp32 上,所以這必然就需要交叉編譯工具鏈,所以寫代碼先需要先配置好編譯環境。

值得一提的是官方的配置文檔(/get-started/linux-setup)寫的流程很好,所以照着做就行,但要注意的是,它們都是在 i686(i386) 或 ARM64 上的機器上跑的二進制(bin)文件,如果需要在類似樹莓派的 arm linux 上編譯,則需要重新編譯工具鏈了。

請准備一台 linux 按上述官方配置文檔配置完成后,在命令行下輸入 xtensa-esp32-elf 然后按 tab 鍵補全系統命令,確認配置完成,如下圖。

注意工具鏈相關的文件需要綁定到系統全局下,作為命令(符號)給 makefile 接入。

所以記得在 linux 環境變量里添加路徑,例如配置文檔里講的,至此編譯環境已經建立,注意,不同版本的 idf 可能會變更 工具鏈 ,所以編譯出錯的時候不妨檢查檢查 esp-idf 和 工具鏈 是否匹配。

export PATH="$HOME/esp/xtensa-esp32-elf/bin:$PATH";

至於如果你想編譯工具鏈,可以繼續看官方文檔 從零開始設置 Linux 環境下的工具鏈 ,可喜可賀的是如今都有中文了鴨,上述我們設置的是編譯后的二進制版本,如果想學習工具鏈的本質,就要親自試試編譯工具鏈了。

交叉編譯工具鏈源碼倉庫 在這里 ,是很值得學習的開源代碼呢。

准備 micropython 倉庫

看到這里,我希望你已經按上述的文檔和步驟,成功搭建 esp32 的編譯環境和獲取 esp-idf 源碼。

如果發現 git clone 很慢,記得在尾巴添加 --depth=1 的命令,讓它不要獲取歷史提交(commit),這樣下載就會快很多了。

  • 准備好工具鏈xtensa-esp32-elf
  • 准備好開發 SDK 的倉庫 esp-idf 。
  • 看一眼 esp32 目錄下的 readme.md 。

通過下述命令獲取 micropython 的倉庫。

$ git clone https://github.com/micropython/micropython --depth=1

接着編譯一下 mpy-coress ,用來給 Python 文件預編譯為 bytecode 到固件里的工具鏈。

$ make -C mpy-cross

然后初始化一下相關的子倉庫。

$ git submodule init lib/berkeley-db-1.xx
$ git submodule update

最后在編譯(make)一下。

$ cd ports/esp32
$ make

此時編譯就開始了,會有如下滾動信息。

大致是這樣的流程,但要注意的是我這里只是簡化了操作,接着說一下下述幾個注意點。

注意看 micropython/port/esp32 的 readme.md 。

有如下內容:

Setting up the toolchain and ESP-IDF
------------------------------------

There are two main components that are needed to build the firmware:
- the Xtensa cross-compiler that targets the CPU in the ESP32 (this is different to the compiler used by the ESP8266)
- the Espressif IDF (IoT development framework, aka SDK)

The ESP-IDF changes quickly and MicroPython only supports a certain version. The
git hash of this version can be found by running `make` without a configured
`ESPIDF`. Then you can fetch only the given esp-idf using the following command:

    $ git clone https://github.com/espressif/esp-idf.git
    $ git checkout <Current supported ESP-IDF commit hash>
    $ git submodule update --init --recursive

所以沒事多看 readme ,比看一般人的博客強多了,所以我這里主要是交待一些編譯的方法和常見錯誤的坑。

上述的意思很簡單,就是 micropython 依賴於 esp-idf ,但是需要切換 esp-idf 的版本,也就是說隨着 micropython 不一定會支持最新的 esp-idf 代碼,如果出現錯誤,你需要通過 git checkout 切換版本號。

命令格式示范:git checkout <Current supported ESP-IDF commit hash>

而尾巴的<hash> 存放在 Makefile 文件中的,如下內容。

# the git hash of the currently supported ESP IDF version
ESPIDF_SUPHASH := 6b3da6b1882f3b72e904cc90be67e9c4e3f369a9

所以在 esp-idf 的目錄下有如下操作(注意和 readme 有點點不同鴨)

$ cd esp-idf
$ git checkout 6b3da6b1882f3b72e904cc90be67e9c4e3f369a9
$ git submodule update --init --recursive

那么現在就可以繼續編譯 esp32 的 micropython 了。

此時注意,雖然前面說過直接 make 是可以,但實際上官方的做法是額外在 ports/esp32 里准備一個 makefile ,並且區別於 Makefile 文件(Linux 文件區分大小寫),按 readme 所述填下列內容即可。

ESPIDF = <path to root of esp-idf repository> # such as ESPIDF = /root/esp-idf
BOARD = GENERIC
# PORT = /dev/ttyUSB0
# FLASH_MODE = qio
# FLASH_SIZE = 4MB
# CROSS_COMPILE = xtensa-esp32-elf-

include Makefile

注意這里可以指定填寫你的 ESP-IDF 路徑,這樣做的好處就是不需要添加到系統環境變量中了,所以你可以同時擁有許多份不同工程用的 esp-idf 倉庫,並且此時 make 命令調用的是 makefile ,接着 makefile 末尾將會調用 Makefile(即 include Makefile),其他內容可以選填(# 為注釋),相當於預先為 Makefile 的執行載入環境變量。

此時就開始編譯固件吧,編譯成功如下圖:

此時常用命令有如下(查閱 readme 可知):

  • 打開串口收發,組合 Ctrl + A 和 Ctrl + Q 退出串口(需要安裝 picocom )
$ picocom -b 115200 /dev/ttyUSB0
  • 擦除 esp32 中 flash 。
$ make erase
  • 編譯后燒錄 micropython 固件。
$ make deploy
  • 清理編譯結果。
$ make clean
  • 組合命令,燒錄完固件后打開串口。
$ make deploy && picocom -b 115200 /dev/ttyUSB0

如下圖運行結果:

順手輸入了 print('hello esp32') ,值得注意的是,這里也支持 tab 補全操作多多體驗吧。

額外的信息

為什么固件只有一個 firmware.bin 文件?

固件編譯后的 firmware.bin 文件產生在 port/esp32/build 文件夾,它是通過 makeimg.py 合成的,看一下就知道發生了什么。

import sys

OFFSET_BOOTLOADER = 0x1000
OFFSET_PARTITIONS = 0x8000
OFFSET_APPLICATION = 0x10000

files_in = [
    ('bootloader', OFFSET_BOOTLOADER, sys.argv[1]),
    ('partitions', OFFSET_PARTITIONS, sys.argv[2]),
    ('application', OFFSET_APPLICATION, sys.argv[3]),
]
file_out = sys.argv[4]

cur_offset = OFFSET_BOOTLOADER
with open(file_out, 'wb') as fout:
    for name, offset, file_in in files_in:
        assert offset >= cur_offset
        fout.write(b'\xff' * (offset - cur_offset))
        cur_offset = offset
        with open(file_in, 'rb') as fin:
            data = fin.read()
            fout.write(data)
            cur_offset += len(data)
            print('%-12s% 8d' % (name, len(data))) 
    print('%-12s% 8d' % ('total', cur_offset))

可以得知,firmware.bin 是由 bootloader + partitions + application 而來的一個單獨的 bin ,即為固件,所以只需要在 0x1000 起始位置燒入 esp32 的 flash 里就可以運行 micropython 了。

如何編譯 8M spiflash 的固件?

此外我們還需要知道如何編譯帶 SPIRAM 固件,通常來說,只需要修改 makefile 的 BOARD = GENERIC_SPIRAM

ESPIDF = <path to root of esp-idf repository> # such as ESPIDF = /root/esp-idf
BOARD = GENERIC_SPIRAM
include Makefile

不過你也可能會遇到一些問題,比如我修改了編譯工具鏈里的一些頭文件才編譯通過的,所以得做好准備隨時修改源碼的准備趴。

至於我遇到了什么問題,唔,改一下編譯中的文件之間的符號關系就好了。

編譯后運行可以看到 Found 64MBit SPI RAM device ,然后查看 gc.mem_free() 可以看到 3997 * 4096 Byte,也就是 4M RAM ,如下圖(帶有 SPIRAM 的固件)。

下圖就是對照的無 Flash 固件,可以看到 111 * 1024 的,用的是內部的 RAM (小於 384 KB)。

結語

最后,如果遇到在本文的流程下出現編譯問題,可以留言,也可以直接問我。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM