Merge pull request #2297 from embassy-rs/stm32-docs

stm32: add some docs.
This commit is contained in:
Dario Nieuwenhuis 2023-12-17 23:59:29 +00:00 committed by GitHub
commit c0cfd68c0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 544 additions and 124 deletions

View File

@ -50,19 +50,19 @@ impl<'d, T: Pin> Input<'d, T> {
Self { pin } Self { pin }
} }
/// Test if current pin level is high. /// 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()
} }
/// Test if current pin level 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 {
self.pin.is_low() self.pin.is_low()
} }
/// Returns current pin level /// Get the pin input level.
#[inline] #[inline]
pub fn get_level(&mut self) -> Level { pub fn get_level(&mut self) -> Level {
self.pin.get_level() self.pin.get_level()
@ -158,19 +158,19 @@ impl<'d, T: Pin> Output<'d, T> {
self.pin.set_level(level) self.pin.set_level(level)
} }
/// Is the output pin set as high? /// Get whether the output level is set to high.
#[inline] #[inline]
pub fn is_set_high(&mut self) -> bool { pub fn is_set_high(&mut self) -> bool {
self.pin.is_set_high() self.pin.is_set_high()
} }
/// Is the output pin set as low? /// Get whether the output level is set to low.
#[inline] #[inline]
pub fn is_set_low(&mut self) -> bool { pub fn is_set_low(&mut self) -> bool {
self.pin.is_set_low() self.pin.is_set_low()
} }
/// What level output is set to /// Get the current output level.
#[inline] #[inline]
pub fn get_output_level(&mut self) -> Level { pub fn get_output_level(&mut self) -> Level {
self.pin.get_output_level() self.pin.get_output_level()
@ -275,13 +275,13 @@ impl<'d, T: Pin> Flex<'d, T> {
self.pin.conf().reset(); self.pin.conf().reset();
} }
/// Test if current pin level is high. /// 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()
} }
/// Test if current pin level 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 {
self.ref_is_low() self.ref_is_low()
@ -292,7 +292,7 @@ impl<'d, T: Pin> Flex<'d, T> {
self.pin.block().in_.read().bits() & (1 << self.pin.pin()) == 0 self.pin.block().in_.read().bits() & (1 << self.pin.pin()) == 0
} }
/// Returns current pin level /// Get the pin input level.
#[inline] #[inline]
pub fn get_level(&mut self) -> Level { pub fn get_level(&mut self) -> Level {
self.is_high().into() self.is_high().into()
@ -319,25 +319,24 @@ impl<'d, T: Pin> Flex<'d, T> {
} }
} }
/// Is the output pin set as high? /// Get whether the output level is set to high.
#[inline] #[inline]
pub fn is_set_high(&mut self) -> bool { pub fn is_set_high(&mut self) -> bool {
!self.is_set_low() !self.is_set_low()
} }
/// Is the output pin set as low? /// Get whether the output level is set to low.
#[inline] #[inline]
pub fn is_set_low(&mut self) -> bool { pub fn is_set_low(&mut self) -> bool {
self.ref_is_set_low() self.ref_is_set_low()
} }
/// Is the output pin set as low?
#[inline] #[inline]
pub(crate) fn ref_is_set_low(&self) -> bool { pub(crate) fn ref_is_set_low(&self) -> bool {
self.pin.block().out.read().bits() & (1 << self.pin.pin()) == 0 self.pin.block().out.read().bits() & (1 << self.pin.pin()) == 0
} }
/// What level output is set to /// Get the current output level.
#[inline] #[inline]
pub fn get_output_level(&mut self) -> Level { pub fn get_output_level(&mut self) -> Level {
self.is_set_high().into() self.is_set_high().into()

View File

@ -1,3 +1,4 @@
//! Analog to Digital (ADC) converter driver.
#![macro_use] #![macro_use]
#[cfg(not(adc_f3_v2))] #[cfg(not(adc_f3_v2))]
@ -24,6 +25,7 @@ pub use sample_time::SampleTime;
use crate::peripherals; use crate::peripherals;
/// Analog to Digital driver.
pub struct Adc<'d, T: Instance> { pub struct Adc<'d, T: Instance> {
#[allow(unused)] #[allow(unused)]
adc: crate::PeripheralRef<'d, T>, adc: crate::PeripheralRef<'d, T>,
@ -75,12 +77,16 @@ pub(crate) mod sealed {
} }
} }
/// ADC instance.
#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))] #[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))]
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {} pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {}
/// ADC instance.
#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))] #[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))]
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {}
/// ADC pin.
pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}
/// ADC internal channel.
pub trait InternalChannel<T>: sealed::InternalChannel<T> {} pub trait InternalChannel<T>: sealed::InternalChannel<T> {}
foreach_adc!( foreach_adc!(

View File

@ -1,3 +1,5 @@
/// ADC resolution
#[allow(missing_docs)]
#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))] #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
@ -8,6 +10,8 @@ pub enum Resolution {
SixBit, SixBit,
} }
/// ADC resolution
#[allow(missing_docs)]
#[cfg(adc_v4)] #[cfg(adc_v4)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
@ -49,6 +53,9 @@ impl From<Resolution> for crate::pac::adc::vals::Res {
} }
impl Resolution { impl Resolution {
/// Get the maximum reading value for this resolution.
///
/// This is `2**n - 1`.
pub fn to_max_count(&self) -> u32 { pub fn to_max_count(&self) -> u32 {
match self { match self {
#[cfg(adc_v4)] #[cfg(adc_v4)]

View File

@ -32,6 +32,7 @@ const TEMP_CHANNEL: u8 = 18;
const VBAT_CHANNEL: u8 = 17; const VBAT_CHANNEL: u8 = 17;
// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs // NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
/// Internal voltage reference channel.
pub struct VrefInt; pub struct VrefInt;
impl<T: Instance> InternalChannel<T> for VrefInt {} impl<T: Instance> InternalChannel<T> for VrefInt {}
impl<T: Instance> super::sealed::InternalChannel<T> for VrefInt { impl<T: Instance> super::sealed::InternalChannel<T> for VrefInt {
@ -40,6 +41,7 @@ impl<T: Instance> super::sealed::InternalChannel<T> for VrefInt {
} }
} }
/// Internal temperature channel.
pub struct Temperature; pub struct Temperature;
impl<T: Instance> InternalChannel<T> for Temperature {} impl<T: Instance> InternalChannel<T> for Temperature {}
impl<T: Instance> super::sealed::InternalChannel<T> for Temperature { impl<T: Instance> super::sealed::InternalChannel<T> for Temperature {
@ -48,6 +50,7 @@ impl<T: Instance> super::sealed::InternalChannel<T> for Temperature {
} }
} }
/// Internal battery voltage channel.
pub struct Vbat; pub struct Vbat;
impl<T: Instance> InternalChannel<T> for Vbat {} impl<T: Instance> InternalChannel<T> for Vbat {}
impl<T: Instance> super::sealed::InternalChannel<T> for Vbat { impl<T: Instance> super::sealed::InternalChannel<T> for Vbat {
@ -125,6 +128,7 @@ impl Prescaler {
} }
impl<'d, T: Instance> Adc<'d, T> { impl<'d, T: Instance> Adc<'d, T> {
/// Create a new ADC driver.
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u16>) -> Self { pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u16>) -> Self {
embassy_hal_internal::into_ref!(adc); embassy_hal_internal::into_ref!(adc);
T::enable_and_reset(); T::enable_and_reset();
@ -212,6 +216,7 @@ impl<'d, T: Instance> Adc<'d, T> {
}); });
} }
/// Enable reading the voltage reference internal channel.
pub fn enable_vrefint(&self) -> VrefInt { pub fn enable_vrefint(&self) -> VrefInt {
T::common_regs().ccr().modify(|reg| { T::common_regs().ccr().modify(|reg| {
reg.set_vrefen(true); reg.set_vrefen(true);
@ -220,6 +225,7 @@ impl<'d, T: Instance> Adc<'d, T> {
VrefInt {} VrefInt {}
} }
/// Enable reading the temperature internal channel.
pub fn enable_temperature(&self) -> Temperature { pub fn enable_temperature(&self) -> Temperature {
T::common_regs().ccr().modify(|reg| { T::common_regs().ccr().modify(|reg| {
reg.set_vsenseen(true); reg.set_vsenseen(true);
@ -228,6 +234,7 @@ impl<'d, T: Instance> Adc<'d, T> {
Temperature {} Temperature {}
} }
/// Enable reading the vbat internal channel.
pub fn enable_vbat(&self) -> Vbat { pub fn enable_vbat(&self) -> Vbat {
T::common_regs().ccr().modify(|reg| { T::common_regs().ccr().modify(|reg| {
reg.set_vbaten(true); reg.set_vbaten(true);
@ -236,10 +243,12 @@ impl<'d, T: Instance> Adc<'d, T> {
Vbat {} Vbat {}
} }
/// Set the ADC sample time.
pub fn set_sample_time(&mut self, sample_time: SampleTime) { pub fn set_sample_time(&mut self, sample_time: SampleTime) {
self.sample_time = sample_time; self.sample_time = sample_time;
} }
/// Set the ADC resolution.
pub fn set_resolution(&mut self, resolution: Resolution) { pub fn set_resolution(&mut self, resolution: Resolution) {
T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
} }
@ -263,6 +272,7 @@ impl<'d, T: Instance> Adc<'d, T> {
T::regs().dr().read().0 as u16 T::regs().dr().read().0 as u16
} }
/// Read an ADC pin.
pub fn read<P>(&mut self, pin: &mut P) -> u16 pub fn read<P>(&mut self, pin: &mut P) -> u16
where where
P: AdcPin<T>, P: AdcPin<T>,
@ -273,6 +283,7 @@ impl<'d, T: Instance> Adc<'d, T> {
self.read_channel(pin.channel()) self.read_channel(pin.channel())
} }
/// Read an ADC internal channel.
pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
self.read_channel(channel.channel()) self.read_channel(channel.channel())
} }

View File

@ -1,6 +1,3 @@
pub use bxcan;
use embassy_hal_internal::PeripheralRef;
use crate::peripherals; use crate::peripherals;
pub(crate) mod sealed { pub(crate) mod sealed {
@ -25,27 +22,19 @@ pub(crate) mod sealed {
} }
pub trait Instance { pub trait Instance {
const REGISTERS: *mut bxcan::RegisterBlock;
fn regs() -> &'static crate::pac::can::Fdcan; fn regs() -> &'static crate::pac::can::Fdcan;
fn state() -> &'static State; fn state() -> &'static State;
} }
} }
/// Interruptable FDCAN instance.
pub trait InterruptableInstance {} pub trait InterruptableInstance {}
/// FDCAN instance.
pub trait Instance: sealed::Instance + InterruptableInstance + 'static {} pub trait Instance: sealed::Instance + InterruptableInstance + 'static {}
pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>);
unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> {
const REGISTERS: *mut bxcan::RegisterBlock = T::REGISTERS;
}
foreach_peripheral!( foreach_peripheral!(
(can, $inst:ident) => { (can, $inst:ident) => {
impl sealed::Instance for peripherals::$inst { impl sealed::Instance for peripherals::$inst {
const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _;
fn regs() -> &'static crate::pac::can::Fdcan { fn regs() -> &'static crate::pac::can::Fdcan {
&crate::pac::$inst &crate::pac::$inst
} }

View File

@ -6,15 +6,19 @@ use crate::peripherals::CRC;
use crate::rcc::sealed::RccPeripheral; use crate::rcc::sealed::RccPeripheral;
use crate::Peripheral; use crate::Peripheral;
/// CRC driver.
pub struct Crc<'d> { pub struct Crc<'d> {
_peripheral: PeripheralRef<'d, CRC>, _peripheral: PeripheralRef<'d, CRC>,
_config: Config, _config: Config,
} }
/// CRC configuration errlr
pub enum ConfigError { pub enum ConfigError {
/// The selected polynomial is invalid.
InvalidPolynomial, InvalidPolynomial,
} }
/// CRC configuration
pub struct Config { pub struct Config {
reverse_in: InputReverseConfig, reverse_in: InputReverseConfig,
reverse_out: bool, reverse_out: bool,
@ -25,14 +29,20 @@ pub struct Config {
crc_poly: u32, crc_poly: u32,
} }
/// Input reverse configuration.
pub enum InputReverseConfig { pub enum InputReverseConfig {
/// Don't reverse anything
None, None,
/// Reverse bytes
Byte, Byte,
/// Reverse 16-bit halfwords.
Halfword, Halfword,
/// Reverse 32-bit words.
Word, Word,
} }
impl Config { impl Config {
/// Create a new CRC config.
pub fn new( pub fn new(
reverse_in: InputReverseConfig, reverse_in: InputReverseConfig,
reverse_out: bool, reverse_out: bool,
@ -57,7 +67,9 @@ impl Config {
} }
} }
/// Polynomial size
#[cfg(crc_v3)] #[cfg(crc_v3)]
#[allow(missing_docs)]
pub enum PolySize { pub enum PolySize {
Width7, Width7,
Width8, Width8,
@ -81,6 +93,7 @@ impl<'d> Crc<'d> {
instance instance
} }
/// Reset the CRC engine.
pub fn reset(&mut self) { pub fn reset(&mut self) {
PAC_CRC.cr().modify(|w| w.set_reset(true)); PAC_CRC.cr().modify(|w| w.set_reset(true));
} }

View File

@ -62,11 +62,11 @@ impl Mode {
/// ///
/// 12-bit values outside the permitted range are silently truncated. /// 12-bit values outside the permitted range are silently truncated.
pub enum Value { pub enum Value {
// 8 bit value /// 8 bit value
Bit8(u8), Bit8(u8),
// 12 bit value stored in a u16, left-aligned /// 12 bit value stored in a u16, left-aligned
Bit12Left(u16), Bit12Left(u16),
// 12 bit value stored in a u16, right-aligned /// 12 bit value stored in a u16, right-aligned
Bit12Right(u16), Bit12Right(u16),
} }
@ -76,11 +76,11 @@ pub enum Value {
/// ///
/// 12-bit values outside the permitted range are silently truncated. /// 12-bit values outside the permitted range are silently truncated.
pub enum DualValue { pub enum DualValue {
// 8 bit value /// 8 bit value
Bit8(u8, u8), Bit8(u8, u8),
// 12 bit value stored in a u16, left-aligned /// 12 bit value stored in a u16, left-aligned
Bit12Left(u16, u16), Bit12Left(u16, u16),
// 12 bit value stored in a u16, right-aligned /// 12 bit value stored in a u16, right-aligned
Bit12Right(u16, u16), Bit12Right(u16, u16),
} }
@ -88,11 +88,11 @@ pub enum DualValue {
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Array variant of [`Value`]. /// Array variant of [`Value`].
pub enum ValueArray<'a> { pub enum ValueArray<'a> {
// 8 bit values /// 8 bit values
Bit8(&'a [u8]), Bit8(&'a [u8]),
// 12 bit value stored in a u16, left-aligned /// 12 bit value stored in a u16, left-aligned
Bit12Left(&'a [u16]), Bit12Left(&'a [u16]),
// 12 bit values stored in a u16, right-aligned /// 12 bit values stored in a u16, right-aligned
Bit12Right(&'a [u16]), Bit12Right(&'a [u16]),
} }
@ -106,7 +106,9 @@ pub struct DacChannel<'d, T: Instance, const N: u8, DMA = NoDma> {
dma: PeripheralRef<'d, DMA>, dma: PeripheralRef<'d, DMA>,
} }
/// DAC channel 1 type alias.
pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, 1, DMA>; pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, 1, DMA>;
/// DAC channel 2 type alias.
pub type DacCh2<'d, T, DMA = NoDma> = DacChannel<'d, T, 2, DMA>; pub type DacCh2<'d, T, DMA = NoDma> = DacChannel<'d, T, 2, DMA>;
impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
@ -492,6 +494,7 @@ pub(crate) mod sealed {
} }
} }
/// DAC instance.
pub trait Instance: sealed::Instance + RccPeripheral + 'static {} pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
dma_trait!(DacDma1, Instance); dma_trait!(DacDma1, Instance);
dma_trait!(DacDma2, Instance); dma_trait!(DacDma2, Instance);

View File

@ -1,3 +1,5 @@
#![allow(missing_docs)]
/// Trigger selection for STM32F0. /// Trigger selection for STM32F0.
#[cfg(stm32f0)] #[cfg(stm32f0)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[derive(Debug, Copy, Clone, Eq, PartialEq)]

View File

@ -36,6 +36,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
} }
/// The level on the VSync pin when the data is not valid on the parallel interface. /// The level on the VSync pin when the data is not valid on the parallel interface.
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq)]
pub enum VSyncDataInvalidLevel { pub enum VSyncDataInvalidLevel {
Low, Low,
@ -43,6 +44,7 @@ pub enum VSyncDataInvalidLevel {
} }
/// The level on the VSync pin when the data is not valid on the parallel interface. /// The level on the VSync pin when the data is not valid on the parallel interface.
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq)]
pub enum HSyncDataInvalidLevel { pub enum HSyncDataInvalidLevel {
Low, Low,
@ -50,14 +52,16 @@ pub enum HSyncDataInvalidLevel {
} }
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq)]
#[allow(missing_docs)]
pub enum PixelClockPolarity { pub enum PixelClockPolarity {
RisingEdge, RisingEdge,
FallingEdge, FallingEdge,
} }
pub struct State { struct State {
waker: AtomicWaker, waker: AtomicWaker,
} }
impl State { impl State {
const fn new() -> State { const fn new() -> State {
State { State {
@ -68,18 +72,25 @@ impl State {
static STATE: State = State::new(); static STATE: State = State::new();
/// DCMI 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))]
#[non_exhaustive] #[non_exhaustive]
pub enum Error { pub enum Error {
/// Overrun error: the hardware generated data faster than we could read it.
Overrun, Overrun,
/// Internal peripheral error.
PeripheralError, PeripheralError,
} }
/// DCMI configuration.
#[non_exhaustive] #[non_exhaustive]
pub struct Config { pub struct Config {
/// VSYNC level.
pub vsync_level: VSyncDataInvalidLevel, pub vsync_level: VSyncDataInvalidLevel,
/// HSYNC level.
pub hsync_level: HSyncDataInvalidLevel, pub hsync_level: HSyncDataInvalidLevel,
/// PIXCLK polarity.
pub pixclk_polarity: PixelClockPolarity, pub pixclk_polarity: PixelClockPolarity,
} }
@ -105,6 +116,7 @@ macro_rules! config_pins {
}; };
} }
/// DCMI driver.
pub struct Dcmi<'d, T: Instance, Dma: FrameDma<T>> { pub struct Dcmi<'d, T: Instance, Dma: FrameDma<T>> {
inner: PeripheralRef<'d, T>, inner: PeripheralRef<'d, T>,
dma: PeripheralRef<'d, Dma>, dma: PeripheralRef<'d, Dma>,
@ -115,6 +127,7 @@ where
T: Instance, T: Instance,
Dma: FrameDma<T>, Dma: FrameDma<T>,
{ {
/// Create a new DCMI driver with 8 data bits.
pub fn new_8bit( pub fn new_8bit(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
dma: impl Peripheral<P = Dma> + 'd, dma: impl Peripheral<P = Dma> + 'd,
@ -139,6 +152,7 @@ where
Self::new_inner(peri, dma, config, false, 0b00) Self::new_inner(peri, dma, config, false, 0b00)
} }
/// Create a new DCMI driver with 10 data bits.
pub fn new_10bit( pub fn new_10bit(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
dma: impl Peripheral<P = Dma> + 'd, dma: impl Peripheral<P = Dma> + 'd,
@ -165,6 +179,7 @@ where
Self::new_inner(peri, dma, config, false, 0b01) Self::new_inner(peri, dma, config, false, 0b01)
} }
/// Create a new DCMI driver with 12 data bits.
pub fn new_12bit( pub fn new_12bit(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
dma: impl Peripheral<P = Dma> + 'd, dma: impl Peripheral<P = Dma> + 'd,
@ -193,6 +208,7 @@ where
Self::new_inner(peri, dma, config, false, 0b10) Self::new_inner(peri, dma, config, false, 0b10)
} }
/// Create a new DCMI driver with 14 data bits.
pub fn new_14bit( pub fn new_14bit(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
dma: impl Peripheral<P = Dma> + 'd, dma: impl Peripheral<P = Dma> + 'd,
@ -223,6 +239,7 @@ where
Self::new_inner(peri, dma, config, false, 0b11) Self::new_inner(peri, dma, config, false, 0b11)
} }
/// Create a new DCMI driver with 8 data bits, with embedded synchronization.
pub fn new_es_8bit( pub fn new_es_8bit(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
dma: impl Peripheral<P = Dma> + 'd, dma: impl Peripheral<P = Dma> + 'd,
@ -245,6 +262,7 @@ where
Self::new_inner(peri, dma, config, true, 0b00) Self::new_inner(peri, dma, config, true, 0b00)
} }
/// Create a new DCMI driver with 10 data bits, with embedded synchronization.
pub fn new_es_10bit( pub fn new_es_10bit(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
dma: impl Peripheral<P = Dma> + 'd, dma: impl Peripheral<P = Dma> + 'd,
@ -269,6 +287,7 @@ where
Self::new_inner(peri, dma, config, true, 0b01) Self::new_inner(peri, dma, config, true, 0b01)
} }
/// Create a new DCMI driver with 12 data bits, with embedded synchronization.
pub fn new_es_12bit( pub fn new_es_12bit(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
dma: impl Peripheral<P = Dma> + 'd, dma: impl Peripheral<P = Dma> + 'd,
@ -295,6 +314,7 @@ where
Self::new_inner(peri, dma, config, true, 0b10) Self::new_inner(peri, dma, config, true, 0b10)
} }
/// Create a new DCMI driver with 14 data bits, with embedded synchronization.
pub fn new_es_14bit( pub fn new_es_14bit(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
dma: impl Peripheral<P = Dma> + 'd, dma: impl Peripheral<P = Dma> + 'd,
@ -538,7 +558,9 @@ mod sealed {
} }
} }
/// DCMI instance.
pub trait Instance: sealed::Instance + 'static { pub trait Instance: sealed::Instance + 'static {
/// Interrupt for this instance.
type Interrupt: interrupt::typelevel::Interrupt; type Interrupt: interrupt::typelevel::Interrupt;
} }

View File

@ -1,4 +1,4 @@
#![macro_use] //! Basic Direct Memory Acccess (BDMA)
use core::future::Future; use core::future::Future;
use core::pin::Pin; use core::pin::Pin;
@ -17,6 +17,7 @@ use crate::interrupt::Priority;
use crate::pac; use crate::pac;
use crate::pac::bdma::{regs, vals}; use crate::pac::bdma::{regs, vals};
/// BDMA transfer options.
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive] #[non_exhaustive]
@ -140,13 +141,17 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: usize, index
STATE.ch_wakers[index].wake(); STATE.ch_wakers[index].wake();
} }
/// DMA request type alias.
#[cfg(any(bdma_v2, dmamux))] #[cfg(any(bdma_v2, dmamux))]
pub type Request = u8; pub type Request = u8;
/// DMA request type alias.
#[cfg(not(any(bdma_v2, dmamux)))] #[cfg(not(any(bdma_v2, dmamux)))]
pub type Request = (); pub type Request = ();
/// DMA channel.
#[cfg(dmamux)] #[cfg(dmamux)]
pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {} pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {}
/// DMA channel.
#[cfg(not(dmamux))] #[cfg(not(dmamux))]
pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {}
@ -161,12 +166,14 @@ pub(crate) mod sealed {
} }
} }
/// DMA transfer.
#[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>,
} }
impl<'a, C: Channel> Transfer<'a, C> { impl<'a, C: Channel> Transfer<'a, C> {
/// Create a new read DMA transfer (peripheral to memory).
pub unsafe fn new_read<W: Word>( pub unsafe fn new_read<W: Word>(
channel: impl Peripheral<P = C> + 'a, channel: impl Peripheral<P = C> + 'a,
request: Request, request: Request,
@ -177,6 +184,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
Self::new_read_raw(channel, request, peri_addr, buf, options) Self::new_read_raw(channel, request, peri_addr, buf, options)
} }
/// Create a new read DMA transfer (peripheral to memory), using raw pointers.
pub unsafe fn new_read_raw<W: Word>( pub unsafe fn new_read_raw<W: Word>(
channel: impl Peripheral<P = C> + 'a, channel: impl Peripheral<P = C> + 'a,
request: Request, request: Request,
@ -202,6 +210,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
) )
} }
/// Create a new write DMA transfer (memory to peripheral).
pub unsafe fn new_write<W: Word>( pub unsafe fn new_write<W: Word>(
channel: impl Peripheral<P = C> + 'a, channel: impl Peripheral<P = C> + 'a,
request: Request, request: Request,
@ -212,6 +221,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
Self::new_write_raw(channel, request, buf, peri_addr, options) Self::new_write_raw(channel, request, buf, peri_addr, options)
} }
/// Create a new write DMA transfer (memory to peripheral), using raw pointers.
pub unsafe fn new_write_raw<W: Word>( pub unsafe fn new_write_raw<W: Word>(
channel: impl Peripheral<P = C> + 'a, channel: impl Peripheral<P = C> + 'a,
request: Request, request: Request,
@ -237,6 +247,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
) )
} }
/// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly.
pub unsafe fn new_write_repeated<W: Word>( pub unsafe fn new_write_repeated<W: Word>(
channel: impl Peripheral<P = C> + 'a, channel: impl Peripheral<P = C> + 'a,
request: Request, request: Request,
@ -321,6 +332,9 @@ impl<'a, C: Channel> Transfer<'a, C> {
}); });
} }
/// Request the transfer to stop.
///
/// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
pub fn request_stop(&mut self) { pub fn request_stop(&mut self) {
let ch = self.channel.regs().ch(self.channel.num()); let ch = self.channel.regs().ch(self.channel.num());
@ -331,6 +345,10 @@ impl<'a, C: Channel> Transfer<'a, C> {
}); });
} }
/// Return whether this transfer is still running.
///
/// If this returns `false`, it can be because either the transfer finished, or
/// it was requested to stop early with [`request_stop`](Self::request_stop).
pub fn is_running(&mut self) -> bool { pub fn is_running(&mut self) -> bool {
let ch = self.channel.regs().ch(self.channel.num()); let ch = self.channel.regs().ch(self.channel.num());
let en = ch.cr().read().en(); let en = ch.cr().read().en();
@ -339,13 +357,15 @@ impl<'a, C: Channel> Transfer<'a, C> {
en && (circular || !tcif) en && (circular || !tcif)
} }
/// Gets the total remaining transfers for the channel /// Get the total remaining transfers for the channel.
/// Note: this will be zero for transfers that completed without cancellation. ///
/// This will be zero for transfers that completed instead of being canceled with [`request_stop`](Self::request_stop).
pub fn get_remaining_transfers(&self) -> u16 { pub fn get_remaining_transfers(&self) -> u16 {
let ch = self.channel.regs().ch(self.channel.num()); let ch = self.channel.regs().ch(self.channel.num());
ch.ndtr().read().ndt() ch.ndtr().read().ndt()
} }
/// Blocking wait until the transfer finishes.
pub fn blocking_wait(mut self) { pub fn blocking_wait(mut self) {
while self.is_running() {} while self.is_running() {}
self.request_stop(); self.request_stop();
@ -411,6 +431,7 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
} }
} }
/// Ringbuffer for reading data using DMA circular mode.
pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
cr: regs::Cr, cr: regs::Cr,
channel: PeripheralRef<'a, C>, channel: PeripheralRef<'a, C>,
@ -418,7 +439,8 @@ pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
} }
impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
pub unsafe fn new_read( /// Create a new ring buffer.
pub unsafe fn new(
channel: impl Peripheral<P = C> + 'a, channel: impl Peripheral<P = C> + 'a,
_request: Request, _request: Request,
peri_addr: *mut W, peri_addr: *mut W,
@ -473,11 +495,15 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
this this
} }
/// Start the ring buffer operation.
///
/// You must call this after creating it for it to work.
pub fn start(&mut self) { pub fn start(&mut self) {
let ch = self.channel.regs().ch(self.channel.num()); let ch = self.channel.regs().ch(self.channel.num());
ch.cr().write_value(self.cr) ch.cr().write_value(self.cr)
} }
/// Clear all data in the ring buffer.
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
} }
@ -509,10 +535,11 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
} }
/// The capacity of the ringbuffer. /// The capacity of the ringbuffer.
pub const fn cap(&self) -> usize { pub const fn capacity(&self) -> usize {
self.ringbuf.cap() self.ringbuf.cap()
} }
/// Set a waker to be woken when at least one byte is received.
pub fn set_waker(&mut self, waker: &Waker) { pub fn set_waker(&mut self, waker: &Waker) {
DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
} }
@ -526,6 +553,9 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
}); });
} }
/// Request DMA to stop.
///
/// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
pub fn request_stop(&mut self) { pub fn request_stop(&mut self) {
let ch = self.channel.regs().ch(self.channel.num()); let ch = self.channel.regs().ch(self.channel.num());
@ -539,6 +569,10 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
}); });
} }
/// Return whether DMA is still running.
///
/// If this returns `false`, it can be because either the transfer finished, or
/// it was requested to stop early with [`request_stop`](Self::request_stop).
pub fn is_running(&mut self) -> bool { pub fn is_running(&mut self) -> bool {
let ch = self.channel.regs().ch(self.channel.num()); let ch = self.channel.regs().ch(self.channel.num());
ch.cr().read().en() ch.cr().read().en()
@ -555,6 +589,7 @@ impl<'a, C: Channel, W: Word> Drop for ReadableRingBuffer<'a, C, W> {
} }
} }
/// Ringbuffer for writing data using DMA circular mode.
pub struct WritableRingBuffer<'a, C: Channel, W: Word> { pub struct WritableRingBuffer<'a, C: Channel, W: Word> {
cr: regs::Cr, cr: regs::Cr,
channel: PeripheralRef<'a, C>, channel: PeripheralRef<'a, C>,
@ -562,7 +597,8 @@ pub struct WritableRingBuffer<'a, C: Channel, W: Word> {
} }
impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
pub unsafe fn new_write( /// Create a new ring buffer.
pub unsafe fn new(
channel: impl Peripheral<P = C> + 'a, channel: impl Peripheral<P = C> + 'a,
_request: Request, _request: Request,
peri_addr: *mut W, peri_addr: *mut W,
@ -617,11 +653,15 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
this this
} }
/// Start the ring buffer operation.
///
/// You must call this after creating it for it to work.
pub fn start(&mut self) { pub fn start(&mut self) {
let ch = self.channel.regs().ch(self.channel.num()); let ch = self.channel.regs().ch(self.channel.num());
ch.cr().write_value(self.cr) ch.cr().write_value(self.cr)
} }
/// Clear all data in the ring buffer.
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
} }
@ -640,10 +680,11 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
} }
/// The capacity of the ringbuffer. /// The capacity of the ringbuffer.
pub const fn cap(&self) -> usize { pub const fn capacity(&self) -> usize {
self.ringbuf.cap() self.ringbuf.cap()
} }
/// Set a waker to be woken when at least one byte is sent.
pub fn set_waker(&mut self, waker: &Waker) { pub fn set_waker(&mut self, waker: &Waker) {
DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
} }
@ -657,6 +698,9 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
}); });
} }
/// Request DMA to stop.
///
/// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
pub fn request_stop(&mut self) { pub fn request_stop(&mut self) {
let ch = self.channel.regs().ch(self.channel.num()); let ch = self.channel.regs().ch(self.channel.num());
@ -670,6 +714,10 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
}); });
} }
/// Return whether DMA is still running.
///
/// If this returns `false`, it can be because either the transfer finished, or
/// it was requested to stop early with [`request_stop`](Self::request_stop).
pub fn is_running(&mut self) -> bool { pub fn is_running(&mut self) -> bool {
let ch = self.channel.regs().ch(self.channel.num()); let ch = self.channel.regs().ch(self.channel.num());
ch.cr().read().en() ch.cr().read().en()

View File

@ -16,6 +16,7 @@ use crate::interrupt::Priority;
use crate::pac::dma::{regs, vals}; use crate::pac::dma::{regs, vals};
use crate::{interrupt, pac}; use crate::{interrupt, pac};
/// DMA transfer options.
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive] #[non_exhaustive]
@ -69,6 +70,7 @@ impl From<Dir> for vals::Dir {
} }
} }
/// DMA transfer burst setting.
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Burst { pub enum Burst {
@ -93,6 +95,7 @@ impl From<Burst> for vals::Burst {
} }
} }
/// DMA flow control setting.
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum FlowControl { pub enum FlowControl {
@ -111,6 +114,7 @@ impl From<FlowControl> for vals::Pfctrl {
} }
} }
/// DMA FIFO threshold.
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum FifoThreshold { pub enum FifoThreshold {
@ -208,13 +212,17 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: usize, index:
STATE.ch_wakers[index].wake(); STATE.ch_wakers[index].wake();
} }
/// DMA request type alias. (also known as DMA channel number in some chips)
#[cfg(any(dma_v2, dmamux))] #[cfg(any(dma_v2, dmamux))]
pub type Request = u8; pub type Request = u8;
/// DMA request type alias. (also known as DMA channel number in some chips)
#[cfg(not(any(dma_v2, dmamux)))] #[cfg(not(any(dma_v2, dmamux)))]
pub type Request = (); pub type Request = ();
/// DMA channel.
#[cfg(dmamux)] #[cfg(dmamux)]
pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {} pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {}
/// DMA channel.
#[cfg(not(dmamux))] #[cfg(not(dmamux))]
pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {}
@ -229,12 +237,14 @@ pub(crate) mod sealed {
} }
} }
/// DMA transfer.
#[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>,
} }
impl<'a, C: Channel> Transfer<'a, C> { impl<'a, C: Channel> Transfer<'a, C> {
/// Create a new read DMA transfer (peripheral to memory).
pub unsafe fn new_read<W: Word>( pub unsafe fn new_read<W: Word>(
channel: impl Peripheral<P = C> + 'a, channel: impl Peripheral<P = C> + 'a,
request: Request, request: Request,
@ -245,6 +255,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
Self::new_read_raw(channel, request, peri_addr, buf, options) Self::new_read_raw(channel, request, peri_addr, buf, options)
} }
/// Create a new read DMA transfer (peripheral to memory), using raw pointers.
pub unsafe fn new_read_raw<W: Word>( pub unsafe fn new_read_raw<W: Word>(
channel: impl Peripheral<P = C> + 'a, channel: impl Peripheral<P = C> + 'a,
request: Request, request: Request,
@ -270,6 +281,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
) )
} }
/// Create a new write DMA transfer (memory to peripheral).
pub unsafe fn new_write<W: Word>( pub unsafe fn new_write<W: Word>(
channel: impl Peripheral<P = C> + 'a, channel: impl Peripheral<P = C> + 'a,
request: Request, request: Request,
@ -280,6 +292,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
Self::new_write_raw(channel, request, buf, peri_addr, options) Self::new_write_raw(channel, request, buf, peri_addr, options)
} }
/// Create a new write DMA transfer (memory to peripheral), using raw pointers.
pub unsafe fn new_write_raw<W: Word>( pub unsafe fn new_write_raw<W: Word>(
channel: impl Peripheral<P = C> + 'a, channel: impl Peripheral<P = C> + 'a,
request: Request, request: Request,
@ -305,6 +318,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
) )
} }
/// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly.
pub unsafe fn new_write_repeated<W: Word>( pub unsafe fn new_write_repeated<W: Word>(
channel: impl Peripheral<P = C> + 'a, channel: impl Peripheral<P = C> + 'a,
request: Request, request: Request,
@ -407,6 +421,9 @@ impl<'a, C: Channel> Transfer<'a, C> {
}); });
} }
/// Request the transfer to stop.
///
/// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
pub fn request_stop(&mut self) { pub fn request_stop(&mut self) {
let ch = self.channel.regs().st(self.channel.num()); let ch = self.channel.regs().st(self.channel.num());
@ -417,6 +434,10 @@ impl<'a, C: Channel> Transfer<'a, C> {
}); });
} }
/// Return whether this transfer is still running.
///
/// If this returns `false`, it can be because either the transfer finished, or
/// it was requested to stop early with [`request_stop`](Self::request_stop).
pub fn is_running(&mut self) -> bool { pub fn is_running(&mut self) -> bool {
let ch = self.channel.regs().st(self.channel.num()); let ch = self.channel.regs().st(self.channel.num());
ch.cr().read().en() ch.cr().read().en()
@ -429,6 +450,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
ch.ndtr().read().ndt() ch.ndtr().read().ndt()
} }
/// Blocking wait until the transfer finishes.
pub fn blocking_wait(mut self) { pub fn blocking_wait(mut self) {
while self.is_running() {} while self.is_running() {}
@ -465,12 +487,14 @@ impl<'a, C: Channel> Future for Transfer<'a, C> {
// ================================== // ==================================
/// Double-buffered DMA transfer.
pub struct DoubleBuffered<'a, C: Channel, W: Word> { pub struct DoubleBuffered<'a, C: Channel, W: Word> {
channel: PeripheralRef<'a, C>, channel: PeripheralRef<'a, C>,
_phantom: PhantomData<W>, _phantom: PhantomData<W>,
} }
impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
/// Create a new read DMA transfer (peripheral to memory).
pub unsafe fn new_read( pub unsafe fn new_read(
channel: impl Peripheral<P = C> + 'a, channel: impl Peripheral<P = C> + 'a,
_request: Request, _request: Request,
@ -554,25 +578,36 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
}); });
} }
/// Set the first buffer address.
///
/// You may call this while DMA is transferring the other buffer.
pub unsafe fn set_buffer0(&mut self, buffer: *mut W) { pub unsafe fn set_buffer0(&mut self, buffer: *mut W) {
let ch = self.channel.regs().st(self.channel.num()); let ch = self.channel.regs().st(self.channel.num());
ch.m0ar().write_value(buffer as _); ch.m0ar().write_value(buffer as _);
} }
/// Set the second buffer address.
///
/// You may call this while DMA is transferring the other buffer.
pub unsafe fn set_buffer1(&mut self, buffer: *mut W) { pub unsafe fn set_buffer1(&mut self, buffer: *mut W) {
let ch = self.channel.regs().st(self.channel.num()); let ch = self.channel.regs().st(self.channel.num());
ch.m1ar().write_value(buffer as _); ch.m1ar().write_value(buffer as _);
} }
/// Returh whether buffer0 is accessible (i.e. whether DMA is transferring buffer1 now)
pub fn is_buffer0_accessible(&mut self) -> bool { pub fn is_buffer0_accessible(&mut self) -> bool {
let ch = self.channel.regs().st(self.channel.num()); let ch = self.channel.regs().st(self.channel.num());
ch.cr().read().ct() == vals::Ct::MEMORY1 ch.cr().read().ct() == vals::Ct::MEMORY1
} }
/// Set a waker to be woken when one of the buffers is being transferred.
pub fn set_waker(&mut self, waker: &Waker) { pub fn set_waker(&mut self, waker: &Waker) {
STATE.ch_wakers[self.channel.index()].register(waker); STATE.ch_wakers[self.channel.index()].register(waker);
} }
/// Request the transfer to stop.
///
/// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
pub fn request_stop(&mut self) { pub fn request_stop(&mut self) {
let ch = self.channel.regs().st(self.channel.num()); let ch = self.channel.regs().st(self.channel.num());
@ -583,6 +618,10 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
}); });
} }
/// Return whether this transfer is still running.
///
/// If this returns `false`, it can be because either the transfer finished, or
/// it was requested to stop early with [`request_stop`](Self::request_stop).
pub fn is_running(&mut self) -> bool { pub fn is_running(&mut self) -> bool {
let ch = self.channel.regs().st(self.channel.num()); let ch = self.channel.regs().st(self.channel.num());
ch.cr().read().en() ch.cr().read().en()
@ -629,6 +668,7 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
} }
} }
/// Ringbuffer for receiving data using DMA circular mode.
pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
cr: regs::Cr, cr: regs::Cr,
channel: PeripheralRef<'a, C>, channel: PeripheralRef<'a, C>,
@ -636,7 +676,8 @@ pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
} }
impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
pub unsafe fn new_read( /// Create a new ring buffer.
pub unsafe fn new(
channel: impl Peripheral<P = C> + 'a, channel: impl Peripheral<P = C> + 'a,
_request: Request, _request: Request,
peri_addr: *mut W, peri_addr: *mut W,
@ -706,11 +747,15 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
this this
} }
/// Start the ring buffer operation.
///
/// You must call this after creating it for it to work.
pub fn start(&mut self) { pub fn start(&mut self) {
let ch = self.channel.regs().st(self.channel.num()); let ch = self.channel.regs().st(self.channel.num());
ch.cr().write_value(self.cr); ch.cr().write_value(self.cr);
} }
/// Clear all data in the ring buffer.
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
} }
@ -741,11 +786,12 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
.await .await
} }
// The capacity of the ringbuffer /// The capacity of the ringbuffer
pub const fn cap(&self) -> usize { pub const fn capacity(&self) -> usize {
self.ringbuf.cap() self.ringbuf.cap()
} }
/// Set a waker to be woken when at least one byte is received.
pub fn set_waker(&mut self, waker: &Waker) { pub fn set_waker(&mut self, waker: &Waker) {
DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
} }
@ -763,6 +809,9 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
}); });
} }
/// Request DMA to stop.
///
/// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
pub fn request_stop(&mut self) { pub fn request_stop(&mut self) {
let ch = self.channel.regs().st(self.channel.num()); let ch = self.channel.regs().st(self.channel.num());
@ -774,6 +823,10 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
}); });
} }
/// Return whether DMA is still running.
///
/// If this returns `false`, it can be because either the transfer finished, or
/// it was requested to stop early with [`request_stop`](Self::request_stop).
pub fn is_running(&mut self) -> bool { pub fn is_running(&mut self) -> bool {
let ch = self.channel.regs().st(self.channel.num()); let ch = self.channel.regs().st(self.channel.num());
ch.cr().read().en() ch.cr().read().en()
@ -790,6 +843,7 @@ impl<'a, C: Channel, W: Word> Drop for ReadableRingBuffer<'a, C, W> {
} }
} }
/// Ringbuffer for writing data using DMA circular mode.
pub struct WritableRingBuffer<'a, C: Channel, W: Word> { pub struct WritableRingBuffer<'a, C: Channel, W: Word> {
cr: regs::Cr, cr: regs::Cr,
channel: PeripheralRef<'a, C>, channel: PeripheralRef<'a, C>,
@ -797,7 +851,8 @@ pub struct WritableRingBuffer<'a, C: Channel, W: Word> {
} }
impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
pub unsafe fn new_write( /// Create a new ring buffer.
pub unsafe fn new(
channel: impl Peripheral<P = C> + 'a, channel: impl Peripheral<P = C> + 'a,
_request: Request, _request: Request,
peri_addr: *mut W, peri_addr: *mut W,
@ -867,11 +922,15 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
this this
} }
/// Start the ring buffer operation.
///
/// You must call this after creating it for it to work.
pub fn start(&mut self) { pub fn start(&mut self) {
let ch = self.channel.regs().st(self.channel.num()); let ch = self.channel.regs().st(self.channel.num());
ch.cr().write_value(self.cr); ch.cr().write_value(self.cr);
} }
/// Clear all data in the ring buffer.
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
} }
@ -889,11 +948,12 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
.await .await
} }
// The capacity of the ringbuffer /// The capacity of the ringbuffer
pub const fn cap(&self) -> usize { pub const fn capacity(&self) -> usize {
self.ringbuf.cap() self.ringbuf.cap()
} }
/// Set a waker to be woken when at least one byte is received.
pub fn set_waker(&mut self, waker: &Waker) { pub fn set_waker(&mut self, waker: &Waker) {
DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
} }
@ -911,6 +971,9 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
}); });
} }
/// Request DMA to stop.
///
/// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
pub fn request_stop(&mut self) { pub fn request_stop(&mut self) {
let ch = self.channel.regs().st(self.channel.num()); let ch = self.channel.regs().st(self.channel.num());
@ -922,6 +985,10 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
}); });
} }
/// Return whether DMA is still running.
///
/// If this returns `false`, it can be because either the transfer finished, or
/// it was requested to stop early with [`request_stop`](Self::request_stop).
pub fn is_running(&mut self) -> bool { pub fn is_running(&mut self) -> bool {
let ch = self.channel.regs().st(self.channel.num()); let ch = self.channel.regs().st(self.channel.num());
ch.cr().read().en() ch.cr().read().en()

View File

@ -22,11 +22,15 @@ pub(crate) mod dmamux_sealed {
} }
} }
/// DMAMUX1 instance.
pub struct DMAMUX1; pub struct DMAMUX1;
/// DMAMUX2 instance.
#[cfg(stm32h7)] #[cfg(stm32h7)]
pub struct DMAMUX2; pub struct DMAMUX2;
/// DMAMUX channel trait.
pub trait MuxChannel: dmamux_sealed::MuxChannel { pub trait MuxChannel: dmamux_sealed::MuxChannel {
/// DMAMUX instance this channel is on.
type Mux; type Mux;
} }

View File

@ -39,6 +39,13 @@ enum Dir {
PeripheralToMemory, PeripheralToMemory,
} }
/// "No DMA" placeholder.
///
/// You may pass this in place of a real DMA channel when creating a driver
/// to indicate it should not use DMA.
///
/// This often causes async functionality to not be available on the instance,
/// leaving only blocking functionality.
pub struct NoDma; pub struct NoDma;
impl_peripheral!(NoDma); impl_peripheral!(NoDma);

View File

@ -1,3 +1,6 @@
//! DMA word sizes.
#[allow(missing_docs)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum WordSize { pub enum WordSize {
@ -7,6 +10,7 @@ pub enum WordSize {
} }
impl WordSize { impl WordSize {
/// Amount of bytes of this word size.
pub fn bytes(&self) -> usize { pub fn bytes(&self) -> usize {
match self { match self {
Self::OneByte => 1, Self::OneByte => 1,
@ -20,8 +24,13 @@ mod sealed {
pub trait Word {} pub trait Word {}
} }
/// DMA word trait.
///
/// This is implemented for u8, u16, u32, etc.
pub trait Word: sealed::Word + Default + Copy + 'static { pub trait Word: sealed::Word + Default + Copy + 'static {
/// Word size
fn size() -> WordSize; fn size() -> WordSize;
/// Amount of bits of this word size.
fn bits() -> usize; fn bits() -> usize;
} }
@ -40,6 +49,7 @@ macro_rules! impl_word {
($T:ident, $uX:ident, $bits:literal, $size:ident) => { ($T:ident, $uX:ident, $bits:literal, $size:ident) => {
#[repr(transparent)] #[repr(transparent)]
#[derive(Copy, Clone, Default)] #[derive(Copy, Clone, Default)]
#[doc = concat!(stringify!($T), " word size")]
pub struct $T(pub $uX); pub struct $T(pub $uX);
impl_word!(_, $T, $bits, $size); impl_word!(_, $T, $bits, $size);
}; };

View File

@ -102,6 +102,7 @@ unsafe impl PHY for GenericSMI {
/// Public functions for the PHY /// Public functions for the PHY
impl GenericSMI { impl GenericSMI {
/// Set the SMI polling interval.
#[cfg(feature = "time")] #[cfg(feature = "time")]
pub fn set_poll_interval(&mut self, poll_interval: Duration) { pub fn set_poll_interval(&mut self, poll_interval: Duration) {
self.poll_interval = poll_interval self.poll_interval = poll_interval

View File

@ -22,6 +22,14 @@ const RX_BUFFER_SIZE: usize = 1536;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub(crate) struct Packet<const N: usize>([u8; N]); pub(crate) struct Packet<const N: usize>([u8; N]);
/// Ethernet packet queue.
///
/// This struct owns the memory used for reading and writing packets.
///
/// `TX` is the number of packets in the transmit queue, `RX` in the receive
/// queue. A bigger queue allows the hardware to receive more packets while the
/// CPU is busy doing other things, which may increase performance (especially for RX)
/// at the cost of more RAM usage.
pub struct PacketQueue<const TX: usize, const RX: usize> { pub struct PacketQueue<const TX: usize, const RX: usize> {
tx_desc: [TDes; TX], tx_desc: [TDes; TX],
rx_desc: [RDes; RX], rx_desc: [RDes; RX],
@ -30,6 +38,7 @@ pub struct PacketQueue<const TX: usize, const RX: usize> {
} }
impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> { impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> {
/// Create a new packet queue.
pub const fn new() -> Self { pub const fn new() -> Self {
const NEW_TDES: TDes = TDes::new(); const NEW_TDES: TDes = TDes::new();
const NEW_RDES: RDes = RDes::new(); const NEW_RDES: RDes = RDes::new();
@ -41,7 +50,18 @@ impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> {
} }
} }
// Allow to initialize a Self without requiring it to go on the stack /// Initialize a packet queue in-place.
///
/// This can be helpful to avoid accidentally stack-allocating the packet queue in the stack. The
/// Rust compiler can sometimes be a bit dumb when working with large owned values: if you call `new()`
/// and then store the returned PacketQueue in its final place (like a `static`), the compiler might
/// place it temporarily on the stack then move it. Since this struct is quite big, it may result
/// in a stack overflow.
///
/// With this function, you can create an uninitialized `static` with type `MaybeUninit<PacketQueue<...>>`
/// and initialize it in-place, guaranteeing no stack usage.
///
/// After calling this function, calling `assume_init` on the MaybeUninit is guaranteed safe.
pub fn init(this: &mut MaybeUninit<Self>) { pub fn init(this: &mut MaybeUninit<Self>) {
unsafe { unsafe {
this.as_mut_ptr().write_bytes(0u8, 1); this.as_mut_ptr().write_bytes(0u8, 1);
@ -93,6 +113,7 @@ impl<'d, T: Instance, P: PHY> embassy_net_driver::Driver for Ethernet<'d, T, P>
} }
} }
/// `embassy-net` RX token.
pub struct RxToken<'a, 'd> { pub struct RxToken<'a, 'd> {
rx: &'a mut RDesRing<'d>, rx: &'a mut RDesRing<'d>,
} }
@ -110,6 +131,7 @@ impl<'a, 'd> embassy_net_driver::RxToken for RxToken<'a, 'd> {
} }
} }
/// `embassy-net` TX token.
pub struct TxToken<'a, 'd> { pub struct TxToken<'a, 'd> {
tx: &'a mut TDesRing<'d>, tx: &'a mut TDesRing<'d>,
} }
@ -159,6 +181,7 @@ pub(crate) mod sealed {
} }
} }
/// Ethernet instance.
pub trait Instance: sealed::Instance + Send + 'static {} pub trait Instance: sealed::Instance + Send + 'static {}
impl sealed::Instance for crate::peripherals::ETH { impl sealed::Instance for crate::peripherals::ETH {

View File

@ -34,6 +34,7 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandl
} }
} }
/// Ethernet driver.
pub struct Ethernet<'d, T: Instance, P: PHY> { pub struct Ethernet<'d, T: Instance, P: PHY> {
_peri: PeripheralRef<'d, T>, _peri: PeripheralRef<'d, T>,
pub(crate) tx: TDesRing<'d>, pub(crate) tx: TDesRing<'d>,
@ -56,6 +57,7 @@ macro_rules! config_pins {
} }
impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
/// Create a new Ethernet driver.
pub fn new<const TX: usize, const RX: usize>( pub fn new<const TX: usize, const RX: usize>(
queue: &'d mut PacketQueue<TX, RX>, queue: &'d mut PacketQueue<TX, RX>,
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
@ -237,6 +239,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
} }
} }
/// Ethernet SMI driver.
pub struct EthernetStationManagement<T: Instance> { pub struct EthernetStationManagement<T: Instance> {
peri: PhantomData<T>, peri: PhantomData<T>,
clock_range: u8, clock_range: u8,

View File

@ -39,7 +39,7 @@ fn exticr_regs() -> pac::afio::Afio {
pac::AFIO pac::AFIO
} }
pub unsafe fn on_irq() { unsafe fn on_irq() {
#[cfg(feature = "low-power")] #[cfg(feature = "low-power")]
crate::low_power::on_wakeup_irq(); crate::low_power::on_wakeup_irq();
@ -85,7 +85,13 @@ impl Iterator for BitIter {
} }
} }
/// EXTI input driver /// EXTI input driver.
///
/// This driver augments a GPIO `Input` with EXTI functionality. EXTI is not
/// built into `Input` itself because it needs to take ownership of the corresponding
/// EXTI channel, which is a limited resource.
///
/// Pins PA5, PB5, PC5... all use EXTI channel 5, so you can't use EXTI on, say, PA5 and PC5 at the same time.
pub struct ExtiInput<'d, T: GpioPin> { pub struct ExtiInput<'d, T: GpioPin> {
pin: Input<'d, T>, pin: Input<'d, T>,
} }
@ -93,23 +99,30 @@ pub struct ExtiInput<'d, T: GpioPin> {
impl<'d, T: GpioPin> Unpin for ExtiInput<'d, T> {} impl<'d, T: GpioPin> Unpin for ExtiInput<'d, T> {}
impl<'d, T: GpioPin> ExtiInput<'d, T> { impl<'d, T: GpioPin> ExtiInput<'d, T> {
/// Create an EXTI input.
pub fn new(pin: Input<'d, T>, _ch: impl Peripheral<P = T::ExtiChannel> + 'd) -> Self { pub fn new(pin: Input<'d, T>, _ch: impl Peripheral<P = T::ExtiChannel> + 'd) -> Self {
Self { pin } Self { pin }
} }
/// Get whether the pin is high.
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 is low.
pub fn is_low(&mut self) -> bool { pub fn is_low(&mut self) -> bool {
self.pin.is_low() self.pin.is_low()
} }
/// Get the pin level.
pub fn get_level(&mut self) -> Level { pub fn get_level(&mut self) -> Level {
self.pin.get_level() self.pin.get_level()
} }
pub async fn wait_for_high<'a>(&'a mut self) { /// Asynchronously wait until the pin is high.
///
/// This returns immediately if the pin is already high.
pub async fn wait_for_high(&mut self) {
let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false); let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false);
if self.is_high() { if self.is_high() {
return; return;
@ -117,7 +130,10 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> {
fut.await fut.await
} }
pub async fn wait_for_low<'a>(&'a mut self) { /// Asynchronously wait until the pin is low.
///
/// This returns immediately if the pin is already low.
pub async fn wait_for_low(&mut self) {
let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true); let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true);
if self.is_low() { if self.is_low() {
return; return;
@ -125,15 +141,22 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> {
fut.await fut.await
} }
pub async fn wait_for_rising_edge<'a>(&'a mut self) { /// Asynchronously wait until the pin sees a rising edge.
///
/// If the pin is already high, it will wait for it to go low then back high.
pub async fn wait_for_rising_edge(&mut self) {
ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false).await ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false).await
} }
pub async fn wait_for_falling_edge<'a>(&'a mut self) { /// Asynchronously wait until the pin sees a falling edge.
///
/// If the pin is already low, it will wait for it to go high then back low.
pub async fn wait_for_falling_edge(&mut self) {
ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true).await ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true).await
} }
pub async fn wait_for_any_edge<'a>(&'a mut self) { /// Asynchronously wait until the pin sees any edge (either rising or falling).
pub async fn wait_for_any_edge(&mut self) {
ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true).await ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true).await
} }
} }
@ -284,6 +307,7 @@ macro_rules! foreach_exti_irq {
macro_rules! impl_irq { macro_rules! impl_irq {
($e:ident) => { ($e:ident) => {
#[allow(non_snake_case)]
#[cfg(feature = "rt")] #[cfg(feature = "rt")]
#[interrupt] #[interrupt]
unsafe fn $e() { unsafe fn $e() {
@ -298,8 +322,16 @@ pub(crate) mod sealed {
pub trait Channel {} pub trait Channel {}
} }
/// EXTI channel trait.
pub trait Channel: sealed::Channel + Sized { pub trait Channel: sealed::Channel + Sized {
/// Get the EXTI channel number.
fn number(&self) -> usize; fn number(&self) -> usize;
/// Type-erase (degrade) this channel into an `AnyChannel`.
///
/// This converts EXTI channel singletons (`EXTI0`, `EXTI1`, ...), which
/// are all different types, into the same type. It is useful for
/// creating arrays of channels, or avoiding generics.
fn degrade(self) -> AnyChannel { fn degrade(self) -> AnyChannel {
AnyChannel { AnyChannel {
number: self.number() as u8, number: self.number() as u8,
@ -307,9 +339,13 @@ pub trait Channel: sealed::Channel + Sized {
} }
} }
/// Type-erased (degraded) EXTI channel.
///
/// This represents ownership over any EXTI channel, known at runtime.
pub struct AnyChannel { pub struct AnyChannel {
number: u8, number: u8,
} }
impl_peripheral!(AnyChannel); impl_peripheral!(AnyChannel);
impl sealed::Channel for AnyChannel {} impl sealed::Channel for AnyChannel {}
impl Channel for AnyChannel { impl Channel for AnyChannel {

View File

@ -59,7 +59,7 @@ impl embedded_storage_async::nor_flash::ReadNorFlash for Flash<'_, Async> {
const READ_SIZE: usize = super::READ_SIZE; const READ_SIZE: usize = super::READ_SIZE;
async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
self.read(offset, bytes) self.blocking_read(offset, bytes)
} }
fn capacity(&self) -> usize { fn capacity(&self) -> usize {

View File

@ -12,12 +12,14 @@ use super::{
use crate::peripherals::FLASH; use crate::peripherals::FLASH;
use crate::Peripheral; use crate::Peripheral;
/// Internal flash memory driver.
pub struct Flash<'d, MODE = Async> { pub struct Flash<'d, MODE = Async> {
pub(crate) inner: PeripheralRef<'d, FLASH>, pub(crate) inner: PeripheralRef<'d, FLASH>,
pub(crate) _mode: PhantomData<MODE>, pub(crate) _mode: PhantomData<MODE>,
} }
impl<'d> Flash<'d, Blocking> { impl<'d> Flash<'d, Blocking> {
/// Create a new flash driver, usable in blocking mode.
pub fn new_blocking(p: impl Peripheral<P = FLASH> + 'd) -> Self { pub fn new_blocking(p: impl Peripheral<P = FLASH> + 'd) -> Self {
into_ref!(p); into_ref!(p);
@ -29,15 +31,26 @@ impl<'d> Flash<'d, Blocking> {
} }
impl<'d, MODE> Flash<'d, MODE> { impl<'d, MODE> Flash<'d, MODE> {
/// Split this flash driver into one instance per flash memory region.
///
/// See module-level documentation for details on how memory regions work.
pub fn into_blocking_regions(self) -> FlashLayout<'d, Blocking> { pub fn into_blocking_regions(self) -> FlashLayout<'d, Blocking> {
assert!(family::is_default_layout()); assert!(family::is_default_layout());
FlashLayout::new(self.inner) FlashLayout::new(self.inner)
} }
pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { /// Blocking read.
///
/// NOTE: `offset` is an offset from the flash start, NOT an absolute address.
/// For example, to read address `0x0800_1234` you have to use offset `0x1234`.
pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
blocking_read(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes) blocking_read(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes)
} }
/// Blocking write.
///
/// NOTE: `offset` is an offset from the flash start, NOT an absolute address.
/// For example, to write address `0x0800_1234` you have to use offset `0x1234`.
pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
unsafe { unsafe {
blocking_write( blocking_write(
@ -50,6 +63,10 @@ impl<'d, MODE> Flash<'d, MODE> {
} }
} }
/// Blocking erase.
///
/// NOTE: `from` and `to` are offsets from the flash start, NOT an absolute address.
/// For example, to erase address `0x0801_0000` you have to use offset `0x1_0000`.
pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
unsafe { blocking_erase(FLASH_BASE as u32, from, to, erase_sector_unlocked) } unsafe { blocking_erase(FLASH_BASE as u32, from, to, erase_sector_unlocked) }
} }
@ -206,7 +223,7 @@ impl<MODE> embedded_storage::nor_flash::ReadNorFlash for Flash<'_, MODE> {
const READ_SIZE: usize = READ_SIZE; const READ_SIZE: usize = READ_SIZE;
fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
self.read(offset, bytes) self.blocking_read(offset, bytes)
} }
fn capacity(&self) -> usize { fn capacity(&self) -> usize {
@ -230,16 +247,28 @@ impl<MODE> embedded_storage::nor_flash::NorFlash for Flash<'_, MODE> {
foreach_flash_region! { foreach_flash_region! {
($type_name:ident, $write_size:literal, $erase_size:literal) => { ($type_name:ident, $write_size:literal, $erase_size:literal) => {
impl<MODE> crate::_generated::flash_regions::$type_name<'_, MODE> { impl<MODE> crate::_generated::flash_regions::$type_name<'_, MODE> {
/// Blocking read.
///
/// NOTE: `offset` is an offset from the flash start, NOT an absolute address.
/// For example, to read address `0x0800_1234` you have to use offset `0x1234`.
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> {
blocking_read(self.0.base, self.0.size, offset, bytes) blocking_read(self.0.base, self.0.size, offset, bytes)
} }
} }
impl crate::_generated::flash_regions::$type_name<'_, Blocking> { impl crate::_generated::flash_regions::$type_name<'_, Blocking> {
/// Blocking write.
///
/// NOTE: `offset` is an offset from the flash start, NOT an absolute address.
/// For example, to write address `0x0800_1234` you have to use offset `0x1234`.
pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
unsafe { blocking_write(self.0.base, self.0.size, offset, bytes, write_chunk_with_critical_section) } unsafe { blocking_write(self.0.base, self.0.size, offset, bytes, write_chunk_with_critical_section) }
} }
/// Blocking erase.
///
/// NOTE: `from` and `to` are offsets from the flash start, NOT an absolute address.
/// For example, to erase address `0x0801_0000` you have to use offset `0x1_0000`.
pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
unsafe { blocking_erase(self.0.base, from, to, erase_sector_with_critical_section) } unsafe { blocking_erase(self.0.base, from, to, erase_sector_with_critical_section) }
} }

View File

@ -6,11 +6,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
use crate::flash::Error; use crate::flash::Error;
use crate::pac; use crate::pac;
pub const fn is_default_layout() -> bool { pub(crate) const fn is_default_layout() -> bool {
true true
} }
pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
&FLASH_REGIONS &FLASH_REGIONS
} }

View File

@ -6,11 +6,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
use crate::flash::Error; use crate::flash::Error;
use crate::pac; use crate::pac;
pub const fn is_default_layout() -> bool { pub(crate) const fn is_default_layout() -> bool {
true true
} }
pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
&FLASH_REGIONS &FLASH_REGIONS
} }

View File

@ -6,11 +6,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
use crate::flash::Error; use crate::flash::Error;
use crate::pac; use crate::pac;
pub const fn is_default_layout() -> bool { pub(crate) const fn is_default_layout() -> bool {
true true
} }
pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
&FLASH_REGIONS &FLASH_REGIONS
} }

View File

@ -8,11 +8,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
use crate::flash::Error; use crate::flash::Error;
use crate::pac; use crate::pac;
pub const fn is_default_layout() -> bool { pub(crate) const fn is_default_layout() -> bool {
true true
} }
pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
&FLASH_REGIONS &FLASH_REGIONS
} }

View File

@ -6,7 +6,7 @@ use super::{FlashRegion, FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE};
use crate::flash::Error; use crate::flash::Error;
use crate::pac; use crate::pac;
pub const fn is_default_layout() -> bool { pub(crate) const fn is_default_layout() -> bool {
true true
} }
@ -14,7 +14,7 @@ const fn is_dual_bank() -> bool {
FLASH_REGIONS.len() >= 2 FLASH_REGIONS.len() >= 2
} }
pub fn get_flash_regions() -> &'static [&'static FlashRegion] { pub(crate) fn get_flash_regions() -> &'static [&'static FlashRegion] {
&FLASH_REGIONS &FLASH_REGIONS
} }

View File

@ -5,11 +5,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
use crate::flash::Error; use crate::flash::Error;
use crate::pac; use crate::pac;
pub const fn is_default_layout() -> bool { pub(crate) const fn is_default_layout() -> bool {
true true
} }
pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
&FLASH_REGIONS &FLASH_REGIONS
} }

View File

@ -14,50 +14,84 @@ pub use crate::_generated::flash_regions::*;
pub use crate::_generated::MAX_ERASE_SIZE; pub use crate::_generated::MAX_ERASE_SIZE;
pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE};
/// Get whether the default flash layout is being used.
///
/// In some chips, dual-bank is not default. This will then return `false`
/// when dual-bank is enabled.
pub fn is_default_layout() -> bool {
family::is_default_layout()
}
/// Get all flash regions.
pub fn get_flash_regions() -> &'static [&'static FlashRegion] {
family::get_flash_regions()
}
/// Read size (always 1)
pub const READ_SIZE: usize = 1; pub const READ_SIZE: usize = 1;
pub struct Blocking; /// Blocking flash mode typestate.
pub struct Async; pub enum Blocking {}
/// Async flash mode typestate.
pub enum Async {}
/// Flash memory region
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FlashRegion { pub struct FlashRegion {
/// Bank number.
pub bank: FlashBank, pub bank: FlashBank,
/// Absolute base address.
pub base: u32, pub base: u32,
/// Size in bytes.
pub size: u32, pub size: u32,
/// Erase size (sector size).
pub erase_size: u32, pub erase_size: u32,
/// Minimum write size.
pub write_size: u32, pub write_size: u32,
/// Erase value (usually `0xFF`, but is `0x00` in some chips)
pub erase_value: u8, pub erase_value: u8,
pub(crate) _ensure_internal: (), pub(crate) _ensure_internal: (),
} }
#[derive(Debug, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FlashSector {
pub bank: FlashBank,
pub index_in_bank: u8,
pub start: u32,
pub size: u32,
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum FlashBank {
Bank1 = 0,
Bank2 = 1,
Otp,
}
impl FlashRegion { impl FlashRegion {
/// Absolute end address.
pub const fn end(&self) -> u32 { pub const fn end(&self) -> u32 {
self.base + self.size self.base + self.size
} }
/// Number of sectors in the region.
pub const fn sectors(&self) -> u8 { pub const fn sectors(&self) -> u8 {
(self.size / self.erase_size) as u8 (self.size / self.erase_size) as u8
} }
} }
/// Flash sector.
#[derive(Debug, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FlashSector {
/// Bank number.
pub bank: FlashBank,
/// Sector number within the bank.
pub index_in_bank: u8,
/// Absolute start address.
pub start: u32,
/// Size in bytes.
pub size: u32,
}
/// Flash bank.
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum FlashBank {
/// Bank 1
Bank1 = 0,
/// Bank 2
Bank2 = 1,
/// OTP region
Otp,
}
#[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")] #[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")]
#[cfg_attr(flash_f0, path = "f0.rs")] #[cfg_attr(flash_f0, path = "f0.rs")]
#[cfg_attr(flash_f3, path = "f3.rs")] #[cfg_attr(flash_f3, path = "f3.rs")]
@ -78,6 +112,10 @@ mod family;
#[allow(unused_imports)] #[allow(unused_imports)]
pub use family::*; pub use family::*;
/// Flash error
///
/// See STM32 Reference Manual for your chip for details.
#[allow(missing_docs)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error { pub enum Error {

View File

@ -2,11 +2,11 @@
use super::{Error, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use super::{Error, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
pub const fn is_default_layout() -> bool { pub(crate) const fn is_default_layout() -> bool {
true true
} }
pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
&FLASH_REGIONS &FLASH_REGIONS
} }

View File

@ -29,6 +29,11 @@ impl<'d, T: Pin> Flex<'d, T> {
Self { pin } Self { pin }
} }
/// Type-erase (degrade) this pin into an `AnyPin`.
///
/// This converts pin singletons (`PA5`, `PB6`, ...), which
/// are all different types, into the same type. It is useful for
/// creating arrays of pins, or avoiding generics.
#[inline] #[inline]
pub fn degrade(self) -> Flex<'d, AnyPin> { pub fn degrade(self) -> Flex<'d, AnyPin> {
// Safety: We are about to drop the other copy of this pin, so // Safety: We are about to drop the other copy of this pin, so
@ -141,11 +146,13 @@ impl<'d, T: Pin> Flex<'d, T> {
}); });
} }
/// 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.ref_is_low() !self.ref_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 {
self.ref_is_low() self.ref_is_low()
@ -157,17 +164,19 @@ impl<'d, T: Pin> Flex<'d, T> {
state == vals::Idr::LOW state == vals::Idr::LOW
} }
/// Get the current pin input level.
#[inline] #[inline]
pub fn get_level(&mut self) -> Level { pub fn get_level(&mut self) -> Level {
self.is_high().into() self.is_high().into()
} }
/// Get whether the output level is set to high.
#[inline] #[inline]
pub fn is_set_high(&mut self) -> bool { pub fn is_set_high(&mut self) -> bool {
!self.ref_is_set_low() !self.ref_is_set_low()
} }
/// Is the output pin set as low? /// Get whether the output level is set to low.
#[inline] #[inline]
pub fn is_set_low(&mut self) -> bool { pub fn is_set_low(&mut self) -> bool {
self.ref_is_set_low() self.ref_is_set_low()
@ -179,12 +188,13 @@ impl<'d, T: Pin> Flex<'d, T> {
state == vals::Odr::LOW state == vals::Odr::LOW
} }
/// What level output is set to /// Get the current output level.
#[inline] #[inline]
pub fn get_output_level(&mut self) -> Level { pub fn get_output_level(&mut self) -> Level {
self.is_set_high().into() self.is_set_high().into()
} }
/// Set the output as high.
#[inline] #[inline]
pub fn set_high(&mut self) { pub fn set_high(&mut self) {
self.pin.set_high(); self.pin.set_high();
@ -196,6 +206,7 @@ impl<'d, T: Pin> Flex<'d, T> {
self.pin.set_low(); self.pin.set_low();
} }
/// Set the output level.
#[inline] #[inline]
pub fn set_level(&mut self, level: Level) { pub fn set_level(&mut self, level: Level) {
match level { match level {
@ -204,7 +215,7 @@ impl<'d, T: Pin> Flex<'d, T> {
} }
} }
/// Toggle pin output /// Toggle the output level.
#[inline] #[inline]
pub fn toggle(&mut self) { pub fn toggle(&mut self) {
if self.is_set_low() { if self.is_set_low() {
@ -242,8 +253,11 @@ impl<'d, T: Pin> Drop for Flex<'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 Pull { pub enum Pull {
/// No pull
None, None,
/// Pull up
Up, Up,
/// Pull down
Down, Down,
} }
@ -261,6 +275,9 @@ impl From<Pull> for vals::Pupdr {
} }
/// Speed settings /// Speed settings
///
/// These vary dpeending on the chip, ceck the reference manual or datasheet for details.
#[allow(missing_docs)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Speed { pub enum Speed {
@ -305,6 +322,7 @@ pub struct Input<'d, T: Pin> {
} }
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);
@ -312,6 +330,11 @@ impl<'d, T: Pin> Input<'d, T> {
Self { pin } Self { pin }
} }
/// Type-erase (degrade) this pin into an `AnyPin`.
///
/// This converts pin singletons (`PA5`, `PB6`, ...), which
/// are all different types, into the same type. It is useful for
/// creating arrays of pins, or avoiding generics.
#[inline] #[inline]
pub fn degrade(self) -> Input<'d, AnyPin> { pub fn degrade(self) -> Input<'d, AnyPin> {
Input { Input {
@ -319,16 +342,19 @@ impl<'d, T: Pin> Input<'d, T> {
} }
} }
/// 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()
} }
/// Get the current pin input level.
#[inline] #[inline]
pub fn get_level(&mut self) -> Level { pub fn get_level(&mut self) -> Level {
self.pin.get_level() self.pin.get_level()
@ -339,7 +365,9 @@ 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 Level { pub enum Level {
/// Low
Low, Low,
/// High
High, High,
} }
@ -371,6 +399,7 @@ pub struct Output<'d, T: Pin> {
} }
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] and [Speed] configuration.
#[inline] #[inline]
pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, speed: Speed) -> Self { pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, speed: Speed) -> Self {
let mut pin = Flex::new(pin); let mut pin = Flex::new(pin);
@ -382,6 +411,11 @@ impl<'d, T: Pin> Output<'d, T> {
Self { pin } Self { pin }
} }
/// Type-erase (degrade) this pin into an `AnyPin`.
///
/// This converts pin singletons (`PA5`, `PB6`, ...), which
/// are all different types, into the same type. It is useful for
/// creating arrays of pins, or avoiding generics.
#[inline] #[inline]
pub fn degrade(self) -> Output<'d, AnyPin> { pub fn degrade(self) -> Output<'d, AnyPin> {
Output { Output {
@ -442,6 +476,7 @@ pub struct OutputOpenDrain<'d, T: Pin> {
} }
impl<'d, T: Pin> OutputOpenDrain<'d, T> { impl<'d, T: Pin> OutputOpenDrain<'d, T> {
/// Create a new GPIO open drain output driver for a [Pin] with the provided [Level] and [Speed], [Pull] configuration.
#[inline] #[inline]
pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, speed: Speed, pull: Pull) -> Self { pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, speed: Speed, pull: Pull) -> Self {
let mut pin = Flex::new(pin); let mut pin = Flex::new(pin);
@ -455,6 +490,11 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
Self { pin } Self { pin }
} }
/// Type-erase (degrade) this pin into an `AnyPin`.
///
/// This converts pin singletons (`PA5`, `PB6`, ...), which
/// are all different types, into the same type. It is useful for
/// creating arrays of pins, or avoiding generics.
#[inline] #[inline]
pub fn degrade(self) -> Output<'d, AnyPin> { pub fn degrade(self) -> Output<'d, AnyPin> {
Output { Output {
@ -462,17 +502,19 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
} }
} }
/// 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_low() !self.pin.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 {
self.pin.is_low() self.pin.is_low()
} }
/// Returns current pin level /// Get the current pin input level.
#[inline] #[inline]
pub fn get_level(&mut self) -> Level { pub fn get_level(&mut self) -> Level {
self.pin.get_level() self.pin.get_level()
@ -496,19 +538,19 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
self.pin.set_level(level); self.pin.set_level(level);
} }
/// Is the output pin set as high? /// Get whether the output level is set to high.
#[inline] #[inline]
pub fn is_set_high(&mut self) -> bool { pub fn is_set_high(&mut self) -> bool {
self.pin.is_set_high() self.pin.is_set_high()
} }
/// Is the output pin set as low? /// Get whether the output level is set to low.
#[inline] #[inline]
pub fn is_set_low(&mut self) -> bool { pub fn is_set_low(&mut self) -> bool {
self.pin.is_set_low() self.pin.is_set_low()
} }
/// What level output is set to /// Get the current output level.
#[inline] #[inline]
pub fn get_output_level(&mut self) -> Level { pub fn get_output_level(&mut self) -> Level {
self.pin.get_output_level() self.pin.get_output_level()
@ -521,8 +563,11 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
} }
} }
/// GPIO output type
pub enum OutputType { pub enum OutputType {
/// Drive the pin both high or low.
PushPull, PushPull,
/// Drive the pin low, or don't drive it at all if the output level is high.
OpenDrain, OpenDrain,
} }
@ -535,6 +580,7 @@ impl From<OutputType> for sealed::AFType {
} }
} }
#[allow(missing_docs)]
pub(crate) mod sealed { pub(crate) mod sealed {
use super::*; use super::*;
@ -542,8 +588,11 @@ pub(crate) mod sealed {
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum AFType { pub enum AFType {
/// Input
Input, Input,
/// Output, drive the pin both high or low.
OutputPushPull, OutputPushPull,
/// Output, drive the pin low, or don't drive it at all if the output level is high.
OutputOpenDrain, OutputOpenDrain,
} }
@ -686,7 +735,11 @@ pub(crate) mod sealed {
} }
} }
/// GPIO pin trait.
pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'static { pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'static {
/// EXTI channel assigned to this pin.
///
/// For example, PC4 uses EXTI4.
#[cfg(feature = "exti")] #[cfg(feature = "exti")]
type ExtiChannel: crate::exti::Channel; type ExtiChannel: crate::exti::Channel;
@ -702,7 +755,11 @@ pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'stat
self._port() self._port()
} }
/// Convert from concrete pin type PX_XX to type erased `AnyPin`. /// Type-erase (degrade) this pin into an `AnyPin`.
///
/// This converts pin singletons (`PA5`, `PB6`, ...), which
/// are all different types, into the same type. It is useful for
/// creating arrays of pins, or avoiding generics.
#[inline] #[inline]
fn degrade(self) -> AnyPin { fn degrade(self) -> AnyPin {
AnyPin { AnyPin {
@ -711,12 +768,15 @@ pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'stat
} }
} }
// Type-erased GPIO pin /// Type-erased GPIO pin
pub struct AnyPin { pub struct AnyPin {
pin_port: u8, pin_port: u8,
} }
impl AnyPin { impl AnyPin {
/// Unsafely create an `AnyPin` from a pin+port number.
///
/// `pin_port` is `port_num * 16 + pin_num`, where `port_num` is 0 for port `A`, 1 for port `B`, etc...
#[inline] #[inline]
pub unsafe fn steal(pin_port: u8) -> Self { pub unsafe fn steal(pin_port: u8) -> Self {
Self { pin_port } Self { pin_port }
@ -727,6 +787,8 @@ impl AnyPin {
self.pin_port / 16 self.pin_port / 16
} }
/// Get the GPIO register block for this pin.
#[cfg(feature = "unstable-pac")]
#[inline] #[inline]
pub fn block(&self) -> gpio::Gpio { pub fn block(&self) -> gpio::Gpio {
pac::GPIO(self._port() as _) pac::GPIO(self._port() as _)
@ -1072,6 +1134,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> {
} }
} }
/// Low-level GPIO manipulation.
#[cfg(feature = "unstable-pac")] #[cfg(feature = "unstable-pac")]
pub mod low_level { pub mod low_level {
pub use super::sealed::*; pub use super::sealed::*;

View File

@ -13,15 +13,23 @@ use embassy_sync::waitqueue::AtomicWaker;
use crate::peripherals; use crate::peripherals;
/// I2C error.
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error { pub enum Error {
/// Bus error
Bus, Bus,
/// Arbitration lost
Arbitration, Arbitration,
/// ACK not received (either to the address or to a data byte)
Nack, Nack,
/// Timeout
Timeout, Timeout,
/// CRC error
Crc, Crc,
/// Overrun error
Overrun, Overrun,
/// Zero-length transfers are not allowed.
ZeroLengthTransfer, ZeroLengthTransfer,
} }
@ -47,8 +55,11 @@ pub(crate) mod sealed {
} }
} }
/// I2C peripheral instance
pub trait Instance: sealed::Instance + 'static { pub trait Instance: sealed::Instance + 'static {
/// Event interrupt for this instance
type EventInterrupt: interrupt::typelevel::Interrupt; type EventInterrupt: interrupt::typelevel::Interrupt;
/// Error interrupt for this instance
type ErrorInterrupt: interrupt::typelevel::Interrupt; type ErrorInterrupt: interrupt::typelevel::Interrupt;
} }
@ -57,7 +68,7 @@ pin_trait!(SdaPin, Instance);
dma_trait!(RxDma, Instance); dma_trait!(RxDma, Instance);
dma_trait!(TxDma, Instance); dma_trait!(TxDma, Instance);
/// Interrupt handler. /// Event interrupt handler.
pub struct EventInterruptHandler<T: Instance> { pub struct EventInterruptHandler<T: Instance> {
_phantom: PhantomData<T>, _phantom: PhantomData<T>,
} }
@ -68,6 +79,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::EventInterrupt> for EventInte
} }
} }
/// Error interrupt handler.
pub struct ErrorInterruptHandler<T: Instance> { pub struct ErrorInterruptHandler<T: Instance> {
_phantom: PhantomData<T>, _phantom: PhantomData<T>,
} }

View File

@ -18,12 +18,17 @@ impl Into<u8> for QspiMode {
} }
} }
/// QSPI lane width
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum QspiWidth { pub enum QspiWidth {
/// None
NONE, NONE,
/// Single lane
SING, SING,
/// Dual lanes
DUAL, DUAL,
/// Quad lanes
QUAD, QUAD,
} }
@ -38,10 +43,13 @@ impl Into<u8> for QspiWidth {
} }
} }
/// Flash bank selection
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum FlashSelection { pub enum FlashSelection {
/// Bank 1
Flash1, Flash1,
/// Bank 2
Flash2, Flash2,
} }
@ -54,6 +62,8 @@ impl Into<bool> for FlashSelection {
} }
} }
/// QSPI memory size.
#[allow(missing_docs)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum MemorySize { pub enum MemorySize {
_1KiB, _1KiB,
@ -113,11 +123,16 @@ impl Into<u8> for MemorySize {
} }
} }
/// QSPI Address size
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum AddressSize { pub enum AddressSize {
/// 8-bit address
_8Bit, _8Bit,
/// 16-bit address
_16Bit, _16Bit,
/// 24-bit address
_24bit, _24bit,
/// 32-bit address
_32bit, _32bit,
} }
@ -132,8 +147,10 @@ impl Into<u8> for AddressSize {
} }
} }
/// Time the Chip Select line stays high.
#[allow(missing_docs)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum ChipSelectHightTime { pub enum ChipSelectHighTime {
_1Cycle, _1Cycle,
_2Cycle, _2Cycle,
_3Cycle, _3Cycle,
@ -144,21 +161,23 @@ pub enum ChipSelectHightTime {
_8Cycle, _8Cycle,
} }
impl Into<u8> for ChipSelectHightTime { impl Into<u8> for ChipSelectHighTime {
fn into(self) -> u8 { fn into(self) -> u8 {
match self { match self {
ChipSelectHightTime::_1Cycle => 0, ChipSelectHighTime::_1Cycle => 0,
ChipSelectHightTime::_2Cycle => 1, ChipSelectHighTime::_2Cycle => 1,
ChipSelectHightTime::_3Cycle => 2, ChipSelectHighTime::_3Cycle => 2,
ChipSelectHightTime::_4Cycle => 3, ChipSelectHighTime::_4Cycle => 3,
ChipSelectHightTime::_5Cycle => 4, ChipSelectHighTime::_5Cycle => 4,
ChipSelectHightTime::_6Cycle => 5, ChipSelectHighTime::_6Cycle => 5,
ChipSelectHightTime::_7Cycle => 6, ChipSelectHighTime::_7Cycle => 6,
ChipSelectHightTime::_8Cycle => 7, ChipSelectHighTime::_8Cycle => 7,
} }
} }
} }
/// FIFO threshold.
#[allow(missing_docs)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum FIFOThresholdLevel { pub enum FIFOThresholdLevel {
_1Bytes, _1Bytes,
@ -234,6 +253,8 @@ impl Into<u8> for FIFOThresholdLevel {
} }
} }
/// Dummy cycle count
#[allow(missing_docs)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum DummyCycles { pub enum DummyCycles {
_0, _0,

View File

@ -54,7 +54,7 @@ pub struct Config {
/// Number of bytes to trigger FIFO threshold flag. /// Number of bytes to trigger FIFO threshold flag.
pub fifo_threshold: FIFOThresholdLevel, pub fifo_threshold: FIFOThresholdLevel,
/// Minimum number of cycles that chip select must be high between issued commands /// Minimum number of cycles that chip select must be high between issued commands
pub cs_high_time: ChipSelectHightTime, pub cs_high_time: ChipSelectHighTime,
} }
impl Default for Config { impl Default for Config {
@ -64,7 +64,7 @@ impl Default for Config {
address_size: AddressSize::_24bit, address_size: AddressSize::_24bit,
prescaler: 128, prescaler: 128,
fifo_threshold: FIFOThresholdLevel::_17Bytes, fifo_threshold: FIFOThresholdLevel::_17Bytes,
cs_high_time: ChipSelectHightTime::_5Cycle, cs_high_time: ChipSelectHighTime::_5Cycle,
} }
} }
} }

View File

@ -583,10 +583,10 @@ fn get_ring_buffer<'d, T: Instance, C: Channel, W: word::Word>(
}; };
match tx_rx { match tx_rx {
TxRx::Transmitter => RingBuffer::Writable(unsafe { TxRx::Transmitter => RingBuffer::Writable(unsafe {
WritableRingBuffer::new_write(dma, request, dr(T::REGS, sub_block), dma_buf, opts) WritableRingBuffer::new(dma, request, dr(T::REGS, sub_block), dma_buf, opts)
}), }),
TxRx::Receiver => RingBuffer::Readable(unsafe { TxRx::Receiver => RingBuffer::Readable(unsafe {
ReadableRingBuffer::new_read(dma, request, dr(T::REGS, sub_block), dma_buf, opts) ReadableRingBuffer::new(dma, request, dr(T::REGS, sub_block), dma_buf, opts)
}), }),
} }
} }

View File

@ -2,7 +2,9 @@
macro_rules! pin_trait { macro_rules! pin_trait {
($signal:ident, $instance:path) => { ($signal:ident, $instance:path) => {
#[doc = concat!(stringify!($signal), " pin trait")]
pub trait $signal<T: $instance>: crate::gpio::Pin { pub trait $signal<T: $instance>: crate::gpio::Pin {
#[doc = concat!("Get the AF number needed to use this pin as", stringify!($signal))]
fn af_num(&self) -> u8; fn af_num(&self) -> u8;
} }
}; };
@ -22,7 +24,11 @@ macro_rules! pin_trait_impl {
macro_rules! dma_trait { macro_rules! dma_trait {
($signal:ident, $instance:path) => { ($signal:ident, $instance:path) => {
#[doc = concat!(stringify!($signal), " DMA request trait")]
pub trait $signal<T: $instance>: crate::dma::Channel { pub trait $signal<T: $instance>: crate::dma::Channel {
#[doc = concat!("Get the DMA request number needed to use this channel as", stringify!($signal))]
/// Note: in some chips, ST calls this the "channel", and calls channels "streams".
/// `embassy-stm32` always uses the "channel" and "request number" names.
fn request(&self) -> crate::dma::Request; fn request(&self) -> crate::dma::Request;
} }
}; };

View File

@ -39,7 +39,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> {
let rx_dma = unsafe { self.rx_dma.clone_unchecked() }; let rx_dma = unsafe { self.rx_dma.clone_unchecked() };
let _peri = unsafe { self._peri.clone_unchecked() }; let _peri = unsafe { self._peri.clone_unchecked() };
let ring_buf = unsafe { ReadableRingBuffer::new_read(rx_dma, request, rdr(T::regs()), dma_buf, opts) }; let ring_buf = unsafe { ReadableRingBuffer::new(rx_dma, request, rdr(T::regs()), dma_buf, opts) };
// Don't disable the clock // Don't disable the clock
mem::forget(self); mem::forget(self);

View File

@ -31,7 +31,7 @@ fn test_flash(f: &mut Flash<'_, Blocking>, offset: u32, size: u32) {
info!("Reading..."); info!("Reading...");
let mut buf = [0u8; 32]; let mut buf = [0u8; 32];
unwrap!(f.read(offset, &mut buf)); unwrap!(f.blocking_read(offset, &mut buf));
info!("Read: {=[u8]:x}", buf); info!("Read: {=[u8]:x}", buf);
info!("Erasing..."); info!("Erasing...");
@ -39,7 +39,7 @@ fn test_flash(f: &mut Flash<'_, Blocking>, offset: u32, size: u32) {
info!("Reading..."); info!("Reading...");
let mut buf = [0u8; 32]; let mut buf = [0u8; 32];
unwrap!(f.read(offset, &mut buf)); unwrap!(f.blocking_read(offset, &mut buf));
info!("Read after erase: {=[u8]:x}", buf); info!("Read after erase: {=[u8]:x}", buf);
info!("Writing..."); info!("Writing...");
@ -53,7 +53,7 @@ fn test_flash(f: &mut Flash<'_, Blocking>, offset: u32, size: u32) {
info!("Reading..."); info!("Reading...");
let mut buf = [0u8; 32]; let mut buf = [0u8; 32];
unwrap!(f.read(offset, &mut buf)); unwrap!(f.blocking_read(offset, &mut buf));
info!("Read: {=[u8]:x}", buf); info!("Read: {=[u8]:x}", buf);
assert_eq!( assert_eq!(
&buf[..], &buf[..],

View File

@ -48,7 +48,7 @@ async fn test_flash<'a>(f: &mut Flash<'a>, offset: u32, size: u32) {
info!("Reading..."); info!("Reading...");
let mut buf = [0u8; 32]; let mut buf = [0u8; 32];
unwrap!(f.read(offset, &mut buf)); unwrap!(f.blocking_read(offset, &mut buf));
info!("Read: {=[u8]:x}", buf); info!("Read: {=[u8]:x}", buf);
info!("Erasing..."); info!("Erasing...");
@ -56,7 +56,7 @@ async fn test_flash<'a>(f: &mut Flash<'a>, offset: u32, size: u32) {
info!("Reading..."); info!("Reading...");
let mut buf = [0u8; 32]; let mut buf = [0u8; 32];
unwrap!(f.read(offset, &mut buf)); unwrap!(f.blocking_read(offset, &mut buf));
info!("Read after erase: {=[u8]:x}", buf); info!("Read after erase: {=[u8]:x}", buf);
info!("Writing..."); info!("Writing...");
@ -73,7 +73,7 @@ async fn test_flash<'a>(f: &mut Flash<'a>, offset: u32, size: u32) {
info!("Reading..."); info!("Reading...");
let mut buf = [0u8; 32]; let mut buf = [0u8; 32];
unwrap!(f.read(offset, &mut buf)); unwrap!(f.blocking_read(offset, &mut buf));
info!("Read: {=[u8]:x}", buf); info!("Read: {=[u8]:x}", buf);
assert_eq!( assert_eq!(
&buf[..], &buf[..],