diff options
| -rw-r--r-- | .vscode/settings.json | 4 | ||||
| -rw-r--r-- | Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-macros/Cargo.toml | 1 | ||||
| -rw-r--r-- | embassy-macros/src/chip/nrf.rs | 1 | ||||
| -rw-r--r-- | embassy-macros/src/chip/rp.rs | 16 | ||||
| -rw-r--r-- | embassy-macros/src/chip/stm32.rs | 1 | ||||
| -rw-r--r-- | embassy-macros/src/lib.rs | 13 | ||||
| -rw-r--r-- | embassy-rp-examples/.cargo/config | 30 | ||||
| -rw-r--r-- | embassy-rp-examples/Cargo.toml | 33 | ||||
| -rw-r--r-- | embassy-rp-examples/build.rs | 31 | ||||
| -rw-r--r-- | embassy-rp-examples/memory.x | 13 | ||||
| -rw-r--r-- | embassy-rp-examples/src/main.rs | 72 | ||||
| -rw-r--r-- | embassy-rp/Cargo.toml | 25 | ||||
| -rw-r--r-- | embassy-rp/funcsel.txt | 30 | ||||
| -rw-r--r-- | embassy-rp/src/dma.rs | 87 | ||||
| -rw-r--r-- | embassy-rp/src/fmt.rs | 118 | ||||
| -rw-r--r-- | embassy-rp/src/gpio.rs | 250 | ||||
| -rw-r--r-- | embassy-rp/src/interrupt.rs | 110 | ||||
| -rw-r--r-- | embassy-rp/src/lib.rs | 74 | ||||
| -rw-r--r-- | embassy-rp/src/pll.rs | 79 | ||||
| -rw-r--r-- | embassy-rp/src/resets.rs | 29 | ||||
| -rw-r--r-- | embassy-rp/src/system.rs | 90 | ||||
| -rw-r--r-- | embassy-rp/src/uart.rs | 173 |
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 = [ | |||
| 19 | exclude = [ | 19 | exclude = [ |
| 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 | |||
| 52 | debug-assertions = false | 54 | debug-assertions = false |
| 53 | opt-level = 0 | 55 | opt-level = 0 |
| 54 | overflow-checks = false | 56 | overflow-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] |
| 17 | stm32 = [] | 17 | stm32 = [] |
| 18 | nrf = [] | 18 | nrf = [] |
| 19 | rp = [] | ||
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 @@ | |||
| 1 | use darling::FromMeta; | ||
| 2 | use proc_macro2::TokenStream; | ||
| 3 | use quote::{format_ident, quote}; | ||
| 4 | use syn::spanned::Spanned; | ||
| 5 | |||
| 6 | #[derive(Debug, FromMeta)] | ||
| 7 | pub struct Args {} | ||
| 8 | |||
| 9 | pub 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"] |
| 200 | mod chip; | 200 | mod chip; |
| 201 | 201 | ||
| 202 | #[cfg(any(feature = "nrf", feature = "stm32"))] | 202 | #[cfg(feature = "rp")] |
| 203 | #[path = "chip/rp.rs"] | ||
| 204 | mod chip; | ||
| 205 | |||
| 206 | #[cfg(any(feature = "nrf", feature = "stm32", feature = "rp"))] | ||
| 203 | #[proc_macro_attribute] | 207 | #[proc_macro_attribute] |
| 204 | pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { | 208 | pub 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] | ||
| 2 | build-std = ["core"] | ||
| 3 | build-std-features = ["panic_immediate_abort"] | ||
| 4 | |||
| 5 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | ||
| 6 | runner = "probe-run-rp --chip RP2040" | ||
| 7 | |||
| 8 | rustflags = [ | ||
| 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] | ||
| 30 | target = "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] | ||
| 2 | authors = ["Dario Nieuwenhuis <[email protected]>"] | ||
| 3 | edition = "2018" | ||
| 4 | name = "embassy-rp-examples" | ||
| 5 | version = "0.1.0" | ||
| 6 | |||
| 7 | [features] | ||
| 8 | default = [ | ||
| 9 | "defmt-default", | ||
| 10 | ] | ||
| 11 | defmt-default = [] | ||
| 12 | defmt-trace = [] | ||
| 13 | defmt-debug = [] | ||
| 14 | defmt-info = [] | ||
| 15 | defmt-warn = [] | ||
| 16 | defmt-error = [] | ||
| 17 | |||
| 18 | |||
| 19 | [dependencies] | ||
| 20 | embassy = { version = "0.1.0", path = "../embassy", features = ["defmt", "defmt-trace"] } | ||
| 21 | embassy-rp = { version = "0.1.0", path = "../embassy-rp", features = ["defmt", "defmt-trace"] } | ||
| 22 | rp2040-boot2 = { git = "https://github.com/rp-rs/rp2040-boot2-rs", branch="main" } | ||
| 23 | rp2040-pac2 = { git = "https://github.com/Dirbaio/rp2040-pac", rev="254f4677937801155ca3cb17c7bb9d38eb62683e" } | ||
| 24 | atomic-polyfill = { version = "0.1.1" } | ||
| 25 | |||
| 26 | defmt = "0.2.0" | ||
| 27 | defmt-rtt = "0.2.0" | ||
| 28 | |||
| 29 | cortex-m = { version = "0.7.1", features = ["inline-asm"] } | ||
| 30 | cortex-m-rt = "0.6.13" | ||
| 31 | embedded-hal = { version = "0.2.4" } | ||
| 32 | panic-probe = "0.1.0" | ||
| 33 | futures = { 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 | |||
| 11 | use std::env; | ||
| 12 | use std::fs::File; | ||
| 13 | use std::io::Write; | ||
| 14 | use std::path::PathBuf; | ||
| 15 | |||
| 16 | fn 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 @@ | |||
| 1 | MEMORY { | ||
| 2 | BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 | ||
| 3 | FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100 | ||
| 4 | RAM : ORIGIN = 0x20000000, LENGTH = 256K | ||
| 5 | } | ||
| 6 | |||
| 7 | SECTIONS { | ||
| 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 | |||
| 8 | use core::sync::atomic::{AtomicUsize, Ordering}; | ||
| 9 | use defmt::{panic, *}; | ||
| 10 | use defmt_rtt as _; | ||
| 11 | use embassy::executor::Spawner; | ||
| 12 | use embassy::interrupt::InterruptExt; | ||
| 13 | use embassy_rp::{dma, gpio, interrupt, uart, Peripherals}; | ||
| 14 | use embedded_hal::digital::v2::OutputPin; | ||
| 15 | use panic_probe as _; | ||
| 16 | use rp2040_pac2 as pac; | ||
| 17 | |||
| 18 | #[link_section = ".boot2"] | ||
| 19 | #[used] | ||
| 20 | pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; | ||
| 21 | |||
| 22 | defmt::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] | ||
| 32 | async 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 | |||
| 70 | unsafe 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] | ||
| 2 | name = "embassy-rp" | ||
| 3 | version = "0.1.0" | ||
| 4 | authors = ["Dario Nieuwenhuis <[email protected]>"] | ||
| 5 | edition = "2018" | ||
| 6 | |||
| 7 | [features] | ||
| 8 | defmt-trace = [ ] | ||
| 9 | defmt-debug = [ ] | ||
| 10 | defmt-info = [ ] | ||
| 11 | defmt-warn = [ ] | ||
| 12 | defmt-error = [ ] | ||
| 13 | |||
| 14 | [dependencies] | ||
| 15 | embassy = { version = "0.1.0", path = "../embassy" } | ||
| 16 | embassy-extras = {version = "0.1.0", path = "../embassy-extras" } | ||
| 17 | embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["rp"]} | ||
| 18 | |||
| 19 | defmt = { version = "0.2.0", optional = true } | ||
| 20 | log = { version = "0.4.11", optional = true } | ||
| 21 | cortex-m-rt = "0.6.13" | ||
| 22 | cortex-m = "0.7.1" | ||
| 23 | |||
| 24 | rp2040-pac2 = { git = "https://github.com/Dirbaio/rp2040-pac", rev="254f4677937801155ca3cb17c7bb9d38eb62683e", features = ["rt"] } | ||
| 25 | embedded-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 @@ | |||
| 1 | 0 SPI0 RX UART0 TX I2C0 SDA PWM0 A SIO PIO0 PIO1 USB OVCUR DET | ||
| 2 | 1 SPI0 CSn UART0 RX I2C0 SCL PWM0 B SIO PIO0 PIO1 USB VBUS DET | ||
| 3 | 2 SPI0 SCK UART0 CTS I2C1 SDA PWM1 A SIO PIO0 PIO1 USB VBUS EN | ||
| 4 | 3 SPI0 TX UART0 RTS I2C1 SCL PWM1 B SIO PIO0 PIO1 USB OVCUR DET | ||
| 5 | 4 SPI0 RX UART1 TX I2C0 SDA PWM2 A SIO PIO0 PIO1 USB VBUS DET | ||
| 6 | 5 SPI0 CSn UART1 RX I2C0 SCL PWM2 B SIO PIO0 PIO1 USB VBUS EN | ||
| 7 | 6 SPI0 SCK UART1 CTS I2C1 SDA PWM3 A SIO PIO0 PIO1 USB OVCUR DET | ||
| 8 | 7 SPI0 TX UART1 RTS I2C1 SCL PWM3 B SIO PIO0 PIO1 USB VBUS DET | ||
| 9 | 8 SPI1 RX UART1 TX I2C0 SDA PWM4 A SIO PIO0 PIO1 USB VBUS EN | ||
| 10 | 9 SPI1 CSn UART1 RX I2C0 SCL PWM4 B SIO PIO0 PIO1 USB OVCUR DET | ||
| 11 | 10 SPI1 SCK UART1 CTS I2C1 SDA PWM5 A SIO PIO0 PIO1 USB VBUS DET | ||
| 12 | 11 SPI1 TX UART1 RTS I2C1 SCL PWM5 B SIO PIO0 PIO1 USB VBUS EN | ||
| 13 | 12 SPI1 RX UART0 TX I2C0 SDA PWM6 A SIO PIO0 PIO1 USB OVCUR DET | ||
| 14 | 13 SPI1 CSn UART0 RX I2C0 SCL PWM6 B SIO PIO0 PIO1 USB VBUS DET | ||
| 15 | 14 SPI1 SCK UART0 CTS I2C1 SDA PWM7 A SIO PIO0 PIO1 USB VBUS EN | ||
| 16 | 15 SPI1 TX UART0 RTS I2C1 SCL PWM7 B SIO PIO0 PIO1 USB OVCUR DET | ||
| 17 | 16 SPI0 RX UART0 TX I2C0 SDA PWM0 A SIO PIO0 PIO1 USB VBUS DET | ||
| 18 | 17 SPI0 CSn UART0 RX I2C0 SCL PWM0 B SIO PIO0 PIO1 USB VBUS EN | ||
| 19 | 18 SPI0 SCK UART0 CTS I2C1 SDA PWM1 A SIO PIO0 PIO1 USB OVCUR DET | ||
| 20 | 19 SPI0 TX UART0 RTS I2C1 SCL PWM1 B SIO PIO0 PIO1 USB VBUS DET | ||
| 21 | 20 SPI0 RX UART1 TX I2C0 SDA PWM2 A SIO PIO0 PIO1 CLOCK GPIN0 USB VBUS EN | ||
| 22 | 21 SPI0 CSn UART1 RX I2C0 SCL PWM2 B SIO PIO0 PIO1 CLOCK GPOUT0 USB OVCUR DET | ||
| 23 | 22 SPI0 SCK UART1 CTS I2C1 SDA PWM3 A SIO PIO0 PIO1 CLOCK GPIN1 USB VBUS DET | ||
| 24 | 23 SPI0 TX UART1 RTS I2C1 SCL PWM3 B SIO PIO0 PIO1 CLOCK GPOUT1 USB VBUS EN | ||
| 25 | 24 SPI1 RX UART1 TX I2C0 SDA PWM4 A SIO PIO0 PIO1 CLOCK GPOUT2 USB OVCUR DET | ||
| 26 | 25 SPI1 CSn UART1 RX I2C0 SCL PWM4 B SIO PIO0 PIO1 CLOCK GPOUT3 USB VBUS DET | ||
| 27 | 26 SPI1 SCK UART1 CTS I2C1 SDA PWM5 A SIO PIO0 PIO1 USB VBUS EN | ||
| 28 | 27 SPI1 TX UART1 RTS I2C1 SCL PWM5 B SIO PIO0 PIO1 USB OVCUR DET | ||
| 29 | 28 SPI1 RX UART0 TX I2C0 SDA PWM6 A SIO PIO0 PIO1 USB VBUS DET | ||
| 30 | 29 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 @@ | |||
| 1 | use core::sync::atomic::{compiler_fence, Ordering}; | ||
| 2 | |||
| 3 | use defmt::{assert, *}; | ||
| 4 | |||
| 5 | use crate::{pac, peripherals}; | ||
| 6 | use pac::dma::vals; | ||
| 7 | |||
| 8 | pub struct Dma<T: Channel> { | ||
| 9 | inner: T, | ||
| 10 | } | ||
| 11 | |||
| 12 | impl<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 | |||
| 40 | mod 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 | |||
| 52 | pub trait Channel: sealed::Channel {} | ||
| 53 | |||
| 54 | pub struct AnyChannel { | ||
| 55 | number: u8, | ||
| 56 | } | ||
| 57 | |||
| 58 | impl Channel for AnyChannel {} | ||
| 59 | impl sealed::Channel for AnyChannel { | ||
| 60 | fn number(&self) -> u8 { | ||
| 61 | self.number | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | macro_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 | |||
| 76 | channel!(DMA_CH0, 0); | ||
| 77 | channel!(DMA_CH1, 1); | ||
| 78 | channel!(DMA_CH2, 2); | ||
| 79 | channel!(DMA_CH3, 3); | ||
| 80 | channel!(DMA_CH4, 4); | ||
| 81 | channel!(DMA_CH5, 5); | ||
| 82 | channel!(DMA_CH6, 6); | ||
| 83 | channel!(DMA_CH7, 7); | ||
| 84 | channel!(DMA_CH8, 8); | ||
| 85 | channel!(DMA_CH9, 9); | ||
| 86 | channel!(DMA_CH10, 10); | ||
| 87 | channel!(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"))] | ||
| 4 | compile_error!("You may not enable both `defmt` and `log` features."); | ||
| 5 | |||
| 6 | pub use fmt::*; | ||
| 7 | |||
| 8 | #[cfg(feature = "defmt")] | ||
| 9 | mod 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")] | ||
| 17 | mod 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")))] | ||
| 26 | mod 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] | ||
| 72 | macro_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)] | ||
| 92 | pub struct NoneError; | ||
| 93 | |||
| 94 | pub trait Try { | ||
| 95 | type Ok; | ||
| 96 | type Error; | ||
| 97 | fn into_result(self) -> Result<Self::Ok, Self::Error>; | ||
| 98 | } | ||
| 99 | |||
| 100 | impl<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 | |||
| 110 | impl<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 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 3 | use crate::pac; | ||
| 4 | use crate::pac::generic::{Reg, RW}; | ||
| 5 | use crate::pac::SIO; | ||
| 6 | use crate::peripherals; | ||
| 7 | |||
| 8 | use embassy::util::PeripheralBorrow; | ||
| 9 | use embassy_extras::{impl_unborrow, unborrow}; | ||
| 10 | use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; | ||
| 11 | |||
| 12 | /// Represents a digital input or output level. | ||
| 13 | #[derive(Debug, Eq, PartialEq)] | ||
| 14 | pub enum Level { | ||
| 15 | Low, | ||
| 16 | High, | ||
| 17 | } | ||
| 18 | |||
| 19 | /// Represents a pull setting for an input. | ||
| 20 | #[derive(Debug, Eq, PartialEq)] | ||
| 21 | pub enum Pull { | ||
| 22 | None, | ||
| 23 | Up, | ||
| 24 | Down, | ||
| 25 | } | ||
| 26 | |||
| 27 | /// A GPIO bank with up to 32 pins. | ||
| 28 | #[derive(Debug, Eq, PartialEq)] | ||
| 29 | pub enum Bank { | ||
| 30 | Bank0 = 0, | ||
| 31 | Qspi = 1, | ||
| 32 | } | ||
| 33 | |||
| 34 | pub struct Input<'d, T: Pin> { | ||
| 35 | pin: T, | ||
| 36 | phantom: PhantomData<&'d mut T>, | ||
| 37 | } | ||
| 38 | |||
| 39 | impl<'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 | |||
| 51 | impl<'d, T: Pin> Drop for Input<'d, T> { | ||
| 52 | fn drop(&mut self) { | ||
| 53 | // todo | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | impl<'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 | |||
| 70 | pub struct Output<'d, T: Pin> { | ||
| 71 | pin: T, | ||
| 72 | phantom: PhantomData<&'d mut T>, | ||
| 73 | } | ||
| 74 | |||
| 75 | impl<'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 | |||
| 99 | impl<'d, T: Pin> Drop for Output<'d, T> { | ||
| 100 | fn drop(&mut self) { | ||
| 101 | // todo | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | impl<'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 | |||
| 123 | impl<'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 | |||
| 136 | pub(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 | |||
| 183 | pub 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 | |||
| 192 | pub struct AnyPin { | ||
| 193 | pin_bank: u8, | ||
| 194 | } | ||
| 195 | impl_unborrow!(AnyPin); | ||
| 196 | impl Pin for AnyPin {} | ||
| 197 | impl sealed::Pin for AnyPin { | ||
| 198 | fn pin_bank(&self) -> u8 { | ||
| 199 | self.pin_bank | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | macro_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 | |||
| 214 | impl_pin!(PIN_0, Bank::Bank0, 0); | ||
| 215 | impl_pin!(PIN_1, Bank::Bank0, 1); | ||
| 216 | impl_pin!(PIN_2, Bank::Bank0, 2); | ||
| 217 | impl_pin!(PIN_3, Bank::Bank0, 3); | ||
| 218 | impl_pin!(PIN_4, Bank::Bank0, 4); | ||
| 219 | impl_pin!(PIN_5, Bank::Bank0, 5); | ||
| 220 | impl_pin!(PIN_6, Bank::Bank0, 6); | ||
| 221 | impl_pin!(PIN_7, Bank::Bank0, 7); | ||
| 222 | impl_pin!(PIN_8, Bank::Bank0, 8); | ||
| 223 | impl_pin!(PIN_9, Bank::Bank0, 9); | ||
| 224 | impl_pin!(PIN_10, Bank::Bank0, 10); | ||
| 225 | impl_pin!(PIN_11, Bank::Bank0, 11); | ||
| 226 | impl_pin!(PIN_12, Bank::Bank0, 12); | ||
| 227 | impl_pin!(PIN_13, Bank::Bank0, 13); | ||
| 228 | impl_pin!(PIN_14, Bank::Bank0, 14); | ||
| 229 | impl_pin!(PIN_15, Bank::Bank0, 15); | ||
| 230 | impl_pin!(PIN_16, Bank::Bank0, 16); | ||
| 231 | impl_pin!(PIN_17, Bank::Bank0, 17); | ||
| 232 | impl_pin!(PIN_18, Bank::Bank0, 18); | ||
| 233 | impl_pin!(PIN_19, Bank::Bank0, 19); | ||
| 234 | impl_pin!(PIN_20, Bank::Bank0, 20); | ||
| 235 | impl_pin!(PIN_21, Bank::Bank0, 21); | ||
| 236 | impl_pin!(PIN_22, Bank::Bank0, 22); | ||
| 237 | impl_pin!(PIN_23, Bank::Bank0, 23); | ||
| 238 | impl_pin!(PIN_24, Bank::Bank0, 24); | ||
| 239 | impl_pin!(PIN_25, Bank::Bank0, 25); | ||
| 240 | impl_pin!(PIN_26, Bank::Bank0, 26); | ||
| 241 | impl_pin!(PIN_27, Bank::Bank0, 27); | ||
| 242 | impl_pin!(PIN_28, Bank::Bank0, 28); | ||
| 243 | impl_pin!(PIN_29, Bank::Bank0, 29); | ||
| 244 | |||
| 245 | impl_pin!(PIN_QSPI_SCLK, Bank::Qspi, 0); | ||
| 246 | impl_pin!(PIN_QSPI_SS, Bank::Qspi, 1); | ||
| 247 | impl_pin!(PIN_QSPI_SD0, Bank::Qspi, 2); | ||
| 248 | impl_pin!(PIN_QSPI_SD1, Bank::Qspi, 3); | ||
| 249 | impl_pin!(PIN_QSPI_SD2, Bank::Qspi, 4); | ||
| 250 | impl_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 | |||
| 6 | use core::sync::atomic::{compiler_fence, Ordering}; | ||
| 7 | |||
| 8 | use crate::pac::NVIC_PRIO_BITS; | ||
| 9 | |||
| 10 | // Re-exports | ||
| 11 | pub use cortex_m::interrupt::{CriticalSection, Mutex}; | ||
| 12 | pub 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)] | ||
| 17 | pub 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 | |||
| 28 | impl 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 | |||
| 44 | impl From<Priority> for u8 { | ||
| 45 | fn from(p: Priority) -> Self { | ||
| 46 | (p as u8) << (8 - NVIC_PRIO_BITS) | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | #[inline] | ||
| 51 | pub fn free<F, R>(f: F) -> R | ||
| 52 | where | ||
| 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 | |||
| 79 | mod 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 | |||
| 110 | pub 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 | |||
| 7 | pub use rp2040_pac2 as pac; | ||
| 8 | |||
| 9 | // This mod MUST go first, so that the others see its macros. | ||
| 10 | pub(crate) mod fmt; | ||
| 11 | |||
| 12 | pub mod interrupt; | ||
| 13 | |||
| 14 | pub mod dma; | ||
| 15 | pub mod gpio; | ||
| 16 | pub mod pll; | ||
| 17 | pub mod resets; | ||
| 18 | pub mod system; | ||
| 19 | pub mod uart; | ||
| 20 | |||
| 21 | embassy_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 @@ | |||
| 1 | use core::ops::Deref; | ||
| 2 | use defmt::{assert, *}; | ||
| 3 | |||
| 4 | use crate::pac; | ||
| 5 | |||
| 6 | const XOSC_MHZ: u32 = 12; | ||
| 7 | |||
| 8 | pub struct PLL<T: Instance> { | ||
| 9 | inner: T, | ||
| 10 | } | ||
| 11 | |||
| 12 | impl<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 | |||
| 57 | mod sealed { | ||
| 58 | pub trait Instance {} | ||
| 59 | impl Instance for super::PllSys {} | ||
| 60 | impl Instance for super::PllUsb {} | ||
| 61 | } | ||
| 62 | |||
| 63 | // todo make owned | ||
| 64 | pub struct PllSys; | ||
| 65 | pub struct PllUsb; | ||
| 66 | |||
| 67 | pub trait Instance { | ||
| 68 | fn regs(&self) -> pac::pll::Pll; | ||
| 69 | } | ||
| 70 | impl Instance for PllSys { | ||
| 71 | fn regs(&self) -> pac::pll::Pll { | ||
| 72 | pac::PLL_SYS | ||
| 73 | } | ||
| 74 | } | ||
| 75 | impl 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 @@ | |||
| 1 | use crate::pac; | ||
| 2 | |||
| 3 | pub use pac::resets::regs::Peripherals; | ||
| 4 | |||
| 5 | pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ffffff); | ||
| 6 | |||
| 7 | pub struct Resets {} | ||
| 8 | |||
| 9 | impl 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 @@ | |||
| 1 | use crate::{pac, pll, resets}; | ||
| 2 | |||
| 3 | #[non_exhaustive] | ||
| 4 | pub struct Config {} | ||
| 5 | |||
| 6 | impl Default for Config { | ||
| 7 | fn default() -> Self { | ||
| 8 | Self {} | ||
| 9 | } | ||
| 10 | } | ||
| 11 | |||
| 12 | /// safety: must only call once. | ||
| 13 | pub 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 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 3 | use embassy::util::PeripheralBorrow; | ||
| 4 | use embassy_extras::unborrow; | ||
| 5 | use gpio::Pin; | ||
| 6 | |||
| 7 | use crate::{gpio, pac, peripherals}; | ||
| 8 | |||
| 9 | #[non_exhaustive] | ||
| 10 | pub struct Config { | ||
| 11 | pub baudrate: u32, | ||
| 12 | pub data_bits: u8, | ||
| 13 | pub stop_bits: u8, | ||
| 14 | } | ||
| 15 | |||
| 16 | impl Default for Config { | ||
| 17 | fn default() -> Self { | ||
| 18 | Self { | ||
| 19 | baudrate: 115200, | ||
| 20 | data_bits: 8, | ||
| 21 | stop_bits: 1, | ||
| 22 | } | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
| 26 | pub struct Uart<'d, T: Instance> { | ||
| 27 | inner: T, | ||
| 28 | phantom: PhantomData<&'d mut T>, | ||
| 29 | } | ||
| 30 | |||
| 31 | impl<'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 | |||
| 104 | mod 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 | |||
| 116 | pub trait Instance: sealed::Instance {} | ||
| 117 | |||
| 118 | macro_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 | |||
| 129 | impl_instance!(UART0, UART0); | ||
| 130 | impl_instance!(UART1, UART1); | ||
| 131 | |||
| 132 | pub trait TxPin<T: Instance>: sealed::TxPin<T> + Pin {} | ||
| 133 | pub trait RxPin<T: Instance>: sealed::RxPin<T> + Pin {} | ||
| 134 | pub trait CtsPin<T: Instance>: sealed::CtsPin<T> + Pin {} | ||
| 135 | pub trait RtsPin<T: Instance>: sealed::RtsPin<T> + Pin {} | ||
| 136 | |||
| 137 | macro_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 | |||
| 144 | impl_pin!(PIN_0, UART0, TxPin); | ||
| 145 | impl_pin!(PIN_1, UART0, RxPin); | ||
| 146 | impl_pin!(PIN_2, UART0, CtsPin); | ||
| 147 | impl_pin!(PIN_3, UART0, RtsPin); | ||
| 148 | impl_pin!(PIN_4, UART1, TxPin); | ||
| 149 | impl_pin!(PIN_5, UART1, RxPin); | ||
| 150 | impl_pin!(PIN_6, UART1, CtsPin); | ||
| 151 | impl_pin!(PIN_7, UART1, RtsPin); | ||
| 152 | impl_pin!(PIN_8, UART1, TxPin); | ||
| 153 | impl_pin!(PIN_9, UART1, RxPin); | ||
| 154 | impl_pin!(PIN_10, UART1, CtsPin); | ||
| 155 | impl_pin!(PIN_11, UART1, RtsPin); | ||
| 156 | impl_pin!(PIN_12, UART0, TxPin); | ||
| 157 | impl_pin!(PIN_13, UART0, RxPin); | ||
| 158 | impl_pin!(PIN_14, UART0, CtsPin); | ||
| 159 | impl_pin!(PIN_15, UART0, RtsPin); | ||
| 160 | impl_pin!(PIN_16, UART0, TxPin); | ||
| 161 | impl_pin!(PIN_17, UART0, RxPin); | ||
| 162 | impl_pin!(PIN_18, UART0, CtsPin); | ||
| 163 | impl_pin!(PIN_19, UART0, RtsPin); | ||
| 164 | impl_pin!(PIN_20, UART1, TxPin); | ||
| 165 | impl_pin!(PIN_21, UART1, RxPin); | ||
| 166 | impl_pin!(PIN_22, UART1, CtsPin); | ||
| 167 | impl_pin!(PIN_23, UART1, RtsPin); | ||
| 168 | impl_pin!(PIN_24, UART1, TxPin); | ||
| 169 | impl_pin!(PIN_25, UART1, RxPin); | ||
| 170 | impl_pin!(PIN_26, UART1, CtsPin); | ||
| 171 | impl_pin!(PIN_27, UART1, RtsPin); | ||
| 172 | impl_pin!(PIN_28, UART0, TxPin); | ||
| 173 | impl_pin!(PIN_29, UART0, RxPin); | ||
