aboutsummaryrefslogtreecommitdiff
path: root/embassy-nrf
diff options
context:
space:
mode:
authorMaarten de Vries <[email protected]>2025-10-15 12:01:18 +0200
committerMaarten de Vries <[email protected]>2025-10-15 14:42:08 +0200
commit9c66ec1589ae2e55817e03d9e2bb8666050d054c (patch)
tree37c8ea7eb56e1a0853c71df4defcd7c6fd008d28 /embassy-nrf
parentb2dce7a67e0dc18c568da5758190e23778d025ef (diff)
embassy_nrf::pwm: add channel idle level to config
Diffstat (limited to 'embassy-nrf')
-rw-r--r--embassy-nrf/src/pwm.rs85
1 files changed, 35 insertions, 50 deletions
diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs
index 7fbe9be9d..6743674e8 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
7use embassy_hal_internal::{Peri, PeripheralType}; 7use embassy_hal_internal::{Peri, PeripheralType};
8 8
9use crate::gpio::{AnyPin, DISCONNECTED, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _, convert_drive}; 9use crate::gpio::{AnyPin, DISCONNECTED, Level, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _, convert_drive};
10use crate::pac::gpio::vals as gpiovals; 10use crate::pac::gpio::vals as gpiovals;
11use crate::pac::pwm::vals; 11use crate::pac::pwm::vals;
12use crate::ppi::{Event, Task}; 12use crate::ppi::{Event, Task};
@@ -53,13 +53,11 @@ pub const PWM_CLK_HZ: u32 = 16_000_000;
53 53
54impl<'d> SequencePwm<'d> { 54impl<'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.
@@ -309,11 +282,19 @@ pub struct Config {
309 pub ch2_drive: OutputDrive, 282 pub ch2_drive: OutputDrive,
310 /// Drive strength for the channel 3 line. 283 /// Drive strength for the channel 3 line.
311 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,
312} 293}
313 294
314impl Default for Config { 295impl Default for Config {
315 fn default() -> Config { 296 fn default() -> Self {
316 Config { 297 Self {
317 counter_mode: CounterMode::Up, 298 counter_mode: CounterMode::Up,
318 max_duty: 1000, 299 max_duty: 1000,
319 prescaler: Prescaler::Div16, 300 prescaler: Prescaler::Div16,
@@ -322,6 +303,10 @@ impl Default for Config {
322 ch1_drive: OutputDrive::Standard, 303 ch1_drive: OutputDrive::Standard,
323 ch2_drive: OutputDrive::Standard, 304 ch2_drive: OutputDrive::Standard,
324 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,
325 } 310 }
326 } 311 }
327} 312}