diff options
| author | Rick Rogers <[email protected]> | 2025-07-25 11:34:21 -0400 |
|---|---|---|
| committer | Rick Rogers <[email protected]> | 2025-07-25 11:34:21 -0400 |
| commit | 33fc82a455df058c5bdef23b68304a3dcb33f069 (patch) | |
| tree | 63f876b833e5ced8863b0b4825e8ab822190dd13 /embassy-stm32 | |
| parent | 24b2794931e73325ad969d83453d0cf872ac4775 (diff) | |
| parent | 996974e313fa5ec2c7c2d9dd0998fab244c0a180 (diff) | |
Merge branch 'main' into h7rs-xspi-fixes
Diffstat (limited to 'embassy-stm32')
| -rw-r--r-- | embassy-stm32/Cargo.toml | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/dac/mod.rs | 40 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/v2.rs | 278 | ||||
| -rw-r--r-- | embassy-stm32/src/lptim/timer/mod.rs | 50 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/u5.rs | 165 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/complementary_pwm.rs | 13 |
6 files changed, 482 insertions, 65 deletions
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 | ||
| 134 | exti = [] | 135 | exti = [] |
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 | ||
| 39 | enum ReceiveResult { | ||
| 40 | DataAvailable, | ||
| 41 | StopReceived, | ||
| 42 | NewStart, | ||
| 43 | } | ||
| 44 | |||
| 45 | fn 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 | |||
| 39 | pub(crate) unsafe fn on_interrupt<T: Instance>() { | 72 | pub(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 | }; |
| 8 | use crate::pac::rcc::vals::{Hseext, Msirgsel, Pllmboost, Pllrge}; | 8 | use crate::pac::rcc::vals::{Hseext, Msipllfast, Msipllsel, Msirgsel, Pllmboost, Pllrge}; |
| 9 | #[cfg(all(peri_usb_otg_hs))] | 9 | #[cfg(all(peri_usb_otg_hs))] |
| 10 | pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG}; | 10 | pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG}; |
| 11 | use crate::pac::{FLASH, PWR, RCC}; | 11 | use 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)] | ||
| 68 | pub 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 | |||
| 81 | impl 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 | |||
| 101 | impl Default for MsiAutoCalibration { | ||
| 102 | fn default() -> Self { | ||
| 103 | Self::default() | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 67 | #[derive(Clone, Copy)] | 107 | #[derive(Clone, Copy)] |
| 68 | pub struct Config { | 108 | pub 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 | ||
| 100 | impl Config { | 141 | impl 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)] | ||
| 642 | struct MsiFraction { | ||
| 643 | numerator: u32, | ||
| 644 | denominator: u32, | ||
| 645 | } | ||
| 646 | |||
| 647 | impl 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 | |||
| 658 | fn 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 | ||
| 668 | fn 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) { |
