使用 MicroPython 快速開發即時微控制器架構的應用

作者:Jacob Beningo

資料提供者:Digi-Key 北美編輯群

即時嵌入式系統越來越複雜,不僅需要深入瞭解精密複雜的 32 位元微控制器,也要瞭解感測器、運算法、網際網路協定,以及多種不同的最終用戶應用。隨著開發週期縮短且功能增多,開發團隊需要設法加快設計速度,並且將程式碼移植到新產品中,因此需要使用靈活彈性的整合式開發平台。

目前有幾個微控制器專屬平台可供使用,有助於加速開發流程,但這些解決方案的問題在於,開發人員必須受限於單一家微控制器供應商。平台間的軟體移植相當耗時且費用高昂。

有個獨特且創新的解決方案目前逐漸廣受採納且前景看好,那就是將低階微控制器軟體與高階程式語言 (如 Python) 互相結合。MicroPython 就是其中一個解決方案。此語言可在多個不同的微控制器廠商零件上執行,而且採用開放原始碼,因此開發人員可立即使用並依照自身需求進行自訂。

MicroPython.org 說明 MicroPython 是一種精簡且高效率實作的 Python 3 程式語言,其中含有少量 Python 標準函式庫子集,針對在微控制器和受限環境中執行進行最佳化。MicroPython 一開始是 Kickstarter 的募資專案,後來不僅成功募資,而且吸引眾多擁護者,現已成功運用在許多產業的專案中,例如工業和太空相關系統。

選擇正確的微控制器

MicroPython 可在多種不同的微控制器上執行,而且只要具有足夠的 RAM、快閃記憶體和處理能力來執行解譯器,將 MicroPython 移植到更多微控制器方面並無重大限制。儘管如此,開發人員仍應針對要用來執行 MicroPython 的微控制器,確認是否達到以下幾項重要要求:

  • 快閃記憶體至少 256 KB
  • RAM 至少 16 KB
  • CPU 時脈至少 80 MHz

這些只是一般建議,開發人員可根據應用需求以及要花多少時間自訂 MicroPython 核心,自行從這些建議衍生要求。例如可修改 MicroPython,使用遠低於 256 KB 的快閃記憶體。這些建議的目的是讓開發人員獲得最佳體驗,並且在應用程式碼方面提供成長空間。

MicroPython 已移植到幾個不同的微控制器系列中,是移植到新平台或選擇已支援的微控制器時的絕佳起點。圖 1 顯示了 MicroPython 原始碼的主目錄。裡面列出了幾個受支援的微控制器元件,例如:

範例資料夾目錄結構圖片

圖 1:範例資料夾目錄結構顯示了目前支援 MicroPython 的微控制器平台。其中包括 ARM、CC3200、esp8266、Microchip PIC 和 STM32。(圖片來源:Beningo Embedded Group)

根目錄中的各個資料夾皆為高階資料夾,其中含有該晶片系統的通用驅動程式和支援項目。各資料夾中可能有幾個獲得支援的開發板或處理器。例如,stmhal 資料夾支援 STMicroelectronics 的 STM32F429 探索板和 STM32 IoT Discovery Node (STM32L) 等開發板,以及 Adafruit Industries 的 STM32F405 pyboard 等其他板件。ESP8266 資料夾的支援適用於 ESP8266 和 Feather Huzzah 堆疊板的 Adafruit Huzzah 分接板。

可執行 MicroPython 的開發板價格不高,開發人員可購買幾片來感受一下該應用需要多少記憶體、儲存空間和處理能力。例如,開發人員可能先使用 STM32F405 pyboard,然後決定在最終產品中改用 STM32F429,以便達到符合未來需求的功能和升級項目。STM32F429 具有 2 MB 快閃、256 KB RAM,以及特殊的 0-wait-state RAM (稱為 CCM)。

開發人員撰寫的 MicroPython 應用程式碼不一定要儲存於微控制器的內部快閃中。雖然 MicroPython 的核心需要位於微處理器上,但應用程式碼可以在外部儲存媒介上,例如 PanasonicmicroSD 8 GB 記憶卡。使用外部記憶體儲存裝置來儲存應用程式碼,就有機會使用記憶體較少的微控制器,還可能節省整體系統支出。

設定並執行 MicroPython

MicroPython 預先安裝在 Adafruit 的 STM32F405 pyboard 上。不過,其他任何開發工具或自訂硬體則需要開發人員下載 MicroPython 原始碼,並針對目標板建構原始碼,然後用軟體來刷寫微控制器。取用 MicroPython 原始碼很容易,因為全都託管在 GitHub 上。開發人員需要遵循幾個步驟來設定工具鏈並設定環境,以便建立 MicroPython。在此範例中,我們將針對 STM32F429 探索板建立 MicroPython。

首先,建議開發人員建立 Linux 架構的虛擬機,或使用原生 Linux 安裝版本。一旦可從終端機取得 Linux,開發人員即可使用以下命令來安裝 ARM 編譯器工具鏈:

sudo apt-get install gcc-arm-none-eabi

 

如果剛安裝完 Linux,版本修訂控制系統 Git 可能尚未安裝。可依照以下命令,從終端機安裝 Git:

 

sudo apt-get install git

 

一旦安裝好 Git,可在終端機中執行以下命令,從儲存庫核發 MicroPython 原始碼:

 

git clone https://github.com/micropython/micropython.git

執行此程序可能要耗用幾分鐘,不過開發人員應該可看到圖 2 所展示的序列。

將 MicroPython 儲存庫複製到本機檔案系統示意圖

圖 2:將 MicroPython 儲存庫複製到本機檔案系統中,開發人員即可在此針對目標板建立 MicroPython,或針對其專屬應用來自訂核心。(圖片來源:Beningo Embedded Group)

一旦將 MicroPython 原始碼複製到本機檔案系統中,應立刻切換到該目錄,然後在終端機內執行執行「cd stmhal」。stmhal 目錄內含有 STM32 微控制器用的 MicroPython makefile。也有一個「boards」資料夾可供開發人員檢視,會列出所有目前支援的 STM32 板件。開發人員即可從終端機打造「boards」資料夾中所列的任何板件。例如,開發人員可以鍵入以下命令,建立 STM32F4 探索板:

make BOARD=STM32F4DISC

MicroPython 需數分鐘後才會建立。在建立期間,開發人員可安裝裝置韌體更新 (DFU) 工具,此工具可透過 USB 將 MicroPython 編程到微控制器上。此工具僅需安裝一次,在終端機上鍵入以下命令即可完成:

sudo apt-get install dfu-util

MicroPython 建立完成且 dfu-util 安裝後,開發人員接著便能在微控制器上載入 MicroPython。開發人員首先需要讓微控制器進入 DFU 開機載入器模式。作法是設定開機引腳,在重置時載入內部開機載入器,而不是從快閃記憶體執行程式碼。

當微控制器處於開機載入器模式並透過 USB 連接至主機電腦,就可利用 dfu-util 用下列命令下載 MicroPython:

dfu-util -a 0 -d 0483:df11 -D build-STM32F4DISC/firmware.dfu

dfu-util 會使用由編譯程序所輸出的 dfu 檔案。此程序將花上幾分鐘的時間,因為微控制器會完全抹除並重新編程。此程序的畫面與圖 3 顯示的程序很類似。工具完成後,應立即調整開機跳接線,以從內部快閃記憶體來載入,然後微控制器就可進行電源循環。MicroPython 即可在目標微控制器上執行。

利用 dfu-util 將 MicroPython 載入到微控制器的示意圖

圖 3:利用 dfu-util 將 MicroPython 載入到微控制器。(圖片來源:Beningo Embedded Group)

感測器和相連裝置的介接

使用 MicroPython 等高階程式語言開發即時嵌入式軟體的最大優勢在於,軟體能在任何底層硬體上執行。這表示開發人員所開發的 MicroPython 指令碼能在 pyboard 上執行,而且僅需少許甚至完全不需要修改,就可以在 ESP8266 或 STM32F4 探索板上執行。讓我們以一個基本的 MicroPython 指令碼為例。此指令碼將 Bosch Sensortec BMP280 氣壓計和溫度感測器介接到 I2C 匯流排,然後使用 Microchip Technology RN-42 藍牙模組以藍牙序列鏈路來傳輸資料。

BMP280 是以 I2C 為基礎的氣壓計和溫度感測器,預設的 I2C 從屬位址為十進位 119。將其介接至 pyboard 最簡單的方法是使用 DFRobotGravity 板,此板件提供了穩固的連接器可輕鬆存取,以驅動元件和存取 I2C。開發人員可選擇 I2C1 或 I2C2 匯流排來連接 Gravity 板。板連接後,MicroPython 指令碼的部分就很簡單了。

首先,開發人員將從 pyb 函式庫匯入 I2C 等級。pyb 函式庫可供存取微控制器周邊裝置功能,例如 SPI、I2C 和 UART。在使用任何周邊裝置之前,開發人員必須將周邊裝置等級進行例項化,以建立可用來控制周邊裝置的物件。周邊裝置等級初始化後,開發人員就可進行其他初始化作業,例如在進入主要應用迴路之前確認元件的存在。主要的應用程式碼之後將對感測器每秒取樣一次。作法如範例所示 (程式碼列表 1)。

Copy
from pyb import I2C
 
GlobalTemp = 0.0
GlobalBarometer = 0.0
 
# Initialize and Instantiate I2C peripheral 2
I2C2 = I2C(2,I2C.MASTER, baudrate=100000)
 
while True:
            SensorSample()
            pyb.delay(1000)
 
def SensorSample():
            #Read the Temperature Data
            TempSample = I2C2.readfrom_mem(119, 0xFA,3)
 
            #Read the Pressure Data
            PressureSample = I2C2.readfrom_mem(119, 0xF7,3)

程式碼列表 1:MicroPython 指令碼將 I2C 周邊裝置初始化,並與 DFRobot Gravity 板通訊,以取得溫度和氣壓計感測器資料。(程式碼來源:Beningo Embedded Group)

對感測器資料進行取樣但不對此資料採取任何動作,無法有效證明 MicroPython 能為開發團隊帶來的強大能力。許多開發團隊正面臨技術挑戰,難以將感測器元件連接到網際網路或利用藍牙連接至本機感測器中樞。

使用 RN-42 就可輕鬆在專案內增添藍牙功能。RN-42 提供一種模式,能讓微控制器只傳送應透過藍牙傳輸的 UART 資料,再由 RN-42 處理整個藍牙堆疊 (圖 4)。

執行 MicroPython 的 pyboard 透過 UART 連接到 RN-42 藍牙模組示意圖

圖 4:透過 UART 將執行 MicroPython 的 pyboard 連接到 RN-42 藍牙模組。(圖片來源:Beningo Embedded Group)

一旦連接藍牙板,開發人員就可建立一個非常簡單的指令碼,透過藍牙將獲得的感測器資料傳輸至行動裝置,再由裝置將資料儲存或轉送至雲端以供日後分析。範例程式碼如程式碼列表 2 所示。在此範例中,UART1 針對 115200 bps、8 位元傳輸進行配置,無同位和單一停止位元。

Copy
from pyb import uart
from pyb import I2C
 
GlobalTemp = 0.0
GlobalBarometer = 0.0
 
# Initialize and Instantiate I2C peripheral 2
I2C2 = I2C(2,I2C.MASTER, baudrate=100000)
 
# Configure Uart1 for communication
Uart1 = pyb.UART(1,115200)
Uart1.init(115200, bits=8, parity=None, stop=1)
 
while True:
            SampleSensor()
            pyb.delay(1000)
 
def SensorSample():
            #Read the Temperature Data
            TempSample = I2C2.readfrom_mem(119, 0xFA,3)
 
            #Read the Pressure Data
            PressureSample = I2C2.readfrom_mem(119, 0xF7,3)
 
            #Convert Sample data to string
            data = “#,temperature=”str(TempSample)+”,pressure”+str(PressureSample)+”,#,\n\r”
 
            #Write the data to Bluetooth
            Uart1.write(data)

程式碼列表 2:範例 MicroPython 指令碼將 UART1 初始化,並與外部裝置通訊。(程式碼來源:Beningo Embedded Group)

Python 應用程式碼不僅可輕鬆移植到其他硬體平台,應用程式也使用通用函式庫,並使用已實作來協助開發人員加速開發作業的功能。打造上述應用程式僅需依小時甚至更短的時間,相較之下,開發人員如果從最底層軟體一路往上進行則可能需要一週甚至更久。

開發即時軟體的秘訣和技巧

使用 MicroPython 開發嵌入式應用很容易,但從系統取得即時效能可能不如想像中簡單。雖然 MicroPython 有龐大優勢可簡化並再次使用程式碼,但如果開發人員不瞭解幾個有趣的事實和函式庫,可能很難從系統取得可預測且一致的時序。

MicroPython 具有在背景中執行的記憶體回收行程,並管理堆積記憶體和其他記憶體資源。記憶體回收行程不具決定性,因此假如記憶體回收行程開始在時間關鍵區段中執行,期待會有決定性行為的開發人員將遭遇麻煩。開發人員應遵守幾項建議,確保避免發生此情況。

首先,開發人員可匯入 gc 這個記憶體回收行程函式庫,並使用啟用和停用方法來控制何時啟用或停用記憶體回收行程。開發人員可在某個關鍵區段前停用記憶體回收行程,之後再予以啟用,如以下程式碼列表 3 所示。

Copy
import gc
 
gc.disable()
 
#My time critical code
 
gc.enable()

程式碼列表 3:在時間關鍵程式碼區段前停用 MicroPython 記憶體回收行程。(程式碼來源:Beningo Embedded Group)

其次,開發人員亦可手動控制記憶體回收行程的流程。開發人員建立和損毀物件時,這些物件會在堆積記憶體上分配記憶體。記憶體回收行程會執行並釋放未使用的空間。由於此流程不定期進行,開發人員可以使用收集方法定期執行記憶體回收行程,確保堆積空間不會裝滿無用的項目以至滿溢。完成此動作後,記憶體回收行程每次執行時間可從 10 毫秒縮短到不到 1 毫秒。手動調用記憶體回收行程,也可確保開發人員的應用程式能控制不具決定性的計時程式碼。這可讓開發人員決定何時執行記憶體回收行程,並確保應用程式具備即時效能。

有意編寫即時程式碼的開發人員,亦可參考其他幾種最佳作法。作法包括:

  • 針對通訊通道使用預先分配的緩衝器
  • 使用通訊周邊裝置時使用 readinto 方法
  • 避免使用 ### 的傳統 Python 文件
  • 徹底避免在執行時間內建立和損毀物件
  • 監控應用執行時間

開發人員如果有興趣瞭解更多「最佳作法」,可在此處查看 MicroPython 最佳化文件。

結論

如果開發人員希望實作能在任何底層微控制器硬體上執行的即時嵌入式應用程式,會對 MicroPython 平台感興趣。開發人員可以使用 MicroPython 提供的標準函式庫編寫高階 Python 指令碼,並在任何支援的微控制器上執行。這為開發人員帶來許多優點,包含:

  • 提升應用程式的再次利用率
  • 加速產品上市
  • 將應用程式從硬體中抽離

MicroPython 即便無法在各種應用中完美發揮,但目前已在工業和太空系統應用中順利運用,同時亦可用於快速原型開發和概念驗證。

聲明:各作者及/或論壇參與者於本網站所發表之意見、理念和觀點,概不反映 Digi-Key Electronics 的意見、理念和觀點,亦非 Digi-Key Electronics 的正式原則。

關於作者

Jacob Beningo

Jacob Beningo 是嵌入式軟體顧問,目前與超過十幾個國家的客戶合作,透過產品品質、成本和上市時間的改善,促成業務的大幅轉型。他曾在嵌入式軟體開發技術上發表超過兩百篇文章,是深思熟慮的講師和技術培訓師,共擁有三個學位,包括密西根大學的工程碩士學位。歡迎透過以下方法洽詢,電郵:jacob@beningo.com、網站:www.beningo.com,亦可登記取得他發行的Embedded Bytes 每月電子報

關於出版者

Digi-Key 北美編輯群