diff --git a/Makefile b/Makefile index 487801ab38..025628a7c3 100644 --- a/Makefile +++ b/Makefile @@ -38,6 +38,7 @@ PROCESSOR = -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 LINKER_DIR = $(srctree)/tools/make/F405/linker LDFLAGS += --specs=nosys.specs --specs=nano.specs $(PROCESSOR) -nostdlib +image_LDFLAGS += -z noexecstack image_LDFLAGS += -Wl,-Map=$(PROG).map,--cref,--gc-sections,--undefined=uxTopUsedPriority image_LDFLAGS += -L$(srctree)/tools/make/F405/linker image_LDFLAGS += -T $(LINKER_DIR)/FLASH_CLOAD.ld diff --git a/examples/app_hello_rs/.gitignore b/examples/app_hello_rs/.gitignore new file mode 100644 index 0000000000..2f7896d1d1 --- /dev/null +++ b/examples/app_hello_rs/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/examples/app_hello_rs/Cargo.lock b/examples/app_hello_rs/Cargo.lock new file mode 100644 index 0000000000..0f8a153be3 --- /dev/null +++ b/examples/app_hello_rs/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfapprs" +version = "0.1.0" +dependencies = [ + "panic-halt", +] + +[[package]] +name = "panic-halt" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a513e167849a384b7f9b746e517604398518590a9142f4846a32e3c2a4de7b11" diff --git a/examples/app_hello_rs/Cargo.toml b/examples/app_hello_rs/Cargo.toml new file mode 100644 index 0000000000..35da66aa02 --- /dev/null +++ b/examples/app_hello_rs/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "cfapprs" +version = "0.1.0" +authors = ["Arnaud Taffanel "] +edition = "2021" + +[lib] +crate-type = ["staticlib"] + +[dependencies] +panic-halt = "1.0.0" diff --git a/examples/app_hello_rs/Kbuild b/examples/app_hello_rs/Kbuild new file mode 100644 index 0000000000..515270e5fe --- /dev/null +++ b/examples/app_hello_rs/Kbuild @@ -0,0 +1,15 @@ +# Name of the RUST lib crate to include in the build +CRATE_NAME := cfapprs + +# The crate's output lib will become app.o to make KBUILD happy +obj-y += app.o + +# Flag required to link the whole static library into built-in.o, noexecstack matches the default behavior of LLVM +EXTRA_LDFLAGS += -Wl,--whole-archive -z noexecstack + +# Always build the Rust lib crate and copy it to app.o +$(obj)/app.o: FORCE + cargo build --release --target thumbv7em-none-eabihf + cp $(obj)/target/thumbv7em-none-eabihf/release/lib$(CRATE_NAME).a $@ + +FORCE: \ No newline at end of file diff --git a/examples/app_hello_rs/Makefile b/examples/app_hello_rs/Makefile new file mode 100644 index 0000000000..d0a76e2ac3 --- /dev/null +++ b/examples/app_hello_rs/Makefile @@ -0,0 +1,23 @@ +# The firmware uses the Kbuild build system. There are 'Kbuild' files in this +# example that outlays what needs to be built. (check src/Kbuild). +# +# The firmware is configured using options in Kconfig files, the +# values of these end up in the .config file in the firmware directory. +# +# By setting the OOT_CONFIG (it is '$(PWD)/oot-config' by default) environment +# variable you can provide a custom configuration. It is important that you +# enable the app-layer. See app-config in this directory for example. + +# +# We want to execute the main Makefile for the firmware project, +# it will handle the build for us. +# +CRAZYFLIE_BASE := ../.. + +# +# We override the default OOT_CONFIG here, we could also name our config +# to oot-config and that would be the default. +# +OOT_CONFIG := $(PWD)/app-config + +include $(CRAZYFLIE_BASE)/tools/make/oot.mk diff --git a/examples/app_hello_rs/README.md b/examples/app_hello_rs/README.md new file mode 100644 index 0000000000..b680ec3874 --- /dev/null +++ b/examples/app_hello_rs/README.md @@ -0,0 +1,28 @@ +# Rust Hello world App for Crazyflie 2.x + +Rust version of the Hello-world app. + +This folder shows a proof of concept of how to compile some Rust in the Crazyflie to call firmware functions. + +This is a very minimal examples that can be used as a starting point to build better Rust integration for the Crazyflie fiwmware. + +## Build dependencies + +The prerequisite to build the rust app is to have a recent rust compiler (tested with 1.82.0) and the target for the Crazyflie CPU. +To install the target with [rustup](https://rustup.rs): +``` +rustup target add thumbv7em-none-eabihf +``` + +## Architecture + +The Crazyflie build system is based on KBuild and it had to be creatively bent to allow to link a static library. +This is done my renaming the Rust crate output static lib into a .o and make sure GCC copies the full lib content into the resulting firmware (See [Kbuild](Kbuild)). + +The Rust project is setup to generate a C static library. +The Makefile calls `cargo build` to build the lib and copies the resulting lib into ```app.o```. + +The Crazyflie firmware will call `appMain()` at startup. +This function is declared in rust as `pub extern "C"` to be callable from C. + +The FreeRTOS delay function and Crazyflie console putchar function are manually declared `extern "C"` which allows Rust to call them. \ No newline at end of file diff --git a/examples/app_hello_rs/app-config b/examples/app_hello_rs/app-config new file mode 100644 index 0000000000..c86fe9169e --- /dev/null +++ b/examples/app_hello_rs/app-config @@ -0,0 +1,3 @@ +CONFIG_APP_ENABLE=y +CONFIG_APP_PRIORITY=1 +CONFIG_APP_STACKSIZE=350 diff --git a/examples/app_hello_rs/src/lib.rs b/examples/app_hello_rs/src/lib.rs new file mode 100644 index 0000000000..192d59d984 --- /dev/null +++ b/examples/app_hello_rs/src/lib.rs @@ -0,0 +1,23 @@ +#![no_std] + +use panic_halt as _; + +extern "C" { + pub fn vTaskDelay(ticks: u32); + pub fn consolePutchar(ch: i32) -> i32; +} + +fn console_print(msg: &str) { + for c in msg.as_bytes() { + unsafe{ consolePutchar(*c as i32); } + } +} + +#[no_mangle] +pub extern "C" fn appMain() -> i32 { + console_print("Hello from Rust!\n"); + + loop { + unsafe { vTaskDelay(1000); } + } +}