mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-22 06:42:32 +00:00
docs: document all embassy-rp public apis
Enable missing doc warnings.
This commit is contained in:
parent
ca2e3759ad
commit
f4b77c967f
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user