-
Notifications
You must be signed in to change notification settings - Fork 7k
/
i2s_hal.c
413 lines (376 loc) · 14.5 KB
/
i2s_hal.c
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
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// The HAL layer for I2S (common part)
#include "soc/soc.h"
#include "soc/soc_caps.h"
#include "hal/i2s_hal.h"
#include "sdkconfig.h"
#ifndef SOC_I2S_SUPPORTS_TDM
#define I2S_HAL_DEFAULT_MSB_RIGHT (true) // Default msb_right bit to true
#define I2S_HAL_DEFAULT_RIGHT_FIRST (I2S_HAL_DEFAULT_MSB_RIGHT) // Normally right_first bit keeps same as msb_right
#endif // SOC_I2S_SUPPORTS_TDM
/**
* @brief Calculate the closest sample rate clock configuration.
* clock relationship:
* Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a)
*
* @param clk_cfg I2S clock configuration(input)
* @param cal Point to `i2s_ll_mclk_div_t` structure(output).
*/
void i2s_hal_mclk_div_decimal_cal(i2s_hal_clock_cfg_t *clk_cfg, i2s_ll_mclk_div_t *cal)
{
int ma = 0;
int mb = 0;
cal->mclk_div = clk_cfg->mclk_div;
cal->a = 1;
cal->b = 0;
uint32_t freq_diff = abs(clk_cfg->sclk - clk_cfg->mclk * cal->mclk_div);
if (!freq_diff) {
return;
}
float decimal = freq_diff / (float)clk_cfg->mclk;
// Carry bit if the decimal is greater than 1.0 - 1.0 / (63.0 * 2) = 125.0 / 126.0
if (decimal > 125.0 / 126.0) {
cal->mclk_div++;
return;
}
uint32_t min = ~0;
for (int a = 2; a <= I2S_LL_MCLK_DIVIDER_MAX; a++) {
// Calculate the closest 'b' in this loop, no need to loop 'b' to seek the closest value
int b = (int)(a * (freq_diff / (double)clk_cfg->mclk) + 0.5);
ma = freq_diff * a;
mb = clk_cfg->mclk * b;
if (ma == mb) {
cal->a = a;
cal->b = b;
return;
}
if (abs((mb - ma)) < min) {
cal->a = a;
cal->b = b;
min = abs(mb - ma);
}
}
}
void i2s_hal_set_clock_src(i2s_hal_context_t *hal, i2s_clock_src_t sel)
{
i2s_ll_tx_clk_set_src(hal->dev, sel);
i2s_ll_rx_clk_set_src(hal->dev, sel);
}
void i2s_hal_tx_clock_config(i2s_hal_context_t *hal, i2s_hal_clock_cfg_t *clk_cfg)
{
i2s_ll_mclk_div_t mclk_set;
i2s_hal_mclk_div_decimal_cal(clk_cfg, &mclk_set);
i2s_ll_tx_set_clk(hal->dev, &mclk_set);
i2s_ll_tx_set_bck_div_num(hal->dev, clk_cfg->bclk_div);
}
void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, i2s_hal_clock_cfg_t *clk_cfg)
{
i2s_ll_mclk_div_t mclk_set;
i2s_hal_mclk_div_decimal_cal(clk_cfg, &mclk_set);
i2s_ll_rx_set_clk(hal->dev, &mclk_set);
i2s_ll_rx_set_bck_div_num(hal->dev, clk_cfg->bclk_div);
}
void i2s_hal_enable_master_fd_mode(i2s_hal_context_t *hal)
{
i2s_ll_tx_set_slave_mod(hal->dev, false); //TX master
i2s_ll_rx_set_slave_mod(hal->dev, true); //RX Slave
}
void i2s_hal_enable_slave_fd_mode(i2s_hal_context_t *hal)
{
i2s_ll_tx_set_slave_mod(hal->dev, true); //TX Slave
i2s_ll_rx_set_slave_mod(hal->dev, true); //RX Slave
}
void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num)
{
/* Get hardware instance */
hal->dev = I2S_LL_GET_HW(i2s_num);
}
#if SOC_I2S_SUPPORTS_PDM_TX
void i2s_hal_tx_set_pdm_mode_default(i2s_hal_context_t *hal, uint32_t sample_rate, bool is_mono)
{
/* enable pdm tx mode */
i2s_ll_tx_enable_pdm(hal->dev, true);
#if SOC_I2S_SUPPORTS_TDM
i2s_ll_tx_enable_clock(hal->dev);
i2s_ll_tx_clk_set_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default
i2s_ll_mclk_use_tx_clk(hal->dev);
/* Still need to enable the first 2 TDM channel mask to get the correct number of frame */
i2s_ll_tx_set_active_chan_mask(hal->dev, I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1);
#else
i2s_ll_tx_force_enable_fifo_mod(hal->dev, true);
#endif
/* set pdm tx default presacle */
i2s_ll_tx_set_pdm_prescale(hal->dev, 0);
/* set pdm tx default sacle of high pass filter */
i2s_ll_tx_set_pdm_hp_scale(hal->dev, I2S_PDM_SIG_SCALING_MUL_1);
/* set pdm tx default sacle of low pass filter */
i2s_ll_tx_set_pdm_lp_scale(hal->dev, I2S_PDM_SIG_SCALING_MUL_1);
/* set pdm tx default sacle of sinc filter */
i2s_ll_tx_set_pdm_sinc_scale(hal->dev, I2S_PDM_SIG_SCALING_MUL_1);
/* set pdm tx default sacle of sigma-delta filter */
i2s_ll_tx_set_pdm_sd_scale(hal->dev, I2S_PDM_SIG_SCALING_MUL_1);
/* set pdm tx sample rate */
i2s_ll_tx_set_pdm_fpfs(hal->dev, 960, sample_rate / 100);
#if SOC_I2S_SUPPORTS_PDM_CODEC
/* enable pdm high pass filter */
i2s_ll_tx_enable_pdm_hp_filter(hal->dev, true);
/* set pdm tx high pass filter parameters */
i2s_ll_tx_set_pdm_hp_filter_param0(hal->dev, 6);
i2s_ll_tx_set_pdm_hp_filter_param5(hal->dev, 7);
/* enable pdm sigma-delta dac */
i2s_ll_tx_enable_pdm_sd_codec(hal->dev, is_mono);
/* set pdm tx sigma-delta codec dither */
i2s_ll_tx_set_pdm_sd_dither(hal->dev, 0);
i2s_ll_tx_set_pdm_sd_dither2(hal->dev, 1);
#endif // SOC_I2S_SUPPORTS_PDM_CODEC
}
#endif // SOC_I2S_SUPPORTS_PDM_TX
#if SOC_I2S_SUPPORTS_PDM_RX
void i2s_hal_rx_set_pdm_mode_default(i2s_hal_context_t *hal)
{
/* enable pdm rx mode */
i2s_ll_rx_enable_pdm(hal->dev, true);
/* set pdm rx downsample number */
i2s_ll_rx_set_pdm_dsr(hal->dev, I2S_PDM_DSR_8S);
#if !SOC_I2S_SUPPORTS_TDM
i2s_ll_rx_force_enable_fifo_mod(hal->dev, true);
#endif
#if SOC_I2S_SUPPORTS_TDM
i2s_ll_rx_enable_clock(hal->dev);
i2s_ll_rx_clk_set_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default
i2s_ll_mclk_use_rx_clk(hal->dev);
/* Still need to enable the first 2 TDM channel mask to get the correct number of frame */
i2s_ll_rx_set_active_chan_mask(hal->dev, I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1);
#else
i2s_ll_rx_force_enable_fifo_mod(hal->dev, true);
#endif
}
#endif // SOC_I2S_SUPPORTS_PDM_RX
void i2s_hal_tx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg)
{
/* Disable PDM tx mode and enable TDM mode (if support) */
i2s_ll_tx_enable_pdm(hal->dev, false);
#if SOC_I2S_SUPPORTS_TDM
i2s_ll_tx_enable_clock(hal->dev);
i2s_ll_tx_clk_set_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default
i2s_ll_mclk_use_tx_clk(hal->dev);
// In TDM mode(more than 2 channels), the ws polarity should be high first.
if (hal_cfg->total_chan > 2) {
i2s_ll_tx_set_ws_idle_pol(hal->dev, true);
}
i2s_ll_tx_enable_left_align(hal->dev, hal_cfg->left_align);
i2s_ll_tx_enable_big_endian(hal->dev, hal_cfg->big_edin);
i2s_ll_tx_set_bit_order(hal->dev, hal_cfg->bit_order_msb);
i2s_ll_tx_set_skip_mask(hal->dev, hal_cfg->skip_msk);
#else
#if CONFIG_IDF_TARGET_ESP32
i2s_ll_tx_enable_msb_right(hal->dev, hal_cfg->sample_bits <= I2S_BITS_PER_SAMPLE_16BIT);
#else
i2s_ll_tx_enable_msb_right(hal->dev, I2S_HAL_DEFAULT_MSB_RIGHT);
#endif
i2s_ll_tx_enable_right_first(hal->dev, I2S_HAL_DEFAULT_RIGHT_FIRST);
i2s_ll_tx_force_enable_fifo_mod(hal->dev, true);
#endif
}
void i2s_hal_rx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg)
{
/* Disable PDM rx mode and enable TDM rx mode (if support)*/
i2s_ll_rx_enable_pdm(hal->dev, false);
#if SOC_I2S_SUPPORTS_TDM
i2s_ll_rx_enable_clock(hal->dev);
i2s_ll_rx_clk_set_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default
i2s_ll_mclk_use_rx_clk(hal->dev);
// In TDM mode(more than 2 channels), the ws polarity should be high first.
if (hal_cfg->total_chan > 2) {
i2s_ll_rx_set_ws_idle_pol(hal->dev, true);
}
i2s_ll_rx_enable_left_align(hal->dev, hal_cfg->left_align);
i2s_ll_rx_enable_big_endian(hal->dev, hal_cfg->big_edin);
i2s_ll_rx_set_bit_order(hal->dev, hal_cfg->bit_order_msb);
#else
#if CONFIG_IDF_TARGET_ESP32
i2s_ll_rx_enable_msb_right(hal->dev, hal_cfg->sample_bits <= I2S_BITS_PER_SAMPLE_16BIT);
#else
i2s_ll_rx_enable_msb_right(hal->dev, I2S_HAL_DEFAULT_MSB_RIGHT);
#endif
i2s_ll_rx_enable_right_first(hal->dev, I2S_HAL_DEFAULT_RIGHT_FIRST);
i2s_ll_rx_force_enable_fifo_mod(hal->dev, true);
#endif
}
static uint32_t i2s_hal_get_ws_bit(i2s_comm_format_t fmt, uint32_t chan_num, uint32_t chan_bits)
{
switch (fmt) {
case I2S_COMM_FORMAT_STAND_MSB:
return chan_num * chan_bits / 2;
case I2S_COMM_FORMAT_STAND_PCM_SHORT:
return 1;
case I2S_COMM_FORMAT_STAND_PCM_LONG:
return chan_bits;
default: //I2S_COMM_FORMAT_STAND_I2S
return chan_num * chan_bits / 2;
}
}
void i2s_hal_tx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg)
{
uint32_t chan_num = 2;
uint32_t chan_bits = hal_cfg->chan_bits;
uint32_t data_bits = hal_cfg->sample_bits;
#if SOC_I2S_SUPPORTS_TDM
bool is_mono = (hal_cfg->chan_fmt == I2S_CHANNEL_FMT_ALL_RIGHT) ||
(hal_cfg->chan_fmt == I2S_CHANNEL_FMT_ALL_LEFT);
#else
bool is_mono = (hal_cfg->chan_fmt == I2S_CHANNEL_FMT_ONLY_RIGHT) ||
(hal_cfg->chan_fmt == I2S_CHANNEL_FMT_ONLY_LEFT);
#endif
/* Set channel number and valid data bits */
#if SOC_I2S_SUPPORTS_TDM
chan_num = hal_cfg->total_chan;
i2s_ll_tx_set_active_chan_mask(hal->dev, hal_cfg->chan_mask >> 16);
i2s_ll_tx_set_chan_num(hal->dev, chan_num);
#else
i2s_ll_tx_set_chan_mod(hal->dev, hal_cfg->chan_fmt);
#endif // SOC_I2S_SUPPORTS_TDM
#if SOC_I2S_SUPPORTS_PDM_CODEC
if (hal_cfg->mode & I2S_MODE_PDM) {
// Fixed to 16 while using mono mode and 32 while using stereo mode
data_bits = hal_cfg->chan_fmt == I2S_CHANNEL_FMT_RIGHT_LEFT ? 32 : 16;
chan_bits = data_bits;
}
#endif
i2s_ll_tx_set_sample_bit(hal->dev, chan_bits, data_bits);
i2s_ll_tx_enable_mono_mode(hal->dev, is_mono);
/* Set communication format */
bool shift_en = hal_cfg->comm_fmt == I2S_COMM_FORMAT_STAND_I2S ? true : false;
uint32_t ws_width = i2s_hal_get_ws_bit(hal_cfg->comm_fmt, chan_num, chan_bits);
i2s_ll_tx_enable_msb_shift(hal->dev, shift_en);
i2s_ll_tx_set_ws_width(hal->dev, ws_width);
#if SOC_I2S_SUPPORTS_TDM
uint32_t half_sample_bits = chan_num * chan_bits / 2;
#if SOC_I2S_SUPPORTS_PDM_CODEC
if (hal_cfg->mode & I2S_MODE_PDM) {
half_sample_bits = 16; // Fixed to 16 in PDM mode
}
#endif
i2s_ll_tx_set_half_sample_bit(hal->dev, half_sample_bits);
#endif
}
void i2s_hal_rx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg)
{
uint32_t chan_num = 2;
uint32_t chan_bits = hal_cfg->chan_bits;
uint32_t data_bits = hal_cfg->sample_bits;
bool is_mono = (hal_cfg->chan_fmt == I2S_CHANNEL_FMT_ONLY_RIGHT) ||
(hal_cfg->chan_fmt == I2S_CHANNEL_FMT_ONLY_LEFT);
#if SOC_I2S_SUPPORTS_TDM
chan_num = hal_cfg->total_chan;
i2s_ll_rx_set_active_chan_mask(hal->dev, hal_cfg->chan_mask >> 16);
i2s_ll_rx_set_chan_num(hal->dev, chan_num);
#if SOC_I2S_SUPPORTS_PDM_RX
is_mono = (hal_cfg->mode & I2S_MODE_PDM) ? false : true;
#endif // SOC_I2S_SUPPORTS_PDM_RX
#else
/* rx_chan_mod is related to msb_right, we take it into consideration here.
* It is calculated again here instead of reading the value from the register,
* so that we can avoid introducing the calling sequence dependency */
bool is_msb_right = I2S_HAL_DEFAULT_MSB_RIGHT; // Set default to false for ESP32-S2
#if CONFIG_IDF_TARGET_ESP32
/* Specially, `msb_right` on esp32 is related to sample bits and PDM mode */
is_msb_right |= (hal_cfg->sample_bits <= I2S_BITS_PER_SAMPLE_16BIT) || (hal_cfg->mode & I2S_MODE_PDM);
#endif // CONFIG_IDF_TARGET_ESP32
i2s_ll_rx_set_chan_mod(hal->dev, hal_cfg->chan_fmt, is_msb_right);
#endif // SOC_I2S_SUPPORTS_TDM
i2s_ll_rx_set_sample_bit(hal->dev, chan_bits, data_bits);
i2s_ll_rx_enable_mono_mode(hal->dev, is_mono);
/* Set communication format */
bool shift_en = hal_cfg->comm_fmt == I2S_COMM_FORMAT_STAND_I2S ? true : false;
uint32_t ws_width = i2s_hal_get_ws_bit(hal_cfg->comm_fmt, chan_num, chan_bits);
i2s_ll_rx_enable_msb_shift(hal->dev, shift_en);
i2s_ll_rx_set_ws_width(hal->dev, ws_width);
#if SOC_I2S_SUPPORTS_TDM
i2s_ll_rx_set_half_sample_bit(hal->dev, chan_num * chan_bits / 2);
#endif
}
void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg)
{
#if SOC_I2S_SUPPORTS_ADC
if (hal_cfg->mode & I2S_MODE_ADC_BUILT_IN) {
/* In ADC built-in mode, we need to call i2s_set_adc_mode to initialize the specific ADC channel.
* In the current stage, we only support ADC1 and single channel mode.
* In default data mode, the ADC data is in 12-bit resolution mode.
*/
i2s_ll_enable_builtin_adc(hal->dev, true);
return;
}
i2s_ll_enable_builtin_adc(hal->dev, false);
#endif
#if SOC_I2S_SUPPORTS_DAC
if (hal_cfg->mode & I2S_MODE_DAC_BUILT_IN) {
i2s_ll_enable_builtin_dac(hal->dev, true);
return;
}
i2s_ll_enable_builtin_dac(hal->dev, false);
#endif
/* Set configurations for TX mode */
if (hal_cfg->mode & I2S_MODE_TX) {
i2s_ll_tx_stop(hal->dev);
i2s_ll_tx_reset(hal->dev);
i2s_ll_tx_set_slave_mod(hal->dev, (hal_cfg->mode & I2S_MODE_SLAVE) != 0); //TX Slave
#if SOC_I2S_SUPPORTS_PDM_TX
if (hal_cfg->mode & I2S_MODE_PDM) {
/* Set tx pdm mode */
i2s_hal_tx_set_pdm_mode_default(hal, hal_cfg->sample_rate, hal_cfg->chan_fmt != I2S_CHANNEL_FMT_RIGHT_LEFT);
} else
#endif
{
/* Set tx common mode */
i2s_hal_tx_set_common_mode(hal, hal_cfg);
}
i2s_hal_tx_set_channel_style(hal, hal_cfg);
}
/* Set configurations for RX mode */
if (hal_cfg->mode & I2S_MODE_RX) {
i2s_ll_rx_stop(hal->dev);
i2s_ll_rx_reset(hal->dev);
i2s_ll_rx_set_slave_mod(hal->dev, (hal_cfg->mode & I2S_MODE_SLAVE) != 0); //RX Slave
#if SOC_I2S_SUPPORTS_PDM_RX
if (hal_cfg->mode & I2S_MODE_PDM) {
/* Set rx pdm mode */
i2s_hal_rx_set_pdm_mode_default(hal);
} else
#endif
{
/* Set rx common mode */
i2s_hal_rx_set_common_mode(hal, hal_cfg);
}
i2s_hal_rx_set_channel_style(hal, hal_cfg);
}
/* Set configurations for full-duplex mode */
if ((hal_cfg->mode & I2S_MODE_RX) && (hal_cfg->mode & I2S_MODE_TX)) {
i2s_ll_share_bck_ws(hal->dev, true);
if (hal_cfg->mode & I2S_MODE_MASTER) {
i2s_hal_enable_master_fd_mode(hal);
} else {
i2s_hal_enable_slave_fd_mode(hal);
}
}
}
void i2s_hal_start_tx(i2s_hal_context_t *hal)
{
i2s_ll_tx_start(hal->dev);
}
void i2s_hal_start_rx(i2s_hal_context_t *hal)
{
i2s_ll_rx_start(hal->dev);
}
void i2s_hal_stop_tx(i2s_hal_context_t *hal)
{
i2s_ll_tx_stop(hal->dev);
}
void i2s_hal_stop_rx(i2s_hal_context_t *hal)
{
i2s_ll_rx_stop(hal->dev);
}