aboutsummaryrefslogtreecommitdiff
path: root/embassy-rp/src
diff options
context:
space:
mode:
authorCaleb Jamison <[email protected]>2024-08-07 23:20:26 -0400
committerCaleb Jamison <[email protected]>2024-08-08 21:35:21 -0400
commitb185e02a42ad751ec6c31ffa6a1b87503f15489d (patch)
tree0f0c66747267d24d95b5957b22db7e5c525cb00e /embassy-rp/src
parent891c5ee10584cd990dad529e3506fe1328e4e69d (diff)
Initial rp235x support
Examples have been run, but there is not yet a test suite.
Diffstat (limited to 'embassy-rp/src')
-rw-r--r--embassy-rp/src/adc.rs27
-rw-r--r--embassy-rp/src/binary_info/consts.rs31
-rw-r--r--embassy-rp/src/binary_info/macros.rs171
-rw-r--r--embassy-rp/src/binary_info/mod.rs174
-rw-r--r--embassy-rp/src/binary_info/types.rs192
-rw-r--r--embassy-rp/src/block.rs1076
-rw-r--r--embassy-rp/src/clocks.rs84
-rw-r--r--embassy-rp/src/dma.rs32
-rw-r--r--embassy-rp/src/flash.rs25
-rw-r--r--embassy-rp/src/float/mod.rs1
-rw-r--r--embassy-rp/src/gpio.rs76
-rw-r--r--embassy-rp/src/i2c.rs36
-rw-r--r--embassy-rp/src/lib.rs218
-rw-r--r--embassy-rp/src/multicore.rs36
-rw-r--r--embassy-rp/src/pio/mod.rs95
-rw-r--r--embassy-rp/src/pwm.rs45
-rw-r--r--embassy-rp/src/reset.rs2
-rw-r--r--embassy-rp/src/rtc/mod.rs1
-rw-r--r--embassy-rp/src/spi.rs98
-rw-r--r--embassy-rp/src/time_driver.rs73
-rw-r--r--embassy-rp/src/uart/mod.rs122
-rw-r--r--embassy-rp/src/usb.rs6
-rw-r--r--embassy-rp/src/watchdog.rs1
23 files changed, 2546 insertions, 76 deletions
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;
11use crate::gpio::{self, AnyPin, Pull, SealedPin as GpioPin}; 11use crate::gpio::{self, AnyPin, Pull, SealedPin as GpioPin};
12use crate::interrupt::typelevel::Binding; 12use crate::interrupt::typelevel::Binding;
13use crate::interrupt::InterruptExt; 13use crate::interrupt::InterruptExt;
14use crate::pac::dma::vals::TreqSel;
14use crate::peripherals::{ADC, ADC_TEMP_SENSOR}; 15use crate::peripherals::{ADC, ADC_TEMP_SENSOR};
15use crate::{dma, interrupt, pac, peripherals, Peripheral, RegExt}; 16use crate::{dma, interrupt, pac, peripherals, Peripheral, RegExt};
16 17
@@ -229,7 +230,10 @@ impl<'d> Adc<'d, Async> {
229 div: u16, 230 div: u16,
230 dma: impl Peripheral<P = impl dma::Channel>, 231 dma: impl Peripheral<P = impl dma::Channel>,
231 ) -> Result<(), Error> { 232 ) -> Result<(), Error> {
233 #[cfg(feature = "rp2040")]
232 let mut rrobin = 0_u8; 234 let mut rrobin = 0_u8;
235 #[cfg(feature = "rp235x")]
236 let mut rrobin = 0_u16;
233 for c in channels { 237 for c in channels {
234 rrobin |= 1 << c; 238 rrobin |= 1 << c;
235 } 239 }
@@ -278,7 +282,7 @@ impl<'d> Adc<'d, Async> {
278 } 282 }
279 let auto_reset = ResetDmaConfig; 283 let auto_reset = ResetDmaConfig;
280 284
281 let dma = unsafe { dma::read(dma, r.fifo().as_ptr() as *const W, buf as *mut [W], 36) }; 285 let dma = unsafe { dma::read(dma, r.fifo().as_ptr() as *const W, buf as *mut [W], TreqSel::ADC) };
282 // start conversions and wait for dma to finish. we can't report errors early 286 // start conversions and wait for dma to finish. we can't report errors early
283 // because there's no interrupt to signal them, and inspecting every element 287 // because there's no interrupt to signal them, and inspecting every element
284 // of the fifo is too costly to do here. 288 // of the fifo is too costly to do here.
@@ -423,10 +427,31 @@ macro_rules! impl_pin {
423 }; 427 };
424} 428}
425 429
430#[cfg(any(feature = "rp235xa", feature = "rp2040"))]
426impl_pin!(PIN_26, 0); 431impl_pin!(PIN_26, 0);
432#[cfg(any(feature = "rp235xa", feature = "rp2040"))]
427impl_pin!(PIN_27, 1); 433impl_pin!(PIN_27, 1);
434#[cfg(any(feature = "rp235xa", feature = "rp2040"))]
428impl_pin!(PIN_28, 2); 435impl_pin!(PIN_28, 2);
436#[cfg(any(feature = "rp235xa", feature = "rp2040"))]
429impl_pin!(PIN_29, 3); 437impl_pin!(PIN_29, 3);
430 438
439#[cfg(feature = "rp235xb")]
440impl_pin!(PIN_40, 0);
441#[cfg(feature = "rp235xb")]
442impl_pin!(PIN_41, 1);
443#[cfg(feature = "rp235xb")]
444impl_pin!(PIN_42, 2);
445#[cfg(feature = "rp235xb")]
446impl_pin!(PIN_43, 3);
447#[cfg(feature = "rp235xb")]
448impl_pin!(PIN_44, 4);
449#[cfg(feature = "rp235xb")]
450impl_pin!(PIN_45, 5);
451#[cfg(feature = "rp235xb")]
452impl_pin!(PIN_46, 6);
453#[cfg(feature = "rp235xb")]
454impl_pin!(PIN_47, 7);
455
431impl SealedAdcChannel for peripherals::ADC_TEMP_SENSOR {} 456impl SealedAdcChannel for peripherals::ADC_TEMP_SENSOR {}
432impl AdcChannel for peripherals::ADC_TEMP_SENSOR {} 457impl 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 @@
1//! Constants for binary info
2
3/// All Raspberry Pi specified IDs have this tag.
4///
5/// You can create your own for custom fields.
6pub const TAG_RASPBERRY_PI: u16 = super::make_tag(b"RP");
7
8/// Used to note the program name - use with StringEntry
9pub const ID_RP_PROGRAM_NAME: u32 = 0x02031c86;
10/// Used to note the program version - use with StringEntry
11pub const ID_RP_PROGRAM_VERSION_STRING: u32 = 0x11a9bc3a;
12/// Used to note the program build date - use with StringEntry
13pub const ID_RP_PROGRAM_BUILD_DATE_STRING: u32 = 0x9da22254;
14/// Used to note the size of the binary - use with IntegerEntry
15pub const ID_RP_BINARY_END: u32 = 0x68f465de;
16/// Used to note a URL for the program - use with StringEntry
17pub const ID_RP_PROGRAM_URL: u32 = 0x1856239a;
18/// Used to note a description of the program - use with StringEntry
19pub const ID_RP_PROGRAM_DESCRIPTION: u32 = 0xb6a07c19;
20/// Used to note some feature of the program - use with StringEntry
21pub const ID_RP_PROGRAM_FEATURE: u32 = 0xa1f4b453;
22/// Used to note some whether this was a Debug or Release build - use with StringEntry
23pub const ID_RP_PROGRAM_BUILD_ATTRIBUTE: u32 = 0x4275f0d3;
24/// Used to note the Pico SDK version used - use with StringEntry
25pub const ID_RP_SDK_VERSION: u32 = 0x5360b3ab;
26/// Used to note which board this program targets - use with StringEntry
27pub const ID_RP_PICO_BOARD: u32 = 0xb63cffbb;
28/// Used to note which `boot2` image this program uses - use with StringEntry
29pub const ID_RP_BOOT2_NAME: u32 = 0x7f8882e1;
30
31// 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 @@
1//! Handy macros for making Binary Info entries
2
3/// Generate a static item containing the given environment variable,
4/// and return its [`EntryAddr`](super::EntryAddr).
5#[macro_export]
6macro_rules! binary_info_env {
7 ($tag:expr, $id:expr, $env_var_name:expr) => {
8 $crate::binary_info_str!($tag, $id, {
9 let value = concat!(env!($env_var_name), "\0");
10 // # Safety
11 //
12 // We used `concat!` to null-terminate on the line above.
13 let value_cstr =
14 unsafe { core::ffi::CStr::from_bytes_with_nul_unchecked(value.as_bytes()) };
15 value_cstr
16 })
17 };
18}
19
20/// Generate a static item containing the given string, and return its
21/// [`EntryAddr`](super::EntryAddr).
22///
23/// You must pass a numeric tag, a numeric ID, and `&CStr` (which is always
24/// null-terminated).
25#[macro_export]
26macro_rules! binary_info_str {
27 ($tag:expr, $id:expr, $str:expr) => {{
28 static ENTRY: $crate::binary_info::StringEntry =
29 $crate::binary_info::StringEntry::new($tag, $id, $str);
30 ENTRY.addr()
31 }};
32}
33
34/// Generate a static item containing the given string, and return its
35/// [`EntryAddr`](super::EntryAddr).
36///
37/// You must pass a numeric tag, a numeric ID, and `&CStr` (which is always
38/// null-terminated).
39#[macro_export]
40macro_rules! binary_info_int {
41 ($tag:expr, $id:expr, $int:expr) => {{
42 static ENTRY: $crate::binary_info::IntegerEntry =
43 $crate::binary_info::IntegerEntry::new($tag, $id, $int);
44 ENTRY.addr()
45 }};
46}
47
48/// Generate a static item containing the program name, and return its
49/// [`EntryAddr`](super::EntryAddr).
50#[macro_export]
51macro_rules! binary_info_rp_program_name {
52 ($name:expr) => {
53 $crate::binary_info_str!(
54 $crate::binary_info::consts::TAG_RASPBERRY_PI,
55 $crate::binary_info::consts::ID_RP_PROGRAM_NAME,
56 $name
57 )
58 };
59}
60
61/// Generate a static item containing the `CARGO_BIN_NAME` as the program name,
62/// and return its [`EntryAddr`](super::EntryAddr).
63#[macro_export]
64macro_rules! binary_info_rp_cargo_bin_name {
65 () => {
66 $crate::binary_info_env!(
67 $crate::binary_info::consts::TAG_RASPBERRY_PI,
68 $crate::binary_info::consts::ID_RP_PROGRAM_NAME,
69 "CARGO_BIN_NAME"
70 )
71 };
72}
73
74/// Generate a static item containing the program version, and return its
75/// [`EntryAddr`](super::EntryAddr).
76#[macro_export]
77macro_rules! binary_info_rp_program_version {
78 ($version:expr) => {{
79 $crate::binary_info_str!(
80 $crate::binary_info::consts::TAG_RASPBERRY_PI,
81 $crate::binary_info::consts::ID_RP_PROGRAM_VERSION,
82 $version
83 )
84 }};
85}
86
87/// Generate a static item containing the `CARGO_PKG_VERSION` as the program
88/// version, and return its [`EntryAddr`](super::EntryAddr).
89#[macro_export]
90macro_rules! binary_info_rp_cargo_version {
91 () => {
92 $crate::binary_info_env!(
93 $crate::binary_info::consts::TAG_RASPBERRY_PI,
94 $crate::binary_info::consts::ID_RP_PROGRAM_VERSION_STRING,
95 "CARGO_PKG_VERSION"
96 )
97 };
98}
99
100/// Generate a static item containing the program URL, and return its
101/// [`EntryAddr`](super::EntryAddr).
102#[macro_export]
103macro_rules! binary_info_rp_program_url {
104 ($url:expr) => {
105 $crate::binary_info_str!(
106 $crate::binary_info::consts::TAG_RASPBERRY_PI,
107 $crate::binary_info::consts::ID_RP_PROGRAM_URL,
108 $url
109 )
110 };
111}
112
113/// Generate a static item containing the `CARGO_PKG_HOMEPAGE` as the program URL,
114/// and return its [`EntryAddr`](super::EntryAddr).
115#[macro_export]
116macro_rules! binary_info_rp_cargo_homepage_url {
117 () => {
118 $crate::binary_info_env!(
119 $crate::binary_info::consts::TAG_RASPBERRY_PI,
120 $crate::binary_info::consts::ID_RP_PROGRAM_URL,
121 "CARGO_PKG_HOMEPAGE"
122 )
123 };
124}
125
126/// Generate a static item containing the program description, and return its
127/// [`EntryAddr`](super::EntryAddr).
128#[macro_export]
129macro_rules! binary_info_rp_program_description {
130 ($description:expr) => {
131 $crate::binary_info_str!(
132 $crate::binary_info::consts::TAG_RASPBERRY_PI,
133 $crate::binary_info::consts::ID_RP_PROGRAM_DESCRIPTION,
134 $description
135 )
136 };
137}
138
139/// Generate a static item containing whether this is a debug or a release
140/// build, and return its [`EntryAddr`](super::EntryAddr).
141#[macro_export]
142macro_rules! binary_info_rp_program_build_attribute {
143 () => {
144 $crate::binary_info_str!(
145 $crate::binary_info::consts::TAG_RASPBERRY_PI,
146 $crate::binary_info::consts::ID_RP_PROGRAM_BUILD_ATTRIBUTE,
147 {
148 if cfg!(debug_assertions) {
149 c"debug"
150 } else {
151 c"release"
152 }
153 }
154 )
155 };
156}
157
158/// Generate a static item containing the specific board this program runs on,
159/// and return its [`EntryAddr`](super::EntryAddr).
160#[macro_export]
161macro_rules! binary_info_rp_pico_board {
162 ($board:expr) => {
163 $crate::binary_info_str!(
164 $crate::binary_info::consts::TAG_RASPBERRY_PI,
165 $crate::binary_info::consts::ID_RP_PICO_BOARD,
166 $board
167 )
168 };
169}
170
171// 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 @@
1//! Code and types for creating Picotool compatible "Binary Info" metadata
2//!
3//! Add something like this to your program, and compile with the "binary-info"
4//! and "rt" features:
5//!
6//! ```
7//! # use rp235x_hal as hal;
8//! #[link_section = ".bi_entries"]
9//! #[used]
10//! pub static PICOTOOL_ENTRIES: [hal::binary_info::EntryAddr; 3] = [
11//! hal::binary_info_rp_program_name!(c"Program Name Here"),
12//! hal::binary_info_rp_cargo_version!(),
13//! hal::binary_info_int!(hal::binary_info::make_tag(b"JP"), 0x0000_0001, 0x12345678),
14//! ];
15//! ```
16
17pub mod consts;
18
19mod types;
20pub use types::*;
21
22#[macro_use]
23mod macros;
24
25extern "C" {
26 /// The linker script sets this symbol to have the address of the first
27 /// entry in the `.bi_entries` section.
28 static __bi_entries_start: EntryAddr;
29 /// The linker script sets this symbol to have the address just past the
30 /// last entry in the `.bi_entries` section.
31 static __bi_entries_end: EntryAddr;
32 /// The linker script sets this symbol to have the address of the first
33 /// entry in the `.data` section.
34 static __sdata: u32;
35 /// The linker script sets this symbol to have the address just past the
36 /// first entry in the `.data` section.
37 static __edata: u32;
38 /// The linker script sets this symbol to have the address of the
39 /// initialisation data for the first entry in the `.data` section (i.e. a
40 /// flash address, not a RAM address).
41 static __sidata: u32;
42}
43
44/// Picotool can find this block in our ELF file and report interesting
45/// metadata.
46///
47/// The data here tells picotool the start and end flash addresses of our
48/// metadata.
49#[cfg(feature = "binary-info")]
50#[link_section = ".start_block"]
51#[used]
52pub static PICOTOOL_HEADER: Header = unsafe {
53 Header::new(
54 core::ptr::addr_of!(__bi_entries_start),
55 core::ptr::addr_of!(__bi_entries_end),
56 &MAPPING_TABLE,
57 )
58};
59
60/// This tells picotool how to convert RAM addresses back into Flash addresses
61#[cfg(feature = "binary-info")]
62pub static MAPPING_TABLE: [MappingTableEntry; 2] = [
63 // This is the entry for .data
64 MappingTableEntry {
65 source_addr_start: unsafe { core::ptr::addr_of!(__sidata) },
66 dest_addr_start: unsafe { core::ptr::addr_of!(__sdata) },
67 dest_addr_end: unsafe { core::ptr::addr_of!(__edata) },
68 },
69 // This is the terminating marker
70 MappingTableEntry::null(),
71];
72
73/// Create a 'Binary Info' entry containing the program name
74///
75/// This is well-known to picotool, and will be displayed if you run `picotool info`.
76///
77/// * Tag: [`consts::TAG_RASPBERRY_PI`]
78/// * ID: [`consts::ID_RP_PROGRAM_NAME`]
79pub const fn rp_program_name(name: &'static core::ffi::CStr) -> StringEntry {
80 StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_NAME, name)
81}
82
83/// Create a 'Binary Info' entry containing the program version.
84///
85/// * Tag: [`consts::TAG_RASPBERRY_PI`]
86/// * Id: [`consts::ID_RP_PROGRAM_VERSION_STRING`]
87pub const fn rp_program_version(name: &'static core::ffi::CStr) -> StringEntry {
88 StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_VERSION_STRING, name)
89}
90
91/// Create a 'Binary Info' entry with a URL
92///
93/// * Tag: [`consts::TAG_RASPBERRY_PI`]
94/// * Id: [`consts::ID_RP_PROGRAM_URL`]
95pub const fn rp_program_url(url: &'static core::ffi::CStr) -> StringEntry {
96 StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_URL, url)
97}
98
99/// Create a 'Binary Info' with the program build date
100///
101/// * Tag: [`consts::TAG_RASPBERRY_PI`]
102/// * Id: [`consts::ID_RP_PROGRAM_BUILD_DATE_STRING`]
103pub const fn rp_program_build_date_string(value: &'static core::ffi::CStr) -> StringEntry {
104 StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_BUILD_DATE_STRING, value)
105}
106
107/// Create a 'Binary Info' with the size of the binary
108///
109/// * Tag: [`consts::TAG_RASPBERRY_PI`]
110/// * Id: [`consts::ID_RP_BINARY_END`]
111pub const fn rp_binary_end(value: u32) -> IntegerEntry {
112 IntegerEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_BINARY_END, value)
113}
114
115/// Create a 'Binary Info' with a description of the program
116///
117/// * Tag: [`consts::TAG_RASPBERRY_PI`]
118/// * Id: [`consts::ID_RP_PROGRAM_DESCRIPTION`]
119pub const fn rp_program_description(value: &'static core::ffi::CStr) -> StringEntry {
120 StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_DESCRIPTION, value)
121}
122
123/// Create a 'Binary Info' with some feature of the program
124///
125/// * Tag: [`consts::TAG_RASPBERRY_PI`]
126/// * Id: [`consts::ID_RP_PROGRAM_FEATURE`]
127pub const fn rp_program_feature(value: &'static core::ffi::CStr) -> StringEntry {
128 StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_FEATURE, value)
129}
130
131/// Create a 'Binary Info' with some whether this was a Debug or Release build
132///
133/// * Tag: [`consts::TAG_RASPBERRY_PI`]
134/// * Id: [`consts::ID_RP_PROGRAM_BUILD_ATTRIBUTE`]
135pub const fn rp_program_build_attribute(value: &'static core::ffi::CStr) -> StringEntry {
136 StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_BUILD_ATTRIBUTE, value)
137}
138
139/// Create a 'Binary Info' with the Pico SDK version used
140///
141/// * Tag: [`consts::TAG_RASPBERRY_PI`]
142/// * Id: [`consts::ID_RP_SDK_VERSION`]
143pub const fn rp_sdk_version(value: &'static core::ffi::CStr) -> StringEntry {
144 StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_SDK_VERSION, value)
145}
146
147/// Create a 'Binary Info' with which board this program targets
148///
149/// * Tag: [`consts::TAG_RASPBERRY_PI`]
150/// * Id: [`consts::ID_RP_PICO_BOARD`]
151pub const fn rp_pico_board(value: &'static core::ffi::CStr) -> StringEntry {
152 StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PICO_BOARD, value)
153}
154
155/// Create a 'Binary Info' with which `boot2` image this program uses
156///
157/// * Tag: [`consts::TAG_RASPBERRY_PI`]
158/// * Id: [`consts::ID_RP_BOOT2_NAME`]
159pub const fn rp_boot2_name(value: &'static core::ffi::CStr) -> StringEntry {
160 StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_BOOT2_NAME, value)
161}
162
163/// Create a tag from two ASCII letters.
164///
165/// ```
166/// # use rp235x_hal as hal;
167/// let tag = hal::binary_info::make_tag(b"RP");
168/// assert_eq!(tag, 0x5052);
169/// ```
170pub const fn make_tag(c: &[u8; 2]) -> u16 {
171 u16::from_le_bytes(*c)
172}
173
174// 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 @@
1//! Types for the Binary Info system
2
3/// This is the 'Binary Info' header block that `picotool` looks for in your UF2
4/// file/ELF file/Pico in Bootloader Mode to give you useful metadata about your
5/// program.
6///
7/// It should be placed in the first 4096 bytes of flash, so use your `memory.x`
8/// to insert a section between `.text` and `.vector_table` and put a static
9/// value of this type in that section.
10#[repr(C)]
11pub struct Header {
12 /// Must be equal to Picotool::MARKER_START
13 marker_start: u32,
14 /// The first in our table of pointers to Entries
15 entries_start: *const EntryAddr,
16 /// The last in our table of pointers to Entries
17 entries_end: *const EntryAddr,
18 /// The first entry in a null-terminated RAM/Flash mapping table
19 mapping_table: *const MappingTableEntry,
20 /// Must be equal to Picotool::MARKER_END
21 marker_end: u32,
22}
23
24impl Header {
25 /// This is the `BINARY_INFO_MARKER_START` magic value from `picotool`
26 const MARKER_START: u32 = 0x7188ebf2;
27 /// This is the `BINARY_INFO_MARKER_END` magic value from `picotool`
28 const MARKER_END: u32 = 0xe71aa390;
29
30 /// Create a new `picotool` compatible header.
31 ///
32 /// * `entries_start` - the first [`EntryAddr`] in the table
33 /// * `entries_end` - the last [`EntryAddr`] in the table
34 /// * `mapping_table` - the RAM/Flash address mapping table
35 pub const fn new(
36 entries_start: *const EntryAddr,
37 entries_end: *const EntryAddr,
38 mapping_table: &'static [MappingTableEntry],
39 ) -> Self {
40 let mapping_table = mapping_table.as_ptr();
41 Self {
42 marker_start: Self::MARKER_START,
43 entries_start,
44 entries_end,
45 mapping_table,
46 marker_end: Self::MARKER_END,
47 }
48 }
49}
50
51// We need this as rustc complains that is is unsafe to share `*const u32`
52// pointers between threads. We only allow these to be created with static
53// data, so this is OK.
54unsafe impl Sync for Header {}
55
56/// This is a reference to an entry. It's like a `&dyn` ref to some type `T:
57/// Entry`, except that the run-time type information is encoded into the
58/// Entry itself in very specific way.
59#[repr(transparent)]
60pub struct EntryAddr(*const u32);
61
62// We need this as rustc complains that is is unsafe to share `*const u32`
63// pointers between threads. We only allow these to be created with static
64// data, so this is OK.
65unsafe impl Sync for EntryAddr {}
66
67/// Allows us to tell picotool where values are in the UF2 given their run-time
68/// address.
69///
70/// The most obvious example is RAM variables, which must be found in the
71/// `.data` section of the UF2.
72#[repr(C)]
73pub struct MappingTableEntry {
74 /// The start address in RAM (or wherever the address picotool finds will
75 /// point)
76 pub source_addr_start: *const u32,
77 /// The start address in flash (or whever the data actually lives in the
78 /// ELF)
79 pub dest_addr_start: *const u32,
80 /// The end address in flash
81 pub dest_addr_end: *const u32,
82}
83
84impl MappingTableEntry {
85 /// Generate a null entry to mark the end of the list
86 pub const fn null() -> MappingTableEntry {
87 MappingTableEntry {
88 source_addr_start: core::ptr::null(),
89 dest_addr_start: core::ptr::null(),
90 dest_addr_end: core::ptr::null(),
91 }
92 }
93}
94
95// We need this as rustc complains that is is unsafe to share `*const u32`
96// pointers between threads. We only allow these to be created with static
97// data, so this is OK.
98unsafe impl Sync for MappingTableEntry {}
99
100/// This is the set of data types that `picotool` supports.
101#[repr(u16)]
102pub enum DataType {
103 /// Raw data
104 Raw = 1,
105 /// Data with a size
106 SizedData = 2,
107 /// A list of binary data
108 BinaryInfoListZeroTerminated = 3,
109 /// A BSON encoded blob
110 Bson = 4,
111 /// An Integer with an ID
112 IdAndInt = 5,
113 /// A string with an Id
114 IdAndString = 6,
115 /// A block device
116 BlockDevice = 7,
117 /// GPIO pins, with their function
118 PinsWithFunction = 8,
119 /// GPIO pins, with their name
120 PinsWithName = 9,
121 /// GPIO pins, with multiple names?
122 PinsWithNames = 10,
123}
124
125/// All Entries start with this common header
126#[repr(C)]
127struct EntryCommon {
128 data_type: DataType,
129 tag: u16,
130}
131
132/// An entry which contains both an ID (e.g. `ID_RP_PROGRAM_NAME`) and a pointer
133/// to a null-terminated string.
134#[repr(C)]
135pub struct StringEntry {
136 header: EntryCommon,
137 id: u32,
138 value: *const core::ffi::c_char,
139}
140
141impl StringEntry {
142 /// Create a new `StringEntry`
143 pub const fn new(tag: u16, id: u32, value: &'static core::ffi::CStr) -> StringEntry {
144 StringEntry {
145 header: EntryCommon {
146 data_type: DataType::IdAndString,
147 tag,
148 },
149 id,
150 value: value.as_ptr(),
151 }
152 }
153
154 /// Get this entry's address
155 pub const fn addr(&self) -> EntryAddr {
156 EntryAddr(self as *const Self as *const u32)
157 }
158}
159
160// We need this as rustc complains that is is unsafe to share `*const
161// core::ffi::c_char` pointers between threads. We only allow these to be
162// created with static string slices, so it's OK.
163unsafe impl Sync for StringEntry {}
164
165/// An entry which contains both an ID (e.g. `ID_RP_BINARY_END`) and an integer.
166#[repr(C)]
167pub struct IntegerEntry {
168 header: EntryCommon,
169 id: u32,
170 value: u32,
171}
172
173impl IntegerEntry {
174 /// Create a new `StringEntry`
175 pub const fn new(tag: u16, id: u32, value: u32) -> IntegerEntry {
176 IntegerEntry {
177 header: EntryCommon {
178 data_type: DataType::IdAndInt,
179 tag,
180 },
181 id,
182 value,
183 }
184 }
185
186 /// Get this entry's address
187 pub const fn addr(&self) -> EntryAddr {
188 EntryAddr(self as *const Self as *const u32)
189 }
190}
191
192// 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 @@
1//! Support for the RP235x Boot ROM's "Block" structures
2//!
3//! Blocks contain pointers, to form Block Loops.
4//!
5//! The `IMAGE_DEF` Block (here the `ImageDef` type) tells the ROM how to boot a
6//! firmware image. The `PARTITION_TABLE` Block (here the `PartitionTable` type)
7//! tells the ROM how to divide the flash space up into partitions.
8
9// These all have a 1 byte size
10
11/// An item ID for encoding a Vector Table address
12pub const ITEM_1BS_VECTOR_TABLE: u8 = 0x03;
13
14/// An item ID for encoding a Rolling Window Delta
15pub const ITEM_1BS_ROLLING_WINDOW_DELTA: u8 = 0x05;
16
17/// An item ID for encoding a Signature
18pub const ITEM_1BS_SIGNATURE: u8 = 0x09;
19
20/// An item ID for encoding a Salt
21pub const ITEM_1BS_SALT: u8 = 0x0c;
22
23/// An item ID for encoding an Image Type
24pub const ITEM_1BS_IMAGE_TYPE: u8 = 0x42;
25
26/// An item ID for encoding the image's Entry Point
27pub const ITEM_1BS_ENTRY_POINT: u8 = 0x44;
28
29/// An item ID for encoding the definition of a Hash
30pub const ITEM_2BS_HASH_DEF: u8 = 0x47;
31
32/// An item ID for encoding a Version
33pub const ITEM_1BS_VERSION: u8 = 0x48;
34
35/// An item ID for encoding a Hash
36pub const ITEM_1BS_HASH_VALUE: u8 = 0x4b;
37
38// These all have a 2-byte size
39
40/// An item ID for encoding a Load Map
41pub const ITEM_2BS_LOAD_MAP: u8 = 0x06;
42
43/// An item ID for encoding a Partition Table
44pub const ITEM_2BS_PARTITION_TABLE: u8 = 0x0a;
45
46/// An item ID for encoding a placeholder entry that is ignored
47///
48/// Allows a Block to not be empty.
49pub const ITEM_2BS_IGNORED: u8 = 0xfe;
50
51/// An item ID for encoding the special last item in a Block
52///
53/// It records how long the Block is.
54pub const ITEM_2BS_LAST: u8 = 0xff;
55
56// Options for ITEM_1BS_IMAGE_TYPE
57
58/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark an image as invalid
59pub const IMAGE_TYPE_INVALID: u16 = 0x0000;
60
61/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark an image as an executable
62pub const IMAGE_TYPE_EXE: u16 = 0x0001;
63
64/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark an image as data
65pub const IMAGE_TYPE_DATA: u16 = 0x0002;
66
67/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU security mode as unspecified
68pub const IMAGE_TYPE_EXE_TYPE_SECURITY_UNSPECIFIED: u16 = 0x0000;
69
70/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU security mode as Non Secure
71pub const IMAGE_TYPE_EXE_TYPE_SECURITY_NS: u16 = 0x0010;
72
73/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU security mode as Non Secure
74pub const IMAGE_TYPE_EXE_TYPE_SECURITY_S: u16 = 0x0020;
75
76/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU type as Arm
77pub const IMAGE_TYPE_EXE_CPU_ARM: u16 = 0x0000;
78
79/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU type as RISC-V
80pub const IMAGE_TYPE_EXE_CPU_RISCV: u16 = 0x0100;
81
82/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU as an RP2040
83pub const IMAGE_TYPE_EXE_CHIP_RP2040: u16 = 0x0000;
84
85/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU as an RP2350
86pub const IMAGE_TYPE_EXE_CHIP_RP2350: u16 = 0x1000;
87
88/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the image as Try Before You Buy.
89///
90/// This means the image must be marked as 'Bought' with the ROM before the
91/// watchdog times out the trial period, otherwise it is erased and the previous
92/// image will be booted.
93pub const IMAGE_TYPE_TBYB: u16 = 0x8000;
94
95/// This is the magic Block Start value.
96///
97/// The Pico-SDK calls it `PICOBIN_BLOCK_MARKER_START`
98const BLOCK_MARKER_START: u32 = 0xffffded3;
99
100/// This is the magic Block END value.
101///
102/// The Pico-SDK calls it `PICOBIN_BLOCK_MARKER_END`
103const BLOCK_MARKER_END: u32 = 0xab123579;
104
105/// An Image Definition has one item in it - an [`ITEM_1BS_IMAGE_TYPE`]
106pub type ImageDef = Block<1>;
107
108/// A Block as understood by the Boot ROM.
109///
110/// This could be an Image Definition, or a Partition Table, or maybe some other
111/// kind of block.
112///
113/// It contains within the special start and end markers the Boot ROM is looking
114/// for.
115#[derive(Debug)]
116#[repr(C)]
117pub struct Block<const N: usize> {
118 marker_start: u32,
119 items: [u32; N],
120 length: u32,
121 offset: *const u32,
122 marker_end: u32,
123}
124
125unsafe impl<const N: usize> Sync for Block<N> {}
126
127impl<const N: usize> Block<N> {
128 /// Construct a new Binary Block, with the given items.
129 ///
130 /// The length, and the Start and End markers are added automatically. The
131 /// Block Loop pointer initially points to itself.
132 pub const fn new(items: [u32; N]) -> Block<N> {
133 Block {
134 marker_start: BLOCK_MARKER_START,
135 items,
136 length: item_last(N as u16),
137 // offset from this block to next block in loop. By default
138 // we form a Block Loop with a single Block in it.
139 offset: core::ptr::null(),
140 marker_end: BLOCK_MARKER_END,
141 }
142 }
143
144 /// Change the Block Loop offset value.
145 ///
146 /// This method isn't that useful because you can't evaluate the difference
147 /// between two pointers in a const context as the addresses aren't assigned
148 /// until long after the const evaluator has run.
149 ///
150 /// If you think you need this method, you might want to set a unique random
151 /// value here and swap it for the real offset as a post-processing step.
152 pub const fn with_offset(self, offset: *const u32) -> Block<N> {
153 Block { offset, ..self }
154 }
155}
156
157impl Block<0> {
158 /// Construct an empty block.
159 pub const fn empty() -> Block<0> {
160 Block::new([])
161 }
162
163 /// Make the block one word larger
164 pub const fn extend(self, word: u32) -> Block<1> {
165 Block::new([word])
166 }
167}
168
169impl Block<1> {
170 /// Make the block one word larger
171 pub const fn extend(self, word: u32) -> Block<2> {
172 Block::new([self.items[0], word])
173 }
174}
175
176impl Block<2> {
177 /// Make the block one word larger
178 pub const fn extend(self, word: u32) -> Block<3> {
179 Block::new([self.items[0], self.items[1], word])
180 }
181}
182
183impl ImageDef {
184 /// Construct a new IMAGE_DEF Block, for an EXE with the given security and
185 /// architecture.
186 pub const fn arch_exe(security: Security, architecture: Architecture) -> Self {
187 Self::new([item_image_type_exe(security, architecture)])
188 }
189
190 /// Construct a new IMAGE_DEF Block, for an EXE with the given security.
191 ///
192 /// The target architecture is taken from the current build target (i.e. Arm
193 /// or RISC-V).
194 pub const fn exe(security: Security) -> Self {
195 if cfg!(all(target_arch = "riscv32", target_os = "none")) {
196 Self::arch_exe(security, Architecture::Riscv)
197 } else {
198 Self::arch_exe(security, Architecture::Arm)
199 }
200 }
201
202 /// Construct a new IMAGE_DEF Block, for a Non-Secure EXE.
203 ///
204 /// The target architecture is taken from the current build target (i.e. Arm
205 /// or RISC-V).
206 pub const fn non_secure_exe() -> Self {
207 Self::exe(Security::NonSecure)
208 }
209
210 /// Construct a new IMAGE_DEF Block, for a Secure EXE.
211 ///
212 /// The target architecture is taken from the current build target (i.e. Arm
213 /// or RISC-V).
214 pub const fn secure_exe() -> Self {
215 Self::exe(Security::Secure)
216 }
217}
218
219/// We make our partition table this fixed size.
220pub const PARTITION_TABLE_MAX_ITEMS: usize = 128;
221
222/// Describes a unpartitioned space
223#[derive(Debug, Clone, PartialEq, Eq, Default)]
224pub struct UnpartitionedSpace {
225 permissions_and_location: u32,
226 permissions_and_flags: u32,
227}
228
229impl UnpartitionedSpace {
230 /// Create a new unpartitioned space.
231 ///
232 /// It defaults to no permissions.
233 pub const fn new() -> Self {
234 Self {
235 permissions_and_location: 0,
236 permissions_and_flags: 0,
237 }
238 }
239
240 /// Create a new unpartition space from run-time values.
241 ///
242 /// Get these from the ROM function `get_partition_table_info` with an argument of `PT_INFO`.
243 pub const fn from_raw(permissions_and_location: u32, permissions_and_flags: u32) -> Self {
244 Self {
245 permissions_and_location,
246 permissions_and_flags,
247 }
248 }
249
250 /// Add a permission
251 pub const fn with_permission(self, permission: Permission) -> Self {
252 Self {
253 permissions_and_flags: self.permissions_and_flags | permission as u32,
254 permissions_and_location: self.permissions_and_location | permission as u32,
255 }
256 }
257
258 /// Set a flag
259 pub const fn with_flag(self, flag: UnpartitionedFlag) -> Self {
260 Self {
261 permissions_and_flags: self.permissions_and_flags | flag as u32,
262 ..self
263 }
264 }
265
266 /// Get the partition start and end
267 ///
268 /// The offsets are in 4 KiB sectors, inclusive.
269 pub fn get_first_last_sectors(&self) -> (u16, u16) {
270 (
271 (self.permissions_and_location & 0x0000_1FFF) as u16,
272 ((self.permissions_and_location >> 13) & 0x0000_1FFF) as u16,
273 )
274 }
275
276 /// Get the partition start and end
277 ///
278 /// The offsets are in bytes, inclusive.
279 pub fn get_first_last_bytes(&self) -> (u32, u32) {
280 let (first, last) = self.get_first_last_sectors();
281 (u32::from(first) * 4096, (u32::from(last) * 4096) + 4095)
282 }
283
284 /// Check if it has a permission
285 pub fn has_permission(&self, permission: Permission) -> bool {
286 let mask = permission as u32;
287 (self.permissions_and_flags & mask) != 0
288 }
289
290 /// Check if the partition has a flag set
291 pub fn has_flag(&self, flag: UnpartitionedFlag) -> bool {
292 let mask = flag as u32;
293 (self.permissions_and_flags & mask) != 0
294 }
295}
296
297impl core::fmt::Display for UnpartitionedSpace {
298 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
299 let (first, last) = self.get_first_last_bytes();
300 write!(
301 f,
302 "{:#010x}..{:#010x} S:{}{} NS:{}{} B:{}{}",
303 first,
304 last,
305 if self.has_permission(Permission::SecureRead) {
306 'R'
307 } else {
308 '_'
309 },
310 if self.has_permission(Permission::SecureWrite) {
311 'W'
312 } else {
313 '_'
314 },
315 if self.has_permission(Permission::NonSecureRead) {
316 'R'
317 } else {
318 '_'
319 },
320 if self.has_permission(Permission::NonSecureWrite) {
321 'W'
322 } else {
323 '_'
324 },
325 if self.has_permission(Permission::BootRead) {
326 'R'
327 } else {
328 '_'
329 },
330 if self.has_permission(Permission::BootWrite) {
331 'W'
332 } else {
333 '_'
334 }
335 )
336 }
337}
338
339/// Describes a Partition
340#[derive(Debug, Clone, PartialEq, Eq)]
341pub struct Partition {
342 permissions_and_location: u32,
343 permissions_and_flags: u32,
344 id: Option<u64>,
345 extra_families: [u32; 4],
346 extra_families_len: usize,
347 name: [u8; 128],
348}
349
350impl Partition {
351 const FLAGS_HAS_ID: u32 = 0b1;
352 const FLAGS_LINK_TYPE_A_PARTITION: u32 = 0b01 << 1;
353 const FLAGS_LINK_TYPE_OWNER: u32 = 0b10 << 1;
354 const FLAGS_LINK_MASK: u32 = 0b111111 << 1;
355 const FLAGS_HAS_NAME: u32 = 0b1 << 12;
356 const FLAGS_HAS_EXTRA_FAMILIES_SHIFT: u8 = 7;
357 const FLAGS_HAS_EXTRA_FAMILIES_MASK: u32 = 0b11 << Self::FLAGS_HAS_EXTRA_FAMILIES_SHIFT;
358
359 /// Create a new partition, with the given start and end sectors.
360 ///
361 /// It defaults to no permissions.
362 pub const fn new(first_sector: u16, last_sector: u16) -> Self {
363 // 0x2000 sectors of 4 KiB is 32 MiB, which is the total XIP area
364 core::assert!(first_sector < 0x2000);
365 core::assert!(last_sector < 0x2000);
366 core::assert!(first_sector <= last_sector);
367 Self {
368 permissions_and_location: (last_sector as u32) << 13 | first_sector as u32,
369 permissions_and_flags: 0,
370 id: None,
371 extra_families: [0; 4],
372 extra_families_len: 0,
373 name: [0; 128],
374 }
375 }
376
377 /// Create a new partition from run-time values.
378 ///
379 /// Get these from the ROM function `get_partition_table_info` with an argument of `PARTITION_LOCATION_AND_FLAGS`.
380 pub const fn from_raw(permissions_and_location: u32, permissions_and_flags: u32) -> Self {
381 Self {
382 permissions_and_location,
383 permissions_and_flags,
384 id: None,
385 extra_families: [0; 4],
386 extra_families_len: 0,
387 name: [0; 128],
388 }
389 }
390
391 /// Add a permission
392 pub const fn with_permission(self, permission: Permission) -> Self {
393 Self {
394 permissions_and_location: self.permissions_and_location | permission as u32,
395 permissions_and_flags: self.permissions_and_flags | permission as u32,
396 ..self
397 }
398 }
399
400 /// Set the name of the partition
401 pub const fn with_name(self, name: &str) -> Self {
402 let mut new_name = [0u8; 128];
403 let name = name.as_bytes();
404 let mut idx = 0;
405 new_name[0] = name.len() as u8;
406 while idx < name.len() {
407 new_name[idx + 1] = name[idx];
408 idx += 1;
409 }
410 Self {
411 name: new_name,
412 permissions_and_flags: self.permissions_and_flags | Self::FLAGS_HAS_NAME,
413 ..self
414 }
415 }
416
417 /// Set the extra families for the partition.
418 ///
419 /// You can supply up to four.
420 pub const fn with_extra_families(self, extra_families: &[u32]) -> Self {
421 core::assert!(extra_families.len() <= 4);
422 let mut new_extra_families = [0u32; 4];
423 let mut idx = 0;
424 while idx < extra_families.len() {
425 new_extra_families[idx] = extra_families[idx];
426 idx += 1;
427 }
428 Self {
429 extra_families: new_extra_families,
430 extra_families_len: extra_families.len(),
431 permissions_and_flags: (self.permissions_and_flags & !Self::FLAGS_HAS_EXTRA_FAMILIES_MASK)
432 | (extra_families.len() as u32) << Self::FLAGS_HAS_EXTRA_FAMILIES_SHIFT,
433 ..self
434 }
435 }
436
437 /// Set the ID
438 pub const fn with_id(self, id: u64) -> Self {
439 Self {
440 id: Some(id),
441 permissions_and_flags: self.permissions_and_flags | Self::FLAGS_HAS_ID,
442 ..self
443 }
444 }
445
446 /// Add a link
447 pub const fn with_link(self, link: Link) -> Self {
448 let mut new_flags = self.permissions_and_flags & !Self::FLAGS_LINK_MASK;
449 match link {
450 Link::Nothing => {}
451 Link::ToA { partition_idx } => {
452 core::assert!(partition_idx < 16);
453 new_flags |= Self::FLAGS_LINK_TYPE_A_PARTITION;
454 new_flags |= (partition_idx as u32) << 3;
455 }
456 Link::ToOwner { partition_idx } => {
457 core::assert!(partition_idx < 16);
458 new_flags |= Self::FLAGS_LINK_TYPE_OWNER;
459 new_flags |= (partition_idx as u32) << 3;
460 }
461 }
462 Self {
463 permissions_and_flags: new_flags,
464 ..self
465 }
466 }
467
468 /// Set a flag
469 pub const fn with_flag(self, flag: PartitionFlag) -> Self {
470 Self {
471 permissions_and_flags: self.permissions_and_flags | flag as u32,
472 ..self
473 }
474 }
475
476 /// Get the partition start and end
477 ///
478 /// The offsets are in 4 KiB sectors, inclusive.
479 pub fn get_first_last_sectors(&self) -> (u16, u16) {
480 (
481 (self.permissions_and_location & 0x0000_1FFF) as u16,
482 ((self.permissions_and_location >> 13) & 0x0000_1FFF) as u16,
483 )
484 }
485
486 /// Get the partition start and end
487 ///
488 /// The offsets are in bytes, inclusive.
489 pub fn get_first_last_bytes(&self) -> (u32, u32) {
490 let (first, last) = self.get_first_last_sectors();
491 (u32::from(first) * 4096, (u32::from(last) * 4096) + 4095)
492 }
493
494 /// Check if it has a permission
495 pub fn has_permission(&self, permission: Permission) -> bool {
496 let mask = permission as u32;
497 (self.permissions_and_flags & mask) != 0
498 }
499
500 /// Get which extra families are allowed in this partition
501 pub fn get_extra_families(&self) -> &[u32] {
502 &self.extra_families[0..self.extra_families_len]
503 }
504
505 /// Get the name of the partition
506 ///
507 /// Returns `None` if there's no name, or the name is not valid UTF-8.
508 pub fn get_name(&self) -> Option<&str> {
509 let len = self.name[0] as usize;
510 if len == 0 {
511 None
512 } else {
513 core::str::from_utf8(&self.name[1..=len]).ok()
514 }
515 }
516
517 /// Get the ID
518 pub fn get_id(&self) -> Option<u64> {
519 self.id
520 }
521
522 /// Check if this partition is linked
523 pub fn get_link(&self) -> Link {
524 if (self.permissions_and_flags & Self::FLAGS_LINK_TYPE_A_PARTITION) != 0 {
525 let partition_idx = ((self.permissions_and_flags >> 3) & 0x0F) as u8;
526 Link::ToA { partition_idx }
527 } else if (self.permissions_and_flags & Self::FLAGS_LINK_TYPE_OWNER) != 0 {
528 let partition_idx = ((self.permissions_and_flags >> 3) & 0x0F) as u8;
529 Link::ToOwner { partition_idx }
530 } else {
531 Link::Nothing
532 }
533 }
534
535 /// Check if the partition has a flag set
536 pub fn has_flag(&self, flag: PartitionFlag) -> bool {
537 let mask = flag as u32;
538 (self.permissions_and_flags & mask) != 0
539 }
540}
541
542impl core::fmt::Display for Partition {
543 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
544 let (first, last) = self.get_first_last_bytes();
545 write!(
546 f,
547 "{:#010x}..{:#010x} S:{}{} NS:{}{} B:{}{}",
548 first,
549 last,
550 if self.has_permission(Permission::SecureRead) {
551 'R'
552 } else {
553 '_'
554 },
555 if self.has_permission(Permission::SecureWrite) {
556 'W'
557 } else {
558 '_'
559 },
560 if self.has_permission(Permission::NonSecureRead) {
561 'R'
562 } else {
563 '_'
564 },
565 if self.has_permission(Permission::NonSecureWrite) {
566 'W'
567 } else {
568 '_'
569 },
570 if self.has_permission(Permission::BootRead) {
571 'R'
572 } else {
573 '_'
574 },
575 if self.has_permission(Permission::BootWrite) {
576 'W'
577 } else {
578 '_'
579 }
580 )
581 }
582}
583
584/// Describes a partition table.
585///
586/// Don't store this as a static - make sure you convert it to a block.
587#[derive(Clone)]
588pub struct PartitionTableBlock {
589 /// This must look like a block, including the 1 word header and the 3 word footer.
590 contents: [u32; PARTITION_TABLE_MAX_ITEMS],
591 /// This value doesn't include the 1 word header or the 3 word footer
592 num_items: usize,
593}
594
595impl PartitionTableBlock {
596 /// Create an empty Block, big enough for a partition table.
597 ///
598 /// At a minimum you need to call [`Self::add_partition_item`].
599 pub const fn new() -> PartitionTableBlock {
600 let mut contents = [0; PARTITION_TABLE_MAX_ITEMS];
601 contents[0] = BLOCK_MARKER_START;
602 contents[1] = item_last(0);
603 contents[2] = 0;
604 contents[3] = BLOCK_MARKER_END;
605 PartitionTableBlock { contents, num_items: 0 }
606 }
607
608 /// Add a partition to the partition table
609 pub const fn add_partition_item(self, unpartitioned: UnpartitionedSpace, partitions: &[Partition]) -> Self {
610 let mut new_table = PartitionTableBlock::new();
611 let mut idx = 0;
612 // copy over old table, with the header but not the footer
613 while idx < self.num_items + 1 {
614 new_table.contents[idx] = self.contents[idx];
615 idx += 1;
616 }
617
618 // 1. add item header space (we fill this in later)
619 let header_idx = idx;
620 new_table.contents[idx] = 0;
621 idx += 1;
622
623 // 2. unpartitioned space flags
624 //
625 // (the location of unpartition space is not recorded here - it is
626 // inferred because the unpartitioned space is where the partitions are
627 // not)
628 new_table.contents[idx] = unpartitioned.permissions_and_flags;
629 idx += 1;
630
631 // 3. partition info
632
633 let mut partition_no = 0;
634 while partition_no < partitions.len() {
635 // a. permissions_and_location (4K units)
636 new_table.contents[idx] = partitions[partition_no].permissions_and_location;
637 idx += 1;
638
639 // b. permissions_and_flags
640 new_table.contents[idx] = partitions[partition_no].permissions_and_flags;
641 idx += 1;
642
643 // c. ID
644 if let Some(id) = partitions[partition_no].id {
645 new_table.contents[idx] = id as u32;
646 new_table.contents[idx + 1] = (id >> 32) as u32;
647 idx += 2;
648 }
649
650 // d. Extra Families
651 let mut extra_families_idx = 0;
652 while extra_families_idx < partitions[partition_no].extra_families_len {
653 new_table.contents[idx] = partitions[partition_no].extra_families[extra_families_idx];
654 idx += 1;
655 extra_families_idx += 1;
656 }
657
658 // e. Name
659 let mut name_idx = 0;
660 while name_idx < partitions[partition_no].name[0] as usize {
661 let name_chunk = [
662 partitions[partition_no].name[name_idx],
663 partitions[partition_no].name[name_idx + 1],
664 partitions[partition_no].name[name_idx + 2],
665 partitions[partition_no].name[name_idx + 3],
666 ];
667 new_table.contents[idx] = u32::from_le_bytes(name_chunk);
668 name_idx += 4;
669 idx += 1;
670 }
671
672 partition_no += 1;
673 }
674
675 let len = idx - header_idx;
676 new_table.contents[header_idx] = item_generic_2bs(partitions.len() as u8, len as u16, ITEM_2BS_PARTITION_TABLE);
677
678 // 7. New Footer
679 new_table.contents[idx] = item_last(idx as u16 - 1);
680 new_table.contents[idx + 1] = 0;
681 new_table.contents[idx + 2] = BLOCK_MARKER_END;
682
683 // ignore the header
684 new_table.num_items = idx - 1;
685 new_table
686 }
687
688 /// Add a version number to the partition table
689 pub const fn with_version(self, major: u16, minor: u16) -> Self {
690 let mut new_table = PartitionTableBlock::new();
691 let mut idx = 0;
692 // copy over old table, with the header but not the footer
693 while idx < self.num_items + 1 {
694 new_table.contents[idx] = self.contents[idx];
695 idx += 1;
696 }
697
698 // 1. add item
699 new_table.contents[idx] = item_generic_2bs(0, 2, ITEM_1BS_VERSION);
700 idx += 1;
701 new_table.contents[idx] = (major as u32) << 16 | minor as u32;
702 idx += 1;
703
704 // 2. New Footer
705 new_table.contents[idx] = item_last(idx as u16 - 1);
706 new_table.contents[idx + 1] = 0;
707 new_table.contents[idx + 2] = BLOCK_MARKER_END;
708
709 // ignore the header
710 new_table.num_items = idx - 1;
711 new_table
712 }
713
714 /// Add a a SHA256 hash of the Block
715 ///
716 /// Adds a `HASH_DEF` covering all the previous items in the Block, and a
717 /// `HASH_VALUE` with a SHA-256 hash of them.
718 pub const fn with_sha256(self) -> Self {
719 let mut new_table = PartitionTableBlock::new();
720 let mut idx = 0;
721 // copy over old table, with the header but not the footer
722 while idx < self.num_items + 1 {
723 new_table.contents[idx] = self.contents[idx];
724 idx += 1;
725 }
726
727 // 1. HASH_DEF says what is hashed
728 new_table.contents[idx] = item_generic_2bs(1, 2, ITEM_2BS_HASH_DEF);
729 idx += 1;
730 // we're hashing all the previous contents - including this line.
731 new_table.contents[idx] = (idx + 1) as u32;
732 idx += 1;
733
734 // calculate hash over prior contents
735 let input = unsafe { core::slice::from_raw_parts(new_table.contents.as_ptr() as *const u8, idx * 4) };
736 let hash: [u8; 32] = sha2_const_stable::Sha256::new().update(input).finalize();
737
738 // 2. HASH_VALUE contains the hash
739 new_table.contents[idx] = item_generic_2bs(0, 9, ITEM_1BS_HASH_VALUE);
740 idx += 1;
741
742 let mut hash_idx = 0;
743 while hash_idx < hash.len() {
744 new_table.contents[idx] = u32::from_le_bytes([
745 hash[hash_idx],
746 hash[hash_idx + 1],
747 hash[hash_idx + 2],
748 hash[hash_idx + 3],
749 ]);
750 idx += 1;
751 hash_idx += 4;
752 }
753
754 // 3. New Footer
755 new_table.contents[idx] = item_last(idx as u16 - 1);
756 new_table.contents[idx + 1] = 0;
757 new_table.contents[idx + 2] = BLOCK_MARKER_END;
758
759 // ignore the header
760 new_table.num_items = idx - 1;
761 new_table
762 }
763}
764
765impl Default for PartitionTableBlock {
766 fn default() -> Self {
767 Self::new()
768 }
769}
770
771/// Flags that a Partition can have
772#[derive(Debug, Copy, Clone, PartialEq, Eq)]
773#[repr(u32)]
774#[allow(missing_docs)]
775pub enum PartitionFlag {
776 NotBootableArm = 1 << 9,
777 NotBootableRiscv = 1 << 10,
778 Uf2DownloadAbNonBootableOwnerAffinity = 1 << 11,
779 Uf2DownloadNoReboot = 1 << 13,
780 AcceptsDefaultFamilyRp2040 = 1 << 14,
781 AcceptsDefaultFamilyData = 1 << 16,
782 AcceptsDefaultFamilyRp2350ArmS = 1 << 17,
783 AcceptsDefaultFamilyRp2350Riscv = 1 << 18,
784 AcceptsDefaultFamilyRp2350ArmNs = 1 << 19,
785}
786
787/// Flags that a Partition can have
788#[derive(Debug, Copy, Clone, PartialEq, Eq)]
789#[repr(u32)]
790#[allow(missing_docs)]
791pub enum UnpartitionedFlag {
792 Uf2DownloadNoReboot = 1 << 13,
793 AcceptsDefaultFamilyRp2040 = 1 << 14,
794 AcceptsDefaultFamilyAbsolute = 1 << 15,
795 AcceptsDefaultFamilyData = 1 << 16,
796 AcceptsDefaultFamilyRp2350ArmS = 1 << 17,
797 AcceptsDefaultFamilyRp2350Riscv = 1 << 18,
798 AcceptsDefaultFamilyRp2350ArmNs = 1 << 19,
799}
800
801/// Kinds of linked partition
802#[derive(Debug, Copy, Clone, PartialEq, Eq)]
803pub enum Link {
804 /// Not linked to anything
805 Nothing,
806 /// This is a B partition - link to our A partition.
807 ToA {
808 /// The index of our matching A partition.
809 partition_idx: u8,
810 },
811 /// Link to the partition that owns this one.
812 ToOwner {
813 /// The idx of our owner
814 partition_idx: u8,
815 },
816}
817
818/// Permissions that a Partition can have
819#[derive(Debug, Copy, Clone, PartialEq, Eq)]
820#[repr(u32)]
821pub enum Permission {
822 /// Can be read in Secure Mode
823 ///
824 /// Corresponds to `PERMISSION_S_R_BITS` in the Pico SDK
825 SecureRead = 1 << 26,
826 /// Can be written in Secure Mode
827 ///
828 /// Corresponds to `PERMISSION_S_W_BITS` in the Pico SDK
829 SecureWrite = 1 << 27,
830 /// Can be read in Non-Secure Mode
831 ///
832 /// Corresponds to `PERMISSION_NS_R_BITS` in the Pico SDK
833 NonSecureRead = 1 << 28,
834 /// Can be written in Non-Secure Mode
835 ///
836 /// Corresponds to `PERMISSION_NS_W_BITS` in the Pico SDK
837 NonSecureWrite = 1 << 29,
838 /// Can be read in Non-Secure Bootloader mode
839 ///
840 /// Corresponds to `PERMISSION_NSBOOT_R_BITS` in the Pico SDK
841 BootRead = 1 << 30,
842 /// Can be written in Non-Secure Bootloader mode
843 ///
844 /// Corresponds to `PERMISSION_NSBOOT_W_BITS` in the Pico SDK
845 BootWrite = 1 << 31,
846}
847
848impl Permission {
849 /// Is this permission bit set this in this bitmask?
850 pub const fn is_in(self, mask: u32) -> bool {
851 (mask & (self as u32)) != 0
852 }
853}
854
855/// The supported RP2350 CPU architectures
856#[derive(Debug, Copy, Clone, PartialEq, Eq)]
857pub enum Architecture {
858 /// Core is in Arm Cortex-M33 mode
859 Arm,
860 /// Core is in RISC-V / Hazard3 mode
861 Riscv,
862}
863
864/// The kinds of Secure Boot we support
865#[derive(Debug, Copy, Clone)]
866pub enum Security {
867 /// Security mode not given
868 Unspecified,
869 /// Start in Non-Secure mode
870 NonSecure,
871 /// Start in Secure mode
872 Secure,
873}
874
875/// Make an item containing a tag, 1 byte length and two extra bytes.
876///
877/// The `command` arg should contain `1BS`
878pub const fn item_generic_1bs(value: u16, length: u8, command: u8) -> u32 {
879 ((value as u32) << 16) | ((length as u32) << 8) | (command as u32)
880}
881
882/// Make an item containing a tag, 2 byte length and one extra byte.
883///
884/// The `command` arg should contain `2BS`
885pub const fn item_generic_2bs(value: u8, length: u16, command: u8) -> u32 {
886 ((value as u32) << 24) | ((length as u32) << 8) | (command as u32)
887}
888
889/// Create Image Type item, of type IGNORED.
890pub const fn item_ignored() -> u32 {
891 item_generic_2bs(0, 1, ITEM_2BS_IGNORED)
892}
893
894/// Create Image Type item, of type INVALID.
895pub const fn item_image_type_invalid() -> u32 {
896 let value = IMAGE_TYPE_INVALID;
897 item_generic_1bs(value, 1, ITEM_1BS_IMAGE_TYPE)
898}
899
900/// Create Image Type item, of type DATA.
901pub const fn item_image_type_data() -> u32 {
902 let value = IMAGE_TYPE_DATA;
903 item_generic_1bs(value, 1, ITEM_1BS_IMAGE_TYPE)
904}
905
906/// Create Image Type item, of type EXE.
907pub const fn item_image_type_exe(security: Security, arch: Architecture) -> u32 {
908 let mut value = IMAGE_TYPE_EXE | IMAGE_TYPE_EXE_CHIP_RP2350;
909
910 match arch {
911 Architecture::Arm => {
912 value |= IMAGE_TYPE_EXE_CPU_ARM;
913 }
914 Architecture::Riscv => {
915 value |= IMAGE_TYPE_EXE_CPU_RISCV;
916 }
917 }
918
919 match security {
920 Security::Unspecified => value |= IMAGE_TYPE_EXE_TYPE_SECURITY_UNSPECIFIED,
921 Security::NonSecure => value |= IMAGE_TYPE_EXE_TYPE_SECURITY_NS,
922 Security::Secure => value |= IMAGE_TYPE_EXE_TYPE_SECURITY_S,
923 }
924
925 item_generic_1bs(value, 1, ITEM_1BS_IMAGE_TYPE)
926}
927
928/// Create a Block Last item.
929pub const fn item_last(length: u16) -> u32 {
930 item_generic_2bs(0, length, ITEM_2BS_LAST)
931}
932
933/// Create a Vector Table item.
934///
935/// This is only allowed on Arm systems.
936pub const fn item_vector_table(table_ptr: u32) -> [u32; 2] {
937 [item_generic_1bs(0, 2, ITEM_1BS_VECTOR_TABLE), table_ptr]
938}
939
940/// Create an Entry Point item.
941pub const fn item_entry_point(entry_point: u32, initial_sp: u32) -> [u32; 3] {
942 [item_generic_1bs(0, 3, ITEM_1BS_ENTRY_POINT), entry_point, initial_sp]
943}
944
945/// Create an Rolling Window item.
946///
947/// The delta is the number of bytes into the image that 0x10000000 should
948/// be mapped.
949pub const fn item_rolling_window(delta: u32) -> [u32; 2] {
950 [item_generic_1bs(0, 3, ITEM_1BS_ROLLING_WINDOW_DELTA), delta]
951}
952
953#[cfg(test)]
954mod test {
955 use super::*;
956
957 /// I used this JSON, with `picotool partition create`:
958 ///
959 /// ```json
960 /// {
961 /// "version": [1, 0],
962 /// "unpartitioned": {
963 /// "families": ["absolute"],
964 /// "permissions": {
965 /// "secure": "rw",
966 /// "nonsecure": "rw",
967 /// "bootloader": "rw"
968 /// }
969 /// },
970 /// "partitions": [
971 /// {
972 /// "name": "A",
973 /// "id": 0,
974 /// "size": "2044K",
975 /// "families": ["rp2350-arm-s", "rp2350-riscv"],
976 /// "permissions": {
977 /// "secure": "rw",
978 /// "nonsecure": "rw",
979 /// "bootloader": "rw"
980 /// }
981 /// },
982 /// {
983 /// "name": "B",
984 /// "id": 1,
985 /// "size": "2044K",
986 /// "families": ["rp2350-arm-s", "rp2350-riscv"],
987 /// "permissions": {
988 /// "secure": "rw",
989 /// "nonsecure": "rw",
990 /// "bootloader": "rw"
991 /// },
992 /// "link": ["a", 0]
993 /// }
994 /// ]
995 /// }
996 /// ```
997 #[test]
998 fn make_hashed_partition_table() {
999 let table = PartitionTableBlock::new()
1000 .add_partition_item(
1001 UnpartitionedSpace::new()
1002 .with_permission(Permission::SecureRead)
1003 .with_permission(Permission::SecureWrite)
1004 .with_permission(Permission::NonSecureRead)
1005 .with_permission(Permission::NonSecureWrite)
1006 .with_permission(Permission::BootRead)
1007 .with_permission(Permission::BootWrite)
1008 .with_flag(UnpartitionedFlag::AcceptsDefaultFamilyAbsolute),
1009 &[
1010 Partition::new(2, 512)
1011 .with_id(0)
1012 .with_flag(PartitionFlag::AcceptsDefaultFamilyRp2350ArmS)
1013 .with_flag(PartitionFlag::AcceptsDefaultFamilyRp2350Riscv)
1014 .with_permission(Permission::SecureRead)
1015 .with_permission(Permission::SecureWrite)
1016 .with_permission(Permission::NonSecureRead)
1017 .with_permission(Permission::NonSecureWrite)
1018 .with_permission(Permission::BootRead)
1019 .with_permission(Permission::BootWrite)
1020 .with_name("A"),
1021 Partition::new(513, 1023)
1022 .with_id(1)
1023 .with_flag(PartitionFlag::AcceptsDefaultFamilyRp2350ArmS)
1024 .with_flag(PartitionFlag::AcceptsDefaultFamilyRp2350Riscv)
1025 .with_link(Link::ToA { partition_idx: 0 })
1026 .with_permission(Permission::SecureRead)
1027 .with_permission(Permission::SecureWrite)
1028 .with_permission(Permission::NonSecureRead)
1029 .with_permission(Permission::NonSecureWrite)
1030 .with_permission(Permission::BootRead)
1031 .with_permission(Permission::BootWrite)
1032 .with_name("B"),
1033 ],
1034 )
1035 .with_version(1, 0)
1036 .with_sha256();
1037 let expected = &[
1038 0xffffded3, // start
1039 0x02000c0a, // Item = PARTITION_TABLE
1040 0xfc008000, // Unpartitioned Space - permissions_and_flags
1041 0xfc400002, // Partition 0 - permissions_and_location (512 * 4096, 2 * 4096)
1042 0xfc061001, // permissions_and_flags HAS_ID | HAS_NAME | ARM-S | RISC-V
1043 0x00000000, // ID
1044 0x00000000, // ID
1045 0x00004101, // Name ("A")
1046 0xfc7fe201, // Partition 1 - permissions_and_location (1023 * 4096, 513 * 4096)
1047 0xfc061003, // permissions_and_flags LINKA(0) | HAS_ID | HAS_NAME | ARM-S | RISC-V
1048 0x00000001, // ID
1049 0x00000000, // ID
1050 0x00004201, // Name ("B")
1051 0x00000248, // Item = Version
1052 0x00010000, // 0, 1
1053 0x01000247, // HASH_DEF with 2 words, and SHA256 hash
1054 0x00000011, // 17 words hashed
1055 0x0000094b, // HASH_VALUE with 9 words
1056 0x1945cdad, // Hash word 0
1057 0x6b5f9773, // Hash word 1
1058 0xe2bf39bd, // Hash word 2
1059 0xb243e599, // Hash word 3
1060 0xab2f0e9a, // Hash word 4
1061 0x4d5d6d0b, // Hash word 5
1062 0xf973050f, // Hash word 6
1063 0x5ab6dadb, // Hash word 7
1064 0x000019ff, // Last Item
1065 0x00000000, // Block Loop Next Offset
1066 0xab123579, // End
1067 ];
1068 core::assert_eq!(
1069 &table.contents[..29],
1070 expected,
1071 "{:#010x?}\n != \n{:#010x?}",
1072 &table.contents[0..29],
1073 expected,
1074 );
1075 }
1076}
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 @@
1//! Clock configuration for the RP2040 1//! Clock configuration for the RP2040
2
3#[cfg(feature = "rp2040")]
2use core::arch::asm; 4use core::arch::asm;
3use core::marker::PhantomData; 5use core::marker::PhantomData;
4use core::sync::atomic::{AtomicU16, AtomicU32, Ordering}; 6#[cfg(feature = "rp2040")]
7use core::sync::atomic::AtomicU16;
8use core::sync::atomic::{AtomicU32, Ordering};
5 9
6use embassy_hal_internal::{into_ref, PeripheralRef}; 10use embassy_hal_internal::{into_ref, PeripheralRef};
7use pac::clocks::vals::*; 11use pac::clocks::vals::*;
8 12
9use crate::gpio::{AnyPin, SealedPin}; 13use crate::gpio::{AnyPin, SealedPin};
14#[cfg(feature = "rp2040")]
10use crate::pac::common::{Reg, RW}; 15use crate::pac::common::{Reg, RW};
11use crate::{pac, reset, Peripheral}; 16use crate::{pac, reset, Peripheral};
12 17
@@ -26,6 +31,7 @@ struct Clocks {
26 // gpin1: AtomicU32, 31 // gpin1: AtomicU32,
27 rosc: AtomicU32, 32 rosc: AtomicU32,
28 peri: AtomicU32, 33 peri: AtomicU32,
34 #[cfg(feature = "rp2040")]
29 rtc: AtomicU16, 35 rtc: AtomicU16,
30} 36}
31 37
@@ -41,6 +47,7 @@ static CLOCKS: Clocks = Clocks {
41 // gpin1: AtomicU32::new(0), 47 // gpin1: AtomicU32::new(0),
42 rosc: AtomicU32::new(0), 48 rosc: AtomicU32::new(0),
43 peri: AtomicU32::new(0), 49 peri: AtomicU32::new(0),
50 #[cfg(feature = "rp2040")]
44 rtc: AtomicU16::new(0), 51 rtc: AtomicU16::new(0),
45}; 52};
46 53
@@ -81,6 +88,7 @@ pub struct ClockConfig {
81 /// ADC clock configuration. 88 /// ADC clock configuration.
82 pub adc_clk: Option<AdcClkConfig>, 89 pub adc_clk: Option<AdcClkConfig>,
83 /// RTC clock configuration. 90 /// RTC clock configuration.
91 #[cfg(feature = "rp2040")]
84 pub rtc_clk: Option<RtcClkConfig>, 92 pub rtc_clk: Option<RtcClkConfig>,
85 // gpin0: Option<(u32, Gpin<'static, AnyPin>)>, 93 // gpin0: Option<(u32, Gpin<'static, AnyPin>)>,
86 // gpin1: Option<(u32, Gpin<'static, AnyPin>)>, 94 // gpin1: Option<(u32, Gpin<'static, AnyPin>)>,
@@ -135,6 +143,7 @@ impl ClockConfig {
135 phase: 0, 143 phase: 0,
136 }), 144 }),
137 // CLK RTC = PLL USB (48MHz) / 1024 = 46875Hz 145 // CLK RTC = PLL USB (48MHz) / 1024 = 46875Hz
146 #[cfg(feature = "rp2040")]
138 rtc_clk: Some(RtcClkConfig { 147 rtc_clk: Some(RtcClkConfig {
139 src: RtcClkSrc::PllUsb, 148 src: RtcClkSrc::PllUsb,
140 div_int: 1024, 149 div_int: 1024,
@@ -174,6 +183,7 @@ impl ClockConfig {
174 phase: 0, 183 phase: 0,
175 }), 184 }),
176 // CLK RTC = ROSC (140MHz) / 2986.667969 ≅ 46875Hz 185 // CLK RTC = ROSC (140MHz) / 2986.667969 ≅ 46875Hz
186 #[cfg(feature = "rp2040")]
177 rtc_clk: Some(RtcClkConfig { 187 rtc_clk: Some(RtcClkConfig {
178 src: RtcClkSrc::Rosc, 188 src: RtcClkSrc::Rosc,
179 div_int: 2986, 189 div_int: 2986,
@@ -295,9 +305,17 @@ pub struct SysClkConfig {
295 /// SYS clock source. 305 /// SYS clock source.
296 pub src: SysClkSrc, 306 pub src: SysClkSrc,
297 /// SYS clock divider. 307 /// SYS clock divider.
308 #[cfg(feature = "rp2040")]
298 pub div_int: u32, 309 pub div_int: u32,
299 /// SYS clock fraction. 310 /// SYS clock fraction.
311 #[cfg(feature = "rp2040")]
300 pub div_frac: u8, 312 pub div_frac: u8,
313 /// SYS clock divider.
314 #[cfg(feature = "rp235x")]
315 pub div_int: u16,
316 /// SYS clock fraction.
317 #[cfg(feature = "rp235x")]
318 pub div_frac: u16,
301} 319}
302 320
303/// USB clock source. 321/// USB clock source.
@@ -358,6 +376,7 @@ pub struct AdcClkConfig {
358#[repr(u8)] 376#[repr(u8)]
359#[non_exhaustive] 377#[non_exhaustive]
360#[derive(Clone, Copy, Debug, PartialEq, Eq)] 378#[derive(Clone, Copy, Debug, PartialEq, Eq)]
379#[cfg(feature = "rp2040")]
361pub enum RtcClkSrc { 380pub enum RtcClkSrc {
362 /// PLL USB. 381 /// PLL USB.
363 PllUsb = ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB as _, 382 PllUsb = ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB as _,
@@ -372,6 +391,7 @@ pub enum RtcClkSrc {
372} 391}
373 392
374/// RTC clock config. 393/// RTC clock config.
394#[cfg(feature = "rp2040")]
375pub struct RtcClkConfig { 395pub struct RtcClkConfig {
376 /// RTC clock source. 396 /// RTC clock source.
377 pub src: RtcClkSrc, 397 pub src: RtcClkSrc,
@@ -396,10 +416,9 @@ pub(crate) unsafe fn init(config: ClockConfig) {
396 peris.set_pads_qspi(false); 416 peris.set_pads_qspi(false);
397 peris.set_pll_sys(false); 417 peris.set_pll_sys(false);
398 peris.set_pll_usb(false); 418 peris.set_pll_usb(false);
399 // TODO investigate if usb should be unreset here
400 peris.set_usbctrl(false); 419 peris.set_usbctrl(false);
401 peris.set_syscfg(false); 420 peris.set_syscfg(false);
402 peris.set_rtc(false); 421 //peris.set_rtc(false);
403 reset::reset(peris); 422 reset::reset(peris);
404 423
405 // Disable resus that may be enabled from previous software 424 // Disable resus that may be enabled from previous software
@@ -409,9 +428,15 @@ pub(crate) unsafe fn init(config: ClockConfig) {
409 428
410 // Before we touch PLLs, switch sys and ref cleanly away from their aux sources. 429 // Before we touch PLLs, switch sys and ref cleanly away from their aux sources.
411 c.clk_sys_ctrl().modify(|w| w.set_src(ClkSysCtrlSrc::CLK_REF)); 430 c.clk_sys_ctrl().modify(|w| w.set_src(ClkSysCtrlSrc::CLK_REF));
431 #[cfg(feature = "rp2040")]
412 while c.clk_sys_selected().read() != 1 {} 432 while c.clk_sys_selected().read() != 1 {}
433 #[cfg(feature = "rp235x")]
434 while c.clk_sys_selected().read() != pac::clocks::regs::ClkSysSelected(1) {}
413 c.clk_ref_ctrl().modify(|w| w.set_src(ClkRefCtrlSrc::ROSC_CLKSRC_PH)); 435 c.clk_ref_ctrl().modify(|w| w.set_src(ClkRefCtrlSrc::ROSC_CLKSRC_PH));
436 #[cfg(feature = "rp2040")]
414 while c.clk_ref_selected().read() != 1 {} 437 while c.clk_ref_selected().read() != 1 {}
438 #[cfg(feature = "rp235x")]
439 while c.clk_ref_selected().read() != pac::clocks::regs::ClkRefSelected(1) {}
415 440
416 // Reset the PLLs 441 // Reset the PLLs
417 let mut peris = reset::Peripherals(0); 442 let mut peris = reset::Peripherals(0);
@@ -479,11 +504,16 @@ pub(crate) unsafe fn init(config: ClockConfig) {
479 w.set_src(ref_src); 504 w.set_src(ref_src);
480 w.set_auxsrc(ref_aux); 505 w.set_auxsrc(ref_aux);
481 }); 506 });
482 while c.clk_ref_selected().read() != 1 << ref_src as u32 {} 507 #[cfg(feature = "rp2040")]
508 while c.clk_ref_selected().read() != (1 << ref_src as u32) {}
509 #[cfg(feature = "rp235x")]
510 while c.clk_ref_selected().read() != pac::clocks::regs::ClkRefSelected(1 << ref_src as u32) {}
483 c.clk_ref_div().write(|w| { 511 c.clk_ref_div().write(|w| {
484 w.set_int(config.ref_clk.div); 512 w.set_int(config.ref_clk.div);
485 }); 513 });
486 514
515 // Configure tick generation on the 2040. On the 2350 the timers are driven from the sysclk.
516 #[cfg(feature = "rp2040")]
487 pac::WATCHDOG.tick().write(|w| { 517 pac::WATCHDOG.tick().write(|w| {
488 w.set_cycles((clk_ref_freq / 1_000_000) as u16); 518 w.set_cycles((clk_ref_freq / 1_000_000) as u16);
489 w.set_enable(true); 519 w.set_enable(true);
@@ -500,7 +530,6 @@ pub(crate) unsafe fn init(config: ClockConfig) {
500 // SysClkSrc::Gpin0 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN0, gpin0_freq), 530 // SysClkSrc::Gpin0 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN0, gpin0_freq),
501 // SysClkSrc::Gpin1 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN1, gpin1_freq), 531 // SysClkSrc::Gpin1 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN1, gpin1_freq),
502 }; 532 };
503 assert!(config.sys_clk.div_int <= 0x1000000);
504 let div = config.sys_clk.div_int as u64 * 256 + config.sys_clk.div_frac as u64; 533 let div = config.sys_clk.div_int as u64 * 256 + config.sys_clk.div_frac as u64;
505 (src, aux, ((freq as u64 * 256) / div) as u32) 534 (src, aux, ((freq as u64 * 256) / div) as u32)
506 }; 535 };
@@ -508,13 +537,21 @@ pub(crate) unsafe fn init(config: ClockConfig) {
508 CLOCKS.sys.store(clk_sys_freq, Ordering::Relaxed); 537 CLOCKS.sys.store(clk_sys_freq, Ordering::Relaxed);
509 if sys_src != ClkSysCtrlSrc::CLK_REF { 538 if sys_src != ClkSysCtrlSrc::CLK_REF {
510 c.clk_sys_ctrl().write(|w| w.set_src(ClkSysCtrlSrc::CLK_REF)); 539 c.clk_sys_ctrl().write(|w| w.set_src(ClkSysCtrlSrc::CLK_REF));
511 while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF as u32 {} 540 #[cfg(feature = "rp2040")]
541 while c.clk_sys_selected().read() != (1 << ClkSysCtrlSrc::CLK_REF as u32) {}
542 #[cfg(feature = "rp235x")]
543 while c.clk_sys_selected().read() != pac::clocks::regs::ClkSysSelected(1 << ClkSysCtrlSrc::CLK_REF as u32) {}
512 } 544 }
513 c.clk_sys_ctrl().write(|w| { 545 c.clk_sys_ctrl().write(|w| {
514 w.set_auxsrc(sys_aux); 546 w.set_auxsrc(sys_aux);
515 w.set_src(sys_src); 547 w.set_src(sys_src);
516 }); 548 });
517 while c.clk_sys_selected().read() != 1 << sys_src as u32 {} 549
550 #[cfg(feature = "rp2040")]
551 while c.clk_sys_selected().read() != (1 << sys_src as u32) {}
552 #[cfg(feature = "rp235x")]
553 while c.clk_sys_selected().read() != pac::clocks::regs::ClkSysSelected(1 << sys_src as u32) {}
554
518 c.clk_sys_div().write(|w| { 555 c.clk_sys_div().write(|w| {
519 w.set_int(config.sys_clk.div_int); 556 w.set_int(config.sys_clk.div_int);
520 w.set_frac(config.sys_clk.div_frac); 557 w.set_frac(config.sys_clk.div_frac);
@@ -592,6 +629,8 @@ pub(crate) unsafe fn init(config: ClockConfig) {
592 CLOCKS.adc.store(0, Ordering::Relaxed); 629 CLOCKS.adc.store(0, Ordering::Relaxed);
593 } 630 }
594 631
632 // rp2040 specific clocks
633 #[cfg(feature = "rp2040")]
595 if let Some(conf) = config.rtc_clk { 634 if let Some(conf) = config.rtc_clk {
596 c.clk_rtc_div().write(|w| { 635 c.clk_rtc_div().write(|w| {
597 w.set_int(conf.div_int); 636 w.set_int(conf.div_int);
@@ -621,6 +660,13 @@ pub(crate) unsafe fn init(config: ClockConfig) {
621 CLOCKS.rtc.store(0, Ordering::Relaxed); 660 CLOCKS.rtc.store(0, Ordering::Relaxed);
622 } 661 }
623 662
663 // rp235x specific clocks
664 #[cfg(feature = "rp235x")]
665 {
666 // TODO hstx clock
667 peris.set_hstx(false);
668 }
669
624 // Peripheral clocks should now all be running 670 // Peripheral clocks should now all be running
625 reset::unreset_wait(peris); 671 reset::unreset_wait(peris);
626} 672}
@@ -709,6 +755,7 @@ pub fn clk_adc_freq() -> u32 {
709} 755}
710 756
711/// RTC clock frequency. 757/// RTC clock frequency.
758#[cfg(feature = "rp2040")]
712pub fn clk_rtc_freq() -> u16 { 759pub fn clk_rtc_freq() -> u16 {
713 CLOCKS.rtc.load(Ordering::Relaxed) 760 CLOCKS.rtc.load(Ordering::Relaxed)
714} 761}
@@ -855,8 +902,8 @@ pub enum GpoutSrc {
855 Usb = ClkGpoutCtrlAuxsrc::CLK_USB as _, 902 Usb = ClkGpoutCtrlAuxsrc::CLK_USB as _,
856 /// ADC. 903 /// ADC.
857 Adc = ClkGpoutCtrlAuxsrc::CLK_ADC as _, 904 Adc = ClkGpoutCtrlAuxsrc::CLK_ADC as _,
858 /// RTC. 905 // RTC.
859 Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC as _, 906 //Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC as _,
860 /// REF. 907 /// REF.
861 Ref = ClkGpoutCtrlAuxsrc::CLK_REF as _, 908 Ref = ClkGpoutCtrlAuxsrc::CLK_REF as _,
862} 909}
@@ -877,6 +924,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
877 } 924 }
878 925
879 /// Set clock divider. 926 /// Set clock divider.
927 #[cfg(feature = "rp2040")]
880 pub fn set_div(&self, int: u32, frac: u8) { 928 pub fn set_div(&self, int: u32, frac: u8) {
881 let c = pac::CLOCKS; 929 let c = pac::CLOCKS;
882 c.clk_gpout_div(self.gpout.number()).write(|w| { 930 c.clk_gpout_div(self.gpout.number()).write(|w| {
@@ -885,6 +933,16 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
885 }); 933 });
886 } 934 }
887 935
936 /// Set clock divider.
937 #[cfg(feature = "rp235x")]
938 pub fn set_div(&self, int: u16, frac: u16) {
939 let c = pac::CLOCKS;
940 c.clk_gpout_div(self.gpout.number()).write(|w| {
941 w.set_int(int);
942 w.set_frac(frac);
943 });
944 }
945
888 /// Set clock source. 946 /// Set clock source.
889 pub fn set_src(&self, src: GpoutSrc) { 947 pub fn set_src(&self, src: GpoutSrc) {
890 let c = pac::CLOCKS; 948 let c = pac::CLOCKS;
@@ -924,13 +982,13 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
924 ClkGpoutCtrlAuxsrc::CLK_SYS => clk_sys_freq(), 982 ClkGpoutCtrlAuxsrc::CLK_SYS => clk_sys_freq(),
925 ClkGpoutCtrlAuxsrc::CLK_USB => clk_usb_freq(), 983 ClkGpoutCtrlAuxsrc::CLK_USB => clk_usb_freq(),
926 ClkGpoutCtrlAuxsrc::CLK_ADC => clk_adc_freq(), 984 ClkGpoutCtrlAuxsrc::CLK_ADC => clk_adc_freq(),
927 ClkGpoutCtrlAuxsrc::CLK_RTC => clk_rtc_freq() as _, 985 //ClkGpoutCtrlAuxsrc::CLK_RTC => clk_rtc_freq() as _,
928 ClkGpoutCtrlAuxsrc::CLK_REF => clk_ref_freq(), 986 ClkGpoutCtrlAuxsrc::CLK_REF => clk_ref_freq(),
929 _ => unreachable!(), 987 _ => unreachable!(),
930 }; 988 };
931 989
932 let div = c.clk_gpout_div(self.gpout.number()).read(); 990 let div = c.clk_gpout_div(self.gpout.number()).read();
933 let int = if div.int() == 0 { 65536 } else { div.int() } as u64; 991 let int = if div.int() == 0 { 0xFFFF } else { div.int() } as u64;
934 let frac = div.frac() as u64; 992 let frac = div.frac() as u64;
935 993
936 ((base as u64 * 256) / (int * 256 + frac)) as u32 994 ((base as u64 * 256) / (int * 256 + frac)) as u32
@@ -987,7 +1045,7 @@ impl rand_core::RngCore for RoscRng {
987/// and can only be exited through resets, dormant-wake GPIO interrupts, 1045/// and can only be exited through resets, dormant-wake GPIO interrupts,
988/// and RTC interrupts. If RTC is clocked from an internal clock source 1046/// and RTC interrupts. If RTC is clocked from an internal clock source
989/// it will be stopped and not function as a wakeup source. 1047/// it will be stopped and not function as a wakeup source.
990#[cfg(target_arch = "arm")] 1048#[cfg(all(target_arch = "arm", feature = "rp2040"))]
991pub fn dormant_sleep() { 1049pub fn dormant_sleep() {
992 struct Set<T: Copy, F: Fn()>(Reg<T, RW>, T, F); 1050 struct Set<T: Copy, F: Fn()>(Reg<T, RW>, T, F);
993 1051
@@ -1107,7 +1165,7 @@ pub fn dormant_sleep() {
1107 coma = in (reg) 0x636f6d61, 1165 coma = in (reg) 0x636f6d61,
1108 ); 1166 );
1109 } else { 1167 } else {
1110 pac::ROSC.dormant().write_value(0x636f6d61); 1168 pac::ROSC.dormant().write_value(rp_pac::rosc::regs::Dormant(0x636f6d61));
1111 } 1169 }
1112 } 1170 }
1113} 1171}
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>(
45 ch: impl Peripheral<P = C> + 'a, 45 ch: impl Peripheral<P = C> + 'a,
46 from: *const W, 46 from: *const W,
47 to: *mut [W], 47 to: *mut [W],
48 dreq: u8, 48 dreq: vals::TreqSel,
49) -> Transfer<'a, C> { 49) -> Transfer<'a, C> {
50 copy_inner( 50 copy_inner(
51 ch, 51 ch,
@@ -66,7 +66,7 @@ pub unsafe fn write<'a, C: Channel, W: Word>(
66 ch: impl Peripheral<P = C> + 'a, 66 ch: impl Peripheral<P = C> + 'a,
67 from: *const [W], 67 from: *const [W],
68 to: *mut W, 68 to: *mut W,
69 dreq: u8, 69 dreq: vals::TreqSel,
70) -> Transfer<'a, C> { 70) -> Transfer<'a, C> {
71 copy_inner( 71 copy_inner(
72 ch, 72 ch,
@@ -90,7 +90,7 @@ pub unsafe fn write_repeated<'a, C: Channel, W: Word>(
90 ch: impl Peripheral<P = C> + 'a, 90 ch: impl Peripheral<P = C> + 'a,
91 to: *mut W, 91 to: *mut W,
92 len: usize, 92 len: usize,
93 dreq: u8, 93 dreq: vals::TreqSel,
94) -> Transfer<'a, C> { 94) -> Transfer<'a, C> {
95 copy_inner( 95 copy_inner(
96 ch, 96 ch,
@@ -123,7 +123,7 @@ pub unsafe fn copy<'a, C: Channel, W: Word>(
123 W::size(), 123 W::size(),
124 true, 124 true,
125 true, 125 true,
126 vals::TreqSel::PERMANENT.0, 126 vals::TreqSel::PERMANENT,
127 ) 127 )
128} 128}
129 129
@@ -135,7 +135,7 @@ fn copy_inner<'a, C: Channel>(
135 data_size: DataSize, 135 data_size: DataSize,
136 incr_read: bool, 136 incr_read: bool,
137 incr_write: bool, 137 incr_write: bool,
138 dreq: u8, 138 dreq: vals::TreqSel,
139) -> Transfer<'a, C> { 139) -> Transfer<'a, C> {
140 into_ref!(ch); 140 into_ref!(ch);
141 141
@@ -143,14 +143,20 @@ fn copy_inner<'a, C: Channel>(
143 143
144 p.read_addr().write_value(from as u32); 144 p.read_addr().write_value(from as u32);
145 p.write_addr().write_value(to as u32); 145 p.write_addr().write_value(to as u32);
146 p.trans_count().write_value(len as u32); 146 #[cfg(feature = "rp2040")]
147 p.trans_count().write(|w| {
148 *w = len as u32;
149 });
150 #[cfg(feature = "rp235x")]
151 p.trans_count().write(|w| {
152 w.set_mode(0.into());
153 w.set_count(len as u32);
154 });
147 155
148 compiler_fence(Ordering::SeqCst); 156 compiler_fence(Ordering::SeqCst);
149 157
150 p.ctrl_trig().write(|w| { 158 p.ctrl_trig().write(|w| {
151 // TODO: Add all DREQ options to pac vals::TreqSel, and use 159 w.set_treq_sel(dreq);
152 // `set_treq:sel`
153 w.0 = ((dreq as u32) & 0x3f) << 15usize;
154 w.set_data_size(data_size); 160 w.set_data_size(data_size);
155 w.set_incr_read(incr_read); 161 w.set_incr_read(incr_read);
156 w.set_incr_write(incr_write); 162 w.set_incr_write(incr_write);
@@ -297,3 +303,11 @@ channel!(DMA_CH8, 8);
297channel!(DMA_CH9, 9); 303channel!(DMA_CH9, 9);
298channel!(DMA_CH10, 10); 304channel!(DMA_CH10, 10);
299channel!(DMA_CH11, 11); 305channel!(DMA_CH11, 11);
306#[cfg(feature = "rp235x")]
307channel!(DMA_CH12, 12);
308#[cfg(feature = "rp235x")]
309channel!(DMA_CH13, 13);
310#[cfg(feature = "rp235x")]
311channel!(DMA_CH14, 14);
312#[cfg(feature = "rp235x")]
313channel!(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> {
302 // pac::XIP_CTRL.stream_fifo().as_ptr()) to avoid DMA stalling on 302 // pac::XIP_CTRL.stream_fifo().as_ptr()) to avoid DMA stalling on
303 // general XIP access. 303 // general XIP access.
304 const XIP_AUX_BASE: *const u32 = 0x50400000 as *const _; 304 const XIP_AUX_BASE: *const u32 = 0x50400000 as *const _;
305 let transfer = unsafe { crate::dma::read(self.dma.as_mut().unwrap(), XIP_AUX_BASE, data, 37) }; 305 let transfer = unsafe {
306 crate::dma::read(
307 self.dma.as_mut().unwrap(),
308 XIP_AUX_BASE,
309 data,
310 pac::dma::vals::TreqSel::XIP_STREAM,
311 )
312 };
306 313
307 Ok(BackgroundRead { 314 Ok(BackgroundRead {
308 flash: PhantomData, 315 flash: PhantomData,
@@ -597,6 +604,7 @@ mod ram_helpers {
597 /// addr must be aligned to 4096 604 /// addr must be aligned to 4096
598 #[inline(never)] 605 #[inline(never)]
599 #[link_section = ".data.ram_func"] 606 #[link_section = ".data.ram_func"]
607 #[cfg(feature = "rp2040")]
600 unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) { 608 unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) {
601 /* 609 /*
602 Should be equivalent to: 610 Should be equivalent to:
@@ -659,6 +667,11 @@ mod ram_helpers {
659 ); 667 );
660 } 668 }
661 669
670 #[inline(never)]
671 #[link_section = ".data.ram_func"]
672 #[cfg(feature = "rp235x")]
673 unsafe fn write_flash_inner(_addr: u32, _len: u32, _data: Option<&[u8]>, _ptrs: *const FlashFunctionPointers) {}
674
662 #[repr(C)] 675 #[repr(C)]
663 struct FlashCommand { 676 struct FlashCommand {
664 cmd_addr: *const u8, 677 cmd_addr: *const u8,
@@ -758,6 +771,7 @@ mod ram_helpers {
758 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) 771 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
759 #[inline(never)] 772 #[inline(never)]
760 #[link_section = ".data.ram_func"] 773 #[link_section = ".data.ram_func"]
774 #[cfg(feature = "rp2040")]
761 unsafe fn read_flash_inner(cmd: FlashCommand, ptrs: *const FlashFunctionPointers) { 775 unsafe fn read_flash_inner(cmd: FlashCommand, ptrs: *const FlashFunctionPointers) {
762 #[cfg(target_arch = "arm")] 776 #[cfg(target_arch = "arm")]
763 core::arch::asm!( 777 core::arch::asm!(
@@ -874,6 +888,11 @@ mod ram_helpers {
874 clobber_abi("C"), 888 clobber_abi("C"),
875 ); 889 );
876 } 890 }
891
892 #[inline(never)]
893 #[link_section = ".data.ram_func"]
894 #[cfg(feature = "rp235x")]
895 unsafe fn read_flash_inner(_cmd: FlashCommand, _ptrs: *const FlashFunctionPointers) {}
877} 896}
878 897
879/// Make sure to uphold the contract points with rp2040-flash. 898/// 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> {
887 } 906 }
888 907
889 // Make sure CORE1 is paused during the entire duration of the RAM function 908 // Make sure CORE1 is paused during the entire duration of the RAM function
890 crate::multicore::pause_core1(); 909 //crate::multicore::pause_core1();
891 910
892 critical_section::with(|_| { 911 critical_section::with(|_| {
893 // Wait for all DMA channels in flash to finish before ram operation 912 // 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> {
904 }); 923 });
905 924
906 // Resume CORE1 execution 925 // Resume CORE1 execution
907 crate::multicore::resume_core1(); 926 //crate::multicore::resume_core1();
908 Ok(()) 927 Ok(())
909} 928}
910 929
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 @@
1#![cfg(feature = "rp2040")]
1// Credit: taken from `rp-hal` (also licensed Apache+MIT) 2// Credit: taken from `rp-hal` (also licensed Apache+MIT)
2// https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/src/float/mod.rs 3// https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/src/float/mod.rs
3 4
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> {
178 pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake<'_> { 178 pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake<'_> {
179 self.pin.dormant_wake(cfg) 179 self.pin.dormant_wake(cfg)
180 } 180 }
181
182 /// Set the pin's pad isolation
183 #[cfg(feature = "rp235x")]
184 #[inline]
185 pub fn set_pad_isolation(&mut self, isolate: bool) {
186 self.pin.set_pad_isolation(isolate)
187 }
181} 188}
182 189
183/// Interrupt trigger levels. 190/// Interrupt trigger levels.
@@ -413,6 +420,13 @@ impl<'d> Output<'d> {
413 pub fn toggle(&mut self) { 420 pub fn toggle(&mut self) {
414 self.pin.toggle() 421 self.pin.toggle()
415 } 422 }
423
424 /// Set the pin's pad isolation
425 #[cfg(feature = "rp235x")]
426 #[inline]
427 pub fn set_pad_isolation(&mut self, isolate: bool) {
428 self.pin.set_pad_isolation(isolate)
429 }
416} 430}
417 431
418/// GPIO output open-drain. 432/// GPIO output open-drain.
@@ -539,6 +553,13 @@ impl<'d> OutputOpenDrain<'d> {
539 pub async fn wait_for_any_edge(&mut self) { 553 pub async fn wait_for_any_edge(&mut self) {
540 self.pin.wait_for_any_edge().await; 554 self.pin.wait_for_any_edge().await;
541 } 555 }
556
557 /// Set the pin's pad isolation
558 #[cfg(feature = "rp235x")]
559 #[inline]
560 pub fn set_pad_isolation(&mut self, isolate: bool) {
561 self.pin.set_pad_isolation(isolate)
562 }
542} 563}
543 564
544/// GPIO flexible pin. 565/// GPIO flexible pin.
@@ -564,7 +585,15 @@ impl<'d> Flex<'d> {
564 }); 585 });
565 586
566 pin.gpio().ctrl().write(|w| { 587 pin.gpio().ctrl().write(|w| {
588 #[cfg(feature = "rp2040")]
567 w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0 as _); 589 w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0 as _);
590 #[cfg(feature = "rp235x")]
591 w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIOB_PROC_0 as _);
592 });
593
594 #[cfg(feature = "rp235x")]
595 pin.pad_ctrl().modify(|w| {
596 w.set_iso(false);
568 }); 597 });
569 598
570 Self { pin: pin.map_into() } 599 Self { pin: pin.map_into() }
@@ -760,6 +789,15 @@ impl<'d> Flex<'d> {
760 cfg, 789 cfg,
761 } 790 }
762 } 791 }
792
793 /// Set the pin's pad isolation
794 #[cfg(feature = "rp235x")]
795 #[inline]
796 pub fn set_pad_isolation(&mut self, isolate: bool) {
797 self.pin.pad_ctrl().modify(|w| {
798 w.set_iso(isolate);
799 });
800 }
763} 801}
764 802
765impl<'d> Drop for Flex<'d> { 803impl<'d> Drop for Flex<'d> {
@@ -956,6 +994,44 @@ impl_pin!(PIN_27, Bank::Bank0, 27);
956impl_pin!(PIN_28, Bank::Bank0, 28); 994impl_pin!(PIN_28, Bank::Bank0, 28);
957impl_pin!(PIN_29, Bank::Bank0, 29); 995impl_pin!(PIN_29, Bank::Bank0, 29);
958 996
997#[cfg(feature = "rp235xb")]
998impl_pin!(PIN_30, Bank::Bank0, 30);
999#[cfg(feature = "rp235xb")]
1000impl_pin!(PIN_31, Bank::Bank0, 31);
1001#[cfg(feature = "rp235xb")]
1002impl_pin!(PIN_32, Bank::Bank0, 32);
1003#[cfg(feature = "rp235xb")]
1004impl_pin!(PIN_33, Bank::Bank0, 33);
1005#[cfg(feature = "rp235xb")]
1006impl_pin!(PIN_34, Bank::Bank0, 34);
1007#[cfg(feature = "rp235xb")]
1008impl_pin!(PIN_35, Bank::Bank0, 35);
1009#[cfg(feature = "rp235xb")]
1010impl_pin!(PIN_36, Bank::Bank0, 36);
1011#[cfg(feature = "rp235xb")]
1012impl_pin!(PIN_37, Bank::Bank0, 37);
1013#[cfg(feature = "rp235xb")]
1014impl_pin!(PIN_38, Bank::Bank0, 38);
1015#[cfg(feature = "rp235xb")]
1016impl_pin!(PIN_39, Bank::Bank0, 39);
1017#[cfg(feature = "rp235xb")]
1018impl_pin!(PIN_40, Bank::Bank0, 40);
1019#[cfg(feature = "rp235xb")]
1020impl_pin!(PIN_41, Bank::Bank0, 41);
1021#[cfg(feature = "rp235xb")]
1022impl_pin!(PIN_42, Bank::Bank0, 42);
1023#[cfg(feature = "rp235xb")]
1024impl_pin!(PIN_43, Bank::Bank0, 43);
1025#[cfg(feature = "rp235xb")]
1026impl_pin!(PIN_44, Bank::Bank0, 44);
1027#[cfg(feature = "rp235xb")]
1028impl_pin!(PIN_45, Bank::Bank0, 45);
1029#[cfg(feature = "rp235xb")]
1030impl_pin!(PIN_46, Bank::Bank0, 46);
1031#[cfg(feature = "rp235xb")]
1032impl_pin!(PIN_47, Bank::Bank0, 47);
1033
1034// TODO rp235x bank1 as gpio support
959#[cfg(feature = "qspi-as-gpio")] 1035#[cfg(feature = "qspi-as-gpio")]
960impl_pin!(PIN_QSPI_SCLK, Bank::Qspi, 0); 1036impl_pin!(PIN_QSPI_SCLK, Bank::Qspi, 0);
961#[cfg(feature = "qspi-as-gpio")] 1037#[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);
884impl_pin!(PIN_27, I2C1, SclPin); 884impl_pin!(PIN_27, I2C1, SclPin);
885impl_pin!(PIN_28, I2C0, SdaPin); 885impl_pin!(PIN_28, I2C0, SdaPin);
886impl_pin!(PIN_29, I2C0, SclPin); 886impl_pin!(PIN_29, I2C0, SclPin);
887#[cfg(feature = "rp235xb")]
888impl_pin!(PIN_30, I2C1, SdaPin);
889#[cfg(feature = "rp235xb")]
890impl_pin!(PIN_31, I2C1, SclPin);
891#[cfg(feature = "rp235xb")]
892impl_pin!(PIN_32, I2C0, SdaPin);
893#[cfg(feature = "rp235xb")]
894impl_pin!(PIN_33, I2C0, SclPin);
895#[cfg(feature = "rp235xb")]
896impl_pin!(PIN_34, I2C1, SdaPin);
897#[cfg(feature = "rp235xb")]
898impl_pin!(PIN_35, I2C1, SclPin);
899#[cfg(feature = "rp235xb")]
900impl_pin!(PIN_36, I2C0, SdaPin);
901#[cfg(feature = "rp235xb")]
902impl_pin!(PIN_37, I2C0, SclPin);
903#[cfg(feature = "rp235xb")]
904impl_pin!(PIN_38, I2C1, SdaPin);
905#[cfg(feature = "rp235xb")]
906impl_pin!(PIN_39, I2C1, SclPin);
907#[cfg(feature = "rp235xb")]
908impl_pin!(PIN_40, I2C0, SdaPin);
909#[cfg(feature = "rp235xb")]
910impl_pin!(PIN_41, I2C0, SclPin);
911#[cfg(feature = "rp235xb")]
912impl_pin!(PIN_42, I2C1, SdaPin);
913#[cfg(feature = "rp235xb")]
914impl_pin!(PIN_43, I2C1, SclPin);
915#[cfg(feature = "rp235xb")]
916impl_pin!(PIN_44, I2C0, SdaPin);
917#[cfg(feature = "rp235xb")]
918impl_pin!(PIN_45, I2C0, SclPin);
919#[cfg(feature = "rp235xb")]
920impl_pin!(PIN_46, I2C1, SdaPin);
921#[cfg(feature = "rp235xb")]
922impl_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;
15mod intrinsics; 15mod intrinsics;
16 16
17pub mod adc; 17pub mod adc;
18#[cfg(feature = "rp235x")]
19pub mod binary_info;
20#[cfg(feature = "rp235x")]
21pub mod block;
22#[cfg(feature = "rp2040")]
18pub mod bootsel; 23pub mod bootsel;
19pub mod clocks; 24pub mod clocks;
20pub mod dma; 25pub mod dma;
@@ -41,14 +46,20 @@ pub(crate) mod relocate;
41 46
42// Reexports 47// Reexports
43pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; 48pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
44#[cfg(feature = "unstable-pac")] 49#[cfg(all(feature = "unstable-pac", feature = "rp235x"))]
50pub use rp23_pac as pac;
51#[cfg(all(feature = "unstable-pac", feature = "rp2040"))]
45pub use rp_pac as pac; 52pub use rp_pac as pac;
46#[cfg(not(feature = "unstable-pac"))] 53
54#[cfg(all(not(feature = "unstable-pac"), feature = "rp235x"))]
55pub(crate) use rp23_pac as pac;
56#[cfg(all(not(feature = "unstable-pac"), feature = "rp2040"))]
47pub(crate) use rp_pac as pac; 57pub(crate) use rp_pac as pac;
48 58
49#[cfg(feature = "rt")] 59#[cfg(feature = "rt")]
50pub use crate::pac::NVIC_PRIO_BITS; 60pub use crate::pac::NVIC_PRIO_BITS;
51 61
62#[cfg(feature = "rp2040")]
52embassy_hal_internal::interrupt_mod!( 63embassy_hal_internal::interrupt_mod!(
53 TIMER_IRQ_0, 64 TIMER_IRQ_0,
54 TIMER_IRQ_1, 65 TIMER_IRQ_1,
@@ -84,6 +95,54 @@ embassy_hal_internal::interrupt_mod!(
84 SWI_IRQ_5, 95 SWI_IRQ_5,
85); 96);
86 97
98#[cfg(feature = "rp235x")]
99embassy_hal_internal::interrupt_mod!(
100 TIMER0_IRQ_0,
101 TIMER0_IRQ_1,
102 TIMER0_IRQ_2,
103 TIMER0_IRQ_3,
104 TIMER1_IRQ_0,
105 TIMER1_IRQ_1,
106 TIMER1_IRQ_2,
107 TIMER1_IRQ_3,
108 PWM_IRQ_WRAP_0,
109 PWM_IRQ_WRAP_1,
110 DMA_IRQ_0,
111 DMA_IRQ_1,
112 USBCTRL_IRQ,
113 PIO0_IRQ_0,
114 PIO0_IRQ_1,
115 PIO1_IRQ_0,
116 PIO1_IRQ_1,
117 PIO2_IRQ_0,
118 PIO2_IRQ_1,
119 IO_IRQ_BANK0,
120 IO_IRQ_BANK0_NS,
121 IO_IRQ_QSPI,
122 IO_IRQ_QSPI_NS,
123 SIO_IRQ_FIFO,
124 SIO_IRQ_BELL,
125 SIO_IRQ_FIFO_NS,
126 SIO_IRQ_BELL_NS,
127 CLOCKS_IRQ,
128 SPI0_IRQ,
129 SPI1_IRQ,
130 UART0_IRQ,
131 UART1_IRQ,
132 ADC_IRQ_FIFO,
133 I2C0_IRQ,
134 I2C1_IRQ,
135 TRNG_IRQ,
136 PLL_SYS_IRQ,
137 PLL_USB_IRQ,
138 SWI_IRQ_0,
139 SWI_IRQ_1,
140 SWI_IRQ_2,
141 SWI_IRQ_3,
142 SWI_IRQ_4,
143 SWI_IRQ_5,
144);
145
87/// Macro to bind interrupts to handlers. 146/// Macro to bind interrupts to handlers.
88/// 147///
89/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`) 148/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
@@ -123,6 +182,95 @@ macro_rules! bind_interrupts {
123 }; 182 };
124} 183}
125 184
185#[cfg(feature = "rp2040")]
186embassy_hal_internal::peripherals! {
187 PIN_0,
188 PIN_1,
189 PIN_2,
190 PIN_3,
191 PIN_4,
192 PIN_5,
193 PIN_6,
194 PIN_7,
195 PIN_8,
196 PIN_9,
197 PIN_10,
198 PIN_11,
199 PIN_12,
200 PIN_13,
201 PIN_14,
202 PIN_15,
203 PIN_16,
204 PIN_17,
205 PIN_18,
206 PIN_19,
207 PIN_20,
208 PIN_21,
209 PIN_22,
210 PIN_23,
211 PIN_24,
212 PIN_25,
213 PIN_26,
214 PIN_27,
215 PIN_28,
216 PIN_29,
217 PIN_QSPI_SCLK,
218 PIN_QSPI_SS,
219 PIN_QSPI_SD0,
220 PIN_QSPI_SD1,
221 PIN_QSPI_SD2,
222 PIN_QSPI_SD3,
223
224 UART0,
225 UART1,
226
227 SPI0,
228 SPI1,
229
230 I2C0,
231 I2C1,
232
233 DMA_CH0,
234 DMA_CH1,
235 DMA_CH2,
236 DMA_CH3,
237 DMA_CH4,
238 DMA_CH5,
239 DMA_CH6,
240 DMA_CH7,
241 DMA_CH8,
242 DMA_CH9,
243 DMA_CH10,
244 DMA_CH11,
245
246 PWM_SLICE0,
247 PWM_SLICE1,
248 PWM_SLICE2,
249 PWM_SLICE3,
250 PWM_SLICE4,
251 PWM_SLICE5,
252 PWM_SLICE6,
253 PWM_SLICE7,
254
255 USB,
256
257 RTC,
258
259 FLASH,
260
261 ADC,
262 ADC_TEMP_SENSOR,
263
264 CORE1,
265
266 PIO0,
267 PIO1,
268
269 WATCHDOG,
270 BOOTSEL,
271}
272
273#[cfg(feature = "rp235x")]
126embassy_hal_internal::peripherals! { 274embassy_hal_internal::peripherals! {
127 PIN_0, 275 PIN_0,
128 PIN_1, 276 PIN_1,
@@ -154,6 +302,42 @@ embassy_hal_internal::peripherals! {
154 PIN_27, 302 PIN_27,
155 PIN_28, 303 PIN_28,
156 PIN_29, 304 PIN_29,
305 #[cfg(feature = "rp235xb")]
306 PIN_30,
307 #[cfg(feature = "rp235xb")]
308 PIN_31,
309 #[cfg(feature = "rp235xb")]
310 PIN_32,
311 #[cfg(feature = "rp235xb")]
312 PIN_33,
313 #[cfg(feature = "rp235xb")]
314 PIN_34,
315 #[cfg(feature = "rp235xb")]
316 PIN_35,
317 #[cfg(feature = "rp235xb")]
318 PIN_36,
319 #[cfg(feature = "rp235xb")]
320 PIN_37,
321 #[cfg(feature = "rp235xb")]
322 PIN_38,
323 #[cfg(feature = "rp235xb")]
324 PIN_39,
325 #[cfg(feature = "rp235xb")]
326 PIN_40,
327 #[cfg(feature = "rp235xb")]
328 PIN_41,
329 #[cfg(feature = "rp235xb")]
330 PIN_42,
331 #[cfg(feature = "rp235xb")]
332 PIN_43,
333 #[cfg(feature = "rp235xb")]
334 PIN_44,
335 #[cfg(feature = "rp235xb")]
336 PIN_45,
337 #[cfg(feature = "rp235xb")]
338 PIN_46,
339 #[cfg(feature = "rp235xb")]
340 PIN_47,
157 PIN_QSPI_SCLK, 341 PIN_QSPI_SCLK,
158 PIN_QSPI_SS, 342 PIN_QSPI_SS,
159 PIN_QSPI_SD0, 343 PIN_QSPI_SD0,
@@ -182,6 +366,10 @@ embassy_hal_internal::peripherals! {
182 DMA_CH9, 366 DMA_CH9,
183 DMA_CH10, 367 DMA_CH10,
184 DMA_CH11, 368 DMA_CH11,
369 DMA_CH12,
370 DMA_CH13,
371 DMA_CH14,
372 DMA_CH15,
185 373
186 PWM_SLICE0, 374 PWM_SLICE0,
187 PWM_SLICE1, 375 PWM_SLICE1,
@@ -191,6 +379,10 @@ embassy_hal_internal::peripherals! {
191 PWM_SLICE5, 379 PWM_SLICE5,
192 PWM_SLICE6, 380 PWM_SLICE6,
193 PWM_SLICE7, 381 PWM_SLICE7,
382 PWM_SLICE8,
383 PWM_SLICE9,
384 PWM_SLICE10,
385 PWM_SLICE11,
194 386
195 USB, 387 USB,
196 388
@@ -205,6 +397,7 @@ embassy_hal_internal::peripherals! {
205 397
206 PIO0, 398 PIO0,
207 PIO1, 399 PIO1,
400 PIO2,
208 401
209 WATCHDOG, 402 WATCHDOG,
210 BOOTSEL, 403 BOOTSEL,
@@ -279,6 +472,7 @@ pub fn install_core0_stack_guard() -> Result<(), ()> {
279 unsafe { install_stack_guard(core::ptr::addr_of_mut!(_stack_end)) } 472 unsafe { install_stack_guard(core::ptr::addr_of_mut!(_stack_end)) }
280} 473}
281 474
475#[cfg(feature = "rp2040")]
282#[inline(always)] 476#[inline(always)]
283fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { 477fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> {
284 let core = unsafe { cortex_m::Peripherals::steal() }; 478 let core = unsafe { cortex_m::Peripherals::steal() };
@@ -306,6 +500,24 @@ fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> {
306 Ok(()) 500 Ok(())
307} 501}
308 502
503#[cfg(feature = "rp235x")]
504#[inline(always)]
505fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> {
506 let core = unsafe { cortex_m::Peripherals::steal() };
507
508 // Fail if MPU is already configured
509 if core.MPU.ctrl.read() != 0 {
510 return Err(());
511 }
512
513 unsafe {
514 core.MPU.ctrl.write(5); // enable mpu with background default map
515 core.MPU.rbar.write(stack_bottom as u32 & !0xff); // set address
516 core.MPU.rlar.write(1); // enable region
517 }
518 Ok(())
519}
520
309/// HAL configuration for RP. 521/// HAL configuration for RP.
310pub mod config { 522pub mod config {
311 use crate::clocks::ClockConfig; 523 use crate::clocks::ClockConfig;
@@ -354,7 +566,7 @@ pub fn init(config: config::Config) -> Peripherals {
354 peripherals 566 peripherals
355} 567}
356 568
357#[cfg(feature = "rt")] 569#[cfg(all(feature = "rt", feature = "rp2040"))]
358#[cortex_m_rt::pre_init] 570#[cortex_m_rt::pre_init]
359unsafe fn pre_init() { 571unsafe fn pre_init() {
360 // SIO does not get reset when core0 is reset with either `scb::sys_reset()` or with SWD. 572 // 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<const SIZE: usize> Stack<SIZE> {
84 } 84 }
85} 85}
86 86
87#[cfg(feature = "rt")] 87#[cfg(all(feature = "rt", feature = "rp2040"))]
88#[interrupt] 88#[interrupt]
89#[link_section = ".data.ram_func"] 89#[link_section = ".data.ram_func"]
90unsafe fn SIO_IRQ_PROC1() { 90unsafe fn SIO_IRQ_PROC1() {
@@ -109,6 +109,31 @@ unsafe fn SIO_IRQ_PROC1() {
109 } 109 }
110} 110}
111 111
112#[cfg(all(feature = "rt", feature = "rp235x"))]
113#[interrupt]
114#[link_section = ".data.ram_func"]
115unsafe fn SIO_IRQ_FIFO() {
116 let sio = pac::SIO;
117 // Clear IRQ
118 sio.fifo().st().write(|w| w.set_wof(false));
119
120 while sio.fifo().st().read().vld() {
121 // Pause CORE1 execution and disable interrupts
122 if fifo_read_wfe() == PAUSE_TOKEN {
123 cortex_m::interrupt::disable();
124 // Signal to CORE0 that execution is paused
125 fifo_write(PAUSE_TOKEN);
126 // Wait for `resume` signal from CORE0
127 while fifo_read_wfe() != RESUME_TOKEN {
128 cortex_m::asm::nop();
129 }
130 cortex_m::interrupt::enable();
131 // Signal to CORE0 that execution is resumed
132 fifo_write(RESUME_TOKEN);
133 }
134 }
135}
136
112/// Spawn a function on this core 137/// Spawn a function on this core
113pub fn spawn_core1<F, const SIZE: usize>(_core1: CORE1, stack: &'static mut Stack<SIZE>, entry: F) 138pub fn spawn_core1<F, const SIZE: usize>(_core1: CORE1, stack: &'static mut Stack<SIZE>, entry: F)
114where 139where
@@ -135,7 +160,14 @@ where
135 160
136 IS_CORE1_INIT.store(true, Ordering::Release); 161 IS_CORE1_INIT.store(true, Ordering::Release);
137 // Enable fifo interrupt on CORE1 for `pause` functionality. 162 // Enable fifo interrupt on CORE1 for `pause` functionality.
138 unsafe { interrupt::SIO_IRQ_PROC1.enable() }; 163 #[cfg(feature = "rp2040")]
164 unsafe {
165 interrupt::SIO_IRQ_PROC1.enable()
166 };
167 #[cfg(feature = "rp235x")]
168 unsafe {
169 interrupt::SIO_IRQ_FIFO.enable()
170 };
139 171
140 entry() 172 entry()
141 } 173 }
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};
10use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
11use fixed::types::extra::U8; 11use fixed::types::extra::U8;
12use fixed::FixedU32; 12use fixed::FixedU32;
13use pac::io::vals::Gpio0ctrlFuncsel;
14use pac::pio::vals::SmExecctrlStatusSel;
15use pio::{Program, SideSet, Wrap}; 13use pio::{Program, SideSet, Wrap};
16 14
17use crate::dma::{Channel, Transfer, Word}; 15use crate::dma::{Channel, Transfer, Word};
18use crate::gpio::{self, AnyPin, Drive, Level, Pull, SealedPin, SlewRate}; 16use crate::gpio::{self, AnyPin, Drive, Level, Pull, SealedPin, SlewRate};
19use crate::interrupt::typelevel::{Binding, Handler, Interrupt}; 17use crate::interrupt::typelevel::{Binding, Handler, Interrupt};
20use crate::pac::dma::vals::TreqSel;
21use crate::relocate::RelocatedProgram; 18use crate::relocate::RelocatedProgram;
22use crate::{pac, peripherals, RegExt}; 19use crate::{pac, peripherals, RegExt};
23 20
@@ -355,11 +352,14 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
355 let p = ch.regs(); 352 let p = ch.regs();
356 p.write_addr().write_value(data.as_ptr() as u32); 353 p.write_addr().write_value(data.as_ptr() as u32);
357 p.read_addr().write_value(PIO::PIO.rxf(SM).as_ptr() as u32); 354 p.read_addr().write_value(PIO::PIO.rxf(SM).as_ptr() as u32);
358 p.trans_count().write_value(data.len() as u32); 355 #[cfg(feature = "rp2040")]
356 p.trans_count().write(|w| *w = data.len() as u32);
357 #[cfg(feature = "rp235x")]
358 p.trans_count().write(|w| w.set_count(data.len() as u32));
359 compiler_fence(Ordering::SeqCst); 359 compiler_fence(Ordering::SeqCst);
360 p.ctrl_trig().write(|w| { 360 p.ctrl_trig().write(|w| {
361 // Set RX DREQ for this statemachine 361 // Set RX DREQ for this statemachine
362 w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8 + 4)); 362 w.set_treq_sel(crate::pac::dma::vals::TreqSel::from(pio_no * 8 + SM as u8 + 4));
363 w.set_data_size(W::size()); 363 w.set_data_size(W::size());
364 w.set_chain_to(ch.number()); 364 w.set_chain_to(ch.number());
365 w.set_incr_read(false); 365 w.set_incr_read(false);
@@ -437,11 +437,14 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
437 let p = ch.regs(); 437 let p = ch.regs();
438 p.read_addr().write_value(data.as_ptr() as u32); 438 p.read_addr().write_value(data.as_ptr() as u32);
439 p.write_addr().write_value(PIO::PIO.txf(SM).as_ptr() as u32); 439 p.write_addr().write_value(PIO::PIO.txf(SM).as_ptr() as u32);
440 p.trans_count().write_value(data.len() as u32); 440 #[cfg(feature = "rp2040")]
441 p.trans_count().write(|w| *w = data.len() as u32);
442 #[cfg(feature = "rp235x")]
443 p.trans_count().write(|w| w.set_count(data.len() as u32));
441 compiler_fence(Ordering::SeqCst); 444 compiler_fence(Ordering::SeqCst);
442 p.ctrl_trig().write(|w| { 445 p.ctrl_trig().write(|w| {
443 // Set TX DREQ for this statemachine 446 // Set TX DREQ for this statemachine
444 w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8)); 447 w.set_treq_sel(crate::pac::dma::vals::TreqSel::from(pio_no * 8 + SM as u8));
445 w.set_data_size(W::size()); 448 w.set_data_size(W::size());
446 w.set_chain_to(ch.number()); 449 w.set_chain_to(ch.number());
447 w.set_incr_read(true); 450 w.set_incr_read(true);
@@ -523,6 +526,39 @@ pub struct PinConfig {
523 pub out_base: u8, 526 pub out_base: u8,
524} 527}
525 528
529/// Comparison level or IRQ index for the MOV x, STATUS instruction.
530#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
531#[cfg_attr(feature = "defmt", derive(defmt::Format))]
532#[cfg(feature = "rp235x")]
533pub enum StatusN {
534 /// IRQ flag in this PIO block
535 This(u8),
536 /// IRQ flag in the next lower PIO block
537 Lower(u8),
538 /// IRQ flag in the next higher PIO block
539 Higher(u8),
540}
541
542#[cfg(feature = "rp235x")]
543impl Default for StatusN {
544 fn default() -> Self {
545 Self::This(0)
546 }
547}
548
549#[cfg(feature = "rp235x")]
550impl Into<crate::pac::pio::vals::ExecctrlStatusN> for StatusN {
551 fn into(self) -> crate::pac::pio::vals::ExecctrlStatusN {
552 let x = match self {
553 StatusN::This(n) => n,
554 StatusN::Lower(n) => n + 0x08,
555 StatusN::Higher(n) => n + 0x10,
556 };
557
558 crate::pac::pio::vals::ExecctrlStatusN(x)
559 }
560}
561
526/// PIO config. 562/// PIO config.
527#[derive(Clone, Copy, Debug)] 563#[derive(Clone, Copy, Debug)]
528pub struct Config<'d, PIO: Instance> { 564pub struct Config<'d, PIO: Instance> {
@@ -537,7 +573,12 @@ pub struct Config<'d, PIO: Instance> {
537 /// Which source to use for checking status. 573 /// Which source to use for checking status.
538 pub status_sel: StatusSource, 574 pub status_sel: StatusSource,
539 /// Status comparison level. 575 /// Status comparison level.
576 #[cfg(feature = "rp2040")]
540 pub status_n: u8, 577 pub status_n: u8,
578 // This cfg probably shouldn't be required, but the SVD for the 2040 doesn't have the enum
579 #[cfg(feature = "rp235x")]
580 /// Status comparison level.
581 pub status_n: StatusN,
541 exec: ExecConfig, 582 exec: ExecConfig,
542 origin: Option<u8>, 583 origin: Option<u8>,
543 /// Configure FIFO allocation. 584 /// Configure FIFO allocation.
@@ -653,7 +694,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
653 assert!(config.clock_divider <= 65536, "clkdiv must be <= 65536"); 694 assert!(config.clock_divider <= 65536, "clkdiv must be <= 65536");
654 assert!(config.clock_divider >= 1, "clkdiv must be >= 1"); 695 assert!(config.clock_divider >= 1, "clkdiv must be >= 1");
655 assert!(config.out_en_sel < 32, "out_en_sel must be < 32"); 696 assert!(config.out_en_sel < 32, "out_en_sel must be < 32");
656 assert!(config.status_n < 32, "status_n must be < 32"); 697 //assert!(config.status_n < 32, "status_n must be < 32");
657 // sm expects 0 for 32, truncation makes that happen 698 // sm expects 0 for 32, truncation makes that happen
658 assert!(config.shift_in.threshold <= 32, "shift_in.threshold must be <= 32"); 699 assert!(config.shift_in.threshold <= 32, "shift_in.threshold must be <= 32");
659 assert!(config.shift_out.threshold <= 32, "shift_out.threshold must be <= 32"); 700 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> {
668 w.set_out_sticky(config.out_sticky); 709 w.set_out_sticky(config.out_sticky);
669 w.set_wrap_top(config.exec.wrap_top); 710 w.set_wrap_top(config.exec.wrap_top);
670 w.set_wrap_bottom(config.exec.wrap_bottom); 711 w.set_wrap_bottom(config.exec.wrap_bottom);
712 #[cfg(feature = "rp235x")]
671 w.set_status_sel(match config.status_sel { 713 w.set_status_sel(match config.status_sel {
672 StatusSource::TxFifoLevel => SmExecctrlStatusSel::TXLEVEL, 714 StatusSource::TxFifoLevel => pac::pio::vals::ExecctrlStatusSel::TXLEVEL,
673 StatusSource::RxFifoLevel => SmExecctrlStatusSel::RXLEVEL, 715 StatusSource::RxFifoLevel => pac::pio::vals::ExecctrlStatusSel::RXLEVEL,
674 }); 716 });
675 w.set_status_n(config.status_n); 717 #[cfg(feature = "rp2040")]
718 w.set_status_sel(match config.status_sel {
719 StatusSource::TxFifoLevel => pac::pio::vals::SmExecctrlStatusSel::TXLEVEL,
720 StatusSource::RxFifoLevel => pac::pio::vals::SmExecctrlStatusSel::RXLEVEL,
721 });
722 w.set_status_n(config.status_n.into());
676 }); 723 });
677 sm.shiftctrl().write(|w| { 724 sm.shiftctrl().write(|w| {
678 w.set_fjoin_rx(config.fifo_join == FifoJoin::RxOnly); 725 w.set_fjoin_rx(config.fifo_join == FifoJoin::RxOnly);
@@ -1147,7 +1194,7 @@ fn on_pio_drop<PIO: Instance>() {
1147 let state = PIO::state(); 1194 let state = PIO::state();
1148 if state.users.fetch_sub(1, Ordering::AcqRel) == 1 { 1195 if state.users.fetch_sub(1, Ordering::AcqRel) == 1 {
1149 let used_pins = state.used_pins.load(Ordering::Relaxed); 1196 let used_pins = state.used_pins.load(Ordering::Relaxed);
1150 let null = Gpio0ctrlFuncsel::NULL as _; 1197 let null = pac::io::vals::Gpio0ctrlFuncsel::NULL as _;
1151 // we only have 30 pins. don't test the other two since gpio() asserts. 1198 // we only have 30 pins. don't test the other two since gpio() asserts.
1152 for i in 0..30 { 1199 for i in 0..30 {
1153 if used_pins & (1 << i) != 0 { 1200 if used_pins & (1 << i) != 0 {
@@ -1203,6 +1250,8 @@ macro_rules! impl_pio {
1203 1250
1204impl_pio!(PIO0, 0, PIO0, PIO0_0, PIO0_IRQ_0); 1251impl_pio!(PIO0, 0, PIO0, PIO0_0, PIO0_IRQ_0);
1205impl_pio!(PIO1, 1, PIO1, PIO1_0, PIO1_IRQ_0); 1252impl_pio!(PIO1, 1, PIO1, PIO1_0, PIO1_IRQ_0);
1253#[cfg(feature = "rp235x")]
1254impl_pio!(PIO2, 2, PIO2, PIO2_0, PIO2_IRQ_0);
1206 1255
1207/// PIO pin. 1256/// PIO pin.
1208pub trait PioPin: gpio::Pin {} 1257pub trait PioPin: gpio::Pin {}
@@ -1247,3 +1296,25 @@ impl_pio_pin! {
1247 PIN_28, 1296 PIN_28,
1248 PIN_29, 1297 PIN_29,
1249} 1298}
1299
1300#[cfg(feature = "rp235xb")]
1301impl_pio_pin! {
1302 PIN_30,
1303 PIN_31,
1304 PIN_32,
1305 PIN_33,
1306 PIN_34,
1307 PIN_35,
1308 PIN_36,
1309 PIN_37,
1310 PIN_38,
1311 PIN_39,
1312 PIN_40,
1313 PIN_41,
1314 PIN_42,
1315 PIN_43,
1316 PIN_44,
1317 PIN_45,
1318 PIN_46,
1319 PIN_47,
1320}
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);
363slice!(PWM_SLICE6, 6); 363slice!(PWM_SLICE6, 6);
364slice!(PWM_SLICE7, 7); 364slice!(PWM_SLICE7, 7);
365 365
366#[cfg(feature = "rp235x")]
367slice!(PWM_SLICE8, 8);
368#[cfg(feature = "rp235x")]
369slice!(PWM_SLICE9, 9);
370#[cfg(feature = "rp235x")]
371slice!(PWM_SLICE10, 10);
372#[cfg(feature = "rp235x")]
373slice!(PWM_SLICE11, 11);
374
366/// PWM Channel A. 375/// PWM Channel A.
367pub trait ChannelAPin<T: Slice>: GpioPin {} 376pub trait ChannelAPin<T: Slice>: GpioPin {}
368/// PWM Channel B. 377/// PWM Channel B.
@@ -404,3 +413,39 @@ impl_pin!(PIN_26, PWM_SLICE5, ChannelAPin);
404impl_pin!(PIN_27, PWM_SLICE5, ChannelBPin); 413impl_pin!(PIN_27, PWM_SLICE5, ChannelBPin);
405impl_pin!(PIN_28, PWM_SLICE6, ChannelAPin); 414impl_pin!(PIN_28, PWM_SLICE6, ChannelAPin);
406impl_pin!(PIN_29, PWM_SLICE6, ChannelBPin); 415impl_pin!(PIN_29, PWM_SLICE6, ChannelBPin);
416#[cfg(feature = "rp235xb")]
417impl_pin!(PIN_30, PWM_SLICE7, ChannelAPin);
418#[cfg(feature = "rp235xb")]
419impl_pin!(PIN_31, PWM_SLICE7, ChannelBPin);
420#[cfg(feature = "rp235xb")]
421impl_pin!(PIN_32, PWM_SLICE8, ChannelAPin);
422#[cfg(feature = "rp235xb")]
423impl_pin!(PIN_33, PWM_SLICE8, ChannelBPin);
424#[cfg(feature = "rp235xb")]
425impl_pin!(PIN_34, PWM_SLICE9, ChannelAPin);
426#[cfg(feature = "rp235xb")]
427impl_pin!(PIN_35, PWM_SLICE9, ChannelBPin);
428#[cfg(feature = "rp235xb")]
429impl_pin!(PIN_36, PWM_SLICE10, ChannelAPin);
430#[cfg(feature = "rp235xb")]
431impl_pin!(PIN_37, PWM_SLICE10, ChannelBPin);
432#[cfg(feature = "rp235xb")]
433impl_pin!(PIN_38, PWM_SLICE11, ChannelAPin);
434#[cfg(feature = "rp235xb")]
435impl_pin!(PIN_39, PWM_SLICE11, ChannelBPin);
436#[cfg(feature = "rp235xb")]
437impl_pin!(PIN_40, PWM_SLICE8, ChannelAPin);
438#[cfg(feature = "rp235xb")]
439impl_pin!(PIN_41, PWM_SLICE8, ChannelBPin);
440#[cfg(feature = "rp235xb")]
441impl_pin!(PIN_42, PWM_SLICE9, ChannelAPin);
442#[cfg(feature = "rp235xb")]
443impl_pin!(PIN_43, PWM_SLICE9, ChannelBPin);
444#[cfg(feature = "rp235xb")]
445impl_pin!(PIN_44, PWM_SLICE10, ChannelAPin);
446#[cfg(feature = "rp235xb")]
447impl_pin!(PIN_45, PWM_SLICE10, ChannelBPin);
448#[cfg(feature = "rp235xb")]
449impl_pin!(PIN_46, PWM_SLICE11, ChannelAPin);
450#[cfg(feature = "rp235xb")]
451impl_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;
2 2
3use crate::pac; 3use crate::pac;
4 4
5pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ffffff); 5pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ff_ffff);
6 6
7pub(crate) fn reset(peris: Peripherals) { 7pub(crate) fn reset(peris: Peripherals) {
8 pac::RESETS.reset().write_value(peris); 8 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 @@
1#![cfg(feature = "rp2040")]
1//! RTC driver. 2//! RTC driver.
2mod filter; 3mod filter;
3 4
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> {
106 106
107 if let Some(pin) = &clk { 107 if let Some(pin) = &clk {
108 pin.gpio().ctrl().write(|w| w.set_funcsel(1)); 108 pin.gpio().ctrl().write(|w| w.set_funcsel(1));
109 pin.pad_ctrl().write(|w| {
110 #[cfg(feature = "rp235x")]
111 w.set_iso(false);
112 w.set_schmitt(true);
113 w.set_slewfast(false);
114 w.set_ie(true);
115 w.set_od(false);
116 w.set_pue(false);
117 w.set_pde(false);
118 });
109 } 119 }
110 if let Some(pin) = &mosi { 120 if let Some(pin) = &mosi {
111 pin.gpio().ctrl().write(|w| w.set_funcsel(1)); 121 pin.gpio().ctrl().write(|w| w.set_funcsel(1));
122 pin.pad_ctrl().write(|w| {
123 #[cfg(feature = "rp235x")]
124 w.set_iso(false);
125 w.set_schmitt(true);
126 w.set_slewfast(false);
127 w.set_ie(true);
128 w.set_od(false);
129 w.set_pue(false);
130 w.set_pde(false);
131 });
112 } 132 }
113 if let Some(pin) = &miso { 133 if let Some(pin) = &miso {
114 pin.gpio().ctrl().write(|w| w.set_funcsel(1)); 134 pin.gpio().ctrl().write(|w| w.set_funcsel(1));
135 pin.pad_ctrl().write(|w| {
136 #[cfg(feature = "rp235x")]
137 w.set_iso(false);
138 w.set_schmitt(true);
139 w.set_slewfast(false);
140 w.set_ie(true);
141 w.set_od(false);
142 w.set_pue(false);
143 w.set_pde(false);
144 });
115 } 145 }
116 if let Some(pin) = &cs { 146 if let Some(pin) = &cs {
117 pin.gpio().ctrl().write(|w| w.set_funcsel(1)); 147 pin.gpio().ctrl().write(|w| w.set_funcsel(1));
148 pin.pad_ctrl().write(|w| {
149 #[cfg(feature = "rp235x")]
150 w.set_iso(false);
151 w.set_schmitt(true);
152 w.set_slewfast(false);
153 w.set_ie(true);
154 w.set_od(false);
155 w.set_pue(false);
156 w.set_pde(false);
157 });
118 } 158 }
119 Self { 159 Self {
120 inner, 160 inner,
@@ -442,8 +482,8 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
442trait SealedMode {} 482trait SealedMode {}
443 483
444trait SealedInstance { 484trait SealedInstance {
445 const TX_DREQ: u8; 485 const TX_DREQ: pac::dma::vals::TreqSel;
446 const RX_DREQ: u8; 486 const RX_DREQ: pac::dma::vals::TreqSel;
447 487
448 fn regs(&self) -> pac::spi::Spi; 488 fn regs(&self) -> pac::spi::Spi;
449} 489}
@@ -459,8 +499,8 @@ pub trait Instance: SealedInstance {}
459macro_rules! impl_instance { 499macro_rules! impl_instance {
460 ($type:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => { 500 ($type:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => {
461 impl SealedInstance for peripherals::$type { 501 impl SealedInstance for peripherals::$type {
462 const TX_DREQ: u8 = $tx_dreq; 502 const TX_DREQ: pac::dma::vals::TreqSel = $tx_dreq;
463 const RX_DREQ: u8 = $rx_dreq; 503 const RX_DREQ: pac::dma::vals::TreqSel = $rx_dreq;
464 504
465 fn regs(&self) -> pac::spi::Spi { 505 fn regs(&self) -> pac::spi::Spi {
466 pac::$type 506 pac::$type
@@ -470,8 +510,18 @@ macro_rules! impl_instance {
470 }; 510 };
471} 511}
472 512
473impl_instance!(SPI0, Spi0, 16, 17); 513impl_instance!(
474impl_instance!(SPI1, Spi1, 18, 19); 514 SPI0,
515 Spi0,
516 pac::dma::vals::TreqSel::SPI0_TX,
517 pac::dma::vals::TreqSel::SPI0_RX
518);
519impl_instance!(
520 SPI1,
521 Spi1,
522 pac::dma::vals::TreqSel::SPI1_TX,
523 pac::dma::vals::TreqSel::SPI1_RX
524);
475 525
476/// CLK pin. 526/// CLK pin.
477pub trait ClkPin<T: Instance>: GpioPin {} 527pub trait ClkPin<T: Instance>: GpioPin {}
@@ -518,6 +568,42 @@ impl_pin!(PIN_26, SPI1, ClkPin);
518impl_pin!(PIN_27, SPI1, MosiPin); 568impl_pin!(PIN_27, SPI1, MosiPin);
519impl_pin!(PIN_28, SPI1, MisoPin); 569impl_pin!(PIN_28, SPI1, MisoPin);
520impl_pin!(PIN_29, SPI1, CsPin); 570impl_pin!(PIN_29, SPI1, CsPin);
571#[cfg(feature = "rp235xb")]
572impl_pin!(PIN_30, SPI1, ClkPin);
573#[cfg(feature = "rp235xb")]
574impl_pin!(PIN_31, SPI1, MosiPin);
575#[cfg(feature = "rp235xb")]
576impl_pin!(PIN_32, SPI0, MisoPin);
577#[cfg(feature = "rp235xb")]
578impl_pin!(PIN_33, SPI0, CsPin);
579#[cfg(feature = "rp235xb")]
580impl_pin!(PIN_34, SPI0, ClkPin);
581#[cfg(feature = "rp235xb")]
582impl_pin!(PIN_35, SPI0, MosiPin);
583#[cfg(feature = "rp235xb")]
584impl_pin!(PIN_36, SPI0, MisoPin);
585#[cfg(feature = "rp235xb")]
586impl_pin!(PIN_37, SPI0, CsPin);
587#[cfg(feature = "rp235xb")]
588impl_pin!(PIN_38, SPI0, ClkPin);
589#[cfg(feature = "rp235xb")]
590impl_pin!(PIN_39, SPI0, MosiPin);
591#[cfg(feature = "rp235xb")]
592impl_pin!(PIN_40, SPI1, MisoPin);
593#[cfg(feature = "rp235xb")]
594impl_pin!(PIN_41, SPI1, CsPin);
595#[cfg(feature = "rp235xb")]
596impl_pin!(PIN_42, SPI1, ClkPin);
597#[cfg(feature = "rp235xb")]
598impl_pin!(PIN_43, SPI1, MosiPin);
599#[cfg(feature = "rp235xb")]
600impl_pin!(PIN_44, SPI1, MisoPin);
601#[cfg(feature = "rp235xb")]
602impl_pin!(PIN_45, SPI1, CsPin);
603#[cfg(feature = "rp235xb")]
604impl_pin!(PIN_46, SPI1, ClkPin);
605#[cfg(feature = "rp235xb")]
606impl_pin!(PIN_47, SPI1, MosiPin);
521 607
522macro_rules! impl_mode { 608macro_rules! impl_mode {
523 ($name:ident) => { 609 ($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};
10use crate::interrupt::InterruptExt; 10use crate::interrupt::InterruptExt;
11use crate::{interrupt, pac}; 11use crate::{interrupt, pac};
12 12
13#[cfg(feature = "rp2040")]
14use pac::TIMER;
15#[cfg(feature = "rp235x")]
16use pac::TIMER0 as TIMER;
17
13struct AlarmState { 18struct AlarmState {
14 timestamp: Cell<u64>, 19 timestamp: Cell<u64>,
15 callback: Cell<Option<(fn(*mut ()), *mut ())>>, 20 callback: Cell<Option<(fn(*mut ()), *mut ())>>,
@@ -35,9 +40,9 @@ embassy_time_driver::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{
35impl Driver for TimerDriver { 40impl Driver for TimerDriver {
36 fn now(&self) -> u64 { 41 fn now(&self) -> u64 {
37 loop { 42 loop {
38 let hi = pac::TIMER.timerawh().read(); 43 let hi = TIMER.timerawh().read();
39 let lo = pac::TIMER.timerawl().read(); 44 let lo = TIMER.timerawl().read();
40 let hi2 = pac::TIMER.timerawh().read(); 45 let hi2 = TIMER.timerawh().read();
41 if hi == hi2 { 46 if hi == hi2 {
42 return (hi as u64) << 32 | (lo as u64); 47 return (hi as u64) << 32 | (lo as u64);
43 } 48 }
@@ -77,13 +82,13 @@ impl Driver for TimerDriver {
77 // Note that we're not checking the high bits at all. This means the irq may fire early 82 // Note that we're not checking the high bits at all. This means the irq may fire early
78 // if the alarm is more than 72 minutes (2^32 us) in the future. This is OK, since on irq fire 83 // if the alarm is more than 72 minutes (2^32 us) in the future. This is OK, since on irq fire
79 // it is checked if the alarm time has passed. 84 // it is checked if the alarm time has passed.
80 pac::TIMER.alarm(n).write_value(timestamp as u32); 85 TIMER.alarm(n).write_value(timestamp as u32);
81 86
82 let now = self.now(); 87 let now = self.now();
83 if timestamp <= now { 88 if timestamp <= now {
84 // If alarm timestamp has passed the alarm will not fire. 89 // If alarm timestamp has passed the alarm will not fire.
85 // Disarm the alarm and return `false` to indicate that. 90 // Disarm the alarm and return `false` to indicate that.
86 pac::TIMER.armed().write(|w| w.set_armed(1 << n)); 91 TIMER.armed().write(|w| w.set_armed(1 << n));
87 92
88 alarm.timestamp.set(u64::MAX); 93 alarm.timestamp.set(u64::MAX);
89 94
@@ -105,17 +110,17 @@ impl TimerDriver {
105 } else { 110 } else {
106 // Not elapsed, arm it again. 111 // Not elapsed, arm it again.
107 // This can happen if it was set more than 2^32 us in the future. 112 // This can happen if it was set more than 2^32 us in the future.
108 pac::TIMER.alarm(n).write_value(timestamp as u32); 113 TIMER.alarm(n).write_value(timestamp as u32);
109 } 114 }
110 }); 115 });
111 116
112 // clear the irq 117 // clear the irq
113 pac::TIMER.intr().write(|w| w.set_alarm(n, true)); 118 TIMER.intr().write(|w| w.set_alarm(n, true));
114 } 119 }
115 120
116 fn trigger_alarm(&self, n: usize, cs: CriticalSection) { 121 fn trigger_alarm(&self, n: usize, cs: CriticalSection) {
117 // disarm 122 // disarm
118 pac::TIMER.armed().write(|w| w.set_armed(1 << n)); 123 TIMER.armed().write(|w| w.set_armed(1 << n));
119 124
120 let alarm = &self.alarms.borrow(cs)[n]; 125 let alarm = &self.alarms.borrow(cs)[n];
121 alarm.timestamp.set(u64::MAX); 126 alarm.timestamp.set(u64::MAX);
@@ -138,38 +143,72 @@ pub unsafe fn init() {
138 }); 143 });
139 144
140 // enable all irqs 145 // enable all irqs
141 pac::TIMER.inte().write(|w| { 146 TIMER.inte().write(|w| {
142 w.set_alarm(0, true); 147 w.set_alarm(0, true);
143 w.set_alarm(1, true); 148 w.set_alarm(1, true);
144 w.set_alarm(2, true); 149 w.set_alarm(2, true);
145 w.set_alarm(3, true); 150 w.set_alarm(3, true);
146 }); 151 });
147 interrupt::TIMER_IRQ_0.enable(); 152 #[cfg(feature = "rp2040")]
148 interrupt::TIMER_IRQ_1.enable(); 153 {
149 interrupt::TIMER_IRQ_2.enable(); 154 interrupt::TIMER_IRQ_0.enable();
150 interrupt::TIMER_IRQ_3.enable(); 155 interrupt::TIMER_IRQ_1.enable();
156 interrupt::TIMER_IRQ_2.enable();
157 interrupt::TIMER_IRQ_3.enable();
158 }
159 #[cfg(feature = "rp235x")]
160 {
161 interrupt::TIMER0_IRQ_0.enable();
162 interrupt::TIMER0_IRQ_1.enable();
163 interrupt::TIMER0_IRQ_2.enable();
164 interrupt::TIMER0_IRQ_3.enable();
165 }
151} 166}
152 167
153#[cfg(feature = "rt")] 168#[cfg(all(feature = "rt", feature = "rp2040"))]
154#[interrupt] 169#[interrupt]
155fn TIMER_IRQ_0() { 170fn TIMER_IRQ_0() {
156 DRIVER.check_alarm(0) 171 DRIVER.check_alarm(0)
157} 172}
158 173
159#[cfg(feature = "rt")] 174#[cfg(all(feature = "rt", feature = "rp2040"))]
160#[interrupt] 175#[interrupt]
161fn TIMER_IRQ_1() { 176fn TIMER_IRQ_1() {
162 DRIVER.check_alarm(1) 177 DRIVER.check_alarm(1)
163} 178}
164 179
165#[cfg(feature = "rt")] 180#[cfg(all(feature = "rt", feature = "rp2040"))]
166#[interrupt] 181#[interrupt]
167fn TIMER_IRQ_2() { 182fn TIMER_IRQ_2() {
168 DRIVER.check_alarm(2) 183 DRIVER.check_alarm(2)
169} 184}
170 185
171#[cfg(feature = "rt")] 186#[cfg(all(feature = "rt", feature = "rp2040"))]
172#[interrupt] 187#[interrupt]
173fn TIMER_IRQ_3() { 188fn TIMER_IRQ_3() {
174 DRIVER.check_alarm(3) 189 DRIVER.check_alarm(3)
175} 190}
191
192#[cfg(all(feature = "rt", feature = "rp235x"))]
193#[interrupt]
194fn TIMER0_IRQ_0() {
195 DRIVER.check_alarm(0)
196}
197
198#[cfg(all(feature = "rt", feature = "rp235x"))]
199#[interrupt]
200fn TIMER0_IRQ_1() {
201 DRIVER.check_alarm(1)
202}
203
204#[cfg(all(feature = "rt", feature = "rp235x"))]
205#[interrupt]
206fn TIMER0_IRQ_2() {
207 DRIVER.check_alarm(2)
208}
209
210#[cfg(all(feature = "rt", feature = "rp235x"))]
211#[interrupt]
212fn TIMER0_IRQ_3() {
213 DRIVER.check_alarm(3)
214}
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs
index d50f5b4d5..058cfcbee 100644
--- a/embassy-rp/src/uart/mod.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -247,7 +247,7 @@ impl<'d, T: Instance> UartTx<'d, T, Async> {
247 }); 247 });
248 // If we don't assign future to a variable, the data register pointer 248 // If we don't assign future to a variable, the data register pointer
249 // is held across an await and makes the future non-Send. 249 // is held across an await and makes the future non-Send.
250 crate::dma::write(ch, buffer, T::regs().uartdr().as_ptr() as *mut _, T::TX_DREQ) 250 crate::dma::write(ch, buffer, T::regs().uartdr().as_ptr() as *mut _, T::TX_DREQ.into())
251 }; 251 };
252 transfer.await; 252 transfer.await;
253 Ok(()) 253 Ok(())
@@ -422,7 +422,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
422 let transfer = unsafe { 422 let transfer = unsafe {
423 // If we don't assign future to a variable, the data register pointer 423 // If we don't assign future to a variable, the data register pointer
424 // is held across an await and makes the future non-Send. 424 // is held across an await and makes the future non-Send.
425 crate::dma::read(ch, T::regs().uartdr().as_ptr() as *const _, buffer, T::RX_DREQ) 425 crate::dma::read(ch, T::regs().uartdr().as_ptr() as *const _, buffer, T::RX_DREQ.into())
426 }; 426 };
427 427
428 // wait for either the transfer to complete or an error to happen. 428 // wait for either the transfer to complete or an error to happen.
@@ -571,7 +571,12 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
571 let transfer = unsafe { 571 let transfer = unsafe {
572 // If we don't assign future to a variable, the data register pointer 572 // If we don't assign future to a variable, the data register pointer
573 // is held across an await and makes the future non-Send. 573 // is held across an await and makes the future non-Send.
574 crate::dma::read(&mut ch, T::regs().uartdr().as_ptr() as *const _, sbuffer, T::RX_DREQ) 574 crate::dma::read(
575 &mut ch,
576 T::regs().uartdr().as_ptr() as *const _,
577 sbuffer,
578 T::RX_DREQ.into(),
579 )
575 }; 580 };
576 581
577 // wait for either the transfer to complete or an error to happen. 582 // wait for either the transfer to complete or an error to happen.
@@ -830,8 +835,16 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
830 ) { 835 ) {
831 let r = T::regs(); 836 let r = T::regs();
832 if let Some(pin) = &tx { 837 if let Some(pin) = &tx {
838 let funcsel = {
839 let pin_number = ((pin.gpio().as_ptr() as u32) & 0x1FF) / 8;
840 if (pin_number % 4) == 0 {
841 2
842 } else {
843 11
844 }
845 };
833 pin.gpio().ctrl().write(|w| { 846 pin.gpio().ctrl().write(|w| {
834 w.set_funcsel(2); 847 w.set_funcsel(funcsel);
835 w.set_outover(if config.invert_tx { 848 w.set_outover(if config.invert_tx {
836 Outover::INVERT 849 Outover::INVERT
837 } else { 850 } else {
@@ -841,8 +854,16 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
841 pin.pad_ctrl().write(|w| w.set_ie(true)); 854 pin.pad_ctrl().write(|w| w.set_ie(true));
842 } 855 }
843 if let Some(pin) = &rx { 856 if let Some(pin) = &rx {
857 let funcsel = {
858 let pin_number = ((pin.gpio().as_ptr() as u32) & 0x1FF) / 8;
859 if ((pin_number - 1) % 4) == 0 {
860 2
861 } else {
862 11
863 }
864 };
844 pin.gpio().ctrl().write(|w| { 865 pin.gpio().ctrl().write(|w| {
845 w.set_funcsel(2); 866 w.set_funcsel(funcsel);
846 w.set_inover(if config.invert_rx { 867 w.set_inover(if config.invert_rx {
847 Inover::INVERT 868 Inover::INVERT
848 } else { 869 } else {
@@ -904,7 +925,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
904 }); 925 });
905 } 926 }
906 927
907 fn lcr_modify<R>(f: impl FnOnce(&mut rp_pac::uart::regs::UartlcrH) -> R) -> R { 928 fn lcr_modify<R>(f: impl FnOnce(&mut crate::pac::uart::regs::UartlcrH) -> R) -> R {
908 let r = T::regs(); 929 let r = T::regs();
909 930
910 // Notes from PL011 reference manual: 931 // Notes from PL011 reference manual:
@@ -1332,3 +1353,92 @@ impl_pin!(PIN_26, UART1, CtsPin);
1332impl_pin!(PIN_27, UART1, RtsPin); 1353impl_pin!(PIN_27, UART1, RtsPin);
1333impl_pin!(PIN_28, UART0, TxPin); 1354impl_pin!(PIN_28, UART0, TxPin);
1334impl_pin!(PIN_29, UART0, RxPin); 1355impl_pin!(PIN_29, UART0, RxPin);
1356
1357// Additional functions added by all 2350s
1358#[cfg(feature = "rp235x")]
1359impl_pin!(PIN_2, UART0, TxPin);
1360#[cfg(feature = "rp235x")]
1361impl_pin!(PIN_3, UART0, RxPin);
1362#[cfg(feature = "rp235x")]
1363impl_pin!(PIN_6, UART1, TxPin);
1364#[cfg(feature = "rp235x")]
1365impl_pin!(PIN_7, UART1, RxPin);
1366#[cfg(feature = "rp235x")]
1367impl_pin!(PIN_10, UART1, TxPin);
1368#[cfg(feature = "rp235x")]
1369impl_pin!(PIN_11, UART1, RxPin);
1370#[cfg(feature = "rp235x")]
1371impl_pin!(PIN_14, UART0, TxPin);
1372#[cfg(feature = "rp235x")]
1373impl_pin!(PIN_15, UART0, RxPin);
1374#[cfg(feature = "rp235x")]
1375impl_pin!(PIN_18, UART0, TxPin);
1376#[cfg(feature = "rp235x")]
1377impl_pin!(PIN_19, UART0, RxPin);
1378#[cfg(feature = "rp235x")]
1379impl_pin!(PIN_22, UART1, TxPin);
1380#[cfg(feature = "rp235x")]
1381impl_pin!(PIN_23, UART1, RxPin);
1382#[cfg(feature = "rp235x")]
1383impl_pin!(PIN_26, UART1, TxPin);
1384#[cfg(feature = "rp235x")]
1385impl_pin!(PIN_27, UART1, RxPin);
1386
1387// Additional pins added by larger 2350 packages.
1388#[cfg(feature = "rp235xb")]
1389impl_pin!(PIN_30, UART0, CtsPin);
1390#[cfg(feature = "rp235xb")]
1391impl_pin!(PIN_31, UART0, RtsPin);
1392#[cfg(feature = "rp235xb")]
1393impl_pin!(PIN_32, UART0, TxPin);
1394#[cfg(feature = "rp235xb")]
1395impl_pin!(PIN_33, UART0, RxPin);
1396#[cfg(feature = "rp235xb")]
1397impl_pin!(PIN_34, UART0, CtsPin);
1398#[cfg(feature = "rp235xb")]
1399impl_pin!(PIN_35, UART0, RtsPin);
1400#[cfg(feature = "rp235xb")]
1401impl_pin!(PIN_36, UART1, TxPin);
1402#[cfg(feature = "rp235xb")]
1403impl_pin!(PIN_37, UART1, RxPin);
1404#[cfg(feature = "rp235xb")]
1405impl_pin!(PIN_38, UART1, CtsPin);
1406#[cfg(feature = "rp235xb")]
1407impl_pin!(PIN_39, UART1, RtsPin);
1408#[cfg(feature = "rp235xb")]
1409impl_pin!(PIN_40, UART1, TxPin);
1410#[cfg(feature = "rp235xb")]
1411impl_pin!(PIN_41, UART1, RxPin);
1412#[cfg(feature = "rp235xb")]
1413impl_pin!(PIN_42, UART1, CtsPin);
1414#[cfg(feature = "rp235xb")]
1415impl_pin!(PIN_43, UART1, RtsPin);
1416#[cfg(feature = "rp235xb")]
1417impl_pin!(PIN_44, UART0, TxPin);
1418#[cfg(feature = "rp235xb")]
1419impl_pin!(PIN_45, UART0, RxPin);
1420#[cfg(feature = "rp235xb")]
1421impl_pin!(PIN_46, UART0, CtsPin);
1422#[cfg(feature = "rp235xb")]
1423impl_pin!(PIN_47, UART0, RtsPin);
1424
1425#[cfg(feature = "rp235xb")]
1426impl_pin!(PIN_30, UART0, TxPin);
1427#[cfg(feature = "rp235xb")]
1428impl_pin!(PIN_31, UART0, RxPin);
1429#[cfg(feature = "rp235xb")]
1430impl_pin!(PIN_34, UART0, TxPin);
1431#[cfg(feature = "rp235xb")]
1432impl_pin!(PIN_35, UART0, RxPin);
1433#[cfg(feature = "rp235xb")]
1434impl_pin!(PIN_38, UART1, TxPin);
1435#[cfg(feature = "rp235xb")]
1436impl_pin!(PIN_39, UART1, RxPin);
1437#[cfg(feature = "rp235xb")]
1438impl_pin!(PIN_42, UART1, TxPin);
1439#[cfg(feature = "rp235xb")]
1440impl_pin!(PIN_43, UART1, RxPin);
1441#[cfg(feature = "rp235xb")]
1442impl_pin!(PIN_46, UART0, TxPin);
1443#[cfg(feature = "rp235xb")]
1444impl_pin!(PIN_47, UART0, RxPin);
diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs
index 512271ae4..20ef881f9 100644
--- a/embassy-rp/src/usb.rs
+++ b/embassy-rp/src/usb.rs
@@ -28,10 +28,10 @@ pub trait Instance: SealedInstance + 'static {
28 28
29impl crate::usb::SealedInstance for peripherals::USB { 29impl crate::usb::SealedInstance for peripherals::USB {
30 fn regs() -> pac::usb::Usb { 30 fn regs() -> pac::usb::Usb {
31 pac::USBCTRL_REGS 31 pac::USB
32 } 32 }
33 fn dpram() -> crate::pac::usb_dpram::UsbDpram { 33 fn dpram() -> crate::pac::usb_dpram::UsbDpram {
34 pac::USBCTRL_DPRAM 34 pac::USB_DPRAM
35 } 35 }
36} 36}
37 37
@@ -41,7 +41,7 @@ impl crate::usb::Instance for peripherals::USB {
41 41
42const EP_COUNT: usize = 16; 42const EP_COUNT: usize = 16;
43const EP_MEMORY_SIZE: usize = 4096; 43const EP_MEMORY_SIZE: usize = 4096;
44const EP_MEMORY: *mut u8 = pac::USBCTRL_DPRAM.as_ptr() as *mut u8; 44const EP_MEMORY: *mut u8 = pac::USB_DPRAM.as_ptr() as *mut u8;
45 45
46const NEW_AW: AtomicWaker = AtomicWaker::new(); 46const NEW_AW: AtomicWaker = AtomicWaker::new();
47static BUS_WAKER: AtomicWaker = NEW_AW; 47static BUS_WAKER: AtomicWaker = NEW_AW;
diff --git a/embassy-rp/src/watchdog.rs b/embassy-rp/src/watchdog.rs
index 229a306fe..edd48e0e0 100644
--- a/embassy-rp/src/watchdog.rs
+++ b/embassy-rp/src/watchdog.rs
@@ -34,6 +34,7 @@ impl Watchdog {
34 /// 34 ///
35 /// * `cycles` - Total number of tick cycles before the next tick is generated. 35 /// * `cycles` - Total number of tick cycles before the next tick is generated.
36 /// It is expected to be the frequency in MHz of clk_ref. 36 /// It is expected to be the frequency in MHz of clk_ref.
37 #[cfg(feature = "rp2040")]
37 pub fn enable_tick_generation(&mut self, cycles: u8) { 38 pub fn enable_tick_generation(&mut self, cycles: u8) {
38 let watchdog = pac::WATCHDOG; 39 let watchdog = pac::WATCHDOG;
39 watchdog.tick().write(|w| { 40 watchdog.tick().write(|w| {