1use crate::gpio::{self, NoPin, PinSpeed, Speed};
10use crate::pac;
11#[allow(unused)]
12use crate::rcc::{self, Clocks, Reset};
13use fugit::HertzU32 as Hertz;
14
15#[cfg(feature = "i2s")]
16pub extern crate stm32_i2s_v12x;
17
18pub type NoMasterClock = NoPin;
26
27pub trait Instance:
29 I2sFreq + rcc::Enable + rcc::Reset + gpio::alt::I2sCommon + gpio::alt::I2sMaster
30{
31}
32
33pub trait DualInstance: Instance + gpio::alt::I2sExtPin {
35 type I2sExtPeripheral;
37}
38
39pub trait I2sFreq {
41 fn try_i2s_freq(clocks: &Clocks) -> Option<Hertz>;
42 fn i2s_freq(clocks: &Clocks) -> Hertz {
43 Self::try_i2s_freq(clocks).expect("I2S clock input for SPI not enabled")
44 }
45}
46
47impl<T> I2sFreq for T
48where
49 T: rcc::RccBus,
50 T::Bus: I2sFreq,
51{
52 fn try_i2s_freq(clocks: &Clocks) -> Option<Hertz> {
53 T::Bus::try_i2s_freq(clocks)
54 }
55}
56
57impl I2sFreq for rcc::APB1 {
58 fn try_i2s_freq(clocks: &Clocks) -> Option<Hertz> {
59 #[cfg(not(feature = "rcc_i2s_apb"))]
60 {
61 clocks.i2s_clk()
62 }
63 #[cfg(feature = "rcc_i2s_apb")]
64 {
65 clocks.i2s_apb1_clk()
66 }
67 }
68}
69
70impl I2sFreq for rcc::APB2 {
71 fn try_i2s_freq(clocks: &Clocks) -> Option<Hertz> {
72 #[cfg(not(feature = "rcc_i2s_apb"))]
73 {
74 clocks.i2s_clk()
75 }
76 #[cfg(feature = "rcc_i2s_apb")]
77 {
78 clocks.i2s_apb2_clk()
79 }
80 }
81}
82
83pub trait I2sExt: Sized + Instance {
85 fn i2s(
86 self,
87 pins: (
88 impl Into<Self::Ws>,
89 impl Into<Self::Ck>,
90 impl Into<Self::Mck>,
91 impl Into<Self::Sd>,
92 ),
93 clocks: &Clocks,
94 ) -> I2s<Self>;
95}
96
97impl<SPI: Instance> I2sExt for SPI {
98 fn i2s(
99 self,
100 pins: (
101 impl Into<Self::Ws>,
102 impl Into<Self::Ck>,
103 impl Into<Self::Mck>,
104 impl Into<Self::Sd>,
105 ),
106 clocks: &Clocks,
107 ) -> I2s<Self> {
108 I2s::new(self, pins, clocks)
109 }
110}
111
112pub trait DualI2sExt: Sized + DualInstance {
114 fn dual_i2s(
115 self,
116 i2s_ext: Self::I2sExtPeripheral,
117 pins: (
118 impl Into<Self::Ws>,
119 impl Into<Self::Ck>,
120 impl Into<Self::Mck>,
121 impl Into<Self::Sd>,
122 impl Into<Self::ExtSd>,
123 ),
124 clocks: &Clocks,
125 ) -> DualI2s<Self>;
126}
127
128impl<SPI: DualInstance> DualI2sExt for SPI {
129 fn dual_i2s(
130 self,
131 i2s_ext: Self::I2sExtPeripheral,
132 pins: (
133 impl Into<Self::Ws>,
134 impl Into<Self::Ck>,
135 impl Into<Self::Mck>,
136 impl Into<Self::Sd>,
137 impl Into<Self::ExtSd>,
138 ),
139 clocks: &Clocks,
140 ) -> DualI2s<Self> {
141 DualI2s::new(self, i2s_ext, pins, clocks)
142 }
143}
144
145pub struct I2s<I: Instance> {
147 spi: I,
148 pins: (I::Ws, I::Ck, I::Mck, I::Sd),
149 input_clock: Hertz,
151}
152
153impl<SPI: Instance> I2s<SPI> {
156 pub fn new(
168 spi: SPI,
169 pins: (
170 impl Into<SPI::Ws>,
171 impl Into<SPI::Ck>,
172 impl Into<SPI::Mck>,
173 impl Into<SPI::Sd>,
174 ),
175 clocks: &Clocks,
176 ) -> Self {
177 let input_clock = SPI::i2s_freq(clocks);
178 unsafe {
179 SPI::enable_unchecked();
181 SPI::reset_unchecked();
182 }
183
184 let pins = (
185 pins.0.into(),
186 pins.1.into().speed(Speed::VeryHigh),
188 pins.2.into(),
189 pins.3.into(),
190 );
191
192 I2s {
193 spi,
194 pins,
195 input_clock,
196 }
197 }
198
199 #[allow(clippy::type_complexity)]
200 pub fn release(self) -> (SPI, (SPI::Ws, SPI::Ck, SPI::Mck, SPI::Sd)) {
201 (self.spi, self.pins)
202 }
203}
204
205impl<SPI: Instance> I2s<SPI> {
206 pub fn ws_pin(&self) -> &SPI::Ws {
207 &self.pins.0
208 }
209 pub fn ws_pin_mut(&mut self) -> &mut SPI::Ws {
210 &mut self.pins.0
211 }
212}
213
214impl<I: Instance> I2s<I> {
215 pub fn input_clock(&self) -> Hertz {
218 self.input_clock
219 }
220}
221
222macro_rules! i2s {
229 ($SPI:ty, $I2s:ident, $i2s:ident) => {
230 pub type $I2s = I2s<$SPI>;
231
232 impl Instance for $SPI {}
233
234 #[cfg(feature = "i2s")]
235 impl stm32_i2s_v12x::WsPin for gpio::alt::$i2s::Ws {
236 fn is_high(&self) -> bool {
237 use crate::gpio::ReadPin;
238 <Self as ReadPin>::is_high(self)
239 }
240 fn is_low(&self) -> bool {
241 use crate::gpio::ReadPin;
242 <Self as ReadPin>::is_low(self)
243 }
244 }
245
246 #[cfg(feature = "i2s")]
247 unsafe impl stm32_i2s_v12x::I2sPeripheral for I2s<$SPI>
248 where
249 $SPI: rcc::Reset,
250 {
251 type WsPin = gpio::alt::$i2s::Ws;
252 const REGISTERS: *const () = <$SPI>::ptr() as *const _;
253 fn i2s_freq(&self) -> u32 {
254 self.input_clock.raw()
255 }
256 fn ws_pin(&self) -> &Self::WsPin {
257 self.ws_pin()
258 }
259 fn ws_pin_mut(&mut self) -> &mut Self::WsPin {
260 self.ws_pin_mut()
261 }
262 fn rcc_reset(&mut self) {
263 unsafe {
264 <$SPI>::reset_unchecked();
265 }
266 }
267 }
268 };
269}
270
271#[cfg(any(
272 feature = "gpio-f410",
273 feature = "gpio-f411",
274 feature = "gpio-f412",
275 feature = "gpio-f413",
276 feature = "gpio-f446"
277))]
278i2s!(pac::SPI1, I2s1, i2s1);
279
280i2s!(pac::SPI2, I2s2, i2s2);
281
282#[cfg(feature = "spi3")]
283i2s!(pac::SPI3, I2s3, i2s3);
284
285#[cfg(feature = "spi4")]
286i2s!(pac::SPI4, I2s4, i2s4);
287
288#[cfg(feature = "spi5")]
289i2s!(pac::SPI5, I2s5, i2s5);
290
291#[allow(clippy::type_complexity)]
293pub struct DualI2s<I: DualInstance> {
294 spi: I,
295 i2s_ext: I::I2sExtPeripheral,
296 pins: (I::Ws, I::Ck, I::Mck, I::Sd, I::ExtSd),
297 input_clock: Hertz,
299}
300
301impl<SPI: DualInstance> DualI2s<SPI> {
302 pub fn new(
314 spi: SPI,
315 i2s_ext: SPI::I2sExtPeripheral,
316 pins: (
317 impl Into<SPI::Ws>,
318 impl Into<SPI::Ck>,
319 impl Into<SPI::Mck>,
320 impl Into<SPI::Sd>,
321 impl Into<SPI::ExtSd>,
322 ),
323 clocks: &Clocks,
324 ) -> Self {
325 let input_clock = SPI::i2s_freq(clocks);
326 unsafe {
327 SPI::enable_unchecked();
330 SPI::reset_unchecked();
331 }
332
333 let pins = (
334 pins.0.into(),
335 pins.1.into().speed(Speed::VeryHigh),
337 pins.2.into(),
338 pins.3.into(),
339 pins.4.into(),
340 );
341
342 Self {
343 spi,
344 i2s_ext,
345 pins,
346 input_clock,
347 }
348 }
349
350 #[allow(clippy::type_complexity)]
351 pub fn release(
352 self,
353 ) -> (
354 SPI,
355 SPI::I2sExtPeripheral,
356 (SPI::Ws, SPI::Ck, SPI::Mck, SPI::Sd, SPI::ExtSd),
357 ) {
358 (self.spi, self.i2s_ext, self.pins)
359 }
360}
361
362impl<SPI: DualInstance> DualI2s<SPI> {
363 pub fn ws_pin(&self) -> &SPI::Ws {
364 &self.pins.0
365 }
366 pub fn ws_pin_mut(&mut self) -> &mut SPI::Ws {
367 &mut self.pins.0
368 }
369}
370
371impl<I: DualInstance> DualI2s<I> {
372 pub fn input_clock(&self) -> Hertz {
375 self.input_clock
376 }
377}
378
379#[cfg(any(
388 feature = "gpio-f401",
389 feature = "gpio-f411",
390 feature = "gpio-f412",
391 feature = "gpio-f417",
392 feature = "gpio-f427",
393 feature = "gpio-f469",
394))]
395macro_rules! dual_i2s {
396 ($SPI:ty,$I2SEXT:ty, $DualI2s:ident, $i2s:ident, $clock:ident) => {
397 pub type $DualI2s = DualI2s<$SPI>;
398
399 impl DualInstance for $SPI {
400 type I2sExtPeripheral = $I2SEXT;
401 }
402
403 #[cfg(feature = "i2s")]
404 unsafe impl stm32_i2s_v12x::DualI2sPeripheral for DualI2s<$SPI>
405 where
406 $SPI: rcc::Reset,
407 {
408 type WsPin = gpio::alt::$i2s::Ws;
409 const MAIN_REGISTERS: *const () = <$SPI>::ptr() as *const _;
410 const EXT_REGISTERS: *const () = <$I2SEXT>::ptr() as *const _;
411 fn i2s_freq(&self) -> u32 {
412 self.input_clock.raw()
413 }
414 fn ws_pin(&self) -> &Self::WsPin {
415 self.ws_pin()
416 }
417 fn ws_pin_mut(&mut self) -> &mut Self::WsPin {
418 self.ws_pin_mut()
419 }
420 fn rcc_reset(&mut self) {
421 unsafe {
422 <$SPI>::reset_unchecked();
423 }
424 }
425 }
426 };
427}
428
429#[cfg(any(
434 feature = "gpio-f401",
435 feature = "gpio-f411",
436 feature = "gpio-f417",
437 feature = "gpio-f427",
438 feature = "gpio-f469",
439))]
440dual_i2s!(pac::SPI2, pac::I2S2EXT, DualI2s2, i2s2, i2s_clk);
441
442#[cfg(feature = "gpio-f412")]
444dual_i2s!(pac::SPI2, pac::I2S2EXT, DualI2s2, i2s2, i2s_apb1_clk);
445
446#[cfg(any(
447 feature = "gpio-f401",
448 feature = "gpio-f411",
449 feature = "gpio-f417",
450 feature = "gpio-f427",
451 feature = "gpio-f469",
452))]
453dual_i2s!(pac::SPI3, pac::I2S3EXT, DualI2s3, i2s3, i2s_clk);
454
455#[cfg(feature = "gpio-f412")]
457dual_i2s!(pac::SPI3, pac::I2S3EXT, DualI2s3, i2s3, i2s_apb1_clk);
458
459#[cfg(feature = "i2s")]
461mod dma {
462 use super::*;
463 use crate::dma::traits::{DMASet, PeriAddress};
464 use crate::pac::spi1::RegisterBlock;
465 use core::marker::PhantomData;
466 use core::ops::Deref;
467 use stm32_i2s_v12x::driver::{I2sCore, I2sDriver};
468 use stm32_i2s_v12x::transfer::{Ext, Main};
469 use stm32_i2s_v12x::DualI2sPeripheral;
470
471 unsafe impl<SPI: Instance, MS, TR, STD> PeriAddress for I2sDriver<I2s<SPI>, MS, TR, STD>
473 where
474 I2s<SPI>: stm32_i2s_v12x::I2sPeripheral,
475 SPI: Deref<Target = crate::pac::spi1::RegisterBlock>,
476 {
477 type MemSize = u16;
480
481 fn address(&self) -> u32 {
482 self.data_register_address()
483 }
484 }
485
486 unsafe impl<SPI: Instance, MS, TR, STD, STREAM, const CHANNEL: u8, DIR>
488 DMASet<STREAM, CHANNEL, DIR> for I2sDriver<I2s<SPI>, MS, TR, STD>
489 where
490 SPI: DMASet<STREAM, CHANNEL, DIR>,
491 {
492 }
493
494 pub trait DualI2sDmaTargetExt<I, PART, MS, DIR, STD> {
495 fn dma_target(&self) -> DualI2sDmaTarget<I, PART, MS, DIR, STD>;
496 }
497 impl<I, PART, MS, DIR, STD> DualI2sDmaTargetExt<I, PART, MS, DIR, STD>
498 for I2sCore<I, PART, MS, DIR, STD>
499 {
500 fn dma_target(&self) -> DualI2sDmaTarget<I, PART, MS, DIR, STD> {
501 DualI2sDmaTarget {
502 _dual_i2s_peripheral: PhantomData,
503 _part: PhantomData,
504 _ms: PhantomData,
505 _dir: PhantomData,
506 _std: PhantomData,
507 }
508 }
509 }
510
511 pub struct DualI2sDmaTarget<I, PART, MS, DIR, STD> {
517 _dual_i2s_peripheral: PhantomData<I>,
518 _part: PhantomData<PART>,
519 _ms: PhantomData<MS>,
520 _dir: PhantomData<DIR>,
521 _std: PhantomData<STD>,
522 }
523
524 macro_rules! dual_dma {
525 ($ext: ty, $reg: ident) => {
526 unsafe impl<SPIext: DualInstance, MS, TR, STD> PeriAddress
528 for DualI2sDmaTarget<DualI2s<SPIext>, $ext, MS, TR, STD>
529 where
530 DualI2s<SPIext>: DualI2sPeripheral,
531 {
532 type MemSize = u16;
535
536 fn address(&self) -> u32 {
537 let reg = unsafe { &*(DualI2s::$reg as *const RegisterBlock) };
538 reg.dr().as_ptr() as u32
539 }
540 }
541 };
542 }
543
544 dual_dma!(Main, MAIN_REGISTERS);
545 dual_dma!(Ext, EXT_REGISTERS);
546
547 unsafe impl<SPIext: DualInstance, PART, MS, TR, STD, STREAM, const CHANNEL: u8, DIR>
549 DMASet<STREAM, CHANNEL, DIR> for DualI2sDmaTarget<DualI2s<SPIext>, PART, MS, TR, STD>
550 where
551 SPIext: DMASet<STREAM, CHANNEL, DIR>,
552 {
553 }
554}
555
556#[cfg(feature = "i2s")]
557pub use dma::{DualI2sDmaTarget, DualI2sDmaTargetExt};