Merge remote-tracking branch 'origin/main' into bxcan_timestamp
This commit is contained in:
@ -34,7 +34,7 @@ flavors = [
|
||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
||||
embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common", features = ["cortex-m", "prio-bits-4"] }
|
||||
embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] }
|
||||
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
|
||||
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true }
|
||||
@ -57,7 +57,7 @@ sdio-host = "0.5.0"
|
||||
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
||||
critical-section = "1.1"
|
||||
atomic-polyfill = "1.0.1"
|
||||
stm32-metapac = "13"
|
||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-1f8ab493e029fc601edebc6bac105a63cc9858fe" }
|
||||
vcell = "0.1.3"
|
||||
bxcan = "0.7.0"
|
||||
nb = "1.0.0"
|
||||
@ -67,6 +67,7 @@ cfg-if = "1.0.0"
|
||||
embedded-io = { version = "0.4.0", features = ["async"], optional = true }
|
||||
chrono = { version = "^0.4", default-features = false, optional = true}
|
||||
bit_field = "0.10.2"
|
||||
document-features = "0.2.7"
|
||||
|
||||
[dev-dependencies]
|
||||
critical-section = { version = "1.1", features = ["std"] }
|
||||
@ -74,44 +75,67 @@ critical-section = { version = "1.1", features = ["std"] }
|
||||
[build-dependencies]
|
||||
proc-macro2 = "1.0.36"
|
||||
quote = "1.0.15"
|
||||
stm32-metapac = { version = "13", default-features = false, features = ["metadata"]}
|
||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-1f8ab493e029fc601edebc6bac105a63cc9858fe", default-features = false, features = ["metadata"]}
|
||||
|
||||
[features]
|
||||
default = ["rt"]
|
||||
|
||||
## Enable `stm32-metapac`'s `rt` feature
|
||||
rt = ["stm32-metapac/rt"]
|
||||
|
||||
defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt", "embassy-net-driver/defmt", "embassy-time?/defmt"]
|
||||
memory-x = ["stm32-metapac/memory-x"]
|
||||
## Use [`defmt`](https://docs.rs/defmt/latest/defmt/) for logging
|
||||
defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-internal/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt", "embassy-net-driver/defmt", "embassy-time?/defmt"]
|
||||
|
||||
exti = []
|
||||
|
||||
# Enables additional driver features that depend on embassy-time
|
||||
## Automatically generate `memory.x` file using [`stm32-metapac`](https://docs.rs/stm32-metapac/)
|
||||
memory-x = ["stm32-metapac/memory-x"]
|
||||
|
||||
## Enable nightly-only features
|
||||
nightly = ["embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "dep:embedded-io", "dep:embassy-usb-driver", "embassy-embedded-hal/nightly"]
|
||||
|
||||
## Re-export stm32-metapac at `embassy_stm32::pac`.
|
||||
## This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version.
|
||||
## If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC.
|
||||
## There are no plans to make this stable.
|
||||
unstable-pac = []
|
||||
|
||||
## Implement embedded-hal 1.0 alpha traits.
|
||||
## Implement embedded-hal-async traits if `nightly` is set as well.
|
||||
unstable-traits = ["embedded-hal-1", "dep:embedded-hal-nb"]
|
||||
|
||||
#! ## Time
|
||||
|
||||
## Enables additional driver features that depend on embassy-time
|
||||
time = ["dep:embassy-time"]
|
||||
|
||||
# Features starting with `_` are for internal use only. They're not intended
|
||||
# to be enabled by other crates, and are not covered by semver guarantees.
|
||||
_time-driver = ["time"]
|
||||
|
||||
## Use any time driver
|
||||
time-driver-any = ["_time-driver"]
|
||||
## Use TIM2 as time driver
|
||||
time-driver-tim2 = ["_time-driver"]
|
||||
## Use TIM3 as time driver
|
||||
time-driver-tim3 = ["_time-driver"]
|
||||
## Use TIM4 as time driver
|
||||
time-driver-tim4 = ["_time-driver"]
|
||||
## Use TIM5 as time driver
|
||||
time-driver-tim5 = ["_time-driver"]
|
||||
## Use TIM12 as time driver
|
||||
time-driver-tim12 = ["_time-driver"]
|
||||
## Use TIM15 as time driver
|
||||
time-driver-tim15 = ["_time-driver"]
|
||||
|
||||
# Enable nightly-only features
|
||||
nightly = ["embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "dep:embedded-io", "dep:embassy-usb-driver", "embassy-embedded-hal/nightly"]
|
||||
|
||||
# Reexport stm32-metapac at `embassy_stm32::pac`.
|
||||
# This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version.
|
||||
# If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC.
|
||||
# There are no plans to make this stable.
|
||||
unstable-pac = []
|
||||
#! ## Chip-selection features
|
||||
#! Select your chip by specifying the model as a feature, e.g. `stm32c011d6`.
|
||||
#! Check the `Cargo.toml` for the latest list of supported chips.
|
||||
#!
|
||||
#! **Important:** Do not forget to adapt the target chip in your toolchain,
|
||||
#! e.g. in `.cargo/config.toml`.
|
||||
|
||||
# Implement embedded-hal 1.0 alpha traits.
|
||||
# Implement embedded-hal-async traits if `nightly` is set as well.
|
||||
unstable-traits = ["embedded-hal-1", "dep:embedded-hal-nb"]
|
||||
|
||||
# Chip-selection features
|
||||
stm32c011d6 = [ "stm32-metapac/stm32c011d6" ]
|
||||
stm32c011f4 = [ "stm32-metapac/stm32c011f4" ]
|
||||
stm32c011f6 = [ "stm32-metapac/stm32c011f6" ]
|
||||
|
@ -138,7 +138,7 @@ fn main() {
|
||||
let singleton_tokens: Vec<_> = singletons.iter().map(|s| format_ident!("{}", s)).collect();
|
||||
|
||||
g.extend(quote! {
|
||||
embassy_hal_common::peripherals_definition!(#(#singleton_tokens),*);
|
||||
embassy_hal_internal::peripherals_definition!(#(#singleton_tokens),*);
|
||||
});
|
||||
|
||||
let singleton_tokens: Vec<_> = singletons
|
||||
@ -148,7 +148,7 @@ fn main() {
|
||||
.collect();
|
||||
|
||||
g.extend(quote! {
|
||||
embassy_hal_common::peripherals_struct!(#(#singleton_tokens),*);
|
||||
embassy_hal_internal::peripherals_struct!(#(#singleton_tokens),*);
|
||||
});
|
||||
|
||||
// ========
|
||||
@ -160,7 +160,7 @@ fn main() {
|
||||
}
|
||||
|
||||
g.extend(quote! {
|
||||
embassy_hal_common::interrupt_mod!(
|
||||
embassy_hal_internal::interrupt_mod!(
|
||||
#(
|
||||
#irqs,
|
||||
)*
|
||||
@ -211,7 +211,7 @@ fn main() {
|
||||
let region_type = format_ident!("{}", get_flash_region_type_name(region.name));
|
||||
flash_regions.extend(quote! {
|
||||
#[cfg(flash)]
|
||||
pub struct #region_type<'d, MODE = crate::flash::Async>(pub &'static crate::flash::FlashRegion, pub(crate) embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>, pub(crate) core::marker::PhantomData<MODE>);
|
||||
pub struct #region_type<'d, MODE = crate::flash::Async>(pub &'static crate::flash::FlashRegion, pub(crate) embassy_hal_internal::PeripheralRef<'d, crate::peripherals::FLASH>, pub(crate) core::marker::PhantomData<MODE>);
|
||||
});
|
||||
}
|
||||
|
||||
@ -243,7 +243,7 @@ fn main() {
|
||||
|
||||
#[cfg(flash)]
|
||||
impl<'d, MODE> FlashLayout<'d, MODE> {
|
||||
pub(crate) fn new(p: embassy_hal_common::PeripheralRef<'d, crate::peripherals::FLASH>) -> Self {
|
||||
pub(crate) fn new(p: embassy_hal_internal::PeripheralRef<'d, crate::peripherals::FLASH>) -> Self {
|
||||
Self {
|
||||
#(#inits),*,
|
||||
_mode: core::marker::PhantomData,
|
||||
@ -572,21 +572,31 @@ fn main() {
|
||||
(("fmc", "Clk"), quote!(crate::fmc::ClkPin)),
|
||||
(("fmc", "BA0"), quote!(crate::fmc::BA0Pin)),
|
||||
(("fmc", "BA1"), quote!(crate::fmc::BA1Pin)),
|
||||
(("timer", "CH1"), quote!(crate::pwm::Channel1Pin)),
|
||||
(("timer", "CH1N"), quote!(crate::pwm::Channel1ComplementaryPin)),
|
||||
(("timer", "CH2"), quote!(crate::pwm::Channel2Pin)),
|
||||
(("timer", "CH2N"), quote!(crate::pwm::Channel2ComplementaryPin)),
|
||||
(("timer", "CH3"), quote!(crate::pwm::Channel3Pin)),
|
||||
(("timer", "CH3N"), quote!(crate::pwm::Channel3ComplementaryPin)),
|
||||
(("timer", "CH4"), quote!(crate::pwm::Channel4Pin)),
|
||||
(("timer", "CH4N"), quote!(crate::pwm::Channel4ComplementaryPin)),
|
||||
(("timer", "ETR"), quote!(crate::pwm::ExternalTriggerPin)),
|
||||
(("timer", "BKIN"), quote!(crate::pwm::BreakInputPin)),
|
||||
(("timer", "BKIN_COMP1"), quote!(crate::pwm::BreakInputComparator1Pin)),
|
||||
(("timer", "BKIN_COMP2"), quote!(crate::pwm::BreakInputComparator2Pin)),
|
||||
(("timer", "BKIN2"), quote!(crate::pwm::BreakInput2Pin)),
|
||||
(("timer", "BKIN2_COMP1"), quote!(crate::pwm::BreakInput2Comparator1Pin)),
|
||||
(("timer", "BKIN2_COMP2"), quote!(crate::pwm::BreakInput2Comparator2Pin)),
|
||||
(("timer", "CH1"), quote!(crate::timer::Channel1Pin)),
|
||||
(("timer", "CH1N"), quote!(crate::timer::Channel1ComplementaryPin)),
|
||||
(("timer", "CH2"), quote!(crate::timer::Channel2Pin)),
|
||||
(("timer", "CH2N"), quote!(crate::timer::Channel2ComplementaryPin)),
|
||||
(("timer", "CH3"), quote!(crate::timer::Channel3Pin)),
|
||||
(("timer", "CH3N"), quote!(crate::timer::Channel3ComplementaryPin)),
|
||||
(("timer", "CH4"), quote!(crate::timer::Channel4Pin)),
|
||||
(("timer", "CH4N"), quote!(crate::timer::Channel4ComplementaryPin)),
|
||||
(("timer", "ETR"), quote!(crate::timer::ExternalTriggerPin)),
|
||||
(("timer", "BKIN"), quote!(crate::timer::BreakInputPin)),
|
||||
(("timer", "BKIN_COMP1"), quote!(crate::timer::BreakInputComparator1Pin)),
|
||||
(("timer", "BKIN_COMP2"), quote!(crate::timer::BreakInputComparator2Pin)),
|
||||
(("timer", "BKIN2"), quote!(crate::timer::BreakInput2Pin)),
|
||||
(("timer", "BKIN2_COMP1"), quote!(crate::timer::BreakInput2Comparator1Pin)),
|
||||
(("timer", "BKIN2_COMP2"), quote!(crate::timer::BreakInput2Comparator2Pin)),
|
||||
(("hrtim", "CHA1"), quote!(crate::hrtim::ChannelAPin)),
|
||||
(("hrtim", "CHA2"), quote!(crate::hrtim::ChannelAComplementaryPin)),
|
||||
(("hrtim", "CHB1"), quote!(crate::hrtim::ChannelBPin)),
|
||||
(("hrtim", "CHB2"), quote!(crate::hrtim::ChannelBComplementaryPin)),
|
||||
(("hrtim", "CHC1"), quote!(crate::hrtim::ChannelCPin)),
|
||||
(("hrtim", "CHC2"), quote!(crate::hrtim::ChannelCComplementaryPin)),
|
||||
(("hrtim", "CHD1"), quote!(crate::hrtim::ChannelDPin)),
|
||||
(("hrtim", "CHD2"), quote!(crate::hrtim::ChannelDComplementaryPin)),
|
||||
(("hrtim", "CHE1"), quote!(crate::hrtim::ChannelEPin)),
|
||||
(("hrtim", "CHE2"), quote!(crate::hrtim::ChannelEComplementaryPin)),
|
||||
(("sdmmc", "CK"), quote!(crate::sdmmc::CkPin)),
|
||||
(("sdmmc", "CMD"), quote!(crate::sdmmc::CmdPin)),
|
||||
(("sdmmc", "D0"), quote!(crate::sdmmc::D0Pin)),
|
||||
|
@ -1,4 +1,4 @@
|
||||
use embassy_hal_common::into_ref;
|
||||
use embassy_hal_internal::into_ref;
|
||||
use embedded_hal_02::blocking::delay::DelayUs;
|
||||
|
||||
use crate::adc::{Adc, AdcPin, Instance, SampleTime};
|
||||
|
@ -1,4 +1,4 @@
|
||||
use embassy_hal_common::into_ref;
|
||||
use embassy_hal_internal::into_ref;
|
||||
use embedded_hal_02::blocking::delay::DelayUs;
|
||||
|
||||
use crate::adc::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime};
|
||||
|
@ -1,4 +1,4 @@
|
||||
use embassy_hal_common::into_ref;
|
||||
use embassy_hal_internal::into_ref;
|
||||
use embedded_hal_02::blocking::delay::DelayUs;
|
||||
|
||||
use super::InternalChannel;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use embassy_hal_common::into_ref;
|
||||
use embassy_hal_internal::into_ref;
|
||||
use embedded_hal_02::blocking::delay::DelayUs;
|
||||
|
||||
use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
|
||||
|
@ -226,7 +226,7 @@ impl Prescaler {
|
||||
|
||||
impl<'d, T: Instance> Adc<'d, T> {
|
||||
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u16>) -> Self {
|
||||
embassy_hal_common::into_ref!(adc);
|
||||
embassy_hal_internal::into_ref!(adc);
|
||||
T::enable();
|
||||
T::reset();
|
||||
|
||||
|
@ -6,7 +6,7 @@ use core::task::Poll;
|
||||
|
||||
pub use bxcan;
|
||||
use bxcan::{Data, ExtendedId, Frame, Id, StandardId};
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use futures::FutureExt;
|
||||
|
||||
use crate::gpio::sealed::AFType;
|
||||
@ -88,6 +88,7 @@ pub struct Can<'d, T: Instance> {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum BusError {
|
||||
Stuff,
|
||||
Form,
|
||||
@ -101,6 +102,22 @@ pub enum BusError {
|
||||
BusWarning,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum TryReadError {
|
||||
/// Bus error
|
||||
BusError(BusError),
|
||||
/// Receive buffer is empty
|
||||
Empty,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum TryWriteError {
|
||||
/// All transmit mailboxes are full
|
||||
Full,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Can<'d, T> {
|
||||
/// Creates a new Bxcan instance, keeping the peripheral in sleep mode.
|
||||
/// You must call [Can::enable_non_blocking] to use the peripheral.
|
||||
@ -186,56 +203,46 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
|
||||
/// Queues the message to be sent but exerts backpressure
|
||||
pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
|
||||
poll_fn(|cx| {
|
||||
T::state().tx_waker.register(cx.waker());
|
||||
if let Ok(status) = self.can.borrow_mut().transmit(frame) {
|
||||
return Poll::Ready(status);
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
})
|
||||
.await
|
||||
CanTx { can: &self.can }.write(frame).await
|
||||
}
|
||||
|
||||
pub async fn flush(&self, mb: bxcan::Mailbox) {
|
||||
poll_fn(|cx| {
|
||||
T::state().tx_waker.register(cx.waker());
|
||||
if T::regs().tsr().read().tme(mb.index()) {
|
||||
return Poll::Ready(());
|
||||
}
|
||||
/// Attempts to transmit a frame without blocking.
|
||||
///
|
||||
/// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full.
|
||||
pub fn try_write(&mut self, frame: &Frame) -> Result<bxcan::TransmitStatus, TryWriteError> {
|
||||
CanTx { can: &self.can }.try_write(frame)
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
})
|
||||
.await;
|
||||
/// Waits for a specific transmit mailbox to become empty
|
||||
pub async fn flush(&self, mb: bxcan::Mailbox) {
|
||||
CanTx { can: &self.can }.flush(mb).await
|
||||
}
|
||||
|
||||
/// Waits until any of the transmit mailboxes become empty
|
||||
pub async fn flush_any(&self) {
|
||||
CanTx { can: &self.can }.flush_any().await
|
||||
}
|
||||
|
||||
/// Waits until all of the transmit mailboxes become empty
|
||||
pub async fn flush_all(&self) {
|
||||
CanTx { can: &self.can }.flush_all().await
|
||||
}
|
||||
|
||||
/// Returns a tuple of the time the message was received and the message frame
|
||||
pub async fn read(&mut self) -> Result<Envelope, BusError> {
|
||||
poll_fn(|cx| {
|
||||
T::state().err_waker.register(cx.waker());
|
||||
if let Poll::Ready(envelope) = T::state().rx_queue.recv().poll_unpin(cx) {
|
||||
return Poll::Ready(Ok(envelope));
|
||||
} else if let Some(err) = self.curr_error() {
|
||||
return Poll::Ready(Err(err));
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
})
|
||||
.await
|
||||
CanRx { can: &self.can }.read().await
|
||||
}
|
||||
|
||||
fn curr_error(&self) -> Option<BusError> {
|
||||
let err = { T::regs().esr().read() };
|
||||
if err.boff() {
|
||||
return Some(BusError::BusOff);
|
||||
} else if err.epvf() {
|
||||
return Some(BusError::BusPassive);
|
||||
} else if err.ewgf() {
|
||||
return Some(BusError::BusWarning);
|
||||
} else if let Some(err) = err.lec().into_bus_err() {
|
||||
return Some(err);
|
||||
}
|
||||
None
|
||||
/// Attempts to read a can frame without blocking.
|
||||
///
|
||||
/// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
|
||||
pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
|
||||
CanRx { can: &self.can }.try_read()
|
||||
}
|
||||
|
||||
/// Waits while receive queue is empty.
|
||||
pub async fn wait_not_empty(&mut self) {
|
||||
CanRx { can: &self.can }.wait_not_empty().await
|
||||
}
|
||||
|
||||
unsafe fn receive_fifo(fifo: RxFifo) {
|
||||
@ -405,6 +412,14 @@ impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> {
|
||||
.await
|
||||
}
|
||||
|
||||
/// Attempts to transmit a frame without blocking.
|
||||
///
|
||||
/// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full.
|
||||
pub fn try_write(&mut self, frame: &Frame) -> Result<bxcan::TransmitStatus, TryWriteError> {
|
||||
self.can.borrow_mut().transmit(frame).map_err(|_| TryWriteError::Full)
|
||||
}
|
||||
|
||||
/// Waits for a specific transmit mailbox to become empty
|
||||
pub async fn flush(&self, mb: bxcan::Mailbox) {
|
||||
poll_fn(|cx| {
|
||||
T::state().tx_waker.register(cx.waker());
|
||||
@ -416,6 +431,42 @@ impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> {
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
/// Waits until any of the transmit mailboxes become empty
|
||||
pub async fn flush_any(&self) {
|
||||
poll_fn(|cx| {
|
||||
T::state().tx_waker.register(cx.waker());
|
||||
|
||||
let tsr = T::regs().tsr().read();
|
||||
if tsr.tme(bxcan::Mailbox::Mailbox0.index())
|
||||
|| tsr.tme(bxcan::Mailbox::Mailbox1.index())
|
||||
|| tsr.tme(bxcan::Mailbox::Mailbox2.index())
|
||||
{
|
||||
return Poll::Ready(());
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
/// Waits until all of the transmit mailboxes become empty
|
||||
pub async fn flush_all(&self) {
|
||||
poll_fn(|cx| {
|
||||
T::state().tx_waker.register(cx.waker());
|
||||
|
||||
let tsr = T::regs().tsr().read();
|
||||
if tsr.tme(bxcan::Mailbox::Mailbox0.index())
|
||||
&& tsr.tme(bxcan::Mailbox::Mailbox1.index())
|
||||
&& tsr.tme(bxcan::Mailbox::Mailbox2.index())
|
||||
{
|
||||
return Poll::Ready(());
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
})
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@ -438,6 +489,33 @@ impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> {
|
||||
.await
|
||||
}
|
||||
|
||||
/// Attempts to read a CAN frame without blocking.
|
||||
///
|
||||
/// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
|
||||
pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
|
||||
if let Ok(envelope) = T::state().rx_queue.try_recv() {
|
||||
return Ok(envelope);
|
||||
}
|
||||
|
||||
if let Some(err) = self.curr_error() {
|
||||
return Err(TryReadError::BusError(err));
|
||||
}
|
||||
|
||||
Err(TryReadError::Empty)
|
||||
}
|
||||
|
||||
/// Waits while receive queue is empty.
|
||||
pub async fn wait_not_empty(&mut self) {
|
||||
poll_fn(|cx| {
|
||||
if T::state().rx_queue.poll_ready_to_receive(cx) {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
fn curr_error(&self) -> Option<BusError> {
|
||||
let err = { T::regs().esr().read() };
|
||||
if err.boff() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
pub use bxcan;
|
||||
use embassy_hal_common::PeripheralRef;
|
||||
use embassy_hal_internal::PeripheralRef;
|
||||
|
||||
use crate::peripherals;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
|
||||
use crate::pac::CRC as PAC_CRC;
|
||||
use crate::peripherals::CRC;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
|
||||
use crate::pac::crc::vals;
|
||||
use crate::pac::CRC as PAC_CRC;
|
||||
|
@ -3,7 +3,7 @@
|
||||
//! Provide access to the STM32 digital-to-analog converter (DAC).
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
|
||||
use crate::pac::dac;
|
||||
use crate::rcc::RccPeripheral;
|
||||
|
@ -2,7 +2,7 @@ use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use crate::dma::Transfer;
|
||||
|
@ -6,7 +6,7 @@ use core::sync::atomic::{fence, Ordering};
|
||||
use core::task::{Context, Poll, Waker};
|
||||
|
||||
use atomic_polyfill::AtomicUsize;
|
||||
use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
|
||||
use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use super::ringbuffer::{DmaCtrl, DmaRingBuffer, OverrunError};
|
||||
@ -466,15 +466,53 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
|
||||
self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow()));
|
||||
}
|
||||
|
||||
/// Read bytes from the ring buffer
|
||||
/// Read elements from the ring buffer
|
||||
/// Return a tuple of the length read and the length remaining in the buffer
|
||||
/// If not all of the bytes were read, then there will be some bytes in the buffer remaining
|
||||
/// The length remaining is the capacity, ring_buf.len(), less the bytes remaining after the read
|
||||
/// If not all of the elements were read, then there will be some elements in the buffer remaining
|
||||
/// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read
|
||||
/// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
|
||||
pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
|
||||
self.ringbuf.read(DmaCtrlImpl(self.channel.reborrow()), buf)
|
||||
}
|
||||
|
||||
/// Read an exact number of elements from the ringbuffer.
|
||||
///
|
||||
/// Returns the remaining number of elements available for immediate reading.
|
||||
/// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
|
||||
///
|
||||
/// Async/Wake Behavior:
|
||||
/// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point,
|
||||
/// and when it wraps around. This means that when called with a buffer of length 'M', when this
|
||||
/// ring buffer was created with a buffer of size 'N':
|
||||
/// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source.
|
||||
/// - Otherwise, this function may need up to N/2 extra elements to arrive before returning.
|
||||
pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, OverrunError> {
|
||||
use core::future::poll_fn;
|
||||
use core::sync::atomic::compiler_fence;
|
||||
|
||||
let mut read_data = 0;
|
||||
let buffer_len = buffer.len();
|
||||
|
||||
poll_fn(|cx| {
|
||||
self.set_waker(cx.waker());
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
match self.read(&mut buffer[read_data..buffer_len]) {
|
||||
Ok((len, remaining)) => {
|
||||
read_data += len;
|
||||
if read_data == buffer_len {
|
||||
Poll::Ready(Ok(remaining))
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
Err(e) => Poll::Ready(Err(e)),
|
||||
}
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// The capacity of the ringbuffer
|
||||
pub fn cap(&self) -> usize {
|
||||
self.ringbuf.cap()
|
||||
|
@ -4,7 +4,7 @@ use core::pin::Pin;
|
||||
use core::sync::atomic::{fence, AtomicUsize, Ordering};
|
||||
use core::task::{Context, Poll, Waker};
|
||||
|
||||
use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
|
||||
use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use super::ringbuffer::{DmaCtrl, DmaRingBuffer, OverrunError};
|
||||
@ -711,15 +711,53 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
|
||||
self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow()));
|
||||
}
|
||||
|
||||
/// Read bytes from the ring buffer
|
||||
/// Read elements from the ring buffer
|
||||
/// Return a tuple of the length read and the length remaining in the buffer
|
||||
/// If not all of the bytes were read, then there will be some bytes in the buffer remaining
|
||||
/// The length remaining is the capacity, ring_buf.len(), less the bytes remaining after the read
|
||||
/// If not all of the elements were read, then there will be some elements in the buffer remaining
|
||||
/// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read
|
||||
/// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
|
||||
pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
|
||||
self.ringbuf.read(DmaCtrlImpl(self.channel.reborrow()), buf)
|
||||
}
|
||||
|
||||
/// Read an exact number of elements from the ringbuffer.
|
||||
///
|
||||
/// Returns the remaining number of elements available for immediate reading.
|
||||
/// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
|
||||
///
|
||||
/// Async/Wake Behavior:
|
||||
/// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point,
|
||||
/// and when it wraps around. This means that when called with a buffer of length 'M', when this
|
||||
/// ring buffer was created with a buffer of size 'N':
|
||||
/// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source.
|
||||
/// - Otherwise, this function may need up to N/2 extra elements to arrive before returning.
|
||||
pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, OverrunError> {
|
||||
use core::future::poll_fn;
|
||||
use core::sync::atomic::compiler_fence;
|
||||
|
||||
let mut read_data = 0;
|
||||
let buffer_len = buffer.len();
|
||||
|
||||
poll_fn(|cx| {
|
||||
self.set_waker(cx.waker());
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
match self.read(&mut buffer[read_data..buffer_len]) {
|
||||
Ok((len, remaining)) => {
|
||||
read_data += len;
|
||||
if read_data == buffer_len {
|
||||
Poll::Ready(Ok(remaining))
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
Err(e) => Poll::Ready(Err(e)),
|
||||
}
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
// The capacity of the ringbuffer
|
||||
pub fn cap(&self) -> usize {
|
||||
self.ringbuf.cap()
|
||||
|
@ -5,7 +5,7 @@ use core::pin::Pin;
|
||||
use core::sync::atomic::{fence, Ordering};
|
||||
use core::task::{Context, Poll};
|
||||
|
||||
use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
|
||||
use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use super::word::{Word, WordSize};
|
||||
|
@ -26,7 +26,7 @@ pub mod word;
|
||||
|
||||
use core::mem;
|
||||
|
||||
use embassy_hal_common::impl_peripheral;
|
||||
use embassy_hal_internal::impl_peripheral;
|
||||
|
||||
#[cfg(dmamux)]
|
||||
pub use self::dmamux::*;
|
||||
|
@ -72,10 +72,10 @@ impl<'a, W: Word> DmaRingBuffer<'a, W> {
|
||||
self.cap() - remaining_transfers
|
||||
}
|
||||
|
||||
/// Read bytes from the ring buffer
|
||||
/// Read elements from the ring buffer
|
||||
/// Return a tuple of the length read and the length remaining in the buffer
|
||||
/// If not all of the bytes were read, then there will be some bytes in the buffer remaining
|
||||
/// The length remaining is the capacity, ring_buf.len(), less the bytes remaining after the read
|
||||
/// If not all of the elements were read, then there will be some elements in the buffer remaining
|
||||
/// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read
|
||||
/// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
|
||||
pub fn read(&mut self, mut dma: impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
|
||||
/*
|
||||
@ -95,11 +95,11 @@ impl<'a, W: Word> DmaRingBuffer<'a, W> {
|
||||
*/
|
||||
let end = self.pos(dma.get_remaining_transfers());
|
||||
if self.start == end && dma.get_complete_count() == 0 {
|
||||
// No bytes are available in the buffer
|
||||
// No elements are available in the buffer
|
||||
Ok((0, self.cap()))
|
||||
} else if self.start < end {
|
||||
// The available, unread portion in the ring buffer DOES NOT wrap
|
||||
// Copy out the bytes from the dma buffer
|
||||
// Copy out the elements from the dma buffer
|
||||
let len = self.copy_to(buf, self.start..end);
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
@ -128,7 +128,7 @@ impl<'a, W: Word> DmaRingBuffer<'a, W> {
|
||||
// The DMA writer has wrapped since we last read and is currently
|
||||
// writing (or the next byte added will be) in the beginning of the ring buffer.
|
||||
|
||||
// The provided read buffer is not large enough to include all bytes from the tail of the dma buffer.
|
||||
// The provided read buffer is not large enough to include all elements from the tail of the dma buffer.
|
||||
|
||||
// Copy out from the dma buffer
|
||||
let len = self.copy_to(buf, self.start..self.cap());
|
||||
@ -154,8 +154,8 @@ impl<'a, W: Word> DmaRingBuffer<'a, W> {
|
||||
// The DMA writer has wrapped since we last read and is currently
|
||||
// writing (or the next byte added will be) in the beginning of the ring buffer.
|
||||
|
||||
// The provided read buffer is large enough to include all bytes from the tail of the dma buffer,
|
||||
// so the next read will not have any unread tail bytes in the ring buffer.
|
||||
// The provided read buffer is large enough to include all elements from the tail of the dma buffer,
|
||||
// so the next read will not have any unread tail elements in the ring buffer.
|
||||
|
||||
// Copy out from the dma buffer
|
||||
let tail = self.copy_to(buf, self.start..self.cap());
|
||||
@ -180,7 +180,7 @@ impl<'a, W: Word> DmaRingBuffer<'a, W> {
|
||||
}
|
||||
/// Copy from the dma buffer at `data_range` into `buf`
|
||||
fn copy_to(&mut self, buf: &mut [W], data_range: Range<usize>) -> usize {
|
||||
// Limit the number of bytes that can be copied
|
||||
// Limit the number of elements that can be copied
|
||||
let length = usize::min(data_range.len(), buf.len());
|
||||
|
||||
// Copy from dma buffer into read buffer
|
||||
|
@ -6,7 +6,7 @@ mod tx_desc;
|
||||
use core::marker::PhantomData;
|
||||
use core::sync::atomic::{fence, Ordering};
|
||||
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf};
|
||||
|
||||
pub(crate) use self::rx_desc::{RDes, RDesRing};
|
||||
|
@ -3,7 +3,7 @@ mod descriptors;
|
||||
use core::marker::PhantomData;
|
||||
use core::sync::atomic::{fence, Ordering};
|
||||
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
|
||||
pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing};
|
||||
use super::*;
|
||||
|
@ -3,7 +3,7 @@ use core::marker::PhantomData;
|
||||
use core::pin::Pin;
|
||||
use core::task::{Context, Poll};
|
||||
|
||||
use embassy_hal_common::impl_peripheral;
|
||||
use embassy_hal_internal::impl_peripheral;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use crate::gpio::{AnyPin, Input, Pin as GpioPin};
|
||||
|
@ -1,8 +1,8 @@
|
||||
use core::marker::PhantomData;
|
||||
use core::sync::atomic::{fence, Ordering};
|
||||
|
||||
use embassy_hal_common::drop::OnDrop;
|
||||
use embassy_hal_common::into_ref;
|
||||
use embassy_hal_internal::drop::OnDrop;
|
||||
use embassy_hal_internal::into_ref;
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::mutex::Mutex;
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
use core::marker::PhantomData;
|
||||
use core::sync::atomic::{fence, Ordering};
|
||||
|
||||
use embassy_hal_common::drop::OnDrop;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_hal_internal::drop::OnDrop;
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use stm32_metapac::FLASH_BASE;
|
||||
|
||||
use super::{
|
||||
|
@ -14,7 +14,7 @@ use crate::pac;
|
||||
mod alt_regions {
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use embassy_hal_common::PeripheralRef;
|
||||
use embassy_hal_internal::PeripheralRef;
|
||||
use stm32_metapac::FLASH_SIZE;
|
||||
|
||||
use crate::_generated::flash_regions::{OTPRegion, BANK1_REGION1, BANK1_REGION2, BANK1_REGION3, OTP_REGION};
|
||||
|
@ -1,6 +1,6 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use embassy_hal_common::into_ref;
|
||||
use embassy_hal_internal::into_ref;
|
||||
|
||||
use crate::gpio::sealed::AFType;
|
||||
use crate::gpio::{Pull, Speed};
|
||||
|
@ -1,7 +1,7 @@
|
||||
#![macro_use]
|
||||
use core::convert::Infallible;
|
||||
|
||||
use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
|
||||
use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef};
|
||||
|
||||
use crate::pac::gpio::{self, vals};
|
||||
use crate::{pac, peripherals, Peripheral};
|
||||
@ -502,6 +502,20 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum OutputType {
|
||||
PushPull,
|
||||
OpenDrain,
|
||||
}
|
||||
|
||||
impl From<OutputType> for sealed::AFType {
|
||||
fn from(value: OutputType) -> Self {
|
||||
match value {
|
||||
OutputType::OpenDrain => sealed::AFType::OutputOpenDrain,
|
||||
OutputType::PushPull => sealed::AFType::OutputPushPull,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod sealed {
|
||||
use super::*;
|
||||
|
||||
|
409
embassy-stm32/src/hrtim/mod.rs
Normal file
409
embassy-stm32/src/hrtim/mod.rs
Normal file
@ -0,0 +1,409 @@
|
||||
mod traits;
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
pub use traits::Instance;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use crate::gpio::sealed::{AFType, Pin};
|
||||
use crate::gpio::AnyPin;
|
||||
use crate::time::Hertz;
|
||||
use crate::Peripheral;
|
||||
|
||||
pub enum Source {
|
||||
Master,
|
||||
ChA,
|
||||
ChB,
|
||||
ChC,
|
||||
ChD,
|
||||
ChE,
|
||||
}
|
||||
|
||||
pub struct BurstController<T: Instance> {
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
pub struct Master<T: Instance> {
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
pub struct ChA<T: Instance> {
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
pub struct ChB<T: Instance> {
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
pub struct ChC<T: Instance> {
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
pub struct ChD<T: Instance> {
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
pub struct ChE<T: Instance> {
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
mod sealed {
|
||||
use super::Instance;
|
||||
|
||||
pub trait AdvancedChannel<T: Instance> {
|
||||
fn raw() -> usize;
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {}
|
||||
|
||||
pub struct PwmPin<'d, Perip, Channel> {
|
||||
_pin: PeripheralRef<'d, AnyPin>,
|
||||
phantom: PhantomData<(Perip, Channel)>,
|
||||
}
|
||||
|
||||
pub struct ComplementaryPwmPin<'d, Perip, Channel> {
|
||||
_pin: PeripheralRef<'d, AnyPin>,
|
||||
phantom: PhantomData<(Perip, Channel)>,
|
||||
}
|
||||
|
||||
macro_rules! advanced_channel_impl {
|
||||
($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => {
|
||||
impl<'d, Perip: Instance> PwmPin<'d, Perip, $channel<Perip>> {
|
||||
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self {
|
||||
into_ref!(pin);
|
||||
critical_section::with(|_| {
|
||||
pin.set_low();
|
||||
pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
|
||||
#[cfg(gpio_v2)]
|
||||
pin.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
});
|
||||
PwmPin {
|
||||
_pin: pin.map_into(),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, Perip: Instance> ComplementaryPwmPin<'d, Perip, $channel<Perip>> {
|
||||
pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self {
|
||||
into_ref!(pin);
|
||||
critical_section::with(|_| {
|
||||
pin.set_low();
|
||||
pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
|
||||
#[cfg(gpio_v2)]
|
||||
pin.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
});
|
||||
ComplementaryPwmPin {
|
||||
_pin: pin.map_into(),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Instance> sealed::AdvancedChannel<T> for $channel<T> {
|
||||
fn raw() -> usize {
|
||||
$ch_num
|
||||
}
|
||||
}
|
||||
impl<T: Instance> AdvancedChannel<T> for $channel<T> {}
|
||||
};
|
||||
}
|
||||
|
||||
advanced_channel_impl!(new_cha, ChA, 0, ChannelAPin, ChannelAComplementaryPin);
|
||||
advanced_channel_impl!(new_chb, ChB, 1, ChannelBPin, ChannelBComplementaryPin);
|
||||
advanced_channel_impl!(new_chc, ChC, 2, ChannelCPin, ChannelCComplementaryPin);
|
||||
advanced_channel_impl!(new_chd, ChD, 3, ChannelDPin, ChannelDComplementaryPin);
|
||||
advanced_channel_impl!(new_che, ChE, 4, ChannelEPin, ChannelEComplementaryPin);
|
||||
|
||||
/// Struct used to divide a high resolution timer into multiple channels
|
||||
pub struct AdvancedPwm<'d, T: Instance> {
|
||||
_inner: PeripheralRef<'d, T>,
|
||||
pub master: Master<T>,
|
||||
pub burst_controller: BurstController<T>,
|
||||
pub ch_a: ChA<T>,
|
||||
pub ch_b: ChB<T>,
|
||||
pub ch_c: ChC<T>,
|
||||
pub ch_d: ChD<T>,
|
||||
pub ch_e: ChE<T>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> AdvancedPwm<'d, T> {
|
||||
pub fn new(
|
||||
tim: impl Peripheral<P = T> + 'd,
|
||||
_cha: Option<PwmPin<'d, T, ChA<T>>>,
|
||||
_chan: Option<ComplementaryPwmPin<'d, T, ChA<T>>>,
|
||||
_chb: Option<PwmPin<'d, T, ChB<T>>>,
|
||||
_chbn: Option<ComplementaryPwmPin<'d, T, ChB<T>>>,
|
||||
_chc: Option<PwmPin<'d, T, ChC<T>>>,
|
||||
_chcn: Option<ComplementaryPwmPin<'d, T, ChC<T>>>,
|
||||
_chd: Option<PwmPin<'d, T, ChD<T>>>,
|
||||
_chdn: Option<ComplementaryPwmPin<'d, T, ChD<T>>>,
|
||||
_che: Option<PwmPin<'d, T, ChE<T>>>,
|
||||
_chen: Option<ComplementaryPwmPin<'d, T, ChE<T>>>,
|
||||
) -> Self {
|
||||
Self::new_inner(tim)
|
||||
}
|
||||
|
||||
fn new_inner(tim: impl Peripheral<P = T> + 'd) -> Self {
|
||||
into_ref!(tim);
|
||||
|
||||
T::enable();
|
||||
<T as crate::rcc::sealed::RccPeripheral>::reset();
|
||||
|
||||
// // Enable and and stabilize the DLL
|
||||
// T::regs().dllcr().modify(|w| {
|
||||
// // w.set_calen(true);
|
||||
// // w.set_calrte(11);
|
||||
// w.set_cal(true);
|
||||
// });
|
||||
//
|
||||
// debug!("wait for dll calibration");
|
||||
// while !T::regs().isr().read().dllrdy() {}
|
||||
//
|
||||
// debug!("dll calibration complete");
|
||||
|
||||
Self {
|
||||
_inner: tim,
|
||||
master: Master { phantom: PhantomData },
|
||||
burst_controller: BurstController { phantom: PhantomData },
|
||||
ch_a: ChA { phantom: PhantomData },
|
||||
ch_b: ChB { phantom: PhantomData },
|
||||
ch_c: ChC { phantom: PhantomData },
|
||||
ch_d: ChD { phantom: PhantomData },
|
||||
ch_e: ChE { phantom: PhantomData },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Instance> BurstController<T> {
|
||||
pub fn set_source(&mut self, _source: Source) {
|
||||
todo!("burst mode control registers not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a fixed-frequency bridge converter
|
||||
///
|
||||
/// Our implementation of the bridge converter uses a single channel and three compare registers,
|
||||
/// allowing implementation of a synchronous buck or boost converter in continuous or discontinuous
|
||||
/// conduction mode.
|
||||
///
|
||||
/// It is important to remember that in synchronous topologies, energy can flow in reverse during
|
||||
/// light loading conditions, and that the low-side switch must be active for a short time to drive
|
||||
/// a bootstrapped high-side switch.
|
||||
pub struct BridgeConverter<T: Instance, C: AdvancedChannel<T>> {
|
||||
timer: PhantomData<T>,
|
||||
channel: PhantomData<C>,
|
||||
dead_time: u16,
|
||||
primary_duty: u16,
|
||||
min_secondary_duty: u16,
|
||||
max_secondary_duty: u16,
|
||||
}
|
||||
|
||||
impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
|
||||
pub fn new(_channel: C, frequency: Hertz) -> Self {
|
||||
use crate::pac::hrtim::vals::{Activeeffect, Inactiveeffect};
|
||||
|
||||
T::set_channel_frequency(C::raw(), frequency);
|
||||
|
||||
// Always enable preload
|
||||
T::regs().tim(C::raw()).cr().modify(|w| {
|
||||
w.set_preen(true);
|
||||
w.set_repu(true);
|
||||
w.set_cont(true);
|
||||
});
|
||||
|
||||
// Enable timer outputs
|
||||
T::regs().oenr().modify(|w| {
|
||||
w.set_t1oen(C::raw(), true);
|
||||
w.set_t2oen(C::raw(), true);
|
||||
});
|
||||
|
||||
// The dead-time generation unit cannot be used because it forces the other output
|
||||
// to be completely complementary to the first output, which restricts certain waveforms
|
||||
// Therefore, software-implemented dead time must be used when setting the duty cycles
|
||||
|
||||
// Set output 1 to active on a period event
|
||||
T::regs()
|
||||
.tim(C::raw())
|
||||
.setr(0)
|
||||
.modify(|w| w.set_per(Activeeffect::SETACTIVE));
|
||||
|
||||
// Set output 1 to inactive on a compare 1 event
|
||||
T::regs()
|
||||
.tim(C::raw())
|
||||
.rstr(0)
|
||||
.modify(|w| w.set_cmp(0, Inactiveeffect::SETINACTIVE));
|
||||
|
||||
// Set output 2 to active on a compare 2 event
|
||||
T::regs()
|
||||
.tim(C::raw())
|
||||
.setr(1)
|
||||
.modify(|w| w.set_cmp(1, Activeeffect::SETACTIVE));
|
||||
|
||||
// Set output 2 to inactive on a compare 3 event
|
||||
T::regs()
|
||||
.tim(C::raw())
|
||||
.rstr(1)
|
||||
.modify(|w| w.set_cmp(2, Inactiveeffect::SETINACTIVE));
|
||||
|
||||
Self {
|
||||
timer: PhantomData,
|
||||
channel: PhantomData,
|
||||
dead_time: 0,
|
||||
primary_duty: 0,
|
||||
min_secondary_duty: 0,
|
||||
max_secondary_duty: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(&mut self) {
|
||||
T::regs().mcr().modify(|w| w.set_tcen(C::raw(), true));
|
||||
}
|
||||
|
||||
pub fn stop(&mut self) {
|
||||
T::regs().mcr().modify(|w| w.set_tcen(C::raw(), false));
|
||||
}
|
||||
|
||||
pub fn enable_burst_mode(&mut self) {
|
||||
T::regs().tim(C::raw()).outr().modify(|w| {
|
||||
// Enable Burst Mode
|
||||
w.set_idlem(0, true);
|
||||
w.set_idlem(1, true);
|
||||
|
||||
// Set output to active during the burst
|
||||
w.set_idles(0, true);
|
||||
w.set_idles(1, true);
|
||||
})
|
||||
}
|
||||
|
||||
pub fn disable_burst_mode(&mut self) {
|
||||
T::regs().tim(C::raw()).outr().modify(|w| {
|
||||
// Disable Burst Mode
|
||||
w.set_idlem(0, false);
|
||||
w.set_idlem(1, false);
|
||||
})
|
||||
}
|
||||
|
||||
fn update_primary_duty_or_dead_time(&mut self) {
|
||||
self.min_secondary_duty = self.primary_duty + self.dead_time;
|
||||
|
||||
T::regs().tim(C::raw()).cmp(0).modify(|w| w.set_cmp(self.primary_duty));
|
||||
T::regs()
|
||||
.tim(C::raw())
|
||||
.cmp(1)
|
||||
.modify(|w| w.set_cmp(self.min_secondary_duty));
|
||||
}
|
||||
|
||||
/// Set the dead time as a proportion of the maximum compare value
|
||||
pub fn set_dead_time(&mut self, dead_time: u16) {
|
||||
self.dead_time = dead_time;
|
||||
self.max_secondary_duty = self.get_max_compare_value() - dead_time;
|
||||
self.update_primary_duty_or_dead_time();
|
||||
}
|
||||
|
||||
/// Get the maximum compare value of a duty cycle
|
||||
pub fn get_max_compare_value(&mut self) -> u16 {
|
||||
T::regs().tim(C::raw()).per().read().per()
|
||||
}
|
||||
|
||||
/// The primary duty is the period in which the primary switch is active
|
||||
///
|
||||
/// In the case of a buck converter, this is the high-side switch
|
||||
/// In the case of a boost converter, this is the low-side switch
|
||||
pub fn set_primary_duty(&mut self, primary_duty: u16) {
|
||||
self.primary_duty = primary_duty;
|
||||
self.update_primary_duty_or_dead_time();
|
||||
}
|
||||
|
||||
/// The secondary duty is the period in any switch is active
|
||||
///
|
||||
/// If less than or equal to the primary duty, the secondary switch will be active for one tick
|
||||
/// If a fully complementary output is desired, the secondary duty can be set to the max compare
|
||||
pub fn set_secondary_duty(&mut self, secondary_duty: u16) {
|
||||
let secondary_duty = if secondary_duty > self.max_secondary_duty {
|
||||
self.max_secondary_duty
|
||||
} else if secondary_duty <= self.min_secondary_duty {
|
||||
self.min_secondary_duty + 1
|
||||
} else {
|
||||
secondary_duty
|
||||
};
|
||||
|
||||
T::regs().tim(C::raw()).cmp(2).modify(|w| w.set_cmp(secondary_duty));
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a variable-frequency resonant converter
|
||||
///
|
||||
/// This implementation of a resonsant converter is appropriate for a half or full bridge,
|
||||
/// but does not include secondary rectification, which is appropriate for applications
|
||||
/// with a low-voltage on the secondary side.
|
||||
pub struct ResonantConverter<T: Instance, C: AdvancedChannel<T>> {
|
||||
timer: PhantomData<T>,
|
||||
channel: PhantomData<C>,
|
||||
min_period: u16,
|
||||
max_period: u16,
|
||||
}
|
||||
|
||||
impl<T: Instance, C: AdvancedChannel<T>> ResonantConverter<T, C> {
|
||||
pub fn new(_channel: C, min_frequency: Hertz, max_frequency: Hertz) -> Self {
|
||||
T::set_channel_frequency(C::raw(), min_frequency);
|
||||
|
||||
// Always enable preload
|
||||
T::regs().tim(C::raw()).cr().modify(|w| {
|
||||
w.set_preen(true);
|
||||
w.set_repu(true);
|
||||
|
||||
w.set_cont(true);
|
||||
w.set_half(true);
|
||||
});
|
||||
|
||||
// Enable timer outputs
|
||||
T::regs().oenr().modify(|w| {
|
||||
w.set_t1oen(C::raw(), true);
|
||||
w.set_t2oen(C::raw(), true);
|
||||
});
|
||||
|
||||
// Dead-time generator can be used in this case because the primary fets
|
||||
// of a resonant converter are always complementary
|
||||
T::regs().tim(C::raw()).outr().modify(|w| w.set_dten(true));
|
||||
|
||||
let max_period = T::regs().tim(C::raw()).per().read().per();
|
||||
let min_period = max_period * (min_frequency.0 / max_frequency.0) as u16;
|
||||
|
||||
Self {
|
||||
timer: PhantomData,
|
||||
channel: PhantomData,
|
||||
min_period: min_period,
|
||||
max_period: max_period,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the dead time as a proportion of the maximum compare value
|
||||
pub fn set_dead_time(&mut self, value: u16) {
|
||||
T::set_channel_dead_time(C::raw(), value);
|
||||
}
|
||||
|
||||
pub fn set_period(&mut self, period: u16) {
|
||||
assert!(period < self.max_period);
|
||||
assert!(period > self.min_period);
|
||||
|
||||
T::regs().tim(C::raw()).per().modify(|w| w.set_per(period));
|
||||
}
|
||||
|
||||
/// Get the minimum compare value of a duty cycle
|
||||
pub fn get_min_period(&mut self) -> u16 {
|
||||
self.min_period
|
||||
}
|
||||
|
||||
/// Get the maximum compare value of a duty cycle
|
||||
pub fn get_max_period(&mut self) -> u16 {
|
||||
self.max_period
|
||||
}
|
||||
}
|
||||
|
||||
pin_trait!(ChannelAPin, Instance);
|
||||
pin_trait!(ChannelAComplementaryPin, Instance);
|
||||
pin_trait!(ChannelBPin, Instance);
|
||||
pin_trait!(ChannelBComplementaryPin, Instance);
|
||||
pin_trait!(ChannelCPin, Instance);
|
||||
pin_trait!(ChannelCComplementaryPin, Instance);
|
||||
pin_trait!(ChannelDPin, Instance);
|
||||
pin_trait!(ChannelDComplementaryPin, Instance);
|
||||
pin_trait!(ChannelEPin, Instance);
|
||||
pin_trait!(ChannelEComplementaryPin, Instance);
|
193
embassy-stm32/src/hrtim/traits.rs
Normal file
193
embassy-stm32/src/hrtim/traits.rs
Normal file
@ -0,0 +1,193 @@
|
||||
use crate::rcc::sealed::RccPeripheral;
|
||||
use crate::time::Hertz;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) enum Prescaler {
|
||||
Div1,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
Div32,
|
||||
Div64,
|
||||
Div128,
|
||||
}
|
||||
|
||||
impl From<Prescaler> for u32 {
|
||||
fn from(val: Prescaler) -> Self {
|
||||
match val {
|
||||
Prescaler::Div1 => 1,
|
||||
Prescaler::Div2 => 2,
|
||||
Prescaler::Div4 => 4,
|
||||
Prescaler::Div8 => 8,
|
||||
Prescaler::Div16 => 16,
|
||||
Prescaler::Div32 => 32,
|
||||
Prescaler::Div64 => 64,
|
||||
Prescaler::Div128 => 128,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Prescaler> for u8 {
|
||||
fn from(val: Prescaler) -> Self {
|
||||
match val {
|
||||
Prescaler::Div1 => 0b000,
|
||||
Prescaler::Div2 => 0b001,
|
||||
Prescaler::Div4 => 0b010,
|
||||
Prescaler::Div8 => 0b011,
|
||||
Prescaler::Div16 => 0b100,
|
||||
Prescaler::Div32 => 0b101,
|
||||
Prescaler::Div64 => 0b110,
|
||||
Prescaler::Div128 => 0b111,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for Prescaler {
|
||||
fn from(val: u8) -> Self {
|
||||
match val {
|
||||
0b000 => Prescaler::Div1,
|
||||
0b001 => Prescaler::Div2,
|
||||
0b010 => Prescaler::Div4,
|
||||
0b011 => Prescaler::Div8,
|
||||
0b100 => Prescaler::Div16,
|
||||
0b101 => Prescaler::Div32,
|
||||
0b110 => Prescaler::Div64,
|
||||
0b111 => Prescaler::Div128,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Prescaler {
|
||||
pub fn compute_min_high_res(val: u32) -> Self {
|
||||
*[
|
||||
Prescaler::Div1,
|
||||
Prescaler::Div2,
|
||||
Prescaler::Div4,
|
||||
Prescaler::Div8,
|
||||
Prescaler::Div16,
|
||||
Prescaler::Div32,
|
||||
Prescaler::Div64,
|
||||
Prescaler::Div128,
|
||||
]
|
||||
.iter()
|
||||
.skip_while(|psc| <Prescaler as Into<u32>>::into(**psc) <= val)
|
||||
.next()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn compute_min_low_res(val: u32) -> Self {
|
||||
*[Prescaler::Div32, Prescaler::Div64, Prescaler::Div128]
|
||||
.iter()
|
||||
.skip_while(|psc| <Prescaler as Into<u32>>::into(**psc) <= val)
|
||||
.next()
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod sealed {
|
||||
use super::*;
|
||||
|
||||
pub trait Instance: RccPeripheral {
|
||||
fn regs() -> crate::pac::hrtim::Hrtim;
|
||||
|
||||
fn set_master_frequency(frequency: Hertz);
|
||||
|
||||
fn set_channel_frequency(channnel: usize, frequency: Hertz);
|
||||
|
||||
/// Set the dead time as a proportion of max_duty
|
||||
fn set_channel_dead_time(channnel: usize, dead_time: u16);
|
||||
|
||||
// fn enable_outputs(enable: bool);
|
||||
//
|
||||
// fn enable_channel(&mut self, channel: usize, enable: bool);
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Instance: sealed::Instance + 'static {}
|
||||
|
||||
foreach_interrupt! {
|
||||
($inst:ident, hrtim, HRTIM, MASTER, $irq:ident) => {
|
||||
impl sealed::Instance for crate::peripherals::$inst {
|
||||
fn regs() -> crate::pac::hrtim::Hrtim {
|
||||
crate::pac::$inst
|
||||
}
|
||||
|
||||
fn set_master_frequency(frequency: Hertz) {
|
||||
use crate::rcc::sealed::RccPeripheral;
|
||||
|
||||
let f = frequency.0;
|
||||
let timer_f = Self::frequency().0;
|
||||
let psc_min = (timer_f / f) / (u16::MAX as u32 / 32);
|
||||
let psc = if Self::regs().isr().read().dllrdy() {
|
||||
Prescaler::compute_min_high_res(psc_min)
|
||||
} else {
|
||||
Prescaler::compute_min_low_res(psc_min)
|
||||
};
|
||||
|
||||
let psc_val: u32 = psc.into();
|
||||
let timer_f = 32 * (timer_f / psc_val);
|
||||
let per: u16 = (timer_f / f) as u16;
|
||||
|
||||
let regs = Self::regs();
|
||||
|
||||
regs.mcr().modify(|w| w.set_ckpsc(psc.into()));
|
||||
regs.mper().modify(|w| w.set_mper(per));
|
||||
}
|
||||
|
||||
fn set_channel_frequency(channel: usize, frequency: Hertz) {
|
||||
use crate::rcc::sealed::RccPeripheral;
|
||||
|
||||
let f = frequency.0;
|
||||
let timer_f = Self::frequency().0;
|
||||
let psc_min = (timer_f / f) / (u16::MAX as u32 / 32);
|
||||
let psc = if Self::regs().isr().read().dllrdy() {
|
||||
Prescaler::compute_min_high_res(psc_min)
|
||||
} else {
|
||||
Prescaler::compute_min_low_res(psc_min)
|
||||
};
|
||||
|
||||
let psc_val: u32 = psc.into();
|
||||
let timer_f = 32 * (timer_f / psc_val);
|
||||
let per: u16 = (timer_f / f) as u16;
|
||||
|
||||
let regs = Self::regs();
|
||||
|
||||
regs.tim(channel).cr().modify(|w| w.set_ckpsc(psc.into()));
|
||||
regs.tim(channel).per().modify(|w| w.set_per(per));
|
||||
}
|
||||
|
||||
fn set_channel_dead_time(channel: usize, dead_time: u16) {
|
||||
|
||||
let regs = Self::regs();
|
||||
|
||||
let channel_psc: Prescaler = regs.tim(channel).cr().read().ckpsc().into();
|
||||
let psc_val: u32 = channel_psc.into();
|
||||
|
||||
|
||||
// The dead-time base clock runs 4 times slower than the hrtim base clock
|
||||
// u9::MAX = 511
|
||||
let psc_min = (psc_val * dead_time as u32) / (4 * 511);
|
||||
let psc = if Self::regs().isr().read().dllrdy() {
|
||||
Prescaler::compute_min_high_res(psc_min)
|
||||
} else {
|
||||
Prescaler::compute_min_low_res(psc_min)
|
||||
};
|
||||
|
||||
let dt_psc_val: u32 = psc.into();
|
||||
let dt_val = (dt_psc_val * dead_time as u32) / (4 * psc_val);
|
||||
|
||||
regs.tim(channel).dt().modify(|w| {
|
||||
w.set_dtprsc(psc.into());
|
||||
w.set_dtf(dt_val as u16);
|
||||
w.set_dtr(dt_val as u16);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Instance for crate::peripherals::$inst {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
@ -6,8 +6,8 @@ use super::{Error, I2c, Instance};
|
||||
///
|
||||
/// This is useful for recovering from a shorted bus or a device stuck in a clock stretching state.
|
||||
/// A regular [I2c] would freeze until condition is removed.
|
||||
pub struct TimeoutI2c<'d, T: Instance, TXDMA, RXDMA> {
|
||||
i2c: &'d mut I2c<'d, T, TXDMA, RXDMA>,
|
||||
pub struct TimeoutI2c<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> {
|
||||
i2c: &'a mut I2c<'d, T, TXDMA, RXDMA>,
|
||||
timeout: Duration,
|
||||
}
|
||||
|
||||
@ -22,8 +22,8 @@ fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, TXDMA, RXDMA> TimeoutI2c<'d, T, TXDMA, RXDMA> {
|
||||
pub fn new(i2c: &'d mut I2c<'d, T, TXDMA, RXDMA>, timeout: Duration) -> Self {
|
||||
impl<'a, 'd, T: Instance, TXDMA, RXDMA> TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> {
|
||||
pub fn new(i2c: &'a mut I2c<'d, T, TXDMA, RXDMA>, timeout: Duration) -> Self {
|
||||
Self { i2c, timeout }
|
||||
}
|
||||
|
||||
@ -65,7 +65,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> TimeoutI2c<'d, T, TXDMA, RXDMA> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Read for TimeoutI2c<'d, T, TXDMA, RXDMA> {
|
||||
impl<'a, 'd, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Read for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> {
|
||||
type Error = Error;
|
||||
|
||||
fn read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Self::Error> {
|
||||
@ -73,7 +73,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Read for Tim
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Write for TimeoutI2c<'d, T, TXDMA, RXDMA> {
|
||||
impl<'a, 'd, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Write for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> {
|
||||
type Error = Error;
|
||||
|
||||
fn write(&mut self, addr: u8, write: &[u8]) -> Result<(), Self::Error> {
|
||||
@ -81,7 +81,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Write for Ti
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::WriteRead for TimeoutI2c<'d, T, TXDMA, RXDMA> {
|
||||
impl<'a, 'd, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::WriteRead
|
||||
for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA>
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
|
||||
@ -93,11 +95,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::WriteRead fo
|
||||
mod eh1 {
|
||||
use super::*;
|
||||
|
||||
impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::ErrorType for TimeoutI2c<'d, T, TXDMA, RXDMA> {
|
||||
impl<'a, 'd, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::ErrorType for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::I2c for TimeoutI2c<'d, T, TXDMA, RXDMA> {
|
||||
impl<'a, 'd, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::I2c for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> {
|
||||
fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
|
||||
self.blocking_read(address, read)
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use embassy_embedded_hal::SetConfig;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
|
||||
use crate::dma::NoDma;
|
||||
use crate::gpio::sealed::AFType;
|
||||
|
@ -4,8 +4,8 @@ use core::marker::PhantomData;
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_embedded_hal::SetConfig;
|
||||
use embassy_hal_common::drop::OnDrop;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_hal_internal::drop::OnDrop;
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use crate::dma::{NoDma, Transfer};
|
||||
|
@ -1,4 +1,4 @@
|
||||
use embassy_hal_common::into_ref;
|
||||
use embassy_hal_internal::into_ref;
|
||||
|
||||
use crate::gpio::sealed::{AFType, Pin as _};
|
||||
use crate::gpio::AnyPin;
|
||||
@ -165,7 +165,9 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
|
||||
mck.set_as_af(mck.af_num(), AFType::OutputPushPull);
|
||||
mck.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
|
||||
let spi = Spi::new_internal(peri, txdma, rxdma, freq, SpiConfig::default());
|
||||
let mut spi_cfg = SpiConfig::default();
|
||||
spi_cfg.frequency = freq;
|
||||
let spi = Spi::new_internal(peri, txdma, rxdma, spi_cfg);
|
||||
|
||||
#[cfg(all(rcc_f4, not(stm32f410)))]
|
||||
let pclk = unsafe { get_freqs() }.plli2s.unwrap();
|
||||
|
@ -1,6 +1,9 @@
|
||||
#![cfg_attr(not(test), no_std)]
|
||||
#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections))]
|
||||
|
||||
//! ## Feature flags
|
||||
#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
|
||||
|
||||
// This must go FIRST so that all the other modules see its macros.
|
||||
pub mod fmt;
|
||||
include!(concat!(env!("OUT_DIR"), "/_macros.rs"));
|
||||
@ -23,6 +26,8 @@ pub mod timer;
|
||||
pub mod adc;
|
||||
#[cfg(can)]
|
||||
pub mod can;
|
||||
#[cfg(crc)]
|
||||
pub mod crc;
|
||||
#[cfg(dac)]
|
||||
pub mod dac;
|
||||
#[cfg(dcmi)]
|
||||
@ -31,19 +36,17 @@ pub mod dcmi;
|
||||
pub mod eth;
|
||||
#[cfg(feature = "exti")]
|
||||
pub mod exti;
|
||||
pub mod flash;
|
||||
#[cfg(fmc)]
|
||||
pub mod fmc;
|
||||
#[cfg(hrtim_v1)]
|
||||
pub mod hrtim;
|
||||
#[cfg(i2c)]
|
||||
pub mod i2c;
|
||||
|
||||
#[cfg(crc)]
|
||||
pub mod crc;
|
||||
pub mod flash;
|
||||
#[cfg(all(spi_v1, rcc_f4))]
|
||||
pub mod i2s;
|
||||
#[cfg(stm32wb)]
|
||||
pub mod ipcc;
|
||||
pub mod pwm;
|
||||
#[cfg(quadspi)]
|
||||
pub mod qspi;
|
||||
#[cfg(rng)]
|
||||
@ -79,7 +82,7 @@ pub use crate::_generated::interrupt;
|
||||
/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
|
||||
/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
|
||||
/// prove at compile-time that the right interrupts have been bound.
|
||||
// developer note: this macro can't be in `embassy-hal-common` due to the use of `$crate`.
|
||||
// developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`.
|
||||
#[macro_export]
|
||||
macro_rules! bind_interrupts {
|
||||
($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
|
||||
@ -103,7 +106,7 @@ macro_rules! bind_interrupts {
|
||||
|
||||
// Reexports
|
||||
pub use _generated::{peripherals, Peripherals};
|
||||
pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
|
||||
pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
|
||||
#[cfg(feature = "unstable-pac")]
|
||||
pub use stm32_metapac as pac;
|
||||
#[cfg(not(feature = "unstable-pac"))]
|
||||
|
@ -1,269 +0,0 @@
|
||||
pub mod complementary_pwm;
|
||||
pub mod simple_pwm;
|
||||
|
||||
use stm32_metapac::timer::vals::Ckd;
|
||||
|
||||
#[cfg(feature = "unstable-pac")]
|
||||
pub mod low_level {
|
||||
pub use super::sealed::*;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Channel {
|
||||
Ch1,
|
||||
Ch2,
|
||||
Ch3,
|
||||
Ch4,
|
||||
}
|
||||
|
||||
impl Channel {
|
||||
pub fn raw(&self) -> usize {
|
||||
match self {
|
||||
Channel::Ch1 => 0,
|
||||
Channel::Ch2 => 1,
|
||||
Channel::Ch3 => 2,
|
||||
Channel::Ch4 => 3,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum OutputCompareMode {
|
||||
Frozen,
|
||||
ActiveOnMatch,
|
||||
InactiveOnMatch,
|
||||
Toggle,
|
||||
ForceInactive,
|
||||
ForceActive,
|
||||
PwmMode1,
|
||||
PwmMode2,
|
||||
}
|
||||
|
||||
impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm {
|
||||
fn from(mode: OutputCompareMode) -> Self {
|
||||
match mode {
|
||||
OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN,
|
||||
OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVEONMATCH,
|
||||
OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVEONMATCH,
|
||||
OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE,
|
||||
OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCEINACTIVE,
|
||||
OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCEACTIVE,
|
||||
OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWMMODE1,
|
||||
OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWMMODE2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod sealed {
|
||||
use super::*;
|
||||
|
||||
pub trait CaptureCompare16bitInstance: crate::timer::sealed::GeneralPurpose16bitInstance {
|
||||
/// Global output enable. Does not do anything on non-advanced timers.
|
||||
fn enable_outputs(&mut self, enable: bool);
|
||||
|
||||
fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
|
||||
|
||||
fn enable_channel(&mut self, channel: Channel, enable: bool);
|
||||
|
||||
fn set_compare_value(&mut self, channel: Channel, value: u16);
|
||||
|
||||
fn get_max_compare_value(&self) -> u16;
|
||||
}
|
||||
|
||||
pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance {
|
||||
fn set_dead_time_clock_division(&mut self, value: Ckd);
|
||||
|
||||
fn set_dead_time_value(&mut self, value: u8);
|
||||
|
||||
fn enable_complementary_channel(&mut self, channel: Channel, enable: bool);
|
||||
}
|
||||
|
||||
pub trait CaptureCompare32bitInstance: crate::timer::sealed::GeneralPurpose32bitInstance {
|
||||
fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
|
||||
|
||||
fn enable_channel(&mut self, channel: Channel, enable: bool);
|
||||
|
||||
fn set_compare_value(&mut self, channel: Channel, value: u32);
|
||||
|
||||
fn get_max_compare_value(&self) -> u32;
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CaptureCompare16bitInstance:
|
||||
sealed::CaptureCompare16bitInstance + crate::timer::GeneralPurpose16bitInstance + 'static
|
||||
{
|
||||
}
|
||||
|
||||
pub trait ComplementaryCaptureCompare16bitInstance:
|
||||
sealed::ComplementaryCaptureCompare16bitInstance + crate::timer::AdvancedControlInstance + 'static
|
||||
{
|
||||
}
|
||||
|
||||
pub trait CaptureCompare32bitInstance:
|
||||
sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + crate::timer::GeneralPurpose32bitInstance + 'static
|
||||
{
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
macro_rules! impl_compare_capable_16bit {
|
||||
($inst:ident) => {
|
||||
impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
|
||||
fn enable_outputs(&mut self, _enable: bool) {}
|
||||
|
||||
fn set_output_compare_mode(&mut self, channel: crate::pwm::Channel, mode: OutputCompareMode) {
|
||||
use crate::timer::sealed::GeneralPurpose16bitInstance;
|
||||
let r = Self::regs_gp16();
|
||||
let raw_channel: usize = channel.raw();
|
||||
r.ccmr_output(raw_channel / 2)
|
||||
.modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
|
||||
}
|
||||
|
||||
fn enable_channel(&mut self, channel: Channel, enable: bool) {
|
||||
use crate::timer::sealed::GeneralPurpose16bitInstance;
|
||||
Self::regs_gp16()
|
||||
.ccer()
|
||||
.modify(|w| w.set_cce(channel.raw(), enable));
|
||||
}
|
||||
|
||||
fn set_compare_value(&mut self, channel: Channel, value: u16) {
|
||||
use crate::timer::sealed::GeneralPurpose16bitInstance;
|
||||
Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value));
|
||||
}
|
||||
|
||||
fn get_max_compare_value(&self) -> u16 {
|
||||
use crate::timer::sealed::GeneralPurpose16bitInstance;
|
||||
Self::regs_gp16().arr().read().arr()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
foreach_interrupt! {
|
||||
($inst:ident, timer, TIM_GP16, UP, $irq:ident) => {
|
||||
impl_compare_capable_16bit!($inst);
|
||||
|
||||
impl CaptureCompare16bitInstance for crate::peripherals::$inst {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
($inst:ident, timer, TIM_GP32, UP, $irq:ident) => {
|
||||
impl_compare_capable_16bit!($inst);
|
||||
impl crate::pwm::sealed::CaptureCompare32bitInstance for crate::peripherals::$inst {
|
||||
fn set_output_compare_mode(
|
||||
&mut self,
|
||||
channel: crate::pwm::Channel,
|
||||
mode: OutputCompareMode,
|
||||
) {
|
||||
use crate::timer::sealed::GeneralPurpose32bitInstance;
|
||||
let raw_channel = channel.raw();
|
||||
Self::regs_gp32().ccmr_output(raw_channel / 2).modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
|
||||
}
|
||||
|
||||
fn enable_channel(&mut self, channel: Channel, enable: bool) {
|
||||
use crate::timer::sealed::GeneralPurpose32bitInstance;
|
||||
Self::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), enable));
|
||||
}
|
||||
|
||||
fn set_compare_value(&mut self, channel: Channel, value: u32) {
|
||||
use crate::timer::sealed::GeneralPurpose32bitInstance;
|
||||
Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value));
|
||||
}
|
||||
|
||||
fn get_max_compare_value(&self) -> u32 {
|
||||
use crate::timer::sealed::GeneralPurpose32bitInstance;
|
||||
Self::regs_gp32().arr().read().arr() as u32
|
||||
}
|
||||
}
|
||||
impl CaptureCompare16bitInstance for crate::peripherals::$inst {
|
||||
|
||||
}
|
||||
impl CaptureCompare32bitInstance for crate::peripherals::$inst {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
($inst:ident, timer, TIM_ADV, UP, $irq:ident) => {
|
||||
impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
|
||||
fn enable_outputs(&mut self, enable: bool) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
let r = Self::regs_advanced();
|
||||
r.bdtr().modify(|w| w.set_moe(enable));
|
||||
}
|
||||
|
||||
fn set_output_compare_mode(
|
||||
&mut self,
|
||||
channel: crate::pwm::Channel,
|
||||
mode: OutputCompareMode,
|
||||
) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
let r = Self::regs_advanced();
|
||||
let raw_channel: usize = channel.raw();
|
||||
r.ccmr_output(raw_channel / 2)
|
||||
.modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
|
||||
}
|
||||
|
||||
fn enable_channel(&mut self, channel: Channel, enable: bool) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced()
|
||||
.ccer()
|
||||
.modify(|w| w.set_cce(channel.raw(), enable));
|
||||
}
|
||||
|
||||
fn set_compare_value(&mut self, channel: Channel, value: u16) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced()
|
||||
.ccr(channel.raw())
|
||||
.modify(|w| w.set_ccr(value));
|
||||
}
|
||||
|
||||
fn get_max_compare_value(&self) -> u16 {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced().arr().read().arr()
|
||||
}
|
||||
}
|
||||
|
||||
impl CaptureCompare16bitInstance for crate::peripherals::$inst {
|
||||
|
||||
}
|
||||
|
||||
impl crate::pwm::sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {
|
||||
fn set_dead_time_clock_division(&mut self, value: Ckd) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced().cr1().modify(|w| w.set_ckd(value));
|
||||
}
|
||||
|
||||
fn set_dead_time_value(&mut self, value: u8) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value));
|
||||
}
|
||||
|
||||
fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced()
|
||||
.ccer()
|
||||
.modify(|w| w.set_ccne(channel.raw(), enable));
|
||||
}
|
||||
}
|
||||
|
||||
impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pin_trait!(Channel1Pin, CaptureCompare16bitInstance);
|
||||
pin_trait!(Channel1ComplementaryPin, CaptureCompare16bitInstance);
|
||||
pin_trait!(Channel2Pin, CaptureCompare16bitInstance);
|
||||
pin_trait!(Channel2ComplementaryPin, CaptureCompare16bitInstance);
|
||||
pin_trait!(Channel3Pin, CaptureCompare16bitInstance);
|
||||
pin_trait!(Channel3ComplementaryPin, CaptureCompare16bitInstance);
|
||||
pin_trait!(Channel4Pin, CaptureCompare16bitInstance);
|
||||
pin_trait!(Channel4ComplementaryPin, CaptureCompare16bitInstance);
|
||||
pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance);
|
||||
pin_trait!(BreakInputPin, CaptureCompare16bitInstance);
|
||||
pin_trait!(BreakInputComparator1Pin, CaptureCompare16bitInstance);
|
||||
pin_trait!(BreakInputComparator2Pin, CaptureCompare16bitInstance);
|
||||
pin_trait!(BreakInput2Pin, CaptureCompare16bitInstance);
|
||||
pin_trait!(BreakInput2Comparator1Pin, CaptureCompare16bitInstance);
|
||||
pin_trait!(BreakInput2Comparator2Pin, CaptureCompare16bitInstance);
|
@ -2,7 +2,7 @@
|
||||
|
||||
pub mod enums;
|
||||
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use enums::*;
|
||||
|
||||
use crate::dma::Transfer;
|
||||
|
@ -1,5 +1,6 @@
|
||||
pub use super::common::{AHBPrescaler, APBPrescaler};
|
||||
use crate::pac::flash::vals::Latency;
|
||||
use crate::pac::rcc::vals::{Hpre, Hsidiv, Ppre, Sw};
|
||||
use crate::pac::rcc::vals::{Hsidiv, Ppre, Sw};
|
||||
use crate::pac::{FLASH, RCC};
|
||||
use crate::rcc::{set_freqs, Clocks};
|
||||
use crate::time::Hertz;
|
||||
@ -45,58 +46,6 @@ impl Into<Hsidiv> for HSIPrescaler {
|
||||
}
|
||||
}
|
||||
|
||||
/// AHB prescaler
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum AHBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
Div64,
|
||||
Div128,
|
||||
Div256,
|
||||
Div512,
|
||||
}
|
||||
|
||||
/// APB prescaler
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum APBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
}
|
||||
|
||||
impl Into<Ppre> for APBPrescaler {
|
||||
fn into(self) -> Ppre {
|
||||
match self {
|
||||
APBPrescaler::NotDivided => Ppre::DIV1,
|
||||
APBPrescaler::Div2 => Ppre::DIV2,
|
||||
APBPrescaler::Div4 => Ppre::DIV4,
|
||||
APBPrescaler::Div8 => Ppre::DIV8,
|
||||
APBPrescaler::Div16 => Ppre::DIV16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Hpre> for AHBPrescaler {
|
||||
fn into(self) -> Hpre {
|
||||
match self {
|
||||
AHBPrescaler::NotDivided => Hpre::DIV1,
|
||||
AHBPrescaler::Div2 => Hpre::DIV2,
|
||||
AHBPrescaler::Div4 => Hpre::DIV4,
|
||||
AHBPrescaler::Div8 => Hpre::DIV8,
|
||||
AHBPrescaler::Div16 => Hpre::DIV16,
|
||||
AHBPrescaler::Div64 => Hpre::DIV64,
|
||||
AHBPrescaler::Div128 => Hpre::DIV128,
|
||||
AHBPrescaler::Div256 => Hpre::DIV256,
|
||||
AHBPrescaler::Div512 => Hpre::DIV512,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Clocks configutation
|
||||
pub struct Config {
|
||||
pub mux: ClockSrc,
|
||||
|
174
embassy-stm32/src/rcc/common.rs
Normal file
174
embassy-stm32/src/rcc/common.rs
Normal file
@ -0,0 +1,174 @@
|
||||
use core::ops::Div;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use crate::pac::rcc;
|
||||
use crate::time::Hertz;
|
||||
|
||||
/// Voltage Scale
|
||||
///
|
||||
/// Represents the voltage range feeding the CPU core. The maximum core
|
||||
/// clock frequency depends on this value.
|
||||
///
|
||||
/// Scale0 represents the highest voltage range
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum VoltageScale {
|
||||
Scale0,
|
||||
Scale1,
|
||||
#[cfg(not(any(rcc_wl5, rcc_wle)))]
|
||||
Scale2,
|
||||
#[cfg(not(any(rcc_wl5, rcc_wle)))]
|
||||
Scale3,
|
||||
}
|
||||
|
||||
/// AHB prescaler
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum AHBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
||||
Div3,
|
||||
Div4,
|
||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
||||
Div5,
|
||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
||||
Div6,
|
||||
Div8,
|
||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
||||
Div10,
|
||||
Div16,
|
||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
||||
Div32,
|
||||
Div64,
|
||||
Div128,
|
||||
Div256,
|
||||
Div512,
|
||||
}
|
||||
|
||||
impl Div<AHBPrescaler> for Hertz {
|
||||
type Output = Hertz;
|
||||
|
||||
fn div(self, rhs: AHBPrescaler) -> Self::Output {
|
||||
let divisor = match rhs {
|
||||
AHBPrescaler::NotDivided => 1,
|
||||
AHBPrescaler::Div2 => 2,
|
||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
||||
AHBPrescaler::Div3 => 3,
|
||||
AHBPrescaler::Div4 => 4,
|
||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
||||
AHBPrescaler::Div5 => 5,
|
||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
||||
AHBPrescaler::Div6 => 6,
|
||||
AHBPrescaler::Div8 => 8,
|
||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
||||
AHBPrescaler::Div10 => 10,
|
||||
AHBPrescaler::Div16 => 16,
|
||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
||||
AHBPrescaler::Div32 => 32,
|
||||
AHBPrescaler::Div64 => 64,
|
||||
AHBPrescaler::Div128 => 128,
|
||||
AHBPrescaler::Div256 => 256,
|
||||
AHBPrescaler::Div512 => 512,
|
||||
};
|
||||
Hertz(self.0 / divisor)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(rcc_g4, rcc_wb, rcc_wl5, rcc_wle)))]
|
||||
impl From<AHBPrescaler> for rcc::vals::Hpre {
|
||||
fn from(val: AHBPrescaler) -> rcc::vals::Hpre {
|
||||
use rcc::vals::Hpre;
|
||||
|
||||
match val {
|
||||
#[cfg(not(rcc_u5))]
|
||||
AHBPrescaler::NotDivided => Hpre::DIV1,
|
||||
#[cfg(rcc_u5)]
|
||||
AHBPrescaler::NotDivided => Hpre::NONE,
|
||||
AHBPrescaler::Div2 => Hpre::DIV2,
|
||||
AHBPrescaler::Div4 => Hpre::DIV4,
|
||||
AHBPrescaler::Div8 => Hpre::DIV8,
|
||||
AHBPrescaler::Div16 => Hpre::DIV16,
|
||||
AHBPrescaler::Div64 => Hpre::DIV64,
|
||||
AHBPrescaler::Div128 => Hpre::DIV128,
|
||||
AHBPrescaler::Div256 => Hpre::DIV256,
|
||||
AHBPrescaler::Div512 => Hpre::DIV512,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
||||
impl From<AHBPrescaler> for u8 {
|
||||
fn from(val: AHBPrescaler) -> u8 {
|
||||
match val {
|
||||
AHBPrescaler::NotDivided => 0x0,
|
||||
AHBPrescaler::Div2 => 0x08,
|
||||
AHBPrescaler::Div3 => 0x01,
|
||||
AHBPrescaler::Div4 => 0x09,
|
||||
AHBPrescaler::Div5 => 0x02,
|
||||
AHBPrescaler::Div6 => 0x05,
|
||||
AHBPrescaler::Div8 => 0x0a,
|
||||
AHBPrescaler::Div10 => 0x06,
|
||||
AHBPrescaler::Div16 => 0x0b,
|
||||
AHBPrescaler::Div32 => 0x07,
|
||||
AHBPrescaler::Div64 => 0x0c,
|
||||
AHBPrescaler::Div128 => 0x0d,
|
||||
AHBPrescaler::Div256 => 0x0e,
|
||||
AHBPrescaler::Div512 => 0x0f,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// APB prescaler
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum APBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
}
|
||||
|
||||
impl Div<APBPrescaler> for Hertz {
|
||||
type Output = Hertz;
|
||||
|
||||
fn div(self, rhs: APBPrescaler) -> Self::Output {
|
||||
let divisor = match rhs {
|
||||
APBPrescaler::NotDivided => 1,
|
||||
APBPrescaler::Div2 => 2,
|
||||
APBPrescaler::Div4 => 4,
|
||||
APBPrescaler::Div8 => 8,
|
||||
APBPrescaler::Div16 => 16,
|
||||
};
|
||||
Hertz(self.0 / divisor)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(rcc_f1, rcc_f100, rcc_f1cl, rcc_g4, rcc_h7, rcc_h7ab, rcc_wb, rcc_wl5, rcc_wle)))]
|
||||
impl From<APBPrescaler> for rcc::vals::Ppre {
|
||||
fn from(val: APBPrescaler) -> rcc::vals::Ppre {
|
||||
use rcc::vals::Ppre;
|
||||
|
||||
match val {
|
||||
#[cfg(not(rcc_u5))]
|
||||
APBPrescaler::NotDivided => Ppre::DIV1,
|
||||
#[cfg(rcc_u5)]
|
||||
APBPrescaler::NotDivided => Ppre::NONE,
|
||||
APBPrescaler::Div2 => Ppre::DIV2,
|
||||
APBPrescaler::Div4 => Ppre::DIV4,
|
||||
APBPrescaler::Div8 => Ppre::DIV8,
|
||||
APBPrescaler::Div16 => Ppre::DIV16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
||||
impl From<APBPrescaler> for u8 {
|
||||
fn from(val: APBPrescaler) -> u8 {
|
||||
match val {
|
||||
APBPrescaler::NotDivided => 1,
|
||||
APBPrescaler::Div2 => 0x04,
|
||||
APBPrescaler::Div4 => 0x05,
|
||||
APBPrescaler::Div8 => 0x06,
|
||||
APBPrescaler::Div16 => 0x07,
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,9 @@
|
||||
use core::convert::TryFrom;
|
||||
use core::ops::{Div, Mul};
|
||||
|
||||
pub use super::common::{AHBPrescaler, APBPrescaler};
|
||||
use crate::pac::flash::vals::Latency;
|
||||
use crate::pac::rcc::vals::{Hpre, Pllp, Pllsrc, Ppre, Sw};
|
||||
use crate::pac::rcc::vals::{Pllp, Pllsrc, Sw};
|
||||
use crate::pac::{FLASH, RCC};
|
||||
use crate::rcc::{set_freqs, Clocks};
|
||||
use crate::time::Hertz;
|
||||
@ -58,7 +59,7 @@ impl Default for PLLConfig {
|
||||
impl PLLConfig {
|
||||
pub fn clocks(&self, src_freq: Hertz) -> PLLClocks {
|
||||
let in_freq = src_freq / self.pre_div;
|
||||
let vco_freq = src_freq * self.mul / self.pre_div;
|
||||
let vco_freq = Hertz((src_freq.0 as u64 * self.mul.0 as u64 / self.pre_div.0 as u64) as u32);
|
||||
let main_freq = vco_freq / self.main_div;
|
||||
let pll48_freq = vco_freq / self.pll48_div;
|
||||
PLLClocks {
|
||||
@ -200,114 +201,15 @@ pub struct PLLClocks {
|
||||
pub pll48_freq: Hertz,
|
||||
}
|
||||
|
||||
/// AHB prescaler
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum AHBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
Div64,
|
||||
Div128,
|
||||
Div256,
|
||||
Div512,
|
||||
}
|
||||
pub use super::common::VoltageScale;
|
||||
|
||||
impl Div<AHBPrescaler> for Hertz {
|
||||
type Output = Hertz;
|
||||
|
||||
fn div(self, rhs: AHBPrescaler) -> Self::Output {
|
||||
let divisor = match rhs {
|
||||
AHBPrescaler::NotDivided => 1,
|
||||
AHBPrescaler::Div2 => 2,
|
||||
AHBPrescaler::Div4 => 4,
|
||||
AHBPrescaler::Div8 => 8,
|
||||
AHBPrescaler::Div16 => 16,
|
||||
AHBPrescaler::Div64 => 64,
|
||||
AHBPrescaler::Div128 => 128,
|
||||
AHBPrescaler::Div256 => 256,
|
||||
AHBPrescaler::Div512 => 512,
|
||||
};
|
||||
Hertz(self.0 / divisor)
|
||||
}
|
||||
}
|
||||
|
||||
/// APB prescaler
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum APBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
}
|
||||
|
||||
impl Div<APBPrescaler> for Hertz {
|
||||
type Output = Hertz;
|
||||
|
||||
fn div(self, rhs: APBPrescaler) -> Self::Output {
|
||||
let divisor = match rhs {
|
||||
APBPrescaler::NotDivided => 1,
|
||||
APBPrescaler::Div2 => 2,
|
||||
APBPrescaler::Div4 => 4,
|
||||
APBPrescaler::Div8 => 8,
|
||||
APBPrescaler::Div16 => 16,
|
||||
};
|
||||
Hertz(self.0 / divisor)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Ppre> for APBPrescaler {
|
||||
fn into(self) -> Ppre {
|
||||
match self {
|
||||
APBPrescaler::NotDivided => Ppre::DIV1,
|
||||
APBPrescaler::Div2 => Ppre::DIV2,
|
||||
APBPrescaler::Div4 => Ppre::DIV4,
|
||||
APBPrescaler::Div8 => Ppre::DIV8,
|
||||
APBPrescaler::Div16 => Ppre::DIV16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Hpre> for AHBPrescaler {
|
||||
fn into(self) -> Hpre {
|
||||
match self {
|
||||
AHBPrescaler::NotDivided => Hpre::DIV1,
|
||||
AHBPrescaler::Div2 => Hpre::DIV2,
|
||||
AHBPrescaler::Div4 => Hpre::DIV4,
|
||||
AHBPrescaler::Div8 => Hpre::DIV8,
|
||||
AHBPrescaler::Div16 => Hpre::DIV16,
|
||||
AHBPrescaler::Div64 => Hpre::DIV64,
|
||||
AHBPrescaler::Div128 => Hpre::DIV128,
|
||||
AHBPrescaler::Div256 => Hpre::DIV256,
|
||||
AHBPrescaler::Div512 => Hpre::DIV512,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Voltage Range
|
||||
///
|
||||
/// Represents the system supply voltage range
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum VoltageRange {
|
||||
/// 1.8 to 3.6 V
|
||||
Min1V8,
|
||||
/// 2.1 to 3.6 V
|
||||
Min2V1,
|
||||
/// 2.4 to 3.6 V
|
||||
Min2V4,
|
||||
/// 2.7 to 3.6 V
|
||||
Min2V7,
|
||||
}
|
||||
|
||||
impl VoltageRange {
|
||||
impl VoltageScale {
|
||||
const fn wait_states(&self, ahb_freq: Hertz) -> Option<Latency> {
|
||||
let ahb_freq = ahb_freq.0;
|
||||
// Reference: RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock
|
||||
// frequency
|
||||
match self {
|
||||
VoltageRange::Min1V8 => {
|
||||
VoltageScale::Scale3 => {
|
||||
if ahb_freq <= 16_000_000 {
|
||||
Some(Latency::WS0)
|
||||
} else if ahb_freq <= 32_000_000 {
|
||||
@ -328,7 +230,7 @@ impl VoltageRange {
|
||||
None
|
||||
}
|
||||
}
|
||||
VoltageRange::Min2V1 => {
|
||||
VoltageScale::Scale2 => {
|
||||
if ahb_freq <= 18_000_000 {
|
||||
Some(Latency::WS0)
|
||||
} else if ahb_freq <= 36_000_000 {
|
||||
@ -347,7 +249,7 @@ impl VoltageRange {
|
||||
None
|
||||
}
|
||||
}
|
||||
VoltageRange::Min2V4 => {
|
||||
VoltageScale::Scale1 => {
|
||||
if ahb_freq <= 24_000_000 {
|
||||
Some(Latency::WS0)
|
||||
} else if ahb_freq <= 48_000_000 {
|
||||
@ -362,7 +264,7 @@ impl VoltageRange {
|
||||
None
|
||||
}
|
||||
}
|
||||
VoltageRange::Min2V7 => {
|
||||
VoltageScale::Scale0 => {
|
||||
if ahb_freq <= 30_000_000 {
|
||||
Some(Latency::WS0)
|
||||
} else if ahb_freq <= 60_000_000 {
|
||||
@ -386,7 +288,7 @@ pub struct Config {
|
||||
pub pll_mux: PLLSrc,
|
||||
pub pll: PLLConfig,
|
||||
pub mux: ClockSrc,
|
||||
pub voltage: VoltageRange,
|
||||
pub voltage: VoltageScale,
|
||||
pub ahb_pre: AHBPrescaler,
|
||||
pub apb1_pre: APBPrescaler,
|
||||
pub apb2_pre: APBPrescaler,
|
||||
@ -400,7 +302,7 @@ impl Default for Config {
|
||||
hsi: true,
|
||||
pll_mux: PLLSrc::HSI,
|
||||
pll: PLLConfig::default(),
|
||||
voltage: VoltageRange::Min1V8,
|
||||
voltage: VoltageScale::Scale3,
|
||||
mux: ClockSrc::HSI,
|
||||
ahb_pre: AHBPrescaler::NotDivided,
|
||||
apb1_pre: APBPrescaler::NotDivided,
|
||||
|
@ -264,6 +264,7 @@ fn calc_pll(config: &Config, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(unused_variables)]
|
||||
fn get_usb_pre(config: &Config, sysclk: u32, pclk1: u32, pll_config: &Option<PllConfig>) -> Usbpre {
|
||||
cfg_if::cfg_if! {
|
||||
// Some chips do not have USB
|
||||
|
@ -1,6 +1,6 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use embassy_hal_common::into_ref;
|
||||
use embassy_hal_internal::into_ref;
|
||||
use stm32_metapac::rcc::vals::{Mco1, Mco2, Mcopre};
|
||||
|
||||
use super::sealed::RccPeripheral;
|
||||
|
@ -1,5 +1,6 @@
|
||||
pub use super::common::{AHBPrescaler, APBPrescaler};
|
||||
use crate::pac::flash::vals::Latency;
|
||||
use crate::pac::rcc::vals::{self, Hpre, Hsidiv, Ppre, Sw};
|
||||
use crate::pac::rcc::vals::{self, Hsidiv, Ppre, Sw};
|
||||
use crate::pac::{FLASH, PWR, RCC};
|
||||
use crate::rcc::{set_freqs, Clocks};
|
||||
use crate::time::Hertz;
|
||||
@ -172,58 +173,6 @@ impl From<Pllr> for u32 {
|
||||
}
|
||||
}
|
||||
|
||||
/// AHB prescaler
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum AHBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
Div64,
|
||||
Div128,
|
||||
Div256,
|
||||
Div512,
|
||||
}
|
||||
|
||||
/// APB prescaler
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum APBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
}
|
||||
|
||||
impl Into<Ppre> for APBPrescaler {
|
||||
fn into(self) -> Ppre {
|
||||
match self {
|
||||
APBPrescaler::NotDivided => Ppre::DIV1,
|
||||
APBPrescaler::Div2 => Ppre::DIV2,
|
||||
APBPrescaler::Div4 => Ppre::DIV4,
|
||||
APBPrescaler::Div8 => Ppre::DIV8,
|
||||
APBPrescaler::Div16 => Ppre::DIV16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Hpre> for AHBPrescaler {
|
||||
fn into(self) -> Hpre {
|
||||
match self {
|
||||
AHBPrescaler::NotDivided => Hpre::DIV1,
|
||||
AHBPrescaler::Div2 => Hpre::DIV2,
|
||||
AHBPrescaler::Div4 => Hpre::DIV4,
|
||||
AHBPrescaler::Div8 => Hpre::DIV8,
|
||||
AHBPrescaler::Div16 => Hpre::DIV16,
|
||||
AHBPrescaler::Div64 => Hpre::DIV64,
|
||||
AHBPrescaler::Div128 => Hpre::DIV128,
|
||||
AHBPrescaler::Div256 => Hpre::DIV256,
|
||||
AHBPrescaler::Div512 => Hpre::DIV512,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Clocks configutation
|
||||
pub struct Config {
|
||||
pub mux: ClockSrc,
|
||||
@ -425,25 +374,14 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
FLASH.acr().modify(|w| w.set_latency(target_flash_latency));
|
||||
}
|
||||
|
||||
let ahb_div = match config.ahb_pre {
|
||||
AHBPrescaler::NotDivided => 1,
|
||||
AHBPrescaler::Div2 => 2,
|
||||
AHBPrescaler::Div4 => 4,
|
||||
AHBPrescaler::Div8 => 8,
|
||||
AHBPrescaler::Div16 => 16,
|
||||
AHBPrescaler::Div64 => 64,
|
||||
AHBPrescaler::Div128 => 128,
|
||||
AHBPrescaler::Div256 => 256,
|
||||
AHBPrescaler::Div512 => 512,
|
||||
};
|
||||
let ahb_freq = sys_clk / ahb_div;
|
||||
let ahb_freq = Hertz(sys_clk) / config.ahb_pre;
|
||||
|
||||
let (apb_freq, apb_tim_freq) = match config.apb_pre {
|
||||
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
|
||||
APBPrescaler::NotDivided => (ahb_freq.0, ahb_freq.0),
|
||||
pre => {
|
||||
let pre: Ppre = pre.into();
|
||||
let pre: u8 = 1 << (pre.to_bits() - 3);
|
||||
let freq = ahb_freq / pre as u32;
|
||||
let freq = ahb_freq.0 / pre as u32;
|
||||
(freq, freq * 2)
|
||||
}
|
||||
};
|
||||
@ -455,7 +393,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: Hertz(sys_clk),
|
||||
ahb1: Hertz(ahb_freq),
|
||||
ahb1: ahb_freq,
|
||||
apb1: Hertz(apb_freq),
|
||||
apb1_tim: Hertz(apb_tim_freq),
|
||||
});
|
||||
|
@ -2,6 +2,7 @@ use stm32_metapac::flash::vals::Latency;
|
||||
use stm32_metapac::rcc::vals::{Hpre, Pllsrc, Ppre, Sw};
|
||||
use stm32_metapac::FLASH;
|
||||
|
||||
pub use super::common::{AHBPrescaler, APBPrescaler};
|
||||
use crate::pac::{PWR, RCC};
|
||||
use crate::rcc::sealed::RccPeripheral;
|
||||
use crate::rcc::{set_freqs, Clocks};
|
||||
@ -21,30 +22,6 @@ pub enum ClockSrc {
|
||||
PLL,
|
||||
}
|
||||
|
||||
/// AHB prescaler
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum AHBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
Div64,
|
||||
Div128,
|
||||
Div256,
|
||||
Div512,
|
||||
}
|
||||
|
||||
/// APB prescaler
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum APBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
}
|
||||
|
||||
/// PLL clock input source
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum PllSrc {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use stm32_metapac::rcc::vals::{Hpre, Ppre, Timpre};
|
||||
use stm32_metapac::rcc::vals::Timpre;
|
||||
|
||||
use crate::pac::pwr::vals::Vos;
|
||||
use crate::pac::rcc::vals::{Hseext, Hsidiv, Mco1, Mco2, Pllrge, Pllsrc, Pllvcosel, Sw};
|
||||
@ -26,21 +26,7 @@ const VCO_MAX: u32 = 420_000_000;
|
||||
const VCO_WIDE_MIN: u32 = 128_000_000;
|
||||
const VCO_WIDE_MAX: u32 = 560_000_000;
|
||||
|
||||
/// Voltage Scale
|
||||
///
|
||||
/// Represents the voltage range feeding the CPU core. The maximum core
|
||||
/// clock frequency depends on this value.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum VoltageScale {
|
||||
/// VOS 0 range VCORE 1.30V - 1.40V
|
||||
Scale0,
|
||||
/// VOS 1 range VCORE 1.15V - 1.26V
|
||||
Scale1,
|
||||
/// VOS 2 range VCORE 1.05V - 1.15V
|
||||
Scale2,
|
||||
/// VOS 3 range VCORE 0.95V - 1.05V
|
||||
Scale3,
|
||||
}
|
||||
pub use super::common::{AHBPrescaler, APBPrescaler, VoltageScale};
|
||||
|
||||
pub enum HseMode {
|
||||
/// crystal/ceramic oscillator (HSEBYP=0)
|
||||
@ -105,57 +91,7 @@ pub struct Pll {
|
||||
pub divr: Option<u16>,
|
||||
}
|
||||
|
||||
/// AHB prescaler
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum AHBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
Div64,
|
||||
Div128,
|
||||
Div256,
|
||||
Div512,
|
||||
}
|
||||
|
||||
impl AHBPrescaler {
|
||||
fn div(&self, clk: Hertz) -> Hertz {
|
||||
match self {
|
||||
Self::NotDivided => clk,
|
||||
Self::Div2 => clk / 2u32,
|
||||
Self::Div4 => clk / 4u32,
|
||||
Self::Div8 => clk / 8u32,
|
||||
Self::Div16 => clk / 16u32,
|
||||
Self::Div64 => clk / 64u32,
|
||||
Self::Div128 => clk / 128u32,
|
||||
Self::Div256 => clk / 256u32,
|
||||
Self::Div512 => clk / 512u32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// APB prescaler
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum APBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
}
|
||||
|
||||
impl APBPrescaler {
|
||||
fn div(&self, clk: Hertz) -> Hertz {
|
||||
match self {
|
||||
Self::NotDivided => clk,
|
||||
Self::Div2 => clk / 2u32,
|
||||
Self::Div4 => clk / 4u32,
|
||||
Self::Div8 => clk / 8u32,
|
||||
Self::Div16 => clk / 16u32,
|
||||
}
|
||||
}
|
||||
|
||||
fn div_tim(&self, clk: Hertz, tim: TimerPrescaler) -> Hertz {
|
||||
match (tim, self) {
|
||||
// The timers kernel clock is equal to rcc_hclk1 if PPRE1 or PPRE2 corresponds to a
|
||||
@ -193,34 +129,6 @@ impl From<TimerPrescaler> for Timpre {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<APBPrescaler> for Ppre {
|
||||
fn from(val: APBPrescaler) -> Ppre {
|
||||
match val {
|
||||
APBPrescaler::NotDivided => Ppre::DIV1,
|
||||
APBPrescaler::Div2 => Ppre::DIV2,
|
||||
APBPrescaler::Div4 => Ppre::DIV4,
|
||||
APBPrescaler::Div8 => Ppre::DIV8,
|
||||
APBPrescaler::Div16 => Ppre::DIV16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AHBPrescaler> for Hpre {
|
||||
fn from(val: AHBPrescaler) -> Hpre {
|
||||
match val {
|
||||
AHBPrescaler::NotDivided => Hpre::DIV1,
|
||||
AHBPrescaler::Div2 => Hpre::DIV2,
|
||||
AHBPrescaler::Div4 => Hpre::DIV4,
|
||||
AHBPrescaler::Div8 => Hpre::DIV8,
|
||||
AHBPrescaler::Div16 => Hpre::DIV16,
|
||||
AHBPrescaler::Div64 => Hpre::DIV64,
|
||||
AHBPrescaler::Div128 => Hpre::DIV128,
|
||||
AHBPrescaler::Div256 => Hpre::DIV256,
|
||||
AHBPrescaler::Div512 => Hpre::DIV512,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration of the core clocks
|
||||
#[non_exhaustive]
|
||||
pub struct Config {
|
||||
@ -406,13 +314,13 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
};
|
||||
assert!(sys <= max_clk);
|
||||
|
||||
let hclk = config.ahb_pre.div(sys);
|
||||
let hclk = sys / config.ahb_pre;
|
||||
|
||||
let apb1 = config.apb1_pre.div(hclk);
|
||||
let apb1 = hclk / config.apb1_pre;
|
||||
let apb1_tim = config.apb1_pre.div_tim(hclk, config.timer_prescaler);
|
||||
let apb2 = config.apb2_pre.div(hclk);
|
||||
let apb2 = hclk / config.apb2_pre;
|
||||
let apb2_tim = config.apb2_pre.div_tim(hclk, config.timer_prescaler);
|
||||
let apb3 = config.apb3_pre.div(hclk);
|
||||
let apb3 = hclk / config.apb3_pre;
|
||||
|
||||
flash_setup(hclk, config.voltage_scale);
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use embassy_hal_common::into_ref;
|
||||
use embassy_hal_internal::into_ref;
|
||||
pub use pll::PllConfig;
|
||||
use stm32_metapac::rcc::vals::{Mco1, Mco2};
|
||||
|
||||
@ -24,21 +24,7 @@ pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
|
||||
/// LSI speed
|
||||
pub const LSI_FREQ: Hertz = Hertz(32_000);
|
||||
|
||||
/// Voltage Scale
|
||||
///
|
||||
/// Represents the voltage range feeding the CPU core. The maximum core
|
||||
/// clock frequency depends on this value.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum VoltageScale {
|
||||
/// VOS 0 range VCORE 1.26V - 1.40V
|
||||
Scale0,
|
||||
/// VOS 1 range VCORE 1.15V - 1.26V
|
||||
Scale1,
|
||||
/// VOS 2 range VCORE 1.05V - 1.15V
|
||||
Scale2,
|
||||
/// VOS 3 range VCORE 0.95V - 1.05V
|
||||
Scale3,
|
||||
}
|
||||
pub use super::common::VoltageScale;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum AdcClockSource {
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub use super::common::{AHBPrescaler, APBPrescaler};
|
||||
use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
|
||||
use crate::pac::RCC;
|
||||
#[cfg(crs)]
|
||||
@ -70,30 +71,6 @@ pub enum PLLMul {
|
||||
Mul48,
|
||||
}
|
||||
|
||||
/// AHB prescaler
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum AHBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
Div64,
|
||||
Div128,
|
||||
Div256,
|
||||
Div512,
|
||||
}
|
||||
|
||||
/// APB prescaler
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum APBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
}
|
||||
|
||||
/// PLL clock input source
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum PLLSource {
|
||||
@ -136,34 +113,6 @@ impl From<PLLSource> for Pllsrc {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<APBPrescaler> for Ppre {
|
||||
fn from(val: APBPrescaler) -> Ppre {
|
||||
match val {
|
||||
APBPrescaler::NotDivided => Ppre::DIV1,
|
||||
APBPrescaler::Div2 => Ppre::DIV2,
|
||||
APBPrescaler::Div4 => Ppre::DIV4,
|
||||
APBPrescaler::Div8 => Ppre::DIV8,
|
||||
APBPrescaler::Div16 => Ppre::DIV16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AHBPrescaler> for Hpre {
|
||||
fn from(val: AHBPrescaler) -> Hpre {
|
||||
match val {
|
||||
AHBPrescaler::NotDivided => Hpre::DIV1,
|
||||
AHBPrescaler::Div2 => Hpre::DIV2,
|
||||
AHBPrescaler::Div4 => Hpre::DIV4,
|
||||
AHBPrescaler::Div8 => Hpre::DIV8,
|
||||
AHBPrescaler::Div16 => Hpre::DIV16,
|
||||
AHBPrescaler::Div64 => Hpre::DIV64,
|
||||
AHBPrescaler::Div128 => Hpre::DIV128,
|
||||
AHBPrescaler::Div256 => Hpre::DIV256,
|
||||
AHBPrescaler::Div512 => Hpre::DIV512,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MSIRange> for Msirange {
|
||||
fn from(val: MSIRange) -> Msirange {
|
||||
match val {
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub use super::common::{AHBPrescaler, APBPrescaler};
|
||||
use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
|
||||
use crate::pac::{FLASH, RCC};
|
||||
use crate::rcc::{set_freqs, Clocks};
|
||||
@ -68,30 +69,6 @@ pub enum PLLMul {
|
||||
Mul48,
|
||||
}
|
||||
|
||||
/// AHB prescaler
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum AHBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
Div64,
|
||||
Div128,
|
||||
Div256,
|
||||
Div512,
|
||||
}
|
||||
|
||||
/// APB prescaler
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum APBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
}
|
||||
|
||||
/// PLL clock input source
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum PLLSource {
|
||||
@ -134,34 +111,6 @@ impl From<PLLSource> for Pllsrc {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<APBPrescaler> for Ppre {
|
||||
fn from(val: APBPrescaler) -> Ppre {
|
||||
match val {
|
||||
APBPrescaler::NotDivided => Ppre::DIV1,
|
||||
APBPrescaler::Div2 => Ppre::DIV2,
|
||||
APBPrescaler::Div4 => Ppre::DIV4,
|
||||
APBPrescaler::Div8 => Ppre::DIV8,
|
||||
APBPrescaler::Div16 => Ppre::DIV16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AHBPrescaler> for Hpre {
|
||||
fn from(val: AHBPrescaler) -> Hpre {
|
||||
match val {
|
||||
AHBPrescaler::NotDivided => Hpre::DIV1,
|
||||
AHBPrescaler::Div2 => Hpre::DIV2,
|
||||
AHBPrescaler::Div4 => Hpre::DIV4,
|
||||
AHBPrescaler::Div8 => Hpre::DIV8,
|
||||
AHBPrescaler::Div16 => Hpre::DIV16,
|
||||
AHBPrescaler::Div64 => Hpre::DIV64,
|
||||
AHBPrescaler::Div128 => Hpre::DIV128,
|
||||
AHBPrescaler::Div256 => Hpre::DIV256,
|
||||
AHBPrescaler::Div512 => Hpre::DIV512,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MSIRange> for Msirange {
|
||||
fn from(val: MSIRange) -> Msirange {
|
||||
match val {
|
||||
|
@ -1,9 +1,10 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use embassy_hal_common::into_ref;
|
||||
use embassy_hal_internal::into_ref;
|
||||
use stm32_metapac::rcc::regs::Cfgr;
|
||||
use stm32_metapac::rcc::vals::{Lsedrv, Mcopre, Mcosel};
|
||||
|
||||
pub use super::common::{AHBPrescaler, APBPrescaler};
|
||||
use crate::gpio::sealed::AFType;
|
||||
use crate::gpio::Speed;
|
||||
use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw};
|
||||
@ -78,30 +79,6 @@ pub enum PLLDiv {
|
||||
Div4,
|
||||
}
|
||||
|
||||
/// AHB prescaler
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum AHBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
Div64,
|
||||
Div128,
|
||||
Div256,
|
||||
Div512,
|
||||
}
|
||||
|
||||
/// APB prescaler
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum APBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
}
|
||||
|
||||
/// PLL clock input source
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum PLLSource {
|
||||
@ -209,34 +186,6 @@ impl From<PLLSource> for Pllsrc {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<APBPrescaler> for Ppre {
|
||||
fn from(val: APBPrescaler) -> Ppre {
|
||||
match val {
|
||||
APBPrescaler::NotDivided => Ppre::DIV1,
|
||||
APBPrescaler::Div2 => Ppre::DIV2,
|
||||
APBPrescaler::Div4 => Ppre::DIV4,
|
||||
APBPrescaler::Div8 => Ppre::DIV8,
|
||||
APBPrescaler::Div16 => Ppre::DIV16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AHBPrescaler> for Hpre {
|
||||
fn from(val: AHBPrescaler) -> Hpre {
|
||||
match val {
|
||||
AHBPrescaler::NotDivided => Hpre::DIV1,
|
||||
AHBPrescaler::Div2 => Hpre::DIV2,
|
||||
AHBPrescaler::Div4 => Hpre::DIV4,
|
||||
AHBPrescaler::Div8 => Hpre::DIV8,
|
||||
AHBPrescaler::Div16 => Hpre::DIV16,
|
||||
AHBPrescaler::Div64 => Hpre::DIV64,
|
||||
AHBPrescaler::Div128 => Hpre::DIV128,
|
||||
AHBPrescaler::Div256 => Hpre::DIV256,
|
||||
AHBPrescaler::Div512 => Hpre::DIV512,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MSIRange> for Msirange {
|
||||
fn from(val: MSIRange) -> Msirange {
|
||||
match val {
|
||||
|
@ -1,5 +1,6 @@
|
||||
use stm32_metapac::PWR;
|
||||
|
||||
pub use super::common::{AHBPrescaler, APBPrescaler};
|
||||
use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw};
|
||||
use crate::pac::{FLASH, RCC};
|
||||
use crate::rcc::{set_freqs, Clocks};
|
||||
@ -71,30 +72,6 @@ pub enum PLLDiv {
|
||||
Div4,
|
||||
}
|
||||
|
||||
/// AHB prescaler
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum AHBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
Div64,
|
||||
Div128,
|
||||
Div256,
|
||||
Div512,
|
||||
}
|
||||
|
||||
/// APB prescaler
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum APBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
}
|
||||
|
||||
/// PLL clock input source
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum PLLSource {
|
||||
@ -202,34 +179,6 @@ impl From<PLLSource> for Pllsrc {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<APBPrescaler> for Ppre {
|
||||
fn from(val: APBPrescaler) -> Ppre {
|
||||
match val {
|
||||
APBPrescaler::NotDivided => Ppre::DIV1,
|
||||
APBPrescaler::Div2 => Ppre::DIV2,
|
||||
APBPrescaler::Div4 => Ppre::DIV4,
|
||||
APBPrescaler::Div8 => Ppre::DIV8,
|
||||
APBPrescaler::Div16 => Ppre::DIV16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AHBPrescaler> for Hpre {
|
||||
fn from(val: AHBPrescaler) -> Hpre {
|
||||
match val {
|
||||
AHBPrescaler::NotDivided => Hpre::DIV1,
|
||||
AHBPrescaler::Div2 => Hpre::DIV2,
|
||||
AHBPrescaler::Div4 => Hpre::DIV4,
|
||||
AHBPrescaler::Div8 => Hpre::DIV8,
|
||||
AHBPrescaler::Div16 => Hpre::DIV16,
|
||||
AHBPrescaler::Div64 => Hpre::DIV64,
|
||||
AHBPrescaler::Div128 => Hpre::DIV128,
|
||||
AHBPrescaler::Div256 => Hpre::DIV256,
|
||||
AHBPrescaler::Div512 => Hpre::DIV512,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MSIRange> for Msirange {
|
||||
fn from(val: MSIRange) -> Msirange {
|
||||
match val {
|
||||
|
@ -1,5 +1,7 @@
|
||||
#![macro_use]
|
||||
|
||||
pub mod common;
|
||||
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use crate::time::Hertz;
|
||||
|
@ -1,5 +1,6 @@
|
||||
use stm32_metapac::rcc::vals::{Hpre, Msirange, Msirgsel, Pllm, Pllsrc, Ppre, Sw};
|
||||
use stm32_metapac::rcc::vals::{Msirange, Msirgsel, Pllm, Pllsrc, Sw};
|
||||
|
||||
pub use super::common::{AHBPrescaler, APBPrescaler};
|
||||
use crate::pac::{FLASH, RCC};
|
||||
use crate::rcc::{set_freqs, Clocks};
|
||||
use crate::time::Hertz;
|
||||
@ -10,19 +11,7 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000);
|
||||
/// LSI speed
|
||||
pub const LSI_FREQ: Hertz = Hertz(32_000);
|
||||
|
||||
/// Voltage Scale
|
||||
///
|
||||
/// Represents the voltage range feeding the CPU core. The maximum core
|
||||
/// clock frequency depends on this value.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum VoltageScale {
|
||||
// Highest frequency
|
||||
Range1,
|
||||
Range2,
|
||||
Range3,
|
||||
// Lowest power
|
||||
Range4,
|
||||
}
|
||||
pub use super::common::VoltageScale;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum ClockSrc {
|
||||
@ -130,36 +119,6 @@ impl Into<Pllm> for PllM {
|
||||
}
|
||||
}
|
||||
|
||||
/// AHB prescaler
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum AHBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
Div64,
|
||||
Div128,
|
||||
Div256,
|
||||
Div512,
|
||||
}
|
||||
|
||||
impl Into<Hpre> for AHBPrescaler {
|
||||
fn into(self) -> Hpre {
|
||||
match self {
|
||||
AHBPrescaler::NotDivided => Hpre::NONE,
|
||||
AHBPrescaler::Div2 => Hpre::DIV2,
|
||||
AHBPrescaler::Div4 => Hpre::DIV4,
|
||||
AHBPrescaler::Div8 => Hpre::DIV8,
|
||||
AHBPrescaler::Div16 => Hpre::DIV16,
|
||||
AHBPrescaler::Div64 => Hpre::DIV64,
|
||||
AHBPrescaler::Div128 => Hpre::DIV128,
|
||||
AHBPrescaler::Div256 => Hpre::DIV256,
|
||||
AHBPrescaler::Div512 => Hpre::DIV512,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for AHBPrescaler {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
@ -182,28 +141,6 @@ impl Default for AHBPrescaler {
|
||||
}
|
||||
}
|
||||
|
||||
/// APB prescaler
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum APBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
}
|
||||
|
||||
impl Into<Ppre> for APBPrescaler {
|
||||
fn into(self) -> Ppre {
|
||||
match self {
|
||||
APBPrescaler::NotDivided => Ppre::NONE,
|
||||
APBPrescaler::Div2 => Ppre::DIV2,
|
||||
APBPrescaler::Div4 => Ppre::DIV4,
|
||||
APBPrescaler::Div8 => Ppre::DIV8,
|
||||
APBPrescaler::Div16 => Ppre::DIV16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for APBPrescaler {
|
||||
fn default() -> Self {
|
||||
APBPrescaler::NotDivided
|
||||
@ -389,12 +326,12 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
}
|
||||
|
||||
// TODO make configurable
|
||||
let power_vos = VoltageScale::Range4;
|
||||
let power_vos = VoltageScale::Scale3;
|
||||
|
||||
// states and programming delay
|
||||
let wait_states = match power_vos {
|
||||
// VOS 0 range VCORE 1.26V - 1.40V
|
||||
VoltageScale::Range1 => {
|
||||
VoltageScale::Scale0 => {
|
||||
if sys_clk < 32_000_000 {
|
||||
0
|
||||
} else if sys_clk < 64_000_000 {
|
||||
@ -408,7 +345,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
}
|
||||
}
|
||||
// VOS 1 range VCORE 1.15V - 1.26V
|
||||
VoltageScale::Range2 => {
|
||||
VoltageScale::Scale1 => {
|
||||
if sys_clk < 30_000_000 {
|
||||
0
|
||||
} else if sys_clk < 60_000_000 {
|
||||
@ -420,7 +357,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
}
|
||||
}
|
||||
// VOS 2 range VCORE 1.05V - 1.15V
|
||||
VoltageScale::Range3 => {
|
||||
VoltageScale::Scale2 => {
|
||||
if sys_clk < 24_000_000 {
|
||||
0
|
||||
} else if sys_clk < 48_000_000 {
|
||||
@ -430,7 +367,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
}
|
||||
}
|
||||
// VOS 3 range VCORE 0.95V - 1.05V
|
||||
VoltageScale::Range4 => {
|
||||
VoltageScale::Scale3 => {
|
||||
if sys_clk < 12_000_000 {
|
||||
0
|
||||
} else {
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub use super::common::{AHBPrescaler, APBPrescaler};
|
||||
use crate::rcc::Clocks;
|
||||
use crate::time::{khz, mhz, Hertz};
|
||||
|
||||
@ -102,68 +103,6 @@ pub struct Pll {
|
||||
pub divr: Option<u16>,
|
||||
}
|
||||
|
||||
/// AHB prescaler
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum AHBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div3,
|
||||
Div4,
|
||||
Div5,
|
||||
Div6,
|
||||
Div8,
|
||||
Div10,
|
||||
Div16,
|
||||
Div32,
|
||||
Div64,
|
||||
Div128,
|
||||
Div256,
|
||||
Div512,
|
||||
}
|
||||
|
||||
/// APB prescaler
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum APBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
}
|
||||
|
||||
impl Into<u8> for APBPrescaler {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
APBPrescaler::NotDivided => 1,
|
||||
APBPrescaler::Div2 => 0x04,
|
||||
APBPrescaler::Div4 => 0x05,
|
||||
APBPrescaler::Div8 => 0x06,
|
||||
APBPrescaler::Div16 => 0x07,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for AHBPrescaler {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
AHBPrescaler::NotDivided => 0x0,
|
||||
AHBPrescaler::Div2 => 0x08,
|
||||
AHBPrescaler::Div3 => 0x01,
|
||||
AHBPrescaler::Div4 => 0x09,
|
||||
AHBPrescaler::Div5 => 0x02,
|
||||
AHBPrescaler::Div6 => 0x05,
|
||||
AHBPrescaler::Div8 => 0x0a,
|
||||
AHBPrescaler::Div10 => 0x06,
|
||||
AHBPrescaler::Div16 => 0x0b,
|
||||
AHBPrescaler::Div32 => 0x07,
|
||||
AHBPrescaler::Div64 => 0x0c,
|
||||
AHBPrescaler::Div128 => 0x0d,
|
||||
AHBPrescaler::Div256 => 0x0e,
|
||||
AHBPrescaler::Div512 => 0x0f,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Clocks configutation
|
||||
pub struct Config {
|
||||
pub hse: Option<Hse>,
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub use super::common::{AHBPrescaler, APBPrescaler, VoltageScale};
|
||||
use crate::pac::pwr::vals::Dbp;
|
||||
use crate::pac::{FLASH, PWR, RCC};
|
||||
use crate::rcc::{set_freqs, Clocks};
|
||||
@ -73,9 +74,9 @@ impl MSIRange {
|
||||
|
||||
fn vos(&self) -> VoltageScale {
|
||||
if self > &MSIRange::Range8 {
|
||||
VoltageScale::Range1
|
||||
VoltageScale::Scale0
|
||||
} else {
|
||||
VoltageScale::Range2
|
||||
VoltageScale::Scale1
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -105,78 +106,6 @@ impl Into<u8> for MSIRange {
|
||||
}
|
||||
}
|
||||
|
||||
/// Voltage Scale
|
||||
///
|
||||
/// Represents the voltage range feeding the CPU core. The maximum core
|
||||
/// clock frequency depends on this value.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum VoltageScale {
|
||||
Range1,
|
||||
Range2,
|
||||
}
|
||||
|
||||
/// AHB prescaler
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum AHBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div3,
|
||||
Div4,
|
||||
Div5,
|
||||
Div6,
|
||||
Div8,
|
||||
Div10,
|
||||
Div16,
|
||||
Div32,
|
||||
Div64,
|
||||
Div128,
|
||||
Div256,
|
||||
Div512,
|
||||
}
|
||||
|
||||
/// APB prescaler
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum APBPrescaler {
|
||||
NotDivided,
|
||||
Div2,
|
||||
Div4,
|
||||
Div8,
|
||||
Div16,
|
||||
}
|
||||
|
||||
impl Into<u8> for APBPrescaler {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
APBPrescaler::NotDivided => 1,
|
||||
APBPrescaler::Div2 => 0x04,
|
||||
APBPrescaler::Div4 => 0x05,
|
||||
APBPrescaler::Div8 => 0x06,
|
||||
APBPrescaler::Div16 => 0x07,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for AHBPrescaler {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
AHBPrescaler::NotDivided => 0x0,
|
||||
AHBPrescaler::Div2 => 0x08,
|
||||
AHBPrescaler::Div3 => 0x01,
|
||||
AHBPrescaler::Div4 => 0x09,
|
||||
AHBPrescaler::Div5 => 0x02,
|
||||
AHBPrescaler::Div6 => 0x05,
|
||||
AHBPrescaler::Div8 => 0x0a,
|
||||
AHBPrescaler::Div10 => 0x06,
|
||||
AHBPrescaler::Div16 => 0x0b,
|
||||
AHBPrescaler::Div32 => 0x07,
|
||||
AHBPrescaler::Div64 => 0x0c,
|
||||
AHBPrescaler::Div128 => 0x0d,
|
||||
AHBPrescaler::Div256 => 0x0e,
|
||||
AHBPrescaler::Div512 => 0x0f,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Clocks configutation
|
||||
pub struct Config {
|
||||
pub mux: ClockSrc,
|
||||
@ -220,8 +149,8 @@ pub enum Lsedrv {
|
||||
|
||||
pub(crate) unsafe fn init(config: Config) {
|
||||
let (sys_clk, sw, vos) = match config.mux {
|
||||
ClockSrc::HSI16 => (HSI_FREQ.0, 0x01, VoltageScale::Range2),
|
||||
ClockSrc::HSE32 => (HSE32_FREQ.0, 0x02, VoltageScale::Range1),
|
||||
ClockSrc::HSI16 => (HSI_FREQ.0, 0x01, VoltageScale::Scale1),
|
||||
ClockSrc::HSE32 => (HSE32_FREQ.0, 0x02, VoltageScale::Scale0),
|
||||
ClockSrc::MSI(range) => (range.freq(), 0x00, range.vos()),
|
||||
};
|
||||
|
||||
@ -266,12 +195,12 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
// Adjust flash latency
|
||||
let flash_clk_src_freq: u32 = shd_ahb_freq;
|
||||
let ws = match vos {
|
||||
VoltageScale::Range1 => match flash_clk_src_freq {
|
||||
VoltageScale::Scale0 => match flash_clk_src_freq {
|
||||
0..=18_000_000 => 0b000,
|
||||
18_000_001..=36_000_000 => 0b001,
|
||||
_ => 0b010,
|
||||
},
|
||||
VoltageScale::Range2 => match flash_clk_src_freq {
|
||||
VoltageScale::Scale1 => match flash_clk_src_freq {
|
||||
0..=6_000_000 => 0b000,
|
||||
6_000_001..=12_000_000 => 0b001,
|
||||
_ => 0b010,
|
||||
|
@ -1,15 +1,17 @@
|
||||
#![macro_use]
|
||||
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
|
||||
use crate::{pac, peripherals, Peripheral};
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::{interrupt, pac, peripherals, Peripheral};
|
||||
|
||||
pub(crate) static RNG_WAKER: AtomicWaker = AtomicWaker::new();
|
||||
static RNG_WAKER: AtomicWaker = AtomicWaker::new();
|
||||
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Error {
|
||||
@ -17,68 +19,145 @@ pub enum Error {
|
||||
ClockError,
|
||||
}
|
||||
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let bits = T::regs().sr().read();
|
||||
if bits.drdy() || bits.seis() || bits.ceis() {
|
||||
T::regs().cr().modify(|reg| reg.set_ie(false));
|
||||
RNG_WAKER.wake();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Rng<'d, T: Instance> {
|
||||
_inner: PeripheralRef<'d, T>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Rng<'d, T> {
|
||||
pub fn new(inner: impl Peripheral<P = T> + 'd) -> Self {
|
||||
pub fn new(
|
||||
inner: impl Peripheral<P = T> + 'd,
|
||||
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
) -> Self {
|
||||
T::enable();
|
||||
T::reset();
|
||||
into_ref!(inner);
|
||||
let mut random = Self { _inner: inner };
|
||||
random.reset();
|
||||
|
||||
T::Interrupt::unpend();
|
||||
unsafe { T::Interrupt::enable() };
|
||||
|
||||
random
|
||||
}
|
||||
|
||||
#[cfg(rng_v1)]
|
||||
pub fn reset(&mut self) {
|
||||
// rng_v2 locks up on seed error, needs reset
|
||||
#[cfg(rng_v2)]
|
||||
if T::regs().sr().read().seis() {
|
||||
T::reset();
|
||||
}
|
||||
T::regs().cr().modify(|reg| {
|
||||
reg.set_rngen(true);
|
||||
reg.set_ie(true);
|
||||
T::regs().cr().write(|reg| {
|
||||
reg.set_rngen(false);
|
||||
});
|
||||
T::regs().sr().modify(|reg| {
|
||||
reg.set_seis(false);
|
||||
reg.set_ceis(false);
|
||||
});
|
||||
T::regs().cr().modify(|reg| {
|
||||
reg.set_rngen(true);
|
||||
});
|
||||
// Reference manual says to discard the first.
|
||||
let _ = self.next_u32();
|
||||
}
|
||||
|
||||
pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
|
||||
#[cfg(not(rng_v1))]
|
||||
pub fn reset(&mut self) {
|
||||
T::regs().cr().write(|reg| {
|
||||
reg.set_rngen(false);
|
||||
reg.set_condrst(true);
|
||||
// set RNG config "A" according to reference manual
|
||||
// this has to be written within the same write access as setting the CONDRST bit
|
||||
reg.set_nistc(pac::rng::vals::Nistc::DEFAULT);
|
||||
reg.set_rng_config1(pac::rng::vals::RngConfig1::CONFIGA);
|
||||
reg.set_rng_config2(pac::rng::vals::RngConfig2::CONFIGA_B);
|
||||
reg.set_rng_config3(pac::rng::vals::RngConfig3::CONFIGA);
|
||||
reg.set_clkdiv(pac::rng::vals::Clkdiv::NODIV);
|
||||
});
|
||||
// wait for CONDRST to be set
|
||||
while !T::regs().cr().read().condrst() {}
|
||||
// magic number must be written immediately before every read or write access to HTCR
|
||||
T::regs().htcr().write(|w| w.set_htcfg(pac::rng::vals::Htcfg::MAGIC));
|
||||
// write recommended value according to reference manual
|
||||
// note: HTCR can only be written during conditioning
|
||||
T::regs()
|
||||
.htcr()
|
||||
.write(|w| w.set_htcfg(pac::rng::vals::Htcfg::RECOMMENDED));
|
||||
// finish conditioning
|
||||
T::regs().cr().modify(|reg| {
|
||||
reg.set_rngen(true);
|
||||
reg.set_condrst(false);
|
||||
});
|
||||
// wait for CONDRST to be reset
|
||||
while T::regs().cr().read().condrst() {}
|
||||
}
|
||||
|
||||
pub fn recover_seed_error(&mut self) -> () {
|
||||
self.reset();
|
||||
// reset should also clear the SEIS flag
|
||||
if T::regs().sr().read().seis() {
|
||||
warn!("recovering from seed error failed");
|
||||
return;
|
||||
}
|
||||
// wait for SECS to be cleared by RNG
|
||||
while T::regs().sr().read().secs() {}
|
||||
}
|
||||
|
||||
pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
|
||||
for chunk in dest.chunks_mut(4) {
|
||||
poll_fn(|cx| {
|
||||
RNG_WAKER.register(cx.waker());
|
||||
T::regs().cr().modify(|reg| {
|
||||
reg.set_ie(true);
|
||||
});
|
||||
|
||||
let bits = T::regs().sr().read();
|
||||
|
||||
if bits.drdy() {
|
||||
Poll::Ready(Ok(()))
|
||||
} else if bits.seis() {
|
||||
self.reset();
|
||||
Poll::Ready(Err(Error::SeedError))
|
||||
} else if bits.ceis() {
|
||||
self.reset();
|
||||
Poll::Ready(Err(Error::ClockError))
|
||||
} else {
|
||||
Poll::Pending
|
||||
let bits = T::regs().sr().read();
|
||||
if bits.seis() {
|
||||
// in case of noise-source or seed error we try to recover here
|
||||
// but we must not use the data in DR and we return an error
|
||||
// to leave retry-logic to the application
|
||||
self.recover_seed_error();
|
||||
return Err(Error::SeedError);
|
||||
} else if bits.ceis() {
|
||||
// clock error detected, DR could still be used but keep it safe,
|
||||
// clear the error and abort
|
||||
T::regs().sr().modify(|sr| sr.set_ceis(false));
|
||||
return Err(Error::ClockError);
|
||||
} else if bits.drdy() {
|
||||
// DR can be read up to four times until the output buffer is empty
|
||||
// DRDY is cleared automatically when that happens
|
||||
let random_word = T::regs().dr().read();
|
||||
// reference manual: always check if DR is zero
|
||||
if random_word == 0 {
|
||||
return Err(Error::SeedError);
|
||||
}
|
||||
})
|
||||
.await?;
|
||||
let random_bytes = T::regs().dr().read().to_be_bytes();
|
||||
for (dest, src) in chunk.iter_mut().zip(random_bytes.iter()) {
|
||||
*dest = *src
|
||||
// write bytes to chunk
|
||||
for (dest, src) in chunk.iter_mut().zip(random_word.to_be_bytes().iter()) {
|
||||
*dest = *src
|
||||
}
|
||||
} else {
|
||||
// wait for interrupt
|
||||
poll_fn(|cx| {
|
||||
// quick check to avoid registration if already done.
|
||||
let bits = T::regs().sr().read();
|
||||
if bits.drdy() || bits.seis() || bits.ceis() {
|
||||
return Poll::Ready(());
|
||||
}
|
||||
RNG_WAKER.register(cx.waker());
|
||||
T::regs().cr().modify(|reg| reg.set_ie(true));
|
||||
// Need to check condition **after** `register` to avoid a race
|
||||
// condition that would result in lost notifications.
|
||||
let bits = T::regs().sr().read();
|
||||
if bits.drdy() || bits.seis() || bits.ceis() {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,57 +208,20 @@ pub(crate) mod sealed {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Instance: sealed::Instance + crate::rcc::RccPeripheral {}
|
||||
pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send {
|
||||
type Interrupt: interrupt::typelevel::Interrupt;
|
||||
}
|
||||
|
||||
foreach_peripheral!(
|
||||
(rng, $inst:ident) => {
|
||||
impl Instance for peripherals::$inst {}
|
||||
foreach_interrupt!(
|
||||
($inst:ident, rng, RNG, GLOBAL, $irq:ident) => {
|
||||
impl Instance for peripherals::$inst {
|
||||
type Interrupt = crate::interrupt::typelevel::$irq;
|
||||
}
|
||||
|
||||
impl sealed::Instance for peripherals::$inst {
|
||||
fn regs() -> crate::pac::rng::Rng {
|
||||
crate::pac::RNG
|
||||
crate::pac::$inst
|
||||
}
|
||||
}
|
||||
};
|
||||
);
|
||||
|
||||
#[cfg(feature = "rt")]
|
||||
macro_rules! irq {
|
||||
($irq:ident) => {
|
||||
mod rng_irq {
|
||||
use crate::interrupt;
|
||||
|
||||
#[interrupt]
|
||||
unsafe fn $irq() {
|
||||
let bits = $crate::pac::RNG.sr().read();
|
||||
if bits.drdy() || bits.seis() || bits.ceis() {
|
||||
$crate::pac::RNG.cr().write(|reg| reg.set_ie(false));
|
||||
$crate::rng::RNG_WAKER.wake();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "rt")]
|
||||
foreach_interrupt!(
|
||||
(RNG) => {
|
||||
irq!(RNG);
|
||||
};
|
||||
|
||||
(RNG_LPUART1) => {
|
||||
irq!(RNG_LPUART1);
|
||||
};
|
||||
|
||||
(AES_RNG_LPUART1) => {
|
||||
irq!(AES_RNG_LPUART1);
|
||||
};
|
||||
|
||||
(AES_RNG) => {
|
||||
irq!(AES_RNG);
|
||||
};
|
||||
|
||||
(HASH_RNG) => {
|
||||
irq!(HASH_RNG);
|
||||
};
|
||||
);
|
||||
|
@ -15,7 +15,7 @@ pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
|
||||
#[cfg_attr(any(rtc_v3, rtc_v3u5), path = "v3.rs")]
|
||||
mod _version;
|
||||
pub use _version::*;
|
||||
use embassy_hal_common::Peripheral;
|
||||
use embassy_hal_internal::Peripheral;
|
||||
|
||||
/// Errors that can occur on methods on [RtcClock]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -39,9 +39,8 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
|
||||
let rtcsel = reg.rtcsel().to_bits();
|
||||
|
||||
if !reg.rtcen() || rtcsel != clock_config {
|
||||
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
|
||||
#[cfg(not(any(rtc_v2l0, rtc_v2l1, rtc_v2f2)))]
|
||||
crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));
|
||||
|
||||
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
|
||||
let cr = crate::pac::RCC.bdcr();
|
||||
#[cfg(any(rtc_v2l0, rtc_v2l1))]
|
||||
@ -201,6 +200,11 @@ impl sealed::Instance for crate::peripherals::RTC {
|
||||
// read to allow the pwr clock to enable
|
||||
crate::pac::PWR.cr1().read();
|
||||
}
|
||||
#[cfg(any(rtc_v2f2))]
|
||||
{
|
||||
crate::pac::RCC.apb1enr().modify(|w| w.set_pwren(true));
|
||||
crate::pac::PWR.cr().read();
|
||||
}
|
||||
}
|
||||
|
||||
fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32> {
|
||||
|
@ -6,8 +6,8 @@ use core::marker::PhantomData;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_hal_common::drop::OnDrop;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_hal_internal::drop::OnDrop;
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR};
|
||||
|
||||
|
@ -4,7 +4,7 @@ use core::ptr;
|
||||
|
||||
use embassy_embedded_hal::SetConfig;
|
||||
use embassy_futures::join::join;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
|
||||
|
||||
use crate::dma::{slice_ptr_parts, word, Transfer};
|
||||
@ -36,6 +36,7 @@ pub enum BitOrder {
|
||||
pub struct Config {
|
||||
pub mode: Mode,
|
||||
pub bit_order: BitOrder,
|
||||
pub frequency: Hertz,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
@ -43,6 +44,7 @@ impl Default for Config {
|
||||
Self {
|
||||
mode: MODE_0,
|
||||
bit_order: BitOrder::MsbFirst,
|
||||
frequency: Hertz(1_000_000),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -88,7 +90,6 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
||||
miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
|
||||
txdma: impl Peripheral<P = Tx> + 'd,
|
||||
rxdma: impl Peripheral<P = Rx> + 'd,
|
||||
freq: Hertz,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(peri, sck, mosi, miso);
|
||||
@ -112,7 +113,6 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
||||
Some(miso.map_into()),
|
||||
txdma,
|
||||
rxdma,
|
||||
freq,
|
||||
config,
|
||||
)
|
||||
}
|
||||
@ -123,7 +123,6 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
||||
miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
|
||||
txdma: impl Peripheral<P = Tx> + 'd, // TODO remove
|
||||
rxdma: impl Peripheral<P = Rx> + 'd,
|
||||
freq: Hertz,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(sck, miso);
|
||||
@ -139,7 +138,6 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
||||
Some(miso.map_into()),
|
||||
txdma,
|
||||
rxdma,
|
||||
freq,
|
||||
config,
|
||||
)
|
||||
}
|
||||
@ -150,7 +148,6 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
||||
mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
|
||||
txdma: impl Peripheral<P = Tx> + 'd,
|
||||
rxdma: impl Peripheral<P = Rx> + 'd, // TODO remove
|
||||
freq: Hertz,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(sck, mosi);
|
||||
@ -166,7 +163,6 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
||||
None,
|
||||
txdma,
|
||||
rxdma,
|
||||
freq,
|
||||
config,
|
||||
)
|
||||
}
|
||||
@ -176,14 +172,13 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
||||
mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
|
||||
txdma: impl Peripheral<P = Tx> + 'd,
|
||||
rxdma: impl Peripheral<P = Rx> + 'd, // TODO: remove
|
||||
freq: Hertz,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(mosi);
|
||||
mosi.set_as_af_pull(mosi.af_num(), AFType::OutputPushPull, Pull::Down);
|
||||
mosi.set_speed(crate::gpio::Speed::Medium);
|
||||
|
||||
Self::new_inner(peri, None, Some(mosi.map_into()), None, txdma, rxdma, freq, config)
|
||||
Self::new_inner(peri, None, Some(mosi.map_into()), None, txdma, rxdma, config)
|
||||
}
|
||||
|
||||
#[cfg(stm32wl)]
|
||||
@ -201,7 +196,8 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
||||
let mut config = Config::default();
|
||||
config.mode = MODE_0;
|
||||
config.bit_order = BitOrder::MsbFirst;
|
||||
Self::new_inner(peri, None, None, None, txdma, rxdma, freq, config)
|
||||
config.frequency = freq;
|
||||
Self::new_inner(peri, None, None, None, txdma, rxdma, config)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@ -209,10 +205,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
txdma: impl Peripheral<P = Tx> + 'd,
|
||||
rxdma: impl Peripheral<P = Rx> + 'd,
|
||||
freq: Hertz,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
Self::new_inner(peri, None, None, None, txdma, rxdma, freq, config)
|
||||
Self::new_inner(peri, None, None, None, txdma, rxdma, config)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
@ -222,12 +217,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
||||
miso: Option<PeripheralRef<'d, AnyPin>>,
|
||||
txdma: impl Peripheral<P = Tx> + 'd,
|
||||
rxdma: impl Peripheral<P = Rx> + 'd,
|
||||
freq: Hertz,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(peri, txdma, rxdma);
|
||||
|
||||
let pclk = T::frequency();
|
||||
let freq = config.frequency;
|
||||
let br = compute_baud_rate(pclk, freq.into());
|
||||
|
||||
let cpha = config.raw_phase();
|
||||
@ -334,19 +329,29 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
||||
|
||||
let lsbfirst = config.raw_byte_order();
|
||||
|
||||
let pclk = T::frequency();
|
||||
let freq = config.frequency;
|
||||
let br = compute_baud_rate(pclk, freq.into());
|
||||
|
||||
#[cfg(any(spi_v1, spi_f1, spi_v2))]
|
||||
T::REGS.cr1().modify(|w| {
|
||||
w.set_cpha(cpha);
|
||||
w.set_cpol(cpol);
|
||||
w.set_br(br);
|
||||
w.set_lsbfirst(lsbfirst);
|
||||
});
|
||||
|
||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||
T::REGS.cfg2().modify(|w| {
|
||||
w.set_cpha(cpha);
|
||||
w.set_cpol(cpol);
|
||||
w.set_lsbfirst(lsbfirst);
|
||||
});
|
||||
{
|
||||
T::REGS.cfg2().modify(|w| {
|
||||
w.set_cpha(cpha);
|
||||
w.set_cpol(cpol);
|
||||
w.set_lsbfirst(lsbfirst);
|
||||
});
|
||||
T::REGS.cfg1().modify(|w| {
|
||||
w.set_mbr(br);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_current_config(&self) -> Config {
|
||||
@ -354,6 +359,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
||||
let cfg = T::REGS.cr1().read();
|
||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||
let cfg = T::REGS.cfg2().read();
|
||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||
let cfg1 = T::REGS.cfg1().read();
|
||||
|
||||
let polarity = if cfg.cpol() == vals::Cpol::IDLELOW {
|
||||
Polarity::IdleLow
|
||||
} else {
|
||||
@ -371,9 +379,18 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
|
||||
BitOrder::MsbFirst
|
||||
};
|
||||
|
||||
#[cfg(any(spi_v1, spi_f1, spi_v2))]
|
||||
let br = cfg.br();
|
||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||
let br = cfg1.mbr();
|
||||
|
||||
let pclk = T::frequency();
|
||||
let frequency = compute_frequency(pclk, br);
|
||||
|
||||
Config {
|
||||
mode: Mode { polarity, phase },
|
||||
bit_order,
|
||||
frequency,
|
||||
}
|
||||
}
|
||||
|
||||
@ -653,6 +670,21 @@ fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> Br {
|
||||
Br::from_bits(val)
|
||||
}
|
||||
|
||||
fn compute_frequency(clocks: Hertz, br: Br) -> Hertz {
|
||||
let div: u16 = match br {
|
||||
Br::DIV2 => 2,
|
||||
Br::DIV4 => 4,
|
||||
Br::DIV8 => 8,
|
||||
Br::DIV16 => 16,
|
||||
Br::DIV32 => 32,
|
||||
Br::DIV64 => 64,
|
||||
Br::DIV128 => 128,
|
||||
Br::DIV256 => 256,
|
||||
};
|
||||
|
||||
clocks / div
|
||||
}
|
||||
|
||||
trait RegsExt {
|
||||
fn tx_ptr<W>(&self) -> *mut W;
|
||||
fn rx_ptr<W>(&self) -> *mut W;
|
||||
|
@ -1,13 +1,13 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use stm32_metapac::timer::vals::Ckd;
|
||||
|
||||
use super::simple_pwm::*;
|
||||
use super::*;
|
||||
#[allow(unused_imports)]
|
||||
use crate::gpio::sealed::{AFType, Pin};
|
||||
use crate::gpio::AnyPin;
|
||||
use crate::gpio::{AnyPin, OutputType};
|
||||
use crate::time::Hertz;
|
||||
use crate::Peripheral;
|
||||
|
||||
@ -17,13 +17,13 @@ pub struct ComplementaryPwmPin<'d, Perip, Channel> {
|
||||
}
|
||||
|
||||
macro_rules! complementary_channel_impl {
|
||||
($new_chx:ident, $channel:ident, $pin_trait:ident, $complementary_pin_trait:ident) => {
|
||||
($new_chx:ident, $channel:ident, $pin_trait:ident) => {
|
||||
impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> {
|
||||
pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self {
|
||||
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd, output_type: OutputType) -> Self {
|
||||
into_ref!(pin);
|
||||
critical_section::with(|_| {
|
||||
pin.set_low();
|
||||
pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
|
||||
pin.set_as_af(pin.af_num(), output_type.into());
|
||||
#[cfg(gpio_v2)]
|
||||
pin.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
});
|
||||
@ -36,10 +36,10 @@ macro_rules! complementary_channel_impl {
|
||||
};
|
||||
}
|
||||
|
||||
complementary_channel_impl!(new_ch1, Ch1, Channel1Pin, Channel1ComplementaryPin);
|
||||
complementary_channel_impl!(new_ch2, Ch2, Channel2Pin, Channel2ComplementaryPin);
|
||||
complementary_channel_impl!(new_ch3, Ch3, Channel3Pin, Channel3ComplementaryPin);
|
||||
complementary_channel_impl!(new_ch4, Ch4, Channel4Pin, Channel4ComplementaryPin);
|
||||
complementary_channel_impl!(new_ch1, Ch1, Channel1ComplementaryPin);
|
||||
complementary_channel_impl!(new_ch2, Ch2, Channel2ComplementaryPin);
|
||||
complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin);
|
||||
complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin);
|
||||
|
||||
pub struct ComplementaryPwm<'d, T> {
|
||||
inner: PeripheralRef<'d, T>,
|
@ -1,3 +1,6 @@
|
||||
pub mod complementary_pwm;
|
||||
pub mod simple_pwm;
|
||||
|
||||
use stm32_metapac::timer::vals;
|
||||
|
||||
use crate::interrupt;
|
||||
@ -43,15 +46,123 @@ pub(crate) mod sealed {
|
||||
pub trait AdvancedControlInstance: GeneralPurpose16bitInstance {
|
||||
fn regs_advanced() -> crate::pac::timer::TimAdv;
|
||||
}
|
||||
|
||||
pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance {
|
||||
/// Global output enable. Does not do anything on non-advanced timers.
|
||||
fn enable_outputs(&mut self, enable: bool);
|
||||
|
||||
fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
|
||||
|
||||
fn enable_channel(&mut self, channel: Channel, enable: bool);
|
||||
|
||||
fn set_compare_value(&mut self, channel: Channel, value: u16);
|
||||
|
||||
fn get_max_compare_value(&self) -> u16;
|
||||
}
|
||||
|
||||
pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance {
|
||||
fn set_dead_time_clock_division(&mut self, value: vals::Ckd);
|
||||
|
||||
fn set_dead_time_value(&mut self, value: u8);
|
||||
|
||||
fn enable_complementary_channel(&mut self, channel: Channel, enable: bool);
|
||||
}
|
||||
|
||||
pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance {
|
||||
fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
|
||||
|
||||
fn enable_channel(&mut self, channel: Channel, enable: bool);
|
||||
|
||||
fn set_compare_value(&mut self, channel: Channel, value: u32);
|
||||
|
||||
fn get_max_compare_value(&self) -> u32;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Channel {
|
||||
Ch1,
|
||||
Ch2,
|
||||
Ch3,
|
||||
Ch4,
|
||||
}
|
||||
|
||||
impl Channel {
|
||||
pub fn raw(&self) -> usize {
|
||||
match self {
|
||||
Channel::Ch1 => 0,
|
||||
Channel::Ch2 => 1,
|
||||
Channel::Ch3 => 2,
|
||||
Channel::Ch4 => 3,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum OutputCompareMode {
|
||||
Frozen,
|
||||
ActiveOnMatch,
|
||||
InactiveOnMatch,
|
||||
Toggle,
|
||||
ForceInactive,
|
||||
ForceActive,
|
||||
PwmMode1,
|
||||
PwmMode2,
|
||||
}
|
||||
|
||||
impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm {
|
||||
fn from(mode: OutputCompareMode) -> Self {
|
||||
match mode {
|
||||
OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN,
|
||||
OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVEONMATCH,
|
||||
OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVEONMATCH,
|
||||
OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE,
|
||||
OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCEINACTIVE,
|
||||
OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCEACTIVE,
|
||||
OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWMMODE1,
|
||||
OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWMMODE2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {}
|
||||
|
||||
pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {}
|
||||
|
||||
pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {}
|
||||
|
||||
pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {}
|
||||
|
||||
pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {}
|
||||
pub trait CaptureCompare16bitInstance:
|
||||
sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static
|
||||
{
|
||||
}
|
||||
|
||||
pub trait ComplementaryCaptureCompare16bitInstance:
|
||||
sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static
|
||||
{
|
||||
}
|
||||
|
||||
pub trait CaptureCompare32bitInstance:
|
||||
sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static
|
||||
{
|
||||
}
|
||||
|
||||
pin_trait!(Channel1Pin, CaptureCompare16bitInstance);
|
||||
pin_trait!(Channel1ComplementaryPin, CaptureCompare16bitInstance);
|
||||
pin_trait!(Channel2Pin, CaptureCompare16bitInstance);
|
||||
pin_trait!(Channel2ComplementaryPin, CaptureCompare16bitInstance);
|
||||
pin_trait!(Channel3Pin, CaptureCompare16bitInstance);
|
||||
pin_trait!(Channel3ComplementaryPin, CaptureCompare16bitInstance);
|
||||
pin_trait!(Channel4Pin, CaptureCompare16bitInstance);
|
||||
pin_trait!(Channel4ComplementaryPin, CaptureCompare16bitInstance);
|
||||
pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance);
|
||||
pin_trait!(BreakInputPin, CaptureCompare16bitInstance);
|
||||
pin_trait!(BreakInputComparator1Pin, CaptureCompare16bitInstance);
|
||||
pin_trait!(BreakInputComparator2Pin, CaptureCompare16bitInstance);
|
||||
pin_trait!(BreakInput2Pin, CaptureCompare16bitInstance);
|
||||
pin_trait!(BreakInput2Comparator1Pin, CaptureCompare16bitInstance);
|
||||
pin_trait!(BreakInput2Comparator2Pin, CaptureCompare16bitInstance);
|
||||
|
||||
#[allow(unused)]
|
||||
macro_rules! impl_basic_16bit_timer {
|
||||
@ -140,33 +251,94 @@ macro_rules! impl_32bit_timer {
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
macro_rules! impl_compare_capable_16bit {
|
||||
($inst:ident) => {
|
||||
impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
|
||||
fn enable_outputs(&mut self, _enable: bool) {}
|
||||
|
||||
fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) {
|
||||
use sealed::GeneralPurpose16bitInstance;
|
||||
let r = Self::regs_gp16();
|
||||
let raw_channel: usize = channel.raw();
|
||||
r.ccmr_output(raw_channel / 2)
|
||||
.modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
|
||||
}
|
||||
|
||||
fn enable_channel(&mut self, channel: Channel, enable: bool) {
|
||||
use sealed::GeneralPurpose16bitInstance;
|
||||
Self::regs_gp16()
|
||||
.ccer()
|
||||
.modify(|w| w.set_cce(channel.raw(), enable));
|
||||
}
|
||||
|
||||
fn set_compare_value(&mut self, channel: Channel, value: u16) {
|
||||
use sealed::GeneralPurpose16bitInstance;
|
||||
Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value));
|
||||
}
|
||||
|
||||
fn get_max_compare_value(&self) -> u16 {
|
||||
use sealed::GeneralPurpose16bitInstance;
|
||||
Self::regs_gp16().arr().read().arr()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
foreach_interrupt! {
|
||||
($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => {
|
||||
impl_basic_16bit_timer!($inst, $irq);
|
||||
|
||||
impl Basic16bitInstance for crate::peripherals::$inst {
|
||||
}
|
||||
impl Basic16bitInstance for crate::peripherals::$inst {}
|
||||
};
|
||||
($inst:ident, timer, TIM_GP16, UP, $irq:ident) => {
|
||||
impl_basic_16bit_timer!($inst, $irq);
|
||||
|
||||
impl Basic16bitInstance for crate::peripherals::$inst {
|
||||
}
|
||||
impl_compare_capable_16bit!($inst);
|
||||
impl Basic16bitInstance for crate::peripherals::$inst {}
|
||||
impl GeneralPurpose16bitInstance for crate::peripherals::$inst {}
|
||||
impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
|
||||
|
||||
impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
|
||||
fn regs_gp16() -> crate::pac::timer::TimGp16 {
|
||||
crate::pac::$inst
|
||||
}
|
||||
}
|
||||
|
||||
impl GeneralPurpose16bitInstance for crate::peripherals::$inst {
|
||||
}
|
||||
};
|
||||
|
||||
($inst:ident, timer, TIM_GP32, UP, $irq:ident) => {
|
||||
impl_basic_16bit_timer!($inst, $irq);
|
||||
impl_32bit_timer!($inst);
|
||||
impl_compare_capable_16bit!($inst);
|
||||
impl Basic16bitInstance for crate::peripherals::$inst {}
|
||||
impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
|
||||
impl CaptureCompare32bitInstance for crate::peripherals::$inst {}
|
||||
impl GeneralPurpose16bitInstance for crate::peripherals::$inst {}
|
||||
impl GeneralPurpose32bitInstance for crate::peripherals::$inst {}
|
||||
|
||||
impl Basic16bitInstance for crate::peripherals::$inst {
|
||||
impl sealed::CaptureCompare32bitInstance for crate::peripherals::$inst {
|
||||
fn set_output_compare_mode(
|
||||
&mut self,
|
||||
channel: Channel,
|
||||
mode: OutputCompareMode,
|
||||
) {
|
||||
use crate::timer::sealed::GeneralPurpose32bitInstance;
|
||||
let raw_channel = channel.raw();
|
||||
Self::regs_gp32().ccmr_output(raw_channel / 2).modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
|
||||
}
|
||||
|
||||
fn enable_channel(&mut self, channel: Channel, enable: bool) {
|
||||
use crate::timer::sealed::GeneralPurpose32bitInstance;
|
||||
Self::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), enable));
|
||||
}
|
||||
|
||||
fn set_compare_value(&mut self, channel: Channel, value: u32) {
|
||||
use crate::timer::sealed::GeneralPurpose32bitInstance;
|
||||
Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value));
|
||||
}
|
||||
|
||||
fn get_max_compare_value(&self) -> u32 {
|
||||
use crate::timer::sealed::GeneralPurpose32bitInstance;
|
||||
Self::regs_gp32().arr().read().arr() as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
|
||||
@ -174,21 +346,16 @@ foreach_interrupt! {
|
||||
unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl GeneralPurpose16bitInstance for crate::peripherals::$inst {
|
||||
}
|
||||
|
||||
impl_32bit_timer!($inst);
|
||||
|
||||
impl GeneralPurpose32bitInstance for crate::peripherals::$inst {
|
||||
}
|
||||
};
|
||||
|
||||
($inst:ident, timer, TIM_ADV, UP, $irq:ident) => {
|
||||
impl_basic_16bit_timer!($inst, $irq);
|
||||
|
||||
impl Basic16bitInstance for crate::peripherals::$inst {
|
||||
}
|
||||
impl Basic16bitInstance for crate::peripherals::$inst {}
|
||||
impl GeneralPurpose16bitInstance for crate::peripherals::$inst {}
|
||||
impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
|
||||
impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
|
||||
impl AdvancedControlInstance for crate::peripherals::$inst {}
|
||||
|
||||
impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
|
||||
fn regs_gp16() -> crate::pac::timer::TimGp16 {
|
||||
@ -196,16 +363,70 @@ foreach_interrupt! {
|
||||
}
|
||||
}
|
||||
|
||||
impl GeneralPurpose16bitInstance for crate::peripherals::$inst {
|
||||
}
|
||||
|
||||
impl sealed::AdvancedControlInstance for crate::peripherals::$inst {
|
||||
fn regs_advanced() -> crate::pac::timer::TimAdv {
|
||||
crate::pac::$inst
|
||||
}
|
||||
}
|
||||
|
||||
impl AdvancedControlInstance for crate::peripherals::$inst {
|
||||
impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
|
||||
fn enable_outputs(&mut self, enable: bool) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
let r = Self::regs_advanced();
|
||||
r.bdtr().modify(|w| w.set_moe(enable));
|
||||
}
|
||||
|
||||
fn set_output_compare_mode(
|
||||
&mut self,
|
||||
channel: Channel,
|
||||
mode: OutputCompareMode,
|
||||
) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
let r = Self::regs_advanced();
|
||||
let raw_channel: usize = channel.raw();
|
||||
r.ccmr_output(raw_channel / 2)
|
||||
.modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
|
||||
}
|
||||
|
||||
fn enable_channel(&mut self, channel: Channel, enable: bool) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced()
|
||||
.ccer()
|
||||
.modify(|w| w.set_cce(channel.raw(), enable));
|
||||
}
|
||||
|
||||
fn set_compare_value(&mut self, channel: Channel, value: u16) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced()
|
||||
.ccr(channel.raw())
|
||||
.modify(|w| w.set_ccr(value));
|
||||
}
|
||||
|
||||
fn get_max_compare_value(&self) -> u16 {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced().arr().read().arr()
|
||||
}
|
||||
}
|
||||
|
||||
impl sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {
|
||||
fn set_dead_time_clock_division(&mut self, value: vals::Ckd) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced().cr1().modify(|w| w.set_ckd(value));
|
||||
}
|
||||
|
||||
fn set_dead_time_value(&mut self, value: u8) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value));
|
||||
}
|
||||
|
||||
fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) {
|
||||
use crate::timer::sealed::AdvancedControlInstance;
|
||||
Self::regs_advanced()
|
||||
.ccer()
|
||||
.modify(|w| w.set_ccne(channel.raw(), enable));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
|
||||
use super::*;
|
||||
#[allow(unused_imports)]
|
||||
use crate::gpio::sealed::{AFType, Pin};
|
||||
use crate::gpio::AnyPin;
|
||||
use crate::gpio::{AnyPin, OutputType};
|
||||
use crate::time::Hertz;
|
||||
use crate::Peripheral;
|
||||
|
||||
@ -22,11 +22,11 @@ pub struct PwmPin<'d, Perip, Channel> {
|
||||
macro_rules! channel_impl {
|
||||
($new_chx:ident, $channel:ident, $pin_trait:ident) => {
|
||||
impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> {
|
||||
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self {
|
||||
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd, output_type: OutputType) -> Self {
|
||||
into_ref!(pin);
|
||||
critical_section::with(|_| {
|
||||
pin.set_low();
|
||||
pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
|
||||
pin.set_as_af(pin.af_num(), output_type.into());
|
||||
#[cfg(gpio_v2)]
|
||||
pin.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
});
|
@ -2,7 +2,7 @@ use core::future::poll_fn;
|
||||
use core::slice;
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_hal_common::atomic_ring_buffer::RingBuffer;
|
||||
use embassy_hal_internal::atomic_ring_buffer::RingBuffer;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use super::*;
|
||||
|
@ -5,8 +5,8 @@ use core::marker::PhantomData;
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_hal_common::drop::OnDrop;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_hal_internal::drop::OnDrop;
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use futures::future::{select, Either};
|
||||
|
||||
use crate::dma::{NoDma, Transfer};
|
||||
@ -857,7 +857,7 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
|
||||
"Using {} oversampling, desired baudrate: {}, actual baudrate: {}",
|
||||
oversampling,
|
||||
config.baudrate,
|
||||
pclk_freq.0 / div
|
||||
(pclk_freq.0 * mul as u32) / div
|
||||
);
|
||||
|
||||
r.cr2().write(|w| {
|
||||
|
@ -2,7 +2,7 @@ use core::future::poll_fn;
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_hal_common::PeripheralRef;
|
||||
use embassy_hal_internal::PeripheralRef;
|
||||
use futures::future::{select, Either};
|
||||
|
||||
use super::{clear_interrupt_flags, rdr, sr, BasicInstance, Error, UartRx};
|
||||
|
@ -5,7 +5,7 @@ use core::marker::PhantomData;
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_hal_common::into_ref;
|
||||
use embassy_hal_internal::into_ref;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use embassy_usb_driver as driver;
|
||||
use embassy_usb_driver::{
|
||||
|
@ -3,7 +3,7 @@ use core::marker::PhantomData;
|
||||
use core::sync::atomic::{AtomicBool, AtomicU16, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_hal_common::{into_ref, Peripheral};
|
||||
use embassy_hal_internal::{into_ref, Peripheral};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use embassy_usb_driver::{
|
||||
self, Bus as _, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use embassy_hal_common::{into_ref, Peripheral};
|
||||
use embassy_hal_internal::{into_ref, Peripheral};
|
||||
use stm32_metapac::iwdg::vals::{Key, Pr};
|
||||
|
||||
use crate::rcc::LSI_FREQ;
|
||||
|
Reference in New Issue
Block a user