From 63607e5533ddf2194cb0756673303d49ee19b175 Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Sat, 17 Apr 2021 14:09:54 -0500 Subject: [PATCH 01/40] Add CI checks --- .github/workflows/check.yml | 15 +++++ .gitignore | 1 + Cargo.lock | 118 ++++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 .github/workflows/check.yml create mode 100644 Cargo.lock diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml new file mode 100644 index 0000000..c097d2b --- /dev/null +++ b/.github/workflows/check.yml @@ -0,0 +1,15 @@ +on: push +name: CI Checks +jobs: + check: + name: Check and Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + target: thumbv6m-none-eabi + - run: "cargo check" + - run: "cargo fmt -- --check" + - run: "cargo clippy -- -Dwarnings" diff --git a/.gitignore b/.gitignore index 9f11b75..2f5a8f4 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .idea/ +target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..b70fbd7 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,118 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "bare-metal" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + +[[package]] +name = "cortex-m" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643a210c1bdc23d0db511e2a576082f4ff4dcae9d0c37f50b431b8f8439d6d6b" +dependencies = [ + "bare-metal", + "bitfield", + "embedded-hal", + "volatile-register", +] + +[[package]] +name = "embedded-hal" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa998ce59ec9765d15216393af37a58961ddcefb14c753b4816ba2191d865fcb" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.0.0", +] + +[[package]] +name = "nb" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" + +[[package]] +name = "rp2040-hal" +version = "0.1.0" +dependencies = [ + "cortex-m", + "embedded-hal", + "nb 1.0.0", + "rp2040-pac", +] + +[[package]] +name = "rp2040-pac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8ce571c4f868bea60de3bf03be22bb92bbb63b6678b8062c6fe7de0b6071963" +dependencies = [ + "cortex-m", + "vcell", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "vcell" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "volatile-register" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" +dependencies = [ + "vcell", +] From d318d050673b1b2113fe11935e8ca82ac99229d7 Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Sat, 17 Apr 2021 14:11:47 -0500 Subject: [PATCH 02/40] Run `cargo fmt` --- rp2040-hal/src/rom_data.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/rp2040-hal/src/rom_data.rs b/rp2040-hal/src/rom_data.rs index cbf99ef..e55ccb3 100644 --- a/rp2040-hal/src/rom_data.rs +++ b/rp2040-hal/src/rom_data.rs @@ -21,7 +21,10 @@ fn rom_table_lookup(table: *const u16, tag: RomFnTableCode) -> T { unsafe { let rom_table_lookup_ptr: *const u32 = rom_hword_as_ptr(ROM_TABLE_LOOKUP_PTR); let rom_table_lookup: RomTableLookupFn = core::mem::transmute(rom_table_lookup_ptr); - rom_table_lookup(rom_hword_as_ptr(table) as *const u16, u16::from_le_bytes(tag) as u32) + rom_table_lookup( + rom_hword_as_ptr(table) as *const u16, + u16::from_le_bytes(tag) as u32, + ) } } @@ -342,7 +345,7 @@ double_funcs! { 0x40 dsin(angle: f64) -> f64; /// Return the tangent of angle. angle is in radians, and must be in the range -1024 to 1024 0x44 dtan(angle: f64) -> f64; - /// Return the exponential value of v, i.e. so + /// Return the exponential value of v, i.e. so 0x4c dexp(v: f64) -> f64; /// Return the natural logarithm of v. If v <= 0 return -Infinity 0x50 dln(v: f64) -> f64; @@ -371,7 +374,7 @@ double_funcs! { /// Convert a double to a signed fixed point 64-bit integer representation where n specifies the /// position of the binary point in the resulting fixed point representation - e.g. _double2fix(0.5f, /// 16) == 0x8000. This method rounds towards -Infinity, and clamps the resulting integer to lie - /// within the range -0x8000000000000000 to 0x7FFFFFFFFFFFFFFF + /// within the range -0x8000000000000000 to 0x7FFFFFFFFFFFFFFF 0x70 double_to_fix64(v: f64, n: i32) -> i64; /// Convert a double to an unsigned 64-bit integer, rounding towards -Infinity, and clamping the /// result to lie within the range 0x0000000000000000 to 0xFFFFFFFFFFFFFFFF From 778a87dfaaa176857d169924336d0d5147a4a824 Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Sat, 17 Apr 2021 14:21:55 -0500 Subject: [PATCH 03/40] Also run the checks on PRs I forgot you have to add that event explicitly. --- .github/workflows/check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index c097d2b..100bfc8 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -1,4 +1,4 @@ -on: push +on: [push, pull_request] name: CI Checks jobs: check: From 45580ec4c8c9955ba7cdc403ce3ba30ae6774e9f Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Sat, 17 Apr 2021 18:18:10 -0500 Subject: [PATCH 04/40] Add basic output support for GPIOs --- .gitignore | 1 + Cargo.lock | 117 +++++++++++++++++++++++++++++++++ rp2040-hal/Cargo.toml | 2 +- rp2040-hal/src/gpio.rs | 132 ++++++++++++++++++++++++++++++++++++++ rp2040-hal/src/lib.rs | 1 + rp2040-hal/src/prelude.rs | 1 + 6 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 Cargo.lock create mode 100644 rp2040-hal/src/gpio.rs diff --git a/.gitignore b/.gitignore index 9f11b75..2f5a8f4 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .idea/ +target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..c4cfdca --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,117 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "bare-metal" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + +[[package]] +name = "cortex-m" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643a210c1bdc23d0db511e2a576082f4ff4dcae9d0c37f50b431b8f8439d6d6b" +dependencies = [ + "bare-metal", + "bitfield", + "embedded-hal", + "volatile-register", +] + +[[package]] +name = "embedded-hal" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa998ce59ec9765d15216393af37a58961ddcefb14c753b4816ba2191d865fcb" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.0.0", +] + +[[package]] +name = "nb" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" + +[[package]] +name = "rp2040-hal" +version = "0.1.0" +dependencies = [ + "cortex-m", + "embedded-hal", + "nb 1.0.0", + "rp2040-pac", +] + +[[package]] +name = "rp2040-pac" +version = "0.1.1" +source = "git+https://github.com/rp-rs/rp2040-pac?branch=main#f4339cb856f082970767099a0079259f333cdc7e" +dependencies = [ + "cortex-m", + "vcell", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "vcell" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "volatile-register" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" +dependencies = [ + "vcell", +] diff --git a/rp2040-hal/Cargo.toml b/rp2040-hal/Cargo.toml index 782adb1..3d4600a 100644 --- a/rp2040-hal/Cargo.toml +++ b/rp2040-hal/Cargo.toml @@ -13,4 +13,4 @@ license = "MIT OR Apache-2.0" cortex-m = "0.7.1" embedded-hal = "0.2.4" nb = "1.0.0" -rp2040-pac = "0.1.1" +rp2040-pac = { git = "https://github.com/rp-rs/rp2040-pac", branch="main" } diff --git a/rp2040-hal/src/gpio.rs b/rp2040-hal/src/gpio.rs new file mode 100644 index 0000000..53af7e9 --- /dev/null +++ b/rp2040-hal/src/gpio.rs @@ -0,0 +1,132 @@ +//! General Purpose Input and Output (GPIO) +//! +//! TODO: Docs for this whole module +//! +//! For example, to turn on the LED on a Pico board: +//! +//! ```rust +//! let mut pac = rp2040_pac::Peripherals::take().unwrap(); +//! +//! let pins = pac.IO_BANK0.split(&mut pac.RESETS); +//! let mut led_pin = pins.gpio25.into_output(&mut pac.PADS_BANK0, &mut pac.SIO); +//! led_pin.set_low().unwrap(); +//! ``` +use core::convert::Infallible; +use core::marker::PhantomData; +use embedded_hal::digital::v2::OutputPin; + +pub struct Floating; +pub struct Input { + _mode: PhantomData, +} +pub struct Output; + +pub trait GpioExt { + type Parts; + + // TODO: Do we need a marker to check that clocks are up? + fn split(self, reset: &mut rp2040_pac::RESETS) -> Self::Parts; +} + +const FUNCTION_SIO: u8 = 5; + +macro_rules! gpio { + ($GPIOX:ident, $gpiox:ident, $PADSX:ident, [ + $($PXi:ident: ($pxi:ident, $i:expr),)+ + ]) => { + impl GpioExt for pac::$GPIOX { + type Parts = Parts; + + fn split(self, resets: &mut pac::RESETS) -> Parts { + resets.reset.modify(|_, w| w.$gpiox().clear_bit()); + Parts { + $( + $pxi: $PXi { _mode: PhantomData }, + )+ + } + } + } + + pub struct Parts { + $( + pub $pxi: $PXi>, + )+ + } + + $( + pub struct $PXi { + _mode: PhantomData, + } + + impl $PXi { + pub fn into_output( + self, + pads: &mut pac::$PADSX, + sio: &mut pac::SIO, + ) -> $PXi { + pads.gpio[$i].modify(|_, w| w.ie().set_bit().od().clear_bit()); + unsafe { + (*pac::$GPIOX::ptr()).gpio[$i] + .gpio_ctrl + .write_with_zero(|x| x.funcsel().bits(FUNCTION_SIO)); + } + sio.gpio_oe.modify(|_, x| unsafe { x.bits(1 << $i) }); + $PXi { _mode: PhantomData } + } + } + + impl OutputPin for $PXi { + type Error = Infallible; + + fn set_low(&mut self) -> Result<(), Self::Error> { + unsafe { + (*pac::SIO::ptr()).gpio_out_clr.write(|x| x.bits(1 << $i)); + } + Ok(()) + } + + fn set_high(&mut self) -> Result<(), Self::Error> { + unsafe { + (*pac::SIO::ptr()).gpio_out_set.write(|x| x.bits(1 << $i)); + } + Ok(()) + } + } + )+ + }; +} + +gpio!( + IO_BANK0, io_bank0, PADS_BANK0, [ + Gpio0: (gpio0, 0), + Gpio1: (gpio1, 1), + Gpio2: (gpio2, 2), + Gpio3: (gpio3, 3), + Gpio4: (gpio4, 4), + Gpio5: (gpio5, 5), + Gpio6: (gpio6, 6), + Gpio7: (gpio7, 7), + Gpio8: (gpio8, 8), + Gpio9: (gpio9, 9), + Gpio10: (gpio10, 10), + Gpio11: (gpio11, 11), + Gpio12: (gpio12, 12), + Gpio13: (gpio13, 13), + Gpio14: (gpio14, 14), + Gpio15: (gpio15, 15), + Gpio16: (gpio16, 16), + Gpio17: (gpio17, 17), + Gpio18: (gpio18, 18), + Gpio19: (gpio19, 19), + Gpio20: (gpio20, 20), + Gpio21: (gpio21, 21), + Gpio22: (gpio22, 22), + Gpio23: (gpio23, 23), + Gpio24: (gpio24, 24), + Gpio25: (gpio25, 25), + Gpio26: (gpio26, 26), + Gpio27: (gpio27, 27), + Gpio28: (gpio28, 28), + Gpio29: (gpio29, 29), + ] +); diff --git a/rp2040-hal/src/lib.rs b/rp2040-hal/src/lib.rs index e8d96e2..719afcc 100644 --- a/rp2040-hal/src/lib.rs +++ b/rp2040-hal/src/lib.rs @@ -13,6 +13,7 @@ extern crate nb; pub extern crate rp2040_pac as pac; pub mod adc; +pub mod gpio; pub mod i2c; pub mod prelude; pub mod pwm; diff --git a/rp2040-hal/src/prelude.rs b/rp2040-hal/src/prelude.rs index 8e3e645..57edf4f 100644 --- a/rp2040-hal/src/prelude.rs +++ b/rp2040-hal/src/prelude.rs @@ -1 +1,2 @@ //! Prelude +pub use crate::gpio::GpioExt; From d0d9291cdee12bcdf9c294cacba94dc6e6da9eb6 Mon Sep 17 00:00:00 2001 From: Nic0w Date: Sat, 24 Apr 2021 13:38:17 +0200 Subject: [PATCH 05/40] Working HAL for the XOSC --- rp2040-hal/Cargo.toml | 1 + rp2040-hal/src/lib.rs | 3 + rp2040-hal/src/xosc.rs | 192 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 196 insertions(+) create mode 100644 rp2040-hal/src/xosc.rs diff --git a/rp2040-hal/Cargo.toml b/rp2040-hal/Cargo.toml index 782adb1..b0c0238 100644 --- a/rp2040-hal/Cargo.toml +++ b/rp2040-hal/Cargo.toml @@ -14,3 +14,4 @@ cortex-m = "0.7.1" embedded-hal = "0.2.4" nb = "1.0.0" rp2040-pac = "0.1.1" +embedded-time = "0.10.1" diff --git a/rp2040-hal/src/lib.rs b/rp2040-hal/src/lib.rs index e8d96e2..8fb2aba 100644 --- a/rp2040-hal/src/lib.rs +++ b/rp2040-hal/src/lib.rs @@ -10,6 +10,8 @@ extern crate cortex_m; extern crate embedded_hal as hal; extern crate nb; +extern crate embedded_time; + pub extern crate rp2040_pac as pac; pub mod adc; @@ -24,3 +26,4 @@ pub mod timer; pub mod uart; pub mod usb; pub mod watchdog; +pub mod xosc; diff --git a/rp2040-hal/src/xosc.rs b/rp2040-hal/src/xosc.rs new file mode 100644 index 0000000..2f07acf --- /dev/null +++ b/rp2040-hal/src/xosc.rs @@ -0,0 +1,192 @@ +//! Crystal Oscillator (XOSC) +// See [Chapter 2 Section 16](https://datasheets.raspberrypi.org/rp2040/rp2040_datasheet.pdf) for more details + +use core::{ + convert::Infallible, + ops::RangeInclusive +}; + +use embedded_time::{ + fraction::Fraction, + fixed_point::FixedPoint, + rate::{ + Hertz, + Megahertz, + }, + duration::{ + Seconds, + Milliseconds, + Duration + } +}; + +use nb::Error::WouldBlock; + +/// State of the Crystal Oscillator (typestate trait) +pub trait State {} + +/// XOSC is disabled (typestate) +pub struct Disabled; + +/// XOSC is initialized, ie we've given parameters (typestate) +pub struct Initialized { + freq_hz: Hertz +} + +/// Stable state (typestate) +pub struct Stable{ + freq_hz: Hertz +} + +/// XOSC is disabling (typestate) +pub struct Disabling; + +/// XOSC is in dormant mode (see Chapter 2, Section 16, §5) +pub struct Dormant; + +impl State for Disabled {} +impl State for Initialized {} +impl State for Stable {} +impl State for Disabling {} +impl State for Dormant {} + +/// Possible errors when initializing the CrystalOscillator +pub enum Error { + /// Frequency is out of the 1-15MHz range (see datasheet) + FrequencyOutOfRange, + + /// Argument is bad : overflows, ... + BadArgument +} + +/// A Crystal Oscillator. +pub struct CrystalOscillator { + device: rp2040_pac::XOSC, + state: S +} + +impl CrystalOscillator { + /// Transitions the oscillator to another state. + fn transition(self, state: To) -> CrystalOscillator { + CrystalOscillator { + device: self.device, + state: state + } + } + + /// Releases the underlying device. + pub fn free(self) -> rp2040_pac::XOSC { + self.device + } +} + +impl CrystalOscillator { + + /// Creates a new CrystalOscillator from the underlying device. + pub fn new(dev: rp2040_pac::XOSC) -> Self { + CrystalOscillator { + device: dev, + state: Disabled + } + } + + /// Initializes the XOSC : frequency range is set, startup delay is calculated and set. + pub fn initialize(self, frequency: Megahertz) -> Result, Error> { + + const ALLOWED_FREQUENCY_RANGE: RangeInclusive> = Megahertz(1)..=Megahertz(15); + const STABLE_DELAY: Milliseconds = Milliseconds(1_u64); + const DIVIDER: Fraction = Fraction::new(1, 256); + + if !ALLOWED_FREQUENCY_RANGE.contains(&frequency) { + return Err(Error::FrequencyOutOfRange) + } + + self.device.ctrl.write(|w| { + w.freq_range()._1_15mhz(); + w + }); + + let freq_hz: Hertz = frequency.into(); + let delay_sec: Seconds = STABLE_DELAY.into(); + + //let startup_delay = ((freq_hz / 1000) + 128) / 256; + let startup_delay = delay_sec. + checked_mul(freq_hz.integer()).and_then(|r| + r.to_generic::(DIVIDER).ok() + ). + ok_or(Error::BadArgument)?; + + self.device.startup.write(|w| unsafe { + w.delay().bits(*startup_delay.integer() as u16); + w + }); + + self.device.ctrl.write(|w| { + w.enable().enable(); + w + }); + + Ok(self.transition(Initialized { + freq_hz: freq_hz + })) + } +} + +/// A token that's given when the oscillator is stablilzed, and can be exchanged to proceed to the next stage. +pub struct StableOscillatorToken { + _private : () +} + +impl CrystalOscillator { + + /// One has to wait for the startup delay before using the oscillator, ie awaiting stablilzation of the XOSC + pub fn await_stabilization(&self) -> nb::Result { + + if self.device.status.read().stable().bit_is_clear() { + return Err(WouldBlock) + } + + Ok(StableOscillatorToken { + _private: () + }) + } + + /// Returns the stablilzed oscillator + pub fn get_stable(self, _token: StableOscillatorToken) -> CrystalOscillator { + let freq_hz = self.state.freq_hz; + self.transition(Stable { + freq_hz:freq_hz + }) + } +} + +impl CrystalOscillator { + + /// Operating frequency of the XOSC in hertz + pub fn operating_frequency(&self) -> Hertz { + self.state.freq_hz + } + + /// Disables the XOSC + pub fn disable(self) -> CrystalOscillator { + self.device.ctrl.modify(|_r,w| { + w.enable().disable(); + w + }); + + self.transition(Disabling) + } + + /// Put the XOSC in dormant state + pub fn dormant(self) -> CrystalOscillator { + //taken from the C SDK + const XOSC_DORMANT_VALUE: u32 = 0x636f6d61; + + self.device.dormant.write(|w| unsafe { + w.bits(XOSC_DORMANT_VALUE); + w + }); + + self.transition(Dormant) + } +} From 3c528c6a93b754f211f7d7d3c818b97240bdeb89 Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Sat, 24 Apr 2021 14:35:23 -0500 Subject: [PATCH 06/40] Remove Cargo.lock --- .gitignore | 1 + Cargo.lock | 118 ----------------------------------------------------- 2 files changed, 1 insertion(+), 118 deletions(-) delete mode 100644 Cargo.lock diff --git a/.gitignore b/.gitignore index 2f5a8f4..781f1c6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .idea/ target +Cargo.lock diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index b70fbd7..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,118 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "bare-metal" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" -dependencies = [ - "rustc_version", -] - -[[package]] -name = "bitfield" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" - -[[package]] -name = "cortex-m" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643a210c1bdc23d0db511e2a576082f4ff4dcae9d0c37f50b431b8f8439d6d6b" -dependencies = [ - "bare-metal", - "bitfield", - "embedded-hal", - "volatile-register", -] - -[[package]] -name = "embedded-hal" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa998ce59ec9765d15216393af37a58961ddcefb14c753b4816ba2191d865fcb" -dependencies = [ - "nb 0.1.3", - "void", -] - -[[package]] -name = "nb" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" -dependencies = [ - "nb 1.0.0", -] - -[[package]] -name = "nb" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" - -[[package]] -name = "rp2040-hal" -version = "0.1.0" -dependencies = [ - "cortex-m", - "embedded-hal", - "nb 1.0.0", - "rp2040-pac", -] - -[[package]] -name = "rp2040-pac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8ce571c4f868bea60de3bf03be22bb92bbb63b6678b8062c6fe7de0b6071963" -dependencies = [ - "cortex-m", - "vcell", -] - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "vcell" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - -[[package]] -name = "volatile-register" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" -dependencies = [ - "vcell", -] From 5dfa550663788399d5c1be1235f326e2a4c89abe Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Sat, 24 Apr 2021 14:36:39 -0500 Subject: [PATCH 07/40] Pass --all to cargo check This will be useful once we have examples, which I'm working on in another PR. --- .github/workflows/check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 100bfc8..cbda6da 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -10,6 +10,6 @@ jobs: with: toolchain: stable target: thumbv6m-none-eabi - - run: "cargo check" + - run: "cargo check --all" - run: "cargo fmt -- --check" - run: "cargo clippy -- -Dwarnings" From ed1e847618cccc54780963e664ffb1ef043319e3 Mon Sep 17 00:00:00 2001 From: Nic0w Date: Sat, 24 Apr 2021 22:26:26 +0200 Subject: [PATCH 08/40] Remove line as it builds fine without it. --- rp2040-hal/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/rp2040-hal/src/lib.rs b/rp2040-hal/src/lib.rs index 8fb2aba..477db61 100644 --- a/rp2040-hal/src/lib.rs +++ b/rp2040-hal/src/lib.rs @@ -10,7 +10,6 @@ extern crate cortex_m; extern crate embedded_hal as hal; extern crate nb; -extern crate embedded_time; pub extern crate rp2040_pac as pac; From 2c3a0956fa321062c0a7b68ad716596ce550ed1c Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Sat, 24 Apr 2021 16:18:57 -0500 Subject: [PATCH 09/40] Add input support, examples, SIO/PADS ownership Sorry this is a large commit :( This adds support for input pins, including pulling them high or low. It also adds two examples: the start of a classic blinky LED example, and an example for reading input. --- .cargo/config | 8 + .gitignore | 1 + Cargo.lock | 117 --------------- memory.x | 13 ++ rp2040-hal/Cargo.toml | 7 +- rp2040-hal/examples/blinky.rs | 31 ++++ rp2040-hal/examples/gpio_in_out.rs | 36 +++++ rp2040-hal/src/gpio.rs | 225 ++++++++++++++++++++--------- 8 files changed, 253 insertions(+), 185 deletions(-) delete mode 100644 Cargo.lock create mode 100644 memory.x create mode 100644 rp2040-hal/examples/blinky.rs create mode 100644 rp2040-hal/examples/gpio_in_out.rs diff --git a/.cargo/config b/.cargo/config index 3500668..4dc2c04 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,3 +1,11 @@ [build] # Instruction set of Cortex-M0+ target = "thumbv6m-none-eabi" + +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +rustflags = [ + "-C", "link-arg=--nmagic", + "-C", "link-arg=-Tlink.x", + "-C", "inline-threshold=5", + "-C", "no-vectorize-loops", +] diff --git a/.gitignore b/.gitignore index 2f5a8f4..781f1c6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .idea/ target +Cargo.lock diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index c4cfdca..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,117 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "bare-metal" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" -dependencies = [ - "rustc_version", -] - -[[package]] -name = "bitfield" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" - -[[package]] -name = "cortex-m" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643a210c1bdc23d0db511e2a576082f4ff4dcae9d0c37f50b431b8f8439d6d6b" -dependencies = [ - "bare-metal", - "bitfield", - "embedded-hal", - "volatile-register", -] - -[[package]] -name = "embedded-hal" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa998ce59ec9765d15216393af37a58961ddcefb14c753b4816ba2191d865fcb" -dependencies = [ - "nb 0.1.3", - "void", -] - -[[package]] -name = "nb" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" -dependencies = [ - "nb 1.0.0", -] - -[[package]] -name = "nb" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" - -[[package]] -name = "rp2040-hal" -version = "0.1.0" -dependencies = [ - "cortex-m", - "embedded-hal", - "nb 1.0.0", - "rp2040-pac", -] - -[[package]] -name = "rp2040-pac" -version = "0.1.1" -source = "git+https://github.com/rp-rs/rp2040-pac?branch=main#f4339cb856f082970767099a0079259f333cdc7e" -dependencies = [ - "cortex-m", - "vcell", -] - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "vcell" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - -[[package]] -name = "volatile-register" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" -dependencies = [ - "vcell", -] diff --git a/memory.x b/memory.x new file mode 100644 index 0000000..23918e1 --- /dev/null +++ b/memory.x @@ -0,0 +1,13 @@ +MEMORY { + BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 + FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100 + RAM : ORIGIN = 0x20000000, LENGTH = 256K +} + +SECTIONS { + /* ### Boot loader */ + .boot2 ORIGIN(BOOT2) : + { + KEEP(*(.boot2)); + } > BOOT2 +} INSERT BEFORE .text; diff --git a/rp2040-hal/Cargo.toml b/rp2040-hal/Cargo.toml index 3d4600a..e567ef1 100644 --- a/rp2040-hal/Cargo.toml +++ b/rp2040-hal/Cargo.toml @@ -11,6 +11,11 @@ license = "MIT OR Apache-2.0" [dependencies] cortex-m = "0.7.1" -embedded-hal = "0.2.4" +embedded-hal = { version = "0.2.4", features = ["unproven"] } nb = "1.0.0" rp2040-pac = { git = "https://github.com/rp-rs/rp2040-pac", branch="main" } + +[dev-dependencies] +cortex-m-rt = "0.6.13" +panic-halt = "0.2.0" +rp2040-boot2 = { git = "https://github.com/rp-rs/rp2040-boot2-rs", branch="main" } diff --git a/rp2040-hal/examples/blinky.rs b/rp2040-hal/examples/blinky.rs new file mode 100644 index 0000000..a51c50c --- /dev/null +++ b/rp2040-hal/examples/blinky.rs @@ -0,0 +1,31 @@ +//! Blinks the LED on a Pico board +//! +//! This will blink an LED attached to GP25, which is the pin the Pico uses for the on-board LED. +#![no_std] +#![no_main] + +use panic_halt as _; + +use cortex_m_rt::entry; + +#[link_section = ".boot2"] +#[used] +pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; + +use embedded_hal::digital::v2::OutputPin; +use rp2040_hal::prelude::*; + +#[entry] +fn main() -> ! { + let mut pac = rp2040_pac::Peripherals::take().unwrap(); + + let pins = pac.IO_BANK0.split(pac.PADS_BANK0, pac.SIO, &mut pac.RESETS); + let mut led_pin = pins.gpio25.into_output(); + + loop { + led_pin.set_low().unwrap(); + // TODO: I dare not use delays until we've got clocks running + led_pin.set_high().unwrap(); + // TODO: Other delay + } +} diff --git a/rp2040-hal/examples/gpio_in_out.rs b/rp2040-hal/examples/gpio_in_out.rs new file mode 100644 index 0000000..77a9271 --- /dev/null +++ b/rp2040-hal/examples/gpio_in_out.rs @@ -0,0 +1,36 @@ +//! Toggle LED based on GPIO input +//! +//! This will control an LED on GP25 based on a button hooked up to GP15. The button should be tied +//! to ground, as the input pin is pulled high internally by this example. When the button is +//! pressed, the LED will turn off. +#![no_std] +#![no_main] + +use panic_halt as _; + +use cortex_m_rt::entry; + +#[link_section = ".boot2"] +#[used] +pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; + +use embedded_hal::digital::v2::{InputPin, OutputPin}; +use rp2040_hal::prelude::*; + +#[entry] +fn main() -> ! { + let mut pac = rp2040_pac::Peripherals::take().unwrap(); + + let pins = pac.IO_BANK0.split(pac.PADS_BANK0, pac.SIO, &mut pac.RESETS); + let mut led_pin = pins.gpio25.into_output(); + let mut button_pin = pins.gpio15.into_input(); + button_pin.pull_high(); + + loop { + if button_pin.is_high().unwrap() { + led_pin.set_high().unwrap(); + } else { + led_pin.set_low().unwrap(); + } + } +} diff --git a/rp2040-hal/src/gpio.rs b/rp2040-hal/src/gpio.rs index 53af7e9..b2e6fb6 100644 --- a/rp2040-hal/src/gpio.rs +++ b/rp2040-hal/src/gpio.rs @@ -7,97 +7,188 @@ //! ```rust //! let mut pac = rp2040_pac::Peripherals::take().unwrap(); //! -//! let pins = pac.IO_BANK0.split(&mut pac.RESETS); -//! let mut led_pin = pins.gpio25.into_output(&mut pac.PADS_BANK0, &mut pac.SIO); -//! led_pin.set_low().unwrap(); +//! let pins = pac.IO_BANK0.split(pac.PADS_BANK0, pac.SIO, &mut pac.RESETS); +//! let mut led_pin = pins.gpio25.into_output(); +//! led_pin.set_high().unwrap(); //! ``` -use core::convert::Infallible; -use core::marker::PhantomData; -use embedded_hal::digital::v2::OutputPin; - -pub struct Floating; -pub struct Input { - _mode: PhantomData, -} +pub struct Input; pub struct Output; +pub struct Unknown; -pub trait GpioExt { +pub trait GpioExt { type Parts; // TODO: Do we need a marker to check that clocks are up? - fn split(self, reset: &mut rp2040_pac::RESETS) -> Self::Parts; + fn split(self, pads: PADS, sio: SIO, reset: &mut rp2040_pac::RESETS) -> Self::Parts; } +// Magic numbers from the datasheet +// const FUNCTION_SPI: u8 = 1; +// const FUNCTION_UART: u8 = 2; +// const FUNCTION_I2C: u8 = 3; +// const FUNCTION_PWM: u8 = 4; const FUNCTION_SIO: u8 = 5; +// const FUNCTION_PIO0: u8 = 6; +// const FUNCTION_PIO1: u8 = 7; +// const FUNCTION_CLOCK: u8 = 8; +// const FUNCTION_USB: u8 = 9; macro_rules! gpio { - ($GPIOX:ident, $gpiox:ident, $PADSX:ident, [ + ($GPIOX:ident, $gpiox:ident, $PADSX:ident, $padsx:ident, [ $($PXi:ident: ($pxi:ident, $i:expr),)+ ]) => { - impl GpioExt for pac::$GPIOX { - type Parts = Parts; + mod $gpiox { + use core::convert::Infallible; + use core::marker::PhantomData; + use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; + use super::{GpioExt, Input, Output, Unknown, FUNCTION_SIO}; - fn split(self, resets: &mut pac::RESETS) -> Parts { - resets.reset.modify(|_, w| w.$gpiox().clear_bit()); - Parts { - $( - $pxi: $PXi { _mode: PhantomData }, - )+ + impl GpioExt for pac::$GPIOX { + type Parts = Parts; + + fn split(self, pads: pac::$PADSX, sio: pac::SIO, resets: &mut pac::RESETS) -> Parts { + resets.reset.modify(|_, w| w.$gpiox().clear_bit()); + Parts { + _pads: pads, + _sio: sio, + $( + $pxi: $PXi { _mode: PhantomData }, + )+ + } } } - } - pub struct Parts { + pub struct Parts { + _pads: pac::$PADSX, + _sio: pac::SIO, + $( + pub $pxi: $PXi, + )+ + } + + // Puts pad in default state as far as this crate is concerned: + // - Input is enabled + // - Output is enabled (if also set in SIO) + // - Pull up/down is disabled + // + // TODO: Drive strength, smitty, slewing + fn setup_pad_io(pads: &pac::$padsx::RegisterBlock, index: usize) { + pads.gpio[index].modify(|_, w| w.ie().set_bit().od().clear_bit().pue().clear_bit().pde().clear_bit()); + } + + fn set_gpio_function(gpios: &pac::$gpiox::RegisterBlock, index: usize, function: u8) { + gpios.gpio[index] + .gpio_ctrl + .write_with_zero(|x| unsafe { x.funcsel().bits(function) }); + } + $( - pub $pxi: $PXi>, + pub struct $PXi { + _mode: PhantomData, + } + + // Safety: We own our $i slice of padsx, gpiox, and sio because the + // construction of Parts assumes ownership of all 3 and will not release + // them. Thus several of the methods below will reconstruct these objects + // as-needed + + impl $PXi { + pub fn into_output( + self, + ) -> $PXi { + unsafe { + setup_pad_io(&*pac::$PADSX::ptr(), $i); + } + unsafe { + set_gpio_function(&*pac::$GPIOX::ptr(), $i, FUNCTION_SIO); + } + unsafe { + (*pac::SIO::ptr()).gpio_oe_set.write(|x| { x.bits(1 << $i) }); + } + $PXi { _mode: PhantomData } + } + + pub fn into_input( + self, + ) -> $PXi { + unsafe { + setup_pad_io(&*pac::$PADSX::ptr(), $i); + } + unsafe { + set_gpio_function(&*pac::$GPIOX::ptr(), $i, FUNCTION_SIO); + } + unsafe { + (*pac::SIO::ptr()).gpio_oe_clr.write(|x| { x.bits(1 << $i) }); + } + $PXi { _mode: PhantomData } + } + } + + impl OutputPin for $PXi { + type Error = Infallible; + + fn set_low(&mut self) -> Result<(), Self::Error> { + unsafe { + (*pac::SIO::ptr()).gpio_out_clr.write(|x| x.bits(1 << $i)); + } + Ok(()) + } + + fn set_high(&mut self) -> Result<(), Self::Error> { + unsafe { + (*pac::SIO::ptr()).gpio_out_set.write(|x| x.bits(1 << $i)); + } + Ok(()) + } + } + + impl StatefulOutputPin for $PXi { + fn is_set_low(&self) -> Result { + Ok(!self.is_set_high()?) + } + + fn is_set_high(&self) -> Result { + unsafe { + Ok((*pac::SIO::ptr()).gpio_out_set.read().bits() & (1 << $i) != 0) + } + } + } + + // TODO: Don't allow Unknown since we need to fix up the pad at least + impl InputPin for $PXi { + type Error = Infallible; + + fn is_low(&self) -> Result { + Ok(!self.is_high()?) + } + + fn is_high(&self) -> Result { + unsafe { + Ok((*pac::SIO::ptr()).gpio_in.read().bits() & (1 << $i) != 0) + } + } + } + + impl $PXi { + pub fn pull_high(&mut self) { + unsafe { + (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.pue().set_bit().pde().clear_bit()); + } + } + + pub fn pull_low(&mut self) { + unsafe { + (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.pue().clear_bit().pde().set_bit()); + } + } + } )+ } - - $( - pub struct $PXi { - _mode: PhantomData, - } - - impl $PXi { - pub fn into_output( - self, - pads: &mut pac::$PADSX, - sio: &mut pac::SIO, - ) -> $PXi { - pads.gpio[$i].modify(|_, w| w.ie().set_bit().od().clear_bit()); - unsafe { - (*pac::$GPIOX::ptr()).gpio[$i] - .gpio_ctrl - .write_with_zero(|x| x.funcsel().bits(FUNCTION_SIO)); - } - sio.gpio_oe.modify(|_, x| unsafe { x.bits(1 << $i) }); - $PXi { _mode: PhantomData } - } - } - - impl OutputPin for $PXi { - type Error = Infallible; - - fn set_low(&mut self) -> Result<(), Self::Error> { - unsafe { - (*pac::SIO::ptr()).gpio_out_clr.write(|x| x.bits(1 << $i)); - } - Ok(()) - } - - fn set_high(&mut self) -> Result<(), Self::Error> { - unsafe { - (*pac::SIO::ptr()).gpio_out_set.write(|x| x.bits(1 << $i)); - } - Ok(()) - } - } - )+ }; } gpio!( - IO_BANK0, io_bank0, PADS_BANK0, [ + IO_BANK0, io_bank0, PADS_BANK0, pads_bank0, [ Gpio0: (gpio0, 0), Gpio1: (gpio1, 1), Gpio2: (gpio2, 2), From 2e5c1fc0e36e812dd05ca21614dd5f9b09191f38 Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Sat, 24 Apr 2021 16:22:27 -0500 Subject: [PATCH 10/40] Cleanup wacky imports in examples --- rp2040-hal/examples/blinky.rs | 8 +++----- rp2040-hal/examples/gpio_in_out.rs | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/rp2040-hal/examples/blinky.rs b/rp2040-hal/examples/blinky.rs index a51c50c..3e53311 100644 --- a/rp2040-hal/examples/blinky.rs +++ b/rp2040-hal/examples/blinky.rs @@ -4,17 +4,15 @@ #![no_std] #![no_main] -use panic_halt as _; - use cortex_m_rt::entry; +use embedded_hal::digital::v2::OutputPin; +use panic_halt as _; +use rp2040_hal::prelude::*; #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; -use embedded_hal::digital::v2::OutputPin; -use rp2040_hal::prelude::*; - #[entry] fn main() -> ! { let mut pac = rp2040_pac::Peripherals::take().unwrap(); diff --git a/rp2040-hal/examples/gpio_in_out.rs b/rp2040-hal/examples/gpio_in_out.rs index 77a9271..b162483 100644 --- a/rp2040-hal/examples/gpio_in_out.rs +++ b/rp2040-hal/examples/gpio_in_out.rs @@ -6,17 +6,15 @@ #![no_std] #![no_main] -use panic_halt as _; - use cortex_m_rt::entry; +use embedded_hal::digital::v2::{InputPin, OutputPin}; +use panic_halt as _; +use rp2040_hal::prelude::*; #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; -use embedded_hal::digital::v2::{InputPin, OutputPin}; -use rp2040_hal::prelude::*; - #[entry] fn main() -> ! { let mut pac = rp2040_pac::Peripherals::take().unwrap(); From 568cafe2d109ac3263c530b5adad708cf6efc063 Mon Sep 17 00:00:00 2001 From: Nic0w Date: Sat, 24 Apr 2021 23:38:49 +0200 Subject: [PATCH 11/40] Multiple changes related to @tdittr 's comments --- rp2040-hal/src/xosc.rs | 47 +++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/rp2040-hal/src/xosc.rs b/rp2040-hal/src/xosc.rs index 2f07acf..54a5147 100644 --- a/rp2040-hal/src/xosc.rs +++ b/rp2040-hal/src/xosc.rs @@ -1,6 +1,7 @@ //! Crystal Oscillator (XOSC) // See [Chapter 2 Section 16](https://datasheets.raspberrypi.org/rp2040/rp2040_datasheet.pdf) for more details +use core::convert::TryInto; use core::{ convert::Infallible, ops::RangeInclusive @@ -30,24 +31,20 @@ pub struct Disabled; /// XOSC is initialized, ie we've given parameters (typestate) pub struct Initialized { - freq_hz: Hertz + freq_hz: Hertz } /// Stable state (typestate) pub struct Stable{ - freq_hz: Hertz + freq_hz: Hertz } -/// XOSC is disabling (typestate) -pub struct Disabling; - /// XOSC is in dormant mode (see Chapter 2, Section 16, §5) pub struct Dormant; impl State for Disabled {} impl State for Initialized {} impl State for Stable {} -impl State for Disabling {} impl State for Dormant {} /// Possible errors when initializing the CrystalOscillator @@ -91,10 +88,10 @@ impl CrystalOscillator { } /// Initializes the XOSC : frequency range is set, startup delay is calculated and set. - pub fn initialize(self, frequency: Megahertz) -> Result, Error> { + pub fn initialize(self, frequency: Hertz) -> Result, Error> { const ALLOWED_FREQUENCY_RANGE: RangeInclusive> = Megahertz(1)..=Megahertz(15); - const STABLE_DELAY: Milliseconds = Milliseconds(1_u64); + const STABLE_DELAY: Milliseconds = Milliseconds(1_u32); const DIVIDER: Fraction = Fraction::new(1, 256); if !ALLOWED_FREQUENCY_RANGE.contains(&frequency) { @@ -106,18 +103,22 @@ impl CrystalOscillator { w }); - let freq_hz: Hertz = frequency.into(); - let delay_sec: Seconds = STABLE_DELAY.into(); + let delay_sec: Seconds = STABLE_DELAY.into(); - //let startup_delay = ((freq_hz / 1000) + 128) / 256; + //startup_delay = ((freq_hz * 10e-3) / 256; See Chapter 2, Section 16, §3) + //We do the calculation first. let startup_delay = delay_sec. - checked_mul(freq_hz.integer()).and_then(|r| - r.to_generic::(DIVIDER).ok() + checked_mul(frequency.integer()).and_then(|r| + r.to_generic::(DIVIDER).ok() ). ok_or(Error::BadArgument)?; + //Then we check if it fits into an u16. + let startup_delay: u16 = (*startup_delay.integer()).try_into(). + map_err(|_|Error::BadArgument)?; + self.device.startup.write(|w| unsafe { - w.delay().bits(*startup_delay.integer() as u16); + w.delay().bits(startup_delay); w }); @@ -127,7 +128,7 @@ impl CrystalOscillator { }); Ok(self.transition(Initialized { - freq_hz: freq_hz + freq_hz: frequency })) } } @@ -155,7 +156,7 @@ impl CrystalOscillator { pub fn get_stable(self, _token: StableOscillatorToken) -> CrystalOscillator { let freq_hz = self.state.freq_hz; self.transition(Stable { - freq_hz:freq_hz + freq_hz }) } } @@ -163,22 +164,26 @@ impl CrystalOscillator { impl CrystalOscillator { /// Operating frequency of the XOSC in hertz - pub fn operating_frequency(&self) -> Hertz { + pub fn operating_frequency(&self) -> Hertz { self.state.freq_hz } /// Disables the XOSC - pub fn disable(self) -> CrystalOscillator { + pub fn disable(self) -> CrystalOscillator { self.device.ctrl.modify(|_r,w| { w.enable().disable(); w }); - self.transition(Disabling) + self.transition(Disabled) } - /// Put the XOSC in dormant state - pub fn dormant(self) -> CrystalOscillator { + /// Put the XOSC in DORMANT state. + /// This method is marked unsafe because prior to switch the XOSC into DORMANT state, + /// PLLs must be stopped and IRQs have to be properly configured. + /// This method does not do any of that, it merely switches the XOSC to DORMANT state. + /// See Chapter 2, Section 16, §5) for details. + pub unsafe fn dormant(self) -> CrystalOscillator { //taken from the C SDK const XOSC_DORMANT_VALUE: u32 = 0x636f6d61; From 3536604b9e5b83056480f21d05da032a49220f73 Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Sat, 24 Apr 2021 17:28:33 -0500 Subject: [PATCH 12/40] Block input reads on Unknown state --- rp2040-hal/src/gpio.rs | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/rp2040-hal/src/gpio.rs b/rp2040-hal/src/gpio.rs index b2e6fb6..106a233 100644 --- a/rp2040-hal/src/gpio.rs +++ b/rp2040-hal/src/gpio.rs @@ -154,20 +154,26 @@ macro_rules! gpio { } } - // TODO: Don't allow Unknown since we need to fix up the pad at least - impl InputPin for $PXi { - type Error = Infallible; + macro_rules! impl_input_for { + ($MODE:ident) => { + impl InputPin for $PXi<$MODE> { + type Error = Infallible; - fn is_low(&self) -> Result { - Ok(!self.is_high()?) - } + fn is_low(&self) -> Result { + Ok(!self.is_high()?) + } - fn is_high(&self) -> Result { - unsafe { - Ok((*pac::SIO::ptr()).gpio_in.read().bits() & (1 << $i) != 0) + fn is_high(&self) -> Result { + unsafe { + Ok((*pac::SIO::ptr()).gpio_in.read().bits() & (1 << $i) != 0) + } + } } - } + }; } + // Not allowed for Unknown since we don't know what state the pad is in + impl_input_for!(Input); + impl_input_for!(Output); impl $PXi { pub fn pull_high(&mut self) { From d5cbd44adeb9137df7394b7daf887aafe5f2703c Mon Sep 17 00:00:00 2001 From: Nic0w Date: Sun, 25 Apr 2021 00:36:46 +0200 Subject: [PATCH 13/40] Fixing calculation bug pointed out by @tdittr --- rp2040-hal/src/xosc.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/rp2040-hal/src/xosc.rs b/rp2040-hal/src/xosc.rs index 54a5147..124cde6 100644 --- a/rp2040-hal/src/xosc.rs +++ b/rp2040-hal/src/xosc.rs @@ -92,7 +92,7 @@ impl CrystalOscillator { const ALLOWED_FREQUENCY_RANGE: RangeInclusive> = Megahertz(1)..=Megahertz(15); const STABLE_DELAY: Milliseconds = Milliseconds(1_u32); - const DIVIDER: Fraction = Fraction::new(1, 256); + const DIVIDER: Fraction = Fraction::new(256, 1); if !ALLOWED_FREQUENCY_RANGE.contains(&frequency) { return Err(Error::FrequencyOutOfRange) @@ -103,12 +103,14 @@ impl CrystalOscillator { w }); - let delay_sec: Seconds = STABLE_DELAY.into(); + //1 ms = 10e-3 sec and Freq = 1/T where T is in seconds so 1ms converts to 1000Hz + let delay_to_hz: Hertz = STABLE_DELAY.to_rate(); - //startup_delay = ((freq_hz * 10e-3) / 256; See Chapter 2, Section 16, §3) + //startup_delay = ((freq_hz * 10e-3) / 256) = ((freq_hz / 1000) / 256) + //See Chapter 2, Section 16, §3) //We do the calculation first. - let startup_delay = delay_sec. - checked_mul(frequency.integer()).and_then(|r| + let startup_delay = frequency. + checked_div(delay_to_hz.integer()).and_then(|r| r.to_generic::(DIVIDER).ok() ). ok_or(Error::BadArgument)?; @@ -118,7 +120,7 @@ impl CrystalOscillator { map_err(|_|Error::BadArgument)?; self.device.startup.write(|w| unsafe { - w.delay().bits(startup_delay); + w.delay().bits(startup_delay+1); w }); From 94f67f7ecac49c3b3e00c5b0e5ed259cd6ae2903 Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Sat, 24 Apr 2021 18:03:03 -0500 Subject: [PATCH 14/40] Finish configuration options for IOs --- rp2040-hal/examples/gpio_in_out.rs | 3 +- rp2040-hal/src/gpio.rs | 82 ++++++++++++++++++++++++++---- 2 files changed, 73 insertions(+), 12 deletions(-) diff --git a/rp2040-hal/examples/gpio_in_out.rs b/rp2040-hal/examples/gpio_in_out.rs index b162483..7a6036a 100644 --- a/rp2040-hal/examples/gpio_in_out.rs +++ b/rp2040-hal/examples/gpio_in_out.rs @@ -21,8 +21,7 @@ fn main() -> ! { let pins = pac.IO_BANK0.split(pac.PADS_BANK0, pac.SIO, &mut pac.RESETS); let mut led_pin = pins.gpio25.into_output(); - let mut button_pin = pins.gpio15.into_input(); - button_pin.pull_high(); + let button_pin = pins.gpio15.into_input().pull_high(); loop { if button_pin.is_high().unwrap() { diff --git a/rp2040-hal/src/gpio.rs b/rp2040-hal/src/gpio.rs index 106a233..f4d97ba 100644 --- a/rp2040-hal/src/gpio.rs +++ b/rp2040-hal/src/gpio.rs @@ -22,6 +22,20 @@ pub trait GpioExt { fn split(self, pads: PADS, sio: SIO, reset: &mut rp2040_pac::RESETS) -> Self::Parts; } +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +pub enum OutputDriveStrength { + Ma2, + Ma4, + Ma8, + Ma12, +} + +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +pub enum OutputSlewRate { + Slow, + Fast, +} + // Magic numbers from the datasheet // const FUNCTION_SPI: u8 = 1; // const FUNCTION_UART: u8 = 2; @@ -41,7 +55,7 @@ macro_rules! gpio { use core::convert::Infallible; use core::marker::PhantomData; use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; - use super::{GpioExt, Input, Output, Unknown, FUNCTION_SIO}; + use super::*; impl GpioExt for pac::$GPIOX { type Parts = Parts; @@ -66,14 +80,15 @@ macro_rules! gpio { )+ } - // Puts pad in default state as far as this crate is concerned: - // - Input is enabled - // - Output is enabled (if also set in SIO) - // - Pull up/down is disabled - // - // TODO: Drive strength, smitty, slewing + // Puts pad in same state as post-reset, according to datasheet fn setup_pad_io(pads: &pac::$padsx::RegisterBlock, index: usize) { - pads.gpio[index].modify(|_, w| w.ie().set_bit().od().clear_bit().pue().clear_bit().pde().clear_bit()); + pads.gpio[index].modify(|_, w| w.ie().set_bit() + .od().clear_bit() + .pue().clear_bit() + .pde().set_bit() + .schmitt().set_bit() + .drive()._4m_a() + .slewfast().clear_bit()); } fn set_gpio_function(gpios: &pac::$gpiox::RegisterBlock, index: usize, function: u8) { @@ -82,6 +97,8 @@ macro_rules! gpio { .write_with_zero(|x| unsafe { x.funcsel().bits(function) }); } + type PacDriveStrength = pac::$padsx::gpio::DRIVE_A; + $( pub struct $PXi { _mode: PhantomData, @@ -175,17 +192,62 @@ macro_rules! gpio { impl_input_for!(Input); impl_input_for!(Output); + impl $PXi { + pub fn drive_strength(self, strength: OutputDriveStrength) -> Self { + let converted = match strength { + OutputDriveStrength::Ma2 => PacDriveStrength::_2MA, + OutputDriveStrength::Ma4 => PacDriveStrength::_4MA, + OutputDriveStrength::Ma8 => PacDriveStrength::_8MA, + OutputDriveStrength::Ma12 => PacDriveStrength::_12MA, + }; + unsafe { + (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.drive().variant(converted)); + } + self + } + + pub fn slew_rate(self, slew_rate: OutputSlewRate) -> Self { + unsafe { + (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.slewfast().bit(slew_rate == OutputSlewRate::Fast)); + } + self + } + } + impl $PXi { - pub fn pull_high(&mut self) { + pub fn pull_high(self) -> Self { unsafe { (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.pue().set_bit().pde().clear_bit()); } + self } - pub fn pull_low(&mut self) { + pub fn pull_low(self) -> Self { unsafe { (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.pue().clear_bit().pde().set_bit()); } + self + } + + pub fn float(self) -> Self { + unsafe { + (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.pue().clear_bit().pde().clear_bit()); + } + self + } + + pub fn enable_schmitt_trigger(self) -> Self { + unsafe { + (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.schmitt().set_bit()); + } + self + } + + pub fn disable_schmitt_trigger(self) -> Self { + unsafe { + (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.schmitt().clear_bit()); + } + self } } )+ From 422a45fbc5b6779163912c7f88aca8d8645d2172 Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Sat, 24 Apr 2021 18:41:12 -0500 Subject: [PATCH 15/40] Add documentation --- rp2040-hal/src/gpio.rs | 122 ++++++++++++++++++++++++++++------------- 1 file changed, 84 insertions(+), 38 deletions(-) diff --git a/rp2040-hal/src/gpio.rs b/rp2040-hal/src/gpio.rs index f4d97ba..57207d0 100644 --- a/rp2040-hal/src/gpio.rs +++ b/rp2040-hal/src/gpio.rs @@ -1,38 +1,65 @@ //! General Purpose Input and Output (GPIO) //! -//! TODO: Docs for this whole module -//! -//! For example, to turn on the LED on a Pico board: +//! To access the GPIO pins you must call the `split` method on the IO bank. This will return a +//! `Parts` struct with access to the individual pins: //! //! ```rust +//! use rp2040_hal::prelude::*; //! let mut pac = rp2040_pac::Peripherals::take().unwrap(); -//! //! let pins = pac.IO_BANK0.split(pac.PADS_BANK0, pac.SIO, &mut pac.RESETS); +//! ``` +//! +//! Once you have the GPIO pins struct, you can take individual pins and configure them: +//! +//! ```rust //! let mut led_pin = pins.gpio25.into_output(); //! led_pin.set_high().unwrap(); //! ``` +//! +//! Input pins support the following options: +//! - Pull high, pull low, or floating +//! - Schmitt trigger +//! +//! Output pins support the following options: +//! - Slew rate (fast or slow) +//! - Drive strength (2, 4, 8 or 12 mA) + +/// Mode marker for an input pin pub struct Input; +/// Mode marker for an output pin pub struct Output; +/// Mode marker for a pin in an unknown state (generally happens at startup) pub struct Unknown; +/// This trait adds a method to extract pins from an IO bank and convert them into HAL objects pub trait GpioExt { + /// The type of struct that will hold the pins once they're converted to HAL objects type Parts; + /// Convert the IO bank into a struct of HAL pin objects // TODO: Do we need a marker to check that clocks are up? fn split(self, pads: PADS, sio: SIO, reset: &mut rp2040_pac::RESETS) -> Self::Parts; } #[derive(Clone, Copy, Eq, PartialEq, Debug)] +/// The amount of current that a pin can drive when used as an output pub enum OutputDriveStrength { + /// 2 mA Ma2, + /// 4 mA Ma4, + /// 8 mA Ma8, + /// 12 mA Ma12, } #[derive(Clone, Copy, Eq, PartialEq, Debug)] +/// The slew rate of a pin when used as an output pub enum OutputSlewRate { + /// Slew slow Slow, + /// Slew fast Fast, } @@ -48,10 +75,13 @@ const FUNCTION_SIO: u8 = 5; // const FUNCTION_USB: u8 = 9; macro_rules! gpio { - ($GPIOX:ident, $gpiox:ident, $PADSX:ident, $padsx:ident, [ - $($PXi:ident: ($pxi:ident, $i:expr),)+ + ($GPIOX:ident, $gpiox:ident, $PADSX:ident, $padsx:ident, $gpioxs:expr, [ + $($PXi:ident: ($pxi:ident, $i:expr, $is:expr),)+ ]) => { - mod $gpiox { + #[doc = "HAL objects for the "] + #[doc = $gpioxs] + #[doc = " bank of GPIO pins"] + pub mod $gpiox { use core::convert::Infallible; use core::marker::PhantomData; use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; @@ -72,10 +102,15 @@ macro_rules! gpio { } } + #[doc = "Struct containing HAL objects for all the "] + #[doc = $gpioxs] + #[doc = " pins"] pub struct Parts { _pads: pac::$PADSX, _sio: pac::SIO, $( + #[doc = "GPIO pin "] + #[doc = $is] pub $pxi: $PXi, )+ } @@ -100,6 +135,8 @@ macro_rules! gpio { type PacDriveStrength = pac::$padsx::gpio::DRIVE_A; $( + #[doc = "HAL object for GPIO pin "] + #[doc = $is] pub struct $PXi { _mode: PhantomData, } @@ -110,6 +147,7 @@ macro_rules! gpio { // as-needed impl $PXi { + #[doc = "Configure this pin as an output"] pub fn into_output( self, ) -> $PXi { @@ -125,6 +163,7 @@ macro_rules! gpio { $PXi { _mode: PhantomData } } + #[doc = "Configure this pin as an input"] pub fn into_input( self, ) -> $PXi { @@ -193,6 +232,7 @@ macro_rules! gpio { impl_input_for!(Output); impl $PXi { + #[doc = "Configure the drive strength for this output pin"] pub fn drive_strength(self, strength: OutputDriveStrength) -> Self { let converted = match strength { OutputDriveStrength::Ma2 => PacDriveStrength::_2MA, @@ -206,6 +246,7 @@ macro_rules! gpio { self } + #[doc = "Configure the slew rate for this output pin"] pub fn slew_rate(self, slew_rate: OutputSlewRate) -> Self { unsafe { (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.slewfast().bit(slew_rate == OutputSlewRate::Fast)); @@ -215,6 +256,7 @@ macro_rules! gpio { } impl $PXi { + #[doc = "Pull this input pin high using internal resistors"] pub fn pull_high(self) -> Self { unsafe { (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.pue().set_bit().pde().clear_bit()); @@ -222,6 +264,7 @@ macro_rules! gpio { self } + #[doc = "Pull this input pin low using internal resistors"] pub fn pull_low(self) -> Self { unsafe { (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.pue().clear_bit().pde().set_bit()); @@ -229,6 +272,7 @@ macro_rules! gpio { self } + #[doc = "Allow this input pin to float (i.e. don't pull it high or low)"] pub fn float(self) -> Self { unsafe { (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.pue().clear_bit().pde().clear_bit()); @@ -236,6 +280,7 @@ macro_rules! gpio { self } + #[doc = "Enable the schmitt trigger for this input pin"] pub fn enable_schmitt_trigger(self) -> Self { unsafe { (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.schmitt().set_bit()); @@ -243,6 +288,7 @@ macro_rules! gpio { self } + #[doc = "Disable the schmitt trigger for this input pin"] pub fn disable_schmitt_trigger(self) -> Self { unsafe { (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.schmitt().clear_bit()); @@ -256,36 +302,36 @@ macro_rules! gpio { } gpio!( - IO_BANK0, io_bank0, PADS_BANK0, pads_bank0, [ - Gpio0: (gpio0, 0), - Gpio1: (gpio1, 1), - Gpio2: (gpio2, 2), - Gpio3: (gpio3, 3), - Gpio4: (gpio4, 4), - Gpio5: (gpio5, 5), - Gpio6: (gpio6, 6), - Gpio7: (gpio7, 7), - Gpio8: (gpio8, 8), - Gpio9: (gpio9, 9), - Gpio10: (gpio10, 10), - Gpio11: (gpio11, 11), - Gpio12: (gpio12, 12), - Gpio13: (gpio13, 13), - Gpio14: (gpio14, 14), - Gpio15: (gpio15, 15), - Gpio16: (gpio16, 16), - Gpio17: (gpio17, 17), - Gpio18: (gpio18, 18), - Gpio19: (gpio19, 19), - Gpio20: (gpio20, 20), - Gpio21: (gpio21, 21), - Gpio22: (gpio22, 22), - Gpio23: (gpio23, 23), - Gpio24: (gpio24, 24), - Gpio25: (gpio25, 25), - Gpio26: (gpio26, 26), - Gpio27: (gpio27, 27), - Gpio28: (gpio28, 28), - Gpio29: (gpio29, 29), + IO_BANK0, io_bank0, PADS_BANK0, pads_bank0, "IO_BANK0", [ + Gpio0: (gpio0, 0, "0"), + Gpio1: (gpio1, 1, "1"), + Gpio2: (gpio2, 2, "2"), + Gpio3: (gpio3, 3, "3"), + Gpio4: (gpio4, 4, "4"), + Gpio5: (gpio5, 5, "5"), + Gpio6: (gpio6, 6, "6"), + Gpio7: (gpio7, 7, "7"), + Gpio8: (gpio8, 8, "8"), + Gpio9: (gpio9, 9, "9"), + Gpio10: (gpio10, 10, "10"), + Gpio11: (gpio11, 11, "11"), + Gpio12: (gpio12, 12, "12"), + Gpio13: (gpio13, 13, "13"), + Gpio14: (gpio14, 14, "14"), + Gpio15: (gpio15, 15, "15"), + Gpio16: (gpio16, 16, "16"), + Gpio17: (gpio17, 17, "17"), + Gpio18: (gpio18, 18, "18"), + Gpio19: (gpio19, 19, "19"), + Gpio20: (gpio20, 20, "20"), + Gpio21: (gpio21, 21, "21"), + Gpio22: (gpio22, 22, "22"), + Gpio23: (gpio23, 23, "23"), + Gpio24: (gpio24, 24, "24"), + Gpio25: (gpio25, 25, "25"), + Gpio26: (gpio26, 26, "26"), + Gpio27: (gpio27, 27, "27"), + Gpio28: (gpio28, 28, "28"), + Gpio29: (gpio29, 29, "29"), ] ); From cc1a1bee2cc0d5dd978004b81988bf6355527823 Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Sat, 24 Apr 2021 18:46:07 -0500 Subject: [PATCH 16/40] Also build all examples My other PR has some examples. It turns out `cargo check --all` doesn't actually check _all_ buildable things :( --- .github/workflows/check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index cbda6da..cd42d94 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -10,6 +10,6 @@ jobs: with: toolchain: stable target: thumbv6m-none-eabi - - run: "cargo check --all" + - run: "cargo check --all --examples" - run: "cargo fmt -- --check" - run: "cargo clippy -- -Dwarnings" From cb51448089620fa69c4333a634bc2f331ff5ea41 Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Sat, 24 Apr 2021 20:17:42 -0500 Subject: [PATCH 17/40] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Émile Grégoire --- .github/workflows/check.yml | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index cd42d94..4a96375 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -5,11 +5,23 @@ jobs: name: Check and Lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@master + - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: toolchain: stable target: thumbv6m-none-eabi - - run: "cargo check --all --examples" - - run: "cargo fmt -- --check" - - run: "cargo clippy -- -Dwarnings" + override: true + profile: minimal + components: rustfmt, clippy + - uses: actions-rs/cargo@v1 + with: + command: check + args: --workspace + - uses: actions-rs/cargo@v1 + with: + command: fmt + args: -- --check + - uses: actions-rs/cargo@v1 + with: + command: clippy + args: -- -Dwarnings From 72694a07b5bff9dd0531e4042c08c5fb04e6824c Mon Sep 17 00:00:00 2001 From: Nic0w Date: Sun, 25 Apr 2021 08:58:43 +0200 Subject: [PATCH 18/40] Fix frequency range check. --- rp2040-hal/src/xosc.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rp2040-hal/src/xosc.rs b/rp2040-hal/src/xosc.rs index 124cde6..b97724d 100644 --- a/rp2040-hal/src/xosc.rs +++ b/rp2040-hal/src/xosc.rs @@ -94,7 +94,9 @@ impl CrystalOscillator { const STABLE_DELAY: Milliseconds = Milliseconds(1_u32); const DIVIDER: Fraction = Fraction::new(256, 1); - if !ALLOWED_FREQUENCY_RANGE.contains(&frequency) { + let freq_mhz: Megahertz = frequency.into(); + + if !ALLOWED_FREQUENCY_RANGE.contains(&freq_mhz) { return Err(Error::FrequencyOutOfRange) } @@ -120,7 +122,7 @@ impl CrystalOscillator { map_err(|_|Error::BadArgument)?; self.device.startup.write(|w| unsafe { - w.delay().bits(startup_delay+1); + w.delay().bits(startup_delay); w }); From 8f6aea6a31b04b43851b4755cd463b3e11d84b97 Mon Sep 17 00:00:00 2001 From: Nic0w Date: Sun, 25 Apr 2021 09:03:20 +0200 Subject: [PATCH 19/40] Fix compilation issues. --- rp2040-hal/src/xosc.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rp2040-hal/src/xosc.rs b/rp2040-hal/src/xosc.rs index b97724d..0d3a1f5 100644 --- a/rp2040-hal/src/xosc.rs +++ b/rp2040-hal/src/xosc.rs @@ -13,9 +13,9 @@ use embedded_time::{ rate::{ Hertz, Megahertz, + Rate }, duration::{ - Seconds, Milliseconds, Duration } @@ -106,7 +106,7 @@ impl CrystalOscillator { }); //1 ms = 10e-3 sec and Freq = 1/T where T is in seconds so 1ms converts to 1000Hz - let delay_to_hz: Hertz = STABLE_DELAY.to_rate(); + let delay_to_hz: Hertz = STABLE_DELAY.to_rate().map_err(|_|Error::BadArgument)?; //startup_delay = ((freq_hz * 10e-3) / 256) = ((freq_hz / 1000) / 256) //See Chapter 2, Section 16, §3) From 2a704a73f0fa0178e0775c2aec64183061deee4c Mon Sep 17 00:00:00 2001 From: Nic0w Date: Sun, 25 Apr 2021 16:34:48 +0200 Subject: [PATCH 20/40] Adding blocking helper method to setup the XOSC easily. --- rp2040-hal/src/xosc.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/rp2040-hal/src/xosc.rs b/rp2040-hal/src/xosc.rs index 0d3a1f5..cf5d9ed 100644 --- a/rp2040-hal/src/xosc.rs +++ b/rp2040-hal/src/xosc.rs @@ -56,6 +56,18 @@ pub enum Error { BadArgument } + +/// Blocking helper method to setup the XOSC without going through all the steps. +pub fn setup_xosc_blocking(xosc_dev: rp2040_pac::XOSC, frequency: Hertz) -> Result, Error> { + + let initialized_xosc = CrystalOscillator::new(xosc_dev).initialize(frequency)?; + + let stable_xosc_token = nb::block!(initialized_xosc.await_stabilization()).unwrap(); + + Ok(initialized_xosc.get_stable(stable_xosc_token)) +} + + /// A Crystal Oscillator. pub struct CrystalOscillator { device: rp2040_pac::XOSC, From 037fc665b2ce57a43a070258ac529b0ee59ed811 Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Sun, 25 Apr 2021 10:15:32 -0500 Subject: [PATCH 21/40] Apply suggestions from code review Co-authored-by: tdittr --- rp2040-hal/src/gpio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rp2040-hal/src/gpio.rs b/rp2040-hal/src/gpio.rs index 57207d0..22c7eb6 100644 --- a/rp2040-hal/src/gpio.rs +++ b/rp2040-hal/src/gpio.rs @@ -205,7 +205,7 @@ macro_rules! gpio { fn is_set_high(&self) -> Result { unsafe { - Ok((*pac::SIO::ptr()).gpio_out_set.read().bits() & (1 << $i) != 0) + Ok((*pac::SIO::ptr()).gpio_out.read().bits() & (1 << $i) != 0) } } } From b3b7677f82fd59b1f1da1f94816a036a1750cb81 Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Sun, 25 Apr 2021 11:13:21 -0500 Subject: [PATCH 22/40] More review comments --- rp2040-hal/examples/blinky.rs | 7 +-- rp2040-hal/examples/gpio_in_out.rs | 2 +- rp2040-hal/src/gpio.rs | 68 +++++++++++++++--------------- 3 files changed, 39 insertions(+), 38 deletions(-) diff --git a/rp2040-hal/examples/blinky.rs b/rp2040-hal/examples/blinky.rs index 3e53311..2bae343 100644 --- a/rp2040-hal/examples/blinky.rs +++ b/rp2040-hal/examples/blinky.rs @@ -21,9 +21,10 @@ fn main() -> ! { let mut led_pin = pins.gpio25.into_output(); loop { - led_pin.set_low().unwrap(); - // TODO: I dare not use delays until we've got clocks running led_pin.set_high().unwrap(); - // TODO: Other delay + // TODO: Replace with proper 1s delays once we have clocks working + cortex_m::asm::delay(500_000); + led_pin.set_low().unwrap(); + cortex_m::asm::delay(500_000); } } diff --git a/rp2040-hal/examples/gpio_in_out.rs b/rp2040-hal/examples/gpio_in_out.rs index 7a6036a..963b150 100644 --- a/rp2040-hal/examples/gpio_in_out.rs +++ b/rp2040-hal/examples/gpio_in_out.rs @@ -21,7 +21,7 @@ fn main() -> ! { let pins = pac.IO_BANK0.split(pac.PADS_BANK0, pac.SIO, &mut pac.RESETS); let mut led_pin = pins.gpio25.into_output(); - let button_pin = pins.gpio15.into_input().pull_high(); + let button_pin = pins.gpio15.into_input().pull_up(); loop { if button_pin.is_high().unwrap() { diff --git a/rp2040-hal/src/gpio.rs b/rp2040-hal/src/gpio.rs index 22c7eb6..fe0e8c7 100644 --- a/rp2040-hal/src/gpio.rs +++ b/rp2040-hal/src/gpio.rs @@ -45,13 +45,13 @@ pub trait GpioExt { /// The amount of current that a pin can drive when used as an output pub enum OutputDriveStrength { /// 2 mA - Ma2, + TwoMilliAmps, /// 4 mA - Ma4, + FourMilliAmps, /// 8 mA - Ma8, + EightMilliAmps, /// 12 mA - Ma12, + TwelveMilliAmps, } #[derive(Clone, Copy, Eq, PartialEq, Debug)] @@ -64,15 +64,19 @@ pub enum OutputSlewRate { } // Magic numbers from the datasheet -// const FUNCTION_SPI: u8 = 1; -// const FUNCTION_UART: u8 = 2; -// const FUNCTION_I2C: u8 = 3; -// const FUNCTION_PWM: u8 = 4; -const FUNCTION_SIO: u8 = 5; -// const FUNCTION_PIO0: u8 = 6; -// const FUNCTION_PIO1: u8 = 7; -// const FUNCTION_CLOCK: u8 = 8; -// const FUNCTION_USB: u8 = 9; +// Order is important! Do not rearrange these +#[allow(dead_code)] +enum GpioFunction { + Spi = 1, + Uart, + I2c, + Pwn, + Sio, + Pio0, + Pio1, + Clock, + Usb, +} macro_rules! gpio { ($GPIOX:ident, $gpiox:ident, $PADSX:ident, $padsx:ident, $gpioxs:expr, [ @@ -85,6 +89,7 @@ macro_rules! gpio { use core::convert::Infallible; use core::marker::PhantomData; use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; + use pac::generic::ResetValue; use super::*; impl GpioExt for pac::$GPIOX { @@ -115,21 +120,16 @@ macro_rules! gpio { )+ } - // Puts pad in same state as post-reset, according to datasheet - fn setup_pad_io(pads: &pac::$padsx::RegisterBlock, index: usize) { - pads.gpio[index].modify(|_, w| w.ie().set_bit() - .od().clear_bit() - .pue().clear_bit() - .pde().set_bit() - .schmitt().set_bit() - .drive()._4m_a() - .slewfast().clear_bit()); + fn reset_pad(pads: &pac::$padsx::RegisterBlock, index: usize) { + let reset_value: u32 = pac::$padsx::GPIO::reset_value(); + // This is safe, we get the value we're setting directly from the PAC + pads.gpio[index].write(|w| unsafe { w.bits(reset_value) }); } - fn set_gpio_function(gpios: &pac::$gpiox::RegisterBlock, index: usize, function: u8) { + fn set_gpio_function(gpios: &pac::$gpiox::RegisterBlock, index: usize, function: GpioFunction) { gpios.gpio[index] .gpio_ctrl - .write_with_zero(|x| unsafe { x.funcsel().bits(function) }); + .write_with_zero(|x| unsafe { x.funcsel().bits(function as _) }); } type PacDriveStrength = pac::$padsx::gpio::DRIVE_A; @@ -152,10 +152,10 @@ macro_rules! gpio { self, ) -> $PXi { unsafe { - setup_pad_io(&*pac::$PADSX::ptr(), $i); + reset_pad(&*pac::$PADSX::ptr(), $i); } unsafe { - set_gpio_function(&*pac::$GPIOX::ptr(), $i, FUNCTION_SIO); + set_gpio_function(&*pac::$GPIOX::ptr(), $i, GpioFunction::Sio); } unsafe { (*pac::SIO::ptr()).gpio_oe_set.write(|x| { x.bits(1 << $i) }); @@ -168,10 +168,10 @@ macro_rules! gpio { self, ) -> $PXi { unsafe { - setup_pad_io(&*pac::$PADSX::ptr(), $i); + reset_pad(&*pac::$PADSX::ptr(), $i); } unsafe { - set_gpio_function(&*pac::$GPIOX::ptr(), $i, FUNCTION_SIO); + set_gpio_function(&*pac::$GPIOX::ptr(), $i, GpioFunction::Sio); } unsafe { (*pac::SIO::ptr()).gpio_oe_clr.write(|x| { x.bits(1 << $i) }); @@ -235,10 +235,10 @@ macro_rules! gpio { #[doc = "Configure the drive strength for this output pin"] pub fn drive_strength(self, strength: OutputDriveStrength) -> Self { let converted = match strength { - OutputDriveStrength::Ma2 => PacDriveStrength::_2MA, - OutputDriveStrength::Ma4 => PacDriveStrength::_4MA, - OutputDriveStrength::Ma8 => PacDriveStrength::_8MA, - OutputDriveStrength::Ma12 => PacDriveStrength::_12MA, + OutputDriveStrength::TwoMilliAmps => PacDriveStrength::_2MA, + OutputDriveStrength::FourMilliAmps => PacDriveStrength::_4MA, + OutputDriveStrength::EightMilliAmps => PacDriveStrength::_8MA, + OutputDriveStrength::TwelveMilliAmps => PacDriveStrength::_12MA, }; unsafe { (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.drive().variant(converted)); @@ -257,7 +257,7 @@ macro_rules! gpio { impl $PXi { #[doc = "Pull this input pin high using internal resistors"] - pub fn pull_high(self) -> Self { + pub fn pull_up(self) -> Self { unsafe { (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.pue().set_bit().pde().clear_bit()); } @@ -265,7 +265,7 @@ macro_rules! gpio { } #[doc = "Pull this input pin low using internal resistors"] - pub fn pull_low(self) -> Self { + pub fn pull_down(self) -> Self { unsafe { (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.pue().clear_bit().pde().set_bit()); } From 7e45c96a658be5c2c4287503e7a68d92e3eae65a Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Sun, 25 Apr 2021 11:17:33 -0500 Subject: [PATCH 23/40] Do reset in a good way instead of a wacky way --- rp2040-hal/src/gpio.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/rp2040-hal/src/gpio.rs b/rp2040-hal/src/gpio.rs index fe0e8c7..96dab87 100644 --- a/rp2040-hal/src/gpio.rs +++ b/rp2040-hal/src/gpio.rs @@ -89,7 +89,6 @@ macro_rules! gpio { use core::convert::Infallible; use core::marker::PhantomData; use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; - use pac::generic::ResetValue; use super::*; impl GpioExt for pac::$GPIOX { @@ -120,12 +119,6 @@ macro_rules! gpio { )+ } - fn reset_pad(pads: &pac::$padsx::RegisterBlock, index: usize) { - let reset_value: u32 = pac::$padsx::GPIO::reset_value(); - // This is safe, we get the value we're setting directly from the PAC - pads.gpio[index].write(|w| unsafe { w.bits(reset_value) }); - } - fn set_gpio_function(gpios: &pac::$gpiox::RegisterBlock, index: usize, function: GpioFunction) { gpios.gpio[index] .gpio_ctrl @@ -152,7 +145,7 @@ macro_rules! gpio { self, ) -> $PXi { unsafe { - reset_pad(&*pac::$PADSX::ptr(), $i); + (*pac::$PADSX::ptr()).gpio[$i].reset(); } unsafe { set_gpio_function(&*pac::$GPIOX::ptr(), $i, GpioFunction::Sio); @@ -168,7 +161,7 @@ macro_rules! gpio { self, ) -> $PXi { unsafe { - reset_pad(&*pac::$PADSX::ptr(), $i); + (*pac::$PADSX::ptr()).gpio[$i].reset(); } unsafe { set_gpio_function(&*pac::$GPIOX::ptr(), $i, GpioFunction::Sio); From 8290368c10a9ca54bd0ea5b5ffb8c63ce213371f Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Sun, 25 Apr 2021 11:43:44 -0500 Subject: [PATCH 24/40] Pull pads out of reset and wait We're technically supposed to wait for these resets to finish before poking at registers. This seems to fix the instability I was seeing on the input example especially (TBH I have no idea how it ever worked) --- rp2040-hal/src/gpio.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/rp2040-hal/src/gpio.rs b/rp2040-hal/src/gpio.rs index 96dab87..03b7f9d 100644 --- a/rp2040-hal/src/gpio.rs +++ b/rp2040-hal/src/gpio.rs @@ -95,7 +95,13 @@ macro_rules! gpio { type Parts = Parts; fn split(self, pads: pac::$PADSX, sio: pac::SIO, resets: &mut pac::RESETS) -> Parts { - resets.reset.modify(|_, w| w.$gpiox().clear_bit()); + resets.reset.modify(|_, w| w.$gpiox().clear_bit().$padsx().clear_bit()); + while resets.reset_done.read().$gpiox().bit_is_clear() { + cortex_m::asm::delay(10); + } + while resets.reset_done.read().$padsx().bit_is_clear() { + cortex_m::asm::delay(10); + } Parts { _pads: pads, _sio: sio, From eaea9ae1ed663907ed434bc098cc35798023a654 Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Sun, 25 Apr 2021 12:13:44 -0500 Subject: [PATCH 25/40] Concentrate the unsafe register constructs This moves almost all of the unsafe stuff together. The last remaining bit is going to need a PAC fix. --- rp2040-hal/src/gpio.rs | 129 +++++++++++++++-------------------------- 1 file changed, 46 insertions(+), 83 deletions(-) diff --git a/rp2040-hal/src/gpio.rs b/rp2040-hal/src/gpio.rs index 03b7f9d..9a9152a 100644 --- a/rp2040-hal/src/gpio.rs +++ b/rp2040-hal/src/gpio.rs @@ -63,21 +63,6 @@ pub enum OutputSlewRate { Fast, } -// Magic numbers from the datasheet -// Order is important! Do not rearrange these -#[allow(dead_code)] -enum GpioFunction { - Spi = 1, - Uart, - I2c, - Pwn, - Sio, - Pio0, - Pio1, - Clock, - Usb, -} - macro_rules! gpio { ($GPIOX:ident, $gpiox:ident, $PADSX:ident, $padsx:ident, $gpioxs:expr, [ $($PXi:ident: ($pxi:ident, $i:expr, $is:expr),)+ @@ -125,12 +110,6 @@ macro_rules! gpio { )+ } - fn set_gpio_function(gpios: &pac::$gpiox::RegisterBlock, index: usize, function: GpioFunction) { - gpios.gpio[index] - .gpio_ctrl - .write_with_zero(|x| unsafe { x.funcsel().bits(function as _) }); - } - type PacDriveStrength = pac::$padsx::gpio::DRIVE_A; $( @@ -140,41 +119,47 @@ macro_rules! gpio { _mode: PhantomData, } - // Safety: We own our $i slice of padsx, gpiox, and sio because the - // construction of Parts assumes ownership of all 3 and will not release - // them. Thus several of the methods below will reconstruct these objects - // as-needed - impl $PXi { + // This is safe because Parts owns the pads, and each pin is responsible + // for its own pad + fn pad(&self) -> &pac::$padsx::GPIO { + unsafe { + &(*pac::$PADSX::ptr()).gpio[$i] + } + } + + // This is safe because Parts owns the SIO. But callers must only touch their + // own pin + fn sio(&self) -> &pac::sio::RegisterBlock { + unsafe { + &(*pac::SIO::ptr()) + } + } + + // This is safe because Parts owns the bank, and each pin is responsible + // for its own slice of the bank + fn gpio_ctrl(&self) -> &pac::$gpiox::gpio::GPIO_CTRL { + unsafe { + &(*pac::$GPIOX::ptr()).gpio[$i].gpio_ctrl + } + } + #[doc = "Configure this pin as an output"] - pub fn into_output( - self, - ) -> $PXi { - unsafe { - (*pac::$PADSX::ptr()).gpio[$i].reset(); - } - unsafe { - set_gpio_function(&*pac::$GPIOX::ptr(), $i, GpioFunction::Sio); - } - unsafe { - (*pac::SIO::ptr()).gpio_oe_set.write(|x| { x.bits(1 << $i) }); - } + pub fn into_output(self)-> $PXi { + self.pad().reset(); + self.gpio_ctrl().write_with_zero(|x| { x.funcsel().sio_0() }); + // TODO: Can we update the PAC to give us a safe register field + // instead of `bits`? + self.sio().gpio_oe_set.write(|x| unsafe { x.bits(1 << $i) }); $PXi { _mode: PhantomData } } #[doc = "Configure this pin as an input"] - pub fn into_input( - self, - ) -> $PXi { - unsafe { - (*pac::$PADSX::ptr()).gpio[$i].reset(); - } - unsafe { - set_gpio_function(&*pac::$GPIOX::ptr(), $i, GpioFunction::Sio); - } - unsafe { - (*pac::SIO::ptr()).gpio_oe_clr.write(|x| { x.bits(1 << $i) }); - } + pub fn into_input(self) -> $PXi { + self.pad().reset(); + self.gpio_ctrl().write_with_zero(|x| { x.funcsel().sio_0() }); + self.sio().gpio_oe_clr.write(|x| unsafe { x.bits(1 << $i) }); + $PXi { _mode: PhantomData } } } @@ -183,16 +168,12 @@ macro_rules! gpio { type Error = Infallible; fn set_low(&mut self) -> Result<(), Self::Error> { - unsafe { - (*pac::SIO::ptr()).gpio_out_clr.write(|x| x.bits(1 << $i)); - } + self.sio().gpio_out_clr.write(|x| unsafe { x.bits(1 << $i) }); Ok(()) } fn set_high(&mut self) -> Result<(), Self::Error> { - unsafe { - (*pac::SIO::ptr()).gpio_out_set.write(|x| x.bits(1 << $i)); - } + self.sio().gpio_out_set.write(|x| unsafe { x.bits(1 << $i) }); Ok(()) } } @@ -203,9 +184,7 @@ macro_rules! gpio { } fn is_set_high(&self) -> Result { - unsafe { - Ok((*pac::SIO::ptr()).gpio_out.read().bits() & (1 << $i) != 0) - } + Ok(self.sio().gpio_out.read().bits() & (1 << $i) != 0) } } @@ -219,9 +198,7 @@ macro_rules! gpio { } fn is_high(&self) -> Result { - unsafe { - Ok((*pac::SIO::ptr()).gpio_in.read().bits() & (1 << $i) != 0) - } + Ok(self.sio().gpio_in.read().bits() & (1 << $i) != 0) } } }; @@ -239,17 +216,13 @@ macro_rules! gpio { OutputDriveStrength::EightMilliAmps => PacDriveStrength::_8MA, OutputDriveStrength::TwelveMilliAmps => PacDriveStrength::_12MA, }; - unsafe { - (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.drive().variant(converted)); - } + self.pad().modify(|_, w| w.drive().variant(converted)); self } #[doc = "Configure the slew rate for this output pin"] pub fn slew_rate(self, slew_rate: OutputSlewRate) -> Self { - unsafe { - (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.slewfast().bit(slew_rate == OutputSlewRate::Fast)); - } + self.pad().modify(|_, w| w.slewfast().bit(slew_rate == OutputSlewRate::Fast)); self } } @@ -257,41 +230,31 @@ macro_rules! gpio { impl $PXi { #[doc = "Pull this input pin high using internal resistors"] pub fn pull_up(self) -> Self { - unsafe { - (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.pue().set_bit().pde().clear_bit()); - } + self.pad().modify(|_, w| w.pue().set_bit().pde().clear_bit()); self } #[doc = "Pull this input pin low using internal resistors"] pub fn pull_down(self) -> Self { - unsafe { - (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.pue().clear_bit().pde().set_bit()); - } + self.pad().modify(|_, w| w.pue().clear_bit().pde().set_bit()); self } #[doc = "Allow this input pin to float (i.e. don't pull it high or low)"] pub fn float(self) -> Self { - unsafe { - (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.pue().clear_bit().pde().clear_bit()); - } + self.pad().modify(|_, w| w.pue().clear_bit().pde().clear_bit()); self } #[doc = "Enable the schmitt trigger for this input pin"] pub fn enable_schmitt_trigger(self) -> Self { - unsafe { - (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.schmitt().set_bit()); - } + self.pad().modify(|_, w| w.schmitt().set_bit()); self } #[doc = "Disable the schmitt trigger for this input pin"] pub fn disable_schmitt_trigger(self) -> Self { - unsafe { - (*pac::$PADSX::ptr()).gpio[$i].modify(|_, w| w.schmitt().clear_bit()); - } + self.pad().modify(|_, w| w.schmitt().clear_bit()); self } } From c4ae152fda7a5499e1e4bf8cf4fb2f55d57e69f5 Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Sun, 25 Apr 2021 12:17:05 -0500 Subject: [PATCH 26/40] Update rp2040-hal/src/gpio.rs Co-authored-by: tdittr --- rp2040-hal/src/gpio.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rp2040-hal/src/gpio.rs b/rp2040-hal/src/gpio.rs index 9a9152a..e954257 100644 --- a/rp2040-hal/src/gpio.rs +++ b/rp2040-hal/src/gpio.rs @@ -81,6 +81,7 @@ macro_rules! gpio { fn split(self, pads: pac::$PADSX, sio: pac::SIO, resets: &mut pac::RESETS) -> Parts { resets.reset.modify(|_, w| w.$gpiox().clear_bit().$padsx().clear_bit()); + // TODO: Implement Resets in the HAL while resets.reset_done.read().$gpiox().bit_is_clear() { cortex_m::asm::delay(10); } From e9721e14c252f3f7adb9abb8969bffb48a938fa1 Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Sun, 25 Apr 2021 12:24:47 -0500 Subject: [PATCH 27/40] Pin ubuntu version --- .github/workflows/check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 4a96375..3319f39 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -3,7 +3,7 @@ name: CI Checks jobs: check: name: Check and Lint - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 From d738626f70cfe40ef2659d262887af12578520df Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Mon, 26 Apr 2021 12:00:23 -0500 Subject: [PATCH 28/40] Also check examples A quick check on my machine showed that just `cargo check --workspace` didn't verify the examples. Quite silly. --- .github/workflows/check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 3319f39..96b1663 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -16,7 +16,7 @@ jobs: - uses: actions-rs/cargo@v1 with: command: check - args: --workspace + args: --workspace --examples - uses: actions-rs/cargo@v1 with: command: fmt From 0badff4f1cdb6f1e2d476f288f3a25da2966e332 Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Mon, 26 Apr 2021 12:04:11 -0500 Subject: [PATCH 29/40] Install arm-none-eabi-gcc in CI --- .github/workflows/check.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 96b1663..b4251f4 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -6,6 +6,8 @@ jobs: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 + - run: apt-get update + - run: apt-get install arm-none-eabi-gcc - uses: actions-rs/toolchain@v1 with: toolchain: stable From 09d9247f2f076a14b775b1cce9a695401241c07c Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Mon, 26 Apr 2021 12:05:24 -0500 Subject: [PATCH 30/40] apt-get requires sudo --- .github/workflows/check.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index b4251f4..dc2144f 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -6,8 +6,8 @@ jobs: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - - run: apt-get update - - run: apt-get install arm-none-eabi-gcc + - run: sudo apt-get update + - run: sudo apt-get install arm-none-eabi-gcc - uses: actions-rs/toolchain@v1 with: toolchain: stable From a4b15a3547522bcac10a9c54eae2bd9390d9991b Mon Sep 17 00:00:00 2001 From: Jennifer Wilcox Date: Mon, 26 Apr 2021 12:06:57 -0500 Subject: [PATCH 31/40] Fix ARM toolchain apt package name --- .github/workflows/check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index dc2144f..1e1b275 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -7,7 +7,7 @@ jobs: steps: - uses: actions/checkout@v2 - run: sudo apt-get update - - run: sudo apt-get install arm-none-eabi-gcc + - run: sudo apt-get install gcc-arm-none-eabi - uses: actions-rs/toolchain@v1 with: toolchain: stable From 39f02c4a441dad79f6e8bbb3199130a3f1d61c1a Mon Sep 17 00:00:00 2001 From: tdittr Date: Tue, 27 Apr 2021 11:59:44 +0200 Subject: [PATCH 32/40] Add `cargo test` to CI run and fix an error found by it Besides the normal usage of unit-tests this also ensures that example in doc-comments do at least compile. --- .github/workflows/check.yml | 4 ++++ rp2040-hal/src/rom_data.rs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 3319f39..3441ac5 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -25,3 +25,7 @@ jobs: with: command: clippy args: -- -Dwarnings + - uses: actions-rs/cargo@v1 + with: + command: test + args: --target x86_64-unknown-linux-gnu diff --git a/rp2040-hal/src/rom_data.rs b/rp2040-hal/src/rom_data.rs index e55ccb3..8b80148 100644 --- a/rp2040-hal/src/rom_data.rs +++ b/rp2040-hal/src/rom_data.rs @@ -266,7 +266,7 @@ float_funcs! { /// Convert a float to a signed 64-bit integer, rounding towards -Infinity, and clamping /// the result to lie within the range -0x8000000000000000 to 0x7FFFFFFFFFFFFFFF 0x6c float_to_int64(v: f32) -> i64; - /// Convert a float to a signed fixed point 64-bit integer representation where n + /// Convert a float to a signed fixed point 64-bit integer representation where n /// specifies the position of the binary point in the resulting fixed point representation - /// e.g. _float2fix(0.5f, 16) == 0x8000. This method rounds towards -Infinity, and /// clamps the resulting integer to lie within the range -0x8000000000000000 to From 1b4291307758b71dbdfb4ba28ec300154d169aa1 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Thu, 29 Apr 2021 11:11:11 +1000 Subject: [PATCH 33/40] Remove unneeded unsafe --- rp2040-hal/src/xosc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rp2040-hal/src/xosc.rs b/rp2040-hal/src/xosc.rs index cf5d9ed..dcf324d 100644 --- a/rp2040-hal/src/xosc.rs +++ b/rp2040-hal/src/xosc.rs @@ -203,7 +203,7 @@ impl CrystalOscillator { //taken from the C SDK const XOSC_DORMANT_VALUE: u32 = 0x636f6d61; - self.device.dormant.write(|w| unsafe { + self.device.dormant.write(|w| { w.bits(XOSC_DORMANT_VALUE); w }); From f21648de933e24a330cdb05759590e5db442ba74 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Thu, 29 Apr 2021 11:15:41 +1000 Subject: [PATCH 34/40] Autoformatted using cargo fmt --- rp2040-hal/src/xosc.rs | 84 ++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 52 deletions(-) diff --git a/rp2040-hal/src/xosc.rs b/rp2040-hal/src/xosc.rs index dcf324d..f2f266e 100644 --- a/rp2040-hal/src/xosc.rs +++ b/rp2040-hal/src/xosc.rs @@ -2,23 +2,13 @@ // See [Chapter 2 Section 16](https://datasheets.raspberrypi.org/rp2040/rp2040_datasheet.pdf) for more details use core::convert::TryInto; -use core::{ - convert::Infallible, - ops::RangeInclusive -}; +use core::{convert::Infallible, ops::RangeInclusive}; use embedded_time::{ - fraction::Fraction, + duration::{Duration, Milliseconds}, fixed_point::FixedPoint, - rate::{ - Hertz, - Megahertz, - Rate - }, - duration::{ - Milliseconds, - Duration - } + fraction::Fraction, + rate::{Hertz, Megahertz, Rate}, }; use nb::Error::WouldBlock; @@ -31,12 +21,12 @@ pub struct Disabled; /// XOSC is initialized, ie we've given parameters (typestate) pub struct Initialized { - freq_hz: Hertz + freq_hz: Hertz, } /// Stable state (typestate) -pub struct Stable{ - freq_hz: Hertz +pub struct Stable { + freq_hz: Hertz, } /// XOSC is in dormant mode (see Chapter 2, Section 16, §5) @@ -53,13 +43,14 @@ pub enum Error { FrequencyOutOfRange, /// Argument is bad : overflows, ... - BadArgument + BadArgument, } - /// Blocking helper method to setup the XOSC without going through all the steps. -pub fn setup_xosc_blocking(xosc_dev: rp2040_pac::XOSC, frequency: Hertz) -> Result, Error> { - +pub fn setup_xosc_blocking( + xosc_dev: rp2040_pac::XOSC, + frequency: Hertz, +) -> Result, Error> { let initialized_xosc = CrystalOscillator::new(xosc_dev).initialize(frequency)?; let stable_xosc_token = nb::block!(initialized_xosc.await_stabilization()).unwrap(); @@ -67,11 +58,10 @@ pub fn setup_xosc_blocking(xosc_dev: rp2040_pac::XOSC, frequency: Hertz) -> Resu Ok(initialized_xosc.get_stable(stable_xosc_token)) } - /// A Crystal Oscillator. pub struct CrystalOscillator { device: rp2040_pac::XOSC, - state: S + state: S, } impl CrystalOscillator { @@ -79,7 +69,7 @@ impl CrystalOscillator { fn transition(self, state: To) -> CrystalOscillator { CrystalOscillator { device: self.device, - state: state + state: state, } } @@ -90,26 +80,25 @@ impl CrystalOscillator { } impl CrystalOscillator { - /// Creates a new CrystalOscillator from the underlying device. pub fn new(dev: rp2040_pac::XOSC) -> Self { CrystalOscillator { device: dev, - state: Disabled + state: Disabled, } } /// Initializes the XOSC : frequency range is set, startup delay is calculated and set. pub fn initialize(self, frequency: Hertz) -> Result, Error> { - - const ALLOWED_FREQUENCY_RANGE: RangeInclusive> = Megahertz(1)..=Megahertz(15); + const ALLOWED_FREQUENCY_RANGE: RangeInclusive> = + Megahertz(1)..=Megahertz(15); const STABLE_DELAY: Milliseconds = Milliseconds(1_u32); const DIVIDER: Fraction = Fraction::new(256, 1); let freq_mhz: Megahertz = frequency.into(); if !ALLOWED_FREQUENCY_RANGE.contains(&freq_mhz) { - return Err(Error::FrequencyOutOfRange) + return Err(Error::FrequencyOutOfRange); } self.device.ctrl.write(|w| { @@ -118,20 +107,20 @@ impl CrystalOscillator { }); //1 ms = 10e-3 sec and Freq = 1/T where T is in seconds so 1ms converts to 1000Hz - let delay_to_hz: Hertz = STABLE_DELAY.to_rate().map_err(|_|Error::BadArgument)?; + let delay_to_hz: Hertz = STABLE_DELAY.to_rate().map_err(|_| Error::BadArgument)?; //startup_delay = ((freq_hz * 10e-3) / 256) = ((freq_hz / 1000) / 256) //See Chapter 2, Section 16, §3) //We do the calculation first. - let startup_delay = frequency. - checked_div(delay_to_hz.integer()).and_then(|r| - r.to_generic::(DIVIDER).ok() - ). - ok_or(Error::BadArgument)?; + let startup_delay = frequency + .checked_div(delay_to_hz.integer()) + .and_then(|r| r.to_generic::(DIVIDER).ok()) + .ok_or(Error::BadArgument)?; //Then we check if it fits into an u16. - let startup_delay: u16 = (*startup_delay.integer()).try_into(). - map_err(|_|Error::BadArgument)?; + let startup_delay: u16 = (*startup_delay.integer()) + .try_into() + .map_err(|_| Error::BadArgument)?; self.device.startup.write(|w| unsafe { w.delay().bits(startup_delay); @@ -143,42 +132,33 @@ impl CrystalOscillator { w }); - Ok(self.transition(Initialized { - freq_hz: frequency - })) + Ok(self.transition(Initialized { freq_hz: frequency })) } } /// A token that's given when the oscillator is stablilzed, and can be exchanged to proceed to the next stage. pub struct StableOscillatorToken { - _private : () + _private: (), } impl CrystalOscillator { - /// One has to wait for the startup delay before using the oscillator, ie awaiting stablilzation of the XOSC pub fn await_stabilization(&self) -> nb::Result { - if self.device.status.read().stable().bit_is_clear() { - return Err(WouldBlock) + return Err(WouldBlock); } - Ok(StableOscillatorToken { - _private: () - }) + Ok(StableOscillatorToken { _private: () }) } /// Returns the stablilzed oscillator pub fn get_stable(self, _token: StableOscillatorToken) -> CrystalOscillator { let freq_hz = self.state.freq_hz; - self.transition(Stable { - freq_hz - }) + self.transition(Stable { freq_hz }) } } impl CrystalOscillator { - /// Operating frequency of the XOSC in hertz pub fn operating_frequency(&self) -> Hertz { self.state.freq_hz @@ -186,7 +166,7 @@ impl CrystalOscillator { /// Disables the XOSC pub fn disable(self) -> CrystalOscillator { - self.device.ctrl.modify(|_r,w| { + self.device.ctrl.modify(|_r, w| { w.enable().disable(); w }); From 010a5cabf3b6967489bda8a24759dbd425e4d6f4 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Thu, 29 Apr 2021 11:19:47 +1000 Subject: [PATCH 35/40] Remove redundant field name --- rp2040-hal/src/xosc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rp2040-hal/src/xosc.rs b/rp2040-hal/src/xosc.rs index f2f266e..a499488 100644 --- a/rp2040-hal/src/xosc.rs +++ b/rp2040-hal/src/xosc.rs @@ -69,7 +69,7 @@ impl CrystalOscillator { fn transition(self, state: To) -> CrystalOscillator { CrystalOscillator { device: self.device, - state: state, + state, } } From 95a1080a4615be5e33ad544d579c54e2addd1269 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Tue, 4 May 2021 17:38:01 +1000 Subject: [PATCH 36/40] Move rustfmt to seperateworkflow --- .github/workflows/check.yml | 6 +----- .github/workflows/rustfmt.yml | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/rustfmt.yml diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 3441ac5..bc86c13 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -12,15 +12,11 @@ jobs: target: thumbv6m-none-eabi override: true profile: minimal - components: rustfmt, clippy + components: clippy - uses: actions-rs/cargo@v1 with: command: check args: --workspace - - uses: actions-rs/cargo@v1 - with: - command: fmt - args: -- --check - uses: actions-rs/cargo@v1 with: command: clippy diff --git a/.github/workflows/rustfmt.yml b/.github/workflows/rustfmt.yml new file mode 100644 index 0000000..528bb71 --- /dev/null +++ b/.github/workflows/rustfmt.yml @@ -0,0 +1,19 @@ +on: [push, pull_request] +name: Code formatting check +jobs: + fmt: + name: Rustfmt + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + target: thumbv6m-none-eabi + override: true + profile: minimal + components: rustfmt + - uses: actions-rs/cargo@v1 + with: + command: fmt + args: -- --check From 41c6db68114933202b4111348b133bf7f8130d57 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Tue, 4 May 2021 17:41:33 +1000 Subject: [PATCH 37/40] Move clippy into seperate workflow --- .github/workflows/check.yml | 5 ----- .github/workflows/clippy.yml | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/clippy.yml diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index bc86c13..748f82e 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -12,15 +12,10 @@ jobs: target: thumbv6m-none-eabi override: true profile: minimal - components: clippy - uses: actions-rs/cargo@v1 with: command: check args: --workspace - - uses: actions-rs/cargo@v1 - with: - command: clippy - args: -- -Dwarnings - uses: actions-rs/cargo@v1 with: command: test diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml new file mode 100644 index 0000000..4675ef7 --- /dev/null +++ b/.github/workflows/clippy.yml @@ -0,0 +1,18 @@ +on: [push, pull_request] +name: Clippy check +jobs: + clippy_check: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + target: thumbv6m-none-eabi + override: true + profile: minimal + components: clippy + - uses: actions-rs/cargo@v1 + with: + command: clippy + args: -- -Dwarnings From 691f43c17baee0a2d45cc4861f66629996bd8a1f Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Tue, 4 May 2021 17:52:48 +1000 Subject: [PATCH 38/40] Move tests into seperate workflow --- .github/workflows/check.yml | 6 +----- .github/workflows/tests_host.yml | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/tests_host.yml diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 748f82e..c0f5358 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -2,7 +2,7 @@ on: [push, pull_request] name: CI Checks jobs: check: - name: Check and Lint + name: cargo-check runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 @@ -16,7 +16,3 @@ jobs: with: command: check args: --workspace - - uses: actions-rs/cargo@v1 - with: - command: test - args: --target x86_64-unknown-linux-gnu diff --git a/.github/workflows/tests_host.yml b/.github/workflows/tests_host.yml new file mode 100644 index 0000000..0d50f03 --- /dev/null +++ b/.github/workflows/tests_host.yml @@ -0,0 +1,19 @@ +on: [push, pull_request] +name: On-host tests +jobs: + check: + name: Check and Lint + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + target: thumbv6m-none-eabi + override: true + profile: minimal + ## Tests are currently not working on host - disabled until we can find a good solution + # - uses: actions-rs/cargo@v1 + # with: + # command: test + # args: --target x86_64-unknown-linux-gnu From 416baf64054ed038af804408ca03a8d861a4db9b Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Tue, 4 May 2021 18:08:06 +1000 Subject: [PATCH 39/40] Add #Safety tag to unsafe rationale docstring --- rp2040-hal/src/xosc.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rp2040-hal/src/xosc.rs b/rp2040-hal/src/xosc.rs index a499488..6f67b1e 100644 --- a/rp2040-hal/src/xosc.rs +++ b/rp2040-hal/src/xosc.rs @@ -175,6 +175,8 @@ impl CrystalOscillator { } /// Put the XOSC in DORMANT state. + /// + /// # Safety /// This method is marked unsafe because prior to switch the XOSC into DORMANT state, /// PLLs must be stopped and IRQs have to be properly configured. /// This method does not do any of that, it merely switches the XOSC to DORMANT state. From 72127aa8e7b41e50f06e5a71c4ff2395fddd79ff Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Wed, 5 May 2021 12:48:40 +1000 Subject: [PATCH 40/40] Remove duplicate entry in Cargo.toml Remove accidental duplication of embedded-time dependency introduced when performing merge-conflict resolution --- rp2040-hal/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/rp2040-hal/Cargo.toml b/rp2040-hal/Cargo.toml index 0209b96..9fbe9cb 100644 --- a/rp2040-hal/Cargo.toml +++ b/rp2040-hal/Cargo.toml @@ -15,7 +15,6 @@ embedded-hal = { version = "0.2.4", features = ["unproven"] } embedded-time = "0.10.1" nb = "1.0.0" rp2040-pac = { git = "https://github.com/rp-rs/rp2040-pac", branch="main" } -embedded-time = "0.10.1" [dev-dependencies] cortex-m-rt = "0.6.13"