aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRick Rogers <[email protected]>2025-07-25 11:34:21 -0400
committerRick Rogers <[email protected]>2025-07-25 11:34:21 -0400
commit33fc82a455df058c5bdef23b68304a3dcb33f069 (patch)
tree63f876b833e5ced8863b0b4825e8ab822190dd13
parent24b2794931e73325ad969d83453d0cf872ac4775 (diff)
parent996974e313fa5ec2c7c2d9dd0998fab244c0a180 (diff)
Merge branch 'main' into h7rs-xspi-fixes
-rwxr-xr-x.github/ci/book.sh2
-rwxr-xr-x.github/ci/doc.sh2
-rwxr-xr-xci.sh2
-rw-r--r--docs/pages/layer_by_layer.adoc2
-rw-r--r--embassy-embedded-hal/Cargo.toml1
-rw-r--r--embassy-embedded-hal/src/adapter/blocking_async.rs28
-rw-r--r--embassy-rp/src/lib.rs2
-rw-r--r--embassy-stm32/Cargo.toml1
-rw-r--r--embassy-stm32/src/dac/mod.rs40
-rw-r--r--embassy-stm32/src/i2c/v2.rs278
-rw-r--r--embassy-stm32/src/lptim/timer/mod.rs50
-rw-r--r--embassy-stm32/src/rcc/u5.rs165
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs13
-rw-r--r--examples/stm32wb/src/bin/gatt_server.rs9
14 files changed, 508 insertions, 87 deletions
diff --git a/.github/ci/book.sh b/.github/ci/book.sh
index 285cdc8fa..2466f53f5 100755
--- a/.github/ci/book.sh
+++ b/.github/ci/book.sh
@@ -1,5 +1,7 @@
1#!/bin/bash 1#!/bin/bash
2## on push branch=main 2## on push branch=main
3## priority -9
4## dedup dequeue
3 5
4set -euxo pipefail 6set -euxo pipefail
5 7
diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh
index 90662af82..9162b37ae 100755
--- a/.github/ci/doc.sh
+++ b/.github/ci/doc.sh
@@ -1,5 +1,7 @@
1#!/bin/bash 1#!/bin/bash
2## on push branch=main 2## on push branch=main
3## priority -10
4## dedup dequeue
3 5
4set -euxo pipefail 6set -euxo pipefail
5 7
diff --git a/ci.sh b/ci.sh
index 94f70aae8..f4db1da03 100755
--- a/ci.sh
+++ b/ci.sh
@@ -40,6 +40,8 @@ cargo batch \
40 --- build --release --manifest-path embassy-executor/Cargo.toml --target armv7r-none-eabihf --features arch-cortex-ar,executor-thread \ 40 --- build --release --manifest-path embassy-executor/Cargo.toml --target armv7r-none-eabihf --features arch-cortex-ar,executor-thread \
41 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32 \ 41 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32 \
42 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,executor-thread \ 42 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,executor-thread \
43 --- build --release --manifest-path embassy-embedded-hal/Cargo.toml --target thumbv7em-none-eabi \
44 --- build --release --manifest-path embassy-embedded-hal/Cargo.toml --target thumbv7em-none-eabi --features time \
43 --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features defmt \ 45 --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features defmt \
44 --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features defmt,defmt-timestamp-uptime,mock-driver \ 46 --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features defmt,defmt-timestamp-uptime,mock-driver \
45 --- build --release --manifest-path embassy-time-queue-utils/Cargo.toml --target thumbv6m-none-eabi \ 47 --- build --release --manifest-path embassy-time-queue-utils/Cargo.toml --target thumbv6m-none-eabi \
diff --git a/docs/pages/layer_by_layer.adoc b/docs/pages/layer_by_layer.adoc
index 7dba11b5e..0692ee4fa 100644
--- a/docs/pages/layer_by_layer.adoc
+++ b/docs/pages/layer_by_layer.adoc
@@ -8,7 +8,7 @@ The application we'll write is a simple 'push button, blink led' application, wh
8 8
9== PAC version 9== PAC version
10 10
11The PAC is the lowest API for accessing peripherals and registers, if you don't count reading/writing directly to memory addresses. It provides distinct types to make accessing peripheral registers easier, but it does not prevent you from writing unsafe code. 11The PAC is the lowest API for accessing peripherals and registers, if you don't count reading/writing directly to memory addresses. It provides distinct types to make accessing peripheral registers easier, but it does little to prevent you from configuring or coordinating those registers incorrectly.
12 12
13Writing an application using the PAC directly is therefore not recommended, but if the functionality you want to use is not exposed in the upper layers, that's what you need to use. 13Writing an application using the PAC directly is therefore not recommended, but if the functionality you want to use is not exposed in the upper layers, that's what you need to use.
14 14
diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml
index aab6e0f1e..8277aa291 100644
--- a/embassy-embedded-hal/Cargo.toml
+++ b/embassy-embedded-hal/Cargo.toml
@@ -19,7 +19,6 @@ target = "x86_64-unknown-linux-gnu"
19 19
20[features] 20[features]
21time = ["dep:embassy-time"] 21time = ["dep:embassy-time"]
22default = ["time"]
23 22
24[dependencies] 23[dependencies]
25embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal" } 24embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal" }
diff --git a/embassy-embedded-hal/src/adapter/blocking_async.rs b/embassy-embedded-hal/src/adapter/blocking_async.rs
index bafc31583..3b6e0ec00 100644
--- a/embassy-embedded-hal/src/adapter/blocking_async.rs
+++ b/embassy-embedded-hal/src/adapter/blocking_async.rs
@@ -1,5 +1,3 @@
1use embedded_hal_02::blocking;
2
3/// Wrapper that implements async traits using blocking implementations. 1/// Wrapper that implements async traits using blocking implementations.
4/// 2///
5/// This allows driver writers to depend on the async traits while still supporting embedded-hal peripheral implementations. 3/// This allows driver writers to depend on the async traits while still supporting embedded-hal peripheral implementations.
@@ -24,7 +22,7 @@ impl<T> BlockingAsync<T> {
24impl<T, E> embedded_hal_1::i2c::ErrorType for BlockingAsync<T> 22impl<T, E> embedded_hal_1::i2c::ErrorType for BlockingAsync<T>
25where 23where
26 E: embedded_hal_1::i2c::Error + 'static, 24 E: embedded_hal_1::i2c::Error + 'static,
27 T: blocking::i2c::WriteRead<Error = E> + blocking::i2c::Read<Error = E> + blocking::i2c::Write<Error = E>, 25 T: embedded_hal_1::i2c::I2c<Error = E>,
28{ 26{
29 type Error = E; 27 type Error = E;
30} 28}
@@ -32,7 +30,7 @@ where
32impl<T, E> embedded_hal_async::i2c::I2c for BlockingAsync<T> 30impl<T, E> embedded_hal_async::i2c::I2c for BlockingAsync<T>
33where 31where
34 E: embedded_hal_1::i2c::Error + 'static, 32 E: embedded_hal_1::i2c::Error + 'static,
35 T: blocking::i2c::WriteRead<Error = E> + blocking::i2c::Read<Error = E> + blocking::i2c::Write<Error = E>, 33 T: embedded_hal_1::i2c::I2c<Error = E>,
36{ 34{
37 async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { 35 async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
38 self.wrapped.read(address, read) 36 self.wrapped.read(address, read)
@@ -51,9 +49,7 @@ where
51 address: u8, 49 address: u8,
52 operations: &mut [embedded_hal_1::i2c::Operation<'_>], 50 operations: &mut [embedded_hal_1::i2c::Operation<'_>],
53 ) -> Result<(), Self::Error> { 51 ) -> Result<(), Self::Error> {
54 let _ = address; 52 self.wrapped.transaction(address, operations)
55 let _ = operations;
56 todo!()
57 } 53 }
58} 54}
59 55
@@ -63,16 +59,16 @@ where
63 59
64impl<T, E> embedded_hal_async::spi::ErrorType for BlockingAsync<T> 60impl<T, E> embedded_hal_async::spi::ErrorType for BlockingAsync<T>
65where 61where
66 E: embedded_hal_1::spi::Error, 62 E: embedded_hal_async::spi::Error,
67 T: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>, 63 T: embedded_hal_1::spi::SpiBus<Error = E>,
68{ 64{
69 type Error = E; 65 type Error = E;
70} 66}
71 67
72impl<T, E> embedded_hal_async::spi::SpiBus<u8> for BlockingAsync<T> 68impl<T, E> embedded_hal_async::spi::SpiBus<u8> for BlockingAsync<T>
73where 69where
74 E: embedded_hal_1::spi::Error + 'static, 70 E: embedded_hal_async::spi::Error,
75 T: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>, 71 T: embedded_hal_1::spi::SpiBus<Error = E>,
76{ 72{
77 async fn flush(&mut self) -> Result<(), Self::Error> { 73 async fn flush(&mut self) -> Result<(), Self::Error> {
78 Ok(()) 74 Ok(())
@@ -84,21 +80,17 @@ where
84 } 80 }
85 81
86 async fn read(&mut self, data: &mut [u8]) -> Result<(), Self::Error> { 82 async fn read(&mut self, data: &mut [u8]) -> Result<(), Self::Error> {
87 self.wrapped.transfer(data)?; 83 self.wrapped.read(data)?;
88 Ok(()) 84 Ok(())
89 } 85 }
90 86
91 async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { 87 async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
92 // Ensure we write the expected bytes 88 self.wrapped.transfer(read, write)?;
93 for i in 0..core::cmp::min(read.len(), write.len()) {
94 read[i] = write[i].clone();
95 }
96 self.wrapped.transfer(read)?;
97 Ok(()) 89 Ok(())
98 } 90 }
99 91
100 async fn transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Self::Error> { 92 async fn transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Self::Error> {
101 self.wrapped.transfer(data)?; 93 self.wrapped.transfer_in_place(data)?;
102 Ok(()) 94 Ok(())
103 } 95 }
104} 96}
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index 9c450b6dc..eb497de1a 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -569,7 +569,7 @@ unsafe fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> {
569 unsafe { 569 unsafe {
570 core.MPU.ctrl.write(5); // enable mpu with background default map 570 core.MPU.ctrl.write(5); // enable mpu with background default map
571 core.MPU.rbar.write(stack_bottom as u32 & !0xff); // set address 571 core.MPU.rbar.write(stack_bottom as u32 & !0xff); // set address
572 core.MPU.rlar.write(1); // enable region 572 core.MPU.rlar.write(((stack_bottom as usize + 255) as u32) | 1);
573 } 573 }
574 Ok(()) 574 Ok(())
575} 575}
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 38254ee40..02e75733e 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -129,6 +129,7 @@ defmt = [
129 "embassy-net-driver/defmt", 129 "embassy-net-driver/defmt",
130 "embassy-time?/defmt", 130 "embassy-time?/defmt",
131 "embassy-usb-synopsys-otg/defmt", 131 "embassy-usb-synopsys-otg/defmt",
132 "stm32-metapac/defmt"
132] 133]
133 134
134exti = [] 135exti = []
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 30046849b..d8f1f96f2 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -403,6 +403,46 @@ impl<'d, T: Instance> Dac<'d, T, Async> {
403 Mode::NormalExternalBuffered, 403 Mode::NormalExternalBuffered,
404 ) 404 )
405 } 405 }
406 /// Create a new `Dac` instance with external output pins and unbuffered mode.
407 ///
408 /// This function consumes the underlying DAC peripheral and allows access to both channels.
409 /// The channels are configured for external output with the buffer disabled.
410 ///
411 /// The channels are enabled on creation and begin to drive their output pins.
412 /// Note that some methods, such as `set_trigger()` and `set_mode()`, will
413 /// disable the channel; you must re-enable them with `enable()`.
414 ///
415 /// By default, triggering is disabled, but it can be enabled using the `set_trigger()`
416 /// method on the underlying channels.
417 ///
418 /// # Arguments
419 ///
420 /// * `peri` - The DAC peripheral instance.
421 /// * `dma_ch1` - The DMA channel for DAC channel 1.
422 /// * `dma_ch2` - The DMA channel for DAC channel 2.
423 /// * `pin_ch1` - The GPIO pin for DAC channel 1 output.
424 /// * `pin_ch2` - The GPIO pin for DAC channel 2 output.
425 ///
426 /// # Returns
427 ///
428 /// A new `Dac` instance in unbuffered mode.
429 pub fn new_unbuffered(
430 peri: Peri<'d, T>,
431 dma_ch1: Peri<'d, impl Dma<T, Ch1>>,
432 dma_ch2: Peri<'d, impl Dma<T, Ch2>>,
433 pin_ch1: Peri<'d, impl DacPin<T, Ch1> + crate::gpio::Pin>,
434 pin_ch2: Peri<'d, impl DacPin<T, Ch2> + crate::gpio::Pin>,
435 ) -> Self {
436 pin_ch1.set_as_analog();
437 pin_ch2.set_as_analog();
438 Self::new_inner(
439 peri,
440 new_dma!(dma_ch1),
441 new_dma!(dma_ch2),
442 #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
443 Mode::NormalExternalUnbuffered,
444 )
445 }
406 446
407 /// Create a new `Dac` instance where the external output pins are not used, 447 /// Create a new `Dac` instance where the external output pins are not used,
408 /// so the DAC can only be used to generate internal signals but the GPIO 448 /// so the DAC can only be used to generate internal signals but the GPIO
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 35dc91c86..e24cce5c6 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -36,11 +36,46 @@ impl Address {
36 } 36 }
37} 37}
38 38
39enum ReceiveResult {
40 DataAvailable,
41 StopReceived,
42 NewStart,
43}
44
45fn debug_print_interrupts(isr: stm32_metapac::i2c::regs::Isr) {
46 if isr.tcr() {
47 trace!("interrupt: tcr");
48 }
49 if isr.tc() {
50 trace!("interrupt: tc");
51 }
52 if isr.addr() {
53 trace!("interrupt: addr");
54 }
55 if isr.stopf() {
56 trace!("interrupt: stopf");
57 }
58 if isr.nackf() {
59 trace!("interrupt: nackf");
60 }
61 if isr.berr() {
62 trace!("interrupt: berr");
63 }
64 if isr.arlo() {
65 trace!("interrupt: arlo");
66 }
67 if isr.ovr() {
68 trace!("interrupt: ovr");
69 }
70}
71
39pub(crate) unsafe fn on_interrupt<T: Instance>() { 72pub(crate) unsafe fn on_interrupt<T: Instance>() {
40 let regs = T::info().regs; 73 let regs = T::info().regs;
41 let isr = regs.isr().read(); 74 let isr = regs.isr().read();
42 75
43 if isr.tcr() || isr.tc() || isr.addr() || isr.stopf() || isr.nackf() || isr.berr() || isr.arlo() || isr.ovr() { 76 if isr.tcr() || isr.tc() || isr.addr() || isr.stopf() || isr.nackf() || isr.berr() || isr.arlo() || isr.ovr() {
77 debug_print_interrupts(isr);
78
44 T::state().waker.wake(); 79 T::state().waker.wake();
45 } 80 }
46 81
@@ -193,49 +228,132 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
193 228
194 fn flush_txdr(&self) { 229 fn flush_txdr(&self) {
195 if self.info.regs.isr().read().txis() { 230 if self.info.regs.isr().read().txis() {
196 self.info.regs.txdr().write(|w| w.set_txdata(0)); 231 trace!("Flush TXDATA with zeroes");
232 self.info.regs.txdr().modify(|w| w.set_txdata(0));
197 } 233 }
198 if !self.info.regs.isr().read().txe() { 234 if !self.info.regs.isr().read().txe() {
235 trace!("Flush TXDR");
199 self.info.regs.isr().modify(|w| w.set_txe(true)) 236 self.info.regs.isr().modify(|w| w.set_txe(true))
200 } 237 }
201 } 238 }
202 239
203 fn wait_txe(&self, timeout: Timeout) -> Result<(), Error> { 240 fn error_occurred(&self, isr: &i2c::regs::Isr, timeout: Timeout) -> Result<(), Error> {
241 if isr.nackf() {
242 trace!("NACK triggered.");
243 self.info.regs.icr().modify(|reg| reg.set_nackcf(true));
244 // NACK should be followed by STOP
245 if let Ok(()) = self.wait_stop(timeout) {
246 trace!("Got STOP after NACK, clearing flag.");
247 self.info.regs.icr().modify(|reg| reg.set_stopcf(true));
248 }
249 self.flush_txdr();
250 return Err(Error::Nack);
251 } else if isr.berr() {
252 trace!("BERR triggered.");
253 self.info.regs.icr().modify(|reg| reg.set_berrcf(true));
254 self.flush_txdr();
255 return Err(Error::Bus);
256 } else if isr.arlo() {
257 trace!("ARLO triggered.");
258 self.info.regs.icr().modify(|reg| reg.set_arlocf(true));
259 self.flush_txdr();
260 return Err(Error::Arbitration);
261 } else if isr.ovr() {
262 trace!("OVR triggered.");
263 self.info.regs.icr().modify(|reg| reg.set_ovrcf(true));
264 return Err(Error::Overrun);
265 }
266 return Ok(());
267 }
268
269 fn wait_txis(&self, timeout: Timeout) -> Result<(), Error> {
270 let mut first_loop = true;
271
204 loop { 272 loop {
205 let isr = self.info.regs.isr().read(); 273 let isr = self.info.regs.isr().read();
206 if isr.txe() { 274 self.error_occurred(&isr, timeout)?;
275 if isr.txis() {
276 trace!("TXIS");
207 return Ok(()); 277 return Ok(());
208 } else if isr.berr() {
209 self.info.regs.icr().write(|reg| reg.set_berrcf(true));
210 return Err(Error::Bus);
211 } else if isr.arlo() {
212 self.info.regs.icr().write(|reg| reg.set_arlocf(true));
213 return Err(Error::Arbitration);
214 } else if isr.nackf() {
215 self.info.regs.icr().write(|reg| reg.set_nackcf(true));
216 self.flush_txdr();
217 return Err(Error::Nack);
218 } 278 }
219 279
280 {
281 if first_loop {
282 trace!("Waiting for TXIS...");
283 first_loop = false;
284 }
285 }
220 timeout.check()?; 286 timeout.check()?;
221 } 287 }
222 } 288 }
223 289
224 fn wait_rxne(&self, timeout: Timeout) -> Result<(), Error> { 290 fn wait_stop_or_err(&self, timeout: Timeout) -> Result<(), Error> {
291 loop {
292 let isr = self.info.regs.isr().read();
293 self.error_occurred(&isr, timeout)?;
294 if isr.stopf() {
295 trace!("STOP triggered.");
296 self.info.regs.icr().modify(|reg| reg.set_stopcf(true));
297 return Ok(());
298 }
299 timeout.check()?;
300 }
301 }
302 fn wait_stop(&self, timeout: Timeout) -> Result<(), Error> {
225 loop { 303 loop {
226 let isr = self.info.regs.isr().read(); 304 let isr = self.info.regs.isr().read();
227 if isr.rxne() { 305 if isr.stopf() {
306 trace!("STOP triggered.");
307 self.info.regs.icr().modify(|reg| reg.set_stopcf(true));
228 return Ok(()); 308 return Ok(());
229 } else if isr.berr() { 309 }
230 self.info.regs.icr().write(|reg| reg.set_berrcf(true)); 310 timeout.check()?;
231 return Err(Error::Bus); 311 }
232 } else if isr.arlo() { 312 }
233 self.info.regs.icr().write(|reg| reg.set_arlocf(true)); 313
234 return Err(Error::Arbitration); 314 fn wait_af(&self, timeout: Timeout) -> Result<(), Error> {
235 } else if isr.nackf() { 315 loop {
236 self.info.regs.icr().write(|reg| reg.set_nackcf(true)); 316 let isr = self.info.regs.isr().read();
237 self.flush_txdr(); 317 if isr.nackf() {
238 return Err(Error::Nack); 318 trace!("AF triggered.");
319 self.info.regs.icr().modify(|reg| reg.set_nackcf(true));
320 return Ok(());
321 }
322 timeout.check()?;
323 }
324 }
325
326 fn wait_rxne(&self, timeout: Timeout) -> Result<ReceiveResult, Error> {
327 let mut first_loop = true;
328
329 loop {
330 let isr = self.info.regs.isr().read();
331 self.error_occurred(&isr, timeout)?;
332 if isr.stopf() {
333 trace!("STOP when waiting for RXNE.");
334 if self.info.regs.isr().read().rxne() {
335 trace!("Data received with STOP.");
336 return Ok(ReceiveResult::DataAvailable);
337 }
338 trace!("STOP triggered without data.");
339 return Ok(ReceiveResult::StopReceived);
340 } else if isr.rxne() {
341 trace!("RXNE.");
342 return Ok(ReceiveResult::DataAvailable);
343 } else if isr.addr() {
344 // Another addr event received, which means START was sent again
345 // which happens when accessing memory registers (common i2c interface design)
346 // e.g. master sends: START, write 1 byte (register index), START, read N bytes (until NACK)
347 // Possible to receive this flag at the same time as rxne, so check rxne first
348 trace!("START when waiting for RXNE. Ending receive loop.");
349 // Return without clearing ADDR so `listen` can catch it
350 return Ok(ReceiveResult::NewStart);
351 }
352 {
353 if first_loop {
354 trace!("Waiting for RXNE...");
355 first_loop = false;
356 }
239 } 357 }
240 358
241 timeout.check()?; 359 timeout.check()?;
@@ -245,20 +363,10 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
245 fn wait_tc(&self, timeout: Timeout) -> Result<(), Error> { 363 fn wait_tc(&self, timeout: Timeout) -> Result<(), Error> {
246 loop { 364 loop {
247 let isr = self.info.regs.isr().read(); 365 let isr = self.info.regs.isr().read();
366 self.error_occurred(&isr, timeout)?;
248 if isr.tc() { 367 if isr.tc() {
249 return Ok(()); 368 return Ok(());
250 } else if isr.berr() {
251 self.info.regs.icr().write(|reg| reg.set_berrcf(true));
252 return Err(Error::Bus);
253 } else if isr.arlo() {
254 self.info.regs.icr().write(|reg| reg.set_arlocf(true));
255 return Err(Error::Arbitration);
256 } else if isr.nackf() {
257 self.info.regs.icr().write(|reg| reg.set_nackcf(true));
258 self.flush_txdr();
259 return Err(Error::Nack);
260 } 369 }
261
262 timeout.check()?; 370 timeout.check()?;
263 } 371 }
264 } 372 }
@@ -344,7 +452,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
344 // Wait until we are allowed to send data 452 // Wait until we are allowed to send data
345 // (START has been ACKed or last byte when 453 // (START has been ACKed or last byte when
346 // through) 454 // through)
347 if let Err(err) = self.wait_txe(timeout) { 455 if let Err(err) = self.wait_txis(timeout) {
348 if send_stop { 456 if send_stop {
349 self.master_stop(); 457 self.master_stop();
350 } 458 }
@@ -459,7 +567,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
459 // Wait until we are allowed to send data 567 // Wait until we are allowed to send data
460 // (START has been ACKed or last byte when 568 // (START has been ACKed or last byte when
461 // through) 569 // through)
462 if let Err(err) = self.wait_txe(timeout) { 570 if let Err(err) = self.wait_txis(timeout) {
463 self.master_stop(); 571 self.master_stop();
464 return Err(err); 572 return Err(err);
465 } 573 }
@@ -884,10 +992,11 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
884 // clear the address flag, will stop the clock stretching. 992 // clear the address flag, will stop the clock stretching.
885 // this should only be done after the dma transfer has been set up. 993 // this should only be done after the dma transfer has been set up.
886 info.regs.icr().modify(|reg| reg.set_addrcf(true)); 994 info.regs.icr().modify(|reg| reg.set_addrcf(true));
995 trace!("ADDRCF cleared (ADDR interrupt enabled, clock stretching ended)");
887 } 996 }
888 997
889 // A blocking read operation 998 // A blocking read operation
890 fn slave_read_internal(&self, read: &mut [u8], timeout: Timeout) -> Result<(), Error> { 999 fn slave_read_internal(&self, read: &mut [u8], timeout: Timeout) -> Result<usize, Error> {
891 let completed_chunks = read.len() / 255; 1000 let completed_chunks = read.len() / 255;
892 let total_chunks = if completed_chunks * 255 == read.len() { 1001 let total_chunks = if completed_chunks * 255 == read.len() {
893 completed_chunks 1002 completed_chunks
@@ -895,20 +1004,46 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
895 completed_chunks + 1 1004 completed_chunks + 1
896 }; 1005 };
897 let last_chunk_idx = total_chunks.saturating_sub(1); 1006 let last_chunk_idx = total_chunks.saturating_sub(1);
1007 let total_len = read.len();
1008 let mut remaining_len = total_len;
1009
898 for (number, chunk) in read.chunks_mut(255).enumerate() { 1010 for (number, chunk) in read.chunks_mut(255).enumerate() {
899 if number != 0 { 1011 trace!(
1012 "--- Slave RX transmission start - chunk: {}, expected (max) size: {}",
1013 number,
1014 chunk.len()
1015 );
1016 if number == 0 {
1017 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx);
1018 } else {
900 Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; 1019 Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?;
901 } 1020 }
902 1021
1022 let mut index = 0;
1023
903 for byte in chunk { 1024 for byte in chunk {
904 // Wait until we have received something 1025 // Wait until we have received something
905 self.wait_rxne(timeout)?; 1026 match self.wait_rxne(timeout) {
906 1027 Ok(ReceiveResult::StopReceived) | Ok(ReceiveResult::NewStart) => {
907 *byte = self.info.regs.rxdr().read().rxdata(); 1028 trace!("--- Slave RX transmission end (early)");
1029 return Ok(total_len - remaining_len); // Return N bytes read
1030 }
1031 Ok(ReceiveResult::DataAvailable) => {
1032 *byte = self.info.regs.rxdr().read().rxdata();
1033 remaining_len = remaining_len.saturating_sub(1);
1034 {
1035 trace!("Slave RX data {}: {:#04x}", index, byte);
1036 index = index + 1;
1037 }
1038 }
1039 Err(e) => return Err(e),
1040 };
908 } 1041 }
909 } 1042 }
1043 self.wait_stop_or_err(timeout)?;
910 1044
911 Ok(()) 1045 trace!("--- Slave RX transmission end");
1046 Ok(total_len - remaining_len) // Return N bytes read
912 } 1047 }
913 1048
914 // A blocking write operation 1049 // A blocking write operation
@@ -922,19 +1057,36 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
922 let last_chunk_idx = total_chunks.saturating_sub(1); 1057 let last_chunk_idx = total_chunks.saturating_sub(1);
923 1058
924 for (number, chunk) in write.chunks(255).enumerate() { 1059 for (number, chunk) in write.chunks(255).enumerate() {
925 if number != 0 { 1060 trace!(
1061 "--- Slave TX transmission start - chunk: {}, size: {}",
1062 number,
1063 chunk.len()
1064 );
1065 if number == 0 {
1066 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx);
1067 } else {
926 Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; 1068 Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?;
927 } 1069 }
928 1070
1071 let mut index = 0;
1072
929 for byte in chunk { 1073 for byte in chunk {
930 // Wait until we are allowed to send data 1074 // Wait until we are allowed to send data
931 // (START has been ACKed or last byte when 1075 // (START has been ACKed or last byte when through)
932 // through) 1076 self.wait_txis(timeout)?;
933 self.wait_txe(timeout)?;
934 1077
1078 {
1079 trace!("Slave TX data {}: {:#04x}", index, byte);
1080 index = index + 1;
1081 }
935 self.info.regs.txdr().write(|w| w.set_txdata(*byte)); 1082 self.info.regs.txdr().write(|w| w.set_txdata(*byte));
936 } 1083 }
937 } 1084 }
1085 self.wait_af(timeout)?;
1086 self.flush_txdr();
1087 self.wait_stop_or_err(timeout)?;
1088
1089 trace!("--- Slave TX transmission end");
938 Ok(()) 1090 Ok(())
939 } 1091 }
940 1092
@@ -945,6 +1097,7 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
945 let state = self.state; 1097 let state = self.state;
946 self.info.regs.cr1().modify(|reg| { 1098 self.info.regs.cr1().modify(|reg| {
947 reg.set_addrie(true); 1099 reg.set_addrie(true);
1100 trace!("Enable ADDRIE");
948 }); 1101 });
949 1102
950 poll_fn(|cx| { 1103 poll_fn(|cx| {
@@ -953,17 +1106,24 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
953 if !isr.addr() { 1106 if !isr.addr() {
954 Poll::Pending 1107 Poll::Pending
955 } else { 1108 } else {
1109 trace!("ADDR triggered (address match)");
956 // we do not clear the address flag here as it will be cleared by the dma read/write 1110 // we do not clear the address flag here as it will be cleared by the dma read/write
957 // if we clear it here the clock stretching will stop and the master will read in data before the slave is ready to send it 1111 // if we clear it here the clock stretching will stop and the master will read in data before the slave is ready to send it
958 match isr.dir() { 1112 match isr.dir() {
959 i2c::vals::Dir::WRITE => Poll::Ready(Ok(SlaveCommand { 1113 i2c::vals::Dir::WRITE => {
960 kind: SlaveCommandKind::Write, 1114 trace!("DIR: write");
961 address: self.determine_matched_address()?, 1115 Poll::Ready(Ok(SlaveCommand {
962 })), 1116 kind: SlaveCommandKind::Write,
963 i2c::vals::Dir::READ => Poll::Ready(Ok(SlaveCommand { 1117 address: self.determine_matched_address()?,
964 kind: SlaveCommandKind::Read, 1118 }))
965 address: self.determine_matched_address()?, 1119 }
966 })), 1120 i2c::vals::Dir::READ => {
1121 trace!("DIR: read");
1122 Poll::Ready(Ok(SlaveCommand {
1123 kind: SlaveCommandKind::Read,
1124 address: self.determine_matched_address()?,
1125 }))
1126 }
967 } 1127 }
968 } 1128 }
969 }) 1129 })
@@ -971,7 +1131,9 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
971 } 1131 }
972 1132
973 /// Respond to a write command. 1133 /// Respond to a write command.
974 pub fn blocking_respond_to_write(&self, read: &mut [u8]) -> Result<(), Error> { 1134 ///
1135 /// Returns total number of bytes received.
1136 pub fn blocking_respond_to_write(&self, read: &mut [u8]) -> Result<usize, Error> {
975 let timeout = self.timeout(); 1137 let timeout = self.timeout();
976 self.slave_read_internal(read, timeout) 1138 self.slave_read_internal(read, timeout)
977 } 1139 }
@@ -1025,7 +1187,7 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1025 w.set_rxdmaen(false); 1187 w.set_rxdmaen(false);
1026 w.set_stopie(false); 1188 w.set_stopie(false);
1027 w.set_tcie(false); 1189 w.set_tcie(false);
1028 }) 1190 });
1029 }); 1191 });
1030 1192
1031 let total_received = poll_fn(|cx| { 1193 let total_received = poll_fn(|cx| {
diff --git a/embassy-stm32/src/lptim/timer/mod.rs b/embassy-stm32/src/lptim/timer/mod.rs
index a629be62b..648da5940 100644
--- a/embassy-stm32/src/lptim/timer/mod.rs
+++ b/embassy-stm32/src/lptim/timer/mod.rs
@@ -115,6 +115,31 @@ impl<'d, T: Instance> Timer<'d, T> {
115 .ccmr(0) 115 .ccmr(0)
116 .modify(|w| w.set_ccsel(channel.index(), direction.into())); 116 .modify(|w| w.set_ccsel(channel.index(), direction.into()));
117 } 117 }
118
119 /// Enable the timer interrupt.
120 pub fn enable_interrupt(&self) {
121 T::regs().dier().modify(|w| w.set_arrmie(true));
122 }
123
124 /// Disable the timer interrupt.
125 pub fn disable_interrupt(&self) {
126 T::regs().dier().modify(|w| w.set_arrmie(false));
127 }
128
129 /// Check if the timer interrupt is enabled.
130 pub fn is_interrupt_enabled(&self) -> bool {
131 T::regs().dier().read().arrmie()
132 }
133
134 /// Check if the timer interrupt is pending.
135 pub fn is_interrupt_pending(&self) -> bool {
136 T::regs().isr().read().arrm()
137 }
138
139 /// Clear the timer interrupt.
140 pub fn clear_interrupt(&self) {
141 T::regs().icr().write(|w| w.set_arrmcf(true));
142 }
118} 143}
119 144
120#[cfg(not(any(lptim_v2a, lptim_v2b)))] 145#[cfg(not(any(lptim_v2a, lptim_v2b)))]
@@ -128,4 +153,29 @@ impl<'d, T: Instance> Timer<'d, T> {
128 pub fn get_compare_value(&self) -> u16 { 153 pub fn get_compare_value(&self) -> u16 {
129 T::regs().cmp().read().cmp() 154 T::regs().cmp().read().cmp()
130 } 155 }
156
157 /// Enable the timer interrupt.
158 pub fn enable_interrupt(&self) {
159 T::regs().ier().modify(|w| w.set_arrmie(true));
160 }
161
162 /// Disable the timer interrupt.
163 pub fn disable_interrupt(&self) {
164 T::regs().ier().modify(|w| w.set_arrmie(false));
165 }
166
167 /// Check if the timer interrupt is enabled.
168 pub fn is_interrupt_enabled(&self) -> bool {
169 T::regs().ier().read().arrmie()
170 }
171
172 /// Check if the timer interrupt is pending.
173 pub fn is_interrupt_pending(&self) -> bool {
174 T::regs().isr().read().arrm()
175 }
176
177 /// Clear the timer interrupt.
178 pub fn clear_interrupt(&self) {
179 T::regs().icr().write(|w| w.set_arrmcf(true));
180 }
131} 181}
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index 97eb2eb6d..06895a99a 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -5,7 +5,7 @@ pub use crate::pac::rcc::vals::{
5 Hpre as AHBPrescaler, Msirange, Msirange as MSIRange, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, 5 Hpre as AHBPrescaler, Msirange, Msirange as MSIRange, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul,
6 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, 6 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk,
7}; 7};
8use crate::pac::rcc::vals::{Hseext, Msirgsel, Pllmboost, Pllrge}; 8use crate::pac::rcc::vals::{Hseext, Msipllfast, Msipllsel, Msirgsel, Pllmboost, Pllrge};
9#[cfg(all(peri_usb_otg_hs))] 9#[cfg(all(peri_usb_otg_hs))]
10pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG}; 10pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG};
11use crate::pac::{FLASH, PWR, RCC}; 11use crate::pac::{FLASH, PWR, RCC};
@@ -64,6 +64,46 @@ pub struct Pll {
64 pub divr: Option<PllDiv>, 64 pub divr: Option<PllDiv>,
65} 65}
66 66
67#[derive(Clone, Copy, PartialEq)]
68pub enum MsiAutoCalibration {
69 /// MSI auto-calibration is disabled
70 Disabled,
71 /// MSIS is given priority for auto-calibration
72 MSIS,
73 /// MSIK is given priority for auto-calibration
74 MSIK,
75 /// MSIS with fast mode (always on)
76 MsisFast,
77 /// MSIK with fast mode (always on)
78 MsikFast,
79}
80
81impl MsiAutoCalibration {
82 const fn default() -> Self {
83 MsiAutoCalibration::Disabled
84 }
85
86 fn base_mode(&self) -> Self {
87 match self {
88 MsiAutoCalibration::Disabled => MsiAutoCalibration::Disabled,
89 MsiAutoCalibration::MSIS => MsiAutoCalibration::MSIS,
90 MsiAutoCalibration::MSIK => MsiAutoCalibration::MSIK,
91 MsiAutoCalibration::MsisFast => MsiAutoCalibration::MSIS,
92 MsiAutoCalibration::MsikFast => MsiAutoCalibration::MSIK,
93 }
94 }
95
96 fn is_fast(&self) -> bool {
97 matches!(self, MsiAutoCalibration::MsisFast | MsiAutoCalibration::MsikFast)
98 }
99}
100
101impl Default for MsiAutoCalibration {
102 fn default() -> Self {
103 Self::default()
104 }
105}
106
67#[derive(Clone, Copy)] 107#[derive(Clone, Copy)]
68pub struct Config { 108pub struct Config {
69 // base clock sources 109 // base clock sources
@@ -95,6 +135,7 @@ pub struct Config {
95 135
96 /// Per-peripheral kernel clock selection muxes 136 /// Per-peripheral kernel clock selection muxes
97 pub mux: super::mux::ClockMux, 137 pub mux: super::mux::ClockMux,
138 pub auto_calibration: MsiAutoCalibration,
98} 139}
99 140
100impl Config { 141impl Config {
@@ -116,6 +157,7 @@ impl Config {
116 voltage_range: VoltageScale::RANGE1, 157 voltage_range: VoltageScale::RANGE1,
117 ls: crate::rcc::LsConfig::new(), 158 ls: crate::rcc::LsConfig::new(),
118 mux: super::mux::ClockMux::default(), 159 mux: super::mux::ClockMux::default(),
160 auto_calibration: MsiAutoCalibration::default(),
119 } 161 }
120 } 162 }
121} 163}
@@ -131,7 +173,42 @@ pub(crate) unsafe fn init(config: Config) {
131 PWR.vosr().modify(|w| w.set_vos(config.voltage_range)); 173 PWR.vosr().modify(|w| w.set_vos(config.voltage_range));
132 while !PWR.vosr().read().vosrdy() {} 174 while !PWR.vosr().read().vosrdy() {}
133 175
134 let msis = config.msis.map(|range| { 176 let lse_calibration_freq = if config.auto_calibration != MsiAutoCalibration::Disabled {
177 // LSE must be configured and peripherals clocked for MSI auto-calibration
178 let lse_config = config
179 .ls
180 .lse
181 .clone()
182 .expect("LSE must be configured for MSI auto-calibration");
183 assert!(lse_config.peripherals_clocked);
184
185 // Expect less than +/- 5% deviation for LSE frequency
186 if (31_100..=34_400).contains(&lse_config.frequency.0) {
187 // Check that the calibration is applied to an active clock
188 match (
189 config.auto_calibration.base_mode(),
190 config.msis.is_some(),
191 config.msik.is_some(),
192 ) {
193 (MsiAutoCalibration::MSIS, true, _) => {
194 // MSIS is active and using LSE for auto-calibration
195 Some(lse_config.frequency)
196 }
197 (MsiAutoCalibration::MSIK, _, true) => {
198 // MSIK is active and using LSE for auto-calibration
199 Some(lse_config.frequency)
200 }
201 // improper configuration
202 _ => panic!("MSIx auto-calibration is enabled for a source that has not been configured."),
203 }
204 } else {
205 panic!("LSE frequency more than 5% off from 32.768 kHz, cannot use for MSI auto-calibration");
206 }
207 } else {
208 None
209 };
210
211 let mut msis = config.msis.map(|range| {
135 // Check MSI output per RM0456 § 11.4.10 212 // Check MSI output per RM0456 § 11.4.10
136 match config.voltage_range { 213 match config.voltage_range {
137 VoltageScale::RANGE4 => { 214 VoltageScale::RANGE4 => {
@@ -156,11 +233,21 @@ pub(crate) unsafe fn init(config: Config) {
156 w.set_msipllen(false); 233 w.set_msipllen(false);
157 w.set_msison(true); 234 w.set_msison(true);
158 }); 235 });
236 let msis = if let (Some(freq), MsiAutoCalibration::MSIS) =
237 (lse_calibration_freq, config.auto_calibration.base_mode())
238 {
239 // Enable the MSIS auto-calibration feature
240 RCC.cr().modify(|w| w.set_msipllsel(Msipllsel::MSIS));
241 RCC.cr().modify(|w| w.set_msipllen(true));
242 calculate_calibrated_msi_frequency(range, freq)
243 } else {
244 msirange_to_hertz(range)
245 };
159 while !RCC.cr().read().msisrdy() {} 246 while !RCC.cr().read().msisrdy() {}
160 msirange_to_hertz(range) 247 msis
161 }); 248 });
162 249
163 let msik = config.msik.map(|range| { 250 let mut msik = config.msik.map(|range| {
164 // Check MSI output per RM0456 § 11.4.10 251 // Check MSI output per RM0456 § 11.4.10
165 match config.voltage_range { 252 match config.voltage_range {
166 VoltageScale::RANGE4 => { 253 VoltageScale::RANGE4 => {
@@ -184,10 +271,44 @@ pub(crate) unsafe fn init(config: Config) {
184 RCC.cr().modify(|w| { 271 RCC.cr().modify(|w| {
185 w.set_msikon(true); 272 w.set_msikon(true);
186 }); 273 });
274 let msik = if let (Some(freq), MsiAutoCalibration::MSIK) =
275 (lse_calibration_freq, config.auto_calibration.base_mode())
276 {
277 // Enable the MSIK auto-calibration feature
278 RCC.cr().modify(|w| w.set_msipllsel(Msipllsel::MSIK));
279 RCC.cr().modify(|w| w.set_msipllen(true));
280 calculate_calibrated_msi_frequency(range, freq)
281 } else {
282 msirange_to_hertz(range)
283 };
187 while !RCC.cr().read().msikrdy() {} 284 while !RCC.cr().read().msikrdy() {}
188 msirange_to_hertz(range) 285 msik
189 }); 286 });
190 287
288 if let Some(lse_freq) = lse_calibration_freq {
289 // If both MSIS and MSIK are enabled, we need to check if they are using the same internal source.
290 if let (Some(msis_range), Some(msik_range)) = (config.msis, config.msik) {
291 if (msis_range as u8 >> 2) == (msik_range as u8 >> 2) {
292 // Clock source is shared, both will be auto calibrated, recalculate other frequency
293 match config.auto_calibration.base_mode() {
294 MsiAutoCalibration::MSIS => {
295 msik = Some(calculate_calibrated_msi_frequency(msik_range, lse_freq));
296 }
297 MsiAutoCalibration::MSIK => {
298 msis = Some(calculate_calibrated_msi_frequency(msis_range, lse_freq));
299 }
300 _ => {}
301 }
302 }
303 }
304 // Check if Fast mode should be used
305 if config.auto_calibration.is_fast() {
306 RCC.cr().modify(|w| {
307 w.set_msipllfast(Msipllfast::FAST);
308 });
309 }
310 }
311
191 let hsi = config.hsi.then(|| { 312 let hsi = config.hsi.then(|| {
192 RCC.cr().modify(|w| w.set_hsion(true)); 313 RCC.cr().modify(|w| w.set_hsion(true));
193 while !RCC.cr().read().hsirdy() {} 314 while !RCC.cr().read().hsirdy() {}
@@ -514,3 +635,37 @@ fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput, voltag
514 635
515 PllOutput { p, q, r } 636 PllOutput { p, q, r }
516} 637}
638
639/// Fraction structure for MSI auto-calibration
640/// Represents the multiplier as numerator/denominator that LSE frequency is multiplied by
641#[derive(Debug, Clone, Copy)]
642struct MsiFraction {
643 numerator: u32,
644 denominator: u32,
645}
646
647impl MsiFraction {
648 const fn new(numerator: u32, denominator: u32) -> Self {
649 Self { numerator, denominator }
650 }
651
652 /// Calculate the calibrated frequency given an LSE frequency
653 fn calculate_frequency(&self, lse_freq: Hertz) -> Hertz {
654 Hertz(lse_freq.0 * self.numerator / self.denominator)
655 }
656}
657
658fn get_msi_calibration_fraction(range: Msirange) -> MsiFraction {
659 // Exploiting the MSIx internals to make calculations compact
660 let denominator = (range as u32 & 0x03) + 1;
661 // Base multipliers are deduced from Table 82: MSI oscillator characteristics in data sheet
662 let numerator = [1465, 122, 94, 12][range as usize >> 2];
663
664 MsiFraction::new(numerator, denominator)
665}
666
667/// Calculate the calibrated MSI frequency for a given range and LSE frequency
668fn calculate_calibrated_msi_frequency(range: Msirange, lse_freq: Hertz) -> Hertz {
669 let fraction = get_msi_calibration_fraction(range);
670 fraction.calculate_frequency(lse_freq)
671}
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index a450705a2..b00cc18ad 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -77,6 +77,7 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
77 this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1); 77 this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1);
78 this.inner.set_output_compare_preload(channel, true); 78 this.inner.set_output_compare_preload(channel, true);
79 }); 79 });
80 this.inner.set_autoreload_preload(true);
80 81
81 this 82 this
82 } 83 }
@@ -110,7 +111,11 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
110 /// 111 ///
111 /// This value depends on the configured frequency and the timer's clock rate from RCC. 112 /// This value depends on the configured frequency and the timer's clock rate from RCC.
112 pub fn get_max_duty(&self) -> u16 { 113 pub fn get_max_duty(&self) -> u16 {
113 self.inner.get_max_compare_value() as u16 + 1 114 if self.inner.get_counting_mode().is_center_aligned() {
115 self.inner.get_max_compare_value() as u16
116 } else {
117 self.inner.get_max_compare_value() as u16 + 1
118 }
114 } 119 }
115 120
116 /// Set the duty for a given channel. 121 /// Set the duty for a given channel.
@@ -160,7 +165,11 @@ impl<'d, T: AdvancedInstance4Channel> embedded_hal_02::Pwm for ComplementaryPwm<
160 } 165 }
161 166
162 fn get_max_duty(&self) -> Self::Duty { 167 fn get_max_duty(&self) -> Self::Duty {
163 self.inner.get_max_compare_value() as u16 + 1 168 if self.inner.get_counting_mode().is_center_aligned() {
169 self.inner.get_max_compare_value() as u16
170 } else {
171 self.inner.get_max_compare_value() as u16 + 1
172 }
164 } 173 }
165 174
166 fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { 175 fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
diff --git a/examples/stm32wb/src/bin/gatt_server.rs b/examples/stm32wb/src/bin/gatt_server.rs
index 041dc0cf5..9864fa026 100644
--- a/examples/stm32wb/src/bin/gatt_server.rs
+++ b/examples/stm32wb/src/bin/gatt_server.rs
@@ -27,6 +27,7 @@ use embassy_stm32_wpan::hci::vendor::event::{self, AttributeHandle, VendorEvent}
27use embassy_stm32_wpan::hci::{BdAddr, Event}; 27use embassy_stm32_wpan::hci::{BdAddr, Event};
28use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp; 28use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp;
29use embassy_stm32_wpan::sub::ble::Ble; 29use embassy_stm32_wpan::sub::ble::Ble;
30use embassy_stm32_wpan::sub::mm;
30use embassy_stm32_wpan::TlMbox; 31use embassy_stm32_wpan::TlMbox;
31use {defmt_rtt as _, panic_probe as _}; 32use {defmt_rtt as _, panic_probe as _};
32 33
@@ -38,7 +39,7 @@ bind_interrupts!(struct Irqs{
38const BLE_GAP_DEVICE_NAME_LENGTH: u8 = 7; 39const BLE_GAP_DEVICE_NAME_LENGTH: u8 = 7;
39 40
40#[embassy_executor::main] 41#[embassy_executor::main]
41async fn main(_spawner: Spawner) { 42async fn main(spawner: Spawner) {
42 /* 43 /*
43 How to make this work: 44 How to make this work:
44 45
@@ -70,6 +71,7 @@ async fn main(_spawner: Spawner) {
70 let config = Config::default(); 71 let config = Config::default();
71 let mut mbox = TlMbox::init(p.IPCC, Irqs, config); 72 let mut mbox = TlMbox::init(p.IPCC, Irqs, config);
72 73
74 spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
73 let sys_event = mbox.sys_subsystem.read().await; 75 let sys_event = mbox.sys_subsystem.read().await;
74 info!("sys event: {}", sys_event.payload()); 76 info!("sys event: {}", sys_event.payload());
75 77
@@ -221,6 +223,11 @@ async fn main(_spawner: Spawner) {
221 } 223 }
222} 224}
223 225
226#[embassy_executor::task]
227async fn run_mm_queue(memory_manager: mm::MemoryManager) {
228 memory_manager.run_queue().await;
229}
230
224fn get_bd_addr() -> BdAddr { 231fn get_bd_addr() -> BdAddr {
225 let mut bytes = [0u8; 6]; 232 let mut bytes = [0u8; 6];
226 233