diff --git a/Cargo.toml b/Cargo.toml index ceef861a4..59a7dddeb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ members = [ "boards/pimoroni-servo2040", "boards/pimoroni-tiny2040", "boards/rp-pico", + "boards/rp-pico-w", "boards/seeeduino-xiao-rp2040", "boards/solderparty-rp2040-stamp", "boards/sparkfun-pro-micro-rp2040", diff --git a/README.md b/README.md index 862eb1c04..9397fcdb0 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,19 @@ RP2040 chip according to how it is connected up on the Pico. [Raspberry Pi Pico]: https://www.raspberrypi.org/products/raspberry-pi-pico/ [rp-pico]: https://github.com/rp-rs/rp-hal/tree/main/boards/rp-pico +### [rp-pico-w] - Board Support for the [Raspberry Pi Pico] W + +You should include this crate if you are writing code that you want to run on +a [Raspberry Pi Pico] W - the Wifi enabled version of the [Raspberry Pi Pico]. + +This crate includes the [rp2040-hal], but also configures each pin of the +RP2040 chip according to how it is connected up on the Pico W. + +**NOTE**: This is work in progress. Wifi access is not yet implemented. + +[Raspberry Pi Pico]: https://www.raspberrypi.org/products/raspberry-pi-pico/ +[rp-pico-w]: https://github.com/rp-rs/rp-hal/tree/main/boards/rp-pico-w + ### [adafruit-feather-rp2040] - Board Support for the [Adafruit Feather RP2040] You should include this crate if you are writing code that you want to run on diff --git a/boards/rp-pico-w/.gitignore b/boards/rp-pico-w/.gitignore new file mode 100644 index 000000000..ff47c2d77 --- /dev/null +++ b/boards/rp-pico-w/.gitignore @@ -0,0 +1,11 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk diff --git a/boards/rp-pico-w/CHANGELOG.md b/boards/rp-pico-w/CHANGELOG.md new file mode 100644 index 000000000..3519434ba --- /dev/null +++ b/boards/rp-pico-w/CHANGELOG.md @@ -0,0 +1,28 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Unreleased + +Created based on the rp-pico BSP. + +### Added + +- None + +### Changed + +- Pin assignments to match Pico W hardware. + +### TODO + +- Implement Wifi driver +- Add led pin (not a native GPIO, but could provide a compatible + API so rp-pico examples can work on rp-pico-w with little modification) +- Fix pico_w_blinky example. + +[@jannic]: https://github.com/jannic +[rp-rs]: https://github.com/rp-rs diff --git a/boards/rp-pico-w/Cargo.toml b/boards/rp-pico-w/Cargo.toml new file mode 100644 index 000000000..daac5d298 --- /dev/null +++ b/boards/rp-pico-w/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "rp-pico-w" +version = "0.0.1" +authors = ["The rp-rs Developers"] +edition = "2018" +homepage = "https://github.com/rp-rs/rp-hal/tree/main/boards/rp-pico-w" +description = "Board Support Package for the Raspberry Pi Pico W" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rp-rs/rp-hal.git" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +cortex-m = "0.7.2" +rp2040-boot2 = { version = "0.2.0", optional = true } +rp2040-hal = { path = "../../rp2040-hal", version = "0.6.0", features=["eh1_0_alpha"] } +cortex-m-rt = { version = "0.7", optional = true } +embassy-time = { version = "0.1.0", features = ["tick-hz-1_000_000"] } +embassy-sync = { version = "0.1.0" } + +defmt = "0.3" + +atomic-polyfill = "0.1.8" +critical-section = "1.1.0" +embedded-hal = "0.2.7" +embedded-hal-1 = { version = "=1.0.0-alpha.9", package = "embedded-hal" } +fugit = "0.3.6" + +[dev-dependencies] +panic-probe = { version = "0.3", features = ["print-defmt"] } +cyw43 = { version = "0.1.0", git = "https://github.com/jannic-dev-forks/cyw43", branch = "stable", features=["defmt"] } +embassy-executor = { version = "0.1.1", features=["integrated-timers"] } +embassy-futures = { version = "0.1.0" } +embassy-net = { version = "0.1.0", git = "https://github.com/embassy-rs/embassy.git", rev = "2528f451387e6c7b27c3140cd87d47521d1971a2", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } +defmt-rtt = "0.3" +embedded-hal-bus = "0.1.0-alpha.1" + +[features] +default = ["boot2", "rt", "critical-section-impl"] +critical-section-impl = ["rp2040-hal/critical-section-impl"] +boot2 = ["rp2040-boot2"] +rt = ["cortex-m-rt","rp2040-hal/rt"] +fix_fw = ["cyw43/fix_fw"] diff --git a/boards/rp-pico-w/README.md b/boards/rp-pico-w/README.md new file mode 100644 index 000000000..de158c94a --- /dev/null +++ b/boards/rp-pico-w/README.md @@ -0,0 +1,97 @@ +# [rp-pico-w] - Board Support for the [Raspberry Pi Pico] W + +You should include this crate if you are writing code that you want to run on +a [Raspberry Pi Pico] W - the Wifi enabled version of the [Raspberry Pi Pico]. + +This crate includes the [rp2040-hal], but also configures each pin of the +RP2040 chip according to how it is connected up on the Pico W. + +**NOTE**: This is work in progress. Wifi access is not yet implemented. + +[Raspberry Pi Pico]: https://www.raspberrypi.org/products/raspberry-pi-pico/ +[rp-pico-w]: https://github.com/rp-rs/rp-hal/tree/main/boards/rp-pico-w +[rp2040-hal]: https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal +[Raspberry Silicon RP2040]: https://www.raspberrypi.org/products/rp2040/ + +## Using + +To use this crate, your `Cargo.toml` file should contain: + +```toml +rp-pico-w = "0.0.1" +``` + +In your program, you will need to call `rp_pico_w::Pins::new` to create +a new `Pins` structure. This will set up all the GPIOs for any on-board +devices. See the [examples](./examples) folder for more details. + +## Examples + +### General Instructions + +To compile an example, clone the _rp-hal_ repository and run: + +```console +rp-hal/boards/rp-pico-w $ cargo build --release --example +``` + +You will get an ELF file called +`./target/thumbv6m-none-eabi/release/examples/`, where the `target` +folder is located at the top of the _rp-hal_ repository checkout. Normally +you would also need to specify `--target=thumbv6m-none-eabi` but when +building examples from this git repository, that is set as the default. + +If you want to convert the ELF file to a UF2 and automatically copy it to the +USB drive exported by the RP2040 bootloader, simply boot your board into +bootloader mode and run: + +```console +rp-hal/boards/rp-pico-w $ cargo run --release --example +``` + +If you get an error about not being able to find `elf2uf2-rs`, try: + +```console +$ cargo install elf2uf2-rs +``` +then try repeating the `cargo run` command above. + +### [pico_w_blinky](./examples/pico_w_blinky.rs) + +Flashes the Pico W's on-board LED on and off. + +## Contributing + +Contributions are what make the open source community such an amazing place to +be learn, inspire, and create. Any contributions you make are **greatly +appreciated**. + +The steps are: + +1. Fork the Project by clicking the 'Fork' button at the top of the page. +2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) +3. Make some changes to the code or documentation. +4. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) +5. Push to the Feature Branch (`git push origin feature/AmazingFeature`) +6. Create a [New Pull Request](https://github.com/rp-rs/rp-hal/pulls) +7. An admin will review the Pull Request and discuss any changes that may be required. +8. Once everyone is happy, the Pull Request can be merged by an admin, and your work is part of our project! + +## Code of Conduct + +Contribution to this crate is organized under the terms of the [Rust Code of +Conduct][CoC], and the maintainer of this crate, the [rp-rs team], promises +to intervene to uphold that code of conduct. + +[CoC]: CODE_OF_CONDUCT.md +[rp-rs team]: https://github.com/orgs/rp-rs/teams/rp-rs + +## License + +The contents of this repository are dual-licensed under the _MIT OR Apache +2.0_ License. That means you can choose either the MIT license or the +Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more +information on each specific license. + +Any submissions to this project (e.g. as Pull Requests) must be made available +under these terms. diff --git a/boards/rp-pico-w/build.rs b/boards/rp-pico-w/build.rs new file mode 100644 index 000000000..dd9a37119 --- /dev/null +++ b/boards/rp-pico-w/build.rs @@ -0,0 +1,6 @@ +//! This build script makes sure the linker flag -Tdefmt.x is added +//! for the examples. + +fn main() { + println!("cargo:rustc-link-arg-examples=-Tdefmt.x"); +} diff --git a/boards/rp-pico-w/examples/pico_w_blinky.rs b/boards/rp-pico-w/examples/pico_w_blinky.rs new file mode 100644 index 000000000..a752ea06e --- /dev/null +++ b/boards/rp-pico-w/examples/pico_w_blinky.rs @@ -0,0 +1,190 @@ +//! # Pico W Blinky Example +//! +//! Blinks the LED on a Pico W board. +//! +//! This will blink an LED attached to WL_GPIO0, which is the pin the Pico W uses for +//! the on-board LED. It is connected to the the Wifi chip so it cannot be set using RP2040 pins +//! +//! See the `Cargo.toml` file for Copyright and license details. + +#![no_std] +#![no_main] + +use rp_pico_w::entry; + +use defmt::*; +use defmt_rtt as _; +use panic_probe as _; + +use rp_pico_w::hal::pac; + +use rp_pico_w::gspi::GSpi; +use rp_pico_w::hal; + +use embedded_hal::digital::v2::OutputPin; + +use embassy_executor::raw::TaskPool; +use embassy_executor::Executor; +use embassy_executor::Spawner; +use embassy_net::Stack; +use embassy_time::{Duration, Timer}; + +/// The function configures the RP2040 peripherals, initializes +/// networking, then blinks the LED in an infinite loop. +/// TODO: add some simple network service +#[entry] +fn main() -> ! { + info!("start"); + + // Grab our singleton objects + let mut pac = pac::Peripherals::take().unwrap(); + + // Set up the watchdog driver - needed by the clock setup code + let mut watchdog = hal::Watchdog::new(pac.WATCHDOG); + + // Configure the clocks + // + // The default is to generate a 125 MHz system clock + let _clocks = hal::clocks::init_clocks_and_plls( + rp_pico_w::XOSC_CRYSTAL_FREQ, + pac.XOSC, + pac.CLOCKS, + pac.PLL_SYS, + pac.PLL_USB, + &mut pac.RESETS, + &mut watchdog, + ) + .ok() + .unwrap(); + + let sio = hal::Sio::new(pac.SIO); + + let pins = rp_pico_w::Pins::new( + pac.IO_BANK0, + pac.PADS_BANK0, + sio.gpio_bank0, + &mut pac.RESETS, + ); + + info!("init time driver"); + let timer = hal::timer::Timer::new(pac.TIMER, &mut pac.RESETS); + unsafe { rp_pico_w::embassy_time_driver::init(timer) }; + + let mut executor = Executor::new(); + + // Safety: function never returns, executor is never dropped + let executor: &'static mut Executor = unsafe { forever_mut(&mut executor) }; + + let task_pool: TaskPool<_, 1> = TaskPool::new(); + let task_pool = unsafe { forever(&task_pool) }; + + let state = cyw43::State::new(); + let state = unsafe { forever(&state) }; + + info!("run spawner"); + executor.run(|spawner| { + let spawn_token = task_pool.spawn(|| run(spawner, pins, state)); + spawner.spawn(spawn_token).unwrap(); + }); +} + +// TODO documentation +unsafe fn forever_mut(r: &'_ mut T) -> &'static mut T { + core::mem::transmute(r) +} + +// TODO documentation +unsafe fn forever(r: &'_ T) -> &'static T { + core::mem::transmute(r) +} + +async fn run(spawner: Spawner, pins: rp_pico_w::Pins, state: &'static cyw43::State) -> ! { + // These are implicitly used by the spi driver if they are in the correct mode + let mut spi_cs: hal::gpio::dynpin::DynPin = pins.wl_cs.into(); + // TODO should be high from the beginning :-( + spi_cs.into_readable_output(); + spi_cs.set_high().unwrap(); + spi_cs.into_push_pull_output(); + spi_cs.set_high().unwrap(); + + let mut spi_clk = pins.voltage_monitor_wl_clk.into_push_pull_output(); + spi_clk.set_low().unwrap(); + + let mut spi_mosi_miso: hal::gpio::dynpin::DynPin = pins.wl_d.into(); + spi_mosi_miso.into_readable_output(); + spi_mosi_miso.set_low().unwrap(); + spi_mosi_miso.into_push_pull_output(); + spi_mosi_miso.set_low().unwrap(); + + let bus = GSpi::new(spi_clk, spi_mosi_miso); + let spi = embedded_hal_bus::spi::ExclusiveDevice::new(bus, spi_cs); + + let pwr = pins.wl_on.into_push_pull_output(); + + let fw = cyw43::firmware::firmware(); + let clm = cyw43::firmware::clm(); + + use embassy_futures::yield_now; + yield_now().await; + + info!("create cyw43 driver"); + let (mut control, runner) = cyw43::new(state, pwr, spi, fw).await; + + let task_pool: TaskPool<_, 1> = TaskPool::new(); + let task_pool = unsafe { forever(&task_pool) }; + let spawn_token = task_pool.spawn(|| runner.run()); + spawner.spawn(spawn_token).unwrap(); + + info!("init net net device"); + let net_device = control.init(clm).await; + info!("init net net device done"); + + if option_env!("WIFI_NETWORK").is_some() { + if option_env!("WIFI_PASSWORD").is_some() { + control + .join_wpa2( + option_env!("WIFI_NETWORK").unwrap(), + option_env!("WIFI_PASSWORD").unwrap(), + ) + .await; + } else { + control + .join_open(option_env!("WIFI_NETWORK").unwrap()) + .await; + } + } else { + warn!("Environment variable WIFI_NETWORK not set during compilation - not joining wireless network"); + } + let config = embassy_net::ConfigStrategy::Dhcp; + //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config { + // address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), + // dns_servers: Vec::new(), + // gateway: Some(Ipv4Address::new(192, 168, 69, 1)), + //}); + + // Generate random seed + let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. + + let mut stack_resources = embassy_net::StackResources::<1, 2, 8>::new(); + let stack_resources = unsafe { forever_mut(&mut stack_resources) }; + + // Init network stack + let stack = Stack::new(net_device, config, stack_resources, seed); + let stack = unsafe { forever(&stack) }; + + let task_pool: TaskPool<_, 1> = TaskPool::new(); + let task_pool = unsafe { forever(&task_pool) }; + let spawn_token = task_pool.spawn(|| stack.run()); + spawner.spawn(spawn_token).unwrap(); + + // Blink the LED at 1 Hz + loop { + info!("on"); + control.gpio_set(0, true).await; + Timer::after(Duration::from_millis(500)).await; + + info!("off"); + control.gpio_set(0, false).await; + Timer::after(Duration::from_millis(500)).await; + } +} diff --git a/boards/rp-pico-w/src/embassy_time_driver.rs b/boards/rp-pico-w/src/embassy_time_driver.rs new file mode 100644 index 000000000..6350bb78d --- /dev/null +++ b/boards/rp-pico-w/src/embassy_time_driver.rs @@ -0,0 +1,229 @@ +// copied from embassy-rp + +use core::cell::Cell; +use core::cell::RefCell; +use core::ops::DerefMut; + +use atomic_polyfill::{AtomicU8, Ordering}; +use critical_section::CriticalSection; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::blocking_mutex::Mutex; +use embassy_time::driver::{AlarmHandle, Driver}; + +use rp2040_hal::pac; +use rp2040_hal::pac::interrupt; +use rp2040_hal::timer::Alarm; +use rp2040_hal::timer::Alarm0; +use rp2040_hal::timer::Instant; +use rp2040_hal::timer::ScheduleAlarmError; +use rp2040_hal::timer::Timer; + +use defmt::*; + +struct AlarmState { + timestamp: Cell, + #[allow(clippy::type_complexity)] + callback: Cell>, +} +unsafe impl Send for AlarmState {} + +const ALARM_COUNT: usize = 4; +const NO_ALARM: Instant = Instant::from_ticks(u64::MAX); + +#[allow(clippy::declare_interior_mutable_const)] +const DUMMY_ALARM: AlarmState = AlarmState { + timestamp: Cell::new(NO_ALARM), + callback: Cell::new(None), +}; + +struct TimerDriver { + timer: Mutex>>, + alarm: Mutex>>, + alarms: Mutex, + next_alarm: AtomicU8, +} + +embassy_time::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{ + timer: Mutex::const_new(CriticalSectionRawMutex::new(), RefCell::new(None)), + alarm: Mutex::const_new(CriticalSectionRawMutex::new(), RefCell::new(None)), + alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [DUMMY_ALARM; ALARM_COUNT]), + next_alarm: AtomicU8::new(0), +}); + +impl Driver for TimerDriver { + fn now(&self) -> u64 { + self.now_instant().ticks() + } + + unsafe fn allocate_alarm(&self) -> Option { + let id = self + .next_alarm + .fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| { + if x < ALARM_COUNT as u8 { + Some(x + 1) + } else { + warn!("No alarm left"); + None + } + }); + + match id { + Ok(id) => Some(AlarmHandle::new(id)), + Err(_) => None, + } + } + + fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { + let n = alarm.id() as usize; + critical_section::with(|cs| { + let alarm = &self.alarms.borrow(cs)[n]; + alarm.callback.set(Some((callback, ctx))); + }) + } + + fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { + let n = alarm.id() as usize; + critical_section::with(|cs| { + let alarms = self.alarms.borrow(cs); + let alarm = &alarms[n]; + if alarm.timestamp.get().ticks() == timestamp { + // redundant set_alarm - ignore + return true; + } + alarm.timestamp.set(Instant::from_ticks(timestamp)); + + self.arm(cs); + trace!("set alarm {} to {}", n, timestamp); + true + }) + } +} + +impl TimerDriver { + fn now_instant(&self) -> Instant { + critical_section::with(|cs| { + self.timer + .borrow(cs) + .borrow() + .as_ref() + .unwrap() + .get_counter() + }) + } + + fn arm(&self, cs: CriticalSection) { + let (_, min_timestamp) = self.next_scheduled_alarm(); + if min_timestamp == NO_ALARM { + // no alarm set + trace!("Trying to arm non-existing alarm"); + return; + } + // Arm it. + trace!("arm!"); + // Note that we're not checking the high bits at all. This means the irq may fire early + // if the alarm is more than 72 minutes (2^32 us) in the future. This is OK, since on irq fire + // it is checked if the alarm time has passed. + let now = self.now_instant(); + use fugit::MicrosDurationU32; + let mut alarm = self.alarm.borrow(cs).borrow_mut(); + let alarm = alarm.deref_mut().as_mut().unwrap(); + match alarm.schedule_at(min_timestamp) { + Result::Err(ScheduleAlarmError::AlarmTooLate) => { + // Duration >72 minutes. Reschedule 1 hour later. + trace!("reschedule in 1h"); + alarm.schedule(MicrosDurationU32::hours(1)).unwrap(); + } + Ok(_) => { + debug!("min: {}, now: {}", min_timestamp.ticks(), now.ticks()); + } + } + } + + fn check_alarm(&self) { + trace!("checking alarm"); + critical_section::with(|cs| { + self.alarm + .borrow(cs) + .borrow_mut() + .deref_mut() + .as_mut() + .unwrap() + .clear_interrupt(); + let next = self.next_scheduled_alarm(); + if next.1 == NO_ALARM { + warn!("No next alarm. Spurious interrupt?"); + return; + } + let (n, timestamp) = next; + let now = self.now_instant(); + // alarm peripheral has only 32 bits, so might have triggered early + if timestamp.const_cmp(now) == core::cmp::Ordering::Less { + self.trigger_alarm(n, cs) + } else { + warn!( + "Alarm in future, {} < {} re-arm", + now.ticks(), + timestamp.ticks() + ); + } + // next alarm could have changed - rearm + self.arm(cs); + }); + } + + fn trigger_alarm(&self, n: usize, cs: CriticalSection) { + debug!("triggered alarm {}", n); + // disarm + // ignore... for now unsafe { pac::TIMER.armed().write(|w| w.set_armed(1 << n)) } + + let alarm = &self.alarms.borrow(cs)[n]; + alarm.timestamp.set(NO_ALARM); + + // Call after clearing alarm, so the callback can set another alarm. + if let Some((f, ctx)) = alarm.callback.get() { + trace!("callback:"); + f(ctx); + } + trace!("callback executed"); + } + + fn next_scheduled_alarm(&self) -> (usize, Instant) { + critical_section::with(|cs| { + self.alarms + .borrow(cs) + .iter() + .map(|a| a.timestamp.get()) + .enumerate() + .min_by_key(|p| p.1.ticks()) + .unwrap() + }) + } +} + +/// # Safety +/// must be called exactly once at bootup +pub unsafe fn init(mut timer: Timer) { + // init alarms + critical_section::with(|cs| { + // make sure the alarm is not yet taken, + // and leak it, so it can be used safely + let mut alarm = timer.alarm_0().unwrap(); + alarm.enable_interrupt(); + //unsafe { + pac::NVIC::unmask(pac::Interrupt::TIMER_IRQ_0); + //} + trace!("interrupt enabled!"); + DRIVER.alarm.borrow(cs).replace(Some(alarm)); + DRIVER.timer.borrow(cs).replace(Some(timer)); + let alarms = DRIVER.alarms.borrow(cs); + for a in alarms { + a.timestamp.set(NO_ALARM); + } + }); +} + +#[interrupt] +unsafe fn TIMER_IRQ_0() { + trace!("Interrupt!"); + DRIVER.check_alarm() +} diff --git a/boards/rp-pico-w/src/gspi.rs b/boards/rp-pico-w/src/gspi.rs new file mode 100644 index 000000000..8735d6d5b --- /dev/null +++ b/boards/rp-pico-w/src/gspi.rs @@ -0,0 +1,107 @@ +//! Simple driver for the gSPI connection between rp2040 and CYW43439 wifi chip. +//! +//! This is just a quick bit-banging hack to get pico-w working and should be replaced +//! by a PIO based driver. + +use defmt::*; + +use core::convert::Infallible; + +// A shorter alias for the Hardware Abstraction Layer, which provides +// higher-level drivers. +use crate::hal; + +use embedded_hal::digital::v2::InputPin; +use embedded_hal::digital::v2::OutputPin; +use embedded_hal_1::spi::ErrorType; +use embedded_hal_1::spi::SpiBusFlush; +use embedded_hal_1::spi::{SpiBusRead, SpiBusWrite}; + +pub struct GSpi { + /// SPI clock + clk: hal::gpio::Pin>, + + /// 4 signals, all in one!! + /// - SPI MISO + /// - SPI MOSI + /// - IRQ + /// - strap to set to gSPI mode on boot. + dio: hal::gpio::dynpin::DynPin, +} + +impl GSpi { + pub fn new( + clk: hal::gpio::Pin>, + dio: hal::gpio::dynpin::DynPin, + ) -> Self { + Self { clk, dio } + } +} + +impl ErrorType for GSpi { + type Error = Infallible; +} + +impl SpiBusFlush for GSpi { + fn flush(&mut self) -> Result<(), Self::Error> { + Ok(()) + } +} + +impl SpiBusRead for GSpi { + fn read<'a>(&'a mut self, words: &'a mut [u32]) -> Result<(), Self::Error> { + trace!("spi read {}", words.len()); + self.dio.into_floating_input(); + for word in words.iter_mut() { + let mut w = 0; + for _ in 0..32 { + w <<= 1; + + cortex_m::asm::nop(); + // rising edge, sample data + if self.dio.is_high().unwrap() { + w |= 0x01; + } + self.clk.set_high().unwrap(); + + cortex_m::asm::nop(); + // falling edge + self.clk.set_low().unwrap(); + } + *word = w + } + + trace!("spi read result: {:x}", words); + Ok(()) + } +} + +impl SpiBusWrite for GSpi { + fn write<'a>(&'a mut self, words: &'a [u32]) -> Result<(), Self::Error> { + trace!("spi write {:x}", words); + self.dio.into_push_pull_output(); + for word in words { + let mut word = *word; + for _ in 0..32 { + // falling edge, setup data + cortex_m::asm::nop(); + self.clk.set_low().unwrap(); + if word & 0x8000_0000 == 0 { + self.dio.set_low().unwrap(); + } else { + self.dio.set_high().unwrap(); + } + + cortex_m::asm::nop(); + // rising edge + self.clk.set_high().unwrap(); + + word <<= 1; + } + } + self.clk.set_low().unwrap(); + + self.dio.into_floating_input(); + Ok(()) + } +} diff --git a/boards/rp-pico-w/src/lib.rs b/boards/rp-pico-w/src/lib.rs new file mode 100644 index 000000000..b5d5282ef --- /dev/null +++ b/boards/rp-pico-w/src/lib.rs @@ -0,0 +1,775 @@ +#![no_std] + +pub extern crate rp2040_hal as hal; + +#[cfg(feature = "rt")] +extern crate cortex_m_rt; +#[cfg(feature = "rt")] +pub use hal::entry; + +pub mod embassy_time_driver; +pub mod gspi; + +/// The linker will place this boot block at the start of our program image. We +/// need this to help the ROM bootloader get our code up and running. +#[cfg(feature = "boot2")] +#[link_section = ".boot2"] +#[no_mangle] +#[used] +pub static BOOT2_FIRMWARE: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080; + +pub use hal::pac; + +hal::bsp_pins!( + /// GPIO 0 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI0 RX` | [crate::Gp0Spi0Rx] | + /// | `UART0 TX` | [crate::Gp0Uart0Tx] | + /// | `I2C0 SDA` | [crate::Gp0I2C0Sda] | + /// | `PWM0 A` | [crate::Gp0Pwm0A] | + /// | `PIO0` | [crate::Gp0Pio0] | + /// | `PIO1` | [crate::Gp0Pio1] | + Gpio0 { + name: gpio0, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio0]. + FunctionUart: Gp0Uart0Tx, + /// SPI Function alias for pin [crate::Pins::gpio0]. + FunctionSpi: Gp0Spi0Rx, + /// I2C Function alias for pin [crate::Pins::gpio0]. + FunctionI2C: Gp0I2C0Sda, + /// PWM Function alias for pin [crate::Pins::gpio0]. + FunctionPwm: Gp0Pwm0A, + /// PIO0 Function alias for pin [crate::Pins::gpio0]. + FunctionPio0: Gp0Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio0]. + FunctionPio1: Gp0Pio1 + } + }, + + /// GPIO 1 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI0 CSn` | [crate::Gp1Spi0Csn] | + /// | `UART0 RX` | [crate::Gp1Uart0Rx] | + /// | `I2C0 SCL` | [crate::Gp1I2C0Scl] | + /// | `PWM0 B` | [crate::Gp1Pwm0B] | + /// | `PIO0` | [crate::Gp1Pio0] | + /// | `PIO1` | [crate::Gp1Pio1] | + Gpio1 { + name: gpio1, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio1]. + FunctionUart: Gp1Uart0Rx, + /// SPI Function alias for pin [crate::Pins::gpio1]. + FunctionSpi: Gp1Spi0Csn, + /// I2C Function alias for pin [crate::Pins::gpio1]. + FunctionI2C: Gp1I2C0Scl, + /// PWM Function alias for pin [crate::Pins::gpio1]. + FunctionPwm: Gp1Pwm0B, + /// PIO0 Function alias for pin [crate::Pins::gpio1]. + FunctionPio0: Gp1Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio1]. + FunctionPio1: Gp1Pio1 + } + }, + + /// GPIO 2 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI0 SCK` | [crate::Gp2Spi0Sck] | + /// | `UART0 CTS` | [crate::Gp2Uart0Cts] | + /// | `I2C1 SDA` | [crate::Gp2I2C1Sda] | + /// | `PWM1 A` | [crate::Gp2Pwm1A] | + /// | `PIO0` | [crate::Gp2Pio0] | + /// | `PIO1` | [crate::Gp2Pio1] | + Gpio2 { + name: gpio2, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio2]. + FunctionUart: Gp2Uart0Cts, + /// SPI Function alias for pin [crate::Pins::gpio2]. + FunctionSpi: Gp2Spi0Sck, + /// I2C Function alias for pin [crate::Pins::gpio2]. + FunctionI2C: Gp2I2C1Sda, + /// PWM Function alias for pin [crate::Pins::gpio2]. + FunctionPwm: Gp2Pwm1A, + /// PIO0 Function alias for pin [crate::Pins::gpio2]. + FunctionPio0: Gp2Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio2]. + FunctionPio1: Gp2Pio1 + } + }, + + /// GPIO 3 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI0 TX` | [crate::Gp3Spi0Tx] | + /// | `UART0 RTS` | [crate::Gp3Uart0Rts] | + /// | `I2C1 SCL` | [crate::Gp3I2C1Scl] | + /// | `PWM1 B` | [crate::Gp3Pwm1B] | + /// | `PIO0` | [crate::Gp3Pio0] | + /// | `PIO1` | [crate::Gp3Pio1] | + Gpio3 { + name: gpio3, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio3]. + FunctionUart: Gp3Uart0Rts, + /// SPI Function alias for pin [crate::Pins::gpio3]. + FunctionSpi: Gp3Spi0Tx, + /// I2C Function alias for pin [crate::Pins::gpio3]. + FunctionI2C: Gp3I2C1Scl, + /// PWM Function alias for pin [crate::Pins::gpio3]. + FunctionPwm: Gp3Pwm1B, + /// PIO0 Function alias for pin [crate::Pins::gpio3]. + FunctionPio0: Gp3Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio3]. + FunctionPio1: Gp3Pio1 + } + }, + + /// GPIO 4 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI0 RX` | [crate::Gp4Spi0Rx] | + /// | `UART1 TX` | [crate::Gp4Uart1Tx] | + /// | `I2C0 SDA` | [crate::Gp4I2C0Sda] | + /// | `PWM2 A` | [crate::Gp4Pwm2A] | + /// | `PIO0` | [crate::Gp4Pio0] | + /// | `PIO1` | [crate::Gp4Pio1] | + Gpio4 { + name: gpio4, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio4]. + FunctionUart: Gp4Uart1Tx, + /// SPI Function alias for pin [crate::Pins::gpio4]. + FunctionSpi: Gp4Spi0Rx, + /// I2C Function alias for pin [crate::Pins::gpio4]. + FunctionI2C: Gp4I2C0Sda, + /// PWM Function alias for pin [crate::Pins::gpio4]. + FunctionPwm: Gp4Pwm2A, + /// PIO0 Function alias for pin [crate::Pins::gpio4]. + FunctionPio0: Gp4Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio4]. + FunctionPio1: Gp4Pio1 + } + }, + + /// GPIO 5 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI0 CSn` | [crate::Gp5Spi0Csn] | + /// | `UART1 RX` | [crate::Gp5Uart1Rx] | + /// | `I2C0 SCL` | [crate::Gp5I2C0Scl] | + /// | `PWM2 B` | [crate::Gp5Pwm2B] | + /// | `PIO0` | [crate::Gp5Pio0] | + /// | `PIO1` | [crate::Gp5Pio1] | + Gpio5 { + name: gpio5, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio5]. + FunctionUart: Gp5Uart1Rx, + /// SPI Function alias for pin [crate::Pins::gpio5]. + FunctionSpi: Gp5Spi0Csn, + /// I2C Function alias for pin [crate::Pins::gpio5]. + FunctionI2C: Gp5I2C0Scl, + /// PWM Function alias for pin [crate::Pins::gpio5]. + FunctionPwm: Gp5Pwm2B, + /// PIO0 Function alias for pin [crate::Pins::gpio5]. + FunctionPio0: Gp5Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio5]. + FunctionPio1: Gp5Pio1 + } + }, + + /// GPIO 6 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI0 SCK` | [crate::Gp6Spi0Sck] | + /// | `UART1 CTS` | [crate::Gp6Uart1Cts] | + /// | `I2C1 SDA` | [crate::Gp6I2C1Sda] | + /// | `PWM3 A` | [crate::Gp6Pwm3A] | + /// | `PIO0` | [crate::Gp6Pio0] | + /// | `PIO1` | [crate::Gp6Pio1] | + Gpio6 { + name: gpio6, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio6]. + FunctionUart: Gp6Uart1Cts, + /// SPI Function alias for pin [crate::Pins::gpio6]. + FunctionSpi: Gp6Spi0Sck, + /// I2C Function alias for pin [crate::Pins::gpio6]. + FunctionI2C: Gp6I2C1Sda, + /// PWM Function alias for pin [crate::Pins::gpio6]. + FunctionPwm: Gp6Pwm3A, + /// PIO0 Function alias for pin [crate::Pins::gpio6]. + FunctionPio0: Gp6Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio6]. + FunctionPio1: Gp6Pio1 + } + }, + + /// GPIO 7 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI0 TX` | [crate::Gp7Spi0Tx] | + /// | `UART1 RTS` | [crate::Gp7Uart1Rts] | + /// | `I2C1 SCL` | [crate::Gp7I2C1Scl] | + /// | `PWM3 B` | [crate::Gp7Pwm3B] | + /// | `PIO0` | [crate::Gp7Pio0] | + /// | `PIO1` | [crate::Gp7Pio1] | + Gpio7 { + name: gpio7, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio7]. + FunctionUart: Gp7Uart1Rts, + /// SPI Function alias for pin [crate::Pins::gpio7]. + FunctionSpi: Gp7Spi0Tx, + /// I2C Function alias for pin [crate::Pins::gpio7]. + FunctionI2C: Gp7I2C1Scl, + /// PWM Function alias for pin [crate::Pins::gpio7]. + FunctionPwm: Gp7Pwm3B, + /// PIO0 Function alias for pin [crate::Pins::gpio7]. + FunctionPio0: Gp7Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio7]. + FunctionPio1: Gp7Pio1 + } + }, + + /// GPIO 8 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI1 RX` | [crate::Gp8Spi1Rx] | + /// | `UART1 TX` | [crate::Gp8Uart1Tx] | + /// | `I2C0 SDA` | [crate::Gp8I2C0Sda] | + /// | `PWM4 A` | [crate::Gp8Pwm4A] | + /// | `PIO0` | [crate::Gp8Pio0] | + /// | `PIO1` | [crate::Gp8Pio1] | + Gpio8 { + name: gpio8, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio8]. + FunctionUart: Gp8Uart1Tx, + /// SPI Function alias for pin [crate::Pins::gpio8]. + FunctionSpi: Gp8Spi1Rx, + /// I2C Function alias for pin [crate::Pins::gpio8]. + FunctionI2C: Gp8I2C0Sda, + /// PWM Function alias for pin [crate::Pins::gpio8]. + FunctionPwm: Gp8Pwm4A, + /// PIO0 Function alias for pin [crate::Pins::gpio8]. + FunctionPio0: Gp8Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio8]. + FunctionPio1: Gp8Pio1 + } + }, + + /// GPIO 9 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI1 CSn` | [crate::Gp9Spi1Csn] | + /// | `UART1 RX` | [crate::Gp9Uart1Rx] | + /// | `I2C0 SCL` | [crate::Gp9I2C0Scl] | + /// | `PWM4 B` | [crate::Gp9Pwm4B] | + /// | `PIO0` | [crate::Gp9Pio0] | + /// | `PIO1` | [crate::Gp9Pio1] | + Gpio9 { + name: gpio9, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio9]. + FunctionUart: Gp9Uart1Rx, + /// SPI Function alias for pin [crate::Pins::gpio9]. + FunctionSpi: Gp9Spi1Csn, + /// I2C Function alias for pin [crate::Pins::gpio9]. + FunctionI2C: Gp9I2C0Scl, + /// PWM Function alias for pin [crate::Pins::gpio9]. + FunctionPwm: Gp9Pwm4B, + /// PIO0 Function alias for pin [crate::Pins::gpio9]. + FunctionPio0: Gp9Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio9]. + FunctionPio1: Gp9Pio1 + } + }, + + /// GPIO 10 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI1 SCK` | [crate::Gp10Spi1Sck] | + /// | `UART1 CTS` | [crate::Gp10Uart1Cts] | + /// | `I2C1 SDA` | [crate::Gp10I2C1Sda] | + /// | `PWM5 A` | [crate::Gp10Pwm5A] | + /// | `PIO0` | [crate::Gp10Pio0] | + /// | `PIO1` | [crate::Gp10Pio1] | + Gpio10 { + name: gpio10, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio10]. + FunctionUart: Gp10Uart1Cts, + /// SPI Function alias for pin [crate::Pins::gpio10]. + FunctionSpi: Gp10Spi1Sck, + /// I2C Function alias for pin [crate::Pins::gpio10]. + FunctionI2C: Gp10I2C1Sda, + /// PWM Function alias for pin [crate::Pins::gpio10]. + FunctionPwm: Gp10Pwm5A, + /// PIO0 Function alias for pin [crate::Pins::gpio10]. + FunctionPio0: Gp10Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio10]. + FunctionPio1: Gp10Pio1 + } + }, + + /// GPIO 11 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI1 TX` | [crate::Gp11Spi1Tx] | + /// | `UART1 RTS` | [crate::Gp11Uart1Rts] | + /// | `I2C1 SCL` | [crate::Gp11I2C1Scl] | + /// | `PWM5 B` | [crate::Gp11Pwm5B] | + /// | `PIO0` | [crate::Gp11Pio0] | + /// | `PIO1` | [crate::Gp11Pio1] | + Gpio11 { + name: gpio11, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio11]. + FunctionUart: Gp11Uart1Rts, + /// SPI Function alias for pin [crate::Pins::gpio11]. + FunctionSpi: Gp11Spi1Tx, + /// I2C Function alias for pin [crate::Pins::gpio11]. + FunctionI2C: Gp11I2C1Scl, + /// PWM Function alias for pin [crate::Pins::gpio11]. + FunctionPwm: Gp11Pwm5B, + /// PIO0 Function alias for pin [crate::Pins::gpio11]. + FunctionPio0: Gp11Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio11]. + FunctionPio1: Gp11Pio1 + } + }, + + /// GPIO 12 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI1 RX` | [crate::Gp12Spi1Rx] | + /// | `UART0 TX` | [crate::Gp12Uart0Tx] | + /// | `I2C0 SDA` | [crate::Gp12I2C0Sda] | + /// | `PWM6 A` | [crate::Gp12Pwm6A] | + /// | `PIO0` | [crate::Gp12Pio0] | + /// | `PIO1` | [crate::Gp12Pio1] | + Gpio12 { + name: gpio12, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio12]. + FunctionUart: Gp12Uart0Tx, + /// SPI Function alias for pin [crate::Pins::gpio12]. + FunctionSpi: Gp12Spi1Rx, + /// I2C Function alias for pin [crate::Pins::gpio12]. + FunctionI2C: Gp12I2C0Sda, + /// PWM Function alias for pin [crate::Pins::gpio12]. + FunctionPwm: Gp12Pwm6A, + /// PIO0 Function alias for pin [crate::Pins::gpio12]. + FunctionPio0: Gp12Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio12]. + FunctionPio1: Gp12Pio1 + } + }, + + /// GPIO 13 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI1 CSn` | [crate::Gp13Spi1Csn] | + /// | `UART0 RX` | [crate::Gp13Uart0Rx] | + /// | `I2C0 SCL` | [crate::Gp13I2C0Scl] | + /// | `PWM6 B` | [crate::Gp13Pwm6B] | + /// | `PIO0` | [crate::Gp13Pio0] | + /// | `PIO1` | [crate::Gp13Pio1] | + Gpio13 { + name: gpio13, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio13]. + FunctionUart: Gp13Uart0Rx, + /// SPI Function alias for pin [crate::Pins::gpio13]. + FunctionSpi: Gp13Spi1Csn, + /// I2C Function alias for pin [crate::Pins::gpio13]. + FunctionI2C: Gp13I2C0Scl, + /// PWM Function alias for pin [crate::Pins::gpio13]. + FunctionPwm: Gp13Pwm6B, + /// PIO0 Function alias for pin [crate::Pins::gpio13]. + FunctionPio0: Gp13Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio13]. + FunctionPio1: Gp13Pio1 + } + }, + + /// GPIO 14 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI1 SCK` | [crate::Gp14Spi1Sck] | + /// | `UART0 CTS` | [crate::Gp14Uart0Cts] | + /// | `I2C1 SDA` | [crate::Gp14I2C1Sda] | + /// | `PWM7 A` | [crate::Gp14Pwm7A] | + /// | `PIO0` | [crate::Gp14Pio0] | + /// | `PIO1` | [crate::Gp14Pio1] | + Gpio14 { + name: gpio14, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio14]. + FunctionUart: Gp14Uart0Cts, + /// SPI Function alias for pin [crate::Pins::gpio14]. + FunctionSpi: Gp14Spi1Sck, + /// I2C Function alias for pin [crate::Pins::gpio14]. + FunctionI2C: Gp14I2C1Sda, + /// PWM Function alias for pin [crate::Pins::gpio14]. + FunctionPwm: Gp14Pwm7A, + /// PIO0 Function alias for pin [crate::Pins::gpio14]. + FunctionPio0: Gp14Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio14]. + FunctionPio1: Gp14Pio1 + } + }, + + /// GPIO 15 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI1 TX` | [crate::Gp15Spi1Tx] | + /// | `UART0 RTS` | [crate::Gp15Uart0Rts] | + /// | `I2C1 SCL` | [crate::Gp15I2C1Scl] | + /// | `PWM7 B` | [crate::Gp15Pwm7B] | + /// | `PIO0` | [crate::Gp15Pio0] | + /// | `PIO1` | [crate::Gp15Pio1] | + Gpio15 { + name: gpio15, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio15]. + FunctionUart: Gp15Uart0Rts, + /// SPI Function alias for pin [crate::Pins::gpio15]. + FunctionSpi: Gp15Spi1Tx, + /// I2C Function alias for pin [crate::Pins::gpio15]. + FunctionI2C: Gp15I2C1Scl, + /// PWM Function alias for pin [crate::Pins::gpio15]. + FunctionPwm: Gp15Pwm7B, + /// PIO0 Function alias for pin [crate::Pins::gpio15]. + FunctionPio0: Gp15Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio15]. + FunctionPio1: Gp15Pio1 + } + }, + + /// GPIO 16 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI0 RX` | [crate::Gp16Spi0Rx] | + /// | `UART0 TX` | [crate::Gp16Uart0Tx] | + /// | `I2C0 SDA` | [crate::Gp16I2C0Sda] | + /// | `PWM0 A` | [crate::Gp16Pwm0A] | + /// | `PIO0` | [crate::Gp16Pio0] | + /// | `PIO1` | [crate::Gp16Pio1] | + Gpio16 { + name: gpio16, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio16]. + FunctionUart: Gp16Uart0Tx, + /// SPI Function alias for pin [crate::Pins::gpio16]. + FunctionSpi: Gp16Spi0Rx, + /// I2C Function alias for pin [crate::Pins::gpio16]. + FunctionI2C: Gp16I2C0Sda, + /// PWM Function alias for pin [crate::Pins::gpio16]. + FunctionPwm: Gp16Pwm0A, + /// PIO0 Function alias for pin [crate::Pins::gpio16]. + FunctionPio0: Gp16Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio16]. + FunctionPio1: Gp16Pio1 + } + }, + + /// GPIO 17 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI0 CSn` | [crate::Gp17Spi0Csn] | + /// | `UART0 RX` | [crate::Gp17Uart0Rx] | + /// | `I2C0 SCL` | [crate::Gp17I2C0Scl] | + /// | `PWM0 B` | [crate::Gp17Pwm0B] | + /// | `PIO0` | [crate::Gp17Pio0] | + /// | `PIO1` | [crate::Gp17Pio1] | + Gpio17 { + name: gpio17, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio17]. + FunctionUart: Gp17Uart0Rx, + /// SPI Function alias for pin [crate::Pins::gpio17]. + FunctionSpi: Gp17Spi0Csn, + /// I2C Function alias for pin [crate::Pins::gpio17]. + FunctionI2C: Gp17I2C0Scl, + /// PWM Function alias for pin [crate::Pins::gpio17]. + FunctionPwm: Gp17Pwm0B, + /// PIO0 Function alias for pin [crate::Pins::gpio17]. + FunctionPio0: Gp17Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio17]. + FunctionPio1: Gp17Pio1 + } + }, + + /// GPIO 18 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI0 SCK` | [crate::Gp18Spi0Sck] | + /// | `UART0 CTS` | [crate::Gp18Uart0Cts] | + /// | `I2C1 SDA` | [crate::Gp18I2C1Sda] | + /// | `PWM1 A` | [crate::Gp18Pwm1A] | + /// | `PIO0` | [crate::Gp18Pio0] | + /// | `PIO1` | [crate::Gp18Pio1] | + Gpio18 { + name: gpio18, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio18]. + FunctionUart: Gp18Uart0Cts, + /// SPI Function alias for pin [crate::Pins::gpio18]. + FunctionSpi: Gp18Spi0Sck, + /// I2C Function alias for pin [crate::Pins::gpio18]. + FunctionI2C: Gp18I2C1Sda, + /// PWM Function alias for pin [crate::Pins::gpio18]. + FunctionPwm: Gp18Pwm1A, + /// PIO0 Function alias for pin [crate::Pins::gpio18]. + FunctionPio0: Gp18Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio18]. + FunctionPio1: Gp18Pio1 + } + }, + + /// GPIO 19 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI0 TX` | [crate::Gp19Spi0Tx] | + /// | `UART0 RTS` | [crate::Gp19Uart0Rts] | + /// | `I2C1 SCL` | [crate::Gp19I2C1Scl] | + /// | `PWM1 B` | [crate::Gp19Pwm1B] | + /// | `PIO0` | [crate::Gp19Pio0] | + /// | `PIO1` | [crate::Gp19Pio1] | + Gpio19 { + name: gpio19, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio19]. + FunctionUart: Gp19Uart0Rts, + /// SPI Function alias for pin [crate::Pins::gpio19]. + FunctionSpi: Gp19Spi0Tx, + /// I2C Function alias for pin [crate::Pins::gpio19]. + FunctionI2C: Gp19I2C1Scl, + /// PWM Function alias for pin [crate::Pins::gpio19]. + FunctionPwm: Gp19Pwm1B, + /// PIO0 Function alias for pin [crate::Pins::gpio19]. + FunctionPio0: Gp19Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio19]. + FunctionPio1: Gp19Pio1 + } + }, + + /// GPIO 20 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI0 RX` | [crate::Gp20Spi0Rx] | + /// | `UART1 TX` | [crate::Gp20Uart1Tx] | + /// | `I2C0 SDA` | [crate::Gp20I2C0Sda] | + /// | `PWM2 A` | [crate::Gp20Pwm2A] | + /// | `PIO0` | [crate::Gp20Pio0] | + /// | `PIO1` | [crate::Gp20Pio1] | + Gpio20 { + name: gpio20, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio20]. + FunctionUart: Gp20Uart1Tx, + /// SPI Function alias for pin [crate::Pins::gpio20]. + FunctionSpi: Gp20Spi0Rx, + /// I2C Function alias for pin [crate::Pins::gpio20]. + FunctionI2C: Gp20I2C0Sda, + /// PWM Function alias for pin [crate::Pins::gpio20]. + FunctionPwm: Gp20Pwm2A, + /// PIO0 Function alias for pin [crate::Pins::gpio20]. + FunctionPio0: Gp20Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio20]. + FunctionPio1: Gp20Pio1 + } + }, + + /// GPIO 21 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI0 CSn` | [crate::Gp21Spi0Csn] | + /// | `UART1 RX` | [crate::Gp21Uart1Rx] | + /// | `I2C0 SCL` | [crate::Gp21I2C0Scl] | + /// | `PWM2 B` | [crate::Gp21Pwm2B] | + /// | `PIO0` | [crate::Gp21Pio0] | + /// | `PIO1` | [crate::Gp21Pio1] | + Gpio21 { + name: gpio21, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio21]. + FunctionUart: Gp21Uart1Rx, + /// SPI Function alias for pin [crate::Pins::gpio21]. + FunctionSpi: Gp21Spi0Csn, + /// I2C Function alias for pin [crate::Pins::gpio21]. + FunctionI2C: Gp21I2C0Scl, + /// PWM Function alias for pin [crate::Pins::gpio21]. + FunctionPwm: Gp21Pwm2B, + /// PIO0 Function alias for pin [crate::Pins::gpio21]. + FunctionPio0: Gp21Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio21]. + FunctionPio1: Gp21Pio1 + } + }, + + /// GPIO 22 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI0 SCK` | [crate::Gp22Spi0Sck] | + /// | `UART1 CTS` | [crate::Gp22Uart1Cts] | + /// | `I2C1 SDA` | [crate::Gp22I2C1Sda] | + /// | `PWM3 A` | [crate::Gp22Pwm3A] | + /// | `PIO0` | [crate::Gp22Pio0] | + /// | `PIO1` | [crate::Gp22Pio1] | + Gpio22 { + name: gpio22, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio22]. + FunctionUart: Gp22Uart1Cts, + /// SPI Function alias for pin [crate::Pins::gpio22]. + FunctionSpi: Gp22Spi0Sck, + /// I2C Function alias for pin [crate::Pins::gpio22]. + FunctionI2C: Gp22I2C1Sda, + /// PWM Function alias for pin [crate::Pins::gpio22]. + FunctionPwm: Gp22Pwm3A, + /// PIO0 Function alias for pin [crate::Pins::gpio22]. + FunctionPio0: Gp22Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio22]. + FunctionPio1: Gp22Pio1 + } + }, + + /// GPIO 23 is connected to wireless power on signal + Gpio23 { + name: wl_on, + }, + + /// GPIO 24 is connected to wireless SPI data/IRQ. + Gpio24 { + name: wl_d, + }, + + /// GPIO 25 is connected to wireless SPI CS (when high also enables GPIO29 ADC pin to read + /// VSYS) + Gpio25 { + name: wl_cs, + }, + + /// GPIO 26 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI1 SCK` | [crate::Gp26Spi1Sck] | + /// | `UART1 CTS` | [crate::Gp26Uart1Cts] | + /// | `I2C1 SDA` | [crate::Gp26I2C1Sda] | + /// | `PWM5 A` | [crate::Gp26Pwm5A] | + /// | `PIO0` | [crate::Gp26Pio0] | + /// | `PIO1` | [crate::Gp26Pio1] | + Gpio26 { + name: gpio26, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio26]. + FunctionUart: Gp26Uart1Cts, + /// SPI Function alias for pin [crate::Pins::gpio26]. + FunctionSpi: Gp26Spi1Sck, + /// I2C Function alias for pin [crate::Pins::gpio26]. + FunctionI2C: Gp26I2C1Sda, + /// PWM Function alias for pin [crate::Pins::gpio26]. + FunctionPwm: Gp26Pwm5A, + /// PIO0 Function alias for pin [crate::Pins::gpio26]. + FunctionPio0: Gp26Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio26]. + FunctionPio1: Gp26Pio1 + } + }, + + /// GPIO 27 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI1 TX` | [crate::Gp27Spi1Tx] | + /// | `UART1 RTS` | [crate::Gp27Uart1Rts] | + /// | `I2C1 SCL` | [crate::Gp27I2C1Scl] | + /// | `PWM5 B` | [crate::Gp27Pwm5B] | + /// | `PIO0` | [crate::Gp27Pio0] | + /// | `PIO1` | [crate::Gp27Pio1] | + Gpio27 { + name: gpio27, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio27]. + FunctionUart: Gp27Uart1Rts, + /// SPI Function alias for pin [crate::Pins::gpio27]. + FunctionSpi: Gp27Spi1Tx, + /// I2C Function alias for pin [crate::Pins::gpio27]. + FunctionI2C: Gp27I2C1Scl, + /// PWM Function alias for pin [crate::Pins::gpio27]. + FunctionPwm: Gp27Pwm5B, + /// PIO0 Function alias for pin [crate::Pins::gpio27]. + FunctionPio0: Gp27Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio27]. + FunctionPio1: Gp27Pio1 + } + }, + + /// GPIO 28 supports following functions: + /// + /// | Function | Alias with applied function | + /// |--------------|-----------------------------| + /// | `SPI1 RX` | [crate::Gp28Spi1Rx] | + /// | `UART0 TX` | [crate::Gp28Uart0Tx] | + /// | `I2C0 SDA` | [crate::Gp28I2C0Sda] | + /// | `PWM6 A` | [crate::Gp28Pwm6A] | + /// | `PIO0` | [crate::Gp28Pio0] | + /// | `PIO1` | [crate::Gp28Pio1] | + Gpio28 { + name: gpio28, + aliases: { + /// UART Function alias for pin [crate::Pins::gpio28]. + FunctionUart: Gp28Uart0Tx, + /// SPI Function alias for pin [crate::Pins::gpio28]. + FunctionSpi: Gp28Spi1Rx, + /// I2C Function alias for pin [crate::Pins::gpio28]. + FunctionI2C: Gp28I2C0Sda, + /// PWM Function alias for pin [crate::Pins::gpio28]. + FunctionPwm: Gp28Pwm6A, + /// PIO0 Function alias for pin [crate::Pins::gpio28]. + FunctionPio0: Gp28Pio0, + /// PIO1 Function alias for pin [crate::Pins::gpio28]. + FunctionPio1: Gp28Pio1 + } + }, + + /// GPIO 29 is connected to voltage_monitor of the Raspberry Pi Pico board + /// when GPIO 25 is high, otherwise acts as wireless SPI CLK + Gpio29 { + name: voltage_monitor_wl_clk, + }, +); + +pub const XOSC_CRYSTAL_FREQ: u32 = 12_000_000; diff --git a/rp2040-hal/Cargo.toml b/rp2040-hal/Cargo.toml index 2568024fd..b42ee9993 100644 --- a/rp2040-hal/Cargo.toml +++ b/rp2040-hal/Cargo.toml @@ -33,7 +33,7 @@ critical-section = { version = "1.0.0" } chrono = { version = "0.4", default-features = false, optional = true } -defmt = { version = ">=0.2.0, <0.4", optional = true } +defmt = { version = ">=0.3.0, <0.4", optional = true } rtic-monotonic = { version = "1.0.0", optional = true } diff --git a/rp2040-hal/src/timer.rs b/rp2040-hal/src/timer.rs index cb0b9e71c..06ffbfe65 100644 --- a/rp2040-hal/src/timer.rs +++ b/rp2040-hal/src/timer.rs @@ -230,7 +230,9 @@ macro_rules! impl_alarm { // If it is not set, it has already triggered. let now = get_counter(timer); - if now > timestamp && (timer.armed.read().bits() & $armed_bit_mask) != 0 { + if now.const_cmp(timestamp) == core::cmp::Ordering::Greater + && (timer.armed.read().bits() & $armed_bit_mask) != 0 + { // timestamp was set in the past // safety: TIMER.armed is a write-clear register, and there can only be