diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index b7f5a2bcc..4e36c885b 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -15,6 +15,7 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-rp/sr
features = ["defmt", "unstable-pac", "time-driver"]
flavors = [
{ name = "rp2040", target = "thumbv6m-none-eabi" },
+ { name = "rp235x", target = "thumbv8m.main-none-eabi" },
]
[package.metadata.docs.rs]
@@ -23,7 +24,9 @@ features = ["defmt", "unstable-pac", "time-driver"]
[features]
default = [ "rt" ]
## Enable the rt feature of [`rp-pac`](https://docs.rs/rp-pac). This brings in the [`cortex-m-rt`](https://docs.rs/cortex-m-rt) crate, which adds startup code and minimal runtime initialization.
-rt = [ "rp-pac/rt" ]
+rt = []
+rt-2040 = [ "rt", "rp-pac/rt" ]
+rt-235x = [ "rt", "rp23-pac/rt" ]
## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers.
defmt = ["dep:defmt", "embassy-usb-driver/defmt", "embassy-hal-internal/defmt"]
@@ -88,6 +91,17 @@ boot2-w25x10cl = []
## ```
boot2-none = []
+rp2040 = ["dep:rp-pac"]
+rp235x = ["dep:rp23-pac"]
+rp235xa = ["rp235x"]
+rp235xb = ["rp235x"]
+
+# Add a binary-info header block containing picotool-compatible metadata.
+#
+# Takes up a little flash space, but picotool can then report the name of your
+# program and other details.
+binary-info = [ "rt-235x" ]
+
[dependencies]
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true }
@@ -112,7 +126,8 @@ embedded-storage-async = { version = "0.4.1" }
rand_core = "0.6.4"
fixed = "1.23.1"
-rp-pac = { version = "6" }
+rp-pac = { path = "/home/cbjamo/235x/rp-pac", feature = ["rt"], optional = true }
+rp23-pac = { path = "/home/cbjamo/235x/rp23-pac/", feature = ["rt"], optional = true }
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
@@ -123,6 +138,7 @@ pio-proc = {version= "0.2" }
pio = {version= "0.2.1" }
rp2040-boot2 = "0.3"
document-features = "0.2.7"
+sha2-const-stable = "0.1"
[dev-dependencies]
embassy-executor = { version = "0.6.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] }
diff --git a/embassy-rp/build.rs b/embassy-rp/build.rs
index f41ccd220..3216a3826 100644
--- a/embassy-rp/build.rs
+++ b/embassy-rp/build.rs
@@ -4,14 +4,16 @@ use std::io::Write;
use std::path::PathBuf;
fn main() {
- // Put the linker script somewhere the linker can find it
- let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
- let link_x = include_bytes!("link-rp.x.in");
- let mut f = File::create(out.join("link-rp.x")).unwrap();
- f.write_all(link_x).unwrap();
+ if env::var("CARGO_FEATURE_RP2040").is_ok() {
+ // Put the linker script somewhere the linker can find it
+ let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
+ let link_x = include_bytes!("link-rp.x.in");
+ let mut f = File::create(out.join("link-rp.x")).unwrap();
+ f.write_all(link_x).unwrap();
- println!("cargo:rustc-link-search={}", out.display());
+ println!("cargo:rustc-link-search={}", out.display());
- println!("cargo:rerun-if-changed=build.rs");
- println!("cargo:rerun-if-changed=link-rp.x.in");
+ println!("cargo:rerun-if-changed=build.rs");
+ println!("cargo:rerun-if-changed=link-rp.x.in");
+ }
}
diff --git a/embassy-rp/link-rp.x.in b/embassy-rp/link-rp.x.in
index af463f963..1839dda68 100644
--- a/embassy-rp/link-rp.x.in
+++ b/embassy-rp/link-rp.x.in
@@ -5,4 +5,4 @@ SECTIONS {
{
KEEP(*(.boot2));
} > BOOT2
-}
\ No newline at end of file
+}
diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs
index eb1cc9a66..12d08d06b 100644
--- a/embassy-rp/src/adc.rs
+++ b/embassy-rp/src/adc.rs
@@ -11,6 +11,7 @@ use embassy_sync::waitqueue::AtomicWaker;
use crate::gpio::{self, AnyPin, Pull, SealedPin as GpioPin};
use crate::interrupt::typelevel::Binding;
use crate::interrupt::InterruptExt;
+use crate::pac::dma::vals::TreqSel;
use crate::peripherals::{ADC, ADC_TEMP_SENSOR};
use crate::{dma, interrupt, pac, peripherals, Peripheral, RegExt};
@@ -229,7 +230,10 @@ impl<'d> Adc<'d, Async> {
div: u16,
dma: impl Peripheral
,
) -> Result<(), Error> {
+ #[cfg(feature = "rp2040")]
let mut rrobin = 0_u8;
+ #[cfg(feature = "rp235x")]
+ let mut rrobin = 0_u16;
for c in channels {
rrobin |= 1 << c;
}
@@ -278,7 +282,7 @@ impl<'d> Adc<'d, Async> {
}
let auto_reset = ResetDmaConfig;
- let dma = unsafe { dma::read(dma, r.fifo().as_ptr() as *const W, buf as *mut [W], 36) };
+ let dma = unsafe { dma::read(dma, r.fifo().as_ptr() as *const W, buf as *mut [W], TreqSel::ADC) };
// start conversions and wait for dma to finish. we can't report errors early
// because there's no interrupt to signal them, and inspecting every element
// of the fifo is too costly to do here.
@@ -423,10 +427,31 @@ macro_rules! impl_pin {
};
}
+#[cfg(any(feature = "rp235xa", feature = "rp2040"))]
impl_pin!(PIN_26, 0);
+#[cfg(any(feature = "rp235xa", feature = "rp2040"))]
impl_pin!(PIN_27, 1);
+#[cfg(any(feature = "rp235xa", feature = "rp2040"))]
impl_pin!(PIN_28, 2);
+#[cfg(any(feature = "rp235xa", feature = "rp2040"))]
impl_pin!(PIN_29, 3);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_40, 0);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_41, 1);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_42, 2);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_43, 3);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_44, 4);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_45, 5);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_46, 6);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_47, 7);
+
impl SealedAdcChannel for peripherals::ADC_TEMP_SENSOR {}
impl AdcChannel for peripherals::ADC_TEMP_SENSOR {}
diff --git a/embassy-rp/src/binary_info/consts.rs b/embassy-rp/src/binary_info/consts.rs
new file mode 100644
index 000000000..c8270c081
--- /dev/null
+++ b/embassy-rp/src/binary_info/consts.rs
@@ -0,0 +1,31 @@
+//! Constants for binary info
+
+/// All Raspberry Pi specified IDs have this tag.
+///
+/// You can create your own for custom fields.
+pub const TAG_RASPBERRY_PI: u16 = super::make_tag(b"RP");
+
+/// Used to note the program name - use with StringEntry
+pub const ID_RP_PROGRAM_NAME: u32 = 0x02031c86;
+/// Used to note the program version - use with StringEntry
+pub const ID_RP_PROGRAM_VERSION_STRING: u32 = 0x11a9bc3a;
+/// Used to note the program build date - use with StringEntry
+pub const ID_RP_PROGRAM_BUILD_DATE_STRING: u32 = 0x9da22254;
+/// Used to note the size of the binary - use with IntegerEntry
+pub const ID_RP_BINARY_END: u32 = 0x68f465de;
+/// Used to note a URL for the program - use with StringEntry
+pub const ID_RP_PROGRAM_URL: u32 = 0x1856239a;
+/// Used to note a description of the program - use with StringEntry
+pub const ID_RP_PROGRAM_DESCRIPTION: u32 = 0xb6a07c19;
+/// Used to note some feature of the program - use with StringEntry
+pub const ID_RP_PROGRAM_FEATURE: u32 = 0xa1f4b453;
+/// Used to note some whether this was a Debug or Release build - use with StringEntry
+pub const ID_RP_PROGRAM_BUILD_ATTRIBUTE: u32 = 0x4275f0d3;
+/// Used to note the Pico SDK version used - use with StringEntry
+pub const ID_RP_SDK_VERSION: u32 = 0x5360b3ab;
+/// Used to note which board this program targets - use with StringEntry
+pub const ID_RP_PICO_BOARD: u32 = 0xb63cffbb;
+/// Used to note which `boot2` image this program uses - use with StringEntry
+pub const ID_RP_BOOT2_NAME: u32 = 0x7f8882e1;
+
+// End of file
diff --git a/embassy-rp/src/binary_info/macros.rs b/embassy-rp/src/binary_info/macros.rs
new file mode 100644
index 000000000..ef98c8399
--- /dev/null
+++ b/embassy-rp/src/binary_info/macros.rs
@@ -0,0 +1,171 @@
+//! Handy macros for making Binary Info entries
+
+/// Generate a static item containing the given environment variable,
+/// and return its [`EntryAddr`](super::EntryAddr).
+#[macro_export]
+macro_rules! binary_info_env {
+ ($tag:expr, $id:expr, $env_var_name:expr) => {
+ $crate::binary_info_str!($tag, $id, {
+ let value = concat!(env!($env_var_name), "\0");
+ // # Safety
+ //
+ // We used `concat!` to null-terminate on the line above.
+ let value_cstr =
+ unsafe { core::ffi::CStr::from_bytes_with_nul_unchecked(value.as_bytes()) };
+ value_cstr
+ })
+ };
+}
+
+/// Generate a static item containing the given string, and return its
+/// [`EntryAddr`](super::EntryAddr).
+///
+/// You must pass a numeric tag, a numeric ID, and `&CStr` (which is always
+/// null-terminated).
+#[macro_export]
+macro_rules! binary_info_str {
+ ($tag:expr, $id:expr, $str:expr) => {{
+ static ENTRY: $crate::binary_info::StringEntry =
+ $crate::binary_info::StringEntry::new($tag, $id, $str);
+ ENTRY.addr()
+ }};
+}
+
+/// Generate a static item containing the given string, and return its
+/// [`EntryAddr`](super::EntryAddr).
+///
+/// You must pass a numeric tag, a numeric ID, and `&CStr` (which is always
+/// null-terminated).
+#[macro_export]
+macro_rules! binary_info_int {
+ ($tag:expr, $id:expr, $int:expr) => {{
+ static ENTRY: $crate::binary_info::IntegerEntry =
+ $crate::binary_info::IntegerEntry::new($tag, $id, $int);
+ ENTRY.addr()
+ }};
+}
+
+/// Generate a static item containing the program name, and return its
+/// [`EntryAddr`](super::EntryAddr).
+#[macro_export]
+macro_rules! binary_info_rp_program_name {
+ ($name:expr) => {
+ $crate::binary_info_str!(
+ $crate::binary_info::consts::TAG_RASPBERRY_PI,
+ $crate::binary_info::consts::ID_RP_PROGRAM_NAME,
+ $name
+ )
+ };
+}
+
+/// Generate a static item containing the `CARGO_BIN_NAME` as the program name,
+/// and return its [`EntryAddr`](super::EntryAddr).
+#[macro_export]
+macro_rules! binary_info_rp_cargo_bin_name {
+ () => {
+ $crate::binary_info_env!(
+ $crate::binary_info::consts::TAG_RASPBERRY_PI,
+ $crate::binary_info::consts::ID_RP_PROGRAM_NAME,
+ "CARGO_BIN_NAME"
+ )
+ };
+}
+
+/// Generate a static item containing the program version, and return its
+/// [`EntryAddr`](super::EntryAddr).
+#[macro_export]
+macro_rules! binary_info_rp_program_version {
+ ($version:expr) => {{
+ $crate::binary_info_str!(
+ $crate::binary_info::consts::TAG_RASPBERRY_PI,
+ $crate::binary_info::consts::ID_RP_PROGRAM_VERSION,
+ $version
+ )
+ }};
+}
+
+/// Generate a static item containing the `CARGO_PKG_VERSION` as the program
+/// version, and return its [`EntryAddr`](super::EntryAddr).
+#[macro_export]
+macro_rules! binary_info_rp_cargo_version {
+ () => {
+ $crate::binary_info_env!(
+ $crate::binary_info::consts::TAG_RASPBERRY_PI,
+ $crate::binary_info::consts::ID_RP_PROGRAM_VERSION_STRING,
+ "CARGO_PKG_VERSION"
+ )
+ };
+}
+
+/// Generate a static item containing the program URL, and return its
+/// [`EntryAddr`](super::EntryAddr).
+#[macro_export]
+macro_rules! binary_info_rp_program_url {
+ ($url:expr) => {
+ $crate::binary_info_str!(
+ $crate::binary_info::consts::TAG_RASPBERRY_PI,
+ $crate::binary_info::consts::ID_RP_PROGRAM_URL,
+ $url
+ )
+ };
+}
+
+/// Generate a static item containing the `CARGO_PKG_HOMEPAGE` as the program URL,
+/// and return its [`EntryAddr`](super::EntryAddr).
+#[macro_export]
+macro_rules! binary_info_rp_cargo_homepage_url {
+ () => {
+ $crate::binary_info_env!(
+ $crate::binary_info::consts::TAG_RASPBERRY_PI,
+ $crate::binary_info::consts::ID_RP_PROGRAM_URL,
+ "CARGO_PKG_HOMEPAGE"
+ )
+ };
+}
+
+/// Generate a static item containing the program description, and return its
+/// [`EntryAddr`](super::EntryAddr).
+#[macro_export]
+macro_rules! binary_info_rp_program_description {
+ ($description:expr) => {
+ $crate::binary_info_str!(
+ $crate::binary_info::consts::TAG_RASPBERRY_PI,
+ $crate::binary_info::consts::ID_RP_PROGRAM_DESCRIPTION,
+ $description
+ )
+ };
+}
+
+/// Generate a static item containing whether this is a debug or a release
+/// build, and return its [`EntryAddr`](super::EntryAddr).
+#[macro_export]
+macro_rules! binary_info_rp_program_build_attribute {
+ () => {
+ $crate::binary_info_str!(
+ $crate::binary_info::consts::TAG_RASPBERRY_PI,
+ $crate::binary_info::consts::ID_RP_PROGRAM_BUILD_ATTRIBUTE,
+ {
+ if cfg!(debug_assertions) {
+ c"debug"
+ } else {
+ c"release"
+ }
+ }
+ )
+ };
+}
+
+/// Generate a static item containing the specific board this program runs on,
+/// and return its [`EntryAddr`](super::EntryAddr).
+#[macro_export]
+macro_rules! binary_info_rp_pico_board {
+ ($board:expr) => {
+ $crate::binary_info_str!(
+ $crate::binary_info::consts::TAG_RASPBERRY_PI,
+ $crate::binary_info::consts::ID_RP_PICO_BOARD,
+ $board
+ )
+ };
+}
+
+// End of file
diff --git a/embassy-rp/src/binary_info/mod.rs b/embassy-rp/src/binary_info/mod.rs
new file mode 100644
index 000000000..ce3829a7c
--- /dev/null
+++ b/embassy-rp/src/binary_info/mod.rs
@@ -0,0 +1,174 @@
+//! Code and types for creating Picotool compatible "Binary Info" metadata
+//!
+//! Add something like this to your program, and compile with the "binary-info"
+//! and "rt" features:
+//!
+//! ```
+//! # use rp235x_hal as hal;
+//! #[link_section = ".bi_entries"]
+//! #[used]
+//! pub static PICOTOOL_ENTRIES: [hal::binary_info::EntryAddr; 3] = [
+//! hal::binary_info_rp_program_name!(c"Program Name Here"),
+//! hal::binary_info_rp_cargo_version!(),
+//! hal::binary_info_int!(hal::binary_info::make_tag(b"JP"), 0x0000_0001, 0x12345678),
+//! ];
+//! ```
+
+pub mod consts;
+
+mod types;
+pub use types::*;
+
+#[macro_use]
+mod macros;
+
+extern "C" {
+ /// The linker script sets this symbol to have the address of the first
+ /// entry in the `.bi_entries` section.
+ static __bi_entries_start: EntryAddr;
+ /// The linker script sets this symbol to have the address just past the
+ /// last entry in the `.bi_entries` section.
+ static __bi_entries_end: EntryAddr;
+ /// The linker script sets this symbol to have the address of the first
+ /// entry in the `.data` section.
+ static __sdata: u32;
+ /// The linker script sets this symbol to have the address just past the
+ /// first entry in the `.data` section.
+ static __edata: u32;
+ /// The linker script sets this symbol to have the address of the
+ /// initialisation data for the first entry in the `.data` section (i.e. a
+ /// flash address, not a RAM address).
+ static __sidata: u32;
+}
+
+/// Picotool can find this block in our ELF file and report interesting
+/// metadata.
+///
+/// The data here tells picotool the start and end flash addresses of our
+/// metadata.
+#[cfg(feature = "binary-info")]
+#[link_section = ".start_block"]
+#[used]
+pub static PICOTOOL_HEADER: Header = unsafe {
+ Header::new(
+ core::ptr::addr_of!(__bi_entries_start),
+ core::ptr::addr_of!(__bi_entries_end),
+ &MAPPING_TABLE,
+ )
+};
+
+/// This tells picotool how to convert RAM addresses back into Flash addresses
+#[cfg(feature = "binary-info")]
+pub static MAPPING_TABLE: [MappingTableEntry; 2] = [
+ // This is the entry for .data
+ MappingTableEntry {
+ source_addr_start: unsafe { core::ptr::addr_of!(__sidata) },
+ dest_addr_start: unsafe { core::ptr::addr_of!(__sdata) },
+ dest_addr_end: unsafe { core::ptr::addr_of!(__edata) },
+ },
+ // This is the terminating marker
+ MappingTableEntry::null(),
+];
+
+/// Create a 'Binary Info' entry containing the program name
+///
+/// This is well-known to picotool, and will be displayed if you run `picotool info`.
+///
+/// * Tag: [`consts::TAG_RASPBERRY_PI`]
+/// * ID: [`consts::ID_RP_PROGRAM_NAME`]
+pub const fn rp_program_name(name: &'static core::ffi::CStr) -> StringEntry {
+ StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_NAME, name)
+}
+
+/// Create a 'Binary Info' entry containing the program version.
+///
+/// * Tag: [`consts::TAG_RASPBERRY_PI`]
+/// * Id: [`consts::ID_RP_PROGRAM_VERSION_STRING`]
+pub const fn rp_program_version(name: &'static core::ffi::CStr) -> StringEntry {
+ StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_VERSION_STRING, name)
+}
+
+/// Create a 'Binary Info' entry with a URL
+///
+/// * Tag: [`consts::TAG_RASPBERRY_PI`]
+/// * Id: [`consts::ID_RP_PROGRAM_URL`]
+pub const fn rp_program_url(url: &'static core::ffi::CStr) -> StringEntry {
+ StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_URL, url)
+}
+
+/// Create a 'Binary Info' with the program build date
+///
+/// * Tag: [`consts::TAG_RASPBERRY_PI`]
+/// * Id: [`consts::ID_RP_PROGRAM_BUILD_DATE_STRING`]
+pub const fn rp_program_build_date_string(value: &'static core::ffi::CStr) -> StringEntry {
+ StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_BUILD_DATE_STRING, value)
+}
+
+/// Create a 'Binary Info' with the size of the binary
+///
+/// * Tag: [`consts::TAG_RASPBERRY_PI`]
+/// * Id: [`consts::ID_RP_BINARY_END`]
+pub const fn rp_binary_end(value: u32) -> IntegerEntry {
+ IntegerEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_BINARY_END, value)
+}
+
+/// Create a 'Binary Info' with a description of the program
+///
+/// * Tag: [`consts::TAG_RASPBERRY_PI`]
+/// * Id: [`consts::ID_RP_PROGRAM_DESCRIPTION`]
+pub const fn rp_program_description(value: &'static core::ffi::CStr) -> StringEntry {
+ StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_DESCRIPTION, value)
+}
+
+/// Create a 'Binary Info' with some feature of the program
+///
+/// * Tag: [`consts::TAG_RASPBERRY_PI`]
+/// * Id: [`consts::ID_RP_PROGRAM_FEATURE`]
+pub const fn rp_program_feature(value: &'static core::ffi::CStr) -> StringEntry {
+ StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_FEATURE, value)
+}
+
+/// Create a 'Binary Info' with some whether this was a Debug or Release build
+///
+/// * Tag: [`consts::TAG_RASPBERRY_PI`]
+/// * Id: [`consts::ID_RP_PROGRAM_BUILD_ATTRIBUTE`]
+pub const fn rp_program_build_attribute(value: &'static core::ffi::CStr) -> StringEntry {
+ StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_BUILD_ATTRIBUTE, value)
+}
+
+/// Create a 'Binary Info' with the Pico SDK version used
+///
+/// * Tag: [`consts::TAG_RASPBERRY_PI`]
+/// * Id: [`consts::ID_RP_SDK_VERSION`]
+pub const fn rp_sdk_version(value: &'static core::ffi::CStr) -> StringEntry {
+ StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_SDK_VERSION, value)
+}
+
+/// Create a 'Binary Info' with which board this program targets
+///
+/// * Tag: [`consts::TAG_RASPBERRY_PI`]
+/// * Id: [`consts::ID_RP_PICO_BOARD`]
+pub const fn rp_pico_board(value: &'static core::ffi::CStr) -> StringEntry {
+ StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PICO_BOARD, value)
+}
+
+/// Create a 'Binary Info' with which `boot2` image this program uses
+///
+/// * Tag: [`consts::TAG_RASPBERRY_PI`]
+/// * Id: [`consts::ID_RP_BOOT2_NAME`]
+pub const fn rp_boot2_name(value: &'static core::ffi::CStr) -> StringEntry {
+ StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_BOOT2_NAME, value)
+}
+
+/// Create a tag from two ASCII letters.
+///
+/// ```
+/// # use rp235x_hal as hal;
+/// let tag = hal::binary_info::make_tag(b"RP");
+/// assert_eq!(tag, 0x5052);
+/// ```
+pub const fn make_tag(c: &[u8; 2]) -> u16 {
+ u16::from_le_bytes(*c)
+}
+
+// End of file
diff --git a/embassy-rp/src/binary_info/types.rs b/embassy-rp/src/binary_info/types.rs
new file mode 100644
index 000000000..d2b192e32
--- /dev/null
+++ b/embassy-rp/src/binary_info/types.rs
@@ -0,0 +1,192 @@
+//! Types for the Binary Info system
+
+/// This is the 'Binary Info' header block that `picotool` looks for in your UF2
+/// file/ELF file/Pico in Bootloader Mode to give you useful metadata about your
+/// program.
+///
+/// It should be placed in the first 4096 bytes of flash, so use your `memory.x`
+/// to insert a section between `.text` and `.vector_table` and put a static
+/// value of this type in that section.
+#[repr(C)]
+pub struct Header {
+ /// Must be equal to Picotool::MARKER_START
+ marker_start: u32,
+ /// The first in our table of pointers to Entries
+ entries_start: *const EntryAddr,
+ /// The last in our table of pointers to Entries
+ entries_end: *const EntryAddr,
+ /// The first entry in a null-terminated RAM/Flash mapping table
+ mapping_table: *const MappingTableEntry,
+ /// Must be equal to Picotool::MARKER_END
+ marker_end: u32,
+}
+
+impl Header {
+ /// This is the `BINARY_INFO_MARKER_START` magic value from `picotool`
+ const MARKER_START: u32 = 0x7188ebf2;
+ /// This is the `BINARY_INFO_MARKER_END` magic value from `picotool`
+ const MARKER_END: u32 = 0xe71aa390;
+
+ /// Create a new `picotool` compatible header.
+ ///
+ /// * `entries_start` - the first [`EntryAddr`] in the table
+ /// * `entries_end` - the last [`EntryAddr`] in the table
+ /// * `mapping_table` - the RAM/Flash address mapping table
+ pub const fn new(
+ entries_start: *const EntryAddr,
+ entries_end: *const EntryAddr,
+ mapping_table: &'static [MappingTableEntry],
+ ) -> Self {
+ let mapping_table = mapping_table.as_ptr();
+ Self {
+ marker_start: Self::MARKER_START,
+ entries_start,
+ entries_end,
+ mapping_table,
+ marker_end: Self::MARKER_END,
+ }
+ }
+}
+
+// We need this as rustc complains that is is unsafe to share `*const u32`
+// pointers between threads. We only allow these to be created with static
+// data, so this is OK.
+unsafe impl Sync for Header {}
+
+/// This is a reference to an entry. It's like a `&dyn` ref to some type `T:
+/// Entry`, except that the run-time type information is encoded into the
+/// Entry itself in very specific way.
+#[repr(transparent)]
+pub struct EntryAddr(*const u32);
+
+// We need this as rustc complains that is is unsafe to share `*const u32`
+// pointers between threads. We only allow these to be created with static
+// data, so this is OK.
+unsafe impl Sync for EntryAddr {}
+
+/// Allows us to tell picotool where values are in the UF2 given their run-time
+/// address.
+///
+/// The most obvious example is RAM variables, which must be found in the
+/// `.data` section of the UF2.
+#[repr(C)]
+pub struct MappingTableEntry {
+ /// The start address in RAM (or wherever the address picotool finds will
+ /// point)
+ pub source_addr_start: *const u32,
+ /// The start address in flash (or whever the data actually lives in the
+ /// ELF)
+ pub dest_addr_start: *const u32,
+ /// The end address in flash
+ pub dest_addr_end: *const u32,
+}
+
+impl MappingTableEntry {
+ /// Generate a null entry to mark the end of the list
+ pub const fn null() -> MappingTableEntry {
+ MappingTableEntry {
+ source_addr_start: core::ptr::null(),
+ dest_addr_start: core::ptr::null(),
+ dest_addr_end: core::ptr::null(),
+ }
+ }
+}
+
+// We need this as rustc complains that is is unsafe to share `*const u32`
+// pointers between threads. We only allow these to be created with static
+// data, so this is OK.
+unsafe impl Sync for MappingTableEntry {}
+
+/// This is the set of data types that `picotool` supports.
+#[repr(u16)]
+pub enum DataType {
+ /// Raw data
+ Raw = 1,
+ /// Data with a size
+ SizedData = 2,
+ /// A list of binary data
+ BinaryInfoListZeroTerminated = 3,
+ /// A BSON encoded blob
+ Bson = 4,
+ /// An Integer with an ID
+ IdAndInt = 5,
+ /// A string with an Id
+ IdAndString = 6,
+ /// A block device
+ BlockDevice = 7,
+ /// GPIO pins, with their function
+ PinsWithFunction = 8,
+ /// GPIO pins, with their name
+ PinsWithName = 9,
+ /// GPIO pins, with multiple names?
+ PinsWithNames = 10,
+}
+
+/// All Entries start with this common header
+#[repr(C)]
+struct EntryCommon {
+ data_type: DataType,
+ tag: u16,
+}
+
+/// An entry which contains both an ID (e.g. `ID_RP_PROGRAM_NAME`) and a pointer
+/// to a null-terminated string.
+#[repr(C)]
+pub struct StringEntry {
+ header: EntryCommon,
+ id: u32,
+ value: *const core::ffi::c_char,
+}
+
+impl StringEntry {
+ /// Create a new `StringEntry`
+ pub const fn new(tag: u16, id: u32, value: &'static core::ffi::CStr) -> StringEntry {
+ StringEntry {
+ header: EntryCommon {
+ data_type: DataType::IdAndString,
+ tag,
+ },
+ id,
+ value: value.as_ptr(),
+ }
+ }
+
+ /// Get this entry's address
+ pub const fn addr(&self) -> EntryAddr {
+ EntryAddr(self as *const Self as *const u32)
+ }
+}
+
+// We need this as rustc complains that is is unsafe to share `*const
+// core::ffi::c_char` pointers between threads. We only allow these to be
+// created with static string slices, so it's OK.
+unsafe impl Sync for StringEntry {}
+
+/// An entry which contains both an ID (e.g. `ID_RP_BINARY_END`) and an integer.
+#[repr(C)]
+pub struct IntegerEntry {
+ header: EntryCommon,
+ id: u32,
+ value: u32,
+}
+
+impl IntegerEntry {
+ /// Create a new `StringEntry`
+ pub const fn new(tag: u16, id: u32, value: u32) -> IntegerEntry {
+ IntegerEntry {
+ header: EntryCommon {
+ data_type: DataType::IdAndInt,
+ tag,
+ },
+ id,
+ value,
+ }
+ }
+
+ /// Get this entry's address
+ pub const fn addr(&self) -> EntryAddr {
+ EntryAddr(self as *const Self as *const u32)
+ }
+}
+
+// End of file
diff --git a/embassy-rp/src/block.rs b/embassy-rp/src/block.rs
new file mode 100644
index 000000000..d270bbf1c
--- /dev/null
+++ b/embassy-rp/src/block.rs
@@ -0,0 +1,1076 @@
+//! Support for the RP235x Boot ROM's "Block" structures
+//!
+//! Blocks contain pointers, to form Block Loops.
+//!
+//! The `IMAGE_DEF` Block (here the `ImageDef` type) tells the ROM how to boot a
+//! firmware image. The `PARTITION_TABLE` Block (here the `PartitionTable` type)
+//! tells the ROM how to divide the flash space up into partitions.
+
+// These all have a 1 byte size
+
+/// An item ID for encoding a Vector Table address
+pub const ITEM_1BS_VECTOR_TABLE: u8 = 0x03;
+
+/// An item ID for encoding a Rolling Window Delta
+pub const ITEM_1BS_ROLLING_WINDOW_DELTA: u8 = 0x05;
+
+/// An item ID for encoding a Signature
+pub const ITEM_1BS_SIGNATURE: u8 = 0x09;
+
+/// An item ID for encoding a Salt
+pub const ITEM_1BS_SALT: u8 = 0x0c;
+
+/// An item ID for encoding an Image Type
+pub const ITEM_1BS_IMAGE_TYPE: u8 = 0x42;
+
+/// An item ID for encoding the image's Entry Point
+pub const ITEM_1BS_ENTRY_POINT: u8 = 0x44;
+
+/// An item ID for encoding the definition of a Hash
+pub const ITEM_2BS_HASH_DEF: u8 = 0x47;
+
+/// An item ID for encoding a Version
+pub const ITEM_1BS_VERSION: u8 = 0x48;
+
+/// An item ID for encoding a Hash
+pub const ITEM_1BS_HASH_VALUE: u8 = 0x4b;
+
+// These all have a 2-byte size
+
+/// An item ID for encoding a Load Map
+pub const ITEM_2BS_LOAD_MAP: u8 = 0x06;
+
+/// An item ID for encoding a Partition Table
+pub const ITEM_2BS_PARTITION_TABLE: u8 = 0x0a;
+
+/// An item ID for encoding a placeholder entry that is ignored
+///
+/// Allows a Block to not be empty.
+pub const ITEM_2BS_IGNORED: u8 = 0xfe;
+
+/// An item ID for encoding the special last item in a Block
+///
+/// It records how long the Block is.
+pub const ITEM_2BS_LAST: u8 = 0xff;
+
+// Options for ITEM_1BS_IMAGE_TYPE
+
+/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark an image as invalid
+pub const IMAGE_TYPE_INVALID: u16 = 0x0000;
+
+/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark an image as an executable
+pub const IMAGE_TYPE_EXE: u16 = 0x0001;
+
+/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark an image as data
+pub const IMAGE_TYPE_DATA: u16 = 0x0002;
+
+/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU security mode as unspecified
+pub const IMAGE_TYPE_EXE_TYPE_SECURITY_UNSPECIFIED: u16 = 0x0000;
+
+/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU security mode as Non Secure
+pub const IMAGE_TYPE_EXE_TYPE_SECURITY_NS: u16 = 0x0010;
+
+/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU security mode as Non Secure
+pub const IMAGE_TYPE_EXE_TYPE_SECURITY_S: u16 = 0x0020;
+
+/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU type as Arm
+pub const IMAGE_TYPE_EXE_CPU_ARM: u16 = 0x0000;
+
+/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU type as RISC-V
+pub const IMAGE_TYPE_EXE_CPU_RISCV: u16 = 0x0100;
+
+/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU as an RP2040
+pub const IMAGE_TYPE_EXE_CHIP_RP2040: u16 = 0x0000;
+
+/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU as an RP2350
+pub const IMAGE_TYPE_EXE_CHIP_RP2350: u16 = 0x1000;
+
+/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the image as Try Before You Buy.
+///
+/// This means the image must be marked as 'Bought' with the ROM before the
+/// watchdog times out the trial period, otherwise it is erased and the previous
+/// image will be booted.
+pub const IMAGE_TYPE_TBYB: u16 = 0x8000;
+
+/// This is the magic Block Start value.
+///
+/// The Pico-SDK calls it `PICOBIN_BLOCK_MARKER_START`
+const BLOCK_MARKER_START: u32 = 0xffffded3;
+
+/// This is the magic Block END value.
+///
+/// The Pico-SDK calls it `PICOBIN_BLOCK_MARKER_END`
+const BLOCK_MARKER_END: u32 = 0xab123579;
+
+/// An Image Definition has one item in it - an [`ITEM_1BS_IMAGE_TYPE`]
+pub type ImageDef = Block<1>;
+
+/// A Block as understood by the Boot ROM.
+///
+/// This could be an Image Definition, or a Partition Table, or maybe some other
+/// kind of block.
+///
+/// It contains within the special start and end markers the Boot ROM is looking
+/// for.
+#[derive(Debug)]
+#[repr(C)]
+pub struct Block {
+ marker_start: u32,
+ items: [u32; N],
+ length: u32,
+ offset: *const u32,
+ marker_end: u32,
+}
+
+unsafe impl Sync for Block {}
+
+impl Block {
+ /// Construct a new Binary Block, with the given items.
+ ///
+ /// The length, and the Start and End markers are added automatically. The
+ /// Block Loop pointer initially points to itself.
+ pub const fn new(items: [u32; N]) -> Block {
+ Block {
+ marker_start: BLOCK_MARKER_START,
+ items,
+ length: item_last(N as u16),
+ // offset from this block to next block in loop. By default
+ // we form a Block Loop with a single Block in it.
+ offset: core::ptr::null(),
+ marker_end: BLOCK_MARKER_END,
+ }
+ }
+
+ /// Change the Block Loop offset value.
+ ///
+ /// This method isn't that useful because you can't evaluate the difference
+ /// between two pointers in a const context as the addresses aren't assigned
+ /// until long after the const evaluator has run.
+ ///
+ /// If you think you need this method, you might want to set a unique random
+ /// value here and swap it for the real offset as a post-processing step.
+ pub const fn with_offset(self, offset: *const u32) -> Block {
+ Block { offset, ..self }
+ }
+}
+
+impl Block<0> {
+ /// Construct an empty block.
+ pub const fn empty() -> Block<0> {
+ Block::new([])
+ }
+
+ /// Make the block one word larger
+ pub const fn extend(self, word: u32) -> Block<1> {
+ Block::new([word])
+ }
+}
+
+impl Block<1> {
+ /// Make the block one word larger
+ pub const fn extend(self, word: u32) -> Block<2> {
+ Block::new([self.items[0], word])
+ }
+}
+
+impl Block<2> {
+ /// Make the block one word larger
+ pub const fn extend(self, word: u32) -> Block<3> {
+ Block::new([self.items[0], self.items[1], word])
+ }
+}
+
+impl ImageDef {
+ /// Construct a new IMAGE_DEF Block, for an EXE with the given security and
+ /// architecture.
+ pub const fn arch_exe(security: Security, architecture: Architecture) -> Self {
+ Self::new([item_image_type_exe(security, architecture)])
+ }
+
+ /// Construct a new IMAGE_DEF Block, for an EXE with the given security.
+ ///
+ /// The target architecture is taken from the current build target (i.e. Arm
+ /// or RISC-V).
+ pub const fn exe(security: Security) -> Self {
+ if cfg!(all(target_arch = "riscv32", target_os = "none")) {
+ Self::arch_exe(security, Architecture::Riscv)
+ } else {
+ Self::arch_exe(security, Architecture::Arm)
+ }
+ }
+
+ /// Construct a new IMAGE_DEF Block, for a Non-Secure EXE.
+ ///
+ /// The target architecture is taken from the current build target (i.e. Arm
+ /// or RISC-V).
+ pub const fn non_secure_exe() -> Self {
+ Self::exe(Security::NonSecure)
+ }
+
+ /// Construct a new IMAGE_DEF Block, for a Secure EXE.
+ ///
+ /// The target architecture is taken from the current build target (i.e. Arm
+ /// or RISC-V).
+ pub const fn secure_exe() -> Self {
+ Self::exe(Security::Secure)
+ }
+}
+
+/// We make our partition table this fixed size.
+pub const PARTITION_TABLE_MAX_ITEMS: usize = 128;
+
+/// Describes a unpartitioned space
+#[derive(Debug, Clone, PartialEq, Eq, Default)]
+pub struct UnpartitionedSpace {
+ permissions_and_location: u32,
+ permissions_and_flags: u32,
+}
+
+impl UnpartitionedSpace {
+ /// Create a new unpartitioned space.
+ ///
+ /// It defaults to no permissions.
+ pub const fn new() -> Self {
+ Self {
+ permissions_and_location: 0,
+ permissions_and_flags: 0,
+ }
+ }
+
+ /// Create a new unpartition space from run-time values.
+ ///
+ /// Get these from the ROM function `get_partition_table_info` with an argument of `PT_INFO`.
+ pub const fn from_raw(permissions_and_location: u32, permissions_and_flags: u32) -> Self {
+ Self {
+ permissions_and_location,
+ permissions_and_flags,
+ }
+ }
+
+ /// Add a permission
+ pub const fn with_permission(self, permission: Permission) -> Self {
+ Self {
+ permissions_and_flags: self.permissions_and_flags | permission as u32,
+ permissions_and_location: self.permissions_and_location | permission as u32,
+ }
+ }
+
+ /// Set a flag
+ pub const fn with_flag(self, flag: UnpartitionedFlag) -> Self {
+ Self {
+ permissions_and_flags: self.permissions_and_flags | flag as u32,
+ ..self
+ }
+ }
+
+ /// Get the partition start and end
+ ///
+ /// The offsets are in 4 KiB sectors, inclusive.
+ pub fn get_first_last_sectors(&self) -> (u16, u16) {
+ (
+ (self.permissions_and_location & 0x0000_1FFF) as u16,
+ ((self.permissions_and_location >> 13) & 0x0000_1FFF) as u16,
+ )
+ }
+
+ /// Get the partition start and end
+ ///
+ /// The offsets are in bytes, inclusive.
+ pub fn get_first_last_bytes(&self) -> (u32, u32) {
+ let (first, last) = self.get_first_last_sectors();
+ (u32::from(first) * 4096, (u32::from(last) * 4096) + 4095)
+ }
+
+ /// Check if it has a permission
+ pub fn has_permission(&self, permission: Permission) -> bool {
+ let mask = permission as u32;
+ (self.permissions_and_flags & mask) != 0
+ }
+
+ /// Check if the partition has a flag set
+ pub fn has_flag(&self, flag: UnpartitionedFlag) -> bool {
+ let mask = flag as u32;
+ (self.permissions_and_flags & mask) != 0
+ }
+}
+
+impl core::fmt::Display for UnpartitionedSpace {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ let (first, last) = self.get_first_last_bytes();
+ write!(
+ f,
+ "{:#010x}..{:#010x} S:{}{} NS:{}{} B:{}{}",
+ first,
+ last,
+ if self.has_permission(Permission::SecureRead) {
+ 'R'
+ } else {
+ '_'
+ },
+ if self.has_permission(Permission::SecureWrite) {
+ 'W'
+ } else {
+ '_'
+ },
+ if self.has_permission(Permission::NonSecureRead) {
+ 'R'
+ } else {
+ '_'
+ },
+ if self.has_permission(Permission::NonSecureWrite) {
+ 'W'
+ } else {
+ '_'
+ },
+ if self.has_permission(Permission::BootRead) {
+ 'R'
+ } else {
+ '_'
+ },
+ if self.has_permission(Permission::BootWrite) {
+ 'W'
+ } else {
+ '_'
+ }
+ )
+ }
+}
+
+/// Describes a Partition
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Partition {
+ permissions_and_location: u32,
+ permissions_and_flags: u32,
+ id: Option,
+ extra_families: [u32; 4],
+ extra_families_len: usize,
+ name: [u8; 128],
+}
+
+impl Partition {
+ const FLAGS_HAS_ID: u32 = 0b1;
+ const FLAGS_LINK_TYPE_A_PARTITION: u32 = 0b01 << 1;
+ const FLAGS_LINK_TYPE_OWNER: u32 = 0b10 << 1;
+ const FLAGS_LINK_MASK: u32 = 0b111111 << 1;
+ const FLAGS_HAS_NAME: u32 = 0b1 << 12;
+ const FLAGS_HAS_EXTRA_FAMILIES_SHIFT: u8 = 7;
+ const FLAGS_HAS_EXTRA_FAMILIES_MASK: u32 = 0b11 << Self::FLAGS_HAS_EXTRA_FAMILIES_SHIFT;
+
+ /// Create a new partition, with the given start and end sectors.
+ ///
+ /// It defaults to no permissions.
+ pub const fn new(first_sector: u16, last_sector: u16) -> Self {
+ // 0x2000 sectors of 4 KiB is 32 MiB, which is the total XIP area
+ core::assert!(first_sector < 0x2000);
+ core::assert!(last_sector < 0x2000);
+ core::assert!(first_sector <= last_sector);
+ Self {
+ permissions_and_location: (last_sector as u32) << 13 | first_sector as u32,
+ permissions_and_flags: 0,
+ id: None,
+ extra_families: [0; 4],
+ extra_families_len: 0,
+ name: [0; 128],
+ }
+ }
+
+ /// Create a new partition from run-time values.
+ ///
+ /// Get these from the ROM function `get_partition_table_info` with an argument of `PARTITION_LOCATION_AND_FLAGS`.
+ pub const fn from_raw(permissions_and_location: u32, permissions_and_flags: u32) -> Self {
+ Self {
+ permissions_and_location,
+ permissions_and_flags,
+ id: None,
+ extra_families: [0; 4],
+ extra_families_len: 0,
+ name: [0; 128],
+ }
+ }
+
+ /// Add a permission
+ pub const fn with_permission(self, permission: Permission) -> Self {
+ Self {
+ permissions_and_location: self.permissions_and_location | permission as u32,
+ permissions_and_flags: self.permissions_and_flags | permission as u32,
+ ..self
+ }
+ }
+
+ /// Set the name of the partition
+ pub const fn with_name(self, name: &str) -> Self {
+ let mut new_name = [0u8; 128];
+ let name = name.as_bytes();
+ let mut idx = 0;
+ new_name[0] = name.len() as u8;
+ while idx < name.len() {
+ new_name[idx + 1] = name[idx];
+ idx += 1;
+ }
+ Self {
+ name: new_name,
+ permissions_and_flags: self.permissions_and_flags | Self::FLAGS_HAS_NAME,
+ ..self
+ }
+ }
+
+ /// Set the extra families for the partition.
+ ///
+ /// You can supply up to four.
+ pub const fn with_extra_families(self, extra_families: &[u32]) -> Self {
+ core::assert!(extra_families.len() <= 4);
+ let mut new_extra_families = [0u32; 4];
+ let mut idx = 0;
+ while idx < extra_families.len() {
+ new_extra_families[idx] = extra_families[idx];
+ idx += 1;
+ }
+ Self {
+ extra_families: new_extra_families,
+ extra_families_len: extra_families.len(),
+ permissions_and_flags: (self.permissions_and_flags & !Self::FLAGS_HAS_EXTRA_FAMILIES_MASK)
+ | (extra_families.len() as u32) << Self::FLAGS_HAS_EXTRA_FAMILIES_SHIFT,
+ ..self
+ }
+ }
+
+ /// Set the ID
+ pub const fn with_id(self, id: u64) -> Self {
+ Self {
+ id: Some(id),
+ permissions_and_flags: self.permissions_and_flags | Self::FLAGS_HAS_ID,
+ ..self
+ }
+ }
+
+ /// Add a link
+ pub const fn with_link(self, link: Link) -> Self {
+ let mut new_flags = self.permissions_and_flags & !Self::FLAGS_LINK_MASK;
+ match link {
+ Link::Nothing => {}
+ Link::ToA { partition_idx } => {
+ core::assert!(partition_idx < 16);
+ new_flags |= Self::FLAGS_LINK_TYPE_A_PARTITION;
+ new_flags |= (partition_idx as u32) << 3;
+ }
+ Link::ToOwner { partition_idx } => {
+ core::assert!(partition_idx < 16);
+ new_flags |= Self::FLAGS_LINK_TYPE_OWNER;
+ new_flags |= (partition_idx as u32) << 3;
+ }
+ }
+ Self {
+ permissions_and_flags: new_flags,
+ ..self
+ }
+ }
+
+ /// Set a flag
+ pub const fn with_flag(self, flag: PartitionFlag) -> Self {
+ Self {
+ permissions_and_flags: self.permissions_and_flags | flag as u32,
+ ..self
+ }
+ }
+
+ /// Get the partition start and end
+ ///
+ /// The offsets are in 4 KiB sectors, inclusive.
+ pub fn get_first_last_sectors(&self) -> (u16, u16) {
+ (
+ (self.permissions_and_location & 0x0000_1FFF) as u16,
+ ((self.permissions_and_location >> 13) & 0x0000_1FFF) as u16,
+ )
+ }
+
+ /// Get the partition start and end
+ ///
+ /// The offsets are in bytes, inclusive.
+ pub fn get_first_last_bytes(&self) -> (u32, u32) {
+ let (first, last) = self.get_first_last_sectors();
+ (u32::from(first) * 4096, (u32::from(last) * 4096) + 4095)
+ }
+
+ /// Check if it has a permission
+ pub fn has_permission(&self, permission: Permission) -> bool {
+ let mask = permission as u32;
+ (self.permissions_and_flags & mask) != 0
+ }
+
+ /// Get which extra families are allowed in this partition
+ pub fn get_extra_families(&self) -> &[u32] {
+ &self.extra_families[0..self.extra_families_len]
+ }
+
+ /// Get the name of the partition
+ ///
+ /// Returns `None` if there's no name, or the name is not valid UTF-8.
+ pub fn get_name(&self) -> Option<&str> {
+ let len = self.name[0] as usize;
+ if len == 0 {
+ None
+ } else {
+ core::str::from_utf8(&self.name[1..=len]).ok()
+ }
+ }
+
+ /// Get the ID
+ pub fn get_id(&self) -> Option {
+ self.id
+ }
+
+ /// Check if this partition is linked
+ pub fn get_link(&self) -> Link {
+ if (self.permissions_and_flags & Self::FLAGS_LINK_TYPE_A_PARTITION) != 0 {
+ let partition_idx = ((self.permissions_and_flags >> 3) & 0x0F) as u8;
+ Link::ToA { partition_idx }
+ } else if (self.permissions_and_flags & Self::FLAGS_LINK_TYPE_OWNER) != 0 {
+ let partition_idx = ((self.permissions_and_flags >> 3) & 0x0F) as u8;
+ Link::ToOwner { partition_idx }
+ } else {
+ Link::Nothing
+ }
+ }
+
+ /// Check if the partition has a flag set
+ pub fn has_flag(&self, flag: PartitionFlag) -> bool {
+ let mask = flag as u32;
+ (self.permissions_and_flags & mask) != 0
+ }
+}
+
+impl core::fmt::Display for Partition {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ let (first, last) = self.get_first_last_bytes();
+ write!(
+ f,
+ "{:#010x}..{:#010x} S:{}{} NS:{}{} B:{}{}",
+ first,
+ last,
+ if self.has_permission(Permission::SecureRead) {
+ 'R'
+ } else {
+ '_'
+ },
+ if self.has_permission(Permission::SecureWrite) {
+ 'W'
+ } else {
+ '_'
+ },
+ if self.has_permission(Permission::NonSecureRead) {
+ 'R'
+ } else {
+ '_'
+ },
+ if self.has_permission(Permission::NonSecureWrite) {
+ 'W'
+ } else {
+ '_'
+ },
+ if self.has_permission(Permission::BootRead) {
+ 'R'
+ } else {
+ '_'
+ },
+ if self.has_permission(Permission::BootWrite) {
+ 'W'
+ } else {
+ '_'
+ }
+ )
+ }
+}
+
+/// Describes a partition table.
+///
+/// Don't store this as a static - make sure you convert it to a block.
+#[derive(Clone)]
+pub struct PartitionTableBlock {
+ /// This must look like a block, including the 1 word header and the 3 word footer.
+ contents: [u32; PARTITION_TABLE_MAX_ITEMS],
+ /// This value doesn't include the 1 word header or the 3 word footer
+ num_items: usize,
+}
+
+impl PartitionTableBlock {
+ /// Create an empty Block, big enough for a partition table.
+ ///
+ /// At a minimum you need to call [`Self::add_partition_item`].
+ pub const fn new() -> PartitionTableBlock {
+ let mut contents = [0; PARTITION_TABLE_MAX_ITEMS];
+ contents[0] = BLOCK_MARKER_START;
+ contents[1] = item_last(0);
+ contents[2] = 0;
+ contents[3] = BLOCK_MARKER_END;
+ PartitionTableBlock { contents, num_items: 0 }
+ }
+
+ /// Add a partition to the partition table
+ pub const fn add_partition_item(self, unpartitioned: UnpartitionedSpace, partitions: &[Partition]) -> Self {
+ let mut new_table = PartitionTableBlock::new();
+ let mut idx = 0;
+ // copy over old table, with the header but not the footer
+ while idx < self.num_items + 1 {
+ new_table.contents[idx] = self.contents[idx];
+ idx += 1;
+ }
+
+ // 1. add item header space (we fill this in later)
+ let header_idx = idx;
+ new_table.contents[idx] = 0;
+ idx += 1;
+
+ // 2. unpartitioned space flags
+ //
+ // (the location of unpartition space is not recorded here - it is
+ // inferred because the unpartitioned space is where the partitions are
+ // not)
+ new_table.contents[idx] = unpartitioned.permissions_and_flags;
+ idx += 1;
+
+ // 3. partition info
+
+ let mut partition_no = 0;
+ while partition_no < partitions.len() {
+ // a. permissions_and_location (4K units)
+ new_table.contents[idx] = partitions[partition_no].permissions_and_location;
+ idx += 1;
+
+ // b. permissions_and_flags
+ new_table.contents[idx] = partitions[partition_no].permissions_and_flags;
+ idx += 1;
+
+ // c. ID
+ if let Some(id) = partitions[partition_no].id {
+ new_table.contents[idx] = id as u32;
+ new_table.contents[idx + 1] = (id >> 32) as u32;
+ idx += 2;
+ }
+
+ // d. Extra Families
+ let mut extra_families_idx = 0;
+ while extra_families_idx < partitions[partition_no].extra_families_len {
+ new_table.contents[idx] = partitions[partition_no].extra_families[extra_families_idx];
+ idx += 1;
+ extra_families_idx += 1;
+ }
+
+ // e. Name
+ let mut name_idx = 0;
+ while name_idx < partitions[partition_no].name[0] as usize {
+ let name_chunk = [
+ partitions[partition_no].name[name_idx],
+ partitions[partition_no].name[name_idx + 1],
+ partitions[partition_no].name[name_idx + 2],
+ partitions[partition_no].name[name_idx + 3],
+ ];
+ new_table.contents[idx] = u32::from_le_bytes(name_chunk);
+ name_idx += 4;
+ idx += 1;
+ }
+
+ partition_no += 1;
+ }
+
+ let len = idx - header_idx;
+ new_table.contents[header_idx] = item_generic_2bs(partitions.len() as u8, len as u16, ITEM_2BS_PARTITION_TABLE);
+
+ // 7. New Footer
+ new_table.contents[idx] = item_last(idx as u16 - 1);
+ new_table.contents[idx + 1] = 0;
+ new_table.contents[idx + 2] = BLOCK_MARKER_END;
+
+ // ignore the header
+ new_table.num_items = idx - 1;
+ new_table
+ }
+
+ /// Add a version number to the partition table
+ pub const fn with_version(self, major: u16, minor: u16) -> Self {
+ let mut new_table = PartitionTableBlock::new();
+ let mut idx = 0;
+ // copy over old table, with the header but not the footer
+ while idx < self.num_items + 1 {
+ new_table.contents[idx] = self.contents[idx];
+ idx += 1;
+ }
+
+ // 1. add item
+ new_table.contents[idx] = item_generic_2bs(0, 2, ITEM_1BS_VERSION);
+ idx += 1;
+ new_table.contents[idx] = (major as u32) << 16 | minor as u32;
+ idx += 1;
+
+ // 2. New Footer
+ new_table.contents[idx] = item_last(idx as u16 - 1);
+ new_table.contents[idx + 1] = 0;
+ new_table.contents[idx + 2] = BLOCK_MARKER_END;
+
+ // ignore the header
+ new_table.num_items = idx - 1;
+ new_table
+ }
+
+ /// Add a a SHA256 hash of the Block
+ ///
+ /// Adds a `HASH_DEF` covering all the previous items in the Block, and a
+ /// `HASH_VALUE` with a SHA-256 hash of them.
+ pub const fn with_sha256(self) -> Self {
+ let mut new_table = PartitionTableBlock::new();
+ let mut idx = 0;
+ // copy over old table, with the header but not the footer
+ while idx < self.num_items + 1 {
+ new_table.contents[idx] = self.contents[idx];
+ idx += 1;
+ }
+
+ // 1. HASH_DEF says what is hashed
+ new_table.contents[idx] = item_generic_2bs(1, 2, ITEM_2BS_HASH_DEF);
+ idx += 1;
+ // we're hashing all the previous contents - including this line.
+ new_table.contents[idx] = (idx + 1) as u32;
+ idx += 1;
+
+ // calculate hash over prior contents
+ let input = unsafe { core::slice::from_raw_parts(new_table.contents.as_ptr() as *const u8, idx * 4) };
+ let hash: [u8; 32] = sha2_const_stable::Sha256::new().update(input).finalize();
+
+ // 2. HASH_VALUE contains the hash
+ new_table.contents[idx] = item_generic_2bs(0, 9, ITEM_1BS_HASH_VALUE);
+ idx += 1;
+
+ let mut hash_idx = 0;
+ while hash_idx < hash.len() {
+ new_table.contents[idx] = u32::from_le_bytes([
+ hash[hash_idx],
+ hash[hash_idx + 1],
+ hash[hash_idx + 2],
+ hash[hash_idx + 3],
+ ]);
+ idx += 1;
+ hash_idx += 4;
+ }
+
+ // 3. New Footer
+ new_table.contents[idx] = item_last(idx as u16 - 1);
+ new_table.contents[idx + 1] = 0;
+ new_table.contents[idx + 2] = BLOCK_MARKER_END;
+
+ // ignore the header
+ new_table.num_items = idx - 1;
+ new_table
+ }
+}
+
+impl Default for PartitionTableBlock {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+/// Flags that a Partition can have
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+#[repr(u32)]
+#[allow(missing_docs)]
+pub enum PartitionFlag {
+ NotBootableArm = 1 << 9,
+ NotBootableRiscv = 1 << 10,
+ Uf2DownloadAbNonBootableOwnerAffinity = 1 << 11,
+ Uf2DownloadNoReboot = 1 << 13,
+ AcceptsDefaultFamilyRp2040 = 1 << 14,
+ AcceptsDefaultFamilyData = 1 << 16,
+ AcceptsDefaultFamilyRp2350ArmS = 1 << 17,
+ AcceptsDefaultFamilyRp2350Riscv = 1 << 18,
+ AcceptsDefaultFamilyRp2350ArmNs = 1 << 19,
+}
+
+/// Flags that a Partition can have
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+#[repr(u32)]
+#[allow(missing_docs)]
+pub enum UnpartitionedFlag {
+ Uf2DownloadNoReboot = 1 << 13,
+ AcceptsDefaultFamilyRp2040 = 1 << 14,
+ AcceptsDefaultFamilyAbsolute = 1 << 15,
+ AcceptsDefaultFamilyData = 1 << 16,
+ AcceptsDefaultFamilyRp2350ArmS = 1 << 17,
+ AcceptsDefaultFamilyRp2350Riscv = 1 << 18,
+ AcceptsDefaultFamilyRp2350ArmNs = 1 << 19,
+}
+
+/// Kinds of linked partition
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum Link {
+ /// Not linked to anything
+ Nothing,
+ /// This is a B partition - link to our A partition.
+ ToA {
+ /// The index of our matching A partition.
+ partition_idx: u8,
+ },
+ /// Link to the partition that owns this one.
+ ToOwner {
+ /// The idx of our owner
+ partition_idx: u8,
+ },
+}
+
+/// Permissions that a Partition can have
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+#[repr(u32)]
+pub enum Permission {
+ /// Can be read in Secure Mode
+ ///
+ /// Corresponds to `PERMISSION_S_R_BITS` in the Pico SDK
+ SecureRead = 1 << 26,
+ /// Can be written in Secure Mode
+ ///
+ /// Corresponds to `PERMISSION_S_W_BITS` in the Pico SDK
+ SecureWrite = 1 << 27,
+ /// Can be read in Non-Secure Mode
+ ///
+ /// Corresponds to `PERMISSION_NS_R_BITS` in the Pico SDK
+ NonSecureRead = 1 << 28,
+ /// Can be written in Non-Secure Mode
+ ///
+ /// Corresponds to `PERMISSION_NS_W_BITS` in the Pico SDK
+ NonSecureWrite = 1 << 29,
+ /// Can be read in Non-Secure Bootloader mode
+ ///
+ /// Corresponds to `PERMISSION_NSBOOT_R_BITS` in the Pico SDK
+ BootRead = 1 << 30,
+ /// Can be written in Non-Secure Bootloader mode
+ ///
+ /// Corresponds to `PERMISSION_NSBOOT_W_BITS` in the Pico SDK
+ BootWrite = 1 << 31,
+}
+
+impl Permission {
+ /// Is this permission bit set this in this bitmask?
+ pub const fn is_in(self, mask: u32) -> bool {
+ (mask & (self as u32)) != 0
+ }
+}
+
+/// The supported RP2350 CPU architectures
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum Architecture {
+ /// Core is in Arm Cortex-M33 mode
+ Arm,
+ /// Core is in RISC-V / Hazard3 mode
+ Riscv,
+}
+
+/// The kinds of Secure Boot we support
+#[derive(Debug, Copy, Clone)]
+pub enum Security {
+ /// Security mode not given
+ Unspecified,
+ /// Start in Non-Secure mode
+ NonSecure,
+ /// Start in Secure mode
+ Secure,
+}
+
+/// Make an item containing a tag, 1 byte length and two extra bytes.
+///
+/// The `command` arg should contain `1BS`
+pub const fn item_generic_1bs(value: u16, length: u8, command: u8) -> u32 {
+ ((value as u32) << 16) | ((length as u32) << 8) | (command as u32)
+}
+
+/// Make an item containing a tag, 2 byte length and one extra byte.
+///
+/// The `command` arg should contain `2BS`
+pub const fn item_generic_2bs(value: u8, length: u16, command: u8) -> u32 {
+ ((value as u32) << 24) | ((length as u32) << 8) | (command as u32)
+}
+
+/// Create Image Type item, of type IGNORED.
+pub const fn item_ignored() -> u32 {
+ item_generic_2bs(0, 1, ITEM_2BS_IGNORED)
+}
+
+/// Create Image Type item, of type INVALID.
+pub const fn item_image_type_invalid() -> u32 {
+ let value = IMAGE_TYPE_INVALID;
+ item_generic_1bs(value, 1, ITEM_1BS_IMAGE_TYPE)
+}
+
+/// Create Image Type item, of type DATA.
+pub const fn item_image_type_data() -> u32 {
+ let value = IMAGE_TYPE_DATA;
+ item_generic_1bs(value, 1, ITEM_1BS_IMAGE_TYPE)
+}
+
+/// Create Image Type item, of type EXE.
+pub const fn item_image_type_exe(security: Security, arch: Architecture) -> u32 {
+ let mut value = IMAGE_TYPE_EXE | IMAGE_TYPE_EXE_CHIP_RP2350;
+
+ match arch {
+ Architecture::Arm => {
+ value |= IMAGE_TYPE_EXE_CPU_ARM;
+ }
+ Architecture::Riscv => {
+ value |= IMAGE_TYPE_EXE_CPU_RISCV;
+ }
+ }
+
+ match security {
+ Security::Unspecified => value |= IMAGE_TYPE_EXE_TYPE_SECURITY_UNSPECIFIED,
+ Security::NonSecure => value |= IMAGE_TYPE_EXE_TYPE_SECURITY_NS,
+ Security::Secure => value |= IMAGE_TYPE_EXE_TYPE_SECURITY_S,
+ }
+
+ item_generic_1bs(value, 1, ITEM_1BS_IMAGE_TYPE)
+}
+
+/// Create a Block Last item.
+pub const fn item_last(length: u16) -> u32 {
+ item_generic_2bs(0, length, ITEM_2BS_LAST)
+}
+
+/// Create a Vector Table item.
+///
+/// This is only allowed on Arm systems.
+pub const fn item_vector_table(table_ptr: u32) -> [u32; 2] {
+ [item_generic_1bs(0, 2, ITEM_1BS_VECTOR_TABLE), table_ptr]
+}
+
+/// Create an Entry Point item.
+pub const fn item_entry_point(entry_point: u32, initial_sp: u32) -> [u32; 3] {
+ [item_generic_1bs(0, 3, ITEM_1BS_ENTRY_POINT), entry_point, initial_sp]
+}
+
+/// Create an Rolling Window item.
+///
+/// The delta is the number of bytes into the image that 0x10000000 should
+/// be mapped.
+pub const fn item_rolling_window(delta: u32) -> [u32; 2] {
+ [item_generic_1bs(0, 3, ITEM_1BS_ROLLING_WINDOW_DELTA), delta]
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ /// I used this JSON, with `picotool partition create`:
+ ///
+ /// ```json
+ /// {
+ /// "version": [1, 0],
+ /// "unpartitioned": {
+ /// "families": ["absolute"],
+ /// "permissions": {
+ /// "secure": "rw",
+ /// "nonsecure": "rw",
+ /// "bootloader": "rw"
+ /// }
+ /// },
+ /// "partitions": [
+ /// {
+ /// "name": "A",
+ /// "id": 0,
+ /// "size": "2044K",
+ /// "families": ["rp2350-arm-s", "rp2350-riscv"],
+ /// "permissions": {
+ /// "secure": "rw",
+ /// "nonsecure": "rw",
+ /// "bootloader": "rw"
+ /// }
+ /// },
+ /// {
+ /// "name": "B",
+ /// "id": 1,
+ /// "size": "2044K",
+ /// "families": ["rp2350-arm-s", "rp2350-riscv"],
+ /// "permissions": {
+ /// "secure": "rw",
+ /// "nonsecure": "rw",
+ /// "bootloader": "rw"
+ /// },
+ /// "link": ["a", 0]
+ /// }
+ /// ]
+ /// }
+ /// ```
+ #[test]
+ fn make_hashed_partition_table() {
+ let table = PartitionTableBlock::new()
+ .add_partition_item(
+ UnpartitionedSpace::new()
+ .with_permission(Permission::SecureRead)
+ .with_permission(Permission::SecureWrite)
+ .with_permission(Permission::NonSecureRead)
+ .with_permission(Permission::NonSecureWrite)
+ .with_permission(Permission::BootRead)
+ .with_permission(Permission::BootWrite)
+ .with_flag(UnpartitionedFlag::AcceptsDefaultFamilyAbsolute),
+ &[
+ Partition::new(2, 512)
+ .with_id(0)
+ .with_flag(PartitionFlag::AcceptsDefaultFamilyRp2350ArmS)
+ .with_flag(PartitionFlag::AcceptsDefaultFamilyRp2350Riscv)
+ .with_permission(Permission::SecureRead)
+ .with_permission(Permission::SecureWrite)
+ .with_permission(Permission::NonSecureRead)
+ .with_permission(Permission::NonSecureWrite)
+ .with_permission(Permission::BootRead)
+ .with_permission(Permission::BootWrite)
+ .with_name("A"),
+ Partition::new(513, 1023)
+ .with_id(1)
+ .with_flag(PartitionFlag::AcceptsDefaultFamilyRp2350ArmS)
+ .with_flag(PartitionFlag::AcceptsDefaultFamilyRp2350Riscv)
+ .with_link(Link::ToA { partition_idx: 0 })
+ .with_permission(Permission::SecureRead)
+ .with_permission(Permission::SecureWrite)
+ .with_permission(Permission::NonSecureRead)
+ .with_permission(Permission::NonSecureWrite)
+ .with_permission(Permission::BootRead)
+ .with_permission(Permission::BootWrite)
+ .with_name("B"),
+ ],
+ )
+ .with_version(1, 0)
+ .with_sha256();
+ let expected = &[
+ 0xffffded3, // start
+ 0x02000c0a, // Item = PARTITION_TABLE
+ 0xfc008000, // Unpartitioned Space - permissions_and_flags
+ 0xfc400002, // Partition 0 - permissions_and_location (512 * 4096, 2 * 4096)
+ 0xfc061001, // permissions_and_flags HAS_ID | HAS_NAME | ARM-S | RISC-V
+ 0x00000000, // ID
+ 0x00000000, // ID
+ 0x00004101, // Name ("A")
+ 0xfc7fe201, // Partition 1 - permissions_and_location (1023 * 4096, 513 * 4096)
+ 0xfc061003, // permissions_and_flags LINKA(0) | HAS_ID | HAS_NAME | ARM-S | RISC-V
+ 0x00000001, // ID
+ 0x00000000, // ID
+ 0x00004201, // Name ("B")
+ 0x00000248, // Item = Version
+ 0x00010000, // 0, 1
+ 0x01000247, // HASH_DEF with 2 words, and SHA256 hash
+ 0x00000011, // 17 words hashed
+ 0x0000094b, // HASH_VALUE with 9 words
+ 0x1945cdad, // Hash word 0
+ 0x6b5f9773, // Hash word 1
+ 0xe2bf39bd, // Hash word 2
+ 0xb243e599, // Hash word 3
+ 0xab2f0e9a, // Hash word 4
+ 0x4d5d6d0b, // Hash word 5
+ 0xf973050f, // Hash word 6
+ 0x5ab6dadb, // Hash word 7
+ 0x000019ff, // Last Item
+ 0x00000000, // Block Loop Next Offset
+ 0xab123579, // End
+ ];
+ core::assert_eq!(
+ &table.contents[..29],
+ expected,
+ "{:#010x?}\n != \n{:#010x?}",
+ &table.contents[0..29],
+ expected,
+ );
+ }
+}
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index d0c6c19bd..9f387b70f 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -1,12 +1,17 @@
//! Clock configuration for the RP2040
+
+#[cfg(feature = "rp2040")]
use core::arch::asm;
use core::marker::PhantomData;
-use core::sync::atomic::{AtomicU16, AtomicU32, Ordering};
+#[cfg(feature = "rp2040")]
+use core::sync::atomic::AtomicU16;
+use core::sync::atomic::{AtomicU32, Ordering};
use embassy_hal_internal::{into_ref, PeripheralRef};
use pac::clocks::vals::*;
use crate::gpio::{AnyPin, SealedPin};
+#[cfg(feature = "rp2040")]
use crate::pac::common::{Reg, RW};
use crate::{pac, reset, Peripheral};
@@ -26,6 +31,7 @@ struct Clocks {
// gpin1: AtomicU32,
rosc: AtomicU32,
peri: AtomicU32,
+ #[cfg(feature = "rp2040")]
rtc: AtomicU16,
}
@@ -41,6 +47,7 @@ static CLOCKS: Clocks = Clocks {
// gpin1: AtomicU32::new(0),
rosc: AtomicU32::new(0),
peri: AtomicU32::new(0),
+ #[cfg(feature = "rp2040")]
rtc: AtomicU16::new(0),
};
@@ -81,6 +88,7 @@ pub struct ClockConfig {
/// ADC clock configuration.
pub adc_clk: Option,
/// RTC clock configuration.
+ #[cfg(feature = "rp2040")]
pub rtc_clk: Option,
// gpin0: Option<(u32, Gpin<'static, AnyPin>)>,
// gpin1: Option<(u32, Gpin<'static, AnyPin>)>,
@@ -135,6 +143,7 @@ impl ClockConfig {
phase: 0,
}),
// CLK RTC = PLL USB (48MHz) / 1024 = 46875Hz
+ #[cfg(feature = "rp2040")]
rtc_clk: Some(RtcClkConfig {
src: RtcClkSrc::PllUsb,
div_int: 1024,
@@ -174,6 +183,7 @@ impl ClockConfig {
phase: 0,
}),
// CLK RTC = ROSC (140MHz) / 2986.667969 ≅ 46875Hz
+ #[cfg(feature = "rp2040")]
rtc_clk: Some(RtcClkConfig {
src: RtcClkSrc::Rosc,
div_int: 2986,
@@ -295,9 +305,17 @@ pub struct SysClkConfig {
/// SYS clock source.
pub src: SysClkSrc,
/// SYS clock divider.
+ #[cfg(feature = "rp2040")]
pub div_int: u32,
/// SYS clock fraction.
+ #[cfg(feature = "rp2040")]
pub div_frac: u8,
+ /// SYS clock divider.
+ #[cfg(feature = "rp235x")]
+ pub div_int: u16,
+ /// SYS clock fraction.
+ #[cfg(feature = "rp235x")]
+ pub div_frac: u16,
}
/// USB clock source.
@@ -358,6 +376,7 @@ pub struct AdcClkConfig {
#[repr(u8)]
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[cfg(feature = "rp2040")]
pub enum RtcClkSrc {
/// PLL USB.
PllUsb = ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB as _,
@@ -372,6 +391,7 @@ pub enum RtcClkSrc {
}
/// RTC clock config.
+#[cfg(feature = "rp2040")]
pub struct RtcClkConfig {
/// RTC clock source.
pub src: RtcClkSrc,
@@ -396,10 +416,9 @@ pub(crate) unsafe fn init(config: ClockConfig) {
peris.set_pads_qspi(false);
peris.set_pll_sys(false);
peris.set_pll_usb(false);
- // TODO investigate if usb should be unreset here
peris.set_usbctrl(false);
peris.set_syscfg(false);
- peris.set_rtc(false);
+ //peris.set_rtc(false);
reset::reset(peris);
// Disable resus that may be enabled from previous software
@@ -409,9 +428,15 @@ pub(crate) unsafe fn init(config: ClockConfig) {
// Before we touch PLLs, switch sys and ref cleanly away from their aux sources.
c.clk_sys_ctrl().modify(|w| w.set_src(ClkSysCtrlSrc::CLK_REF));
+ #[cfg(feature = "rp2040")]
while c.clk_sys_selected().read() != 1 {}
+ #[cfg(feature = "rp235x")]
+ while c.clk_sys_selected().read() != pac::clocks::regs::ClkSysSelected(1) {}
c.clk_ref_ctrl().modify(|w| w.set_src(ClkRefCtrlSrc::ROSC_CLKSRC_PH));
+ #[cfg(feature = "rp2040")]
while c.clk_ref_selected().read() != 1 {}
+ #[cfg(feature = "rp235x")]
+ while c.clk_ref_selected().read() != pac::clocks::regs::ClkRefSelected(1) {}
// Reset the PLLs
let mut peris = reset::Peripherals(0);
@@ -479,11 +504,16 @@ pub(crate) unsafe fn init(config: ClockConfig) {
w.set_src(ref_src);
w.set_auxsrc(ref_aux);
});
- while c.clk_ref_selected().read() != 1 << ref_src as u32 {}
+ #[cfg(feature = "rp2040")]
+ while c.clk_ref_selected().read() != (1 << ref_src as u32) {}
+ #[cfg(feature = "rp235x")]
+ while c.clk_ref_selected().read() != pac::clocks::regs::ClkRefSelected(1 << ref_src as u32) {}
c.clk_ref_div().write(|w| {
w.set_int(config.ref_clk.div);
});
+ // Configure tick generation on the 2040. On the 2350 the timers are driven from the sysclk.
+ #[cfg(feature = "rp2040")]
pac::WATCHDOG.tick().write(|w| {
w.set_cycles((clk_ref_freq / 1_000_000) as u16);
w.set_enable(true);
@@ -500,7 +530,6 @@ pub(crate) unsafe fn init(config: ClockConfig) {
// SysClkSrc::Gpin0 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN0, gpin0_freq),
// SysClkSrc::Gpin1 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN1, gpin1_freq),
};
- assert!(config.sys_clk.div_int <= 0x1000000);
let div = config.sys_clk.div_int as u64 * 256 + config.sys_clk.div_frac as u64;
(src, aux, ((freq as u64 * 256) / div) as u32)
};
@@ -508,13 +537,21 @@ pub(crate) unsafe fn init(config: ClockConfig) {
CLOCKS.sys.store(clk_sys_freq, Ordering::Relaxed);
if sys_src != ClkSysCtrlSrc::CLK_REF {
c.clk_sys_ctrl().write(|w| w.set_src(ClkSysCtrlSrc::CLK_REF));
- while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF as u32 {}
+ #[cfg(feature = "rp2040")]
+ while c.clk_sys_selected().read() != (1 << ClkSysCtrlSrc::CLK_REF as u32) {}
+ #[cfg(feature = "rp235x")]
+ while c.clk_sys_selected().read() != pac::clocks::regs::ClkSysSelected(1 << ClkSysCtrlSrc::CLK_REF as u32) {}
}
c.clk_sys_ctrl().write(|w| {
w.set_auxsrc(sys_aux);
w.set_src(sys_src);
});
- while c.clk_sys_selected().read() != 1 << sys_src as u32 {}
+
+ #[cfg(feature = "rp2040")]
+ while c.clk_sys_selected().read() != (1 << sys_src as u32) {}
+ #[cfg(feature = "rp235x")]
+ while c.clk_sys_selected().read() != pac::clocks::regs::ClkSysSelected(1 << sys_src as u32) {}
+
c.clk_sys_div().write(|w| {
w.set_int(config.sys_clk.div_int);
w.set_frac(config.sys_clk.div_frac);
@@ -592,6 +629,8 @@ pub(crate) unsafe fn init(config: ClockConfig) {
CLOCKS.adc.store(0, Ordering::Relaxed);
}
+ // rp2040 specific clocks
+ #[cfg(feature = "rp2040")]
if let Some(conf) = config.rtc_clk {
c.clk_rtc_div().write(|w| {
w.set_int(conf.div_int);
@@ -621,6 +660,13 @@ pub(crate) unsafe fn init(config: ClockConfig) {
CLOCKS.rtc.store(0, Ordering::Relaxed);
}
+ // rp235x specific clocks
+ #[cfg(feature = "rp235x")]
+ {
+ // TODO hstx clock
+ peris.set_hstx(false);
+ }
+
// Peripheral clocks should now all be running
reset::unreset_wait(peris);
}
@@ -709,6 +755,7 @@ pub fn clk_adc_freq() -> u32 {
}
/// RTC clock frequency.
+#[cfg(feature = "rp2040")]
pub fn clk_rtc_freq() -> u16 {
CLOCKS.rtc.load(Ordering::Relaxed)
}
@@ -855,8 +902,8 @@ pub enum GpoutSrc {
Usb = ClkGpoutCtrlAuxsrc::CLK_USB as _,
/// ADC.
Adc = ClkGpoutCtrlAuxsrc::CLK_ADC as _,
- /// RTC.
- Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC as _,
+ // RTC.
+ //Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC as _,
/// REF.
Ref = ClkGpoutCtrlAuxsrc::CLK_REF as _,
}
@@ -877,6 +924,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
}
/// Set clock divider.
+ #[cfg(feature = "rp2040")]
pub fn set_div(&self, int: u32, frac: u8) {
let c = pac::CLOCKS;
c.clk_gpout_div(self.gpout.number()).write(|w| {
@@ -885,6 +933,16 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
});
}
+ /// Set clock divider.
+ #[cfg(feature = "rp235x")]
+ pub fn set_div(&self, int: u16, frac: u16) {
+ let c = pac::CLOCKS;
+ c.clk_gpout_div(self.gpout.number()).write(|w| {
+ w.set_int(int);
+ w.set_frac(frac);
+ });
+ }
+
/// Set clock source.
pub fn set_src(&self, src: GpoutSrc) {
let c = pac::CLOCKS;
@@ -924,13 +982,13 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
ClkGpoutCtrlAuxsrc::CLK_SYS => clk_sys_freq(),
ClkGpoutCtrlAuxsrc::CLK_USB => clk_usb_freq(),
ClkGpoutCtrlAuxsrc::CLK_ADC => clk_adc_freq(),
- ClkGpoutCtrlAuxsrc::CLK_RTC => clk_rtc_freq() as _,
+ //ClkGpoutCtrlAuxsrc::CLK_RTC => clk_rtc_freq() as _,
ClkGpoutCtrlAuxsrc::CLK_REF => clk_ref_freq(),
_ => unreachable!(),
};
let div = c.clk_gpout_div(self.gpout.number()).read();
- let int = if div.int() == 0 { 65536 } else { div.int() } as u64;
+ let int = if div.int() == 0 { 0xFFFF } else { div.int() } as u64;
let frac = div.frac() as u64;
((base as u64 * 256) / (int * 256 + frac)) as u32
@@ -987,7 +1045,7 @@ impl rand_core::RngCore for RoscRng {
/// and can only be exited through resets, dormant-wake GPIO interrupts,
/// and RTC interrupts. If RTC is clocked from an internal clock source
/// it will be stopped and not function as a wakeup source.
-#[cfg(target_arch = "arm")]
+#[cfg(all(target_arch = "arm", feature = "rp2040"))]
pub fn dormant_sleep() {
struct Set(Reg, T, F);
@@ -1107,7 +1165,7 @@ pub fn dormant_sleep() {
coma = in (reg) 0x636f6d61,
);
} else {
- pac::ROSC.dormant().write_value(0x636f6d61);
+ pac::ROSC.dormant().write_value(rp_pac::rosc::regs::Dormant(0x636f6d61));
}
}
}
diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs
index 8c04b43a1..df10da0b6 100644
--- a/embassy-rp/src/dma.rs
+++ b/embassy-rp/src/dma.rs
@@ -45,7 +45,7 @@ pub unsafe fn read<'a, C: Channel, W: Word>(
ch: impl Peripheral + 'a,
from: *const W,
to: *mut [W],
- dreq: u8,
+ dreq: vals::TreqSel,
) -> Transfer<'a, C> {
copy_inner(
ch,
@@ -66,7 +66,7 @@ pub unsafe fn write<'a, C: Channel, W: Word>(
ch: impl Peripheral
+ 'a,
from: *const [W],
to: *mut W,
- dreq: u8,
+ dreq: vals::TreqSel,
) -> Transfer<'a, C> {
copy_inner(
ch,
@@ -90,7 +90,7 @@ pub unsafe fn write_repeated<'a, C: Channel, W: Word>(
ch: impl Peripheral
+ 'a,
to: *mut W,
len: usize,
- dreq: u8,
+ dreq: vals::TreqSel,
) -> Transfer<'a, C> {
copy_inner(
ch,
@@ -123,7 +123,7 @@ pub unsafe fn copy<'a, C: Channel, W: Word>(
W::size(),
true,
true,
- vals::TreqSel::PERMANENT.0,
+ vals::TreqSel::PERMANENT,
)
}
@@ -135,7 +135,7 @@ fn copy_inner<'a, C: Channel>(
data_size: DataSize,
incr_read: bool,
incr_write: bool,
- dreq: u8,
+ dreq: vals::TreqSel,
) -> Transfer<'a, C> {
into_ref!(ch);
@@ -143,14 +143,20 @@ fn copy_inner<'a, C: Channel>(
p.read_addr().write_value(from as u32);
p.write_addr().write_value(to as u32);
- p.trans_count().write_value(len as u32);
+ #[cfg(feature = "rp2040")]
+ p.trans_count().write(|w| {
+ *w = len as u32;
+ });
+ #[cfg(feature = "rp235x")]
+ p.trans_count().write(|w| {
+ w.set_mode(0.into());
+ w.set_count(len as u32);
+ });
compiler_fence(Ordering::SeqCst);
p.ctrl_trig().write(|w| {
- // TODO: Add all DREQ options to pac vals::TreqSel, and use
- // `set_treq:sel`
- w.0 = ((dreq as u32) & 0x3f) << 15usize;
+ w.set_treq_sel(dreq);
w.set_data_size(data_size);
w.set_incr_read(incr_read);
w.set_incr_write(incr_write);
@@ -297,3 +303,11 @@ channel!(DMA_CH8, 8);
channel!(DMA_CH9, 9);
channel!(DMA_CH10, 10);
channel!(DMA_CH11, 11);
+#[cfg(feature = "rp235x")]
+channel!(DMA_CH12, 12);
+#[cfg(feature = "rp235x")]
+channel!(DMA_CH13, 13);
+#[cfg(feature = "rp235x")]
+channel!(DMA_CH14, 14);
+#[cfg(feature = "rp235x")]
+channel!(DMA_CH15, 15);
diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs
index 9e4542b2f..cc84bb12d 100644
--- a/embassy-rp/src/flash.rs
+++ b/embassy-rp/src/flash.rs
@@ -302,7 +302,14 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> {
// pac::XIP_CTRL.stream_fifo().as_ptr()) to avoid DMA stalling on
// general XIP access.
const XIP_AUX_BASE: *const u32 = 0x50400000 as *const _;
- let transfer = unsafe { crate::dma::read(self.dma.as_mut().unwrap(), XIP_AUX_BASE, data, 37) };
+ let transfer = unsafe {
+ crate::dma::read(
+ self.dma.as_mut().unwrap(),
+ XIP_AUX_BASE,
+ data,
+ pac::dma::vals::TreqSel::XIP_STREAM,
+ )
+ };
Ok(BackgroundRead {
flash: PhantomData,
@@ -597,6 +604,7 @@ mod ram_helpers {
/// addr must be aligned to 4096
#[inline(never)]
#[link_section = ".data.ram_func"]
+ #[cfg(feature = "rp2040")]
unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) {
/*
Should be equivalent to:
@@ -659,6 +667,11 @@ mod ram_helpers {
);
}
+ #[inline(never)]
+ #[link_section = ".data.ram_func"]
+ #[cfg(feature = "rp235x")]
+ unsafe fn write_flash_inner(_addr: u32, _len: u32, _data: Option<&[u8]>, _ptrs: *const FlashFunctionPointers) {}
+
#[repr(C)]
struct FlashCommand {
cmd_addr: *const u8,
@@ -758,6 +771,7 @@ mod ram_helpers {
/// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
#[inline(never)]
#[link_section = ".data.ram_func"]
+ #[cfg(feature = "rp2040")]
unsafe fn read_flash_inner(cmd: FlashCommand, ptrs: *const FlashFunctionPointers) {
#[cfg(target_arch = "arm")]
core::arch::asm!(
@@ -874,6 +888,11 @@ mod ram_helpers {
clobber_abi("C"),
);
}
+
+ #[inline(never)]
+ #[link_section = ".data.ram_func"]
+ #[cfg(feature = "rp235x")]
+ unsafe fn read_flash_inner(_cmd: FlashCommand, _ptrs: *const FlashFunctionPointers) {}
}
/// Make sure to uphold the contract points with rp2040-flash.
@@ -887,7 +906,7 @@ pub(crate) unsafe fn in_ram(operation: impl FnOnce()) -> Result<(), Error> {
}
// Make sure CORE1 is paused during the entire duration of the RAM function
- crate::multicore::pause_core1();
+ //crate::multicore::pause_core1();
critical_section::with(|_| {
// Wait for all DMA channels in flash to finish before ram operation
@@ -904,7 +923,7 @@ pub(crate) unsafe fn in_ram(operation: impl FnOnce()) -> Result<(), Error> {
});
// Resume CORE1 execution
- crate::multicore::resume_core1();
+ //crate::multicore::resume_core1();
Ok(())
}
diff --git a/embassy-rp/src/float/mod.rs b/embassy-rp/src/float/mod.rs
index 3ad6f1c50..1df8c0e08 100644
--- a/embassy-rp/src/float/mod.rs
+++ b/embassy-rp/src/float/mod.rs
@@ -1,3 +1,4 @@
+#![cfg(feature = "rp2040")]
// Credit: taken from `rp-hal` (also licensed Apache+MIT)
// https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/src/float/mod.rs
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index ea87fd9da..8d6a8f2bd 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -178,6 +178,13 @@ impl<'d> Input<'d> {
pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake<'_> {
self.pin.dormant_wake(cfg)
}
+
+ /// Set the pin's pad isolation
+ #[cfg(feature = "rp235x")]
+ #[inline]
+ pub fn set_pad_isolation(&mut self, isolate: bool) {
+ self.pin.set_pad_isolation(isolate)
+ }
}
/// Interrupt trigger levels.
@@ -413,6 +420,13 @@ impl<'d> Output<'d> {
pub fn toggle(&mut self) {
self.pin.toggle()
}
+
+ /// Set the pin's pad isolation
+ #[cfg(feature = "rp235x")]
+ #[inline]
+ pub fn set_pad_isolation(&mut self, isolate: bool) {
+ self.pin.set_pad_isolation(isolate)
+ }
}
/// GPIO output open-drain.
@@ -539,6 +553,13 @@ impl<'d> OutputOpenDrain<'d> {
pub async fn wait_for_any_edge(&mut self) {
self.pin.wait_for_any_edge().await;
}
+
+ /// Set the pin's pad isolation
+ #[cfg(feature = "rp235x")]
+ #[inline]
+ pub fn set_pad_isolation(&mut self, isolate: bool) {
+ self.pin.set_pad_isolation(isolate)
+ }
}
/// GPIO flexible pin.
@@ -564,7 +585,15 @@ impl<'d> Flex<'d> {
});
pin.gpio().ctrl().write(|w| {
+ #[cfg(feature = "rp2040")]
w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0 as _);
+ #[cfg(feature = "rp235x")]
+ w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIOB_PROC_0 as _);
+ });
+
+ #[cfg(feature = "rp235x")]
+ pin.pad_ctrl().modify(|w| {
+ w.set_iso(false);
});
Self { pin: pin.map_into() }
@@ -760,6 +789,15 @@ impl<'d> Flex<'d> {
cfg,
}
}
+
+ /// Set the pin's pad isolation
+ #[cfg(feature = "rp235x")]
+ #[inline]
+ pub fn set_pad_isolation(&mut self, isolate: bool) {
+ self.pin.pad_ctrl().modify(|w| {
+ w.set_iso(isolate);
+ });
+ }
}
impl<'d> Drop for Flex<'d> {
@@ -956,6 +994,44 @@ impl_pin!(PIN_27, Bank::Bank0, 27);
impl_pin!(PIN_28, Bank::Bank0, 28);
impl_pin!(PIN_29, Bank::Bank0, 29);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_30, Bank::Bank0, 30);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_31, Bank::Bank0, 31);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_32, Bank::Bank0, 32);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_33, Bank::Bank0, 33);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_34, Bank::Bank0, 34);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_35, Bank::Bank0, 35);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_36, Bank::Bank0, 36);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_37, Bank::Bank0, 37);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_38, Bank::Bank0, 38);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_39, Bank::Bank0, 39);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_40, Bank::Bank0, 40);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_41, Bank::Bank0, 41);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_42, Bank::Bank0, 42);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_43, Bank::Bank0, 43);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_44, Bank::Bank0, 44);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_45, Bank::Bank0, 45);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_46, Bank::Bank0, 46);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_47, Bank::Bank0, 47);
+
+// TODO rp235x bank1 as gpio support
#[cfg(feature = "qspi-as-gpio")]
impl_pin!(PIN_QSPI_SCLK, Bank::Qspi, 0);
#[cfg(feature = "qspi-as-gpio")]
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs
index ac2b1bc5a..d95b17ff1 100644
--- a/embassy-rp/src/i2c.rs
+++ b/embassy-rp/src/i2c.rs
@@ -884,3 +884,39 @@ impl_pin!(PIN_26, I2C1, SdaPin);
impl_pin!(PIN_27, I2C1, SclPin);
impl_pin!(PIN_28, I2C0, SdaPin);
impl_pin!(PIN_29, I2C0, SclPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_30, I2C1, SdaPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_31, I2C1, SclPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_32, I2C0, SdaPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_33, I2C0, SclPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_34, I2C1, SdaPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_35, I2C1, SclPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_36, I2C0, SdaPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_37, I2C0, SclPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_38, I2C1, SdaPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_39, I2C1, SclPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_40, I2C0, SdaPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_41, I2C0, SclPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_42, I2C1, SdaPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_43, I2C1, SclPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_44, I2C0, SdaPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_45, I2C0, SclPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_46, I2C1, SdaPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_47, I2C1, SclPin);
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index 471e7f8b1..c5b2498b4 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -15,6 +15,11 @@ mod critical_section_impl;
mod intrinsics;
pub mod adc;
+#[cfg(feature = "rp235x")]
+pub mod binary_info;
+#[cfg(feature = "rp235x")]
+pub mod block;
+#[cfg(feature = "rp2040")]
pub mod bootsel;
pub mod clocks;
pub mod dma;
@@ -41,14 +46,20 @@ pub(crate) mod relocate;
// Reexports
pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
-#[cfg(feature = "unstable-pac")]
+#[cfg(all(feature = "unstable-pac", feature = "rp235x"))]
+pub use rp23_pac as pac;
+#[cfg(all(feature = "unstable-pac", feature = "rp2040"))]
pub use rp_pac as pac;
-#[cfg(not(feature = "unstable-pac"))]
+
+#[cfg(all(not(feature = "unstable-pac"), feature = "rp235x"))]
+pub(crate) use rp23_pac as pac;
+#[cfg(all(not(feature = "unstable-pac"), feature = "rp2040"))]
pub(crate) use rp_pac as pac;
#[cfg(feature = "rt")]
pub use crate::pac::NVIC_PRIO_BITS;
+#[cfg(feature = "rp2040")]
embassy_hal_internal::interrupt_mod!(
TIMER_IRQ_0,
TIMER_IRQ_1,
@@ -84,6 +95,54 @@ embassy_hal_internal::interrupt_mod!(
SWI_IRQ_5,
);
+#[cfg(feature = "rp235x")]
+embassy_hal_internal::interrupt_mod!(
+ TIMER0_IRQ_0,
+ TIMER0_IRQ_1,
+ TIMER0_IRQ_2,
+ TIMER0_IRQ_3,
+ TIMER1_IRQ_0,
+ TIMER1_IRQ_1,
+ TIMER1_IRQ_2,
+ TIMER1_IRQ_3,
+ PWM_IRQ_WRAP_0,
+ PWM_IRQ_WRAP_1,
+ DMA_IRQ_0,
+ DMA_IRQ_1,
+ USBCTRL_IRQ,
+ PIO0_IRQ_0,
+ PIO0_IRQ_1,
+ PIO1_IRQ_0,
+ PIO1_IRQ_1,
+ PIO2_IRQ_0,
+ PIO2_IRQ_1,
+ IO_IRQ_BANK0,
+ IO_IRQ_BANK0_NS,
+ IO_IRQ_QSPI,
+ IO_IRQ_QSPI_NS,
+ SIO_IRQ_FIFO,
+ SIO_IRQ_BELL,
+ SIO_IRQ_FIFO_NS,
+ SIO_IRQ_BELL_NS,
+ CLOCKS_IRQ,
+ SPI0_IRQ,
+ SPI1_IRQ,
+ UART0_IRQ,
+ UART1_IRQ,
+ ADC_IRQ_FIFO,
+ I2C0_IRQ,
+ I2C1_IRQ,
+ TRNG_IRQ,
+ PLL_SYS_IRQ,
+ PLL_USB_IRQ,
+ SWI_IRQ_0,
+ SWI_IRQ_1,
+ SWI_IRQ_2,
+ SWI_IRQ_3,
+ SWI_IRQ_4,
+ SWI_IRQ_5,
+);
+
/// Macro to bind interrupts to handlers.
///
/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
@@ -123,6 +182,7 @@ macro_rules! bind_interrupts {
};
}
+#[cfg(feature = "rp2040")]
embassy_hal_internal::peripherals! {
PIN_0,
PIN_1,
@@ -210,6 +270,139 @@ embassy_hal_internal::peripherals! {
BOOTSEL,
}
+#[cfg(feature = "rp235x")]
+embassy_hal_internal::peripherals! {
+ PIN_0,
+ PIN_1,
+ PIN_2,
+ PIN_3,
+ PIN_4,
+ PIN_5,
+ PIN_6,
+ PIN_7,
+ PIN_8,
+ PIN_9,
+ PIN_10,
+ PIN_11,
+ PIN_12,
+ PIN_13,
+ PIN_14,
+ PIN_15,
+ PIN_16,
+ PIN_17,
+ PIN_18,
+ PIN_19,
+ PIN_20,
+ PIN_21,
+ PIN_22,
+ PIN_23,
+ PIN_24,
+ PIN_25,
+ PIN_26,
+ PIN_27,
+ PIN_28,
+ PIN_29,
+ #[cfg(feature = "rp235xb")]
+ PIN_30,
+ #[cfg(feature = "rp235xb")]
+ PIN_31,
+ #[cfg(feature = "rp235xb")]
+ PIN_32,
+ #[cfg(feature = "rp235xb")]
+ PIN_33,
+ #[cfg(feature = "rp235xb")]
+ PIN_34,
+ #[cfg(feature = "rp235xb")]
+ PIN_35,
+ #[cfg(feature = "rp235xb")]
+ PIN_36,
+ #[cfg(feature = "rp235xb")]
+ PIN_37,
+ #[cfg(feature = "rp235xb")]
+ PIN_38,
+ #[cfg(feature = "rp235xb")]
+ PIN_39,
+ #[cfg(feature = "rp235xb")]
+ PIN_40,
+ #[cfg(feature = "rp235xb")]
+ PIN_41,
+ #[cfg(feature = "rp235xb")]
+ PIN_42,
+ #[cfg(feature = "rp235xb")]
+ PIN_43,
+ #[cfg(feature = "rp235xb")]
+ PIN_44,
+ #[cfg(feature = "rp235xb")]
+ PIN_45,
+ #[cfg(feature = "rp235xb")]
+ PIN_46,
+ #[cfg(feature = "rp235xb")]
+ PIN_47,
+ PIN_QSPI_SCLK,
+ PIN_QSPI_SS,
+ PIN_QSPI_SD0,
+ PIN_QSPI_SD1,
+ PIN_QSPI_SD2,
+ PIN_QSPI_SD3,
+
+ UART0,
+ UART1,
+
+ SPI0,
+ SPI1,
+
+ I2C0,
+ I2C1,
+
+ DMA_CH0,
+ DMA_CH1,
+ DMA_CH2,
+ DMA_CH3,
+ DMA_CH4,
+ DMA_CH5,
+ DMA_CH6,
+ DMA_CH7,
+ DMA_CH8,
+ DMA_CH9,
+ DMA_CH10,
+ DMA_CH11,
+ DMA_CH12,
+ DMA_CH13,
+ DMA_CH14,
+ DMA_CH15,
+
+ PWM_SLICE0,
+ PWM_SLICE1,
+ PWM_SLICE2,
+ PWM_SLICE3,
+ PWM_SLICE4,
+ PWM_SLICE5,
+ PWM_SLICE6,
+ PWM_SLICE7,
+ PWM_SLICE8,
+ PWM_SLICE9,
+ PWM_SLICE10,
+ PWM_SLICE11,
+
+ USB,
+
+ RTC,
+
+ FLASH,
+
+ ADC,
+ ADC_TEMP_SENSOR,
+
+ CORE1,
+
+ PIO0,
+ PIO1,
+ PIO2,
+
+ WATCHDOG,
+ BOOTSEL,
+}
+
#[cfg(not(feature = "boot2-none"))]
macro_rules! select_bootloader {
( $( $feature:literal => $loader:ident, )+ default => $default:ident ) => {
@@ -279,6 +472,7 @@ pub fn install_core0_stack_guard() -> Result<(), ()> {
unsafe { install_stack_guard(core::ptr::addr_of_mut!(_stack_end)) }
}
+#[cfg(feature = "rp2040")]
#[inline(always)]
fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> {
let core = unsafe { cortex_m::Peripherals::steal() };
@@ -306,6 +500,24 @@ fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> {
Ok(())
}
+#[cfg(feature = "rp235x")]
+#[inline(always)]
+fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> {
+ let core = unsafe { cortex_m::Peripherals::steal() };
+
+ // Fail if MPU is already configured
+ if core.MPU.ctrl.read() != 0 {
+ return Err(());
+ }
+
+ unsafe {
+ core.MPU.ctrl.write(5); // enable mpu with background default map
+ core.MPU.rbar.write(stack_bottom as u32 & !0xff); // set address
+ core.MPU.rlar.write(1); // enable region
+ }
+ Ok(())
+}
+
/// HAL configuration for RP.
pub mod config {
use crate::clocks::ClockConfig;
@@ -354,7 +566,7 @@ pub fn init(config: config::Config) -> Peripherals {
peripherals
}
-#[cfg(feature = "rt")]
+#[cfg(all(feature = "rt", feature = "rp2040"))]
#[cortex_m_rt::pre_init]
unsafe fn pre_init() {
// SIO does not get reset when core0 is reset with either `scb::sys_reset()` or with SWD.
diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs
index d9d65694a..d1ce688ce 100644
--- a/embassy-rp/src/multicore.rs
+++ b/embassy-rp/src/multicore.rs
@@ -84,7 +84,7 @@ impl Stack {
}
}
-#[cfg(feature = "rt")]
+#[cfg(all(feature = "rt", feature = "rp2040"))]
#[interrupt]
#[link_section = ".data.ram_func"]
unsafe fn SIO_IRQ_PROC1() {
@@ -109,6 +109,31 @@ unsafe fn SIO_IRQ_PROC1() {
}
}
+#[cfg(all(feature = "rt", feature = "rp235x"))]
+#[interrupt]
+#[link_section = ".data.ram_func"]
+unsafe fn SIO_IRQ_FIFO() {
+ let sio = pac::SIO;
+ // Clear IRQ
+ sio.fifo().st().write(|w| w.set_wof(false));
+
+ while sio.fifo().st().read().vld() {
+ // Pause CORE1 execution and disable interrupts
+ if fifo_read_wfe() == PAUSE_TOKEN {
+ cortex_m::interrupt::disable();
+ // Signal to CORE0 that execution is paused
+ fifo_write(PAUSE_TOKEN);
+ // Wait for `resume` signal from CORE0
+ while fifo_read_wfe() != RESUME_TOKEN {
+ cortex_m::asm::nop();
+ }
+ cortex_m::interrupt::enable();
+ // Signal to CORE0 that execution is resumed
+ fifo_write(RESUME_TOKEN);
+ }
+ }
+}
+
/// Spawn a function on this core
pub fn spawn_core1(_core1: CORE1, stack: &'static mut Stack, entry: F)
where
@@ -135,7 +160,14 @@ where
IS_CORE1_INIT.store(true, Ordering::Release);
// Enable fifo interrupt on CORE1 for `pause` functionality.
- unsafe { interrupt::SIO_IRQ_PROC1.enable() };
+ #[cfg(feature = "rp2040")]
+ unsafe {
+ interrupt::SIO_IRQ_PROC1.enable()
+ };
+ #[cfg(feature = "rp235x")]
+ unsafe {
+ interrupt::SIO_IRQ_FIFO.enable()
+ };
entry()
}
diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs
index 1f7adbda3..89313086b 100644
--- a/embassy-rp/src/pio/mod.rs
+++ b/embassy-rp/src/pio/mod.rs
@@ -10,14 +10,11 @@ use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker;
use fixed::types::extra::U8;
use fixed::FixedU32;
-use pac::io::vals::Gpio0ctrlFuncsel;
-use pac::pio::vals::SmExecctrlStatusSel;
use pio::{Program, SideSet, Wrap};
use crate::dma::{Channel, Transfer, Word};
use crate::gpio::{self, AnyPin, Drive, Level, Pull, SealedPin, SlewRate};
use crate::interrupt::typelevel::{Binding, Handler, Interrupt};
-use crate::pac::dma::vals::TreqSel;
use crate::relocate::RelocatedProgram;
use crate::{pac, peripherals, RegExt};
@@ -355,11 +352,14 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
let p = ch.regs();
p.write_addr().write_value(data.as_ptr() as u32);
p.read_addr().write_value(PIO::PIO.rxf(SM).as_ptr() as u32);
- p.trans_count().write_value(data.len() as u32);
+ #[cfg(feature = "rp2040")]
+ p.trans_count().write(|w| *w = data.len() as u32);
+ #[cfg(feature = "rp235x")]
+ p.trans_count().write(|w| w.set_count(data.len() as u32));
compiler_fence(Ordering::SeqCst);
p.ctrl_trig().write(|w| {
// Set RX DREQ for this statemachine
- w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8 + 4));
+ w.set_treq_sel(crate::pac::dma::vals::TreqSel::from(pio_no * 8 + SM as u8 + 4));
w.set_data_size(W::size());
w.set_chain_to(ch.number());
w.set_incr_read(false);
@@ -437,11 +437,14 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
let p = ch.regs();
p.read_addr().write_value(data.as_ptr() as u32);
p.write_addr().write_value(PIO::PIO.txf(SM).as_ptr() as u32);
- p.trans_count().write_value(data.len() as u32);
+ #[cfg(feature = "rp2040")]
+ p.trans_count().write(|w| *w = data.len() as u32);
+ #[cfg(feature = "rp235x")]
+ p.trans_count().write(|w| w.set_count(data.len() as u32));
compiler_fence(Ordering::SeqCst);
p.ctrl_trig().write(|w| {
// Set TX DREQ for this statemachine
- w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8));
+ w.set_treq_sel(crate::pac::dma::vals::TreqSel::from(pio_no * 8 + SM as u8));
w.set_data_size(W::size());
w.set_chain_to(ch.number());
w.set_incr_read(true);
@@ -523,6 +526,39 @@ pub struct PinConfig {
pub out_base: u8,
}
+/// Comparison level or IRQ index for the MOV x, STATUS instruction.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+#[cfg(feature = "rp235x")]
+pub enum StatusN {
+ /// IRQ flag in this PIO block
+ This(u8),
+ /// IRQ flag in the next lower PIO block
+ Lower(u8),
+ /// IRQ flag in the next higher PIO block
+ Higher(u8),
+}
+
+#[cfg(feature = "rp235x")]
+impl Default for StatusN {
+ fn default() -> Self {
+ Self::This(0)
+ }
+}
+
+#[cfg(feature = "rp235x")]
+impl Into for StatusN {
+ fn into(self) -> crate::pac::pio::vals::ExecctrlStatusN {
+ let x = match self {
+ StatusN::This(n) => n,
+ StatusN::Lower(n) => n + 0x08,
+ StatusN::Higher(n) => n + 0x10,
+ };
+
+ crate::pac::pio::vals::ExecctrlStatusN(x)
+ }
+}
+
/// PIO config.
#[derive(Clone, Copy, Debug)]
pub struct Config<'d, PIO: Instance> {
@@ -537,7 +573,12 @@ pub struct Config<'d, PIO: Instance> {
/// Which source to use for checking status.
pub status_sel: StatusSource,
/// Status comparison level.
+ #[cfg(feature = "rp2040")]
pub status_n: u8,
+ // This cfg probably shouldn't be required, but the SVD for the 2040 doesn't have the enum
+ #[cfg(feature = "rp235x")]
+ /// Status comparison level.
+ pub status_n: StatusN,
exec: ExecConfig,
origin: Option,
/// Configure FIFO allocation.
@@ -653,7 +694,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
assert!(config.clock_divider <= 65536, "clkdiv must be <= 65536");
assert!(config.clock_divider >= 1, "clkdiv must be >= 1");
assert!(config.out_en_sel < 32, "out_en_sel must be < 32");
- assert!(config.status_n < 32, "status_n must be < 32");
+ //assert!(config.status_n < 32, "status_n must be < 32");
// sm expects 0 for 32, truncation makes that happen
assert!(config.shift_in.threshold <= 32, "shift_in.threshold must be <= 32");
assert!(config.shift_out.threshold <= 32, "shift_out.threshold must be <= 32");
@@ -668,11 +709,17 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
w.set_out_sticky(config.out_sticky);
w.set_wrap_top(config.exec.wrap_top);
w.set_wrap_bottom(config.exec.wrap_bottom);
+ #[cfg(feature = "rp235x")]
w.set_status_sel(match config.status_sel {
- StatusSource::TxFifoLevel => SmExecctrlStatusSel::TXLEVEL,
- StatusSource::RxFifoLevel => SmExecctrlStatusSel::RXLEVEL,
+ StatusSource::TxFifoLevel => pac::pio::vals::ExecctrlStatusSel::TXLEVEL,
+ StatusSource::RxFifoLevel => pac::pio::vals::ExecctrlStatusSel::RXLEVEL,
});
- w.set_status_n(config.status_n);
+ #[cfg(feature = "rp2040")]
+ w.set_status_sel(match config.status_sel {
+ StatusSource::TxFifoLevel => pac::pio::vals::SmExecctrlStatusSel::TXLEVEL,
+ StatusSource::RxFifoLevel => pac::pio::vals::SmExecctrlStatusSel::RXLEVEL,
+ });
+ w.set_status_n(config.status_n.into());
});
sm.shiftctrl().write(|w| {
w.set_fjoin_rx(config.fifo_join == FifoJoin::RxOnly);
@@ -1147,7 +1194,7 @@ fn on_pio_drop() {
let state = PIO::state();
if state.users.fetch_sub(1, Ordering::AcqRel) == 1 {
let used_pins = state.used_pins.load(Ordering::Relaxed);
- let null = Gpio0ctrlFuncsel::NULL as _;
+ let null = pac::io::vals::Gpio0ctrlFuncsel::NULL as _;
// we only have 30 pins. don't test the other two since gpio() asserts.
for i in 0..30 {
if used_pins & (1 << i) != 0 {
@@ -1203,6 +1250,8 @@ macro_rules! impl_pio {
impl_pio!(PIO0, 0, PIO0, PIO0_0, PIO0_IRQ_0);
impl_pio!(PIO1, 1, PIO1, PIO1_0, PIO1_IRQ_0);
+#[cfg(feature = "rp235x")]
+impl_pio!(PIO2, 2, PIO2, PIO2_0, PIO2_IRQ_0);
/// PIO pin.
pub trait PioPin: gpio::Pin {}
@@ -1247,3 +1296,25 @@ impl_pio_pin! {
PIN_28,
PIN_29,
}
+
+#[cfg(feature = "rp235xb")]
+impl_pio_pin! {
+ PIN_30,
+ PIN_31,
+ PIN_32,
+ PIN_33,
+ PIN_34,
+ PIN_35,
+ PIN_36,
+ PIN_37,
+ PIN_38,
+ PIN_39,
+ PIN_40,
+ PIN_41,
+ PIN_42,
+ PIN_43,
+ PIN_44,
+ PIN_45,
+ PIN_46,
+ PIN_47,
+}
diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs
index c35e76587..3f96a3f05 100644
--- a/embassy-rp/src/pwm.rs
+++ b/embassy-rp/src/pwm.rs
@@ -363,6 +363,15 @@ slice!(PWM_SLICE5, 5);
slice!(PWM_SLICE6, 6);
slice!(PWM_SLICE7, 7);
+#[cfg(feature = "rp235x")]
+slice!(PWM_SLICE8, 8);
+#[cfg(feature = "rp235x")]
+slice!(PWM_SLICE9, 9);
+#[cfg(feature = "rp235x")]
+slice!(PWM_SLICE10, 10);
+#[cfg(feature = "rp235x")]
+slice!(PWM_SLICE11, 11);
+
/// PWM Channel A.
pub trait ChannelAPin: GpioPin {}
/// PWM Channel B.
@@ -404,3 +413,39 @@ impl_pin!(PIN_26, PWM_SLICE5, ChannelAPin);
impl_pin!(PIN_27, PWM_SLICE5, ChannelBPin);
impl_pin!(PIN_28, PWM_SLICE6, ChannelAPin);
impl_pin!(PIN_29, PWM_SLICE6, ChannelBPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_30, PWM_SLICE7, ChannelAPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_31, PWM_SLICE7, ChannelBPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_32, PWM_SLICE8, ChannelAPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_33, PWM_SLICE8, ChannelBPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_34, PWM_SLICE9, ChannelAPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_35, PWM_SLICE9, ChannelBPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_36, PWM_SLICE10, ChannelAPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_37, PWM_SLICE10, ChannelBPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_38, PWM_SLICE11, ChannelAPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_39, PWM_SLICE11, ChannelBPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_40, PWM_SLICE8, ChannelAPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_41, PWM_SLICE8, ChannelBPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_42, PWM_SLICE9, ChannelAPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_43, PWM_SLICE9, ChannelBPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_44, PWM_SLICE10, ChannelAPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_45, PWM_SLICE10, ChannelBPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_46, PWM_SLICE11, ChannelAPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_47, PWM_SLICE11, ChannelBPin);
diff --git a/embassy-rp/src/reset.rs b/embassy-rp/src/reset.rs
index 70512fa14..4b9e42483 100644
--- a/embassy-rp/src/reset.rs
+++ b/embassy-rp/src/reset.rs
@@ -2,7 +2,7 @@ pub use pac::resets::regs::Peripherals;
use crate::pac;
-pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ffffff);
+pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ff_ffff);
pub(crate) fn reset(peris: Peripherals) {
pac::RESETS.reset().write_value(peris);
diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs
index 2ce7ac645..4ba5bad4b 100644
--- a/embassy-rp/src/rtc/mod.rs
+++ b/embassy-rp/src/rtc/mod.rs
@@ -1,3 +1,4 @@
+#![cfg(feature = "rp2040")]
//! RTC driver.
mod filter;
diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs
index 1617c144c..bc852ff7b 100644
--- a/embassy-rp/src/spi.rs
+++ b/embassy-rp/src/spi.rs
@@ -106,15 +106,55 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
if let Some(pin) = &clk {
pin.gpio().ctrl().write(|w| w.set_funcsel(1));
+ pin.pad_ctrl().write(|w| {
+ #[cfg(feature = "rp235x")]
+ w.set_iso(false);
+ w.set_schmitt(true);
+ w.set_slewfast(false);
+ w.set_ie(true);
+ w.set_od(false);
+ w.set_pue(false);
+ w.set_pde(false);
+ });
}
if let Some(pin) = &mosi {
pin.gpio().ctrl().write(|w| w.set_funcsel(1));
+ pin.pad_ctrl().write(|w| {
+ #[cfg(feature = "rp235x")]
+ w.set_iso(false);
+ w.set_schmitt(true);
+ w.set_slewfast(false);
+ w.set_ie(true);
+ w.set_od(false);
+ w.set_pue(false);
+ w.set_pde(false);
+ });
}
if let Some(pin) = &miso {
pin.gpio().ctrl().write(|w| w.set_funcsel(1));
+ pin.pad_ctrl().write(|w| {
+ #[cfg(feature = "rp235x")]
+ w.set_iso(false);
+ w.set_schmitt(true);
+ w.set_slewfast(false);
+ w.set_ie(true);
+ w.set_od(false);
+ w.set_pue(false);
+ w.set_pde(false);
+ });
}
if let Some(pin) = &cs {
pin.gpio().ctrl().write(|w| w.set_funcsel(1));
+ pin.pad_ctrl().write(|w| {
+ #[cfg(feature = "rp235x")]
+ w.set_iso(false);
+ w.set_schmitt(true);
+ w.set_slewfast(false);
+ w.set_ie(true);
+ w.set_od(false);
+ w.set_pue(false);
+ w.set_pde(false);
+ });
}
Self {
inner,
@@ -442,8 +482,8 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
trait SealedMode {}
trait SealedInstance {
- const TX_DREQ: u8;
- const RX_DREQ: u8;
+ const TX_DREQ: pac::dma::vals::TreqSel;
+ const RX_DREQ: pac::dma::vals::TreqSel;
fn regs(&self) -> pac::spi::Spi;
}
@@ -459,8 +499,8 @@ pub trait Instance: SealedInstance {}
macro_rules! impl_instance {
($type:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => {
impl SealedInstance for peripherals::$type {
- const TX_DREQ: u8 = $tx_dreq;
- const RX_DREQ: u8 = $rx_dreq;
+ const TX_DREQ: pac::dma::vals::TreqSel = $tx_dreq;
+ const RX_DREQ: pac::dma::vals::TreqSel = $rx_dreq;
fn regs(&self) -> pac::spi::Spi {
pac::$type
@@ -470,8 +510,18 @@ macro_rules! impl_instance {
};
}
-impl_instance!(SPI0, Spi0, 16, 17);
-impl_instance!(SPI1, Spi1, 18, 19);
+impl_instance!(
+ SPI0,
+ Spi0,
+ pac::dma::vals::TreqSel::SPI0_TX,
+ pac::dma::vals::TreqSel::SPI0_RX
+);
+impl_instance!(
+ SPI1,
+ Spi1,
+ pac::dma::vals::TreqSel::SPI1_TX,
+ pac::dma::vals::TreqSel::SPI1_RX
+);
/// CLK pin.
pub trait ClkPin: GpioPin {}
@@ -518,6 +568,42 @@ impl_pin!(PIN_26, SPI1, ClkPin);
impl_pin!(PIN_27, SPI1, MosiPin);
impl_pin!(PIN_28, SPI1, MisoPin);
impl_pin!(PIN_29, SPI1, CsPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_30, SPI1, ClkPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_31, SPI1, MosiPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_32, SPI0, MisoPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_33, SPI0, CsPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_34, SPI0, ClkPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_35, SPI0, MosiPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_36, SPI0, MisoPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_37, SPI0, CsPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_38, SPI0, ClkPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_39, SPI0, MosiPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_40, SPI1, MisoPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_41, SPI1, CsPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_42, SPI1, ClkPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_43, SPI1, MosiPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_44, SPI1, MisoPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_45, SPI1, CsPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_46, SPI1, ClkPin);
+#[cfg(feature = "rp235xb")]
+impl_pin!(PIN_47, SPI1, MosiPin);
macro_rules! impl_mode {
($name:ident) => {
diff --git a/embassy-rp/src/time_driver.rs b/embassy-rp/src/time_driver.rs
index bab1044cb..6f532fa8e 100644
--- a/embassy-rp/src/time_driver.rs
+++ b/embassy-rp/src/time_driver.rs
@@ -10,6 +10,11 @@ use embassy_time_driver::{AlarmHandle, Driver};
use crate::interrupt::InterruptExt;
use crate::{interrupt, pac};
+#[cfg(feature = "rp2040")]
+use pac::TIMER;
+#[cfg(feature = "rp235x")]
+use pac::TIMER0 as TIMER;
+
struct AlarmState {
timestamp: Cell,
callback: Cell