< 返回版块

ThinkCodeStudio 发表于 2025-06-19 17:21

Tags:嵌入式, 交叉编译

实验开发板: Luckfox Lyra
首先安装 arm-unknown-linux-gnueabihf 编译器

$ rustup target add arm-unknown-linux-gnueabihf 

$ rustup target list
aarch64-apple-darwin
aarch64-apple-ios
aarch64-apple-ios-macabi
aarch64-apple-ios-sim
aarch64-linux-android
aarch64-pc-windows-gnullvm
aarch64-pc-windows-msvc
aarch64-unknown-fuchsia
aarch64-unknown-linux-gnu
aarch64-unknown-linux-musl
aarch64-unknown-linux-ohos
aarch64-unknown-none
aarch64-unknown-none-softfloat
aarch64-unknown-uefi
arm-linux-androideabi
arm-unknown-linux-gnueabi
arm-unknown-linux-gnueabihf (installed)
arm-unknown-linux-musleabi
arm-unknown-linux-musleabihf
arm64ec-pc-windows-msvc
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
armv7-unknown-linux-ohos
armv7a-none-eabi
armv7r-none-eabi
armv7r-none-eabihf
i586-unknown-linux-gnu
i586-unknown-linux-musl
i686-linux-android
i686-pc-windows-gnu
i686-pc-windows-gnullvm
i686-pc-windows-msvc
i686-unknown-freebsd
i686-unknown-linux-gnu
i686-unknown-linux-musl
i686-unknown-uefi
loongarch64-unknown-linux-gnu
loongarch64-unknown-linux-musl
loongarch64-unknown-none
loongarch64-unknown-none-softfloat
nvptx64-nvidia-cuda
powerpc-unknown-linux-gnu
powerpc64-unknown-linux-gnu
powerpc64le-unknown-linux-gnu
powerpc64le-unknown-linux-musl
riscv32i-unknown-none-elf
riscv32im-unknown-none-elf
riscv32imac-unknown-none-elf
riscv32imafc-unknown-none-elf
riscv32imc-unknown-none-elf
riscv64gc-unknown-linux-gnu
riscv64gc-unknown-linux-musl
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-wasip1
wasm32-wasip1-threads
wasm32-wasip2
wasm32v1-none
x86_64-apple-darwin
x86_64-apple-ios
x86_64-apple-ios-macabi
x86_64-fortanix-unknown-sgx
x86_64-linux-android
x86_64-pc-solaris
x86_64-pc-windows-gnu
x86_64-pc-windows-gnullvm
x86_64-pc-windows-msvc
x86_64-unknown-freebsd
x86_64-unknown-fuchsia
x86_64-unknown-illumos
x86_64-unknown-linux-gnu (installed)
x86_64-unknown-linux-gnux32
x86_64-unknown-linux-musl
x86_64-unknown-linux-ohos
x86_64-unknown-netbsd
x86_64-unknown-none
x86_64-unknown-redox
x86_64-unknown-uefi

使用 Cargo 创建一个项目, 然后在项目的根目录创建一个文件夹并创建一个文件(.cargo/config), 这个文件是用来配置Cargo使用其他编译器, 详细看这篇文章 https://course.rs/cargo/reference/configuration.html

[build]
jobs = 8
target = "arm-unknown-linux-gnueabihf"

[target.arm-unknown-linux-gnueabihf]
linker = "/home/think/work/Lyra-sdk/prebuilts/gcc/linux-x86/arm/gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf/bin/arm-none-linux-gnueabihf-gcc"

其中只配置target编译会报连接失败的错误, 所以要加linker的路径, 如何配置了环境变量就需要就对路径, 我只是偷懒使用了sdk中的工具

之后使用cargo就可以编译成功了, 把编译出来的程序传到开发板上就可以运行了, 注意: rust工程交叉编译后的程序在编译器对应的文件夹里, 所以默认路径在: target/arm-unknown-linux-gnueabihf/debug/hello-rust

是不是非常简单, 接着编写一个控制GPIO程序, 这里要注意一下: 如果使用File来操作文件会报没有权限的问题, 原因可能是Rust的File打开文件权限是可读可写的, 但是GPIO操作的文件只能写, 所以报了没有权限的错误, 所以要使用OpenOptions能控制文件权限的接口操作文件: GPIO | LUCKFOX WIKI

use std::{fs::{OpenOptions}, io::{Read, Write}, thread::sleep, time::Duration};

const GPIO_PATH: &str = "/sys/class/gpio";

fn delete_gpio(pin_num: &str) {
    if let Ok(mut f) = OpenOptions::new().write(true).open(format!("{}/unexport", GPIO_PATH)) {
        write!(f, "{}", pin_num)
            .expect("Failed to write to unexport file");
        println!("Pin {} unexported", pin_num);
    } else {
        println!("Failed to open unexport file");
    }
}

fn main() -> std::io::Result<()> {
    println!("Hello, world!");
    let args: Vec<String> = std::env::args().collect();
    let pin_num = args
        .get(1)
        .expect("Please provide a pin number as an argument");

    match OpenOptions::new().write(true).open(format!("{}/export", GPIO_PATH)) {
        Ok(mut f) => {
            write!(f, "{}", pin_num)
                .expect("Failed to write to export file");
        }
        Err(e) => {
            println!("Failed to open export file, error: {}", e);
        }
    }
    let pin_num_cp = pin_num.clone();
    std::panic::set_hook(Box::new(move |panic_info| {
        delete_gpio(pin_num_cp.as_str());
        println!("Panic occurred: {}", panic_info);
    }));

    let pin_num_cp = pin_num.clone();
    ctrlc::set_handler(move || {
        delete_gpio(pin_num_cp.as_str());
        println!("Exiting...");
        std::process::exit(0);
    })
    .expect("Error setting Ctrl-C handler");

    if let Ok(mut f) = OpenOptions::new().write(true).open(format!("{}/gpio{}/direction", GPIO_PATH, pin_num)) {
        write!(f, "out")
            .expect("Failed to write to direction file");
    } else {
        println!("Failed to set direction for pin {}", pin_num);
        return Ok(());
    }

    let mut value = "1";
    loop {
        if let Ok(mut f) = OpenOptions::new().write(true).open(format!("{}/gpio{}/value", GPIO_PATH, pin_num)) {
            write!(f, "{}", value)
                .expect("Failed to write to value file");
        }

        if let Ok(mut f) = OpenOptions::new().read(true).open(format!("{}/gpio{}/value", GPIO_PATH, pin_num)) {
            let mut str = String::new();
            f.read_to_string(&mut str)
                .expect("Failed to write to value file");
            println!("Pin {} value: {}", pin_num, str.trim());
        }


        value = if value == "1" { "0" } else { "1" };
        sleep(Duration::from_secs(1));
    }
}

这里使用了一个库用来挂ctrlc信号的:

[dependencies]
ctrlc = "3.1.7"

运行结果:

root@luckfox:~# ./hello-rust 10
Hello, world!
Pin 10 value: 1
Pin 10 value: 0
Pin 10 value: 1
Pin 10 value: 0
Pin 10 value: 1
Pin 10 value: 0
Pin 10 value: 1
Pin 10 value: 0
Pin 10 value: 1
^CExiting...

评论区

写评论

还没有评论

1 共 0 条评论, 1 页