MoonBit支持國產芯片開發--性能媲美C

MoonBit支持國產芯片開發–性能媲美C

在 ESP32-C3 上實現生命游戲

過去,我們曾在文章《硬件實現:在ESP32-C6單片機上運行MoonBit WASM-4小游戲》中,展示了如何通過 WebAssembly (WASM) 將 MoonBit 程序移植到物理硬件,初步探索其在嵌入式領域的潛力。
而如今,隨著 MoonBit Native 后端 的正式發布: MoonBit 支持 Native 后端,MoonBit 邁出了關鍵一步:無需再依賴 WebAssembly 作為中間層,代碼可以直接以原生形式運行在嵌入式硬件之上
這項進步不僅顯著提升了性能和資源利用效率,也為 MoonBit 深度整合進嵌入式與物聯網生態、直接控制硬件設備,奠定了堅實基礎。

為了具體展示 MoonBit Native 在嵌入式開發中的優勢,本文將通過一個經典實例——在樂鑫 ESP32-C3 芯片(或其 QEMU 仿真環境)上實現“康威生命游戲”——來進行探討。

  • 生命游戲是一個非常經典的細胞自動機,在一個二維網格上模擬細胞的生死演化。每個細胞的狀態(存活或死亡)根據其周圍 8 個鄰居的狀態,在離散的時間步中同時更新。基本規則包括:存活細胞在鄰居過少(<2)或過多(>3)時死亡,在鄰居適中(2或3)時繼續存活;死亡細胞在正好有 3 個存活鄰居時“復活”。
  • ESP32-C3 是一款流行的低成本、低功耗 RISC-V 微控制器,資源相對有限。生命游戲對計算和內存訪問有一定要求,使其成為檢驗嵌入式系統性能和編程語言效率的理想模型。我們的目標是利用 MoonBit 編寫生命游戲的核心邏輯,并將其運行結果顯示出來。不僅支持在連接了 ST7789 LCD 的真實 ESP32-C3 硬件上運行,也支持在開發機上通過 QEMU 仿真環境運行,以方便開發和驗證。

準備工作

在開始之前,請確保你的系統中安裝了樂鑫官方提供的鏈接: ESP IDF 開發框架。請參考鏈接: ESP官方文檔,當前支持的ESP-IDF(樂鑫物聯網開發框架)版本為 v5.4.1。若希望使用 QEMU 仿真,請參考樂鑫官方文檔中的鏈接: QEMU模擬器章節安裝相關工具鏈。

本文使用MoonBit native后端生成C代碼,并且借助鏈接: moonbit-esp32 包將MoonBit項目打包為靜態鏈接庫,以嵌入到標準的ESP-IDF項目中。 moonbit-esp32 庫的核心功能體現在其 components 包中。這個目錄扮演著關鍵的橋梁角色,專門負責提供 MoonBit 語言到 ESP-IDF中各種核心組件功能的綁定。具體來說,該目錄下包含了多個子模塊,例如 gpio (通用輸入輸出)、 spi(串行外設接口)、 lcd(液晶顯示屏控制,包含通用接口和特定驅動如 ST7789 的封裝)、 task(封裝 FreeRTOS 任務管理)以及 qemu_lcd(針對 QEMU 仿真環境的 LCD 接口)。每一個子模塊都封裝了對應的 ESP-IDF C API,允許開發者使用類型安全、更符合 MoonBit 語言習慣的方式來直接操作 ESP32 的硬件外設和系統服務,從而將 MoonBit 的現代語言特性帶入底層嵌入式開發。

本文相關代碼位于 鏈接 倉庫中的 game-of-life 子目錄中。

注意:本文所述的開發與測試流程僅在 macOS 系統上驗證通過,其他操作系統用戶可能需要根據平臺差異自行進行調整。

生命游戲邏輯的實現

相關代碼位于game.mbt 文件中。

  1. 首先我們定義DEAD 定義為 0ALIVE 定義為 Int16 類型的-1 。這里定義ALIVE-1 而不是1 是一個巧妙的優化:在 RGB565 顏色格式下,00x0000)恰好代表黑色,而 -10xFFFF )恰好代表白色。這樣,在將游戲狀態數據傳輸給 LCD 時,可以省去顏色轉換的步驟。
  2. 網格大小由ROWSCOLS (均為 240) 定義。cells 使用一個一維 FixedArray 全局變量來存儲整個二維網格的當前狀態。FixedArray 是固定大小的數組,大小為 112.5KB(240 * 240 * 2 / 1024)。因為ESP32-C3可用內存約有320KB,且并不是連續的,所以next數組沒有定義成完整的下一個狀態副本,而是定義為一個 3 行滾動緩沖區,大小約為1.4KB。我們通過模運算循環使用這三行空間來存儲計算中的下一代狀態,并采用延遲提交策略將計算完成的舊行寫回cells ,以降低內存使用峰值。

const DEAD : Int16 = 0
const ALIVE : Int16 = -1pub const ROWS : Int = 240
pub const COLS : Int = 240let cells : FixedArray[Int16] = FixedArray::make(ROWS * COLS, 0)
let next : FixedArray[Int16] = FixedArray::make(3 * COLS, 0)

在計算下一個狀態時,核心代碼如下:

let live_neighbors = live_neighbor_count(row, col)
let next_cell = match (cell, live_neighbors) {(ALIVE, _..<2) => DEAD  // 優雅地用范圍模式匹配鄰居數小于2的情況(ALIVE, 2 | 3) => ALIVE // 使用或模式, 將鄰居數為2或3的情況合并在一個分支(ALIVE, 3..<_) => DEAD  // 用范圍模式匹配鄰居數大于3的情況(DEAD, 3) => ALIVE(otherwise, _) => otherwise // 必須考慮所有情況, 編譯器會進行窮盡性檢查
}

這是實現生命游戲規則的核心,充分展現了 MoonBit 模式匹配的強大和優雅。生命游戲的規則被近乎直譯地映射到 MoonBit 的 match 模式匹配語句中,代碼清晰、直觀且不易出錯。

此外,在需要性能的場景,MoonBit提供了對數組的unsafe操作。這在性能關鍵路徑上消除了數組邊界檢查的開銷,是嵌入式開發中為了榨取極致性能的常用手段,但需要開發者確保邏輯的正確性。

最后,對比 QEMU(仿真)版本和 ST7789(硬件)版本的 main.mbt 文件。
與 QEMU 虛擬 LCD 面板相關的邏輯位于 game-of-life/qemu/src/main/main.mbt,關鍵代碼摘錄如下:

let panel = @qemu_lcd.esp_lcd_new_rgb_qemu(@game.COLS, @game.ROWS, BPP_16)..reset!()..initialize!()
@game.init_universe()
for i = 0; ; i = i + 1 {let start = esp_timer_get_time()panel.draw_bitmap!(0, 0, @game.ROWS, @game.COLS, cast(@game.get_cells()))@game.tick()let end = esp_timer_get_time()println("tick \\\\{i} took \\\\{end - start} us")
}

這段代碼借助MoonBit ESP32 binding,首先初始化一個用于 QEMU 仿真的虛擬 LCD 面板,并對其進行復位和初始化設置。這段 MoonBit 代碼利用了級聯運算符 (..) 和錯誤處理(!)。

  • 首先創建 panel 對象。
  • 接著,..reset!() 使用級聯運算符,在 panel 上調用 reset 方法;由于 reset 函數的返回類型可能包含錯誤,末尾的 ! 表示:如果 reset 成功,則繼續執行;如果 reset 引發了一個錯誤,! 會立即將該錯誤重新拋出,中斷后續操作。
  • 同理,..initialize!() 只有在 reset! 成功后才會執行,并且同樣帶有自動錯誤傳播的 !。這種組合使得對同一對象執行一系列可能失敗的操作時,代碼既簡潔(避免重復寫 panel)又安全(錯誤自動向上傳播)。
  • 接著,它初始化生命游戲的世界狀態。
  • 最后,代碼進入一個無限循環:在每次循環中,它將當前的游戲狀態繪制到虛擬 LCD 上,然后計算并更新游戲到下一代狀態,同時測量并打印出每次繪制和更新操作所花費的時間。

與 ST7789 LCD 相關的邏輯位于 game-of-life/st7789/src/main/main.mbt,關鍵代碼摘錄如下:

let spi_config : @spi.SPI_BUS_CONFIG = { ... }
@spi.spi_bus_initialize(@spi.SPI2_HOST, spi_config, SPI_DMA_CH_AUTO) |> ignore...let panel = @lcd.esp_lcd_new_panel_st7789(io_handle~,reset_gpio_num=PIN_RST,rgb_ele_order=@lcd.BGR,bits_per_pixel=16,)..reset!()..initialize!()..config!(on_off=true, sleep=false, invert_color=true)
@game.init_universe()
for i = 0; ; i = i + 1 {let start = esp_timer_get_time()panel.draw_bitmap!(0, 0, @game.ROWS, @game.COLS, cast(@game.get_cells()))@game.tick()let end = esp_timer_get_time()println("tick \\\\{i} took \\\\{end - start} us")
}
  • 這段代碼首先定義了與物理 ST7789 LCD 連接所需的 GPIO 引腳和 SPI 時鐘速度等常量。
  • 接著,它執行了一系列硬件初始化步驟:配置并啟動 SPI 總線,創建基于 SPI 的 LCD IO 句柄,然后使用特定驅動初始化 ST7789 面板并設置其顯示狀態(復位、初始化、開啟顯示、喚醒、顏色反轉)。
  • 完成硬件準備后,它初始化生命游戲的狀態。
  • 最后,程序進入一個無限循環,在循環中不斷將當前游戲畫面繪制到物理 LCD 屏幕上,計算游戲的下一代狀態,并測量打印每次循環所需的時間。

此外,讀者可以注意到,MoonBit支持標簽參數。無論是在 esp_lcd_new_panel_st7789 的調用中(如reset_gpio_num=PIN_RST, rgb_ele_order=...),還是在后續鏈式調用的 ..config!(on_off=true, ...) 中,都明確地將值與其參數名稱關聯起來。這種方式極大地提高了代碼的可讀性和自文檔性,使得參數的意圖一目了然,并且也無需關心參數順序。

我們可以發現:生命游戲的計算 (@game.tick()) 和主循環結構完全相同。主要的區別在于與顯示設備的交互層。ST7789 版本需要進行詳細的物理硬件配置(定義 GPIO 引腳、配置 SPI 總線、初始化特定 LCD 驅動);而 QEMU 版本則直接與仿真環境提供的虛擬 LCD 接口交互,初始化過程相對簡單。

運行實例代碼

您可以通過克隆示例代碼倉庫來親自體驗:

git clone <https://github.com/moonbit-community/moonbit-esp32-example.git>
  1. QEMU 版本
    為了方便讀者不借助硬件復現,我們提供了QEMU版本,代碼位于 game-of-life/qemu 目錄,在確保環境配置無誤后,運行以下命令便可看到結果。33.1 FPS (每幀約 30.2 ms)
cd game-of-life/qemu
moon install
make set-target esp32c3
make update-deps
make build
make qemu

以下為運行效果

MoonBit 支付國產芯片-Part1

此外,我們還提供了一份使用C實現的代碼,位于 game-of-life/qemu-c 目錄,測試結果表明,使用C實現的生命游戲每幀的計算時間與MoonBit版本相同,均為30.1ms左右。

  1. ST7789 版本

此版本在真實的 ESP32-C3 開發板和 ST7789 LCD 上運行。實測幀率約 27.1 FPS (每幀約 36.9ms)。

cd game-of-life/st7789
moon install
make set-target esp32c3
make build
make flash monitor

此外,我們還提供了一份使用C實現的代碼,位于 game-of-life/st7789-c 目錄,測試結果表明,使用C實現的生命游戲每幀的計算時間與 MoonBit 版本幾乎相同,為36.4ms。

對于具體的測試方法,詳見鏈接: 倉庫

總結

通過在 ESP32-C3 上運行生命游戲的實例,我們展示了 MoonBit 的 Native 后端在嵌入式開發中的應用。MoonBit生命游戲代碼經過優化,能到達與C幾乎相同的速度。同時,MoonBit 的模式匹配等現代語言特性有助于提升代碼的可讀性和開發體驗。結合其與 ESP-IDF 等生態系統的無縫集成能力,MoonBit 為ESP32嵌入式開發提供了一種將原生級執行效率與現代化開發體驗相結合的高效解決方案。

New to MoonBit?

  • Download MoonBit.
  • Explore MoonBit Beginner’s Guide.
  • Play with MoonBit Language Tour.
  • Check out MoonBit Docs.
  • Join our Discord community.

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/77959.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/77959.shtml
英文地址,請注明出處:http://en.pswp.cn/web/77959.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【RAG 框架部署】LangChain-Chatchat (原 Langchain-ChatGLM) + Ollama

目錄 前言 一、什么是RAG&#xff1f; 二、環境準備和Ollama搭建 1、conda虛擬環境配置 2、Ollama搭建 三、LangChain-Chatchat搭建 1、框架安裝 2、文件配置 3、初始化知識庫 4、啟動Langchan-Chatchat 前言 由于LangChain-Chatchat的 0.3.0 版本已修改為支持不同模…

python對接馬來西亞股票完整代碼

StockTV全球股票數據API對接實戰&#xff1a;構建智能金融分析系統 一、StockTV API核心功能解析 StockTV作為覆蓋200國家證券市場的數據平臺&#xff0c;其API提供三大核心模塊的對接能力&#xff1a; 市場列表查詢 - 獲取指定國家的股票基礎數據個股詳情檢索 - 查詢實時行情…

普通IT的股票交易成長史--20250430晚

聲明&#xff1a;本文章的內容只是自己學習的總結&#xff0c;不構成投資建議。文中觀點基本來自yt站Andylee&#xff0c;美股Alpha姐&#xff0c;綜合自己的觀點得出。感謝他們的無私分享。 送給自己的話&#xff1a; 倉位就是生命&#xff0c;絕對不能滿倉&#xff01;&…

windows 下 oracle 數據庫的備份與還原

1、備份 創建備份出來的文件存放的位置。 創建目錄對象&#xff0c;在數據庫中創建一個目錄對象&#xff0c;該對象指向文件系統中用于存儲導出文件的實際目錄&#xff08; sql 命令&#xff0c;可以在 plsql 中執行&#xff09;。 -- 創建目錄對象&#xff0c;\D:\Oracle19c\…

基于單片機的智能藥盒系統

標題:基于單片機的智能藥盒系統 內容:1.摘要 本文聚焦于基于單片機的智能藥盒系統。背景方面&#xff0c;隨著人口老齡化加劇&#xff0c;老年人按時準確服藥問題愈發凸顯&#xff0c;同時現代快節奏生活也使人們容易遺忘服藥時間。目的是設計并實現一個能幫助人們按時、按量服…

“100% 成功的 PyTorch CUDA GPU 支持” 安裝攻略

#工作記錄 一、總述 在深度學習領域&#xff0c;PyTorch 憑借其靈活性和強大的功能&#xff0c;成為了眾多開發者和研究者的首選框架。而 CUDA GPU 支持能夠顯著加速 PyTorch 的計算過程&#xff0c;大幅提升訓練和推理效率。然而&#xff0c;安裝帶有 CUDA GPU 支持的 PyTor…

圖數據庫榜單網站

圖數據庫榜單 https://db-engines.com/en/ranking/graphdbms點擊跳轉

Android Jetpack Compose 面試題大全(2025最新整理)

基礎概念 什么是 Jetpack Compose&#xff1f;它與傳統 Android UI 開發有何不同&#xff1f; Compose 是 Android 的現代聲明式 UI 工具包&#xff0c;使用 Kotlin 編寫不同于傳統的基于 View 和 XML 的 imperative 方式&#xff0c;Compose 使用聲明式范式主要區別&#xff1…

添加了addResourceHandlers 但沒用

B站黑馬的視頻 public class WebMvcConfig extends WebMvcConfigurationSupport { /** * 設置靜態資源映射 * param registry */ Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { log.info("開始進…

STM32實現simpleFOC控制無刷電機

一、FOC基礎知識學習 使用simpleFOC控制無刷電機前&#xff0c;需要大概了解一下相關知識&#xff0c;包括力矩控制、速度控制、位置控制的原理和它們之間的聯系。 推薦學習資料&#xff1a; 教你寫一個比SimpleFOC更好的電機庫_嗶哩嗶哩_bilibili 《燈哥手把手教你寫FOC算…

【數據結構】快慢指針

一、快慢指針的原理 定義&#xff1a; 快指針&#xff1a;每次移動兩步 慢指針&#xff1a;每次移動一步 終止條件&#xff1a; 當快指針到達鏈表末尾時停止 事件復雜度&#xff1a; 始終為O(n),僅需依次遍歷 空間復雜度&#xff1a; …

畢業論文 | 基于STM32的自動煙霧報警系統設計

基于STM32的煙霧報警系統 一、系統設計原理1. **系統架構**2. **工作原理**二、核心公式與算法1. **MQ-2傳感器濃度計算**2. **溫度傳感器數據處理**3. **校準與濾波**三、關鍵代碼實現1. **ADC初始化與數據讀取(以MQ-2為例)**2. **報警邏輯與閾值設置**3. **EEPROM存儲閾值*…

Android Gradle插件開發

文章目錄 1. Gradle插件是什么2. 為什么需要插件3. 編寫插件位置4. 編寫插件5. 自定義插件擴展5.1 訂閱擴展對象5.2 把擴展添加給Plugin并使用5.3 配置參數5.4 嵌套擴展5.4.1 定義擴展5.4.2 獲取擴展屬性5.4.3 使用5.4.4 執行5.4.5 輸出 6. 編寫在單獨項目里6.1 新建Module6.2 …

PPIO X OWL:一鍵開啟任務自動化的高效革命

2024年&#xff0c;僅憑一PPIO X OWL&#xff1a;一鍵開啟任務自動化的高效革命篇技術論文&#xff0c;OWL的Github倉庫便在24小時斬獲了15k Star&#xff0c;成為2024年增速最快的多智能體協作框架&#xff0c;重新定義了任務自動化的效率邊界。Camel AI團隊開源全棧方案&…

分布式事務,事務失效,TC事務協調者

1. 概述 本方案書旨在解決分布式系統中事務一致性問題&#xff0c;重點闡述全局事務標識&#xff08;XID&#xff09;的傳遞與存儲機制、事務協調者&#xff08;TC&#xff09;的設計與部署&#xff0c;以及分布式事務失效場景的應對策略。基于業界成熟框架&#xff08;如Seat…

2025年“深圳杯”數學建模挑戰賽D題-法醫物證多人身份鑒定問題

法醫物證多人身份鑒定問題 小驢數模 犯罪現場法醫物證鑒定是關系到國家安全、公共安全、人民生命財產安全和社會穩定的重大問題。目前法醫物證鑒定依賴DNA分析技術不斷提升。DNA檢驗的核心是STR&#xff08;Short Tandem Repeat&#xff0c;短串聯重復序列&#xff09;分析技術…

Mysql查詢異常【Truncated incorrect INTEGER value】

文章目錄 異常原因分析1、數據類型不一致2、數據長度超長3、數據格式要正確 處理方案模擬案例創建表數據查詢 異常 在執行MySQL的語句時&#xff0c;在控制臺報錯如下所示。 Data truncation: Truncated incorrect INTEGER value 原因分析 1、數據類型不一致 必須要保證數據…

WPF性能優化舉例

WPF性能優化集錦 一、UI渲染性能優化 1. 虛擬化技術 ??ListView/GridView虛擬化??: <ListView VirtualizingStackPanel.IsVirtualizing="True"VirtualizingStackPanel.VirtualizationMode="Recycling"ScrollViewer.IsDeferredScrollingEnabled=…

C# 面向對象實例演示

C# 面向對象編程實例演示 一、基礎概念回顧 面向對象編程(OOP)的四大基本特性&#xff1a; ??封裝?? - 將數據和操作數據的方法綁定在一起??繼承?? - 創建新類時重用現有類的屬性和方法??多態?? - 同一操作作用于不同對象產生不同結果??抽象?? - 簡化復雜系…

大連理工大學選修課——機器學習筆記(3):KNN原理及應用

KNN原理及應用 機器學習方法的分類 基于概率統計的方法 K-近鄰&#xff08;KNN&#xff09;貝葉斯模型最小均值距離最大熵模型條件隨機場&#xff08;CRF&#xff09;隱馬爾可夫模型&#xff08;HMM&#xff09; 基于判別式的方法 決策樹&#xff08;DT&#xff09;感知機…