diff options
| author | Gordon Tyler <[email protected]> | 2025-10-28 09:08:53 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-10-28 09:08:53 -0400 |
| commit | f1053b4dabb9035831787cbc5f2626ee04d39337 (patch) | |
| tree | f8a92345bb2cf3c88a1fa6570d2cd0f4bf4ee795 | |
| parent | 3923f881c63a483c1593cc345079581ffcce5ff1 (diff) | |
| parent | 41ff72bbce343c1e3c5efa2939e08a73b9122552 (diff) | |
Merge branch 'embassy-rs:main' into gpio-nointr
| -rw-r--r-- | embassy-nrf/CHANGELOG.md | 4 | ||||
| -rw-r--r-- | embassy-nrf/src/pwm.rs | 324 | ||||
| -rw-r--r-- | embassy-rp/CHANGELOG.md | 2 | ||||
| -rw-r--r-- | embassy-rp/src/block.rs | 4 | ||||
| -rw-r--r-- | embassy-rp/src/clocks.rs | 2 | ||||
| -rw-r--r-- | embassy-rp/src/i2c_slave.rs | 4 | ||||
| -rw-r--r-- | embassy-rp/src/multicore.rs | 2 | ||||
| -rw-r--r-- | embassy-rp/src/pio/mod.rs | 2 | ||||
| -rw-r--r-- | embassy-rp/src/pio_programs/i2s.rs | 18 | ||||
| -rw-r--r-- | embassy-rp/src/pio_programs/pwm.rs | 2 | ||||
| -rw-r--r-- | embassy-rp/src/pio_programs/spi.rs | 4 | ||||
| -rw-r--r-- | embassy-rp/src/pio_programs/uart.rs | 2 | ||||
| -rw-r--r-- | embassy-rp/src/rom_data/rp2040.rs | 2 | ||||
| -rw-r--r-- | embassy-rp/src/rtc/mod.rs | 2 | ||||
| -rw-r--r-- | embassy-rp/src/spi.rs | 2 | ||||
| -rw-r--r-- | embassy-rp/src/uart/mod.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/CHANGELOG.md | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/low_level.rs | 69 | ||||
| -rw-r--r-- | examples/nrf52840/src/bin/i2s_monitor.rs | 9 | ||||
| -rw-r--r-- | examples/nrf52840/src/bin/pwm.rs | 14 | ||||
| -rw-r--r-- | examples/nrf52840/src/bin/pwm_servo.rs | 14 |
21 files changed, 346 insertions, 139 deletions
diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index 0280e2730..89adaf2da 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md | |||
| @@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 13 | - changed: do not panic on BufferedUarte overrun | 13 | - changed: do not panic on BufferedUarte overrun |
| 14 | - added: allow direct access to the input pin of `gpiote::InputChannel` | 14 | - added: allow direct access to the input pin of `gpiote::InputChannel` |
| 15 | - bugfix: use DETECTMODE_SEC in GPIOTE in secure mode | 15 | - bugfix: use DETECTMODE_SEC in GPIOTE in secure mode |
| 16 | - added: allow configuring the idle state of GPIO pins connected to PWM channels | ||
| 17 | - changed: allow configuring the PWM peripheral in the constructor of `SimplePwm` | ||
| 18 | - changed: support setting duty cycles with inverted polarity in `SimplePwm` | ||
| 19 | - added: support setting the duty cycles of all channels at once in `SimplePwm` | ||
| 16 | 20 | ||
| 17 | ## 0.8.0 - 2025-09-30 | 21 | ## 0.8.0 - 2025-09-30 |
| 18 | 22 | ||
diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index e038f44b8..00b3278c7 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs | |||
| @@ -6,7 +6,7 @@ use core::sync::atomic::{Ordering, compiler_fence}; | |||
| 6 | 6 | ||
| 7 | use embassy_hal_internal::{Peri, PeripheralType}; | 7 | use embassy_hal_internal::{Peri, PeripheralType}; |
| 8 | 8 | ||
| 9 | use crate::gpio::{AnyPin, DISCONNECTED, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _, convert_drive}; | 9 | use crate::gpio::{AnyPin, DISCONNECTED, Level, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _, convert_drive}; |
| 10 | use crate::pac::gpio::vals as gpiovals; | 10 | use crate::pac::gpio::vals as gpiovals; |
| 11 | use crate::pac::pwm::vals; | 11 | use crate::pac::pwm::vals; |
| 12 | use crate::ppi::{Event, Task}; | 12 | use crate::ppi::{Event, Task}; |
| @@ -17,7 +17,7 @@ use crate::{interrupt, pac}; | |||
| 17 | /// to simply set a duty cycle across up to four channels. | 17 | /// to simply set a duty cycle across up to four channels. |
| 18 | pub struct SimplePwm<'d> { | 18 | pub struct SimplePwm<'d> { |
| 19 | r: pac::pwm::Pwm, | 19 | r: pac::pwm::Pwm, |
| 20 | duty: [u16; 4], | 20 | duty: [DutyCycle; 4], |
| 21 | ch0: Option<Peri<'d, AnyPin>>, | 21 | ch0: Option<Peri<'d, AnyPin>>, |
| 22 | ch1: Option<Peri<'d, AnyPin>>, | 22 | ch1: Option<Peri<'d, AnyPin>>, |
| 23 | ch2: Option<Peri<'d, AnyPin>>, | 23 | ch2: Option<Peri<'d, AnyPin>>, |
| @@ -53,13 +53,11 @@ pub const PWM_CLK_HZ: u32 = 16_000_000; | |||
| 53 | 53 | ||
| 54 | impl<'d> SequencePwm<'d> { | 54 | impl<'d> SequencePwm<'d> { |
| 55 | /// Create a new 1-channel PWM | 55 | /// Create a new 1-channel PWM |
| 56 | #[allow(unused_unsafe)] | ||
| 57 | pub fn new_1ch<T: Instance>(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, config: Config) -> Result<Self, Error> { | 56 | pub fn new_1ch<T: Instance>(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, config: Config) -> Result<Self, Error> { |
| 58 | Self::new_inner(pwm, Some(ch0.into()), None, None, None, config) | 57 | Self::new_inner(pwm, Some(ch0.into()), None, None, None, config) |
| 59 | } | 58 | } |
| 60 | 59 | ||
| 61 | /// Create a new 2-channel PWM | 60 | /// Create a new 2-channel PWM |
| 62 | #[allow(unused_unsafe)] | ||
| 63 | pub fn new_2ch<T: Instance>( | 61 | pub fn new_2ch<T: Instance>( |
| 64 | pwm: Peri<'d, T>, | 62 | pwm: Peri<'d, T>, |
| 65 | ch0: Peri<'d, impl GpioPin>, | 63 | ch0: Peri<'d, impl GpioPin>, |
| @@ -70,7 +68,6 @@ impl<'d> SequencePwm<'d> { | |||
| 70 | } | 68 | } |
| 71 | 69 | ||
| 72 | /// Create a new 3-channel PWM | 70 | /// Create a new 3-channel PWM |
| 73 | #[allow(unused_unsafe)] | ||
| 74 | pub fn new_3ch<T: Instance>( | 71 | pub fn new_3ch<T: Instance>( |
| 75 | pwm: Peri<'d, T>, | 72 | pwm: Peri<'d, T>, |
| 76 | ch0: Peri<'d, impl GpioPin>, | 73 | ch0: Peri<'d, impl GpioPin>, |
| @@ -82,7 +79,6 @@ impl<'d> SequencePwm<'d> { | |||
| 82 | } | 79 | } |
| 83 | 80 | ||
| 84 | /// Create a new 4-channel PWM | 81 | /// Create a new 4-channel PWM |
| 85 | #[allow(unused_unsafe)] | ||
| 86 | pub fn new_4ch<T: Instance>( | 82 | pub fn new_4ch<T: Instance>( |
| 87 | pwm: Peri<'d, T>, | 83 | pwm: Peri<'d, T>, |
| 88 | ch0: Peri<'d, impl GpioPin>, | 84 | ch0: Peri<'d, impl GpioPin>, |
| @@ -111,44 +107,27 @@ impl<'d> SequencePwm<'d> { | |||
| 111 | ) -> Result<Self, Error> { | 107 | ) -> Result<Self, Error> { |
| 112 | let r = T::regs(); | 108 | let r = T::regs(); |
| 113 | 109 | ||
| 114 | if let Some(pin) = &ch0 { | 110 | let channels = [ |
| 115 | pin.set_low(); | 111 | (&ch0, config.ch0_drive, config.ch0_idle_level), |
| 116 | pin.conf().write(|w| { | 112 | (&ch1, config.ch1_drive, config.ch1_idle_level), |
| 117 | w.set_dir(gpiovals::Dir::OUTPUT); | 113 | (&ch2, config.ch2_drive, config.ch2_idle_level), |
| 118 | w.set_input(gpiovals::Input::DISCONNECT); | 114 | (&ch3, config.ch3_drive, config.ch3_idle_level), |
| 119 | convert_drive(w, config.ch0_drive); | 115 | ]; |
| 120 | }); | 116 | for (i, (pin, drive, idle_level)) in channels.into_iter().enumerate() { |
| 121 | } | 117 | if let Some(pin) = pin { |
| 122 | if let Some(pin) = &ch1 { | 118 | match idle_level { |
| 123 | pin.set_low(); | 119 | Level::Low => pin.set_low(), |
| 124 | pin.conf().write(|w| { | 120 | Level::High => pin.set_high(), |
| 125 | w.set_dir(gpiovals::Dir::OUTPUT); | 121 | } |
| 126 | w.set_input(gpiovals::Input::DISCONNECT); | 122 | pin.conf().write(|w| { |
| 127 | convert_drive(w, config.ch1_drive); | 123 | w.set_dir(gpiovals::Dir::OUTPUT); |
| 128 | }); | 124 | w.set_input(gpiovals::Input::DISCONNECT); |
| 129 | } | 125 | convert_drive(w, drive); |
| 130 | if let Some(pin) = &ch2 { | 126 | }); |
| 131 | pin.set_low(); | 127 | } |
| 132 | pin.conf().write(|w| { | 128 | r.psel().out(i).write_value(pin.psel_bits()); |
| 133 | w.set_dir(gpiovals::Dir::OUTPUT); | ||
| 134 | w.set_input(gpiovals::Input::DISCONNECT); | ||
| 135 | convert_drive(w, config.ch2_drive); | ||
| 136 | }); | ||
| 137 | } | ||
| 138 | if let Some(pin) = &ch3 { | ||
| 139 | pin.set_low(); | ||
| 140 | pin.conf().write(|w| { | ||
| 141 | w.set_dir(gpiovals::Dir::OUTPUT); | ||
| 142 | w.set_input(gpiovals::Input::DISCONNECT); | ||
| 143 | convert_drive(w, config.ch3_drive); | ||
| 144 | }); | ||
| 145 | } | 129 | } |
| 146 | 130 | ||
| 147 | r.psel().out(0).write_value(ch0.psel_bits()); | ||
| 148 | r.psel().out(1).write_value(ch1.psel_bits()); | ||
| 149 | r.psel().out(2).write_value(ch2.psel_bits()); | ||
| 150 | r.psel().out(3).write_value(ch3.psel_bits()); | ||
| 151 | |||
| 152 | // Disable all interrupts | 131 | // Disable all interrupts |
| 153 | r.intenclr().write(|w| w.0 = 0xFFFF_FFFF); | 132 | r.intenclr().write(|w| w.0 = 0xFFFF_FFFF); |
| 154 | r.shorts().write(|_| ()); | 133 | r.shorts().write(|_| ()); |
| @@ -173,13 +152,7 @@ impl<'d> SequencePwm<'d> { | |||
| 173 | .write(|w| w.set_prescaler(vals::Prescaler::from_bits(config.prescaler as u8))); | 152 | .write(|w| w.set_prescaler(vals::Prescaler::from_bits(config.prescaler as u8))); |
| 174 | r.countertop().write(|w| w.set_countertop(config.max_duty)); | 153 | r.countertop().write(|w| w.set_countertop(config.max_duty)); |
| 175 | 154 | ||
| 176 | Ok(Self { | 155 | Ok(Self { r, ch0, ch1, ch2, ch3 }) |
| 177 | r: T::regs(), | ||
| 178 | ch0, | ||
| 179 | ch1, | ||
| 180 | ch2, | ||
| 181 | ch3, | ||
| 182 | }) | ||
| 183 | } | 156 | } |
| 184 | 157 | ||
| 185 | /// Returns reference to `Stopped` event endpoint for PPI. | 158 | /// Returns reference to `Stopped` event endpoint for PPI. |
| @@ -289,6 +262,8 @@ impl<'a> Drop for SequencePwm<'a> { | |||
| 289 | } | 262 | } |
| 290 | 263 | ||
| 291 | /// Configuration for the PWM as a whole. | 264 | /// Configuration for the PWM as a whole. |
| 265 | #[derive(Debug, Clone)] | ||
| 266 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 292 | #[non_exhaustive] | 267 | #[non_exhaustive] |
| 293 | pub struct Config { | 268 | pub struct Config { |
| 294 | /// Selects up mode or up-and-down mode for the counter | 269 | /// Selects up mode or up-and-down mode for the counter |
| @@ -307,11 +282,19 @@ pub struct Config { | |||
| 307 | pub ch2_drive: OutputDrive, | 282 | pub ch2_drive: OutputDrive, |
| 308 | /// Drive strength for the channel 3 line. | 283 | /// Drive strength for the channel 3 line. |
| 309 | pub ch3_drive: OutputDrive, | 284 | pub ch3_drive: OutputDrive, |
| 285 | /// Output level for the channel 0 line when PWM if disabled. | ||
| 286 | pub ch0_idle_level: Level, | ||
| 287 | /// Output level for the channel 1 line when PWM if disabled. | ||
| 288 | pub ch1_idle_level: Level, | ||
| 289 | /// Output level for the channel 2 line when PWM if disabled. | ||
| 290 | pub ch2_idle_level: Level, | ||
| 291 | /// Output level for the channel 3 line when PWM if disabled. | ||
| 292 | pub ch3_idle_level: Level, | ||
| 310 | } | 293 | } |
| 311 | 294 | ||
| 312 | impl Default for Config { | 295 | impl Default for Config { |
| 313 | fn default() -> Config { | 296 | fn default() -> Self { |
| 314 | Config { | 297 | Self { |
| 315 | counter_mode: CounterMode::Up, | 298 | counter_mode: CounterMode::Up, |
| 316 | max_duty: 1000, | 299 | max_duty: 1000, |
| 317 | prescaler: Prescaler::Div16, | 300 | prescaler: Prescaler::Div16, |
| @@ -320,13 +303,65 @@ impl Default for Config { | |||
| 320 | ch1_drive: OutputDrive::Standard, | 303 | ch1_drive: OutputDrive::Standard, |
| 321 | ch2_drive: OutputDrive::Standard, | 304 | ch2_drive: OutputDrive::Standard, |
| 322 | ch3_drive: OutputDrive::Standard, | 305 | ch3_drive: OutputDrive::Standard, |
| 306 | ch0_idle_level: Level::Low, | ||
| 307 | ch1_idle_level: Level::Low, | ||
| 308 | ch2_idle_level: Level::Low, | ||
| 309 | ch3_idle_level: Level::Low, | ||
| 310 | } | ||
| 311 | } | ||
| 312 | } | ||
| 313 | |||
| 314 | /// Configuration for the simple PWM driver. | ||
| 315 | #[derive(Debug, Clone)] | ||
| 316 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 317 | #[non_exhaustive] | ||
| 318 | pub struct SimpleConfig { | ||
| 319 | /// Selects up mode or up-and-down mode for the counter | ||
| 320 | pub counter_mode: CounterMode, | ||
| 321 | /// Top value to be compared against buffer values | ||
| 322 | pub max_duty: u16, | ||
| 323 | /// Configuration for PWM_CLK | ||
| 324 | pub prescaler: Prescaler, | ||
| 325 | /// Drive strength for the channel 0 line. | ||
| 326 | pub ch0_drive: OutputDrive, | ||
| 327 | /// Drive strength for the channel 1 line. | ||
| 328 | pub ch1_drive: OutputDrive, | ||
| 329 | /// Drive strength for the channel 2 line. | ||
| 330 | pub ch2_drive: OutputDrive, | ||
| 331 | /// Drive strength for the channel 3 line. | ||
| 332 | pub ch3_drive: OutputDrive, | ||
| 333 | /// Output level for the channel 0 line when PWM if disabled. | ||
| 334 | pub ch0_idle_level: Level, | ||
| 335 | /// Output level for the channel 1 line when PWM if disabled. | ||
| 336 | pub ch1_idle_level: Level, | ||
| 337 | /// Output level for the channel 2 line when PWM if disabled. | ||
| 338 | pub ch2_idle_level: Level, | ||
| 339 | /// Output level for the channel 3 line when PWM if disabled. | ||
| 340 | pub ch3_idle_level: Level, | ||
| 341 | } | ||
| 342 | |||
| 343 | impl Default for SimpleConfig { | ||
| 344 | fn default() -> Self { | ||
| 345 | Self { | ||
| 346 | counter_mode: CounterMode::Up, | ||
| 347 | max_duty: 1000, | ||
| 348 | prescaler: Prescaler::Div16, | ||
| 349 | ch0_drive: OutputDrive::Standard, | ||
| 350 | ch1_drive: OutputDrive::Standard, | ||
| 351 | ch2_drive: OutputDrive::Standard, | ||
| 352 | ch3_drive: OutputDrive::Standard, | ||
| 353 | ch0_idle_level: Level::Low, | ||
| 354 | ch1_idle_level: Level::Low, | ||
| 355 | ch2_idle_level: Level::Low, | ||
| 356 | ch3_idle_level: Level::Low, | ||
| 323 | } | 357 | } |
| 324 | } | 358 | } |
| 325 | } | 359 | } |
| 326 | 360 | ||
| 327 | /// Configuration per sequence | 361 | /// Configuration per sequence |
| 328 | #[non_exhaustive] | 362 | #[non_exhaustive] |
| 329 | #[derive(Clone)] | 363 | #[derive(Debug, Clone)] |
| 364 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 330 | pub struct SequenceConfig { | 365 | pub struct SequenceConfig { |
| 331 | /// Number of PWM periods to delay between each sequence sample | 366 | /// Number of PWM periods to delay between each sequence sample |
| 332 | pub refresh: u32, | 367 | pub refresh: u32, |
| @@ -345,6 +380,8 @@ impl Default for SequenceConfig { | |||
| 345 | 380 | ||
| 346 | /// A composition of a sequence buffer and its configuration. | 381 | /// A composition of a sequence buffer and its configuration. |
| 347 | #[non_exhaustive] | 382 | #[non_exhaustive] |
| 383 | #[derive(Debug, Clone)] | ||
| 384 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 348 | pub struct Sequence<'s> { | 385 | pub struct Sequence<'s> { |
| 349 | /// The words comprising the sequence. Must not exceed 32767 words. | 386 | /// The words comprising the sequence. Must not exceed 32767 words. |
| 350 | pub words: &'s [u16], | 387 | pub words: &'s [u16], |
| @@ -496,6 +533,7 @@ impl<'d, 's> Drop for Sequencer<'d, 's> { | |||
| 496 | 533 | ||
| 497 | /// How many times to run a single sequence | 534 | /// How many times to run a single sequence |
| 498 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | 535 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] |
| 536 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 499 | pub enum SingleSequenceMode { | 537 | pub enum SingleSequenceMode { |
| 500 | /// Run a single sequence n Times total. | 538 | /// Run a single sequence n Times total. |
| 501 | Times(u16), | 539 | Times(u16), |
| @@ -505,6 +543,7 @@ pub enum SingleSequenceMode { | |||
| 505 | 543 | ||
| 506 | /// Which sequence to start a loop with | 544 | /// Which sequence to start a loop with |
| 507 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | 545 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] |
| 546 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 508 | pub enum StartSequence { | 547 | pub enum StartSequence { |
| 509 | /// Start with Sequence 0 | 548 | /// Start with Sequence 0 |
| 510 | Zero, | 549 | Zero, |
| @@ -514,6 +553,7 @@ pub enum StartSequence { | |||
| 514 | 553 | ||
| 515 | /// How many loops to run two sequences | 554 | /// How many loops to run two sequences |
| 516 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | 555 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] |
| 556 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 517 | pub enum SequenceMode { | 557 | pub enum SequenceMode { |
| 518 | /// Run two sequences n loops i.e. (n * (seq0 + seq1.unwrap_or(seq0))) | 558 | /// Run two sequences n loops i.e. (n * (seq0 + seq1.unwrap_or(seq0))) |
| 519 | Loop(u16), | 559 | Loop(u16), |
| @@ -523,6 +563,7 @@ pub enum SequenceMode { | |||
| 523 | 563 | ||
| 524 | /// PWM Base clock is system clock (16MHz) divided by prescaler | 564 | /// PWM Base clock is system clock (16MHz) divided by prescaler |
| 525 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | 565 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] |
| 566 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 526 | pub enum Prescaler { | 567 | pub enum Prescaler { |
| 527 | /// Divide by 1 | 568 | /// Divide by 1 |
| 528 | Div1, | 569 | Div1, |
| @@ -544,6 +585,7 @@ pub enum Prescaler { | |||
| 544 | 585 | ||
| 545 | /// How the sequence values are distributed across the channels | 586 | /// How the sequence values are distributed across the channels |
| 546 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | 587 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] |
| 588 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 547 | pub enum SequenceLoad { | 589 | pub enum SequenceLoad { |
| 548 | /// Provided sequence will be used across all channels | 590 | /// Provided sequence will be used across all channels |
| 549 | Common, | 591 | Common, |
| @@ -560,6 +602,7 @@ pub enum SequenceLoad { | |||
| 560 | 602 | ||
| 561 | /// Selects up mode or up-and-down mode for the counter | 603 | /// Selects up mode or up-and-down mode for the counter |
| 562 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | 604 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] |
| 605 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 563 | pub enum CounterMode { | 606 | pub enum CounterMode { |
| 564 | /// Up counter (edge-aligned PWM duty cycle) | 607 | /// Up counter (edge-aligned PWM duty cycle) |
| 565 | Up, | 608 | Up, |
| @@ -567,48 +610,128 @@ pub enum CounterMode { | |||
| 567 | UpAndDown, | 610 | UpAndDown, |
| 568 | } | 611 | } |
| 569 | 612 | ||
| 613 | /// Duty value and polarity for a single channel. | ||
| 614 | /// | ||
| 615 | /// If the channel has inverted polarity, the output is set high as long as the counter is below the duty value. | ||
| 616 | #[repr(transparent)] | ||
| 617 | #[derive(Eq, PartialEq, Clone, Copy)] | ||
| 618 | pub struct DutyCycle { | ||
| 619 | /// The raw duty cycle valuea. | ||
| 620 | /// | ||
| 621 | /// This has the duty cycle in the lower 15 bits. | ||
| 622 | /// The highest bit indicates that the duty cycle has inverted polarity. | ||
| 623 | raw: u16, | ||
| 624 | } | ||
| 625 | |||
| 626 | impl DutyCycle { | ||
| 627 | /// Make a new duty value with normal polarity. | ||
| 628 | /// | ||
| 629 | /// The value is truncated to 15 bits. | ||
| 630 | /// | ||
| 631 | /// The output is set high if the counter is at or above the duty value. | ||
| 632 | pub const fn normal(value: u16) -> Self { | ||
| 633 | let raw = value & 0x7FFF; | ||
| 634 | Self { raw } | ||
| 635 | } | ||
| 636 | |||
| 637 | /// Make a new duty cycle with inverted polarity. | ||
| 638 | /// | ||
| 639 | /// The value is truncated to 15 bits. | ||
| 640 | /// | ||
| 641 | /// The output is set high if the counter is below the duty value. | ||
| 642 | pub const fn inverted(value: u16) -> Self { | ||
| 643 | let raw = value | 0x8000; | ||
| 644 | Self { raw } | ||
| 645 | } | ||
| 646 | |||
| 647 | /// Adjust the polarity of the duty cycle (returns a new object). | ||
| 648 | #[must_use = "this function return a new object, it does not modify self"] | ||
| 649 | pub const fn with_inverted(self, inverted_polarity: bool) -> Self { | ||
| 650 | if inverted_polarity { | ||
| 651 | Self::inverted(self.value()) | ||
| 652 | } else { | ||
| 653 | Self::normal(self.value()) | ||
| 654 | } | ||
| 655 | } | ||
| 656 | |||
| 657 | /// Gets the 15-bit value of the duty cycle. | ||
| 658 | pub const fn value(&self) -> u16 { | ||
| 659 | self.raw & 0x7FFF | ||
| 660 | } | ||
| 661 | |||
| 662 | /// Checks if the duty period has inverted polarity. | ||
| 663 | /// | ||
| 664 | /// If the channel has inverted polarity, the output is set high as long as the counter is below the duty value. | ||
| 665 | pub const fn is_inverted(&self) -> bool { | ||
| 666 | self.raw & 0x8000 != 0 | ||
| 667 | } | ||
| 668 | } | ||
| 669 | |||
| 670 | impl core::fmt::Debug for DutyCycle { | ||
| 671 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { | ||
| 672 | f.debug_struct("DutyCycle") | ||
| 673 | .field("value", &self.value()) | ||
| 674 | .field("inverted", &self.is_inverted()) | ||
| 675 | .finish() | ||
| 676 | } | ||
| 677 | } | ||
| 678 | |||
| 679 | #[cfg(feature = "defmt")] | ||
| 680 | impl defmt::Format for DutyCycle { | ||
| 681 | fn format(&self, f: defmt::Formatter) { | ||
| 682 | defmt::write!( | ||
| 683 | f, | ||
| 684 | "DutyCycle {{ value: {=u16}, inverted: {=bool} }}", | ||
| 685 | self.value(), | ||
| 686 | self.is_inverted(), | ||
| 687 | ); | ||
| 688 | } | ||
| 689 | } | ||
| 690 | |||
| 570 | impl<'d> SimplePwm<'d> { | 691 | impl<'d> SimplePwm<'d> { |
| 571 | /// Create a new 1-channel PWM | 692 | /// Create a new 1-channel PWM |
| 572 | #[allow(unused_unsafe)] | 693 | pub fn new_1ch<T: Instance>(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, config: &SimpleConfig) -> Self { |
| 573 | pub fn new_1ch<T: Instance>(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>) -> Self { | 694 | Self::new_inner(pwm, Some(ch0.into()), None, None, None, config) |
| 574 | unsafe { Self::new_inner(pwm, Some(ch0.into()), None, None, None) } | ||
| 575 | } | 695 | } |
| 576 | 696 | ||
| 577 | /// Create a new 2-channel PWM | 697 | /// Create a new 2-channel PWM |
| 578 | #[allow(unused_unsafe)] | 698 | pub fn new_2ch<T: Instance>( |
| 579 | pub fn new_2ch<T: Instance>(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, ch1: Peri<'d, impl GpioPin>) -> Self { | 699 | pwm: Peri<'d, T>, |
| 580 | Self::new_inner(pwm, Some(ch0.into()), Some(ch1.into()), None, None) | 700 | ch0: Peri<'d, impl GpioPin>, |
| 701 | ch1: Peri<'d, impl GpioPin>, | ||
| 702 | config: &SimpleConfig, | ||
| 703 | ) -> Self { | ||
| 704 | Self::new_inner(pwm, Some(ch0.into()), Some(ch1.into()), None, None, config) | ||
| 581 | } | 705 | } |
| 582 | 706 | ||
| 583 | /// Create a new 3-channel PWM | 707 | /// Create a new 3-channel PWM |
| 584 | #[allow(unused_unsafe)] | ||
| 585 | pub fn new_3ch<T: Instance>( | 708 | pub fn new_3ch<T: Instance>( |
| 586 | pwm: Peri<'d, T>, | 709 | pwm: Peri<'d, T>, |
| 587 | ch0: Peri<'d, impl GpioPin>, | 710 | ch0: Peri<'d, impl GpioPin>, |
| 588 | ch1: Peri<'d, impl GpioPin>, | 711 | ch1: Peri<'d, impl GpioPin>, |
| 589 | ch2: Peri<'d, impl GpioPin>, | 712 | ch2: Peri<'d, impl GpioPin>, |
| 713 | config: &SimpleConfig, | ||
| 590 | ) -> Self { | 714 | ) -> Self { |
| 591 | unsafe { Self::new_inner(pwm, Some(ch0.into()), Some(ch1.into()), Some(ch2.into()), None) } | 715 | Self::new_inner(pwm, Some(ch0.into()), Some(ch1.into()), Some(ch2.into()), None, config) |
| 592 | } | 716 | } |
| 593 | 717 | ||
| 594 | /// Create a new 4-channel PWM | 718 | /// Create a new 4-channel PWM |
| 595 | #[allow(unused_unsafe)] | ||
| 596 | pub fn new_4ch<T: Instance>( | 719 | pub fn new_4ch<T: Instance>( |
| 597 | pwm: Peri<'d, T>, | 720 | pwm: Peri<'d, T>, |
| 598 | ch0: Peri<'d, impl GpioPin>, | 721 | ch0: Peri<'d, impl GpioPin>, |
| 599 | ch1: Peri<'d, impl GpioPin>, | 722 | ch1: Peri<'d, impl GpioPin>, |
| 600 | ch2: Peri<'d, impl GpioPin>, | 723 | ch2: Peri<'d, impl GpioPin>, |
| 601 | ch3: Peri<'d, impl GpioPin>, | 724 | ch3: Peri<'d, impl GpioPin>, |
| 725 | config: &SimpleConfig, | ||
| 602 | ) -> Self { | 726 | ) -> Self { |
| 603 | unsafe { | 727 | Self::new_inner( |
| 604 | Self::new_inner( | 728 | pwm, |
| 605 | pwm, | 729 | Some(ch0.into()), |
| 606 | Some(ch0.into()), | 730 | Some(ch1.into()), |
| 607 | Some(ch1.into()), | 731 | Some(ch2.into()), |
| 608 | Some(ch2.into()), | 732 | Some(ch3.into()), |
| 609 | Some(ch3.into()), | 733 | config, |
| 610 | ) | 734 | ) |
| 611 | } | ||
| 612 | } | 735 | } |
| 613 | 736 | ||
| 614 | fn new_inner<T: Instance>( | 737 | fn new_inner<T: Instance>( |
| @@ -617,29 +740,38 @@ impl<'d> SimplePwm<'d> { | |||
| 617 | ch1: Option<Peri<'d, AnyPin>>, | 740 | ch1: Option<Peri<'d, AnyPin>>, |
| 618 | ch2: Option<Peri<'d, AnyPin>>, | 741 | ch2: Option<Peri<'d, AnyPin>>, |
| 619 | ch3: Option<Peri<'d, AnyPin>>, | 742 | ch3: Option<Peri<'d, AnyPin>>, |
| 743 | config: &SimpleConfig, | ||
| 620 | ) -> Self { | 744 | ) -> Self { |
| 621 | let r = T::regs(); | 745 | let r = T::regs(); |
| 622 | 746 | ||
| 623 | for (i, ch) in [&ch0, &ch1, &ch2, &ch3].into_iter().enumerate() { | 747 | let channels = [ |
| 624 | if let Some(pin) = ch { | 748 | (&ch0, config.ch0_drive, config.ch0_idle_level), |
| 625 | pin.set_low(); | 749 | (&ch1, config.ch1_drive, config.ch1_idle_level), |
| 626 | 750 | (&ch2, config.ch2_drive, config.ch2_idle_level), | |
| 751 | (&ch3, config.ch3_drive, config.ch3_idle_level), | ||
| 752 | ]; | ||
| 753 | for (i, (pin, drive, idle_level)) in channels.into_iter().enumerate() { | ||
| 754 | if let Some(pin) = pin { | ||
| 755 | match idle_level { | ||
| 756 | Level::Low => pin.set_low(), | ||
| 757 | Level::High => pin.set_high(), | ||
| 758 | } | ||
| 627 | pin.conf().write(|w| { | 759 | pin.conf().write(|w| { |
| 628 | w.set_dir(gpiovals::Dir::OUTPUT); | 760 | w.set_dir(gpiovals::Dir::OUTPUT); |
| 629 | w.set_input(gpiovals::Input::DISCONNECT); | 761 | w.set_input(gpiovals::Input::DISCONNECT); |
| 630 | w.set_drive(gpiovals::Drive::S0S1); | 762 | convert_drive(w, drive); |
| 631 | }); | 763 | }); |
| 632 | } | 764 | } |
| 633 | r.psel().out(i).write_value(ch.psel_bits()); | 765 | r.psel().out(i).write_value(pin.psel_bits()); |
| 634 | } | 766 | } |
| 635 | 767 | ||
| 636 | let pwm = Self { | 768 | let pwm = Self { |
| 637 | r: T::regs(), | 769 | r, |
| 638 | ch0, | 770 | ch0, |
| 639 | ch1, | 771 | ch1, |
| 640 | ch2, | 772 | ch2, |
| 641 | ch3, | 773 | ch3, |
| 642 | duty: [0; 4], | 774 | duty: [const { DutyCycle::normal(0) }; 4], |
| 643 | }; | 775 | }; |
| 644 | 776 | ||
| 645 | // Disable all interrupts | 777 | // Disable all interrupts |
| @@ -658,9 +790,13 @@ impl<'d> SimplePwm<'d> { | |||
| 658 | w.set_load(vals::Load::INDIVIDUAL); | 790 | w.set_load(vals::Load::INDIVIDUAL); |
| 659 | w.set_mode(vals::Mode::REFRESH_COUNT); | 791 | w.set_mode(vals::Mode::REFRESH_COUNT); |
| 660 | }); | 792 | }); |
| 661 | r.mode().write(|w| w.set_updown(vals::Updown::UP)); | 793 | r.mode().write(|w| match config.counter_mode { |
| 662 | r.prescaler().write(|w| w.set_prescaler(vals::Prescaler::DIV_16)); | 794 | CounterMode::UpAndDown => w.set_updown(vals::Updown::UP_AND_DOWN), |
| 663 | r.countertop().write(|w| w.set_countertop(1000)); | 795 | CounterMode::Up => w.set_updown(vals::Updown::UP), |
| 796 | }); | ||
| 797 | r.prescaler() | ||
| 798 | .write(|w| w.set_prescaler(vals::Prescaler::from_bits(config.prescaler as u8))); | ||
| 799 | r.countertop().write(|w| w.set_countertop(config.max_duty)); | ||
| 664 | r.loop_().write(|w| w.set_cnt(vals::LoopCnt::DISABLED)); | 800 | r.loop_().write(|w| w.set_cnt(vals::LoopCnt::DISABLED)); |
| 665 | 801 | ||
| 666 | pwm | 802 | pwm |
| @@ -684,15 +820,31 @@ impl<'d> SimplePwm<'d> { | |||
| 684 | self.r.enable().write(|w| w.set_enable(false)); | 820 | self.r.enable().write(|w| w.set_enable(false)); |
| 685 | } | 821 | } |
| 686 | 822 | ||
| 687 | /// Returns the current duty of the channel | 823 | /// Returns the current duty of the channel. |
| 688 | pub fn duty(&self, channel: usize) -> u16 { | 824 | pub fn duty(&self, channel: usize) -> DutyCycle { |
| 689 | self.duty[channel] | 825 | self.duty[channel] |
| 690 | } | 826 | } |
| 691 | 827 | ||
| 692 | /// Sets duty cycle (15 bit) for a PWM channel. | 828 | /// Sets duty cycle (15 bit) and polarity for a PWM channel. |
| 693 | pub fn set_duty(&mut self, channel: usize, duty: u16) { | 829 | pub fn set_duty(&mut self, channel: usize, duty: DutyCycle) { |
| 694 | self.duty[channel] = duty & 0x7FFF; | 830 | self.duty[channel] = duty; |
| 831 | self.sync_duty_cyles_to_peripheral(); | ||
| 832 | } | ||
| 833 | |||
| 834 | /// Sets the duty cycle (15 bit) and polarity for all PWM channels. | ||
| 835 | /// | ||
| 836 | /// You can safely set the duty cycle of disabled PWM channels. | ||
| 837 | /// | ||
| 838 | /// When using this function, a single DMA transfer sets all the duty cycles. | ||
| 839 | /// If you call [`Self::set_duty()`] multiple times, | ||
| 840 | /// each duty cycle will be set by a separate DMA transfer. | ||
| 841 | pub fn set_all_duties(&mut self, duty: [DutyCycle; 4]) { | ||
| 842 | self.duty = duty; | ||
| 843 | self.sync_duty_cyles_to_peripheral(); | ||
| 844 | } | ||
| 695 | 845 | ||
| 846 | /// Transfer the duty cycles from `self` to the peripheral. | ||
| 847 | fn sync_duty_cyles_to_peripheral(&self) { | ||
| 696 | // reload ptr in case self was moved | 848 | // reload ptr in case self was moved |
| 697 | self.r.seq(0).ptr().write_value((self.duty).as_ptr() as u32); | 849 | self.r.seq(0).ptr().write_value((self.duty).as_ptr() as u32); |
| 698 | 850 | ||
diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md index a99d04aa4..57ec13658 100644 --- a/embassy-rp/CHANGELOG.md +++ b/embassy-rp/CHANGELOG.md | |||
| @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 8 | <!-- next-header --> | 8 | <!-- next-header --> |
| 9 | ## Unreleased - ReleaseDate | 9 | ## Unreleased - ReleaseDate |
| 10 | 10 | ||
| 11 | - Fix typo in interrupt comment | 11 | - Fix several minor typos in documentation |
| 12 | - Add PIO SPI | 12 | - Add PIO SPI |
| 13 | - Add PIO I2S input | 13 | - Add PIO I2S input |
| 14 | - Add PIO onewire parasite power strong pullup | 14 | - Add PIO onewire parasite power strong pullup |
diff --git a/embassy-rp/src/block.rs b/embassy-rp/src/block.rs index a3e1ad925..745883b83 100644 --- a/embassy-rp/src/block.rs +++ b/embassy-rp/src/block.rs | |||
| @@ -240,7 +240,7 @@ impl UnpartitionedSpace { | |||
| 240 | } | 240 | } |
| 241 | } | 241 | } |
| 242 | 242 | ||
| 243 | /// Create a new unpartition space from run-time values. | 243 | /// Create a new unpartitioned space from run-time values. |
| 244 | /// | 244 | /// |
| 245 | /// Get these from the ROM function `get_partition_table_info` with an argument of `PT_INFO`. | 245 | /// Get these from the ROM function `get_partition_table_info` with an argument of `PT_INFO`. |
| 246 | pub const fn from_raw(permissions_and_location: u32, permissions_and_flags: u32) -> Self { | 246 | pub const fn from_raw(permissions_and_location: u32, permissions_and_flags: u32) -> Self { |
| @@ -714,7 +714,7 @@ impl PartitionTableBlock { | |||
| 714 | new_table | 714 | new_table |
| 715 | } | 715 | } |
| 716 | 716 | ||
| 717 | /// Add a a SHA256 hash of the Block | 717 | /// Add a SHA256 hash of the Block |
| 718 | /// | 718 | /// |
| 719 | /// Adds a `HASH_DEF` covering all the previous items in the Block, and a | 719 | /// Adds a `HASH_DEF` covering all the previous items in the Block, and a |
| 720 | /// `HASH_VALUE` with a SHA-256 hash of them. | 720 | /// `HASH_VALUE` with a SHA-256 hash of them. |
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 56892d7a2..8bfb5129a 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs | |||
| @@ -267,7 +267,7 @@ impl CoreVoltage { | |||
| 267 | } | 267 | } |
| 268 | } | 268 | } |
| 269 | 269 | ||
| 270 | /// CLock configuration. | 270 | /// Clock configuration. |
| 271 | #[non_exhaustive] | 271 | #[non_exhaustive] |
| 272 | pub struct ClockConfig { | 272 | pub struct ClockConfig { |
| 273 | /// Ring oscillator configuration. | 273 | /// Ring oscillator configuration. |
diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs index 770087bc8..0853709df 100644 --- a/embassy-rp/src/i2c_slave.rs +++ b/embassy-rp/src/i2c_slave.rs | |||
| @@ -52,7 +52,7 @@ pub enum ReadStatus { | |||
| 52 | Done, | 52 | Done, |
| 53 | /// Transaction Incomplete, controller trying to read more bytes than were provided | 53 | /// Transaction Incomplete, controller trying to read more bytes than were provided |
| 54 | NeedMoreBytes, | 54 | NeedMoreBytes, |
| 55 | /// Transaction Complere, but controller stopped reading bytes before we ran out | 55 | /// Transaction Complete, but controller stopped reading bytes before we ran out |
| 56 | LeftoverBytes(u16), | 56 | LeftoverBytes(u16), |
| 57 | } | 57 | } |
| 58 | 58 | ||
| @@ -240,7 +240,7 @@ impl<'d, T: Instance> I2cSlave<'d, T> { | |||
| 240 | 240 | ||
| 241 | if p.ic_rxflr().read().rxflr() > 0 || me.pending_byte.is_some() { | 241 | if p.ic_rxflr().read().rxflr() > 0 || me.pending_byte.is_some() { |
| 242 | me.drain_fifo(buffer, &mut len); | 242 | me.drain_fifo(buffer, &mut len); |
| 243 | // we're recieving data, set rx fifo watermark to 12 bytes (3/4 full) to reduce interrupt noise | 243 | // we're receiving data, set rx fifo watermark to 12 bytes (3/4 full) to reduce interrupt noise |
| 244 | p.ic_rx_tl().write(|w| w.set_rx_tl(11)); | 244 | p.ic_rx_tl().write(|w| w.set_rx_tl(11)); |
| 245 | } | 245 | } |
| 246 | 246 | ||
diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs index 3b120e349..572d8db91 100644 --- a/embassy-rp/src/multicore.rs +++ b/embassy-rp/src/multicore.rs | |||
| @@ -58,7 +58,7 @@ const PAUSE_TOKEN: u32 = 0xDEADBEEF; | |||
| 58 | const RESUME_TOKEN: u32 = !0xDEADBEEF; | 58 | const RESUME_TOKEN: u32 = !0xDEADBEEF; |
| 59 | static IS_CORE1_INIT: AtomicBool = AtomicBool::new(false); | 59 | static IS_CORE1_INIT: AtomicBool = AtomicBool::new(false); |
| 60 | 60 | ||
| 61 | /// Represents a partiticular CPU core (SIO_CPUID) | 61 | /// Represents a particular CPU core (SIO_CPUID) |
| 62 | #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] | 62 | #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] |
| 63 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 63 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 64 | #[repr(u8)] | 64 | #[repr(u8)] |
diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 38ee1f97c..92b2c603e 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs | |||
| @@ -62,7 +62,7 @@ pub enum FifoJoin { | |||
| 62 | #[cfg(feature = "_rp235x")] | 62 | #[cfg(feature = "_rp235x")] |
| 63 | RxAsControl, | 63 | RxAsControl, |
| 64 | /// FJOIN_RX_PUT | FJOIN_RX_GET: RX can be used as a scratch register, | 64 | /// FJOIN_RX_PUT | FJOIN_RX_GET: RX can be used as a scratch register, |
| 65 | /// not accesible from the CPU | 65 | /// not accessible from the CPU |
| 66 | #[cfg(feature = "_rp235x")] | 66 | #[cfg(feature = "_rp235x")] |
| 67 | PioScratch, | 67 | PioScratch, |
| 68 | } | 68 | } |
diff --git a/embassy-rp/src/pio_programs/i2s.rs b/embassy-rp/src/pio_programs/i2s.rs index 7e5f68ad6..5c49beecb 100644 --- a/embassy-rp/src/pio_programs/i2s.rs +++ b/embassy-rp/src/pio_programs/i2s.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | //! Pio backed I2s output and output drivers | 1 | //! Pio backed I2S output and output drivers |
| 2 | 2 | ||
| 3 | use fixed::traits::ToFixed; | 3 | use fixed::traits::ToFixed; |
| 4 | 4 | ||
| @@ -9,7 +9,7 @@ use crate::pio::{ | |||
| 9 | Common, Config, Direction, FifoJoin, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, | 9 | Common, Config, Direction, FifoJoin, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, |
| 10 | }; | 10 | }; |
| 11 | 11 | ||
| 12 | /// This struct represents an i2s receiver & controller driver program | 12 | /// This struct represents an I2S receiver & controller driver program |
| 13 | pub struct PioI2sInProgram<'d, PIO: Instance> { | 13 | pub struct PioI2sInProgram<'d, PIO: Instance> { |
| 14 | prg: LoadedProgram<'d, PIO>, | 14 | prg: LoadedProgram<'d, PIO>, |
| 15 | } | 15 | } |
| @@ -35,7 +35,7 @@ impl<'d, PIO: Instance> PioI2sInProgram<'d, PIO> { | |||
| 35 | } | 35 | } |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | /// Pio backed I2s input driver | 38 | /// Pio backed I2S input driver |
| 39 | pub struct PioI2sIn<'d, P: Instance, const S: usize> { | 39 | pub struct PioI2sIn<'d, P: Instance, const S: usize> { |
| 40 | dma: Peri<'d, AnyChannel>, | 40 | dma: Peri<'d, AnyChannel>, |
| 41 | sm: StateMachine<'d, P, S>, | 41 | sm: StateMachine<'d, P, S>, |
| @@ -50,7 +50,7 @@ impl<'d, P: Instance, const S: usize> PioI2sIn<'d, P, S> { | |||
| 50 | // Whether or not to use the MCU's internal pull-down resistor, as the | 50 | // Whether or not to use the MCU's internal pull-down resistor, as the |
| 51 | // Pico 2 is known to have problems with the inbuilt pulldowns, many | 51 | // Pico 2 is known to have problems with the inbuilt pulldowns, many |
| 52 | // opt to just use an external pull down resistor to meet requirements of common | 52 | // opt to just use an external pull down resistor to meet requirements of common |
| 53 | // i2s microphones such as the INMP441 | 53 | // I2S microphones such as the INMP441 |
| 54 | data_pulldown: bool, | 54 | data_pulldown: bool, |
| 55 | data_pin: Peri<'d, impl PioPin>, | 55 | data_pin: Peri<'d, impl PioPin>, |
| 56 | bit_clock_pin: Peri<'d, impl PioPin>, | 56 | bit_clock_pin: Peri<'d, impl PioPin>, |
| @@ -90,13 +90,13 @@ impl<'d, P: Instance, const S: usize> PioI2sIn<'d, P, S> { | |||
| 90 | Self { dma: dma.into(), sm } | 90 | Self { dma: dma.into(), sm } |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | /// Return an in-prograss dma transfer future. Awaiting it will guarentee a complete transfer. | 93 | /// Return an in-progress dma transfer future. Awaiting it will guarantee a complete transfer. |
| 94 | pub fn read<'b>(&'b mut self, buff: &'b mut [u32]) -> Transfer<'b, AnyChannel> { | 94 | pub fn read<'b>(&'b mut self, buff: &'b mut [u32]) -> Transfer<'b, AnyChannel> { |
| 95 | self.sm.rx().dma_pull(self.dma.reborrow(), buff, false) | 95 | self.sm.rx().dma_pull(self.dma.reborrow(), buff, false) |
| 96 | } | 96 | } |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | /// This struct represents an i2s output driver program | 99 | /// This struct represents an I2S output driver program |
| 100 | /// | 100 | /// |
| 101 | /// The sample bit-depth is set through scratch register `Y`. | 101 | /// The sample bit-depth is set through scratch register `Y`. |
| 102 | /// `Y` has to be set to sample bit-depth - 2. | 102 | /// `Y` has to be set to sample bit-depth - 2. |
| @@ -128,14 +128,14 @@ impl<'d, PIO: Instance> PioI2sOutProgram<'d, PIO> { | |||
| 128 | } | 128 | } |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | /// Pio backed I2s output driver | 131 | /// Pio backed I2S output driver |
| 132 | pub struct PioI2sOut<'d, P: Instance, const S: usize> { | 132 | pub struct PioI2sOut<'d, P: Instance, const S: usize> { |
| 133 | dma: Peri<'d, AnyChannel>, | 133 | dma: Peri<'d, AnyChannel>, |
| 134 | sm: StateMachine<'d, P, S>, | 134 | sm: StateMachine<'d, P, S>, |
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | impl<'d, P: Instance, const S: usize> PioI2sOut<'d, P, S> { | 137 | impl<'d, P: Instance, const S: usize> PioI2sOut<'d, P, S> { |
| 138 | /// Configure a state machine to output I2s | 138 | /// Configure a state machine to output I2S |
| 139 | pub fn new( | 139 | pub fn new( |
| 140 | common: &mut Common<'d, P>, | 140 | common: &mut Common<'d, P>, |
| 141 | mut sm: StateMachine<'d, P, S>, | 141 | mut sm: StateMachine<'d, P, S>, |
| @@ -179,7 +179,7 @@ impl<'d, P: Instance, const S: usize> PioI2sOut<'d, P, S> { | |||
| 179 | Self { dma: dma.into(), sm } | 179 | Self { dma: dma.into(), sm } |
| 180 | } | 180 | } |
| 181 | 181 | ||
| 182 | /// Return an in-prograss dma transfer future. Awaiting it will guarentee a complete transfer. | 182 | /// Return an in-progress dma transfer future. Awaiting it will guarantee a complete transfer. |
| 183 | pub fn write<'b>(&'b mut self, buff: &'b [u32]) -> Transfer<'b, AnyChannel> { | 183 | pub fn write<'b>(&'b mut self, buff: &'b [u32]) -> Transfer<'b, AnyChannel> { |
| 184 | self.sm.tx().dma_push(self.dma.reborrow(), buff, false) | 184 | self.sm.tx().dma_push(self.dma.reborrow(), buff, false) |
| 185 | } | 185 | } |
diff --git a/embassy-rp/src/pio_programs/pwm.rs b/embassy-rp/src/pio_programs/pwm.rs index ba06bb3c1..e4ad4a6f0 100644 --- a/embassy-rp/src/pio_programs/pwm.rs +++ b/embassy-rp/src/pio_programs/pwm.rs | |||
| @@ -67,7 +67,7 @@ impl<'d, T: Instance, const SM: usize> PioPwm<'d, T, SM> { | |||
| 67 | Self { sm, pin } | 67 | Self { sm, pin } |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | /// Enable's the PIO program, continuing the wave generation from the PIO program. | 70 | /// Enables the PIO program, continuing the wave generation from the PIO program. |
| 71 | pub fn start(&mut self) { | 71 | pub fn start(&mut self) { |
| 72 | self.sm.set_enable(true); | 72 | self.sm.set_enable(true); |
| 73 | } | 73 | } |
diff --git a/embassy-rp/src/pio_programs/spi.rs b/embassy-rp/src/pio_programs/spi.rs index b10fc6628..765ffaa06 100644 --- a/embassy-rp/src/pio_programs/spi.rs +++ b/embassy-rp/src/pio_programs/spi.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | //! PIO backed SPi drivers | 1 | //! PIO backed SPI drivers |
| 2 | 2 | ||
| 3 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 4 | 4 | ||
| @@ -83,7 +83,7 @@ pub enum Error { | |||
| 83 | // No errors for now | 83 | // No errors for now |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | /// PIO based Spi driver. | 86 | /// PIO based SPI driver. |
| 87 | /// Unlike other PIO programs, the PIO SPI driver owns and holds a reference to | 87 | /// Unlike other PIO programs, the PIO SPI driver owns and holds a reference to |
| 88 | /// the PIO memory it uses. This is so that it can be reconfigured at runtime if | 88 | /// the PIO memory it uses. This is so that it can be reconfigured at runtime if |
| 89 | /// desired. | 89 | /// desired. |
diff --git a/embassy-rp/src/pio_programs/uart.rs b/embassy-rp/src/pio_programs/uart.rs index 444efb5db..d59596dd1 100644 --- a/embassy-rp/src/pio_programs/uart.rs +++ b/embassy-rp/src/pio_programs/uart.rs | |||
| @@ -130,7 +130,7 @@ impl<'d, PIO: Instance> PioUartRxProgram<'d, PIO> { | |||
| 130 | } | 130 | } |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | /// PIO backed Uart reciever | 133 | /// PIO backed Uart receiver |
| 134 | pub struct PioUartRx<'d, PIO: Instance, const SM: usize> { | 134 | pub struct PioUartRx<'d, PIO: Instance, const SM: usize> { |
| 135 | sm_rx: StateMachine<'d, PIO, SM>, | 135 | sm_rx: StateMachine<'d, PIO, SM>, |
| 136 | } | 136 | } |
diff --git a/embassy-rp/src/rom_data/rp2040.rs b/embassy-rp/src/rom_data/rp2040.rs index 5a74eddd6..27a8d8981 100644 --- a/embassy-rp/src/rom_data/rp2040.rs +++ b/embassy-rp/src/rom_data/rp2040.rs | |||
| @@ -30,7 +30,7 @@ const DATA_TABLE: *const u16 = 0x0000_0016 as _; | |||
| 30 | /// Address of the version number of the ROM. | 30 | /// Address of the version number of the ROM. |
| 31 | const VERSION_NUMBER: *const u8 = 0x0000_0013 as _; | 31 | const VERSION_NUMBER: *const u8 = 0x0000_0013 as _; |
| 32 | 32 | ||
| 33 | /// Retrive rom content from a table using a code. | 33 | /// Retrieve rom content from a table using a code. |
| 34 | fn rom_table_lookup<T>(table: *const u16, tag: RomFnTableCode) -> T { | 34 | fn rom_table_lookup<T>(table: *const u16, tag: RomFnTableCode) -> T { |
| 35 | unsafe { | 35 | unsafe { |
| 36 | let rom_table_lookup_ptr: *const u32 = rom_hword_as_ptr(ROM_TABLE_LOOKUP_PTR); | 36 | let rom_table_lookup_ptr: *const u32 = rom_hword_as_ptr(ROM_TABLE_LOOKUP_PTR); |
diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs index 68fb3b765..054572903 100644 --- a/embassy-rp/src/rtc/mod.rs +++ b/embassy-rp/src/rtc/mod.rs | |||
| @@ -47,7 +47,7 @@ impl<'d, T: Instance> Rtc<'d, T> { | |||
| 47 | Self { inner } | 47 | Self { inner } |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | /// Enable or disable the leap year check. The rp2040 chip will always add a Feb 29th on every year that is divisable by 4, but this may be incorrect (e.g. on century years). This function allows you to disable this check. | 50 | /// Enable or disable the leap year check. The rp2040 chip will always add a Feb 29th on every year that is divisible by 4, but this may be incorrect (e.g. on century years). This function allows you to disable this check. |
| 51 | /// | 51 | /// |
| 52 | /// Leap year checking is enabled by default. | 52 | /// Leap year checking is enabled by default. |
| 53 | pub fn set_leap_year_check(&mut self, leap_year_check_enabled: bool) { | 53 | pub fn set_leap_year_check(&mut self, leap_year_check_enabled: bool) { |
diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs index 559b3b909..d9410e78d 100644 --- a/embassy-rp/src/spi.rs +++ b/embassy-rp/src/spi.rs | |||
| @@ -157,7 +157,7 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { | |||
| 157 | 157 | ||
| 158 | /// Private function to apply SPI configuration (phase, polarity, frequency) settings. | 158 | /// Private function to apply SPI configuration (phase, polarity, frequency) settings. |
| 159 | /// | 159 | /// |
| 160 | /// Driver should be disabled before making changes and reenabled after the modifications | 160 | /// Driver should be disabled before making changes and re-enabled after the modifications |
| 161 | /// are applied. | 161 | /// are applied. |
| 162 | fn apply_config(inner: &Peri<'d, T>, config: &Config) { | 162 | fn apply_config(inner: &Peri<'d, T>, config: &Config) { |
| 163 | let p = inner.regs(); | 163 | let p = inner.regs(); |
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 43187df2d..8be87a5d2 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs | |||
| @@ -315,7 +315,7 @@ impl<'d, M: Mode> UartRx<'d, M> { | |||
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | /// Returns Ok(len) if no errors occurred. Returns Err((len, err)) if an error was | 317 | /// Returns Ok(len) if no errors occurred. Returns Err((len, err)) if an error was |
| 318 | /// encountered. in both cases, `len` is the number of *good* bytes copied into | 318 | /// encountered. In both cases, `len` is the number of *good* bytes copied into |
| 319 | /// `buffer`. | 319 | /// `buffer`. |
| 320 | fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, (usize, Error)> { | 320 | fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, (usize, Error)> { |
| 321 | let r = self.info.regs; | 321 | let r = self.info.regs; |
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 9848daf49..000d215b7 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md | |||
| @@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 35 | - feat: stm32/usart: add `eager_reads` option to control if buffered readers return as soon as possible or after more data is available ([#4668](https://github.com/embassy-rs/embassy/pull/4668)) | 35 | - feat: stm32/usart: add `eager_reads` option to control if buffered readers return as soon as possible or after more data is available ([#4668](https://github.com/embassy-rs/embassy/pull/4668)) |
| 36 | - feat: stm32/usart: add `de_assertion_time` and `de_deassertion_time` config options | 36 | - feat: stm32/usart: add `de_assertion_time` and `de_deassertion_time` config options |
| 37 | - change: stm32/uart: BufferedUartRx now returns all available bytes from the internal buffer | 37 | - change: stm32/uart: BufferedUartRx now returns all available bytes from the internal buffer |
| 38 | - change: timer: added output compare values | ||
| 38 | 39 | ||
| 39 | ## 0.4.0 - 2025-08-26 | 40 | ## 0.4.0 - 2025-08-26 |
| 40 | 41 | ||
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index ac039bb0d..7c02e7e62 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs | |||
| @@ -143,20 +143,69 @@ pub enum OutputCompareMode { | |||
| 143 | /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as | 143 | /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as |
| 144 | /// TIMx_CNT>TIMx_CCRx else inactive. | 144 | /// TIMx_CNT>TIMx_CCRx else inactive. |
| 145 | PwmMode2, | 145 | PwmMode2, |
| 146 | // TODO: there's more modes here depending on the chip family. | 146 | |
| 147 | #[cfg(timer_v2)] | ||
| 148 | /// In up-counting mode, the channel is active until a trigger | ||
| 149 | /// event is detected (on tim_trgi signal). Then, a comparison is performed as in PWM | ||
| 150 | /// mode 1 and the channels becomes active again at the next update. In down-counting | ||
| 151 | /// mode, the channel is inactive until a trigger event is detected (on tim_trgi signal). | ||
| 152 | /// Then, a comparison is performed as in PWM mode 1 and the channels becomes | ||
| 153 | /// inactive again at the next update. | ||
| 154 | OnePulseMode1, | ||
| 155 | |||
| 156 | #[cfg(timer_v2)] | ||
| 157 | /// In up-counting mode, the channel is inactive until a | ||
| 158 | /// trigger event is detected (on tim_trgi signal). Then, a comparison is performed as in | ||
| 159 | /// PWM mode 2 and the channels becomes inactive again at the next update. In down | ||
| 160 | /// counting mode, the channel is active until a trigger event is detected (on tim_trgi | ||
| 161 | /// signal). Then, a comparison is performed as in PWM mode 1 and the channels | ||
| 162 | /// becomes active again at the next update. | ||
| 163 | OnePulseMode2, | ||
| 164 | |||
| 165 | #[cfg(timer_v2)] | ||
| 166 | /// Combined PWM mode 1 - tim_oc1ref has the same behavior as in PWM mode 1. | ||
| 167 | /// tim_oc1refc is the logical OR between tim_oc1ref and tim_oc2ref. | ||
| 168 | CombinedPwmMode1, | ||
| 169 | |||
| 170 | #[cfg(timer_v2)] | ||
| 171 | /// Combined PWM mode 2 - tim_oc1ref has the same behavior as in PWM mode 2. | ||
| 172 | /// tim_oc1refc is the logical AND between tim_oc1ref and tim_oc2ref. | ||
| 173 | CombinedPwmMode2, | ||
| 174 | |||
| 175 | #[cfg(timer_v2)] | ||
| 176 | /// tim_oc1ref has the same behavior as in PWM mode 1. tim_oc1refc outputs tim_oc1ref | ||
| 177 | /// when the counter is counting up, tim_oc2ref when it is counting down. | ||
| 178 | AsymmetricPwmMode1, | ||
| 179 | |||
| 180 | #[cfg(timer_v2)] | ||
| 181 | /// tim_oc1ref has the same behavior as in PWM mode 2. tim_oc1refc outputs tim_oc1ref | ||
| 182 | /// when the counter is counting up, tim_oc2ref when it is counting down. | ||
| 183 | AsymmetricPwmMode2, | ||
| 147 | } | 184 | } |
| 148 | 185 | ||
| 149 | impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { | 186 | impl From<OutputCompareMode> for crate::pac::timer::vals::Ocm { |
| 150 | fn from(mode: OutputCompareMode) -> Self { | 187 | fn from(mode: OutputCompareMode) -> Self { |
| 151 | match mode { | 188 | match mode { |
| 152 | OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN, | 189 | OutputCompareMode::Frozen => crate::pac::timer::vals::Ocm::FROZEN, |
| 153 | OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVE_ON_MATCH, | 190 | OutputCompareMode::ActiveOnMatch => crate::pac::timer::vals::Ocm::ACTIVE_ON_MATCH, |
| 154 | OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVE_ON_MATCH, | 191 | OutputCompareMode::InactiveOnMatch => crate::pac::timer::vals::Ocm::INACTIVE_ON_MATCH, |
| 155 | OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE, | 192 | OutputCompareMode::Toggle => crate::pac::timer::vals::Ocm::TOGGLE, |
| 156 | OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCE_INACTIVE, | 193 | OutputCompareMode::ForceInactive => crate::pac::timer::vals::Ocm::FORCE_INACTIVE, |
| 157 | OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCE_ACTIVE, | 194 | OutputCompareMode::ForceActive => crate::pac::timer::vals::Ocm::FORCE_ACTIVE, |
| 158 | OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWM_MODE1, | 195 | OutputCompareMode::PwmMode1 => crate::pac::timer::vals::Ocm::PWM_MODE1, |
| 159 | OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWM_MODE2, | 196 | OutputCompareMode::PwmMode2 => crate::pac::timer::vals::Ocm::PWM_MODE2, |
| 197 | #[cfg(timer_v2)] | ||
| 198 | OutputCompareMode::OnePulseMode1 => crate::pac::timer::vals::Ocm::RETRIGERRABLE_OPM_MODE_1, | ||
| 199 | #[cfg(timer_v2)] | ||
| 200 | OutputCompareMode::OnePulseMode2 => crate::pac::timer::vals::Ocm::RETRIGERRABLE_OPM_MODE_2, | ||
| 201 | #[cfg(timer_v2)] | ||
| 202 | OutputCompareMode::CombinedPwmMode1 => crate::pac::timer::vals::Ocm::COMBINED_PWM_MODE_1, | ||
| 203 | #[cfg(timer_v2)] | ||
| 204 | OutputCompareMode::CombinedPwmMode2 => crate::pac::timer::vals::Ocm::COMBINED_PWM_MODE_2, | ||
| 205 | #[cfg(timer_v2)] | ||
| 206 | OutputCompareMode::AsymmetricPwmMode1 => crate::pac::timer::vals::Ocm::ASYMMETRIC_PWM_MODE_1, | ||
| 207 | #[cfg(timer_v2)] | ||
| 208 | OutputCompareMode::AsymmetricPwmMode2 => crate::pac::timer::vals::Ocm::ASYMMETRIC_PWM_MODE_2, | ||
| 160 | } | 209 | } |
| 161 | } | 210 | } |
| 162 | } | 211 | } |
diff --git a/examples/nrf52840/src/bin/i2s_monitor.rs b/examples/nrf52840/src/bin/i2s_monitor.rs index 66b429b09..a54659101 100644 --- a/examples/nrf52840/src/bin/i2s_monitor.rs +++ b/examples/nrf52840/src/bin/i2s_monitor.rs | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | use defmt::{debug, error, info}; | 4 | use defmt::{debug, error, info}; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, I2S, MasterClock, Sample as _, SampleWidth}; | 6 | use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, I2S, MasterClock, Sample as _, SampleWidth}; |
| 7 | use embassy_nrf::pwm::{Prescaler, SimplePwm}; | 7 | use embassy_nrf::pwm::{DutyCycle, Prescaler, SimplePwm}; |
| 8 | use embassy_nrf::{bind_interrupts, peripherals}; | 8 | use embassy_nrf::{bind_interrupts, peripherals}; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| 10 | 10 | ||
| @@ -34,7 +34,7 @@ async fn main(_spawner: Spawner) { | |||
| 34 | I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config).input(p.P0_29, buffers); | 34 | I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config).input(p.P0_29, buffers); |
| 35 | 35 | ||
| 36 | // Configure the PWM to use the pins corresponding to the RGB leds | 36 | // Configure the PWM to use the pins corresponding to the RGB leds |
| 37 | let mut pwm = SimplePwm::new_3ch(p.PWM0, p.P0_23, p.P0_22, p.P0_24); | 37 | let mut pwm = SimplePwm::new_3ch(p.PWM0, p.P0_23, p.P0_22, p.P0_24, &Default::default()); |
| 38 | pwm.set_prescaler(Prescaler::Div1); | 38 | pwm.set_prescaler(Prescaler::Div1); |
| 39 | pwm.set_max_duty(255); | 39 | pwm.set_max_duty(255); |
| 40 | 40 | ||
| @@ -47,9 +47,8 @@ async fn main(_spawner: Spawner) { | |||
| 47 | let rgb = rgb_from_rms(rms); | 47 | let rgb = rgb_from_rms(rms); |
| 48 | 48 | ||
| 49 | debug!("RMS: {}, RGB: {:?}", rms, rgb); | 49 | debug!("RMS: {}, RGB: {:?}", rms, rgb); |
| 50 | for i in 0..3 { | 50 | let duties = rgb.map(|byte| DutyCycle::normal(u16::from(byte))); |
| 51 | pwm.set_duty(i, rgb[i].into()); | 51 | pwm.set_all_duties([duties[0], duties[1], duties[2], DutyCycle::normal(0)]); |
| 52 | } | ||
| 53 | 52 | ||
| 54 | if let Err(err) = input_stream.receive().await { | 53 | if let Err(err) = input_stream.receive().await { |
| 55 | error!("{}", err); | 54 | error!("{}", err); |
diff --git a/examples/nrf52840/src/bin/pwm.rs b/examples/nrf52840/src/bin/pwm.rs index a5bb1347a..02f9b4191 100644 --- a/examples/nrf52840/src/bin/pwm.rs +++ b/examples/nrf52840/src/bin/pwm.rs | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_nrf::pwm::{Prescaler, SimplePwm}; | 6 | use embassy_nrf::pwm::{DutyCycle, Prescaler, SimplePwm}; |
| 7 | use embassy_time::Timer; | 7 | use embassy_time::Timer; |
| 8 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {defmt_rtt as _, panic_probe as _}; |
| 9 | 9 | ||
| @@ -71,7 +71,7 @@ static DUTY: [u16; 1024] = [ | |||
| 71 | #[embassy_executor::main] | 71 | #[embassy_executor::main] |
| 72 | async fn main(_spawner: Spawner) { | 72 | async fn main(_spawner: Spawner) { |
| 73 | let p = embassy_nrf::init(Default::default()); | 73 | let p = embassy_nrf::init(Default::default()); |
| 74 | let mut pwm = SimplePwm::new_4ch(p.PWM0, p.P0_13, p.P0_14, p.P0_16, p.P0_15); | 74 | let mut pwm = SimplePwm::new_4ch(p.PWM0, p.P0_13, p.P0_14, p.P0_16, p.P0_15, &Default::default()); |
| 75 | pwm.set_prescaler(Prescaler::Div1); | 75 | pwm.set_prescaler(Prescaler::Div1); |
| 76 | pwm.set_max_duty(32767); | 76 | pwm.set_max_duty(32767); |
| 77 | info!("pwm initialized!"); | 77 | info!("pwm initialized!"); |
| @@ -79,10 +79,12 @@ async fn main(_spawner: Spawner) { | |||
| 79 | let mut i = 0; | 79 | let mut i = 0; |
| 80 | loop { | 80 | loop { |
| 81 | i += 1; | 81 | i += 1; |
| 82 | pwm.set_duty(0, DUTY[i % 1024]); | 82 | pwm.set_all_duties([ |
| 83 | pwm.set_duty(1, DUTY[(i + 256) % 1024]); | 83 | DutyCycle::normal(DUTY[i % 1024]), |
| 84 | pwm.set_duty(2, DUTY[(i + 512) % 1024]); | 84 | DutyCycle::normal(DUTY[(i + 256) % 1024]), |
| 85 | pwm.set_duty(3, DUTY[(i + 768) % 1024]); | 85 | DutyCycle::normal(DUTY[(i + 512) % 1024]), |
| 86 | DutyCycle::normal(DUTY[(i + 768) % 1024]), | ||
| 87 | ]); | ||
| 86 | Timer::after_millis(3).await; | 88 | Timer::after_millis(3).await; |
| 87 | } | 89 | } |
| 88 | } | 90 | } |
diff --git a/examples/nrf52840/src/bin/pwm_servo.rs b/examples/nrf52840/src/bin/pwm_servo.rs index d772d2f5d..93cb984e6 100644 --- a/examples/nrf52840/src/bin/pwm_servo.rs +++ b/examples/nrf52840/src/bin/pwm_servo.rs | |||
| @@ -3,14 +3,14 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_nrf::pwm::{Prescaler, SimplePwm}; | 6 | use embassy_nrf::pwm::{DutyCycle, Prescaler, SimplePwm}; |
| 7 | use embassy_time::Timer; | 7 | use embassy_time::Timer; |
| 8 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {defmt_rtt as _, panic_probe as _}; |
| 9 | 9 | ||
| 10 | #[embassy_executor::main] | 10 | #[embassy_executor::main] |
| 11 | async fn main(_spawner: Spawner) { | 11 | async fn main(_spawner: Spawner) { |
| 12 | let p = embassy_nrf::init(Default::default()); | 12 | let p = embassy_nrf::init(Default::default()); |
| 13 | let mut pwm = SimplePwm::new_1ch(p.PWM0, p.P0_05); | 13 | let mut pwm = SimplePwm::new_1ch(p.PWM0, p.P0_05, &Default::default()); |
| 14 | // sg90 microervo requires 50hz or 20ms period | 14 | // sg90 microervo requires 50hz or 20ms period |
| 15 | // set_period can only set down to 125khz so we cant use it directly | 15 | // set_period can only set down to 125khz so we cant use it directly |
| 16 | // Div128 is 125khz or 0.000008s or 0.008ms, 20/0.008 is 2500 is top | 16 | // Div128 is 125khz or 0.000008s or 0.008ms, 20/0.008 is 2500 is top |
| @@ -24,23 +24,23 @@ async fn main(_spawner: Spawner) { | |||
| 24 | loop { | 24 | loop { |
| 25 | info!("45 deg"); | 25 | info!("45 deg"); |
| 26 | // poor mans inverting, subtract our value from max_duty | 26 | // poor mans inverting, subtract our value from max_duty |
| 27 | pwm.set_duty(0, 2500 - 156); | 27 | pwm.set_duty(0, DutyCycle::normal(2500 - 156)); |
| 28 | Timer::after_millis(5000).await; | 28 | Timer::after_millis(5000).await; |
| 29 | 29 | ||
| 30 | info!("90 deg"); | 30 | info!("90 deg"); |
| 31 | pwm.set_duty(0, 2500 - 187); | 31 | pwm.set_duty(0, DutyCycle::normal(2500 - 187)); |
| 32 | Timer::after_millis(5000).await; | 32 | Timer::after_millis(5000).await; |
| 33 | 33 | ||
| 34 | info!("135 deg"); | 34 | info!("135 deg"); |
| 35 | pwm.set_duty(0, 2500 - 218); | 35 | pwm.set_duty(0, DutyCycle::normal(2500 - 218)); |
| 36 | Timer::after_millis(5000).await; | 36 | Timer::after_millis(5000).await; |
| 37 | 37 | ||
| 38 | info!("180 deg"); | 38 | info!("180 deg"); |
| 39 | pwm.set_duty(0, 2500 - 250); | 39 | pwm.set_duty(0, DutyCycle::normal(2500 - 250)); |
| 40 | Timer::after_millis(5000).await; | 40 | Timer::after_millis(5000).await; |
| 41 | 41 | ||
| 42 | info!("0 deg"); | 42 | info!("0 deg"); |
| 43 | pwm.set_duty(0, 2500 - 125); | 43 | pwm.set_duty(0, DutyCycle::normal(2500 - 125)); |
| 44 | Timer::after_millis(5000).await; | 44 | Timer::after_millis(5000).await; |
| 45 | } | 45 | } |
| 46 | } | 46 | } |
