aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2021-03-29 04:11:32 +0200
committerDario Nieuwenhuis <[email protected]>2021-03-29 21:35:25 +0200
commit2cd3bdc90cf5da6d07ddad91e875733b8e354dc5 (patch)
tree846d9ef3d4b3171a6fcf4febe1a79aefa23cd378
parent2bcd1aaebbf255de1ded97356c107df5bea04e57 (diff)
rp: add initial version
-rw-r--r--.vscode/settings.json4
-rw-r--r--Cargo.toml4
-rw-r--r--embassy-macros/Cargo.toml1
-rw-r--r--embassy-macros/src/chip/nrf.rs1
-rw-r--r--embassy-macros/src/chip/rp.rs16
-rw-r--r--embassy-macros/src/chip/stm32.rs1
-rw-r--r--embassy-macros/src/lib.rs13
-rw-r--r--embassy-rp-examples/.cargo/config30
-rw-r--r--embassy-rp-examples/Cargo.toml33
-rw-r--r--embassy-rp-examples/build.rs31
-rw-r--r--embassy-rp-examples/memory.x13
-rw-r--r--embassy-rp-examples/src/main.rs72
-rw-r--r--embassy-rp/Cargo.toml25
-rw-r--r--embassy-rp/funcsel.txt30
-rw-r--r--embassy-rp/src/dma.rs87
-rw-r--r--embassy-rp/src/fmt.rs118
-rw-r--r--embassy-rp/src/gpio.rs250
-rw-r--r--embassy-rp/src/interrupt.rs110
-rw-r--r--embassy-rp/src/lib.rs74
-rw-r--r--embassy-rp/src/pll.rs79
-rw-r--r--embassy-rp/src/resets.rs29
-rw-r--r--embassy-rp/src/system.rs90
-rw-r--r--embassy-rp/src/uart.rs173
23 files changed, 1277 insertions, 7 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 58ef9d8af..9818e4f1d 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -5,8 +5,8 @@
5 "rust-analyzer.cargo.allFeatures": false, 5 "rust-analyzer.cargo.allFeatures": false,
6 "rust-analyzer.checkOnSave.allFeatures": false, 6 "rust-analyzer.checkOnSave.allFeatures": false,
7 "rust-analyzer.checkOnSave.allTargets": false, 7 "rust-analyzer.checkOnSave.allTargets": false,
8 "rust-analyzer.cargo.target": "thumbv7em-none-eabi", 8 "rust-analyzer.cargo.target": "thumbv6m-none-eabi",
9 "rust-analyzer.checkOnSave.target": "thumbv7em-none-eabi", 9 "rust-analyzer.checkOnSave.target": "thumbv6m-none-eabi",
10 "rust-analyzer.procMacro.enable": true, 10 "rust-analyzer.procMacro.enable": true,
11 "rust-analyzer.cargo.loadOutDirsFromCheck": true, 11 "rust-analyzer.cargo.loadOutDirsFromCheck": true,
12 "files.watcherExclude": { 12 "files.watcherExclude": {
diff --git a/Cargo.toml b/Cargo.toml
index d9fbeaf45..bc3fcdd37 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,6 +19,8 @@ members = [
19exclude = [ 19exclude = [
20 "embassy-std", 20 "embassy-std",
21 "embassy-std-examples", 21 "embassy-std-examples",
22 "embassy-rp",
23 "embassy-rp-examples",
22] 24]
23 25
24[profile.dev] 26[profile.dev]
@@ -52,3 +54,5 @@ debug = false
52debug-assertions = false 54debug-assertions = false
53opt-level = 0 55opt-level = 0
54overflow-checks = false 56overflow-checks = false
57
58[patch.crates-io]
diff --git a/embassy-macros/Cargo.toml b/embassy-macros/Cargo.toml
index a3d2fd37c..20dc7c381 100644
--- a/embassy-macros/Cargo.toml
+++ b/embassy-macros/Cargo.toml
@@ -16,3 +16,4 @@ proc-macro = true
16[features] 16[features]
17stm32 = [] 17stm32 = []
18nrf = [] 18nrf = []
19rp = []
diff --git a/embassy-macros/src/chip/nrf.rs b/embassy-macros/src/chip/nrf.rs
index d89223415..b2d1c322f 100644
--- a/embassy-macros/src/chip/nrf.rs
+++ b/embassy-macros/src/chip/nrf.rs
@@ -58,5 +58,6 @@ pub fn generate(args: Args) -> TokenStream {
58 unsafe { embassy::time::set_clock(rtc) }; 58 unsafe { embassy::time::set_clock(rtc) };
59 59
60 let alarm = unsafe { make_static(&mut alarm) }; 60 let alarm = unsafe { make_static(&mut alarm) };
61 executor.set_alarm(alarm);
61 ) 62 )
62} 63}
diff --git a/embassy-macros/src/chip/rp.rs b/embassy-macros/src/chip/rp.rs
new file mode 100644
index 000000000..25c6705cd
--- /dev/null
+++ b/embassy-macros/src/chip/rp.rs
@@ -0,0 +1,16 @@
1use darling::FromMeta;
2use proc_macro2::TokenStream;
3use quote::{format_ident, quote};
4use syn::spanned::Spanned;
5
6#[derive(Debug, FromMeta)]
7pub struct Args {}
8
9pub fn generate(args: Args) -> TokenStream {
10 quote!(
11 use embassy_rp::{interrupt, peripherals};
12
13 let mut config = embassy_rp::system::Config::default();
14 unsafe { embassy_rp::system::configure(config) };
15 )
16}
diff --git a/embassy-macros/src/chip/stm32.rs b/embassy-macros/src/chip/stm32.rs
index e94c21a97..2476a9623 100644
--- a/embassy-macros/src/chip/stm32.rs
+++ b/embassy-macros/src/chip/stm32.rs
@@ -53,5 +53,6 @@ pub fn generate(args: Args) -> TokenStream {
53 unsafe { embassy::time::set_clock(rtc) }; 53 unsafe { embassy::time::set_clock(rtc) };
54 54
55 let alarm = unsafe { make_static(&mut alarm) }; 55 let alarm = unsafe { make_static(&mut alarm) };
56 executor.set_alarm(alarm);
56 ) 57 )
57} 58}
diff --git a/embassy-macros/src/lib.rs b/embassy-macros/src/lib.rs
index 145714f22..72f0b0eca 100644
--- a/embassy-macros/src/lib.rs
+++ b/embassy-macros/src/lib.rs
@@ -125,7 +125,7 @@ pub fn interrupt_declare(item: TokenStream) -> TokenStream {
125 type Priority = crate::interrupt::Priority; 125 type Priority = crate::interrupt::Priority;
126 fn number(&self) -> u16 { 126 fn number(&self) -> u16 {
127 use cortex_m::interrupt::InterruptNumber; 127 use cortex_m::interrupt::InterruptNumber;
128 let irq = crate::pac::interrupt::#name; 128 let irq = crate::pac::Interrupt::#name;
129 irq.number() as u16 129 irq.number() as u16
130 } 130 }
131 unsafe fn steal() -> Self { 131 unsafe fn steal() -> Self {
@@ -199,7 +199,11 @@ mod chip;
199#[path = "chip/stm32.rs"] 199#[path = "chip/stm32.rs"]
200mod chip; 200mod chip;
201 201
202#[cfg(any(feature = "nrf", feature = "stm32"))] 202#[cfg(feature = "rp")]
203#[path = "chip/rp.rs"]
204mod chip;
205
206#[cfg(any(feature = "nrf", feature = "stm32", feature = "rp"))]
203#[proc_macro_attribute] 207#[proc_macro_attribute]
204pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { 208pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
205 let macro_args = syn::parse_macro_input!(args as syn::AttributeArgs); 209 let macro_args = syn::parse_macro_input!(args as syn::AttributeArgs);
@@ -267,11 +271,10 @@ pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
267 ::core::mem::transmute(t) 271 ::core::mem::transmute(t)
268 } 272 }
269 273
270 #chip_setup
271
272 let mut executor = ::embassy::executor::Executor::new(); 274 let mut executor = ::embassy::executor::Executor::new();
273 let executor = unsafe { make_static(&mut executor) }; 275 let executor = unsafe { make_static(&mut executor) };
274 executor.set_alarm(alarm); 276
277 #chip_setup
275 278
276 executor.run(|spawner| { 279 executor.run(|spawner| {
277 spawner.spawn(__embassy_main(spawner)).unwrap(); 280 spawner.spawn(__embassy_main(spawner)).unwrap();
diff --git a/embassy-rp-examples/.cargo/config b/embassy-rp-examples/.cargo/config
new file mode 100644
index 000000000..1f6a94f88
--- /dev/null
+++ b/embassy-rp-examples/.cargo/config
@@ -0,0 +1,30 @@
1[unstable]
2build-std = ["core"]
3build-std-features = ["panic_immediate_abort"]
4
5[target.'cfg(all(target_arch = "arm", target_os = "none"))']
6runner = "probe-run-rp --chip RP2040"
7
8rustflags = [
9 # LLD (shipped with the Rust toolchain) is used as the default linker
10 "-C", "link-arg=--nmagic",
11 "-C", "link-arg=-Tlink.x",
12 "-C", "link-arg=-Tdefmt.x",
13
14 # if you run into problems with LLD switch to the GNU linker by commenting out
15 # this line
16 # "-C", "linker=arm-none-eabi-ld",
17
18 # if you need to link to pre-compiled C libraries provided by a C toolchain
19 # use GCC as the linker by commenting out both lines above and then
20 # uncommenting the three lines below
21 # "-C", "linker=arm-none-eabi-gcc",
22 # "-C", "link-arg=-Wl,-Tlink.x",
23 # "-C", "link-arg=-nostartfiles",
24
25 # Code-size optimizations.
26 "-Z", "trap-unreachable=no",
27]
28
29[build]
30target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
diff --git a/embassy-rp-examples/Cargo.toml b/embassy-rp-examples/Cargo.toml
new file mode 100644
index 000000000..0744fa1e9
--- /dev/null
+++ b/embassy-rp-examples/Cargo.toml
@@ -0,0 +1,33 @@
1[package]
2authors = ["Dario Nieuwenhuis <[email protected]>"]
3edition = "2018"
4name = "embassy-rp-examples"
5version = "0.1.0"
6
7[features]
8default = [
9 "defmt-default",
10]
11defmt-default = []
12defmt-trace = []
13defmt-debug = []
14defmt-info = []
15defmt-warn = []
16defmt-error = []
17
18
19[dependencies]
20embassy = { version = "0.1.0", path = "../embassy", features = ["defmt", "defmt-trace"] }
21embassy-rp = { version = "0.1.0", path = "../embassy-rp", features = ["defmt", "defmt-trace"] }
22rp2040-boot2 = { git = "https://github.com/rp-rs/rp2040-boot2-rs", branch="main" }
23rp2040-pac2 = { git = "https://github.com/Dirbaio/rp2040-pac", rev="254f4677937801155ca3cb17c7bb9d38eb62683e" }
24atomic-polyfill = { version = "0.1.1" }
25
26defmt = "0.2.0"
27defmt-rtt = "0.2.0"
28
29cortex-m = { version = "0.7.1", features = ["inline-asm"] }
30cortex-m-rt = "0.6.13"
31embedded-hal = { version = "0.2.4" }
32panic-probe = "0.1.0"
33futures = { version = "0.3.8", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } \ No newline at end of file
diff --git a/embassy-rp-examples/build.rs b/embassy-rp-examples/build.rs
new file mode 100644
index 000000000..d534cc3df
--- /dev/null
+++ b/embassy-rp-examples/build.rs
@@ -0,0 +1,31 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31}
diff --git a/embassy-rp-examples/memory.x b/embassy-rp-examples/memory.x
new file mode 100644
index 000000000..0596611d2
--- /dev/null
+++ b/embassy-rp-examples/memory.x
@@ -0,0 +1,13 @@
1MEMORY {
2 BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
3 FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
4 RAM : ORIGIN = 0x20000000, LENGTH = 256K
5}
6
7SECTIONS {
8 /* ### Boot loader */
9 .boot2 ORIGIN(BOOT2) :
10 {
11 KEEP(*(.boot2));
12 } > BOOT2
13} INSERT BEFORE .text; \ No newline at end of file
diff --git a/embassy-rp-examples/src/main.rs b/embassy-rp-examples/src/main.rs
new file mode 100644
index 000000000..e1da77aa5
--- /dev/null
+++ b/embassy-rp-examples/src/main.rs
@@ -0,0 +1,72 @@
1#![no_std]
2#![no_main]
3#![feature(asm)]
4#![feature(min_type_alias_impl_trait)]
5#![feature(impl_trait_in_bindings)]
6#![feature(type_alias_impl_trait)]
7
8use core::sync::atomic::{AtomicUsize, Ordering};
9use defmt::{panic, *};
10use defmt_rtt as _;
11use embassy::executor::Spawner;
12use embassy::interrupt::InterruptExt;
13use embassy_rp::{dma, gpio, interrupt, uart, Peripherals};
14use embedded_hal::digital::v2::OutputPin;
15use panic_probe as _;
16use rp2040_pac2 as pac;
17
18#[link_section = ".boot2"]
19#[used]
20pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER;
21
22defmt::timestamp! {"{=u64}", {
23 static COUNT: AtomicUsize = AtomicUsize::new(0);
24 // NOTE(no-CAS) `timestamps` runs with interrupts disabled
25 let n = COUNT.load(Ordering::Relaxed);
26 COUNT.store(n + 1, Ordering::Relaxed);
27 n as u64
28}
29}
30
31#[embassy::main]
32async fn main(spanwer: Spawner) {
33 let p = unwrap!(Peripherals::take());
34
35 let mut config = uart::Config::default();
36 let mut uart = uart::Uart::new(p.UART0, p.PIN_0, p.PIN_1, p.PIN_2, p.PIN_3, config);
37 uart.send("Hello World!\r\n".as_bytes());
38
39 let mut led = gpio::Output::new(p.PIN_25, gpio::Level::Low);
40
41 let irq = interrupt::take!(DMA_IRQ_0);
42 unsafe {
43 //pac::DMA.inte0().write(|w| w.set_inte0(1 << 0));
44 }
45 irq.set_handler(dma_irq);
46 irq.unpend();
47 irq.enable();
48
49 let from: [u32; 4] = [1, 2, 3, 4];
50 let mut to: [u32; 4] = [9, 8, 7, 6];
51 info!("before dma: from = {:?}, to = {:?}", from, to);
52 cortex_m::asm::delay(4_000_000);
53 dma::Dma::copy(p.DMA_CH0, &from, &mut to);
54 cortex_m::asm::delay(4_000_000);
55 info!("after dma: from = {:?}, to = {:?}", from, to);
56
57 loop {
58 info!("led on!");
59 uart.send("ON!\r".as_bytes());
60 led.set_high().unwrap();
61 cortex_m::asm::delay(1_000_000);
62
63 info!("led off!");
64 uart.send("Off!\r".as_bytes());
65 led.set_low().unwrap();
66 cortex_m::asm::delay(4_000_000);
67 }
68}
69
70unsafe fn dma_irq(ctx: *mut ()) {
71 info!("DMA IRQ!");
72}
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
new file mode 100644
index 000000000..1d11fb0d7
--- /dev/null
+++ b/embassy-rp/Cargo.toml
@@ -0,0 +1,25 @@
1[package]
2name = "embassy-rp"
3version = "0.1.0"
4authors = ["Dario Nieuwenhuis <[email protected]>"]
5edition = "2018"
6
7[features]
8defmt-trace = [ ]
9defmt-debug = [ ]
10defmt-info = [ ]
11defmt-warn = [ ]
12defmt-error = [ ]
13
14[dependencies]
15embassy = { version = "0.1.0", path = "../embassy" }
16embassy-extras = {version = "0.1.0", path = "../embassy-extras" }
17embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["rp"]}
18
19defmt = { version = "0.2.0", optional = true }
20log = { version = "0.4.11", optional = true }
21cortex-m-rt = "0.6.13"
22cortex-m = "0.7.1"
23
24rp2040-pac2 = { git = "https://github.com/Dirbaio/rp2040-pac", rev="254f4677937801155ca3cb17c7bb9d38eb62683e", features = ["rt"] }
25embedded-hal = { version = "0.2.4", features = [ "unproven" ] }
diff --git a/embassy-rp/funcsel.txt b/embassy-rp/funcsel.txt
new file mode 100644
index 000000000..4dc893967
--- /dev/null
+++ b/embassy-rp/funcsel.txt
@@ -0,0 +1,30 @@
10 SPI0 RX UART0 TX I2C0 SDA PWM0 A SIO PIO0 PIO1 USB OVCUR DET
21 SPI0 CSn UART0 RX I2C0 SCL PWM0 B SIO PIO0 PIO1 USB VBUS DET
32 SPI0 SCK UART0 CTS I2C1 SDA PWM1 A SIO PIO0 PIO1 USB VBUS EN
43 SPI0 TX UART0 RTS I2C1 SCL PWM1 B SIO PIO0 PIO1 USB OVCUR DET
54 SPI0 RX UART1 TX I2C0 SDA PWM2 A SIO PIO0 PIO1 USB VBUS DET
65 SPI0 CSn UART1 RX I2C0 SCL PWM2 B SIO PIO0 PIO1 USB VBUS EN
76 SPI0 SCK UART1 CTS I2C1 SDA PWM3 A SIO PIO0 PIO1 USB OVCUR DET
87 SPI0 TX UART1 RTS I2C1 SCL PWM3 B SIO PIO0 PIO1 USB VBUS DET
98 SPI1 RX UART1 TX I2C0 SDA PWM4 A SIO PIO0 PIO1 USB VBUS EN
109 SPI1 CSn UART1 RX I2C0 SCL PWM4 B SIO PIO0 PIO1 USB OVCUR DET
1110 SPI1 SCK UART1 CTS I2C1 SDA PWM5 A SIO PIO0 PIO1 USB VBUS DET
1211 SPI1 TX UART1 RTS I2C1 SCL PWM5 B SIO PIO0 PIO1 USB VBUS EN
1312 SPI1 RX UART0 TX I2C0 SDA PWM6 A SIO PIO0 PIO1 USB OVCUR DET
1413 SPI1 CSn UART0 RX I2C0 SCL PWM6 B SIO PIO0 PIO1 USB VBUS DET
1514 SPI1 SCK UART0 CTS I2C1 SDA PWM7 A SIO PIO0 PIO1 USB VBUS EN
1615 SPI1 TX UART0 RTS I2C1 SCL PWM7 B SIO PIO0 PIO1 USB OVCUR DET
1716 SPI0 RX UART0 TX I2C0 SDA PWM0 A SIO PIO0 PIO1 USB VBUS DET
1817 SPI0 CSn UART0 RX I2C0 SCL PWM0 B SIO PIO0 PIO1 USB VBUS EN
1918 SPI0 SCK UART0 CTS I2C1 SDA PWM1 A SIO PIO0 PIO1 USB OVCUR DET
2019 SPI0 TX UART0 RTS I2C1 SCL PWM1 B SIO PIO0 PIO1 USB VBUS DET
2120 SPI0 RX UART1 TX I2C0 SDA PWM2 A SIO PIO0 PIO1 CLOCK GPIN0 USB VBUS EN
2221 SPI0 CSn UART1 RX I2C0 SCL PWM2 B SIO PIO0 PIO1 CLOCK GPOUT0 USB OVCUR DET
2322 SPI0 SCK UART1 CTS I2C1 SDA PWM3 A SIO PIO0 PIO1 CLOCK GPIN1 USB VBUS DET
2423 SPI0 TX UART1 RTS I2C1 SCL PWM3 B SIO PIO0 PIO1 CLOCK GPOUT1 USB VBUS EN
2524 SPI1 RX UART1 TX I2C0 SDA PWM4 A SIO PIO0 PIO1 CLOCK GPOUT2 USB OVCUR DET
2625 SPI1 CSn UART1 RX I2C0 SCL PWM4 B SIO PIO0 PIO1 CLOCK GPOUT3 USB VBUS DET
2726 SPI1 SCK UART1 CTS I2C1 SDA PWM5 A SIO PIO0 PIO1 USB VBUS EN
2827 SPI1 TX UART1 RTS I2C1 SCL PWM5 B SIO PIO0 PIO1 USB OVCUR DET
2928 SPI1 RX UART0 TX I2C0 SDA PWM6 A SIO PIO0 PIO1 USB VBUS DET
3029 SPI1 CSn UART0 RX I2C0 SCL PWM6 B SIO PIO0 PIO1 USB VBUS EN \ No newline at end of file
diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs
new file mode 100644
index 000000000..73be6d76c
--- /dev/null
+++ b/embassy-rp/src/dma.rs
@@ -0,0 +1,87 @@
1use core::sync::atomic::{compiler_fence, Ordering};
2
3use defmt::{assert, *};
4
5use crate::{pac, peripherals};
6use pac::dma::vals;
7
8pub struct Dma<T: Channel> {
9 inner: T,
10}
11
12impl<T: Channel> Dma<T> {
13 pub fn copy(inner: T, from: &[u32], to: &mut [u32]) {
14 assert!(from.len() == to.len());
15
16 unsafe {
17 let p = inner.regs();
18
19 p.read_addr().write_value(from.as_ptr() as u32);
20 p.write_addr().write_value(to.as_mut_ptr() as u32);
21 p.trans_count().write_value(from.len() as u32);
22
23 compiler_fence(Ordering::SeqCst);
24
25 p.ctrl_trig().write(|w| {
26 w.set_data_size(vals::DataSize::SIZE_WORD);
27 w.set_incr_read(true);
28 w.set_incr_write(true);
29 w.set_chain_to(inner.number());
30 w.set_en(true);
31 });
32
33 while p.ctrl_trig().read().busy() {}
34
35 compiler_fence(Ordering::SeqCst);
36 }
37 }
38}
39
40mod sealed {
41 use super::*;
42
43 pub trait Channel {
44 fn number(&self) -> u8;
45
46 fn regs(&self) -> pac::dma::Channel {
47 pac::DMA.ch(self.number() as _)
48 }
49 }
50}
51
52pub trait Channel: sealed::Channel {}
53
54pub struct AnyChannel {
55 number: u8,
56}
57
58impl Channel for AnyChannel {}
59impl sealed::Channel for AnyChannel {
60 fn number(&self) -> u8 {
61 self.number
62 }
63}
64
65macro_rules! channel {
66 ($type:ident, $num:expr) => {
67 impl Channel for peripherals::$type {}
68 impl sealed::Channel for peripherals::$type {
69 fn number(&self) -> u8 {
70 $num
71 }
72 }
73 };
74}
75
76channel!(DMA_CH0, 0);
77channel!(DMA_CH1, 1);
78channel!(DMA_CH2, 2);
79channel!(DMA_CH3, 3);
80channel!(DMA_CH4, 4);
81channel!(DMA_CH5, 5);
82channel!(DMA_CH6, 6);
83channel!(DMA_CH7, 7);
84channel!(DMA_CH8, 8);
85channel!(DMA_CH9, 9);
86channel!(DMA_CH10, 10);
87channel!(DMA_CH11, 11);
diff --git a/embassy-rp/src/fmt.rs b/embassy-rp/src/fmt.rs
new file mode 100644
index 000000000..4da69766c
--- /dev/null
+++ b/embassy-rp/src/fmt.rs
@@ -0,0 +1,118 @@
1#![macro_use]
2
3#[cfg(all(feature = "defmt", feature = "log"))]
4compile_error!("You may not enable both `defmt` and `log` features.");
5
6pub use fmt::*;
7
8#[cfg(feature = "defmt")]
9mod fmt {
10 pub use defmt::{
11 assert, assert_eq, assert_ne, debug, debug_assert, debug_assert_eq, debug_assert_ne, error,
12 info, panic, todo, trace, unreachable, unwrap, warn,
13 };
14}
15
16#[cfg(feature = "log")]
17mod fmt {
18 pub use core::{
19 assert, assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, panic, todo,
20 unreachable,
21 };
22 pub use log::{debug, error, info, trace, warn};
23}
24
25#[cfg(not(any(feature = "defmt", feature = "log")))]
26mod fmt {
27 #![macro_use]
28
29 pub use core::{
30 assert, assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, panic, todo,
31 unreachable,
32 };
33
34 #[macro_export]
35 macro_rules! trace {
36 ($($msg:expr),+ $(,)?) => {
37 ()
38 };
39 }
40
41 #[macro_export]
42 macro_rules! debug {
43 ($($msg:expr),+ $(,)?) => {
44 ()
45 };
46 }
47
48 #[macro_export]
49 macro_rules! info {
50 ($($msg:expr),+ $(,)?) => {
51 ()
52 };
53 }
54
55 #[macro_export]
56 macro_rules! warn {
57 ($($msg:expr),+ $(,)?) => {
58 ()
59 };
60 }
61
62 #[macro_export]
63 macro_rules! error {
64 ($($msg:expr),+ $(,)?) => {
65 ()
66 };
67 }
68}
69
70#[cfg(not(feature = "defmt"))]
71#[macro_export]
72macro_rules! unwrap {
73 ($arg:expr) => {
74 match $crate::fmt::Try::into_result($arg) {
75 ::core::result::Result::Ok(t) => t,
76 ::core::result::Result::Err(e) => {
77 ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
78 }
79 }
80 };
81 ($arg:expr, $($msg:expr),+ $(,)? ) => {
82 match $crate::fmt::Try::into_result($arg) {
83 ::core::result::Result::Ok(t) => t,
84 ::core::result::Result::Err(e) => {
85 ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
86 }
87 }
88 }
89}
90
91#[derive(Debug, Copy, Clone, Eq, PartialEq)]
92pub struct NoneError;
93
94pub trait Try {
95 type Ok;
96 type Error;
97 fn into_result(self) -> Result<Self::Ok, Self::Error>;
98}
99
100impl<T> Try for Option<T> {
101 type Ok = T;
102 type Error = NoneError;
103
104 #[inline]
105 fn into_result(self) -> Result<T, NoneError> {
106 self.ok_or(NoneError)
107 }
108}
109
110impl<T, E> Try for Result<T, E> {
111 type Ok = T;
112 type Error = E;
113
114 #[inline]
115 fn into_result(self) -> Self {
116 self
117 }
118}
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
new file mode 100644
index 000000000..3ab35ee3a
--- /dev/null
+++ b/embassy-rp/src/gpio.rs
@@ -0,0 +1,250 @@
1use core::marker::PhantomData;
2
3use crate::pac;
4use crate::pac::generic::{Reg, RW};
5use crate::pac::SIO;
6use crate::peripherals;
7
8use embassy::util::PeripheralBorrow;
9use embassy_extras::{impl_unborrow, unborrow};
10use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin};
11
12/// Represents a digital input or output level.
13#[derive(Debug, Eq, PartialEq)]
14pub enum Level {
15 Low,
16 High,
17}
18
19/// Represents a pull setting for an input.
20#[derive(Debug, Eq, PartialEq)]
21pub enum Pull {
22 None,
23 Up,
24 Down,
25}
26
27/// A GPIO bank with up to 32 pins.
28#[derive(Debug, Eq, PartialEq)]
29pub enum Bank {
30 Bank0 = 0,
31 Qspi = 1,
32}
33
34pub struct Input<'d, T: Pin> {
35 pin: T,
36 phantom: PhantomData<&'d mut T>,
37}
38
39impl<'d, T: Pin> Input<'d, T> {
40 pub fn new(pin: impl PeripheralBorrow<Target = T> + 'd, pull: Pull) -> Self {
41 unborrow!(pin);
42
43 // todo
44 Self {
45 pin,
46 phantom: PhantomData,
47 }
48 }
49}
50
51impl<'d, T: Pin> Drop for Input<'d, T> {
52 fn drop(&mut self) {
53 // todo
54 }
55}
56
57impl<'d, T: Pin> InputPin for Input<'d, T> {
58 type Error = !;
59
60 fn is_high(&self) -> Result<bool, Self::Error> {
61 self.is_low().map(|v| !v)
62 }
63
64 fn is_low(&self) -> Result<bool, Self::Error> {
65 // todo
66 Ok(true)
67 }
68}
69
70pub struct Output<'d, T: Pin> {
71 pin: T,
72 phantom: PhantomData<&'d mut T>,
73}
74
75impl<'d, T: Pin> Output<'d, T> {
76 // TODO opendrain
77 pub fn new(pin: impl PeripheralBorrow<Target = T> + 'd, initial_output: Level) -> Self {
78 unborrow!(pin);
79
80 unsafe {
81 match initial_output {
82 Level::High => pin.sio_out().value_set().write_value(1 << pin.pin()),
83 Level::Low => pin.sio_out().value_clr().write_value(1 << pin.pin()),
84 }
85 pin.sio_oe().value_set().write_value(1 << pin.pin());
86
87 pin.io().ctrl().write(|w| {
88 w.set_funcsel(pac::io::vals::Gpio0CtrlFuncsel::SIO_0.0);
89 });
90 }
91
92 Self {
93 pin,
94 phantom: PhantomData,
95 }
96 }
97}
98
99impl<'d, T: Pin> Drop for Output<'d, T> {
100 fn drop(&mut self) {
101 // todo
102 }
103}
104
105impl<'d, T: Pin> OutputPin for Output<'d, T> {
106 type Error = !;
107
108 /// Set the output as high.
109 fn set_high(&mut self) -> Result<(), Self::Error> {
110 let val = 1 << self.pin.pin();
111 unsafe { self.pin.sio_out().value_set().write_value(val) };
112 Ok(())
113 }
114
115 /// Set the output as low.
116 fn set_low(&mut self) -> Result<(), Self::Error> {
117 let val = 1 << self.pin.pin();
118 unsafe { self.pin.sio_out().value_clr().write_value(val) };
119 Ok(())
120 }
121}
122
123impl<'d, T: Pin> StatefulOutputPin for Output<'d, T> {
124 /// Is the output pin set as high?
125 fn is_set_high(&self) -> Result<bool, Self::Error> {
126 self.is_set_low().map(|v| !v)
127 }
128
129 /// Is the output pin set as low?
130 fn is_set_low(&self) -> Result<bool, Self::Error> {
131 // todo
132 Ok(true)
133 }
134}
135
136pub(crate) mod sealed {
137 use super::*;
138
139 pub trait Pin: Sized {
140 fn pin_bank(&self) -> u8;
141
142 #[inline]
143 fn pin(&self) -> u8 {
144 self.pin_bank() & 0x1f
145 }
146
147 #[inline]
148 fn bank(&self) -> Bank {
149 if self.pin_bank() & 0x20 == 0 {
150 Bank::Bank0
151 } else {
152 Bank::Qspi
153 }
154 }
155
156 fn io(&self) -> pac::io::Gpio {
157 let block = match self.bank() {
158 Bank::Bank0 => crate::pac::IO_BANK0,
159 Bank::Qspi => crate::pac::IO_QSPI,
160 };
161 block.gpio(self.pin() as _)
162 }
163
164 fn pad_ctrl(&self) -> Reg<pac::pads::regs::GpioCtrl, RW> {
165 let block = match self.bank() {
166 Bank::Bank0 => crate::pac::PADS_BANK0,
167 Bank::Qspi => crate::pac::PADS_QSPI,
168 };
169 block.gpio(self.pin() as _)
170 }
171 fn sio_out(&self) -> pac::sio::Gpio {
172 SIO.gpio_out(self.bank() as _)
173 }
174 fn sio_oe(&self) -> pac::sio::Gpio {
175 SIO.gpio_oe(self.bank() as _)
176 }
177 fn sio_in(&self) -> Reg<u32, RW> {
178 SIO.gpio_in(self.bank() as _)
179 }
180 }
181}
182
183pub trait Pin: sealed::Pin {
184 /// Degrade to a generic pin struct
185 fn degrade(self) -> AnyPin {
186 AnyPin {
187 pin_bank: self.pin_bank(),
188 }
189 }
190}
191
192pub struct AnyPin {
193 pin_bank: u8,
194}
195impl_unborrow!(AnyPin);
196impl Pin for AnyPin {}
197impl sealed::Pin for AnyPin {
198 fn pin_bank(&self) -> u8 {
199 self.pin_bank
200 }
201}
202
203macro_rules! impl_pin {
204 ($name:ident, $bank:expr, $pin_num:expr) => {
205 impl Pin for peripherals::$name {}
206 impl sealed::Pin for peripherals::$name {
207 fn pin_bank(&self) -> u8 {
208 ($bank as u8) * 32 + $pin_num
209 }
210 }
211 };
212}
213
214impl_pin!(PIN_0, Bank::Bank0, 0);
215impl_pin!(PIN_1, Bank::Bank0, 1);
216impl_pin!(PIN_2, Bank::Bank0, 2);
217impl_pin!(PIN_3, Bank::Bank0, 3);
218impl_pin!(PIN_4, Bank::Bank0, 4);
219impl_pin!(PIN_5, Bank::Bank0, 5);
220impl_pin!(PIN_6, Bank::Bank0, 6);
221impl_pin!(PIN_7, Bank::Bank0, 7);
222impl_pin!(PIN_8, Bank::Bank0, 8);
223impl_pin!(PIN_9, Bank::Bank0, 9);
224impl_pin!(PIN_10, Bank::Bank0, 10);
225impl_pin!(PIN_11, Bank::Bank0, 11);
226impl_pin!(PIN_12, Bank::Bank0, 12);
227impl_pin!(PIN_13, Bank::Bank0, 13);
228impl_pin!(PIN_14, Bank::Bank0, 14);
229impl_pin!(PIN_15, Bank::Bank0, 15);
230impl_pin!(PIN_16, Bank::Bank0, 16);
231impl_pin!(PIN_17, Bank::Bank0, 17);
232impl_pin!(PIN_18, Bank::Bank0, 18);
233impl_pin!(PIN_19, Bank::Bank0, 19);
234impl_pin!(PIN_20, Bank::Bank0, 20);
235impl_pin!(PIN_21, Bank::Bank0, 21);
236impl_pin!(PIN_22, Bank::Bank0, 22);
237impl_pin!(PIN_23, Bank::Bank0, 23);
238impl_pin!(PIN_24, Bank::Bank0, 24);
239impl_pin!(PIN_25, Bank::Bank0, 25);
240impl_pin!(PIN_26, Bank::Bank0, 26);
241impl_pin!(PIN_27, Bank::Bank0, 27);
242impl_pin!(PIN_28, Bank::Bank0, 28);
243impl_pin!(PIN_29, Bank::Bank0, 29);
244
245impl_pin!(PIN_QSPI_SCLK, Bank::Qspi, 0);
246impl_pin!(PIN_QSPI_SS, Bank::Qspi, 1);
247impl_pin!(PIN_QSPI_SD0, Bank::Qspi, 2);
248impl_pin!(PIN_QSPI_SD1, Bank::Qspi, 3);
249impl_pin!(PIN_QSPI_SD2, Bank::Qspi, 4);
250impl_pin!(PIN_QSPI_SD3, Bank::Qspi, 5);
diff --git a/embassy-rp/src/interrupt.rs b/embassy-rp/src/interrupt.rs
new file mode 100644
index 000000000..a913ea60c
--- /dev/null
+++ b/embassy-rp/src/interrupt.rs
@@ -0,0 +1,110 @@
1//! Interrupt management
2//!
3//! This module implements an API for managing interrupts compatible with
4//! nrf_softdevice::interrupt. Intended for switching between the two at compile-time.
5
6use core::sync::atomic::{compiler_fence, Ordering};
7
8use crate::pac::NVIC_PRIO_BITS;
9
10// Re-exports
11pub use cortex_m::interrupt::{CriticalSection, Mutex};
12pub use embassy::interrupt::{declare, take, Interrupt};
13
14#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
15#[cfg_attr(feature = "defmt", derive(defmt::Format))]
16#[repr(u8)]
17pub enum Priority {
18 Level0 = 0,
19 Level1 = 1,
20 Level2 = 2,
21 Level3 = 3,
22 Level4 = 4,
23 Level5 = 5,
24 Level6 = 6,
25 Level7 = 7,
26}
27
28impl From<u8> for Priority {
29 fn from(priority: u8) -> Self {
30 match priority >> (8 - NVIC_PRIO_BITS) {
31 0 => Self::Level0,
32 1 => Self::Level1,
33 2 => Self::Level2,
34 3 => Self::Level3,
35 4 => Self::Level4,
36 5 => Self::Level5,
37 6 => Self::Level6,
38 7 => Self::Level7,
39 _ => unreachable!(),
40 }
41 }
42}
43
44impl From<Priority> for u8 {
45 fn from(p: Priority) -> Self {
46 (p as u8) << (8 - NVIC_PRIO_BITS)
47 }
48}
49
50#[inline]
51pub fn free<F, R>(f: F) -> R
52where
53 F: FnOnce(&CriticalSection) -> R,
54{
55 unsafe {
56 // TODO: assert that we're in privileged level
57 // Needed because disabling irqs in non-privileged level is a noop, which would break safety.
58
59 let primask: u32;
60 asm!("mrs {}, PRIMASK", out(reg) primask);
61
62 asm!("cpsid i");
63
64 // Prevent compiler from reordering operations inside/outside the critical section.
65 compiler_fence(Ordering::SeqCst);
66
67 let r = f(&CriticalSection::new());
68
69 compiler_fence(Ordering::SeqCst);
70
71 if primask & 1 == 0 {
72 asm!("cpsie i");
73 }
74
75 r
76 }
77}
78
79mod irqs {
80 use super::*;
81
82 declare!(TIMER_IRQ_0);
83 declare!(TIMER_IRQ_1);
84 declare!(TIMER_IRQ_2);
85 declare!(TIMER_IRQ_3);
86 declare!(PWM_IRQ_WRAP);
87 declare!(USBCTRL_IRQ);
88 declare!(XIP_IRQ);
89 declare!(PIO0_IRQ_0);
90 declare!(PIO0_IRQ_1);
91 declare!(PIO1_IRQ_0);
92 declare!(PIO1_IRQ_1);
93 declare!(DMA_IRQ_0);
94 declare!(DMA_IRQ_1);
95 declare!(IO_IRQ_BANK0);
96 declare!(IO_IRQ_QSPI);
97 declare!(SIO_IRQ_PROC0);
98 declare!(SIO_IRQ_PROC1);
99 declare!(CLOCKS_IRQ);
100 declare!(SPI0_IRQ);
101 declare!(SPI1_IRQ);
102 declare!(UART0_IRQ);
103 declare!(UART1_IRQ);
104 declare!(ADC_IRQ_FIFO);
105 declare!(I2C0_IRQ);
106 declare!(I2C1_IRQ);
107 declare!(RTC_IRQ);
108}
109
110pub use irqs::*;
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
new file mode 100644
index 000000000..f64464d13
--- /dev/null
+++ b/embassy-rp/src/lib.rs
@@ -0,0 +1,74 @@
1#![no_std]
2#![feature(generic_associated_types)]
3#![feature(asm)]
4#![feature(type_alias_impl_trait)]
5#![feature(never_type)]
6
7pub use rp2040_pac2 as pac;
8
9// This mod MUST go first, so that the others see its macros.
10pub(crate) mod fmt;
11
12pub mod interrupt;
13
14pub mod dma;
15pub mod gpio;
16pub mod pll;
17pub mod resets;
18pub mod system;
19pub mod uart;
20
21embassy_extras::peripherals! {
22 PIN_0,
23 PIN_1,
24 PIN_2,
25 PIN_3,
26 PIN_4,
27 PIN_5,
28 PIN_6,
29 PIN_7,
30 PIN_8,
31 PIN_9,
32 PIN_10,
33 PIN_11,
34 PIN_12,
35 PIN_13,
36 PIN_14,
37 PIN_15,
38 PIN_16,
39 PIN_17,
40 PIN_18,
41 PIN_19,
42 PIN_20,
43 PIN_21,
44 PIN_22,
45 PIN_23,
46 PIN_24,
47 PIN_25,
48 PIN_26,
49 PIN_27,
50 PIN_28,
51 PIN_29,
52 PIN_QSPI_SCLK,
53 PIN_QSPI_SS,
54 PIN_QSPI_SD0,
55 PIN_QSPI_SD1,
56 PIN_QSPI_SD2,
57 PIN_QSPI_SD3,
58
59 UART0,
60 UART1,
61
62 DMA_CH0,
63 DMA_CH1,
64 DMA_CH2,
65 DMA_CH3,
66 DMA_CH4,
67 DMA_CH5,
68 DMA_CH6,
69 DMA_CH7,
70 DMA_CH8,
71 DMA_CH9,
72 DMA_CH10,
73 DMA_CH11,
74}
diff --git a/embassy-rp/src/pll.rs b/embassy-rp/src/pll.rs
new file mode 100644
index 000000000..2726367e7
--- /dev/null
+++ b/embassy-rp/src/pll.rs
@@ -0,0 +1,79 @@
1use core::ops::Deref;
2use defmt::{assert, *};
3
4use crate::pac;
5
6const XOSC_MHZ: u32 = 12;
7
8pub struct PLL<T: Instance> {
9 inner: T,
10}
11
12impl<T: Instance> PLL<T> {
13 pub fn new(inner: T) -> Self {
14 Self { inner }
15 }
16
17 pub fn configure(&mut self, refdiv: u32, vco_freq: u32, post_div1: u8, post_div2: u8) {
18 unsafe {
19 let p = self.inner.regs();
20 // Power off in case it's already running
21 p.pwr().write(|w| {
22 w.set_vcopd(true);
23 w.set_postdivpd(true);
24 w.set_dsmpd(true);
25 w.set_pd(true);
26 });
27 p.fbdiv_int().write(|w| w.set_fbdiv_int(0));
28
29 let ref_mhz = XOSC_MHZ / refdiv;
30 p.cs().write(|w| w.set_refdiv(ref_mhz as _));
31
32 let fbdiv = vco_freq / (ref_mhz * 1_000_000);
33 assert!(fbdiv >= 16 && fbdiv <= 520);
34 assert!((post_div1 >= 1 && post_div1 <= 7) && (post_div2 >= 1 && post_div2 <= 7));
35 assert!(post_div2 <= post_div1);
36 assert!(ref_mhz <= (vco_freq / 16));
37
38 p.fbdiv_int().write(|w| w.set_fbdiv_int(fbdiv as _));
39
40 p.pwr().modify(|w| {
41 w.set_pd(false);
42 w.set_vcopd(false);
43 });
44
45 while !p.cs().read().lock() {}
46
47 p.prim().write(|w| {
48 w.set_postdiv1(post_div1);
49 w.set_postdiv2(post_div2);
50 });
51
52 p.pwr().modify(|w| w.set_postdivpd(false));
53 }
54 }
55}
56
57mod sealed {
58 pub trait Instance {}
59 impl Instance for super::PllSys {}
60 impl Instance for super::PllUsb {}
61}
62
63// todo make owned
64pub struct PllSys;
65pub struct PllUsb;
66
67pub trait Instance {
68 fn regs(&self) -> pac::pll::Pll;
69}
70impl Instance for PllSys {
71 fn regs(&self) -> pac::pll::Pll {
72 pac::PLL_SYS
73 }
74}
75impl Instance for PllUsb {
76 fn regs(&self) -> pac::pll::Pll {
77 pac::PLL_USB
78 }
79}
diff --git a/embassy-rp/src/resets.rs b/embassy-rp/src/resets.rs
new file mode 100644
index 000000000..29610e202
--- /dev/null
+++ b/embassy-rp/src/resets.rs
@@ -0,0 +1,29 @@
1use crate::pac;
2
3pub use pac::resets::regs::Peripherals;
4
5pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ffffff);
6
7pub struct Resets {}
8
9impl Resets {
10 pub fn new() -> Self {
11 Self {}
12 }
13
14 pub fn reset(&self, peris: Peripherals) {
15 unsafe {
16 pac::RESETS.reset().write_value(peris);
17 }
18 }
19
20 pub fn unreset_wait(&self, peris: Peripherals) {
21 unsafe {
22 // TODO use the "atomic clear" register version
23 pac::RESETS
24 .reset()
25 .modify(|v| *v = Peripherals(v.0 & !peris.0));
26 while ((!pac::RESETS.reset_done().read().0) & peris.0) != 0 {}
27 }
28 }
29}
diff --git a/embassy-rp/src/system.rs b/embassy-rp/src/system.rs
new file mode 100644
index 000000000..200f88d63
--- /dev/null
+++ b/embassy-rp/src/system.rs
@@ -0,0 +1,90 @@
1use crate::{pac, pll, resets};
2
3#[non_exhaustive]
4pub struct Config {}
5
6impl Default for Config {
7 fn default() -> Self {
8 Self {}
9 }
10}
11
12/// safety: must only call once.
13pub unsafe fn configure(_config: Config) {
14 // Now reset all the peripherals, except QSPI and XIP (we're using those
15 // to execute from external flash!)
16
17 let resets = resets::Resets::new();
18
19 // Reset everything except:
20 // - QSPI (we're using it to run this code!)
21 // - PLLs (it may be suicide if that's what's clocking us)
22 let mut peris = resets::ALL_PERIPHERALS;
23 peris.set_io_qspi(false);
24 peris.set_pads_qspi(false);
25 peris.set_pll_sys(false);
26 peris.set_pll_usb(false);
27 resets.reset(peris);
28
29 let mut peris = resets::ALL_PERIPHERALS;
30 peris.set_adc(false);
31 peris.set_rtc(false);
32 peris.set_spi0(false);
33 peris.set_spi1(false);
34 peris.set_uart0(false);
35 peris.set_uart1(false);
36 peris.set_usbctrl(false);
37 resets.unreset_wait(peris);
38
39 // xosc 12 mhz
40 pac::WATCHDOG.tick().write(|w| {
41 w.set_cycles(XOSC_MHZ as u16);
42 w.set_enable(true);
43 });
44
45 pac::CLOCKS
46 .clk_sys_resus_ctrl()
47 .write_value(pac::clocks::regs::ClkSysResusCtrl(0));
48
49 // Enable XOSC
50 // TODO extract to HAL module
51 const XOSC_MHZ: u32 = 12;
52 pac::XOSC
53 .ctrl()
54 .write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ));
55
56 let startup_delay = (((XOSC_MHZ * 1_000_000) / 1000) + 128) / 256;
57 pac::XOSC
58 .startup()
59 .write(|w| w.set_delay(startup_delay as u16));
60 pac::XOSC.ctrl().write(|w| {
61 w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ);
62 w.set_enable(pac::xosc::vals::CtrlEnable::ENABLE);
63 });
64 while !pac::XOSC.status().read().stable() {}
65
66 // Before we touch PLLs, switch sys and ref cleanly away from their aux sources.
67 pac::CLOCKS
68 .clk_sys_ctrl()
69 .modify(|w| w.set_src(pac::clocks::vals::ClkSysCtrlSrc::CLK_REF));
70 while pac::CLOCKS.clk_sys_selected().read() != 1 {}
71 pac::CLOCKS
72 .clk_ref_ctrl()
73 .modify(|w| w.set_src(pac::clocks::vals::ClkRefCtrlSrc::ROSC_CLKSRC_PH));
74 while pac::CLOCKS.clk_ref_selected().read() != 1 {}
75
76 let mut peris = resets::Peripherals(0);
77 peris.set_pll_sys(true);
78 peris.set_pll_usb(true);
79 resets.reset(peris);
80 resets.unreset_wait(peris);
81
82 pll::PLL::new(pll::PllSys).configure(1, 1500_000_000, 6, 2);
83 pll::PLL::new(pll::PllUsb).configure(1, 480_000_000, 5, 2);
84
85 // Activate peripheral clock and take external oscillator as input
86 pac::CLOCKS.clk_peri_ctrl().write(|w| {
87 w.set_enable(true);
88 w.set_auxsrc(pac::clocks::vals::ClkPeriCtrlAuxsrc::XOSC_CLKSRC);
89 });
90}
diff --git a/embassy-rp/src/uart.rs b/embassy-rp/src/uart.rs
new file mode 100644
index 000000000..3eb768a7d
--- /dev/null
+++ b/embassy-rp/src/uart.rs
@@ -0,0 +1,173 @@
1use core::marker::PhantomData;
2
3use embassy::util::PeripheralBorrow;
4use embassy_extras::unborrow;
5use gpio::Pin;
6
7use crate::{gpio, pac, peripherals};
8
9#[non_exhaustive]
10pub struct Config {
11 pub baudrate: u32,
12 pub data_bits: u8,
13 pub stop_bits: u8,
14}
15
16impl Default for Config {
17 fn default() -> Self {
18 Self {
19 baudrate: 115200,
20 data_bits: 8,
21 stop_bits: 1,
22 }
23 }
24}
25
26pub struct Uart<'d, T: Instance> {
27 inner: T,
28 phantom: PhantomData<&'d mut T>,
29}
30
31impl<'d, T: Instance> Uart<'d, T> {
32 pub fn new(
33 inner: impl PeripheralBorrow<Target = T>,
34 tx: impl PeripheralBorrow<Target = impl TxPin<T>>,
35 rx: impl PeripheralBorrow<Target = impl RxPin<T>>,
36 cts: impl PeripheralBorrow<Target = impl CtsPin<T>>,
37 rts: impl PeripheralBorrow<Target = impl RtsPin<T>>,
38 config: Config,
39 ) -> Self {
40 unborrow!(inner, tx, rx, cts, rts);
41
42 unsafe {
43 let p = inner.regs();
44
45 // todo get this from somewhere
46 let clk_base = 12_000_000;
47
48 let baud_rate_div = (8 * clk_base) / config.baudrate;
49 let mut baud_ibrd = baud_rate_div >> 7;
50 let mut baud_fbrd = ((baud_rate_div & 0x7f) + 1) / 2;
51
52 if baud_ibrd == 0 {
53 baud_ibrd = 1;
54 baud_fbrd = 0;
55 } else if baud_ibrd >= 65535 {
56 baud_ibrd = 65535;
57 baud_fbrd = 0;
58 }
59
60 // Load PL011's baud divisor registers
61 p.uartibrd()
62 .write_value(pac::uart::regs::Uartibrd(baud_ibrd));
63 p.uartfbrd()
64 .write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
65
66 p.uartlcr_h().write(|w| {
67 w.set_wlen(config.data_bits - 5);
68 w.set_stp2(config.stop_bits == 2);
69 w.set_pen(false);
70 w.set_eps(false);
71 w.set_fen(true);
72 });
73
74 p.uartcr().write(|w| {
75 w.set_uarten(true);
76 w.set_rxe(true);
77 w.set_txe(true);
78 });
79
80 tx.io().ctrl().write(|w| w.set_funcsel(2));
81 rx.io().ctrl().write(|w| w.set_funcsel(2));
82 cts.io().ctrl().write(|w| w.set_funcsel(2));
83 rts.io().ctrl().write(|w| w.set_funcsel(2));
84 }
85 Self {
86 inner,
87 phantom: PhantomData,
88 }
89 }
90
91 pub fn send(&mut self, data: &[u8]) {
92 unsafe {
93 let p = self.inner.regs();
94
95 for &byte in data {
96 if !p.uartfr().read().txff() {
97 p.uartdr().write(|w| w.set_data(byte));
98 }
99 }
100 }
101 }
102}
103
104mod sealed {
105 use super::*;
106
107 pub trait Instance {
108 fn regs(&self) -> pac::uart::Uart;
109 }
110 pub trait TxPin<T: Instance> {}
111 pub trait RxPin<T: Instance> {}
112 pub trait CtsPin<T: Instance> {}
113 pub trait RtsPin<T: Instance> {}
114}
115
116pub trait Instance: sealed::Instance {}
117
118macro_rules! impl_instance {
119 ($type:ident, $irq:ident) => {
120 impl sealed::Instance for peripherals::$type {
121 fn regs(&self) -> pac::uart::Uart {
122 pac::$type
123 }
124 }
125 impl Instance for peripherals::$type {}
126 };
127}
128
129impl_instance!(UART0, UART0);
130impl_instance!(UART1, UART1);
131
132pub trait TxPin<T: Instance>: sealed::TxPin<T> + Pin {}
133pub trait RxPin<T: Instance>: sealed::RxPin<T> + Pin {}
134pub trait CtsPin<T: Instance>: sealed::CtsPin<T> + Pin {}
135pub trait RtsPin<T: Instance>: sealed::RtsPin<T> + Pin {}
136
137macro_rules! impl_pin {
138 ($pin:ident, $instance:ident, $function:ident) => {
139 impl sealed::$function<peripherals::$instance> for peripherals::$pin {}
140 impl $function<peripherals::$instance> for peripherals::$pin {}
141 };
142}
143
144impl_pin!(PIN_0, UART0, TxPin);
145impl_pin!(PIN_1, UART0, RxPin);
146impl_pin!(PIN_2, UART0, CtsPin);
147impl_pin!(PIN_3, UART0, RtsPin);
148impl_pin!(PIN_4, UART1, TxPin);
149impl_pin!(PIN_5, UART1, RxPin);
150impl_pin!(PIN_6, UART1, CtsPin);
151impl_pin!(PIN_7, UART1, RtsPin);
152impl_pin!(PIN_8, UART1, TxPin);
153impl_pin!(PIN_9, UART1, RxPin);
154impl_pin!(PIN_10, UART1, CtsPin);
155impl_pin!(PIN_11, UART1, RtsPin);
156impl_pin!(PIN_12, UART0, TxPin);
157impl_pin!(PIN_13, UART0, RxPin);
158impl_pin!(PIN_14, UART0, CtsPin);
159impl_pin!(PIN_15, UART0, RtsPin);
160impl_pin!(PIN_16, UART0, TxPin);
161impl_pin!(PIN_17, UART0, RxPin);
162impl_pin!(PIN_18, UART0, CtsPin);
163impl_pin!(PIN_19, UART0, RtsPin);
164impl_pin!(PIN_20, UART1, TxPin);
165impl_pin!(PIN_21, UART1, RxPin);
166impl_pin!(PIN_22, UART1, CtsPin);
167impl_pin!(PIN_23, UART1, RtsPin);
168impl_pin!(PIN_24, UART1, TxPin);
169impl_pin!(PIN_25, UART1, RxPin);
170impl_pin!(PIN_26, UART1, CtsPin);
171impl_pin!(PIN_27, UART1, RtsPin);
172impl_pin!(PIN_28, UART0, TxPin);
173impl_pin!(PIN_29, UART0, RxPin);