-
Notifications
You must be signed in to change notification settings - Fork 7.3k
/
i2s_std.h
348 lines (323 loc) · 15.1 KB
/
i2s_std.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* This file is specified for I2S standard communication mode
* Features:
* - Philips/MSB/PCM are supported in standard mode
* - Fixed to 2 slots
*/
#pragma once
#include "hal/i2s_types.h"
#include "hal/gpio_types.h"
#include "driver/i2s_common.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_IDF_TARGET_ESP32
/**
* @brief Philips format in 2 slots
* @param bits_per_sample I2S data bit width
* @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
*/
#define I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
.data_bit_width = bits_per_sample, \
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
.slot_mode = mono_or_stereo, \
.slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \
I2S_STD_SLOT_LEFT : I2S_STD_SLOT_BOTH, \
.ws_width = bits_per_sample, \
.ws_pol = false, \
.bit_shift = true, \
.msb_right = (bits_per_sample <= I2S_DATA_BIT_WIDTH_16BIT) ? \
true : false, \
}
/**
* @brief PCM(short) format in 2 slots
* @note PCM(long) is same as Philips in 2 slots
* @param bits_per_sample I2S data bit width
* @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
*/
#define I2S_STD_PCM_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
.data_bit_width = bits_per_sample, \
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
.slot_mode = mono_or_stereo, \
.slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \
I2S_STD_SLOT_LEFT : I2S_STD_SLOT_BOTH, \
.ws_width = 1, \
.ws_pol = true, \
.bit_shift = true, \
.msb_right = (bits_per_sample <= I2S_DATA_BIT_WIDTH_16BIT) ? \
true : false, \
}
/**
* @brief MSB format in 2 slots
* @param bits_per_sample I2S data bit width
* @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
*/
#define I2S_STD_MSB_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
.data_bit_width = bits_per_sample, \
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
.slot_mode = mono_or_stereo, \
.slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \
I2S_STD_SLOT_LEFT : I2S_STD_SLOT_BOTH, \
.ws_width = bits_per_sample, \
.ws_pol = false, \
.bit_shift = false, \
.msb_right = (bits_per_sample <= I2S_DATA_BIT_WIDTH_16BIT) ? \
true : false, \
}
#elif CONFIG_IDF_TARGET_ESP32S2
/**
* @brief Philips format in 2 slots
* @param bits_per_sample I2S data bit width
* @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
*/
#define I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
.data_bit_width = bits_per_sample, \
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
.slot_mode = mono_or_stereo, \
.slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \
I2S_STD_SLOT_LEFT : I2S_STD_SLOT_BOTH, \
.ws_width = bits_per_sample, \
.ws_pol = false, \
.bit_shift = true, \
.msb_right = true, \
}
/**
* @brief PCM(short) format in 2 slots
* @note PCM(long) is same as Philips in 2 slots
* @param bits_per_sample I2S data bit width
* @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
*/
#define I2S_STD_PCM_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
.data_bit_width = bits_per_sample, \
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
.slot_mode = mono_or_stereo, \
.slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \
I2S_STD_SLOT_LEFT : I2S_STD_SLOT_BOTH, \
.ws_width = 1, \
.ws_pol = true, \
.bit_shift = true, \
.msb_right = true, \
}
/**
* @brief MSB format in 2 slots
* @param bits_per_sample I2S data bit width
* @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
*/
#define I2S_STD_MSB_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
.data_bit_width = bits_per_sample, \
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
.slot_mode = mono_or_stereo, \
.slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \
I2S_STD_SLOT_LEFT : I2S_STD_SLOT_BOTH, \
.ws_width = bits_per_sample, \
.ws_pol = false, \
.bit_shift = false, \
.msb_right = true, \
}
#else
/**
* @brief Philips format in 2 slots
* @param bits_per_sample I2S data bit width
* @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
*/
#define I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
.data_bit_width = bits_per_sample, \
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
.slot_mode = mono_or_stereo, \
.slot_mask = I2S_STD_SLOT_BOTH, \
.ws_width = bits_per_sample, \
.ws_pol = false, \
.bit_shift = true, \
.left_align = true, \
.big_endian = false, \
.bit_order_lsb = false \
}
/**
* @brief PCM(short) format in 2 slots
* @note PCM(long) is same as Philips in 2 slots
* @param bits_per_sample I2S data bit width
* @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
*/
#define I2S_STD_PCM_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
.data_bit_width = bits_per_sample, \
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
.slot_mode = mono_or_stereo, \
.slot_mask = I2S_STD_SLOT_BOTH, \
.ws_width = 1, \
.ws_pol = true, \
.bit_shift = true, \
.left_align = true, \
.big_endian = false, \
.bit_order_lsb = false \
}
/**
* @brief MSB format in 2 slots
* @param bits_per_sample I2S data bit width
* @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
*/
#define I2S_STD_MSB_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
.data_bit_width = bits_per_sample, \
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
.slot_mode = mono_or_stereo, \
.slot_mask = I2S_STD_SLOT_BOTH, \
.ws_width = bits_per_sample, \
.ws_pol = false, \
.bit_shift = false, \
.left_align = true, \
.big_endian = false, \
.bit_order_lsb = false \
}
#endif
/** @cond */
#define I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) \
I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) // Alias
/** @endcond */
/**
* @brief I2S default standard clock configuration
* @note Please set the mclk_multiple to I2S_MCLK_MULTIPLE_384 while using 24 bits data width
* Otherwise the sample rate might be imprecise since the BCLK division is not a integer
* @param rate sample rate
*/
#define I2S_STD_CLK_DEFAULT_CONFIG(rate) { \
.sample_rate_hz = rate, \
.clk_src = I2S_CLK_SRC_DEFAULT, \
.mclk_multiple = I2S_MCLK_MULTIPLE_256, \
}
/**
* @brief I2S slot configuration for standard mode
*/
typedef struct {
/* General fields */
i2s_data_bit_width_t data_bit_width; /*!< I2S sample data bit width (valid data bits per sample) */
i2s_slot_bit_width_t slot_bit_width; /*!< I2S slot bit width (total bits per slot) */
i2s_slot_mode_t slot_mode; /*!< Set mono or stereo mode with I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
* In TX direction, mono means the written buffer contains only one slot data
* and stereo means the written buffer contains both left and right data
*/
/* Particular fields */
i2s_std_slot_mask_t slot_mask; /*!< Select the left, right or both slot */
uint32_t ws_width; /*!< WS signal width (i.e. the number of BCLK ticks that WS signal is high) */
bool ws_pol; /*!< WS signal polarity, set true to enable high lever first */
bool bit_shift; /*!< Set to enable bit shift in Philips mode */
#if SOC_I2S_HW_VERSION_1 // For esp32/esp32-s2
bool msb_right; /*!< Set to place right channel data at the MSB in the FIFO */
#else
bool left_align; /*!< Set to enable left alignment */
bool big_endian; /*!< Set to enable big endian */
bool bit_order_lsb; /*!< Set to enable lsb first */
#endif
} i2s_std_slot_config_t;
/**
* @brief I2S clock configuration for standard mode
*/
typedef struct {
/* General fields */
uint32_t sample_rate_hz; /*!< I2S sample rate */
i2s_clock_src_t clk_src; /*!< Choose clock source, see `soc_periph_i2s_clk_src_t` for the supported clock sources.
* selected `I2S_CLK_SRC_EXTERNAL` (if supports) to enable the external source clock input via MCLK pin,
*/
#if SOC_I2S_HW_VERSION_2
uint32_t ext_clk_freq_hz; /*!< External clock source frequency in Hz, only take effect when `clk_src = I2S_CLK_SRC_EXTERNAL`, otherwise this field will be ignored,
* Please make sure the frequency input is equal or greater than BCLK, i.e. `sample_rate_hz * slot_bits * 2`
*/
#endif
i2s_mclk_multiple_t mclk_multiple; /*!< The multiple of MCLK to the sample rate
* Default is 256 in the helper macro, it can satisfy most of cases,
* but please set this field a multiple of `3` (like 384) when using 24-bit data width,
* otherwise the sample rate might be inaccurate
*/
} i2s_std_clk_config_t;
/**
* @brief I2S standard mode GPIO pins configuration
*/
typedef struct {
gpio_num_t mclk; /*!< MCK pin, output by default, input if the clock source is selected to `I2S_CLK_SRC_EXTERNAL` */
gpio_num_t bclk; /*!< BCK pin, input in slave role, output in master role */
gpio_num_t ws; /*!< WS pin, input in slave role, output in master role */
gpio_num_t dout; /*!< DATA pin, output */
gpio_num_t din; /*!< DATA pin, input */
struct {
uint32_t mclk_inv: 1; /*!< Set 1 to invert the MCLK input/output */
uint32_t bclk_inv: 1; /*!< Set 1 to invert the BCLK input/output */
uint32_t ws_inv: 1; /*!< Set 1 to invert the WS input/output */
} invert_flags; /*!< GPIO pin invert flags */
} i2s_std_gpio_config_t;
/**
* @brief I2S standard mode major configuration that including clock/slot/GPIO configuration
*/
typedef struct {
i2s_std_clk_config_t clk_cfg; /*!< Standard mode clock configuration, can be generated by macro I2S_STD_CLK_DEFAULT_CONFIG */
i2s_std_slot_config_t slot_cfg; /*!< Standard mode slot configuration, can be generated by macros I2S_STD_[mode]_SLOT_DEFAULT_CONFIG, [mode] can be replaced with PHILIPS/MSB/PCM */
i2s_std_gpio_config_t gpio_cfg; /*!< Standard mode GPIO configuration, specified by user */
} i2s_std_config_t;
/**
* @brief Initialize I2S channel to standard mode
* @note Only allowed to be called when the channel state is REGISTERED, (i.e., channel has been allocated, but not initialized)
* and the state will be updated to READY if initialization success, otherwise the state will return to REGISTERED.
*
* @param[in] handle I2S channel handler
* @param[in] std_cfg Configurations for standard mode, including clock, slot and GPIO
* The clock configuration can be generated by the helper macro `I2S_STD_CLK_DEFAULT_CONFIG`
* The slot configuration can be generated by the helper macro `I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG`,
* `I2S_STD_PCM_SLOT_DEFAULT_CONFIG` or `I2S_STD_MSB_SLOT_DEFAULT_CONFIG`
*
* @return
* - ESP_OK Initialize successfully
* - ESP_ERR_NO_MEM No memory for storing the channel information
* - ESP_ERR_INVALID_ARG NULL pointer or invalid configuration
* - ESP_ERR_INVALID_STATE This channel is not registered
*/
esp_err_t i2s_channel_init_std_mode(i2s_chan_handle_t handle, const i2s_std_config_t *std_cfg);
/**
* @brief Reconfigure the I2S clock for standard mode
* @note Only allowed to be called when the channel state is READY, i.e., channel has been initialized, but not started
* this function won't change the state. `i2s_channel_disable` should be called before calling this function if I2S has started.
* @note The input channel handle has to be initialized to standard mode, i.e., `i2s_channel_init_std_mode` has been called before reconfiguring
*
* @param[in] handle I2S channel handler
* @param[in] clk_cfg Standard mode clock configuration, can be generated by `I2S_STD_CLK_DEFAULT_CONFIG`
* @return
* - ESP_OK Set clock successfully
* - ESP_ERR_INVALID_ARG NULL pointer, invalid configuration or not standard mode
* - ESP_ERR_INVALID_STATE This channel is not initialized or not stopped
*/
esp_err_t i2s_channel_reconfig_std_clock(i2s_chan_handle_t handle, const i2s_std_clk_config_t *clk_cfg);
/**
* @brief Reconfigure the I2S slot for standard mode
* @note Only allowed to be called when the channel state is READY, i.e., channel has been initialized, but not started
* this function won't change the state. `i2s_channel_disable` should be called before calling this function if I2S has started.
* @note The input channel handle has to be initialized to standard mode, i.e., `i2s_channel_init_std_mode` has been called before reconfiguring
*
* @param[in] handle I2S channel handler
* @param[in] slot_cfg Standard mode slot configuration, can be generated by `I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG`,
* `I2S_STD_PCM_SLOT_DEFAULT_CONFIG` and `I2S_STD_MSB_SLOT_DEFAULT_CONFIG`.
* @return
* - ESP_OK Set clock successfully
* - ESP_ERR_NO_MEM No memory for DMA buffer
* - ESP_ERR_INVALID_ARG NULL pointer, invalid configuration or not standard mode
* - ESP_ERR_INVALID_STATE This channel is not initialized or not stopped
*/
esp_err_t i2s_channel_reconfig_std_slot(i2s_chan_handle_t handle, const i2s_std_slot_config_t *slot_cfg);
/**
* @brief Reconfigure the I2S GPIO for standard mode
* @note Only allowed to be called when the channel state is READY, i.e., channel has been initialized, but not started
* this function won't change the state. `i2s_channel_disable` should be called before calling this function if I2S has started.
* @note The input channel handle has to be initialized to standard mode, i.e., `i2s_channel_init_std_mode` has been called before reconfiguring
*
* @param[in] handle I2S channel handler
* @param[in] gpio_cfg Standard mode GPIO configuration, specified by user
* @return
* - ESP_OK Set clock successfully
* - ESP_ERR_INVALID_ARG NULL pointer, invalid configuration or not standard mode
* - ESP_ERR_INVALID_STATE This channel is not initialized or not stopped
*/
esp_err_t i2s_channel_reconfig_std_gpio(i2s_chan_handle_t handle, const i2s_std_gpio_config_t *gpio_cfg);
#ifdef __cplusplus
}
#endif