Merge branch 'reafactor/esp_hal_i2s' into 'master'

feat(hal): graudate the I2S hal driver into a new component

Closes IDF-14078

See merge request espressif/esp-idf!43267
This commit is contained in:
Kevin (Lao Kaiyao)
2025-11-19 14:08:20 +08:00
64 changed files with 526 additions and 577 deletions

View File

@@ -3,6 +3,12 @@ idf_build_get_property(esp_tee_build ESP_TEE_BUILD)
set(srcs "hal_utils.c")
set(includes "platform_port/include")
set(requires)
if(${target} STREQUAL "esp32")
# TODO: IDF-14079 remove this dependency when ADC hal is graduated from the common hal component
list(APPEND requires esp_hal_i2s)
endif()
# target specific include must be added before the generic one
# because of the "include_next" directive used by the efuse_hal.h
@@ -103,10 +109,6 @@ elseif(NOT BOOTLOADER_BUILD)
list(APPEND srcs "isp_hal.c")
endif()
if(CONFIG_SOC_LP_I2S_SUPPORTED)
list(APPEND srcs "lp_i2s_hal.c")
endif()
if(CONFIG_SOC_RMT_SUPPORTED)
list(APPEND srcs "rmt_hal.c")
endif()
@@ -123,10 +125,6 @@ elseif(NOT BOOTLOADER_BUILD)
endif()
endif()
if(CONFIG_SOC_I2S_SUPPORTED)
list(APPEND srcs "i2s_hal.c")
endif()
if(CONFIG_SOC_SDM_SUPPORTED)
list(APPEND srcs "sdm_hal.c")
endif()
@@ -261,7 +259,7 @@ endif()
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ${includes}
PRIV_INCLUDE_DIRS ${priv_include}
REQUIRES soc esp_rom
REQUIRES ${requires}
LDFRAGMENTS linker.lf)
if(CONFIG_HAL_DEFAULT_ASSERTION_LEVEL EQUAL 1)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,849 +0,0 @@
/*
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// The LL layer for LP I2S register operations
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
#pragma once
#include <stdbool.h>
#include <math.h>
#include "hal/misc.h"
#include "hal/assert.h"
#include "hal/i2s_types.h"
#include "soc/lp_i2s_struct.h"
#include "soc/lpperi_struct.h"
#include "soc/lp_system_struct.h"
#include "soc/clk_tree_defs.h"
#include "soc/reg_base.h"
#ifdef __cplusplus
extern "C" {
#endif
#define LP_I2S_LL_GET_HW(num) (((num) == 0)? (&LP_I2S) : NULL)
#define LP_I2S_LL_EVENT_RX_DONE_INT (1<<0)
#define LP_I2S_LL_EVENT_RX_HUNG_INT_INT (1<<1)
#define LP_I2S_LL_EVENT_RX_FIFOMEM_UDF_INT (1<<2)
#define LP_I2S_LL_EVENT_VAD_DONE_INT (1<<3)
#define LP_I2S_LL_EVENT_VAD_RESET_DONE_INT (1<<4)
#define LP_I2S_LL_EVENT_RX_MEM_THRESHOLD_INT (1<<5)
#define LP_I2S_LL_TDM_CH_MASK (0x03UL)
#define LP_I2S_LL_RX_SUPPORTED 1
#define LP_I2S_LL_TDM_MAX_DATA_BIT_WIDTH 16
#define LP_I2S_LL_TDM_MAX_CHAN_BIT_WIDTH 16
#define LP_I2S_LL_RX_MEM_THRESH_BYTES_MAX 1020
#define LP_I2S_LL_RX_MEM_POP_BYTES 4
#define LP_I2S_LL_CUT_OFF_COEF_X_NUM 21
#define LP_I2S_LL_CUT_OFF_COEF_Y_NUM 3
/* PDM high pass filter cut-off frequency and coefficients list
* [0]: cut-off frequency * 10; [1]: param0; [2]: param5
* NOTE: the cut-off frequency was timed 10 to use integer type */
#define LP_I2S_LL_CUT_OFF_COEF {{1850, 0, 0}, {1720, 0, 1}, {1600, 1, 1}, \
{1500, 1, 2}, {1370, 2, 2}, {1260, 2, 3}, \
{1200, 0, 3}, {1150, 3, 3}, {1060, 1, 7}, \
{1040, 2, 4}, {920, 4, 4}, {915, 2, 7}, \
{810, 4, 5}, {772, 3, 7}, {690, 5, 5}, \
{630, 4, 7}, {580, 5, 6}, {490, 5, 7}, \
{460, 6, 6}, {355, 6, 7}, {233, 7, 7}}
/**
* @brief LP I2S rx stop mode enum type
*/
typedef enum {
LP_I2S_LL_RX_STOP_MODE_START_CLEAR,
LP_I2S_LL_RX_STOP_MODE_START_CLEAR_EOF_NUM,
} lp_i2s_ll_rx_stop_mode_t;
/**
* @brief LP I2S rx polarity mode enum type
*/
typedef enum {
LP_I2S_LL_RX_WS_POL_NEGATIVE,
LP_I2S_LL_RX_WS_POL_POSITIVE,
} lp_i2s_ll_rx_ws_pol_t;
/**
* @brief LP I2S rx bit order enum type
*/
typedef enum {
LP_I2S_LL_RX_BIT_ORDER_BIG_ENDIAN,
LP_I2S_LL_RX_BIT_ORDER_SMALL_ENDIAN,
} lp_i2s_ll_rx_bit_order_t;
/**
* @brief LP I2S rx align enum type
*/
typedef enum {
LP_I2S_LL_RX_RIGHT_ALIGN,
LP_I2S_LL_RX_LEFT_ALIGN,
} lp_i2s_ll_rx_alignment_t;
/**
* @brief LP I2S rx endian enum type
*/
typedef enum {
LP_I2S_LL_RX_SMALL_ENDIAN,
LP_I2S_LL_RX_BIG_ENDIAN,
} lp_i2s_ll_rx_endian_t;
/*---------------------------------------------------------------
Mem
---------------------------------------------------------------*/
/**
* @brief Enable the internal memory for LP I2S module
*
* @param id Instance id
* @param en enable / disable
*/
static inline void lp_i2s_ll_enable_mem(int id, bool en)
{
LP_SYS.lp_mem_aux_ctrl.lp_mem_aux_ctrl = !en;
}
static inline void lp_i2s_ll_set_rx_mem_threshold(lp_i2s_dev_t *hw, uint32_t words)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_mem_conf, rx_mem_threshold, words);
}
/*---------------------------------------------------------------
Clock
---------------------------------------------------------------*/
/**
* @brief Enable the bus clock for LP I2S module
*
* @param id Instance id
* @param en enable / disable
*/
static inline void lp_i2s_ll_enable_module_clock(int id, bool en)
{
LPPERI.clk_en.ck_en_lp_i2s = en;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define lp_i2s_ll_enable_module_clock(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
lp_i2s_ll_enable_module_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Reset the LP I2S module
*
* @param hw Hardware instance address
*/
static inline void lp_i2s_ll_reset_module_clock(int id)
{
LPPERI.reset_en.rst_en_lp_i2s = 1;
LPPERI.reset_en.rst_en_lp_i2s = 0;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define lp_i2s_ll_reset_module_clock(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
lp_i2s_ll_reset_module_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Enable the bus clock for LP I2S RX module
*
* @param id Instance id
* @param en enable / disable
*/
static inline void lp_i2s_ll_enable_rx_module_clock(int id, bool en)
{
LPPERI.clk_en.ck_en_lp_i2s_rx = en;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define lp_i2s_ll_enable_rx_module_clock(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
lp_i2s_ll_enable_rx_module_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Select ISP clock source
*
* @param id Instance id
* @param clk_src clock source, see valid sources in type `soc_periph_lp_i2s_clk_src_t`
*/
static inline void lp_i2s_ll_select_rx_clk_source(int id, soc_periph_lp_i2s_clk_src_t clk_src)
{
uint8_t clk_val = 0;
switch (clk_src) {
case LP_I2S_CLK_SRC_LP_PERI:
clk_val = 0;
break;
case LP_I2S_CLK_SRC_XTAL_D2:
clk_val = 1;
break;
default:
HAL_ASSERT(false);
break;
}
LPPERI.core_clk_sel.lp_i2s_rx_clk_sel = clk_val;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define lp_i2s_ll_select_rx_clk_source(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
lp_i2s_ll_select_rx_clk_source(__VA_ARGS__); \
} while(0)
/**
* @brief Set LP I2S clock source div num
*
* @note f_LP_I2S_CLK_S / (N + b / a) = f_LP_I2S_RX_CLK
*
* @param id Instance id
* @param val value to set div num
*/
static inline void lp_i2s_ll_clk_source_div_num(int id, uint32_t val)
{
if (val == 256) {
HAL_FORCE_MODIFY_U32_REG_FIELD(LPPERI.lp_i2s_rxclk_div_num, lp_i2s_rx_clkm_div_num, 0);
} else if (val == 2) {
HAL_FORCE_MODIFY_U32_REG_FIELD(LPPERI.lp_i2s_rxclk_div_num, lp_i2s_rx_clkm_div_num, 1);
} else {
HAL_FORCE_MODIFY_U32_REG_FIELD(LPPERI.lp_i2s_rxclk_div_num, lp_i2s_rx_clkm_div_num, val);
}
}
/**
* @brief Set LP I2S rx raw clock division
*
* @param id Instance id
* @param a div a
* @param b div b
*/
static inline void lp_i2s_ll_rx_set_raw_clk_div(int id, uint32_t a, uint32_t b)
{
HAL_ASSERT(b > 0);
if (b <= a / 2) {
LPPERI.lp_i2s_rxclk_div_xyz.lp_i2s_rx_clkm_div_yn1 = 0;
LPPERI.lp_i2s_rxclk_div_xyz.lp_i2s_rx_clkm_div_x = floor(a / b) - 1;
LPPERI.lp_i2s_rxclk_div_xyz.lp_i2s_rx_clkm_div_y = a % b;
LPPERI.lp_i2s_rxclk_div_xyz.lp_i2s_rx_clkm_div_z = b;
} else {
LPPERI.lp_i2s_rxclk_div_xyz.lp_i2s_rx_clkm_div_yn1 = 1;
LPPERI.lp_i2s_rxclk_div_xyz.lp_i2s_rx_clkm_div_x = floor(a / (a - b)) - 1;
LPPERI.lp_i2s_rxclk_div_xyz.lp_i2s_rx_clkm_div_y = a % (a - b);
LPPERI.lp_i2s_rxclk_div_xyz.lp_i2s_rx_clkm_div_z = a - b;
}
if (a == 0 && b == 0) {
LPPERI.lp_i2s_rxclk_div_xyz.lp_i2s_rx_clkm_div_x = 0;
LPPERI.lp_i2s_rxclk_div_xyz.lp_i2s_rx_clkm_div_z = 0;
LPPERI.lp_i2s_rxclk_div_xyz.lp_i2s_rx_clkm_div_y = 1;
}
}
/**
* @brief Set LP I2S rx bck div num
*
* @param hw LP I2S hardware instance
* @param val value to set rx bck div num
*/
static inline void lp_i2s_ll_rx_set_bck_div_num(lp_i2s_dev_t *hw, uint32_t val)
{
hw->rx_conf1.rx_bck_div_num = val - 1;
}
/**
* @brief Enable/Disable clock gate
*
* @param hw LP I2S hardware instance
* @param enable enable or disable
*/
static inline void lp_i2s_ll_clk_gate_en(lp_i2s_dev_t *hw, bool enable)
{
hw->clk_gate.clk_en = enable;
}
/**
* @brief Enable/Disable rx mem clock gate
*
* @param hw LP I2S hardware instance
* @param enable enable or disable
*/
static inline void lp_i2s_ll_rx_mem_clk_gate_en(lp_i2s_dev_t *hw, bool enable)
{
hw->clk_gate.rx_mem_cg_force_on = enable;
}
/**
* @brief Enable/Disable rx reg clock gate
*
* @param hw LP I2S hardware instance
* @param enable enable or disable
*/
static inline void lp_i2s_ll_rx_reg_clk_gate_en(lp_i2s_dev_t *hw, bool enable)
{
hw->clk_gate.rx_reg_cg_force_on = enable;
}
/*---------------------------------------------------------------
Reset
---------------------------------------------------------------*/
/**
* @brief Reset LP I2S RX module
*
* @param hw LP I2S hardware instance
*/
static inline void lp_i2s_ll_rx_reset(lp_i2s_dev_t *hw)
{
hw->rx_conf.rx_reset = 1;
hw->rx_conf.rx_reset = 0;
}
/**
* @brief Reset LP I2S RX FIFO
*
* @param hw LP I2S hardware instance
*/
static inline void lp_i2s_ll_rx_reset_fifo(lp_i2s_dev_t *hw)
{
hw->rx_conf.rx_fifo_reset = 1;
hw->rx_conf.rx_fifo_reset = 0;
}
/**
* @brief Reset LP I2S RX FIFO mem
*
* @param hw LP I2S hardware instance
*/
static inline void lp_i2s_ll_rx_reset_fifo_mem(lp_i2s_dev_t *hw)
{
hw->rx_conf.rx_fifomem_reset = 1;
hw->rx_conf.rx_fifomem_reset = 0;
}
/*---------------------------------------------------------------
Master/Slave
---------------------------------------------------------------*/
/**
* @brief Start LP I2S RX
*
* @param hw LP I2S hardware instance
*/
static inline void lp_i2s_ll_rx_start(lp_i2s_dev_t *hw)
{
hw->rx_conf.rx_update = 1;
while (hw->rx_conf.rx_update);
hw->rx_conf.rx_start = 1;
}
/**
* @brief Set LP I2S RX stop mode
*
* @param hw LP I2S hardware instance
*/
static inline void lp_i2s_ll_set_rx_stop_mode(lp_i2s_dev_t *hw, lp_i2s_ll_rx_stop_mode_t rx_stop_mode)
{
hw->rx_conf.rx_stop_mode = rx_stop_mode;
}
/**
* @brief Configure the received length to trigger in_suc_eof interrupt
*
* @param hw LP I2S hardware instance
* @param eof_num the byte length to trigger in_suc_eof interrupt
*/
static inline void lp_i2s_ll_rx_set_eof_num(lp_i2s_dev_t *hw, int eof_num)
{
hw->rxeof_num.rx_eof_num = eof_num;
}
/**
* @brief Stop LP I2S RX
*
* @param hw LP I2S hardware instance
*/
static inline void lp_i2s_ll_rx_stop(lp_i2s_dev_t *hw)
{
hw->rx_conf.rx_start = 0;
}
/**
* @brief Stop LP I2S RX
*
* @param hw LP I2S hardware instance
* @param is_slave Is slave or master
*/
static inline void lp_i2s_ll_set_rx_master_slave_mode(lp_i2s_dev_t *hw, bool is_slave)
{
hw->rx_conf.rx_slave_mod = is_slave;
}
/*---------------------------------------------------------------
Receive
---------------------------------------------------------------*/
/*--------------------------------------------------
TDM
--------------------------------------------------*/
/**
* @brief Enable LP I2S RX TDM mode
*
* @param hw LP I2S hardware instance
*/
static inline void lp_i2s_ll_rx_enable_tdm(lp_i2s_dev_t *hw)
{
hw->rx_conf.rx_pdm_en = false;
hw->rx_conf.rx_tdm_en = true;
}
/**
* @brief Configure RX total chan number under TDM mode
*
* @param hw LP I2S hardware instance
* @param total_num Total chan number
*/
static inline void lp_i2s_ll_rx_set_tdm_chan_num(lp_i2s_dev_t *hw, int total_num)
{
hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num - 1;
}
/*--------------------------------------------------
PDM
--------------------------------------------------*/
/**
* @brief Enable LP RX PDM mode.
*
* @param hw LP I2S hardware instance
*/
static inline void lp_i2s_ll_rx_enable_pdm(lp_i2s_dev_t *hw)
{
hw->rx_conf.rx_pdm_en = 1;
hw->rx_conf.rx_tdm_en = 0;
}
/**
* @brief Enable LP I2S RX PDM high pass filter
*
* @param hw LP I2S hardware instance
* @param enable Set true to enable I2S RX PDM high pass filter, set false to bypass it
*/
static inline void lp_i2s_ll_rx_enable_pdm_hp_filter(lp_i2s_dev_t *hw, bool enable)
{
hw->rx_pdm_conf.rx_pdm_hp_bypass = !enable;
}
/**
* @brief Set LP_I2S RX PDM high pass filter param0
*
* @param hw Peripheral LP_I2S hardware instance address.
* @param param The fourth parameter of PDM RX IIR_HP filter stage 1 is (504 + LP_I2S_RX_IIR_HP_MULT12_0[2:0])
*/
static inline void lp_i2s_ll_rx_set_pdm_hp_filter_param0(lp_i2s_dev_t *hw, uint32_t param)
{
hw->rx_pdm_conf.rx_iir_hp_mult12_0 = param;
}
/**
* @brief Set LP I2S RX PDM high pass filter param5
*
* @param hw Peripheral LP_I2S hardware instance address.
* @param param The fourth parameter of PDM RX IIR_HP filter stage 2 is (504 + LP_I2S_RX_IIR_HP_MULT12_5[2:0])
*/
static inline void lp_i2s_ll_rx_set_pdm_hp_filter_param5(lp_i2s_dev_t *hw, uint32_t param)
{
hw->rx_pdm_conf.rx_iir_hp_mult12_5 = param;
}
/**
* @brief Configure RX PDM amplify number
* @note This is the amplification number of the digital amplifier,
* which is added after the PDM to PCM conversion result and mainly used for
* amplify the small PDM signal under the VAD scenario
* pcm_result = pdm_input * amplify_num
* pcm_result = 0 if amplify_num = 0
*
* @param hw Peripheral LP_I2S hardware instance address.
* @param amp_num PDM RX amplify number
*/
static inline void lp_i2s_ll_rx_set_pdm_amplify_num(lp_i2s_dev_t *hw, uint32_t amp_num)
{
hw->rx_pdm_conf.rx_pdm2pcm_amplify_num = amp_num;
}
/*---------------------------------------------------------------
General
---------------------------------------------------------------*/
/**
* @brief Configure LP I2S rx channel bits and bits mode
*
* @param hw LP I2S hardware instance
* @param chan_bits Chan bits
* @param bits_mode Bits mode
*/
static inline void lp_i2s_ll_rx_set_sample_bit(lp_i2s_dev_t *hw, int chan_bits, int bits_mode)
{
hw->rx_conf1.rx_tdm_chan_bits = chan_bits - 1;
hw->rx_conf1.rx_bits_mod = bits_mode - 1;
}
/**
* @brief Set LP I2S rx ws polarity
*
* @param hw LP I2S hardware instance
* @param pol ws polarity
*/
static inline void lp_i2s_ll_rx_set_ws_pol(lp_i2s_dev_t *hw, lp_i2s_ll_rx_ws_pol_t pol)
{
hw->rx_conf.rx_ws_idle_pol = pol;
}
/**
* @brief Set LP I2S rx ws width
*
* @param hw LP I2S hardware instance
* @param width ws width
*/
static inline void lp_i2s_ll_rx_set_ws_width(lp_i2s_dev_t *hw, int width)
{
hw->rx_conf1.rx_tdm_ws_width = width - 1;
}
/**
* @brief Set LP I2S rx half sample bits
*
* @param hw LP I2S hardware instance
* @param half_sample_bits Half sample bits
*/
static inline void lp_i2s_ll_rx_set_half_sample_bits(lp_i2s_dev_t *hw, int half_sample_bits)
{
hw->rx_conf1.rx_half_sample_bits = half_sample_bits - 1;
}
/**
* @brief Enable LP I2S RX set active channul
*
* @param hw LP I2S hardware instance
* @param chanid channel id
* @param enable enable or disable
*/
static inline void lp_i2s_ll_rx_set_active_chan(lp_i2s_dev_t *hw, uint32_t chan_mask)
{
uint32_t tdm_ctrl = hw->rx_tdm_ctrl.val;
tdm_ctrl &= ~LP_I2S_LL_TDM_CH_MASK;
tdm_ctrl |= (chan_mask & LP_I2S_LL_TDM_CH_MASK);
hw->rx_tdm_ctrl.val = tdm_ctrl;
}
/**
* @brief Set LP I2S rx std channels
*
* @param hw LP I2S hardware instance
* @param chan_mask select chan to receive data
*/
static inline void lp_i2s_ll_rx_select_std_chan(lp_i2s_dev_t *hw, i2s_std_slot_mask_t chan_mask)
{
hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = 1;
uint32_t mask = 0;
switch (chan_mask)
{
case I2S_STD_SLOT_LEFT:
mask = 0x01;
break;
case I2S_STD_SLOT_RIGHT:
mask = 0x02;
break;
case I2S_STD_SLOT_BOTH:
mask = 0x03;
break;
default:
HAL_ASSERT(false);
break;
}
lp_i2s_ll_rx_set_active_chan(hw, mask);
}
/**
* @brief Set LP I2S rx pdm2pcm enable
*
* @param hw LP I2S hardware instance
* @param en enable or disable
*/
static inline void lp_i2s_ll_rx_set_pdm2pcm_en(lp_i2s_dev_t *hw, bool en)
{
hw->rx_pdm_conf.rx_pdm2pcm_en = en;
}
/**
* @brief Set LP I2S rx bit order
*
* @param hw LP I2S hardware instance
* @param bit_order bit order
*/
static inline void lp_i2s_ll_rx_set_bit_order(lp_i2s_dev_t *hw, lp_i2s_ll_rx_bit_order_t bit_order)
{
hw->rx_conf.rx_bit_order = bit_order;
}
/**
* @brief Enable LP I2S 24 fill
*
* @param hw LP I2S hardware instance
* @param en enable or disable
*/
static inline void lp_i2s_ll_rx_enable_24_fill(lp_i2s_dev_t *hw, bool en)
{
hw->rx_conf.rx_24_fill_en = en;
}
/**
* @brief Set LP I2S rx alignment mode
*
* @param hw LP I2S hardware instance
* @param align align
*/
static inline void lp_i2s_ll_rx_set_alignment_mode(lp_i2s_dev_t *hw, lp_i2s_ll_rx_alignment_t align)
{
hw->rx_conf.rx_left_align = align;
}
/**
* @brief Set LP I2S rx endian
*
* @param hw LP I2S hardware instance
* @param endian endian
*/
static inline void lp_i2s_ll_rx_set_endian(lp_i2s_dev_t *hw, lp_i2s_ll_rx_endian_t endian)
{
hw->rx_conf.rx_big_endian = endian;
}
/**
* @brief Enable RX mono mode
*
* @param hw LP I2S hardware instance
* @param mono_ena Set true to enable mono mde.
*/
static inline void lp_i2s_ll_rx_enable_mono_mode(lp_i2s_dev_t *hw, bool mono_ena)
{
hw->rx_conf.rx_mono = mono_ena;
hw->rx_conf.rx_mono_fst_vld = mono_ena;
}
/**
* @brief Enable RX MSB shift, the data will be launch at the first BCK clock
*
* @param hw LP I2S hardware instance
* @param msb_shift_enable Set true to enable MSB shift
*/
static inline void lp_i2s_ll_rx_enable_msb_shift(lp_i2s_dev_t *hw, bool msb_shift_enable)
{
hw->rx_conf1.rx_msb_shift = msb_shift_enable;
}
/**
* Read from LP I2S hardware data buffer.
*
* @param hw Beginning address of the peripheral registers.
* @param buffer_to_rcv Address of a buffer to read data from hardware data buffer
* @param byte_len Length to read, in bytes.
*/
static inline void lp_i2s_ll_read_buffer(lp_i2s_dev_t *hw, void *buffer_to_rcv, size_t byte_len)
{
for (int i = 0; i < byte_len; i += 4) {
*(uint32_t *)(buffer_to_rcv + i) = *((uint32_t *)LP_I2S_RAM_BASE);
}
}
/**
* Write from LP I2S hardware data buffer.
*
* @param hw Beginning address of the peripheral registers.
* @param buffer_to_rcv Address of a buffer to write data from hardware data buffer
* @param bitlbyte_lenen Length to write, in bytes.
*/
static inline void lp_i2s_ll_write_buffer(lp_i2s_dev_t *hw, const void *buffer_to_send, size_t byte_len)
{
for (int i = 0; i < byte_len; i += 4) {
//Use memcpy to get around alignment issues for txdata
*((uint32_t *)LP_I2S_RAM_BASE) = *(uint32_t *)(buffer_to_send + i);
}
}
/**
* Get RX mem fifo cnt, in bytes
*
* @param hw Beginning address of the peripheral registers.
*/
static inline uint32_t lp_i2s_ll_get_rx_mem_fifo_cnt(lp_i2s_dev_t *hw)
{
return hw->rx_mem_conf.rx_mem_fifo_cnt * 4;
}
/*---------------------------------------------------------------
Interrupt
---------------------------------------------------------------*/
/**
* @brief Get LP I2S RX interrupt status word
*
* @param hw LP I2S hardware instance
* @param raw raw or status
*/
__attribute__((always_inline))
static inline uint32_t lp_i2s_ll_rx_get_interrupt_status(lp_i2s_dev_t *hw, bool raw)
{
if (raw) {
return hw->int_raw.val;
} else {
return hw->int_st.val;
}
}
/**
* @brief Get interrupt status reg address
*
* @param[in] hw LP I2S hardware instance
*
* @return Interrupt status reg address
*/
static inline uint32_t lp_i2s_ll_get_intr_status_reg_addr(lp_i2s_dev_t *hw)
{
return (uint32_t)&(hw->int_st);
}
/**
* @brief Enable LP I2S RX channel interrupt
*
* @param[in] hw LP I2S hardware instance
* @param[in] mask mask
* @param[in] enable enable or disable
*/
static inline void lp_i2s_ll_rx_enable_interrupt(lp_i2s_dev_t *hw, uint32_t mask, bool enable)
{
uint32_t int_ena = hw->int_ena.val;
if (enable) {
int_ena |= mask;
} else {
int_ena &= ~mask;
}
hw->int_ena.val = int_ena;
}
/**
* @brief Clear LP I2S RX channel interrupt
*
* @param[in] hw LP I2S hardware instance
* @param[in] mask mask
*/
__attribute__((always_inline))
static inline void lp_i2s_ll_rx_clear_interrupt_status(lp_i2s_dev_t *hw, uint32_t mask)
{
hw->int_clr.val = mask;
}
/*---------------------------------------------------------------
VAD
---------------------------------------------------------------*/
#define LP_VAD_LL_INIT_FRAME_MIN 100
#define LP_VAD_LL_INIT_FRAME_MAX 200
/**
* @brief Set VAD init frame number
*
* @param[in] hw LP I2S hardware instance
* @param[in] frame_num Frame number
*/
static inline void lp_vad_ll_set_init_frame_num(lp_i2s_dev_t *hw, int frame_num)
{
hw->vad_param0.param_init_frame_num = frame_num;
}
/**
* @brief Set VAD min energy
*
* @param[in] hw LP I2S hardware instance
* @param[in] min_energy Min energy
*/
static inline void lp_vad_ll_set_init_min_energy(lp_i2s_dev_t *hw, int min_energy)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->vad_param0, param_min_energy, min_energy);
}
/**
* @brief Set VAD speak activity thresh
*
* @param[in] hw LP I2S hardware instance
* @param[in] thresh Threshold
*/
static inline void lp_vad_ll_set_speak_activity_thresh(lp_i2s_dev_t *hw, int thresh)
{
hw->vad_param1.param_hangover_speech = thresh;
}
/**
* @brief Set VAD non speak activity thresh
*
* @param[in] hw LP I2S hardware instance
* @param[in] thresh Threshold
*/
static inline void lp_vad_ll_set_non_speak_activity_thresh(lp_i2s_dev_t *hw, int thresh)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->vad_param1, param_hangover_silent, thresh);
}
/**
* @brief Set VAD min speak activity thresh
*
* @param[in] hw LP I2S hardware instance
* @param[in] thresh Threshold
*/
static inline void lp_vad_ll_set_min_speak_activity_thresh(lp_i2s_dev_t *hw, int thresh)
{
hw->vad_param1.param_min_speech_count = thresh;
}
/**
* @brief Set VAD max speak activity thresh
*
* @param[in] hw LP I2S hardware instance
* @param[in] thresh Threshold
*/
static inline void lp_vad_ll_set_max_speak_activity_thresh(lp_i2s_dev_t *hw, int thresh)
{
hw->vad_param1.param_max_speech_count = thresh;
}
/**
* @brief Skip band energy check
*
* @param[in] hw LP I2S hardware instance
* @param[in] skip 1: skip; 0: not skip
*/
static inline void lp_vad_ll_skip_band_energy(lp_i2s_dev_t *hw, bool skip)
{
hw->vad_param1.param_skip_band_energy = skip;
}
/**
* @brief Enable LP I2S 24 fill
*
* @param[in] hw LP I2S hardware instance
* @param[in] en enable or disable
*/
static inline void lp_vad_ll_enable(lp_i2s_dev_t *hw, bool en)
{
hw->vad_conf.vad_en = en;
}
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,406 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// The HAL layer for I2S (common part)
#include "soc/soc.h"
#include "hal/assert.h"
#include "hal/i2s_hal.h"
#if SOC_I2S_HW_VERSION_2 && (SOC_I2S_SUPPORTS_PDM_TX || SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER)
/* PDM tx high pass filter cut-off frequency and coefficients list
* [0]: cut-off frequency * 10; [1]: param0; [2]: param5
* NOTE: the cut-off frequency was timed 10 to use integer type */
static const uint32_t cut_off_coef[21][3] = {
{1850, 0, 0}, {1720, 0, 1}, {1600, 1, 1},
{1500, 1, 2}, {1370, 2, 2}, {1260, 2, 3},
{1200, 0, 3}, {1150, 3, 3}, {1060, 1, 7},
{1040, 2, 4}, {920, 4, 4}, {915, 2, 7},
{810, 4, 5}, {772, 3, 7}, {690, 5, 5},
{630, 4, 7}, {580, 5, 6}, {490, 5, 7},
{460, 6, 6}, {355, 6, 7}, {233, 7, 7}
};
static void s_i2s_hal_get_cut_off_coef(uint32_t freq, uint32_t *param0, uint32_t *param5)
{
uint8_t cnt = 0;
uint32_t min = 10000;
/* Find the closest cut-off frequency and its coefficients */
for (int i = 0; i < 21; i++) {
uint32_t tmp = cut_off_coef[i][0] < freq ? freq - cut_off_coef[i][0] : cut_off_coef[i][0] - freq;
if (tmp < min) {
min = tmp;
cnt = i;
}
}
*param0 = (uint32_t)cut_off_coef[cnt][1];
*param5 = (uint32_t)cut_off_coef[cnt][2];
}
#endif
/**
* @brief Calculate the precise mclk division by sclk and mclk
*
* @param sclk system clock
* @param mclk module clock
* @param mclk_div output the mclk division coefficients
*/
void i2s_hal_calc_mclk_precise_division(uint32_t sclk, uint32_t mclk, hal_utils_clk_div_t *mclk_div)
{
hal_utils_clk_info_t i2s_clk_info = {
.src_freq_hz = sclk,
.exp_freq_hz = mclk,
.max_integ = I2S_LL_CLK_FRAC_DIV_N_MAX,
.min_integ = 1,
.max_fract = I2S_LL_CLK_FRAC_DIV_AB_MAX,
};
hal_utils_calc_clk_div_frac_accurate(&i2s_clk_info, mclk_div);
}
void i2s_hal_init(i2s_hal_context_t *hal, int port_id)
{
/* Get hardware instance */
hal->dev = I2S_LL_GET_HW(port_id);
}
#if SOC_PERIPH_CLK_CTRL_SHARED
void _i2s_hal_set_tx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src, hal_utils_clk_div_t *ret_mclk_div)
{
if (clk_info) {
hal_utils_clk_div_t mclk_div = {};
hal_utils_clk_div_t *mclk_div_ptr = ret_mclk_div ? ret_mclk_div : &mclk_div;
#if SOC_I2S_HW_VERSION_2
_i2s_ll_tx_enable_clock(hal->dev);
_i2s_ll_mclk_bind_to_tx_clk(hal->dev);
#endif
_i2s_ll_tx_clk_set_src(hal->dev, clk_src);
i2s_hal_calc_mclk_precise_division(clk_info->sclk, clk_info->mclk, mclk_div_ptr);
_i2s_ll_tx_set_mclk(hal->dev, mclk_div_ptr);
i2s_ll_tx_set_bck_div_num(hal->dev, clk_info->bclk_div);
} else {
_i2s_ll_tx_clk_set_src(hal->dev, clk_src);
}
}
void _i2s_hal_set_rx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src, hal_utils_clk_div_t *ret_mclk_div)
{
if (clk_info) {
hal_utils_clk_div_t mclk_div = {};
hal_utils_clk_div_t *mclk_div_ptr = ret_mclk_div ? ret_mclk_div : &mclk_div;
#if SOC_I2S_HW_VERSION_2
_i2s_ll_rx_enable_clock(hal->dev);
_i2s_ll_mclk_bind_to_rx_clk(hal->dev);
#endif
_i2s_ll_rx_clk_set_src(hal->dev, clk_src);
i2s_hal_calc_mclk_precise_division(clk_info->sclk, clk_info->mclk, mclk_div_ptr);
_i2s_ll_rx_set_mclk(hal->dev, mclk_div_ptr);
i2s_ll_rx_set_bck_div_num(hal->dev, clk_info->bclk_div);
} else {
_i2s_ll_rx_clk_set_src(hal->dev, clk_src);
}
}
#else
void i2s_hal_set_tx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src, hal_utils_clk_div_t *ret_mclk_div)
{
if (clk_info) {
hal_utils_clk_div_t mclk_div = {};
hal_utils_clk_div_t *mclk_div_ptr = ret_mclk_div ? ret_mclk_div : &mclk_div;
#if SOC_I2S_HW_VERSION_2
i2s_ll_tx_enable_clock(hal->dev);
i2s_ll_mclk_bind_to_tx_clk(hal->dev);
#endif
i2s_ll_tx_clk_set_src(hal->dev, clk_src);
i2s_hal_calc_mclk_precise_division(clk_info->sclk, clk_info->mclk, mclk_div_ptr);
i2s_ll_tx_set_mclk(hal->dev, mclk_div_ptr);
i2s_ll_tx_set_bck_div_num(hal->dev, clk_info->bclk_div);
} else {
i2s_ll_tx_clk_set_src(hal->dev, clk_src);
}
}
void i2s_hal_set_rx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src, hal_utils_clk_div_t *ret_mclk_div)
{
if (clk_info) {
hal_utils_clk_div_t mclk_div = {};
hal_utils_clk_div_t *mclk_div_ptr = ret_mclk_div ? ret_mclk_div : &mclk_div;
#if SOC_I2S_HW_VERSION_2
i2s_ll_rx_enable_clock(hal->dev);
i2s_ll_mclk_bind_to_rx_clk(hal->dev);
#endif
i2s_ll_rx_clk_set_src(hal->dev, clk_src);
i2s_hal_calc_mclk_precise_division(clk_info->sclk, clk_info->mclk, mclk_div_ptr);
i2s_ll_rx_set_mclk(hal->dev, mclk_div_ptr);
i2s_ll_rx_set_bck_div_num(hal->dev, clk_info->bclk_div);
} else {
i2s_ll_rx_clk_set_src(hal->dev, clk_src);
}
}
#endif // SOC_PERIPH_CLK_CTRL_SHARED
/*-------------------------------------------------------------------------
| STD Specific Slot Configurations |
-------------------------------------------------------------------------*/
void i2s_hal_std_set_tx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_hal_slot_config_t *slot_cfg)
{
uint32_t slot_bit_width = (int)slot_cfg->slot_bit_width < (int)slot_cfg->data_bit_width ?
slot_cfg->data_bit_width : slot_cfg->slot_bit_width;
i2s_ll_tx_reset(hal->dev);
i2s_ll_tx_set_slave_mod(hal->dev, is_slave); //TX Slave
i2s_ll_tx_set_sample_bit(hal->dev, slot_bit_width, slot_cfg->data_bit_width);
i2s_ll_tx_enable_msb_shift(hal->dev, slot_cfg->std.bit_shift);
i2s_ll_tx_set_ws_width(hal->dev, slot_cfg->std.ws_width);
#if SOC_I2S_HW_VERSION_1
i2s_ll_tx_enable_mono_mode(hal->dev, slot_cfg->slot_mode == I2S_SLOT_MODE_MONO);
i2s_ll_tx_select_std_slot(hal->dev, slot_cfg->std.slot_mask, slot_cfg->slot_mode == I2S_SLOT_MODE_MONO);
// According to the test, the behavior of tx_msb_right is opposite with TRM, TRM is wrong?
i2s_ll_tx_enable_msb_right(hal->dev, slot_cfg->std.msb_right);
i2s_ll_tx_enable_right_first(hal->dev, slot_cfg->std.ws_pol);
/* Should always enable fifo */
i2s_ll_tx_force_enable_fifo_mod(hal->dev, true);
#elif SOC_I2S_HW_VERSION_2
bool is_copy_mono = slot_cfg->slot_mode == I2S_SLOT_MODE_MONO && slot_cfg->std.slot_mask == I2S_STD_SLOT_BOTH;
i2s_ll_tx_enable_mono_mode(hal->dev, is_copy_mono);
i2s_ll_tx_select_std_slot(hal->dev, is_copy_mono ? I2S_STD_SLOT_LEFT : slot_cfg->std.slot_mask);
i2s_ll_tx_set_skip_mask(hal->dev, (slot_cfg->std.slot_mask != I2S_STD_SLOT_BOTH) &&
(slot_cfg->slot_mode == I2S_SLOT_MODE_STEREO));
i2s_ll_tx_set_half_sample_bit(hal->dev, slot_bit_width);
i2s_ll_tx_set_ws_idle_pol(hal->dev, slot_cfg->std.ws_pol);
i2s_ll_tx_set_bit_order(hal->dev, slot_cfg->std.bit_order_lsb);
i2s_ll_tx_enable_left_align(hal->dev, slot_cfg->std.left_align);
i2s_ll_tx_enable_big_endian(hal->dev, slot_cfg->std.big_endian);
#endif
}
void i2s_hal_std_set_rx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_hal_slot_config_t *slot_cfg)
{
uint32_t slot_bit_width = (int)slot_cfg->slot_bit_width < (int)slot_cfg->data_bit_width ?
slot_cfg->data_bit_width : slot_cfg->slot_bit_width;
i2s_ll_rx_reset(hal->dev);
i2s_ll_rx_set_slave_mod(hal->dev, is_slave); //RX Slave
i2s_ll_rx_set_sample_bit(hal->dev, slot_bit_width, slot_cfg->data_bit_width);
i2s_ll_rx_enable_mono_mode(hal->dev, slot_cfg->slot_mode == I2S_SLOT_MODE_MONO);
i2s_ll_rx_enable_msb_shift(hal->dev, slot_cfg->std.bit_shift);
i2s_ll_rx_set_ws_width(hal->dev, slot_cfg->std.ws_width);
#if SOC_I2S_HW_VERSION_1
i2s_ll_rx_select_std_slot(hal->dev, slot_cfg->std.slot_mask, slot_cfg->std.msb_right);
i2s_ll_rx_enable_msb_right(hal->dev, slot_cfg->std.msb_right);
i2s_ll_rx_enable_right_first(hal->dev, slot_cfg->std.ws_pol);
/* Should always enable fifo */
i2s_ll_rx_force_enable_fifo_mod(hal->dev, true);
#elif SOC_I2S_HW_VERSION_2
i2s_ll_rx_select_std_slot(hal->dev, slot_cfg->std.slot_mask);
i2s_ll_rx_set_half_sample_bit(hal->dev, slot_bit_width);
i2s_ll_rx_set_ws_idle_pol(hal->dev, slot_cfg->std.ws_pol);
i2s_ll_rx_set_bit_order(hal->dev, slot_cfg->std.bit_order_lsb);
i2s_ll_rx_enable_left_align(hal->dev, slot_cfg->std.left_align);
i2s_ll_rx_enable_big_endian(hal->dev, slot_cfg->std.big_endian);
#endif
}
void i2s_hal_std_enable_tx_channel(i2s_hal_context_t *hal)
{
i2s_ll_tx_enable_std(hal->dev);
}
void i2s_hal_std_enable_rx_channel(i2s_hal_context_t *hal)
{
i2s_ll_rx_enable_std(hal->dev);
}
/*-------------------------------------------------------------------------
| PDM Specific Slot Configurations |
-------------------------------------------------------------------------*/
#if SOC_I2S_SUPPORTS_PDM_TX
void i2s_hal_pdm_set_tx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_hal_slot_config_t *slot_cfg)
{
bool is_mono = slot_cfg->slot_mode == I2S_SLOT_MODE_MONO;
i2s_ll_tx_reset(hal->dev);
i2s_ll_tx_set_slave_mod(hal->dev, is_slave); //TX Slave
i2s_ll_tx_enable_msb_shift(hal->dev, false);
if (slot_cfg->pdm_tx.data_fmt == I2S_PDM_DATA_FMT_PCM) {
i2s_ll_tx_set_pdm_prescale(hal->dev, slot_cfg->pdm_tx.sd_prescale);
i2s_ll_tx_set_pdm_hp_scale(hal->dev, slot_cfg->pdm_tx.hp_scale);
i2s_ll_tx_set_pdm_lp_scale(hal->dev, slot_cfg->pdm_tx.lp_scale);
i2s_ll_tx_set_pdm_sinc_scale(hal->dev, slot_cfg->pdm_tx.sinc_scale);
i2s_ll_tx_set_pdm_sd_scale(hal->dev, slot_cfg->pdm_tx.sd_scale);
}
#if SOC_I2S_HW_VERSION_1
uint32_t slot_bit_width = (int)slot_cfg->slot_bit_width < (int)slot_cfg->data_bit_width ?
slot_cfg->data_bit_width : slot_cfg->slot_bit_width;
i2s_ll_tx_force_enable_fifo_mod(hal->dev, true);
i2s_ll_tx_set_sample_bit(hal->dev, slot_bit_width, slot_cfg->data_bit_width);
i2s_ll_tx_enable_mono_mode(hal->dev, is_mono);
i2s_ll_tx_select_pdm_slot(hal->dev, slot_cfg->pdm_tx.slot_mask & I2S_STD_SLOT_BOTH, is_mono);
i2s_ll_tx_enable_msb_right(hal->dev, false);
i2s_ll_tx_enable_right_first(hal->dev, false);
#elif SOC_I2S_HW_VERSION_2
/* PDM TX line mode */
i2s_ll_tx_pdm_line_mode(hal->dev, slot_cfg->pdm_tx.line_mode);
/* Force use 32 bit in PDM TX stereo mode to satisfy the frequency */
uint32_t slot_bit_width = is_mono ? 16 : 32;
i2s_ll_tx_set_sample_bit(hal->dev, slot_bit_width, slot_bit_width);
i2s_ll_tx_set_half_sample_bit(hal->dev, 16); // Fixed to 16 in PDM mode
/* By default, taking the DMA data at the first half period of WS */
i2s_ll_tx_pdm_dma_take_mode(hal->dev, is_mono, true);
i2s_ll_tx_set_ws_idle_pol(hal->dev, false);
/* Slot mode seems not take effect according to the test, leave it default here */
i2s_ll_tx_pdm_slot_mode(hal->dev, is_mono, false, I2S_PDM_SLOT_BOTH);
if (slot_cfg->pdm_tx.data_fmt == I2S_PDM_DATA_FMT_PCM) {
uint32_t param0;
uint32_t param5;
s_i2s_hal_get_cut_off_coef(slot_cfg->pdm_tx.hp_cut_off_freq_hzx10, &param0, &param5);
i2s_ll_tx_enable_pdm_hp_filter(hal->dev, slot_cfg->pdm_tx.hp_en);
i2s_ll_tx_set_pdm_hp_filter_param0(hal->dev, param0);
i2s_ll_tx_set_pdm_hp_filter_param5(hal->dev, param5);
i2s_ll_tx_set_pdm_sd_dither(hal->dev, slot_cfg->pdm_tx.sd_dither);
i2s_ll_tx_set_pdm_sd_dither2(hal->dev, slot_cfg->pdm_tx.sd_dither2);
}
#endif
}
void i2s_hal_pdm_enable_tx_channel(i2s_hal_context_t *hal, bool pcm2pdm_en)
{
#if !SOC_I2S_SUPPORTS_PCM2PDM
HAL_ASSERT(!pcm2pdm_en);
#endif
i2s_ll_tx_enable_pdm(hal->dev, pcm2pdm_en);
}
#endif
#if SOC_I2S_SUPPORTS_PDM_RX
void i2s_hal_pdm_set_rx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_hal_slot_config_t *slot_cfg)
{
uint32_t slot_bit_width = (int)slot_cfg->slot_bit_width < (int)slot_cfg->data_bit_width ?
slot_cfg->data_bit_width : slot_cfg->slot_bit_width;
i2s_ll_rx_reset(hal->dev);
i2s_ll_rx_set_slave_mod(hal->dev, is_slave); //RX Slave
i2s_ll_rx_set_sample_bit(hal->dev, slot_bit_width, slot_cfg->data_bit_width);
#if SOC_I2S_HW_VERSION_1
i2s_ll_rx_enable_mono_mode(hal->dev, slot_cfg->slot_mode == I2S_SLOT_MODE_MONO);
i2s_ll_rx_select_pdm_slot(hal->dev, slot_cfg->pdm_rx.slot_mask);
i2s_ll_rx_force_enable_fifo_mod(hal->dev, true);
i2s_ll_rx_enable_msb_right(hal->dev, false);
i2s_ll_rx_enable_right_first(hal->dev, false);
#elif SOC_I2S_HW_VERSION_2
i2s_ll_rx_set_half_sample_bit(hal->dev, 16);
i2s_ll_rx_enable_mono_mode(hal->dev, false);
#if SOC_I2S_PDM_MAX_RX_LINES > 1
uint32_t slot_mask = (slot_cfg->slot_mode == I2S_SLOT_MODE_STEREO && slot_cfg->pdm_rx.slot_mask <= I2S_PDM_SLOT_BOTH) ?
I2S_PDM_SLOT_BOTH : slot_cfg->pdm_rx.slot_mask;
#else
/* Set the channel mask to enable corresponding slots, always enable two slots for stereo mode */
uint32_t slot_mask = slot_cfg->slot_mode == I2S_SLOT_MODE_STEREO ? I2S_PDM_SLOT_BOTH : slot_cfg->pdm_rx.slot_mask;
#endif // SOC_I2S_SUPPORTS_PDM_RX > 1
i2s_ll_rx_set_active_chan_mask(hal->dev, slot_mask);
#endif // SOC_I2S_HW_VERSION_1
#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
if (slot_cfg->pdm_rx.data_fmt != I2S_PDM_DATA_FMT_RAW) {
uint32_t param0;
uint32_t param5;
s_i2s_hal_get_cut_off_coef(slot_cfg->pdm_rx.hp_cut_off_freq_hzx10, &param0, &param5);
i2s_ll_rx_enable_pdm_hp_filter(hal->dev, slot_cfg->pdm_rx.hp_en);
i2s_ll_rx_set_pdm_hp_filter_param0(hal->dev, param0);
i2s_ll_rx_set_pdm_hp_filter_param5(hal->dev, param5);
/* Set the amplification number, the default and the minimum value is 1. 0 will mute the channel */
i2s_ll_rx_set_pdm_amplify_num(hal->dev, slot_cfg->pdm_rx.amplify_num ? slot_cfg->pdm_rx.amplify_num : 1);
}
#endif // SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
}
void i2s_hal_pdm_enable_rx_channel(i2s_hal_context_t *hal, bool pdm2pcm_en)
{
#if !SOC_I2S_SUPPORTS_PDM2PCM
HAL_ASSERT(!pdm2pcm_en);
#endif
i2s_ll_rx_enable_pdm(hal->dev, pdm2pcm_en);
}
#endif
/*-------------------------------------------------------------------------
| TDM Specific Slot Configurations |
-------------------------------------------------------------------------*/
#if SOC_I2S_SUPPORTS_TDM
void i2s_hal_tdm_set_tx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_hal_slot_config_t *slot_cfg)
{
uint32_t slot_bit_width = (int)slot_cfg->slot_bit_width < (int)slot_cfg->data_bit_width ?
slot_cfg->data_bit_width : slot_cfg->slot_bit_width;
uint32_t cnt;
uint32_t msk = slot_cfg->tdm.slot_mask;
/* Get the maximum slot number */
cnt = 32 - __builtin_clz(msk);
/* Except PCM short format (ws_width = 1), there should be at least 2 slots in total even for mono mode */
cnt = ((cnt < 2) && (slot_cfg->tdm.ws_width != 1)) ? 2 : cnt;
uint32_t total_slot = slot_cfg->tdm.total_slot > cnt ? slot_cfg->tdm.total_slot : cnt;
i2s_ll_tx_reset(hal->dev);
i2s_ll_tx_set_slave_mod(hal->dev, is_slave); //TX Slave
i2s_ll_tx_set_sample_bit(hal->dev, slot_bit_width, slot_cfg->data_bit_width);
i2s_ll_tx_enable_mono_mode(hal->dev, slot_cfg->slot_mode == I2S_SLOT_MODE_MONO);
i2s_ll_tx_enable_msb_shift(hal->dev, slot_cfg->tdm.bit_shift);
if (slot_cfg->tdm.ws_width == 0) { // 0: I2S_TDM_AUTO_WS_WIDTH
i2s_ll_tx_set_ws_width(hal->dev, (total_slot * slot_bit_width) / 2);
} else {
i2s_ll_tx_set_ws_width(hal->dev, slot_cfg->tdm.ws_width);
}
i2s_ll_tx_set_ws_idle_pol(hal->dev, slot_cfg->tdm.ws_pol);
i2s_ll_tx_set_chan_num(hal->dev, total_slot);
/* In mono mode, there only should be one slot enabled, other inactive slots will transmit same data as enabled slot */
i2s_ll_tx_set_active_chan_mask(hal->dev, (slot_cfg->slot_mode == I2S_SLOT_MODE_MONO) ?
I2S_TDM_SLOT0 : (uint32_t)slot_cfg->tdm.slot_mask);
i2s_ll_tx_set_skip_mask(hal->dev, slot_cfg->tdm.skip_mask);
i2s_ll_tx_set_half_sample_bit(hal->dev, total_slot * slot_bit_width / 2);
i2s_ll_tx_set_bit_order(hal->dev, slot_cfg->tdm.bit_order_lsb);
i2s_ll_tx_enable_left_align(hal->dev, slot_cfg->tdm.left_align);
i2s_ll_tx_enable_big_endian(hal->dev, slot_cfg->tdm.big_endian);
}
void i2s_hal_tdm_set_rx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_hal_slot_config_t *slot_cfg)
{
uint32_t slot_bit_width = (int)slot_cfg->slot_bit_width < (int)slot_cfg->data_bit_width ?
slot_cfg->data_bit_width : slot_cfg->slot_bit_width;
uint32_t cnt;
uint32_t msk = slot_cfg->tdm.slot_mask;
/* Get the maximum slot number */
cnt = 32 - __builtin_clz(msk);
/* Except PCM short format (ws_width = 1), there should be at least 2 slots in total even for mono mode */
cnt = ((cnt < 2) && (slot_cfg->tdm.ws_width != 1)) ? 2 : cnt;
uint32_t total_slot = slot_cfg->tdm.total_slot > cnt ? slot_cfg->tdm.total_slot : cnt;
i2s_ll_rx_reset(hal->dev);
i2s_ll_rx_set_slave_mod(hal->dev, is_slave); //RX Slave
i2s_ll_rx_set_sample_bit(hal->dev, slot_bit_width, slot_cfg->data_bit_width);
i2s_ll_rx_enable_mono_mode(hal->dev, slot_cfg->slot_mode == I2S_SLOT_MODE_MONO);
i2s_ll_rx_enable_msb_shift(hal->dev, slot_cfg->tdm.bit_shift);
if (slot_cfg->tdm.ws_width == 0) { // 0: I2S_TDM_AUTO_WS_WIDTH
i2s_ll_rx_set_ws_width(hal->dev, (total_slot * slot_bit_width) / 2);
} else {
i2s_ll_rx_set_ws_width(hal->dev, slot_cfg->tdm.ws_width);
}
i2s_ll_rx_set_ws_idle_pol(hal->dev, slot_cfg->tdm.ws_pol);
i2s_ll_rx_set_chan_num(hal->dev, total_slot);
/* In mono mode, there only should be one slot enabled, other inactive slots will transmit same data as enabled slot */
i2s_ll_rx_set_active_chan_mask(hal->dev, (slot_cfg->slot_mode == I2S_SLOT_MODE_MONO) ?
I2S_TDM_SLOT0 : (uint32_t)slot_cfg->tdm.slot_mask);
i2s_ll_rx_set_half_sample_bit(hal->dev, total_slot * slot_bit_width / 2);
i2s_ll_rx_set_bit_order(hal->dev, slot_cfg->tdm.bit_order_lsb);
i2s_ll_rx_enable_left_align(hal->dev, slot_cfg->tdm.left_align);
i2s_ll_rx_enable_big_endian(hal->dev, slot_cfg->tdm.big_endian);
}
void i2s_hal_tdm_enable_tx_channel(i2s_hal_context_t *hal)
{
i2s_ll_tx_enable_tdm(hal->dev);
}
void i2s_hal_tdm_enable_rx_channel(i2s_hal_context_t *hal)
{
i2s_ll_rx_enable_tdm(hal->dev);
}
#endif

View File

@@ -138,7 +138,7 @@ typedef struct {
* @brief Init I2S hal context
*
* @param hal Context of the HAL layer
* @param port_id The I2S port number, the max port number is (SOC_I2S_ATTR(INST_NUM) -1)
* @param port_id The I2S port number, the max port number is (I2S_LL_GET(INST_NUM) -1)
*/
void i2s_hal_init(i2s_hal_context_t *hal, int port_id);

View File

@@ -1,244 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stddef.h>
#include "esp_bit_defs.h"
#include "soc/soc_caps.h"
#include "soc/clk_tree_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief I2S channel slot mode
*/
typedef enum {
I2S_SLOT_MODE_MONO = 1, /*!< I2S channel slot format mono, transmit same data in all slots for tx mode, only receive the data in the first slots for rx mode. */
I2S_SLOT_MODE_STEREO = 2, /*!< I2S channel slot format stereo, transmit different data in different slots for tx mode, receive the data in all slots for rx mode. */
} i2s_slot_mode_t;
/**
* @brief I2S channel direction
*/
typedef enum {
I2S_DIR_RX = BIT(0), /*!< I2S channel direction RX */
I2S_DIR_TX = BIT(1), /*!< I2S channel direction TX */
} i2s_dir_t;
/**
* @brief I2S controller role
*/
typedef enum {
I2S_ROLE_MASTER, /*!< I2S controller master role, bclk and ws signal will be set to output */
I2S_ROLE_SLAVE /*!< I2S controller slave role, bclk and ws signal will be set to input */
} i2s_role_t;
/**
* @brief Available data bit width in one slot
*/
typedef enum {
I2S_DATA_BIT_WIDTH_8BIT = 8, /*!< I2S channel data bit-width: 8 */
I2S_DATA_BIT_WIDTH_16BIT = 16, /*!< I2S channel data bit-width: 16 */
I2S_DATA_BIT_WIDTH_24BIT = 24, /*!< I2S channel data bit-width: 24 */
I2S_DATA_BIT_WIDTH_32BIT = 32, /*!< I2S channel data bit-width: 32 */
} i2s_data_bit_width_t;
/**
* @brief Total slot bit width in one slot
*
*/
typedef enum {
I2S_SLOT_BIT_WIDTH_AUTO = (0), /*!< I2S channel slot bit-width equals to data bit-width */
I2S_SLOT_BIT_WIDTH_8BIT = (8), /*!< I2S channel slot bit-width: 8 */
I2S_SLOT_BIT_WIDTH_16BIT = (16), /*!< I2S channel slot bit-width: 16 */
I2S_SLOT_BIT_WIDTH_24BIT = (24), /*!< I2S channel slot bit-width: 24 */
I2S_SLOT_BIT_WIDTH_32BIT = (32), /*!< I2S channel slot bit-width: 32 */
} i2s_slot_bit_width_t;
#if SOC_HAS(I2S)
typedef soc_periph_i2s_clk_src_t i2s_clock_src_t; /*!< I2S clock source */
#else
typedef int i2s_clock_src_t; /*!< Define a default type to avoid compiling warnings */
#endif
#if SOC_I2S_SUPPORTS_PCM
/**
* @brief A/U-law decompress or compress configuration.
*
*/
typedef enum {
I2S_PCM_DISABLE = 0, /*!< Disable A/U law decompress or compress*/
I2S_PCM_A_DECOMPRESS, /*!< A-law decompress*/
I2S_PCM_A_COMPRESS, /*!< A-law compress*/
I2S_PCM_U_DECOMPRESS, /*!< U-law decompress*/
I2S_PCM_U_COMPRESS, /*!< U-law compress*/
} i2s_pcm_compress_t;
#endif // SOC_I2S_SUPPORTS_PCM
/**
* @brief I2S PDM data format
*
*/
typedef enum {
I2S_PDM_DATA_FMT_PCM = 0, /*!< PDM RX:
* Enable the hardware PDM to PCM filter to convert the inputted PDM data on the line into PCM format in software,
* so that the read data in software is PCM format data already, no need additional software filter.
* PCM data format is only available when PCM2PDM filter is supported in hardware.
* PDM TX:
* Enable the hardware PCM to PDM filter to convert the written PCM data in software into PDM format on the line,
* so that we only need to write the PCM data in software, no need to prepare raw PDM data in software.
* PCM data format is only available when PDM2PCM filter is supported in hardware.
*/
I2S_PDM_DATA_FMT_RAW = 1, /*!< PDM RX:
* Read the raw PDM data directly in software, without the hardware PDM to PCM filter.
* You may need a software PDM to PCM filter to convert the raw PDM data that read into PCM format.
* PDM TX:
* Write the raw PDM data directly in software, without the hardware PCM to PDM filter.
* You may need to prepare the raw PDM data in software to output the PDM format data on the line.
*/
} i2s_pdm_data_fmt_t;
#if SOC_I2S_SUPPORTS_PDM_RX
/**
* @brief I2S PDM RX down-sampling mode
*/
typedef enum {
I2S_PDM_DSR_8S = 0, /*!< downsampling number is 8 for PDM RX mode*/
I2S_PDM_DSR_16S, /*!< downsampling number is 16 for PDM RX mode*/
I2S_PDM_DSR_MAX,
} i2s_pdm_dsr_t;
#endif // SOC_I2S_SUPPORTS_PDM_RX
#if SOC_I2S_SUPPORTS_PDM_TX
/**
* @brief pdm tx signal scaling mode
*/
typedef enum {
I2S_PDM_SIG_SCALING_DIV_2 = 0, /*!< I2S TX PDM signal scaling: /2 */
I2S_PDM_SIG_SCALING_MUL_1 = 1, /*!< I2S TX PDM signal scaling: x1 */
I2S_PDM_SIG_SCALING_MUL_2 = 2, /*!< I2S TX PDM signal scaling: x2 */
I2S_PDM_SIG_SCALING_MUL_4 = 3, /*!< I2S TX PDM signal scaling: x4 */
} i2s_pdm_sig_scale_t;
#if SOC_I2S_HW_VERSION_2
/**
* @brief PDM TX line mode
* @note For the standard codec mode, PDM pins are connect to a codec which requires both clock signal and data signal
* For the DAC output mode, PDM data signal can be connected to a power amplifier directly with a low-pass filter,
* normally, DAC output mode doesn't need the clock signal.
*/
typedef enum {
I2S_PDM_TX_ONE_LINE_CODEC, /*!< Standard PDM format output, left and right slot data on a single line */
I2S_PDM_TX_ONE_LINE_DAC, /*!< PDM DAC format output, left or right slot data on a single line */
I2S_PDM_TX_TWO_LINE_DAC, /*!< PDM DAC format output, left and right slot data on separated lines */
} i2s_pdm_tx_line_mode_t;
#endif // SOC_I2S_HW_VERSION_2
#endif // SOC_I2S_SUPPORTS_PDM_TX
/**
* @brief I2S slot select in standard mode
* @note It has different meanings in tx/rx/mono/stereo mode, and it may have different behaviors on different targets
* For the details, please refer to the I2S API reference
*/
typedef enum {
I2S_STD_SLOT_LEFT = BIT(0), /*!< I2S transmits or receives left slot */
I2S_STD_SLOT_RIGHT = BIT(1), /*!< I2S transmits or receives right slot */
I2S_STD_SLOT_BOTH = BIT(0) | BIT(1), /*!< I2S transmits or receives both left and right slot */
} i2s_std_slot_mask_t;
/**
* @brief I2S slot select in PDM mode
*
*/
typedef enum {
I2S_PDM_SLOT_RIGHT = BIT(0), /*!< I2S PDM only transmits or receives the PDM device whose 'select' pin is pulled up */
I2S_PDM_SLOT_LEFT = BIT(1), /*!< I2S PDM only transmits or receives the PDM device whose 'select' pin is pulled down */
I2S_PDM_SLOT_BOTH = BIT(0) | BIT(1), /*!< I2S PDM transmits or receives both two slots */
#if SOC_I2S_PDM_MAX_RX_LINES > 1
/* The following enumerators are only used in multi-line PDM RX mode */
I2S_PDM_RX_LINE0_SLOT_RIGHT = I2S_PDM_SLOT_RIGHT, /*!< I2S PDM receives the right slot on line 0 */
I2S_PDM_RX_LINE0_SLOT_LEFT = I2S_PDM_SLOT_LEFT, /*!< I2S PDM receives the left slot on line 0 */
I2S_PDM_RX_LINE1_SLOT_RIGHT = BIT(2), /*!< I2S PDM receives the right slot on line 1 */
I2S_PDM_RX_LINE1_SLOT_LEFT = BIT(3), /*!< I2S PDM receives the left slot on line 1 */
I2S_PDM_RX_LINE2_SLOT_RIGHT = BIT(4), /*!< I2S PDM receives the right slot on line 2 */
I2S_PDM_RX_LINE2_SLOT_LEFT = BIT(5), /*!< I2S PDM receives the left slot on line 2 */
I2S_PDM_RX_LINE3_SLOT_RIGHT = BIT(6), /*!< I2S PDM receives the right slot on line 3 */
I2S_PDM_RX_LINE3_SLOT_LEFT = BIT(7), /*!< I2S PDM receives the left slot on line 3 */
I2S_PDM_LINE_SLOT_ALL = 0x00ff, /*!< I2S PDM receives all slots */
#endif
} i2s_pdm_slot_mask_t;
#if SOC_I2S_SUPPORTS_TDM
/**
* @brief tdm slot number
* @note Multiple slots in TDM mode.
* For TX module, only the active slot send the audio data, the inactive slot send a constant or will be skipped if 'skip_msk' is set.
* For RX module, only receive the audio data in active slots, the data in inactive slots will be ignored.
* the bit map of active slot can not exceed (0x1<<total_slot_num).
* e.g: slot_mask = (I2S_TDM_SLOT0 | I2S_TDM_SLOT3), here the active slot number is 2 and total_slot is not supposed to be smaller than 4.
*/
typedef enum {
I2S_TDM_SLOT0 = BIT(0), /*!< I2S slot 0 enabled */
I2S_TDM_SLOT1 = BIT(1), /*!< I2S slot 1 enabled */
I2S_TDM_SLOT2 = BIT(2), /*!< I2S slot 2 enabled */
I2S_TDM_SLOT3 = BIT(3), /*!< I2S slot 3 enabled */
I2S_TDM_SLOT4 = BIT(4), /*!< I2S slot 4 enabled */
I2S_TDM_SLOT5 = BIT(5), /*!< I2S slot 5 enabled */
I2S_TDM_SLOT6 = BIT(6), /*!< I2S slot 6 enabled */
I2S_TDM_SLOT7 = BIT(7), /*!< I2S slot 7 enabled */
I2S_TDM_SLOT8 = BIT(8), /*!< I2S slot 8 enabled */
I2S_TDM_SLOT9 = BIT(9), /*!< I2S slot 9 enabled */
I2S_TDM_SLOT10 = BIT(10), /*!< I2S slot 10 enabled */
I2S_TDM_SLOT11 = BIT(11), /*!< I2S slot 11 enabled */
I2S_TDM_SLOT12 = BIT(12), /*!< I2S slot 12 enabled */
I2S_TDM_SLOT13 = BIT(13), /*!< I2S slot 13 enabled */
I2S_TDM_SLOT14 = BIT(14), /*!< I2S slot 14 enabled */
I2S_TDM_SLOT15 = BIT(15), /*!< I2S slot 15 enabled */
} i2s_tdm_slot_mask_t;
#endif // SOC_I2S_SUPPORTS_TDM
/**
* @brief I2S channel events that supported by the ETM module
*/
typedef enum {
/** Trigger condition:
* TX: no data to send in the TX FIFO, i.e., DMA need to stop (next desc is NULL)
* RX: 1. If rx_stop_mode = 0, this event will trigger when DMA is stopped (next desc is NULL)
* 2. If rx_stop_mode = 1, this event will trigger when DMA in_suc_eof.
* 3. If rx_stop_mode = 2, this event will trigger when RX FIFO is full.
*/
I2S_ETM_EVENT_DONE, /*!< Event that I2S TX or RX stopped */
/** Trigger condition:
* TX: the sent words(in 32-bit) number reach the threshold that configured in `etm_tx_send_word_num`
* RX: the received words(in 32-bit) number reach the threshold that configured in `etm_rx_receive_word_num`
* and `etm_rx_receive_word_num` should be smaller than the size of the DMA buffer in one `in_suc_eof` event.
*/
I2S_ETM_EVENT_REACH_THRESH, /*!< Event that the I2S sent or received data reached the threshold */
I2S_ETM_EVENT_MAX, /*!< Maximum number of events */
} i2s_etm_event_type_t;
/**
* @brief I2S channel tasks that supported by the ETM module
*/
typedef enum {
I2S_ETM_TASK_START, /*!< Start the I2S channel */
I2S_ETM_TASK_STOP, /*!< Stop the I2S channel */
#if SOC_I2S_SUPPORTS_TX_FIFO_SYNC
I2S_ETM_TASK_SYNC_FIFO, /*!< Check the I2S TX channel sync status */
#endif
I2S_ETM_TASK_MAX, /*!< Maximum number of tasks */
} i2s_etm_task_type_t;
#ifdef __cplusplus
}
#endif

View File

@@ -1,16 +0,0 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// The HAL layer for LP I2S
#include "soc/soc.h"
#include "hal/lp_i2s_hal.h"
#include "hal/lp_i2s_ll.h"
void lp_i2s_hal_init(lp_i2s_hal_context_t *hal, int group_id)
{
hal->dev = LP_I2S_LL_GET_HW(group_id);
}