From a6d17a33b91610b85b840b8665d4e0a9f24215ff Mon Sep 17 00:00:00 2001 From: Ryan Butler Date: Tue, 8 Nov 2022 12:04:20 -0500 Subject: [PATCH] firmware: hello world nrf (#48) * hello world nrf * Fixed up the readme and linker script --- .gitignore | 2 +- Cargo.toml | 15 +- nrf_demo/.cargo/config.toml | 15 ++ nrf_demo/.gitignore | 2 + nrf_demo/Cargo.lock | 387 +++++++++++++++++++++++++++++++++++ nrf_demo/Cargo.toml | 16 ++ nrf_demo/README.md | 27 +++ nrf_demo/build.rs | 31 +++ nrf_demo/memory.x | 23 +++ nrf_demo/rust-toolchain.toml | 4 + nrf_demo/src/main.rs | 25 +++ 11 files changed, 538 insertions(+), 9 deletions(-) create mode 100644 nrf_demo/.cargo/config.toml create mode 100644 nrf_demo/.gitignore create mode 100644 nrf_demo/Cargo.lock create mode 100644 nrf_demo/Cargo.toml create mode 100644 nrf_demo/README.md create mode 100644 nrf_demo/build.rs create mode 100644 nrf_demo/memory.x create mode 100644 nrf_demo/rust-toolchain.toml create mode 100644 nrf_demo/src/main.rs diff --git a/.gitignore b/.gitignore index 35d60fe4..ab3e0001 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # Cargo stuff -/target +**/target # OS-specific stuff .DS_Store diff --git a/Cargo.toml b/Cargo.toml index 98ac8a67..c5e68a3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,12 @@ [workspace] members = [ - "autoupdater", - "overlay/app", - "overlay/tokio_shutdown", - "skeletal_model", - "testing-jig", - # "firmware", + "autoupdater", + "overlay/app", + "overlay/tokio_shutdown", + "skeletal_model", + "testing-jig", + # "firmware", ] -exclude = ["firmware"] - +exclude = ["nrf_demo", "firmware"] resolver = "2" diff --git a/nrf_demo/.cargo/config.toml b/nrf_demo/.cargo/config.toml new file mode 100644 index 00000000..40b921e5 --- /dev/null +++ b/nrf_demo/.cargo/config.toml @@ -0,0 +1,15 @@ +[target.thumbv7em-none-eabihf] + +rustflags = [ + "-C", + "link-arg=--nmagic", + "-C", + "link-arg=-Tlink.x", + "-C", + "link-arg=-Tdefmt.x", + "-C", + "linker=flip-link", # Requires you to `cargo install flip-link` +] + +[build] +target = "thumbv7em-none-eabihf" diff --git a/nrf_demo/.gitignore b/nrf_demo/.gitignore new file mode 100644 index 00000000..811d1262 --- /dev/null +++ b/nrf_demo/.gitignore @@ -0,0 +1,2 @@ +*.uf2 +*.bin diff --git a/nrf_demo/Cargo.lock b/nrf_demo/Cargo.lock new file mode 100644 index 00000000..3d5b825b --- /dev/null +++ b/nrf_demo/Cargo.lock @@ -0,0 +1,387 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "az" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" + +[[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 = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bytemuck" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaa3a8d9a1ca92e282c96a32d6511b695d7d994d1d102ba85d279f9b2756947f" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cortex-m" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70858629a458fdfd39f9675c4dc309411f2a3f83bede76988d81bf1a0ecee9e0" +dependencies = [ + "bare-metal", + "bitfield", + "embedded-hal", + "volatile-register", +] + +[[package]] +name = "cortex-m-rt" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c433da385b720d5bb9f52362fa2782420798e68d40d67bfe4b0d992aba5dfe7" +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 = "critical-section" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6548a0ad5d2549e111e1f6a11a6c2e2d00ce6a3dafe22948d67c2b443f775e52" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "defmt" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3a0ae7494d9bff013d7b89471f4c424356a71e9752e0c78abe7e6c608a16bb3" +dependencies = [ + "bitflags", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8500cbe4cca056412efce4215a63d0bc20492942aeee695f23b624a53e0a6854" +dependencies = [ + "defmt-parser", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "defmt-parser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0db23d29972d99baa3de2ee2ae3f104c10564a6d05a346eb3f4c4f2c0525a06e" + +[[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 = "embedded-storage" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "156d7a2fdd98ebbf9ae579cbceca3058cff946e13f8e17b90e3511db0508c723" + +[[package]] +name = "fixed" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0371cd413fb63f8ec1b9eb4dff47fa2c88b21abc681771234c84808b9920991" +dependencies = [ + "az", + "bytemuck", + "half", + "typenum", +] + +[[package]] +name = "half" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad6a9459c9c30b177b925162351f97e7d967c7ea8bab3b8352805327daf45554" +dependencies = [ + "crunchy", +] + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.0.0", +] + +[[package]] +name = "nb" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" + +[[package]] +name = "nrf-hal-common" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd244c63d588066d75cffdcae8a03299fd5fb272e36bdde4a9f922f3e4bc6e4b" +dependencies = [ + "cast", + "cfg-if", + "cortex-m", + "embedded-dma", + "embedded-hal", + "embedded-storage", + "fixed", + "nb 1.0.0", + "nrf-usbd", + "nrf52840-pac", + "rand_core", + "void", +] + +[[package]] +name = "nrf-usbd" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66b2907c0b3ec4d264981c1fc5a2321d51c463d5a63d386e573f00e84d5495e6" +dependencies = [ + "cortex-m", + "critical-section", + "usb-device", + "vcell", +] + +[[package]] +name = "nrf52840-hal" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b54757ec98f38331889d1d6c535edb5dd543c762751abfe507f2d644b30f6d4f" +dependencies = [ + "embedded-hal", + "nrf-hal-common", + "nrf52840-pac", +] + +[[package]] +name = "nrf52840-pac" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30713f36f1be02e5bc9abefa30eae4a1f943d810f199d4923d3ad062d1be1b3d" +dependencies = [ + "cortex-m", + "vcell", +] + +[[package]] +name = "nrf_demo" +version = "0.1.0" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "defmt", + "embedded-hal", + "nrf52840-hal", + "panic-halt", +] + +[[package]] +name = "panic-halt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +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 = "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.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" + +[[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 = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6" +dependencies = [ + "vcell", +] diff --git a/nrf_demo/Cargo.toml b/nrf_demo/Cargo.toml new file mode 100644 index 00000000..f0517f63 --- /dev/null +++ b/nrf_demo/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "nrf_demo" +version = "0.1.0" +authors = ["Ryan Butler "] +edition = "2021" +license = "MIT OR Apache-2.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +cortex-m = "0.7.6" +cortex-m-rt = { version = "0.7.1" } +nrf52840-hal = { version = "0.16.0", default-features = false } +panic-halt = "0.2.0" +defmt = "0.3" +embedded-hal = "0.2" diff --git a/nrf_demo/README.md b/nrf_demo/README.md new file mode 100644 index 00000000..547b88bb --- /dev/null +++ b/nrf_demo/README.md @@ -0,0 +1,27 @@ +# NRF Demo +This code demos the use of the nrf52840 on embedded rust. + +## Prerequisites +You need all the usual rust tools, which can be gotten from [rustup](https://rustup.rs). +Then, we need the `flip-link` linker which improves memory safety. Install it via +`cargo install flip-link`. We also need to `cargo install cargo-binutils` to get +objcopy. Finally we need to `cargo install uf2conv` to allow us to convert from .bin to +the uf2 flashing format. + +## Building the code +You can check that code compiles with `cargo check` or `cargo build`. + +To actually build the code, you should run `cargo objcopy -- -O binary nrf_demo.bin` to +get the .bin file for the firmware (note that this will run `cargo build` for you). +Then we need to convert it into uf2 format by running `uf2conv nrf_demo.bin -b 0x26000 +--family 0xada52840`. + +Then you can double tap the reset button (or short RST to GND) to get into bootloader +mode. After doing so, a USB drive for the NRF will appear, into which you may copy your +UF2 file you created. This will upload and flash the firmware to the nrf. + +Please note that this assumes your NRF chip has the softdevice firmware already loaded +on the bootloader, and that the bootloader starts the code at 0x2600. If not, you may +need to use `-b 0x1000` instead and modify `memory.x`. We found that the seed studio +bootloader did not work with this approach, so we had to flash the adafruit bootloader +on instead. diff --git a/nrf_demo/build.rs b/nrf_demo/build.rs new file mode 100644 index 00000000..d534cc3d --- /dev/null +++ b/nrf_demo/build.rs @@ -0,0 +1,31 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // 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()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); +} diff --git a/nrf_demo/memory.x b/nrf_demo/memory.x new file mode 100644 index 00000000..eb82cdcd --- /dev/null +++ b/nrf_demo/memory.x @@ -0,0 +1,23 @@ +/* Linker script for the nRF52 - WITH SOFT DEVICE */ +MEMORY +{ + /* NOTE K = KiBi = 1024 bytes */ + FLASH : ORIGIN = 0x00026000, LENGTH = 1024K // Change to 0x1000 if you don't have softdevice + RAM : ORIGIN = 0x20000000, LENGTH = 256K +} + +/* This is where the call stack will be allocated. */ +/* The stack is of the full descending type. */ +/* You may want to use this variable to locate the call stack and static + variables in different memory regions. Below is shown the default value */ +/* _stack_start = ORIGIN(RAM) + LENGTH(RAM); */ + +/* You can use this symbol to customize the location of the .text section */ +/* If omitted the .text section will be placed right after the .vector_table + section */ +/* This is required only on microcontrollers that store some configuration right + after the vector table */ +/* _stext = ORIGIN(FLASH) + 0x400; */ + +/* Size of the heap (in bytes) */ +/* _heap_size = 1024; */ diff --git a/nrf_demo/rust-toolchain.toml b/nrf_demo/rust-toolchain.toml new file mode 100644 index 00000000..22c28abb --- /dev/null +++ b/nrf_demo/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "stable" +components = ["llvm-tools-preview"] +targets = ["thumbv7em-none-eabihf"] diff --git a/nrf_demo/src/main.rs b/nrf_demo/src/main.rs new file mode 100644 index 00000000..015a53c0 --- /dev/null +++ b/nrf_demo/src/main.rs @@ -0,0 +1,25 @@ +#![no_main] +#![no_std] + +use nrf52840_hal::{gpio::Level, prelude::OutputPin, Delay}; +use panic_halt as _; + +use cortex_m_rt::entry; +use embedded_hal::blocking::delay::DelayMs; + +#[entry] +fn main() -> ! { + let p = nrf52840_hal::pac::Peripherals::take().unwrap(); + let cp = nrf52840_hal::pac::CorePeripherals::take().unwrap(); + + let p0 = nrf52840_hal::gpio::p0::Parts::new(p.P0); + let mut led = p0.p0_15.into_push_pull_output(Level::Low); + let mut delay = Delay::new(cp.SYST); + + loop { + delay.delay_ms(1000 as u16); + led.set_high().expect("Failed to set high"); + delay.delay_ms(1000 as u16); + led.set_low().expect("Failed to set low"); + } +}