【板子申请】Ai-M61-32S开发环境搭建之Embedded Rust for Windows 10

[复制链接]
查看1057 | 回复8 | 2023-11-20 16:11:18 | 显示全部楼层 |阅读模式

本帖最后由 instead 于 2023-11-23 09:10 编辑

前言

说到嵌入式,就不得不提一嘴Mozilla的Rust。Rust作为一种系统级编程语言,它提供了许多内存安全保证和线程安全保证,虽然自由度比C/C++差了许多,但也比较适合我这种10行代码,9行报错,8个警告的人(

安装Rust环境

Windows上安装Rust需要有C++环境,有两种安装方法,分别是 x86_64-pc-windows-msvcx86_64-pc-windows-gnu。在这里因为使用习惯上的问题,选用 x86_64-pc-windows-gnu 作为例子。

安装MSYS

这里按照MSYS2官网的说明一路next安装即可,这里就不赘述了。

安装完成后会弹出一个命令行窗口,在里面输入

pacman -S mingw-w64-x86_64-toolchain

安装开发环境 mingw-toolchain

安装rustup

在同一个窗口内输入如下的命令来启动安装脚本

curl https://sh.rustup.rs -sSf | sh

回车后,根据下面的输出进行配置

info: downloading installer

Rust Visual C++ prerequisites

Rust requires a linker and Windows API libraries but they don't seem to be
available.

These components can be acquired through a Visual Studio installer.

1) Quick install via the Visual Studio Community installer
   (free for individuals, academic uses, and open source).

2) Manually install the prerequisites
   (for enterprise and advanced users).

3) Don't install the prerequisites
   (if you're targeting the GNU ABI).

>3


## 敏感信息已删除 ##

Current installation options:


   default host triple: x86_64-pc-windows-msvc
     default toolchain: stable (default)
               profile: default
  modify PATH variable: yes

1) Proceed with installation (default)
2) Customize installation
3) Cancel installation
>2

I'm going to ask you the value of each of these installation options.
You may simply press the Enter key to leave unchanged.

Default host triple? [x86_64-pc-windows-msvc]
x86_64-pc-windows-gnu

Default toolchain? (stable/beta/nightly/none) [stable]
stable

Profile (which tools and data to install)? (minimal/default/complete) [default]
complete

Modify PATH variable? (Y/n)
y


Current installation options:


   default host triple: x86_64-pc-windows-gnu
     default toolchain: stable
               profile: complete
  modify PATH variable: yes

1) Proceed with installation (default)
2) Customize installation
3) Cancel installation
>1

等待上面的操作完成后,如果没有提示什么错误信息,Rust和rustup就已经被成功安装了。

配置RISC-V开发环境

使用Rust在stm32和risc-v的板子上进行开发的流程其实差不多,只要安装对应的target就好了。rust支持的target如下所示

aarch64-apple-darwin
aarch64-apple-ios
aarch64-apple-ios-sim
aarch64-linux-android
aarch64-pc-windows-msvc   
aarch64-unknown-fuchsia   
aarch64-unknown-linux-gnu   
aarch64-unknown-linux-musl  
aarch64-unknown-none
aarch64-unknown-none-softfloat
aarch64-unknown-uefi
arm-linux-androideabi
arm-unknown-linux-gnueabi   
arm-unknown-linux-gnueabihf   
arm-unknown-linux-musleabi  
arm-unknown-linux-musleabihf  
armebv7r-none-eabi
armebv7r-none-eabihf
armv5te-unknown-linux-gnueabi 
armv5te-unknown-linux-musleabi
armv7-linux-androideabi   
armv7-unknown-linux-gnueabi   
armv7-unknown-linux-gnueabihf 
armv7-unknown-linux-musleabi  
armv7-unknown-linux-musleabihf
armv7a-none-eabi
armv7r-none-eabi
armv7r-none-eabihf
asmjs-unknown-emscripten
i586-pc-windows-msvc
i586-unknown-linux-gnu
i586-unknown-linux-musl
i686-linux-android
i686-pc-windows-gnu
i686-pc-windows-msvc
i686-unknown-freebsd
i686-unknown-linux-gnu
i686-unknown-linux-musl
i686-unknown-uefi
loongarch64-unknown-linux-gnu
loongarch64-unknown-none
loongarch64-unknown-none-softfloat
mips-unknown-linux-musl
mips64-unknown-linux-muslabi64
mips64el-unknown-linux-muslabi64
mipsel-unknown-linux-musl
nvptx64-nvidia-cuda
powerpc-unknown-linux-gnu
powerpc64-unknown-linux-gnu
powerpc64le-unknown-linux-gnu
riscv32i-unknown-none-elf
riscv32imac-unknown-none-elf
riscv32imc-unknown-none-elf
riscv64gc-unknown-linux-gnu
riscv64gc-unknown-none-elf
riscv64imac-unknown-none-elf
s390x-unknown-linux-gnu
sparc64-unknown-linux-gnu
sparcv9-sun-solaris
thumbv6m-none-eabi
thumbv7em-none-eabi
thumbv7em-none-eabihf
thumbv7m-none-eabi
thumbv7neon-linux-androideabi
thumbv7neon-unknown-linux-gnueabihf
thumbv8m.base-none-eabi
thumbv8m.main-none-eabi
thumbv8m.main-none-eabihf
wasm32-unknown-emscripten
wasm32-unknown-unknown
wasm32-wasi
wasm32-wasi-preview1-threads
x86_64-apple-darwin
x86_64-apple-ios
x86_64-fortanix-unknown-sgx
x86_64-linux-android
x86_64-pc-solaris
x86_64-pc-windows-gnu (installed)
x86_64-pc-windows-msvc
x86_64-sun-solaris
x86_64-unknown-freebsd
x86_64-unknown-fuchsia
x86_64-unknown-illumos
x86_64-unknown-linux-gnu
x86_64-unknown-linux-gnux32
x86_64-unknown-linux-musl
x86_64-unknown-netbsd
x86_64-unknown-none
x86_64-unknown-redox
x86_64-unknown-uefi

已经被安装的target会在后面标记 (installed)

输入如下的命令安装 rust-std

rustup target add riscv32imac-unknown-none-elf

(可选)cargo-generate是一个用于快速生成rust项目的一个工具,如果有需要的话可以使用以下命令安装

cargo install cargo-generate

到这里你会认为环境已经搭建的差不多了吗,确实是差不多了。但这里漏了一个非常关键的部分,那就是 HALHALHardware Abstraction Layer 的缩写,即硬件抽象层。它是一种软件抽象层,用于在嵌入式系统中抽象硬件接口,使得应用程序可以独立于底层硬件而编写。

这里我找了一下Rust的支持目录,非常可惜的是没有直接的官方支持库,也没找到有其他具有兼容结构的库可供使用,因此只能等待官方或者其他大手子编写针对Ai-M61-32S的 HAL 库了。

好好好,又看了一遍文档和aithinker_Ai-M6X_SDK,发现板子的处理器是Bouffalo的BL616,顺藤摸瓜找到了他的Embedded Rust Peripheral Access Crate for Bouffalo chips。这就好办了,创建新项目!

Hello, World!——blinky

blinky是一个目标非常简单的项目,只需要让开发板上的板载LED灯以一定的间隔闪烁起来,也是嵌入式领域的"Hello, World!"了。

创建项目

输入如下的命令创建新Rust项目

cargo new ai_m61_32_s_blinky
cd ai_m61_32_s_blinky

执行后,会生成具有如下结构的目录

.
├── Cargo.toml
├── .gitignore
└── src
    └── main.rs

在目录内创建 .cargo 文件夹,并在里面创建配置文件 config

[target.riscv32imac-unknown-none-elf]
rustflags = [
  "-C", "link-arg=-Tmemory.x",
  "-C", "link-arg=-Tlink.x",
]

[build]
target = "riscv32imac-unknown-none-elf"

同时还要在项目的根目录里创建用于描述生成的固件中的内存布局和链接脚本的文件。这里我面向gpt编程,根据sdkflash.ld 文件生成了对应的 memory.xlink.x 文件。(但大概率会扑街,不要小看人类啊!)

/* memory.x */

MEMORY
{
    fw_header_memory  (rx)  : ORIGIN = 0xA0000000 - 0x1000, LENGTH = 4K;
    xip_memory        (rx)  : ORIGIN = 0xA0000000, LENGTH = 4M;
    ram_code          (wxa) : ORIGIN = 0xA8000000, LENGTH = 4M;
    itcm_memory       (rx)  : ORIGIN = 0x62FC0000, LENGTH = 20K;
    dtcm_memory       (rx)  : ORIGIN = 0x62FC5000, LENGTH = 4K;
    nocache_ram_memory (!rx): ORIGIN = 0x22FC6000, LENGTH = 44K+60K;
    ram_memory        (!rx): ORIGIN = 0x62FE0000, LENGTH = 320K-20K-4K-44K-60K;
    ram_wifi          (wxa) : ORIGIN = 0x23010000, LENGTH = 160K - __EM_SIZE;
}

REGION_ALIAS("RAM", ram_memory);
REGION_ALIAS("RAM_CODE", ram_code);

/* Define symbols used in the linker script */
__StackTop = ORIGIN(dtcm_memory) + LENGTH(dtcm_memory);
__StackLimit = __StackTop - SIZEOF(.stack_dummy);

__HeapBase = ORIGIN(ram_memory);
__HeapLimit = ORIGIN(ram_memory) + LENGTH(ram_memory);

__psram_data_start = ORIGIN(ram_code) + SIZEOF(.psram_data);
__psram_data_end = ORIGIN(ram_code) + LENGTH(ram_code);

__psram_heap_base = ORIGIN(ram_code) + SIZEOF(.psram_heap);
__psram_heap_end = ORIGIN(ram_code) + LENGTH(ram_code);

__wifi_bss_start = ADDR(.wifibss);
__wifi_bss_end = ADDR(.wifibss) + SIZEOF(.wifibss);

__LD_CONFIG_EM_SEL = __EM_SIZE;
/* link.x */

ENTRY(__start);

INCLUDE "./memory.x"

SECTIONS
{
    . = ORIGIN(xip_memory) + SIZEOF(.fw_header);

    .fw_header :
    {
        KEEP(*(.fw_header))
    } > fw_header_memory

    .init :
    {
        *(.text.entry)
        KEEP (*(SORT_NONE(.init)))
        KEEP (*(SORT_NONE(.vector)))
    } > xip_memory

    .rftlv.tool :
    {
        . = ORIGIN(xip_memory) + __RFTLV_SIZE_OFFSET;
        PROVIDE( _ld_symbol_rftlv_address = . );
        LONG(__RFTLV_HEAD1_H);
        LONG(__RFTLV_HEAD1_L);
        . = ORIGIN(xip_memory) + __RFTLV_SIZE_OFFSET + __RFTLV_SIZE_HOLE;
    } > xip_memory

    /* ... (rest of the sections remain the same) ... */

    .heap (NOLOAD):
    {
        . = ALIGN(4);
        __HeapBase = .;

        KEEP(*(.heap*))

        . = ALIGN(4);
        __HeapLimit = .;
    } > ram_memory

    .psram_heap (NOLOAD):
    {
        . = ALIGN(4);
        __psram_heap_base = .;
        KEEP(*(.psram_heap*))
        . = ALIGN(4);
        __psram_heap_end = .;
    } > ram_code

    .wifibss (NOLOAD) :
    {
        PROVIDE( __wifi_bss_start = ADDR(.wifibss) );
        PROVIDE( __wifi_bss_end = ADDR(.wifibss) + SIZEOF(.wifibss) );
        _sshram = . ;
        *(SHAREDRAMIPC)
        *(SHAREDRAM)
        _eshram = . ;
        *ipc_shared.o(COMMON)
        *sdu_shared.o(COMMON)
        *hal_desc.o(COMMON)
        *txl_buffer_shared.o(COMMON)
        *txl_frame_shared.o(COMMON)
        *scan_shared.o(COMMON)
        *scanu_shared.o(COMMON)
        *mfp_bip.o(COMMON)
        *me_mic.o(COMMON)
        *(.wifi_ram*)
        . = ALIGN(16);
    } > ram_wifi
}

之后,我们再进入 Cargo.toml,编辑我们这个项目的依赖,大概设置成下面这样子:

[package]
name = "ai_m61_32s_blinky"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
bl616-pac = { version = "0.0.0"}
embedded-hal = "0.2.7"
panic-halt = "0.2.0"
riscv-rt = "0.11.0"
riscv = "0.10.1"

编写裸机程序

之后,便可以正式开始对 src\main.rs 进行编写了!

#![no_std]
#![no_main]

use panic_halt as _;
use bl616_pac::Peripherals;

use riscv_rt::entry;
use riscv::asm;

// get_peripherals 获取外设
fn get_peripherals() -> Peripherals {
    unsafe {
        Peripherals::steal()
    }
}

// 延时函数,占用2000个CPU周期
fn delay() {
    for _ in 0..2_000 {
        unsafe { asm::nop() };
    }
}

#[entry]
fn main() -> ! {
    // 获取外设
    let peripherals = get_peripherals();
    // 获取芯片通用全局设定模块
    let glb = peripherals.GLB;
    // 控制特定gpio脚,这里是IO12,也就是板子上的红色灯
    let gpio_12 = &glb.gpio_config[12];
    // let gpio_14 = &glb.gpio_config[14];
    // let gpio_15 = &glb.gpio_config[15];


    // 控制板子上的红色灯闪烁
    loop {
        unsafe {
            // 设置高电平
            gpio_12.set_bits(|w|{w.bits(1)});
        }
        delay();
        unsafe {
            // 设置低电平
            gpio_12.set_bits(|w|{w.bits(0)});
        }
        delay();
    }
}

完成之后,命令行输入如下命令进行编译

cargo build

哦豁,编译报错

image.png

修正 memory.x文件

看起来.....GPT还是不怎么靠谱,还需要对 memory.x 文件进行修改。在阅读了相关资料后,将 memory.x 的内容修改为

/* Linker script for the Ai-M61-32S-Kit */
MEMORY
{
  FLASH : ORIGIN = 0xA0000000, LENGTH = 8M
  RAM : ORIGIN = 0x62FC0000, LENGTH = 320K
}

REGION_ALIAS("REGION_TEXT", FLASH);
REGION_ALIAS("REGION_RODATA", FLASH);
REGION_ALIAS("REGION_DATA", RAM);
REGION_ALIAS("REGION_BSS", RAM);
REGION_ALIAS("REGION_HEAP", RAM);
REGION_ALIAS("REGION_STACK", RAM);

成功编译

然后执行以下命令清理并编译(你要问我为什么要加 -r?因为我这不加就会报错找不到文件挺奇怪的......)

cargo clean && cargo build -r

当看到类似如下的输出时,便说明编译成功了!

image.png

编译产物位于 target\riscv32imac-unknown-none-elf\release\ai_m61_32s_blinky

终于,终于编译出来了(;´༎ຶД༎ຶ`)

(虽然不知道烧录到板子上后能不能成功跑起来)


参考资料

  1. bouffalolab/bl_docs: Datasheets and Reference Manual for BL602/BL808 (github.com)
  2. bouffalolab/bouffalo_sdk: BouffaloSDK is the IOT and MCU software development kit provided by the Bouffalo Lab Team, supports all the series of Bouffalo chips. Also it is the combination of bl_mcu_sdk and bl_iot_sdk (github.com)
  3. bouffalolab/bl-pac: Embedded Rust Peripheral Access Crate for Bouffalo chips (github.com)
  4. ai-m61-32s-kit_v1.1.0规格书20230324.pdf (ai-thinker.com)
  5. Hardware - The Embedded Rust Book (rust-embedded.org)
  6. BL618评估板教程第一篇:使用GPIO点亮LED灯 - VeriMake
  7. STM32F4 Embedded Rust at the PAC: GPIO Control - DEV Community
  8. 关于本书 - Rust语言圣经(Rust Course)
  9. Rust on RISC-V BL602: Is It Sunny? (lupyuen.github.io)
  10. henry's blog (henrygressmann.de)
  11. cargo build - Cargo 手册 中文版 (rustwiki.org)

感谢以上资料的作者所编写的内容,对本次写作做出的帮助与支持!

百回「可愛い」って言うまで放さないい!
回复

使用道具 举报

jkernet | 2023-11-20 20:49:03 | 显示全部楼层
感谢分享!
回复

使用道具 举报

instead | 2023-11-22 16:26:29 | 显示全部楼层

本帖最后由 instead 于 2023-11-22 23:35 编辑

[quote][size=2][color=#999999]jkernet 发表于 2023-11-20 20:49[/color][/size] 感谢分享![/quote]

大佬大佬Ai-M61-32S的内存布局应该是怎么样的啊(;´д`)ゞ

啊,后面看文档重新修改了下可以跑通了

百回「可愛い」って言うまで放さないい!
回复 支持 反对

使用道具 举报

instead | 2023-11-22 23:50:10 | 显示全部楼层
目前使用Rust开发存在的问题:
资料较少,并且Bouffalo仅有对BL616、BL618、BL808的PAC支持,没有HAL。
这就导致了开发过程中需要直接对硬件进行访问和控制,而且由于资料少导致在调用的时候如果遇到了问题需要自行解决,Bouffalo官方的论坛和对pac库的支持挺少(

没有HAL出来之前还是用隔壁的BouffaloSDK开发舒服一点,至少调用的是更高级别的抽象层(;′⌒`)
百回「可愛い」って言うまで放さないい!
回复 支持 反对

使用道具 举报

WT_0213 | 2023-11-23 08:41:07 | 显示全部楼层
很厉害啊
回复

使用道具 举报

instead | 2023-11-23 10:30:04 | 显示全部楼层

欸嘿ο(=•ω<=)ρ⌒☆
百回「可愛い」って言うまで放さないい!
回复 支持 反对

使用道具 举报

silyhah | 2023-11-23 10:37:47 来自手机 | 显示全部楼层
大佬
回复

使用道具 举报

ai_mcu | 2023-11-24 23:05:44 | 显示全部楼层
插个眼给园长看
明天总会更好
回复 支持 反对

使用道具 举报

爱笑 | 2023-11-27 10:59:06 | 显示全部楼层
通过,私信你了。
用心做好保姆工作
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则