1
1
//! Inter-IC Sound (I2S)
2
2
use embassy_hal_internal:: into_ref;
3
- use stm32_metapac:: SPI3 ;
4
3
4
+ use crate :: dma:: { ringbuffer, word, Channel , NoDma , TransferOptions , WritableRingBuffer } ;
5
5
use crate :: gpio:: sealed:: { AFType , Pin as _} ;
6
6
use crate :: gpio:: AnyPin ;
7
7
use crate :: pac:: spi:: vals;
@@ -154,27 +154,31 @@ impl Default for Config {
154
154
}
155
155
156
156
/// 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 > ,
159
159
sd : Option < PeripheralRef < ' d , AnyPin > > ,
160
160
ws : Option < PeripheralRef < ' d , AnyPin > > ,
161
161
ck : Option < PeripheralRef < ' d , AnyPin > > ,
162
162
mck : Option < PeripheralRef < ' d , AnyPin > > ,
163
+ ring_buffer : WritableRingBuffer < ' d , C , W > ,
163
164
}
164
165
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 > {
166
167
/// Note: Full-Duplex modes are not supported at this time
167
168
pub fn new_no_mck (
168
169
peri : impl Peripheral < P = T > + ' d ,
169
170
sd : impl Peripheral < P = impl MosiPin < T > > + ' d ,
170
171
ws : impl Peripheral < P = impl WsPin < T > > + ' d ,
171
172
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 ] ,
174
175
freq : Hertz ,
175
176
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) ;
178
182
179
183
sd. set_as_af ( sd. af_num ( ) , AFType :: OutputPushPull ) ;
180
184
sd. set_speed ( crate :: gpio:: Speed :: VeryHigh ) ;
@@ -187,7 +191,7 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
187
191
188
192
let mut spi_cfg = SpiConfig :: default ( ) ;
189
193
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) ;
191
195
192
196
#[ cfg( all( rcc_f4, not( stm32f410) ) ) ]
193
197
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> {
197
201
198
202
let ( odd, div) = compute_baud_rate ( pclk, freq, config. master_clock , config. format ) ;
199
203
200
- defmt:: println!( "odd: {}, div {}" , odd, div) ;
204
+ // defmt::println!("odd: {}, div {}", odd, div);
201
205
202
206
#[ cfg( any( spi_v1, spi_f1) ) ]
203
207
{
@@ -218,9 +222,6 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
218
222
w. set_mckoe ( config. master_clock ) ;
219
223
} ) ;
220
224
221
- // T::REGS.cr2().modify(|r| r.set_txdmaen(true));
222
- // T::REGS.dr().write(|w| w.set_dr(0x0000_u16));
223
-
224
225
// 2. Select the CKPOL bit to define the steady level for the communication clock. Set the
225
226
// MCKOE bit in the SPI_I2SPR register if the master clock MCK needs to be provided to
226
227
// 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> {
261
262
} ) ;
262
263
}
263
264
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
+
264
276
Self {
265
277
_peri : spi,
266
278
sd : Some ( sd. map_into ( ) ) ,
267
279
ws : Some ( ws. map_into ( ) ) ,
268
280
ck : Some ( ck. map_into ( ) ) ,
269
281
mck : None ,
282
+ ring_buffer,
270
283
}
271
284
}
272
285
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);
286
298
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);
289
301
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);
292
304
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);
295
307
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);
298
314
299
- let mut spi_cfg = SpiConfig :: default ( ) ;
300
- spi_cfg. frequency = freq;
301
- let spi = Spi :: new_internal ( peri, txdma, rxdma, spi_cfg) ;
302
315
303
316
// TODO move i2s to the new mux infra.
304
317
//#[cfg(all(rcc_f4, not(stm32f410)))]
305
318
//let pclk = unsafe { get_freqs() }.plli2s1_q.unwrap();
306
319
//#[cfg(stm32f410)]
307
320
let pclk = T :: frequency ( ) ;
321
+ // #[cfg(all(rcc_f4, not(stm32f410)))]
322
+ // let pclk = unsafe { get_freqs() }.plli2s1_q.unwrap();
308
323
309
- let ( odd, div) = compute_baud_rate ( pclk, freq, config. master_clock , config. format ) ;
324
+ // #[cfg(stm32f410)]
325
+ // let pclk = T::frequency();
310
326
311
- #[ cfg( any( spi_v1, spi_f1) ) ]
312
- {
313
- use stm32_metapac:: spi:: vals:: { I2scfg , Odd } ;
314
327
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);
318
329
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};
325
333
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.
328
337
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
+ // });
334
344
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
+ // });
340
347
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).
343
353
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.
345
359
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.
348
362
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.
352
364
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 ());
355
367
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());
362
371
363
- w. set_i2se ( true )
364
- } ) ;
365
- }
372
+ // w.set_datlen(config.format.datlen());
373
+ // w.set_chlen(config.format.chlen());
366
374
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
+ // });
375
381
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
+ // }
383
385
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
+ // }
387
395
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
+ }
392
401
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 ( ) ;
394
405
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
+ } ) ;
396
410
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
+ }
403
415
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
+ } ) ;
409
422
410
- spi . cr1 ( ) . modify ( |r| r . set_spe ( false ) ) ;
423
+ self . ring_buffer . request_stop ( ) ;
411
424
412
- Ok ( ( ) )
425
+ T :: REGS . cr1 ( ) . modify ( |w| {
426
+ w. set_spe ( false ) ;
427
+ } ) ;
413
428
}
414
429
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 ( ) ;
422
433
}
423
434
}
424
435
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 > {
426
437
fn drop ( & mut self ) {
427
438
self . sd . as_ref ( ) . map ( |x| x. set_as_disconnected ( ) ) ;
428
439
self . ws . as_ref ( ) . map ( |x| x. set_as_disconnected ( ) ) ;
0 commit comments