diff --git a/README.md b/README.md index 4f3db28..70c08b7 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Get up and running with Embassy in seconds. # Features -- Supports STM32* and NRF* +- Supports STM32*, NRF*, and RP* - Generates project structure - Toolchain - Probing @@ -57,3 +57,8 @@ cargo embassy init my_project --chip nrf52840 ```sh cargo embassy init my_project --chip nrf52832_xxAA --softdevice s132 ``` + +**Create a new Embassy project for the RP Pico** +```sh +cargo embassy init my_project --chip rp2040 +``` \ No newline at end of file diff --git a/ci.sh b/ci.sh index 742c3d1..ed70898 100755 --- a/ci.sh +++ b/ci.sh @@ -27,11 +27,15 @@ $cwd/target/release/cargo-embassy embassy init test-stm32g4 --chip stm32g431rb - $cwd/target/release/cargo-embassy embassy init test-nrf52840 --chip nrf52840 $cwd/target/release/cargo-embassy embassy init test-nrf52832 --chip nrf52832-xxab --softdevice s132 +# rp +$cwd/target/release/cargo-embassy embassy init test-rp2040 --chip rp2040 + # compile cd test-stm32g0; cargo build; cargo build --no-default-features --release cd ../test-stm32g4; cargo build; cargo build --no-default-features --release cd ../test-nrf52840; cargo build; cargo build --no-default-features --release cd ../test-nrf52832; cargo build; cargo build --no-default-features --release +cd ../test-rp2040; cargo build; cargo build --no-default-features --release # clean up cd ../.. diff --git a/src/chip.rs b/src/chip.rs index a2fc418..ff93195 100644 --- a/src/chip.rs +++ b/src/chip.rs @@ -48,6 +48,8 @@ impl FromStr for Chip { ("stm32wb", (STM32, Thumbv7e)), ("stm32wba", (STM32, Thumbv8)), ("stm32wl", (STM32, Thumbv7e)), + // RP2040 + ("rp2040", (RP2040, Thumbv6)), ]; let (family, target) = chips @@ -63,6 +65,7 @@ impl FromStr for Chip { STM32 => chip.to_string(), // FRAGILE: "_" is used to coerce probe-rs chip search NRF(_) => chip.split('_').next().unwrap().to_string(), + RP2040 => chip.to_string(), }, family, target, diff --git a/src/chip/family.rs b/src/chip/family.rs index 5f5d390..344a2a8 100644 --- a/src/chip/family.rs +++ b/src/chip/family.rs @@ -8,6 +8,7 @@ use std::fmt::Display; pub enum Family { STM32, NRF(MemRegion), + RP2040, } impl Display for Family { @@ -15,6 +16,7 @@ impl Display for Family { f.write_str(match self { Self::STM32 => "stm32", Self::NRF(_) => "nrf", + Self::RP2040 => "rp", }) } } diff --git a/src/chip/family/mem_region.rs b/src/chip/family/mem_region.rs index fe61cc9..f91bae9 100644 --- a/src/chip/family/mem_region.rs +++ b/src/chip/family/mem_region.rs @@ -45,4 +45,11 @@ impl MemRegion { ram_origin: 0x2 << 28, ram_length: 256, }; + + pub const RP2040: Self = Self { + flash_origin: 0x10000100, + flash_length: 2048, + ram_origin: 0x2 << 28, + ram_length: 256 + }; } diff --git a/src/init.rs b/src/init.rs index 6567454..6e18dc7 100644 --- a/src/init.rs +++ b/src/init.rs @@ -1,9 +1,5 @@ use crate::{ - chip::{ - family::{mem_region::MemRegion, Family}, - target::Target, - Chip, - }, + chip::{family::Family, target::Target, Chip}, cli::init_args::{panic_handler::PanicHandler, soft_device::Softdevice, InitArgs}, error::{Error, InvalidChip}, }; @@ -65,9 +61,9 @@ impl Init { )?; self.init_fmt()?; self.init_main(&chip.family, &args.panic_handler, args.softdevice.as_ref())?; + self.init_memory_x(&chip.family)?; - if let Family::NRF(mem_reg) = chip.family { - self.init_memory_x(mem_reg)?; + if args.softdevice.is_some() { self.pb.println("[ACTION NEEDED] You must now flash the Softdevice and configure memory.x. Instructions can be found here: https://github.com/embassy-rs/nrf-softdevice#running-examples."); } @@ -134,6 +130,7 @@ impl Init { let template = match family { Family::STM32 => include_str!("templates/build.rs.stm32.template"), Family::NRF(_) => include_str!("templates/build.rs.nrf.template"), + Family::RP2040 => include_str!("templates/build.rs.rp.template"), }; self.create_file("build.rs", template) @@ -159,7 +156,15 @@ impl Init { )?; self.cargo_add("embassy-sync", None, false)?; self.cargo_add("embassy-futures", None, false)?; - self.cargo_add("embassy-time", Some(&["tick-hz-32_768"]), false)?; + + self.cargo_add( + "embassy-time", + match chip.family { + Family::RP2040 => None, + _ => Some(&["tick-hz-32_768"]), + }, + false, + )?; match chip.family { Family::STM32 => self.cargo_add( @@ -178,6 +183,17 @@ impl Init { Some(&[chip.name.as_str(), "gpiote", "time-driver-rtc1"]), false, ), + Family::RP2040 => { + self.cargo_add( + "embassy-rp", + Some(&["unstable-pac", "time-driver", "critical-section-impl"]), + false, + )?; + + self.cargo_add("embassy-embedded-hal", None, false)?; + + Ok(()) + } }?; if let Some(softdevice) = softdevice { @@ -195,15 +211,21 @@ impl Init { self.cargo_add(&format!("nrf-softdevice-{}", softdevice.str()), None, false)?; } - self.cargo_add( - "cortex-m", - Some(if softdevice.is_some() { - &["inline-asm"] - } else { - &["inline-asm", "critical-section-single-core"] - }), - false, - )?; + match chip.family { + Family::RP2040 => self.cargo_add("cortex-m", Some(&["inline-asm"]), false)?, + _ => { + self.cargo_add( + "cortex-m", + Some(if softdevice.is_some() { + &["inline-asm"] + } else { + &["inline-asm", "critical-section-single-core"] + }), + false, + )?; + } + } + self.cargo_add("cortex-m-rt", None, false)?; self.cargo_add("defmt", None, true)?; self.cargo_add("defmt-rtt", None, true)?; @@ -272,21 +294,33 @@ impl Init { panic_handler = panic_handler ) } + (Family::RP2040, _) => { + format!( + include_str!("templates/main.rs.rp.template"), + panic_handler = panic_handler + ) + } }, ) } - fn init_memory_x(&self, memory: MemRegion) -> Result<(), Error> { - self.create_file( - "memory.x", - &format!( - include_str!("templates/memory.x.template"), - flash_origin = memory.flash_origin, - flash_len = memory.flash_length, - ram_origin = memory.ram_origin, - ram_len = memory.ram_length, + fn init_memory_x(&self, family: &Family) -> Result<(), Error> { + match family { + Family::NRF(mem) => self.create_file( + "memory.x", + &format!( + include_str!("templates/memory.x.nrf.template"), + flash_origin = mem.flash_origin, + flash_len = mem.flash_length, + ram_origin = mem.ram_origin, + ram_len = mem.ram_length, + ), ), - ) + Family::RP2040 => { + self.create_file("memory.x", &include_str!("templates/memory.x.rp.template")) + } + _ => Ok(()), + } } fn create_file(&self, name: &str, content: &str) -> Result<(), Error> { diff --git a/src/templates/build.rs.rp.template b/src/templates/build.rs.rp.template new file mode 100644 index 0000000..a665707 --- /dev/null +++ b/src/templates/build.rs.rp.template @@ -0,0 +1,37 @@ +//! 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"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tlink-rp.x"); + #[cfg(feature = "defmt")] + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/src/templates/main.rs.rp.template b/src/templates/main.rs.rp.template new file mode 100644 index 0000000..c654d53 --- /dev/null +++ b/src/templates/main.rs.rp.template @@ -0,0 +1,30 @@ +#![no_std] +#![no_main] + +mod fmt; + +#[cfg(not(feature = "defmt"))] +use {panic_handler} as _; +#[cfg(feature = "defmt")] +use {{defmt_rtt as _, panic_probe as _}}; + +use embassy_executor::Spawner; +use embassy_rp::gpio::{{Level, Output}}; +use embassy_time::Timer; +use fmt::info; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) {{ + let p = embassy_rp::init(Default::default()); + let mut led = Output::new(p.PIN_25, Level::Low); + + loop {{ + info!("led on!"); + led.set_high(); + Timer::after_secs(1).await; + + info!("led off!"); + led.set_low(); + Timer::after_secs(1).await; + }} +}} diff --git a/src/templates/memory.x.template b/src/templates/memory.x.nrf.template similarity index 100% rename from src/templates/memory.x.template rename to src/templates/memory.x.nrf.template diff --git a/src/templates/memory.x.rp.template b/src/templates/memory.x.rp.template new file mode 100644 index 0000000..4077aab --- /dev/null +++ b/src/templates/memory.x.rp.template @@ -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;