| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365 |
- /*
- * SPDX-FileCopyrightText: 2021 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"
- /**
- * @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).
- */
- static 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;
- /* If sclk = 0 means APLL clock applied, mclk_div should set to 1 */
- if (!clk_cfg->sclk) {
- cal->mclk_div = 1;
- return;
- }
- uint32_t freq_diff = clk_cfg->sclk - clk_cfg->mclk * cal->mclk_div;
- uint32_t min = ~0;
- for (int a = 2; a <= I2S_LL_MCLK_DIVIDER_MAX; a++) {
- for (int b = 1; b < a; b++) {
- 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)
- {
- /* 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 codec */
- i2s_ll_tx_enable_pdm_sd_codec(hal->dev, true);
- /* 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, 0);
- #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);
- i2s_ll_tx_set_active_chan_mask(hal->dev, hal_cfg->chan_mask);
- 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
- i2s_ll_tx_enable_msb_right(hal->dev, false);
- i2s_ll_tx_enable_right_first(hal->dev, false);
- 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);
- i2s_ll_rx_set_active_chan_mask(hal->dev, hal_cfg->chan_mask);
- 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
- i2s_ll_rx_enable_msb_right(hal->dev, false);
- i2s_ll_rx_enable_right_first(hal->dev, false);
- 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;
- bool is_mono = (hal_cfg->chan_fmt == I2S_CHANNEL_FMT_ONLY_RIGHT) ||
- (hal_cfg->chan_fmt == I2S_CHANNEL_FMT_ONLY_LEFT);
- /* Set channel number and valid data bits */
- #if SOC_I2S_SUPPORTS_TDM
- chan_num = hal_cfg->total_chan;
- i2s_ll_tx_set_chan_num(hal->dev, chan_num);
- #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
- i2s_ll_tx_set_half_sample_bit(hal->dev, chan_num * chan_bits / 2);
- #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_chan_num(hal->dev, chan_num);
- #endif
- 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);
- } 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)
- {
- #if SOC_I2S_SUPPORTS_TDM
- i2s_ll_tx_enable_clock(hal->dev);
- #endif
- i2s_ll_tx_start(hal->dev);
- }
- void i2s_hal_start_rx(i2s_hal_context_t *hal)
- {
- #if SOC_I2S_SUPPORTS_TDM
- i2s_ll_rx_enable_clock(hal->dev);
- #endif
- i2s_ll_rx_start(hal->dev);
- }
- void i2s_hal_stop_tx(i2s_hal_context_t *hal)
- {
- i2s_ll_tx_stop(hal->dev);
- #if SOC_I2S_SUPPORTS_TDM
- i2s_ll_tx_disable_clock(hal->dev);
- #endif
- }
- void i2s_hal_stop_rx(i2s_hal_context_t *hal)
- {
- i2s_ll_rx_stop(hal->dev);
- #if SOC_I2S_SUPPORTS_TDM
- i2s_ll_rx_disable_clock(hal->dev);
- #endif
- }
|