diff options
| -rw-r--r-- | embassy-nrf/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-nrf/src/gpio.rs | 70 | ||||
| -rw-r--r-- | embassy-nrf/src/twim.rs | 140 | ||||
| -rw-r--r-- | embassy-stm32/src/gpio.rs | 101 | ||||
| -rw-r--r-- | embassy/src/time/timer.rs | 2 |
5 files changed, 288 insertions, 29 deletions
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 979e66a94..b7c09286f 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml | |||
| @@ -17,6 +17,8 @@ flavors = [ | |||
| 17 | 17 | ||
| 18 | [features] | 18 | [features] |
| 19 | 19 | ||
| 20 | time = ["embassy/time"] | ||
| 21 | |||
| 20 | defmt = ["dep:defmt", "embassy/defmt", "embassy-usb?/defmt"] | 22 | defmt = ["dep:defmt", "embassy/defmt", "embassy-usb?/defmt"] |
| 21 | 23 | ||
| 22 | # Enable nightly-only features | 24 | # Enable nightly-only features |
| @@ -56,7 +58,7 @@ _nrf5340-net = ["_nrf5340", "nrf5340-net-pac"] | |||
| 56 | _nrf5340 = ["_gpio-p1", "_dppi"] | 58 | _nrf5340 = ["_gpio-p1", "_dppi"] |
| 57 | _nrf9160 = ["nrf9160-pac", "_dppi"] | 59 | _nrf9160 = ["nrf9160-pac", "_dppi"] |
| 58 | 60 | ||
| 59 | _time-driver = ["embassy/time-tick-32768hz"] | 61 | _time-driver = ["embassy/time-tick-32768hz", "time"] |
| 60 | 62 | ||
| 61 | _ppi = [] | 63 | _ppi = [] |
| 62 | _dppi = [] | 64 | _dppi = [] |
diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index c33cca64b..f5212c6af 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs | |||
| @@ -7,10 +7,10 @@ use core::marker::PhantomData; | |||
| 7 | use cfg_if::cfg_if; | 7 | use cfg_if::cfg_if; |
| 8 | use embassy::util::Unborrow; | 8 | use embassy::util::Unborrow; |
| 9 | use embassy_hal_common::{unborrow, unsafe_impl_unborrow}; | 9 | use embassy_hal_common::{unborrow, unsafe_impl_unborrow}; |
| 10 | use gpio::pin_cnf::DRIVE_A; | ||
| 11 | 10 | ||
| 12 | use crate::pac; | 11 | use crate::pac; |
| 13 | use crate::pac::p0 as gpio; | 12 | use crate::pac::p0 as gpio; |
| 13 | use crate::pac::p0::pin_cnf::{DRIVE_A, PULL_A}; | ||
| 14 | 14 | ||
| 15 | use self::sealed::Pin as _; | 15 | use self::sealed::Pin as _; |
| 16 | 16 | ||
| @@ -129,9 +129,30 @@ impl<'d, T: Pin> Output<'d, T> { | |||
| 129 | } | 129 | } |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | fn convert_drive(drive: OutputDrive) -> DRIVE_A { | ||
| 133 | match drive { | ||
| 134 | OutputDrive::Standard => DRIVE_A::S0S1, | ||
| 135 | OutputDrive::HighDrive0Standard1 => DRIVE_A::H0S1, | ||
| 136 | OutputDrive::Standard0HighDrive1 => DRIVE_A::S0H1, | ||
| 137 | OutputDrive::HighDrive => DRIVE_A::H0H1, | ||
| 138 | OutputDrive::Disconnect0Standard1 => DRIVE_A::D0S1, | ||
| 139 | OutputDrive::Disconnect0HighDrive1 => DRIVE_A::D0H1, | ||
| 140 | OutputDrive::Standard0Disconnect1 => DRIVE_A::S0D1, | ||
| 141 | OutputDrive::HighDrive0Disconnect1 => DRIVE_A::H0D1, | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | fn convert_pull(pull: Pull) -> PULL_A { | ||
| 146 | match pull { | ||
| 147 | Pull::None => PULL_A::DISABLED, | ||
| 148 | Pull::Up => PULL_A::PULLUP, | ||
| 149 | Pull::Down => PULL_A::PULLDOWN, | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 132 | /// GPIO flexible pin. | 153 | /// GPIO flexible pin. |
| 133 | /// | 154 | /// |
| 134 | /// This pin can either be a disconnected, input, or output pin. The level register bit will remain | 155 | /// This pin can either be a disconnected, input, or output pin, or both. The level register bit will remain |
| 135 | /// set while not in output mode, so the pin's level will be 'remembered' when it is not in output | 156 | /// set while not in output mode, so the pin's level will be 'remembered' when it is not in output |
| 136 | /// mode. | 157 | /// mode. |
| 137 | pub struct Flex<'d, T: Pin> { | 158 | pub struct Flex<'d, T: Pin> { |
| @@ -158,17 +179,7 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 158 | self.pin.conf().write(|w| { | 179 | self.pin.conf().write(|w| { |
| 159 | w.dir().input(); | 180 | w.dir().input(); |
| 160 | w.input().connect(); | 181 | w.input().connect(); |
| 161 | match pull { | 182 | w.pull().variant(convert_pull(pull)); |
| 162 | Pull::None => { | ||
| 163 | w.pull().disabled(); | ||
| 164 | } | ||
| 165 | Pull::Up => { | ||
| 166 | w.pull().pullup(); | ||
| 167 | } | ||
| 168 | Pull::Down => { | ||
| 169 | w.pull().pulldown(); | ||
| 170 | } | ||
| 171 | } | ||
| 172 | w.drive().s0s1(); | 183 | w.drive().s0s1(); |
| 173 | w.sense().disabled(); | 184 | w.sense().disabled(); |
| 174 | w | 185 | w |
| @@ -180,22 +191,31 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 180 | /// The pin level will be whatever was set before (or low by default). If you want it to begin | 191 | /// The pin level will be whatever was set before (or low by default). If you want it to begin |
| 181 | /// at a specific level, call `set_high`/`set_low` on the pin first. | 192 | /// at a specific level, call `set_high`/`set_low` on the pin first. |
| 182 | pub fn set_as_output(&mut self, drive: OutputDrive) { | 193 | pub fn set_as_output(&mut self, drive: OutputDrive) { |
| 183 | let drive = match drive { | ||
| 184 | OutputDrive::Standard => DRIVE_A::S0S1, | ||
| 185 | OutputDrive::HighDrive0Standard1 => DRIVE_A::H0S1, | ||
| 186 | OutputDrive::Standard0HighDrive1 => DRIVE_A::S0H1, | ||
| 187 | OutputDrive::HighDrive => DRIVE_A::H0H1, | ||
| 188 | OutputDrive::Disconnect0Standard1 => DRIVE_A::D0S1, | ||
| 189 | OutputDrive::Disconnect0HighDrive1 => DRIVE_A::D0H1, | ||
| 190 | OutputDrive::Standard0Disconnect1 => DRIVE_A::S0D1, | ||
| 191 | OutputDrive::HighDrive0Disconnect1 => DRIVE_A::H0D1, | ||
| 192 | }; | ||
| 193 | |||
| 194 | self.pin.conf().write(|w| { | 194 | self.pin.conf().write(|w| { |
| 195 | w.dir().output(); | 195 | w.dir().output(); |
| 196 | w.input().disconnect(); | 196 | w.input().disconnect(); |
| 197 | w.pull().disabled(); | 197 | w.pull().disabled(); |
| 198 | w.drive().variant(drive); | 198 | w.drive().variant(convert_drive(drive)); |
| 199 | w.sense().disabled(); | ||
| 200 | w | ||
| 201 | }); | ||
| 202 | } | ||
| 203 | |||
| 204 | /// Put the pin into input + output mode. | ||
| 205 | /// | ||
| 206 | /// This is commonly used for "open drain" mode. If you set `drive = Standard0Disconnect1`, | ||
| 207 | /// the hardware will drive the line low if you set it to low, and will leave it floating if you set | ||
| 208 | /// it to high, in which case you can read the input to figure out whether another device | ||
| 209 | /// is driving the line low. | ||
| 210 | /// | ||
| 211 | /// The pin level will be whatever was set before (or low by default). If you want it to begin | ||
| 212 | /// at a specific level, call `set_high`/`set_low` on the pin first. | ||
| 213 | pub fn set_as_input_output(&mut self, pull: Pull, drive: OutputDrive) { | ||
| 214 | self.pin.conf().write(|w| { | ||
| 215 | w.dir().output(); | ||
| 216 | w.input().connect(); | ||
| 217 | w.pull().variant(convert_pull(pull)); | ||
| 218 | w.drive().variant(convert_drive(drive)); | ||
| 199 | w.sense().disabled(); | 219 | w.sense().disabled(); |
| 200 | w | 220 | w |
| 201 | }); | 221 | }); |
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index 9bee16f3d..bb943c2c7 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs | |||
| @@ -11,6 +11,8 @@ use core::marker::PhantomData; | |||
| 11 | use core::sync::atomic::{compiler_fence, Ordering::SeqCst}; | 11 | use core::sync::atomic::{compiler_fence, Ordering::SeqCst}; |
| 12 | use core::task::Poll; | 12 | use core::task::Poll; |
| 13 | use embassy::interrupt::{Interrupt, InterruptExt}; | 13 | use embassy::interrupt::{Interrupt, InterruptExt}; |
| 14 | #[cfg(feature = "time")] | ||
| 15 | use embassy::time::{Duration, Instant}; | ||
| 14 | use embassy::util::Unborrow; | 16 | use embassy::util::Unborrow; |
| 15 | use embassy::waitqueue::AtomicWaker; | 17 | use embassy::waitqueue::AtomicWaker; |
| 16 | use embassy_hal_common::unborrow; | 18 | use embassy_hal_common::unborrow; |
| @@ -34,7 +36,9 @@ pub enum Frequency { | |||
| 34 | #[non_exhaustive] | 36 | #[non_exhaustive] |
| 35 | pub struct Config { | 37 | pub struct Config { |
| 36 | pub frequency: Frequency, | 38 | pub frequency: Frequency, |
| 39 | pub sda_high_drive: bool, | ||
| 37 | pub sda_pullup: bool, | 40 | pub sda_pullup: bool, |
| 41 | pub scl_high_drive: bool, | ||
| 38 | pub scl_pullup: bool, | 42 | pub scl_pullup: bool, |
| 39 | } | 43 | } |
| 40 | 44 | ||
| @@ -42,7 +46,9 @@ impl Default for Config { | |||
| 42 | fn default() -> Self { | 46 | fn default() -> Self { |
| 43 | Self { | 47 | Self { |
| 44 | frequency: Frequency::K100, | 48 | frequency: Frequency::K100, |
| 49 | scl_high_drive: false, | ||
| 45 | sda_pullup: false, | 50 | sda_pullup: false, |
| 51 | sda_high_drive: false, | ||
| 46 | scl_pullup: false, | 52 | scl_pullup: false, |
| 47 | } | 53 | } |
| 48 | } | 54 | } |
| @@ -62,6 +68,7 @@ pub enum Error { | |||
| 62 | AddressNack, | 68 | AddressNack, |
| 63 | DataNack, | 69 | DataNack, |
| 64 | Overrun, | 70 | Overrun, |
| 71 | Timeout, | ||
| 65 | } | 72 | } |
| 66 | 73 | ||
| 67 | /// Interface to a TWIM instance using EasyDMA to offload the transmission and reception workload. | 74 | /// Interface to a TWIM instance using EasyDMA to offload the transmission and reception workload. |
| @@ -87,7 +94,11 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 87 | sda.conf().write(|w| { | 94 | sda.conf().write(|w| { |
| 88 | w.dir().input(); | 95 | w.dir().input(); |
| 89 | w.input().connect(); | 96 | w.input().connect(); |
| 90 | w.drive().s0d1(); | 97 | if config.sda_high_drive { |
| 98 | w.drive().h0d1(); | ||
| 99 | } else { | ||
| 100 | w.drive().s0d1(); | ||
| 101 | } | ||
| 91 | if config.sda_pullup { | 102 | if config.sda_pullup { |
| 92 | w.pull().pullup(); | 103 | w.pull().pullup(); |
| 93 | } | 104 | } |
| @@ -96,7 +107,11 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 96 | scl.conf().write(|w| { | 107 | scl.conf().write(|w| { |
| 97 | w.dir().input(); | 108 | w.dir().input(); |
| 98 | w.input().connect(); | 109 | w.input().connect(); |
| 99 | w.drive().s0d1(); | 110 | if config.scl_high_drive { |
| 111 | w.drive().h0d1(); | ||
| 112 | } else { | ||
| 113 | w.drive().s0d1(); | ||
| 114 | } | ||
| 100 | if config.scl_pullup { | 115 | if config.scl_pullup { |
| 101 | w.pull().pullup(); | 116 | w.pull().pullup(); |
| 102 | } | 117 | } |
| @@ -267,6 +282,29 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 267 | } | 282 | } |
| 268 | 283 | ||
| 269 | /// Wait for stop or error | 284 | /// Wait for stop or error |
| 285 | #[cfg(feature = "time")] | ||
| 286 | fn blocking_wait_timeout(&mut self, timeout: Duration) -> Result<(), Error> { | ||
| 287 | let r = T::regs(); | ||
| 288 | let deadline = Instant::now() + timeout; | ||
| 289 | loop { | ||
| 290 | if r.events_stopped.read().bits() != 0 { | ||
| 291 | r.events_stopped.reset(); | ||
| 292 | break; | ||
| 293 | } | ||
| 294 | if r.events_error.read().bits() != 0 { | ||
| 295 | r.events_error.reset(); | ||
| 296 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 297 | } | ||
| 298 | if Instant::now() > deadline { | ||
| 299 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 300 | return Err(Error::Timeout); | ||
| 301 | } | ||
| 302 | } | ||
| 303 | |||
| 304 | Ok(()) | ||
| 305 | } | ||
| 306 | |||
| 307 | /// Wait for stop or error | ||
| 270 | fn async_wait(&mut self) -> impl Future<Output = ()> { | 308 | fn async_wait(&mut self) -> impl Future<Output = ()> { |
| 271 | poll_fn(move |cx| { | 309 | poll_fn(move |cx| { |
| 272 | let r = T::regs(); | 310 | let r = T::regs(); |
| @@ -493,6 +531,103 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 493 | Ok(()) | 531 | Ok(()) |
| 494 | } | 532 | } |
| 495 | 533 | ||
| 534 | // =========================================== | ||
| 535 | |||
| 536 | /// Write to an I2C slave with timeout. | ||
| 537 | /// | ||
| 538 | /// See [`blocking_write`]. | ||
| 539 | #[cfg(feature = "time")] | ||
| 540 | pub fn blocking_write_timeout( | ||
| 541 | &mut self, | ||
| 542 | address: u8, | ||
| 543 | buffer: &[u8], | ||
| 544 | timeout: Duration, | ||
| 545 | ) -> Result<(), Error> { | ||
| 546 | self.setup_write(address, buffer, false)?; | ||
| 547 | self.blocking_wait_timeout(timeout)?; | ||
| 548 | compiler_fence(SeqCst); | ||
| 549 | self.check_errorsrc()?; | ||
| 550 | self.check_tx(buffer.len())?; | ||
| 551 | Ok(()) | ||
| 552 | } | ||
| 553 | |||
| 554 | /// Same as [`blocking_write`](Twim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. | ||
| 555 | #[cfg(feature = "time")] | ||
| 556 | pub fn blocking_write_from_ram_timeout( | ||
| 557 | &mut self, | ||
| 558 | address: u8, | ||
| 559 | buffer: &[u8], | ||
| 560 | timeout: Duration, | ||
| 561 | ) -> Result<(), Error> { | ||
| 562 | self.setup_write_from_ram(address, buffer, false)?; | ||
| 563 | self.blocking_wait_timeout(timeout)?; | ||
| 564 | compiler_fence(SeqCst); | ||
| 565 | self.check_errorsrc()?; | ||
| 566 | self.check_tx(buffer.len())?; | ||
| 567 | Ok(()) | ||
| 568 | } | ||
| 569 | |||
| 570 | /// Read from an I2C slave. | ||
| 571 | /// | ||
| 572 | /// The buffer must have a length of at most 255 bytes on the nRF52832 | ||
| 573 | /// and at most 65535 bytes on the nRF52840. | ||
| 574 | #[cfg(feature = "time")] | ||
| 575 | pub fn blocking_read_timeout( | ||
| 576 | &mut self, | ||
| 577 | address: u8, | ||
| 578 | buffer: &mut [u8], | ||
| 579 | timeout: Duration, | ||
| 580 | ) -> Result<(), Error> { | ||
| 581 | self.setup_read(address, buffer, false)?; | ||
| 582 | self.blocking_wait_timeout(timeout)?; | ||
| 583 | compiler_fence(SeqCst); | ||
| 584 | self.check_errorsrc()?; | ||
| 585 | self.check_rx(buffer.len())?; | ||
| 586 | Ok(()) | ||
| 587 | } | ||
| 588 | |||
| 589 | /// Write data to an I2C slave, then read data from the slave without | ||
| 590 | /// triggering a stop condition between the two. | ||
| 591 | /// | ||
| 592 | /// The buffers must have a length of at most 255 bytes on the nRF52832 | ||
| 593 | /// and at most 65535 bytes on the nRF52840. | ||
| 594 | #[cfg(feature = "time")] | ||
| 595 | pub fn blocking_write_read_timeout( | ||
| 596 | &mut self, | ||
| 597 | address: u8, | ||
| 598 | wr_buffer: &[u8], | ||
| 599 | rd_buffer: &mut [u8], | ||
| 600 | timeout: Duration, | ||
| 601 | ) -> Result<(), Error> { | ||
| 602 | self.setup_write_read(address, wr_buffer, rd_buffer, false)?; | ||
| 603 | self.blocking_wait_timeout(timeout)?; | ||
| 604 | compiler_fence(SeqCst); | ||
| 605 | self.check_errorsrc()?; | ||
| 606 | self.check_tx(wr_buffer.len())?; | ||
| 607 | self.check_rx(rd_buffer.len())?; | ||
| 608 | Ok(()) | ||
| 609 | } | ||
| 610 | |||
| 611 | /// Same as [`blocking_write_read`](Twim::blocking_write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. | ||
| 612 | #[cfg(feature = "time")] | ||
| 613 | pub fn blocking_write_read_from_ram_timeout( | ||
| 614 | &mut self, | ||
| 615 | address: u8, | ||
| 616 | wr_buffer: &[u8], | ||
| 617 | rd_buffer: &mut [u8], | ||
| 618 | timeout: Duration, | ||
| 619 | ) -> Result<(), Error> { | ||
| 620 | self.setup_write_read_from_ram(address, wr_buffer, rd_buffer, false)?; | ||
| 621 | self.blocking_wait_timeout(timeout)?; | ||
| 622 | compiler_fence(SeqCst); | ||
| 623 | self.check_errorsrc()?; | ||
| 624 | self.check_tx(wr_buffer.len())?; | ||
| 625 | self.check_rx(rd_buffer.len())?; | ||
| 626 | Ok(()) | ||
| 627 | } | ||
| 628 | |||
| 629 | // =========================================== | ||
| 630 | |||
| 496 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { | 631 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { |
| 497 | self.setup_read(address, buffer, true)?; | 632 | self.setup_read(address, buffer, true)?; |
| 498 | self.async_wait().await; | 633 | self.async_wait().await; |
| @@ -677,6 +812,7 @@ mod eh1 { | |||
| 677 | embedded_hal_1::i2c::NoAcknowledgeSource::Data, | 812 | embedded_hal_1::i2c::NoAcknowledgeSource::Data, |
| 678 | ), | 813 | ), |
| 679 | Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun, | 814 | Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun, |
| 815 | Self::Timeout => embedded_hal_1::i2c::ErrorKind::Other, | ||
| 680 | } | 816 | } |
| 681 | } | 817 | } |
| 682 | } | 818 | } |
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 1ac6f3952..30f900316 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs | |||
| @@ -3,7 +3,6 @@ use core::convert::Infallible; | |||
| 3 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 4 | use embassy::util::Unborrow; | 4 | use embassy::util::Unborrow; |
| 5 | use embassy_hal_common::{unborrow, unsafe_impl_unborrow}; | 5 | use embassy_hal_common::{unborrow, unsafe_impl_unborrow}; |
| 6 | use embedded_hal_02::digital::v2::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin}; | ||
| 7 | 6 | ||
| 8 | use crate::pac; | 7 | use crate::pac; |
| 9 | use crate::pac::gpio::{self, vals}; | 8 | use crate::pac::gpio::{self, vals}; |
| @@ -605,6 +604,9 @@ pub(crate) unsafe fn init() { | |||
| 605 | 604 | ||
| 606 | mod eh02 { | 605 | mod eh02 { |
| 607 | use super::*; | 606 | use super::*; |
| 607 | use embedded_hal_02::digital::v2::{ | ||
| 608 | InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin, | ||
| 609 | }; | ||
| 608 | 610 | ||
| 609 | impl<'d, T: Pin> InputPin for Input<'d, T> { | 611 | impl<'d, T: Pin> InputPin for Input<'d, T> { |
| 610 | type Error = Infallible; | 612 | type Error = Infallible; |
| @@ -691,6 +693,103 @@ mod eh02 { | |||
| 691 | } | 693 | } |
| 692 | } | 694 | } |
| 693 | 695 | ||
| 696 | #[cfg(feature = "unstable-traits")] | ||
| 697 | mod eh1 { | ||
| 698 | use super::*; | ||
| 699 | use embedded_hal_1::digital::blocking::{ | ||
| 700 | InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin, | ||
| 701 | }; | ||
| 702 | use embedded_hal_1::digital::ErrorType; | ||
| 703 | |||
| 704 | impl<'d, T: Pin> ErrorType for Input<'d, T> { | ||
| 705 | type Error = Infallible; | ||
| 706 | } | ||
| 707 | |||
| 708 | impl<'d, T: Pin> InputPin for Input<'d, T> { | ||
| 709 | #[inline] | ||
| 710 | fn is_high(&self) -> Result<bool, Self::Error> { | ||
| 711 | Ok(self.is_high()) | ||
| 712 | } | ||
| 713 | |||
| 714 | #[inline] | ||
| 715 | fn is_low(&self) -> Result<bool, Self::Error> { | ||
| 716 | Ok(self.is_low()) | ||
| 717 | } | ||
| 718 | } | ||
| 719 | |||
| 720 | impl<'d, T: Pin> ErrorType for Output<'d, T> { | ||
| 721 | type Error = Infallible; | ||
| 722 | } | ||
| 723 | |||
| 724 | impl<'d, T: Pin> OutputPin for Output<'d, T> { | ||
| 725 | #[inline] | ||
| 726 | fn set_high(&mut self) -> Result<(), Self::Error> { | ||
| 727 | Ok(self.set_high()) | ||
| 728 | } | ||
| 729 | |||
| 730 | #[inline] | ||
| 731 | fn set_low(&mut self) -> Result<(), Self::Error> { | ||
| 732 | Ok(self.set_low()) | ||
| 733 | } | ||
| 734 | } | ||
| 735 | |||
| 736 | impl<'d, T: Pin> StatefulOutputPin for Output<'d, T> { | ||
| 737 | #[inline] | ||
| 738 | fn is_set_high(&self) -> Result<bool, Self::Error> { | ||
| 739 | Ok(self.is_set_high()) | ||
| 740 | } | ||
| 741 | |||
| 742 | /// Is the output pin set as low? | ||
| 743 | #[inline] | ||
| 744 | fn is_set_low(&self) -> Result<bool, Self::Error> { | ||
| 745 | Ok(self.is_set_low()) | ||
| 746 | } | ||
| 747 | } | ||
| 748 | |||
| 749 | impl<'d, T: Pin> ToggleableOutputPin for Output<'d, T> { | ||
| 750 | #[inline] | ||
| 751 | fn toggle(&mut self) -> Result<(), Self::Error> { | ||
| 752 | Ok(self.toggle()) | ||
| 753 | } | ||
| 754 | } | ||
| 755 | |||
| 756 | impl<'d, T: Pin> ErrorType for OutputOpenDrain<'d, T> { | ||
| 757 | type Error = Infallible; | ||
| 758 | } | ||
| 759 | |||
| 760 | impl<'d, T: Pin> OutputPin for OutputOpenDrain<'d, T> { | ||
| 761 | #[inline] | ||
| 762 | fn set_high(&mut self) -> Result<(), Self::Error> { | ||
| 763 | Ok(self.set_high()) | ||
| 764 | } | ||
| 765 | |||
| 766 | #[inline] | ||
| 767 | fn set_low(&mut self) -> Result<(), Self::Error> { | ||
| 768 | Ok(self.set_low()) | ||
| 769 | } | ||
| 770 | } | ||
| 771 | |||
| 772 | impl<'d, T: Pin> StatefulOutputPin for OutputOpenDrain<'d, T> { | ||
| 773 | #[inline] | ||
| 774 | fn is_set_high(&self) -> Result<bool, Self::Error> { | ||
| 775 | Ok(self.is_set_high()) | ||
| 776 | } | ||
| 777 | |||
| 778 | /// Is the output pin set as low? | ||
| 779 | #[inline] | ||
| 780 | fn is_set_low(&self) -> Result<bool, Self::Error> { | ||
| 781 | Ok(self.is_set_low()) | ||
| 782 | } | ||
| 783 | } | ||
| 784 | |||
| 785 | impl<'d, T: Pin> ToggleableOutputPin for OutputOpenDrain<'d, T> { | ||
| 786 | #[inline] | ||
| 787 | fn toggle(&mut self) -> Result<(), Self::Error> { | ||
| 788 | Ok(self.toggle()) | ||
| 789 | } | ||
| 790 | } | ||
| 791 | } | ||
| 792 | |||
| 694 | #[cfg(feature = "unstable-pac")] | 793 | #[cfg(feature = "unstable-pac")] |
| 695 | pub mod low_level { | 794 | pub mod low_level { |
| 696 | pub use super::sealed::*; | 795 | pub use super::sealed::*; |
diff --git a/embassy/src/time/timer.rs b/embassy/src/time/timer.rs index aacaadfc5..1b3832f37 100644 --- a/embassy/src/time/timer.rs +++ b/embassy/src/time/timer.rs | |||
| @@ -7,6 +7,8 @@ use crate::executor::raw; | |||
| 7 | use crate::time::{Duration, Instant}; | 7 | use crate::time::{Duration, Instant}; |
| 8 | 8 | ||
| 9 | /// Error returned by [`with_timeout`] on timeout. | 9 | /// Error returned by [`with_timeout`] on timeout. |
| 10 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
| 11 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 10 | pub struct TimeoutError; | 12 | pub struct TimeoutError; |
| 11 | 13 | ||
| 12 | /// Runs a given future with a timeout. | 14 | /// Runs a given future with a timeout. |
