From 9ea7a245e9f74faa1ba1f35988d98fc914414609 Mon Sep 17 00:00:00 2001 From: Adin Ackerman Date: Sun, 24 Dec 2023 11:51:16 -0800 Subject: [PATCH 01/45] add some generation resources, add some feature descriptions --- docs/modules/ROOT/pages/new_project.adoc | 25 +++++++++++++------ .../modules/ROOT/pages/project_structure.adoc | 9 +++++-- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/docs/modules/ROOT/pages/new_project.adoc b/docs/modules/ROOT/pages/new_project.adoc index ce139ed8d..320966bb6 100644 --- a/docs/modules/ROOT/pages/new_project.adoc +++ b/docs/modules/ROOT/pages/new_project.adoc @@ -1,6 +1,17 @@ = Starting a new Embassy project -Once you’ve successfully xref:getting_started.adoc[run some example projects], the next step is to make a standalone Embassy project. The easiest way to do this is to adapt an example for a similar chip to the one you’re targeting. +Once you’ve successfully xref:getting_started.adoc[run some example projects], the next step is to make a standalone Embassy project. + +There are some tools for generating Embassy projects: (WIP) + +==== CLI +- link:https://github.com/adinack/cargo-embassy[cargo-embassy] (STM32 and NRF) + +==== cargo-generate +- link:https://github.com/lulf/embassy-template[embassy-template] (STM32, NRF, and RP) +- link:https://github.com/bentwire/embassy-rp2040-template[embassy-rp2040-template] (RP) + +But if you want to start from scratch: As an example, let’s create a new embassy project from scratch for a STM32G474. The same instructions are applicable for any supported chip with some minor changes. @@ -166,13 +177,13 @@ should result in a blinking LED (if there’s one attached to the pin in `src/ma Erasing sectors ✔ [00:00:00] [#########################################################] 18.00 KiB/18.00 KiB @ 54.09 KiB/s (eta 0s ) Programming pages ✔ [00:00:00] [#########################################################] 17.00 KiB/17.00 KiB @ 35.91 KiB/s (eta 0s ) Finished in 0.817s 0.000000 TRACE BDCR configured: 00008200 -└─ embassy_stm32::rcc::bd::{impl#3}::init::{closure#4} @ /home/you/.cargo/git/checkouts/embassy-9312dcb0ed774b29/7703f47/embassy-stm32/src/fmt.rs:117 +└─ embassy_stm32::rcc::bd::{impl#3}::init::{closure#4} @ /home/you/.cargo/git/checkouts/embassy-9312dcb0ed774b29/7703f47/embassy-stm32/src/fmt.rs:117 0.000000 DEBUG rcc: Clocks { sys: Hertz(16000000), pclk1: Hertz(16000000), pclk1_tim: Hertz(16000000), pclk2: Hertz(16000000), pclk2_tim: Hertz(16000000), hclk1: Hertz(16000000), hclk2: Hertz(16000000), pll1_p: None, adc: None, adc34: None, rtc: Some(Hertz(32000)) } -└─ embassy_stm32::rcc::set_freqs @ /home/you/.cargo/git/checkouts/embassy-9312dcb0ed774b29/7703f47/embassy-stm32/src/fmt.rs:130 +└─ embassy_stm32::rcc::set_freqs @ /home/you/.cargo/git/checkouts/embassy-9312dcb0ed774b29/7703f47/embassy-stm32/src/fmt.rs:130 0.000000 INFO Hello World! -└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:14 +└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:14 0.000091 INFO high -└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:19 +└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:19 0.300201 INFO low -└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:23 ----- \ No newline at end of file +└─ embassy_stm32g474::____embassy_main_task::{async_fn#0} @ src/main.rs:23 +---- diff --git a/docs/modules/ROOT/pages/project_structure.adoc b/docs/modules/ROOT/pages/project_structure.adoc index 3e6008ec4..bdb41d328 100644 --- a/docs/modules/ROOT/pages/project_structure.adoc +++ b/docs/modules/ROOT/pages/project_structure.adoc @@ -38,13 +38,18 @@ DEFMT_LOG = "trace" # <- can change to info, warn, or error === build.rs -This is the build script for your project. It links defmt (what is defmt?) and the `memory.x` file if needed. This file is pretty specific for each chipset, just copy and paste from the corresponding link:https://github.com/embassy-rs/embassy/tree/main/examples[example]. +This is the build script for your project. It links defmt (what is link:https://defmt.ferrous-systems.com[defmt]?) and the `memory.x` file if needed. This file is pretty specific for each chipset, just copy and paste from the corresponding link:https://github.com/embassy-rs/embassy/tree/main/examples[example]. === Cargo.toml This is your manifest file, where you can configure all of the embassy components to use the features you need. -TODO: someone should exhaustively describe every feature for every component! +==== Features +===== Time +- tick-hz-x: Configures the tick rate of `embassy-time`. Higher tick rate means higher precision, and higher CPU wakes. +- defmt-timestamp-uptime: defmt log entries will display the uptime in seconds. + +...more to come === memory.x From 994b77e6843d70db34c59c0723b7718d52f3fd52 Mon Sep 17 00:00:00 2001 From: Tyler Gilbert Date: Wed, 3 Jan 2024 11:06:03 -0600 Subject: [PATCH 02/45] Add write_immediate() function to STM32 DMA ringbuffer API to pre-fill the buffer before starting the DMA --- embassy-stm32/src/dma/bdma.rs | 7 +++++++ embassy-stm32/src/dma/dma.rs | 7 +++++++ embassy-stm32/src/dma/ringbuffer.rs | 11 +++++++++++ 3 files changed, 25 insertions(+) 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..c5b42060a 100644 --- a/embassy-stm32/src/dma/ringbuffer.rs +++ b/embassy-stm32/src/dma/ringbuffer.rs @@ -263,6 +263,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; From 7ff21e8b8ba3bd03b4317abbc40f0e6a0b02289f Mon Sep 17 00:00:00 2001 From: Justin Beaurivage Date: Tue, 30 Jan 2024 17:06:57 -0500 Subject: [PATCH 03/45] Handle Uarte RX errors --- embassy-nrf/Cargo.toml | 1 + embassy-nrf/src/uarte.rs | 95 +++++++++++++++++++++++++++++++++++----- 2 files changed, 85 insertions(+), 11 deletions(-) diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 10f268b51..580f0e3e6 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -133,6 +133,7 @@ embedded-io = { version = "0.6.0" } embedded-io-async = { version = "0.6.1" } defmt = { version = "0.3", optional = true } +bitflags = "2.4.2" log = { version = "0.4.14", optional = true } cortex-m-rt = ">=0.6.15,<0.8" cortex-m = "0.7.6" diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 95434e7a7..90d851139 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -52,6 +52,39 @@ impl Default for Config { } } +bitflags::bitflags! { + /// Error source flags + pub struct ErrorSource: u32 { + /// Buffer overrun + const OVERRUN = 0x01; + /// Parity error + const PARITY = 0x02; + /// Framing error + const FRAMING = 0x04; + /// Break condition + const BREAK = 0x08; + } +} + +impl TryFrom for () { + type Error = Error; + + #[inline] + fn try_from(errors: ErrorSource) -> Result { + if errors.contains(ErrorSource::OVERRUN) { + Err(Error::Overrun) + } else if errors.contains(ErrorSource::PARITY) { + Err(Error::Parity) + } else if errors.contains(ErrorSource::FRAMING) { + Err(Error::Framing) + } else if errors.contains(ErrorSource::BREAK) { + Err(Error::Break) + } else { + Ok(()) + } + } +} + /// UART error. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -61,6 +94,14 @@ pub enum Error { BufferTooLong, /// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash. BufferNotInRAM, + /// Framing Error + Framing, + /// Parity Error + Parity, + /// Buffer Overrun + Overrun, + /// Break condition + Break, } /// Interrupt handler. @@ -73,9 +114,16 @@ impl interrupt::typelevel::Handler 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 +534,13 @@ impl<'d, T: Instance> UarteRx<'d, T> { Self::new_inner(uarte, rxd.map_into(), Some(rts.map_into()), config) } + fn read_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).try_into() + } + fn new_inner( uarte: impl Peripheral

+ 'd, rxd: PeripheralRef<'d, AnyPin>, @@ -572,7 +627,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 +643,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 +661,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()); + + let maybe_err = self.read_and_clear_errors(); + if let Err(e) = maybe_err { + return Poll::Ready(Err(e)); + } if r.events_endrx.read().bits() != 0 { - return Poll::Ready(()); + return Poll::Ready(Ok(())); } Poll::Pending }) @@ -621,7 +690,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 +711,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.read_and_clear_errors() } } From d364447a34377c708fe6a7ea87aabda3ea1231ba Mon Sep 17 00:00:00 2001 From: Justin Beaurivage Date: Wed, 31 Jan 2024 14:16:58 -0500 Subject: [PATCH 04/45] Add error handling to UarteRxWithIdle --- embassy-nrf/src/uarte.rs | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 90d851139..97c887ab2 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -534,7 +534,8 @@ impl<'d, T: Instance> UarteRx<'d, T> { Self::new_inner(uarte, rxd.map_into(), Some(rts.map_into()), config) } - fn read_and_clear_errors(&mut self) -> Result<(), Error> { + /// 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) }); @@ -675,8 +676,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { let result = poll_fn(|cx| { s.endrx_waker.register(cx.waker()); - let maybe_err = self.read_and_clear_errors(); - if let Err(e) = maybe_err { + if let Err(e) = self.check_and_clear_errors() { return Poll::Ready(Err(e)); } if r.events_endrx.read().bits() != 0 { @@ -727,7 +727,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { compiler_fence(Ordering::SeqCst); r.events_rxstarted.reset(); - self.read_and_clear_errors() + self.check_and_clear_errors() } } @@ -794,8 +794,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 {} @@ -805,17 +809,23 @@ 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() { + return Poll::Ready(Err(e)); } + if r.events_endrx.read().bits() != 0 { + return Poll::Ready(Ok(())); + } + Poll::Pending }) .await; @@ -828,7 +838,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. @@ -853,13 +863,14 @@ 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; @@ -867,7 +878,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) } } From cc12eb9680513f380e9a04e76322ae4355c2b6b2 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage Date: Wed, 31 Jan 2024 14:20:06 -0500 Subject: [PATCH 05/45] Rustfmt --- embassy-nrf/src/uarte.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 97c887ab2..f29b5061b 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -676,7 +676,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { let result = poll_fn(|cx| { s.endrx_waker.register(cx.waker()); - if let Err(e) = self.check_and_clear_errors() { + if let Err(e) = self.check_and_clear_errors() { return Poll::Ready(Err(e)); } if r.events_endrx.read().bits() != 0 { @@ -810,7 +810,10 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { r.events_endrx.reset(); r.events_error.reset(); - r.intenset.write(|w| {w.endrx().set(); w.error().set()}); + r.intenset.write(|w| { + w.endrx().set(); + w.error().set() + }); compiler_fence(Ordering::SeqCst); @@ -864,7 +867,10 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { r.events_endrx.reset(); r.events_error.reset(); - r.intenclr.write(|w| {w.endrx().clear(); w.error().clear()}); + r.intenclr.write(|w| { + w.endrx().clear(); + w.error().clear() + }); compiler_fence(Ordering::SeqCst); From 4650a3566161ece4a743948129112402b9bb6e48 Mon Sep 17 00:00:00 2001 From: Matous Hybl Date: Sat, 3 Feb 2024 09:41:14 +0100 Subject: [PATCH 06/45] docs: Embassy in the wild - add air quality monitoring system --- docs/modules/ROOT/pages/embassy_in_the_wild.adoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/modules/ROOT/pages/embassy_in_the_wild.adoc b/docs/modules/ROOT/pages/embassy_in_the_wild.adoc index a1c31bfc7..dfe9fd6e3 100644 --- a/docs/modules/ROOT/pages/embassy_in_the_wild.adoc +++ b/docs/modules/ROOT/pages/embassy_in_the_wild.adoc @@ -7,3 +7,5 @@ Here are known examples of real-world projects which make use of Embassy. Feel f * link:https://github.com/card-io-ecg/card-io-fw[Card/IO firmware] - firmware for an open source ECG device ** Targets the ESP32-S3 or ESP32-C6 MCU * The link:https://github.com/lora-rs/lora-rs[lora-rs] project includes link:https://github.com/lora-rs/lora-rs/tree/main/examples/stm32l0/src/bin[various standalone examples] for NRF52840, RP2040, STM32L0 and STM32WL +** link:https://github.com/matoushybl/air-force-one[Air force one: A simple air quality monitoring system] +* Targets nRF52 and uses nrf-softdevice From 87a52f5eadbff91ff4fe2df807aa4e7bb3b29d79 Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Sat, 3 Feb 2024 17:04:20 -0600 Subject: [PATCH 07/45] stm32/usart: Add doc links to buffered uarts --- embassy-stm32/src/usart/buffered.rs | 4 ++++ embassy-stm32/src/usart/ringbuffered.rs | 2 ++ 2 files changed, 6 insertions(+) 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>, From 7817c8b17c2a65e799fb3f64e5e3a703ad4ace33 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 5 Feb 2024 09:10:53 +0100 Subject: [PATCH 08/45] docs: fix bullet point indentation --- docs/modules/ROOT/pages/embassy_in_the_wild.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/embassy_in_the_wild.adoc b/docs/modules/ROOT/pages/embassy_in_the_wild.adoc index dfe9fd6e3..85ad7f4a2 100644 --- a/docs/modules/ROOT/pages/embassy_in_the_wild.adoc +++ b/docs/modules/ROOT/pages/embassy_in_the_wild.adoc @@ -8,4 +8,4 @@ Here are known examples of real-world projects which make use of Embassy. Feel f ** Targets the ESP32-S3 or ESP32-C6 MCU * The link:https://github.com/lora-rs/lora-rs[lora-rs] project includes link:https://github.com/lora-rs/lora-rs/tree/main/examples/stm32l0/src/bin[various standalone examples] for NRF52840, RP2040, STM32L0 and STM32WL ** link:https://github.com/matoushybl/air-force-one[Air force one: A simple air quality monitoring system] -* Targets nRF52 and uses nrf-softdevice +*** Targets nRF52 and uses nrf-softdevice From 2575f597cc3aafeb9925511b12adf30f6a67bccb Mon Sep 17 00:00:00 2001 From: Justin Beaurivage Date: Mon, 5 Feb 2024 18:05:59 -0500 Subject: [PATCH 09/45] Address @Dirbaio's comments --- embassy-nrf/src/uarte.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index f29b5061b..de2966ba5 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -66,18 +66,16 @@ bitflags::bitflags! { } } -impl TryFrom for () { - type Error = Error; - +impl ErrorSource { #[inline] - fn try_from(errors: ErrorSource) -> Result { - if errors.contains(ErrorSource::OVERRUN) { + fn check(self) -> Result<(), Error> { + if self.contains(ErrorSource::OVERRUN) { Err(Error::Overrun) - } else if errors.contains(ErrorSource::PARITY) { + } else if self.contains(ErrorSource::PARITY) { Err(Error::Parity) - } else if errors.contains(ErrorSource::FRAMING) { + } else if self.contains(ErrorSource::FRAMING) { Err(Error::Framing) - } else if errors.contains(ErrorSource::BREAK) { + } else if self.contains(ErrorSource::BREAK) { Err(Error::Break) } else { Ok(()) @@ -539,7 +537,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { 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).try_into() + ErrorSource::from_bits_truncate(err_bits).check() } fn new_inner( @@ -677,6 +675,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { 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 { @@ -823,6 +822,7 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { s.endrx_waker.register(cx.waker()); 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 { From e72cc9fb24340ddf1151078779b3f00de9bff3ab Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Tue, 23 Jan 2024 16:33:47 +0100 Subject: [PATCH 10/45] fix(stm32/h7): use correct unit in vco clock check --- embassy-stm32/src/rcc/h.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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| { From aab5da1d3bfe10966bef88217492870b4148b28f Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Tue, 6 Feb 2024 12:30:04 +0100 Subject: [PATCH 11/45] fix(stm32h7/flash): enhance resilience to program sequence errors (pgserr) --- embassy-stm32/src/flash/h7.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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); From c267cb9ab764176bc8514535f4db8ac2331e30ce Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Tue, 6 Feb 2024 16:25:45 +0100 Subject: [PATCH 12/45] feat: enhance bootloader for multiple flash support --- embassy-boot/src/boot_loader.rs | 20 ++++--- embassy-boot/src/firmware_updater/asynch.rs | 13 +++-- embassy-boot/src/firmware_updater/blocking.rs | 14 +++-- .../bootloader/stm32-dual-bank/Cargo.toml | 57 +++++++++++++++++++ .../boot/bootloader/stm32-dual-bank/README.md | 44 ++++++++++++++ .../boot/bootloader/stm32-dual-bank/build.rs | 27 +++++++++ .../boot/bootloader/stm32-dual-bank/memory.x | 18 ++++++ .../bootloader/stm32-dual-bank/src/main.rs | 53 +++++++++++++++++ examples/boot/bootloader/stm32/src/main.rs | 2 +- .../boot/bootloader/stm32wb-dfu/src/main.rs | 4 +- 10 files changed, 231 insertions(+), 21 deletions(-) create mode 100644 examples/boot/bootloader/stm32-dual-bank/Cargo.toml create mode 100644 examples/boot/bootloader/stm32-dual-bank/README.md create mode 100644 examples/boot/bootloader/stm32-dual-bank/build.rs create mode 100644 examples/boot/bootloader/stm32-dual-bank/memory.x create mode 100644 examples/boot/bootloader/stm32-dual-bank/src/main.rs diff --git a/embassy-boot/src/boot_loader.rs b/embassy-boot/src/boot_loader.rs index e568001bc..54ae8a34b 100644 --- a/embassy-boot/src/boot_loader.rs +++ b/embassy-boot/src/boot_loader.rs @@ -49,16 +49,20 @@ pub struct BootLoaderConfig { pub state: STATE, } -impl<'a, FLASH: NorFlash> +impl<'a, ActiveFlash: NorFlash, DFUFlash: NorFlash, StateFlash: NorFlash> BootLoaderConfig< - BlockingPartition<'a, NoopRawMutex, FLASH>, - BlockingPartition<'a, NoopRawMutex, FLASH>, - BlockingPartition<'a, NoopRawMutex, FLASH>, + BlockingPartition<'a, NoopRawMutex, ActiveFlash>, + BlockingPartition<'a, NoopRawMutex, DFUFlash>, + BlockingPartition<'a, NoopRawMutex, StateFlash>, > { /// Create a bootloader config from the flash and address symbols defined in the linkerfile // #[cfg(target_os = "none")] - pub fn from_linkerfile_blocking(flash: &'a Mutex>) -> Self { + pub fn from_linkerfile_blocking( + active_flash: &'a Mutex>, + dfu_flash: &'a Mutex>, + state_flash: &'a Mutex>, + ) -> Self { extern "C" { static __bootloader_state_start: u32; static __bootloader_state_end: u32; @@ -73,21 +77,21 @@ impl<'a, FLASH: NorFlash> let end = &__bootloader_active_end as *const u32 as u32; trace!("ACTIVE: 0x{:x} - 0x{:x}", start, end); - BlockingPartition::new(flash, start, end - start) + BlockingPartition::new(active_flash, start, end - start) }; let dfu = unsafe { let start = &__bootloader_dfu_start as *const u32 as u32; let end = &__bootloader_dfu_end as *const u32 as u32; trace!("DFU: 0x{:x} - 0x{:x}", start, end); - BlockingPartition::new(flash, start, end - start) + BlockingPartition::new(dfu_flash, start, end - start) }; let state = unsafe { let start = &__bootloader_state_start as *const u32 as u32; let end = &__bootloader_state_end as *const u32 as u32; trace!("STATE: 0x{:x} - 0x{:x}", start, end); - BlockingPartition::new(flash, start, end - start) + BlockingPartition::new(state_flash, start, end - start) }; Self { active, dfu, state } diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs index 2e43e1cc1..5634b48d4 100644 --- a/embassy-boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/src/firmware_updater/asynch.rs @@ -16,11 +16,14 @@ pub struct FirmwareUpdater<'d, DFU: NorFlash, STATE: NorFlash> { } #[cfg(target_os = "none")] -impl<'a, FLASH: NorFlash> - FirmwareUpdaterConfig, Partition<'a, NoopRawMutex, FLASH>> +impl<'a, DFUFlash: NorFlash, StateFlash: NorFlash> + FirmwareUpdaterConfig, Partition<'a, NoopRawMutex, StateFlash>> { /// Create a firmware updater config from the flash and address symbols defined in the linkerfile - pub fn from_linkerfile(flash: &'a embassy_sync::mutex::Mutex) -> Self { + pub fn from_linkerfile( + dfu_flash: &'a embassy_sync::mutex::Mutex, + state_flash: &'a embassy_sync::mutex::Mutex, + ) -> Self { extern "C" { static __bootloader_state_start: u32; static __bootloader_state_end: u32; @@ -33,14 +36,14 @@ impl<'a, FLASH: NorFlash> let end = &__bootloader_dfu_end as *const u32 as u32; trace!("DFU: 0x{:x} - 0x{:x}", start, end); - Partition::new(flash, start, end - start) + Partition::new(dfu_flash, start, end - start) }; let state = unsafe { let start = &__bootloader_state_start as *const u32 as u32; let end = &__bootloader_state_end as *const u32 as u32; trace!("STATE: 0x{:x} - 0x{:x}", start, end); - Partition::new(flash, start, end - start) + Partition::new(state_flash, start, end - start) }; Self { dfu, state } diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index f1368540d..3814b6c31 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -16,12 +16,16 @@ pub struct BlockingFirmwareUpdater<'d, DFU: NorFlash, STATE: NorFlash> { } #[cfg(target_os = "none")] -impl<'a, FLASH: NorFlash> - FirmwareUpdaterConfig, BlockingPartition<'a, NoopRawMutex, FLASH>> +impl<'a, DFUFlash: NorFlash, StateFlash: NorFlash> + FirmwareUpdaterConfig< + BlockingPartition<'a, NoopRawMutex, DFUFlash>, + BlockingPartition<'a, NoopRawMutex, StateFlash>, + > { /// Create a firmware updater config from the flash and address symbols defined in the linkerfile pub fn from_linkerfile_blocking( - flash: &'a embassy_sync::blocking_mutex::Mutex>, + dfu_flash: &'a embassy_sync::blocking_mutex::Mutex>, + state_flash: &'a embassy_sync::blocking_mutex::Mutex>, ) -> Self { extern "C" { static __bootloader_state_start: u32; @@ -35,14 +39,14 @@ impl<'a, FLASH: NorFlash> let end = &__bootloader_dfu_end as *const u32 as u32; trace!("DFU: 0x{:x} - 0x{:x}", start, end); - BlockingPartition::new(flash, start, end - start) + BlockingPartition::new(dfu_flash, start, end - start) }; let state = unsafe { let start = &__bootloader_state_start as *const u32 as u32; let end = &__bootloader_state_end as *const u32 as u32; trace!("STATE: 0x{:x} - 0x{:x}", start, end); - BlockingPartition::new(flash, start, end - start) + BlockingPartition::new(state_flash, start, end - start) }; Self { dfu, state } 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/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[..]); From 5f36108896d909ed990a587941d74e0488bcd190 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?xgroleau=F0=9F=90=A2?= Date: Tue, 6 Feb 2024 10:38:48 -0500 Subject: [PATCH 13/45] fix: rtos-usage time missing --- embassy-executor/Cargo.toml | 4 ++++ embassy-executor/src/raw/mod.rs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 409df0d75..0762e2434 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -34,6 +34,7 @@ log = { version = "0.4.14", optional = true } rtos-trace = { version = "0.1.2", optional = true } embassy-executor-macros = { version = "0.4.0", path = "../embassy-executor-macros" } +embassy-time = { version = "0.3.0", path = "../embassy-time", optional = true } embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver", optional = true } embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver", optional = true } critical-section = "1.1" @@ -71,6 +72,9 @@ turbowakers = [] ## Use the executor-integrated `embassy-time` timer queue. integrated-timers = ["dep:embassy-time-driver", "dep:embassy-time-queue-driver"] +# Support for rtos trace require time +rtos-trace = ["dep:rtos-trace", "dep:embassy-time"] + #! ### Architecture _arch = [] # some arch was picked ## std diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 3f00be4a8..fbc0481c2 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -588,7 +588,7 @@ impl rtos_trace::RtosTraceOSCallbacks for Executor { } #[cfg(feature = "integrated-timers")] fn time() -> u64 { - Instant::now().as_micros() + embassy_time::Instant::now().as_millis() } #[cfg(not(feature = "integrated-timers"))] fn time() -> u64 { From af2b4df833902fa8d42cb133c52733fe0b848bc7 Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Wed, 7 Feb 2024 11:32:13 +0100 Subject: [PATCH 14/45] refactor(boot): change generics name to match existing convention --- embassy-boot/src/boot_loader.rs | 14 +++++++------- embassy-boot/src/firmware_updater/asynch.rs | 8 ++++---- embassy-boot/src/firmware_updater/blocking.rs | 11 ++++------- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/embassy-boot/src/boot_loader.rs b/embassy-boot/src/boot_loader.rs index 54ae8a34b..c433ce439 100644 --- a/embassy-boot/src/boot_loader.rs +++ b/embassy-boot/src/boot_loader.rs @@ -49,19 +49,19 @@ pub struct BootLoaderConfig { pub state: STATE, } -impl<'a, ActiveFlash: NorFlash, DFUFlash: NorFlash, StateFlash: NorFlash> +impl<'a, ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BootLoaderConfig< - BlockingPartition<'a, NoopRawMutex, ActiveFlash>, - BlockingPartition<'a, NoopRawMutex, DFUFlash>, - BlockingPartition<'a, NoopRawMutex, StateFlash>, + BlockingPartition<'a, NoopRawMutex, ACTIVE>, + BlockingPartition<'a, NoopRawMutex, DFU>, + BlockingPartition<'a, NoopRawMutex, STATE>, > { /// Create a bootloader config from the flash and address symbols defined in the linkerfile // #[cfg(target_os = "none")] pub fn from_linkerfile_blocking( - active_flash: &'a Mutex>, - dfu_flash: &'a Mutex>, - state_flash: &'a Mutex>, + active_flash: &'a Mutex>, + dfu_flash: &'a Mutex>, + state_flash: &'a Mutex>, ) -> Self { extern "C" { static __bootloader_state_start: u32; diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs index 5634b48d4..668f16f16 100644 --- a/embassy-boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/src/firmware_updater/asynch.rs @@ -16,13 +16,13 @@ pub struct FirmwareUpdater<'d, DFU: NorFlash, STATE: NorFlash> { } #[cfg(target_os = "none")] -impl<'a, DFUFlash: NorFlash, StateFlash: NorFlash> - FirmwareUpdaterConfig, Partition<'a, NoopRawMutex, StateFlash>> +impl<'a, DFU: NorFlash, STATE: NorFlash> + FirmwareUpdaterConfig, Partition<'a, NoopRawMutex, STATE>> { /// Create a firmware updater config from the flash and address symbols defined in the linkerfile pub fn from_linkerfile( - dfu_flash: &'a embassy_sync::mutex::Mutex, - state_flash: &'a embassy_sync::mutex::Mutex, + dfu_flash: &'a embassy_sync::mutex::Mutex, + state_flash: &'a embassy_sync::mutex::Mutex, ) -> Self { extern "C" { static __bootloader_state_start: u32; diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index 3814b6c31..cf850fce3 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -16,16 +16,13 @@ pub struct BlockingFirmwareUpdater<'d, DFU: NorFlash, STATE: NorFlash> { } #[cfg(target_os = "none")] -impl<'a, DFUFlash: NorFlash, StateFlash: NorFlash> - FirmwareUpdaterConfig< - BlockingPartition<'a, NoopRawMutex, DFUFlash>, - BlockingPartition<'a, NoopRawMutex, StateFlash>, - > +impl<'a, DFU: NorFlash, STATE: NorFlash> + FirmwareUpdaterConfig, BlockingPartition<'a, NoopRawMutex, STATE>> { /// Create a firmware updater config from the flash and address symbols defined in the linkerfile pub fn from_linkerfile_blocking( - dfu_flash: &'a embassy_sync::blocking_mutex::Mutex>, - state_flash: &'a embassy_sync::blocking_mutex::Mutex>, + dfu_flash: &'a embassy_sync::blocking_mutex::Mutex>, + state_flash: &'a embassy_sync::blocking_mutex::Mutex>, ) -> Self { extern "C" { static __bootloader_state_start: u32; From 4a72f946e42dde3dbfbf46a676d5b40617e4c92f Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Wed, 7 Feb 2024 11:38:05 +0100 Subject: [PATCH 15/45] fix(boot): update stm32wb-dfu example readme --- examples/boot/bootloader/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/bootloader/stm32wb-dfu/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 ``` From cfc3e966331310b7210c94339cf8f111a65d9e53 Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Wed, 7 Feb 2024 12:50:48 +0100 Subject: [PATCH 16/45] fix(boot): update examples --- examples/boot/application/nrf/src/bin/a.rs | 2 +- examples/boot/application/rp/src/bin/a.rs | 2 +- examples/boot/application/stm32f3/memory.x | 4 ++-- .../boot/application/stm32f3/src/bin/a.rs | 2 +- .../boot/application/stm32f7/src/bin/a.rs | 2 +- .../boot/application/stm32h7/src/bin/a.rs | 2 +- examples/boot/application/stm32l0/memory.x | 4 ++-- .../boot/application/stm32l0/src/bin/a.rs | 2 +- examples/boot/application/stm32l1/memory.x | 4 ++-- .../boot/application/stm32l1/src/bin/a.rs | 2 +- examples/boot/application/stm32l4/memory.x | 4 ++-- .../boot/application/stm32l4/src/bin/a.rs | 2 +- .../boot/application/stm32wb-dfu/README.md | 24 ++----------------- .../boot/application/stm32wb-dfu/src/main.rs | 2 +- examples/boot/application/stm32wl/memory.x | 4 ++-- .../boot/application/stm32wl/src/bin/a.rs | 2 +- examples/boot/bootloader/nrf/src/main.rs | 2 +- examples/boot/bootloader/rp/src/main.rs | 2 +- 18 files changed, 24 insertions(+), 44 deletions(-) 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); From 634c409c55c71ca2871cd05d4a7754654926db48 Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Wed, 7 Feb 2024 13:06:48 +0100 Subject: [PATCH 17/45] docs(boot): document from_linkerfile_blocking method --- embassy-boot/src/boot_loader.rs | 33 ++++++++++++++++++- embassy-boot/src/firmware_updater/blocking.rs | 32 +++++++++++++++++- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/embassy-boot/src/boot_loader.rs b/embassy-boot/src/boot_loader.rs index c433ce439..2a5f024f6 100644 --- a/embassy-boot/src/boot_loader.rs +++ b/embassy-boot/src/boot_loader.rs @@ -56,7 +56,38 @@ impl<'a, ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BlockingPartition<'a, NoopRawMutex, STATE>, > { - /// Create a bootloader config from the flash and address symbols defined in the linkerfile + /// Constructs a `BootLoaderConfig` instance from flash memory and address symbols defined in the linker file. + /// + /// This method initializes `BlockingPartition` instances for the active, DFU (Device Firmware Update), + /// and state partitions, leveraging start and end addresses specified by the linker. These partitions + /// are critical for managing firmware updates, application state, and boot operations within the bootloader. + /// + /// # Parameters + /// - `active_flash`: A reference to a mutex-protected `RefCell` for the active partition's flash interface. + /// - `dfu_flash`: A reference to a mutex-protected `RefCell` for the DFU partition's flash interface. + /// - `state_flash`: A reference to a mutex-protected `RefCell` for the state partition's flash interface. + /// + /// # Safety + /// The method contains `unsafe` blocks for dereferencing raw pointers that represent the start and end addresses + /// of the bootloader's partitions in flash memory. It is crucial that these addresses are accurately defined + /// in the memory.x file to prevent undefined behavior. + /// + /// The caller must ensure that the memory regions defined by these symbols are valid and that the flash memory + /// interfaces provided are compatible with these regions. + /// + /// # Returns + /// A `BootLoaderConfig` instance with `BlockingPartition` instances for the active, DFU, and state partitions. + /// + /// # Example + /// ```no_run + /// // Assume `active_flash`, `dfu_flash`, and `state_flash` all share the same flash memory interface. + /// 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, &flash, &flash); + /// // `config` can now be used to create a `BootLoader` instance for managing boot operations. + /// ``` + /// Working examples can be found in the bootloader examples folder. // #[cfg(target_os = "none")] pub fn from_linkerfile_blocking( active_flash: &'a Mutex>, diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index cf850fce3..a29efabf0 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -19,7 +19,37 @@ pub struct BlockingFirmwareUpdater<'d, DFU: NorFlash, STATE: NorFlash> { impl<'a, DFU: NorFlash, STATE: NorFlash> FirmwareUpdaterConfig, BlockingPartition<'a, NoopRawMutex, STATE>> { - /// Create a firmware updater config from the flash and address symbols defined in the linkerfile + /// Constructs a `FirmwareUpdaterConfig` instance from flash memory and address symbols defined in the linker file. + /// + /// This method initializes `BlockingPartition` instances for the DFU (Device Firmware Update), and state + /// partitions, leveraging start and end addresses specified by the linker. These partitions are critical + /// for managing firmware updates, application state, and boot operations within the bootloader. + /// + /// # Parameters + /// - `dfu_flash`: A reference to a mutex-protected `RefCell` for the DFU partition's flash interface. + /// - `state_flash`: A reference to a mutex-protected `RefCell` for the state partition's flash interface. + /// + /// # Safety + /// The method contains `unsafe` blocks for dereferencing raw pointers that represent the start and end addresses + /// of the bootloader's partitions in flash memory. It is crucial that these addresses are accurately defined + /// in the memory.x file to prevent undefined behavior. + /// + /// The caller must ensure that the memory regions defined by these symbols are valid and that the flash memory + /// interfaces provided are compatible with these regions. + /// + /// # Returns + /// A `FirmwareUpdaterConfig` instance with `BlockingPartition` instances for the DFU, and state partitions. + /// + /// # Example + /// ```no_run + /// // Assume `dfu_flash`, and `state_flash` share the same flash memory interface. + /// let layout = Flash::new_blocking(p.FLASH).into_blocking_regions(); + /// let flash = Mutex::new(RefCell::new(layout.bank1_region)); + /// + /// let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash); + /// // `config` can now be used to create a `FirmwareUpdater` instance for managing boot operations. + /// ``` + /// Working examples can be found in the bootloader examples folder. pub fn from_linkerfile_blocking( dfu_flash: &'a embassy_sync::blocking_mutex::Mutex>, state_flash: &'a embassy_sync::blocking_mutex::Mutex>, From e391b9b74c95090548c50b6f05a859f0220c42f9 Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Wed, 7 Feb 2024 14:37:38 +0100 Subject: [PATCH 18/45] docs(boot): ignore partial non-compilable example in rustdoc --- embassy-boot/src/boot_loader.rs | 2 +- embassy-boot/src/firmware_updater/blocking.rs | 2 +- embassy-boot/src/firmware_updater/mod.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-boot/src/boot_loader.rs b/embassy-boot/src/boot_loader.rs index 2a5f024f6..ca1a1b10c 100644 --- a/embassy-boot/src/boot_loader.rs +++ b/embassy-boot/src/boot_loader.rs @@ -79,7 +79,7 @@ impl<'a, ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> /// A `BootLoaderConfig` instance with `BlockingPartition` instances for the active, DFU, and state partitions. /// /// # Example - /// ```no_run + /// ```ignore /// // Assume `active_flash`, `dfu_flash`, and `state_flash` all share the same flash memory interface. /// let layout = Flash::new_blocking(p.FLASH).into_blocking_regions(); /// let flash = Mutex::new(RefCell::new(layout.bank1_region)); diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index a29efabf0..4044871f0 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -41,7 +41,7 @@ impl<'a, DFU: NorFlash, STATE: NorFlash> /// A `FirmwareUpdaterConfig` instance with `BlockingPartition` instances for the DFU, and state partitions. /// /// # Example - /// ```no_run + /// ```ignore /// // Assume `dfu_flash`, and `state_flash` share the same flash memory interface. /// let layout = Flash::new_blocking(p.FLASH).into_blocking_regions(); /// let flash = Mutex::new(RefCell::new(layout.bank1_region)); diff --git a/embassy-boot/src/firmware_updater/mod.rs b/embassy-boot/src/firmware_updater/mod.rs index 4814786bf..4c4f4f10b 100644 --- a/embassy-boot/src/firmware_updater/mod.rs +++ b/embassy-boot/src/firmware_updater/mod.rs @@ -8,7 +8,7 @@ use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; /// Firmware updater flash configuration holding the two flashes used by the updater /// /// If only a single flash is actually used, then that flash should be partitioned into two partitions before use. -/// The easiest way to do this is to use [`FirmwareUpdaterConfig::from_linkerfile`] or [`FirmwareUpdaterConfig::from_linkerfile_blocking`] which will partition +/// The easiest way to do this is to use [`FirmwareUpdaterConfig::from_linkerfile_blocking`] or [`FirmwareUpdaterConfig::from_linkerfile_blocking`] which will partition /// the provided flash according to symbols defined in the linkerfile. pub struct FirmwareUpdaterConfig { /// The dfu flash partition From 74fbe27a87fc95f75f8c9251520a8dea889159cc Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Wed, 7 Feb 2024 14:55:08 +0100 Subject: [PATCH 19/45] ci(boot): add new example and fix bootloader/stm32wb-dfu --- ci.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index df9e09848..f3742ad76 100755 --- a/ci.sh +++ b/ci.sh @@ -194,7 +194,8 @@ cargo batch \ --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \ --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \ - --- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabihf \ + --- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabihf --features embassy-stm32/stm32wb55rg \ + --- build --release --manifest-path examples/boot/bootloader/stm32-dual-bank/Cargo.toml --target thumbv7em-none-eabihf --features embassy-stm32/stm32h747xi-cm7 \ --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/stm32f103c8 \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/stm32f429zi \ From 2e15d1371a891cc3456d7b9fd22a68291770df41 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 8 Feb 2024 00:31:21 +0100 Subject: [PATCH 20/45] Delete tests/stm32/teleprobe.sh --- tests/stm32/teleprobe.sh | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100755 tests/stm32/teleprobe.sh 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 From ab8f25fd78582aab68c9820e4b4dd9771a1ded65 Mon Sep 17 00:00:00 2001 From: shufps Date: Thu, 8 Feb 2024 10:47:26 +0100 Subject: [PATCH 21/45] added support for ADC of L0s --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/adc/mod.rs | 23 ++++++++++++----------- embassy-stm32/src/adc/resolution.rs | 8 ++++---- embassy-stm32/src/adc/sample_time.rs | 2 +- embassy-stm32/src/adc/v1.rs | 21 +++++++++++++++++++++ 5 files changed, 40 insertions(+), 18 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 8f0fc1c59..61d70b732 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-e702b4d564bc9e3c8a5c0141a11efdc5f7ee8f24" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d7c933984fe0cbd120b6aaa7742bd585f89fa786" } 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-e702b4d564bc9e3c8a5c0141a11efdc5f7ee8f24", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d7c933984fe0cbd120b6aaa7742bd585f89fa786", 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..13a7ead3e 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -6,6 +6,10 @@ use embassy_hal_internal::into_ref; use embedded_hal_02::blocking::delay::DelayUs; use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; + +#[cfg(adc_l0)] +use stm32_metapac::adc::vals::Ckmode; + use crate::interrupt::typelevel::Interrupt; use crate::peripherals::ADC; use crate::{interrupt, Peripheral}; @@ -30,8 +34,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 @@ -72,6 +81,11 @@ impl<'d, T: Instance> Adc<'d, T> { // 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 +111,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 +148,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(); From 8dff89bfd99140bc7de48bb5de600a2aeb920681 Mon Sep 17 00:00:00 2001 From: shufps Date: Thu, 8 Feb 2024 11:07:30 +0100 Subject: [PATCH 22/45] added ADC example running on L0 --- examples/stm32l0/src/bin/adc.rs | 46 +++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 examples/stm32l0/src/bin/adc.rs diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs new file mode 100644 index 000000000..93bf5adc6 --- /dev/null +++ b/examples/stm32l0/src/bin/adc.rs @@ -0,0 +1,46 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_stm32::Config; +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) { + // enable HSI because default is MSI but ADC doesn't support + // this as clock source on L0s and uses HSI by default + let mut config = Config::default(); + config.rcc.hsi = true; + let p = embassy_stm32::init(config); + + 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; + } +} From 158d7dbc8f4714c94cf58e48942543726d717f57 Mon Sep 17 00:00:00 2001 From: shufps Date: Thu, 8 Feb 2024 11:11:13 +0100 Subject: [PATCH 23/45] cargo fmt --- examples/stm32l0/src/bin/adc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs index 93bf5adc6..f94bf907f 100644 --- a/examples/stm32l0/src/bin/adc.rs +++ b/examples/stm32l0/src/bin/adc.rs @@ -2,10 +2,10 @@ #![no_main] use defmt::*; -use embassy_stm32::Config; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::peripherals::ADC; +use embassy_stm32::Config; use embassy_stm32::{adc, bind_interrupts}; use embassy_time::{Delay, Timer}; use {defmt_rtt as _, panic_probe as _}; From 8d0a9bbefb29cab54ba37106a54e5e1f1f04a383 Mon Sep 17 00:00:00 2001 From: shufps Date: Thu, 8 Feb 2024 11:14:14 +0100 Subject: [PATCH 24/45] clippy --- embassy-stm32/src/adc/v1.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 13a7ead3e..92529b036 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -5,11 +5,10 @@ use core::task::Poll; use embassy_hal_internal::into_ref; use embedded_hal_02::blocking::delay::DelayUs; -use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; - #[cfg(adc_l0)] use stm32_metapac::adc::vals::Ckmode; +use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; use crate::interrupt::typelevel::Interrupt; use crate::peripherals::ADC; use crate::{interrupt, Peripheral}; From b2b2abeb333f9bacaa43910d1b75308a3f1c5c4e Mon Sep 17 00:00:00 2001 From: shufps Date: Thu, 8 Feb 2024 11:14:29 +0100 Subject: [PATCH 25/45] clippy --- examples/stm32l0/src/bin/adc.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs index f94bf907f..eee69211c 100644 --- a/examples/stm32l0/src/bin/adc.rs +++ b/examples/stm32l0/src/bin/adc.rs @@ -5,8 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::peripherals::ADC; -use embassy_stm32::Config; -use embassy_stm32::{adc, bind_interrupts}; +use embassy_stm32::{adc, bind_interrupts, Config}; use embassy_time::{Delay, Timer}; use {defmt_rtt as _, panic_probe as _}; From dabe48c3bd647f13d62d15bbb17983be541f7583 Mon Sep 17 00:00:00 2001 From: shufps Date: Thu, 8 Feb 2024 11:15:28 +0100 Subject: [PATCH 26/45] fmt --- embassy-stm32/src/adc/v1.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 92529b036..83bf5aece 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -4,7 +4,6 @@ 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; From 34c71b58cf281e7a0d5517a3f3939477dadb5575 Mon Sep 17 00:00:00 2001 From: shufps Date: Thu, 8 Feb 2024 11:28:53 +0100 Subject: [PATCH 27/45] made adc example working with default clock configuration and switched in `v1` to PCLK/2 per default --- embassy-stm32/src/adc/v1.rs | 4 ++++ examples/stm32l0/src/bin/adc.rs | 9 ++------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 83bf5aece..37115dfab 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -76,6 +76,10 @@ 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)); diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs index eee69211c..adeaa208a 100644 --- a/examples/stm32l0/src/bin/adc.rs +++ b/examples/stm32l0/src/bin/adc.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::peripherals::ADC; -use embassy_stm32::{adc, bind_interrupts, Config}; +use embassy_stm32::{adc, bind_interrupts}; use embassy_time::{Delay, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -15,12 +15,7 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { - // enable HSI because default is MSI but ADC doesn't support - // this as clock source on L0s and uses HSI by default - let mut config = Config::default(); - config.rcc.hsi = true; - let p = embassy_stm32::init(config); - + let p = embassy_stm32::init(Default::default()); info!("Hello World!"); let mut adc = Adc::new(p.ADC, Irqs, &mut Delay); From d48620d58f588936a5c74840063fe422764b749f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?xgroleau=F0=9F=90=A2?= Date: Tue, 6 Feb 2024 15:50:28 -0500 Subject: [PATCH 28/45] fix: compilation for rtos trace --- ci.sh | 2 ++ embassy-executor/Cargo.toml | 4 ---- embassy-executor/src/raw/mod.rs | 12 +++++++++++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/ci.sh b/ci.sh index df9e09848..4f28c5e92 100755 --- a/ci.sh +++ b/ci.sh @@ -23,6 +23,8 @@ cargo batch \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,rtos-trace \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,integrated-timers,rtos-trace \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,integrated-timers \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt \ diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 0762e2434..409df0d75 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -34,7 +34,6 @@ log = { version = "0.4.14", optional = true } rtos-trace = { version = "0.1.2", optional = true } embassy-executor-macros = { version = "0.4.0", path = "../embassy-executor-macros" } -embassy-time = { version = "0.3.0", path = "../embassy-time", optional = true } embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver", optional = true } embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver", optional = true } critical-section = "1.1" @@ -72,9 +71,6 @@ turbowakers = [] ## Use the executor-integrated `embassy-time` timer queue. integrated-timers = ["dep:embassy-time-driver", "dep:embassy-time-queue-driver"] -# Support for rtos trace require time -rtos-trace = ["dep:rtos-trace", "dep:embassy-time"] - #! ### Architecture _arch = [] # some arch was picked ## std diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index fbc0481c2..3d221c94b 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -581,6 +581,15 @@ impl embassy_time_queue_driver::TimerQueue for TimerQueue { #[cfg(feature = "integrated-timers")] embassy_time_queue_driver::timer_queue_impl!(static TIMER_QUEUE: TimerQueue = TimerQueue); +#[cfg(all(feature = "rtos-trace", feature = "integrated-timers"))] +const fn gcd(a: u64, b: u64) -> u64 { + if b == 0 { + a + } else { + gcd(b, a % b) + } +} + #[cfg(feature = "rtos-trace")] impl rtos_trace::RtosTraceOSCallbacks for Executor { fn task_list() { @@ -588,7 +597,8 @@ impl rtos_trace::RtosTraceOSCallbacks for Executor { } #[cfg(feature = "integrated-timers")] fn time() -> u64 { - embassy_time::Instant::now().as_millis() + const GCD_1M: u64 = gcd(embassy_time_driver::TICK_HZ, 1_000_000); + embassy_time_driver::now() * (1_000_00 / GCD_1M) / (embassy_time_driver::TICK_HZ / GCD_1M); } #[cfg(not(feature = "integrated-timers"))] fn time() -> u64 { From 09613e90de92ba43974796efec13e38adf4c3ac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?xgroleau=F0=9F=90=A2?= Date: Thu, 8 Feb 2024 09:01:07 -0500 Subject: [PATCH 29/45] fix: missing 0 --- embassy-executor/src/raw/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 3d221c94b..3c9407d39 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -598,7 +598,7 @@ impl rtos_trace::RtosTraceOSCallbacks for Executor { #[cfg(feature = "integrated-timers")] fn time() -> u64 { const GCD_1M: u64 = gcd(embassy_time_driver::TICK_HZ, 1_000_000); - embassy_time_driver::now() * (1_000_00 / GCD_1M) / (embassy_time_driver::TICK_HZ / GCD_1M); + embassy_time_driver::now() * (1_000_000 / GCD_1M) / (embassy_time_driver::TICK_HZ / GCD_1M); } #[cfg(not(feature = "integrated-timers"))] fn time() -> u64 { From 262518cfe5c303034f71393367914bec221c71be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?xgroleau=F0=9F=90=A2?= Date: Thu, 8 Feb 2024 09:02:07 -0500 Subject: [PATCH 30/45] fix: removed trailing comma --- embassy-executor/src/raw/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 3c9407d39..3d5e3ab9f 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -598,7 +598,7 @@ impl rtos_trace::RtosTraceOSCallbacks for Executor { #[cfg(feature = "integrated-timers")] fn time() -> u64 { const GCD_1M: u64 = gcd(embassy_time_driver::TICK_HZ, 1_000_000); - embassy_time_driver::now() * (1_000_000 / GCD_1M) / (embassy_time_driver::TICK_HZ / GCD_1M); + embassy_time_driver::now() * (1_000_000 / GCD_1M) / (embassy_time_driver::TICK_HZ / GCD_1M) } #[cfg(not(feature = "integrated-timers"))] fn time() -> u64 { From 27411658d9710451b04efe014747606018646527 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Thu, 8 Feb 2024 21:43:05 +0200 Subject: [PATCH 31/45] nrf: spim/spis: Add size checks for EasyDMA buffer On most nRF chips, maximum buffer size for EasyDMA is 255, thus we never got any data when attempting to use 256 bytes as RX/TX buffer. --- embassy-nrf/src/spim.rs | 14 +++++++++++--- embassy-nrf/src/spis.rs | 8 +++++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 6b6f79188..8937159df 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -13,7 +13,7 @@ pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MO pub use pac::spim0::config::ORDER_A as BitOrder; pub use pac::spim0::frequency::FREQUENCY_A as Frequency; -use crate::chip::FORCE_COPY_BUFFER_SIZE; +use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; use crate::gpio::sealed::Pin as _; use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; use crate::interrupt::typelevel::Interrupt; @@ -25,9 +25,9 @@ use crate::{interrupt, pac, Peripheral}; #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] pub enum Error { - /// TX buffer was too long. + /// Supplied TX buffer overflows EasyDMA transmit buffer TxBufferTooLong, - /// RX buffer was too long. + /// Supplied RX buffer overflows EasyDMA receive buffer RxBufferTooLong, /// EasyDMA can only read from data memory, read only buffers in flash will fail. BufferNotInRAM, @@ -220,11 +220,19 @@ impl<'d, T: Instance> Spim<'d, T> { // Set up the DMA write. let (ptr, tx_len) = slice_ptr_parts(tx); + if tx_len > EASY_DMA_SIZE { + return Err(Error::TxBufferTooLong); + } + r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(tx_len as _) }); // Set up the DMA read. let (ptr, rx_len) = slice_ptr_parts_mut(rx); + if rx_len > EASY_DMA_SIZE { + return Err(Error::RxBufferTooLong); + } + r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(rx_len as _) }); diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs index 60f4c9865..772ca40cc 100644 --- a/embassy-nrf/src/spis.rs +++ b/embassy-nrf/src/spis.rs @@ -11,7 +11,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; pub use pac::spis0::config::ORDER_A as BitOrder; -use crate::chip::FORCE_COPY_BUFFER_SIZE; +use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; use crate::gpio::sealed::Pin as _; use crate::gpio::{self, AnyPin, Pin as GpioPin}; use crate::interrupt::typelevel::Interrupt; @@ -227,11 +227,17 @@ impl<'d, T: Instance> Spis<'d, T> { // Set up the DMA write. let (ptr, len) = slice_ptr_parts(tx); + if len > EASY_DMA_SIZE { + return Err(Error::TxBufferTooLong); + } r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); // Set up the DMA read. let (ptr, len) = slice_ptr_parts_mut(rx); + if len > EASY_DMA_SIZE { + return Err(Error::RxBufferTooLong); + } r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); From bb743420be5f7347cab7e2cc19a427b93e90b1e8 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Fri, 9 Feb 2024 10:14:34 +0200 Subject: [PATCH 32/45] faq: Fix typo --- docs/modules/ROOT/pages/best_practices.adoc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/modules/ROOT/pages/best_practices.adoc b/docs/modules/ROOT/pages/best_practices.adoc index 1e02f9ba9..bfcedec06 100644 --- a/docs/modules/ROOT/pages/best_practices.adoc +++ b/docs/modules/ROOT/pages/best_practices.adoc @@ -3,8 +3,10 @@ Over time, a couple of best practices have emerged. The following list should serve as a guideline for developers writing embedded software in _Rust_, especially in the context of the _Embassy_ framework. == Passing Buffers by Reference -It may be tempting to pass arrays or wrappers, like link:https://docs.rs/heapless/latest/heapless/[`heapless::Vec`], to a function or return one just like you would with a `std::Vec`. However, in most embedded applications you don't want to spend ressources on an allocator and end up placing buffers on the stack. -This, however, can easily blow up your stack if you are not careful. +It may be tempting to pass arrays or wrappers, like link:https://docs.rs/heapless/latest/heapless/[`heapless::Vec`], +to a function or return one just like you would with a `std::Vec`. However, in most embedded applications you don't +want to spend resources on an allocator and end up placing buffers on the stack. This, however, can easily blow up +your stack if you are not careful. Consider the following example: [,rust] From 6e2d54c40bfdb07b6bb28f5fd8009846d0695f67 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Fri, 9 Feb 2024 10:14:55 +0200 Subject: [PATCH 33/45] faq: Nightly is not required anymore --- docs/modules/ROOT/pages/faq.adoc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/modules/ROOT/pages/faq.adoc b/docs/modules/ROOT/pages/faq.adoc index 05ff7c598..c8695a01a 100644 --- a/docs/modules/ROOT/pages/faq.adoc +++ b/docs/modules/ROOT/pages/faq.adoc @@ -29,11 +29,10 @@ If you see an error like this: You are likely missing some features of the `embassy-executor` crate. -For Cortex-M targets, consider making sure that ALL of the following features are active in your `Cargo.toml` for the `embassy-executor` crate: +For Cortex-M targets, check whether ALL of the following features are enabled in your `Cargo.toml` for the `embassy-executor` crate: * `arch-cortex-m` * `executor-thread` -* `nightly` For ESP32, consider using the executors and `#[main]` macro provided by your appropriate link:https://crates.io/crates/esp-hal-common[HAL crate]. From cbdc49ef8d92606f917d1df0d88e4baef7bb23df Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Fri, 9 Feb 2024 10:15:15 +0200 Subject: [PATCH 34/45] faq: embassy-time was split into three packages, update faq accordingly I ran into this issue when I had to pull in embassy-nrf from git, though cargo didn't complain about conflicting embassy-time links. --- docs/modules/ROOT/pages/faq.adoc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/modules/ROOT/pages/faq.adoc b/docs/modules/ROOT/pages/faq.adoc index c8695a01a..7fb81e2ca 100644 --- a/docs/modules/ROOT/pages/faq.adoc +++ b/docs/modules/ROOT/pages/faq.adoc @@ -124,15 +124,18 @@ You have multiple versions of the same crate in your dependency tree. This means embassy crates are coming from crates.io, and some from git, each of them pulling in a different set of dependencies. -To resolve this issue, make sure to only use a single source for all your embassy crates! To do this, -you should patch your dependencies to use git sources using `[patch.crates.io]` and maybe `[patch.'https://github.com/embassy-rs/embassy.git']`. +To resolve this issue, make sure to only use a single source for all your embassy crates! +To do this, you should patch your dependencies to use git sources using `[patch.crates.io]` +and maybe `[patch.'https://github.com/embassy-rs/embassy.git']`. Example: [source,toml] ---- [patch.crates-io] -embassy-time = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" } +embassy-time-queue-driver = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" } +embassy-time-driver = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" } +# embassy-time = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" } ---- Note that the git revision should match any other embassy patches or git dependencies that you are using! From 32f950cb5ebe478b2641a991dcaa00591ef081f6 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 9 Feb 2024 20:29:38 +0100 Subject: [PATCH 35/45] docs: use correct link to book Fixes #2550 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 24347a43f..b6f667f75 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Embassy is the next-generation framework for embedded applications. Write safe, correct and energy-efficient embedded code faster, using the Rust programming language, its async facilities, and the Embassy libraries. -## Documentation - API reference - Website - Chat +## Documentation - API reference - Website - Chat ## Rust + async ❤️ embedded The Rust programming language is blazingly fast and memory-efficient, with no runtime, garbage collector or OS. It catches a wide variety of bugs at compile time, thanks to its full memory- and thread-safety, and expressive type system. From d6636ca11669c60925acb08c32d488c481ee1581 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Tue, 30 Jan 2024 16:54:06 +0800 Subject: [PATCH 36/45] minor fix --- embassy-stm32/src/dma/ringbuffer.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/dma/ringbuffer.rs b/embassy-stm32/src/dma/ringbuffer.rs index c5b42060a..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 { From dc4898ca89d2130158acf1ced1f8cb3b25efe4b8 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Tue, 30 Jan 2024 16:53:39 +0800 Subject: [PATCH 37/45] update timer mod after stm32-metapac timer_v2 --- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/src/time_driver.rs | 8 +- embassy-stm32/src/timer/complementary_pwm.rs | 2 +- embassy-stm32/src/timer/mod.rs | 526 ++++++++++++++----- embassy-stm32/src/timer/qei.rs | 2 +- embassy-stm32/src/timer/simple_pwm.rs | 6 +- examples/stm32h7/src/bin/dac_dma.rs | 14 +- examples/stm32l4/src/bin/dac_dma.rs | 14 +- 8 files changed, 433 insertions(+), 143 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 61d70b732..c6bc27f89 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-d7c933984fe0cbd120b6aaa7742bd585f89fa786" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", rev = "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-d7c933984fe0cbd120b6aaa7742bd585f89fa786", 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/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..0470e3048 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -52,7 +52,7 @@ pub struct ComplementaryPwm<'d, T> { inner: PeripheralRef<'d, T>, } -impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { +impl<'d, T: GeneralPurpose16bitInstance + ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { /// Create a new complementary PWM driver. #[allow(clippy::too_many_arguments)] pub fn new( diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 210bf7153..f66b4d094 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -1,5 +1,19 @@ //! Timers, PWM, quadrature decoder. +// Timer inheritance +// +// CaptureCompare16bitInstance ComplementaryCaptureCompare16bitInstance +// v v +// Core -------------------------> 1CH -------------------------> 1CH_CMP +// | | ^ | +// +--> Basic_NoCr2 --> Basic +--> 2CH --> GP16 --> GP32 | +--> 2CH_CMP --> ADV +// | | | ^ | | ^ ^ +// | | +------|--|--------------|-----------+ | +// | +--------------------+ +--------------|-----------|---------+ +// | | | | +// | +--------------------------------------|-----------+ +// +----------------------------------------------------+ + pub mod complementary_pwm; pub mod qei; pub mod simple_pwm; @@ -19,32 +33,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 +78,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 +91,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 +105,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 +125,67 @@ 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)); + } + } + + /// 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 +198,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); @@ -149,11 +212,6 @@ pub(crate) mod sealed { let cr1 = Self::regs_gp16().cr1().read(); (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. @@ -196,36 +254,67 @@ pub(crate) mod sealed { } } + /// 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; + + /// Enable timer outputs. + fn enable_outputs(&mut self) { + Self::regs_1ch_cmp().bdtr().modify(|w| w.set_moe(true)); + } + } + + /// Gneral-purpose 2 channel with one complementary 16-bit timer instance. + pub trait GeneralPurpose2ChannelComplementaryInstance: + BasicInstance + 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; + } + /// Advanced control timer instance. - pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { + pub trait AdvancedControlInstance: + GeneralPurpose2ChannelComplementaryInstance + 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 { + pub trait CaptureCompare16bitInstance: GeneralPurpose1ChannelInstance { /// 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() + Self::regs_1ch() .ccmr_input(raw_channel / 2) .modify(|r| r.set_icf(raw_channel % 2, icf)); } /// Clear input interrupt. fn clear_input_interrupt(&mut self, channel: Channel) { - Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false)); + Self::regs_1ch().sr().modify(|r| r.set_ccif(channel.index(), false)); } /// Enable input interrupt. fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { - Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable)); + Self::regs_1ch().dier().modify(|r| r.set_ccie(channel.index(), enable)); } /// Set input capture prescaler. fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { let raw_channel = channel.index(); - Self::regs_gp16() + Self::regs_1ch() .ccmr_input(raw_channel / 2) .modify(|r| r.set_icpsc(raw_channel % 2, factor)); } @@ -233,14 +322,14 @@ pub(crate) mod sealed { /// Set input TI selection. fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { let raw_channel = channel.index(); - Self::regs_gp16() + Self::regs_1ch() .ccmr_input(raw_channel / 2) .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); } /// Set input capture mode. fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { - Self::regs_gp16().ccer().modify(|r| match mode { + Self::regs_1ch().ccer().modify(|r| match mode { InputCaptureMode::Rising => { r.set_ccnp(channel.index(), false); r.set_ccp(channel.index(), false); @@ -256,12 +345,9 @@ 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 r = Self::regs_1ch(); let raw_channel: usize = channel.index(); r.ccmr_output(raw_channel / 2) .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); @@ -269,45 +355,45 @@ pub(crate) mod sealed { /// Set output polarity. fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { - Self::regs_gp16() + Self::regs_1ch() .ccer() .modify(|w| w.set_ccp(channel.index(), polarity.into())); } /// Enable/disable a channel. fn enable_channel(&mut self, channel: Channel, enable: bool) { - Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable)); + Self::regs_1ch().ccer().modify(|w| w.set_cce(channel.index(), enable)); } /// Get enable/disable state of a channel fn get_channel_enable_state(&self, channel: Channel) -> bool { - Self::regs_gp16().ccer().read().cce(channel.index()) + Self::regs_1ch().ccer().read().cce(channel.index()) } /// Set compare value for a channel. fn set_compare_value(&mut self, channel: Channel, value: u16) { - Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value)); + Self::regs_1ch().ccr(channel.index()).modify(|w| w.set_ccr(value)); } /// Get capture value for a channel. fn get_capture_value(&mut self, channel: Channel) -> u16 { - Self::regs_gp16().ccr(channel.index()).read().ccr() + Self::regs_1ch().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() + Self::regs_1ch().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() + Self::regs_1ch().ccr(channel.index()).read().ccr() } /// Set output compare preload. fn set_output_compare_preload(&mut self, channel: Channel, preload: bool) { let channel_index = channel.index(); - Self::regs_gp16() + Self::regs_1ch() .ccmr_output(channel_index / 2) .modify(|w| w.set_ocpe(channel_index % 2, preload)); } @@ -334,27 +420,29 @@ pub(crate) mod sealed { } /// Capture/Compare 16-bit timer instance with complementary pin support. - pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance { + pub trait ComplementaryCaptureCompare16bitInstance: + CaptureCompare16bitInstance + GeneralPurpose1ChannelComplementaryInstance + { /// Set complementary output polarity. fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { - Self::regs_advanced() + Self::regs_1ch_cmp() .ccer() .modify(|w| w.set_ccnp(channel.index(), polarity.into())); } /// 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)); + 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_advanced().bdtr().modify(|w| w.set_dtg(value)); + Self::regs_1ch_cmp().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() + Self::regs_1ch_cmp() .ccer() .modify(|w| w.set_ccne(channel.index(), enable)); } @@ -571,11 +659,29 @@ impl From for bool { } } -/// Basic 16-bit timer instance. -pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} +/// Virtual Core 16-bit timer instance. +pub trait CoreInstance: sealed::CoreInstance + 'static {} -/// Gneral-purpose 16-bit timer instance. -pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + Basic16bitInstance + 'static {} +/// Virtual Basic 16-bit timer without CR2 register instance. +pub trait BasicNoCr2Instance: sealed::BasicNoCr2Instance + CoreInstance + 'static {} + +/// Basic 16-bit timer instance. +pub trait BasicInstance: sealed::BasicInstance + BasicNoCr2Instance + 'static {} + +/// 1 channel 16-bit instance. +pub trait GeneralPurpose1ChannelInstance: sealed::GeneralPurpose1ChannelInstance + CoreInstance + 'static {} + +/// 2 channel 16-bit instance. +pub trait GeneralPurpose2ChannelInstance: + sealed::GeneralPurpose2ChannelInstance + GeneralPurpose1ChannelInstance + 'static +{ +} + +/// General-purpose 16-bit timer instance. +pub trait GeneralPurpose16bitInstance: + sealed::GeneralPurpose16bitInstance + BasicInstance + GeneralPurpose2ChannelInstance + 'static +{ +} /// Gneral-purpose 32-bit timer instance. pub trait GeneralPurpose32bitInstance: @@ -583,18 +689,39 @@ pub trait GeneralPurpose32bitInstance: { } +/// General-purpose 1 channel with one complementary 16-bit timer instance. +pub trait GeneralPurpose1ChannelComplementaryInstance: + sealed::GeneralPurpose1ChannelComplementaryInstance + GeneralPurpose1ChannelInstance + 'static +{ +} + +/// General-purpose 2 channel with one complementary 16-bit timer instance. +pub trait GeneralPurpose2ChannelComplementaryInstance: + sealed::GeneralPurpose2ChannelComplementaryInstance + + BasicInstance + + GeneralPurpose1ChannelComplementaryInstance + + 'static +{ +} + /// Advanced control timer instance. -pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + GeneralPurpose16bitInstance + 'static {} +pub trait AdvancedControlInstance: + sealed::AdvancedControlInstance + GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance + 'static +{ +} /// Capture/Compare 16-bit timer instance. pub trait CaptureCompare16bitInstance: - sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static + sealed::CaptureCompare16bitInstance + GeneralPurpose1ChannelInstance + 'static { } /// Capture/Compare 16-bit timer instance with complementary pin support. pub trait ComplementaryCaptureCompare16bitInstance: - sealed::ComplementaryCaptureCompare16bitInstance + CaptureCompare16bitInstance + AdvancedControlInstance + 'static + sealed::ComplementaryCaptureCompare16bitInstance + + CaptureCompare16bitInstance + + GeneralPurpose1ChannelComplementaryInstance + + 'static { } @@ -621,12 +748,34 @@ pin_trait!(BreakInput2Comparator1Pin, CaptureCompare16bitInstance); pin_trait!(BreakInput2Comparator2Pin, CaptureCompare16bitInstance); #[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 +783,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_gp_16bit_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_gp_32bit_timer { ($inst:ident) => { impl sealed::GeneralPurpose32bitInstance for crate::peripherals::$inst { fn regs_gp32() -> crate::pac::timer::TimGp32 { @@ -644,84 +826,194 @@ macro_rules! impl_32bit_timer { }; } +#[allow(unused)] +macro_rules! impl_1ch_cmp_timer { + ($inst:ident) => { + 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()) } + } + } + }; +} + #[allow(unused)] macro_rules! impl_compare_capable_16bit { ($inst:ident) => { - impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { - fn enable_outputs(&mut self) {} - } + impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {} + }; +} + +#[allow(unused)] +macro_rules! impl_compare_capable_32bit { + ($inst:ident) => { + impl sealed::CaptureCompare32bitInstance for crate::peripherals::$inst {} + }; +} + +#[allow(unused)] +macro_rules! impl_compare_capable_complementary_16bit { + ($inst:ident) => { + impl sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} }; } 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 CoreInstance for crate::peripherals::$inst {} + impl BasicNoCr2Instance for crate::peripherals::$inst{} + impl BasicInstance for crate::peripherals::$inst {} + }; + + ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => { + impl_core_timer!($inst, $irq); + impl_1ch_timer!($inst); + impl_compare_capable_16bit!($inst); + impl CoreInstance for crate::peripherals::$inst {} + impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + }; + + + ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => { + impl_core_timer!($inst, $irq); + impl_1ch_timer!($inst); + impl_compare_capable_16bit!($inst); + impl_2ch_timer!($inst); + impl CoreInstance for crate::peripherals::$inst {} + impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl GeneralPurpose2ChannelInstance 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_compare_capable_16bit!($inst); + impl_2ch_timer!($inst); + impl_gp_16bit_timer!($inst); + impl CoreInstance for crate::peripherals::$inst {} + impl BasicNoCr2Instance for crate::peripherals::$inst{} + impl BasicInstance for crate::peripherals::$inst {} + impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl GeneralPurpose2ChannelInstance for crate::peripherals::$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_core_timer!($inst, $irq); + impl_basic_no_cr2_timer!($inst); + impl_basic_timer!($inst); + impl_1ch_timer!($inst); impl_compare_capable_16bit!($inst); - impl Basic16bitInstance for crate::peripherals::$inst {} + impl_compare_capable_32bit!($inst); + impl_2ch_timer!($inst); + impl_gp_16bit_timer!($inst); + impl_gp_32bit_timer!($inst); + impl CoreInstance for crate::peripherals::$inst {} + impl BasicNoCr2Instance for crate::peripherals::$inst{} + impl BasicInstance for crate::peripherals::$inst {} + impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} impl CaptureCompare16bitInstance for crate::peripherals::$inst {} impl CaptureCompare32bitInstance for crate::peripherals::$inst {} + impl GeneralPurpose2ChannelInstance 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); + ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => { + impl_core_timer!($inst, $irq); + impl_basic_no_cr2_timer!($inst); + impl_1ch_timer!($inst); + impl_compare_capable_16bit!($inst); + impl_1ch_cmp_timer!($inst); + impl_compare_capable_complementary_16bit!($inst); + impl CoreInstance for crate::peripherals::$inst {} + impl BasicNoCr2Instance for crate::peripherals::$inst{} + impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst {} + impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} + }; - impl Basic16bitInstance for crate::peripherals::$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_compare_capable_16bit!($inst); + impl_1ch_cmp_timer!($inst); + impl_compare_capable_complementary_16bit!($inst); + impl_2ch_cmp_timer!($inst); + impl CoreInstance for crate::peripherals::$inst {} + impl BasicNoCr2Instance for crate::peripherals::$inst{} + impl BasicInstance for crate::peripherals::$inst {} + impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst {} + impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} + impl GeneralPurpose2ChannelComplementaryInstance 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_compare_capable_16bit!($inst); + impl_1ch_cmp_timer!($inst); + impl_gp_16bit_timer!($inst); + impl_compare_capable_complementary_16bit!($inst); + impl_2ch_cmp_timer!($inst); + impl_adv_timer!($inst); + impl CoreInstance for crate::peripherals::$inst {} + impl BasicNoCr2Instance for crate::peripherals::$inst{} + impl BasicInstance for crate::peripherals::$inst {} + impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} + impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst {} impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} + impl GeneralPurpose2ChannelComplementaryInstance 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 - } - } }; } // Update Event trigger DMA for every timer -dma_trait!(UpDma, Basic16bitInstance); +dma_trait!(UpDma, BasicNoCr2Instance); dma_trait!(Ch1Dma, CaptureCompare16bitInstance); dma_trait!(Ch2Dma, CaptureCompare16bitInstance); diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index 59efb72ba..75e5ab12a 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -57,7 +57,7 @@ pub struct Qei<'d, T> { _inner: PeripheralRef<'d, T>, } -impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { +impl<'d, T: GeneralPurpose16bitInstance + CaptureCompare16bitInstance> Qei<'d, T> { /// Create a new quadrature decoder driver. pub fn new(tim: impl Peripheral

+ 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { Self::new_inner(tim) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 0b4c1225f..1c665d456 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -59,7 +59,7 @@ pub struct SimplePwm<'d, T> { inner: PeripheralRef<'d, T>, } -impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { +impl<'d, T: GeneralPurpose16bitInstance + CaptureCompare16bitInstance> SimplePwm<'d, T> { /// Create a new simple PWM driver. pub fn new( tim: impl Peripheral

+ 'd, @@ -84,8 +84,6 @@ 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| { @@ -202,7 +200,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/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/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); }); From 53bf0332e9e862fa5c09a1e9ab9a6d7116219ed7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 10 Feb 2024 00:00:26 +0100 Subject: [PATCH 38/45] asdkf --- embassy-stm32/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index c6bc27f89..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", rev = "stm32-data-028efe4e6e0719b661cbdf8ffda3341e4d63d0df" } +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" From d538829f2f3542c78ee9eb218c0b5c982acfb46b Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Thu, 1 Feb 2024 17:10:47 +0800 Subject: [PATCH 39/45] add methods with macro --- embassy-stm32/src/timer/complementary_pwm.rs | 52 +- embassy-stm32/src/timer/mod.rs | 522 ++++++++---------- embassy-stm32/src/timer/qei.rs | 4 +- embassy-stm32/src/timer/simple_pwm.rs | 40 +- .../stm32h7/src/bin/low_level_timer_api.rs | 4 +- 5 files changed, 298 insertions(+), 324 deletions(-) diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 0470e3048..b9cd044c9 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -1,6 +1,7 @@ //! PWM driver with complementary output support. use core::marker::PhantomData; +use core::ops::{Deref, DerefMut}; use embassy_hal_internal::{into_ref, PeripheralRef}; use stm32_metapac::timer::vals::Ckd; @@ -23,7 +24,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: AdvancedControlInstance> 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); @@ -52,7 +53,7 @@ pub struct ComplementaryPwm<'d, T> { inner: PeripheralRef<'d, T>, } -impl<'d, T: GeneralPurpose16bitInstance + ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { +impl<'d, T: AdvancedControlInstance> ComplementaryPwm<'d, T> { /// Create a new complementary PWM driver. #[allow(clippy::too_many_arguments)] pub fn new( @@ -84,27 +85,30 @@ impl<'d, T: GeneralPurpose16bitInstance + ComplementaryCaptureCompare16bitInstan 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| { + sealed::GeneralPurpose16bitInstance::set_output_compare_mode( + this.inner.deref_mut(), + channel, + OutputCompareMode::PwmMode1, + ); + sealed::GeneralPurpose16bitInstance::set_output_compare_preload(this.inner.deref_mut(), channel, true); + }); + this } /// Enable the given channel. pub fn enable(&mut self, channel: Channel) { - self.inner.enable_channel(channel, true); - self.inner.enable_complementary_channel(channel, true); + sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, true); + sealed::AdvancedControlInstance::enable_complementary_channel(self.inner.deref_mut(), channel, true); } /// Disable the given channel. pub fn disable(&mut self, channel: Channel) { - self.inner.enable_complementary_channel(channel, false); - self.inner.enable_channel(channel, false); + sealed::AdvancedControlInstance::enable_complementary_channel(self.inner.deref_mut(), channel, false); + sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, false); } /// Set PWM frequency. @@ -132,13 +136,13 @@ impl<'d, T: GeneralPurpose16bitInstance + ComplementaryCaptureCompare16bitInstan /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. pub fn set_duty(&mut self, channel: Channel, duty: u16) { assert!(duty <= self.get_max_duty()); - self.inner.set_compare_value(channel, duty) + sealed::GeneralPurpose16bitInstance::set_compare_value(self.inner.deref_mut(), channel, duty) } /// Set the output polarity for a given channel. pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { - self.inner.set_output_polarity(channel, polarity); - self.inner.set_complementary_output_polarity(channel, polarity); + sealed::GeneralPurpose16bitInstance::set_output_polarity(self.inner.deref_mut(), channel, polarity); + sealed::AdvancedControlInstance::set_complementary_output_polarity(self.inner.deref_mut(), channel, polarity); } /// Set the dead time as a proportion of max_duty @@ -150,19 +154,19 @@ impl<'d, T: GeneralPurpose16bitInstance + ComplementaryCaptureCompare16bitInstan } } -impl<'d, T: ComplementaryCaptureCompare16bitInstance> embedded_hal_02::Pwm for ComplementaryPwm<'d, T> { +impl<'d, T: AdvancedControlInstance> embedded_hal_02::Pwm for ComplementaryPwm<'d, T> { type Channel = Channel; type Time = Hertz; type Duty = u16; fn disable(&mut self, channel: Self::Channel) { - self.inner.enable_complementary_channel(channel, false); - self.inner.enable_channel(channel, false); + sealed::AdvancedControlInstance::enable_complementary_channel(self.inner.deref_mut(), channel, false); + sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, false); } fn enable(&mut self, channel: Self::Channel) { - self.inner.enable_channel(channel, true); - self.inner.enable_complementary_channel(channel, true); + sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, true); + sealed::AdvancedControlInstance::enable_complementary_channel(self.inner.deref_mut(), channel, true); } fn get_period(&self) -> Self::Time { @@ -170,7 +174,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> embedded_hal_02::Pwm for C } fn get_duty(&self, channel: Self::Channel) -> Self::Duty { - self.inner.get_compare_value(channel) + sealed::GeneralPurpose16bitInstance::get_compare_value(self.inner.deref(), channel) } fn get_max_duty(&self) -> Self::Duty { @@ -179,7 +183,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> embedded_hal_02::Pwm for C fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { assert!(duty <= self.get_max_duty()); - self.inner.set_compare_value(channel, duty) + sealed::GeneralPurpose16bitInstance::set_compare_value(self.inner.deref_mut(), channel, duty) } fn set_period

(&mut self, period: P) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index f66b4d094..2f5d5770a 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -2,8 +2,6 @@ // Timer inheritance // -// CaptureCompare16bitInstance ComplementaryCaptureCompare16bitInstance -// v v // Core -------------------------> 1CH -------------------------> 1CH_CMP // | | ^ | // +--> Basic_NoCr2 --> Basic +--> 2CH --> GP16 --> GP32 | +--> 2CH_CMP --> ADV @@ -33,6 +31,156 @@ pub mod low_level { pub(crate) mod sealed { use super::*; + macro_rules! add_capture_compare_common_methods { + ($regs:ident) => { + /// Set input capture filter. + fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::FilterValue) { + let raw_channel = channel.index(); + Self::$regs() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_icf(raw_channel % 2, icf)); + } + + /// Clear input interrupt. + fn clear_input_interrupt(&mut self, channel: Channel) { + Self::$regs().sr().modify(|r| r.set_ccif(channel.index(), false)); + } + + /// Enable input interrupt. + fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { + Self::$regs() + .dier() + .modify(|r| r.set_ccie(channel.index(), enable)); + } + + /// Set input capture prescaler. + fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { + let raw_channel = channel.index(); + Self::$regs() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_icpsc(raw_channel % 2, factor)); + } + + /// Set input TI selection. + fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { + let raw_channel = channel.index(); + Self::$regs() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); + } + + /// Set input capture mode. + fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { + Self::$regs().ccer().modify(|r| match mode { + InputCaptureMode::Rising => { + r.set_ccnp(channel.index(), false); + r.set_ccp(channel.index(), false); + } + InputCaptureMode::Falling => { + r.set_ccnp(channel.index(), false); + r.set_ccp(channel.index(), true); + } + InputCaptureMode::BothEdges => { + r.set_ccnp(channel.index(), true); + r.set_ccp(channel.index(), true); + } + }); + } + + /// Set output compare mode. + fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { + let r = Self::$regs(); + let raw_channel: usize = channel.index(); + r.ccmr_output(raw_channel / 2) + .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); + } + + /// Set output polarity. + fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { + Self::$regs() + .ccer() + .modify(|w| w.set_ccp(channel.index(), polarity.into())); + } + + /// Enable/disable a channel. + fn enable_channel(&mut self, channel: Channel, enable: bool) { + Self::$regs() + .ccer() + .modify(|w| w.set_cce(channel.index(), enable)); + } + + /// Get enable/disable state of a channel + fn get_channel_enable_state(&self, channel: Channel) -> bool { + Self::$regs().ccer().read().cce(channel.index()) + } + + /// Set compare value for a channel. + fn set_compare_value(&mut self, channel: Channel, value: u16) { + Self::$regs().ccr(channel.index()).modify(|w| w.set_ccr(value)); + } + + /// Get capture value for a channel. + fn get_capture_value(&mut self, channel: Channel) -> u16 { + Self::$regs().ccr(channel.index()).read().ccr() + } + + /// Get compare value for a channel. + fn get_compare_value(&self, channel: Channel) -> u16 { + Self::$regs().ccr(channel.index()).read().ccr() + } + + /// Set output compare preload. + fn set_output_compare_preload(&mut self, channel: Channel, preload: bool) { + let channel_index = channel.index(); + Self::regs_1ch() + .ccmr_output(channel_index / 2) + .modify(|w| w.set_ocpe(channel_index % 2, preload)); + } + }; + } + + macro_rules! add_capture_compare_dma_methods { + ($regs:ident) => { + /// Get capture compare DMA selection + fn get_cc_dma_selection(&self) -> super::vals::Ccds { + Self::$regs().cr2().read().ccds() + } + + /// Set capture compare DMA selection + fn set_cc_dma_selection(&mut self, ccds: super::vals::Ccds) { + Self::$regs().cr2().modify(|w| w.set_ccds(ccds)) + } + + /// Get capture compare DMA enable state + fn get_cc_dma_enable_state(&self, channel: Channel) -> bool { + Self::$regs().dier().read().ccde(channel.index()) + } + + /// Set capture compare DMA enable state + fn set_cc_dma_enable_state(&mut self, channel: Channel, ccde: bool) { + Self::$regs().dier().modify(|w| w.set_ccde(channel.index(), ccde)) + } + }; + } + + macro_rules! add_complementary_capture_compare_methods { + ($regs:ident) => { + /// Set complementary output polarity. + fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { + Self::$regs() + .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() + .ccer() + .modify(|w| w.set_ccne(channel.index(), enable)); + } + }; + } + /// Virtual Core 16-bit timer instance. pub trait CoreInstance: RccPeripheral { /// Interrupt for this timer. @@ -171,6 +319,13 @@ pub(crate) mod sealed { 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() + } + + add_capture_compare_common_methods!(regs_1ch); } /// Gneral-purpose 1 channel 16-bit timer instance. @@ -182,6 +337,8 @@ pub(crate) mod sealed { /// for a given set of capabilities, and having it transparently work with /// more capable timers. fn regs_2ch() -> crate::pac::timer::Tim2ch; + + add_capture_compare_common_methods!(regs_2ch); } /// Gneral-purpose 16-bit timer instance. @@ -212,6 +369,9 @@ pub(crate) mod sealed { let cr1 = Self::regs_gp16().cr1().read(); (cr1.cms(), cr1.dir()).into() } + + add_capture_compare_common_methods!(regs_gp16); + add_capture_compare_dma_methods!(regs_gp16); } /// Gneral-purpose 32-bit timer instance. @@ -252,204 +412,7 @@ pub(crate) mod sealed { timer_f / arr / (psc + 1) } - } - /// 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; - - /// Enable timer outputs. - fn enable_outputs(&mut self) { - Self::regs_1ch_cmp().bdtr().modify(|w| w.set_moe(true)); - } - } - - /// Gneral-purpose 2 channel with one complementary 16-bit timer instance. - pub trait GeneralPurpose2ChannelComplementaryInstance: - BasicInstance + 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; - } - - /// Advanced control timer instance. - pub trait AdvancedControlInstance: - GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance - { - /// Get access to the advanced timer registers. - fn regs_advanced() -> crate::pac::timer::TimAdv; - } - - /// Capture/Compare 16-bit timer instance. - pub trait CaptureCompare16bitInstance: GeneralPurpose1ChannelInstance { - /// Set input capture filter. - fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::FilterValue) { - let raw_channel = channel.index(); - Self::regs_1ch() - .ccmr_input(raw_channel / 2) - .modify(|r| r.set_icf(raw_channel % 2, icf)); - } - - /// Clear input interrupt. - fn clear_input_interrupt(&mut self, channel: Channel) { - Self::regs_1ch().sr().modify(|r| r.set_ccif(channel.index(), false)); - } - - /// Enable input interrupt. - fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { - Self::regs_1ch().dier().modify(|r| r.set_ccie(channel.index(), enable)); - } - - /// Set input capture prescaler. - fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { - let raw_channel = channel.index(); - Self::regs_1ch() - .ccmr_input(raw_channel / 2) - .modify(|r| r.set_icpsc(raw_channel % 2, factor)); - } - - /// Set input TI selection. - fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { - let raw_channel = channel.index(); - Self::regs_1ch() - .ccmr_input(raw_channel / 2) - .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); - } - - /// Set input capture mode. - fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { - Self::regs_1ch().ccer().modify(|r| match mode { - InputCaptureMode::Rising => { - r.set_ccnp(channel.index(), false); - r.set_ccp(channel.index(), false); - } - InputCaptureMode::Falling => { - r.set_ccnp(channel.index(), false); - r.set_ccp(channel.index(), true); - } - InputCaptureMode::BothEdges => { - r.set_ccnp(channel.index(), true); - r.set_ccp(channel.index(), true); - } - }); - } - - /// Set output compare mode. - fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { - let r = Self::regs_1ch(); - let raw_channel: usize = channel.index(); - r.ccmr_output(raw_channel / 2) - .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); - } - - /// Set output polarity. - fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { - Self::regs_1ch() - .ccer() - .modify(|w| w.set_ccp(channel.index(), polarity.into())); - } - - /// Enable/disable a channel. - fn enable_channel(&mut self, channel: Channel, enable: bool) { - Self::regs_1ch().ccer().modify(|w| w.set_cce(channel.index(), enable)); - } - - /// Get enable/disable state of a channel - fn get_channel_enable_state(&self, channel: Channel) -> bool { - Self::regs_1ch().ccer().read().cce(channel.index()) - } - - /// Set compare value for a channel. - fn set_compare_value(&mut self, channel: Channel, value: u16) { - Self::regs_1ch().ccr(channel.index()).modify(|w| w.set_ccr(value)); - } - - /// Get capture value for a channel. - fn get_capture_value(&mut self, channel: Channel) -> u16 { - Self::regs_1ch().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_1ch().arr().read().arr() - } - - /// Get compare value for a channel. - fn get_compare_value(&self, channel: Channel) -> u16 { - Self::regs_1ch().ccr(channel.index()).read().ccr() - } - - /// Set output compare preload. - fn set_output_compare_preload(&mut self, channel: Channel, preload: bool) { - let channel_index = channel.index(); - Self::regs_1ch() - .ccmr_output(channel_index / 2) - .modify(|w| w.set_ocpe(channel_index % 2, preload)); - } - - /// Get capture compare DMA selection - fn get_cc_dma_selection(&self) -> super::vals::Ccds { - Self::regs_gp16().cr2().read().ccds() - } - - /// Set capture compare DMA selection - fn set_cc_dma_selection(&mut self, ccds: super::vals::Ccds) { - Self::regs_gp16().cr2().modify(|w| w.set_ccds(ccds)) - } - - /// Get capture compare DMA enable state - fn get_cc_dma_enable_state(&self, channel: Channel) -> bool { - Self::regs_gp16().dier().read().ccde(channel.index()) - } - - /// Set capture compare DMA enable state - fn set_cc_dma_enable_state(&mut self, channel: Channel, ccde: bool) { - Self::regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde)) - } - } - - /// Capture/Compare 16-bit timer instance with complementary pin support. - pub trait ComplementaryCaptureCompare16bitInstance: - CaptureCompare16bitInstance + GeneralPurpose1ChannelComplementaryInstance - { - /// Set complementary output polarity. - fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { - Self::regs_1ch_cmp() - .ccer() - .modify(|w| w.set_ccnp(channel.index(), polarity.into())); - } - - /// 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/disable a complementary channel. - fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { - Self::regs_1ch_cmp() - .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)); @@ -470,6 +433,59 @@ pub(crate) mod sealed { Self::regs_gp32().ccr(channel.index()).read().ccr() } } + + /// 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)); + } + + add_complementary_capture_compare_methods!(regs_1ch_cmp); + } + + /// 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; + + add_complementary_capture_compare_methods!(regs_2ch_cmp); + } + + /// Advanced control timer instance. + pub trait AdvancedControlInstance: + GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance + { + /// Get access to the advanced timer registers. + fn regs_advanced() -> crate::pac::timer::TimAdv; + + add_complementary_capture_compare_methods!(regs_advanced); + } } /// Timer channel. @@ -699,6 +715,7 @@ pub trait GeneralPurpose1ChannelComplementaryInstance: pub trait GeneralPurpose2ChannelComplementaryInstance: sealed::GeneralPurpose2ChannelComplementaryInstance + BasicInstance + + GeneralPurpose2ChannelInstance + GeneralPurpose1ChannelComplementaryInstance + 'static { @@ -710,42 +727,30 @@ pub trait AdvancedControlInstance: { } -/// Capture/Compare 16-bit timer instance. -pub trait CaptureCompare16bitInstance: - sealed::CaptureCompare16bitInstance + GeneralPurpose1ChannelInstance + 'static -{ -} +pin_trait!(Channel1Pin, GeneralPurpose1ChannelInstance); +pin_trait!(Channel2Pin, GeneralPurpose2ChannelInstance); +pin_trait!(Channel3Pin, GeneralPurpose16bitInstance); +pin_trait!(Channel4Pin, GeneralPurpose16bitInstance); -/// Capture/Compare 16-bit timer instance with complementary pin support. -pub trait ComplementaryCaptureCompare16bitInstance: - sealed::ComplementaryCaptureCompare16bitInstance - + CaptureCompare16bitInstance - + GeneralPurpose1ChannelComplementaryInstance - + 'static -{ -} +#[cfg(not(stm32l0))] +pin_trait!(ExternalTriggerPin, GeneralPurpose16bitInstance); -/// Capture/Compare 32-bit timer instance. -pub trait CaptureCompare32bitInstance: - sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static -{ -} +#[cfg(stm32l0)] +pin_trait!(ExternalTriggerPin, GeneralPurpose2ChannelInstance); -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); +pin_trait!(Channel1ComplementaryPin, GeneralPurpose1ChannelComplementaryInstance); +pin_trait!(Channel2ComplementaryPin, GeneralPurpose2ChannelComplementaryInstance); +pin_trait!(Channel3ComplementaryPin, AdvancedControlInstance); +pin_trait!(Channel4ComplementaryPin, AdvancedControlInstance); + +pin_trait!(BreakInputPin, GeneralPurpose1ChannelComplementaryInstance); +pin_trait!(BreakInput2Pin, GeneralPurpose2ChannelComplementaryInstance); + +pin_trait!(BreakInputComparator1Pin, GeneralPurpose1ChannelComplementaryInstance); +pin_trait!(BreakInputComparator2Pin, AdvancedControlInstance); + +pin_trait!(BreakInput2Comparator1Pin, AdvancedControlInstance); +pin_trait!(BreakInput2Comparator2Pin, AdvancedControlInstance); #[allow(unused)] macro_rules! impl_core_timer { @@ -859,27 +864,6 @@ macro_rules! impl_adv_timer { }; } -#[allow(unused)] -macro_rules! impl_compare_capable_16bit { - ($inst:ident) => { - impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {} - }; -} - -#[allow(unused)] -macro_rules! impl_compare_capable_32bit { - ($inst:ident) => { - impl sealed::CaptureCompare32bitInstance for crate::peripherals::$inst {} - }; -} - -#[allow(unused)] -macro_rules! impl_compare_capable_complementary_16bit { - ($inst:ident) => { - impl sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} - }; -} - foreach_interrupt! { ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { @@ -894,21 +878,17 @@ foreach_interrupt! { ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => { impl_core_timer!($inst, $irq); impl_1ch_timer!($inst); - impl_compare_capable_16bit!($inst); impl CoreInstance for crate::peripherals::$inst {} impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => { impl_core_timer!($inst, $irq); impl_1ch_timer!($inst); - impl_compare_capable_16bit!($inst); impl_2ch_timer!($inst); impl CoreInstance for crate::peripherals::$inst {} impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst {} impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} }; @@ -917,14 +897,12 @@ foreach_interrupt! { impl_basic_no_cr2_timer!($inst); impl_basic_timer!($inst); impl_1ch_timer!($inst); - impl_compare_capable_16bit!($inst); impl_2ch_timer!($inst); impl_gp_16bit_timer!($inst); impl CoreInstance for crate::peripherals::$inst {} impl BasicNoCr2Instance for crate::peripherals::$inst{} impl BasicInstance for crate::peripherals::$inst {} impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst {} impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} }; @@ -934,8 +912,6 @@ foreach_interrupt! { impl_basic_no_cr2_timer!($inst); impl_basic_timer!($inst); impl_1ch_timer!($inst); - impl_compare_capable_16bit!($inst); - impl_compare_capable_32bit!($inst); impl_2ch_timer!($inst); impl_gp_16bit_timer!($inst); impl_gp_32bit_timer!($inst); @@ -943,8 +919,6 @@ foreach_interrupt! { impl BasicNoCr2Instance for crate::peripherals::$inst{} impl BasicInstance for crate::peripherals::$inst {} impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst {} - impl CaptureCompare32bitInstance for crate::peripherals::$inst {} impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} impl GeneralPurpose32bitInstance for crate::peripherals::$inst {} @@ -954,15 +928,11 @@ foreach_interrupt! { impl_core_timer!($inst, $irq); impl_basic_no_cr2_timer!($inst); impl_1ch_timer!($inst); - impl_compare_capable_16bit!($inst); impl_1ch_cmp_timer!($inst); - impl_compare_capable_complementary_16bit!($inst); impl CoreInstance for crate::peripherals::$inst {} impl BasicNoCr2Instance for crate::peripherals::$inst{} impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst {} impl GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst {} - impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} }; @@ -971,17 +941,15 @@ foreach_interrupt! { impl_basic_no_cr2_timer!($inst); impl_basic_timer!($inst); impl_1ch_timer!($inst); - impl_compare_capable_16bit!($inst); + impl_2ch_timer!($inst); impl_1ch_cmp_timer!($inst); - impl_compare_capable_complementary_16bit!($inst); impl_2ch_cmp_timer!($inst); impl CoreInstance for crate::peripherals::$inst {} impl BasicNoCr2Instance for crate::peripherals::$inst{} impl BasicInstance for crate::peripherals::$inst {} impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} impl GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst {} - impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} impl GeneralPurpose2ChannelComplementaryInstance for crate::peripherals::$inst {} }; @@ -992,10 +960,8 @@ foreach_interrupt! { impl_basic_timer!($inst); impl_1ch_timer!($inst); impl_2ch_timer!($inst); - impl_compare_capable_16bit!($inst); impl_1ch_cmp_timer!($inst); impl_gp_16bit_timer!($inst); - impl_compare_capable_complementary_16bit!($inst); impl_2ch_cmp_timer!($inst); impl_adv_timer!($inst); impl CoreInstance for crate::peripherals::$inst {} @@ -1004,9 +970,7 @@ foreach_interrupt! { impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} - impl CaptureCompare16bitInstance for crate::peripherals::$inst {} impl GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst {} - impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} impl GeneralPurpose2ChannelComplementaryInstance for crate::peripherals::$inst {} impl AdvancedControlInstance for crate::peripherals::$inst {} }; @@ -1015,7 +979,7 @@ foreach_interrupt! { // Update Event trigger DMA for every timer dma_trait!(UpDma, BasicNoCr2Instance); -dma_trait!(Ch1Dma, CaptureCompare16bitInstance); -dma_trait!(Ch2Dma, CaptureCompare16bitInstance); -dma_trait!(Ch3Dma, CaptureCompare16bitInstance); -dma_trait!(Ch4Dma, CaptureCompare16bitInstance); +dma_trait!(Ch1Dma, GeneralPurpose1ChannelInstance); +dma_trait!(Ch2Dma, GeneralPurpose2ChannelInstance); +dma_trait!(Ch3Dma, GeneralPurpose16bitInstance); +dma_trait!(Ch4Dma, GeneralPurpose16bitInstance); diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index 75e5ab12a..7e56312bb 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -30,7 +30,7 @@ pub struct QeiPin<'d, T, Channel> { macro_rules! channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, T: CaptureCompare16bitInstance> QeiPin<'d, T, $channel> { + impl<'d, T: GeneralPurpose16bitInstance> QeiPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")] pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { into_ref!(pin); @@ -57,7 +57,7 @@ pub struct Qei<'d, T> { _inner: PeripheralRef<'d, T>, } -impl<'d, T: GeneralPurpose16bitInstance + CaptureCompare16bitInstance> Qei<'d, T> { +impl<'d, T: GeneralPurpose16bitInstance> Qei<'d, T> { /// Create a new quadrature decoder driver. pub fn new(tim: impl Peripheral

+ 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { Self::new_inner(tim) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 1c665d456..088d02c97 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -1,6 +1,7 @@ //! Simple PWM driver. use core::marker::PhantomData; +use core::ops::{Deref, DerefMut}; use embassy_hal_internal::{into_ref, PeripheralRef}; @@ -30,7 +31,7 @@ pub struct PwmPin<'d, T, C> { macro_rules! channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, T: CaptureCompare16bitInstance> PwmPin<'d, T, $channel> { + impl<'d, T: GeneralPurpose16bitInstance> PwmPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] pub fn $new_chx(pin: impl Peripheral

> + 'd, output_type: OutputType) -> Self { into_ref!(pin); @@ -59,7 +60,7 @@ pub struct SimplePwm<'d, T> { inner: PeripheralRef<'d, T>, } -impl<'d, T: GeneralPurpose16bitInstance + CaptureCompare16bitInstance> SimplePwm<'d, T> { +impl<'d, T: GeneralPurpose16bitInstance> SimplePwm<'d, T> { /// Create a new simple PWM driver. pub fn new( tim: impl Peripheral

+ 'd, @@ -87,8 +88,13 @@ impl<'d, T: GeneralPurpose16bitInstance + CaptureCompare16bitInstance> SimplePwm [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) + sealed::GeneralPurpose16bitInstance::set_output_compare_mode( + this.inner.deref_mut(), + channel, + OutputCompareMode::PwmMode1, + ); + + sealed::GeneralPurpose16bitInstance::set_output_compare_preload(this.inner.deref_mut(), channel, true); }); this @@ -96,17 +102,17 @@ impl<'d, T: GeneralPurpose16bitInstance + CaptureCompare16bitInstance> SimplePwm /// Enable the given channel. pub fn enable(&mut self, channel: Channel) { - self.inner.enable_channel(channel, true); + sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, true); } /// Disable the given channel. pub fn disable(&mut self, channel: Channel) { - self.inner.enable_channel(channel, false); + sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, false); } /// Check whether given channel is enabled pub fn is_enabled(&self, channel: Channel) -> bool { - self.inner.get_channel_enable_state(channel) + sealed::GeneralPurpose16bitInstance::get_channel_enable_state(self.inner.deref(), channel) } /// Set PWM frequency. @@ -134,24 +140,24 @@ impl<'d, T: GeneralPurpose16bitInstance + CaptureCompare16bitInstance> SimplePwm /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. pub fn set_duty(&mut self, channel: Channel, duty: u16) { assert!(duty <= self.get_max_duty()); - self.inner.set_compare_value(channel, duty) + sealed::GeneralPurpose16bitInstance::set_compare_value(self.inner.deref_mut(), channel, duty) } /// Get the duty for a given channel. /// /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. pub fn get_duty(&self, channel: Channel) -> u16 { - self.inner.get_compare_value(channel) + sealed::GeneralPurpose16bitInstance::get_compare_value(self.inner.deref(), channel) } /// Set the output polarity for a given channel. pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { - self.inner.set_output_polarity(channel, polarity); + sealed::GeneralPurpose16bitInstance::set_output_polarity(self.inner.deref_mut(), channel, polarity); } /// Set the output compare mode for a given channel. pub fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { - self.inner.set_output_compare_mode(channel, mode); + sealed::GeneralPurpose16bitInstance::set_output_compare_mode(self.inner.deref_mut(), channel, mode); } /// Generate a sequence of PWM waveform @@ -226,7 +232,7 @@ impl<'d, T: GeneralPurpose16bitInstance + CaptureCompare16bitInstance> SimplePwm macro_rules! impl_waveform_chx { ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => { - impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { + impl<'d, T: GeneralPurpose16bitInstance> SimplePwm<'d, T> { /// Generate a sequence of PWM waveform /// /// Note: @@ -313,17 +319,17 @@ impl_waveform_chx!(waveform_ch2, Ch2Dma, Ch2); impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3); impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4); -impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> { +impl<'d, T: GeneralPurpose16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> { type Channel = Channel; type Time = Hertz; type Duty = u16; fn disable(&mut self, channel: Self::Channel) { - self.inner.enable_channel(channel, false); + sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, false); } fn enable(&mut self, channel: Self::Channel) { - self.inner.enable_channel(channel, true); + sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, true); } fn get_period(&self) -> Self::Time { @@ -331,7 +337,7 @@ impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, } fn get_duty(&self, channel: Self::Channel) -> Self::Duty { - self.inner.get_compare_value(channel) + sealed::GeneralPurpose16bitInstance::get_compare_value(self.inner.deref(), channel) } fn get_max_duty(&self) -> Self::Duty { @@ -340,7 +346,7 @@ impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { assert!(duty <= self.get_max_duty()); - self.inner.set_compare_value(channel, duty) + sealed::GeneralPurpose16bitInstance::set_compare_value(self.inner.deref_mut(), channel, duty) } fn set_period

(&mut self, period: P) diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs index cc508c3cf..0be3eccb7 100644 --- a/examples/stm32h7/src/bin/low_level_timer_api.rs +++ b/examples/stm32h7/src/bin/low_level_timer_api.rs @@ -56,11 +56,11 @@ async fn main(_spawner: Spawner) { Timer::after_millis(300).await; } } -pub struct SimplePwm32<'d, T: CaptureCompare32bitInstance> { +pub struct SimplePwm32<'d, T: GeneralPurpose32bitInstance> { inner: PeripheralRef<'d, T>, } -impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { +impl<'d, T: GeneralPurpose32bitInstance> SimplePwm32<'d, T> { pub fn new( tim: impl Peripheral

+ 'd, ch1: impl Peripheral

> + 'd, From 5b646bc3bd0c4a2cd9acf6a59b3a76f2bbcb0bfb Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Thu, 1 Feb 2024 23:04:39 +0800 Subject: [PATCH 40/45] stm32-timer: L0 is special --- embassy-stm32/src/timer/mod.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 2f5d5770a..8be96b414 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -12,6 +12,7 @@ // | +--------------------------------------|-----------+ // +----------------------------------------------------+ +#[cfg(not(any(stm32l0, stm32l1)))] pub mod complementary_pwm; pub mod qei; pub mod simple_pwm; @@ -163,6 +164,7 @@ pub(crate) mod sealed { }; } + #[cfg(not(any(stm32l0, stm32l1)))] macro_rules! add_complementary_capture_compare_methods { ($regs:ident) => { /// Set complementary output polarity. @@ -374,6 +376,7 @@ pub(crate) mod sealed { add_capture_compare_dma_methods!(regs_gp16); } + #[cfg(not(any(stm32l0)))] /// Gneral-purpose 32-bit timer instance. pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { /// Get access to the general purpose 32bit timer registers. @@ -434,6 +437,7 @@ pub(crate) mod sealed { } } + #[cfg(not(any(stm32l0, stm32l1)))] /// 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. @@ -462,6 +466,7 @@ pub(crate) mod sealed { add_complementary_capture_compare_methods!(regs_1ch_cmp); } + #[cfg(not(any(stm32l0, stm32l1)))] /// Gneral-purpose 2 channel with one complementary 16-bit timer instance. pub trait GeneralPurpose2ChannelComplementaryInstance: BasicInstance + GeneralPurpose2ChannelInstance + GeneralPurpose1ChannelComplementaryInstance @@ -477,6 +482,7 @@ pub(crate) mod sealed { add_complementary_capture_compare_methods!(regs_2ch_cmp); } + #[cfg(not(any(stm32l0, stm32l1)))] /// Advanced control timer instance. pub trait AdvancedControlInstance: GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance @@ -699,18 +705,21 @@ pub trait GeneralPurpose16bitInstance: { } +#[cfg(not(stm32l0))] /// Gneral-purpose 32-bit timer instance. pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + GeneralPurpose16bitInstance + 'static { } +#[cfg(not(any(stm32l0, stm32l1)))] /// General-purpose 1 channel with one complementary 16-bit timer instance. pub trait GeneralPurpose1ChannelComplementaryInstance: sealed::GeneralPurpose1ChannelComplementaryInstance + GeneralPurpose1ChannelInstance + 'static { } +#[cfg(not(any(stm32l0, stm32l1)))] /// General-purpose 2 channel with one complementary 16-bit timer instance. pub trait GeneralPurpose2ChannelComplementaryInstance: sealed::GeneralPurpose2ChannelComplementaryInstance @@ -721,6 +730,7 @@ pub trait GeneralPurpose2ChannelComplementaryInstance: { } +#[cfg(not(any(stm32l0, stm32l1)))] /// Advanced control timer instance. pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance + 'static @@ -738,18 +748,28 @@ pin_trait!(ExternalTriggerPin, GeneralPurpose16bitInstance); #[cfg(stm32l0)] pin_trait!(ExternalTriggerPin, GeneralPurpose2ChannelInstance); +#[cfg(not(any(stm32l0, stm32l1)))] pin_trait!(Channel1ComplementaryPin, GeneralPurpose1ChannelComplementaryInstance); +#[cfg(not(any(stm32l0, stm32l1)))] pin_trait!(Channel2ComplementaryPin, GeneralPurpose2ChannelComplementaryInstance); +#[cfg(not(any(stm32l0, stm32l1)))] pin_trait!(Channel3ComplementaryPin, AdvancedControlInstance); +#[cfg(not(any(stm32l0, stm32l1)))] pin_trait!(Channel4ComplementaryPin, AdvancedControlInstance); +#[cfg(not(any(stm32l0, stm32l1)))] pin_trait!(BreakInputPin, GeneralPurpose1ChannelComplementaryInstance); +#[cfg(not(any(stm32l0, stm32l1)))] pin_trait!(BreakInput2Pin, GeneralPurpose2ChannelComplementaryInstance); +#[cfg(not(any(stm32l0, stm32l1)))] pin_trait!(BreakInputComparator1Pin, GeneralPurpose1ChannelComplementaryInstance); +#[cfg(not(any(stm32l0, stm32l1)))] pin_trait!(BreakInputComparator2Pin, AdvancedControlInstance); +#[cfg(not(any(stm32l0, stm32l1)))] pin_trait!(BreakInput2Comparator1Pin, AdvancedControlInstance); +#[cfg(not(any(stm32l0, stm32l1)))] pin_trait!(BreakInput2Comparator2Pin, AdvancedControlInstance); #[allow(unused)] From 319f10da5daff415ad2dac17f4eed43313455167 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Thu, 1 Feb 2024 23:41:32 +0800 Subject: [PATCH 41/45] stm32-timer: filter out c0, f1 and f37x --- embassy-stm32/src/timer/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 8be96b414..be5c6cf29 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -376,7 +376,7 @@ pub(crate) mod sealed { add_capture_compare_dma_methods!(regs_gp16); } - #[cfg(not(any(stm32l0)))] + #[cfg(not(any(stm32f1, stm32l0, stm32c0)))] /// Gneral-purpose 32-bit timer instance. pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { /// Get access to the general purpose 32bit timer registers. @@ -705,7 +705,7 @@ pub trait GeneralPurpose16bitInstance: { } -#[cfg(not(stm32l0))] +#[cfg(not(any(stm32f1, stm32l0, stm32c0)))] /// Gneral-purpose 32-bit timer instance. pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + GeneralPurpose16bitInstance + 'static @@ -730,7 +730,7 @@ pub trait GeneralPurpose2ChannelComplementaryInstance: { } -#[cfg(not(any(stm32l0, stm32l1)))] +#[cfg(not(any(stm32f37, stm32l0, stm32l1)))] /// Advanced control timer instance. pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance + 'static From b3cdf3a040ae97923e84eca525505f7eff55e870 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Fri, 2 Feb 2024 14:52:54 +0800 Subject: [PATCH 42/45] bug fix --- embassy-stm32/src/timer/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index be5c6cf29..3e303a6cf 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -90,9 +90,9 @@ pub(crate) mod sealed { /// Set output compare mode. fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { - let r = Self::$regs(); let raw_channel: usize = channel.index(); - r.ccmr_output(raw_channel / 2) + Self::$regs() + .ccmr_output(raw_channel / 2) .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); } @@ -133,7 +133,7 @@ pub(crate) mod sealed { /// Set output compare preload. fn set_output_compare_preload(&mut self, channel: Channel, preload: bool) { let channel_index = channel.index(); - Self::regs_1ch() + Self::$regs() .ccmr_output(channel_index / 2) .modify(|w| w.set_ocpe(channel_index % 2, preload)); } From 6c690ab259ed15eece329a53a7147e7780f53cf3 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Fri, 2 Feb 2024 17:45:51 +0800 Subject: [PATCH 43/45] restore original public API of timer, but keep new PAC --- embassy-stm32/src/timer/complementary_pwm.rs | 41 +- embassy-stm32/src/timer/mod.rs | 525 ++++++++---------- embassy-stm32/src/timer/qei.rs | 4 +- embassy-stm32/src/timer/simple_pwm.rs | 39 +- .../stm32h7/src/bin/low_level_timer_api.rs | 4 +- 5 files changed, 274 insertions(+), 339 deletions(-) diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index b9cd044c9..72f1ec864 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -1,7 +1,6 @@ //! PWM driver with complementary output support. use core::marker::PhantomData; -use core::ops::{Deref, DerefMut}; use embassy_hal_internal::{into_ref, PeripheralRef}; use stm32_metapac::timer::vals::Ckd; @@ -24,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: AdvancedControlInstance> 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); @@ -53,7 +52,7 @@ pub struct ComplementaryPwm<'d, T> { inner: PeripheralRef<'d, T>, } -impl<'d, T: AdvancedControlInstance> ComplementaryPwm<'d, T> { +impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { /// Create a new complementary PWM driver. #[allow(clippy::too_many_arguments)] pub fn new( @@ -88,12 +87,8 @@ impl<'d, T: AdvancedControlInstance> ComplementaryPwm<'d, T> { [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] .iter() .for_each(|&channel| { - sealed::GeneralPurpose16bitInstance::set_output_compare_mode( - this.inner.deref_mut(), - channel, - OutputCompareMode::PwmMode1, - ); - sealed::GeneralPurpose16bitInstance::set_output_compare_preload(this.inner.deref_mut(), channel, true); + this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1); + this.inner.set_output_compare_preload(channel, true); }); this @@ -101,14 +96,14 @@ impl<'d, T: AdvancedControlInstance> ComplementaryPwm<'d, T> { /// Enable the given channel. pub fn enable(&mut self, channel: Channel) { - sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, true); - sealed::AdvancedControlInstance::enable_complementary_channel(self.inner.deref_mut(), channel, true); + self.inner.enable_channel(channel, true); + self.inner.enable_complementary_channel(channel, true); } /// Disable the given channel. pub fn disable(&mut self, channel: Channel) { - sealed::AdvancedControlInstance::enable_complementary_channel(self.inner.deref_mut(), channel, false); - sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, false); + self.inner.enable_complementary_channel(channel, false); + self.inner.enable_channel(channel, false); } /// Set PWM frequency. @@ -136,13 +131,13 @@ impl<'d, T: AdvancedControlInstance> ComplementaryPwm<'d, T> { /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. pub fn set_duty(&mut self, channel: Channel, duty: u16) { assert!(duty <= self.get_max_duty()); - sealed::GeneralPurpose16bitInstance::set_compare_value(self.inner.deref_mut(), channel, duty) + self.inner.set_compare_value(channel, duty) } /// Set the output polarity for a given channel. pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { - sealed::GeneralPurpose16bitInstance::set_output_polarity(self.inner.deref_mut(), channel, polarity); - sealed::AdvancedControlInstance::set_complementary_output_polarity(self.inner.deref_mut(), channel, polarity); + self.inner.set_output_polarity(channel, polarity); + self.inner.set_complementary_output_polarity(channel, polarity); } /// Set the dead time as a proportion of max_duty @@ -154,19 +149,19 @@ impl<'d, T: AdvancedControlInstance> ComplementaryPwm<'d, T> { } } -impl<'d, T: AdvancedControlInstance> embedded_hal_02::Pwm for ComplementaryPwm<'d, T> { +impl<'d, T: ComplementaryCaptureCompare16bitInstance> embedded_hal_02::Pwm for ComplementaryPwm<'d, T> { type Channel = Channel; type Time = Hertz; type Duty = u16; fn disable(&mut self, channel: Self::Channel) { - sealed::AdvancedControlInstance::enable_complementary_channel(self.inner.deref_mut(), channel, false); - sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, false); + self.inner.enable_complementary_channel(channel, false); + self.inner.enable_channel(channel, false); } fn enable(&mut self, channel: Self::Channel) { - sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, true); - sealed::AdvancedControlInstance::enable_complementary_channel(self.inner.deref_mut(), channel, true); + self.inner.enable_channel(channel, true); + self.inner.enable_complementary_channel(channel, true); } fn get_period(&self) -> Self::Time { @@ -174,7 +169,7 @@ impl<'d, T: AdvancedControlInstance> embedded_hal_02::Pwm for ComplementaryPwm<' } fn get_duty(&self, channel: Self::Channel) -> Self::Duty { - sealed::GeneralPurpose16bitInstance::get_compare_value(self.inner.deref(), channel) + self.inner.get_compare_value(channel) } fn get_max_duty(&self) -> Self::Duty { @@ -183,7 +178,7 @@ impl<'d, T: AdvancedControlInstance> embedded_hal_02::Pwm for ComplementaryPwm<' fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { assert!(duty <= self.get_max_duty()); - sealed::GeneralPurpose16bitInstance::set_compare_value(self.inner.deref_mut(), channel, duty) + self.inner.set_compare_value(channel, duty) } fn set_period

(&mut self, period: P) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 3e303a6cf..5f40be957 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -1,6 +1,8 @@ //! Timers, PWM, quadrature decoder. -// Timer inheritance +//! Timer inheritance + +// sealed: // // Core -------------------------> 1CH -------------------------> 1CH_CMP // | | ^ | @@ -12,7 +14,18 @@ // | +--------------------------------------|-----------+ // +----------------------------------------------------+ -#[cfg(not(any(stm32l0, stm32l1)))] +//! BasicInstance --> CaptureCompare16bitInstance --+--> ComplementaryCaptureCompare16bitInstance +//! | +//! +--> CaptureCompare32bitInstance +//! +//! mapping: +//! +//! Basic Timer --> BasicInstance +//! 1-channel Timer, 2-channel Timer, General Purpose 16-bit Timer --> CaptureCompare16bitInstance +//! General Purpose 32-bit Timer --> CaptureCompare32bitInstance +//! 1-channel with one complentary Timer, 2-channel with one complentary Timer, Advance Control Timer --> ComplementaryCaptureCompare16bitInstance + +#[cfg(not(stm32l0))] pub mod complementary_pwm; pub mod qei; pub mod simple_pwm; @@ -32,157 +45,6 @@ pub mod low_level { pub(crate) mod sealed { use super::*; - macro_rules! add_capture_compare_common_methods { - ($regs:ident) => { - /// Set input capture filter. - fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::FilterValue) { - let raw_channel = channel.index(); - Self::$regs() - .ccmr_input(raw_channel / 2) - .modify(|r| r.set_icf(raw_channel % 2, icf)); - } - - /// Clear input interrupt. - fn clear_input_interrupt(&mut self, channel: Channel) { - Self::$regs().sr().modify(|r| r.set_ccif(channel.index(), false)); - } - - /// Enable input interrupt. - fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { - Self::$regs() - .dier() - .modify(|r| r.set_ccie(channel.index(), enable)); - } - - /// Set input capture prescaler. - fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { - let raw_channel = channel.index(); - Self::$regs() - .ccmr_input(raw_channel / 2) - .modify(|r| r.set_icpsc(raw_channel % 2, factor)); - } - - /// Set input TI selection. - fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { - let raw_channel = channel.index(); - Self::$regs() - .ccmr_input(raw_channel / 2) - .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); - } - - /// Set input capture mode. - fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { - Self::$regs().ccer().modify(|r| match mode { - InputCaptureMode::Rising => { - r.set_ccnp(channel.index(), false); - r.set_ccp(channel.index(), false); - } - InputCaptureMode::Falling => { - r.set_ccnp(channel.index(), false); - r.set_ccp(channel.index(), true); - } - InputCaptureMode::BothEdges => { - r.set_ccnp(channel.index(), true); - r.set_ccp(channel.index(), true); - } - }); - } - - /// Set output compare mode. - fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { - let raw_channel: usize = channel.index(); - Self::$regs() - .ccmr_output(raw_channel / 2) - .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); - } - - /// Set output polarity. - fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { - Self::$regs() - .ccer() - .modify(|w| w.set_ccp(channel.index(), polarity.into())); - } - - /// Enable/disable a channel. - fn enable_channel(&mut self, channel: Channel, enable: bool) { - Self::$regs() - .ccer() - .modify(|w| w.set_cce(channel.index(), enable)); - } - - /// Get enable/disable state of a channel - fn get_channel_enable_state(&self, channel: Channel) -> bool { - Self::$regs().ccer().read().cce(channel.index()) - } - - /// Set compare value for a channel. - fn set_compare_value(&mut self, channel: Channel, value: u16) { - Self::$regs().ccr(channel.index()).modify(|w| w.set_ccr(value)); - } - - /// Get capture value for a channel. - fn get_capture_value(&mut self, channel: Channel) -> u16 { - Self::$regs().ccr(channel.index()).read().ccr() - } - - /// Get compare value for a channel. - fn get_compare_value(&self, channel: Channel) -> u16 { - Self::$regs().ccr(channel.index()).read().ccr() - } - - /// Set output compare preload. - fn set_output_compare_preload(&mut self, channel: Channel, preload: bool) { - let channel_index = channel.index(); - Self::$regs() - .ccmr_output(channel_index / 2) - .modify(|w| w.set_ocpe(channel_index % 2, preload)); - } - }; - } - - macro_rules! add_capture_compare_dma_methods { - ($regs:ident) => { - /// Get capture compare DMA selection - fn get_cc_dma_selection(&self) -> super::vals::Ccds { - Self::$regs().cr2().read().ccds() - } - - /// Set capture compare DMA selection - fn set_cc_dma_selection(&mut self, ccds: super::vals::Ccds) { - Self::$regs().cr2().modify(|w| w.set_ccds(ccds)) - } - - /// Get capture compare DMA enable state - fn get_cc_dma_enable_state(&self, channel: Channel) -> bool { - Self::$regs().dier().read().ccde(channel.index()) - } - - /// Set capture compare DMA enable state - fn set_cc_dma_enable_state(&mut self, channel: Channel, ccde: bool) { - Self::$regs().dier().modify(|w| w.set_ccde(channel.index(), ccde)) - } - }; - } - - #[cfg(not(any(stm32l0, stm32l1)))] - macro_rules! add_complementary_capture_compare_methods { - ($regs:ident) => { - /// Set complementary output polarity. - fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { - Self::$regs() - .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() - .ccer() - .modify(|w| w.set_ccne(channel.index(), enable)); - } - }; - } - /// Virtual Core 16-bit timer instance. pub trait CoreInstance: RccPeripheral { /// Interrupt for this timer. @@ -326,8 +188,6 @@ pub(crate) mod sealed { fn get_max_compare_value(&self) -> u16 { Self::regs_1ch().arr().read().arr() } - - add_capture_compare_common_methods!(regs_1ch); } /// Gneral-purpose 1 channel 16-bit timer instance. @@ -339,8 +199,6 @@ pub(crate) mod sealed { /// for a given set of capabilities, and having it transparently work with /// more capable timers. fn regs_2ch() -> crate::pac::timer::Tim2ch; - - add_capture_compare_common_methods!(regs_2ch); } /// Gneral-purpose 16-bit timer instance. @@ -372,11 +230,128 @@ pub(crate) mod sealed { (cr1.cms(), cr1.dir()).into() } - add_capture_compare_common_methods!(regs_gp16); - add_capture_compare_dma_methods!(regs_gp16); + /// Set input capture filter. + 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) + .modify(|r| r.set_icf(raw_channel % 2, icf)); + } + + /// Clear input interrupt. + fn clear_input_interrupt(&mut self, channel: Channel) { + Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false)); + } + + /// Enable input interrupt. + fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { + Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable)); + } + + /// Set input capture prescaler. + fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { + let raw_channel = channel.index(); + Self::regs_gp16() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_icpsc(raw_channel % 2, factor)); + } + + /// Set input TI selection. + fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { + let raw_channel = channel.index(); + Self::regs_gp16() + .ccmr_input(raw_channel / 2) + .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); + } + + /// Set input capture mode. + fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { + Self::regs_gp16().ccer().modify(|r| match mode { + InputCaptureMode::Rising => { + r.set_ccnp(channel.index(), false); + r.set_ccp(channel.index(), false); + } + InputCaptureMode::Falling => { + r.set_ccnp(channel.index(), false); + r.set_ccp(channel.index(), true); + } + InputCaptureMode::BothEdges => { + r.set_ccnp(channel.index(), true); + r.set_ccp(channel.index(), true); + } + }); + } + + /// Set output compare mode. + fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { + let raw_channel: usize = channel.index(); + Self::regs_gp16() + .ccmr_output(raw_channel / 2) + .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); + } + + /// Set output polarity. + fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { + Self::regs_gp16() + .ccer() + .modify(|w| w.set_ccp(channel.index(), polarity.into())); + } + + /// Enable/disable a channel. + fn enable_channel(&mut self, channel: Channel, enable: bool) { + Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable)); + } + + /// Get enable/disable state of a channel + fn get_channel_enable_state(&self, channel: Channel) -> bool { + Self::regs_gp16().ccer().read().cce(channel.index()) + } + + /// Set compare value for a channel. + fn set_compare_value(&mut self, channel: Channel, value: u16) { + Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value)); + } + + /// Get capture value for a channel. + fn get_capture_value(&mut self, channel: Channel) -> u16 { + Self::regs_gp16().ccr(channel.index()).read().ccr() + } + + /// Get compare value for a channel. + fn get_compare_value(&self, channel: Channel) -> u16 { + Self::regs_gp16().ccr(channel.index()).read().ccr() + } + + /// Set output compare preload. + fn set_output_compare_preload(&mut self, channel: Channel, preload: bool) { + let channel_index = channel.index(); + Self::regs_gp16() + .ccmr_output(channel_index / 2) + .modify(|w| w.set_ocpe(channel_index % 2, preload)); + } + + /// Get capture compare DMA selection + fn get_cc_dma_selection(&self) -> super::vals::Ccds { + Self::regs_gp16().cr2().read().ccds() + } + + /// Set capture compare DMA selection + fn set_cc_dma_selection(&mut self, ccds: super::vals::Ccds) { + Self::regs_gp16().cr2().modify(|w| w.set_ccds(ccds)) + } + + /// Get capture compare DMA enable state + fn get_cc_dma_enable_state(&self, channel: Channel) -> bool { + Self::regs_gp16().dier().read().ccde(channel.index()) + } + + /// Set capture compare DMA enable state + fn set_cc_dma_enable_state(&mut self, channel: Channel, ccde: bool) { + Self::regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde)) + } } - #[cfg(not(any(stm32f1, stm32l0, stm32c0)))] + #[cfg(not(stm32l0))] /// Gneral-purpose 32-bit timer instance. pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { /// Get access to the general purpose 32bit timer registers. @@ -437,7 +412,7 @@ pub(crate) mod sealed { } } - #[cfg(not(any(stm32l0, stm32l1)))] + #[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. @@ -462,11 +437,9 @@ pub(crate) mod sealed { fn enable_outputs(&mut self) { Self::regs_1ch_cmp().bdtr().modify(|w| w.set_moe(true)); } - - add_complementary_capture_compare_methods!(regs_1ch_cmp); } - #[cfg(not(any(stm32l0, stm32l1)))] + #[cfg(not(stm32l0))] /// Gneral-purpose 2 channel with one complementary 16-bit timer instance. pub trait GeneralPurpose2ChannelComplementaryInstance: BasicInstance + GeneralPurpose2ChannelInstance + GeneralPurpose1ChannelComplementaryInstance @@ -478,11 +451,9 @@ pub(crate) mod sealed { /// for a given set of capabilities, and having it transparently work with /// more capable timers. fn regs_2ch_cmp() -> crate::pac::timer::Tim2chCmp; - - add_complementary_capture_compare_methods!(regs_2ch_cmp); } - #[cfg(not(any(stm32l0, stm32l1)))] + #[cfg(not(stm32l0))] /// Advanced control timer instance. pub trait AdvancedControlInstance: GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance @@ -490,7 +461,19 @@ pub(crate) mod sealed { /// Get access to the advanced timer registers. fn regs_advanced() -> crate::pac::timer::TimAdv; - add_complementary_capture_compare_methods!(regs_advanced); + /// 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)); + } } } @@ -681,96 +664,66 @@ impl From for bool { } } -/// Virtual Core 16-bit timer instance. -pub trait CoreInstance: sealed::CoreInstance + 'static {} - -/// Virtual Basic 16-bit timer without CR2 register instance. -pub trait BasicNoCr2Instance: sealed::BasicNoCr2Instance + CoreInstance + 'static {} - /// Basic 16-bit timer instance. -pub trait BasicInstance: sealed::BasicInstance + BasicNoCr2Instance + 'static {} - -/// 1 channel 16-bit instance. -pub trait GeneralPurpose1ChannelInstance: sealed::GeneralPurpose1ChannelInstance + CoreInstance + 'static {} - -/// 2 channel 16-bit instance. -pub trait GeneralPurpose2ChannelInstance: - sealed::GeneralPurpose2ChannelInstance + GeneralPurpose1ChannelInstance + 'static -{ -} +pub trait BasicInstance: sealed::BasicInstance + sealed::BasicNoCr2Instance + sealed::CoreInstance + 'static {} /// General-purpose 16-bit timer instance. -pub trait GeneralPurpose16bitInstance: - sealed::GeneralPurpose16bitInstance + BasicInstance + GeneralPurpose2ChannelInstance + 'static -{ -} - -#[cfg(not(any(stm32f1, stm32l0, stm32c0)))] -/// Gneral-purpose 32-bit timer instance. -pub trait GeneralPurpose32bitInstance: - sealed::GeneralPurpose32bitInstance + GeneralPurpose16bitInstance + 'static -{ -} - -#[cfg(not(any(stm32l0, stm32l1)))] -/// General-purpose 1 channel with one complementary 16-bit timer instance. -pub trait GeneralPurpose1ChannelComplementaryInstance: - sealed::GeneralPurpose1ChannelComplementaryInstance + GeneralPurpose1ChannelInstance + 'static -{ -} - -#[cfg(not(any(stm32l0, stm32l1)))] -/// General-purpose 2 channel with one complementary 16-bit timer instance. -pub trait GeneralPurpose2ChannelComplementaryInstance: - sealed::GeneralPurpose2ChannelComplementaryInstance - + BasicInstance - + GeneralPurpose2ChannelInstance - + GeneralPurpose1ChannelComplementaryInstance +pub trait CaptureCompare16bitInstance: + BasicInstance + + sealed::GeneralPurpose2ChannelInstance + + sealed::GeneralPurpose1ChannelInstance + + sealed::GeneralPurpose16bitInstance + 'static { } -#[cfg(not(any(stm32f37, stm32l0, stm32l1)))] -/// Advanced control timer instance. -pub trait AdvancedControlInstance: - sealed::AdvancedControlInstance + GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance + 'static +#[cfg(not(stm32l0))] +/// Gneral-purpose 32-bit timer instance. +pub trait CaptureCompare32bitInstance: + sealed::GeneralPurpose32bitInstance + CaptureCompare16bitInstance + 'static { } -pin_trait!(Channel1Pin, GeneralPurpose1ChannelInstance); -pin_trait!(Channel2Pin, GeneralPurpose2ChannelInstance); -pin_trait!(Channel3Pin, GeneralPurpose16bitInstance); -pin_trait!(Channel4Pin, GeneralPurpose16bitInstance); +#[cfg(not(stm32l0))] +/// Advanced control timer instance. +pub trait ComplementaryCaptureCompare16bitInstance: + CaptureCompare16bitInstance + + sealed::GeneralPurpose1ChannelComplementaryInstance + + sealed::GeneralPurpose2ChannelComplementaryInstance + + sealed::AdvancedControlInstance + + 'static +{ +} + +pin_trait!(Channel1Pin, CaptureCompare16bitInstance); +pin_trait!(Channel2Pin, CaptureCompare16bitInstance); +pin_trait!(Channel3Pin, CaptureCompare16bitInstance); +pin_trait!(Channel4Pin, CaptureCompare16bitInstance); +pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance); #[cfg(not(stm32l0))] -pin_trait!(ExternalTriggerPin, GeneralPurpose16bitInstance); +pin_trait!(Channel1ComplementaryPin, ComplementaryCaptureCompare16bitInstance); +#[cfg(not(stm32l0))] +pin_trait!(Channel2ComplementaryPin, ComplementaryCaptureCompare16bitInstance); +#[cfg(not(stm32l0))] +pin_trait!(Channel3ComplementaryPin, ComplementaryCaptureCompare16bitInstance); +#[cfg(not(stm32l0))] +pin_trait!(Channel4ComplementaryPin, ComplementaryCaptureCompare16bitInstance); -#[cfg(stm32l0)] -pin_trait!(ExternalTriggerPin, GeneralPurpose2ChannelInstance); +#[cfg(not(stm32l0))] +pin_trait!(BreakInputPin, ComplementaryCaptureCompare16bitInstance); +#[cfg(not(stm32l0))] +pin_trait!(BreakInput2Pin, ComplementaryCaptureCompare16bitInstance); -#[cfg(not(any(stm32l0, stm32l1)))] -pin_trait!(Channel1ComplementaryPin, GeneralPurpose1ChannelComplementaryInstance); -#[cfg(not(any(stm32l0, stm32l1)))] -pin_trait!(Channel2ComplementaryPin, GeneralPurpose2ChannelComplementaryInstance); -#[cfg(not(any(stm32l0, stm32l1)))] -pin_trait!(Channel3ComplementaryPin, AdvancedControlInstance); -#[cfg(not(any(stm32l0, stm32l1)))] -pin_trait!(Channel4ComplementaryPin, AdvancedControlInstance); +#[cfg(not(stm32l0))] +pin_trait!(BreakInputComparator1Pin, ComplementaryCaptureCompare16bitInstance); +#[cfg(not(stm32l0))] +pin_trait!(BreakInputComparator2Pin, ComplementaryCaptureCompare16bitInstance); -#[cfg(not(any(stm32l0, stm32l1)))] -pin_trait!(BreakInputPin, GeneralPurpose1ChannelComplementaryInstance); -#[cfg(not(any(stm32l0, stm32l1)))] -pin_trait!(BreakInput2Pin, GeneralPurpose2ChannelComplementaryInstance); - -#[cfg(not(any(stm32l0, stm32l1)))] -pin_trait!(BreakInputComparator1Pin, GeneralPurpose1ChannelComplementaryInstance); -#[cfg(not(any(stm32l0, stm32l1)))] -pin_trait!(BreakInputComparator2Pin, AdvancedControlInstance); - -#[cfg(not(any(stm32l0, stm32l1)))] -pin_trait!(BreakInput2Comparator1Pin, AdvancedControlInstance); -#[cfg(not(any(stm32l0, stm32l1)))] -pin_trait!(BreakInput2Comparator2Pin, AdvancedControlInstance); +#[cfg(not(stm32l0))] +pin_trait!(BreakInput2Comparator1Pin, ComplementaryCaptureCompare16bitInstance); +#[cfg(not(stm32l0))] +pin_trait!(BreakInput2Comparator2Pin, ComplementaryCaptureCompare16bitInstance); #[allow(unused)] macro_rules! impl_core_timer { @@ -830,7 +783,7 @@ macro_rules! impl_2ch_timer { } #[allow(unused)] -macro_rules! impl_gp_16bit_timer { +macro_rules! impl_gp16_timer { ($inst:ident) => { impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { fn regs_gp16() -> crate::pac::timer::TimGp16 { @@ -841,7 +794,7 @@ macro_rules! impl_gp_16bit_timer { } #[allow(unused)] -macro_rules! impl_gp_32bit_timer { +macro_rules! impl_gp32_timer { ($inst:ident) => { impl sealed::GeneralPurpose32bitInstance for crate::peripherals::$inst { fn regs_gp32() -> crate::pac::timer::TimGp32 { @@ -890,26 +843,30 @@ foreach_interrupt! { impl_core_timer!($inst, $irq); impl_basic_no_cr2_timer!($inst); impl_basic_timer!($inst); - impl CoreInstance for crate::peripherals::$inst {} - impl BasicNoCr2Instance for crate::peripherals::$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 CoreInstance for crate::peripherals::$inst {} - impl GeneralPurpose1ChannelInstance for crate::peripherals::$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 CoreInstance for crate::peripherals::$inst {} - impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl GeneralPurpose2ChannelInstance for crate::peripherals::$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) => { @@ -918,13 +875,9 @@ foreach_interrupt! { impl_basic_timer!($inst); impl_1ch_timer!($inst); impl_2ch_timer!($inst); - impl_gp_16bit_timer!($inst); - impl CoreInstance for crate::peripherals::$inst {} - impl BasicNoCr2Instance for crate::peripherals::$inst{} + impl_gp16_timer!($inst); impl BasicInstance for crate::peripherals::$inst {} - impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} - impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { @@ -933,26 +886,26 @@ foreach_interrupt! { impl_basic_timer!($inst); impl_1ch_timer!($inst); impl_2ch_timer!($inst); - impl_gp_16bit_timer!($inst); - impl_gp_32bit_timer!($inst); - impl CoreInstance for crate::peripherals::$inst {} - impl BasicNoCr2Instance for crate::peripherals::$inst{} + impl_gp16_timer!($inst); + impl_gp32_timer!($inst); impl BasicInstance for crate::peripherals::$inst {} - impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} - impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} - impl GeneralPurpose32bitInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl CaptureCompare32bitInstance 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 CoreInstance for crate::peripherals::$inst {} - impl BasicNoCr2Instance for crate::peripherals::$inst{} - impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$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 {} }; @@ -962,15 +915,13 @@ foreach_interrupt! { 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 CoreInstance for crate::peripherals::$inst {} - impl BasicNoCr2Instance for crate::peripherals::$inst{} + impl_adv_timer!($inst); impl BasicInstance for crate::peripherals::$inst {} - impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} - impl GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst {} - impl GeneralPurpose2ChannelComplementaryInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} }; @@ -980,26 +931,20 @@ foreach_interrupt! { impl_basic_timer!($inst); impl_1ch_timer!($inst); impl_2ch_timer!($inst); + impl_gp16_timer!($inst); impl_1ch_cmp_timer!($inst); - impl_gp_16bit_timer!($inst); impl_2ch_cmp_timer!($inst); impl_adv_timer!($inst); - impl CoreInstance for crate::peripherals::$inst {} - impl BasicNoCr2Instance for crate::peripherals::$inst{} impl BasicInstance for crate::peripherals::$inst {} - impl GeneralPurpose1ChannelInstance for crate::peripherals::$inst {} - impl GeneralPurpose2ChannelInstance for crate::peripherals::$inst {} - impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} - impl GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst {} - impl GeneralPurpose2ChannelComplementaryInstance for crate::peripherals::$inst {} - impl AdvancedControlInstance 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, BasicNoCr2Instance); +dma_trait!(UpDma, BasicInstance); -dma_trait!(Ch1Dma, GeneralPurpose1ChannelInstance); -dma_trait!(Ch2Dma, GeneralPurpose2ChannelInstance); -dma_trait!(Ch3Dma, GeneralPurpose16bitInstance); -dma_trait!(Ch4Dma, GeneralPurpose16bitInstance); +dma_trait!(Ch1Dma, CaptureCompare16bitInstance); +dma_trait!(Ch2Dma, CaptureCompare16bitInstance); +dma_trait!(Ch3Dma, CaptureCompare16bitInstance); +dma_trait!(Ch4Dma, CaptureCompare16bitInstance); diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index 7e56312bb..59efb72ba 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -30,7 +30,7 @@ pub struct QeiPin<'d, T, Channel> { macro_rules! channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, T: GeneralPurpose16bitInstance> QeiPin<'d, T, $channel> { + impl<'d, T: CaptureCompare16bitInstance> QeiPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")] pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { into_ref!(pin); @@ -57,7 +57,7 @@ pub struct Qei<'d, T> { _inner: PeripheralRef<'d, T>, } -impl<'d, T: GeneralPurpose16bitInstance> Qei<'d, T> { +impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { /// Create a new quadrature decoder driver. pub fn new(tim: impl Peripheral

+ 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { Self::new_inner(tim) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 088d02c97..1acba504e 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -1,7 +1,6 @@ //! Simple PWM driver. use core::marker::PhantomData; -use core::ops::{Deref, DerefMut}; use embassy_hal_internal::{into_ref, PeripheralRef}; @@ -31,7 +30,7 @@ pub struct PwmPin<'d, T, C> { macro_rules! channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, T: GeneralPurpose16bitInstance> PwmPin<'d, T, $channel> { + impl<'d, T: CaptureCompare16bitInstance> PwmPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] pub fn $new_chx(pin: impl Peripheral

> + 'd, output_type: OutputType) -> Self { into_ref!(pin); @@ -60,7 +59,7 @@ pub struct SimplePwm<'d, T> { inner: PeripheralRef<'d, T>, } -impl<'d, T: GeneralPurpose16bitInstance> SimplePwm<'d, T> { +impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { /// Create a new simple PWM driver. pub fn new( tim: impl Peripheral

+ 'd, @@ -88,13 +87,9 @@ impl<'d, T: GeneralPurpose16bitInstance> SimplePwm<'d, T> { [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] .iter() .for_each(|&channel| { - sealed::GeneralPurpose16bitInstance::set_output_compare_mode( - this.inner.deref_mut(), - channel, - OutputCompareMode::PwmMode1, - ); + this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1); - sealed::GeneralPurpose16bitInstance::set_output_compare_preload(this.inner.deref_mut(), channel, true); + this.inner.set_output_compare_preload(channel, true); }); this @@ -102,17 +97,17 @@ impl<'d, T: GeneralPurpose16bitInstance> SimplePwm<'d, T> { /// Enable the given channel. pub fn enable(&mut self, channel: Channel) { - sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, true); + self.inner.enable_channel(channel, true); } /// Disable the given channel. pub fn disable(&mut self, channel: Channel) { - sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, false); + self.inner.enable_channel(channel, false); } /// Check whether given channel is enabled pub fn is_enabled(&self, channel: Channel) -> bool { - sealed::GeneralPurpose16bitInstance::get_channel_enable_state(self.inner.deref(), channel) + self.inner.get_channel_enable_state(channel) } /// Set PWM frequency. @@ -140,24 +135,24 @@ impl<'d, T: GeneralPurpose16bitInstance> SimplePwm<'d, T> { /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. pub fn set_duty(&mut self, channel: Channel, duty: u16) { assert!(duty <= self.get_max_duty()); - sealed::GeneralPurpose16bitInstance::set_compare_value(self.inner.deref_mut(), channel, duty) + self.inner.set_compare_value(channel, duty) } /// Get the duty for a given channel. /// /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. pub fn get_duty(&self, channel: Channel) -> u16 { - sealed::GeneralPurpose16bitInstance::get_compare_value(self.inner.deref(), channel) + self.inner.get_compare_value(channel) } /// Set the output polarity for a given channel. pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { - sealed::GeneralPurpose16bitInstance::set_output_polarity(self.inner.deref_mut(), channel, polarity); + self.inner.set_output_polarity(channel, polarity); } /// Set the output compare mode for a given channel. pub fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { - sealed::GeneralPurpose16bitInstance::set_output_compare_mode(self.inner.deref_mut(), channel, mode); + self.inner.set_output_compare_mode(channel, mode); } /// Generate a sequence of PWM waveform @@ -232,7 +227,7 @@ impl<'d, T: GeneralPurpose16bitInstance> SimplePwm<'d, T> { macro_rules! impl_waveform_chx { ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => { - impl<'d, T: GeneralPurpose16bitInstance> SimplePwm<'d, T> { + impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { /// Generate a sequence of PWM waveform /// /// Note: @@ -319,17 +314,17 @@ impl_waveform_chx!(waveform_ch2, Ch2Dma, Ch2); impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3); impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4); -impl<'d, T: GeneralPurpose16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> { +impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> { type Channel = Channel; type Time = Hertz; type Duty = u16; fn disable(&mut self, channel: Self::Channel) { - sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, false); + self.inner.enable_channel(channel, false); } fn enable(&mut self, channel: Self::Channel) { - sealed::GeneralPurpose16bitInstance::enable_channel(self.inner.deref_mut(), channel, true); + self.inner.enable_channel(channel, true); } fn get_period(&self) -> Self::Time { @@ -337,7 +332,7 @@ impl<'d, T: GeneralPurpose16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, } fn get_duty(&self, channel: Self::Channel) -> Self::Duty { - sealed::GeneralPurpose16bitInstance::get_compare_value(self.inner.deref(), channel) + self.inner.get_compare_value(channel) } fn get_max_duty(&self) -> Self::Duty { @@ -346,7 +341,7 @@ impl<'d, T: GeneralPurpose16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { assert!(duty <= self.get_max_duty()); - sealed::GeneralPurpose16bitInstance::set_compare_value(self.inner.deref_mut(), channel, duty) + self.inner.set_compare_value(channel, duty) } fn set_period

(&mut self, period: P) diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs index 0be3eccb7..cc508c3cf 100644 --- a/examples/stm32h7/src/bin/low_level_timer_api.rs +++ b/examples/stm32h7/src/bin/low_level_timer_api.rs @@ -56,11 +56,11 @@ async fn main(_spawner: Spawner) { Timer::after_millis(300).await; } } -pub struct SimplePwm32<'d, T: GeneralPurpose32bitInstance> { +pub struct SimplePwm32<'d, T: CaptureCompare32bitInstance> { inner: PeripheralRef<'d, T>, } -impl<'d, T: GeneralPurpose32bitInstance> SimplePwm32<'d, T> { +impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { pub fn new( tim: impl Peripheral

+ 'd, ch1: impl Peripheral

> + 'd, From 0f94006be3aa099d0a6039d51834562e51f91580 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Sat, 3 Feb 2024 17:30:00 +0800 Subject: [PATCH 44/45] doc fix --- embassy-stm32/src/timer/mod.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 5f40be957..9780c005c 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -20,10 +20,10 @@ //! //! mapping: //! -//! Basic Timer --> BasicInstance -//! 1-channel Timer, 2-channel Timer, General Purpose 16-bit Timer --> CaptureCompare16bitInstance -//! General Purpose 32-bit Timer --> CaptureCompare32bitInstance -//! 1-channel with one complentary Timer, 2-channel with one complentary Timer, Advance Control Timer --> ComplementaryCaptureCompare16bitInstance +//! 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; @@ -667,7 +667,8 @@ impl From for bool { /// Basic 16-bit timer instance. pub trait BasicInstance: sealed::BasicInstance + sealed::BasicNoCr2Instance + sealed::CoreInstance + 'static {} -/// General-purpose 16-bit timer instance. +// It's just a General-purpose 16-bit timer instance. +/// Capture Compare timer instance. pub trait CaptureCompare16bitInstance: BasicInstance + sealed::GeneralPurpose2ChannelInstance @@ -678,14 +679,16 @@ pub trait CaptureCompare16bitInstance: } #[cfg(not(stm32l0))] -/// Gneral-purpose 32-bit timer instance. +// It's just a General-purpose 32-bit timer instance. +/// Capture Compare 32-bit timer instance. pub trait CaptureCompare32bitInstance: - sealed::GeneralPurpose32bitInstance + CaptureCompare16bitInstance + 'static + CaptureCompare16bitInstance + sealed::GeneralPurpose32bitInstance + 'static { } #[cfg(not(stm32l0))] -/// Advanced control timer instance. +// It's just a Advanced Control timer instance. +/// Complementary Capture Compare 32-bit timer instance. pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + sealed::GeneralPurpose1ChannelComplementaryInstance From 8fd803a5fe0af8cc9d648ba2efba755b502f08e9 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Sun, 4 Feb 2024 15:14:02 +0800 Subject: [PATCH 45/45] use cfg_if to reduce macro condition --- embassy-stm32/src/timer/mod.rs | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 9780c005c..0118395a7 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -704,29 +704,23 @@ pin_trait!(Channel3Pin, CaptureCompare16bitInstance); pin_trait!(Channel4Pin, CaptureCompare16bitInstance); pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance); -#[cfg(not(stm32l0))] -pin_trait!(Channel1ComplementaryPin, ComplementaryCaptureCompare16bitInstance); -#[cfg(not(stm32l0))] -pin_trait!(Channel2ComplementaryPin, ComplementaryCaptureCompare16bitInstance); -#[cfg(not(stm32l0))] -pin_trait!(Channel3ComplementaryPin, ComplementaryCaptureCompare16bitInstance); -#[cfg(not(stm32l0))] -pin_trait!(Channel4ComplementaryPin, ComplementaryCaptureCompare16bitInstance); +cfg_if::cfg_if! { + if #[cfg(not(stm32l0))] { + pin_trait!(Channel1ComplementaryPin, ComplementaryCaptureCompare16bitInstance); + pin_trait!(Channel2ComplementaryPin, ComplementaryCaptureCompare16bitInstance); + pin_trait!(Channel3ComplementaryPin, ComplementaryCaptureCompare16bitInstance); + pin_trait!(Channel4ComplementaryPin, ComplementaryCaptureCompare16bitInstance); -#[cfg(not(stm32l0))] -pin_trait!(BreakInputPin, ComplementaryCaptureCompare16bitInstance); -#[cfg(not(stm32l0))] -pin_trait!(BreakInput2Pin, ComplementaryCaptureCompare16bitInstance); + pin_trait!(BreakInputPin, ComplementaryCaptureCompare16bitInstance); + pin_trait!(BreakInput2Pin, ComplementaryCaptureCompare16bitInstance); -#[cfg(not(stm32l0))] -pin_trait!(BreakInputComparator1Pin, ComplementaryCaptureCompare16bitInstance); -#[cfg(not(stm32l0))] -pin_trait!(BreakInputComparator2Pin, ComplementaryCaptureCompare16bitInstance); + pin_trait!(BreakInputComparator1Pin, ComplementaryCaptureCompare16bitInstance); + pin_trait!(BreakInputComparator2Pin, ComplementaryCaptureCompare16bitInstance); -#[cfg(not(stm32l0))] -pin_trait!(BreakInput2Comparator1Pin, ComplementaryCaptureCompare16bitInstance); -#[cfg(not(stm32l0))] -pin_trait!(BreakInput2Comparator2Pin, ComplementaryCaptureCompare16bitInstance); + pin_trait!(BreakInput2Comparator1Pin, ComplementaryCaptureCompare16bitInstance); + pin_trait!(BreakInput2Comparator2Pin, ComplementaryCaptureCompare16bitInstance); + } +} #[allow(unused)] macro_rules! impl_core_timer {