Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RP2040 Support #16

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
```
4 changes: 4 additions & 0 deletions ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 ../..
Expand Down
3 changes: 3 additions & 0 deletions src/chip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions src/chip/family.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ use std::fmt::Display;
pub enum Family {
STM32,
NRF(MemRegion),
RP2040,
}

impl Display for Family {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Self::STM32 => "stm32",
Self::NRF(_) => "nrf",
Self::RP2040 => "rp",
})
}
}
7 changes: 7 additions & 0 deletions src/chip/family/mem_region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
}
88 changes: 61 additions & 27 deletions src/init.rs
Original file line number Diff line number Diff line change
@@ -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},
};
Expand Down Expand Up @@ -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.");
}

Expand Down Expand Up @@ -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)
Expand All @@ -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(
Expand All @@ -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 {
Expand All @@ -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)?;
Expand Down Expand Up @@ -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> {
Expand Down
37 changes: 37 additions & 0 deletions src/templates/build.rs.rp.template
Original file line number Diff line number Diff line change
@@ -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");
}
30 changes: 30 additions & 0 deletions src/templates/main.rs.rp.template
Original file line number Diff line number Diff line change
@@ -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;
}}
}}
File renamed without changes.
15 changes: 15 additions & 0 deletions src/templates/memory.x.rp.template
Original file line number Diff line number Diff line change
@@ -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;
Loading