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