esp_idf_hal/i2s/std.rs
1//! Standard mode driver for the ESP32 I2S peripheral.
2//!
3//! # Microcontroller support for Standard mode
4//!
5//! | Microcontroller | Standard Rx | Standard Tx |
6//! |--------------------|-----------------|-----------------|
7//! | ESP32 | I2S0, I2S1 | I2S0, I2S11 |
8//! | ESP32-S2 | I2S0 | I2S0 |
9//! | ESP32-S3 | I2S0, I2S1 | I2S0, I2S1 |
10//! | ESP32-C2 (ESP8684) | _not supported_ | _not supported_ |
11//! | ESP32-C3 | I2S0 | I2S0 |
12//! | ESP32-C6 | I2S0 | I2S0 |
13//! | ESP32-H2 | I2S0 | I2S0 |
14
15use super::*;
16use crate::gpio::*;
17
18use esp_idf_sys::*;
19
20pub(super) mod config {
21 #[allow(unused)]
22 use crate::{gpio::*, i2s::config::*};
23 use esp_idf_sys::*;
24
25 /// Standard mode configuration for the I2S peripheral.
26 pub struct StdConfig {
27 /// The base channel configuration.
28 #[allow(dead_code)]
29 pub(super) channel_cfg: Config,
30
31 /// Standard mode channel clock configuration.
32 #[allow(dead_code)]
33 clk_cfg: StdClkConfig,
34
35 /// Standard mode channel slot configuration.
36 #[allow(dead_code)]
37 slot_cfg: StdSlotConfig,
38
39 /// Standard mode channel GPIO configuration.
40 #[cfg(not(esp_idf_version_major = "4"))]
41 #[allow(dead_code)]
42 gpio_cfg: StdGpioConfig,
43 }
44
45 impl StdConfig {
46 /// Create a new standard mode channel configuration from the given clock configuration, slot configuration,
47 /// and GPIO configuration.
48 pub fn new(
49 channel_cfg: Config,
50 clk_cfg: StdClkConfig,
51 slot_cfg: StdSlotConfig,
52 #[cfg(not(esp_idf_version_major = "4"))] gpio_cfg: StdGpioConfig,
53 ) -> Self {
54 Self {
55 channel_cfg,
56 clk_cfg,
57 slot_cfg,
58 #[cfg(not(esp_idf_version_major = "4"))]
59 gpio_cfg,
60 }
61 }
62
63 /// Create a new standard mode channel configuration for the Philips I2S protocol with the specified sample
64 /// rate and bits per sample, in stereo mode, with MCLK set to 256 times the sample rate.
65 #[inline(always)]
66 pub fn philips(sample_rate_hz: u32, bits_per_sample: DataBitWidth) -> Self {
67 Self {
68 channel_cfg: Config::default(),
69 clk_cfg: StdClkConfig::from_sample_rate_hz(sample_rate_hz),
70 slot_cfg: StdSlotConfig::philips_slot_default(bits_per_sample, SlotMode::Stereo),
71 #[cfg(not(esp_idf_version_major = "4"))]
72 gpio_cfg: StdGpioConfig::default(),
73 }
74 }
75
76 /// Create a new standard mode channel configuration for the PCM I2S protocol with the specified sample rate
77 /// and bits per sample, in stereo mode, with MCLK set to 256 times the sample rate.
78 #[inline(always)]
79 pub fn pcm(sample_rate_hz: u32, bits_per_sample: DataBitWidth) -> Self {
80 Self {
81 channel_cfg: Config::default(),
82 clk_cfg: StdClkConfig::from_sample_rate_hz(sample_rate_hz),
83 slot_cfg: StdSlotConfig::pcm_slot_default(bits_per_sample, SlotMode::Stereo),
84 #[cfg(not(esp_idf_version_major = "4"))]
85 gpio_cfg: StdGpioConfig::default(),
86 }
87 }
88
89 /// Create a new standard mode channel configuration for the MSB I2S protocol with the specified sample rate
90 /// and bits per sample, in stereo mode, with MCLK set to 256 times the sample rate.
91 #[inline(always)]
92 pub fn msb(sample_rate_hz: u32, bits_per_sample: DataBitWidth) -> Self {
93 Self {
94 channel_cfg: Config::default(),
95 clk_cfg: StdClkConfig::from_sample_rate_hz(sample_rate_hz),
96 slot_cfg: StdSlotConfig::msb_slot_default(bits_per_sample, SlotMode::Stereo),
97 #[cfg(not(esp_idf_version_major = "4"))]
98 gpio_cfg: StdGpioConfig::default(),
99 }
100 }
101
102 /// Convert to the ESP-IDF SDK `i2s_std_config_t` representation.
103 #[cfg(not(esp_idf_version_major = "4"))]
104 #[inline(always)]
105 pub(crate) fn as_sdk<'d>(
106 &self,
107 bclk: impl InputPin + OutputPin + 'd,
108 din: Option<impl InputPin + 'd>,
109 dout: Option<impl OutputPin + 'd>,
110 mclk: Option<impl InputPin + OutputPin + 'd>,
111 ws: impl InputPin + OutputPin + 'd,
112 ) -> i2s_std_config_t {
113 i2s_std_config_t {
114 clk_cfg: self.clk_cfg.as_sdk(),
115 slot_cfg: self.slot_cfg.as_sdk(),
116 gpio_cfg: self.gpio_cfg.as_sdk(bclk, din, dout, mclk, ws),
117 }
118 }
119
120 /// Convert to the ESP-IDF SDK `i2s_driver_config_t` representation.
121 ///
122 /// # Note
123 /// The mode field is not fully set by this function. Only the controller/target field is set. Before using,
124 /// the following bits must be considered: `I2S_MODE_TX`, `I2S_MODE_RX`, `I2S_MODE_DAC_BUILT_IN`, and
125 /// `I2S_MODE_ADC_BUILT_IN`. (`I2S_MODE_PDM` should not be used here.)
126 #[cfg(esp_idf_version_major = "4")]
127 pub(crate) fn as_sdk(&self) -> i2s_driver_config_t {
128 let chan_fmt = match self.slot_cfg.slot_mode {
129 SlotMode::Stereo => i2s_channel_fmt_t_I2S_CHANNEL_FMT_RIGHT_LEFT,
130 SlotMode::Mono => match self.slot_cfg.slot_mask {
131 StdSlotMask::Both => i2s_channel_fmt_t_I2S_CHANNEL_FMT_RIGHT_LEFT,
132 StdSlotMask::Left => i2s_channel_fmt_t_I2S_CHANNEL_FMT_ONLY_LEFT,
133 StdSlotMask::Right => i2s_channel_fmt_t_I2S_CHANNEL_FMT_ONLY_RIGHT,
134 },
135 };
136
137 i2s_driver_config_t {
138 mode: self.channel_cfg.role.as_sdk(),
139 sample_rate: self.clk_cfg.sample_rate_hz,
140 bits_per_sample: self.slot_cfg.data_bit_width.as_sdk(),
141 channel_format: chan_fmt,
142 communication_format: self.slot_cfg.comm_fmt.as_sdk(),
143 intr_alloc_flags: 1 << 1, // ESP_INTR_FLAG_LEVEL1
144 dma_buf_count: self.channel_cfg.dma_buffer_count as i32,
145 dma_buf_len: self.channel_cfg.frames_per_buffer as i32,
146 #[cfg(any(esp32, esp32s2))]
147 use_apll: matches!(self.clk_cfg.clk_src, ClockSource::Apll),
148 #[cfg(not(any(esp32, esp32s2)))]
149 use_apll: false,
150 tx_desc_auto_clear: self.channel_cfg.auto_clear,
151 fixed_mclk: 0,
152 mclk_multiple: self.clk_cfg.mclk_multiple.as_sdk(),
153 bits_per_chan: self.slot_cfg.slot_bit_width.as_sdk(),
154
155 // The following are TDM-only fields and are not present on chips that don't support TDM mode.
156 // There's no cfg option for this (it's a constant in esp-idf-sys).
157 #[cfg(not(any(esp32, esp32s2)))]
158 chan_mask: 0,
159 #[cfg(not(any(esp32, esp32s2)))]
160 total_chan: 0,
161 #[cfg(not(any(esp32, esp32s2)))]
162 left_align: self.slot_cfg.left_align,
163 #[cfg(not(any(esp32, esp32s2)))]
164 big_edin: self.slot_cfg.big_endian,
165 #[cfg(not(any(esp32, esp32s2)))]
166 bit_order_msb: !self.slot_cfg.bit_order_lsb,
167 #[cfg(not(any(esp32, esp32s2)))]
168 skip_msk: true,
169 }
170 }
171 }
172
173 /// Standard mode channel clock configuration.
174 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
175 pub struct StdClkConfig {
176 /// I2S sample rate.
177 sample_rate_hz: u32,
178
179 /// Clock source.
180 clk_src: ClockSource,
181
182 /// The multiple of MCLK to the sample rate.
183 mclk_multiple: MclkMultiple,
184 }
185
186 impl StdClkConfig {
187 /// Create a standard clock configuration with the specified rate (in Hz), clock source, and MCLK multiple of
188 /// the sample rate.
189 #[inline(always)]
190 pub fn new(sample_rate_hz: u32, clk_src: ClockSource, mclk_multiple: MclkMultiple) -> Self {
191 Self {
192 sample_rate_hz,
193 clk_src,
194 mclk_multiple,
195 }
196 }
197
198 /// Create a standard clock configuration with the specified rate in Hz. This will set the clock source to
199 /// PLL_F160M and the MCLK multiple to 256 times the sample rate.
200 ///
201 /// # Note
202 /// Set the mclk_multiple to [MclkMultiple::M384] when using 24-bit data width. Otherwise, the sample rate
203 /// might be imprecise since the BCLK division is not an integer.
204 #[inline(always)]
205 pub fn from_sample_rate_hz(rate: u32) -> Self {
206 Self {
207 sample_rate_hz: rate,
208 clk_src: ClockSource::default(),
209 mclk_multiple: MclkMultiple::M256,
210 }
211 }
212
213 /// Set the clock source on this standard clock configuration.
214 #[inline(always)]
215 pub fn clk_src(mut self, clk_src: ClockSource) -> Self {
216 self.clk_src = clk_src;
217 self
218 }
219
220 /// Set the MCLK multiple on this standard clock configuration.
221 #[inline(always)]
222 pub fn mclk_multiple(mut self, mclk_multiple: MclkMultiple) -> Self {
223 self.mclk_multiple = mclk_multiple;
224 self
225 }
226
227 /// Convert to the ESP-IDF SDK `i2s_std_clk_config_t` representation.
228 #[cfg(not(esp_idf_version_major = "4"))]
229 #[allow(clippy::needless_update)]
230 #[inline(always)]
231 pub(crate) fn as_sdk(&self) -> i2s_std_clk_config_t {
232 i2s_std_clk_config_t {
233 sample_rate_hz: self.sample_rate_hz,
234 clk_src: self.clk_src.as_sdk(),
235 mclk_multiple: self.mclk_multiple.as_sdk(),
236 ..Default::default()
237 }
238 }
239 }
240
241 /// The communication format used by the v4 driver.
242 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
243 pub enum StdCommFormat {
244 /// Standard I2S/Philips format.
245 #[default]
246 Philips,
247
248 /// MSB-aligned format (data present at first bit clock).
249 Msb,
250
251 /// PCM short standard. Word select is one bit clock.
252 PcmShort,
253
254 /// PCM long standard. Word select is the same as the data bit width.
255 PcmLong,
256 }
257
258 impl StdCommFormat {
259 #[cfg(esp_idf_version_major = "4")]
260 #[inline(always)]
261 pub(in crate::i2s) fn as_sdk(&self) -> i2s_comm_format_t {
262 match self {
263 Self::Philips => i2s_comm_format_t_I2S_COMM_FORMAT_STAND_I2S,
264 Self::Msb => i2s_comm_format_t_I2S_COMM_FORMAT_STAND_MSB,
265 Self::PcmShort => i2s_comm_format_t_I2S_COMM_FORMAT_PCM_SHORT,
266 Self::PcmLong => i2s_comm_format_t_I2S_COMM_FORMAT_PCM_LONG,
267 }
268 }
269 }
270
271 /// Standard mode GPIO (general purpose input/output) configuration.
272 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
273 pub struct StdGpioConfig {
274 /// Invert the BCLK signal.
275 bclk_invert: bool,
276
277 /// Invert the MCLK signal.
278 mclk_invert: bool,
279
280 /// Invert the WS signal.
281 ws_invert: bool,
282 }
283
284 impl StdGpioConfig {
285 /// Create a new standard mode GPIO configuration with the specified inversion flags for BCLK, MCLK, and WS.
286 pub fn new(bclk_invert: bool, mclk_invert: bool, ws_invert: bool) -> Self {
287 Self {
288 bclk_invert,
289 mclk_invert,
290 ws_invert,
291 }
292 }
293
294 /// Set the BCLK inversion flag on this standard GPIO configuration.
295 #[inline(always)]
296 pub fn bclk_invert(mut self, bclk_invert: bool) -> Self {
297 self.bclk_invert = bclk_invert;
298 self
299 }
300
301 /// Set the MCLK inversion flag on this standard GPIO configuration.
302 #[inline(always)]
303 pub fn mclk_invert(mut self, mclk_invert: bool) -> Self {
304 self.mclk_invert = mclk_invert;
305 self
306 }
307
308 /// Set the WS inversion flag on this standard GPIO configuration.
309 #[inline(always)]
310 pub fn ws_invert(mut self, ws_invert: bool) -> Self {
311 self.ws_invert = ws_invert;
312 self
313 }
314
315 /// Convert to the ESP-IDF SDK `i2s_std_gpio_config_t` representation.
316 #[cfg(not(esp_idf_version_major = "4"))]
317 pub(crate) fn as_sdk<'d>(
318 &self,
319 bclk: impl InputPin + OutputPin + 'd,
320 din: Option<impl InputPin + 'd>,
321 dout: Option<impl OutputPin + 'd>,
322 mclk: Option<impl InputPin + OutputPin + 'd>,
323 ws: impl InputPin + OutputPin + 'd,
324 ) -> i2s_std_gpio_config_t {
325 let invert_flags = i2s_std_gpio_config_t__bindgen_ty_1 {
326 _bitfield_1: i2s_std_gpio_config_t__bindgen_ty_1::new_bitfield_1(
327 self.mclk_invert as u32,
328 self.bclk_invert as u32,
329 self.ws_invert as u32,
330 ),
331 ..Default::default()
332 };
333
334 i2s_std_gpio_config_t {
335 bclk: bclk.pin() as _,
336 din: if let Some(din) = din {
337 din.pin() as _
338 } else {
339 -1
340 },
341 dout: if let Some(dout) = dout {
342 dout.pin() as _
343 } else {
344 -1
345 },
346 mclk: if let Some(mclk) = mclk {
347 mclk.pin() as _
348 } else {
349 -1
350 },
351 ws: ws.pin() as _,
352 invert_flags,
353 }
354 }
355 }
356
357 /// Standard mode channel slot configuration.
358 ///
359 /// To create a slot configuration, use [`StdSlotConfig::philips_slot_default`], [`StdSlotConfig::pcm_slot_default`], or
360 /// [`StdSlotConfig::msb_slot_default`], then customize it as needed.
361 ///
362 /// # Note
363 /// The `slot_mode` and `slot_mask` cause the data to be interpreted in different ways, as noted below.
364 /// WS is the "word select" signal, sometimes called LRCLK (left/right clock).
365 ///
366 /// ## Transmit
367 ///
368 /// Assuming the buffered data contains the following samples (where a sample may be 1, 2, 3, or 4 bytes, depending
369 /// on `data_bit_width`):
370 ///
371 /// | **`d[0]`** | **`d[1]`** | **`d[2]`** | **`d[3]`** | **`d[4]`** | **`d[5]`** | **`d[6]`** | **`d[7]`** |
372 /// |------------|------------|------------|------------|------------|------------|------------|------------|
373 /// | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
374 ///
375 /// The actual data on the line will be:
376 ///
377 /// <table>
378 /// <thead>
379 /// <tr><th><code>slot_mode</code></th><th><code>slot_mask</code></th><th colspan=8>Transmitted Data</th></tr>
380 /// <tr><th></th><th></th><th>WS Low</th><th>WS High</th><th>WS Low</th><th>WS High</th><th>WS Low</th><th>WS High</th><th>WS Low</th><th>WS High</th></tr>
381 /// </thead>
382 /// <tbody>
383 /// <tr><td rowspan=3><code>Mono</code></td><td><code>Left</code></td> <td>11</td><td><font color="red">0</font></td><td>12</td><td><font color="red">0</font></td><td>13</td><td><font color="red">0</font></td><td>14</td><td><font color="red">0</font></td></tr>
384 /// <tr> <td><code>Right</code></td><td><font color="red">0</font></td><td>11</td><td><font color="red">0</font></td><td>12</td><td><font color="red">0</font></td><td>13</td><td><font color="red">0</font></td><td>14</td></tr>
385 /// <tr> <td><code>Both</code></td> <td>11</td><td>11</td><td>12</td><td>12</td><td>13</td><td>13</td><td>14</td><td>14</td></tr>
386 /// <tr><td rowspan=3><code>Stereo</code></td><td><code>Left</code></td> <td>11</td><td><font color="red">0</font></td><td>13</td><td><font color="red">0</font></td><td>15</td><td><font color="red">0</font></td><td>17</td><td><font color="red">0</font></td></tr>
387 /// <tr> <td><code>Right</code></td><td><font color="red">0</font></td><td>12</td><td><font color="red">0</font></td><td>14</td><td><font color="red">0</font></td><td>16</td><td><font color="red">0</font></td><td>18</td></tr>
388 /// <tr> <td><code>Both</code></td> <td>11</td><td>12</td><td>13</td><td>14</td><td>15</td><td>16</td><td>17</td><td>18</td></tr>
389 /// </tbody>
390 /// </table>
391 ///
392 ///
393 /// ## Receive
394 ///
395 /// Assuming the received data contains the following samples (where a sample may be 8, 16, 24, or 32 bits, depending on `data_bit_width`):
396 ///
397 /// | **WS Low** | **WS High** | **WS Low** | **WS High** | **WS Low** | **WS High** | **WS Low** | **WS High** | |
398 /// |-------------|-------------|-------------|-------------|-------------|-------------|-------------|-------------|-----|
399 /// | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ... |
400 ///
401 /// The actual data in the buffer will be (1-4 bytes, depending on `data_bit_width`):
402 ///
403 /// <table>
404 /// <thead>
405 /// <tr><th><code>slot_mode</code></th><th><code>slot_mask</code></th><th colspan=8>Buffer Contents</th></tr>
406 /// <tr><th></th><th></th><th><code>d[0]</code></th><th><code>d[1]</code></th><th><code>d[2]</code></th><th><code>d[3]</code></th><th><code>d[4]</code></th><th><code>d[5]</code></th><th><code>d[6]</code></th><th><code>d[7]</code></th></tr>
407 /// </thead>
408 /// <tbody>
409 /// <tr><td rowspan=3><code>Mono</code></td> <td><code>Left</code></td> <td>11</td><td>13</td><td>15</td><td>17</td><td>19</td><td>21</td><td>23</td><td>25</td></tr>
410 /// <tr> <td><code>Right</code></td><td>12</td><td>14</td><td>16</td><td>18</td><td>20</td><td>22</td><td>24</td><td>26</td></tr>
411 /// <tr> <td><code>Both</code></td> <td colspan=8><i>Unspecified behavior</i></td></tr>
412 /// <tr><td rowspan=2><code>Stereo</code></td><td><i>Any</i></td> <td>11</td><td>12</td><td>13</td><td>14</td><td>15</td><td>16</td><td>17</td><td>18</td></tr>
413 /// </tbody>
414 /// </table>
415 ///
416 /// For details, refer to the
417 /// _ESP-IDF Programming Guide_ details for your specific microcontroller:
418 /// * ESP32: [STD Tx Mode](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/i2s.html#std-tx-mode) / [STD Rx Mode](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/i2s.html#std-rx-mode).
419 /// * ESP32-S2: [STD Tx Mode](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/api-reference/peripherals/i2s.html#std-tx-mode) / [STD Rx Mode](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/api-reference/peripherals/i2s.html#std-tx-mode)
420 /// * ESP32-S3: [STD Tx Mode](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/i2s.html#std-tx-mode) / [STD Rx Mode](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/i2s.html#std-tx-mode)
421 /// * ESP32-C3: [STD Tx Mode](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-reference/peripherals/i2s.html#std-tx-mode) / [STD Rx Mode](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-reference/peripherals/i2s.html#std-tx-mode).
422 /// * ESP32-C6: [STD Tx Mode](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/api-reference/peripherals/i2s.html#std-tx-mode) / [STD Rx Mode](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/api-reference/peripherals/i2s.html#std-tx-mode).
423 /// * ESP32-H2: [STD Tx Mode](https://docs.espressif.com/projects/esp-idf/en/latest/esp32h2/api-reference/peripherals/i2s.html#std-tx-mode) / [STD Rx Mode](https://docs.espressif.com/projects/esp-idf/en/latest/esp32h2/api-reference/peripherals/i2s.html#std-tx-mode).
424 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
425 pub struct StdSlotConfig {
426 /// I2S sample data bit width (valid data bits per sample).
427 data_bit_width: DataBitWidth,
428
429 /// I2S slot bit width (total bits per slot).
430 slot_bit_width: SlotBitWidth,
431
432 /// Mono or stereo mode operation.
433 slot_mode: SlotMode,
434
435 /// Are we using the left, right, or both data slots?
436 slot_mask: StdSlotMask,
437
438 /// The word select (WS) signal width, in terms of the bit clock (BCK) periods.
439 #[cfg(not(esp_idf_version_major = "4"))]
440 ws_width: u32,
441
442 /// The word select signal polarity; true enables the light lever first.
443 #[cfg(not(esp_idf_version_major = "4"))]
444 ws_polarity: bool,
445
446 /// Set to enable the additional bit-shift needed in Philips mode.
447 #[cfg(not(esp_idf_version_major = "4"))]
448 bit_shift: bool,
449
450 /// ESP32/ESP32S2 only: place the right slot data in the MSB in the FIFO.
451 #[cfg(all(any(esp32, esp32s2), not(esp_idf_version_major = "4")))]
452 msb_right: bool,
453
454 /// The communication format used by the driver.
455 #[cfg(esp_idf_version_major = "4")]
456 comm_fmt: StdCommFormat,
457
458 /// Non-ESP32/ESP32S2: enable left-alignment
459 #[cfg(not(any(esp32, esp32s2)))]
460 left_align: bool,
461
462 /// Non-ESP32/ESP32S2: Enable big-endian.
463 #[cfg(not(any(esp32, esp32s2)))]
464 big_endian: bool,
465
466 /// Non-ESP32/ESP32S2: Enable LSB-first.
467 #[cfg(not(any(esp32, esp32s2)))]
468 bit_order_lsb: bool,
469 }
470
471 impl StdSlotConfig {
472 /// Update the data bit width on this standard slot configuration.
473 #[inline(always)]
474 pub fn data_bit_width(mut self, data_bit_width: DataBitWidth) -> Self {
475 self.data_bit_width = data_bit_width;
476 self
477 }
478
479 /// Update the slot bit width on this standard slot configuration.
480 #[inline(always)]
481 pub fn slot_bit_width(mut self, slot_bit_width: SlotBitWidth) -> Self {
482 self.slot_bit_width = slot_bit_width;
483 self
484 }
485
486 /// Update the slot mode and mask on this standard slot configuration.
487 #[inline(always)]
488 pub fn slot_mode_mask(mut self, slot_mode: SlotMode, slot_mask: StdSlotMask) -> Self {
489 self.slot_mode = slot_mode;
490 self.slot_mask = slot_mask;
491 self
492 }
493
494 /// Update the word select signal width on this standard slot configuration.
495 #[cfg(not(esp_idf_version_major = "4"))]
496 #[inline(always)]
497 pub fn ws_width(mut self, ws_width: u32) -> Self {
498 self.ws_width = ws_width;
499 self
500 }
501
502 /// Update the word select signal polarity on this standard slot configuration.
503 #[cfg(not(esp_idf_version_major = "4"))]
504 #[inline(always)]
505 pub fn ws_polarity(mut self, ws_polarity: bool) -> Self {
506 self.ws_polarity = ws_polarity;
507 self
508 }
509
510 /// Update the bit shift flag on this standard slot configuration.
511 #[cfg(not(esp_idf_version_major = "4"))]
512 #[inline(always)]
513 pub fn bit_shift(mut self, bit_shift: bool) -> Self {
514 self.bit_shift = bit_shift;
515 self
516 }
517
518 /// Update the MSB-right flag on this standard slot configuration.
519 #[cfg(all(any(esp32, esp32s2), not(esp_idf_version_major = "4")))]
520 #[inline(always)]
521 pub fn msb_right(mut self, msb_right: bool) -> Self {
522 self.msb_right = msb_right;
523 self
524 }
525
526 /// Update the communication format on this standard slot configuration.
527 #[cfg(esp_idf_version_major = "4")]
528 #[inline(always)]
529 pub fn comm_fmt(mut self, comm_fmt: StdCommFormat) -> Self {
530 self.comm_fmt = comm_fmt;
531 self
532 }
533
534 /// Update the left-alignment flag on this standard slot configuration.
535 #[cfg(not(any(esp32, esp32s2)))]
536 #[inline(always)]
537 pub fn left_align(mut self, left_align: bool) -> Self {
538 self.left_align = left_align;
539 self
540 }
541
542 /// Update the big-endian flag on this standard slot configuration.
543 #[cfg(not(any(esp32, esp32s2)))]
544 #[inline(always)]
545 pub fn big_endian(mut self, big_endian: bool) -> Self {
546 self.big_endian = big_endian;
547 self
548 }
549
550 /// Update the LSB-first flag on this standard slot configuration.
551 #[cfg(not(any(esp32, esp32s2)))]
552 #[inline(always)]
553 pub fn bit_order_lsb(mut self, bit_order_lsb: bool) -> Self {
554 self.bit_order_lsb = bit_order_lsb;
555 self
556 }
557
558 /// Configure in Philips format in 2 slots.
559 pub fn philips_slot_default(bits_per_sample: DataBitWidth, slot_mode: SlotMode) -> Self {
560 let slot_mask = if slot_mode == SlotMode::Mono {
561 StdSlotMask::Left
562 } else {
563 StdSlotMask::Both
564 };
565
566 Self {
567 data_bit_width: bits_per_sample,
568 slot_bit_width: SlotBitWidth::Auto,
569 slot_mode,
570 slot_mask,
571 #[cfg(not(esp_idf_version_major = "4"))]
572 ws_width: bits_per_sample.into(),
573 #[cfg(not(esp_idf_version_major = "4"))]
574 ws_polarity: false,
575 #[cfg(not(esp_idf_version_major = "4"))]
576 bit_shift: true,
577 #[cfg(all(esp32, not(esp_idf_version_major = "4")))]
578 msb_right: bits_per_sample <= DataBitWidth::Bits16,
579 #[cfg(all(esp32s2, not(esp_idf_version_major = "4")))]
580 msb_right: true,
581 #[cfg(esp_idf_version_major = "4")]
582 comm_fmt: StdCommFormat::Philips,
583 #[cfg(not(any(esp32, esp32s2)))]
584 left_align: false,
585 #[cfg(not(any(esp32, esp32s2)))]
586 big_endian: false,
587 #[cfg(not(any(esp32, esp32s2)))]
588 bit_order_lsb: false,
589 }
590 }
591
592 /// Configure in PCM (short) format in 2 slots.
593 pub fn pcm_slot_default(bits_per_sample: DataBitWidth, slot_mode: SlotMode) -> Self {
594 let slot_mask = if slot_mode == SlotMode::Mono {
595 StdSlotMask::Left
596 } else {
597 StdSlotMask::Both
598 };
599
600 Self {
601 data_bit_width: bits_per_sample,
602 slot_bit_width: SlotBitWidth::Auto,
603 slot_mode,
604 slot_mask,
605 #[cfg(not(esp_idf_version_major = "4"))]
606 ws_width: 1,
607 #[cfg(not(esp_idf_version_major = "4"))]
608 ws_polarity: true,
609 #[cfg(not(esp_idf_version_major = "4"))]
610 bit_shift: true,
611 #[cfg(all(esp32, not(esp_idf_version_major = "4")))]
612 msb_right: bits_per_sample <= DataBitWidth::Bits16,
613 #[cfg(all(esp32s2, not(esp_idf_version_major = "4")))]
614 msb_right: true,
615 #[cfg(esp_idf_version_major = "4")]
616 comm_fmt: StdCommFormat::PcmShort,
617 #[cfg(not(any(esp32, esp32s2)))]
618 left_align: false,
619 #[cfg(not(any(esp32, esp32s2)))]
620 big_endian: false,
621 #[cfg(not(any(esp32, esp32s2)))]
622 bit_order_lsb: false,
623 }
624 }
625
626 /// Configure in MSB format in 2 slots.
627 pub fn msb_slot_default(bits_per_sample: DataBitWidth, slot_mode: SlotMode) -> Self {
628 let slot_mask = if slot_mode == SlotMode::Mono {
629 StdSlotMask::Left
630 } else {
631 StdSlotMask::Both
632 };
633
634 Self {
635 data_bit_width: bits_per_sample,
636 slot_bit_width: SlotBitWidth::Auto,
637 slot_mode,
638 slot_mask,
639 #[cfg(not(esp_idf_version_major = "4"))]
640 ws_width: bits_per_sample.into(),
641 #[cfg(not(esp_idf_version_major = "4"))]
642 ws_polarity: false,
643 #[cfg(not(esp_idf_version_major = "4"))]
644 bit_shift: false,
645 #[cfg(all(esp32, not(esp_idf_version_major = "4")))]
646 msb_right: bits_per_sample <= DataBitWidth::Bits16,
647 #[cfg(all(esp32s2, not(esp_idf_version_major = "4")))]
648 msb_right: true,
649 #[cfg(esp_idf_version_major = "4")]
650 comm_fmt: StdCommFormat::Msb,
651 #[cfg(not(any(esp32, esp32s2)))]
652 left_align: false,
653 #[cfg(not(any(esp32, esp32s2)))]
654 big_endian: false,
655 #[cfg(not(any(esp32, esp32s2)))]
656 bit_order_lsb: false,
657 }
658 }
659
660 /// Convert to the ESP-IDF SDK `i2s_std_slot_config_t` representation.
661 #[cfg(not(esp_idf_version_major = "4"))]
662 pub(crate) fn as_sdk(&self) -> i2s_std_slot_config_t {
663 i2s_std_slot_config_t {
664 data_bit_width: self.data_bit_width.as_sdk(),
665 slot_bit_width: self.slot_bit_width.as_sdk(),
666 slot_mode: self.slot_mode.as_sdk(),
667 slot_mask: self.slot_mask.as_sdk(),
668 ws_width: self.ws_width,
669 ws_pol: self.ws_polarity,
670 bit_shift: self.bit_shift,
671 #[cfg(any(esp32, esp32s2))]
672 msb_right: self.msb_right,
673 #[cfg(not(any(esp32, esp32s2)))]
674 left_align: self.left_align,
675 #[cfg(not(any(esp32, esp32s2)))]
676 big_endian: self.big_endian,
677 #[cfg(not(any(esp32, esp32s2)))]
678 bit_order_lsb: self.bit_order_lsb,
679 }
680 }
681 }
682
683 /// I2S slot selection in standard mode.
684 ///
685 /// The default is `StdSlotMask::Both`.
686 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
687 pub enum StdSlotMask {
688 /// I2S transmits or receives the left slot.
689 Left,
690
691 /// I2S transmits or receives the right slot.
692 Right,
693
694 /// I2S transmits or receives both slots.
695 #[default]
696 Both,
697 }
698
699 impl StdSlotMask {
700 /// Convert to the ESP-IDF SDK `i2s_std_slot_mask_t` representation.
701 #[cfg(not(esp_idf_version_major = "4"))]
702 #[inline(always)]
703 pub(crate) fn as_sdk(&self) -> i2s_std_slot_mask_t {
704 match self {
705 Self::Left => 1 << 0,
706 Self::Right => 1 << 1,
707 Self::Both => (1 << 0) | (1 << 1),
708 }
709 }
710 }
711}
712
713impl<'d, Dir> I2sDriver<'d, Dir> {
714 #[cfg(not(esp_idf_version_major = "4"))]
715 #[allow(clippy::too_many_arguments)]
716 fn internal_new_std<I2S: I2s + 'd>(
717 _i2s: I2S,
718 config: &config::StdConfig,
719 rx: bool,
720 tx: bool,
721 bclk: impl InputPin + OutputPin + 'd,
722 din: Option<impl InputPin + 'd>,
723 dout: Option<impl OutputPin + 'd>,
724 mclk: Option<impl InputPin + OutputPin + 'd>,
725 ws: impl InputPin + OutputPin + 'd,
726 ) -> Result<Self, EspError> {
727 let chan_cfg = config.channel_cfg.as_sdk(I2S::port());
728
729 let this = Self::internal_new::<I2S>(&chan_cfg, rx, tx)?;
730
731 // Create the channel configuration.
732 let std_config = config.as_sdk(bclk, din, dout, mclk, ws);
733
734 if rx {
735 unsafe {
736 // Open the RX channel.
737 esp!(i2s_channel_init_std_mode(this.rx_handle, &std_config))?;
738 }
739 }
740
741 if tx {
742 unsafe {
743 // Open the TX channel.
744 esp!(i2s_channel_init_std_mode(this.tx_handle, &std_config))?;
745 }
746 }
747
748 Ok(this)
749 }
750
751 #[cfg(esp_idf_version_major = "4")]
752 #[allow(clippy::too_many_arguments)]
753 pub fn internal_new_std<I2S: I2s + 'd>(
754 _i2s: I2S,
755 config: &config::StdConfig,
756 rx: bool,
757 tx: bool,
758 bclk: impl InputPin + OutputPin + 'd,
759 din: Option<impl InputPin + 'd>,
760 dout: Option<impl OutputPin + 'd>,
761 mclk: Option<impl InputPin + OutputPin + 'd>,
762 ws: impl InputPin + OutputPin + 'd,
763 ) -> Result<Self, EspError> {
764 let mut driver_cfg = config.as_sdk();
765
766 if rx {
767 driver_cfg.mode |= i2s_mode_t_I2S_MODE_RX;
768 }
769
770 if tx {
771 driver_cfg.mode |= i2s_mode_t_I2S_MODE_TX;
772 }
773
774 let this = Self::internal_new::<I2S>(&driver_cfg)?;
775
776 // Set the pin configuration.
777 let pin_cfg = i2s_pin_config_t {
778 bck_io_num: bclk.pin() as _,
779 data_in_num: din.map(|din| din.pin() as _).unwrap_or(-1),
780 data_out_num: dout.map(|dout| dout.pin() as _).unwrap_or(-1),
781 mck_io_num: mclk.map(|mclk| mclk.pin() as _).unwrap_or(-1),
782 ws_io_num: ws.pin() as _,
783 };
784
785 // Safety: &pin_cfg is a valid pointer to an i2s_pin_config_t.
786 unsafe {
787 esp!(i2s_set_pin(I2S::port(), &pin_cfg))?;
788 }
789
790 Ok(this)
791 }
792}
793
794impl<'d> I2sDriver<'d, I2sBiDir> {
795 /// Create a new standard mode driver for the given I2S peripheral with both the receive and transmit channels open.
796 #[allow(clippy::too_many_arguments)]
797 pub fn new_std_bidir<I2S: I2s + 'd>(
798 i2s: I2S,
799 config: &config::StdConfig,
800 bclk: impl InputPin + OutputPin + 'd,
801 din: impl InputPin + 'd,
802 dout: impl OutputPin + 'd,
803 mclk: Option<impl InputPin + OutputPin + 'd>,
804 ws: impl InputPin + OutputPin + 'd,
805 ) -> Result<Self, EspError> {
806 Self::internal_new_std(
807 i2s,
808 config,
809 true,
810 true,
811 bclk,
812 Some(din),
813 Some(dout),
814 mclk,
815 ws,
816 )
817 }
818}
819
820impl<'d> I2sDriver<'d, I2sRx> {
821 /// Create a new standard mode driver for the given I2S peripheral with only the receive channel open.
822 #[allow(clippy::too_many_arguments)]
823 pub fn new_std_rx<I2S: I2s + 'd>(
824 i2s: I2S,
825 config: &config::StdConfig,
826 bclk: impl InputPin + OutputPin + 'd,
827 din: impl InputPin + 'd,
828 mclk: Option<impl InputPin + OutputPin + 'd>,
829 ws: impl InputPin + OutputPin + 'd,
830 ) -> Result<Self, EspError> {
831 Self::internal_new_std(
832 i2s,
833 config,
834 true,
835 false,
836 bclk,
837 Some(din),
838 AnyIOPin::none(),
839 mclk,
840 ws,
841 )
842 }
843}
844
845impl<'d> I2sDriver<'d, I2sTx> {
846 /// Create a new standard mode driver for the given I2S peripheral with only the transmit channel open.
847 #[allow(clippy::too_many_arguments)]
848 pub fn new_std_tx<I2S: I2s + 'd>(
849 i2s: I2S,
850 config: &config::StdConfig,
851 bclk: impl InputPin + OutputPin + 'd,
852 dout: impl OutputPin + 'd,
853 mclk: Option<impl InputPin + OutputPin + 'd>,
854 ws: impl InputPin + OutputPin + 'd,
855 ) -> Result<Self, EspError> {
856 Self::internal_new_std(
857 i2s,
858 config,
859 false,
860 true,
861 bclk,
862 AnyIOPin::none(),
863 Some(dout),
864 mclk,
865 ws,
866 )
867 }
868}