aboutsummaryrefslogtreecommitdiff
path: root/embassy-nrf
diff options
context:
space:
mode:
authorChristian Perez Llamas <[email protected]>2022-11-12 18:48:57 +0100
committerChristian Perez Llamas <[email protected]>2022-11-12 18:48:57 +0100
commit122a31d20877005c7201d4e7c98da5544666dd1d (patch)
treec97037ba880f63a4e03e642c6630efb1042a3cde /embassy-nrf
parent10e3c3f2ec358da6d81f2bb9c05936c2ab6da567 (diff)
Interrupts, async, sine oscillator
Diffstat (limited to 'embassy-nrf')
-rw-r--r--embassy-nrf/src/i2s.rs296
-rw-r--r--embassy-nrf/src/lib.rs2
2 files changed, 218 insertions, 80 deletions
diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs
index fb6fa4bdf..f5e36f0dd 100644
--- a/embassy-nrf/src/i2s.rs
+++ b/embassy-nrf/src/i2s.rs
@@ -2,17 +2,18 @@
2 2
3//! I2S 3//! I2S
4 4
5//use core::future::poll_fn; 5use core::future::poll_fn;
6//use core::sync::atomic::{compiler_fence, Ordering}; 6use core::sync::atomic::{compiler_fence, Ordering};
7//use core::task::Poll; 7use core::task::Poll;
8 8
9//use embassy_hal_common::drop::OnDrop; 9use embassy_cortex_m::interrupt::{InterruptExt, Priority};
10use embassy_hal_common::drop::OnDrop;
10use embassy_hal_common::{into_ref, PeripheralRef}; 11use embassy_hal_common::{into_ref, PeripheralRef};
11 12
12//use crate::gpio::sealed::Pin as _; 13//use crate::gpio::sealed::Pin as _;
13use crate::gpio::{AnyPin, Pin as GpioPin}; 14use crate::gpio::{AnyPin, Pin as GpioPin};
14use crate::interrupt::Interrupt; 15use crate::interrupt::Interrupt;
15use crate::pac::i2s::CONFIG; 16use crate::pac::i2s::{RegisterBlock, CONFIG, PSEL};
16use crate::Peripheral; 17use crate::Peripheral;
17 18
18// TODO: Define those in lib.rs somewhere else 19// TODO: Define those in lib.rs somewhere else
@@ -35,10 +36,39 @@ pub enum Error {
35 // TODO: add other error variants. 36 // TODO: add other error variants.
36} 37}
37 38
39pub const MODE_MASTER_8000: Mode = Mode::Master {
40 freq: MckFreq::_32MDiv125,
41 ratio: Ratio::_32x,
42}; // error = 0
43pub const MODE_MASTER_11025: Mode = Mode::Master {
44 freq: MckFreq::_32MDiv15,
45 ratio: Ratio::_192x,
46}; // error = 86
47pub const MODE_MASTER_16000: Mode = Mode::Master {
48 freq: MckFreq::_32MDiv21,
49 ratio: Ratio::_96x,
50}; // error = 127
51pub const MODE_MASTER_22050: Mode = Mode::Master {
52 freq: MckFreq::_32MDiv15,
53 ratio: Ratio::_96x,
54}; // error = 172
55pub const MODE_MASTER_32000: Mode = Mode::Master {
56 freq: MckFreq::_32MDiv21,
57 ratio: Ratio::_48x,
58}; // error = 254
59pub const MODE_MASTER_44100: Mode = Mode::Master {
60 freq: MckFreq::_32MDiv15,
61 ratio: Ratio::_48x,
62}; // error = 344
63pub const MODE_MASTER_48000: Mode = Mode::Master {
64 freq: MckFreq::_32MDiv21,
65 ratio: Ratio::_32x,
66}; // error = 381
67
38#[derive(Clone)] 68#[derive(Clone)]
39#[non_exhaustive] 69#[non_exhaustive]
40pub struct Config { 70pub struct Config {
41 pub ratio: Ratio, 71 pub mode: Mode,
42 pub swidth: SampleWidth, 72 pub swidth: SampleWidth,
43 pub align: Align, 73 pub align: Align,
44 pub format: Format, 74 pub format: Format,
@@ -48,7 +78,7 @@ pub struct Config {
48impl Default for Config { 78impl Default for Config {
49 fn default() -> Self { 79 fn default() -> Self {
50 Self { 80 Self {
51 ratio: Ratio::_32x, 81 mode: MODE_MASTER_32000,
52 swidth: SampleWidth::_16bit, 82 swidth: SampleWidth::_16bit,
53 align: Align::Left, 83 align: Align::Left,
54 format: Format::I2S, 84 format: Format::I2S,
@@ -57,6 +87,66 @@ impl Default for Config {
57 } 87 }
58} 88}
59 89
90/// I2S Mode
91#[derive(Debug, Eq, PartialEq, Clone, Copy)]
92pub enum Mode {
93 Master { freq: MckFreq, ratio: Ratio },
94 Slave,
95}
96
97impl Mode {
98 pub fn sample_rate(&self) -> Option<u32> {
99 match self {
100 Mode::Master { freq, ratio } => Some(freq.to_frequency() / ratio.to_divisor()),
101 Mode::Slave => None,
102 }
103 }
104}
105
106/// Master clock generator frequency.
107#[derive(Debug, Eq, PartialEq, Clone, Copy)]
108pub enum MckFreq {
109 _32MDiv8,
110 _32MDiv10,
111 _32MDiv11,
112 _32MDiv15,
113 _32MDiv16,
114 _32MDiv21,
115 _32MDiv23,
116 _32MDiv30,
117 _32MDiv31,
118 _32MDiv32,
119 _32MDiv42,
120 _32MDiv63,
121 _32MDiv125,
122}
123
124impl MckFreq {
125 const REGISTER_VALUES: &[u32] = &[
126 0x20000000, 0x18000000, 0x16000000, 0x11000000, 0x10000000, 0x0C000000, 0x0B000000, 0x08800000, 0x08400000,
127 0x08000000, 0x06000000, 0x04100000, 0x020C0000,
128 ];
129
130 const FREQUENCIES: &[u32] = &[
131 4000000, 3200000, 2909090, 2133333, 2000000, 1523809, 1391304, 1066666, 1032258, 1000000, 761904, 507936,
132 256000,
133 ];
134
135 pub fn to_register_value(&self) -> u32 {
136 Self::REGISTER_VALUES[usize::from(*self)]
137 }
138
139 pub fn to_frequency(&self) -> u32 {
140 Self::FREQUENCIES[usize::from(*self)]
141 }
142}
143
144impl From<MckFreq> for usize {
145 fn from(variant: MckFreq) -> Self {
146 variant as _
147 }
148}
149
60/// MCK / LRCK ratio. 150/// MCK / LRCK ratio.
61#[derive(Debug, Eq, PartialEq, Clone, Copy)] 151#[derive(Debug, Eq, PartialEq, Clone, Copy)]
62pub enum Ratio { 152pub enum Ratio {
@@ -71,6 +161,14 @@ pub enum Ratio {
71 _512x, 161 _512x,
72} 162}
73 163
164impl Ratio {
165 const RATIOS: &[u32] = &[32, 48, 64, 96, 128, 192, 256, 384, 512];
166
167 pub fn to_divisor(&self) -> u32 {
168 Self::RATIOS[u8::from(*self) as usize]
169 }
170}
171
74impl From<Ratio> for u8 { 172impl From<Ratio> for u8 {
75 fn from(variant: Ratio) -> Self { 173 fn from(variant: Ratio) -> Self {
76 variant as _ 174 variant as _
@@ -136,31 +234,6 @@ impl From<Channels> for u8 {
136 } 234 }
137} 235}
138 236
139/// I2S Mode
140#[derive(Debug, Eq, PartialEq, Clone, Copy)]
141pub enum Mode {
142 Controller,
143 Peripheral,
144}
145
146// /// Master clock generator frequency.
147// #[derive(Debug, Eq, PartialEq, Clone, Copy)]
148// pub enum MckFreq {
149// _32MDiv8 = 0x20000000,
150// _32MDiv10 = 0x18000000,
151// _32MDiv11 = 0x16000000,
152// _32MDiv15 = 0x11000000,
153// _32MDiv16 = 0x10000000,
154// _32MDiv21 = 0x0C000000,
155// _32MDiv23 = 0x0B000000,
156// _32MDiv30 = 0x08800000,
157// _32MDiv31 = 0x08400000,
158// _32MDiv32 = 0x08000000,
159// _32MDiv42 = 0x06000000,
160// _32MDiv63 = 0x04100000,
161// _32MDiv125 = 0x020C0000,
162// }
163
164/// Interface to the UARTE peripheral using EasyDMA to offload the transmission and reception workload. 237/// Interface to the UARTE peripheral using EasyDMA to offload the transmission and reception workload.
165/// 238///
166/// For more details about EasyDMA, consult the module documentation. 239/// For more details about EasyDMA, consult the module documentation.
@@ -185,7 +258,7 @@ impl<'d, T: Instance> I2S<'d, T> {
185 /// Create a new I2S 258 /// Create a new I2S
186 pub fn new( 259 pub fn new(
187 i2s: impl Peripheral<P = T> + 'd, 260 i2s: impl Peripheral<P = T> + 'd,
188 // irq: impl Peripheral<P = T::Interrupt> + 'd, 261 irq: impl Peripheral<P = T::Interrupt> + 'd,
189 mck: impl Peripheral<P = impl GpioPin> + 'd, 262 mck: impl Peripheral<P = impl GpioPin> + 'd,
190 sck: impl Peripheral<P = impl GpioPin> + 'd, 263 sck: impl Peripheral<P = impl GpioPin> + 'd,
191 lrck: impl Peripheral<P = impl GpioPin> + 'd, 264 lrck: impl Peripheral<P = impl GpioPin> + 'd,
@@ -196,7 +269,7 @@ impl<'d, T: Instance> I2S<'d, T> {
196 into_ref!(mck, sck, lrck, sdin, sdout); 269 into_ref!(mck, sck, lrck, sdin, sdout);
197 Self::new_inner( 270 Self::new_inner(
198 i2s, 271 i2s,
199 // irq, 272 irq,
200 mck.map_into(), 273 mck.map_into(),
201 sck.map_into(), 274 sck.map_into(),
202 lrck.map_into(), 275 lrck.map_into(),
@@ -208,7 +281,7 @@ impl<'d, T: Instance> I2S<'d, T> {
208 281
209 fn new_inner( 282 fn new_inner(
210 i2s: impl Peripheral<P = T> + 'd, 283 i2s: impl Peripheral<P = T> + 'd,
211 // irq: impl Peripheral<P = T::Interrupt> + 'd, 284 irq: impl Peripheral<P = T::Interrupt> + 'd,
212 mck: PeripheralRef<'d, AnyPin>, 285 mck: PeripheralRef<'d, AnyPin>,
213 sck: PeripheralRef<'d, AnyPin>, 286 sck: PeripheralRef<'d, AnyPin>,
214 lrck: PeripheralRef<'d, AnyPin>, 287 lrck: PeripheralRef<'d, AnyPin>,
@@ -216,36 +289,12 @@ impl<'d, T: Instance> I2S<'d, T> {
216 sdout: PeripheralRef<'d, AnyPin>, 289 sdout: PeripheralRef<'d, AnyPin>,
217 config: Config, 290 config: Config,
218 ) -> Self { 291 ) -> Self {
219 into_ref!(i2s, /* irq, */ mck, sck, lrck, sdin, sdout); 292 into_ref!(i2s, irq, mck, sck, lrck, sdin, sdout);
220 293
221 let r = T::regs(); 294 let r = T::regs();
222
223 Self::apply_config(&r.config, &config); 295 Self::apply_config(&r.config, &config);
224 296 Self::select_pins(&r.psel, mck, sck, lrck, sdin, sdout);
225 r.psel.mck.write(|w| { 297 Self::setup_interrupt(irq, r);
226 unsafe { w.bits(mck.psel_bits()) };
227 w.connect().connected()
228 });
229
230 r.psel.sck.write(|w| {
231 unsafe { w.bits(sck.psel_bits()) };
232 w.connect().connected()
233 });
234
235 r.psel.lrck.write(|w| {
236 unsafe { w.bits(lrck.psel_bits()) };
237 w.connect().connected()
238 });
239
240 r.psel.sdin.write(|w| {
241 unsafe { w.bits(sdin.psel_bits()) };
242 w.connect().connected()
243 });
244
245 r.psel.sdout.write(|w| {
246 unsafe { w.bits(sdout.psel_bits()) };
247 w.connect().connected()
248 });
249 298
250 r.enable.write(|w| w.enable().enabled()); 299 r.enable.write(|w| w.enable().enabled());
251 300
@@ -322,19 +371,87 @@ impl<'d, T: Instance> I2S<'d, T> {
322 self.input.rx(buffer).await 371 self.input.rx(buffer).await
323 } 372 }
324 373
374 fn on_interrupt(_: *mut ()) {
375 let r = T::regs();
376 let s = T::state();
377
378 if r.events_txptrupd.read().bits() != 0 {
379 s.tx_waker.wake();
380 r.intenclr.write(|w| w.txptrupd().clear());
381 }
382
383 if r.events_rxptrupd.read().bits() != 0 {
384 s.rx_waker.wake();
385 r.intenclr.write(|w| w.rxptrupd().clear());
386 }
387 }
388
325 fn apply_config(c: &CONFIG, config: &Config) { 389 fn apply_config(c: &CONFIG, config: &Config) {
326 // TODO support slave too 390 match config.mode {
327 c.mcken.write(|w| w.mcken().enabled()); 391 Mode::Master { freq, ratio } => {
328 c.mckfreq.write(|w| w.mckfreq()._32mdiv16()); 392 c.mode.write(|w| w.mode().master());
329 c.mode.write(|w| w.mode().master()); 393 c.mcken.write(|w| w.mcken().enabled());
394 c.mckfreq
395 .write(|w| unsafe { w.mckfreq().bits(freq.to_register_value()) });
396 c.ratio.write(|w| unsafe { w.ratio().bits(ratio.into()) });
397 }
398 Mode::Slave => {
399 c.mode.write(|w| w.mode().slave());
400 }
401 };
330 402
331 c.ratio.write(|w| unsafe { w.ratio().bits(config.ratio.into()) });
332 c.swidth.write(|w| unsafe { w.swidth().bits(config.swidth.into()) }); 403 c.swidth.write(|w| unsafe { w.swidth().bits(config.swidth.into()) });
333 c.align.write(|w| w.align().bit(config.align.into())); 404 c.align.write(|w| w.align().bit(config.align.into()));
334 c.format.write(|w| w.format().bit(config.format.into())); 405 c.format.write(|w| w.format().bit(config.format.into()));
335 c.channels 406 c.channels
336 .write(|w| unsafe { w.channels().bits(config.channels.into()) }); 407 .write(|w| unsafe { w.channels().bits(config.channels.into()) });
337 } 408 }
409
410 fn select_pins(
411 psel: &PSEL,
412 mck: PeripheralRef<'d, AnyPin>,
413 sck: PeripheralRef<'d, AnyPin>,
414 lrck: PeripheralRef<'d, AnyPin>,
415 sdin: PeripheralRef<'d, AnyPin>,
416 sdout: PeripheralRef<'d, AnyPin>,
417 ) {
418 psel.mck.write(|w| {
419 unsafe { w.bits(mck.psel_bits()) };
420 w.connect().connected()
421 });
422
423 psel.sck.write(|w| {
424 unsafe { w.bits(sck.psel_bits()) };
425 w.connect().connected()
426 });
427
428 psel.lrck.write(|w| {
429 unsafe { w.bits(lrck.psel_bits()) };
430 w.connect().connected()
431 });
432
433 psel.sdin.write(|w| {
434 unsafe { w.bits(sdin.psel_bits()) };
435 w.connect().connected()
436 });
437
438 psel.sdout.write(|w| {
439 unsafe { w.bits(sdout.psel_bits()) };
440 w.connect().connected()
441 });
442 }
443
444 fn setup_interrupt(irq: PeripheralRef<'d, T::Interrupt>, r: &RegisterBlock) {
445 irq.set_handler(Self::on_interrupt);
446 irq.set_priority(Priority::P1); // TODO review priorities
447 irq.unpend();
448 irq.enable();
449
450 r.intenclr.write(|w| w.rxptrupd().clear());
451 r.intenclr.write(|w| w.txptrupd().clear());
452 r.events_rxptrupd.reset();
453 r.events_txptrupd.reset();
454 }
338} 455}
339 456
340impl<'d, T: Instance> I2sOutput<'d, T> { 457impl<'d, T: Instance> I2sOutput<'d, T> {
@@ -360,15 +477,40 @@ impl<'d, T: Instance> I2sOutput<'d, T> {
360 } 477 }
361 478
362 let r = T::regs(); 479 let r = T::regs();
363 let _s = T::state(); 480 let s = T::state();
364 481
365 // TODO we can not progress until the last buffer written in TXD.PTR 482 let drop = OnDrop::new(move || {
366 // has started the transmission. 483 trace!("write drop: stopping");
367 // We can use some sync primitive from `embassy-sync`. 484
485 r.intenclr.write(|w| w.txptrupd().clear());
486 r.events_txptrupd.reset();
487 r.config.txen.write(|w| w.txen().disabled());
488
489 // TX is stopped almost instantly, spinning is fine.
490 while r.events_txptrupd.read().bits() == 0 {}
491 trace!("write drop: stopped");
492 });
368 493
369 r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); 494 r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
370 r.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) }); 495 r.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) });
371 496
497 r.intenset.write(|w| w.txptrupd().set());
498
499 compiler_fence(Ordering::SeqCst);
500
501 poll_fn(|cx| {
502 s.tx_waker.register(cx.waker());
503 if r.events_txptrupd.read().bits() != 0 {
504 Poll::Ready(())
505 } else {
506 Poll::Pending
507 }
508 })
509 .await;
510
511 compiler_fence(Ordering::SeqCst);
512 drop.defuse();
513
372 Ok(()) 514 Ok(())
373 } 515 }
374} 516}
@@ -451,23 +593,19 @@ impl Buffer for &[i32] {
451} 593}
452 594
453pub(crate) mod sealed { 595pub(crate) mod sealed {
454 use core::sync::atomic::AtomicU8;
455
456 use embassy_sync::waitqueue::AtomicWaker; 596 use embassy_sync::waitqueue::AtomicWaker;
457 597
458 //use super::*; 598 //use super::*;
459 599
460 pub struct State { 600 pub struct State {
461 pub input_waker: AtomicWaker, 601 pub rx_waker: AtomicWaker,
462 pub output_waker: AtomicWaker, 602 pub tx_waker: AtomicWaker,
463 pub buffers_refcount: AtomicU8,
464 } 603 }
465 impl State { 604 impl State {
466 pub const fn new() -> Self { 605 pub const fn new() -> Self {
467 Self { 606 Self {
468 input_waker: AtomicWaker::new(), 607 rx_waker: AtomicWaker::new(),
469 output_waker: AtomicWaker::new(), 608 tx_waker: AtomicWaker::new(),
470 buffers_refcount: AtomicU8::new(0),
471 } 609 }
472 } 610 }
473 } 611 }
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index bdb911ecd..dc018e08e 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -74,7 +74,7 @@ pub mod buffered_uarte;
74pub mod gpio; 74pub mod gpio;
75#[cfg(feature = "gpiote")] 75#[cfg(feature = "gpiote")]
76pub mod gpiote; 76pub mod gpiote;
77#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840",))] 77#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
78pub mod i2s; 78pub mod i2s;
79#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] 79#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
80pub mod nvmc; 80pub mod nvmc;