Skip to content

Commit 30fddad

Browse files
committed
add support i2s without master clock
1 parent 1a0b435 commit 30fddad

File tree

4 files changed

+257
-7
lines changed

4 files changed

+257
-7
lines changed

embassy-stm32/src/i2s.rs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Inter-IC Sound (I2S)
22
use embassy_hal_internal::into_ref;
3+
use stm32_metapac::SPI3;
34

45
use crate::gpio::sealed::{AFType, Pin as _};
56
use crate::gpio::AnyPin;
@@ -154,7 +155,7 @@ impl Default for Config {
154155

155156
/// I2S driver.
156157
pub struct I2S<'d, T: Instance, Tx, Rx> {
157-
_peri: Spi<'d, T, Tx, Rx>,
158+
pub _peri: Spi<'d, T, Tx, Rx>,
158159
sd: Option<PeripheralRef<'d, AnyPin>>,
159160
ws: Option<PeripheralRef<'d, AnyPin>>,
160161
ck: Option<PeripheralRef<'d, AnyPin>>,
@@ -196,6 +197,8 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
196197

197198
let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format);
198199

200+
defmt::println!("odd: {}, div {}", odd, div);
201+
199202
#[cfg(any(spi_v1, spi_f1))]
200203
{
201204
use stm32_metapac::spi::vals::{I2scfg, Odd};
@@ -215,6 +218,9 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
215218
w.set_mckoe(config.master_clock);
216219
});
217220

221+
// T::REGS.cr2().modify(|r| r.set_txdmaen(true));
222+
// T::REGS.dr().write(|w| w.set_dr(0x0000_u16));
223+
218224
// 2. Select the CKPOL bit to define the steady level for the communication clock. Set the
219225
// MCKOE bit in the SPI_I2SPR register if the master clock MCK needs to be provided to
220226
// the external DAC/ADC audio component (the I2SDIV and ODD values should be
@@ -379,13 +385,30 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
379385
pub fn writer(&mut self, data: &[u16]) -> Result<(), Error> {
380386
let mut spi = T::REGS;
381387

388+
// spi.cr2().modify(|r| {
389+
// r.set_frf(vals::Frf::TI);
390+
// r.set_ssoe(true);
391+
// });
392+
393+
spi.cr1().modify(|r| r.set_spe(true));
394+
382395
// let dr = spi.dr().as_ptr() as *mut W;
383396

384-
for sample in data {
385-
while !spi.sr().read().txe() {}
386-
spi.dr().write(|reg| reg.set_dr(*sample));
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+
}
387402
}
388403

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");
409+
410+
spi.cr1().modify(|r| r.set_spe(false));
411+
389412
Ok(())
390413
}
391414

embassy-stm32/src/spi/mod.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ pub struct Spi<'d, T: Instance, Tx, Rx> {
9090
sck: Option<PeripheralRef<'d, AnyPin>>,
9191
mosi: Option<PeripheralRef<'d, AnyPin>>,
9292
miso: Option<PeripheralRef<'d, AnyPin>>,
93-
txdma: PeripheralRef<'d, Tx>,
93+
pub txdma: PeripheralRef<'d, Tx>,
9494
rxdma: PeripheralRef<'d, Rx>,
9595
current_word_size: word_impl::Config,
9696
}
@@ -853,8 +853,7 @@ fn finish_dma(regs: Regs) {
853853
#[cfg(any(spi_v3, spi_v4, spi_v5))]
854854
while !regs.sr().read().txc() {}
855855
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
856-
while regs.sr().read().bsy() {}
857-
856+
while !regs.sr().read().txe() {}
858857
// Disable the spi peripheral
859858
regs.cr1().modify(|w| {
860859
w.set_spe(false);

embassy-usb/src/class/audio.rs

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
//! AUDIO class implementation.
2+
3+
use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
4+
use crate::Builder;
5+
6+
/// This should be used as `device_class` when building the `UsbDevice`.
7+
pub const USB_AUDIO_CLASS: u8 = 0x01;
8+
9+
const USB_AUDIOCONTROL_SUBCLASS: u8 = 0x01;
10+
const USB_MIDISTREAMING_SUBCLASS: u8 = 0x03;
11+
const MIDI_IN_JACK_SUBTYPE: u8 = 0x02;
12+
const MIDI_OUT_JACK_SUBTYPE: u8 = 0x03;
13+
const EMBEDDED: u8 = 0x01;
14+
const EXTERNAL: u8 = 0x02;
15+
const CS_INTERFACE: u8 = 0x24;
16+
const CS_ENDPOINT: u8 = 0x25;
17+
const HEADER_SUBTYPE: u8 = 0x01;
18+
const MS_HEADER_SUBTYPE: u8 = 0x01;
19+
const MS_GENERAL: u8 = 0x01;
20+
const PROTOCOL_NONE: u8 = 0x00;
21+
const MIDI_IN_SIZE: u8 = 0x06;
22+
const MIDI_OUT_SIZE: u8 = 0x09;
23+
24+
/// Packet level implementation of a USB AUDIO device.
25+
///
26+
/// This class can be used directly and it has the least overhead due to directly reading and
27+
/// writing USB packets with no intermediate buffers, but it will not act like a stream-like port.
28+
/// The following constraints must be followed if you use this class directly:
29+
///
30+
/// - `read_packet` must be called with a buffer large enough to hold `max_packet_size` bytes.
31+
/// - `write_packet` must not be called with a buffer larger than `max_packet_size` bytes.
32+
/// - If you write a packet that is exactly `max_packet_size` bytes long, it won't be processed by the
33+
/// host operating system until a subsequent shorter packet is sent. A zero-length packet (ZLP)
34+
/// can be sent if there is no other data to send. This is because USB bulk transactions must be
35+
/// terminated with a short packet, even if the bulk endpoint is used for stream-like data.
36+
pub struct AudioClass<'d, D: Driver<'d>> {
37+
read_ep: D::EndpointOut,
38+
write_ep: D::EndpointIn,
39+
}
40+
41+
impl<'d, D: Driver<'d>> AudioClass<'d, D> {
42+
/// Creates a new `AudioClass` with the provided UsbBus, number of input and output jacks and `max_packet_size` in bytes.
43+
/// For full-speed devices, `max_packet_size` has to be one of 8, 16, 32 or 64.
44+
pub fn new(builder: &mut Builder<'d, D>, n_in_jacks: u8, n_out_jacks: u8, max_packet_size: u16) -> Self {
45+
let mut func = builder.function(USB_AUDIO_CLASS, USB_AUDIOCONTROL_SUBCLASS, PROTOCOL_NONE);
46+
47+
// Audio control interface
48+
let mut iface = func.interface();
49+
let audio_if = iface.interface_number();
50+
let midi_if = u8::from(audio_if) + 1;
51+
let mut alt = iface.alt_setting(USB_AUDIO_CLASS, USB_AUDIOCONTROL_SUBCLASS, PROTOCOL_NONE, None);
52+
alt.descriptor(CS_INTERFACE, &[HEADER_SUBTYPE, 0x00, 0x01, 0x09, 0x00, 0x01, midi_if]);
53+
54+
// MIDIStreaming interface
55+
let mut iface = func.interface();
56+
let _midi_if = iface.interface_number();
57+
let mut alt = iface.alt_setting(USB_AUDIO_CLASS, USB_MIDISTREAMING_SUBCLASS, PROTOCOL_NONE, None);
58+
59+
let midi_streaming_total_length = 7
60+
+ (n_in_jacks + n_out_jacks) as usize * (MIDI_IN_SIZE + MIDI_OUT_SIZE) as usize
61+
+ 7
62+
+ (4 + n_out_jacks as usize)
63+
+ 7
64+
+ (4 + n_in_jacks as usize);
65+
66+
alt.descriptor(
67+
CS_INTERFACE,
68+
&[
69+
MS_HEADER_SUBTYPE,
70+
0x00,
71+
0x01,
72+
(midi_streaming_total_length & 0xFF) as u8,
73+
((midi_streaming_total_length >> 8) & 0xFF) as u8,
74+
],
75+
);
76+
77+
// Calculates the index'th external midi in jack id
78+
let in_jack_id_ext = |index| 2 * index + 1;
79+
// Calculates the index'th embedded midi out jack id
80+
let out_jack_id_emb = |index| 2 * index + 2;
81+
// Calculates the index'th external midi out jack id
82+
let out_jack_id_ext = |index| 2 * n_in_jacks + 2 * index + 1;
83+
// Calculates the index'th embedded midi in jack id
84+
let in_jack_id_emb = |index| 2 * n_in_jacks + 2 * index + 2;
85+
86+
for i in 0..n_in_jacks {
87+
alt.descriptor(CS_INTERFACE, &[MIDI_IN_JACK_SUBTYPE, EXTERNAL, in_jack_id_ext(i), 0x00]);
88+
}
89+
90+
for i in 0..n_out_jacks {
91+
alt.descriptor(CS_INTERFACE, &[MIDI_IN_JACK_SUBTYPE, EMBEDDED, in_jack_id_emb(i), 0x00]);
92+
}
93+
94+
for i in 0..n_out_jacks {
95+
alt.descriptor(
96+
CS_INTERFACE,
97+
&[
98+
MIDI_OUT_JACK_SUBTYPE,
99+
EXTERNAL,
100+
out_jack_id_ext(i),
101+
0x01,
102+
in_jack_id_emb(i),
103+
0x01,
104+
0x00,
105+
],
106+
);
107+
}
108+
109+
for i in 0..n_in_jacks {
110+
alt.descriptor(
111+
CS_INTERFACE,
112+
&[
113+
MIDI_OUT_JACK_SUBTYPE,
114+
EMBEDDED,
115+
out_jack_id_emb(i),
116+
0x01,
117+
in_jack_id_ext(i),
118+
0x01,
119+
0x00,
120+
],
121+
);
122+
}
123+
124+
let mut endpoint_data = [
125+
MS_GENERAL, 0, // Number of jacks
126+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Jack mappings
127+
];
128+
endpoint_data[1] = n_out_jacks;
129+
for i in 0..n_out_jacks {
130+
endpoint_data[2 + i as usize] = in_jack_id_emb(i);
131+
}
132+
let read_ep = alt.endpoint_bulk_out(max_packet_size);
133+
alt.descriptor(CS_ENDPOINT, &endpoint_data[0..2 + n_out_jacks as usize]);
134+
135+
endpoint_data[1] = n_in_jacks;
136+
for i in 0..n_in_jacks {
137+
endpoint_data[2 + i as usize] = out_jack_id_emb(i);
138+
}
139+
let write_ep = alt.endpoint_bulk_in(max_packet_size);
140+
alt.descriptor(CS_ENDPOINT, &endpoint_data[0..2 + n_in_jacks as usize]);
141+
142+
AudioClass { read_ep, write_ep }
143+
}
144+
145+
/// Gets the maximum packet size in bytes.
146+
pub fn max_packet_size(&self) -> u16 {
147+
// The size is the same for both endpoints.
148+
self.read_ep.info().max_packet_size
149+
}
150+
151+
/// Writes a single packet into the IN endpoint.
152+
pub async fn write_packet(&mut self, data: &[u8]) -> Result<(), EndpointError> {
153+
self.write_ep.write(data).await
154+
}
155+
156+
/// Reads a single packet from the OUT endpoint.
157+
pub async fn read_packet(&mut self, data: &mut [u8]) -> Result<usize, EndpointError> {
158+
self.read_ep.read(data).await
159+
}
160+
161+
/// Waits for the USB host to enable this interface
162+
pub async fn wait_connection(&mut self) {
163+
self.read_ep.wait_enabled().await;
164+
}
165+
166+
/// Split the class into a sender and receiver.
167+
///
168+
/// This allows concurrently sending and receiving packets from separate tasks.
169+
pub fn split(self) -> (Sender<'d, D>, Receiver<'d, D>) {
170+
(
171+
Sender {
172+
write_ep: self.write_ep,
173+
},
174+
Receiver { read_ep: self.read_ep },
175+
)
176+
}
177+
}
178+
179+
/// Midi class packet sender.
180+
///
181+
/// You can obtain a `Sender` with [`AudioClass::split`]
182+
pub struct Sender<'d, D: Driver<'d>> {
183+
write_ep: D::EndpointIn,
184+
}
185+
186+
impl<'d, D: Driver<'d>> Sender<'d, D> {
187+
/// Gets the maximum packet size in bytes.
188+
pub fn max_packet_size(&self) -> u16 {
189+
// The size is the same for both endpoints.
190+
self.write_ep.info().max_packet_size
191+
}
192+
193+
/// Writes a single packet.
194+
pub async fn write_packet(&mut self, data: &[u8]) -> Result<(), EndpointError> {
195+
self.write_ep.write(data).await
196+
}
197+
198+
/// Waits for the USB host to enable this interface
199+
pub async fn wait_connection(&mut self) {
200+
self.write_ep.wait_enabled().await;
201+
}
202+
}
203+
204+
/// Midi class packet receiver.
205+
///
206+
/// You can obtain a `Receiver` with [`AudioClass::split`]
207+
pub struct Receiver<'d, D: Driver<'d>> {
208+
read_ep: D::EndpointOut,
209+
}
210+
211+
impl<'d, D: Driver<'d>> Receiver<'d, D> {
212+
/// Gets the maximum packet size in bytes.
213+
pub fn max_packet_size(&self) -> u16 {
214+
// The size is the same for both endpoints.
215+
self.read_ep.info().max_packet_size
216+
}
217+
218+
/// Reads a single packet.
219+
pub async fn read_packet(&mut self, data: &mut [u8]) -> Result<usize, EndpointError> {
220+
self.read_ep.read(data).await
221+
}
222+
223+
/// Waits for the USB host to enable this interface
224+
pub async fn wait_connection(&mut self) {
225+
self.read_ep.wait_enabled().await;
226+
}
227+
}

embassy-usb/src/class/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! Implementations of well-known USB classes.
2+
pub mod audio;
23
pub mod cdc_acm;
34
pub mod cdc_ncm;
45
pub mod hid;

0 commit comments

Comments
 (0)