Compare commits
	
		
			4 Commits
		
	
	
		
			embassy-rp
			...
			embassy-rp
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | f4b77c967f | ||
|  | ca2e3759ad | ||
|  | 6f21f0680e | ||
|  | fc724dd707 | 
| @@ -1,3 +1,4 @@ | |||||||
|  | //! ADC driver. | ||||||
| use core::future::poll_fn; | use core::future::poll_fn; | ||||||
| use core::marker::PhantomData; | use core::marker::PhantomData; | ||||||
| use core::mem; | use core::mem; | ||||||
| @@ -16,6 +17,7 @@ use crate::{dma, interrupt, pac, peripherals, Peripheral, RegExt}; | |||||||
|  |  | ||||||
| static WAKER: AtomicWaker = AtomicWaker::new(); | static WAKER: AtomicWaker = AtomicWaker::new(); | ||||||
|  |  | ||||||
|  | /// ADC config. | ||||||
| #[non_exhaustive] | #[non_exhaustive] | ||||||
| pub struct Config {} | pub struct Config {} | ||||||
|  |  | ||||||
| @@ -30,9 +32,11 @@ enum Source<'p> { | |||||||
|     TempSensor(PeripheralRef<'p, ADC_TEMP_SENSOR>), |     TempSensor(PeripheralRef<'p, ADC_TEMP_SENSOR>), | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// ADC channel. | ||||||
| pub struct Channel<'p>(Source<'p>); | pub struct Channel<'p>(Source<'p>); | ||||||
|  |  | ||||||
| impl<'p> Channel<'p> { | impl<'p> Channel<'p> { | ||||||
|  |     /// Create a new ADC channel from pin with the provided [Pull] configuration. | ||||||
|     pub fn new_pin(pin: impl Peripheral<P = impl AdcPin + 'p> + 'p, pull: Pull) -> Self { |     pub fn new_pin(pin: impl Peripheral<P = impl AdcPin + 'p> + 'p, pull: Pull) -> Self { | ||||||
|         into_ref!(pin); |         into_ref!(pin); | ||||||
|         pin.pad_ctrl().modify(|w| { |         pin.pad_ctrl().modify(|w| { | ||||||
| @@ -49,6 +53,7 @@ impl<'p> Channel<'p> { | |||||||
|         Self(Source::Pin(pin.map_into())) |         Self(Source::Pin(pin.map_into())) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Create a new ADC channel for the internal temperature sensor. | ||||||
|     pub fn new_temp_sensor(s: impl Peripheral<P = ADC_TEMP_SENSOR> + 'p) -> Self { |     pub fn new_temp_sensor(s: impl Peripheral<P = ADC_TEMP_SENSOR> + 'p) -> Self { | ||||||
|         let r = pac::ADC; |         let r = pac::ADC; | ||||||
|         r.cs().write_set(|w| w.set_ts_en(true)); |         r.cs().write_set(|w| w.set_ts_en(true)); | ||||||
| @@ -83,35 +88,44 @@ impl<'p> Drop for Source<'p> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// ADC sample. | ||||||
| #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)] | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)] | ||||||
| #[cfg_attr(feature = "defmt", derive(defmt::Format))] | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||||||
| #[repr(transparent)] | #[repr(transparent)] | ||||||
| pub struct Sample(u16); | pub struct Sample(u16); | ||||||
|  |  | ||||||
| impl Sample { | impl Sample { | ||||||
|  |     /// Sample is valid. | ||||||
|     pub fn good(&self) -> bool { |     pub fn good(&self) -> bool { | ||||||
|         self.0 < 0x8000 |         self.0 < 0x8000 | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Sample value. | ||||||
|     pub fn value(&self) -> u16 { |     pub fn value(&self) -> u16 { | ||||||
|         self.0 & !0x8000 |         self.0 & !0x8000 | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// ADC error. | ||||||
| #[derive(Debug, Eq, PartialEq, Copy, Clone)] | #[derive(Debug, Eq, PartialEq, Copy, Clone)] | ||||||
| #[cfg_attr(feature = "defmt", derive(defmt::Format))] | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||||||
| pub enum Error { | pub enum Error { | ||||||
|  |     /// Error converting value. | ||||||
|     ConversionFailed, |     ConversionFailed, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// ADC mode. | ||||||
| pub trait Mode {} | pub trait Mode {} | ||||||
|  |  | ||||||
|  | /// ADC async mode. | ||||||
| pub struct Async; | pub struct Async; | ||||||
| impl Mode for Async {} | impl Mode for Async {} | ||||||
|  |  | ||||||
|  | /// ADC blocking mode. | ||||||
| pub struct Blocking; | pub struct Blocking; | ||||||
| impl Mode for Blocking {} | impl Mode for Blocking {} | ||||||
|  |  | ||||||
|  | /// ADC driver. | ||||||
| pub struct Adc<'d, M: Mode> { | pub struct Adc<'d, M: Mode> { | ||||||
|     phantom: PhantomData<(&'d ADC, M)>, |     phantom: PhantomData<(&'d ADC, M)>, | ||||||
| } | } | ||||||
| @@ -150,6 +164,7 @@ impl<'d, M: Mode> Adc<'d, M> { | |||||||
|         while !r.cs().read().ready() {} |         while !r.cs().read().ready() {} | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Sample a value from a channel in blocking mode. | ||||||
|     pub fn blocking_read(&mut self, ch: &mut Channel) -> Result<u16, Error> { |     pub fn blocking_read(&mut self, ch: &mut Channel) -> Result<u16, Error> { | ||||||
|         let r = Self::regs(); |         let r = Self::regs(); | ||||||
|         r.cs().modify(|w| { |         r.cs().modify(|w| { | ||||||
| @@ -166,6 +181,7 @@ impl<'d, M: Mode> Adc<'d, M> { | |||||||
| } | } | ||||||
|  |  | ||||||
| impl<'d> Adc<'d, Async> { | impl<'d> Adc<'d, Async> { | ||||||
|  |     /// Create ADC driver in async mode. | ||||||
|     pub fn new( |     pub fn new( | ||||||
|         _inner: impl Peripheral<P = ADC> + 'd, |         _inner: impl Peripheral<P = ADC> + 'd, | ||||||
|         _irq: impl Binding<interrupt::typelevel::ADC_IRQ_FIFO, InterruptHandler>, |         _irq: impl Binding<interrupt::typelevel::ADC_IRQ_FIFO, InterruptHandler>, | ||||||
| @@ -194,6 +210,7 @@ impl<'d> Adc<'d, Async> { | |||||||
|         .await; |         .await; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Sample a value from a channel until completed. | ||||||
|     pub async fn read(&mut self, ch: &mut Channel<'_>) -> Result<u16, Error> { |     pub async fn read(&mut self, ch: &mut Channel<'_>) -> Result<u16, Error> { | ||||||
|         let r = Self::regs(); |         let r = Self::regs(); | ||||||
|         r.cs().modify(|w| { |         r.cs().modify(|w| { | ||||||
| @@ -272,6 +289,7 @@ impl<'d> Adc<'d, Async> { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Sample multiple values from a channel using DMA. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub async fn read_many<S: AdcSample>( |     pub async fn read_many<S: AdcSample>( | ||||||
|         &mut self, |         &mut self, | ||||||
| @@ -283,6 +301,7 @@ impl<'d> Adc<'d, Async> { | |||||||
|         self.read_many_inner(ch, buf, false, div, dma).await |         self.read_many_inner(ch, buf, false, div, dma).await | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Sample multiple values from a channel using DMA with errors inlined in samples. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub async fn read_many_raw( |     pub async fn read_many_raw( | ||||||
|         &mut self, |         &mut self, | ||||||
| @@ -299,6 +318,7 @@ impl<'d> Adc<'d, Async> { | |||||||
| } | } | ||||||
|  |  | ||||||
| impl<'d> Adc<'d, Blocking> { | impl<'d> Adc<'d, Blocking> { | ||||||
|  |     /// Create ADC driver in blocking mode. | ||||||
|     pub fn new_blocking(_inner: impl Peripheral<P = ADC> + 'd, _config: Config) -> Self { |     pub fn new_blocking(_inner: impl Peripheral<P = ADC> + 'd, _config: Config) -> Self { | ||||||
|         Self::setup(); |         Self::setup(); | ||||||
|  |  | ||||||
| @@ -306,6 +326,7 @@ impl<'d> Adc<'d, Blocking> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Interrupt handler. | ||||||
| pub struct InterruptHandler { | pub struct InterruptHandler { | ||||||
|     _empty: (), |     _empty: (), | ||||||
| } | } | ||||||
| @@ -324,6 +345,7 @@ mod sealed { | |||||||
|     pub trait AdcChannel {} |     pub trait AdcChannel {} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// ADC sample. | ||||||
| pub trait AdcSample: sealed::AdcSample {} | pub trait AdcSample: sealed::AdcSample {} | ||||||
|  |  | ||||||
| impl sealed::AdcSample for u16 {} | impl sealed::AdcSample for u16 {} | ||||||
| @@ -332,7 +354,9 @@ impl AdcSample for u16 {} | |||||||
| impl sealed::AdcSample for u8 {} | impl sealed::AdcSample for u8 {} | ||||||
| impl AdcSample for u8 {} | impl AdcSample for u8 {} | ||||||
|  |  | ||||||
|  | /// ADC channel. | ||||||
| pub trait AdcChannel: sealed::AdcChannel {} | pub trait AdcChannel: sealed::AdcChannel {} | ||||||
|  | /// ADC pin. | ||||||
| pub trait AdcPin: AdcChannel + gpio::Pin {} | pub trait AdcPin: AdcChannel + gpio::Pin {} | ||||||
|  |  | ||||||
| macro_rules! impl_pin { | macro_rules! impl_pin { | ||||||
|   | |||||||
| @@ -45,15 +45,20 @@ static CLOCKS: Clocks = Clocks { | |||||||
|     rtc: AtomicU16::new(0), |     rtc: AtomicU16::new(0), | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /// Enumeration of supported clock sources. | /// Peripheral clock sources. | ||||||
| #[repr(u8)] | #[repr(u8)] | ||||||
| #[non_exhaustive] | #[non_exhaustive] | ||||||
| #[derive(Clone, Copy, Debug, PartialEq, Eq)] | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||||||
| pub enum PeriClkSrc { | pub enum PeriClkSrc { | ||||||
|  |     /// SYS. | ||||||
|     Sys = ClkPeriCtrlAuxsrc::CLK_SYS as _, |     Sys = ClkPeriCtrlAuxsrc::CLK_SYS as _, | ||||||
|  |     /// PLL SYS. | ||||||
|     PllSys = ClkPeriCtrlAuxsrc::CLKSRC_PLL_SYS as _, |     PllSys = ClkPeriCtrlAuxsrc::CLKSRC_PLL_SYS as _, | ||||||
|  |     /// PLL USB. | ||||||
|     PllUsb = ClkPeriCtrlAuxsrc::CLKSRC_PLL_USB as _, |     PllUsb = ClkPeriCtrlAuxsrc::CLKSRC_PLL_USB as _, | ||||||
|  |     /// ROSC. | ||||||
|     Rosc = ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH as _, |     Rosc = ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH as _, | ||||||
|  |     /// XOSC. | ||||||
|     Xosc = ClkPeriCtrlAuxsrc::XOSC_CLKSRC as _, |     Xosc = ClkPeriCtrlAuxsrc::XOSC_CLKSRC as _, | ||||||
|     // Gpin0 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN0 as _ , |     // Gpin0 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN0 as _ , | ||||||
|     // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ , |     // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ , | ||||||
| @@ -83,6 +88,7 @@ pub struct ClockConfig { | |||||||
| } | } | ||||||
|  |  | ||||||
| impl ClockConfig { | impl ClockConfig { | ||||||
|  |     /// Clock configuration derived from external crystal. | ||||||
|     pub fn crystal(crystal_hz: u32) -> Self { |     pub fn crystal(crystal_hz: u32) -> Self { | ||||||
|         Self { |         Self { | ||||||
|             rosc: Some(RoscConfig { |             rosc: Some(RoscConfig { | ||||||
| @@ -141,6 +147,7 @@ impl ClockConfig { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Clock configuration from internal oscillator. | ||||||
|     pub fn rosc() -> Self { |     pub fn rosc() -> Self { | ||||||
|         Self { |         Self { | ||||||
|             rosc: Some(RoscConfig { |             rosc: Some(RoscConfig { | ||||||
| @@ -190,13 +197,18 @@ impl ClockConfig { | |||||||
|     // } |     // } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// ROSC freq range. | ||||||
| #[repr(u16)] | #[repr(u16)] | ||||||
| #[non_exhaustive] | #[non_exhaustive] | ||||||
| #[derive(Clone, Copy, Debug, PartialEq, Eq)] | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||||||
| pub enum RoscRange { | pub enum RoscRange { | ||||||
|  |     /// Low range. | ||||||
|     Low = pac::rosc::vals::FreqRange::LOW.0, |     Low = pac::rosc::vals::FreqRange::LOW.0, | ||||||
|  |     /// Medium range (1.33x low) | ||||||
|     Medium = pac::rosc::vals::FreqRange::MEDIUM.0, |     Medium = pac::rosc::vals::FreqRange::MEDIUM.0, | ||||||
|  |     /// High range (2x low) | ||||||
|     High = pac::rosc::vals::FreqRange::HIGH.0, |     High = pac::rosc::vals::FreqRange::HIGH.0, | ||||||
|  |     /// Too high. Should not be used. | ||||||
|     TooHigh = pac::rosc::vals::FreqRange::TOOHIGH.0, |     TooHigh = pac::rosc::vals::FreqRange::TOOHIGH.0, | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -239,96 +251,136 @@ pub struct PllConfig { | |||||||
|     pub post_div2: u8, |     pub post_div2: u8, | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Reference | /// Reference clock config. | ||||||
| pub struct RefClkConfig { | pub struct RefClkConfig { | ||||||
|  |     /// Reference clock source. | ||||||
|     pub src: RefClkSrc, |     pub src: RefClkSrc, | ||||||
|  |     /// Reference clock divider. | ||||||
|     pub div: u8, |     pub div: u8, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Reference clock source. | ||||||
| #[non_exhaustive] | #[non_exhaustive] | ||||||
| #[derive(Clone, Copy, Debug, PartialEq, Eq)] | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||||||
| pub enum RefClkSrc { | pub enum RefClkSrc { | ||||||
|     // main sources |     /// XOSC. | ||||||
|     Xosc, |     Xosc, | ||||||
|  |     /// ROSC. | ||||||
|     Rosc, |     Rosc, | ||||||
|     // aux sources |     /// PLL USB. | ||||||
|     PllUsb, |     PllUsb, | ||||||
|     // Gpin0, |     // Gpin0, | ||||||
|     // Gpin1, |     // Gpin1, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// SYS clock source. | ||||||
| #[non_exhaustive] | #[non_exhaustive] | ||||||
| #[derive(Clone, Copy, Debug, PartialEq, Eq)] | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||||||
| pub enum SysClkSrc { | pub enum SysClkSrc { | ||||||
|     // main sources |     /// REF. | ||||||
|     Ref, |     Ref, | ||||||
|     // aux sources |     /// PLL SYS. | ||||||
|     PllSys, |     PllSys, | ||||||
|  |     /// PLL USB. | ||||||
|     PllUsb, |     PllUsb, | ||||||
|  |     /// ROSC. | ||||||
|     Rosc, |     Rosc, | ||||||
|  |     /// XOSC. | ||||||
|     Xosc, |     Xosc, | ||||||
|     // Gpin0, |     // Gpin0, | ||||||
|     // Gpin1, |     // Gpin1, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// SYS clock config. | ||||||
| pub struct SysClkConfig { | pub struct SysClkConfig { | ||||||
|  |     /// SYS clock source. | ||||||
|     pub src: SysClkSrc, |     pub src: SysClkSrc, | ||||||
|  |     /// SYS clock divider. | ||||||
|     pub div_int: u32, |     pub div_int: u32, | ||||||
|  |     /// SYS clock fraction. | ||||||
|     pub div_frac: u8, |     pub div_frac: u8, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// USB clock source. | ||||||
| #[repr(u8)] | #[repr(u8)] | ||||||
| #[non_exhaustive] | #[non_exhaustive] | ||||||
| #[derive(Clone, Copy, Debug, PartialEq, Eq)] | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||||||
| pub enum UsbClkSrc { | pub enum UsbClkSrc { | ||||||
|  |     /// PLL USB. | ||||||
|     PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB as _, |     PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB as _, | ||||||
|  |     /// PLL SYS. | ||||||
|     PllSys = ClkUsbCtrlAuxsrc::CLKSRC_PLL_SYS as _, |     PllSys = ClkUsbCtrlAuxsrc::CLKSRC_PLL_SYS as _, | ||||||
|  |     /// ROSC. | ||||||
|     Rosc = ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH as _, |     Rosc = ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH as _, | ||||||
|  |     /// XOSC. | ||||||
|     Xosc = ClkUsbCtrlAuxsrc::XOSC_CLKSRC as _, |     Xosc = ClkUsbCtrlAuxsrc::XOSC_CLKSRC as _, | ||||||
|     // Gpin0 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN0 as _ , |     // Gpin0 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN0 as _ , | ||||||
|     // Gpin1 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN1 as _ , |     // Gpin1 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN1 as _ , | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// USB clock config. | ||||||
| pub struct UsbClkConfig { | pub struct UsbClkConfig { | ||||||
|  |     /// USB clock source. | ||||||
|     pub src: UsbClkSrc, |     pub src: UsbClkSrc, | ||||||
|  |     /// USB clock divider. | ||||||
|     pub div: u8, |     pub div: u8, | ||||||
|  |     /// USB clock phase. | ||||||
|     pub phase: u8, |     pub phase: u8, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// ADC clock source. | ||||||
| #[repr(u8)] | #[repr(u8)] | ||||||
| #[non_exhaustive] | #[non_exhaustive] | ||||||
| #[derive(Clone, Copy, Debug, PartialEq, Eq)] | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||||||
| pub enum AdcClkSrc { | pub enum AdcClkSrc { | ||||||
|  |     /// PLL USB. | ||||||
|     PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB as _, |     PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB as _, | ||||||
|  |     /// PLL SYS. | ||||||
|     PllSys = ClkAdcCtrlAuxsrc::CLKSRC_PLL_SYS as _, |     PllSys = ClkAdcCtrlAuxsrc::CLKSRC_PLL_SYS as _, | ||||||
|  |     /// ROSC. | ||||||
|     Rosc = ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH as _, |     Rosc = ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH as _, | ||||||
|  |     /// XOSC. | ||||||
|     Xosc = ClkAdcCtrlAuxsrc::XOSC_CLKSRC as _, |     Xosc = ClkAdcCtrlAuxsrc::XOSC_CLKSRC as _, | ||||||
|     // Gpin0 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN0 as _ , |     // Gpin0 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN0 as _ , | ||||||
|     // Gpin1 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN1 as _ , |     // Gpin1 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN1 as _ , | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// ADC clock config. | ||||||
| pub struct AdcClkConfig { | pub struct AdcClkConfig { | ||||||
|  |     /// ADC clock source. | ||||||
|     pub src: AdcClkSrc, |     pub src: AdcClkSrc, | ||||||
|  |     /// ADC clock divider. | ||||||
|     pub div: u8, |     pub div: u8, | ||||||
|  |     /// ADC clock phase. | ||||||
|     pub phase: u8, |     pub phase: u8, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// RTC clock source. | ||||||
| #[repr(u8)] | #[repr(u8)] | ||||||
| #[non_exhaustive] | #[non_exhaustive] | ||||||
| #[derive(Clone, Copy, Debug, PartialEq, Eq)] | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||||||
| pub enum RtcClkSrc { | pub enum RtcClkSrc { | ||||||
|  |     /// PLL USB. | ||||||
|     PllUsb = ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB as _, |     PllUsb = ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB as _, | ||||||
|  |     /// PLL SYS. | ||||||
|     PllSys = ClkRtcCtrlAuxsrc::CLKSRC_PLL_SYS as _, |     PllSys = ClkRtcCtrlAuxsrc::CLKSRC_PLL_SYS as _, | ||||||
|  |     /// ROSC. | ||||||
|     Rosc = ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH as _, |     Rosc = ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH as _, | ||||||
|  |     /// XOSC. | ||||||
|     Xosc = ClkRtcCtrlAuxsrc::XOSC_CLKSRC as _, |     Xosc = ClkRtcCtrlAuxsrc::XOSC_CLKSRC as _, | ||||||
|     // Gpin0 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN0 as _ , |     // Gpin0 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN0 as _ , | ||||||
|     // Gpin1 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN1 as _ , |     // Gpin1 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN1 as _ , | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// RTC clock config. | ||||||
| pub struct RtcClkConfig { | pub struct RtcClkConfig { | ||||||
|  |     /// RTC clock source. | ||||||
|     pub src: RtcClkSrc, |     pub src: RtcClkSrc, | ||||||
|  |     /// RTC clock divider. | ||||||
|     pub div_int: u32, |     pub div_int: u32, | ||||||
|  |     /// RTC clock divider fraction. | ||||||
|     pub div_frac: u8, |     pub div_frac: u8, | ||||||
|  |     /// RTC clock phase. | ||||||
|     pub phase: u8, |     pub phase: u8, | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -605,10 +657,12 @@ fn configure_rosc(config: RoscConfig) -> u32 { | |||||||
|     config.hz |     config.hz | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// ROSC clock frequency. | ||||||
| pub fn rosc_freq() -> u32 { | pub fn rosc_freq() -> u32 { | ||||||
|     CLOCKS.rosc.load(Ordering::Relaxed) |     CLOCKS.rosc.load(Ordering::Relaxed) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// XOSC clock frequency. | ||||||
| pub fn xosc_freq() -> u32 { | pub fn xosc_freq() -> u32 { | ||||||
|     CLOCKS.xosc.load(Ordering::Relaxed) |     CLOCKS.xosc.load(Ordering::Relaxed) | ||||||
| } | } | ||||||
| @@ -620,34 +674,42 @@ pub fn xosc_freq() -> u32 { | |||||||
| //     CLOCKS.gpin1.load(Ordering::Relaxed) | //     CLOCKS.gpin1.load(Ordering::Relaxed) | ||||||
| // } | // } | ||||||
|  |  | ||||||
|  | /// PLL SYS clock frequency. | ||||||
| pub fn pll_sys_freq() -> u32 { | pub fn pll_sys_freq() -> u32 { | ||||||
|     CLOCKS.pll_sys.load(Ordering::Relaxed) |     CLOCKS.pll_sys.load(Ordering::Relaxed) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// PLL USB clock frequency. | ||||||
| pub fn pll_usb_freq() -> u32 { | pub fn pll_usb_freq() -> u32 { | ||||||
|     CLOCKS.pll_usb.load(Ordering::Relaxed) |     CLOCKS.pll_usb.load(Ordering::Relaxed) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// SYS clock frequency. | ||||||
| pub fn clk_sys_freq() -> u32 { | pub fn clk_sys_freq() -> u32 { | ||||||
|     CLOCKS.sys.load(Ordering::Relaxed) |     CLOCKS.sys.load(Ordering::Relaxed) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// REF clock frequency. | ||||||
| pub fn clk_ref_freq() -> u32 { | pub fn clk_ref_freq() -> u32 { | ||||||
|     CLOCKS.reference.load(Ordering::Relaxed) |     CLOCKS.reference.load(Ordering::Relaxed) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Peripheral clock frequency. | ||||||
| pub fn clk_peri_freq() -> u32 { | pub fn clk_peri_freq() -> u32 { | ||||||
|     CLOCKS.peri.load(Ordering::Relaxed) |     CLOCKS.peri.load(Ordering::Relaxed) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// USB clock frequency. | ||||||
| pub fn clk_usb_freq() -> u32 { | pub fn clk_usb_freq() -> u32 { | ||||||
|     CLOCKS.usb.load(Ordering::Relaxed) |     CLOCKS.usb.load(Ordering::Relaxed) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// ADC clock frequency. | ||||||
| pub fn clk_adc_freq() -> u32 { | pub fn clk_adc_freq() -> u32 { | ||||||
|     CLOCKS.adc.load(Ordering::Relaxed) |     CLOCKS.adc.load(Ordering::Relaxed) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// RTC clock frequency. | ||||||
| pub fn clk_rtc_freq() -> u16 { | pub fn clk_rtc_freq() -> u16 { | ||||||
|     CLOCKS.rtc.load(Ordering::Relaxed) |     CLOCKS.rtc.load(Ordering::Relaxed) | ||||||
| } | } | ||||||
| @@ -708,7 +770,9 @@ fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 { | |||||||
|     vco_freq / ((config.post_div1 * config.post_div2) as u32) |     vco_freq / ((config.post_div1 * config.post_div2) as u32) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// General purpose input clock pin. | ||||||
| pub trait GpinPin: crate::gpio::Pin { | pub trait GpinPin: crate::gpio::Pin { | ||||||
|  |     /// Pin number. | ||||||
|     const NR: usize; |     const NR: usize; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -723,12 +787,14 @@ macro_rules! impl_gpinpin { | |||||||
| impl_gpinpin!(PIN_20, 20, 0); | impl_gpinpin!(PIN_20, 20, 0); | ||||||
| impl_gpinpin!(PIN_22, 22, 1); | impl_gpinpin!(PIN_22, 22, 1); | ||||||
|  |  | ||||||
|  | /// General purpose clock input driver. | ||||||
| pub struct Gpin<'d, T: Pin> { | pub struct Gpin<'d, T: Pin> { | ||||||
|     gpin: PeripheralRef<'d, AnyPin>, |     gpin: PeripheralRef<'d, AnyPin>, | ||||||
|     _phantom: PhantomData<T>, |     _phantom: PhantomData<T>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<'d, T: Pin> Gpin<'d, T> { | impl<'d, T: Pin> Gpin<'d, T> { | ||||||
|  |     /// Create new gpin driver. | ||||||
|     pub fn new<P: GpinPin>(gpin: impl Peripheral<P = P> + 'd) -> Gpin<'d, P> { |     pub fn new<P: GpinPin>(gpin: impl Peripheral<P = P> + 'd) -> Gpin<'d, P> { | ||||||
|         into_ref!(gpin); |         into_ref!(gpin); | ||||||
|  |  | ||||||
| @@ -754,7 +820,9 @@ impl<'d, T: Pin> Drop for Gpin<'d, T> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// General purpose clock output pin. | ||||||
| pub trait GpoutPin: crate::gpio::Pin { | pub trait GpoutPin: crate::gpio::Pin { | ||||||
|  |     /// Pin number. | ||||||
|     fn number(&self) -> usize; |     fn number(&self) -> usize; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -773,26 +841,38 @@ impl_gpoutpin!(PIN_23, 1); | |||||||
| impl_gpoutpin!(PIN_24, 2); | impl_gpoutpin!(PIN_24, 2); | ||||||
| impl_gpoutpin!(PIN_25, 3); | impl_gpoutpin!(PIN_25, 3); | ||||||
|  |  | ||||||
|  | /// Gpout clock source. | ||||||
| #[repr(u8)] | #[repr(u8)] | ||||||
| pub enum GpoutSrc { | pub enum GpoutSrc { | ||||||
|  |     /// Sys PLL. | ||||||
|     PllSys = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS as _, |     PllSys = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS as _, | ||||||
|     // Gpin0 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 as _ , |     // Gpin0 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 as _ , | ||||||
|     // Gpin1 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 as _ , |     // Gpin1 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 as _ , | ||||||
|  |     /// USB PLL. | ||||||
|     PllUsb = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB as _, |     PllUsb = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB as _, | ||||||
|  |     /// ROSC. | ||||||
|     Rosc = ClkGpoutCtrlAuxsrc::ROSC_CLKSRC as _, |     Rosc = ClkGpoutCtrlAuxsrc::ROSC_CLKSRC as _, | ||||||
|  |     /// XOSC. | ||||||
|     Xosc = ClkGpoutCtrlAuxsrc::XOSC_CLKSRC as _, |     Xosc = ClkGpoutCtrlAuxsrc::XOSC_CLKSRC as _, | ||||||
|  |     /// SYS. | ||||||
|     Sys = ClkGpoutCtrlAuxsrc::CLK_SYS as _, |     Sys = ClkGpoutCtrlAuxsrc::CLK_SYS as _, | ||||||
|  |     /// USB. | ||||||
|     Usb = ClkGpoutCtrlAuxsrc::CLK_USB as _, |     Usb = ClkGpoutCtrlAuxsrc::CLK_USB as _, | ||||||
|  |     /// ADC. | ||||||
|     Adc = ClkGpoutCtrlAuxsrc::CLK_ADC as _, |     Adc = ClkGpoutCtrlAuxsrc::CLK_ADC as _, | ||||||
|  |     /// RTC. | ||||||
|     Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC as _, |     Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC as _, | ||||||
|  |     /// REF. | ||||||
|     Ref = ClkGpoutCtrlAuxsrc::CLK_REF as _, |     Ref = ClkGpoutCtrlAuxsrc::CLK_REF as _, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// General purpose clock output driver. | ||||||
| pub struct Gpout<'d, T: GpoutPin> { | pub struct Gpout<'d, T: GpoutPin> { | ||||||
|     gpout: PeripheralRef<'d, T>, |     gpout: PeripheralRef<'d, T>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<'d, T: GpoutPin> Gpout<'d, T> { | impl<'d, T: GpoutPin> Gpout<'d, T> { | ||||||
|  |     /// Create new general purpose cloud output. | ||||||
|     pub fn new(gpout: impl Peripheral<P = T> + 'd) -> Self { |     pub fn new(gpout: impl Peripheral<P = T> + 'd) -> Self { | ||||||
|         into_ref!(gpout); |         into_ref!(gpout); | ||||||
|  |  | ||||||
| @@ -801,6 +881,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { | |||||||
|         Self { gpout } |         Self { gpout } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Set clock divider. | ||||||
|     pub fn set_div(&self, int: u32, frac: u8) { |     pub fn set_div(&self, int: u32, frac: u8) { | ||||||
|         let c = pac::CLOCKS; |         let c = pac::CLOCKS; | ||||||
|         c.clk_gpout_div(self.gpout.number()).write(|w| { |         c.clk_gpout_div(self.gpout.number()).write(|w| { | ||||||
| @@ -809,6 +890,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { | |||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Set clock source. | ||||||
|     pub fn set_src(&self, src: GpoutSrc) { |     pub fn set_src(&self, src: GpoutSrc) { | ||||||
|         let c = pac::CLOCKS; |         let c = pac::CLOCKS; | ||||||
|         c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { |         c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { | ||||||
| @@ -816,6 +898,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { | |||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Enable clock. | ||||||
|     pub fn enable(&self) { |     pub fn enable(&self) { | ||||||
|         let c = pac::CLOCKS; |         let c = pac::CLOCKS; | ||||||
|         c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { |         c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { | ||||||
| @@ -823,6 +906,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { | |||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Disable clock. | ||||||
|     pub fn disable(&self) { |     pub fn disable(&self) { | ||||||
|         let c = pac::CLOCKS; |         let c = pac::CLOCKS; | ||||||
|         c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { |         c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { | ||||||
| @@ -830,6 +914,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { | |||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Clock frequency. | ||||||
|     pub fn get_freq(&self) -> u32 { |     pub fn get_freq(&self) -> u32 { | ||||||
|         let c = pac::CLOCKS; |         let c = pac::CLOCKS; | ||||||
|         let src = c.clk_gpout_ctrl(self.gpout.number()).read().auxsrc(); |         let src = c.clk_gpout_ctrl(self.gpout.number()).read().auxsrc(); | ||||||
|   | |||||||
| @@ -38,6 +38,9 @@ pub(crate) unsafe fn init() { | |||||||
|     interrupt::DMA_IRQ_0.enable(); |     interrupt::DMA_IRQ_0.enable(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// DMA read. | ||||||
|  | /// | ||||||
|  | /// SAFETY: Slice must point to a valid location reachable by DMA. | ||||||
| pub unsafe fn read<'a, C: Channel, W: Word>( | pub unsafe fn read<'a, C: Channel, W: Word>( | ||||||
|     ch: impl Peripheral<P = C> + 'a, |     ch: impl Peripheral<P = C> + 'a, | ||||||
|     from: *const W, |     from: *const W, | ||||||
| @@ -57,6 +60,9 @@ pub unsafe fn read<'a, C: Channel, W: Word>( | |||||||
|     ) |     ) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// DMA write. | ||||||
|  | /// | ||||||
|  | /// SAFETY: Slice must point to a valid location reachable by DMA. | ||||||
| pub unsafe fn write<'a, C: Channel, W: Word>( | pub unsafe fn write<'a, C: Channel, W: Word>( | ||||||
|     ch: impl Peripheral<P = C> + 'a, |     ch: impl Peripheral<P = C> + 'a, | ||||||
|     from: *const [W], |     from: *const [W], | ||||||
| @@ -79,6 +85,9 @@ pub unsafe fn write<'a, C: Channel, W: Word>( | |||||||
| // static mut so that this is allocated in RAM. | // static mut so that this is allocated in RAM. | ||||||
| static mut DUMMY: u32 = 0; | static mut DUMMY: u32 = 0; | ||||||
|  |  | ||||||
|  | /// DMA repeated write. | ||||||
|  | /// | ||||||
|  | /// SAFETY: Slice must point to a valid location reachable by DMA. | ||||||
| pub unsafe fn write_repeated<'a, C: Channel, W: Word>( | pub unsafe fn write_repeated<'a, C: Channel, W: Word>( | ||||||
|     ch: impl Peripheral<P = C> + 'a, |     ch: impl Peripheral<P = C> + 'a, | ||||||
|     to: *mut W, |     to: *mut W, | ||||||
| @@ -97,6 +106,9 @@ pub unsafe fn write_repeated<'a, C: Channel, W: Word>( | |||||||
|     ) |     ) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// DMA copy between slices. | ||||||
|  | /// | ||||||
|  | /// SAFETY: Slices must point to locations reachable by DMA. | ||||||
| pub unsafe fn copy<'a, C: Channel, W: Word>( | pub unsafe fn copy<'a, C: Channel, W: Word>( | ||||||
|     ch: impl Peripheral<P = C> + 'a, |     ch: impl Peripheral<P = C> + 'a, | ||||||
|     from: &[W], |     from: &[W], | ||||||
| @@ -152,6 +164,7 @@ fn copy_inner<'a, C: Channel>( | |||||||
|     Transfer::new(ch) |     Transfer::new(ch) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// DMA transfer driver. | ||||||
| #[must_use = "futures do nothing unless you `.await` or poll them"] | #[must_use = "futures do nothing unless you `.await` or poll them"] | ||||||
| pub struct Transfer<'a, C: Channel> { | pub struct Transfer<'a, C: Channel> { | ||||||
|     channel: PeripheralRef<'a, C>, |     channel: PeripheralRef<'a, C>, | ||||||
| @@ -201,19 +214,25 @@ mod sealed { | |||||||
|     pub trait Word {} |     pub trait Word {} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// DMA channel interface. | ||||||
| pub trait Channel: Peripheral<P = Self> + sealed::Channel + Into<AnyChannel> + Sized + 'static { | pub trait Channel: Peripheral<P = Self> + sealed::Channel + Into<AnyChannel> + Sized + 'static { | ||||||
|  |     /// Channel number. | ||||||
|     fn number(&self) -> u8; |     fn number(&self) -> u8; | ||||||
|  |  | ||||||
|  |     /// Channel registry block. | ||||||
|     fn regs(&self) -> pac::dma::Channel { |     fn regs(&self) -> pac::dma::Channel { | ||||||
|         pac::DMA.ch(self.number() as _) |         pac::DMA.ch(self.number() as _) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Convert into type-erased [AnyChannel]. | ||||||
|     fn degrade(self) -> AnyChannel { |     fn degrade(self) -> AnyChannel { | ||||||
|         AnyChannel { number: self.number() } |         AnyChannel { number: self.number() } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// DMA word. | ||||||
| pub trait Word: sealed::Word { | pub trait Word: sealed::Word { | ||||||
|  |     /// Word size. | ||||||
|     fn size() -> vals::DataSize; |     fn size() -> vals::DataSize; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -238,6 +257,7 @@ impl Word for u32 { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Type erased DMA channel. | ||||||
| pub struct AnyChannel { | pub struct AnyChannel { | ||||||
|     number: u8, |     number: u8, | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | //! Flash driver. | ||||||
| use core::future::Future; | use core::future::Future; | ||||||
| use core::marker::PhantomData; | use core::marker::PhantomData; | ||||||
| use core::pin::Pin; | use core::pin::Pin; | ||||||
| @@ -13,9 +14,10 @@ use crate::dma::{AnyChannel, Channel, Transfer}; | |||||||
| use crate::pac; | use crate::pac; | ||||||
| use crate::peripherals::FLASH; | use crate::peripherals::FLASH; | ||||||
|  |  | ||||||
|  | /// Flash base address. | ||||||
| pub const FLASH_BASE: *const u32 = 0x10000000 as _; | pub const FLASH_BASE: *const u32 = 0x10000000 as _; | ||||||
|  |  | ||||||
| // If running from RAM, we might have no boot2. Use bootrom `flash_enter_cmd_xip` instead. | /// If running from RAM, we might have no boot2. Use bootrom `flash_enter_cmd_xip` instead. | ||||||
| // TODO: when run-from-ram is set, completely skip the "pause cores and jumpp to RAM" dance. | // TODO: when run-from-ram is set, completely skip the "pause cores and jumpp to RAM" dance. | ||||||
| pub const USE_BOOT2: bool = !cfg!(feature = "run-from-ram"); | pub const USE_BOOT2: bool = !cfg!(feature = "run-from-ram"); | ||||||
|  |  | ||||||
| @@ -24,10 +26,15 @@ pub const USE_BOOT2: bool = !cfg!(feature = "run-from-ram"); | |||||||
| // These limitations are currently enforced because of using the | // These limitations are currently enforced because of using the | ||||||
| // RP2040 boot-rom flash functions, that are optimized for flash compatibility | // RP2040 boot-rom flash functions, that are optimized for flash compatibility | ||||||
| // rather than performance. | // rather than performance. | ||||||
|  | /// Flash page size. | ||||||
| pub const PAGE_SIZE: usize = 256; | pub const PAGE_SIZE: usize = 256; | ||||||
|  | /// Flash write size. | ||||||
| pub const WRITE_SIZE: usize = 1; | pub const WRITE_SIZE: usize = 1; | ||||||
|  | /// Flash read size. | ||||||
| pub const READ_SIZE: usize = 1; | pub const READ_SIZE: usize = 1; | ||||||
|  | /// Flash erase size. | ||||||
| pub const ERASE_SIZE: usize = 4096; | pub const ERASE_SIZE: usize = 4096; | ||||||
|  | /// Flash DMA read size. | ||||||
| pub const ASYNC_READ_SIZE: usize = 4; | pub const ASYNC_READ_SIZE: usize = 4; | ||||||
|  |  | ||||||
| /// Error type for NVMC operations. | /// Error type for NVMC operations. | ||||||
| @@ -38,7 +45,9 @@ pub enum Error { | |||||||
|     OutOfBounds, |     OutOfBounds, | ||||||
|     /// Unaligned operation or using unaligned buffers. |     /// Unaligned operation or using unaligned buffers. | ||||||
|     Unaligned, |     Unaligned, | ||||||
|  |     /// Accessed from the wrong core. | ||||||
|     InvalidCore, |     InvalidCore, | ||||||
|  |     /// Other error | ||||||
|     Other, |     Other, | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -96,12 +105,18 @@ impl<'a, 'd, T: Instance, const FLASH_SIZE: usize> Drop for BackgroundRead<'a, ' | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Flash driver. | ||||||
| pub struct Flash<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> { | pub struct Flash<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> { | ||||||
|     dma: Option<PeripheralRef<'d, AnyChannel>>, |     dma: Option<PeripheralRef<'d, AnyChannel>>, | ||||||
|     phantom: PhantomData<(&'d mut T, M)>, |     phantom: PhantomData<(&'d mut T, M)>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SIZE> { | impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SIZE> { | ||||||
|  |     /// Blocking read. | ||||||
|  |     /// | ||||||
|  |     /// The offset and buffer must be aligned. | ||||||
|  |     /// | ||||||
|  |     /// NOTE: `offset` is an offset from the flash start, NOT an absolute address. | ||||||
|     pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { |     pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { | ||||||
|         trace!( |         trace!( | ||||||
|             "Reading from 0x{:x} to 0x{:x}", |             "Reading from 0x{:x} to 0x{:x}", | ||||||
| @@ -116,10 +131,14 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI | |||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Flash capacity. | ||||||
|     pub fn capacity(&self) -> usize { |     pub fn capacity(&self) -> usize { | ||||||
|         FLASH_SIZE |         FLASH_SIZE | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Blocking erase. | ||||||
|  |     /// | ||||||
|  |     /// NOTE: `offset` is an offset from the flash start, NOT an absolute address. | ||||||
|     pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { |     pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { | ||||||
|         check_erase(self, from, to)?; |         check_erase(self, from, to)?; | ||||||
|  |  | ||||||
| @@ -136,6 +155,11 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI | |||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Blocking write. | ||||||
|  |     /// | ||||||
|  |     /// The offset and buffer must be aligned. | ||||||
|  |     /// | ||||||
|  |     /// NOTE: `offset` is an offset from the flash start, NOT an absolute address. | ||||||
|     pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { |     pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { | ||||||
|         check_write(self, offset, bytes.len())?; |         check_write(self, offset, bytes.len())?; | ||||||
|  |  | ||||||
| @@ -219,6 +243,7 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI | |||||||
| } | } | ||||||
|  |  | ||||||
| impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Blocking, FLASH_SIZE> { | impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Blocking, FLASH_SIZE> { | ||||||
|  |     /// Create a new flash driver in blocking mode. | ||||||
|     pub fn new_blocking(_flash: impl Peripheral<P = T> + 'd) -> Self { |     pub fn new_blocking(_flash: impl Peripheral<P = T> + 'd) -> Self { | ||||||
|         Self { |         Self { | ||||||
|             dma: None, |             dma: None, | ||||||
| @@ -228,6 +253,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Blocking, FLASH_SIZE | |||||||
| } | } | ||||||
|  |  | ||||||
| impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> { | impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> { | ||||||
|  |     /// Create a new flash driver in async mode. | ||||||
|     pub fn new(_flash: impl Peripheral<P = T> + 'd, dma: impl Peripheral<P = impl Channel> + 'd) -> Self { |     pub fn new(_flash: impl Peripheral<P = T> + 'd, dma: impl Peripheral<P = impl Channel> + 'd) -> Self { | ||||||
|         into_ref!(dma); |         into_ref!(dma); | ||||||
|         Self { |         Self { | ||||||
| @@ -236,6 +262,11 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Start a background read operation. | ||||||
|  |     /// | ||||||
|  |     /// The offset and buffer must be aligned. | ||||||
|  |     /// | ||||||
|  |     /// NOTE: `offset` is an offset from the flash start, NOT an absolute address. | ||||||
|     pub fn background_read<'a>( |     pub fn background_read<'a>( | ||||||
|         &'a mut self, |         &'a mut self, | ||||||
|         offset: u32, |         offset: u32, | ||||||
| @@ -279,6 +310,11 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> { | |||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Async read. | ||||||
|  |     /// | ||||||
|  |     /// The offset and buffer must be aligned. | ||||||
|  |     /// | ||||||
|  |     /// NOTE: `offset` is an offset from the flash start, NOT an absolute address. | ||||||
|     pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { |     pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { | ||||||
|         use core::mem::MaybeUninit; |         use core::mem::MaybeUninit; | ||||||
|  |  | ||||||
| @@ -874,7 +910,9 @@ mod sealed { | |||||||
|     pub trait Mode {} |     pub trait Mode {} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Flash instance. | ||||||
| pub trait Instance: sealed::Instance {} | pub trait Instance: sealed::Instance {} | ||||||
|  | /// Flash mode. | ||||||
| pub trait Mode: sealed::Mode {} | pub trait Mode: sealed::Mode {} | ||||||
|  |  | ||||||
| impl sealed::Instance for FLASH {} | impl sealed::Instance for FLASH {} | ||||||
| @@ -887,7 +925,9 @@ macro_rules! impl_mode { | |||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Flash blocking mode. | ||||||
| pub struct Blocking; | pub struct Blocking; | ||||||
|  | /// Flash async mode. | ||||||
| pub struct Async; | pub struct Async; | ||||||
|  |  | ||||||
| impl_mode!(Blocking); | impl_mode!(Blocking); | ||||||
|   | |||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | //! GPIO driver. | ||||||
| #![macro_use] | #![macro_use] | ||||||
| use core::convert::Infallible; | use core::convert::Infallible; | ||||||
| use core::future::Future; | use core::future::Future; | ||||||
| @@ -23,7 +24,9 @@ static QSPI_WAKERS: [AtomicWaker; QSPI_PIN_COUNT] = [NEW_AW; QSPI_PIN_COUNT]; | |||||||
| /// Represents a digital input or output level. | /// Represents a digital input or output level. | ||||||
| #[derive(Debug, Eq, PartialEq, Clone, Copy)] | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | ||||||
| pub enum Level { | pub enum Level { | ||||||
|  |     /// Logical low. | ||||||
|     Low, |     Low, | ||||||
|  |     /// Logical high. | ||||||
|     High, |     High, | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -48,48 +51,66 @@ impl From<Level> for bool { | |||||||
| /// Represents a pull setting for an input. | /// Represents a pull setting for an input. | ||||||
| #[derive(Debug, Clone, Copy, Eq, PartialEq)] | #[derive(Debug, Clone, Copy, Eq, PartialEq)] | ||||||
| pub enum Pull { | pub enum Pull { | ||||||
|  |     /// No pull. | ||||||
|     None, |     None, | ||||||
|  |     /// Internal pull-up resistor. | ||||||
|     Up, |     Up, | ||||||
|  |     /// Internal pull-down resistor. | ||||||
|     Down, |     Down, | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Drive strength of an output | /// Drive strength of an output | ||||||
| #[derive(Debug, Eq, PartialEq)] | #[derive(Debug, Eq, PartialEq)] | ||||||
| pub enum Drive { | pub enum Drive { | ||||||
|  |     /// 2 mA drive. | ||||||
|     _2mA, |     _2mA, | ||||||
|  |     /// 4 mA drive. | ||||||
|     _4mA, |     _4mA, | ||||||
|  |     /// 8 mA drive. | ||||||
|     _8mA, |     _8mA, | ||||||
|  |     /// 1 2mA drive. | ||||||
|     _12mA, |     _12mA, | ||||||
| } | } | ||||||
| /// Slew rate of an output | /// Slew rate of an output | ||||||
| #[derive(Debug, Eq, PartialEq)] | #[derive(Debug, Eq, PartialEq)] | ||||||
| pub enum SlewRate { | pub enum SlewRate { | ||||||
|  |     /// Fast slew rate. | ||||||
|     Fast, |     Fast, | ||||||
|  |     /// Slow slew rate. | ||||||
|     Slow, |     Slow, | ||||||
| } | } | ||||||
|  |  | ||||||
| /// A GPIO bank with up to 32 pins. | /// A GPIO bank with up to 32 pins. | ||||||
| #[derive(Debug, Eq, PartialEq)] | #[derive(Debug, Eq, PartialEq)] | ||||||
| pub enum Bank { | pub enum Bank { | ||||||
|  |     /// Bank 0. | ||||||
|     Bank0 = 0, |     Bank0 = 0, | ||||||
|  |     /// QSPI. | ||||||
|     #[cfg(feature = "qspi-as-gpio")] |     #[cfg(feature = "qspi-as-gpio")] | ||||||
|     Qspi = 1, |     Qspi = 1, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Dormant mode config. | ||||||
| #[derive(Debug, Eq, PartialEq, Copy, Clone, Default)] | #[derive(Debug, Eq, PartialEq, Copy, Clone, Default)] | ||||||
| #[cfg_attr(feature = "defmt", derive(defmt::Format))] | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||||||
| pub struct DormantWakeConfig { | pub struct DormantWakeConfig { | ||||||
|  |     /// Wake on edge high. | ||||||
|     pub edge_high: bool, |     pub edge_high: bool, | ||||||
|  |     /// Wake on edge low. | ||||||
|     pub edge_low: bool, |     pub edge_low: bool, | ||||||
|  |     /// Wake on level high. | ||||||
|     pub level_high: bool, |     pub level_high: bool, | ||||||
|  |     /// Wake on level low. | ||||||
|     pub level_low: bool, |     pub level_low: bool, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// GPIO input driver. | ||||||
| pub struct Input<'d, T: Pin> { | pub struct Input<'d, T: Pin> { | ||||||
|     pin: Flex<'d, T>, |     pin: Flex<'d, T>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<'d, T: Pin> Input<'d, T> { | impl<'d, T: Pin> Input<'d, T> { | ||||||
|  |     /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn new(pin: impl Peripheral<P = T> + 'd, pull: Pull) -> Self { |     pub fn new(pin: impl Peripheral<P = T> + 'd, pull: Pull) -> Self { | ||||||
|         let mut pin = Flex::new(pin); |         let mut pin = Flex::new(pin); | ||||||
| @@ -104,11 +125,13 @@ impl<'d, T: Pin> Input<'d, T> { | |||||||
|         self.pin.set_schmitt(enable) |         self.pin.set_schmitt(enable) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Get whether the pin input level is high. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn is_high(&mut self) -> bool { |     pub fn is_high(&mut self) -> bool { | ||||||
|         self.pin.is_high() |         self.pin.is_high() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Get whether the pin input level is low. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn is_low(&mut self) -> bool { |     pub fn is_low(&mut self) -> bool { | ||||||
|         self.pin.is_low() |         self.pin.is_low() | ||||||
| @@ -120,31 +143,37 @@ impl<'d, T: Pin> Input<'d, T> { | |||||||
|         self.pin.get_level() |         self.pin.get_level() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Wait until the pin is high. If it is already high, return immediately. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub async fn wait_for_high(&mut self) { |     pub async fn wait_for_high(&mut self) { | ||||||
|         self.pin.wait_for_high().await; |         self.pin.wait_for_high().await; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Wait until the pin is low. If it is already low, return immediately. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub async fn wait_for_low(&mut self) { |     pub async fn wait_for_low(&mut self) { | ||||||
|         self.pin.wait_for_low().await; |         self.pin.wait_for_low().await; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Wait for the pin to undergo a transition from low to high. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub async fn wait_for_rising_edge(&mut self) { |     pub async fn wait_for_rising_edge(&mut self) { | ||||||
|         self.pin.wait_for_rising_edge().await; |         self.pin.wait_for_rising_edge().await; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Wait for the pin to undergo a transition from high to low. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub async fn wait_for_falling_edge(&mut self) { |     pub async fn wait_for_falling_edge(&mut self) { | ||||||
|         self.pin.wait_for_falling_edge().await; |         self.pin.wait_for_falling_edge().await; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Wait for the pin to undergo any transition, i.e low to high OR high to low. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub async fn wait_for_any_edge(&mut self) { |     pub async fn wait_for_any_edge(&mut self) { | ||||||
|         self.pin.wait_for_any_edge().await; |         self.pin.wait_for_any_edge().await; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Configure dormant wake. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake<T> { |     pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake<T> { | ||||||
|         self.pin.dormant_wake(cfg) |         self.pin.dormant_wake(cfg) | ||||||
| @@ -155,10 +184,15 @@ impl<'d, T: Pin> Input<'d, T> { | |||||||
| #[derive(Debug, Eq, PartialEq, Copy, Clone)] | #[derive(Debug, Eq, PartialEq, Copy, Clone)] | ||||||
| #[cfg_attr(feature = "defmt", derive(defmt::Format))] | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||||||
| pub enum InterruptTrigger { | pub enum InterruptTrigger { | ||||||
|  |     /// Trigger on pin low. | ||||||
|     LevelLow, |     LevelLow, | ||||||
|  |     /// Trigger on pin high. | ||||||
|     LevelHigh, |     LevelHigh, | ||||||
|  |     /// Trigger on high to low transition. | ||||||
|     EdgeLow, |     EdgeLow, | ||||||
|  |     /// Trigger on low to high transition. | ||||||
|     EdgeHigh, |     EdgeHigh, | ||||||
|  |     /// Trigger on any transition. | ||||||
|     AnyEdge, |     AnyEdge, | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -226,6 +260,7 @@ struct InputFuture<'a, T: Pin> { | |||||||
| } | } | ||||||
|  |  | ||||||
| impl<'d, T: Pin> InputFuture<'d, T> { | impl<'d, T: Pin> InputFuture<'d, T> { | ||||||
|  |     /// Create a new future wiating for input trigger. | ||||||
|     pub fn new(pin: impl Peripheral<P = T> + 'd, level: InterruptTrigger) -> Self { |     pub fn new(pin: impl Peripheral<P = T> + 'd, level: InterruptTrigger) -> Self { | ||||||
|         into_ref!(pin); |         into_ref!(pin); | ||||||
|         let pin_group = (pin.pin() % 8) as usize; |         let pin_group = (pin.pin() % 8) as usize; | ||||||
| @@ -308,11 +343,13 @@ impl<'d, T: Pin> Future for InputFuture<'d, T> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// GPIO output driver. | ||||||
| pub struct Output<'d, T: Pin> { | pub struct Output<'d, T: Pin> { | ||||||
|     pin: Flex<'d, T>, |     pin: Flex<'d, T>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<'d, T: Pin> Output<'d, T> { | impl<'d, T: Pin> Output<'d, T> { | ||||||
|  |     /// Create GPIO output driver for a [Pin] with the provided [Level]. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level) -> Self { |     pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level) -> Self { | ||||||
|         let mut pin = Flex::new(pin); |         let mut pin = Flex::new(pin); | ||||||
| @@ -331,7 +368,7 @@ impl<'d, T: Pin> Output<'d, T> { | |||||||
|         self.pin.set_drive_strength(strength) |         self.pin.set_drive_strength(strength) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Set the pin's slew rate. |     /// Set the pin's slew rate. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { |     pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { | ||||||
|         self.pin.set_slew_rate(slew_rate) |         self.pin.set_slew_rate(slew_rate) | ||||||
| @@ -386,6 +423,7 @@ pub struct OutputOpenDrain<'d, T: Pin> { | |||||||
| } | } | ||||||
|  |  | ||||||
| impl<'d, T: Pin> OutputOpenDrain<'d, T> { | impl<'d, T: Pin> OutputOpenDrain<'d, T> { | ||||||
|  |     /// Create GPIO output driver for a [Pin] in open drain mode with the provided [Level]. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level) -> Self { |     pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level) -> Self { | ||||||
|         let mut pin = Flex::new(pin); |         let mut pin = Flex::new(pin); | ||||||
| @@ -403,7 +441,7 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { | |||||||
|         self.pin.set_drive_strength(strength) |         self.pin.set_drive_strength(strength) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Set the pin's slew rate. |     /// Set the pin's slew rate. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { |     pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { | ||||||
|         self.pin.set_slew_rate(slew_rate) |         self.pin.set_slew_rate(slew_rate) | ||||||
| @@ -456,11 +494,13 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { | |||||||
|         self.pin.toggle_set_as_output() |         self.pin.toggle_set_as_output() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Get whether the pin input level is high. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn is_high(&mut self) -> bool { |     pub fn is_high(&mut self) -> bool { | ||||||
|         self.pin.is_high() |         self.pin.is_high() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Get whether the pin input level is low. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn is_low(&mut self) -> bool { |     pub fn is_low(&mut self) -> bool { | ||||||
|         self.pin.is_low() |         self.pin.is_low() | ||||||
| @@ -472,26 +512,31 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { | |||||||
|         self.is_high().into() |         self.is_high().into() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Wait until the pin is high. If it is already high, return immediately. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub async fn wait_for_high(&mut self) { |     pub async fn wait_for_high(&mut self) { | ||||||
|         self.pin.wait_for_high().await; |         self.pin.wait_for_high().await; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Wait until the pin is low. If it is already low, return immediately. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub async fn wait_for_low(&mut self) { |     pub async fn wait_for_low(&mut self) { | ||||||
|         self.pin.wait_for_low().await; |         self.pin.wait_for_low().await; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Wait for the pin to undergo a transition from low to high. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub async fn wait_for_rising_edge(&mut self) { |     pub async fn wait_for_rising_edge(&mut self) { | ||||||
|         self.pin.wait_for_rising_edge().await; |         self.pin.wait_for_rising_edge().await; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Wait for the pin to undergo a transition from high to low. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub async fn wait_for_falling_edge(&mut self) { |     pub async fn wait_for_falling_edge(&mut self) { | ||||||
|         self.pin.wait_for_falling_edge().await; |         self.pin.wait_for_falling_edge().await; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Wait for the pin to undergo any transition, i.e low to high OR high to low. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub async fn wait_for_any_edge(&mut self) { |     pub async fn wait_for_any_edge(&mut self) { | ||||||
|         self.pin.wait_for_any_edge().await; |         self.pin.wait_for_any_edge().await; | ||||||
| @@ -508,6 +553,10 @@ pub struct Flex<'d, T: Pin> { | |||||||
| } | } | ||||||
|  |  | ||||||
| impl<'d, T: Pin> Flex<'d, T> { | impl<'d, T: Pin> Flex<'d, T> { | ||||||
|  |     /// Wrap the pin in a `Flex`. | ||||||
|  |     /// | ||||||
|  |     /// The pin remains disconnected. The initial output level is unspecified, but can be changed | ||||||
|  |     /// before the pin is put into output mode. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn new(pin: impl Peripheral<P = T> + 'd) -> Self { |     pub fn new(pin: impl Peripheral<P = T> + 'd) -> Self { | ||||||
|         into_ref!(pin); |         into_ref!(pin); | ||||||
| @@ -556,7 +605,7 @@ impl<'d, T: Pin> Flex<'d, T> { | |||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Set the pin's slew rate. |     /// Set the pin's slew rate. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { |     pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { | ||||||
|         self.pin.pad_ctrl().modify(|w| { |         self.pin.pad_ctrl().modify(|w| { | ||||||
| @@ -589,6 +638,7 @@ impl<'d, T: Pin> Flex<'d, T> { | |||||||
|         self.pin.sio_oe().value_set().write_value(self.bit()) |         self.pin.sio_oe().value_set().write_value(self.bit()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Set as output pin. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn is_set_as_output(&mut self) -> bool { |     pub fn is_set_as_output(&mut self) -> bool { | ||||||
|         self.ref_is_set_as_output() |         self.ref_is_set_as_output() | ||||||
| @@ -599,15 +649,18 @@ impl<'d, T: Pin> Flex<'d, T> { | |||||||
|         (self.pin.sio_oe().value().read() & self.bit()) != 0 |         (self.pin.sio_oe().value().read() & self.bit()) != 0 | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Toggle output pin. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn toggle_set_as_output(&mut self) { |     pub fn toggle_set_as_output(&mut self) { | ||||||
|         self.pin.sio_oe().value_xor().write_value(self.bit()) |         self.pin.sio_oe().value_xor().write_value(self.bit()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Get whether the pin input level is high. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn is_high(&mut self) -> bool { |     pub fn is_high(&mut self) -> bool { | ||||||
|         !self.is_low() |         !self.is_low() | ||||||
|     } |     } | ||||||
|  |     /// Get whether the pin input level is low. | ||||||
|  |  | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn is_low(&mut self) -> bool { |     pub fn is_low(&mut self) -> bool { | ||||||
| @@ -675,31 +728,37 @@ impl<'d, T: Pin> Flex<'d, T> { | |||||||
|         self.pin.sio_out().value_xor().write_value(self.bit()) |         self.pin.sio_out().value_xor().write_value(self.bit()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Wait until the pin is high. If it is already high, return immediately. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub async fn wait_for_high(&mut self) { |     pub async fn wait_for_high(&mut self) { | ||||||
|         InputFuture::new(&mut self.pin, InterruptTrigger::LevelHigh).await; |         InputFuture::new(&mut self.pin, InterruptTrigger::LevelHigh).await; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Wait until the pin is low. If it is already low, return immediately. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub async fn wait_for_low(&mut self) { |     pub async fn wait_for_low(&mut self) { | ||||||
|         InputFuture::new(&mut self.pin, InterruptTrigger::LevelLow).await; |         InputFuture::new(&mut self.pin, InterruptTrigger::LevelLow).await; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Wait for the pin to undergo a transition from low to high. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub async fn wait_for_rising_edge(&mut self) { |     pub async fn wait_for_rising_edge(&mut self) { | ||||||
|         InputFuture::new(&mut self.pin, InterruptTrigger::EdgeHigh).await; |         InputFuture::new(&mut self.pin, InterruptTrigger::EdgeHigh).await; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Wait for the pin to undergo a transition from high to low. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub async fn wait_for_falling_edge(&mut self) { |     pub async fn wait_for_falling_edge(&mut self) { | ||||||
|         InputFuture::new(&mut self.pin, InterruptTrigger::EdgeLow).await; |         InputFuture::new(&mut self.pin, InterruptTrigger::EdgeLow).await; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Wait for the pin to undergo any transition, i.e low to high OR high to low. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub async fn wait_for_any_edge(&mut self) { |     pub async fn wait_for_any_edge(&mut self) { | ||||||
|         InputFuture::new(&mut self.pin, InterruptTrigger::AnyEdge).await; |         InputFuture::new(&mut self.pin, InterruptTrigger::AnyEdge).await; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Configure dormant wake. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake<T> { |     pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake<T> { | ||||||
|         let idx = self.pin._pin() as usize; |         let idx = self.pin._pin() as usize; | ||||||
| @@ -737,6 +796,7 @@ impl<'d, T: Pin> Drop for Flex<'d, T> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Dormant wake driver. | ||||||
| pub struct DormantWake<'w, T: Pin> { | pub struct DormantWake<'w, T: Pin> { | ||||||
|     pin: PeripheralRef<'w, T>, |     pin: PeripheralRef<'w, T>, | ||||||
|     cfg: DormantWakeConfig, |     cfg: DormantWakeConfig, | ||||||
| @@ -818,6 +878,7 @@ pub(crate) mod sealed { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an [AnyPin]. | ||||||
| pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'static { | pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'static { | ||||||
|     /// Degrade to a generic pin struct |     /// Degrade to a generic pin struct | ||||||
|     fn degrade(self) -> AnyPin { |     fn degrade(self) -> AnyPin { | ||||||
| @@ -839,6 +900,7 @@ pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'stat | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Type-erased GPIO pin | ||||||
| pub struct AnyPin { | pub struct AnyPin { | ||||||
|     pin_bank: u8, |     pin_bank: u8, | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | //! I2C driver. | ||||||
| use core::future; | use core::future; | ||||||
| use core::marker::PhantomData; | use core::marker::PhantomData; | ||||||
| use core::task::Poll; | use core::task::Poll; | ||||||
| @@ -22,6 +23,7 @@ pub enum AbortReason { | |||||||
|     ArbitrationLoss, |     ArbitrationLoss, | ||||||
|     /// Transmit ended with data still in fifo |     /// Transmit ended with data still in fifo | ||||||
|     TxNotEmpty(u16), |     TxNotEmpty(u16), | ||||||
|  |     /// Other reason. | ||||||
|     Other(u32), |     Other(u32), | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -41,9 +43,11 @@ pub enum Error { | |||||||
|     AddressReserved(u16), |     AddressReserved(u16), | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// I2C config. | ||||||
| #[non_exhaustive] | #[non_exhaustive] | ||||||
| #[derive(Copy, Clone)] | #[derive(Copy, Clone)] | ||||||
| pub struct Config { | pub struct Config { | ||||||
|  |     /// Frequency. | ||||||
|     pub frequency: u32, |     pub frequency: u32, | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -53,13 +57,16 @@ impl Default for Config { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Size of I2C FIFO. | ||||||
| pub const FIFO_SIZE: u8 = 16; | pub const FIFO_SIZE: u8 = 16; | ||||||
|  |  | ||||||
|  | /// I2C driver. | ||||||
| pub struct I2c<'d, T: Instance, M: Mode> { | pub struct I2c<'d, T: Instance, M: Mode> { | ||||||
|     phantom: PhantomData<(&'d mut T, M)>, |     phantom: PhantomData<(&'d mut T, M)>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<'d, T: Instance> I2c<'d, T, Blocking> { | impl<'d, T: Instance> I2c<'d, T, Blocking> { | ||||||
|  |     /// Create a new driver instance in blocking mode. | ||||||
|     pub fn new_blocking( |     pub fn new_blocking( | ||||||
|         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, | ||||||
| @@ -72,6 +79,7 @@ impl<'d, T: Instance> I2c<'d, T, Blocking> { | |||||||
| } | } | ||||||
|  |  | ||||||
| impl<'d, T: Instance> I2c<'d, T, Async> { | impl<'d, T: Instance> I2c<'d, T, Async> { | ||||||
|  |     /// Create a new driver instance in async mode. | ||||||
|     pub fn new_async( |     pub fn new_async( | ||||||
|         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, | ||||||
| @@ -292,16 +300,19 @@ impl<'d, T: Instance> I2c<'d, T, Async> { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Read from address into buffer using DMA. | ||||||
|     pub async fn read_async(&mut self, addr: u16, buffer: &mut [u8]) -> Result<(), Error> { |     pub async fn read_async(&mut self, addr: u16, buffer: &mut [u8]) -> Result<(), Error> { | ||||||
|         Self::setup(addr)?; |         Self::setup(addr)?; | ||||||
|         self.read_async_internal(buffer, true, true).await |         self.read_async_internal(buffer, true, true).await | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Write to address from buffer using DMA. | ||||||
|     pub async fn write_async(&mut self, addr: u16, bytes: impl IntoIterator<Item = u8>) -> Result<(), Error> { |     pub async fn write_async(&mut self, addr: u16, bytes: impl IntoIterator<Item = u8>) -> Result<(), Error> { | ||||||
|         Self::setup(addr)?; |         Self::setup(addr)?; | ||||||
|         self.write_async_internal(bytes, true).await |         self.write_async_internal(bytes, true).await | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Write to address from bytes and read from address into buffer using DMA. | ||||||
|     pub async fn write_read_async( |     pub async fn write_read_async( | ||||||
|         &mut self, |         &mut self, | ||||||
|         addr: u16, |         addr: u16, | ||||||
| @@ -314,6 +325,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Interrupt handler. | ||||||
| pub struct InterruptHandler<T: Instance> { | pub struct InterruptHandler<T: Instance> { | ||||||
|     _uart: PhantomData<T>, |     _uart: PhantomData<T>, | ||||||
| } | } | ||||||
| @@ -569,17 +581,20 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { | |||||||
|     // Blocking public API |     // Blocking public API | ||||||
|     // ========================= |     // ========================= | ||||||
|  |  | ||||||
|  |     /// Read from address into buffer blocking caller until done. | ||||||
|     pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { |     pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { | ||||||
|         Self::setup(address.into())?; |         Self::setup(address.into())?; | ||||||
|         self.read_blocking_internal(read, true, true) |         self.read_blocking_internal(read, true, true) | ||||||
|         // Automatic Stop |         // Automatic Stop | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Write to address from buffer blocking caller until done. | ||||||
|     pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { |     pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { | ||||||
|         Self::setup(address.into())?; |         Self::setup(address.into())?; | ||||||
|         self.write_blocking_internal(write, true) |         self.write_blocking_internal(write, true) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Write to address from bytes and read from address into buffer blocking caller until done. | ||||||
|     pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { |     pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { | ||||||
|         Self::setup(address.into())?; |         Self::setup(address.into())?; | ||||||
|         self.write_blocking_internal(write, false)?; |         self.write_blocking_internal(write, false)?; | ||||||
| @@ -742,6 +757,7 @@ where | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Check if address is reserved. | ||||||
| pub fn i2c_reserved_addr(addr: u16) -> bool { | pub fn i2c_reserved_addr(addr: u16) -> bool { | ||||||
|     ((addr & 0x78) == 0 || (addr & 0x78) == 0x78) && addr != 0 |     ((addr & 0x78) == 0 || (addr & 0x78) == 0x78) && addr != 0 | ||||||
| } | } | ||||||
| @@ -768,6 +784,7 @@ mod sealed { | |||||||
|     pub trait SclPin<T: Instance> {} |     pub trait SclPin<T: Instance> {} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Driver mode. | ||||||
| pub trait Mode: sealed::Mode {} | pub trait Mode: sealed::Mode {} | ||||||
|  |  | ||||||
| macro_rules! impl_mode { | macro_rules! impl_mode { | ||||||
| @@ -777,12 +794,15 @@ macro_rules! impl_mode { | |||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Blocking mode. | ||||||
| pub struct Blocking; | pub struct Blocking; | ||||||
|  | /// Async mode. | ||||||
| pub struct Async; | pub struct Async; | ||||||
|  |  | ||||||
| impl_mode!(Blocking); | impl_mode!(Blocking); | ||||||
| impl_mode!(Async); | impl_mode!(Async); | ||||||
|  |  | ||||||
|  | /// I2C instance. | ||||||
| pub trait Instance: sealed::Instance {} | pub trait Instance: sealed::Instance {} | ||||||
|  |  | ||||||
| macro_rules! impl_instance { | macro_rules! impl_instance { | ||||||
| @@ -819,7 +839,9 @@ macro_rules! impl_instance { | |||||||
| impl_instance!(I2C0, I2C0_IRQ, set_i2c0, 32, 33); | impl_instance!(I2C0, I2C0_IRQ, set_i2c0, 32, 33); | ||||||
| impl_instance!(I2C1, I2C1_IRQ, set_i2c1, 34, 35); | impl_instance!(I2C1, I2C1_IRQ, set_i2c1, 34, 35); | ||||||
|  |  | ||||||
|  | /// SDA pin. | ||||||
| pub trait SdaPin<T: Instance>: sealed::SdaPin<T> + crate::gpio::Pin {} | pub trait SdaPin<T: Instance>: sealed::SdaPin<T> + crate::gpio::Pin {} | ||||||
|  | /// SCL pin. | ||||||
| pub trait SclPin<T: Instance>: sealed::SclPin<T> + crate::gpio::Pin {} | pub trait SclPin<T: Instance>: sealed::SclPin<T> + crate::gpio::Pin {} | ||||||
|  |  | ||||||
| macro_rules! impl_pin { | macro_rules! impl_pin { | ||||||
|   | |||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | //! I2C slave driver. | ||||||
| use core::future; | use core::future; | ||||||
| use core::marker::PhantomData; | use core::marker::PhantomData; | ||||||
| use core::task::Poll; | use core::task::Poll; | ||||||
| @@ -63,11 +64,13 @@ impl Default for Config { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// I2CSlave driver. | ||||||
| pub struct I2cSlave<'d, T: Instance> { | pub struct I2cSlave<'d, T: Instance> { | ||||||
|     phantom: PhantomData<&'d mut T>, |     phantom: PhantomData<&'d mut T>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<'d, T: Instance> I2cSlave<'d, T> { | impl<'d, T: Instance> I2cSlave<'d, T> { | ||||||
|  |     /// Create a new instance. | ||||||
|     pub fn new( |     pub fn new( | ||||||
|         _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, | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| #![no_std] | #![no_std] | ||||||
| #![allow(async_fn_in_trait)] | #![allow(async_fn_in_trait)] | ||||||
| #![doc = include_str!("../README.md")] | #![doc = include_str!("../README.md")] | ||||||
|  | #![warn(missing_docs)] | ||||||
|  |  | ||||||
| // This mod MUST go first, so that the others see its macros. | // This mod MUST go first, so that the others see its macros. | ||||||
| pub(crate) mod fmt; | pub(crate) mod fmt; | ||||||
|   | |||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | //! PIO driver. | ||||||
| use core::future::Future; | use core::future::Future; | ||||||
| use core::marker::PhantomData; | use core::marker::PhantomData; | ||||||
| use core::pin::Pin as FuturePin; | use core::pin::Pin as FuturePin; | ||||||
|   | |||||||
| @@ -119,11 +119,13 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Create PWM driver without any configured pins. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn new_free(inner: impl Peripheral<P = T> + 'd, config: Config) -> Self { |     pub fn new_free(inner: impl Peripheral<P = T> + 'd, config: Config) -> Self { | ||||||
|         Self::new_inner(inner, None, None, config, Divmode::DIV) |         Self::new_inner(inner, None, None, config, Divmode::DIV) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Create PWM driver with a single 'a' as output. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn new_output_a( |     pub fn new_output_a( | ||||||
|         inner: impl Peripheral<P = T> + 'd, |         inner: impl Peripheral<P = T> + 'd, | ||||||
| @@ -134,6 +136,7 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||||||
|         Self::new_inner(inner, Some(a.map_into()), None, config, Divmode::DIV) |         Self::new_inner(inner, Some(a.map_into()), None, config, Divmode::DIV) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Create PWM driver with a single 'b' pin as output. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn new_output_b( |     pub fn new_output_b( | ||||||
|         inner: impl Peripheral<P = T> + 'd, |         inner: impl Peripheral<P = T> + 'd, | ||||||
| @@ -144,6 +147,7 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||||||
|         Self::new_inner(inner, None, Some(b.map_into()), config, Divmode::DIV) |         Self::new_inner(inner, None, Some(b.map_into()), config, Divmode::DIV) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Create PWM driver with a 'a' and 'b' pins as output. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn new_output_ab( |     pub fn new_output_ab( | ||||||
|         inner: impl Peripheral<P = T> + 'd, |         inner: impl Peripheral<P = T> + 'd, | ||||||
| @@ -155,6 +159,7 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||||||
|         Self::new_inner(inner, Some(a.map_into()), Some(b.map_into()), config, Divmode::DIV) |         Self::new_inner(inner, Some(a.map_into()), Some(b.map_into()), config, Divmode::DIV) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Create PWM driver with a single 'b' as input pin. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn new_input( |     pub fn new_input( | ||||||
|         inner: impl Peripheral<P = T> + 'd, |         inner: impl Peripheral<P = T> + 'd, | ||||||
| @@ -166,6 +171,7 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||||||
|         Self::new_inner(inner, None, Some(b.map_into()), config, mode.into()) |         Self::new_inner(inner, None, Some(b.map_into()), config, mode.into()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Create PWM driver with a 'a' and 'b' pins in the desired input mode. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn new_output_input( |     pub fn new_output_input( | ||||||
|         inner: impl Peripheral<P = T> + 'd, |         inner: impl Peripheral<P = T> + 'd, | ||||||
| @@ -178,6 +184,7 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||||||
|         Self::new_inner(inner, Some(a.map_into()), Some(b.map_into()), config, mode.into()) |         Self::new_inner(inner, Some(a.map_into()), Some(b.map_into()), config, mode.into()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Set the PWM config. | ||||||
|     pub fn set_config(&mut self, config: &Config) { |     pub fn set_config(&mut self, config: &Config) { | ||||||
|         Self::configure(self.inner.regs(), config); |         Self::configure(self.inner.regs(), config); | ||||||
|     } |     } | ||||||
| @@ -221,28 +228,33 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||||||
|         while p.csr().read().ph_ret() {} |         while p.csr().read().ph_ret() {} | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Read PWM counter. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn counter(&self) -> u16 { |     pub fn counter(&self) -> u16 { | ||||||
|         self.inner.regs().ctr().read().ctr() |         self.inner.regs().ctr().read().ctr() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Write PWM counter. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn set_counter(&self, ctr: u16) { |     pub fn set_counter(&self, ctr: u16) { | ||||||
|         self.inner.regs().ctr().write(|w| w.set_ctr(ctr)) |         self.inner.regs().ctr().write(|w| w.set_ctr(ctr)) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Wait for channel interrupt. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn wait_for_wrap(&mut self) { |     pub fn wait_for_wrap(&mut self) { | ||||||
|         while !self.wrapped() {} |         while !self.wrapped() {} | ||||||
|         self.clear_wrapped(); |         self.clear_wrapped(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Check if interrupt for channel is set. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn wrapped(&mut self) -> bool { |     pub fn wrapped(&mut self) -> bool { | ||||||
|         pac::PWM.intr().read().0 & self.bit() != 0 |         pac::PWM.intr().read().0 & self.bit() != 0 | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[inline] |     #[inline] | ||||||
|  |     /// Clear interrupt flag. | ||||||
|     pub fn clear_wrapped(&mut self) { |     pub fn clear_wrapped(&mut self) { | ||||||
|         pac::PWM.intr().write_value(Intr(self.bit() as _)); |         pac::PWM.intr().write_value(Intr(self.bit() as _)); | ||||||
|     } |     } | ||||||
| @@ -253,15 +265,18 @@ impl<'d, T: Channel> Pwm<'d, T> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Batch representation of PWM channels. | ||||||
| pub struct PwmBatch(u32); | pub struct PwmBatch(u32); | ||||||
|  |  | ||||||
| impl PwmBatch { | impl PwmBatch { | ||||||
|     #[inline] |     #[inline] | ||||||
|  |     /// Enable a PWM channel in this batch. | ||||||
|     pub fn enable(&mut self, pwm: &Pwm<'_, impl Channel>) { |     pub fn enable(&mut self, pwm: &Pwm<'_, impl Channel>) { | ||||||
|         self.0 |= pwm.bit(); |         self.0 |= pwm.bit(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[inline] |     #[inline] | ||||||
|  |     /// Enable channels in this batch in a PWM. | ||||||
|     pub fn set_enabled(enabled: bool, batch: impl FnOnce(&mut PwmBatch)) { |     pub fn set_enabled(enabled: bool, batch: impl FnOnce(&mut PwmBatch)) { | ||||||
|         let mut en = PwmBatch(0); |         let mut en = PwmBatch(0); | ||||||
|         batch(&mut en); |         batch(&mut en); | ||||||
| @@ -289,9 +304,12 @@ mod sealed { | |||||||
|     pub trait Channel {} |     pub trait Channel {} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// PWM Channel. | ||||||
| pub trait Channel: Peripheral<P = Self> + sealed::Channel + Sized + 'static { | pub trait Channel: Peripheral<P = Self> + sealed::Channel + Sized + 'static { | ||||||
|  |     /// Channel number. | ||||||
|     fn number(&self) -> u8; |     fn number(&self) -> u8; | ||||||
|  |  | ||||||
|  |     /// Channel register block. | ||||||
|     fn regs(&self) -> pac::pwm::Channel { |     fn regs(&self) -> pac::pwm::Channel { | ||||||
|         pac::PWM.ch(self.number() as _) |         pac::PWM.ch(self.number() as _) | ||||||
|     } |     } | ||||||
| @@ -317,7 +335,9 @@ channel!(PWM_CH5, 5); | |||||||
| channel!(PWM_CH6, 6); | channel!(PWM_CH6, 6); | ||||||
| channel!(PWM_CH7, 7); | channel!(PWM_CH7, 7); | ||||||
|  |  | ||||||
|  | /// PWM Pin A. | ||||||
| pub trait PwmPinA<T: Channel>: GpioPin {} | pub trait PwmPinA<T: Channel>: GpioPin {} | ||||||
|  | /// PWM Pin B. | ||||||
| pub trait PwmPinB<T: Channel>: GpioPin {} | pub trait PwmPinB<T: Channel>: GpioPin {} | ||||||
|  |  | ||||||
| macro_rules! impl_pin { | macro_rules! impl_pin { | ||||||
|   | |||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | //! RTC driver. | ||||||
| mod filter; | mod filter; | ||||||
|  |  | ||||||
| use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; | use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; | ||||||
|   | |||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | //! Timer driver. | ||||||
| use core::cell::Cell; | use core::cell::Cell; | ||||||
|  |  | ||||||
| use atomic_polyfill::{AtomicU8, Ordering}; | use atomic_polyfill::{AtomicU8, Ordering}; | ||||||
|   | |||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | //! Buffered UART driver. | ||||||
| use core::future::{poll_fn, Future}; | use core::future::{poll_fn, Future}; | ||||||
| use core::slice; | use core::slice; | ||||||
| use core::task::Poll; | use core::task::Poll; | ||||||
|   | |||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | //! UART driver. | ||||||
| use core::future::poll_fn; | use core::future::poll_fn; | ||||||
| use core::marker::PhantomData; | use core::marker::PhantomData; | ||||||
| use core::task::Poll; | use core::task::Poll; | ||||||
| @@ -947,7 +948,7 @@ pub struct Async; | |||||||
| impl_mode!(Blocking); | impl_mode!(Blocking); | ||||||
| impl_mode!(Async); | impl_mode!(Async); | ||||||
|  |  | ||||||
| /// UART instance trait. | /// UART instance. | ||||||
| pub trait Instance: sealed::Instance {} | pub trait Instance: sealed::Instance {} | ||||||
|  |  | ||||||
| macro_rules! impl_instance { | macro_rules! impl_instance { | ||||||
|   | |||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | //! USB driver. | ||||||
| use core::future::poll_fn; | use core::future::poll_fn; | ||||||
| use core::marker::PhantomData; | use core::marker::PhantomData; | ||||||
| use core::slice; | use core::slice; | ||||||
|   | |||||||
| @@ -148,31 +148,20 @@ struct Timeout { | |||||||
|  |  | ||||||
| #[allow(dead_code)] | #[allow(dead_code)] | ||||||
| impl Timeout { | impl Timeout { | ||||||
|     #[cfg(not(feature = "time"))] |  | ||||||
|     #[inline] |     #[inline] | ||||||
|     fn check(self) -> Result<(), Error> { |     fn check(self) -> Result<(), Error> { | ||||||
|         Ok(()) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|         #[cfg(feature = "time")] |         #[cfg(feature = "time")] | ||||||
|     #[inline] |  | ||||||
|     fn check(self) -> Result<(), Error> { |  | ||||||
|         if Instant::now() > self.deadline { |         if Instant::now() > self.deadline { | ||||||
|             Err(Error::Timeout) |             return Err(Error::Timeout); | ||||||
|         } else { |         } | ||||||
|  |  | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #[cfg(not(feature = "time"))] |  | ||||||
|     #[inline] |     #[inline] | ||||||
|     fn with<R>(self, fut: impl Future<Output = Result<R, Error>>) -> impl Future<Output = Result<R, Error>> { |     fn with<R>(self, fut: impl Future<Output = Result<R, Error>>) -> impl Future<Output = Result<R, Error>> { | ||||||
|         fut |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|         #[cfg(feature = "time")] |         #[cfg(feature = "time")] | ||||||
|     #[inline] |         { | ||||||
|     fn with<R>(self, fut: impl Future<Output = Result<R, Error>>) -> impl Future<Output = Result<R, Error>> { |  | ||||||
|             use futures::FutureExt; |             use futures::FutureExt; | ||||||
|  |  | ||||||
|             embassy_futures::select::select(embassy_time::Timer::at(self.deadline), fut).map(|r| match r { |             embassy_futures::select::select(embassy_time::Timer::at(self.deadline), fut).map(|r| match r { | ||||||
| @@ -180,6 +169,10 @@ impl Timeout { | |||||||
|                 embassy_futures::select::Either::Second(r) => r, |                 embassy_futures::select::Either::Second(r) => r, | ||||||
|             }) |             }) | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         #[cfg(not(feature = "time"))] | ||||||
|  |         fut | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| pub(crate) mod sealed { | pub(crate) mod sealed { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user