1 /*
2 * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*******************************************************************************
8 * NOTICE
9 * The hal is not public api, don't use in application code.
10 * See readme.md in hal/include/hal/readme.md
11 ******************************************************************************/
12
13 // The LL layer for ESP32 I2S register operations
14
15 #pragma once
16
17 #include <stdbool.h>
18 #include "hal/misc.h"
19 #include "soc/i2s_periph.h"
20 #include "soc/i2s_struct.h"
21 #include "hal/i2s_types.h"
22
23 #ifdef __cplusplus
24 extern "C" {
25 #endif
26
27 // Get I2S hardware instance with giving i2s num
28 #define I2S_LL_GET_HW(num) (((num) == 0) ? (&I2S0) : (((num) == 1) ? (&I2S1) : NULL))
29
30 #define I2S_LL_AD_BCK_FACTOR (2)
31 #define I2S_LL_PDM_BCK_FACTOR (64)
32
33 #define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (6)
34 #define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1)
35
36 #define I2S_LL_BCK_MAX_PRESCALE (64)
37
38 #define I2S_LL_EVENT_RX_EOF BIT(9)
39 #define I2S_LL_EVENT_TX_EOF BIT(12)
40 #define I2S_LL_EVENT_RX_DSCR_ERR BIT(13)
41 #define I2S_LL_EVENT_TX_DSCR_ERR BIT(14)
42 #define I2S_LL_EVENT_TX_TEOF BIT(16)
43 #define I2S_INTR_MAX (UINT32_MAX)
44
45 #define I2S_LL_TX_EVENT_MASK I2S_LL_EVENT_TX_EOF
46 #define I2S_LL_RX_EVENT_MASK I2S_LL_EVENT_RX_EOF
47
48 #define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz
49 #define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
50
51 /**
52 * @brief I2S clock configuration structure
53 * @note Fmclk = Fsclk /(integ+numer/denom)
54 */
55 typedef struct {
56 uint16_t integ; // Integer part of I2S module clock divider
57 uint16_t denom; // Denominator part of I2S module clock divider
58 uint16_t numer; // Numerator part of I2S module clock divider
59 } i2s_ll_mclk_div_t;
60
61 /**
62 * @brief Enable DMA descriptor owner check
63 *
64 * @param hw Peripheral I2S hardware instance address.
65 * @param en whether to enable owner check
66 */
i2s_ll_dma_enable_owner_check(i2s_dev_t * hw,bool en)67 static inline void i2s_ll_dma_enable_owner_check(i2s_dev_t *hw, bool en)
68 {
69 hw->lc_conf.check_owner = en;
70 }
71
72 /**
73 * @brief Enable DMA descriptor write back
74 *
75 * @param hw Peripheral I2S hardware instance address.
76 * @param en whether to enable write back
77 */
i2s_ll_dma_enable_auto_write_back(i2s_dev_t * hw,bool en)78 static inline void i2s_ll_dma_enable_auto_write_back(i2s_dev_t *hw, bool en)
79 {
80 hw->lc_conf.out_auto_wrback = en;
81 }
82
83 /**
84 * @brief I2S DMA generate EOF event on data in FIFO poped out
85 *
86 * @param hw Peripheral I2S hardware instance address.
87 * @param en True to enable, False to disable
88 */
i2s_ll_dma_enable_eof_on_fifo_empty(i2s_dev_t * hw,bool en)89 static inline void i2s_ll_dma_enable_eof_on_fifo_empty(i2s_dev_t *hw, bool en)
90 {
91 hw->lc_conf.out_eof_mode = en;
92 }
93
94 /**
95 * @brief I2S module general init, enable I2S clock.
96 *
97 * @param hw Peripheral I2S hardware instance address.
98 */
i2s_ll_enable_clock(i2s_dev_t * hw)99 static inline void i2s_ll_enable_clock(i2s_dev_t *hw)
100 {
101 if (hw->clkm_conf.clk_en == 0) {
102 hw->clkm_conf.clk_en = 1;
103 hw->conf2.val = 0;
104 }
105 }
106
107 /**
108 * @brief I2S module disable clock.
109 *
110 * @param hw Peripheral I2S hardware instance address.
111 */
i2s_ll_disable_clock(i2s_dev_t * hw)112 static inline void i2s_ll_disable_clock(i2s_dev_t *hw)
113 {
114 if (hw->clkm_conf.clk_en == 1) {
115 hw->clkm_conf.clk_en = 0;
116 }
117 }
118
119 /**
120 * @brief I2S tx msb right enable
121 *
122 * @param hw Peripheral I2S hardware instance address.
123 * @param enable Set true to enable tx msb right
124 */
i2s_ll_tx_enable_msb_right(i2s_dev_t * hw,bool enable)125 static inline void i2s_ll_tx_enable_msb_right(i2s_dev_t *hw, bool enable)
126 {
127 hw->conf.tx_msb_right = enable;
128 }
129
130 /**
131 * @brief I2S rx msb right enable
132 *
133 * @param hw Peripheral I2S hardware instance address.
134 * @param enable Set true to enable rx msb right
135 */
i2s_ll_rx_enable_msb_right(i2s_dev_t * hw,bool enable)136 static inline void i2s_ll_rx_enable_msb_right(i2s_dev_t *hw, bool enable)
137 {
138 hw->conf.rx_msb_right = enable;
139 }
140
141 /**
142 * @brief I2S tx right channel first
143 *
144 * @param hw Peripheral I2S hardware instance address.
145 * @param enable Set true to enable send right channel first
146 */
i2s_ll_tx_enable_right_first(i2s_dev_t * hw,bool enable)147 static inline void i2s_ll_tx_enable_right_first(i2s_dev_t *hw, bool enable)
148 {
149 hw->conf.tx_right_first = enable;
150 }
151
152 /**
153 * @brief I2S rx right channel first
154 *
155 * @param hw Peripheral I2S hardware instance address.
156 * @param enable Set true to enable receive right channel first
157 */
i2s_ll_rx_enable_right_first(i2s_dev_t * hw,bool enable)158 static inline void i2s_ll_rx_enable_right_first(i2s_dev_t *hw, bool enable)
159 {
160 hw->conf.rx_right_first = enable;
161 }
162
163 /**
164 * @brief I2S tx fifo module force enable
165 *
166 * @param hw Peripheral I2S hardware instance address.
167 * @param enable Set true to enable tx fifo module
168 */
i2s_ll_tx_force_enable_fifo_mod(i2s_dev_t * hw,bool enable)169 static inline void i2s_ll_tx_force_enable_fifo_mod(i2s_dev_t *hw, bool enable)
170 {
171 hw->fifo_conf.tx_fifo_mod_force_en = enable;
172 }
173
174 /**
175 * @brief I2S rx fifo module force enable
176 *
177 * @param hw Peripheral I2S hardware instance address.
178 * @param enable Set true to enable rx fifo module
179 */
i2s_ll_rx_force_enable_fifo_mod(i2s_dev_t * hw,bool enable)180 static inline void i2s_ll_rx_force_enable_fifo_mod(i2s_dev_t *hw, bool enable)
181 {
182 hw->fifo_conf.rx_fifo_mod_force_en = enable;
183 }
184 /**
185 * @brief Enable I2S TX slave mode
186 *
187 * @param hw Peripheral I2S hardware instance address.
188 * @param slave_en Set true to enable slave mode
189 */
i2s_ll_tx_set_slave_mod(i2s_dev_t * hw,bool slave_en)190 static inline void i2s_ll_tx_set_slave_mod(i2s_dev_t *hw, bool slave_en)
191 {
192 hw->conf.tx_slave_mod = slave_en;
193 }
194
195 /**
196 * @brief Enable I2S RX slave mode
197 *
198 * @param hw Peripheral I2S hardware instance address.
199 * @param slave_en Set true to enable slave mode
200 */
i2s_ll_rx_set_slave_mod(i2s_dev_t * hw,bool slave_en)201 static inline void i2s_ll_rx_set_slave_mod(i2s_dev_t *hw, bool slave_en)
202 {
203 hw->conf.rx_slave_mod = slave_en;
204 }
205
206 /**
207 * @brief Reset I2S TX module
208 *
209 * @param hw Peripheral I2S hardware instance address.
210 */
i2s_ll_tx_reset(i2s_dev_t * hw)211 static inline void i2s_ll_tx_reset(i2s_dev_t *hw)
212 {
213 hw->conf.tx_reset = 1;
214 hw->conf.tx_reset = 0;
215 hw->lc_conf.out_rst = 1;
216 hw->lc_conf.out_rst = 0;
217 }
218
219 /**
220 * @brief Reset I2S RX module
221 *
222 * @param hw Peripheral I2S hardware instance address.
223 */
i2s_ll_rx_reset(i2s_dev_t * hw)224 static inline void i2s_ll_rx_reset(i2s_dev_t *hw)
225 {
226 hw->conf.rx_reset = 1;
227 hw->conf.rx_reset = 0;
228 hw->lc_conf.in_rst = 1;
229 hw->lc_conf.in_rst = 0;
230 }
231
232 /**
233 * @brief Reset I2S TX FIFO
234 *
235 * @param hw Peripheral I2S hardware instance address.
236 */
i2s_ll_tx_reset_fifo(i2s_dev_t * hw)237 static inline void i2s_ll_tx_reset_fifo(i2s_dev_t *hw)
238 {
239 hw->conf.tx_fifo_reset = 1;
240 hw->conf.tx_fifo_reset = 0;
241 }
242
243 /**
244 * @brief Reset I2S RX FIFO
245 *
246 * @param hw Peripheral I2S hardware instance address.
247 */
i2s_ll_rx_reset_fifo(i2s_dev_t * hw)248 static inline void i2s_ll_rx_reset_fifo(i2s_dev_t *hw)
249 {
250 hw->conf.rx_fifo_reset = 1;
251 hw->conf.rx_fifo_reset = 0;
252 }
253
254 /**
255 * @brief Set TX source clock
256 *
257 * @param hw Peripheral I2S hardware instance address.
258 * @param src I2S source clock
259 */
i2s_ll_tx_clk_set_src(i2s_dev_t * hw,i2s_clock_src_t src)260 static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
261 {
262 //0: disable APLL clock, I2S module will using PLL_D2_CLK(160M) as source clock
263 //1: Enable APLL clock, I2S module will using APLL as source clock
264 hw->clkm_conf.clka_en = (src == I2S_CLK_SRC_APLL) ? 1 : 0;
265 }
266
267 /**
268 * @brief Set RX source clock
269 *
270 * @param hw Peripheral I2S hardware instance address.
271 * @param src I2S source clock
272 */
i2s_ll_rx_clk_set_src(i2s_dev_t * hw,i2s_clock_src_t src)273 static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
274 {
275 //0: disable APLL clock, I2S module will using PLL_D2_CLK(160M) as source clock
276 //1: Enable APLL clock, I2S module will using APLL as source clock
277 hw->clkm_conf.clka_en = (src == I2S_CLK_SRC_APLL) ? 1 : 0;
278 }
279
280 /**
281 * @brief Set I2S tx bck div num
282 *
283 * @param hw Peripheral I2S hardware instance address.
284 * @param val value to set tx bck div num
285 */
i2s_ll_tx_set_bck_div_num(i2s_dev_t * hw,uint32_t val)286 static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val)
287 {
288 hw->sample_rate_conf.tx_bck_div_num = val;
289 }
290
291 /**
292 * @brief Configure I2S module clock divider
293 * @note mclk on ESP32 is shared by both TX and RX channel
294 * mclk = sclk / (mclk_div + b/a)
295 *
296 * @param hw Peripheral I2S hardware instance address.
297 * @param mclk_div integer part of the division from sclk to mclk
298 * @param a Denominator of decimal part
299 * @param b Numerator of decimal part
300 */
i2s_ll_set_raw_mclk_div(i2s_dev_t * hw,uint32_t mclk_div,uint32_t a,uint32_t b)301 static inline void i2s_ll_set_raw_mclk_div(i2s_dev_t *hw, uint32_t mclk_div, uint32_t a, uint32_t b)
302 {
303 HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkm_conf, clkm_div_num, mclk_div);
304 hw->clkm_conf.clkm_div_b = b;
305 hw->clkm_conf.clkm_div_a = a;
306 }
307
308 /**
309 * @brief Configure I2S TX module clock divider
310 * @note mclk on ESP32 is shared by both TX and RX channel
311 *
312 * @param hw Peripheral I2S hardware instance address.
313 * @param mclk_div The mclk division coefficients
314 */
i2s_ll_tx_set_mclk(i2s_dev_t * hw,const i2s_ll_mclk_div_t * mclk_div)315 static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mclk_div)
316 {
317 /* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate
318 * Set to particular coefficients first then update to the target coefficients,
319 * otherwise the clock division might be inaccurate.
320 * the general idea is to set a value that unlike to calculate from the regular decimal */
321 i2s_ll_set_raw_mclk_div(hw, 7, 47, 3);
322 i2s_ll_set_raw_mclk_div(hw, mclk_div->integ, mclk_div->denom, mclk_div->numer);
323 }
324
325 /**
326 * @brief Set I2S rx bck div num
327 *
328 * @param hw Peripheral I2S hardware instance address.
329 * @param val value to set rx bck div num
330 */
i2s_ll_rx_set_bck_div_num(i2s_dev_t * hw,uint32_t val)331 static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val)
332 {
333 hw->sample_rate_conf.rx_bck_div_num = val;
334 }
335
336 /**
337 * @brief Configure I2S RX module clock divider
338 * @note mclk on ESP32 is shared by both TX and RX channel
339 *
340 * @param hw Peripheral I2S hardware instance address.
341 * @param mclk_div The mclk division coefficients
342 */
i2s_ll_rx_set_mclk(i2s_dev_t * hw,const i2s_ll_mclk_div_t * mclk_div)343 static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mclk_div)
344 {
345 // TX and RX channel on ESP32 shares a same mclk
346 i2s_ll_tx_set_mclk(hw, mclk_div);
347 }
348
349 /**
350 * @brief Enable interrupt by mask
351 *
352 * @param hw Peripheral I2S hardware instance address.
353 * @param mask Interrupt event mask
354 * @param en true to enable, false to disable
355 */
i2s_ll_enable_intr(i2s_dev_t * hw,uint32_t mask,bool en)356 static inline void i2s_ll_enable_intr(i2s_dev_t *hw, uint32_t mask, bool en)
357 {
358 uint32_t int_ena_mask = hw->int_ena.val;
359 if (en) {
360 int_ena_mask |= mask;
361 } else {
362 int_ena_mask &= ~mask;
363 }
364 hw->int_ena.val = int_ena_mask;
365 }
366
367 /**
368 * @brief Enable TX interrupt
369 *
370 * @param hw Peripheral I2S hardware instance address.
371 */
i2s_ll_tx_enable_intr(i2s_dev_t * hw)372 static inline void i2s_ll_tx_enable_intr(i2s_dev_t *hw)
373 {
374 hw->int_ena.out_eof = 1;
375 }
376
377 /**
378 * @brief Disable TX interrupt
379 *
380 * @param hw Peripheral I2S hardware instance address.
381 */
i2s_ll_tx_disable_intr(i2s_dev_t * hw)382 static inline void i2s_ll_tx_disable_intr(i2s_dev_t *hw)
383 {
384 hw->int_ena.out_eof = 0;
385 }
386
387 /**
388 * @brief Enable RX interrupt
389 *
390 * @param hw Peripheral I2S hardware instance address.
391 */
i2s_ll_rx_enable_intr(i2s_dev_t * hw)392 static inline void i2s_ll_rx_enable_intr(i2s_dev_t *hw)
393 {
394 hw->int_ena.in_suc_eof = 1;
395 }
396
397 /**
398 * @brief Disable RX interrupt
399 *
400 * @param hw Peripheral I2S hardware instance address.
401 */
i2s_ll_rx_disable_intr(i2s_dev_t * hw)402 static inline void i2s_ll_rx_disable_intr(i2s_dev_t *hw)
403 {
404 hw->int_ena.in_suc_eof = 0;
405 }
406
407 /**
408 * @brief Get interrupt status register address
409 *
410 * @param hw Peripheral I2S hardware instance address.
411 * @return interrupt status register address
412 */
i2s_ll_get_intr_status_reg(i2s_dev_t * hw)413 static inline volatile void *i2s_ll_get_intr_status_reg(i2s_dev_t *hw)
414 {
415 return &hw->int_st;
416 }
417
418 /**
419 * @brief Get I2S interrupt status
420 *
421 * @param hw Peripheral I2S hardware instance address.
422 * @return
423 * - module interrupt status
424 */
425 __attribute__((always_inline))
i2s_ll_get_intr_status(i2s_dev_t * hw)426 static inline uint32_t i2s_ll_get_intr_status(i2s_dev_t *hw)
427 {
428 return hw->int_st.val;
429 }
430
431 /**
432 * @brief Get channel interrupt status register address
433 */
i2s_ll_get_interrupt_status_reg(i2s_dev_t * hw)434 static inline volatile void *i2s_ll_get_interrupt_status_reg(i2s_dev_t *hw)
435 {
436 return (volatile void *)(&hw->int_st);
437 }
438
439 /**
440 * @brief Clear I2S interrupt status
441 *
442 * @param hw Peripheral I2S hardware instance address.
443 * @param clr_mask Interrupt mask to clear interrupt status
444 */
445 __attribute__((always_inline))
i2s_ll_clear_intr_status(i2s_dev_t * hw,uint32_t clr_mask)446 static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t clr_mask)
447 {
448 hw->int_clr.val = clr_mask;
449 }
450
451 /**
452 * @brief Reset dma out
453 *
454 * @param hw Peripheral I2S hardware instance address.
455 */
i2s_ll_tx_reset_dma(i2s_dev_t * hw)456 static inline void i2s_ll_tx_reset_dma(i2s_dev_t *hw)
457 {
458 hw->lc_conf.out_rst = 1;
459 hw->lc_conf.out_rst = 0;
460 }
461
462 /**
463 * @brief Reset dma in
464 *
465 * @param hw Peripheral I2S hardware instance address.
466 */
i2s_ll_rx_reset_dma(i2s_dev_t * hw)467 static inline void i2s_ll_rx_reset_dma(i2s_dev_t *hw)
468 {
469 hw->lc_conf.in_rst = 1;
470 hw->lc_conf.in_rst = 0;
471 }
472
473 /**
474 * @brief Start out link
475 *
476 * @param hw Peripheral I2S hardware instance address.
477 */
i2s_ll_start_out_link(i2s_dev_t * hw)478 static inline void i2s_ll_start_out_link(i2s_dev_t *hw)
479 {
480 hw->out_link.start = 1;
481 }
482
483 /**
484 * @brief Set I2S out link address
485 *
486 * @param hw Peripheral I2S hardware instance address.
487 * @param val value to set out link address
488 */
i2s_ll_set_out_link_addr(i2s_dev_t * hw,uint32_t val)489 static inline void i2s_ll_set_out_link_addr(i2s_dev_t *hw, uint32_t val)
490 {
491 hw->out_link.addr = val;
492 }
493
494 /**
495 * @brief Start TX module
496 *
497 * @param hw Peripheral I2S hardware instance address.
498 */
i2s_ll_tx_start(i2s_dev_t * hw)499 static inline void i2s_ll_tx_start(i2s_dev_t *hw)
500 {
501 hw->conf.tx_start = 1;
502 }
503
504 /**
505 * @brief Start RX module
506 *
507 * @param hw Peripheral I2S hardware instance address.
508 */
i2s_ll_rx_start(i2s_dev_t * hw)509 static inline void i2s_ll_rx_start(i2s_dev_t *hw)
510 {
511 hw->conf.rx_start = 1;
512 }
513
514 /**
515 * @brief Configure TX DMA descriptor address and start TX DMA
516 *
517 * @param hw Peripheral I2S hardware instance address.
518 * @param link_addr DMA descriptor link address.
519 */
i2s_ll_tx_start_link(i2s_dev_t * hw,uint32_t link_addr)520 static inline void i2s_ll_tx_start_link(i2s_dev_t *hw, uint32_t link_addr)
521 {
522 i2s_ll_set_out_link_addr(hw, link_addr);
523 i2s_ll_start_out_link(hw);
524 }
525
526 /**
527 * @brief Configure RX DMA descriptor address and start RX DMA
528 *
529 * @param hw Peripheral I2S hardware instance address.
530 * @param link_addr DMA descriptor link address.
531 */
i2s_ll_rx_start_link(i2s_dev_t * hw,uint32_t link_addr)532 static inline void i2s_ll_rx_start_link(i2s_dev_t *hw, uint32_t link_addr)
533 {
534 hw->in_link.addr = link_addr;
535 hw->in_link.start = 1;
536 }
537
538 /**
539 * @brief Stop TX module
540 *
541 * @param hw Peripheral I2S hardware instance address.
542 */
i2s_ll_tx_stop(i2s_dev_t * hw)543 static inline void i2s_ll_tx_stop(i2s_dev_t *hw)
544 {
545 hw->conf.tx_start = 0;
546 }
547
548 /**
549 * @brief Stop RX module
550 *
551 * @param hw Peripheral I2S hardware instance address.
552 */
i2s_ll_rx_stop(i2s_dev_t * hw)553 static inline void i2s_ll_rx_stop(i2s_dev_t *hw)
554 {
555 hw->conf.rx_start = 0;
556 }
557
558 /**
559 * @brief Stop out link
560 *
561 * @param hw Peripheral I2S hardware instance address.
562 */
i2s_ll_tx_stop_link(i2s_dev_t * hw)563 static inline void i2s_ll_tx_stop_link(i2s_dev_t *hw)
564 {
565 hw->out_link.stop = 1;
566 }
567
568 /**
569 * @brief Stop in link
570 *
571 * @param hw Peripheral I2S hardware instance address.
572 */
i2s_ll_rx_stop_link(i2s_dev_t * hw)573 static inline void i2s_ll_rx_stop_link(i2s_dev_t *hw)
574 {
575 hw->in_link.stop = 1;
576 }
577
578 /**
579 * @brief Get I2S out eof descriptor address
580 *
581 * @param hw Peripheral I2S hardware instance address.
582 * @param eof_addr Pointer to accept out eof des address
583 */
584 __attribute__((always_inline))
i2s_ll_tx_get_eof_des_addr(i2s_dev_t * hw,uint32_t * eof_addr)585 static inline void i2s_ll_tx_get_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr)
586 {
587 *eof_addr = hw->out_eof_des_addr;
588 }
589
590 /**
591 * @brief Get I2S in eof descriptor address
592 *
593 * @param hw Peripheral I2S hardware instance address.
594 * @param eof_addr Pointer to accept in eof des address
595 */
596 __attribute__((always_inline))
i2s_ll_rx_get_eof_des_addr(i2s_dev_t * hw,uint32_t * eof_addr)597 static inline void i2s_ll_rx_get_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr)
598 {
599 *eof_addr = hw->in_eof_des_addr;
600 }
601
602 /**
603 * @brief Configure the received length to trigger in_suc_eof interrupt
604 *
605 * @param hw Peripheral I2S hardware instance address.
606 * @param eof_num the byte length to trigger in_suc_eof interrupt
607 */
i2s_ll_rx_set_eof_num(i2s_dev_t * hw,int eof_num)608 static inline void i2s_ll_rx_set_eof_num(i2s_dev_t *hw, int eof_num)
609 {
610 // On ESP32, the eof_num count in words.
611 hw->rx_eof_num = eof_num / 4;
612 }
613
614 /**
615 * @brief Set I2S tx bits mod
616 *
617 * @param hw Peripheral I2S hardware instance address.
618 * @param val value to set tx bits mod
619 */
i2s_ll_tx_set_bits_mod(i2s_dev_t * hw,uint32_t val)620 static inline void i2s_ll_tx_set_bits_mod(i2s_dev_t *hw, uint32_t val)
621 {
622 hw->sample_rate_conf.tx_bits_mod = val;
623 }
624
625 /**
626 * @brief Congfigure TX chan bit and audio data bit, on ESP32, sample_bit should equals to data_bit
627 *
628 * @param hw Peripheral I2S hardware instance address.
629 * @param chan_bit The chan bit width
630 * @param data_bit The audio data bit width
631 */
i2s_ll_tx_set_sample_bit(i2s_dev_t * hw,uint8_t chan_bit,int data_bit)632 static inline void i2s_ll_tx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit)
633 {
634 hw->fifo_conf.tx_fifo_mod = (chan_bit <= I2S_DATA_BIT_WIDTH_16BIT ? 0 : 2);
635 hw->sample_rate_conf.tx_bits_mod = data_bit;
636 }
637
638 /**
639 * @brief Congfigure RX chan bit and audio data bit, on ESP32, sample_bit should equals to data_bit
640 *
641 * @param hw Peripheral I2S hardware instance address.
642 * @param chan_bit The chan bit width
643 * @param data_bit The audio data bit width
644 */
i2s_ll_rx_set_sample_bit(i2s_dev_t * hw,uint8_t chan_bit,int data_bit)645 static inline void i2s_ll_rx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit)
646 {
647 hw->fifo_conf.rx_fifo_mod = (chan_bit <= I2S_DATA_BIT_WIDTH_16BIT ? 0 : 2);
648 hw->sample_rate_conf.rx_bits_mod = data_bit;
649 }
650
651 /**
652 * @brief Set whether to continue I2S signal on bus when TX FIFO is empty
653 *
654 * @param hw Peripheral I2S hardware instance address.
655 * @param en whether to stop when tx fifo is empty
656 */
i2s_ll_tx_stop_on_fifo_empty(i2s_dev_t * hw,bool en)657 static inline void i2s_ll_tx_stop_on_fifo_empty(i2s_dev_t *hw, bool en)
658 {
659 hw->conf1.tx_stop_en = en;
660 }
661
662 /**
663 * @brief Set whether to bypass the internal PCM module
664 *
665 * @param hw Peripheral I2S hardware instance address.
666 * @param bypass whether to bypass the PCM module
667 */
i2s_ll_tx_bypass_pcm(i2s_dev_t * hw,bool bypass)668 static inline void i2s_ll_tx_bypass_pcm(i2s_dev_t *hw, bool bypass)
669 {
670 hw->conf1.tx_pcm_bypass = bypass;
671 }
672
673 /**
674 * @brief Enable I2S DMA
675 *
676 * @param hw Peripheral I2S hardware instance address.
677 * @param ena Set true to enable DMA
678 */
i2s_ll_enable_dma(i2s_dev_t * hw,bool ena)679 static inline void i2s_ll_enable_dma(i2s_dev_t *hw, bool ena)
680 {
681 hw->fifo_conf.dscr_en = ena;
682 }
683
684 /**
685 * @brief Configure TX WS signal width
686 *
687 * @param hw Peripheral I2S hardware instance address.
688 * @param width WS width in BCK cycle
689 */
i2s_ll_tx_set_ws_width(i2s_dev_t * hw,int width)690 static inline void i2s_ll_tx_set_ws_width(i2s_dev_t *hw, int width)
691 {
692 hw->conf.tx_short_sync = width == 1 ? 1 : 0;
693 }
694
695 /**
696 * @brief Configure RX WS signal width
697 *
698 * @param hw Peripheral I2S hardware instance address.
699 * @param width WS width in BCK cycle
700 */
i2s_ll_rx_set_ws_width(i2s_dev_t * hw,int width)701 static inline void i2s_ll_rx_set_ws_width(i2s_dev_t *hw, int width)
702 {
703 hw->conf.rx_short_sync = width == 1 ? 1 : 0;
704 }
705
706 /**
707 * @brief Enable TX MSB shift, the data will be launch at the first BCK clock
708 *
709 * @param hw Peripheral I2S hardware instance address.
710 * @param msb_shift_enable Set true to enable MSB shift
711 */
i2s_ll_tx_enable_msb_shift(i2s_dev_t * hw,bool msb_shift_enable)712 static inline void i2s_ll_tx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable)
713 {
714 hw->conf.tx_msb_shift = msb_shift_enable;
715 }
716
717 /**
718 * @brief Enable RX MSB shift, the data will be launch at the first BCK clock
719 *
720 * @param hw Peripheral I2S hardware instance address.
721 * @param msb_shift_enable Set true to enable MSB shift
722 */
i2s_ll_rx_enable_msb_shift(i2s_dev_t * hw,bool msb_shift_enable)723 static inline void i2s_ll_rx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable)
724 {
725 hw->conf.rx_msb_shift = msb_shift_enable;
726 }
727
728 /**
729 * @brief Set I2S PDM TX chan mode
730 * @param slot_mask select slot to send data
731 * @param is_mono is mono mode
732 */
i2s_ll_tx_select_pdm_slot(i2s_dev_t * hw,i2s_pdm_slot_mask_t slot_mask,bool is_mono)733 static inline void i2s_ll_tx_select_pdm_slot(i2s_dev_t *hw, i2s_pdm_slot_mask_t slot_mask, bool is_mono)
734 {
735 if (is_mono) {
736 switch (slot_mask)
737 {
738 case I2S_PDM_SLOT_RIGHT:
739 hw->conf_chan.tx_chan_mod = 3;
740 break;
741 case I2S_PDM_SLOT_LEFT:
742 hw->conf_chan.tx_chan_mod = 4;
743 break;
744 case I2S_PDM_SLOT_BOTH:
745 hw->conf_chan.tx_chan_mod = 1; // 1 & 2 has same effect
746 break;
747 default:
748 break;
749 }
750 } else {
751 switch (slot_mask)
752 {
753 case I2S_PDM_SLOT_RIGHT:
754 hw->conf_chan.tx_chan_mod = 1;
755 break;
756 case I2S_PDM_SLOT_LEFT:
757 hw->conf_chan.tx_chan_mod = 2;
758 break;
759 case I2S_PDM_SLOT_BOTH:
760 hw->conf_chan.tx_chan_mod = 0;
761 break;
762 default:
763 break;
764 }
765 }
766 }
767
768 /**
769 * @brief Set I2S PDM RX chan mode
770 * @param slot_mask select slot to send data
771 */
i2s_ll_rx_select_pdm_slot(i2s_dev_t * hw,i2s_pdm_slot_mask_t slot_mask)772 static inline void i2s_ll_rx_select_pdm_slot(i2s_dev_t *hw, i2s_pdm_slot_mask_t slot_mask)
773 {
774 switch (slot_mask)
775 {
776 case I2S_PDM_SLOT_RIGHT:
777 hw->conf_chan.rx_chan_mod = 1;
778 break;
779 case I2S_PDM_SLOT_LEFT:
780 hw->conf_chan.rx_chan_mod = 2;
781 break;
782 case I2S_PDM_SLOT_BOTH:
783 hw->conf_chan.rx_chan_mod = 0;
784 break;
785 default:
786 break;
787 }
788 }
789
790 /**
791 * @brief Set I2S tx chan mode
792 *
793 * @param hw Peripheral I2S hardware instance address.
794 * @param slot_mask select slot to send data
795 * @param is_mono is mono mode
796 */
i2s_ll_tx_select_std_slot(i2s_dev_t * hw,i2s_std_slot_mask_t slot_mask,bool is_mono)797 static inline void i2s_ll_tx_select_std_slot(i2s_dev_t *hw, i2s_std_slot_mask_t slot_mask, bool is_mono)
798 {
799 if (is_mono) {
800 switch (slot_mask)
801 {
802 case I2S_STD_SLOT_RIGHT:
803 hw->conf_chan.tx_chan_mod = 3;
804 break;
805 case I2S_STD_SLOT_LEFT:
806 hw->conf_chan.tx_chan_mod = 4;
807 break;
808 case I2S_STD_SLOT_BOTH:
809 hw->conf_chan.tx_chan_mod = 1; // 1 & 2 has same effect
810 break;
811 default:
812 break;
813 }
814 } else {
815 switch (slot_mask)
816 {
817 case I2S_STD_SLOT_RIGHT:
818 hw->conf_chan.tx_chan_mod = 1;
819 break;
820 case I2S_STD_SLOT_LEFT:
821 hw->conf_chan.tx_chan_mod = 2;
822 break;
823 case I2S_STD_SLOT_BOTH:
824 hw->conf_chan.tx_chan_mod = 0;
825 break;
826 default:
827 break;
828 }
829 }
830 }
831
832 /**
833 * @brief Set I2S rx chan mode
834 *
835 * @param hw Peripheral I2S hardware instance address.
836 * @param slot_mask select slot to receive data
837 * @param is_msb_right the slot sequence is affected by msb_right according to TRM
838 */
i2s_ll_rx_select_std_slot(i2s_dev_t * hw,i2s_std_slot_mask_t slot_mask,bool is_msb_right)839 static inline void i2s_ll_rx_select_std_slot(i2s_dev_t *hw, i2s_std_slot_mask_t slot_mask, bool is_msb_right)
840 {
841 switch (slot_mask)
842 {
843 case I2S_STD_SLOT_RIGHT:
844 hw->conf_chan.rx_chan_mod = is_msb_right ? 1 : 2;
845 break;
846 case I2S_STD_SLOT_LEFT:
847 hw->conf_chan.rx_chan_mod = is_msb_right ? 2 : 1;
848 break;
849 case I2S_STD_SLOT_BOTH:
850 hw->conf_chan.rx_chan_mod = 0;
851 break;
852 default:
853 break;
854 }
855 }
856
857 /**
858 * @brief Enable TX mono mode
859 *
860 * @param hw Peripheral I2S hardware instance address.
861 * @param mono_ena Set true to enable mono mde.
862 */
i2s_ll_tx_enable_mono_mode(i2s_dev_t * hw,bool mono_ena)863 static inline void i2s_ll_tx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena)
864 {
865 int data_bit = hw->sample_rate_conf.tx_bits_mod;
866 hw->fifo_conf.tx_fifo_mod = data_bit <= I2S_DATA_BIT_WIDTH_16BIT ? mono_ena : 2 + mono_ena;
867 }
868
869 /**
870 * @brief Enable RX mono mode
871 *
872 * @param hw Peripheral I2S hardware instance address.
873 * @param mono_ena Set true to enable mono mde.
874 */
i2s_ll_rx_enable_mono_mode(i2s_dev_t * hw,bool mono_ena)875 static inline void i2s_ll_rx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena)
876 {
877 int data_bit = hw->sample_rate_conf.rx_bits_mod;
878 hw->fifo_conf.rx_fifo_mod = data_bit <= I2S_DATA_BIT_WIDTH_16BIT ? mono_ena : 2 + mono_ena;
879 }
880
881 /**
882 * @brief Enable I2S loopback mode
883 *
884 * @param hw Peripheral I2S hardware instance address.
885 * @param loopback_en Set true to share BCK and WS signal for tx module and rx module.
886 */
i2s_ll_share_bck_ws(i2s_dev_t * hw,bool loopback_en)887 static inline void i2s_ll_share_bck_ws(i2s_dev_t *hw, bool loopback_en)
888 {
889 hw->conf.sig_loopback = loopback_en;
890 }
891
892
893
894 /******************************I2S PDM Configurations*************************************/
895 /**
896 * @brief Configure RX PDM downsample
897 *
898 * @param hw Peripheral I2S hardware instance address.
899 * @param dsr PDM downsample configuration paramater
900 */
i2s_ll_rx_set_pdm_dsr(i2s_dev_t * hw,i2s_pdm_dsr_t dsr)901 static inline void i2s_ll_rx_set_pdm_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr)
902 {
903 hw->pdm_conf.rx_sinc_dsr_16_en = dsr;
904 }
905
906 /**
907 * @brief Get RX PDM downsample configuration
908 *
909 * @param hw Peripheral I2S hardware instance address.
910 * @param dsr Pointer to accept PDM downsample configuration
911 */
i2s_ll_rx_get_pdm_dsr(i2s_dev_t * hw,i2s_pdm_dsr_t * dsr)912 static inline void i2s_ll_rx_get_pdm_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr)
913 {
914 *dsr = (i2s_pdm_dsr_t)hw->pdm_conf.rx_sinc_dsr_16_en;
915 }
916
917 /**
918 * @brief Enable I2S TX STD mode
919 *
920 * @param hw Peripheral I2S hardware instance address.
921 */
i2s_ll_tx_enable_std(i2s_dev_t * hw)922 static inline void i2s_ll_tx_enable_std(i2s_dev_t *hw)
923 {
924 hw->conf2.val = 0;
925 hw->pdm_conf.tx_pdm_en = false;
926 hw->pdm_conf.pcm2pdm_conv_en = false;
927 }
928
929 /**
930 * @brief Enable I2S RX STD mode
931 *
932 * @param hw Peripheral I2S hardware instance address.
933 */
i2s_ll_rx_enable_std(i2s_dev_t * hw)934 static inline void i2s_ll_rx_enable_std(i2s_dev_t *hw)
935 {
936 hw->conf2.val = 0;
937 hw->pdm_conf.rx_pdm_en = false;
938 hw->pdm_conf.pdm2pcm_conv_en = false;
939 }
940
941 /**
942 * @brief Enable I2S TX PDM mode
943 *
944 * @param hw Peripheral I2S hardware instance address.
945 * @param pdm_ena Set true to enable TX PDM mode
946 */
i2s_ll_tx_enable_pdm(i2s_dev_t * hw)947 static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw)
948 {
949 hw->conf2.val = 0;
950 hw->pdm_conf.tx_pdm_en = true;
951 hw->pdm_conf.pcm2pdm_conv_en = true;
952 }
953
954 /**
955 * @brief Enable I2S RX PDM mode
956 *
957 * @param hw Peripheral I2S hardware instance address.
958 */
i2s_ll_rx_enable_pdm(i2s_dev_t * hw)959 static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw)
960 {
961 hw->conf2.val = 0;
962 hw->pdm_conf.rx_pdm_en = true;
963 hw->pdm_conf.pdm2pcm_conv_en = true;
964 }
965
966 /**
967 * @brief Set I2S TX PDM prescale
968 *
969 * @param hw Peripheral I2S hardware instance address.
970 * @param prescale I2S TX PDM prescale
971 */
i2s_ll_tx_set_pdm_prescale(i2s_dev_t * hw,bool prescale)972 static inline void i2s_ll_tx_set_pdm_prescale(i2s_dev_t *hw, bool prescale)
973 {
974 HAL_FORCE_MODIFY_U32_REG_FIELD(hw->pdm_conf, tx_prescale, prescale);
975 }
976
977 /**
978 * @brief Set I2S TX PDM high pass filter scaling
979 *
980 * @param hw Peripheral I2S hardware instance address.
981 * @param sig_scale I2S TX PDM signal scaling before transmit to the filter
982 */
i2s_ll_tx_set_pdm_hp_scale(i2s_dev_t * hw,i2s_pdm_sig_scale_t sig_scale)983 static inline void i2s_ll_tx_set_pdm_hp_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale)
984 {
985 hw->pdm_conf.tx_hp_in_shift = sig_scale;
986 }
987
988 /**
989 * @brief Set I2S TX PDM low pass filter scaling
990 *
991 * @param hw Peripheral I2S hardware instance address.
992 * @param sig_scale I2S TX PDM signal scaling before transmit to the filter
993 */
i2s_ll_tx_set_pdm_lp_scale(i2s_dev_t * hw,i2s_pdm_sig_scale_t sig_scale)994 static inline void i2s_ll_tx_set_pdm_lp_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale)
995 {
996 hw->pdm_conf.tx_lp_in_shift = sig_scale;
997 }
998
999 /**
1000 * @brief Set I2S TX PDM sinc filter scaling
1001 *
1002 * @param hw Peripheral I2S hardware instance address.
1003 * @param sig_scale I2S TX PDM signal scaling before transmit to the filter
1004 */
i2s_ll_tx_set_pdm_sinc_scale(i2s_dev_t * hw,i2s_pdm_sig_scale_t sig_scale)1005 static inline void i2s_ll_tx_set_pdm_sinc_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale)
1006 {
1007 hw->pdm_conf.tx_sinc_in_shift = sig_scale;
1008 }
1009
1010 /**
1011 * @brief Set I2S TX PDM sigma-delta filter scaling
1012 *
1013 * @param hw Peripheral I2S hardware instance address.
1014 * @param sig_scale I2S TX PDM signal scaling before transmit to the filter
1015 */
i2s_ll_tx_set_pdm_sd_scale(i2s_dev_t * hw,i2s_pdm_sig_scale_t sig_scale)1016 static inline void i2s_ll_tx_set_pdm_sd_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale)
1017 {
1018 hw->pdm_conf.tx_sigmadelta_in_shift = sig_scale;
1019 }
1020
1021 /**
1022 * @brief Set the PDM TX over sampling ratio
1023 *
1024 * @param hw Peripheral I2S hardware instance address.
1025 * @param ovr Over sampling ratio
1026 */
i2s_ll_tx_set_pdm_over_sample_ratio(i2s_dev_t * hw,uint32_t ovr)1027 static inline void i2s_ll_tx_set_pdm_over_sample_ratio(i2s_dev_t *hw, uint32_t ovr)
1028 {
1029 hw->pdm_conf.tx_sinc_osr2 = ovr;
1030 }
1031
1032 /**
1033 * @brief Configure I2S TX PDM sample rate
1034 * Fpdm = 64*Fpcm*fp/fs
1035 *
1036 * @param hw Peripheral I2S hardware instance address.
1037 * @param fp The fp value of TX PDM filter module group0.
1038 * @param fs The fs value of TX PDM filter module group0.
1039 */
i2s_ll_tx_set_pdm_fpfs(i2s_dev_t * hw,uint32_t fp,uint32_t fs)1040 static inline void i2s_ll_tx_set_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t fs)
1041 {
1042 hw->pdm_freq_conf.tx_pdm_fp = fp;
1043 hw->pdm_freq_conf.tx_pdm_fs = fs;
1044 }
1045
1046 /**
1047 * @brief Get I2S TX PDM fp configuration paramater
1048 *
1049 * @param hw Peripheral I2S hardware instance address.
1050 * @return
1051 * - fp configuration paramater
1052 */
i2s_ll_tx_get_pdm_fp(i2s_dev_t * hw)1053 static inline uint32_t i2s_ll_tx_get_pdm_fp(i2s_dev_t *hw)
1054 {
1055 return hw->pdm_freq_conf.tx_pdm_fp;
1056 }
1057
1058 /**
1059 * @brief Get I2S TX PDM fs configuration paramater
1060 *
1061 * @param hw Peripheral I2S hardware instance address.
1062 * @return
1063 * - fs configuration paramater
1064 */
i2s_ll_tx_get_pdm_fs(i2s_dev_t * hw)1065 static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw)
1066 {
1067 return hw->pdm_freq_conf.tx_pdm_fs;
1068 }
1069
1070
1071
1072
1073 /****************************I2S ADC/DAC Configurations***********************************/
1074 /**
1075 * @brief Enable I2S LCD mode
1076 * @note Have to enable LCD mode to use build in ADC/DAC
1077 *
1078 * @param hw Peripheral I2S hardware instance address.
1079 * @param enable Set true to enable LCD mode.
1080 */
i2s_ll_enable_lcd(i2s_dev_t * hw,bool enable)1081 static inline void i2s_ll_enable_lcd(i2s_dev_t *hw, bool enable)
1082 {
1083 hw->conf2.lcd_en = enable;
1084 }
1085
1086 /**
1087 * @brief Enable I2S camera mode
1088 *
1089 * @param hw Peripheral I2S hardware instance address.
1090 * @param enable Set true to enable camera mode.
1091 */
i2s_ll_enable_camera(i2s_dev_t * hw,bool enable)1092 static inline void i2s_ll_enable_camera(i2s_dev_t *hw, bool enable)
1093 {
1094 hw->conf2.camera_en = enable;
1095 }
1096
1097 /**
1098 * @brief Enable I2S build in ADC mode
1099 *
1100 * @param hw Peripheral I2S hardware instance address.
1101 * @param enable Set true to enable build in ADC
1102 */
i2s_ll_enable_builtin_adc(i2s_dev_t * hw,bool enable)1103 static inline void i2s_ll_enable_builtin_adc(i2s_dev_t *hw, bool enable)
1104 {
1105 hw->conf2.lcd_en = enable;
1106 hw->conf2.camera_en = 0;
1107 hw->conf.rx_right_first = 0;
1108 hw->conf.rx_msb_shift = 0;
1109 hw->conf.rx_mono = 0;
1110 hw->conf.rx_short_sync = 0;
1111 hw->fifo_conf.rx_fifo_mod = enable;
1112 hw->conf_chan.rx_chan_mod = enable;
1113 }
1114
1115 /**
1116 * @brief Enable I2S build in DAC mode
1117 *
1118 * @param hw Peripheral I2S hardware instance address.
1119 * * @param enable Set true to enable build in DAC
1120 */
i2s_ll_enable_builtin_dac(i2s_dev_t * hw,bool enable)1121 static inline void i2s_ll_enable_builtin_dac(i2s_dev_t *hw, bool enable)
1122 {
1123 hw->conf2.lcd_en = enable;
1124 hw->conf2.camera_en = 0;
1125 hw->conf.tx_right_first = enable;
1126 hw->conf.tx_msb_shift = 0;
1127 hw->conf.tx_short_sync = 0;
1128 }
1129
1130 #ifdef __cplusplus
1131 }
1132 #endif
1133