11//! Inter-IC Sound (I2S)
22use embassy_hal_internal:: into_ref;
3- use stm32_metapac:: SPI3 ;
43
4+ use crate :: dma:: { ringbuffer, word, Channel , NoDma , TransferOptions , WritableRingBuffer } ;
55use crate :: gpio:: sealed:: { AFType , Pin as _} ;
66use crate :: gpio:: AnyPin ;
77use crate :: pac:: spi:: vals;
@@ -154,27 +154,31 @@ impl Default for Config {
154154}
155155
156156/// I2S driver.
157- pub struct I2S < ' d , T : Instance , Tx , Rx > {
158- pub _peri : Spi < ' d , T , Tx , Rx > ,
157+ pub struct I2S < ' d , T : Instance , C : Channel , W : word :: Word > {
158+ _peri : Spi < ' d , T , NoDma , NoDma > ,
159159 sd : Option < PeripheralRef < ' d , AnyPin > > ,
160160 ws : Option < PeripheralRef < ' d , AnyPin > > ,
161161 ck : Option < PeripheralRef < ' d , AnyPin > > ,
162162 mck : Option < PeripheralRef < ' d , AnyPin > > ,
163+ ring_buffer : WritableRingBuffer < ' d , C , W > ,
163164}
164165
165- impl < ' d , T : Instance , Tx , Rx > I2S < ' d , T , Tx , Rx > {
166+ impl < ' d , T : Instance , C : Channel , W : word :: Word > I2S < ' d , T , C , W > {
166167 /// Note: Full-Duplex modes are not supported at this time
167168 pub fn new_no_mck (
168169 peri : impl Peripheral < P = T > + ' d ,
169170 sd : impl Peripheral < P = impl MosiPin < T > > + ' d ,
170171 ws : impl Peripheral < P = impl WsPin < T > > + ' d ,
171172 ck : impl Peripheral < P = impl CkPin < T > > + ' d ,
172- txdma : impl Peripheral < P = Tx > + ' d ,
173- rxdma : impl Peripheral < P = Rx > + ' d ,
173+ txdma : impl Peripheral < P = C > + ' d ,
174+ dma_buf : & ' d mut [ W ] ,
174175 freq : Hertz ,
175176 config : Config ,
176- ) -> Self {
177- into_ref ! ( sd, ws, ck) ;
177+ ) -> Self
178+ where
179+ C : Channel + TxDma < T > ,
180+ {
181+ into_ref ! ( sd, ws, ck, txdma) ;
178182
179183 sd. set_as_af ( sd. af_num ( ) , AFType :: OutputPushPull ) ;
180184 sd. set_speed ( crate :: gpio:: Speed :: VeryHigh ) ;
@@ -187,7 +191,7 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
187191
188192 let mut spi_cfg = SpiConfig :: default ( ) ;
189193 spi_cfg. frequency = freq;
190- let spi = Spi :: new_internal ( peri, txdma , rxdma , spi_cfg) ;
194+ let spi = Spi :: new_internal ( peri, NoDma , NoDma , spi_cfg) ;
191195
192196 #[ cfg( all( rcc_f4, not( stm32f410) ) ) ]
193197 let pclk = Hertz ( 38_400_000 ) ; // unsafe { get_freqs() }.plli2s1_r.unwrap();
@@ -197,7 +201,7 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
197201
198202 let ( odd, div) = compute_baud_rate ( pclk, freq, config. master_clock , config. format ) ;
199203
200- defmt:: println!( "odd: {}, div {}" , odd, div) ;
204+ // defmt::println!("odd: {}, div {}", odd, div);
201205
202206 #[ cfg( any( spi_v1, spi_f1) ) ]
203207 {
@@ -218,9 +222,6 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
218222 w. set_mckoe ( config. master_clock ) ;
219223 } ) ;
220224
221- // T::REGS.cr2().modify(|r| r.set_txdmaen(true));
222- // T::REGS.dr().write(|w| w.set_dr(0x0000_u16));
223-
224225 // 2. Select the CKPOL bit to define the steady level for the communication clock. Set the
225226 // MCKOE bit in the SPI_I2SPR register if the master clock MCK needs to be provided to
226227 // the external DAC/ADC audio component (the I2SDIV and ODD values should be
@@ -261,168 +262,178 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
261262 } ) ;
262263 }
263264
265+ let opts = TransferOptions {
266+ half_transfer_ir : true ,
267+ //the new_write() and new_read() always use circular mode
268+ ..Default :: default ( )
269+ } ;
270+
271+ let request = txdma. request ( ) ;
272+ let data_ptr = T :: REGS . dr ( ) . as_ptr ( ) . cast :: < W > ( ) ;
273+
274+ let ring_buffer = unsafe { WritableRingBuffer :: new ( txdma, request, data_ptr, dma_buf, opts) } ;
275+
264276 Self {
265277 _peri : spi,
266278 sd : Some ( sd. map_into ( ) ) ,
267279 ws : Some ( ws. map_into ( ) ) ,
268280 ck : Some ( ck. map_into ( ) ) ,
269281 mck : None ,
282+ ring_buffer,
270283 }
271284 }
272285
273- /// Note: Full-Duplex modes are not supported at this time
274- pub fn new (
275- peri : impl Peripheral < P = T > + ' d ,
276- sd : impl Peripheral < P = impl MosiPin < T > > + ' d ,
277- ws : impl Peripheral < P = impl WsPin < T > > + ' d ,
278- ck : impl Peripheral < P = impl CkPin < T > > + ' d ,
279- mck : impl Peripheral < P = impl MckPin < T > > + ' d ,
280- txdma : impl Peripheral < P = Tx > + ' d ,
281- rxdma : impl Peripheral < P = Rx > + ' d ,
282- freq : Hertz ,
283- config : Config ,
284- ) -> Self {
285- into_ref ! ( sd, ws, ck, mck) ;
286+ // /// Note: Full-Duplex modes are not supported at this time
287+ // pub fn new(
288+ // peri: impl Peripheral<P = T> + 'd,
289+ // sd: impl Peripheral<P = impl MosiPin<T>> + 'd,
290+ // ws: impl Peripheral<P = impl WsPin<T>> + 'd,
291+ // ck: impl Peripheral<P = impl CkPin<T>> + 'd,
292+ // mck: impl Peripheral<P = impl MckPin<T>> + 'd,
293+ // txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
294+ // freq: Hertz,
295+ // config: Config,
296+ // ) -> Self {
297+ // into_ref!(sd, ws, ck, mck);
286298
287- sd. set_as_af ( sd. af_num ( ) , AFType :: OutputPushPull ) ;
288- sd. set_speed ( crate :: gpio:: Speed :: VeryHigh ) ;
299+ // sd.set_as_af(sd.af_num(), AFType::OutputPushPull);
300+ // sd.set_speed(crate::gpio::Speed::VeryHigh);
289301
290- ws. set_as_af ( ws. af_num ( ) , AFType :: OutputPushPull ) ;
291- ws. set_speed ( crate :: gpio:: Speed :: VeryHigh ) ;
302+ // ws.set_as_af(ws.af_num(), AFType::OutputPushPull);
303+ // ws.set_speed(crate::gpio::Speed::VeryHigh);
292304
293- ck. set_as_af ( ck. af_num ( ) , AFType :: OutputPushPull ) ;
294- ck. set_speed ( crate :: gpio:: Speed :: VeryHigh ) ;
305+ // ck.set_as_af(ck.af_num(), AFType::OutputPushPull);
306+ // ck.set_speed(crate::gpio::Speed::VeryHigh);
295307
296- mck. set_as_af ( mck. af_num ( ) , AFType :: OutputPushPull ) ;
297- mck. set_speed ( crate :: gpio:: Speed :: VeryHigh ) ;
308+ // mck.set_as_af(mck.af_num(), AFType::OutputPushPull);
309+ // mck.set_speed(crate::gpio::Speed::VeryHigh);
310+
311+ // let mut spi_cfg = SpiConfig::default();
312+ // spi_cfg.frequency = freq;
313+ // let spi = Spi::new_internal(peri, NoDma, NoDma, spi_cfg);
298314
299- let mut spi_cfg = SpiConfig :: default ( ) ;
300- spi_cfg. frequency = freq;
301- let spi = Spi :: new_internal ( peri, txdma, rxdma, spi_cfg) ;
302315
303316 // TODO move i2s to the new mux infra.
304317 //#[cfg(all(rcc_f4, not(stm32f410)))]
305318 //let pclk = unsafe { get_freqs() }.plli2s1_q.unwrap();
306319 //#[cfg(stm32f410)]
307320 let pclk = T :: frequency ( ) ;
321+ // #[cfg(all(rcc_f4, not(stm32f410)))]
322+ // let pclk = unsafe { get_freqs() }.plli2s1_q.unwrap();
308323
309- let ( odd, div) = compute_baud_rate ( pclk, freq, config. master_clock , config. format ) ;
324+ // #[cfg(stm32f410)]
325+ // let pclk = T::frequency();
310326
311- #[ cfg( any( spi_v1, spi_f1) ) ]
312- {
313- use stm32_metapac:: spi:: vals:: { I2scfg , Odd } ;
314327
315- // 1. Select the I2SDIV[7:0] bits in the SPI_I2SPR register to define the serial clock baud
316- // rate to reach the proper audio sample frequency. The ODD bit in the SPI_I2SPR
317- // register also has to be defined.
328+ // let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format);
318329
319- T :: REGS . i2spr ( ) . modify ( |w| {
320- w. set_i2sdiv ( div) ;
321- w. set_odd ( match odd {
322- true => Odd :: ODD ,
323- false => Odd :: EVEN ,
324- } ) ;
330+ // #[cfg(any(spi_v1, spi_f1))]
331+ // {
332+ // use stm32_metapac::spi::vals::{I2scfg, Odd};
325333
326- w. set_mckoe ( config. master_clock ) ;
327- } ) ;
334+ // // 1. Select the I2SDIV[7:0] bits in the SPI_I2SPR register to define the serial clock baud
335+ // // rate to reach the proper audio sample frequency. The ODD bit in the SPI_I2SPR
336+ // // register also has to be defined.
328337
329- // 2. Select the CKPOL bit to define the steady level for the communication clock. Set the
330- // MCKOE bit in the SPI_I2SPR register if the master clock MCK needs to be provided to
331- // the external DAC/ADC audio component (the I2SDIV and ODD values should be
332- // computed depending on the state of the MCK output, for more details refer to
333- // Section 28.4.4: Clock generator).
338+ // T::REGS.i2spr().modify(|w| {
339+ // w.set_i2sdiv(div);
340+ // w.set_odd(match odd {
341+ // true => Odd::ODD,
342+ // false => Odd::EVEN,
343+ // });
334344
335- // 3. Set the I2SMOD bit in SPI_I2SCFGR to activate the I2S functionalities and choose the
336- // I2S standard through the I2SSTD[1:0] and PCMSYNC bits, the data length through the
337- // DATLEN[1:0] bits and the number of bits per channel by configuring the CHLEN bit.
338- // Select also the I2S master mode and direction (Transmitter or Receiver) through the
339- // I2SCFG[1:0] bits in the SPI_I2SCFGR register.
345+ // w.set_mckoe(config.master_clock);
346+ // });
340347
341- // 4. If needed, select all the potential interruption sources and the DMA capabilities by
342- // writing the SPI_CR2 register.
348+ // // 2. Select the CKPOL bit to define the steady level for the communication clock. Set the
349+ // // MCKOE bit in the SPI_I2SPR register if the master clock MCK needs to be provided to
350+ // // the external DAC/ADC audio component (the I2SDIV and ODD values should be
351+ // // computed depending on the state of the MCK output, for more details refer to
352+ // // Section 28.4.4: Clock generator).
343353
344- // 5. The I2SE bit in SPI_I2SCFGR register must be set.
354+ // // 3. Set the I2SMOD bit in SPI_I2SCFGR to activate the I2S functionalities and choose the
355+ // // I2S standard through the I2SSTD[1:0] and PCMSYNC bits, the data length through the
356+ // // DATLEN[1:0] bits and the number of bits per channel by configuring the CHLEN bit.
357+ // // Select also the I2S master mode and direction (Transmitter or Receiver) through the
358+ // // I2SCFG[1:0] bits in the SPI_I2SCFGR register.
345359
346- T :: REGS . i2scfgr ( ) . modify ( |w| {
347- w . set_ckpol ( config . clock_polarity . ckpol ( ) ) ;
360+ // // 4. If needed, select all the potential interruption sources and the DMA capabilities by
361+ // // writing the SPI_CR2 register.
348362
349- w. set_i2smod ( true ) ;
350- w. set_i2sstd ( config. standard . i2sstd ( ) ) ;
351- w. set_pcmsync ( config. standard . pcmsync ( ) ) ;
363+ // // 5. The I2SE bit in SPI_I2SCFGR register must be set.
352364
353- w . set_datlen ( config . format . datlen ( ) ) ;
354- w . set_chlen ( config. format . chlen ( ) ) ;
365+ // T::REGS.i2scfgr().modify(|w| {
366+ // w.set_ckpol (config.clock_polarity.ckpol ());
355367
356- w. set_i2scfg ( match ( config. mode , config. function ) {
357- ( Mode :: Master , Function :: Transmit ) => I2scfg :: MASTERTX ,
358- ( Mode :: Master , Function :: Receive ) => I2scfg :: MASTERRX ,
359- ( Mode :: Slave , Function :: Transmit ) => I2scfg :: SLAVETX ,
360- ( Mode :: Slave , Function :: Receive ) => I2scfg :: SLAVERX ,
361- } ) ;
368+ // w.set_i2smod(true);
369+ // w.set_i2sstd(config.standard.i2sstd());
370+ // w.set_pcmsync(config.standard.pcmsync());
362371
363- w. set_i2se ( true )
364- } ) ;
365- }
372+ // w.set_datlen(config.format.datlen());
373+ // w.set_chlen(config.format.chlen());
366374
367- Self {
368- _peri : spi,
369- sd : Some ( sd. map_into ( ) ) ,
370- ws : Some ( ws. map_into ( ) ) ,
371- ck : Some ( ck. map_into ( ) ) ,
372- mck : Some ( mck. map_into ( ) ) ,
373- }
374- }
375+ // w.set_i2scfg(match (config.mode, config.function) {
376+ // (Mode::Master, Function::Transmit) => I2scfg::MASTERTX,
377+ // (Mode::Master, Function::Receive) => I2scfg::MASTERRX,
378+ // (Mode::Slave, Function::Transmit) => I2scfg::SLAVETX,
379+ // (Mode::Slave, Function::Receive) => I2scfg::SLAVERX,
380+ // });
375381
376- /// Write audio data.
377- pub async fn write < W : Word > ( & mut self , data : & [ W ] ) -> Result < ( ) , Error >
378- where
379- Tx : TxDma < T > ,
380- {
381- self . _peri . write ( data) . await
382- }
382+ // w.set_i2se(true)
383+ // });
384+ // }
383385
384- /// Write audio data.
385- pub fn writer ( & mut self , data : & [ u16 ] ) -> Result < ( ) , Error > {
386- let mut spi = T :: REGS ;
386+ // Self {
387+ // _peri: spi,
388+ // sd: Some(sd.map_into()),
389+ // ws: Some(ws.map_into()),
390+ // ck: Some(ck.map_into()),
391+ // mck: Some(mck.map_into()),
392+ // dma: Some(txdma.map_into()),
393+ // }
394+ // }
387395
388- // spi.cr2().modify(|r| {
389- // r.set_frf(vals::Frf::TI);
390- // r.set_ssoe(true);
391- // });
396+ /// Write audio data.
397+ pub async fn write ( & mut self , data : & [ W ] ) -> Result < ( ) , Error > {
398+ self . ring_buffer . write_exact ( data) . await . map_err ( |_| Error :: Overrun ) ?;
399+ Ok ( ( ) )
400+ }
392401
393- spi. cr1 ( ) . modify ( |r| r. set_spe ( true ) ) ;
402+ /// Start the I2S driver.
403+ pub fn start ( & mut self ) {
404+ self . ring_buffer . start ( ) ;
394405
395- // let dr = spi.dr().as_ptr() as *mut W;
406+ #[ cfg( not( any( spi_v3, spi_v4, spi_v5) ) ) ]
407+ T :: REGS . cr2 ( ) . modify ( |reg| {
408+ reg. set_txdmaen ( true ) ;
409+ } ) ;
396410
397- for _ in 0 ..2000 {
398- for sample in data {
399- while !spi. sr ( ) . read ( ) . txe ( ) { }
400- spi. dr ( ) . write ( |reg| reg. set_dr ( * sample) ) ;
401- }
402- }
411+ T :: REGS . cr1 ( ) . modify ( |w| {
412+ w. set_spe ( true ) ;
413+ } ) ;
414+ }
403415
404- // defmt::println!("Wait for TXE go high");
405- while !spi. sr ( ) . read ( ) . txe ( ) { }
406- // defmt::println!("Wait for BSY go low");
407- // while spi.sr().read().bsy() {}
408- // defmt::println!("Wait done");
416+ /// Stop the I2S driver.
417+ pub fn stop ( & mut self ) {
418+ #[ cfg( not( any( spi_v3, spi_v4, spi_v5) ) ) ]
419+ T :: REGS . cr2 ( ) . modify ( |reg| {
420+ reg. set_txdmaen ( false ) ;
421+ } ) ;
409422
410- spi . cr1 ( ) . modify ( |r| r . set_spe ( false ) ) ;
423+ self . ring_buffer . request_stop ( ) ;
411424
412- Ok ( ( ) )
425+ T :: REGS . cr1 ( ) . modify ( |w| {
426+ w. set_spe ( false ) ;
427+ } ) ;
413428 }
414429
415- /// Read audio data.
416- pub async fn read < W : Word > ( & mut self , data : & mut [ W ] ) -> Result < ( ) , Error >
417- where
418- Tx : TxDma < T > ,
419- Rx : RxDma < T > ,
420- {
421- self . _peri . read ( data) . await
430+ /// Reset I2S operation.
431+ pub fn reset ( ) {
432+ T :: enable_and_reset ( ) ;
422433 }
423434}
424435
425- impl < ' d , T : Instance , Tx , Rx > Drop for I2S < ' d , T , Tx , Rx > {
436+ impl < ' d , T : Instance , C : Channel , W : word :: Word > Drop for I2S < ' d , T , C , W > {
426437 fn drop ( & mut self ) {
427438 self . sd . as_ref ( ) . map ( |x| x. set_as_disconnected ( ) ) ;
428439 self . ws . as_ref ( ) . map ( |x| x. set_as_disconnected ( ) ) ;
0 commit comments