Skip to content

Commit 1a0b435

Browse files
committed
stm32f4/i2s: Allow i2c without mcko
1 parent 4c7ed5e commit 1a0b435

File tree

1 file changed

+116
-0
lines changed

1 file changed

+116
-0
lines changed

embassy-stm32/src/i2s.rs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,108 @@ pub struct I2S<'d, T: Instance, Tx, Rx> {
162162
}
163163

164164
impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
165+
/// Note: Full-Duplex modes are not supported at this time
166+
pub fn new_no_mck(
167+
peri: impl Peripheral<P = T> + 'd,
168+
sd: impl Peripheral<P = impl MosiPin<T>> + 'd,
169+
ws: impl Peripheral<P = impl WsPin<T>> + 'd,
170+
ck: impl Peripheral<P = impl CkPin<T>> + 'd,
171+
txdma: impl Peripheral<P = Tx> + 'd,
172+
rxdma: impl Peripheral<P = Rx> + 'd,
173+
freq: Hertz,
174+
config: Config,
175+
) -> Self {
176+
into_ref!(sd, ws, ck);
177+
178+
sd.set_as_af(sd.af_num(), AFType::OutputPushPull);
179+
sd.set_speed(crate::gpio::Speed::VeryHigh);
180+
181+
ws.set_as_af(ws.af_num(), AFType::OutputPushPull);
182+
ws.set_speed(crate::gpio::Speed::VeryHigh);
183+
184+
ck.set_as_af(ck.af_num(), AFType::OutputPushPull);
185+
ck.set_speed(crate::gpio::Speed::VeryHigh);
186+
187+
let mut spi_cfg = SpiConfig::default();
188+
spi_cfg.frequency = freq;
189+
let spi = Spi::new_internal(peri, txdma, rxdma, spi_cfg);
190+
191+
#[cfg(all(rcc_f4, not(stm32f410)))]
192+
let pclk = Hertz(38_400_000); // unsafe { get_freqs() }.plli2s1_r.unwrap();
193+
194+
#[cfg(stm32f410)]
195+
let pclk = T::frequency();
196+
197+
let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format);
198+
199+
#[cfg(any(spi_v1, spi_f1))]
200+
{
201+
use stm32_metapac::spi::vals::{I2scfg, Odd};
202+
203+
// 1. Select the I2SDIV[7:0] bits in the SPI_I2SPR register to define the serial clock baud
204+
// rate to reach the proper audio sample frequency. The ODD bit in the SPI_I2SPR
205+
// register also has to be defined.
206+
207+
T::REGS.i2spr().modify(|w| {
208+
w.set_i2sdiv(div);
209+
w.set_odd(match odd {
210+
true => Odd::ODD,
211+
false => Odd::EVEN,
212+
});
213+
214+
// No mclk
215+
w.set_mckoe(config.master_clock);
216+
});
217+
218+
// 2. Select the CKPOL bit to define the steady level for the communication clock. Set the
219+
// MCKOE bit in the SPI_I2SPR register if the master clock MCK needs to be provided to
220+
// the external DAC/ADC audio component (the I2SDIV and ODD values should be
221+
// computed depending on the state of the MCK output, for more details refer to
222+
// Section 28.4.4: Clock generator).
223+
224+
// 3. Set the I2SMOD bit in SPI_I2SCFGR to activate the I2S functionalities and choose the
225+
// I2S standard through the I2SSTD[1:0] and PCMSYNC bits, the data length through the
226+
// DATLEN[1:0] bits and the number of bits per channel by configuring the CHLEN bit.
227+
// Select also the I2S master mode and direction (Transmitter or Receiver) through the
228+
// I2SCFG[1:0] bits in the SPI_I2SCFGR register.
229+
230+
// 4. If needed, select all the potential interruption sources and the DMA capabilities by
231+
// writing the SPI_CR2 register.
232+
233+
// 5. The I2SE bit in SPI_I2SCFGR register must be set.
234+
235+
T::REGS.i2scfgr().modify(|w| {
236+
w.set_i2se(false);
237+
238+
w.set_ckpol(config.clock_polarity.ckpol());
239+
240+
w.set_i2smod(true);
241+
w.set_i2sstd(config.standard.i2sstd());
242+
w.set_pcmsync(config.standard.pcmsync());
243+
244+
w.set_datlen(config.format.datlen());
245+
w.set_chlen(config.format.chlen());
246+
247+
w.set_i2scfg(match (config.mode, config.function) {
248+
(Mode::Master, Function::Transmit) => I2scfg::MASTERTX,
249+
(Mode::Master, Function::Receive) => I2scfg::MASTERRX,
250+
(Mode::Slave, Function::Transmit) => I2scfg::SLAVETX,
251+
(Mode::Slave, Function::Receive) => I2scfg::SLAVERX,
252+
});
253+
254+
w.set_i2se(true)
255+
});
256+
}
257+
258+
Self {
259+
_peri: spi,
260+
sd: Some(sd.map_into()),
261+
ws: Some(ws.map_into()),
262+
ck: Some(ck.map_into()),
263+
mck: None,
264+
}
265+
}
266+
165267
/// Note: Full-Duplex modes are not supported at this time
166268
pub fn new(
167269
peri: impl Peripheral<P = T> + 'd,
@@ -273,6 +375,20 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
273375
self._peri.write(data).await
274376
}
275377

378+
/// Write audio data.
379+
pub fn writer(&mut self, data: &[u16]) -> Result<(), Error> {
380+
let mut spi = T::REGS;
381+
382+
// let dr = spi.dr().as_ptr() as *mut W;
383+
384+
for sample in data {
385+
while !spi.sr().read().txe() {}
386+
spi.dr().write(|reg| reg.set_dr(*sample));
387+
}
388+
389+
Ok(())
390+
}
391+
276392
/// Read audio data.
277393
pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error>
278394
where

0 commit comments

Comments
 (0)