aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Rosenthal <[email protected]>2021-10-26 00:37:52 -0700
committerJacob Rosenthal <[email protected]>2021-10-29 16:27:26 -0700
commiteb0bf1fd7a33330425a12420e5d948ca6e88d74f (patch)
treed1d93ce868c98f6411b5fa6881a6f54c43a24f30
parentdfccb84fcbb9ab55c3d0f89d99d2049376bff901 (diff)
simple_playback api from nrf sdk
-rw-r--r--embassy-nrf/src/pwm.rs167
-rw-r--r--embassy-nrf/src/util.rs4
-rw-r--r--examples/nrf/src/bin/pwm_sequence.rs41
3 files changed, 207 insertions, 5 deletions
diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs
index 5e996e882..ccab6f48d 100644
--- a/embassy-nrf/src/pwm.rs
+++ b/embassy-nrf/src/pwm.rs
@@ -9,7 +9,8 @@ use embassy_hal_common::unborrow;
9use crate::gpio::sealed::Pin as _; 9use crate::gpio::sealed::Pin as _;
10use crate::gpio::OptionalPin as GpioOptionalPin; 10use crate::gpio::OptionalPin as GpioOptionalPin;
11use crate::interrupt::Interrupt; 11use crate::interrupt::Interrupt;
12use crate::pac; 12use crate::util::slice_in_ram_or;
13use crate::{pac, EASY_DMA_SIZE};
13 14
14#[derive(Debug, Eq, PartialEq, Clone, Copy)] 15#[derive(Debug, Eq, PartialEq, Clone, Copy)]
15pub enum Prescaler { 16pub enum Prescaler {
@@ -23,11 +24,57 @@ pub enum Prescaler {
23 Div128, 24 Div128,
24} 25}
25 26
26/// Interface to the UARTE peripheral 27#[derive(Debug, Eq, PartialEq, Clone, Copy)]
28pub enum SequenceLoad {
29 Common,
30 Grouped,
31 Individual,
32 Waveform,
33}
34
35#[derive(Debug, Eq, PartialEq, Clone, Copy)]
36pub enum CounterMode {
37 Up,
38 UpAndDown,
39}
40
41/// Interface to the PWM peripheral
27pub struct Pwm<'d, T: Instance> { 42pub struct Pwm<'d, T: Instance> {
28 phantom: PhantomData<&'d mut T>, 43 phantom: PhantomData<&'d mut T>,
29} 44}
30 45
46// Configure an infinite looping sequence for `simple_playback`
47pub struct LoopingConfig<'a> {
48 /// Selects up mode or up-and-down mode for the counter
49 pub counter_mode: CounterMode,
50 // top value to be compared against buffer values
51 pub top: u16,
52 /// Configuration for PWM_CLK
53 pub prescaler: Prescaler,
54 /// In ram buffer to be played back
55 pub sequence: &'a [u16],
56 /// Common Mode means seq in buffer will be used across all channels
57 /// Individual Mode buffer holds [ch0_0, ch1_0, ch2_0, ch3_0, ch0_1, ch1_1,
58 /// ch2_1, ch3_1 ... ch0_n, ch1_n, ch2_n, ch3_n]
59 pub sequence_load: SequenceLoad,
60 /// will instruct a new RAM stored pulse width value on every (N+1)th PWM
61 /// period. Setting the register to zero will result in a new duty cycle
62 /// update every PWM period as long as the minimum PWM period is observed.
63 pub repeats: u32,
64 /// enddelay PWM period delays between last period on sequence 0 before repeating
65 pub enddelay: u32,
66}
67
68#[derive(Debug, Clone, Copy, PartialEq, Eq)]
69#[cfg_attr(feature = "defmt", derive(defmt::Format))]
70#[non_exhaustive]
71pub enum Error {
72 Seq0BufferTooLong,
73 Seq1BufferTooLong,
74 /// EasyDMA can only read from data memory, read only buffers in flash will fail.
75 DMABufferNotInDataMemory,
76}
77
31impl<'d, T: Instance> Pwm<'d, T> { 78impl<'d, T: Instance> Pwm<'d, T> {
32 /// Creates the interface to a UARTE instance. 79 /// Creates the interface to a UARTE instance.
33 /// Sets the baud rate, parity and assigns the pins to the UARTE peripheral. 80 /// Sets the baud rate, parity and assigns the pins to the UARTE peripheral.
@@ -99,6 +146,120 @@ impl<'d, T: Instance> Pwm<'d, T> {
99 } 146 }
100 } 147 }
101 148
149 pub fn simple_playback(
150 _pwm: impl Unborrow<Target = T> + 'd,
151 ch0: impl Unborrow<Target = impl GpioOptionalPin> + 'd,
152 ch1: impl Unborrow<Target = impl GpioOptionalPin> + 'd,
153 ch2: impl Unborrow<Target = impl GpioOptionalPin> + 'd,
154 ch3: impl Unborrow<Target = impl GpioOptionalPin> + 'd,
155 config: LoopingConfig,
156 count: u16,
157 ) -> Result<Self, Error> {
158 slice_in_ram_or(config.sequence, Error::DMABufferNotInDataMemory)?;
159
160 if config.sequence.len() > EASY_DMA_SIZE {
161 return Err(Error::Seq0BufferTooLong);
162 }
163
164 unborrow!(ch0, ch1, ch2, ch3);
165
166 let odd: bool = count & 1 == 1;
167
168 let r = T::regs();
169
170 if let Some(pin) = ch0.pin_mut() {
171 pin.set_low();
172 pin.conf().write(|w| w.dir().output());
173 r.psel.out[0].write(|w| unsafe { w.bits(ch0.psel_bits()) });
174 }
175 if let Some(pin) = ch1.pin_mut() {
176 pin.set_low();
177 pin.conf().write(|w| w.dir().output());
178 r.psel.out[1].write(|w| unsafe { w.bits(ch1.psel_bits()) });
179 }
180 if let Some(pin) = ch2.pin_mut() {
181 pin.set_low();
182 pin.conf().write(|w| w.dir().output());
183 r.psel.out[2].write(|w| unsafe { w.bits(ch2.psel_bits()) });
184 }
185 if let Some(pin) = ch3.pin_mut() {
186 pin.set_low();
187 pin.conf().write(|w| w.dir().output());
188 r.psel.out[3].write(|w| unsafe { w.bits(ch3.psel_bits()) });
189 }
190
191 r.enable.write(|w| w.enable().enabled());
192
193 r.mode
194 .write(|w| unsafe { w.bits(config.counter_mode as u32) });
195 r.prescaler
196 .write(|w| w.prescaler().bits(config.prescaler as u8));
197 r.countertop
198 .write(|w| unsafe { w.countertop().bits(config.top) });
199
200 r.decoder.write(|w| {
201 w.load().bits(config.sequence_load as u8);
202 w.mode().refresh_count()
203 });
204
205 r.seq0
206 .ptr
207 .write(|w| unsafe { w.bits(config.sequence.as_ptr() as u32) });
208 r.seq0
209 .cnt
210 .write(|w| unsafe { w.bits(config.sequence.len() as u32) });
211 r.seq0.refresh.write(|w| unsafe { w.bits(config.repeats) });
212 r.seq0
213 .enddelay
214 .write(|w| unsafe { w.bits(config.enddelay) });
215
216 r.seq1
217 .ptr
218 .write(|w| unsafe { w.bits(config.sequence.as_ptr() as u32) });
219 r.seq1
220 .cnt
221 .write(|w| unsafe { w.bits(config.sequence.len() as u32) });
222 r.seq1.refresh.write(|w| unsafe { w.bits(config.repeats) });
223 r.seq1
224 .enddelay
225 .write(|w| unsafe { w.bits(config.enddelay) });
226
227 let mut loop_: u16 = count / 2;
228 if odd {
229 loop_ += 1;
230 }
231
232 r.loop_.write(|w| unsafe { w.cnt().bits(loop_) });
233
234 if odd {
235 r.shorts.write(|w| w.loopsdone_seqstart1().set_bit());
236 } else {
237 r.shorts.write(|w| w.loopsdone_seqstart0().set_bit());
238 }
239
240 // tasks_seqstart doesnt exist in all svds so write its bit instead
241 if odd {
242 r.tasks_seqstart[1].write(|w| unsafe { w.bits(0x01) });
243 } else {
244 r.tasks_seqstart[0].write(|w| unsafe { w.bits(0x01) });
245 }
246
247 Ok(Self {
248 phantom: PhantomData,
249 })
250 }
251
252 /// Stop playback
253 #[inline(always)]
254 pub fn stop(&self) {
255 let r = T::regs();
256
257 r.shorts.write(|w| unsafe { w.bits(0x0) });
258
259 // tasks_stop doesnt exist in all svds so write its bit instead
260 r.tasks_stop.write(|w| unsafe { w.bits(0x01) });
261 }
262
102 /// Enables the PWM generator. 263 /// Enables the PWM generator.
103 #[inline(always)] 264 #[inline(always)]
104 pub fn enable(&self) { 265 pub fn enable(&self) {
@@ -128,7 +289,7 @@ impl<'d, T: Instance> Pwm<'d, T> {
128 T::regs().prescaler.write(|w| w.prescaler().bits(div as u8)); 289 T::regs().prescaler.write(|w| w.prescaler().bits(div as u8));
129 } 290 }
130 291
131 /// Sets the PWM clock prescaler. 292 /// Gets the PWM clock prescaler.
132 #[inline(always)] 293 #[inline(always)]
133 pub fn prescaler(&self) -> Prescaler { 294 pub fn prescaler(&self) -> Prescaler {
134 match T::regs().prescaler.read().prescaler().bits() { 295 match T::regs().prescaler.read().prescaler().bits() {
diff --git a/embassy-nrf/src/util.rs b/embassy-nrf/src/util.rs
index 344fb01f9..d17ec5032 100644
--- a/embassy-nrf/src/util.rs
+++ b/embassy-nrf/src/util.rs
@@ -2,14 +2,14 @@ const SRAM_LOWER: usize = 0x2000_0000;
2const SRAM_UPPER: usize = 0x3000_0000; 2const SRAM_UPPER: usize = 0x3000_0000;
3 3
4/// Does this slice reside entirely within RAM? 4/// Does this slice reside entirely within RAM?
5pub(crate) fn slice_in_ram(slice: &[u8]) -> bool { 5pub(crate) fn slice_in_ram<T>(slice: &[T]) -> bool {
6 let ptr = slice.as_ptr() as usize; 6 let ptr = slice.as_ptr() as usize;
7 ptr >= SRAM_LOWER && (ptr + slice.len()) < SRAM_UPPER 7 ptr >= SRAM_LOWER && (ptr + slice.len()) < SRAM_UPPER
8} 8}
9 9
10/// Return an error if slice is not in RAM. 10/// Return an error if slice is not in RAM.
11#[cfg(not(feature = "nrf51"))] 11#[cfg(not(feature = "nrf51"))]
12pub(crate) fn slice_in_ram_or<T>(slice: &[u8], err: T) -> Result<(), T> { 12pub(crate) fn slice_in_ram_or<T, E>(slice: &[T], err: E) -> Result<(), E> {
13 if slice.len() == 0 || slice_in_ram(slice) { 13 if slice.len() == 0 || slice_in_ram(slice) {
14 Ok(()) 14 Ok(())
15 } else { 15 } else {
diff --git a/examples/nrf/src/bin/pwm_sequence.rs b/examples/nrf/src/bin/pwm_sequence.rs
new file mode 100644
index 000000000..93ee9f5b2
--- /dev/null
+++ b/examples/nrf/src/bin/pwm_sequence.rs
@@ -0,0 +1,41 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5#[path = "../example_common.rs"]
6mod example_common;
7use defmt::*;
8use embassy::executor::Spawner;
9use embassy::time::{Duration, Timer};
10use embassy_nrf::gpio::NoPin;
11use embassy_nrf::pwm::{CounterMode, LoopingConfig, Prescaler, Pwm, SequenceLoad};
12use embassy_nrf::Peripherals;
13
14#[embassy::main]
15async fn main(_spawner: Spawner, p: Peripherals) {
16 let seq_values: [u16; 2] = [0, 0x8000];
17
18 let config = LoopingConfig {
19 counter_mode: CounterMode::Up,
20 top: 31250,
21 prescaler: Prescaler::Div128,
22 sequence: &seq_values,
23 sequence_load: SequenceLoad::Common,
24 repeats: 1,
25 enddelay: 0,
26 };
27
28 let pwm = unwrap!(Pwm::simple_playback(
29 p.PWM0, p.P0_13, NoPin, NoPin, NoPin, config, 1
30 ));
31 info!("pwm started!");
32
33 Timer::after(Duration::from_millis(10000)).await;
34
35 pwm.stop();
36 info!("pwm stopped!");
37
38 loop {
39 Timer::after(Duration::from_millis(1000)).await;
40 }
41}