for InterruptHandl
let r = T::regs();
let s = T::state();
- if r.events_endrx.read().bits() != 0 {
+ let endrx = r.events_endrx.read().bits();
+ let error = r.events_error.read().bits();
+ if endrx != 0 || error != 0 {
s.endrx_waker.wake();
- r.intenclr.write(|w| w.endrx().clear());
+ if endrx != 0 {
+ r.intenclr.write(|w| w.endrx().clear());
+ }
+ if error != 0 {
+ r.intenclr.write(|w| w.error().clear());
+ }
}
if r.events_endtx.read().bits() != 0 {
s.endtx_waker.wake();
@@ -486,6 +532,14 @@ impl<'d, T: Instance> UarteRx<'d, T> {
Self::new_inner(uarte, rxd.map_into(), Some(rts.map_into()), config)
}
+ /// Check for errors and clear the error register if an error occured.
+ fn check_and_clear_errors(&mut self) -> Result<(), Error> {
+ let r = T::regs();
+ let err_bits = r.errorsrc.read().bits();
+ r.errorsrc.write(|w| unsafe { w.bits(err_bits) });
+ ErrorSource::from_bits_truncate(err_bits).check()
+ }
+
fn new_inner(
uarte: impl Peripheral + 'd,
rxd: PeripheralRef<'d, AnyPin>,
@@ -572,7 +626,7 @@ impl<'d, T: Instance> UarteRx<'d, T> {
/// Read bytes until the buffer is filled.
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
- if buffer.len() == 0 {
+ if buffer.is_empty() {
return Ok(());
}
if buffer.len() > EASY_DMA_SIZE {
@@ -588,8 +642,13 @@ impl<'d, T: Instance> UarteRx<'d, T> {
let drop = OnDrop::new(move || {
trace!("read drop: stopping");
- r.intenclr.write(|w| w.endrx().clear());
+ r.intenclr.write(|w| {
+ w.endrx().clear();
+ w.error().clear()
+ });
r.events_rxto.reset();
+ r.events_error.reset();
+ r.errorsrc.reset();
r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
while r.events_endrx.read().bits() == 0 {}
@@ -601,17 +660,26 @@ impl<'d, T: Instance> UarteRx<'d, T> {
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
r.events_endrx.reset();
- r.intenset.write(|w| w.endrx().set());
+ r.events_error.reset();
+ r.intenset.write(|w| {
+ w.endrx().set();
+ w.error().set()
+ });
compiler_fence(Ordering::SeqCst);
trace!("startrx");
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
- poll_fn(|cx| {
+ let result = poll_fn(|cx| {
s.endrx_waker.register(cx.waker());
+
+ if let Err(e) = self.check_and_clear_errors() {
+ r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
+ return Poll::Ready(Err(e));
+ }
if r.events_endrx.read().bits() != 0 {
- return Poll::Ready(());
+ return Poll::Ready(Ok(()));
}
Poll::Pending
})
@@ -621,7 +689,7 @@ impl<'d, T: Instance> UarteRx<'d, T> {
r.events_rxstarted.reset();
drop.defuse();
- Ok(())
+ result
}
/// Read bytes until the buffer is filled.
@@ -642,19 +710,23 @@ impl<'d, T: Instance> UarteRx<'d, T> {
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
r.events_endrx.reset();
- r.intenclr.write(|w| w.endrx().clear());
+ r.events_error.reset();
+ r.intenclr.write(|w| {
+ w.endrx().clear();
+ w.error().clear()
+ });
compiler_fence(Ordering::SeqCst);
trace!("startrx");
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
- while r.events_endrx.read().bits() == 0 {}
+ while r.events_endrx.read().bits() == 0 && r.events_error.read().bits() == 0 {}
compiler_fence(Ordering::SeqCst);
r.events_rxstarted.reset();
- Ok(())
+ self.check_and_clear_errors()
}
}
@@ -721,8 +793,12 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> {
let drop = OnDrop::new(|| {
self.timer.stop();
- r.intenclr.write(|w| w.endrx().clear());
+ r.intenclr.write(|w| {
+ w.endrx().clear();
+ w.error().clear()
+ });
r.events_rxto.reset();
+ r.events_error.reset();
r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
while r.events_endrx.read().bits() == 0 {}
@@ -732,17 +808,27 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> {
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
r.events_endrx.reset();
- r.intenset.write(|w| w.endrx().set());
+ r.events_error.reset();
+ r.intenset.write(|w| {
+ w.endrx().set();
+ w.error().set()
+ });
compiler_fence(Ordering::SeqCst);
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
- poll_fn(|cx| {
+ let result = poll_fn(|cx| {
s.endrx_waker.register(cx.waker());
- if r.events_endrx.read().bits() != 0 {
- return Poll::Ready(());
+
+ if let Err(e) = self.rx.check_and_clear_errors() {
+ r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
+ return Poll::Ready(Err(e));
}
+ if r.events_endrx.read().bits() != 0 {
+ return Poll::Ready(Ok(()));
+ }
+
Poll::Pending
})
.await;
@@ -755,7 +841,7 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> {
drop.defuse();
- Ok(n)
+ result.map(|_| n)
}
/// Read bytes until the buffer is filled, or the line becomes idle.
@@ -780,13 +866,17 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> {
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
r.events_endrx.reset();
- r.intenclr.write(|w| w.endrx().clear());
+ r.events_error.reset();
+ r.intenclr.write(|w| {
+ w.endrx().clear();
+ w.error().clear()
+ });
compiler_fence(Ordering::SeqCst);
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
- while r.events_endrx.read().bits() == 0 {}
+ while r.events_endrx.read().bits() == 0 && r.events_error.read().bits() == 0 {}
compiler_fence(Ordering::SeqCst);
let n = r.rxd.amount.read().amount().bits() as usize;
@@ -794,7 +884,7 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> {
self.timer.stop();
r.events_rxstarted.reset();
- Ok(n)
+ self.rx.check_and_clear_errors().map(|_| n)
}
}
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 87815c63a..eb67404d3 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -68,7 +68,7 @@ rand_core = "0.6.3"
sdio-host = "0.5.0"
critical-section = "1.1"
#stm32-metapac = { version = "15" }
-stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-36a3262735a169e31b702bcb0ac6c0067c3f078e" }
+stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-028efe4e6e0719b661cbdf8ffda3341e4d63d0df" }
vcell = "0.1.3"
bxcan = "0.7.0"
nb = "1.0.0"
@@ -89,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] }
proc-macro2 = "1.0.36"
quote = "1.0.15"
#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
-stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-36a3262735a169e31b702bcb0ac6c0067c3f078e", default-features = false, features = ["metadata"]}
+stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-028efe4e6e0719b661cbdf8ffda3341e4d63d0df", default-features = false, features = ["metadata"]}
[features]
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index d21c3053f..51b4b5fcc 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -8,6 +8,7 @@
#[cfg_attr(adc_f3, path = "f3.rs")]
#[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")]
#[cfg_attr(adc_v1, path = "v1.rs")]
+#[cfg_attr(adc_l0, path = "v1.rs")]
#[cfg_attr(adc_v2, path = "v2.rs")]
#[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")]
#[cfg_attr(adc_v4, path = "v4.rs")]
@@ -36,15 +37,15 @@ pub struct Adc<'d, T: Instance> {
}
pub(crate) mod sealed {
- #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))]
+ #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
use embassy_sync::waitqueue::AtomicWaker;
- #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))]
+ #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
pub struct State {
pub waker: AtomicWaker,
}
- #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))]
+ #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
impl State {
pub const fn new() -> Self {
Self {
@@ -59,14 +60,14 @@ pub(crate) mod sealed {
pub trait Instance: InterruptableInstance {
fn regs() -> crate::pac::adc::Adc;
- #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_f3_v1_1, adc_g0)))]
+ #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))]
fn common_regs() -> crate::pac::adccommon::AdcCommon;
- #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))]
+ #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
fn state() -> &'static State;
}
pub trait AdcPin {
- #[cfg(any(adc_v1, adc_v2))]
+ #[cfg(any(adc_v1, adc_l0, adc_v2))]
fn set_as_analog(&mut self) {}
fn channel(&self) -> u8;
@@ -78,10 +79,10 @@ pub(crate) mod sealed {
}
/// ADC instance.
-#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))]
+#[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))]
pub trait Instance: sealed::Instance + crate::Peripheral {}
/// ADC instance.
-#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))]
+#[cfg(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))]
pub trait Instance: sealed::Instance + crate::Peripheral
+ crate::rcc::RccPeripheral {}
/// ADC pin.
@@ -96,12 +97,12 @@ foreach_adc!(
crate::pac::$inst
}
- #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_f3_v1_1, adc_g0)))]
+ #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))]
fn common_regs() -> crate::pac::adccommon::AdcCommon {
return crate::pac::$common_inst
}
- #[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))]
+ #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
fn state() -> &'static sealed::State {
static STATE: sealed::State = sealed::State::new();
&STATE
@@ -125,7 +126,7 @@ macro_rules! impl_adc_pin {
impl crate::adc::AdcPin for crate::peripherals::$pin {}
impl crate::adc::sealed::AdcPin for crate::peripherals::$pin {
- #[cfg(any(adc_v1, adc_v2))]
+ #[cfg(any(adc_v1, adc_l0, adc_v2))]
fn set_as_analog(&mut self) {
::set_as_analog(self);
}
diff --git a/embassy-stm32/src/adc/resolution.rs b/embassy-stm32/src/adc/resolution.rs
index 9513e1df7..0e6c45c65 100644
--- a/embassy-stm32/src/adc/resolution.rs
+++ b/embassy-stm32/src/adc/resolution.rs
@@ -1,6 +1,6 @@
/// ADC resolution
#[allow(missing_docs)]
-#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))]
+#[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Resolution {
@@ -25,7 +25,7 @@ pub enum Resolution {
impl Default for Resolution {
fn default() -> Self {
- #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))]
+ #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))]
{
Self::TwelveBit
}
@@ -46,7 +46,7 @@ impl From for crate::pac::adc::vals::Res {
Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT,
Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT,
Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT,
- #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))]
+ #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))]
Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT,
}
}
@@ -65,7 +65,7 @@ impl Resolution {
Resolution::TwelveBit => (1 << 12) - 1,
Resolution::TenBit => (1 << 10) - 1,
Resolution::EightBit => (1 << 8) - 1,
- #[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))]
+ #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1))]
Resolution::SixBit => (1 << 6) - 1,
}
}
diff --git a/embassy-stm32/src/adc/sample_time.rs b/embassy-stm32/src/adc/sample_time.rs
index 5a06f1a5a..f4b22b462 100644
--- a/embassy-stm32/src/adc/sample_time.rs
+++ b/embassy-stm32/src/adc/sample_time.rs
@@ -83,7 +83,7 @@ impl_sample_time!(
)
);
-#[cfg(adc_g0)]
+#[cfg(any(adc_l0, adc_g0))]
impl_sample_time!(
"1.5",
Cycles1_5,
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs
index 852b027df..37115dfab 100644
--- a/embassy-stm32/src/adc/v1.rs
+++ b/embassy-stm32/src/adc/v1.rs
@@ -4,6 +4,8 @@ use core::task::Poll;
use embassy_hal_internal::into_ref;
use embedded_hal_02::blocking::delay::DelayUs;
+#[cfg(adc_l0)]
+use stm32_metapac::adc::vals::Ckmode;
use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
use crate::interrupt::typelevel::Interrupt;
@@ -30,8 +32,13 @@ impl interrupt::typelevel::Handler for InterruptHandl
}
}
+#[cfg(not(adc_l0))]
pub struct Vbat;
+
+#[cfg(not(adc_l0))]
impl AdcPin for Vbat {}
+
+#[cfg(not(adc_l0))]
impl super::sealed::AdcPin for Vbat {
fn channel(&self) -> u8 {
18
@@ -69,9 +76,18 @@ impl<'d, T: Instance> Adc<'d, T> {
// tstab = 14 * 1/fadc
delay.delay_us(1);
+ // set default PCKL/2 on L0s because HSI is disabled in the default clock config
+ #[cfg(adc_l0)]
+ T::regs().cfgr2().modify(|reg| reg.set_ckmode(Ckmode::PCLK_DIV2));
+
// A.7.1 ADC calibration code example
T::regs().cfgr1().modify(|reg| reg.set_dmaen(false));
T::regs().cr().modify(|reg| reg.set_adcal(true));
+
+ #[cfg(adc_l0)]
+ while !T::regs().isr().read().eocal() {}
+
+ #[cfg(not(adc_l0))]
while T::regs().cr().read().adcal() {}
// A.7.2 ADC enable sequence code example
@@ -97,6 +113,7 @@ impl<'d, T: Instance> Adc<'d, T> {
}
}
+ #[cfg(not(adc_l0))]
pub fn enable_vbat(&self, _delay: &mut impl DelayUs) -> Vbat {
// SMP must be ≥ 56 ADC clock cycles when using HSI14.
//
@@ -133,6 +150,12 @@ impl<'d, T: Instance> Adc<'d, T> {
T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
}
+ #[cfg(adc_l0)]
+ pub fn set_ckmode(&mut self, ckmode: Ckmode) {
+ // set ADC clock mode
+ T::regs().cfgr2().modify(|reg| reg.set_ckmode(ckmode));
+ }
+
pub async fn read(&mut self, pin: &mut impl AdcPin) -> u16 {
let channel = pin.channel();
pin.set_as_analog();
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index a2b83716d..077cfdcd9 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -664,6 +664,13 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
}
+ /// Write elements directly to the raw buffer.
+ /// This can be used to fill the buffer before starting the DMA transfer.
+ #[allow(dead_code)]
+ pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> {
+ self.ringbuf.write_immediate(buf)
+ }
+
/// Write elements to the ring buffer
/// Return a tuple of the length written and the length remaining in the buffer
pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> {
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index 16d02f273..ef9bb3d78 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -934,6 +934,13 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
}
+ /// Write elements directly to the raw buffer.
+ /// This can be used to fill the buffer before starting the DMA transfer.
+ #[allow(dead_code)]
+ pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> {
+ self.ringbuf.write_immediate(buf)
+ }
+
/// Write elements from the ring buffer
/// Return a tuple of the length written and the length remaining in the buffer
pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> {
diff --git a/embassy-stm32/src/dma/ringbuffer.rs b/embassy-stm32/src/dma/ringbuffer.rs
index c9f7a3026..23f1d67d5 100644
--- a/embassy-stm32/src/dma/ringbuffer.rs
+++ b/embassy-stm32/src/dma/ringbuffer.rs
@@ -37,6 +37,7 @@ pub struct ReadableDmaRingBuffer<'a, W: Word> {
}
#[derive(Debug, PartialEq)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct OverrunError;
pub trait DmaCtrl {
@@ -263,6 +264,17 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
self.cap() - dma.get_remaining_transfers()
}
+ /// Write elements directly to the buffer. This must be done before the DMA is started
+ /// or after the buffer has been cleared using `clear()`.
+ pub fn write_immediate(&mut self, buffer: &[W]) -> Result<(usize, usize), OverrunError> {
+ if self.end != 0 {
+ return Err(OverrunError);
+ }
+ let written = self.copy_from(buffer, 0..self.cap());
+ self.end = written % self.cap();
+ Ok((written, self.cap() - written))
+ }
+
/// Write an exact number of elements to the ringbuffer.
pub async fn write_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result {
let mut written_data = 0;
diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs
index ae395d568..743925e17 100644
--- a/embassy-stm32/src/flash/h7.rs
+++ b/embassy-stm32/src/flash/h7.rs
@@ -77,12 +77,12 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
}
}
- bank.cr().write(|w| w.set_pg(false));
-
cortex_m::asm::isb();
cortex_m::asm::dsb();
fence(Ordering::SeqCst);
+ bank.cr().write(|w| w.set_pg(false));
+
res.unwrap()
}
@@ -100,6 +100,10 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
w.set_start(true);
});
+ cortex_m::asm::isb();
+ cortex_m::asm::dsb();
+ fence(Ordering::SeqCst);
+
let ret: Result<(), Error> = blocking_wait_ready(bank);
bank.cr().modify(|w| w.set_ser(false));
bank_clear_all_err(bank);
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index 9ac2115f0..352e10816 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -721,7 +721,7 @@ fn init_pll(num: usize, config: Option, input: &PllInput) -> PllOutput {
} else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk) {
Pllvcosel::WIDEVCO
} else {
- panic!("pll vco_clk out of range: {} mhz", vco_clk.0)
+ panic!("pll vco_clk out of range: {} hz", vco_clk.0)
};
let p = config.divp.map(|div| {
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index 320b29ddb..29ff4a736 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -14,7 +14,7 @@ use crate::pac::timer::vals;
use crate::rcc::sealed::RccPeripheral;
#[cfg(feature = "low-power")]
use crate::rtc::Rtc;
-use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance};
+use crate::timer::sealed::{CoreInstance, GeneralPurpose16bitInstance as Instance};
use crate::{interrupt, peripherals};
// NOTE regarding ALARM_COUNT:
@@ -234,8 +234,8 @@ impl RtcDriver {
w.set_ccie(0, true);
});
- ::Interrupt::unpend();
- unsafe { ::Interrupt::enable() };
+ ::Interrupt::unpend();
+ unsafe { ::Interrupt::enable() };
r.cr1().modify(|w| w.set_cen(true));
}
@@ -251,7 +251,7 @@ impl RtcDriver {
// Clear all interrupt flags. Bits in SR are "write 0 to clear", so write the bitwise NOT.
// Other approaches such as writing all zeros, or RMWing won't work, they can
// miss interrupts.
- r.sr().write_value(regs::SrGp(!sr.0));
+ r.sr().write_value(regs::SrGp16(!sr.0));
// Overflow
if sr.uif() {
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index eddce0404..72f1ec864 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -23,7 +23,7 @@ pub struct ComplementaryPwmPin<'d, T, C> {
macro_rules! complementary_channel_impl {
($new_chx:ident, $channel:ident, $pin_trait:ident) => {
- impl<'d, T: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, T, $channel> {
+ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwmPin<'d, T, $channel> {
#[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")]
pub fn $new_chx(pin: impl Peripheral> + 'd, output_type: OutputType) -> Self {
into_ref!(pin);
@@ -84,14 +84,13 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
this.inner.enable_outputs();
- this.inner
- .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1);
- this.inner
- .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1);
- this.inner
- .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1);
- this.inner
- .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
+ [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
+ .iter()
+ .for_each(|&channel| {
+ this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1);
+ this.inner.set_output_compare_preload(channel, true);
+ });
+
this
}
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index 210bf7153..0118395a7 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -1,5 +1,31 @@
//! Timers, PWM, quadrature decoder.
+//! Timer inheritance
+
+// sealed:
+//
+// Core -------------------------> 1CH -------------------------> 1CH_CMP
+// | | ^ |
+// +--> Basic_NoCr2 --> Basic +--> 2CH --> GP16 --> GP32 | +--> 2CH_CMP --> ADV
+// | | | ^ | | ^ ^
+// | | +------|--|--------------|-----------+ |
+// | +--------------------+ +--------------|-----------|---------+
+// | | | |
+// | +--------------------------------------|-----------+
+// +----------------------------------------------------+
+
+//! BasicInstance --> CaptureCompare16bitInstance --+--> ComplementaryCaptureCompare16bitInstance
+//! |
+//! +--> CaptureCompare32bitInstance
+//!
+//! mapping:
+//!
+//! BasicInstance --> Basic Timer
+//! CaptureCompare16bitInstance --> 1-channel Timer, 2-channel Timer, General Purpose 16-bit Timer
+//! CaptureCompare32bitInstance --> General Purpose 32-bit Timer
+//! ComplementaryCaptureCompare16bitInstance --> 1-channel with one complentary Timer, 2-channel with one complentary Timer, Advance Control Timer
+
+#[cfg(not(stm32l0))]
pub mod complementary_pwm;
pub mod qei;
pub mod simple_pwm;
@@ -19,32 +45,32 @@ pub mod low_level {
pub(crate) mod sealed {
use super::*;
- /// Basic 16-bit timer instance.
- pub trait Basic16bitInstance: RccPeripheral {
+ /// Virtual Core 16-bit timer instance.
+ pub trait CoreInstance: RccPeripheral {
/// Interrupt for this timer.
type Interrupt: interrupt::typelevel::Interrupt;
- /// Get access to the basic 16bit timer registers.
+ /// Get access to the virutal core 16bit timer registers.
///
/// Note: This works even if the timer is more capable, because registers
/// for the less capable timers are a subset. This allows writing a driver
/// for a given set of capabilities, and having it transparently work with
/// more capable timers.
- fn regs() -> crate::pac::timer::TimBasic;
+ fn regs_core() -> crate::pac::timer::TimCore;
/// Start the timer.
fn start(&mut self) {
- Self::regs().cr1().modify(|r| r.set_cen(true));
+ Self::regs_core().cr1().modify(|r| r.set_cen(true));
}
/// Stop the timer.
fn stop(&mut self) {
- Self::regs().cr1().modify(|r| r.set_cen(false));
+ Self::regs_core().cr1().modify(|r| r.set_cen(false));
}
/// Reset the counter value to 0
fn reset(&mut self) {
- Self::regs().cnt().write(|r| r.set_cnt(0));
+ Self::regs_core().cnt().write(|r| r.set_cnt(0));
}
/// Set the frequency of how many times per second the timer counts up to the max value or down to 0.
@@ -64,7 +90,7 @@ pub(crate) mod sealed {
// the timer counts `0..=arr`, we want it to count `0..divide_by`
let arr = unwrap!(u16::try_from(divide_by - 1));
- let regs = Self::regs();
+ let regs = Self::regs_core();
regs.psc().write(|r| r.set_psc(psc));
regs.arr().write(|r| r.set_arr(arr));
@@ -77,7 +103,7 @@ pub(crate) mod sealed {
///
/// Returns whether the update interrupt flag was set.
fn clear_update_interrupt(&mut self) -> bool {
- let regs = Self::regs();
+ let regs = Self::regs_core();
let sr = regs.sr().read();
if sr.uif() {
regs.sr().modify(|r| {
@@ -91,29 +117,19 @@ pub(crate) mod sealed {
/// Enable/disable the update interrupt.
fn enable_update_interrupt(&mut self, enable: bool) {
- Self::regs().dier().modify(|r| r.set_uie(enable));
- }
-
- /// Enable/disable the update dma.
- fn enable_update_dma(&mut self, enable: bool) {
- Self::regs().dier().modify(|r| r.set_ude(enable));
- }
-
- /// Get the update dma enable/disable state.
- fn get_update_dma_state(&self) -> bool {
- Self::regs().dier().read().ude()
+ Self::regs_core().dier().modify(|r| r.set_uie(enable));
}
/// Enable/disable autoreload preload.
fn set_autoreload_preload(&mut self, enable: bool) {
- Self::regs().cr1().modify(|r| r.set_arpe(enable));
+ Self::regs_core().cr1().modify(|r| r.set_arpe(enable));
}
/// Get the timer frequency.
fn get_frequency(&self) -> Hertz {
let timer_f = Self::frequency();
- let regs = Self::regs();
+ let regs = Self::regs_core();
let arr = regs.arr().read().arr();
let psc = regs.psc().read().psc();
@@ -121,8 +137,72 @@ pub(crate) mod sealed {
}
}
+ /// Virtual Basic without CR2 16-bit timer instance.
+ pub trait BasicNoCr2Instance: CoreInstance {
+ /// Get access to the Baisc 16bit timer registers.
+ ///
+ /// Note: This works even if the timer is more capable, because registers
+ /// for the less capable timers are a subset. This allows writing a driver
+ /// for a given set of capabilities, and having it transparently work with
+ /// more capable timers.
+ fn regs_basic_no_cr2() -> crate::pac::timer::TimBasicNoCr2;
+
+ /// Enable/disable the update dma.
+ fn enable_update_dma(&mut self, enable: bool) {
+ Self::regs_basic_no_cr2().dier().modify(|r| r.set_ude(enable));
+ }
+
+ /// Get the update dma enable/disable state.
+ fn get_update_dma_state(&self) -> bool {
+ Self::regs_basic_no_cr2().dier().read().ude()
+ }
+ }
+
+ /// Basic 16-bit timer instance.
+ pub trait BasicInstance: BasicNoCr2Instance {
+ /// Get access to the Baisc 16bit timer registers.
+ ///
+ /// Note: This works even if the timer is more capable, because registers
+ /// for the less capable timers are a subset. This allows writing a driver
+ /// for a given set of capabilities, and having it transparently work with
+ /// more capable timers.
+ fn regs_basic() -> crate::pac::timer::TimBasic;
+ }
+
+ /// Gneral-purpose 1 channel 16-bit timer instance.
+ pub trait GeneralPurpose1ChannelInstance: CoreInstance {
+ /// Get access to the general purpose 1 channel 16bit timer registers.
+ ///
+ /// Note: This works even if the timer is more capable, because registers
+ /// for the less capable timers are a subset. This allows writing a driver
+ /// for a given set of capabilities, and having it transparently work with
+ /// more capable timers.
+ fn regs_1ch() -> crate::pac::timer::Tim1ch;
+
+ /// Set clock divider.
+ fn set_clock_division(&mut self, ckd: vals::Ckd) {
+ Self::regs_1ch().cr1().modify(|r| r.set_ckd(ckd));
+ }
+
+ /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
+ fn get_max_compare_value(&self) -> u16 {
+ Self::regs_1ch().arr().read().arr()
+ }
+ }
+
+ /// Gneral-purpose 1 channel 16-bit timer instance.
+ pub trait GeneralPurpose2ChannelInstance: GeneralPurpose1ChannelInstance {
+ /// Get access to the general purpose 2 channel 16bit timer registers.
+ ///
+ /// Note: This works even if the timer is more capable, because registers
+ /// for the less capable timers are a subset. This allows writing a driver
+ /// for a given set of capabilities, and having it transparently work with
+ /// more capable timers.
+ fn regs_2ch() -> crate::pac::timer::Tim2ch;
+ }
+
/// Gneral-purpose 16-bit timer instance.
- pub trait GeneralPurpose16bitInstance: Basic16bitInstance {
+ pub trait GeneralPurpose16bitInstance: BasicInstance + GeneralPurpose2ChannelInstance {
/// Get access to the general purpose 16bit timer registers.
///
/// Note: This works even if the timer is more capable, because registers
@@ -135,7 +215,7 @@ pub(crate) mod sealed {
fn set_counting_mode(&mut self, mode: CountingMode) {
let (cms, dir) = mode.into();
- let timer_enabled = Self::regs().cr1().read().cen();
+ let timer_enabled = Self::regs_core().cr1().read().cen();
// Changing from edge aligned to center aligned (and vice versa) is not allowed while the timer is running.
// Changing direction is discouraged while the timer is running.
assert!(!timer_enabled);
@@ -150,62 +230,8 @@ pub(crate) mod sealed {
(cr1.cms(), cr1.dir()).into()
}
- /// Set clock divider.
- fn set_clock_division(&mut self, ckd: vals::Ckd) {
- Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd));
- }
- }
-
- /// Gneral-purpose 32-bit timer instance.
- pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance {
- /// Get access to the general purpose 32bit timer registers.
- ///
- /// Note: This works even if the timer is more capable, because registers
- /// for the less capable timers are a subset. This allows writing a driver
- /// for a given set of capabilities, and having it transparently work with
- /// more capable timers.
- fn regs_gp32() -> crate::pac::timer::TimGp32;
-
- /// Set timer frequency.
- fn set_frequency(&mut self, frequency: Hertz) {
- let f = frequency.0;
- assert!(f > 0);
- let timer_f = Self::frequency().0;
- let pclk_ticks_per_timer_period = (timer_f / f) as u64;
- let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into());
- let arr: u32 = unwrap!((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into());
-
- let regs = Self::regs_gp32();
- regs.psc().write(|r| r.set_psc(psc));
- regs.arr().write(|r| r.set_arr(arr));
-
- regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY));
- regs.egr().write(|r| r.set_ug(true));
- regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
- }
-
- /// Get timer frequency.
- fn get_frequency(&self) -> Hertz {
- let timer_f = Self::frequency();
-
- let regs = Self::regs_gp32();
- let arr = regs.arr().read().arr();
- let psc = regs.psc().read().psc();
-
- timer_f / arr / (psc + 1)
- }
- }
-
- /// Advanced control timer instance.
- pub trait AdvancedControlInstance: GeneralPurpose16bitInstance {
- /// Get access to the advanced timer registers.
- fn regs_advanced() -> crate::pac::timer::TimAdv;
- }
-
- /// Capture/Compare 16-bit timer instance.
- pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance {
/// Set input capture filter.
- fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) {
+ fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::FilterValue) {
let raw_channel = channel.index();
Self::regs_gp16()
.ccmr_input(raw_channel / 2)
@@ -256,14 +282,11 @@ pub(crate) mod sealed {
});
}
- /// Enable timer outputs.
- fn enable_outputs(&mut self);
-
/// Set output compare mode.
fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) {
- let r = Self::regs_gp16();
let raw_channel: usize = channel.index();
- r.ccmr_output(raw_channel / 2)
+ Self::regs_gp16()
+ .ccmr_output(raw_channel / 2)
.modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
}
@@ -294,11 +317,6 @@ pub(crate) mod sealed {
Self::regs_gp16().ccr(channel.index()).read().ccr()
}
- /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
- fn get_max_compare_value(&self) -> u16 {
- Self::regs_gp16().arr().read().arr()
- }
-
/// Get compare value for a channel.
fn get_compare_value(&self, channel: Channel) -> u16 {
Self::regs_gp16().ccr(channel.index()).read().ccr()
@@ -333,35 +351,46 @@ pub(crate) mod sealed {
}
}
- /// Capture/Compare 16-bit timer instance with complementary pin support.
- pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance {
- /// Set complementary output polarity.
- fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
- Self::regs_advanced()
- .ccer()
- .modify(|w| w.set_ccnp(channel.index(), polarity.into()));
+ #[cfg(not(stm32l0))]
+ /// Gneral-purpose 32-bit timer instance.
+ pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance {
+ /// Get access to the general purpose 32bit timer registers.
+ ///
+ /// Note: This works even if the timer is more capable, because registers
+ /// for the less capable timers are a subset. This allows writing a driver
+ /// for a given set of capabilities, and having it transparently work with
+ /// more capable timers.
+ fn regs_gp32() -> crate::pac::timer::TimGp32;
+
+ /// Set timer frequency.
+ fn set_frequency(&mut self, frequency: Hertz) {
+ let f = frequency.0;
+ assert!(f > 0);
+ let timer_f = Self::frequency().0;
+ let pclk_ticks_per_timer_period = (timer_f / f) as u64;
+ let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into());
+ let arr: u32 = unwrap!((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into());
+
+ let regs = Self::regs_gp32();
+ regs.psc().write(|r| r.set_psc(psc));
+ regs.arr().write(|r| r.set_arr(arr));
+
+ regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY));
+ regs.egr().write(|r| r.set_ug(true));
+ regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
}
- /// Set clock divider for the dead time.
- fn set_dead_time_clock_division(&mut self, value: vals::Ckd) {
- Self::regs_advanced().cr1().modify(|w| w.set_ckd(value));
+ /// Get timer frequency.
+ fn get_frequency(&self) -> Hertz {
+ let timer_f = Self::frequency();
+
+ let regs = Self::regs_gp32();
+ let arr = regs.arr().read().arr();
+ let psc = regs.psc().read().psc();
+
+ timer_f / arr / (psc + 1)
}
- /// Set dead time, as a fraction of the max duty value.
- fn set_dead_time_value(&mut self, value: u8) {
- Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value));
- }
-
- /// Enable/disable a complementary channel.
- fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) {
- Self::regs_advanced()
- .ccer()
- .modify(|w| w.set_ccne(channel.index(), enable));
- }
- }
-
- /// Capture/Compare 32-bit timer instance.
- pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance {
/// Set comapre value for a channel.
fn set_compare_value(&mut self, channel: Channel, value: u32) {
Self::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(value));
@@ -382,6 +411,70 @@ pub(crate) mod sealed {
Self::regs_gp32().ccr(channel.index()).read().ccr()
}
}
+
+ #[cfg(not(stm32l0))]
+ /// Gneral-purpose 1 channel with one complementary 16-bit timer instance.
+ pub trait GeneralPurpose1ChannelComplementaryInstance: BasicNoCr2Instance + GeneralPurpose1ChannelInstance {
+ /// Get access to the general purpose 1 channel with one complementary 16bit timer registers.
+ ///
+ /// Note: This works even if the timer is more capable, because registers
+ /// for the less capable timers are a subset. This allows writing a driver
+ /// for a given set of capabilities, and having it transparently work with
+ /// more capable timers.
+ fn regs_1ch_cmp() -> crate::pac::timer::Tim1chCmp;
+
+ /// Set clock divider for the dead time.
+ fn set_dead_time_clock_division(&mut self, value: vals::Ckd) {
+ Self::regs_1ch_cmp().cr1().modify(|w| w.set_ckd(value));
+ }
+
+ /// Set dead time, as a fraction of the max duty value.
+ fn set_dead_time_value(&mut self, value: u8) {
+ Self::regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value));
+ }
+
+ /// Enable timer outputs.
+ fn enable_outputs(&mut self) {
+ Self::regs_1ch_cmp().bdtr().modify(|w| w.set_moe(true));
+ }
+ }
+
+ #[cfg(not(stm32l0))]
+ /// Gneral-purpose 2 channel with one complementary 16-bit timer instance.
+ pub trait GeneralPurpose2ChannelComplementaryInstance:
+ BasicInstance + GeneralPurpose2ChannelInstance + GeneralPurpose1ChannelComplementaryInstance
+ {
+ /// Get access to the general purpose 2 channel with one complementary 16bit timer registers.
+ ///
+ /// Note: This works even if the timer is more capable, because registers
+ /// for the less capable timers are a subset. This allows writing a driver
+ /// for a given set of capabilities, and having it transparently work with
+ /// more capable timers.
+ fn regs_2ch_cmp() -> crate::pac::timer::Tim2chCmp;
+ }
+
+ #[cfg(not(stm32l0))]
+ /// Advanced control timer instance.
+ pub trait AdvancedControlInstance:
+ GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance
+ {
+ /// Get access to the advanced timer registers.
+ fn regs_advanced() -> crate::pac::timer::TimAdv;
+
+ /// Set complementary output polarity.
+ fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
+ Self::regs_advanced()
+ .ccer()
+ .modify(|w| w.set_ccnp(channel.index(), polarity.into()));
+ }
+
+ /// Enable/disable a complementary channel.
+ fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) {
+ Self::regs_advanced()
+ .ccer()
+ .modify(|w| w.set_ccne(channel.index(), enable));
+ }
+ }
}
/// Timer channel.
@@ -572,61 +665,92 @@ impl From for bool {
}
/// Basic 16-bit timer instance.
-pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {}
+pub trait BasicInstance: sealed::BasicInstance + sealed::BasicNoCr2Instance + sealed::CoreInstance + 'static {}
-/// Gneral-purpose 16-bit timer instance.
-pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + Basic16bitInstance + 'static {}
-
-/// Gneral-purpose 32-bit timer instance.
-pub trait GeneralPurpose32bitInstance:
- sealed::GeneralPurpose32bitInstance + GeneralPurpose16bitInstance + 'static
-{
-}
-
-/// Advanced control timer instance.
-pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + GeneralPurpose16bitInstance + 'static {}
-
-/// Capture/Compare 16-bit timer instance.
+// It's just a General-purpose 16-bit timer instance.
+/// Capture Compare timer instance.
pub trait CaptureCompare16bitInstance:
- sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static
+ BasicInstance
+ + sealed::GeneralPurpose2ChannelInstance
+ + sealed::GeneralPurpose1ChannelInstance
+ + sealed::GeneralPurpose16bitInstance
+ + 'static
{
}
-/// Capture/Compare 16-bit timer instance with complementary pin support.
-pub trait ComplementaryCaptureCompare16bitInstance:
- sealed::ComplementaryCaptureCompare16bitInstance + CaptureCompare16bitInstance + AdvancedControlInstance + 'static
-{
-}
-
-/// Capture/Compare 32-bit timer instance.
+#[cfg(not(stm32l0))]
+// It's just a General-purpose 32-bit timer instance.
+/// Capture Compare 32-bit timer instance.
pub trait CaptureCompare32bitInstance:
- sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static
+ CaptureCompare16bitInstance + sealed::GeneralPurpose32bitInstance + 'static
+{
+}
+
+#[cfg(not(stm32l0))]
+// It's just a Advanced Control timer instance.
+/// Complementary Capture Compare 32-bit timer instance.
+pub trait ComplementaryCaptureCompare16bitInstance:
+ CaptureCompare16bitInstance
+ + sealed::GeneralPurpose1ChannelComplementaryInstance
+ + sealed::GeneralPurpose2ChannelComplementaryInstance
+ + sealed::AdvancedControlInstance
+ + '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);
+
+cfg_if::cfg_if! {
+ if #[cfg(not(stm32l0))] {
+ pin_trait!(Channel1ComplementaryPin, ComplementaryCaptureCompare16bitInstance);
+ pin_trait!(Channel2ComplementaryPin, ComplementaryCaptureCompare16bitInstance);
+ pin_trait!(Channel3ComplementaryPin, ComplementaryCaptureCompare16bitInstance);
+ pin_trait!(Channel4ComplementaryPin, ComplementaryCaptureCompare16bitInstance);
+
+ pin_trait!(BreakInputPin, ComplementaryCaptureCompare16bitInstance);
+ pin_trait!(BreakInput2Pin, ComplementaryCaptureCompare16bitInstance);
+
+ pin_trait!(BreakInputComparator1Pin, ComplementaryCaptureCompare16bitInstance);
+ pin_trait!(BreakInputComparator2Pin, ComplementaryCaptureCompare16bitInstance);
+
+ pin_trait!(BreakInput2Comparator1Pin, ComplementaryCaptureCompare16bitInstance);
+ pin_trait!(BreakInput2Comparator2Pin, ComplementaryCaptureCompare16bitInstance);
+ }
+}
#[allow(unused)]
-macro_rules! impl_basic_16bit_timer {
+macro_rules! impl_core_timer {
($inst:ident, $irq:ident) => {
- impl sealed::Basic16bitInstance for crate::peripherals::$inst {
+ impl sealed::CoreInstance for crate::peripherals::$inst {
type Interrupt = crate::interrupt::typelevel::$irq;
- fn regs() -> crate::pac::timer::TimBasic {
+ fn regs_core() -> crate::pac::timer::TimCore {
+ unsafe { crate::pac::timer::TimCore::from_ptr(crate::pac::$inst.as_ptr()) }
+ }
+ }
+ };
+}
+
+#[allow(unused)]
+macro_rules! impl_basic_no_cr2_timer {
+ ($inst:ident) => {
+ impl sealed::BasicNoCr2Instance for crate::peripherals::$inst {
+ fn regs_basic_no_cr2() -> crate::pac::timer::TimBasicNoCr2 {
+ unsafe { crate::pac::timer::TimBasicNoCr2::from_ptr(crate::pac::$inst.as_ptr()) }
+ }
+ }
+ };
+}
+
+#[allow(unused)]
+macro_rules! impl_basic_timer {
+ ($inst:ident) => {
+ impl sealed::BasicInstance for crate::peripherals::$inst {
+ fn regs_basic() -> crate::pac::timer::TimBasic {
unsafe { crate::pac::timer::TimBasic::from_ptr(crate::pac::$inst.as_ptr()) }
}
}
@@ -634,7 +758,40 @@ macro_rules! impl_basic_16bit_timer {
}
#[allow(unused)]
-macro_rules! impl_32bit_timer {
+macro_rules! impl_1ch_timer {
+ ($inst:ident) => {
+ impl sealed::GeneralPurpose1ChannelInstance for crate::peripherals::$inst {
+ fn regs_1ch() -> crate::pac::timer::Tim1ch {
+ unsafe { crate::pac::timer::Tim1ch::from_ptr(crate::pac::$inst.as_ptr()) }
+ }
+ }
+ };
+}
+
+#[allow(unused)]
+macro_rules! impl_2ch_timer {
+ ($inst:ident) => {
+ impl sealed::GeneralPurpose2ChannelInstance for crate::peripherals::$inst {
+ fn regs_2ch() -> crate::pac::timer::Tim2ch {
+ unsafe { crate::pac::timer::Tim2ch::from_ptr(crate::pac::$inst.as_ptr()) }
+ }
+ }
+ };
+}
+
+#[allow(unused)]
+macro_rules! impl_gp16_timer {
+ ($inst:ident) => {
+ impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
+ fn regs_gp16() -> crate::pac::timer::TimGp16 {
+ unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) }
+ }
+ }
+ };
+}
+
+#[allow(unused)]
+macro_rules! impl_gp32_timer {
($inst:ident) => {
impl sealed::GeneralPurpose32bitInstance for crate::peripherals::$inst {
fn regs_gp32() -> crate::pac::timer::TimGp32 {
@@ -645,83 +802,144 @@ macro_rules! impl_32bit_timer {
}
#[allow(unused)]
-macro_rules! impl_compare_capable_16bit {
+macro_rules! impl_1ch_cmp_timer {
($inst:ident) => {
- impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
- fn enable_outputs(&mut self) {}
+ impl sealed::GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst {
+ fn regs_1ch_cmp() -> crate::pac::timer::Tim1chCmp {
+ unsafe { crate::pac::timer::Tim1chCmp::from_ptr(crate::pac::$inst.as_ptr()) }
+ }
+ }
+ };
+}
+
+#[allow(unused)]
+macro_rules! impl_2ch_cmp_timer {
+ ($inst:ident) => {
+ impl sealed::GeneralPurpose2ChannelComplementaryInstance for crate::peripherals::$inst {
+ fn regs_2ch_cmp() -> crate::pac::timer::Tim2chCmp {
+ unsafe { crate::pac::timer::Tim2chCmp::from_ptr(crate::pac::$inst.as_ptr()) }
+ }
+ }
+ };
+}
+
+#[allow(unused)]
+macro_rules! impl_adv_timer {
+ ($inst:ident) => {
+ impl sealed::AdvancedControlInstance for crate::peripherals::$inst {
+ fn regs_advanced() -> crate::pac::timer::TimAdv {
+ unsafe { crate::pac::timer::TimAdv::from_ptr(crate::pac::$inst.as_ptr()) }
+ }
}
};
}
foreach_interrupt! {
- ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => {
- impl_basic_16bit_timer!($inst, $irq);
- impl Basic16bitInstance for crate::peripherals::$inst {}
- };
- ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => {
- impl_basic_16bit_timer!($inst, $irq);
- 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
- }
- }
+ ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => {
+ impl_core_timer!($inst, $irq);
+ impl_basic_no_cr2_timer!($inst);
+ impl_basic_timer!($inst);
+ impl BasicInstance for crate::peripherals::$inst {}
+ };
+
+ ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => {
+ impl_core_timer!($inst, $irq);
+ impl_basic_no_cr2_timer!($inst);
+ impl_basic_timer!($inst);
+ impl_1ch_timer!($inst);
+ impl_2ch_timer!($inst);
+ impl_gp16_timer!($inst);
+ impl BasicInstance for crate::peripherals::$inst {}
+ impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
+ };
+
+
+ ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => {
+ impl_core_timer!($inst, $irq);
+ impl_basic_no_cr2_timer!($inst);
+ impl_basic_timer!($inst);
+ impl_1ch_timer!($inst);
+ impl_2ch_timer!($inst);
+ impl_gp16_timer!($inst);
+ impl BasicInstance for crate::peripherals::$inst {}
+ impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
+ };
+
+ ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => {
+ impl_core_timer!($inst, $irq);
+ impl_basic_no_cr2_timer!($inst);
+ impl_basic_timer!($inst);
+ impl_1ch_timer!($inst);
+ impl_2ch_timer!($inst);
+ impl_gp16_timer!($inst);
+ impl BasicInstance for crate::peripherals::$inst {}
+ impl CaptureCompare16bitInstance 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_core_timer!($inst, $irq);
+ impl_basic_no_cr2_timer!($inst);
+ impl_basic_timer!($inst);
+ impl_1ch_timer!($inst);
+ impl_2ch_timer!($inst);
+ impl_gp16_timer!($inst);
+ impl_gp32_timer!($inst);
+ impl BasicInstance 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 sealed::CaptureCompare32bitInstance for crate::peripherals::$inst {}
-
- impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
- fn regs_gp16() -> crate::pac::timer::TimGp16 {
- unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) }
- }
- }
};
- ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => {
- impl_basic_16bit_timer!($inst, $irq);
-
- impl Basic16bitInstance for crate::peripherals::$inst {}
- impl GeneralPurpose16bitInstance for crate::peripherals::$inst {}
+ ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => {
+ impl_core_timer!($inst, $irq);
+ impl_basic_no_cr2_timer!($inst);
+ impl_basic_timer!($inst);
+ impl_1ch_timer!($inst);
+ impl_2ch_timer!($inst);
+ impl_gp16_timer!($inst);
+ impl_1ch_cmp_timer!($inst);
+ impl_2ch_cmp_timer!($inst);
+ impl_adv_timer!($inst);
+ impl BasicInstance for crate::peripherals::$inst {}
impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
- impl AdvancedControlInstance for crate::peripherals::$inst {}
- impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
- fn enable_outputs(&mut self) {
- use crate::timer::sealed::AdvancedControlInstance;
- let r = Self::regs_advanced();
- r.bdtr().modify(|w| w.set_moe(true));
- }
- }
- impl sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
- impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
- fn regs_gp16() -> crate::pac::timer::TimGp16 {
- unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) }
- }
- }
+ };
- impl sealed::AdvancedControlInstance for crate::peripherals::$inst {
- fn regs_advanced() -> crate::pac::timer::TimAdv {
- crate::pac::$inst
- }
- }
+
+ ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => {
+ impl_core_timer!($inst, $irq);
+ impl_basic_no_cr2_timer!($inst);
+ impl_basic_timer!($inst);
+ impl_1ch_timer!($inst);
+ impl_2ch_timer!($inst);
+ impl_gp16_timer!($inst);
+ impl_1ch_cmp_timer!($inst);
+ impl_2ch_cmp_timer!($inst);
+ impl_adv_timer!($inst);
+ impl BasicInstance for crate::peripherals::$inst {}
+ impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
+ impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
+ };
+
+
+ ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => {
+ impl_core_timer!($inst, $irq);
+ impl_basic_no_cr2_timer!($inst);
+ impl_basic_timer!($inst);
+ impl_1ch_timer!($inst);
+ impl_2ch_timer!($inst);
+ impl_gp16_timer!($inst);
+ impl_1ch_cmp_timer!($inst);
+ impl_2ch_cmp_timer!($inst);
+ impl_adv_timer!($inst);
+ impl BasicInstance for crate::peripherals::$inst {}
+ impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
+ impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
};
}
// Update Event trigger DMA for every timer
-dma_trait!(UpDma, Basic16bitInstance);
+dma_trait!(UpDma, BasicInstance);
dma_trait!(Ch1Dma, CaptureCompare16bitInstance);
dma_trait!(Ch2Dma, CaptureCompare16bitInstance);
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index 0b4c1225f..1acba504e 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -84,13 +84,12 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
this.set_frequency(freq);
this.inner.start();
- this.inner.enable_outputs();
-
[Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
.iter()
.for_each(|&channel| {
this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1);
- this.inner.set_output_compare_preload(channel, true)
+
+ this.inner.set_output_compare_preload(channel, true);
});
this
@@ -202,7 +201,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
&mut dma,
req,
duty,
- T::regs_gp16().ccr(channel.index()).as_ptr() as *mut _,
+ T::regs_1ch().ccr(channel.index()).as_ptr() as *mut _,
dma_transfer_option,
)
.await
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index c78752883..c11e3382f 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -140,11 +140,15 @@ pub struct BufferedUart<'d, T: BasicInstance> {
}
/// Tx-only buffered UART
+///
+/// Created with [BufferedUart::split]
pub struct BufferedUartTx<'d, T: BasicInstance> {
phantom: PhantomData<&'d mut T>,
}
/// Rx-only buffered UART
+///
+/// Created with [BufferedUart::split]
pub struct BufferedUartRx<'d, T: BasicInstance> {
phantom: PhantomData<&'d mut T>,
}
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index 4391bfef7..a0ab060a3 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -12,6 +12,8 @@ use crate::dma::ReadableRingBuffer;
use crate::usart::{Regs, Sr};
/// Rx-only Ring-buffered UART Driver
+///
+/// Created with [UartRx::into_ring_buffered]
pub struct RingBufferedUartRx<'d, T: BasicInstance, RxDma: super::RxDma> {
_peri: PeripheralRef<'d, T>,
ring_buf: ReadableRingBuffer<'d, RxDma, u8>,
diff --git a/examples/boot/application/nrf/src/bin/a.rs b/examples/boot/application/nrf/src/bin/a.rs
index f3abfddbc..851a3d721 100644
--- a/examples/boot/application/nrf/src/bin/a.rs
+++ b/examples/boot/application/nrf/src/bin/a.rs
@@ -50,7 +50,7 @@ async fn main(_spawner: Spawner) {
let nvmc = Nvmc::new(p.NVMC);
let nvmc = Mutex::new(BlockingAsync::new(nvmc));
- let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc);
+ let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc, &nvmc);
let mut magic = [0; 4];
let mut updater = FirmwareUpdater::new(config, &mut magic);
loop {
diff --git a/examples/boot/application/rp/src/bin/a.rs b/examples/boot/application/rp/src/bin/a.rs
index 3f0bf90e2..ede0c07da 100644
--- a/examples/boot/application/rp/src/bin/a.rs
+++ b/examples/boot/application/rp/src/bin/a.rs
@@ -36,7 +36,7 @@ async fn main(_s: Spawner) {
let flash = Flash::<_, _, FLASH_SIZE>::new_blocking(p.FLASH);
let flash = Mutex::new(RefCell::new(flash));
- let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash);
+ let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash);
let mut aligned = AlignedBuffer([0; 1]);
let mut updater = BlockingFirmwareUpdater::new(config, &mut aligned.0);
diff --git a/examples/boot/application/stm32f3/memory.x b/examples/boot/application/stm32f3/memory.x
index f51875766..02ebe3ecf 100644
--- a/examples/boot/application/stm32f3/memory.x
+++ b/examples/boot/application/stm32f3/memory.x
@@ -3,8 +3,8 @@ MEMORY
/* NOTE 1 K = 1 KiBi = 1024 bytes */
BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K
BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K
- FLASH : ORIGIN = 0x08008000, LENGTH = 32K
- DFU : ORIGIN = 0x08010000, LENGTH = 36K
+ FLASH : ORIGIN = 0x08008000, LENGTH = 64K
+ DFU : ORIGIN = 0x08018000, LENGTH = 66K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
}
diff --git a/examples/boot/application/stm32f3/src/bin/a.rs b/examples/boot/application/stm32f3/src/bin/a.rs
index 3f9ebe5c8..8858ae3da 100644
--- a/examples/boot/application/stm32f3/src/bin/a.rs
+++ b/examples/boot/application/stm32f3/src/bin/a.rs
@@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) {
let mut led = Output::new(p.PA5, Level::Low, Speed::Low);
led.set_high();
- let config = FirmwareUpdaterConfig::from_linkerfile(&flash);
+ let config = FirmwareUpdaterConfig::from_linkerfile(&flash, &flash);
let mut magic = AlignedBuffer([0; WRITE_SIZE]);
let mut updater = FirmwareUpdater::new(config, &mut magic.0);
button.wait_for_falling_edge().await;
diff --git a/examples/boot/application/stm32f7/src/bin/a.rs b/examples/boot/application/stm32f7/src/bin/a.rs
index c57c29263..d3df11fe4 100644
--- a/examples/boot/application/stm32f7/src/bin/a.rs
+++ b/examples/boot/application/stm32f7/src/bin/a.rs
@@ -30,7 +30,7 @@ async fn main(_spawner: Spawner) {
let mut led = Output::new(p.PB7, Level::Low, Speed::Low);
led.set_high();
- let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash);
+ let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash);
let mut magic = AlignedBuffer([0; WRITE_SIZE]);
let mut updater = BlockingFirmwareUpdater::new(config, &mut magic.0);
let writer = updater.prepare_update().unwrap();
diff --git a/examples/boot/application/stm32h7/src/bin/a.rs b/examples/boot/application/stm32h7/src/bin/a.rs
index a00d17408..f61ac1f71 100644
--- a/examples/boot/application/stm32h7/src/bin/a.rs
+++ b/examples/boot/application/stm32h7/src/bin/a.rs
@@ -30,7 +30,7 @@ async fn main(_spawner: Spawner) {
let mut led = Output::new(p.PB14, Level::Low, Speed::Low);
led.set_high();
- let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash);
+ let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash);
let mut magic = AlignedBuffer([0; WRITE_SIZE]);
let mut updater = BlockingFirmwareUpdater::new(config, &mut magic.0);
let writer = updater.prepare_update().unwrap();
diff --git a/examples/boot/application/stm32l0/memory.x b/examples/boot/application/stm32l0/memory.x
index a99330145..8866506a8 100644
--- a/examples/boot/application/stm32l0/memory.x
+++ b/examples/boot/application/stm32l0/memory.x
@@ -3,8 +3,8 @@ MEMORY
/* NOTE 1 K = 1 KiBi = 1024 bytes */
BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K
BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K
- FLASH : ORIGIN = 0x08008000, LENGTH = 32K
- DFU : ORIGIN = 0x08010000, LENGTH = 36K
+ FLASH : ORIGIN = 0x08008000, LENGTH = 64K
+ DFU : ORIGIN = 0x08018000, LENGTH = 66K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
}
diff --git a/examples/boot/application/stm32l0/src/bin/a.rs b/examples/boot/application/stm32l0/src/bin/a.rs
index dbec49d44..f066c1139 100644
--- a/examples/boot/application/stm32l0/src/bin/a.rs
+++ b/examples/boot/application/stm32l0/src/bin/a.rs
@@ -30,7 +30,7 @@ async fn main(_spawner: Spawner) {
led.set_high();
- let config = FirmwareUpdaterConfig::from_linkerfile(&flash);
+ let config = FirmwareUpdaterConfig::from_linkerfile(&flash, &flash);
let mut magic = AlignedBuffer([0; WRITE_SIZE]);
let mut updater = FirmwareUpdater::new(config, &mut magic.0);
button.wait_for_falling_edge().await;
diff --git a/examples/boot/application/stm32l1/memory.x b/examples/boot/application/stm32l1/memory.x
index a99330145..caa525278 100644
--- a/examples/boot/application/stm32l1/memory.x
+++ b/examples/boot/application/stm32l1/memory.x
@@ -3,8 +3,8 @@ MEMORY
/* NOTE 1 K = 1 KiBi = 1024 bytes */
BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K
BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K
- FLASH : ORIGIN = 0x08008000, LENGTH = 32K
- DFU : ORIGIN = 0x08010000, LENGTH = 36K
+ FLASH : ORIGIN = 0x08008000, LENGTH = 46K
+ DFU : ORIGIN = 0x08013800, LENGTH = 54K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
}
diff --git a/examples/boot/application/stm32l1/src/bin/a.rs b/examples/boot/application/stm32l1/src/bin/a.rs
index dbec49d44..f066c1139 100644
--- a/examples/boot/application/stm32l1/src/bin/a.rs
+++ b/examples/boot/application/stm32l1/src/bin/a.rs
@@ -30,7 +30,7 @@ async fn main(_spawner: Spawner) {
led.set_high();
- let config = FirmwareUpdaterConfig::from_linkerfile(&flash);
+ let config = FirmwareUpdaterConfig::from_linkerfile(&flash, &flash);
let mut magic = AlignedBuffer([0; WRITE_SIZE]);
let mut updater = FirmwareUpdater::new(config, &mut magic.0);
button.wait_for_falling_edge().await;
diff --git a/examples/boot/application/stm32l4/memory.x b/examples/boot/application/stm32l4/memory.x
index f51875766..e1d4e7fa8 100644
--- a/examples/boot/application/stm32l4/memory.x
+++ b/examples/boot/application/stm32l4/memory.x
@@ -3,8 +3,8 @@ MEMORY
/* NOTE 1 K = 1 KiBi = 1024 bytes */
BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K
BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K
- FLASH : ORIGIN = 0x08008000, LENGTH = 32K
- DFU : ORIGIN = 0x08010000, LENGTH = 36K
+ FLASH : ORIGIN = 0x08008000, LENGTH = 64K
+ DFU : ORIGIN = 0x08018000, LENGTH = 68K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
}
diff --git a/examples/boot/application/stm32l4/src/bin/a.rs b/examples/boot/application/stm32l4/src/bin/a.rs
index e946c3cdf..a0079ee33 100644
--- a/examples/boot/application/stm32l4/src/bin/a.rs
+++ b/examples/boot/application/stm32l4/src/bin/a.rs
@@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) {
let mut led = Output::new(p.PB14, Level::Low, Speed::Low);
led.set_high();
- let config = FirmwareUpdaterConfig::from_linkerfile(&flash);
+ let config = FirmwareUpdaterConfig::from_linkerfile(&flash, &flash);
let mut magic = AlignedBuffer([0; WRITE_SIZE]);
let mut updater = FirmwareUpdater::new(config, &mut magic.0);
button.wait_for_falling_edge().await;
diff --git a/examples/boot/application/stm32wb-dfu/README.md b/examples/boot/application/stm32wb-dfu/README.md
index c8dce0387..7f656cde6 100644
--- a/examples/boot/application/stm32wb-dfu/README.md
+++ b/examples/boot/application/stm32wb-dfu/README.md
@@ -1,29 +1,9 @@
# Examples using bootloader
-Example for STM32WL demonstrating the bootloader. The example consists of application binaries, 'a'
-which allows you to press a button to start the DFU process, and 'b' which is the updated
-application.
-
-
-## Prerequisites
-
-* `cargo-binutils`
-* `cargo-flash`
-* `embassy-boot-stm32`
+Example for STM32WB demonstrating the USB DFU application.
## Usage
```
-# Flash bootloader
-cargo flash --manifest-path ../../bootloader/stm32/Cargo.toml --release --features embassy-stm32/stm32wl55jc-cm4 --chip STM32WLE5JCIx
-# Build 'b'
-cargo build --release --bin b
-# Generate binary for 'b'
-cargo objcopy --release --bin b -- -O binary b.bin
-```
-
-# Flash `a` (which includes b.bin)
-
-```
-cargo flash --release --bin a --chip STM32WLE5JCIx
+cargo flash --release --chip STM32WB55RGVx
```
diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs
index b2ccb9e1a..37c3d7d90 100644
--- a/examples/boot/application/stm32wb-dfu/src/main.rs
+++ b/examples/boot/application/stm32wb-dfu/src/main.rs
@@ -30,7 +30,7 @@ async fn main(_spawner: Spawner) {
let flash = Flash::new_blocking(p.FLASH);
let flash = Mutex::new(RefCell::new(flash));
- let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash);
+ let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash);
let mut magic = AlignedBuffer([0; WRITE_SIZE]);
let mut firmware_state = BlockingFirmwareState::from_config(config, &mut magic.0);
firmware_state.mark_booted().expect("Failed to mark booted");
diff --git a/examples/boot/application/stm32wl/memory.x b/examples/boot/application/stm32wl/memory.x
index f51875766..e1d4e7fa8 100644
--- a/examples/boot/application/stm32wl/memory.x
+++ b/examples/boot/application/stm32wl/memory.x
@@ -3,8 +3,8 @@ MEMORY
/* NOTE 1 K = 1 KiBi = 1024 bytes */
BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K
BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K
- FLASH : ORIGIN = 0x08008000, LENGTH = 32K
- DFU : ORIGIN = 0x08010000, LENGTH = 36K
+ FLASH : ORIGIN = 0x08008000, LENGTH = 64K
+ DFU : ORIGIN = 0x08018000, LENGTH = 68K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
}
diff --git a/examples/boot/application/stm32wl/src/bin/a.rs b/examples/boot/application/stm32wl/src/bin/a.rs
index b582d8b25..2fb16bdc4 100644
--- a/examples/boot/application/stm32wl/src/bin/a.rs
+++ b/examples/boot/application/stm32wl/src/bin/a.rs
@@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) {
let mut led = Output::new(p.PB9, Level::Low, Speed::Low);
led.set_high();
- let config = FirmwareUpdaterConfig::from_linkerfile(&flash);
+ let config = FirmwareUpdaterConfig::from_linkerfile(&flash, &flash);
let mut magic = AlignedBuffer([0; WRITE_SIZE]);
let mut updater = FirmwareUpdater::new(config, &mut magic.0);
button.wait_for_falling_edge().await;
diff --git a/examples/boot/bootloader/nrf/src/main.rs b/examples/boot/bootloader/nrf/src/main.rs
index 74e2e293f..67c700437 100644
--- a/examples/boot/bootloader/nrf/src/main.rs
+++ b/examples/boot/bootloader/nrf/src/main.rs
@@ -31,7 +31,7 @@ fn main() -> ! {
let flash = WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, wdt_config);
let flash = Mutex::new(RefCell::new(flash));
- let config = BootLoaderConfig::from_linkerfile_blocking(&flash);
+ let config = BootLoaderConfig::from_linkerfile_blocking(&flash, &flash, &flash);
let active_offset = config.active.offset();
let bl: BootLoader = BootLoader::prepare(config);
diff --git a/examples/boot/bootloader/rp/src/main.rs b/examples/boot/bootloader/rp/src/main.rs
index c0e75d1ea..25b1657b8 100644
--- a/examples/boot/bootloader/rp/src/main.rs
+++ b/examples/boot/bootloader/rp/src/main.rs
@@ -27,7 +27,7 @@ fn main() -> ! {
let flash = WatchdogFlash::::start(p.FLASH, p.WATCHDOG, Duration::from_secs(8));
let flash = Mutex::new(RefCell::new(flash));
- let config = BootLoaderConfig::from_linkerfile_blocking(&flash);
+ let config = BootLoaderConfig::from_linkerfile_blocking(&flash, &flash, &flash);
let active_offset = config.active.offset();
let bl: BootLoader = BootLoader::prepare(config);
diff --git a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml
new file mode 100644
index 000000000..313187adc
--- /dev/null
+++ b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml
@@ -0,0 +1,57 @@
+[package]
+edition = "2021"
+name = "stm32-bootloader-dual-bank-flash-example"
+version = "0.1.0"
+description = "Example bootloader for dual-bank flash STM32 chips"
+license = "MIT OR Apache-2.0"
+
+[dependencies]
+defmt = { version = "0.3", optional = true }
+defmt-rtt = { version = "0.4", optional = true }
+
+embassy-stm32 = { path = "../../../../embassy-stm32", features = [] }
+embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" }
+cortex-m = { version = "0.7.6", features = [
+ "inline-asm",
+ "critical-section-single-core",
+] }
+embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
+cortex-m-rt = { version = "0.7" }
+embedded-storage = "0.3.1"
+embedded-storage-async = "0.4.0"
+cfg-if = "1.0.0"
+
+[features]
+defmt = ["dep:defmt", "embassy-boot-stm32/defmt", "embassy-stm32/defmt"]
+debug = ["defmt-rtt", "defmt"]
+
+[profile.dev]
+debug = 2
+debug-assertions = true
+incremental = false
+opt-level = 'z'
+overflow-checks = true
+
+[profile.release]
+codegen-units = 1
+debug = 2
+debug-assertions = false
+incremental = false
+lto = 'fat'
+opt-level = 'z'
+overflow-checks = false
+
+# do not optimize proc-macro crates = faster builds from scratch
+[profile.dev.build-override]
+codegen-units = 8
+debug = false
+debug-assertions = false
+opt-level = 0
+overflow-checks = false
+
+[profile.release.build-override]
+codegen-units = 8
+debug = false
+debug-assertions = false
+opt-level = 0
+overflow-checks = false
diff --git a/examples/boot/bootloader/stm32-dual-bank/README.md b/examples/boot/bootloader/stm32-dual-bank/README.md
new file mode 100644
index 000000000..3de3171cd
--- /dev/null
+++ b/examples/boot/bootloader/stm32-dual-bank/README.md
@@ -0,0 +1,44 @@
+# STM32 dual-bank flash Bootloader
+
+## Overview
+
+This bootloader leverages `embassy-boot` to interact with the flash.
+This example targets STM32 devices with dual-bank flash memory, with a primary focus on the STM32H747XI series.
+Users must modify the `memory.x` configuration file to match with the memory layout of their specific STM32 device.
+
+Additionally, this example can be extended to utilize external flash memory, such as QSPI, for storing partitions.
+
+## Memory Configuration
+
+In this example's `memory.x` file, various symbols are defined to assist in effective memory management within the bootloader environment.
+For dual-bank STM32 devices, it's crucial to assign these symbols correctly to their respective memory banks.
+
+### Symbol Definitions
+
+The bootloader's state and active symbols are anchored to the flash origin of **bank 1**:
+
+- `__bootloader_state_start` and `__bootloader_state_end`
+- `__bootloader_active_start` and `__bootloader_active_end`
+
+In contrast, the Device Firmware Upgrade (DFU) symbols are aligned with the DFU flash origin in **bank 2**:
+
+- `__bootloader_dfu_start` and `__bootloader_dfu_end`
+
+```rust
+__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(**FLASH**);
+__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(**FLASH**);
+
+__bootloader_active_start = ORIGIN(ACTIVE) - ORIGIN(**FLASH**);
+__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE) - ORIGIN(**FLASH**);
+
+__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(**DFU**);
+__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(**DFU**);
+```
+
+## Flashing the Bootloader
+
+To flash the bootloader onto your STM32H747XI device, use the following command:
+
+```bash
+cargo flash --features embassy-stm32/stm32h747xi-cm7 --release --chip STM32H747XIHx
+```
diff --git a/examples/boot/bootloader/stm32-dual-bank/build.rs b/examples/boot/bootloader/stm32-dual-bank/build.rs
new file mode 100644
index 000000000..fd605991f
--- /dev/null
+++ b/examples/boot/bootloader/stm32-dual-bank/build.rs
@@ -0,0 +1,27 @@
+use std::env;
+use std::fs::File;
+use std::io::Write;
+use std::path::PathBuf;
+
+fn main() {
+ // Put `memory.x` in our output directory and ensure it's
+ // on the linker search path.
+ let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
+ File::create(out.join("memory.x"))
+ .unwrap()
+ .write_all(include_bytes!("memory.x"))
+ .unwrap();
+ println!("cargo:rustc-link-search={}", out.display());
+
+ // By default, Cargo will re-run a build script whenever
+ // any file in the project changes. By specifying `memory.x`
+ // here, we ensure the build script is only re-run when
+ // `memory.x` is changed.
+ println!("cargo:rerun-if-changed=memory.x");
+
+ println!("cargo:rustc-link-arg-bins=--nmagic");
+ println!("cargo:rustc-link-arg-bins=-Tlink.x");
+ if env::var("CARGO_FEATURE_DEFMT").is_ok() {
+ println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
+ }
+}
diff --git a/examples/boot/bootloader/stm32-dual-bank/memory.x b/examples/boot/bootloader/stm32-dual-bank/memory.x
new file mode 100644
index 000000000..665da7139
--- /dev/null
+++ b/examples/boot/bootloader/stm32-dual-bank/memory.x
@@ -0,0 +1,18 @@
+MEMORY
+{
+ /* NOTE 1 K = 1 KiBi = 1024 bytes */
+ FLASH : ORIGIN = 0x08000000, LENGTH = 128K
+ BOOTLOADER_STATE : ORIGIN = 0x08020000, LENGTH = 128K
+ ACTIVE : ORIGIN = 0x08040000, LENGTH = 512K
+ DFU : ORIGIN = 0x08100000, LENGTH = 640K
+ RAM (rwx) : ORIGIN = 0x24000000, LENGTH = 512K
+}
+
+__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(FLASH);
+__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(FLASH);
+
+__bootloader_active_start = ORIGIN(ACTIVE) - ORIGIN(FLASH);
+__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE) - ORIGIN(FLASH);
+
+__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(DFU);
+__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(DFU);
diff --git a/examples/boot/bootloader/stm32-dual-bank/src/main.rs b/examples/boot/bootloader/stm32-dual-bank/src/main.rs
new file mode 100644
index 000000000..4d2e82d26
--- /dev/null
+++ b/examples/boot/bootloader/stm32-dual-bank/src/main.rs
@@ -0,0 +1,53 @@
+#![no_std]
+#![no_main]
+
+use core::cell::RefCell;
+
+use cortex_m_rt::{entry, exception};
+#[cfg(feature = "defmt")]
+use defmt_rtt as _;
+use embassy_boot_stm32::*;
+use embassy_stm32::flash::{Flash, BANK1_REGION};
+use embassy_sync::blocking_mutex::Mutex;
+
+#[entry]
+fn main() -> ! {
+ let p = embassy_stm32::init(Default::default());
+
+ // Uncomment this if you are debugging the bootloader with debugger/RTT attached,
+ // as it prevents a hard fault when accessing flash 'too early' after boot.
+ /*
+ for i in 0..10000000 {
+ cortex_m::asm::nop();
+ }
+ */
+
+ let layout = Flash::new_blocking(p.FLASH).into_blocking_regions();
+ let flash_bank1 = Mutex::new(RefCell::new(layout.bank1_region));
+ let flash_bank2 = Mutex::new(RefCell::new(layout.bank2_region));
+
+ let config = BootLoaderConfig::from_linkerfile_blocking(&flash_bank1, &flash_bank2, &flash_bank1);
+ let active_offset = config.active.offset();
+ let bl = BootLoader::prepare::<_, _, _, 2048>(config);
+
+ unsafe { bl.load(BANK1_REGION.base + active_offset) }
+}
+
+#[no_mangle]
+#[cfg_attr(target_os = "none", link_section = ".HardFault.user")]
+unsafe extern "C" fn HardFault() {
+ cortex_m::peripheral::SCB::sys_reset();
+}
+
+#[exception]
+unsafe fn DefaultHandler(_: i16) -> ! {
+ const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32;
+ let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16;
+
+ panic!("DefaultHandler #{:?}", irqn);
+}
+
+#[panic_handler]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+ cortex_m::asm::udf();
+}
diff --git a/examples/boot/bootloader/stm32/src/main.rs b/examples/boot/bootloader/stm32/src/main.rs
index 5fd9ea588..99a7a6a6b 100644
--- a/examples/boot/bootloader/stm32/src/main.rs
+++ b/examples/boot/bootloader/stm32/src/main.rs
@@ -25,7 +25,7 @@ fn main() -> ! {
let layout = Flash::new_blocking(p.FLASH).into_blocking_regions();
let flash = Mutex::new(RefCell::new(layout.bank1_region));
- let config = BootLoaderConfig::from_linkerfile_blocking(&flash);
+ let config = BootLoaderConfig::from_linkerfile_blocking(&flash, &flash, &flash);
let active_offset = config.active.offset();
let bl = BootLoader::prepare::<_, _, _, 2048>(config);
diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
index 96635afa2..854f94d85 100644
--- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
+++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
@@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
defmt = { version = "0.3", optional = true }
defmt-rtt = { version = "0.4", optional = true }
-embassy-stm32 = { path = "../../../../embassy-stm32", features = ["stm32wb55rg"] }
+embassy-stm32 = { path = "../../../../embassy-stm32", features = [] }
embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" }
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
diff --git a/examples/boot/bootloader/stm32wb-dfu/README.md b/examples/boot/bootloader/stm32wb-dfu/README.md
index a82b730b9..d5c6ea57c 100644
--- a/examples/boot/bootloader/stm32wb-dfu/README.md
+++ b/examples/boot/bootloader/stm32wb-dfu/README.md
@@ -7,5 +7,5 @@ The bootloader uses `embassy-boot` to interact with the flash.
Flash the bootloader
```
-cargo flash --features embassy-stm32/stm32wl55jc-cm4 --release --chip STM32WLE5JCIx
+cargo flash --features embassy-stm32/stm32wb55rg --release --chip STM32WB55RGVx
```
diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs
index a7ab813b6..d989fbfdf 100644
--- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs
+++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs
@@ -35,7 +35,7 @@ fn main() -> ! {
let layout = Flash::new_blocking(p.FLASH).into_blocking_regions();
let flash = Mutex::new(RefCell::new(layout.bank1_region));
- let config = BootLoaderConfig::from_linkerfile_blocking(&flash);
+ let config = BootLoaderConfig::from_linkerfile_blocking(&flash, &flash, &flash);
let active_offset = config.active.offset();
let bl = BootLoader::prepare::<_, _, _, 2048>(config);
if bl.state == State::DfuDetach {
@@ -45,7 +45,7 @@ fn main() -> ! {
config.product = Some("USB-DFU Bootloader example");
config.serial_number = Some("1235678");
- let fw_config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash);
+ let fw_config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash);
let mut buffer = AlignedBuffer([0; WRITE_SIZE]);
let updater = BlockingFirmwareUpdater::new(fw_config, &mut buffer.0[..]);
diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs
index 8e5c41a43..d88bd838f 100644
--- a/examples/stm32h7/src/bin/dac_dma.rs
+++ b/examples/stm32h7/src/bin/dac_dma.rs
@@ -8,7 +8,7 @@ use embassy_stm32::pac::timer::vals::Mms;
use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7};
use embassy_stm32::rcc::low_level::RccPeripheral;
use embassy_stm32::time::Hertz;
-use embassy_stm32::timer::low_level::Basic16bitInstance;
+use embassy_stm32::timer::low_level::BasicInstance;
use micromath::F32Ext;
use {defmt_rtt as _, panic_probe as _};
@@ -75,9 +75,9 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
dac.enable();
TIM6::enable_and_reset();
- TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1));
- TIM6::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE));
- TIM6::regs().cr1().modify(|w| {
+ TIM6::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1));
+ TIM6::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE));
+ TIM6::regs_basic().cr1().modify(|w| {
w.set_opm(false);
w.set_cen(true);
});
@@ -112,9 +112,9 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) {
}
TIM7::enable_and_reset();
- TIM7::regs().arr().modify(|w| w.set_arr(reload as u16 - 1));
- TIM7::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE));
- TIM7::regs().cr1().modify(|w| {
+ TIM7::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1));
+ TIM7::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE));
+ TIM7::regs_basic().cr1().modify(|w| {
w.set_opm(false);
w.set_cen(true);
});
diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs
new file mode 100644
index 000000000..adeaa208a
--- /dev/null
+++ b/examples/stm32l0/src/bin/adc.rs
@@ -0,0 +1,40 @@
+#![no_std]
+#![no_main]
+
+use defmt::*;
+use embassy_executor::Spawner;
+use embassy_stm32::adc::{Adc, SampleTime};
+use embassy_stm32::peripherals::ADC;
+use embassy_stm32::{adc, bind_interrupts};
+use embassy_time::{Delay, Timer};
+use {defmt_rtt as _, panic_probe as _};
+
+bind_interrupts!(struct Irqs {
+ ADC1_COMP => adc::InterruptHandler;
+});
+
+#[embassy_executor::main]
+async fn main(_spawner: Spawner) {
+ let p = embassy_stm32::init(Default::default());
+ info!("Hello World!");
+
+ let mut adc = Adc::new(p.ADC, Irqs, &mut Delay);
+ adc.set_sample_time(SampleTime::Cycles79_5);
+ let mut pin = p.PA1;
+
+ let mut vrefint = adc.enable_vref(&mut Delay);
+ let vrefint_sample = adc.read(&mut vrefint).await;
+ let convert_to_millivolts = |sample| {
+ // From https://www.st.com/resource/en/datasheet/stm32l051c6.pdf
+ // 6.3.3 Embedded internal reference voltage
+ const VREFINT_MV: u32 = 1224; // mV
+
+ (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16
+ };
+
+ loop {
+ let v = adc.read(&mut pin).await;
+ info!("--> {} - {} mV", v, convert_to_millivolts(v));
+ Timer::after_millis(100).await;
+ }
+}
diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs
index 8e5098557..f227812cd 100644
--- a/examples/stm32l4/src/bin/dac_dma.rs
+++ b/examples/stm32l4/src/bin/dac_dma.rs
@@ -8,7 +8,7 @@ use embassy_stm32::pac::timer::vals::Mms;
use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7};
use embassy_stm32::rcc::low_level::RccPeripheral;
use embassy_stm32::time::Hertz;
-use embassy_stm32::timer::low_level::Basic16bitInstance;
+use embassy_stm32::timer::low_level::BasicInstance;
use micromath::F32Ext;
use {defmt_rtt as _, panic_probe as _};
@@ -46,9 +46,9 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
dac.enable();
TIM6::enable_and_reset();
- TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1));
- TIM6::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE));
- TIM6::regs().cr1().modify(|w| {
+ TIM6::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1));
+ TIM6::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE));
+ TIM6::regs_basic().cr1().modify(|w| {
w.set_opm(false);
w.set_cen(true);
});
@@ -83,9 +83,9 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) {
}
TIM7::enable_and_reset();
- TIM7::regs().arr().modify(|w| w.set_arr(reload as u16 - 1));
- TIM7::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE));
- TIM7::regs().cr1().modify(|w| {
+ TIM7::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1));
+ TIM7::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE));
+ TIM7::regs_basic().cr1().modify(|w| {
w.set_opm(false);
w.set_cen(true);
});
diff --git a/tests/stm32/teleprobe.sh b/tests/stm32/teleprobe.sh
deleted file mode 100755
index 6eec6ca93..000000000
--- a/tests/stm32/teleprobe.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-echo Running target=$1 elf=$2
-STATUSCODE=$(
- curl \
- -sS \
- --output /dev/stderr \
- --write-out "%{http_code}" \
- -H "Authorization: Bearer $TELEPROBE_TOKEN" \
- https://teleprobe.embassy.dev/targets/$1/run --data-binary @$2
-)
-echo
-echo HTTP Status code: $STATUSCODE
-test "$STATUSCODE" -eq 200