From ec1a638e2022bced72719bfad7171112e770088c Mon Sep 17 00:00:00 2001 From: moparisthebest Date: Thu, 8 Feb 2024 21:08:36 -0500 Subject: [PATCH] Initial commit --- c-with-rust/CMakeLists.txt | 26 ++ c-with-rust/blink.c | 61 ++++ c-with-rust/build.sh | 21 ++ c-with-rust/pico_sdk_import.cmake | 62 ++++ c-with-rust/rblink/Cargo.lock | 7 + c-with-rust/rblink/Cargo.toml | 10 + c-with-rust/rblink/src/lib.rs | 73 ++++ c/CMakeLists.txt | 25 ++ c/blink.c | 19 ++ c/build.sh | 16 + c/pico_sdk_import.cmake | 62 ++++ readme.txt | 11 + rust-with-c/.cargo/config.toml | 29 ++ rust-with-c/Cargo.lock | 380 +++++++++++++++++++++ rust-with-c/Cargo.toml | 69 ++++ rust-with-c/build.rs | 23 ++ rust-with-c/build.sh | 13 + rust-with-c/libblink/CMakeLists.txt | 21 ++ rust-with-c/libblink/blink.c | 56 +++ rust-with-c/libblink/pico_sdk_import.cmake | 62 ++++ rust-with-c/memory.x | 15 + rust-with-c/src/main.rs | 125 +++++++ 22 files changed, 1186 insertions(+) create mode 100644 c-with-rust/CMakeLists.txt create mode 100644 c-with-rust/blink.c create mode 100755 c-with-rust/build.sh create mode 100644 c-with-rust/pico_sdk_import.cmake create mode 100644 c-with-rust/rblink/Cargo.lock create mode 100644 c-with-rust/rblink/Cargo.toml create mode 100644 c-with-rust/rblink/src/lib.rs create mode 100644 c/CMakeLists.txt create mode 100644 c/blink.c create mode 100755 c/build.sh create mode 100644 c/pico_sdk_import.cmake create mode 100644 readme.txt create mode 100644 rust-with-c/.cargo/config.toml create mode 100644 rust-with-c/Cargo.lock create mode 100644 rust-with-c/Cargo.toml create mode 100644 rust-with-c/build.rs create mode 100755 rust-with-c/build.sh create mode 100644 rust-with-c/libblink/CMakeLists.txt create mode 100644 rust-with-c/libblink/blink.c create mode 100644 rust-with-c/libblink/pico_sdk_import.cmake create mode 100644 rust-with-c/memory.x create mode 100644 rust-with-c/src/main.rs diff --git a/c-with-rust/CMakeLists.txt b/c-with-rust/CMakeLists.txt new file mode 100644 index 0000000..39aacea --- /dev/null +++ b/c-with-rust/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.12) + +# Pull in SDK (must be before project) +include(pico_sdk_import.cmake) + +project(pico_examples C CXX ASM) +set(CMAKE_C_STANDARD 17) +set(CMAKE_CXX_STANDARD 17) + +# Initialize the SDK +pico_sdk_init() + +add_executable( + blink + blink.c + ) + +# pull in common dependencies +target_link_libraries( + blink + pico_stdlib + /tmp/cargo-target/thumbv6m-none-eabi/release/librblink.a + ) + +# create map/bin/hex file etc. +pico_add_extra_outputs(blink) diff --git a/c-with-rust/blink.c b/c-with-rust/blink.c new file mode 100644 index 0000000..8bff825 --- /dev/null +++ b/c-with-rust/blink.c @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "pico/stdlib.h" + +// https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html +// bool is compatible +#define i8 int8_t +#define i16 int16_t +#define i32 int32_t + +#define u8 uint8_t +#define u16 uint16_t +#define u32 uint32_t + +#define i64 int64_t +#define u64 uint64_t + +#define isize intptr_t +#define usize uintptr_t + + +// used from rust +const uint LED_PIN = PICO_DEFAULT_LED_PIN; +uint led_pin() { + return PICO_DEFAULT_LED_PIN; +} +// without this: undefined reference to `gpio_set_dir' +void c_gpio_set_dir(uint gpio, bool out) { + return gpio_set_dir(gpio, out); +} +// without this: undefined reference to `gpio_put' +void c_gpio_put(uint gpio, bool value) { + return gpio_put(gpio, value); +} + +// defined in rust +u32 add_half(u32 num); +int rs_main(); + +int c_main() { + gpio_init(LED_PIN); + gpio_set_dir(LED_PIN, GPIO_OUT); + int sleep = 250; + while (true) { + gpio_put(LED_PIN, 1); + sleep_ms(sleep); + gpio_put(LED_PIN, 0); + sleep_ms(sleep); + sleep = add_half(sleep); + } +} + +// rename to main() to enable this one +int main_disabled() { + return rs_main(); + //return c_main(); +} diff --git a/c-with-rust/build.sh b/c-with-rust/build.sh new file mode 100755 index 0000000..838e049 --- /dev/null +++ b/c-with-rust/build.sh @@ -0,0 +1,21 @@ +#!/bin/bash +set -euxo pipefail + +# run: rustup target add thumbv6m-none-eabi + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +cd "$SCRIPT_DIR"/rblink +CARGO_TARGET_DIR=/tmp/cargo-target cargo build --release --target thumbv6m-none-eabi + +mkdir -p /tmp/8 +cd /tmp/8 + +cmake "$SCRIPT_DIR" + +make + +picotool info +picotool load blink.uf2 +picotool reboot + diff --git a/c-with-rust/pico_sdk_import.cmake b/c-with-rust/pico_sdk_import.cmake new file mode 100644 index 0000000..28efe9e --- /dev/null +++ b/c-with-rust/pico_sdk_import.cmake @@ -0,0 +1,62 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG master + ) + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + FetchContent_Populate(pico_sdk) + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/c-with-rust/rblink/Cargo.lock b/c-with-rust/rblink/Cargo.lock new file mode 100644 index 0000000..2dffabf --- /dev/null +++ b/c-with-rust/rblink/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rblink" +version = "0.1.0" diff --git a/c-with-rust/rblink/Cargo.toml b/c-with-rust/rblink/Cargo.toml new file mode 100644 index 0000000..063a884 --- /dev/null +++ b/c-with-rust/rblink/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "rblink" +version = "0.1.0" +edition = "2021" + +[lib] +name = "rblink" +crate-type = ["staticlib"] + +[dependencies] diff --git a/c-with-rust/rblink/src/lib.rs b/c-with-rust/rblink/src/lib.rs new file mode 100644 index 0000000..de4dc23 --- /dev/null +++ b/c-with-rust/rblink/src/lib.rs @@ -0,0 +1,73 @@ +#![no_std] + +// https://doc.rust-lang.org/core/ffi/index.html +use core::ffi::{c_int, c_uint, c_void}; + +#[panic_handler] +fn oh_no(_panic_info: &core::panic::PanicInfo) -> ! { + loop {} +} + +mod c { + use core::ffi::{c_int, c_uint, c_void}; + extern "C" { + pub(super) static LED_PIN: c_uint; + + // https://www.raspberrypi.com/documentation/pico-sdk/high_level.html + pub(super) fn gpio_init(gpio: c_uint) -> c_void; + pub(super) fn c_gpio_set_dir(gpio: c_uint, on_off: bool) -> c_void; + pub(super) fn c_gpio_put(gpio: c_uint, on_off: bool) -> c_void; + + pub(super) fn sleep_us(us: u64) -> c_void; + pub(super) fn sleep_ms(ms: u32) -> c_void; + } +} + +static LED_PIN: &c_uint = unsafe { &c::LED_PIN }; + +fn gpio_init(gpio: c_uint) { + unsafe { c::gpio_init(gpio) }; +} +fn gpio_set_dir(gpio: c_uint, on_off: bool) { + unsafe { c::c_gpio_set_dir(gpio, on_off) }; +} +fn gpio_put(gpio: c_uint, on_off: bool) { + unsafe { c::c_gpio_put(gpio, on_off) }; +} + +fn sleep_us(us: u64) { + unsafe { c::sleep_us(us) }; +} +fn sleep_ms(ms: u32) { + unsafe { c::sleep_ms(ms) }; +} + +// this is now the entry point +#[no_mangle] +pub extern "C" fn main() -> c_int { + rs_main() +} + +#[no_mangle] +pub extern "C" fn rs_main() -> c_int { + let led_pin = *LED_PIN; + gpio_init(led_pin); + gpio_set_dir(led_pin, true); + let mut sleep = 250; + loop { + gpio_put(led_pin, true); + sleep_ms(sleep); + gpio_put(led_pin, false); + sleep_ms(sleep); + sleep = add_half(sleep); + } +} + +#[no_mangle] +pub extern "C" fn add_half(num: u32) -> u32 { + let mut half = num / 2; + if half == 0 { + half = 1; + } + num.wrapping_add(half) +} diff --git a/c/CMakeLists.txt b/c/CMakeLists.txt new file mode 100644 index 0000000..868ad2a --- /dev/null +++ b/c/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.12) + +# Pull in SDK (must be before project) +include(pico_sdk_import.cmake) + +project(pico_examples C CXX ASM) +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + +# Initialize the SDK +pico_sdk_init() + +add_executable( + blink + blink.c + ) + +# pull in common dependencies +target_link_libraries( + blink + pico_stdlib + ) + +# create map/bin/hex file etc. +pico_add_extra_outputs(blink) diff --git a/c/blink.c b/c/blink.c new file mode 100644 index 0000000..f413d50 --- /dev/null +++ b/c/blink.c @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "pico/stdlib.h" + +int main() { + const uint LED_PIN = PICO_DEFAULT_LED_PIN; + gpio_init(LED_PIN); + gpio_set_dir(LED_PIN, GPIO_OUT); + while (true) { + gpio_put(LED_PIN, 1); + sleep_ms(250); + gpio_put(LED_PIN, 0); + sleep_ms(250); + } +} diff --git a/c/build.sh b/c/build.sh new file mode 100755 index 0000000..22cb589 --- /dev/null +++ b/c/build.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -euxo pipefail + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +mkdir -p /tmp/8 +cd /tmp/8 + +cmake "$SCRIPT_DIR" + +make + +picotool info +picotool load blink.uf2 +picotool reboot + diff --git a/c/pico_sdk_import.cmake b/c/pico_sdk_import.cmake new file mode 100644 index 0000000..28efe9e --- /dev/null +++ b/c/pico_sdk_import.cmake @@ -0,0 +1,62 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG master + ) + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + FetchContent_Populate(pico_sdk) + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..ceae045 --- /dev/null +++ b/readme.txt @@ -0,0 +1,11 @@ +examples of blinking projects on rpi pico + +one with C only + +one with C using a static rust lib + +one with rust using a static C lib + +run ./build.sh in each of the directories to flash and run them to your rpi pico + +If you have suggestions for better ways let me know diff --git a/rust-with-c/.cargo/config.toml b/rust-with-c/.cargo/config.toml new file mode 100644 index 0000000..1474ed6 --- /dev/null +++ b/rust-with-c/.cargo/config.toml @@ -0,0 +1,29 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# Choose a default "cargo run" tool (see README for more info) +# - `probe-rs` provides flashing and defmt via a hardware debugger, and stack unwind on panic +# - elf2uf2-rs loads firmware over USB when the rp2040 is in boot mode +#runner = "probe-rs run --chip RP2040 --protocol swd" +#runner = "elf2uf2-rs -d" +# runner = "sh -c \"cp /tmp/cargo-target/thumbv6m-none-eabi/debug/rp2040-project-template /tmp/rp.elf && picotool load /tmp/rp.elf\"" +# runner = "cp /tmp/cargo-target/thumbv6m-none-eabi/debug/rp2040-project-template /tmp/rp.elf && picotool load /tmp/rp.elf" +runner = "pico-load-elf.sh" + +rustflags = [ + "-C", "linker=flip-link", + "-C", "link-arg=--nmagic", + "-C", "link-arg=-Tlink.x", + + # Code-size optimizations. + # trap unreachable can save a lot of space, but requires nightly compiler. + # uncomment the next line if you wish to enable it + # "-Z", "trap-unreachable=no", + "-C", "inline-threshold=5", + "-C", "no-vectorize-loops", + +] + +[build] +target = "thumbv6m-none-eabi" + +[env] +DEFMT_LOG = "debug" diff --git a/rust-with-c/Cargo.lock b/rust-with-c/Cargo.lock new file mode 100644 index 0000000..30228b6 --- /dev/null +++ b/rust-with-c/Cargo.lock @@ -0,0 +1,380 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "bare-metal" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cmake" +version = "0.1.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" +dependencies = [ + "cc", +] + +[[package]] +name = "cortex-m" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" +dependencies = [ + "bare-metal", + "bitfield", + "embedded-hal", + "volatile-register", +] + +[[package]] +name = "cortex-m-rt" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee84e813d593101b1723e13ec38b6ab6abbdbaaa4546553f5395ed274079ddb1" +dependencies = [ + "cortex-m-rt-macros", +] + +[[package]] +name = "cortex-m-rt-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f6f3e36f203cfedbc78b357fb28730aa2c6dc1ab060ee5c2405e843988d3c7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "crc-any" +version = "2.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c01a5e1f881f6fb6099a7bdf949e946719fd4f1fefa56264890574febf0eb6d0" +dependencies = [ + "debug-helper", +] + +[[package]] +name = "critical-section" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" + +[[package]] +name = "debug-helper" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f578e8e2c440e7297e008bb5486a3a8a194775224bbc23729b0dbdfaeebf162e" + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "embedded-dma" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "994f7e5b5cb23521c22304927195f236813053eb9c065dd2226a32ba64695446" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "fugit" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17186ad64927d5ac8f02c1e77ccefa08ccd9eaa314d5a4772278aa204a22f7e7" +dependencies = [ + "gcd", +] + +[[package]] +name = "gcd" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "pio" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76e09694b50f89f302ed531c1f2a7569f0be5867aee4ab4f8f729bbeec0078e3" +dependencies = [ + "arrayvec", + "num_enum", + "paste", +] + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rblink" +version = "0.1.0" +dependencies = [ + "cmake", + "cortex-m", + "cortex-m-rt", + "embedded-hal", + "rp-pico", +] + +[[package]] +name = "rp-pico" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aab28f6f4e19cec2d61b64cdd685e69794b81c579fd3b765579c46018fe616d0" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "fugit", + "rp2040-boot2", + "rp2040-hal", + "usb-device", +] + +[[package]] +name = "rp2040-boot2" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c773ec49b836077aa144b58dc7654a243e1eecdb6cf0d25361ae7c7600fabd8" +dependencies = [ + "crc-any", +] + +[[package]] +name = "rp2040-hal" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1369bb84862d7f69391a96606b2f29a00bfce7f29a749e23d5f01fc3f607ada0" +dependencies = [ + "cortex-m", + "critical-section", + "embedded-dma", + "embedded-hal", + "fugit", + "itertools", + "nb 1.1.0", + "paste", + "pio", + "rand_core", + "rp2040-hal-macros", + "rp2040-pac", + "usb-device", + "vcell", + "void", +] + +[[package]] +name = "rp2040-hal-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86479063e497efe1ae81995ef9071f54fd1c7427e04d6c5b84cde545ff672a5e" +dependencies = [ + "cortex-m-rt", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "rp2040-pac" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9192cafbb40d717c9e0ddf767aaf9c69fee1b4e48d22ed853b57b11f6d9f3d7e" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "vcell", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "usb-device" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f6cc3adc849b5292b4075fc0d5fdcf2f24866e88e336dd27a8943090a520508" + +[[package]] +name = "vcell" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "volatile-register" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" +dependencies = [ + "vcell", +] diff --git a/rust-with-c/Cargo.toml b/rust-with-c/Cargo.toml new file mode 100644 index 0000000..65c3bc8 --- /dev/null +++ b/rust-with-c/Cargo.toml @@ -0,0 +1,69 @@ +[package] +name = "rblink" +version = "0.1.0" +edition = "2021" +build="build.rs" + +[dependencies] +cortex-m = "0.7" +cortex-m-rt = "0.7" +rp-pico = "0.7.0" + + +embedded-hal = { version = "0.2.5", features = ["unproven"] } + + +[build-dependencies] +cmake = "0.1" + +# cargo build/run +[profile.dev] +codegen-units = 1 +debug = 2 +debug-assertions = true +incremental = false +opt-level = 3 +overflow-checks = true + +# cargo build/run --release +[profile.release] +codegen-units = 1 +debug = 2 +debug-assertions = false +incremental = false +lto = 'fat' +opt-level = 3 +overflow-checks = false + +# do not optimize proc-macro crates = faster builds from scratch +[profile.dev.build-override] +codegen-units = 8 +debug = false +debug-assertions = false +opt-level = 0 +overflow-checks = false + +[profile.release.build-override] +codegen-units = 8 +debug = false +debug-assertions = false +opt-level = 0 +overflow-checks = false + +# cargo test +[profile.test] +codegen-units = 1 +debug = 2 +debug-assertions = true +incremental = false +opt-level = 3 +overflow-checks = true + +# cargo test --release +[profile.bench] +codegen-units = 1 +debug = 2 +debug-assertions = false +incremental = false +lto = 'fat' +opt-level = 3 diff --git a/rust-with-c/build.rs b/rust-with-c/build.rs new file mode 100644 index 0000000..b555edc --- /dev/null +++ b/rust-with-c/build.rs @@ -0,0 +1,23 @@ +extern crate cmake; +use cmake::Config; + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + let dst = Config::new("libblink").build(); + + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + println!("cargo:rustc-link-search=native={}", dst.display()); + println!("cargo:rustc-link-lib=static=blink"); +} diff --git a/rust-with-c/build.sh b/rust-with-c/build.sh new file mode 100755 index 0000000..d5e9f73 --- /dev/null +++ b/rust-with-c/build.sh @@ -0,0 +1,13 @@ +#!/bin/bash +set -euxo pipefail + +# run: rustup target add thumbv6m-none-eabi +# run: cargo install flip-link + +CARGO_TARGET_DIR=/tmp/cargo-target cargo build -vv --release --target thumbv6m-none-eabi + +picotool info +mv /tmp/cargo-target/thumbv6m-none-eabi/release/rblink /tmp/rp.elf +picotool load /tmp/rp.elf +picotool reboot + diff --git a/rust-with-c/libblink/CMakeLists.txt b/rust-with-c/libblink/CMakeLists.txt new file mode 100644 index 0000000..3524901 --- /dev/null +++ b/rust-with-c/libblink/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.12) + +# Pull in SDK (must be before project) +include(pico_sdk_import.cmake) + +project(pico_examples C CXX ASM) +set(CMAKE_C_STANDARD 17) +set(CMAKE_CXX_STANDARD 17) + +# Initialize the SDK +pico_sdk_init() + +add_library(blink STATIC blink.c) + +target_link_libraries( + blink + pico_stdlib + ) + +install(TARGETS blink DESTINATION .) + diff --git a/rust-with-c/libblink/blink.c b/rust-with-c/libblink/blink.c new file mode 100644 index 0000000..67dec03 --- /dev/null +++ b/rust-with-c/libblink/blink.c @@ -0,0 +1,56 @@ +#include "pico/stdlib.h" +#include "pico/bootrom.h" + +// https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html +// bool is compatible +#define i8 int8_t +#define i16 int16_t +#define i32 int32_t + +#define u8 uint8_t +#define u16 uint16_t +#define u32 uint32_t + +#define i64 int64_t +#define u64 uint64_t + +#define isize intptr_t +#define usize uintptr_t + + +// used from rust +const uint LED_PIN = PICO_DEFAULT_LED_PIN; +uint led_pin() { + return PICO_DEFAULT_LED_PIN; +} +// without this: undefined reference to `gpio_set_dir' +void c_gpio_set_dir(uint gpio, bool out) { + return gpio_set_dir(gpio, out); +} +// without this: undefined reference to `gpio_put' +void c_gpio_put(uint gpio, bool value) { + return gpio_put(gpio, value); +} + + +// defined in rust +u32 add_half(u32 num); +int rs_main(); + +int c_main() { + gpio_init(LED_PIN); + gpio_set_dir(LED_PIN, GPIO_OUT); + int sleep = 250; + while (true) { + gpio_put(LED_PIN, 1); + sleep_ms(sleep); + gpio_put(LED_PIN, 0); + sleep_ms(sleep); + sleep = add_half(sleep); + // in rust: + //reset_to_usb_boot(LED_PIN, 0); + if(sleep > 2000) { + reset_usb_boot(LED_PIN, 0); + } + } +} diff --git a/rust-with-c/libblink/pico_sdk_import.cmake b/rust-with-c/libblink/pico_sdk_import.cmake new file mode 100644 index 0000000..28efe9e --- /dev/null +++ b/rust-with-c/libblink/pico_sdk_import.cmake @@ -0,0 +1,62 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG master + ) + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + FetchContent_Populate(pico_sdk) + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/rust-with-c/memory.x b/rust-with-c/memory.x new file mode 100644 index 0000000..070eac7 --- /dev/null +++ b/rust-with-c/memory.x @@ -0,0 +1,15 @@ +MEMORY { + BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 + FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100 + RAM : ORIGIN = 0x20000000, LENGTH = 256K +} + +EXTERN(BOOT2_FIRMWARE) + +SECTIONS { + /* ### Boot loader */ + .boot2 ORIGIN(BOOT2) : + { + KEEP(*(.boot2)); + } > BOOT2 +} INSERT BEFORE .text; \ No newline at end of file diff --git a/rust-with-c/src/main.rs b/rust-with-c/src/main.rs new file mode 100644 index 0000000..0f41bae --- /dev/null +++ b/rust-with-c/src/main.rs @@ -0,0 +1,125 @@ +#![no_std] +#![no_main] + +use bsp::entry; + +// Provide an alias for our BSP so we can switch targets quickly. +// Uncomment the BSP you included in Cargo.toml, the rest of the code does not need to change. +use rp_pico as bsp; +// use sparkfun_pro_micro_rp2040 as bsp; + +use bsp::hal::{ + clocks::{init_clocks_and_plls, Clock}, + pac, + sio::Sio, + watchdog::Watchdog, +}; + + + +// https://doc.rust-lang.org/core/ffi/index.html +use core::ffi::{c_int, c_uint, c_void}; + +#[panic_handler] +fn oh_no(_panic_info: &core::panic::PanicInfo) -> ! { + loop {} +} + + +mod c { + use core::ffi::{c_int, c_uint, c_void}; + #[link(name = "blink", kind = "static")] + extern "C" { + pub(super) static LED_PIN: c_uint; + + // https://www.raspberrypi.com/documentation/pico-sdk/high_level.html + pub(super) fn gpio_init(gpio: c_uint) -> c_void; + pub(super) fn c_gpio_set_dir(gpio: c_uint, on_off: bool) -> c_void; + pub(super) fn c_gpio_put(gpio: c_uint, on_off: bool) -> c_void; + + pub(super) fn sleep_us(us: u64) -> c_void; + pub(super) fn sleep_ms(ms: u32) -> c_void; + + + pub(super) fn c_main() -> c_void; + } +} + +static LED_PIN: &c_uint = unsafe { &c::LED_PIN }; + +fn gpio_init(gpio: c_uint) { + unsafe { c::gpio_init(gpio) }; +} +fn gpio_set_dir(gpio: c_uint, on_off: bool) { + unsafe { c::c_gpio_set_dir(gpio, on_off) }; +} +fn gpio_put(gpio: c_uint, on_off: bool) { + unsafe { c::c_gpio_put(gpio, on_off) }; +} + +fn sleep_us(us: u64) { + unsafe { c::sleep_us(us) }; +} +fn sleep_ms(ms: u32) { + unsafe { c::sleep_ms(ms) }; +} + +#[no_mangle] +pub extern "C" fn rs_main() -> c_int { + let led_pin = *LED_PIN; + gpio_init(led_pin); + gpio_set_dir(led_pin, true); + let mut sleep = 250; + loop { + gpio_put(led_pin, true); + sleep_ms(sleep); + gpio_put(led_pin, false); + sleep_ms(sleep); + sleep = add_half(sleep); + } +} + +#[no_mangle] +pub extern "C" fn add_half(num: u32) -> u32 { + let mut half = num / 2; + if half == 0 { + half = 1; + } + num.wrapping_add(half) +} + + +#[entry] +fn main() -> ! { + let mut pac = pac::Peripherals::take().unwrap(); + let mut watchdog = Watchdog::new(pac.WATCHDOG); + let sio = Sio::new(pac.SIO); + + // External high-speed crystal on the pico board is 12Mhz + let external_xtal_freq_hz = 12_000_000u32; + let clocks = init_clocks_and_plls( + external_xtal_freq_hz, + pac.XOSC, + pac.CLOCKS, + pac.PLL_SYS, + pac.PLL_USB, + &mut pac.RESETS, + &mut watchdog, + ) + .ok() + .unwrap(); + + let pins = bsp::Pins::new( + pac.IO_BANK0, + pac.PADS_BANK0, + sio.gpio_bank0, + &mut pac.RESETS, + ); + + //use embedded_hal::watchdog::WatchdogEnable; + //watchdog.start(10); + + //rs_main(); + unsafe { c::c_main() }; + loop{} +}