Compare commits
	
		
			2 Commits
		
	
	
		
			make-stati
			...
			asynci2cv1
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 54123de7bd | ||
|  | 838a97c186 | 
| @@ -58,7 +58,7 @@ rand_core = "0.6.3" | |||||||
| sdio-host = "0.5.0" | sdio-host = "0.5.0" | ||||||
| embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } | ||||||
| critical-section = "1.1" | critical-section = "1.1" | ||||||
| stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-fbb8f77326dd066aa6c0d66b3b46e76a569dda8b" } | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f6d1ffc1a25f208b5cd6b1024bff246592da1949" } | ||||||
| vcell = "0.1.3" | vcell = "0.1.3" | ||||||
| bxcan = "0.7.0" | bxcan = "0.7.0" | ||||||
| nb = "1.0.0" | nb = "1.0.0" | ||||||
| @@ -76,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] } | |||||||
| [build-dependencies] | [build-dependencies] | ||||||
| proc-macro2 = "1.0.36" | proc-macro2 = "1.0.36" | ||||||
| quote = "1.0.15" | quote = "1.0.15" | ||||||
| stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-fbb8f77326dd066aa6c0d66b3b46e76a569dda8b", default-features = false, features = ["metadata"]} | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f6d1ffc1a25f208b5cd6b1024bff246592da1949", default-features = false, features = ["metadata"]} | ||||||
|  |  | ||||||
|  |  | ||||||
| [features] | [features] | ||||||
|   | |||||||
| @@ -1137,6 +1137,23 @@ fn main() { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     // ======== | ||||||
|  |     // Write peripheral_interrupts module. | ||||||
|  |     let mut mt = TokenStream::new(); | ||||||
|  |     for p in METADATA.peripherals { | ||||||
|  |         let mut pt = TokenStream::new(); | ||||||
|  |  | ||||||
|  |         for irq in p.interrupts { | ||||||
|  |             let iname = format_ident!("{}", irq.interrupt); | ||||||
|  |             let sname = format_ident!("{}", irq.signal); | ||||||
|  |             pt.extend(quote!(pub type #sname = crate::interrupt::typelevel::#iname;)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let pname = format_ident!("{}", p.name); | ||||||
|  |         mt.extend(quote!(pub mod #pname { #pt })); | ||||||
|  |     } | ||||||
|  |     g.extend(quote!(#[allow(non_camel_case_types)] pub mod peripheral_interrupts { #mt })); | ||||||
|  |  | ||||||
|     // ======== |     // ======== | ||||||
|     // Write foreach_foo! macrotables |     // Write foreach_foo! macrotables | ||||||
|  |  | ||||||
| @@ -1295,6 +1312,9 @@ fn main() { | |||||||
|  |  | ||||||
|     let mut m = String::new(); |     let mut m = String::new(); | ||||||
|  |  | ||||||
|  |     // DO NOT ADD more macros like these. | ||||||
|  |     // These turned to be a bad idea! | ||||||
|  |     // Instead, make build.rs generate the final code. | ||||||
|     make_table(&mut m, "foreach_flash_region", &flash_regions_table); |     make_table(&mut m, "foreach_flash_region", &flash_regions_table); | ||||||
|     make_table(&mut m, "foreach_interrupt", &interrupts_table); |     make_table(&mut m, "foreach_interrupt", &interrupts_table); | ||||||
|     make_table(&mut m, "foreach_peripheral", &peripherals_table); |     make_table(&mut m, "foreach_peripheral", &peripherals_table); | ||||||
|   | |||||||
| @@ -1,11 +1,14 @@ | |||||||
| #![macro_use] | #![macro_use] | ||||||
|  |  | ||||||
|  | use core::marker::PhantomData; | ||||||
|  |  | ||||||
| use crate::interrupt; | use crate::interrupt; | ||||||
|  |  | ||||||
| #[cfg_attr(i2c_v1, path = "v1.rs")] | #[cfg_attr(i2c_v1, path = "v1.rs")] | ||||||
| #[cfg_attr(i2c_v2, path = "v2.rs")] | #[cfg_attr(i2c_v2, path = "v2.rs")] | ||||||
| mod _version; | mod _version; | ||||||
| pub use _version::*; | pub use _version::*; | ||||||
|  | use embassy_sync::waitqueue::AtomicWaker; | ||||||
|  |  | ||||||
| use crate::peripherals; | use crate::peripherals; | ||||||
|  |  | ||||||
| @@ -23,6 +26,20 @@ pub enum Error { | |||||||
|  |  | ||||||
| pub(crate) mod sealed { | pub(crate) mod sealed { | ||||||
|     use super::*; |     use super::*; | ||||||
|  |  | ||||||
|  |     pub struct State { | ||||||
|  |         #[allow(unused)] | ||||||
|  |         pub waker: AtomicWaker, | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     impl State { | ||||||
|  |         pub const fn new() -> Self { | ||||||
|  |             Self { | ||||||
|  |                 waker: AtomicWaker::new(), | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     pub trait Instance: crate::rcc::RccPeripheral { |     pub trait Instance: crate::rcc::RccPeripheral { | ||||||
|         fn regs() -> crate::pac::i2c::I2c; |         fn regs() -> crate::pac::i2c::I2c; | ||||||
|         fn state() -> &'static State; |         fn state() -> &'static State; | ||||||
| @@ -30,7 +47,8 @@ pub(crate) mod sealed { | |||||||
| } | } | ||||||
|  |  | ||||||
| pub trait Instance: sealed::Instance + 'static { | pub trait Instance: sealed::Instance + 'static { | ||||||
|     type Interrupt: interrupt::typelevel::Interrupt; |     type EventInterrupt: interrupt::typelevel::Interrupt; | ||||||
|  |     type ErrorInterrupt: interrupt::typelevel::Interrupt; | ||||||
| } | } | ||||||
|  |  | ||||||
| pin_trait!(SclPin, Instance); | pin_trait!(SclPin, Instance); | ||||||
| @@ -38,21 +56,148 @@ pin_trait!(SdaPin, Instance); | |||||||
| dma_trait!(RxDma, Instance); | dma_trait!(RxDma, Instance); | ||||||
| dma_trait!(TxDma, Instance); | dma_trait!(TxDma, Instance); | ||||||
|  |  | ||||||
| foreach_interrupt!( | /// Interrupt handler. | ||||||
|     ($inst:ident, i2c, $block:ident, EV, $irq:ident) => { | pub struct EventInterruptHandler<T: Instance> { | ||||||
|  |     _phantom: PhantomData<T>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<T: Instance> interrupt::typelevel::Handler<T::EventInterrupt> for EventInterruptHandler<T> { | ||||||
|  |     unsafe fn on_interrupt() { | ||||||
|  |         _version::on_interrupt::<T>() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub struct ErrorInterruptHandler<T: Instance> { | ||||||
|  |     _phantom: PhantomData<T>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<T: Instance> interrupt::typelevel::Handler<T::ErrorInterrupt> for ErrorInterruptHandler<T> { | ||||||
|  |     unsafe fn on_interrupt() { | ||||||
|  |         _version::on_interrupt::<T>() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | foreach_peripheral!( | ||||||
|  |     (i2c, $inst:ident) => { | ||||||
|         impl sealed::Instance for peripherals::$inst { |         impl sealed::Instance for peripherals::$inst { | ||||||
|             fn regs() -> crate::pac::i2c::I2c { |             fn regs() -> crate::pac::i2c::I2c { | ||||||
|                 crate::pac::$inst |                 crate::pac::$inst | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             fn state() -> &'static State { |             fn state() -> &'static sealed::State { | ||||||
|                 static STATE: State = State::new(); |                 static STATE: sealed::State = sealed::State::new(); | ||||||
|                 &STATE |                 &STATE | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         impl Instance for peripherals::$inst { |         impl Instance for peripherals::$inst { | ||||||
|             type Interrupt = crate::interrupt::typelevel::$irq; |             type EventInterrupt = crate::_generated::peripheral_interrupts::$inst::EV; | ||||||
|  |             type ErrorInterrupt = crate::_generated::peripheral_interrupts::$inst::ER; | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  | mod eh02 { | ||||||
|  |     use super::*; | ||||||
|  |  | ||||||
|  |     impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { | ||||||
|  |         type Error = Error; | ||||||
|  |  | ||||||
|  |         fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { | ||||||
|  |             self.blocking_read(address, buffer) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> { | ||||||
|  |         type Error = Error; | ||||||
|  |  | ||||||
|  |         fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { | ||||||
|  |             self.blocking_write(address, write) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T> { | ||||||
|  |         type Error = Error; | ||||||
|  |  | ||||||
|  |         fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { | ||||||
|  |             self.blocking_write_read(address, write, read) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[cfg(feature = "unstable-traits")] | ||||||
|  | mod eh1 { | ||||||
|  |     use super::*; | ||||||
|  |     use crate::dma::NoDma; | ||||||
|  |  | ||||||
|  |     impl embedded_hal_1::i2c::Error for Error { | ||||||
|  |         fn kind(&self) -> embedded_hal_1::i2c::ErrorKind { | ||||||
|  |             match *self { | ||||||
|  |                 Self::Bus => embedded_hal_1::i2c::ErrorKind::Bus, | ||||||
|  |                 Self::Arbitration => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss, | ||||||
|  |                 Self::Nack => { | ||||||
|  |                     embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Unknown) | ||||||
|  |                 } | ||||||
|  |                 Self::Timeout => embedded_hal_1::i2c::ErrorKind::Other, | ||||||
|  |                 Self::Crc => embedded_hal_1::i2c::ErrorKind::Other, | ||||||
|  |                 Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun, | ||||||
|  |                 Self::ZeroLengthTransfer => embedded_hal_1::i2c::ErrorKind::Other, | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::ErrorType for I2c<'d, T, TXDMA, RXDMA> { | ||||||
|  |         type Error = Error; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T, NoDma, NoDma> { | ||||||
|  |         fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { | ||||||
|  |             self.blocking_read(address, read) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { | ||||||
|  |             self.blocking_write(address, write) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { | ||||||
|  |             self.blocking_write_read(address, write, read) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         fn transaction( | ||||||
|  |             &mut self, | ||||||
|  |             _address: u8, | ||||||
|  |             _operations: &mut [embedded_hal_1::i2c::Operation<'_>], | ||||||
|  |         ) -> Result<(), Self::Error> { | ||||||
|  |             todo!(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[cfg(all(feature = "unstable-traits", feature = "nightly", feature = "time"))] | ||||||
|  | mod eha { | ||||||
|  |     use super::*; | ||||||
|  |  | ||||||
|  |     impl<'d, T: Instance, TXDMA: TxDma<T>, RXDMA: RxDma<T>> embedded_hal_async::i2c::I2c for I2c<'d, T, TXDMA, RXDMA> { | ||||||
|  |         async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { | ||||||
|  |             self.read(address, read).await | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { | ||||||
|  |             self.write(address, write).await | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { | ||||||
|  |             self.write_read(address, write, read).await | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         async fn transaction( | ||||||
|  |             &mut self, | ||||||
|  |             address: u8, | ||||||
|  |             operations: &mut [embedded_hal_1::i2c::Operation<'_>], | ||||||
|  |         ) -> Result<(), Self::Error> { | ||||||
|  |             let _ = address; | ||||||
|  |             let _ = operations; | ||||||
|  |             todo!() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|   | |||||||
| @@ -1,23 +1,33 @@ | |||||||
|  | use core::future::poll_fn; | ||||||
| use core::marker::PhantomData; | use core::marker::PhantomData; | ||||||
|  | use core::task::Poll; | ||||||
|  |  | ||||||
| use embassy_embedded_hal::SetConfig; | use embassy_embedded_hal::SetConfig; | ||||||
|  | use embassy_futures::select::{select, Either}; | ||||||
|  | use embassy_hal_internal::drop::OnDrop; | ||||||
| use embassy_hal_internal::{into_ref, PeripheralRef}; | use embassy_hal_internal::{into_ref, PeripheralRef}; | ||||||
|  |  | ||||||
| use crate::dma::NoDma; | use super::*; | ||||||
|  | use crate::dma::{NoDma, Transfer}; | ||||||
| use crate::gpio::sealed::AFType; | use crate::gpio::sealed::AFType; | ||||||
| use crate::gpio::Pull; | use crate::gpio::Pull; | ||||||
| use crate::i2c::{Error, Instance, SclPin, SdaPin}; | use crate::interrupt::typelevel::Interrupt; | ||||||
| use crate::pac::i2c; | use crate::pac::i2c; | ||||||
| use crate::time::Hertz; | use crate::time::Hertz; | ||||||
| use crate::{interrupt, Peripheral}; | use crate::{interrupt, Peripheral}; | ||||||
|  |  | ||||||
| /// Interrupt handler. | pub unsafe fn on_interrupt<T: Instance>() { | ||||||
| pub struct InterruptHandler<T: Instance> { |     let regs = T::regs(); | ||||||
|     _phantom: PhantomData<T>, |     // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of | ||||||
| } |     // other stuff, so we wake the task on every interrupt. | ||||||
|  |     T::state().waker.wake(); | ||||||
| impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |     critical_section::with(|_| { | ||||||
|     unsafe fn on_interrupt() {} |         // Clear event interrupt flag. | ||||||
|  |         regs.cr2().modify(|w| { | ||||||
|  |             w.set_itevten(false); | ||||||
|  |             w.set_iterren(false); | ||||||
|  |         }); | ||||||
|  |     }); | ||||||
| } | } | ||||||
|  |  | ||||||
| #[non_exhaustive] | #[non_exhaustive] | ||||||
| @@ -27,14 +37,6 @@ pub struct Config { | |||||||
|     pub scl_pullup: bool, |     pub scl_pullup: bool, | ||||||
| } | } | ||||||
|  |  | ||||||
| pub struct State {} |  | ||||||
|  |  | ||||||
| impl State { |  | ||||||
|     pub(crate) const fn new() -> Self { |  | ||||||
|         Self {} |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { | pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { | ||||||
|     phantom: PhantomData<&'d mut T>, |     phantom: PhantomData<&'d mut T>, | ||||||
|     #[allow(dead_code)] |     #[allow(dead_code)] | ||||||
| @@ -48,7 +50,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||||||
|         _peri: impl Peripheral<P = T> + 'd, |         _peri: impl Peripheral<P = T> + 'd, | ||||||
|         scl: impl Peripheral<P = impl SclPin<T>> + 'd, |         scl: impl Peripheral<P = impl SclPin<T>> + 'd, | ||||||
|         sda: impl Peripheral<P = impl SdaPin<T>> + 'd, |         sda: impl Peripheral<P = impl SdaPin<T>> + 'd, | ||||||
|         _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |         _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>> | ||||||
|  |             + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>> | ||||||
|  |             + 'd, | ||||||
|         tx_dma: impl Peripheral<P = TXDMA> + 'd, |         tx_dma: impl Peripheral<P = TXDMA> + 'd, | ||||||
|         rx_dma: impl Peripheral<P = RXDMA> + 'd, |         rx_dma: impl Peripheral<P = RXDMA> + 'd, | ||||||
|         freq: Hertz, |         freq: Hertz, | ||||||
| @@ -98,6 +102,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||||||
|             reg.set_pe(true); |             reg.set_pe(true); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|  |         unsafe { T::EventInterrupt::enable() }; | ||||||
|  |         unsafe { T::ErrorInterrupt::enable() }; | ||||||
|  |  | ||||||
|         Self { |         Self { | ||||||
|             phantom: PhantomData, |             phantom: PhantomData, | ||||||
|             tx_dma, |             tx_dma, | ||||||
| @@ -105,40 +112,58 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn check_and_clear_error_flags(&self) -> Result<i2c::regs::Sr1, Error> { |     fn check_and_clear_error_flags() -> Result<i2c::regs::Sr1, Error> { | ||||||
|         // Note that flags should only be cleared once they have been registered. If flags are |         // Note that flags should only be cleared once they have been registered. If flags are | ||||||
|         // cleared otherwise, there may be an inherent race condition and flags may be missed. |         // cleared otherwise, there may be an inherent race condition and flags may be missed. | ||||||
|         let sr1 = T::regs().sr1().read(); |         let sr1 = T::regs().sr1().read(); | ||||||
|  |  | ||||||
|         if sr1.timeout() { |         if sr1.timeout() { | ||||||
|             T::regs().sr1().modify(|reg| reg.set_timeout(false)); |             T::regs().sr1().write(|reg| { | ||||||
|  |                 reg.0 = !0; | ||||||
|  |                 reg.set_timeout(false); | ||||||
|  |             }); | ||||||
|             return Err(Error::Timeout); |             return Err(Error::Timeout); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if sr1.pecerr() { |         if sr1.pecerr() { | ||||||
|             T::regs().sr1().modify(|reg| reg.set_pecerr(false)); |             T::regs().sr1().write(|reg| { | ||||||
|  |                 reg.0 = !0; | ||||||
|  |                 reg.set_pecerr(false); | ||||||
|  |             }); | ||||||
|             return Err(Error::Crc); |             return Err(Error::Crc); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if sr1.ovr() { |         if sr1.ovr() { | ||||||
|             T::regs().sr1().modify(|reg| reg.set_ovr(false)); |             T::regs().sr1().write(|reg| { | ||||||
|  |                 reg.0 = !0; | ||||||
|  |                 reg.set_ovr(false); | ||||||
|  |             }); | ||||||
|             return Err(Error::Overrun); |             return Err(Error::Overrun); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if sr1.af() { |         if sr1.af() { | ||||||
|             T::regs().sr1().modify(|reg| reg.set_af(false)); |             T::regs().sr1().write(|reg| { | ||||||
|  |                 reg.0 = !0; | ||||||
|  |                 reg.set_af(false); | ||||||
|  |             }); | ||||||
|             return Err(Error::Nack); |             return Err(Error::Nack); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if sr1.arlo() { |         if sr1.arlo() { | ||||||
|             T::regs().sr1().modify(|reg| reg.set_arlo(false)); |             T::regs().sr1().write(|reg| { | ||||||
|  |                 reg.0 = !0; | ||||||
|  |                 reg.set_arlo(false); | ||||||
|  |             }); | ||||||
|             return Err(Error::Arbitration); |             return Err(Error::Arbitration); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // The errata indicates that BERR may be incorrectly detected. It recommends ignoring and |         // The errata indicates that BERR may be incorrectly detected. It recommends ignoring and | ||||||
|         // clearing the BERR bit instead. |         // clearing the BERR bit instead. | ||||||
|         if sr1.berr() { |         if sr1.berr() { | ||||||
|             T::regs().sr1().modify(|reg| reg.set_berr(false)); |             T::regs().sr1().write(|reg| { | ||||||
|  |                 reg.0 = !0; | ||||||
|  |                 reg.set_berr(false); | ||||||
|  |             }); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         Ok(sr1) |         Ok(sr1) | ||||||
| @@ -157,13 +182,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         // Wait until START condition was generated |         // Wait until START condition was generated | ||||||
|         while !self.check_and_clear_error_flags()?.start() { |         while !Self::check_and_clear_error_flags()?.start() { | ||||||
|             check_timeout()?; |             check_timeout()?; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Also wait until signalled we're master and everything is waiting for us |         // Also wait until signalled we're master and everything is waiting for us | ||||||
|         while { |         while { | ||||||
|             self.check_and_clear_error_flags()?; |             Self::check_and_clear_error_flags()?; | ||||||
|  |  | ||||||
|             let sr2 = T::regs().sr2().read(); |             let sr2 = T::regs().sr2().read(); | ||||||
|             !sr2.msl() && !sr2.busy() |             !sr2.msl() && !sr2.busy() | ||||||
| @@ -177,7 +202,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||||||
|         // Wait until address was sent |         // Wait until address was sent | ||||||
|         // Wait for the address to be acknowledged |         // Wait for the address to be acknowledged | ||||||
|         // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. |         // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. | ||||||
|         while !self.check_and_clear_error_flags()?.addr() { |         while !Self::check_and_clear_error_flags()?.addr() { | ||||||
|             check_timeout()?; |             check_timeout()?; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -197,7 +222,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||||||
|         // Wait until we're ready for sending |         // Wait until we're ready for sending | ||||||
|         while { |         while { | ||||||
|             // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. |             // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. | ||||||
|             !self.check_and_clear_error_flags()?.txe() |             !Self::check_and_clear_error_flags()?.txe() | ||||||
|         } { |         } { | ||||||
|             check_timeout()?; |             check_timeout()?; | ||||||
|         } |         } | ||||||
| @@ -208,7 +233,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||||||
|         // Wait until byte is transferred |         // Wait until byte is transferred | ||||||
|         while { |         while { | ||||||
|             // Check for any potential error conditions. |             // Check for any potential error conditions. | ||||||
|             !self.check_and_clear_error_flags()?.btf() |             !Self::check_and_clear_error_flags()?.btf() | ||||||
|         } { |         } { | ||||||
|             check_timeout()?; |             check_timeout()?; | ||||||
|         } |         } | ||||||
| @@ -219,7 +244,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||||||
|     fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> { |     fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> { | ||||||
|         while { |         while { | ||||||
|             // Check for any potential error conditions. |             // Check for any potential error conditions. | ||||||
|             self.check_and_clear_error_flags()?; |             Self::check_and_clear_error_flags()?; | ||||||
|  |  | ||||||
|             !T::regs().sr1().read().rxne() |             !T::regs().sr1().read().rxne() | ||||||
|         } { |         } { | ||||||
| @@ -244,7 +269,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||||||
|             }); |             }); | ||||||
|  |  | ||||||
|             // Wait until START condition was generated |             // Wait until START condition was generated | ||||||
|             while !self.check_and_clear_error_flags()?.start() { |             while !Self::check_and_clear_error_flags()?.start() { | ||||||
|                 check_timeout()?; |                 check_timeout()?; | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -261,7 +286,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||||||
|  |  | ||||||
|             // Wait until address was sent |             // Wait until address was sent | ||||||
|             // Wait for the address to be acknowledged |             // Wait for the address to be acknowledged | ||||||
|             while !self.check_and_clear_error_flags()?.addr() { |             while !Self::check_and_clear_error_flags()?.addr() { | ||||||
|                 check_timeout()?; |                 check_timeout()?; | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -336,6 +361,322 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||||||
|     pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { |     pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { | ||||||
|         self.blocking_write_read_timeout(addr, write, read, || Ok(())) |         self.blocking_write_read_timeout(addr, write, read, || Ok(())) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     // Async | ||||||
|  |  | ||||||
|  |     #[inline] // pretty sure this should always be inlined | ||||||
|  |     fn enable_interrupts() -> () { | ||||||
|  |         T::regs().cr2().modify(|w| { | ||||||
|  |             w.set_iterren(true); | ||||||
|  |             w.set_itevten(true); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> | ||||||
|  |     where | ||||||
|  |         TXDMA: crate::i2c::TxDma<T>, | ||||||
|  |     { | ||||||
|  |         let dma_transfer = unsafe { | ||||||
|  |             let regs = T::regs(); | ||||||
|  |             regs.cr2().modify(|w| { | ||||||
|  |                 // DMA mode can be enabled for transmission by setting the DMAEN bit in the I2C_CR2 register. | ||||||
|  |                 w.set_dmaen(true); | ||||||
|  |                 w.set_itbufen(false); | ||||||
|  |             }); | ||||||
|  |             // Set the I2C_DR register address in the DMA_SxPAR register. The data will be moved to this address from the memory after each TxE event. | ||||||
|  |             let dst = regs.dr().as_ptr() as *mut u8; | ||||||
|  |  | ||||||
|  |             let ch = &mut self.tx_dma; | ||||||
|  |             let request = ch.request(); | ||||||
|  |             Transfer::new_write(ch, request, write, dst, Default::default()) | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         let on_drop = OnDrop::new(|| { | ||||||
|  |             let regs = T::regs(); | ||||||
|  |             regs.cr2().modify(|w| { | ||||||
|  |                 w.set_dmaen(false); | ||||||
|  |                 w.set_iterren(false); | ||||||
|  |                 w.set_itevten(false); | ||||||
|  |             }) | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         Self::enable_interrupts(); | ||||||
|  |  | ||||||
|  |         // Send a START condition | ||||||
|  |         T::regs().cr1().modify(|reg| { | ||||||
|  |             reg.set_start(true); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         let state = T::state(); | ||||||
|  |  | ||||||
|  |         // Wait until START condition was generated | ||||||
|  |         poll_fn(|cx| { | ||||||
|  |             state.waker.register(cx.waker()); | ||||||
|  |  | ||||||
|  |             match Self::check_and_clear_error_flags() { | ||||||
|  |                 Err(e) => Poll::Ready(Err(e)), | ||||||
|  |                 Ok(sr1) => { | ||||||
|  |                     if sr1.start() { | ||||||
|  |                         Poll::Ready(Ok(())) | ||||||
|  |                     } else { | ||||||
|  |                         Poll::Pending | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .await?; | ||||||
|  |  | ||||||
|  |         // Also wait until signalled we're master and everything is waiting for us | ||||||
|  |         Self::enable_interrupts(); | ||||||
|  |         poll_fn(|cx| { | ||||||
|  |             state.waker.register(cx.waker()); | ||||||
|  |  | ||||||
|  |             match Self::check_and_clear_error_flags() { | ||||||
|  |                 Err(e) => Poll::Ready(Err(e)), | ||||||
|  |                 Ok(_) => { | ||||||
|  |                     let sr2 = T::regs().sr2().read(); | ||||||
|  |                     if !sr2.msl() && !sr2.busy() { | ||||||
|  |                         Poll::Pending | ||||||
|  |                     } else { | ||||||
|  |                         Poll::Ready(Ok(())) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .await?; | ||||||
|  |  | ||||||
|  |         // Set up current address, we're trying to talk to | ||||||
|  |         T::regs().dr().write(|reg| reg.set_dr(address << 1)); | ||||||
|  |         Self::enable_interrupts(); | ||||||
|  |  | ||||||
|  |         poll_fn(|cx| { | ||||||
|  |             state.waker.register(cx.waker()); | ||||||
|  |             match Self::check_and_clear_error_flags() { | ||||||
|  |                 Err(e) => Poll::Ready(Err(e)), | ||||||
|  |                 Ok(sr1) => { | ||||||
|  |                     if sr1.addr() { | ||||||
|  |                         // Clear the ADDR condition by reading SR2. | ||||||
|  |                         T::regs().sr2().read(); | ||||||
|  |                         Poll::Ready(Ok(())) | ||||||
|  |                     } else { | ||||||
|  |                         Poll::Pending | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .await?; | ||||||
|  |  | ||||||
|  |         Self::enable_interrupts(); | ||||||
|  |         let poll_error = poll_fn(|cx| { | ||||||
|  |             state.waker.register(cx.waker()); | ||||||
|  |  | ||||||
|  |             match Self::check_and_clear_error_flags() { | ||||||
|  |                 // Unclear why the Err turbofish is necessary here? The compiler didn’t require it in the other | ||||||
|  |                 // identical poll_fn check_and_clear matches. | ||||||
|  |                 Err(e) => Poll::Ready(Err::<T, Error>(e)), | ||||||
|  |                 Ok(_) => Poll::Pending, | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         // Wait for either the DMA transfer to successfully finish, or an I2C error to occur. | ||||||
|  |         match select(dma_transfer, poll_error).await { | ||||||
|  |             Either::Second(Err(e)) => Err(e), | ||||||
|  |             _ => Ok(()), | ||||||
|  |         }?; | ||||||
|  |  | ||||||
|  |         // The I2C transfer itself will take longer than the DMA transfer, so wait for that to finish too. | ||||||
|  |  | ||||||
|  |         // 18.3.8 “Master transmitter: In the interrupt routine after the EOT interrupt, disable DMA | ||||||
|  |         // requests then wait for a BTF event before programming the Stop condition.” | ||||||
|  |  | ||||||
|  |         // TODO: If this has to be done “in the interrupt routine after the EOT interrupt”, where to put it? | ||||||
|  |         T::regs().cr2().modify(|w| { | ||||||
|  |             w.set_dmaen(false); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         Self::enable_interrupts(); | ||||||
|  |         poll_fn(|cx| { | ||||||
|  |             state.waker.register(cx.waker()); | ||||||
|  |  | ||||||
|  |             match Self::check_and_clear_error_flags() { | ||||||
|  |                 Err(e) => Poll::Ready(Err(e)), | ||||||
|  |                 Ok(sr1) => { | ||||||
|  |                     if sr1.btf() { | ||||||
|  |                         T::regs().cr1().modify(|w| { | ||||||
|  |                             w.set_stop(true); | ||||||
|  |                         }); | ||||||
|  |                         Poll::Ready(Ok(())) | ||||||
|  |                     } else { | ||||||
|  |                         Poll::Pending | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .await?; | ||||||
|  |         // Wait for STOP condition to transmit. | ||||||
|  |         Self::enable_interrupts(); | ||||||
|  |         poll_fn(|cx| { | ||||||
|  |             state.waker.register(cx.waker()); | ||||||
|  |  | ||||||
|  |             if T::regs().cr1().read().stop() { | ||||||
|  |                 Poll::Pending | ||||||
|  |             } else { | ||||||
|  |                 Poll::Ready(Ok(())) | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .await?; | ||||||
|  |  | ||||||
|  |         drop(on_drop); | ||||||
|  |  | ||||||
|  |         // Fallthrough is success | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> | ||||||
|  |     where | ||||||
|  |         RXDMA: crate::i2c::RxDma<T>, | ||||||
|  |     { | ||||||
|  |         let state = T::state(); | ||||||
|  |         let buffer_len = buffer.len(); | ||||||
|  |  | ||||||
|  |         let dma_transfer = unsafe { | ||||||
|  |             let regs = T::regs(); | ||||||
|  |             regs.cr2().modify(|w| { | ||||||
|  |                 // DMA mode can be enabled for transmission by setting the DMAEN bit in the I2C_CR2 register. | ||||||
|  |                 w.set_itbufen(false); | ||||||
|  |                 w.set_dmaen(true); | ||||||
|  |             }); | ||||||
|  |             // Set the I2C_DR register address in the DMA_SxPAR register. The data will be moved to this address from the memory after each TxE event. | ||||||
|  |             let src = regs.dr().as_ptr() as *mut u8; | ||||||
|  |  | ||||||
|  |             let ch = &mut self.rx_dma; | ||||||
|  |             let request = ch.request(); | ||||||
|  |             Transfer::new_read(ch, request, src, buffer, Default::default()) | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         let on_drop = OnDrop::new(|| { | ||||||
|  |             let regs = T::regs(); | ||||||
|  |             regs.cr2().modify(|w| { | ||||||
|  |                 w.set_dmaen(false); | ||||||
|  |                 w.set_iterren(false); | ||||||
|  |                 w.set_itevten(false); | ||||||
|  |             }) | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         Self::enable_interrupts(); | ||||||
|  |  | ||||||
|  |         // Send a START condition and set ACK bit | ||||||
|  |         T::regs().cr1().modify(|reg| { | ||||||
|  |             reg.set_start(true); | ||||||
|  |             reg.set_ack(true); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         // Wait until START condition was generated | ||||||
|  |         poll_fn(|cx| { | ||||||
|  |             state.waker.register(cx.waker()); | ||||||
|  |  | ||||||
|  |             match Self::check_and_clear_error_flags() { | ||||||
|  |                 Err(e) => Poll::Ready(Err(e)), | ||||||
|  |                 Ok(sr1) => { | ||||||
|  |                     if sr1.start() { | ||||||
|  |                         Poll::Ready(Ok(())) | ||||||
|  |                     } else { | ||||||
|  |                         Poll::Pending | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .await?; | ||||||
|  |  | ||||||
|  |         // Also wait until signalled we're master and everything is waiting for us | ||||||
|  |         Self::enable_interrupts(); | ||||||
|  |         poll_fn(|cx| { | ||||||
|  |             state.waker.register(cx.waker()); | ||||||
|  |  | ||||||
|  |             // blocking read didn’t have a check_and_clear call here, but blocking write did so | ||||||
|  |             // I’m adding it here in case that was an oversight. | ||||||
|  |             match Self::check_and_clear_error_flags() { | ||||||
|  |                 Err(e) => Poll::Ready(Err(e)), | ||||||
|  |                 Ok(_) => { | ||||||
|  |                     let sr2 = T::regs().sr2().read(); | ||||||
|  |                     if !sr2.msl() && !sr2.busy() { | ||||||
|  |                         Poll::Pending | ||||||
|  |                     } else { | ||||||
|  |                         Poll::Ready(Ok(())) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .await?; | ||||||
|  |  | ||||||
|  |         // Set up current address, we're trying to talk to | ||||||
|  |         T::regs().dr().write(|reg| reg.set_dr((address << 1) + 1)); | ||||||
|  |  | ||||||
|  |         // Wait for the address to be acknowledged | ||||||
|  |  | ||||||
|  |         Self::enable_interrupts(); | ||||||
|  |         poll_fn(|cx| { | ||||||
|  |             state.waker.register(cx.waker()); | ||||||
|  |  | ||||||
|  |             match Self::check_and_clear_error_flags() { | ||||||
|  |                 Err(e) => Poll::Ready(Err(e)), | ||||||
|  |                 Ok(sr1) => { | ||||||
|  |                     if sr1.addr() { | ||||||
|  |                         // 18.3.8: When a single byte must be received: the NACK must be programmed during EV6 | ||||||
|  |                         // event, i.e. program ACK=0 when ADDR=1, before clearing ADDR flag. Then the | ||||||
|  |                         // user can program the STOP condition either after clearing ADDR flag, or in the | ||||||
|  |                         // DMA Transfer Complete interrupt routine. | ||||||
|  |                         if buffer_len == 1 { | ||||||
|  |                             T::regs().cr1().modify(|w| { | ||||||
|  |                                 w.set_ack(false); | ||||||
|  |                             }); | ||||||
|  |                         } | ||||||
|  |                         Poll::Ready(Ok(())) | ||||||
|  |                     } else { | ||||||
|  |                         Poll::Pending | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .await?; | ||||||
|  |  | ||||||
|  |         // Clear condition by reading SR2 | ||||||
|  |         T::regs().sr2().read(); | ||||||
|  |  | ||||||
|  |         // Wait for bytes to be received, or an error to occur. | ||||||
|  |         Self::enable_interrupts(); | ||||||
|  |         let poll_error = poll_fn(|cx| { | ||||||
|  |             state.waker.register(cx.waker()); | ||||||
|  |  | ||||||
|  |             match Self::check_and_clear_error_flags() { | ||||||
|  |                 Err(e) => Poll::Ready(Err::<T, Error>(e)), | ||||||
|  |                 _ => Poll::Pending, | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         match select(dma_transfer, poll_error).await { | ||||||
|  |             Either::Second(Err(e)) => Err(e), | ||||||
|  |             _ => Ok(()), | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         // v1 blocking waits for STOP to be written, the manual says to write the STOP bit yourself. | ||||||
|  |         // what to do… | ||||||
|  |         // Wait for the STOP to be sent. | ||||||
|  |         // while T::regs().cr1().read().stop() { | ||||||
|  |         //     check_timeout()?; | ||||||
|  |         // } | ||||||
|  |  | ||||||
|  |         // Fallthrough is success | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub async fn write_read(&mut self, _address: u8, _write: &[u8], _read: &mut [u8]) -> Result<(), Error> | ||||||
|  |     where | ||||||
|  |         RXDMA: crate::i2c::RxDma<T>, | ||||||
|  |         TXDMA: crate::i2c::TxDma<T>, | ||||||
|  |     { | ||||||
|  |         todo!() | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { | impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { | ||||||
| @@ -344,77 +685,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { |  | ||||||
|     type Error = Error; |  | ||||||
|  |  | ||||||
|     fn read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Self::Error> { |  | ||||||
|         self.blocking_read(addr, read) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> { |  | ||||||
|     type Error = Error; |  | ||||||
|  |  | ||||||
|     fn write(&mut self, addr: u8, write: &[u8]) -> Result<(), Self::Error> { |  | ||||||
|         self.blocking_write(addr, write) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T> { |  | ||||||
|     type Error = Error; |  | ||||||
|  |  | ||||||
|     fn write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { |  | ||||||
|         self.blocking_write_read(addr, write, read) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[cfg(feature = "unstable-traits")] |  | ||||||
| mod eh1 { |  | ||||||
|     use super::*; |  | ||||||
|  |  | ||||||
|     impl embedded_hal_1::i2c::Error for Error { |  | ||||||
|         fn kind(&self) -> embedded_hal_1::i2c::ErrorKind { |  | ||||||
|             match *self { |  | ||||||
|                 Self::Bus => embedded_hal_1::i2c::ErrorKind::Bus, |  | ||||||
|                 Self::Arbitration => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss, |  | ||||||
|                 Self::Nack => { |  | ||||||
|                     embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Unknown) |  | ||||||
|                 } |  | ||||||
|                 Self::Timeout => embedded_hal_1::i2c::ErrorKind::Other, |  | ||||||
|                 Self::Crc => embedded_hal_1::i2c::ErrorKind::Other, |  | ||||||
|                 Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun, |  | ||||||
|                 Self::ZeroLengthTransfer => embedded_hal_1::i2c::ErrorKind::Other, |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     impl<'d, T: Instance> embedded_hal_1::i2c::ErrorType for I2c<'d, T> { |  | ||||||
|         type Error = Error; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T> { |  | ||||||
|         fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { |  | ||||||
|             self.blocking_read(address, read) |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { |  | ||||||
|             self.blocking_write(address, write) |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { |  | ||||||
|             self.blocking_write_read(address, write, read) |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         fn transaction( |  | ||||||
|             &mut self, |  | ||||||
|             _address: u8, |  | ||||||
|             _operations: &mut [embedded_hal_1::i2c::Operation<'_>], |  | ||||||
|         ) -> Result<(), Self::Error> { |  | ||||||
|             todo!(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| enum Mode { | enum Mode { | ||||||
|     Fast, |     Fast, | ||||||
|     Standard, |     Standard, | ||||||
|   | |||||||
| @@ -1,19 +1,17 @@ | |||||||
| use core::cmp; | use core::cmp; | ||||||
| use core::future::poll_fn; | use core::future::poll_fn; | ||||||
| use core::marker::PhantomData; |  | ||||||
| use core::task::Poll; | use core::task::Poll; | ||||||
|  |  | ||||||
| use embassy_embedded_hal::SetConfig; | use embassy_embedded_hal::SetConfig; | ||||||
| use embassy_hal_internal::drop::OnDrop; | use embassy_hal_internal::drop::OnDrop; | ||||||
| use embassy_hal_internal::{into_ref, PeripheralRef}; | use embassy_hal_internal::{into_ref, PeripheralRef}; | ||||||
| use embassy_sync::waitqueue::AtomicWaker; |  | ||||||
| #[cfg(feature = "time")] | #[cfg(feature = "time")] | ||||||
| use embassy_time::{Duration, Instant}; | use embassy_time::{Duration, Instant}; | ||||||
|  |  | ||||||
|  | use super::*; | ||||||
| use crate::dma::{NoDma, Transfer}; | use crate::dma::{NoDma, Transfer}; | ||||||
| use crate::gpio::sealed::AFType; | use crate::gpio::sealed::AFType; | ||||||
| use crate::gpio::Pull; | use crate::gpio::Pull; | ||||||
| use crate::i2c::{Error, Instance, SclPin, SdaPin}; |  | ||||||
| use crate::interrupt::typelevel::Interrupt; | use crate::interrupt::typelevel::Interrupt; | ||||||
| use crate::pac::i2c; | use crate::pac::i2c; | ||||||
| use crate::time::Hertz; | use crate::time::Hertz; | ||||||
| @@ -36,25 +34,18 @@ pub fn no_timeout_fn() -> impl Fn() -> Result<(), Error> { | |||||||
|     move || Ok(()) |     move || Ok(()) | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Interrupt handler. | pub unsafe fn on_interrupt<T: Instance>() { | ||||||
| pub struct InterruptHandler<T: Instance> { |     let regs = T::regs(); | ||||||
|     _phantom: PhantomData<T>, |     let isr = regs.isr().read(); | ||||||
| } |  | ||||||
|  |  | ||||||
| impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |     if isr.tcr() || isr.tc() { | ||||||
|     unsafe fn on_interrupt() { |         T::state().waker.wake(); | ||||||
|         let regs = T::regs(); |  | ||||||
|         let isr = regs.isr().read(); |  | ||||||
|  |  | ||||||
|         if isr.tcr() || isr.tc() { |  | ||||||
|             T::state().waker.wake(); |  | ||||||
|         } |  | ||||||
|         // The flag can only be cleared by writting to nbytes, we won't do that here, so disable |  | ||||||
|         // the interrupt |  | ||||||
|         critical_section::with(|_| { |  | ||||||
|             regs.cr1().modify(|w| w.set_tcie(false)); |  | ||||||
|         }); |  | ||||||
|     } |     } | ||||||
|  |     // The flag can only be cleared by writting to nbytes, we won't do that here, so disable | ||||||
|  |     // the interrupt | ||||||
|  |     critical_section::with(|_| { | ||||||
|  |         regs.cr1().modify(|w| w.set_tcie(false)); | ||||||
|  |     }); | ||||||
| } | } | ||||||
|  |  | ||||||
| #[non_exhaustive] | #[non_exhaustive] | ||||||
| @@ -77,18 +68,6 @@ impl Default for Config { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| pub struct State { |  | ||||||
|     waker: AtomicWaker, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl State { |  | ||||||
|     pub(crate) const fn new() -> Self { |  | ||||||
|         Self { |  | ||||||
|             waker: AtomicWaker::new(), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { | pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { | ||||||
|     _peri: PeripheralRef<'d, T>, |     _peri: PeripheralRef<'d, T>, | ||||||
|     #[allow(dead_code)] |     #[allow(dead_code)] | ||||||
| @@ -104,7 +83,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||||||
|         peri: impl Peripheral<P = T> + 'd, |         peri: impl Peripheral<P = T> + 'd, | ||||||
|         scl: impl Peripheral<P = impl SclPin<T>> + 'd, |         scl: impl Peripheral<P = impl SclPin<T>> + 'd, | ||||||
|         sda: impl Peripheral<P = impl SdaPin<T>> + 'd, |         sda: impl Peripheral<P = impl SdaPin<T>> + 'd, | ||||||
|         _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |         _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>> | ||||||
|  |             + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>> | ||||||
|  |             + 'd, | ||||||
|         tx_dma: impl Peripheral<P = TXDMA> + 'd, |         tx_dma: impl Peripheral<P = TXDMA> + 'd, | ||||||
|         rx_dma: impl Peripheral<P = RXDMA> + 'd, |         rx_dma: impl Peripheral<P = RXDMA> + 'd, | ||||||
|         freq: Hertz, |         freq: Hertz, | ||||||
| @@ -150,8 +131,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||||||
|             reg.set_pe(true); |             reg.set_pe(true); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         T::Interrupt::unpend(); |         unsafe { T::EventInterrupt::enable() }; | ||||||
|         unsafe { T::Interrupt::enable() }; |         unsafe { T::ErrorInterrupt::enable() }; | ||||||
|  |  | ||||||
|         Self { |         Self { | ||||||
|             _peri: peri, |             _peri: peri, | ||||||
| @@ -987,35 +968,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| #[cfg(feature = "time")] |  | ||||||
| mod eh02 { |  | ||||||
|     use super::*; |  | ||||||
|  |  | ||||||
|     impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { |  | ||||||
|         type Error = Error; |  | ||||||
|  |  | ||||||
|         fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { |  | ||||||
|             self.blocking_read(address, buffer) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> { |  | ||||||
|         type Error = Error; |  | ||||||
|  |  | ||||||
|         fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { |  | ||||||
|             self.blocking_write(address, write) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T> { |  | ||||||
|         type Error = Error; |  | ||||||
|  |  | ||||||
|         fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { |  | ||||||
|             self.blocking_write_read(address, write, read) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /// I2C Stop Configuration | /// I2C Stop Configuration | ||||||
| /// | /// | ||||||
| /// Peripheral options for generating the STOP condition | /// Peripheral options for generating the STOP condition | ||||||
| @@ -1140,83 +1092,6 @@ impl Timings { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| #[cfg(feature = "unstable-traits")] |  | ||||||
| mod eh1 { |  | ||||||
|     use super::*; |  | ||||||
|  |  | ||||||
|     impl embedded_hal_1::i2c::Error for Error { |  | ||||||
|         fn kind(&self) -> embedded_hal_1::i2c::ErrorKind { |  | ||||||
|             match *self { |  | ||||||
|                 Self::Bus => embedded_hal_1::i2c::ErrorKind::Bus, |  | ||||||
|                 Self::Arbitration => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss, |  | ||||||
|                 Self::Nack => { |  | ||||||
|                     embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Unknown) |  | ||||||
|                 } |  | ||||||
|                 Self::Timeout => embedded_hal_1::i2c::ErrorKind::Other, |  | ||||||
|                 Self::Crc => embedded_hal_1::i2c::ErrorKind::Other, |  | ||||||
|                 Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun, |  | ||||||
|                 Self::ZeroLengthTransfer => embedded_hal_1::i2c::ErrorKind::Other, |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::ErrorType for I2c<'d, T, TXDMA, RXDMA> { |  | ||||||
|         type Error = Error; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     impl<'d, T: Instance> embedded_hal_1::i2c::I2c for I2c<'d, T, NoDma, NoDma> { |  | ||||||
|         fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { |  | ||||||
|             self.blocking_read(address, read) |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { |  | ||||||
|             self.blocking_write(address, write) |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { |  | ||||||
|             self.blocking_write_read(address, write, read) |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         fn transaction( |  | ||||||
|             &mut self, |  | ||||||
|             _address: u8, |  | ||||||
|             _operations: &mut [embedded_hal_1::i2c::Operation<'_>], |  | ||||||
|         ) -> Result<(), Self::Error> { |  | ||||||
|             todo!(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[cfg(all(feature = "unstable-traits", feature = "nightly", feature = "time"))] |  | ||||||
| mod eha { |  | ||||||
|     use super::super::{RxDma, TxDma}; |  | ||||||
|     use super::*; |  | ||||||
|  |  | ||||||
|     impl<'d, T: Instance, TXDMA: TxDma<T>, RXDMA: RxDma<T>> embedded_hal_async::i2c::I2c for I2c<'d, T, TXDMA, RXDMA> { |  | ||||||
|         async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { |  | ||||||
|             self.read(address, read).await |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { |  | ||||||
|             self.write(address, write).await |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { |  | ||||||
|             self.write_read(address, write, read).await |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         async fn transaction( |  | ||||||
|             &mut self, |  | ||||||
|             address: u8, |  | ||||||
|             operations: &mut [embedded_hal_1::i2c::Operation<'_>], |  | ||||||
|         ) -> Result<(), Self::Error> { |  | ||||||
|             let _ = address; |  | ||||||
|             let _ = operations; |  | ||||||
|             todo!() |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl<'d, T: Instance> SetConfig for I2c<'d, T> { | impl<'d, T: Instance> SetConfig for I2c<'d, T> { | ||||||
|     type Config = Hertz; |     type Config = Hertz; | ||||||
|     type ConfigError = (); |     type ConfigError = (); | ||||||
|   | |||||||
| @@ -14,7 +14,8 @@ const ADDRESS: u8 = 0x5F; | |||||||
| const WHOAMI: u8 = 0x0F; | const WHOAMI: u8 = 0x0F; | ||||||
|  |  | ||||||
| bind_interrupts!(struct Irqs { | bind_interrupts!(struct Irqs { | ||||||
|     I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>; |     I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>; | ||||||
|  |     I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>; | ||||||
| }); | }); | ||||||
|  |  | ||||||
| #[embassy_executor::main] | #[embassy_executor::main] | ||||||
|   | |||||||
| @@ -13,7 +13,8 @@ const ADDRESS: u8 = 0x5F; | |||||||
| const WHOAMI: u8 = 0x0F; | const WHOAMI: u8 = 0x0F; | ||||||
|  |  | ||||||
| bind_interrupts!(struct Irqs { | bind_interrupts!(struct Irqs { | ||||||
|     I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>; |     I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>; | ||||||
|  |     I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>; | ||||||
| }); | }); | ||||||
|  |  | ||||||
| #[embassy_executor::main] | #[embassy_executor::main] | ||||||
|   | |||||||
| @@ -19,7 +19,8 @@ const HEIGHT: usize = 100; | |||||||
| static mut FRAME: [u32; WIDTH * HEIGHT / 2] = [0u32; WIDTH * HEIGHT / 2]; | static mut FRAME: [u32; WIDTH * HEIGHT / 2] = [0u32; WIDTH * HEIGHT / 2]; | ||||||
|  |  | ||||||
| bind_interrupts!(struct Irqs { | bind_interrupts!(struct Irqs { | ||||||
|     I2C1_EV => i2c::InterruptHandler<peripherals::I2C1>; |     I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>; | ||||||
|  |     I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>; | ||||||
|     DCMI => dcmi::InterruptHandler<peripherals::DCMI>; |     DCMI => dcmi::InterruptHandler<peripherals::DCMI>; | ||||||
| }); | }); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -13,7 +13,8 @@ const ADDRESS: u8 = 0x5F; | |||||||
| const WHOAMI: u8 = 0x0F; | const WHOAMI: u8 = 0x0F; | ||||||
|  |  | ||||||
| bind_interrupts!(struct Irqs { | bind_interrupts!(struct Irqs { | ||||||
|     I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>; |     I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>; | ||||||
|  |     I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>; | ||||||
| }); | }); | ||||||
|  |  | ||||||
| #[embassy_executor::main] | #[embassy_executor::main] | ||||||
|   | |||||||
| @@ -14,7 +14,8 @@ const ADDRESS: u8 = 0x5F; | |||||||
| const WHOAMI: u8 = 0x0F; | const WHOAMI: u8 = 0x0F; | ||||||
|  |  | ||||||
| bind_interrupts!(struct Irqs { | bind_interrupts!(struct Irqs { | ||||||
|     I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>; |     I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>; | ||||||
|  |     I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>; | ||||||
| }); | }); | ||||||
|  |  | ||||||
| #[embassy_executor::main] | #[embassy_executor::main] | ||||||
|   | |||||||
| @@ -16,7 +16,8 @@ const ADDRESS: u8 = 0x5F; | |||||||
| const WHOAMI: u8 = 0x0F; | const WHOAMI: u8 = 0x0F; | ||||||
|  |  | ||||||
| bind_interrupts!(struct Irqs { | bind_interrupts!(struct Irqs { | ||||||
|     I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>; |     I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>; | ||||||
|  |     I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>; | ||||||
| }); | }); | ||||||
|  |  | ||||||
| #[embassy_executor::main] | #[embassy_executor::main] | ||||||
|   | |||||||
| @@ -13,7 +13,8 @@ const ADDRESS: u8 = 0x5F; | |||||||
| const WHOAMI: u8 = 0x0F; | const WHOAMI: u8 = 0x0F; | ||||||
|  |  | ||||||
| bind_interrupts!(struct Irqs { | bind_interrupts!(struct Irqs { | ||||||
|     I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>; |     I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>; | ||||||
|  |     I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>; | ||||||
| }); | }); | ||||||
|  |  | ||||||
| #[embassy_executor::main] | #[embassy_executor::main] | ||||||
|   | |||||||
| @@ -40,7 +40,8 @@ use static_cell::make_static; | |||||||
| use {embassy_stm32 as hal, panic_probe as _}; | use {embassy_stm32 as hal, panic_probe as _}; | ||||||
|  |  | ||||||
| bind_interrupts!(struct Irqs { | bind_interrupts!(struct Irqs { | ||||||
|     I2C3_EV => i2c::InterruptHandler<peripherals::I2C3>; |     I2C3_EV => i2c::EventInterruptHandler<peripherals::I2C3>; | ||||||
|  |     I2C3_ER => i2c::ErrorInterruptHandler<peripherals::I2C3>; | ||||||
|     RNG => rng::InterruptHandler<peripherals::RNG>; |     RNG => rng::InterruptHandler<peripherals::RNG>; | ||||||
| }); | }); | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user