Merge branch 'main' of https://github.com/embassy-rs/embassy into hrtim

This commit is contained in:
xoviat
2023-07-01 17:32:25 -05:00
109 changed files with 1835 additions and 933 deletions

View File

@ -74,7 +74,7 @@ critical-section = { version = "1.1", features = ["std"] }
[build-dependencies]
proc-macro2 = "1.0.36"
quote = "1.0.15"
stm32-metapac = { version = "10", default-features = false, features = ["metadata"]}
stm32-metapac = { version = "12", default-features = false, features = ["metadata"]}
[features]
default = ["rt"]

View File

@ -709,6 +709,8 @@ fn main() {
// SDMMCv1 uses the same channel for both directions, so just implement for RX
(("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)),
(("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)),
(("dac", "CH1"), quote!(crate::dac::DmaCh1)),
(("dac", "CH2"), quote!(crate::dac::DmaCh2)),
]
.into();

View File

@ -211,10 +211,8 @@ impl<'d, T: Instance> Adc<'d, T> {
#[cfg(not(stm32g0))]
fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
let sample_time = sample_time.into();
if ch <= 9 {
T::regs().smpr1().modify(|reg| reg.set_smp(ch as _, sample_time));
} else {
T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
}
T::regs()
.smpr(ch as usize / 10)
.modify(|reg| reg.set_smp(ch as usize % 10, sample_time));
}
}

View File

@ -116,10 +116,10 @@ impl<'d, T: Instance> Can<'d, T> {
T::regs().ier().write(|w| {
// TODO: fix metapac
w.set_errie(Errie(1));
w.set_fmpie(0, Fmpie(1));
w.set_fmpie(1, Fmpie(1));
w.set_tmeie(Tmeie(1));
w.set_errie(Errie::from_bits(1));
w.set_fmpie(0, Fmpie::from_bits(1));
w.set_fmpie(1, Fmpie::from_bits(1));
w.set_tmeie(Tmeie::from_bits(1));
});
T::regs().mcr().write(|w| {

View File

@ -1,260 +0,0 @@
#![macro_use]
use embassy_hal_common::{into_ref, PeripheralRef};
use crate::pac::dac;
use crate::rcc::RccPeripheral;
use crate::{peripherals, Peripheral};
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
UnconfiguredChannel,
InvalidValue,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Channel {
Ch1,
Ch2,
}
impl Channel {
fn index(&self) -> usize {
match self {
Channel::Ch1 => 0,
Channel::Ch2 => 1,
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Ch1Trigger {
Tim6,
Tim3,
Tim7,
Tim15,
Tim2,
Exti9,
Software,
}
impl Ch1Trigger {
fn tsel(&self) -> dac::vals::Tsel1 {
match self {
Ch1Trigger::Tim6 => dac::vals::Tsel1::TIM6_TRGO,
Ch1Trigger::Tim3 => dac::vals::Tsel1::TIM3_TRGO,
Ch1Trigger::Tim7 => dac::vals::Tsel1::TIM7_TRGO,
Ch1Trigger::Tim15 => dac::vals::Tsel1::TIM15_TRGO,
Ch1Trigger::Tim2 => dac::vals::Tsel1::TIM2_TRGO,
Ch1Trigger::Exti9 => dac::vals::Tsel1::EXTI9,
Ch1Trigger::Software => dac::vals::Tsel1::SOFTWARE,
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Ch2Trigger {
Tim6,
Tim8,
Tim7,
Tim5,
Tim2,
Tim4,
Exti9,
Software,
}
impl Ch2Trigger {
fn tsel(&self) -> dac::vals::Tsel2 {
match self {
Ch2Trigger::Tim6 => dac::vals::Tsel2::TIM6_TRGO,
Ch2Trigger::Tim8 => dac::vals::Tsel2::TIM8_TRGO,
Ch2Trigger::Tim7 => dac::vals::Tsel2::TIM7_TRGO,
Ch2Trigger::Tim5 => dac::vals::Tsel2::TIM5_TRGO,
Ch2Trigger::Tim2 => dac::vals::Tsel2::TIM2_TRGO,
Ch2Trigger::Tim4 => dac::vals::Tsel2::TIM4_TRGO,
Ch2Trigger::Exti9 => dac::vals::Tsel2::EXTI9,
Ch2Trigger::Software => dac::vals::Tsel2::SOFTWARE,
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Alignment {
Left,
Right,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Value {
Bit8(u8),
Bit12(u16, Alignment),
}
pub struct Dac<'d, T: Instance> {
channels: u8,
_peri: PeripheralRef<'d, T>,
}
impl<'d, T: Instance> Dac<'d, T> {
pub fn new_1ch(peri: impl Peripheral<P = T> + 'd, _ch1: impl Peripheral<P = impl DacPin<T, 1>> + 'd) -> Self {
into_ref!(peri);
Self::new_inner(peri, 1)
}
pub fn new_2ch(
peri: impl Peripheral<P = T> + 'd,
_ch1: impl Peripheral<P = impl DacPin<T, 1>> + 'd,
_ch2: impl Peripheral<P = impl DacPin<T, 2>> + 'd,
) -> Self {
into_ref!(peri);
Self::new_inner(peri, 2)
}
fn new_inner(peri: PeripheralRef<'d, T>, channels: u8) -> Self {
T::enable();
T::reset();
T::regs().cr().modify(|reg| {
for ch in 0..channels {
reg.set_en(ch as usize, true);
}
});
Self { channels, _peri: peri }
}
/// Check the channel is configured
fn check_channel_exists(&self, ch: Channel) -> Result<(), Error> {
if ch == Channel::Ch2 && self.channels < 2 {
Err(Error::UnconfiguredChannel)
} else {
Ok(())
}
}
fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> {
self.check_channel_exists(ch)?;
T::regs().cr().modify(|reg| {
reg.set_en(ch.index(), on);
});
Ok(())
}
pub fn enable_channel(&mut self, ch: Channel) -> Result<(), Error> {
self.set_channel_enable(ch, true)
}
pub fn disable_channel(&mut self, ch: Channel) -> Result<(), Error> {
self.set_channel_enable(ch, false)
}
pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> {
self.check_channel_exists(Channel::Ch1)?;
unwrap!(self.disable_channel(Channel::Ch1));
T::regs().cr().modify(|reg| {
reg.set_tsel1(trigger.tsel());
});
Ok(())
}
pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> {
self.check_channel_exists(Channel::Ch2)?;
unwrap!(self.disable_channel(Channel::Ch2));
T::regs().cr().modify(|reg| {
reg.set_tsel2(trigger.tsel());
});
Ok(())
}
pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> {
self.check_channel_exists(ch)?;
T::regs().swtrigr().write(|reg| {
reg.set_swtrig(ch.index(), true);
});
Ok(())
}
pub fn trigger_all(&mut self) {
T::regs().swtrigr().write(|reg| {
reg.set_swtrig(Channel::Ch1.index(), true);
reg.set_swtrig(Channel::Ch2.index(), true);
});
}
pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> {
self.check_channel_exists(ch)?;
match value {
Value::Bit8(v) => T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)),
Value::Bit12(v, Alignment::Left) => T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)),
Value::Bit12(v, Alignment::Right) => T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v)),
}
Ok(())
}
}
pub(crate) mod sealed {
pub trait Instance {
fn regs() -> &'static crate::pac::dac::Dac;
}
}
pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
foreach_peripheral!(
(dac, $inst:ident) => {
// H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented
#[cfg(rcc_h7)]
impl crate::rcc::sealed::RccPeripheral for peripherals::$inst {
fn frequency() -> crate::time::Hertz {
critical_section::with(|_| unsafe {
crate::rcc::get_freqs().apb1
})
}
fn reset() {
critical_section::with(|_| {
crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true));
crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false));
})
}
fn enable() {
critical_section::with(|_| {
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true));
})
}
fn disable() {
critical_section::with(|_| {
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false));
})
}
}
#[cfg(rcc_h7)]
impl crate::rcc::RccPeripheral for peripherals::$inst {}
impl crate::dac::sealed::Instance for peripherals::$inst {
fn regs() -> &'static crate::pac::dac::Dac {
&crate::pac::$inst
}
}
impl crate::dac::Instance for peripherals::$inst {}
};
);
macro_rules! impl_dac_pin {
($inst:ident, $pin:ident, $ch:expr) => {
impl crate::dac::DacPin<peripherals::$inst, $ch> for crate::peripherals::$pin {}
};
}

View File

@ -0,0 +1,570 @@
#![macro_use]
//! Provide access to the STM32 digital-to-analog converter (DAC).
use core::marker::PhantomData;
use embassy_hal_common::{into_ref, PeripheralRef};
use crate::pac::dac;
use crate::rcc::RccPeripheral;
use crate::{peripherals, Peripheral};
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Curstom Errors
pub enum Error {
UnconfiguredChannel,
InvalidValue,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// DAC Channels
pub enum Channel {
Ch1,
Ch2,
}
impl Channel {
const fn index(&self) -> usize {
match self {
Channel::Ch1 => 0,
Channel::Ch2 => 1,
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Trigger sources for CH1
pub enum Ch1Trigger {
Tim6,
Tim3,
Tim7,
Tim15,
Tim2,
Exti9,
Software,
}
impl Ch1Trigger {
fn tsel(&self) -> dac::vals::Tsel1 {
match self {
Ch1Trigger::Tim6 => dac::vals::Tsel1::TIM6_TRGO,
Ch1Trigger::Tim3 => dac::vals::Tsel1::TIM3_TRGO,
Ch1Trigger::Tim7 => dac::vals::Tsel1::TIM7_TRGO,
Ch1Trigger::Tim15 => dac::vals::Tsel1::TIM15_TRGO,
Ch1Trigger::Tim2 => dac::vals::Tsel1::TIM2_TRGO,
Ch1Trigger::Exti9 => dac::vals::Tsel1::EXTI9,
Ch1Trigger::Software => dac::vals::Tsel1::SOFTWARE,
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Trigger sources for CH2
pub enum Ch2Trigger {
Tim6,
Tim8,
Tim7,
Tim5,
Tim2,
Tim4,
Exti9,
Software,
}
impl Ch2Trigger {
fn tsel(&self) -> dac::vals::Tsel2 {
match self {
Ch2Trigger::Tim6 => dac::vals::Tsel2::TIM6_TRGO,
Ch2Trigger::Tim8 => dac::vals::Tsel2::TIM8_TRGO,
Ch2Trigger::Tim7 => dac::vals::Tsel2::TIM7_TRGO,
Ch2Trigger::Tim5 => dac::vals::Tsel2::TIM5_TRGO,
Ch2Trigger::Tim2 => dac::vals::Tsel2::TIM2_TRGO,
Ch2Trigger::Tim4 => dac::vals::Tsel2::TIM4_TRGO,
Ch2Trigger::Exti9 => dac::vals::Tsel2::EXTI9,
Ch2Trigger::Software => dac::vals::Tsel2::SOFTWARE,
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Single 8 or 12 bit value that can be output by the DAC
pub enum Value {
// 8 bit value
Bit8(u8),
// 12 bit value stored in a u16, left-aligned
Bit12Left(u16),
// 12 bit value stored in a u16, right-aligned
Bit12Right(u16),
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Array variant of [`Value`]
pub enum ValueArray<'a> {
// 8 bit values
Bit8(&'a [u8]),
// 12 bit value stored in a u16, left-aligned
Bit12Left(&'a [u16]),
// 12 bit values stored in a u16, right-aligned
Bit12Right(&'a [u16]),
}
/// Provide common functions for DAC channels
pub trait DacChannel<T: Instance, Tx> {
const CHANNEL: Channel;
/// Enable trigger of the given channel
fn set_trigger_enable(&mut self, on: bool) -> Result<(), Error> {
T::regs().cr().modify(|reg| {
reg.set_ten(Self::CHANNEL.index(), on);
});
Ok(())
}
/// Set mode register of the given channel
#[cfg(dac_v2)]
fn set_channel_mode(&mut self, val: u8) -> Result<(), Error> {
T::regs().mcr().modify(|reg| {
reg.set_mode(Self::CHANNEL.index(), val);
});
Ok(())
}
/// Set enable register of the given channel
fn set_channel_enable(&mut self, on: bool) -> Result<(), Error> {
T::regs().cr().modify(|reg| {
reg.set_en(Self::CHANNEL.index(), on);
});
Ok(())
}
/// Enable the DAC channel `ch`
fn enable_channel(&mut self) -> Result<(), Error> {
self.set_channel_enable(true)
}
/// Disable the DAC channel `ch`
fn disable_channel(&mut self) -> Result<(), Error> {
self.set_channel_enable(false)
}
/// Perform a software trigger on `ch`
fn trigger(&mut self) {
T::regs().swtrigr().write(|reg| {
reg.set_swtrig(Self::CHANNEL.index(), true);
});
}
/// Set a value to be output by the DAC on trigger.
///
/// The `value` is written to the corresponding "data holding register".
fn set(&mut self, value: Value) -> Result<(), Error> {
match value {
Value::Bit8(v) => T::regs().dhr8r(Self::CHANNEL.index()).write(|reg| reg.set_dhr(v)),
Value::Bit12Left(v) => T::regs().dhr12l(Self::CHANNEL.index()).write(|reg| reg.set_dhr(v)),
Value::Bit12Right(v) => T::regs().dhr12r(Self::CHANNEL.index()).write(|reg| reg.set_dhr(v)),
}
Ok(())
}
}
/// Hold two DAC channels
///
/// Note: This consumes the DAC `Instance` only once, allowing to get both channels simultaneously.
///
/// # Example for obtaining both DAC channels
///
/// ```ignore
/// // DMA channels and pins may need to be changed for your controller
/// let (dac_ch1, dac_ch2) =
/// embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split();
/// ```
pub struct Dac<'d, T: Instance, TxCh1, TxCh2> {
ch1: DacCh1<'d, T, TxCh1>,
ch2: DacCh2<'d, T, TxCh2>,
}
/// DAC CH1
///
/// Note: This consumes the DAC `Instance`. Use [`Dac::new`] to get both channels simultaneously.
pub struct DacCh1<'d, T: Instance, Tx> {
/// To consume T
_peri: PeripheralRef<'d, T>,
#[allow(unused)] // For chips whose DMA is not (yet) supported
dma: PeripheralRef<'d, Tx>,
}
/// DAC CH2
///
/// Note: This consumes the DAC `Instance`. Use [`Dac::new`] to get both channels simultaneously.
pub struct DacCh2<'d, T: Instance, Tx> {
/// Instead of PeripheralRef to consume T
phantom: PhantomData<&'d mut T>,
#[allow(unused)] // For chips whose DMA is not (yet) supported
dma: PeripheralRef<'d, Tx>,
}
impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
/// Obtain DAC CH1
pub fn new(
peri: impl Peripheral<P = T> + 'd,
dma: impl Peripheral<P = Tx> + 'd,
_pin: impl Peripheral<P = impl DacPin<T, 1>> + 'd,
) -> Self {
into_ref!(peri, dma);
T::enable();
T::reset();
let mut dac = Self { _peri: peri, dma };
// Configure each activated channel. All results can be `unwrap`ed since they
// will only error if the channel is not configured (i.e. ch1, ch2 are false)
#[cfg(dac_v2)]
dac.set_channel_mode(0).unwrap();
dac.enable_channel().unwrap();
dac.set_trigger_enable(true).unwrap();
dac
}
/// Select a new trigger for this channel
///
/// **Important**: This disables the channel!
pub fn select_trigger(&mut self, trigger: Ch1Trigger) -> Result<(), Error> {
unwrap!(self.disable_channel());
T::regs().cr().modify(|reg| {
reg.set_tsel1(trigger.tsel());
});
Ok(())
}
/// Write `data` to the DAC CH1 via DMA.
///
/// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
/// This will configure a circular DMA transfer that periodically outputs the `data`.
/// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
///
/// **Important:** Channel 1 has to be configured for the DAC instance!
#[cfg(all(bdma, not(dma)))] // It currently only works with BDMA-only chips (DMA should theoretically work though)
pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
where
Tx: DmaCh1<T>,
{
let channel = Channel::Ch1.index();
debug!("Writing to channel {}", channel);
// Enable DAC and DMA
T::regs().cr().modify(|w| {
w.set_en(channel, true);
w.set_dmaen(channel, true);
});
let tx_request = self.dma.request();
let dma_channel = &self.dma;
let tx_options = crate::dma::TransferOptions {
circular,
half_transfer_ir: false,
complete_transfer_ir: !circular,
..Default::default()
};
// Initiate the correct type of DMA transfer depending on what data is passed
let tx_f = match data {
ValueArray::Bit8(buf) => unsafe {
crate::dma::Transfer::new_write(
dma_channel,
tx_request,
buf,
T::regs().dhr8r(channel).as_ptr() as *mut u8,
tx_options,
)
},
ValueArray::Bit12Left(buf) => unsafe {
crate::dma::Transfer::new_write(
dma_channel,
tx_request,
buf,
T::regs().dhr12l(channel).as_ptr() as *mut u16,
tx_options,
)
},
ValueArray::Bit12Right(buf) => unsafe {
crate::dma::Transfer::new_write(
dma_channel,
tx_request,
buf,
T::regs().dhr12r(channel).as_ptr() as *mut u16,
tx_options,
)
},
};
tx_f.await;
// finish dma
// TODO: Do we need to check any status registers here?
T::regs().cr().modify(|w| {
// Disable the DAC peripheral
w.set_en(channel, false);
// Disable the DMA. TODO: Is this necessary?
w.set_dmaen(channel, false);
});
Ok(())
}
}
impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
/// Obtain DAC CH2
pub fn new(
_peri: impl Peripheral<P = T> + 'd,
dma: impl Peripheral<P = Tx> + 'd,
_pin: impl Peripheral<P = impl DacPin<T, 2>> + 'd,
) -> Self {
into_ref!(_peri, dma);
T::enable();
T::reset();
let mut dac = Self {
phantom: PhantomData,
dma,
};
// Configure each activated channel. All results can be `unwrap`ed since they
// will only error if the channel is not configured (i.e. ch1, ch2 are false)
#[cfg(dac_v2)]
dac.set_channel_mode(0).unwrap();
dac.enable_channel().unwrap();
dac.set_trigger_enable(true).unwrap();
dac
}
/// Select a new trigger for this channel
pub fn select_trigger(&mut self, trigger: Ch2Trigger) -> Result<(), Error> {
unwrap!(self.disable_channel());
T::regs().cr().modify(|reg| {
reg.set_tsel2(trigger.tsel());
});
Ok(())
}
/// Write `data` to the DAC CH2 via DMA.
///
/// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
/// This will configure a circular DMA transfer that periodically outputs the `data`.
/// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
///
/// **Important:** Channel 2 has to be configured for the DAC instance!
#[cfg(all(bdma, not(dma)))] // It currently only works with BDMA-only chips (DMA should theoretically work though)
pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
where
Tx: DmaCh2<T>,
{
let channel = Channel::Ch2.index();
debug!("Writing to channel {}", channel);
// Enable DAC and DMA
T::regs().cr().modify(|w| {
w.set_en(channel, true);
w.set_dmaen(channel, true);
});
let tx_request = self.dma.request();
let dma_channel = &self.dma;
let tx_options = crate::dma::TransferOptions {
circular,
half_transfer_ir: false,
complete_transfer_ir: !circular,
..Default::default()
};
// Initiate the correct type of DMA transfer depending on what data is passed
let tx_f = match data {
ValueArray::Bit8(buf) => unsafe {
crate::dma::Transfer::new_write(
dma_channel,
tx_request,
buf,
T::regs().dhr8r(channel).as_ptr() as *mut u8,
tx_options,
)
},
ValueArray::Bit12Left(buf) => unsafe {
crate::dma::Transfer::new_write(
dma_channel,
tx_request,
buf,
T::regs().dhr12l(channel).as_ptr() as *mut u16,
tx_options,
)
},
ValueArray::Bit12Right(buf) => unsafe {
crate::dma::Transfer::new_write(
dma_channel,
tx_request,
buf,
T::regs().dhr12r(channel).as_ptr() as *mut u16,
tx_options,
)
},
};
tx_f.await;
// finish dma
// TODO: Do we need to check any status registers here?
T::regs().cr().modify(|w| {
// Disable the DAC peripheral
w.set_en(channel, false);
// Disable the DMA. TODO: Is this necessary?
w.set_dmaen(channel, false);
});
Ok(())
}
}
impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> {
/// Create a new DAC instance with both channels.
///
/// This is used to obtain two independent channels via `split()` for use e.g. with DMA.
pub fn new(
peri: impl Peripheral<P = T> + 'd,
dma_ch1: impl Peripheral<P = TxCh1> + 'd,
dma_ch2: impl Peripheral<P = TxCh2> + 'd,
_pin_ch1: impl Peripheral<P = impl DacPin<T, 1>> + 'd,
_pin_ch2: impl Peripheral<P = impl DacPin<T, 2>> + 'd,
) -> Self {
into_ref!(peri, dma_ch1, dma_ch2);
T::enable();
T::reset();
let mut dac_ch1 = DacCh1 {
_peri: peri,
dma: dma_ch1,
};
let mut dac_ch2 = DacCh2 {
phantom: PhantomData,
dma: dma_ch2,
};
// Configure each activated channel. All results can be `unwrap`ed since they
// will only error if the channel is not configured (i.e. ch1, ch2 are false)
#[cfg(dac_v2)]
dac_ch1.set_channel_mode(0).unwrap();
dac_ch1.enable_channel().unwrap();
dac_ch1.set_trigger_enable(true).unwrap();
#[cfg(dac_v2)]
dac_ch2.set_channel_mode(0).unwrap();
dac_ch2.enable_channel().unwrap();
dac_ch2.set_trigger_enable(true).unwrap();
Self {
ch1: dac_ch1,
ch2: dac_ch2,
}
}
/// Split the DAC into CH1 and CH2 for independent use.
pub fn split(self) -> (DacCh1<'d, T, TxCh1>, DacCh2<'d, T, TxCh2>) {
(self.ch1, self.ch2)
}
/// Get mutable reference to CH1
pub fn ch1_mut(&mut self) -> &mut DacCh1<'d, T, TxCh1> {
&mut self.ch1
}
/// Get mutable reference to CH2
pub fn ch2_mut(&mut self) -> &mut DacCh2<'d, T, TxCh2> {
&mut self.ch2
}
/// Get reference to CH1
pub fn ch1(&mut self) -> &DacCh1<'d, T, TxCh1> {
&self.ch1
}
/// Get reference to CH2
pub fn ch2(&mut self) -> &DacCh2<'d, T, TxCh2> {
&self.ch2
}
}
impl<'d, T: Instance, Tx> DacChannel<T, Tx> for DacCh1<'d, T, Tx> {
const CHANNEL: Channel = Channel::Ch1;
}
impl<'d, T: Instance, Tx> DacChannel<T, Tx> for DacCh2<'d, T, Tx> {
const CHANNEL: Channel = Channel::Ch2;
}
pub(crate) mod sealed {
pub trait Instance {
fn regs() -> &'static crate::pac::dac::Dac;
}
}
pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
dma_trait!(DmaCh1, Instance);
dma_trait!(DmaCh2, Instance);
/// Marks a pin that can be used with the DAC
pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
foreach_peripheral!(
(dac, $inst:ident) => {
// H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented
#[cfg(rcc_h7)]
impl crate::rcc::sealed::RccPeripheral for peripherals::$inst {
fn frequency() -> crate::time::Hertz {
critical_section::with(|_| unsafe { crate::rcc::get_freqs().apb1 })
}
fn reset() {
critical_section::with(|_| {
crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true));
crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false));
})
}
fn enable() {
critical_section::with(|_| {
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true));
})
}
fn disable() {
critical_section::with(|_| {
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false))
})
}
}
#[cfg(rcc_h7)]
impl crate::rcc::RccPeripheral for peripherals::$inst {}
impl crate::dac::sealed::Instance for peripherals::$inst {
fn regs() -> &'static crate::pac::dac::Dac {
&crate::pac::$inst
}
}
impl crate::dac::Instance for peripherals::$inst {}
};
);
macro_rules! impl_dac_pin {
($inst:ident, $pin:ident, $ch:expr) => {
impl crate::dac::DacPin<peripherals::$inst, $ch> for crate::peripherals::$pin {}
};
}

View File

@ -21,11 +21,22 @@ use crate::pac::bdma::{regs, vals};
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub struct TransferOptions {}
pub struct TransferOptions {
/// Enable circular DMA
pub circular: bool,
/// Enable half transfer interrupt
pub half_transfer_ir: bool,
/// Enable transfer complete interrupt
pub complete_transfer_ir: bool,
}
impl Default for TransferOptions {
fn default() -> Self {
Self {}
Self {
circular: false,
half_transfer_ir: false,
complete_transfer_ir: true,
}
}
}
@ -253,7 +264,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
mem_len: usize,
incr_mem: bool,
data_size: WordSize,
_options: TransferOptions,
options: TransferOptions,
) -> Self {
let ch = channel.regs().ch(channel.num());
@ -283,7 +294,15 @@ impl<'a, C: Channel> Transfer<'a, C> {
}
w.set_dir(dir.into());
w.set_teie(true);
w.set_tcie(true);
w.set_tcie(options.complete_transfer_ir);
w.set_htie(options.half_transfer_ir);
if options.circular {
w.set_circ(vals::Circ::ENABLED);
debug!("Setting circular mode");
} else {
w.set_circ(vals::Circ::DISABLED);
}
w.set_pl(vals::Pl::VERYHIGH);
w.set_en(true);
});
@ -310,8 +329,9 @@ impl<'a, C: Channel> Transfer<'a, C> {
pub fn is_running(&mut self) -> bool {
let ch = self.channel.regs().ch(self.channel.num());
let en = ch.cr().read().en();
let circular = ch.cr().read().circ() == vals::Circ::ENABLED;
let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0;
en && !tcif
en && (circular || !tcif)
}
/// Gets the total remaining transfers for the channel
@ -477,6 +497,8 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
let ch = self.channel.regs().ch(self.channel.num());
// Disable the channel. Keep the IEs enabled so the irqs still fire.
// If the channel is enabled and transfer is not completed, we need to perform
// two separate write access to the CR register to disable the channel.
ch.cr().write(|w| {
w.set_teie(true);
w.set_htie(true);

View File

@ -174,7 +174,7 @@ impl<'a> RDesRing<'a> {
// Receive descriptor unavailable
Rps::SUSPENDED => RunningState::Stopped,
// Closing receive descriptor
Rps(0b101) => RunningState::Running,
Rps::_RESERVED_5 => RunningState::Running,
// Transferring the receive packet data from receive buffer to host memory
Rps::RUNNINGWRITING => RunningState::Running,
_ => RunningState::Unknown,

View File

@ -243,7 +243,7 @@ mod tests {
for test_run in fn_results {
let (ckd, bits) = compute_dead_time_value(test_run.value);
assert_eq!(ckd.0, test_run.ckd.0);
assert_eq!(ckd.to_bits(), test_run.ckd.to_bits());
assert_eq!(bits, test_run.bits);
}
}

View File

@ -126,7 +126,7 @@ pub(crate) unsafe fn init(config: Config) {
});
while !RCC.cr().read().hsirdy() {}
(HSI_FREQ.0 >> div.0, Sw::HSI)
(HSI_FREQ.0 >> div.to_bits(), Sw::HSI)
}
ClockSrc::HSE(freq) => {
// Enable HSE
@ -157,7 +157,7 @@ pub(crate) unsafe fn init(config: Config) {
let mut set_flash_latency_after = false;
FLASH.acr().modify(|w| {
// Is the current flash latency less than what we need at the new SYSCLK?
if w.latency().0 <= target_flash_latency.0 {
if w.latency().to_bits() <= target_flash_latency.to_bits() {
// We must increase the number of wait states now
w.set_latency(target_flash_latency)
} else {
@ -171,12 +171,12 @@ pub(crate) unsafe fn init(config: Config) {
// > Flash memory.
//
// Enable flash prefetching if we have at least one wait state, and disable it otherwise.
w.set_prften(target_flash_latency.0 > 0);
w.set_prften(target_flash_latency.to_bits() > 0);
});
if !set_flash_latency_after {
// Spin until the effective flash latency is compatible with the clock change
while FLASH.acr().read().latency().0 < target_flash_latency.0 {}
while FLASH.acr().read().latency().to_bits() < target_flash_latency.to_bits() {}
}
// Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once
@ -218,7 +218,7 @@ pub(crate) unsafe fn init(config: Config) {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3);
let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}

View File

@ -1,3 +1,5 @@
use stm32_metapac::flash::vals::Latency;
use super::{set_freqs, Clocks};
use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Sw, Usbsw};
use crate::pac::{FLASH, RCC};
@ -85,14 +87,11 @@ pub(crate) unsafe fn init(config: Config) {
let timer_mul = if ppre == 1 { 1 } else { 2 };
FLASH.acr().write(|w| {
let latency = if real_sysclk <= 24_000_000 {
0
} else if real_sysclk <= 48_000_000 {
1
w.set_latency(if real_sysclk <= 24_000_000 {
Latency::WS0
} else {
2
};
w.latency().0 = latency;
Latency::WS1
});
});
match (config.hse.is_some(), use_hsi48) {
@ -134,20 +133,20 @@ pub(crate) unsafe fn init(config: Config) {
// TODO: Option to use CRS (Clock Recovery)
if let Some(pllmul_bits) = pllmul_bits {
RCC.cfgr().modify(|w| w.set_pllmul(Pllmul(pllmul_bits)));
RCC.cfgr().modify(|w| w.set_pllmul(Pllmul::from_bits(pllmul_bits)));
RCC.cr().modify(|w| w.set_pllon(true));
while !RCC.cr().read().pllrdy() {}
RCC.cfgr().modify(|w| {
w.set_ppre(Ppre(ppre_bits));
w.set_hpre(Hpre(hpre_bits));
w.set_ppre(Ppre::from_bits(ppre_bits));
w.set_hpre(Hpre::from_bits(hpre_bits));
w.set_sw(Sw::PLL)
});
} else {
RCC.cfgr().modify(|w| {
w.set_ppre(Ppre(ppre_bits));
w.set_hpre(Hpre(hpre_bits));
w.set_ppre(Ppre::from_bits(ppre_bits));
w.set_hpre(Hpre::from_bits(hpre_bits));
if config.hse.is_some() {
w.set_sw(Sw::HSE);

View File

@ -106,11 +106,11 @@ pub(crate) unsafe fn init(config: Config) {
// Only needed for stm32f103?
FLASH.acr().write(|w| {
w.set_latency(if real_sysclk <= 24_000_000 {
Latency(0b000)
Latency::WS0
} else if real_sysclk <= 48_000_000 {
Latency(0b001)
Latency::WS1
} else {
Latency(0b010)
Latency::WS2
});
});
@ -147,12 +147,13 @@ pub(crate) unsafe fn init(config: Config) {
if let Some(pllmul_bits) = pllmul_bits {
let pllctpre_flag: u8 = if config.pllxtpre { 1 } else { 0 };
RCC.cfgr().modify(|w| w.set_pllxtpre(Pllxtpre(pllctpre_flag)));
RCC.cfgr()
.modify(|w| w.set_pllxtpre(Pllxtpre::from_bits(pllctpre_flag)));
// enable PLL and wait for it to be ready
RCC.cfgr().modify(|w| {
w.set_pllmul(Pllmul(pllmul_bits));
w.set_pllsrc(Pllsrc(config.hse.is_some() as u8));
w.set_pllmul(Pllmul::from_bits(pllmul_bits));
w.set_pllsrc(Pllsrc::from_bits(config.hse.is_some() as u8));
});
RCC.cr().modify(|w| w.set_pllon(true));
@ -161,22 +162,19 @@ pub(crate) unsafe fn init(config: Config) {
// Only needed for stm32f103?
RCC.cfgr().modify(|w| {
w.set_adcpre(Adcpre(apre_bits));
w.set_ppre2(Ppre1(ppre2_bits));
w.set_ppre1(Ppre1(ppre1_bits));
w.set_hpre(Hpre(hpre_bits));
w.set_adcpre(Adcpre::from_bits(apre_bits));
w.set_ppre2(Ppre1::from_bits(ppre2_bits));
w.set_ppre1(Ppre1::from_bits(ppre1_bits));
w.set_hpre(Hpre::from_bits(hpre_bits));
#[cfg(not(rcc_f100))]
w.set_usbpre(Usbpre(usbpre as u8));
w.set_sw(Sw(if pllmul_bits.is_some() {
// PLL
0b10
w.set_usbpre(Usbpre::from_bits(usbpre as u8));
w.set_sw(if pllmul_bits.is_some() {
Sw::PLL
} else if config.hse.is_some() {
// HSE
0b1
Sw::HSE
} else {
// HSI
0b0
}));
Sw::HSI
});
});
set_freqs(Clocks {

View File

@ -485,7 +485,7 @@ pub(crate) unsafe fn init(config: Config) {
w.set_ppre1(config.apb1_pre.into());
w.set_ppre2(config.apb2_pre.into());
});
while RCC.cfgr().read().sws() != sw.0 {}
while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {}
// Turn off HSI to save power if we don't need it
if !config.hsi {

View File

@ -87,7 +87,7 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, plli2s: Opti
let sysclk = pllsysclk.unwrap_or(pllsrcclk);
if pllsysclk.is_none() && !pll48clk {
RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8)));
RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc::from_bits(use_hse as u8)));
return PllResults {
use_pll: false,
@ -141,9 +141,9 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, plli2s: Opti
RCC.pllcfgr().modify(|w| {
w.set_pllm(pllm as u8);
w.set_plln(plln as u16);
w.set_pllp(Pllp(pllp as u8));
w.set_pllp(Pllp::from_bits(pllp as u8));
w.set_pllq(pllq as u8);
w.set_pllsrc(Pllsrc(use_hse as u8));
w.set_pllsrc(Pllsrc::from_bits(use_hse as u8));
});
let real_pllsysclk = vco_in * plln / sysclk_div;
@ -323,7 +323,7 @@ fn flash_setup(sysclk: u32) {
critical_section::with(|_| {
FLASH
.acr()
.modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
.modify(|w| w.set_latency(Latency::from_bits(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
});
}
@ -440,8 +440,8 @@ pub(crate) unsafe fn init(config: Config) {
}
RCC.cfgr().modify(|w| {
w.set_ppre2(Ppre(ppre2_bits));
w.set_ppre1(Ppre(ppre1_bits));
w.set_ppre2(Ppre::from_bits(ppre2_bits));
w.set_ppre1(Ppre::from_bits(ppre1_bits));
w.set_hpre(hpre_bits);
});

View File

@ -30,7 +30,7 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bo
let sysclk = pllsysclk.unwrap_or(pllsrcclk);
if pllsysclk.is_none() && !pll48clk {
RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8)));
RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc::from_bits(use_hse as u8)));
return PllResults {
use_pll: false,
@ -83,9 +83,9 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bo
RCC.pllcfgr().modify(|w| {
w.set_pllm(pllm as u8);
w.set_plln(plln as u16);
w.set_pllp(Pllp(pllp as u8));
w.set_pllp(Pllp::from_bits(pllp as u8));
w.set_pllq(pllq as u8);
w.set_pllsrc(Pllsrc(use_hse as u8));
w.set_pllsrc(Pllsrc::from_bits(use_hse as u8));
});
let real_pllsysclk = vco_in * plln / sysclk_div;
@ -106,7 +106,7 @@ fn flash_setup(sysclk: u32) {
critical_section::with(|_| {
FLASH
.acr()
.modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
.modify(|w| w.set_latency(Latency::from_bits(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
});
}
@ -246,8 +246,8 @@ pub(crate) unsafe fn init(config: Config) {
}
RCC.cfgr().modify(|w| {
w.set_ppre2(Ppre(ppre2_bits));
w.set_ppre1(Ppre(ppre1_bits));
w.set_ppre2(Ppre::from_bits(ppre2_bits));
w.set_ppre1(Ppre::from_bits(ppre1_bits));
w.set_hpre(hpre_bits);
});

View File

@ -344,7 +344,7 @@ pub(crate) unsafe fn init(config: Config) {
});
while !RCC.cr().read().hsirdy() {}
(HSI_FREQ.0 >> div.0, Sw::HSI)
(HSI_FREQ.0 >> div.to_bits(), Sw::HSI)
}
ClockSrc::HSE(freq) => {
// Enable HSE
@ -381,7 +381,7 @@ pub(crate) unsafe fn init(config: Config) {
let mut set_flash_latency_after = false;
FLASH.acr().modify(|w| {
// Is the current flash latency less than what we need at the new SYSCLK?
if w.latency().0 <= target_flash_latency.0 {
if w.latency().to_bits() <= target_flash_latency.to_bits() {
// We must increase the number of wait states now
w.set_latency(target_flash_latency)
} else {
@ -395,12 +395,12 @@ pub(crate) unsafe fn init(config: Config) {
// > Flash memory.
//
// Enable flash prefetching if we have at least one wait state, and disable it otherwise.
w.set_prften(target_flash_latency.0 > 0);
w.set_prften(target_flash_latency.to_bits() > 0);
});
if !set_flash_latency_after {
// Spin until the effective flash latency is compatible with the clock change
while FLASH.acr().read().latency().0 < target_flash_latency.0 {}
while FLASH.acr().read().latency().to_bits() < target_flash_latency.to_bits() {}
}
// Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once
@ -442,7 +442,7 @@ pub(crate) unsafe fn init(config: Config) {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3);
let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}

View File

@ -3,6 +3,7 @@ use stm32_metapac::rcc::vals::{Hpre, Pllsrc, Ppre, Sw};
use stm32_metapac::FLASH;
use crate::pac::{PWR, RCC};
use crate::rcc::sealed::RccPeripheral;
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz;
@ -316,6 +317,27 @@ impl Into<Hpre> for AHBPrescaler {
}
}
/// Sets the source for the 48MHz clock to the USB and RNG peripherals.
pub enum Clock48MhzSrc {
/// Use the High Speed Internal Oscillator. For USB usage, the CRS must be used to calibrate the
/// oscillator to comply with the USB specification for oscillator tolerance.
Hsi48(Option<CrsConfig>),
/// Use the PLLQ output. The PLL must be configured to output a 48MHz clock. For USB usage the
/// PLL needs to be using the HSE source to comply with the USB specification for oscillator
/// tolerance.
PllQ,
}
/// Sets the sync source for the Clock Recovery System (CRS).
pub enum CrsSyncSource {
/// Use an external GPIO to sync the CRS.
Gpio,
/// Use the Low Speed External oscillator to sync the CRS.
Lse,
/// Use the USB SOF to sync the CRS.
Usb,
}
/// Clocks configutation
pub struct Config {
pub mux: ClockSrc,
@ -326,6 +348,14 @@ pub struct Config {
/// Iff PLL is requested as the main clock source in the `mux` field then the PLL configuration
/// MUST turn on the PLLR output.
pub pll: Option<Pll>,
/// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals.
pub clock_48mhz_src: Option<Clock48MhzSrc>,
}
/// Configuration for the Clock Recovery System (CRS) used to trim the HSI48 oscillator.
pub struct CrsConfig {
/// Sync source for the CRS.
pub sync_src: CrsSyncSource,
}
impl Default for Config {
@ -338,6 +368,7 @@ impl Default for Config {
apb2_pre: APBPrescaler::NotDivided,
low_power_run: false,
pll: None,
clock_48mhz_src: None,
}
}
}
@ -430,7 +461,7 @@ pub(crate) unsafe fn init(config: Config) {
assert!(pll_freq.is_some());
assert!(pll_freq.as_ref().unwrap().pll_r.is_some());
let freq = pll_freq.unwrap().pll_r.unwrap().0;
let freq = pll_freq.as_ref().unwrap().pll_r.unwrap().0;
assert!(freq <= 170_000_000);
@ -497,6 +528,50 @@ pub(crate) unsafe fn init(config: Config) {
}
};
// Setup the 48 MHz clock if needed
if let Some(clock_48mhz_src) = config.clock_48mhz_src {
let source = match clock_48mhz_src {
Clock48MhzSrc::PllQ => {
// Make sure the PLLQ is enabled and running at 48Mhz
let pllq_freq = pll_freq.as_ref().and_then(|f| f.pll_q);
assert!(pllq_freq.is_some() && pllq_freq.unwrap().0 == 48_000_000);
crate::pac::rcc::vals::Clk48sel::PLLQCLK
}
Clock48MhzSrc::Hsi48(crs_config) => {
// Enable HSI48
RCC.crrcr().modify(|w| w.set_hsi48on(true));
// Wait for HSI48 to turn on
while RCC.crrcr().read().hsi48rdy() == false {}
// Enable and setup CRS if needed
if let Some(crs_config) = crs_config {
crate::peripherals::CRS::enable();
let sync_src = match crs_config.sync_src {
CrsSyncSource::Gpio => crate::pac::crs::vals::Syncsrc::GPIO,
CrsSyncSource::Lse => crate::pac::crs::vals::Syncsrc::LSE,
CrsSyncSource::Usb => crate::pac::crs::vals::Syncsrc::USB,
};
crate::pac::CRS.cfgr().modify(|w| {
w.set_syncsrc(sync_src);
});
// These are the correct settings for standard USB operation. If other settings
// are needed there will need to be additional config options for the CRS.
crate::pac::CRS.cr().modify(|w| {
w.set_autotrimen(true);
w.set_cen(true);
});
}
crate::pac::rcc::vals::Clk48sel::HSI48
}
};
RCC.ccipr().modify(|w| w.set_clk48sel(source));
}
if config.low_power_run {
assert!(sys_clk <= 2_000_000);
PWR.cr1().modify(|w| w.set_lpr(true));

View File

@ -601,22 +601,22 @@ pub(crate) unsafe fn init(mut config: Config) {
// Core Prescaler / AHB Prescaler / APB3 Prescaler
RCC.d1cfgr().modify(|w| {
w.set_d1cpre(Hpre(d1cpre_bits));
w.set_d1ppre(Dppre(ppre3_bits));
w.set_d1cpre(Hpre::from_bits(d1cpre_bits));
w.set_d1ppre(Dppre::from_bits(ppre3_bits));
w.set_hpre(hpre_bits)
});
// Ensure core prescaler value is valid before future lower
// core voltage
while RCC.d1cfgr().read().d1cpre().0 != d1cpre_bits {}
while RCC.d1cfgr().read().d1cpre().to_bits() != d1cpre_bits {}
// APB1 / APB2 Prescaler
RCC.d2cfgr().modify(|w| {
w.set_d2ppre1(Dppre(ppre1_bits));
w.set_d2ppre2(Dppre(ppre2_bits));
w.set_d2ppre1(Dppre::from_bits(ppre1_bits));
w.set_d2ppre2(Dppre::from_bits(ppre2_bits));
});
// APB4 Prescaler
RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre(ppre4_bits)));
RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre::from_bits(ppre4_bits)));
// Peripheral Clock (per_ck)
RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel));
@ -640,7 +640,7 @@ pub(crate) unsafe fn init(mut config: Config) {
_ => Sw::HSI,
};
RCC.cfgr().modify(|w| w.set_sw(sw));
while RCC.cfgr().read().sws() != sw.0 {}
while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {}
// IO compensation cell - Requires CSI clock and SYSCFG
assert!(RCC.cr().read().csirdy());
@ -806,7 +806,8 @@ mod pll {
RCC.pllcfgr().modify(|w| w.set_pllfracen(plln, false));
let vco_ck = ref_x_ck * pll_x_n;
RCC.plldivr(plln).modify(|w| w.set_divp1(Divp((pll_x_p - 1) as u8)));
RCC.plldivr(plln)
.modify(|w| w.set_divp1(Divp::from_bits((pll_x_p - 1) as u8)));
RCC.pllcfgr().modify(|w| w.set_divpen(plln, true));
// Calulate additional output dividers

View File

@ -1,7 +1,7 @@
use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
use crate::pac::RCC;
#[cfg(crs)]
use crate::pac::{CRS, SYSCFG};
use crate::pac::{crs, CRS, SYSCFG};
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz;
@ -293,7 +293,7 @@ pub(crate) unsafe fn init(config: Config) {
AHBPrescaler::NotDivided => sys_clk,
pre => {
let pre: Hpre = pre.into();
let pre = 1 << (pre.0 as u32 - 7);
let pre = 1 << (pre.to_bits() as u32 - 7);
sys_clk / pre
}
};
@ -302,7 +302,7 @@ pub(crate) unsafe fn init(config: Config) {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3);
let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
@ -312,7 +312,7 @@ pub(crate) unsafe fn init(config: Config) {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3);
let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
@ -338,7 +338,7 @@ pub(crate) unsafe fn init(config: Config) {
CRS.cfgr().write(|w|
// Select LSE as synchronization source
w.set_syncsrc(0b01));
w.set_syncsrc(crs::vals::Syncsrc::LSE));
CRS.cr().modify(|w| {
w.set_autotrimen(true);
w.set_cen(true);

View File

@ -294,7 +294,7 @@ pub(crate) unsafe fn init(config: Config) {
AHBPrescaler::NotDivided => sys_clk,
pre => {
let pre: Hpre = pre.into();
let pre = 1 << (pre.0 as u32 - 7);
let pre = 1 << (pre.to_bits() as u32 - 7);
sys_clk / pre
}
};
@ -303,7 +303,7 @@ pub(crate) unsafe fn init(config: Config) {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3);
let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
@ -313,7 +313,7 @@ pub(crate) unsafe fn init(config: Config) {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3);
let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}

View File

@ -635,7 +635,7 @@ pub(crate) unsafe fn init(config: Config) {
AHBPrescaler::NotDivided => sys_clk,
pre => {
let pre: Hpre = pre.into();
let pre = 1 << (pre.0 as u32 - 7);
let pre = 1 << (pre.to_bits() as u32 - 7);
sys_clk / pre
}
};
@ -644,7 +644,7 @@ pub(crate) unsafe fn init(config: Config) {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3);
let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
@ -654,7 +654,7 @@ pub(crate) unsafe fn init(config: Config) {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3);
let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}

View File

@ -461,7 +461,7 @@ pub(crate) unsafe fn init(config: Config) {
AHBPrescaler::NotDivided => sys_clk,
pre => {
let pre: Hpre = pre.into();
let pre = 1 << (pre.0 as u32 - 7);
let pre = 1 << (pre.to_bits() as u32 - 7);
sys_clk / pre
}
};
@ -470,7 +470,7 @@ pub(crate) unsafe fn init(config: Config) {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3);
let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
@ -480,7 +480,7 @@ pub(crate) unsafe fn init(config: Config) {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3);
let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}

View File

@ -126,7 +126,7 @@ pub enum PllM {
impl Into<Pllm> for PllM {
fn into(self) -> Pllm {
Pllm(self as u8)
Pllm::from_bits(self as u8)
}
}

View File

@ -36,7 +36,7 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
#[cfg(rtc_v2wb)]
let rtcsel = reg.rtcsel();
#[cfg(not(rtc_v2wb))]
let rtcsel = reg.rtcsel().0;
let rtcsel = reg.rtcsel().to_bits();
if !reg.rtcen() || rtcsel != clock_config {
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
@ -54,7 +54,7 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
// Select RTC source
#[cfg(not(rtc_v2wb))]
w.set_rtcsel(Rtcsel(clock_config));
w.set_rtcsel(Rtcsel::from_bits(clock_config));
#[cfg(rtc_v2wb)]
w.set_rtcsel(clock_config);
w.set_rtcen(true);

View File

@ -26,7 +26,7 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
let config_rtcsel = rtc_config.clock_config as u8;
#[cfg(not(any(rcc_wl5, rcc_wle)))]
let config_rtcsel = crate::pac::rcc::vals::Rtcsel(config_rtcsel);
let config_rtcsel = crate::pac::rcc::vals::Rtcsel::from_bits(config_rtcsel);
if !reg.rtcen() || reg.rtcsel() != config_rtcsel {
crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));

View File

@ -227,7 +227,11 @@ const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOp
fifo_threshold: Some(crate::dma::FifoThreshold::Full),
};
#[cfg(all(sdmmc_v1, not(dma)))]
const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions {};
const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions {
circular: false,
half_transfer_ir: false,
complete_transfer_ir: true,
};
/// SDMMC configuration
///

View File

@ -650,7 +650,7 @@ fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> Br {
_ => 0b111,
};
Br(val)
Br::from_bits(val)
}
trait RegsExt {
@ -772,7 +772,7 @@ fn set_rxdmaen(regs: Regs, val: bool) {
fn finish_dma(regs: Regs) {
#[cfg(spi_v2)]
while regs.sr().read().ftlvl() > 0 {}
while regs.sr().read().ftlvl().to_bits() > 0 {}
#[cfg(any(spi_v3, spi_v4, spi_v5))]
while !regs.sr().read().txc() {}

View File

@ -869,7 +869,7 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
_ => vals::Ps::EVEN,
});
#[cfg(not(usart_v1))]
w.set_over8(vals::Over8(over8 as _));
w.set_over8(vals::Over8::from_bits(over8 as _));
});
#[cfg(not(usart_v1))]

View File

@ -97,8 +97,8 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
}
epr.set_dtog_rx(false);
epr.set_dtog_tx(false);
epr.set_stat_rx(Stat(0));
epr.set_stat_tx(Stat(0));
epr.set_stat_rx(Stat::from_bits(0));
epr.set_stat_tx(Stat::from_bits(0));
epr.set_ctr_rx(!epr.ctr_rx());
epr.set_ctr_tx(!epr.ctr_tx());
regs.epr(index).write_value(epr);
@ -143,8 +143,8 @@ fn invariant(mut r: regs::Epr) -> regs::Epr {
r.set_ctr_tx(true); // don't clear
r.set_dtog_rx(false); // don't toggle
r.set_dtog_tx(false); // don't toggle
r.set_stat_rx(Stat(0));
r.set_stat_tx(Stat(0));
r.set_stat_rx(Stat::from_bits(0));
r.set_stat_tx(Stat::from_bits(0));
r
}
@ -480,56 +480,57 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
poll_fn(move |cx| {
BUS_WAKER.register(cx.waker());
if self.inited {
let regs = T::regs();
if IRQ_RESUME.load(Ordering::Acquire) {
IRQ_RESUME.store(false, Ordering::Relaxed);
return Poll::Ready(Event::Resume);
}
if IRQ_RESET.load(Ordering::Acquire) {
IRQ_RESET.store(false, Ordering::Relaxed);
trace!("RESET");
regs.daddr().write(|w| {
w.set_ef(true);
w.set_add(0);
});
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
w.set_stat_rx(Stat::NAK);
w.set_stat_tx(Stat::NAK);
});
for i in 1..EP_COUNT {
regs.epr(i).write(|w| {
w.set_ea(i as _);
w.set_ep_type(self.ep_types[i - 1]);
})
}
for w in &EP_IN_WAKERS {
w.wake()
}
for w in &EP_OUT_WAKERS {
w.wake()
}
return Poll::Ready(Event::Reset);
}
if IRQ_SUSPEND.load(Ordering::Acquire) {
IRQ_SUSPEND.store(false, Ordering::Relaxed);
return Poll::Ready(Event::Suspend);
}
Poll::Pending
} else {
// TODO: implement VBUS detection.
if !self.inited {
self.inited = true;
return Poll::Ready(Event::PowerDetected);
}
let regs = T::regs();
if IRQ_RESUME.load(Ordering::Acquire) {
IRQ_RESUME.store(false, Ordering::Relaxed);
return Poll::Ready(Event::Resume);
}
if IRQ_RESET.load(Ordering::Acquire) {
IRQ_RESET.store(false, Ordering::Relaxed);
trace!("RESET");
regs.daddr().write(|w| {
w.set_ef(true);
w.set_add(0);
});
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
w.set_stat_rx(Stat::NAK);
w.set_stat_tx(Stat::NAK);
});
for i in 1..EP_COUNT {
regs.epr(i).write(|w| {
w.set_ea(i as _);
w.set_ep_type(self.ep_types[i - 1]);
})
}
for w in &EP_IN_WAKERS {
w.wake()
}
for w in &EP_OUT_WAKERS {
w.wake()
}
return Poll::Ready(Event::Reset);
}
if IRQ_SUSPEND.load(Ordering::Acquire) {
IRQ_SUSPEND.store(false, Ordering::Relaxed);
return Poll::Ready(Event::Suspend);
}
Poll::Pending
})
.await
}
@ -550,7 +551,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
true => Stat::STALL,
};
let mut w = invariant(r);
w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0));
w.set_stat_tx(Stat::from_bits(r.stat_tx().to_bits() ^ want_stat.to_bits()));
reg.write_value(w);
}
}
@ -569,7 +570,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
true => Stat::STALL,
};
let mut w = invariant(r);
w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0));
w.set_stat_rx(Stat::from_bits(r.stat_rx().to_bits() ^ want_stat.to_bits()));
reg.write_value(w);
}
}
@ -605,7 +606,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
break;
}
let mut w = invariant(r);
w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0));
w.set_stat_tx(Stat::from_bits(r.stat_tx().to_bits() ^ want_stat.to_bits()));
reg.write_value(w);
}
EP_IN_WAKERS[ep_addr.index()].wake();
@ -621,7 +622,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
break;
}
let mut w = invariant(r);
w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0));
w.set_stat_rx(Stat::from_bits(r.stat_rx().to_bits() ^ want_stat.to_bits()));
reg.write_value(w);
}
EP_OUT_WAKERS[ep_addr.index()].wake();
@ -762,8 +763,8 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
regs.epr(index).write(|w| {
w.set_ep_type(convert_type(self.info.ep_type));
w.set_ea(self.info.addr.index() as _);
w.set_stat_rx(Stat(Stat::NAK.0 ^ Stat::VALID.0));
w.set_stat_tx(Stat(0));
w.set_stat_rx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits()));
w.set_stat_tx(Stat::from_bits(0));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
});
@ -804,8 +805,8 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
regs.epr(index).write(|w| {
w.set_ep_type(convert_type(self.info.ep_type));
w.set_ea(self.info.addr.index() as _);
w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0));
w.set_stat_rx(Stat(0));
w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits()));
w.set_stat_rx(Stat::from_bits(0));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
});
@ -868,19 +869,19 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
let mut stat_tx = 0;
if first {
// change NAK -> VALID
stat_rx ^= Stat::NAK.0 ^ Stat::VALID.0;
stat_tx ^= Stat::NAK.0 ^ Stat::STALL.0;
stat_rx ^= Stat::NAK.to_bits() ^ Stat::VALID.to_bits();
stat_tx ^= Stat::NAK.to_bits() ^ Stat::STALL.to_bits();
}
if last {
// change STALL -> VALID
stat_tx ^= Stat::STALL.0 ^ Stat::NAK.0;
stat_tx ^= Stat::STALL.to_bits() ^ Stat::NAK.to_bits();
}
// Note: if this is the first AND last transfer, the above effectively
// changes stat_tx like NAK -> NAK, so noop.
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
w.set_stat_rx(Stat(stat_rx));
w.set_stat_tx(Stat(stat_tx));
w.set_stat_rx(Stat::from_bits(stat_rx));
w.set_stat_tx(Stat::from_bits(stat_tx));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
});
@ -907,11 +908,11 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
w.set_stat_rx(Stat(match last {
w.set_stat_rx(Stat::from_bits(match last {
// If last, set STAT_RX=STALL.
true => Stat::NAK.0 ^ Stat::STALL.0,
true => Stat::NAK.to_bits() ^ Stat::STALL.to_bits(),
// Otherwise, set STAT_RX=VALID, to allow the host to send the next packet.
false => Stat::NAK.0 ^ Stat::VALID.0,
false => Stat::NAK.to_bits() ^ Stat::VALID.to_bits(),
}));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
@ -936,17 +937,17 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
let mut stat_rx = 0;
if first {
// change NAK -> STALL
stat_rx ^= Stat::NAK.0 ^ Stat::STALL.0;
stat_rx ^= Stat::NAK.to_bits() ^ Stat::STALL.to_bits();
}
if last {
// change STALL -> VALID
stat_rx ^= Stat::STALL.0 ^ Stat::VALID.0;
stat_rx ^= Stat::STALL.to_bits() ^ Stat::VALID.to_bits();
}
// Note: if this is the first AND last transfer, the above effectively
// does a change of NAK -> VALID.
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
w.set_stat_rx(Stat(stat_rx));
w.set_stat_rx(Stat::from_bits(stat_rx));
w.set_ep_kind(last); // set OUT_STATUS if last.
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
@ -976,7 +977,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
let regs = T::regs();
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0));
w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits()));
w.set_ep_kind(last); // set OUT_STATUS if last.
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
@ -997,8 +998,8 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
let epr = regs.epr(0).read();
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0));
w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::VALID.0));
w.set_stat_rx(Stat::from_bits(epr.stat_rx().to_bits() ^ Stat::STALL.to_bits()));
w.set_stat_tx(Stat::from_bits(epr.stat_tx().to_bits() ^ Stat::VALID.to_bits()));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
});
@ -1028,8 +1029,8 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
let epr = regs.epr(0).read();
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0));
w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::STALL.0));
w.set_stat_rx(Stat::from_bits(epr.stat_rx().to_bits() ^ Stat::STALL.to_bits()));
w.set_stat_tx(Stat::from_bits(epr.stat_tx().to_bits() ^ Stat::STALL.to_bits()));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
});

View File

@ -6,8 +6,8 @@ use atomic_polyfill::{AtomicBool, AtomicU16, Ordering};
use embassy_hal_common::{into_ref, Peripheral};
use embassy_sync::waitqueue::AtomicWaker;
use embassy_usb_driver::{
self, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo, EndpointOut,
EndpointType, Event, Unsupported,
self, Bus as _, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo,
EndpointOut, EndpointType, Event, Unsupported,
};
use futures::future::poll_fn;
@ -31,7 +31,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
let state = T::state();
let ints = r.gintsts().read();
if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() {
if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() || ints.otgint() || ints.srqint() {
// Mask interrupts and notify `Bus` to process them
r.gintmsk().write(|_| {});
T::state().bus_waker.wake();
@ -97,7 +97,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
vals::Pktstsd::SETUP_DATA_DONE => {
trace!("SETUP_DATA_DONE ep={}", ep_num);
}
x => trace!("unknown PKTSTS: {}", x.0),
x => trace!("unknown PKTSTS: {}", x.to_bits()),
}
}
@ -124,7 +124,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
}
state.ep_in_wakers[ep_num].wake();
trace!("in ep={} irq val={:b}", ep_num, ep_ints.0);
trace!("in ep={} irq val={:08x}", ep_num, ep_ints.0);
}
ep_mask >>= 1;
@ -144,7 +144,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
// // clear all
// r.doepint(ep_num).write_value(ep_ints);
// state.ep_out_wakers[ep_num].wake();
// trace!("out ep={} irq val={=u32:b}", ep_num, ep_ints.0);
// trace!("out ep={} irq val={:08x}", ep_num, ep_ints.0);
// }
// ep_mask >>= 1;
@ -256,7 +256,34 @@ struct EndpointData {
fifo_size_words: u16,
}
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Config {
/// Enable VBUS detection.
///
/// The USB spec requires USB devices monitor for USB cable plug/unplug and react accordingly.
/// This is done by checkihg whether there is 5V on the VBUS pin or not.
///
/// If your device is bus-powered (powers itself from the USB host via VBUS), then this is optional.
/// (if there's no power in VBUS your device would be off anyway, so it's fine to always assume
/// there's power in VBUS, i.e. the USB cable is always plugged in.)
///
/// If your device is self-powered (i.e. it gets power from a source other than the USB cable, and
/// therefore can stay powered through USB cable plug/unplug) then you MUST set this to true.
///
/// If you set this to true, you must connect VBUS to PA9 for FS, PB13 for HS, possibly with a
/// voltage divider. See ST application note AN4879 and the reference manual for more details.
pub vbus_detection: bool,
}
impl Default for Config {
fn default() -> Self {
Self { vbus_detection: true }
}
}
pub struct Driver<'d, T: Instance> {
config: Config,
phantom: PhantomData<&'d mut T>,
ep_in: [Option<EndpointData>; MAX_EP_COUNT],
ep_out: [Option<EndpointData>; MAX_EP_COUNT],
@ -279,6 +306,7 @@ impl<'d, T: Instance> Driver<'d, T> {
dp: impl Peripheral<P = impl DpPin<T>> + 'd,
dm: impl Peripheral<P = impl DmPin<T>> + 'd,
ep_out_buffer: &'d mut [u8],
config: Config,
) -> Self {
into_ref!(dp, dm);
@ -286,6 +314,7 @@ impl<'d, T: Instance> Driver<'d, T> {
dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
Self {
config,
phantom: PhantomData,
ep_in: [None; MAX_EP_COUNT],
ep_out: [None; MAX_EP_COUNT],
@ -318,6 +347,7 @@ impl<'d, T: Instance> Driver<'d, T> {
ulpi_d6: impl Peripheral<P = impl UlpiD6Pin<T>> + 'd,
ulpi_d7: impl Peripheral<P = impl UlpiD7Pin<T>> + 'd,
ep_out_buffer: &'d mut [u8],
config: Config,
) -> Self {
assert!(T::HIGH_SPEED == true, "Peripheral is not capable of high-speed USB");
@ -327,6 +357,7 @@ impl<'d, T: Instance> Driver<'d, T> {
);
Self {
config,
phantom: PhantomData,
ep_in: [None; MAX_EP_COUNT],
ep_out: [None; MAX_EP_COUNT],
@ -464,11 +495,12 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> {
(
Bus {
config: self.config,
phantom: PhantomData,
ep_in: self.ep_in,
ep_out: self.ep_out,
phy_type: self.phy_type,
enabled: false,
inited: false,
},
ControlPipe {
_phantom: PhantomData,
@ -481,11 +513,12 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> {
}
pub struct Bus<'d, T: Instance> {
config: Config,
phantom: PhantomData<&'d mut T>,
ep_in: [Option<EndpointData>; MAX_EP_COUNT],
ep_out: [Option<EndpointData>; MAX_EP_COUNT],
phy_type: PhyType,
enabled: bool,
inited: bool,
}
impl<'d, T: Instance> Bus<'d, T> {
@ -498,282 +531,14 @@ impl<'d, T: Instance> Bus<'d, T> {
w.set_iepint(true);
w.set_oepint(true);
w.set_rxflvlm(true);
w.set_srqim(true);
w.set_otgint(true);
});
}
}
impl<'d, T: Instance> Bus<'d, T> {
fn init_fifo(&mut self) {
trace!("init_fifo");
let r = T::regs();
// Configure RX fifo size. All endpoints share the same FIFO area.
let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out);
trace!("configuring rx fifo size={}", rx_fifo_size_words);
r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words));
// Configure TX (USB in direction) fifo size for each endpoint
let mut fifo_top = rx_fifo_size_words;
for i in 0..T::ENDPOINT_COUNT {
if let Some(ep) = self.ep_in[i] {
trace!(
"configuring tx fifo ep={}, offset={}, size={}",
i,
fifo_top,
ep.fifo_size_words
);
let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) };
dieptxf.write(|w| {
w.set_fd(ep.fifo_size_words);
w.set_sa(fifo_top);
});
fifo_top += ep.fifo_size_words;
}
}
assert!(
fifo_top <= T::FIFO_DEPTH_WORDS,
"FIFO allocations exceeded maximum capacity"
);
}
fn configure_endpoints(&mut self) {
trace!("configure_endpoints");
let r = T::regs();
// Configure IN endpoints
for (index, ep) in self.ep_in.iter().enumerate() {
if let Some(ep) = ep {
critical_section::with(|_| {
r.diepctl(index).write(|w| {
if index == 0 {
w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
} else {
w.set_mpsiz(ep.max_packet_size);
w.set_eptyp(to_eptyp(ep.ep_type));
w.set_sd0pid_sevnfrm(true);
}
});
});
}
}
// Configure OUT endpoints
for (index, ep) in self.ep_out.iter().enumerate() {
if let Some(ep) = ep {
critical_section::with(|_| {
r.doepctl(index).write(|w| {
if index == 0 {
w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
} else {
w.set_mpsiz(ep.max_packet_size);
w.set_eptyp(to_eptyp(ep.ep_type));
w.set_sd0pid_sevnfrm(true);
}
});
r.doeptsiz(index).modify(|w| {
w.set_xfrsiz(ep.max_packet_size as _);
if index == 0 {
w.set_rxdpid_stupcnt(1);
} else {
w.set_pktcnt(1);
}
});
});
}
}
// Enable IRQs for allocated endpoints
r.daintmsk().modify(|w| {
w.set_iepm(ep_irq_mask(&self.ep_in));
// OUT interrupts not used, handled in RXFLVL
// w.set_oepm(ep_irq_mask(&self.ep_out));
});
}
fn disable(&mut self) {
T::Interrupt::disable();
<T as RccPeripheral>::disable();
#[cfg(stm32l4)]
crate::pac::PWR.cr2().modify(|w| w.set_usv(false));
// Cannot disable PWR, because other peripherals might be using it
}
}
impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
async fn poll(&mut self) -> Event {
poll_fn(move |cx| {
// TODO: implement VBUS detection
if !self.enabled {
return Poll::Ready(Event::PowerDetected);
}
let r = T::regs();
T::state().bus_waker.register(cx.waker());
let ints = r.gintsts().read();
if ints.usbrst() {
trace!("reset");
self.init_fifo();
self.configure_endpoints();
// Reset address
critical_section::with(|_| {
r.dcfg().modify(|w| {
w.set_dad(0);
});
});
r.gintsts().write(|w| w.set_usbrst(true)); // clear
Self::restore_irqs();
}
if ints.enumdne() {
trace!("enumdne");
let speed = r.dsts().read().enumspd();
trace!(" speed={}", speed.0);
r.gusbcfg().modify(|w| {
w.set_trdt(calculate_trdt(speed, T::frequency()));
});
r.gintsts().write(|w| w.set_enumdne(true)); // clear
Self::restore_irqs();
return Poll::Ready(Event::Reset);
}
if ints.usbsusp() {
trace!("suspend");
r.gintsts().write(|w| w.set_usbsusp(true)); // clear
Self::restore_irqs();
return Poll::Ready(Event::Suspend);
}
if ints.wkupint() {
trace!("resume");
r.gintsts().write(|w| w.set_wkupint(true)); // clear
Self::restore_irqs();
return Poll::Ready(Event::Resume);
}
Poll::Pending
})
.await
}
fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) {
trace!("endpoint_set_stalled ep={:?} en={}", ep_addr, stalled);
assert!(
ep_addr.index() < T::ENDPOINT_COUNT,
"endpoint_set_stalled index {} out of range",
ep_addr.index()
);
let regs = T::regs();
match ep_addr.direction() {
Direction::Out => {
critical_section::with(|_| {
regs.doepctl(ep_addr.index()).modify(|w| {
w.set_stall(stalled);
});
});
T::state().ep_out_wakers[ep_addr.index()].wake();
}
Direction::In => {
critical_section::with(|_| {
regs.diepctl(ep_addr.index()).modify(|w| {
w.set_stall(stalled);
});
});
T::state().ep_in_wakers[ep_addr.index()].wake();
}
}
}
fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool {
assert!(
ep_addr.index() < T::ENDPOINT_COUNT,
"endpoint_is_stalled index {} out of range",
ep_addr.index()
);
let regs = T::regs();
match ep_addr.direction() {
Direction::Out => regs.doepctl(ep_addr.index()).read().stall(),
Direction::In => regs.diepctl(ep_addr.index()).read().stall(),
}
}
fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) {
trace!("endpoint_set_enabled ep={:?} en={}", ep_addr, enabled);
assert!(
ep_addr.index() < T::ENDPOINT_COUNT,
"endpoint_set_enabled index {} out of range",
ep_addr.index()
);
let r = T::regs();
match ep_addr.direction() {
Direction::Out => {
critical_section::with(|_| {
// cancel transfer if active
if !enabled && r.doepctl(ep_addr.index()).read().epena() {
r.doepctl(ep_addr.index()).modify(|w| {
w.set_snak(true);
w.set_epdis(true);
})
}
r.doepctl(ep_addr.index()).modify(|w| {
w.set_usbaep(enabled);
})
});
// Wake `Endpoint::wait_enabled()`
T::state().ep_out_wakers[ep_addr.index()].wake();
}
Direction::In => {
critical_section::with(|_| {
// cancel transfer if active
if !enabled && r.diepctl(ep_addr.index()).read().epena() {
r.diepctl(ep_addr.index()).modify(|w| {
w.set_snak(true);
w.set_epdis(true);
})
}
r.diepctl(ep_addr.index()).modify(|w| {
w.set_usbaep(enabled);
})
});
// Wake `Endpoint::wait_enabled()`
T::state().ep_in_wakers[ep_addr.index()].wake();
}
}
}
async fn enable(&mut self) {
trace!("enable");
fn init(&mut self) {
#[cfg(stm32l4)]
{
crate::peripherals::PWR::enable();
@ -908,9 +673,9 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
// F429-like chips have the GCCFG.NOVBUSSENS bit
r.gccfg_v1().modify(|w| {
w.set_novbussens(true);
w.set_novbussens(!self.config.vbus_detection);
w.set_vbusasen(false);
w.set_vbusbsen(false);
w.set_vbusbsen(self.config.vbus_detection);
w.set_sofouten(false);
});
}
@ -923,12 +688,12 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
});
r.gccfg_v2().modify(|w| {
w.set_vbden(false);
w.set_vbden(self.config.vbus_detection);
});
// Force B-peripheral session
r.gotgctl().modify(|w| {
w.set_bvaloen(true);
w.set_bvaloen(!self.config.vbus_detection);
w.set_bvaloval(true);
});
}
@ -960,16 +725,352 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
// Connect
r.dctl().write(|w| w.set_sdis(false));
}
self.enabled = true;
fn init_fifo(&mut self) {
trace!("init_fifo");
let r = T::regs();
// Configure RX fifo size. All endpoints share the same FIFO area.
let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out);
trace!("configuring rx fifo size={}", rx_fifo_size_words);
r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words));
// Configure TX (USB in direction) fifo size for each endpoint
let mut fifo_top = rx_fifo_size_words;
for i in 0..T::ENDPOINT_COUNT {
if let Some(ep) = self.ep_in[i] {
trace!(
"configuring tx fifo ep={}, offset={}, size={}",
i,
fifo_top,
ep.fifo_size_words
);
let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) };
dieptxf.write(|w| {
w.set_fd(ep.fifo_size_words);
w.set_sa(fifo_top);
});
fifo_top += ep.fifo_size_words;
}
}
assert!(
fifo_top <= T::FIFO_DEPTH_WORDS,
"FIFO allocations exceeded maximum capacity"
);
// Flush fifos
r.grstctl().write(|w| {
w.set_rxfflsh(true);
w.set_txfflsh(true);
w.set_txfnum(0x10);
});
loop {
let x = r.grstctl().read();
if !x.rxfflsh() && !x.txfflsh() {
break;
}
}
}
fn configure_endpoints(&mut self) {
trace!("configure_endpoints");
let r = T::regs();
// Configure IN endpoints
for (index, ep) in self.ep_in.iter().enumerate() {
if let Some(ep) = ep {
critical_section::with(|_| {
r.diepctl(index).write(|w| {
if index == 0 {
w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
} else {
w.set_mpsiz(ep.max_packet_size);
w.set_eptyp(to_eptyp(ep.ep_type));
w.set_sd0pid_sevnfrm(true);
w.set_txfnum(index as _);
w.set_snak(true);
}
});
});
}
}
// Configure OUT endpoints
for (index, ep) in self.ep_out.iter().enumerate() {
if let Some(ep) = ep {
critical_section::with(|_| {
r.doepctl(index).write(|w| {
if index == 0 {
w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
} else {
w.set_mpsiz(ep.max_packet_size);
w.set_eptyp(to_eptyp(ep.ep_type));
w.set_sd0pid_sevnfrm(true);
}
});
r.doeptsiz(index).modify(|w| {
w.set_xfrsiz(ep.max_packet_size as _);
if index == 0 {
w.set_rxdpid_stupcnt(1);
} else {
w.set_pktcnt(1);
}
});
});
}
}
// Enable IRQs for allocated endpoints
r.daintmsk().modify(|w| {
w.set_iepm(ep_irq_mask(&self.ep_in));
// OUT interrupts not used, handled in RXFLVL
// w.set_oepm(ep_irq_mask(&self.ep_out));
});
}
fn disable_all_endpoints(&mut self) {
for i in 0..T::ENDPOINT_COUNT {
self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::In), false);
self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::Out), false);
}
}
fn disable(&mut self) {
T::Interrupt::disable();
<T as RccPeripheral>::disable();
#[cfg(stm32l4)]
crate::pac::PWR.cr2().modify(|w| w.set_usv(false));
// Cannot disable PWR, because other peripherals might be using it
}
}
impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
async fn poll(&mut self) -> Event {
poll_fn(move |cx| {
if !self.inited {
self.init();
self.inited = true;
// If no vbus detection, just return a single PowerDetected event at startup.
if !self.config.vbus_detection {
return Poll::Ready(Event::PowerDetected);
}
}
let r = T::regs();
T::state().bus_waker.register(cx.waker());
let ints = r.gintsts().read();
if ints.srqint() {
trace!("vbus detected");
r.gintsts().write(|w| w.set_srqint(true)); // clear
Self::restore_irqs();
if self.config.vbus_detection {
return Poll::Ready(Event::PowerDetected);
}
}
if ints.otgint() {
let otgints = r.gotgint().read();
r.gotgint().write_value(otgints); // clear all
Self::restore_irqs();
if otgints.sedet() {
trace!("vbus removed");
if self.config.vbus_detection {
self.disable_all_endpoints();
return Poll::Ready(Event::PowerRemoved);
}
}
}
if ints.usbrst() {
trace!("reset");
self.init_fifo();
self.configure_endpoints();
// Reset address
critical_section::with(|_| {
r.dcfg().modify(|w| {
w.set_dad(0);
});
});
r.gintsts().write(|w| w.set_usbrst(true)); // clear
Self::restore_irqs();
}
if ints.enumdne() {
trace!("enumdne");
let speed = r.dsts().read().enumspd();
trace!(" speed={}", speed.to_bits());
r.gusbcfg().modify(|w| {
w.set_trdt(calculate_trdt(speed, T::frequency()));
});
r.gintsts().write(|w| w.set_enumdne(true)); // clear
Self::restore_irqs();
return Poll::Ready(Event::Reset);
}
if ints.usbsusp() {
trace!("suspend");
r.gintsts().write(|w| w.set_usbsusp(true)); // clear
Self::restore_irqs();
return Poll::Ready(Event::Suspend);
}
if ints.wkupint() {
trace!("resume");
r.gintsts().write(|w| w.set_wkupint(true)); // clear
Self::restore_irqs();
return Poll::Ready(Event::Resume);
}
Poll::Pending
})
.await
}
fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) {
trace!("endpoint_set_stalled ep={:?} en={}", ep_addr, stalled);
assert!(
ep_addr.index() < T::ENDPOINT_COUNT,
"endpoint_set_stalled index {} out of range",
ep_addr.index()
);
let regs = T::regs();
match ep_addr.direction() {
Direction::Out => {
critical_section::with(|_| {
regs.doepctl(ep_addr.index()).modify(|w| {
w.set_stall(stalled);
});
});
T::state().ep_out_wakers[ep_addr.index()].wake();
}
Direction::In => {
critical_section::with(|_| {
regs.diepctl(ep_addr.index()).modify(|w| {
w.set_stall(stalled);
});
});
T::state().ep_in_wakers[ep_addr.index()].wake();
}
}
}
fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool {
assert!(
ep_addr.index() < T::ENDPOINT_COUNT,
"endpoint_is_stalled index {} out of range",
ep_addr.index()
);
let regs = T::regs();
match ep_addr.direction() {
Direction::Out => regs.doepctl(ep_addr.index()).read().stall(),
Direction::In => regs.diepctl(ep_addr.index()).read().stall(),
}
}
fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) {
trace!("endpoint_set_enabled ep={:?} en={}", ep_addr, enabled);
assert!(
ep_addr.index() < T::ENDPOINT_COUNT,
"endpoint_set_enabled index {} out of range",
ep_addr.index()
);
let r = T::regs();
match ep_addr.direction() {
Direction::Out => {
critical_section::with(|_| {
// cancel transfer if active
if !enabled && r.doepctl(ep_addr.index()).read().epena() {
r.doepctl(ep_addr.index()).modify(|w| {
w.set_snak(true);
w.set_epdis(true);
})
}
r.doepctl(ep_addr.index()).modify(|w| {
w.set_usbaep(enabled);
});
// Flush tx fifo
r.grstctl().write(|w| {
w.set_txfflsh(true);
w.set_txfnum(ep_addr.index() as _);
});
loop {
let x = r.grstctl().read();
if !x.txfflsh() {
break;
}
}
});
// Wake `Endpoint::wait_enabled()`
T::state().ep_out_wakers[ep_addr.index()].wake();
}
Direction::In => {
critical_section::with(|_| {
// cancel transfer if active
if !enabled && r.diepctl(ep_addr.index()).read().epena() {
r.diepctl(ep_addr.index()).modify(|w| {
w.set_snak(true); // set NAK
w.set_epdis(true);
})
}
r.diepctl(ep_addr.index()).modify(|w| {
w.set_usbaep(enabled);
w.set_cnak(enabled); // clear NAK that might've been set by SNAK above.
})
});
// Wake `Endpoint::wait_enabled()`
T::state().ep_in_wakers[ep_addr.index()].wake();
}
}
}
async fn enable(&mut self) {
trace!("enable");
// TODO: enable the peripheral once enable/disable semantics are cleared up in embassy-usb
}
async fn disable(&mut self) {
trace!("disable");
Bus::disable(self);
self.enabled = false;
// TODO: disable the peripheral once enable/disable semantics are cleared up in embassy-usb
//Bus::disable(self);
}
async fn remote_wakeup(&mut self) -> Result<(), Unsupported> {
@ -1112,11 +1213,16 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
state.ep_in_wakers[index].register(cx.waker());
let diepctl = r.diepctl(index).read();
let dtxfsts = r.dtxfsts(index).read();
info!("diepctl {:08x} ftxfsts {:08x}", diepctl.0, dtxfsts.0);
if !diepctl.usbaep() {
trace!("write ep={:?} wait for prev: error disabled", self.info.addr);
Poll::Ready(Err(EndpointError::Disabled))
} else if !diepctl.epena() {
trace!("write ep={:?} wait for prev: ready", self.info.addr);
Poll::Ready(Ok(()))
} else {
trace!("write ep={:?} wait for prev: pending", self.info.addr);
Poll::Pending
}
})
@ -1141,6 +1247,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
Poll::Pending
} else {
trace!("write ep={:?} wait for fifo: ready", self.info.addr);
Poll::Ready(())
}
})

View File

@ -49,7 +49,7 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> {
let wdg = T::regs();
wdg.kr().write(|w| w.set_key(Key::ENABLE));
wdg.pr().write(|w| w.set_pr(Pr(pr)));
wdg.pr().write(|w| w.set_pr(Pr::from_bits(pr)));
wdg.rlr().write(|w| w.set_rl(rl));
trace!(