女人自慰AV免费观看内涵网,日韩国产剧情在线观看网址,神马电影网特片网,最新一级电影欧美,在线观看亚洲欧美日韩,黄色视频在线播放免费观看,ABO涨奶期羡澄,第一导航fulione,美女主播操b

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

未來嵌入式系統的黃金搭檔 MCX N947遇上Rust

恩智浦MCU加油站 ? 來源: 恩智浦MCU加油站 ? 2024-07-25 09:14 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

Rust 介紹Rust 是一門注重安全的語言,相比于 C/C++/ASM 有著更高級的抽象能力、編譯器帶來的安全特性與廣泛友好的社區支持。Linux 與 Windows 內核也都基于 Rust 的安全性和性能引入了 Rust。

Rust 有很多優勢,內存安全、并發安全、生態系統、包管理與構建管理,同時也有與 C/C++ 相同等級的性能。Rust 通過強化所有權和借用的概念,盡力消除了開發過程中可能出現的內存問題。同時作為一門現代語言,有著許多方便的特性與豐富的生態資源,如統一的包管理,高可讀代碼等等。

但 Rust 也有美中不足,如缺乏對底層的完全控制,學習難度高,編譯時間長等。由于 Rust 的安全與高抽象能力,許多非安全操作被禁止,許多在 C 中能夠通過指針進行的簡單操作在 Rust 中需要十分復雜的操作,這也導致 Rust 的學習難度更高。

本文會對在 NXP MCX 平臺上使用 Rust 進行簡單介紹。在本文中使用 FRDM-MCXN947 為例,所有的例子均運行在 Core0 上。

安裝Rust工具鏈Rust 工具鏈的安裝十分簡單,參考Rustup即可。默認狀態下,Rustup 工具只會安裝本機的 TARGET ,為了能夠在我們的 MCU 上運行編譯產物, 需要安裝對應的 TARGET 。可以通過運行如下命令來添加 armv8m hard-float 支持。

rustup target add thumbv8m.main-none-eabihf

同樣,如果我們想為其他平臺編譯,像 cortex-m3 ,則需要運行:

rustup target add thumbv8m.main-none-eabihf

如果要在沒有 FPU 的 Core1 上運行,則需要使用命令rustup target add thumbv8m.main-none-eabi添加thumbv8m.main-none-eabi target,注意無 hf 尾綴, 代表不使用硬件浮點數 ABI

創建項目

在添加支持后,在我們想要保存項目的文件夾運行命令cargo new mcx-example創建一個名為 mcx-example 的工程, 同時創建一個配置文件 .cargo/config.toml 來指定編譯參數和默認 target。

創建的 .cargo/config.toml 文件內容如下:

[build]
target = "thumbv8m.main-none-eabihf"


[target.thumbv8m.main-none-eabihf]
rustflags = ["-C", "link-arg=-Tlink.x"]

接下來添加必要的依賴, Cargo.toml 的內容應該與下面的內容類似:

[package]
name = "mcx-example"
version = "0.1.0"
edition = "2021"


[dependencies]
cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7.3"
mcxn947-pac = "0.0.3"
panic-halt = "0.2.0"

讓我簡單介紹各個依賴的作用:

  • cortex-m 該庫引入了 Cortex-M 架構的定義和一些抽象,如常見的匯編指令,中斷等

  • cortex-m-rt 這個庫是 Cortex-M 架構的通用運行時,提供一套內置的linker script 和 ResetHandler 的實現等等

  • mcxn947-pac 包含了 MCXN947 的寄存器定義,中斷定義

  • panic-halt 實現默認的 panic handler

示例:點燈

說起具體介紹,當然舉個例子-點燈:

// src/main.rs


#![no_std] // 無標準庫
#![no_main] // 無入口


// 提供一個 panic 實現
extern crate panic_halt;


use cortex_m_rt::entry;
use mcxn947_pac as pac;


// entry 標志在 Reset 中跳轉到此
#[entry]
fn main() -> ! {
    let dp = pac::take().unwrap();
    let cp = pac::take().unwrap();


    // 啟用 PORT0 和 GPIO0 的時鐘
    dp.SYSCON0
        .ahbclkctrl0()
        .modify(|_r, w| w.port0().enable().gpio0().enable());


    // 設置 PIO0_10 為推挽輸出
    dp.PORT0.pcr(10).modify(|_r, w| w.mux().mux00());
    dp.GPIO0.pdor().modify(|_r, w| w.pdo10().clear_bit());
    dp.GPIO0.pddr().modify(|_r, w| w.pdd10().set_bit());


    // cortex-m 庫提供的方便的抽象,使用 SysTick timer 來進行延時
    // 在默認情況下 SysTick 的頻率與主頻相同,在這段代碼中我們沒有對時鐘進行配置,所以默認為48MHz
    let mut delay = cortex_m::new(cp.SYST, 48_000_000u32);


    loop {
        delay.delay_ms(1000u32);
        dp.GPIO0.ptor().write(|w| w.ptto10().set_bit());
    }
}

#![no_main] 指定不向外暴露符號 main, 所以即使我們的代碼中有 main 函數,它也不會被當作真正的 “main” 函數看待。同時 #[entry] 標志該函數被鏈接到 cortex-m-rt 庫中內置鏈接腳本中的 “main” 函數。

添加一份 memory.x ,這是一份 linker script ,在 cortex-m-rt 庫中包含的默認 linker script 中有 include memory.x 的定義。所以我們需要添加一份,顧名思義,這份文件包含內存定義,同時如果我們想把特定數據或函數放在某個段也是可以在這定義。

MEMORY {
     FLASH : ORIGIN = 0x00000000, LENGTH = 2M
RAM:ORIGIN=0x20000000,LENGTH=320K
}

運行命令 cargo build 進行構建,產物位于 target/thumbv8m.main-none-eabihf/debug/mcx-example 格式為 elf 。

使用任意工具把產物加載到 MCU 上, 就以 jlink 為例,首先把產物轉成 hex 格式,arm-none-eabi-objcopy -O ihex target/thumbv8m.main-none-eabihf/debug/mcx-example mcx-example.hex, 然后使用 jflashLite 加載。

3cc56cae-4a20-11ef-b8af-92fbcf53809c.png

功能正常實現。

如果需要 Debug, 請參考使用VSCode調試嵌入式程序:配置與使用多樣化的gdb server:

3cd8cb96-4a20-11ef-b8af-92fbcf53809c.png

示例:按鍵開燈

此示例主要是介紹中斷用法及Rust 的線程安全用法:

#![no_std]
#![no_main]


extern crate panic_halt;


use core::cell::{Cell, RefCell};


use cortex_m::{asm::wfi, interrupt::Mutex};
use cortex_m_rt::entry;
use mcxn947_pac as pac;
use pac::interrupt;


// Rust 的安全特性要求
static FLAG_BTN_PRESSED: Mutex> = Mutex::new(false));
static GPIO0: Mutex>> = Mutex::new(None));


#[entry]
fn main() -> ! {
    let dp = pac::take().unwrap();
    let cp = pac::take().unwrap();


    // 啟用 PORT0 和 GPIO0 的時鐘
    dp.SYSCON0
        .ahbclkctrl0()
        .modify(|_r, w| w.port0().enable().gpio0().enable());


    // 設置 PIO0_10 為推挽輸出
    dp.PORT0.pcr(10).modify(|_r, w| w.mux().mux00());
    dp.GPIO0.pdor().modify(|_r, w| w.pdo10().clear_bit());
    dp.GPIO0.pddr().modify(|_r, w| w.pdd10().set_bit());


    // 設置 PIO0_6
    dp.PORT0.pcr(6).modify(|_r, w| w.mux().mux00());
    dp.GPIO0.pddr().modify(|_r, w| w.pdd6().clear_bit());
    dp.GPIO0
        .icr(6)
        .write(|w| w.isf().clear_bit_by_one().irqs().irqs0().irqc().irqc10());


    // 啟用 GPIO00 中斷
    unsafe { pac::GPIO00) }


    // 在關閉中斷的情況下向全局變量寫入數據
    // why: GPIO0 可能在 main 與 GPIO00 中共享
    cortex_m::free(|cs| {
        GPIO0.borrow(cs).replace(dp.GPIO0.into());
    });


    loop {
        wfi();


        cortex_m::free(|cs| {
            if FLAG_BTN_PRESSED.borrow(cs).get() {
                GPIO0
                    .borrow(cs)
                    .borrow_mut()
                    .as_mut()
                    .unwrap()
                    .ptor()
                    .write(|w| w.ptto10().set_bit());
            }
        })
    }
}


// GPIO00 中斷
#[interrupt]
fn GPIO00() {
    cortex_m::free(|cs| {
        let mut gpio = GPIO0.borrow(cs).borrow_mut();
        gpio.as_mut()
            .unwrap()
            .icr(6)
            .modify(|_r, w| w.isf().clear_bit_by_one());
        FLAG_BTN_PRESSED.borrow(cs).set(true);
    })
}

在上面這段代碼中我們當然可以不使用 Mutex ,而是直接使用一個 static mut FLAG_BTN_PRESSED: bool = false ,但有關于該變量的所有操作都需要使用 unsafe 標簽,這在正常的開發過程中應該是極力避免的,因為這種 unsafe 操作會導致 data race 。Mutex 是一個簡單包裝,使用一個 CriticalSection 標志來實現,cortex_m::free 提供一個簡單的臨界區實現,即關閉所有中斷。或者可以使用原子操作 core::AtomicBool, static FLAG_BTN_PRESSED: AtomicBool = AtomicBool::new(false);

cortex_m::free 使用一個 lambda 函數來在其操作前后添加關閉、打開中斷的操作。

雖然看起來寫起來很麻煩,但實際上編譯結果并沒有多余的操作,所有看上去繁瑣的操作實際上只是指導編譯器如何編譯,并不會生成實際的代碼,例如中斷中的 cs 變量,它并沒有實際的大小。

同樣燒錄進 MCU ,按下 ISP 按鍵即可控制燈的開關。

使用HAL

上述兩個例子均直接使用寄存器進行操作,方法過于原始,可以使用 HAL 庫來簡化操作。HAL 庫正在積極開發中,所以使用 GitHub 上的最新版本。添加依賴。

[package]
name = "mcx-example"
version = "0.1.0"
edition = "2021"


[dependencies]
cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7.3"
mcxn947-pac = "0.0.3"
panic-halt = "0.2.0"
mcx-hal = { git = "https://github.com/mcx-rs/mcx-hal.git" }
#![no_std]
#![no_main]


use embedded_hal::digital::StatefulOutputPin;
use panic_halt as _;


use core::cell::{Cell, RefCell};
use cortex_m::asm::wfi;
use cortex_m::interrupt::Mutex;
use cortex_m_rt::entry;
use mcx_hal::{self as hal, pac, pac::interrupt};


type BtnType = hal::PIO0_6>;


static FLAG_BTN_PRESSED: Mutex> = Mutex::new(false));
static BTN: Mutex>> = Mutex::new(None));


#[entry]
fn main() -> ! {
    let dp = pac::take().unwrap();


    // 設置 pin 的狀態更方便了
    let gpio0 = hal::split(dp.GPIO0, dp.PORT0);
    let mut btn = gpio0.pio0_6.into_floating_input(); 
    let mut led_r = gpio0.pio0_10.into_push_pull_output();
    btn.enable_irq(
        hal::FallingEdge,
        hal::IRQ0,
    );
    cortex_m::free(|cs| {
        BTN.borrow(cs).replace(Some(btn));
    });


    // enable GPIO0 irq
    unsafe {
        pac::GPIO00);
    }


    loop {
        wfi();


        cortex_m::free(|cs| {
            if FLAG_BTN_PRESSED.borrow(cs).get() {
                FLAG_BTN_PRESSED.borrow(cs).set(false);
                led_r.toggle().unwrap();
            }
        });
    }
}


#[interrupt]
fn GPIO00() {
    cortex_m::free(|cs| {
        let mut btn = BTN.borrow(cs).borrow_mut();
        btn.as_mut().unwrap().clear_irq_flag();
        FLAG_BTN_PRESSED.borrow(cs).set(true);
    });
}

如果我們想要使用其他中斷,該怎么知道它的名字呢?十分簡單,所有的中斷定義都在 mcxn947-pac::Interrupt 中。

3cdd4266-4a20-11ef-b8af-92fbcf53809c.png

這個例子同樣是使用 ISP 按鍵來控制紅燈的開關。

Linkerscript

將特定的數據放置在特定的位置,也是嵌入式開發中常見的操作,那么怎么在 Rust 上實現呢?

修改 memory.x 即可:

MEMORY { 
FLASH:ORIGIN=0x00000000,LENGTH=1M
RAM:ORIGIN=0x20000000,LENGTH=128K
MY_RAM:ORIGIN=0x04000000,LENGTH=16K
}


SECTIONS { 
    .my_custom_data_in_my_ram (NOLOAD) : ALIGN(4) { 
(.my_custom_data_in_my_ram.my_custom_data_in_my_ram.);
.=ALIGN(4);
}>MY_RAM
}

如果要把中斷函數放在 RAM 里,需要一點額外操作,首先需要去掉過程宏#[interrupt]
#[interrupt]可以看作是#[export_name = ...]和一段代碼展開的縮寫。
我們可以去掉它,手動加上一些宏來達到同樣的效果。首先添加
#[no_mangle]防止編譯器對它重新命名,或者使用#[export_name = ...]來讓它的名字是中斷名。
然后添加
#[link_section = ...]來讓它鏈接到MY_RAM中。
#[link_section=".my_custom_data_in_my_ram.my_custom_name"]
#[no_mangle]
fn GPIO00() {
    cortex_m::free(|cs| {
        let mut btn = BTN.borrow(cs).borrow_mut();
        btn.as_mut().unwrap().clear_irq_flag();
        FLAG_BTN_PRESSED.borrow(cs).set(true);
    });
}

使用命令 arm-none-eabi-size -Ax target/thumbv8m.main-none-eabihf/debug/mcx-example 或者使用命令 cargo install cargo-binutils && rustup component add llvm-tools ,之后就可以 cargo size -- -Ax.

查看編譯結果,確認中斷被我們放進了 MY_RAM 里:

3cea4628-4a20-11ef-b8af-92fbcf53809c.png

在 Debug 下,也可以看到中斷時 PC 的地址:

3cee4d68-4a20-11ef-b8af-92fbcf53809c.png

希望以上內容可以對想使用 Rust 進行嵌入式開發的伙伴們提供指引與助力。

接下來,我們還將深入探索Rust 中的RTOS與實時工具,會為大家揭開更多技術奧秘,敬請持續關注,精彩不容錯過!


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 嵌入式系統
    +關注

    關注

    41

    文章

    3672

    瀏覽量

    131132
  • RTOS
    +關注

    關注

    24

    文章

    845

    瀏覽量

    120942
  • Rust
    +關注

    關注

    1

    文章

    233

    瀏覽量

    7017

原文標題:當MCX N947遇上Rust,打造未來嵌入式系統的黃金搭檔!

文章出處:【微信號:NXP_SMART_HARDWARE,微信公眾號:恩智浦MCU加油站】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    使用ConfigTools for USB創建新項目時遇到的問題求解

    使用 ConfigTools for USB 創建新項目時,存在缺少資源的問題,無法添加它: 該問題從 SDK 24.12.00 開始出現。適用于 macOS 的 MCUXpresso。經過 LPC55s69、MCX A153 和 MCX
    發表于 03-26 08:06

    納米材料與新型傳感技術:微觀世界里的“黃金搭檔

    在科技飛速發展的今天,納米材料和新型傳感技術這對“黃金搭檔”正攜手開啟感知世界的新篇章。納米材料,憑借其獨特的尺寸效應和表面效應,為傳感技術帶來了革命性的突破,而新型傳感技術則為納米材料提供了廣闊
    的頭像 發表于 02-12 18:05 ?420次閱讀

    用戶測評之體驗NXP MCX-N板卡的NPU功能

    前言 恩智浦“FRDM-MCXN947”評測活動由安富利和與非網協同舉辦。 01 NXP FRDM-MCXN947: HMI初體驗 N947是NXP推出的MCX系列帶NPU的一款產品,
    的頭像 發表于 01-17 10:27 ?911次閱讀
    用戶測評之體驗NXP <b class='flag-5'>MCX-N</b>板卡的NPU功能

    嵌入式主板的概述與發展

    未來發展趨勢進行深入探討。嵌入式主板的基本概念嵌入式主板是指為嵌入式系統設計的電路板,它通常集成了微處理器、內存、輸入輸出接口等關鍵組件。與
    的頭像 發表于 01-13 16:30 ?739次閱讀
    <b class='flag-5'>嵌入式</b>主板的概述與發展

    基于恩智浦 MCX N947 MCU 通過 NPU 實現 AI 咖啡膠囊識別方案

    本方案充分利用了恩智浦(NXP)高性能微控制器(MCU)MCX N947 集成的神經網絡處理單元(NPU)的強大性能,旨在開發一款具有真正智能化識別能力的 AI 咖啡膠囊識別的咖啡機。 通過
    的頭像 發表于 12-18 13:43 ?713次閱讀
    基于恩智浦 <b class='flag-5'>MCX</b> <b class='flag-5'>N947</b> MCU 通過 NPU 實現 AI 咖啡膠囊識別方案

    嵌入式系統開發與硬件的關系 嵌入式系統開發常見問題解決

    嵌入式系統開發與硬件的關系 嵌入式系統是專為特定應用設計的計算機系統,它們通常嵌入在所控制的設備
    的頭像 發表于 12-09 09:38 ?904次閱讀

    恩智浦 MCX N系列之電源管理(MCX N94/54與MCX N23)

    給大家揭秘MCX N系列在電源管理方面的卓越性能。電源管理對于硬件設計的優化以及低功耗應用的實現至關重要,因此,深入了解MCX N系列的電源管理機制對于開發者而言意義非凡。同時小編也列
    的頭像 發表于 12-05 09:49 ?1557次閱讀
    恩智浦 <b class='flag-5'>MCX</b> <b class='flag-5'>N</b>系列之電源管理(<b class='flag-5'>MCX</b> <b class='flag-5'>N</b>94/54與<b class='flag-5'>MCX</b> <b class='flag-5'>N</b>23)

    什么是嵌入式操作系統?

    指揮官配備最先進的裝備。 未來會怎樣? 隨著技術的發展,嵌入式操作系統將繼續演進,以滿足更多的應用需求和挑戰,它們可能會: 支持更多IoT設備:管理更多的智能家居和工業設備,就像是物聯網世界的大管家
    發表于 11-08 15:07

    嵌入式系統與物聯網的結合

    隨著科技的飛速發展,嵌入式系統和物聯網(IoT)已經成為現代技術領域的重要組成部分。嵌入式系統是指嵌入到設備或
    的頭像 發表于 11-06 10:23 ?1051次閱讀

    什么是嵌入式?一文讀懂嵌入式主板

    在現代科技浪潮中,嵌入式技術已成為支撐各種智能設備和系統運行的核心力量。那么,究竟什么是嵌入式嵌入式系統,顧名思義,是將計算機的硬件和軟件
    的頭像 發表于 10-16 10:14 ?2521次閱讀

    嵌入式系統的原理和應用

    嵌入式系統是一種專用的計算機系統,其設計初衷是執行特定任務,而非作為通用計算機使用。這類系統通常作為更大系統的一部分,起到控制、監控或輔助的
    的頭像 發表于 10-05 17:03 ?2102次閱讀

    嵌入式系統未來趨勢有哪些?

    嵌入式系統是指將我們的操作系統和功能軟件集成于計算機硬件系統之中,形成一個專用的計算機系統。那么嵌入式
    發表于 09-12 15:42

    開啟全新AI時代 智能嵌入式系統快速發展——“第六屆國產嵌入式操作系統技術與產業發展論壇”圓滿結束

    探索及實踐”的專題報告。張云飛介紹了麒麟軟件基于RUST語言實現的嵌入式虛擬化軟件-Kvisor,,該軟件支持實時與非實時操作系統混合部署與通信。最后分享了針對實際應用場景應用探索與實踐。 本屆論壇
    發表于 08-30 17:24

    嵌入式熱門領域有哪些?

    和分析。隨著人們對健康需求的不斷增長,智能醫療領域對嵌入式系統工程師的需求不斷上升,呈現出廣闊的發展空間。 針對嵌入式領域來說,聚焦物聯網、智能家居、自動駕駛、人工智能等方向,這些領域都是當前和
    發表于 07-16 09:23

    嵌入式系統怎么學?

    嵌入式系統怎么學? 隨著物聯網、智能制造等新技術的興起,嵌入式系統的應用范圍更加廣泛。包括但不限于工業控制、汽車電子、醫療設備、智能家居、智慧城市、消費電子、通信設備等。學習
    發表于 07-02 10:10