mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-03 03:31:41 +03:00
feat(hal): graudate the I2S hal driver into a new component
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
|
||||
if(${target} STREQUAL "linux")
|
||||
return() # This component is not supported by the POSIX/Linux simulator
|
||||
endif()
|
||||
|
||||
set(srcs)
|
||||
set(includes "include")
|
||||
|
||||
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${target}/include")
|
||||
list(APPEND includes "${target}/include")
|
||||
endif()
|
||||
|
||||
# I2S related source files
|
||||
if(CONFIG_SOC_I2S_SUPPORTED)
|
||||
list(APPEND srcs "i2s_hal.c" "${target}/i2s_periph.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_LP_I2S_SUPPORTED)
|
||||
list(APPEND srcs "lp_i2s_hal.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS ${includes}
|
||||
REQUIRES soc hal)
|
||||
@@ -0,0 +1,48 @@
|
||||
# ESP Hardware Abstraction Layer for I2S Peripheral(s)
|
||||
|
||||
> [!NOTE]
|
||||
> This component is currently in beta. Its API, behavior, and compatibility may change at any time and without notice; backward compatibility is not guaranteed. Use caution when integrating into production systems.
|
||||
|
||||
## Overview
|
||||
|
||||
The `esp_hal_i2s` component provides a **Hardware Abstraction Layer** for Inter-IC Sound (I2S) controllers across all ESP-IDF supported targets. I2S is a serial bus interface standard used for connecting digital audio devices, enabling high-quality audio data transmission between integrated circuits.
|
||||
|
||||
## Architecture
|
||||
|
||||
The I2S HAL is structured in two main sub-layers:
|
||||
|
||||
1. **HAL Layer (Upper)**: Defines the operational steps and data structures required to control I2S peripherals (e.g., initialization, clock configuration, STD/TDM/PDM slot configuration, channel enable/disable).
|
||||
|
||||
2. **Low-Level Layer (Bottom)**: Serves as a translation layer between the HAL and the register files defined in the `soc` component, handling target-specific register configurations.
|
||||
|
||||
## Supported I2S Controllers
|
||||
|
||||
This HAL supports two I2S controller types depending on the ESP chip:
|
||||
|
||||
- **Standard I2S**: Traditional I2S interface supporting master/slave modes. And the different hardware versions are supported regarding different chips.
|
||||
- **Low-Power I2S (LP I2S)**: Power-efficient I2S controller for low-power applications (on supported chips)
|
||||
|
||||
## Features
|
||||
|
||||
- **Multiple Audio Formats**:
|
||||
- Standard I2S (STD) mode
|
||||
- Pulse Density Modulation (PDM) mode
|
||||
- Time Division Multiplexing (TDM) mode
|
||||
- **Master/Slave Mode Support**: Configurable as master or slave device
|
||||
- **Bidirectional Communication**: Independent TX and RX channel configuration
|
||||
- **Clock Configuration**: Precise master clock (MCLK) and bit clock (BCLK) division
|
||||
- **Slot Configuration**: Mono/stereo mode, slot selection, bit width configuration
|
||||
- **PDM/PCM Converter Features**: PCM-to-PDM and PDM-to-PCM conversion, high-pass filtering (on supported chips)
|
||||
- **TDM Features**: Multi-slot TDM support with configurable slot masks
|
||||
- **Signal Connection Management**: GPIO signal mapping and interrupt configuration
|
||||
|
||||
## Usage
|
||||
|
||||
The HAL functions primarily serve ESP-IDF peripheral drivers such as `esp_driver_i2s`.
|
||||
|
||||
Advanced developers can use these interfaces directly when implementing custom drivers, with the understanding that API stability is not guaranteed.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- `soc`: Provides chip-specific register definitions
|
||||
- `hal`: Core hardware abstraction utilities and macros
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "hal/i2s_periph.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
|
||||
/*
|
||||
Bunch of constants for every I2S peripheral: GPIO signals, irqs, hw addr of registers etc
|
||||
*/
|
||||
const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_ATTR(INST_NUM)] = {
|
||||
{
|
||||
.mck_out_sig = -1, // Unavailable
|
||||
.mck_in_sig = -1, // Unavailable
|
||||
|
||||
.m_tx_bck_sig = I2S0O_BCK_OUT_IDX,
|
||||
.m_rx_bck_sig = I2S0I_BCK_OUT_IDX,
|
||||
.m_tx_ws_sig = I2S0O_WS_OUT_IDX,
|
||||
.m_rx_ws_sig = I2S0I_WS_OUT_IDX,
|
||||
|
||||
.s_tx_bck_sig = I2S0O_BCK_IN_IDX,
|
||||
.s_rx_bck_sig = I2S0I_BCK_IN_IDX,
|
||||
.s_tx_ws_sig = I2S0O_WS_IN_IDX,
|
||||
.s_rx_ws_sig = I2S0I_WS_IN_IDX,
|
||||
|
||||
.data_out_sig = I2S0O_DATA_OUT23_IDX,
|
||||
.data_in_sig = I2S0I_DATA_IN15_IDX,
|
||||
|
||||
.irq = ETS_I2S0_INTR_SOURCE,
|
||||
},
|
||||
{
|
||||
.mck_out_sig = -1, // Unavailable
|
||||
.mck_in_sig = -1, // Unavailable
|
||||
|
||||
.m_tx_bck_sig = I2S1O_BCK_OUT_IDX,
|
||||
.m_rx_bck_sig = I2S1I_BCK_OUT_IDX,
|
||||
.m_tx_ws_sig = I2S1O_WS_OUT_IDX,
|
||||
.m_rx_ws_sig = I2S1I_WS_OUT_IDX,
|
||||
|
||||
.s_tx_bck_sig = I2S1O_BCK_IN_IDX,
|
||||
.s_rx_bck_sig = I2S1I_BCK_IN_IDX,
|
||||
.s_tx_ws_sig = I2S1O_WS_IN_IDX,
|
||||
.s_rx_ws_sig = I2S1I_WS_IN_IDX,
|
||||
|
||||
.data_out_sig = I2S1O_DATA_OUT23_IDX,
|
||||
.data_in_sig = I2S1I_DATA_IN15_IDX,
|
||||
|
||||
.irq = ETS_I2S1_INTR_SOURCE,
|
||||
}
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "hal/i2s_periph.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
|
||||
/*
|
||||
Bunch of constants for every I2S peripheral: GPIO signals, irqs, hw addr of registers etc
|
||||
*/
|
||||
const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_ATTR(INST_NUM)] = {
|
||||
{
|
||||
.mck_out_sig = I2S_MCLK_OUT_IDX,
|
||||
.mck_in_sig = I2S_MCLK_IN_IDX,
|
||||
|
||||
.m_tx_bck_sig = I2SO_BCK_OUT_IDX,
|
||||
.m_rx_bck_sig = I2SI_BCK_OUT_IDX,
|
||||
.m_tx_ws_sig = I2SO_WS_OUT_IDX,
|
||||
.m_rx_ws_sig = I2SI_WS_OUT_IDX,
|
||||
|
||||
.s_tx_bck_sig = I2SO_BCK_IN_IDX,
|
||||
.s_rx_bck_sig = I2SI_BCK_IN_IDX,
|
||||
.s_tx_ws_sig = I2SO_WS_IN_IDX,
|
||||
.s_rx_ws_sig = I2SI_WS_IN_IDX,
|
||||
|
||||
.data_out_sigs[0] = I2SO_SD_OUT_IDX,
|
||||
.data_out_sigs[1] = I2SO_SD1_OUT_IDX,
|
||||
.data_in_sig = I2SI_SD_IN_IDX,
|
||||
|
||||
.irq = ETS_I2S0_INTR_SOURCE,
|
||||
}
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "hal/i2s_periph.h"
|
||||
#include "soc/i2s_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
|
||||
/*
|
||||
Bunch of constants for every I2S peripheral: GPIO signals, irqs, hw addr of registers etc
|
||||
*/
|
||||
const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_ATTR(INST_NUM)] = {
|
||||
{
|
||||
.mck_out_sig = I2S_MCLK_OUT_IDX,
|
||||
.mck_in_sig = I2S_MCLK_IN_IDX,
|
||||
|
||||
.m_tx_bck_sig = I2SO_BCK_OUT_IDX,
|
||||
.m_rx_bck_sig = I2SI_BCK_OUT_IDX,
|
||||
.m_tx_ws_sig = I2SO_WS_OUT_IDX,
|
||||
.m_rx_ws_sig = I2SI_WS_OUT_IDX,
|
||||
|
||||
.s_tx_bck_sig = I2SO_BCK_IN_IDX,
|
||||
.s_rx_bck_sig = I2SI_BCK_IN_IDX,
|
||||
.s_tx_ws_sig = I2SO_WS_IN_IDX,
|
||||
.s_rx_ws_sig = I2SI_WS_IN_IDX,
|
||||
|
||||
.data_out_sigs[0] = I2SO_SD_OUT_IDX,
|
||||
.data_out_sigs[1] = I2SO_SD1_OUT_IDX,
|
||||
.data_in_sig = I2SI_SD_IN_IDX,
|
||||
|
||||
.irq = ETS_I2S0_INTR_SOURCE,
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* I2S Registers to be saved during sleep retention
|
||||
* - I2S_RX_CONF_REG
|
||||
* - I2S_TX_CONF_REG
|
||||
* - I2S_RX_CONF1_REG
|
||||
* - I2S_TX_CONF1_REG
|
||||
* - I2S_TX_PCM2PDM_CONF_REG
|
||||
* - I2S_TX_PCM2PDM_CONF1_REG
|
||||
* - I2S_RX_TDM_CTRL_REG
|
||||
* - I2S_TX_TDM_CTRL_REG
|
||||
* - I2S_RXEOF_NUM_REG
|
||||
* - I2S_ETM_CONF_REG
|
||||
*/
|
||||
#define I2S_RETENTION_REGS_CNT 10
|
||||
#define I2S_RETENTION_REGS_BASE(i) I2S_RX_CONF_REG(i)
|
||||
static const uint32_t i2s_regs_map[4] = {0x12360f, 0x0, 0x0, 0x0};
|
||||
#define I2S_SLEEP_RETENTION_ENTRIES(i2s_port) { \
|
||||
/* Save/restore the register values */ \
|
||||
[0] = { .config = REGDMA_LINK_ADDR_MAP_INIT( \
|
||||
REGDMA_I2S_LINK(0x00), \
|
||||
I2S_RETENTION_REGS_BASE(i2s_port), \
|
||||
I2S_RETENTION_REGS_BASE(i2s_port), \
|
||||
I2S_RETENTION_REGS_CNT, 0, 0, \
|
||||
i2s_regs_map[0], i2s_regs_map[1], \
|
||||
i2s_regs_map[2], i2s_regs_map[3]), \
|
||||
.owner = ENTRY(0) | ENTRY(2)}, \
|
||||
};
|
||||
|
||||
static const regdma_entries_config_t i2s0_regs_retention[] = I2S_SLEEP_RETENTION_ENTRIES(0);
|
||||
|
||||
const i2s_reg_retention_info_t i2s_reg_retention_info[SOC_I2S_ATTR(INST_NUM)] = {
|
||||
[0] = {
|
||||
.retention_module = SLEEP_RETENTION_MODULE_I2S0,
|
||||
.entry_array = i2s0_regs_retention,
|
||||
.array_size = ARRAY_SIZE(i2s0_regs_retention)
|
||||
},
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "hal/i2s_periph.h"
|
||||
#include "soc/i2s_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
|
||||
/*
|
||||
Bunch of constants for every I2S peripheral: GPIO signals, irqs, hw addr of registers etc
|
||||
*/
|
||||
const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_ATTR(INST_NUM)] = {
|
||||
{
|
||||
.mck_out_sig = I2S_MCLK_OUT_IDX,
|
||||
.mck_in_sig = I2S_MCLK_IN_IDX,
|
||||
|
||||
.m_tx_bck_sig = I2SO_BCK_OUT_IDX,
|
||||
.m_rx_bck_sig = I2SI_BCK_OUT_IDX,
|
||||
.m_tx_ws_sig = I2SO_WS_OUT_IDX,
|
||||
.m_rx_ws_sig = I2SI_WS_OUT_IDX,
|
||||
|
||||
.s_tx_bck_sig = I2SO_BCK_IN_IDX,
|
||||
.s_rx_bck_sig = I2SI_BCK_IN_IDX,
|
||||
.s_tx_ws_sig = I2SO_WS_IN_IDX,
|
||||
.s_rx_ws_sig = I2SI_WS_IN_IDX,
|
||||
|
||||
.data_out_sigs[0] = I2SO_SD_OUT_IDX,
|
||||
.data_out_sigs[1] = I2SO_SD1_OUT_IDX,
|
||||
.data_in_sig = I2SI_SD_IN_IDX,
|
||||
|
||||
.irq = ETS_I2S0_INTR_SOURCE,
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* I2S Registers to be saved during sleep retention
|
||||
* - I2S_RX_CONF_REG
|
||||
* - I2S_TX_CONF_REG
|
||||
* - I2S_RX_CONF1_REG
|
||||
* - I2S_TX_CONF1_REG
|
||||
* - I2S_TX_PCM2PDM_CONF_REG
|
||||
* - I2S_TX_PCM2PDM_CONF1_REG
|
||||
* - I2S_RX_TDM_CTRL_REG
|
||||
* - I2S_TX_TDM_CTRL_REG
|
||||
* - I2S_RXEOF_NUM_REG
|
||||
* - I2S_ETM_CONF_REG
|
||||
*/
|
||||
#define I2S_RETENTION_REGS_CNT 10
|
||||
#define I2S_RETENTION_REGS_BASE(i) I2S_RX_CONF_REG(i)
|
||||
static const uint32_t i2s_regs_map[4] = {0x12330f, 0x0, 0x0, 0x0};
|
||||
#define I2S_SLEEP_RETENTION_ENTRIES(i2s_port) { \
|
||||
/* Save/restore the register values */ \
|
||||
[0] = { .config = REGDMA_LINK_ADDR_MAP_INIT( \
|
||||
REGDMA_I2S_LINK(0x00), \
|
||||
I2S_RETENTION_REGS_BASE(i2s_port), \
|
||||
I2S_RETENTION_REGS_BASE(i2s_port), \
|
||||
I2S_RETENTION_REGS_CNT, 0, 0, \
|
||||
i2s_regs_map[0], i2s_regs_map[1], \
|
||||
i2s_regs_map[2], i2s_regs_map[3]), \
|
||||
.owner = ENTRY(0) | ENTRY(2)}, \
|
||||
};
|
||||
|
||||
static const regdma_entries_config_t i2s0_regs_retention[] = I2S_SLEEP_RETENTION_ENTRIES(0);
|
||||
|
||||
const i2s_reg_retention_info_t i2s_reg_retention_info[SOC_I2S_ATTR(INST_NUM)] = {
|
||||
[0] = {
|
||||
.retention_module = SLEEP_RETENTION_MODULE_I2S0,
|
||||
.entry_array = i2s0_regs_retention,
|
||||
.array_size = ARRAY_SIZE(i2s0_regs_retention)
|
||||
},
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "hal/i2s_periph.h"
|
||||
#include "soc/i2s_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
|
||||
/*
|
||||
Bunch of constants for every I2S peripheral: GPIO signals, irqs, hw addr of registers etc
|
||||
*/
|
||||
const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_ATTR(INST_NUM)] = {
|
||||
{
|
||||
.mck_out_sig = I2S_MCLK_OUT_IDX,
|
||||
.mck_in_sig = I2S_MCLK_IN_IDX,
|
||||
|
||||
.m_tx_bck_sig = I2SO_BCK_OUT_IDX,
|
||||
.m_rx_bck_sig = I2SI_BCK_OUT_IDX,
|
||||
.m_tx_ws_sig = I2SO_WS_OUT_IDX,
|
||||
.m_rx_ws_sig = I2SI_WS_OUT_IDX,
|
||||
|
||||
.s_tx_bck_sig = I2SO_BCK_IN_IDX,
|
||||
.s_rx_bck_sig = I2SI_BCK_IN_IDX,
|
||||
.s_tx_ws_sig = I2SO_WS_IN_IDX,
|
||||
.s_rx_ws_sig = I2SI_WS_IN_IDX,
|
||||
|
||||
.data_out_sigs[0] = I2SO_SD_OUT_IDX,
|
||||
.data_out_sigs[1] = I2SO_SD1_OUT_IDX,
|
||||
.data_in_sig = I2SI_SD_IN_IDX,
|
||||
|
||||
.irq = ETS_I2S0_INTR_SOURCE,
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* I2S Registers to be saved during sleep retention
|
||||
* - I2S_RX_CONF_REG
|
||||
* - I2S_TX_CONF_REG
|
||||
* - I2S_RX_CONF1_REG
|
||||
* - I2S_TX_CONF1_REG
|
||||
* - I2S_TX_PCM2PDM_CONF_REG
|
||||
* - I2S_TX_PCM2PDM_CONF1_REG
|
||||
* - I2S_RX_TDM_CTRL_REG
|
||||
* - I2S_TX_TDM_CTRL_REG
|
||||
* - I2S_RXEOF_NUM_REG
|
||||
* - I2S_ETM_CONF_REG
|
||||
*/
|
||||
#define I2S_RETENTION_REGS_CNT 10
|
||||
#define I2S_RETENTION_REGS_BASE(i) I2S_RX_CONF_REG
|
||||
static const uint32_t i2s_regs_map[4] = {0x12360f, 0x0, 0x0, 0x0};
|
||||
#define I2S_SLEEP_RETENTION_ENTRIES(i2s_port) { \
|
||||
/* Save/restore the register values */ \
|
||||
[0] = { .config = REGDMA_LINK_ADDR_MAP_INIT( \
|
||||
REGDMA_I2S_LINK(0x00), \
|
||||
I2S_RETENTION_REGS_BASE(i2s_port), \
|
||||
I2S_RETENTION_REGS_BASE(i2s_port), \
|
||||
I2S_RETENTION_REGS_CNT, 0, 0, \
|
||||
i2s_regs_map[0], i2s_regs_map[1], \
|
||||
i2s_regs_map[2], i2s_regs_map[3]), \
|
||||
.owner = ENTRY(0) | ENTRY(2)}, \
|
||||
};
|
||||
|
||||
static const regdma_entries_config_t i2s0_regs_retention[] = I2S_SLEEP_RETENTION_ENTRIES(0);
|
||||
|
||||
const i2s_reg_retention_info_t i2s_reg_retention_info[SOC_I2S_ATTR(INST_NUM)] = {
|
||||
[0] = {
|
||||
.retention_module = SLEEP_RETENTION_MODULE_I2S0,
|
||||
.entry_array = i2s0_regs_retention,
|
||||
.array_size = ARRAY_SIZE(i2s0_regs_retention)
|
||||
},
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "hal/i2s_periph.h"
|
||||
#include "soc/i2s_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
|
||||
/*
|
||||
Bunch of constants for every I2S peripheral: GPIO signals, irqs, hw addr of registers etc
|
||||
*/
|
||||
const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_ATTR(INST_NUM)] = {
|
||||
{
|
||||
.mck_out_sig = I2S_MCLK_OUT_IDX,
|
||||
.mck_in_sig = I2S_MCLK_IN_IDX,
|
||||
|
||||
.m_tx_bck_sig = I2SO_BCK_OUT_IDX,
|
||||
.m_rx_bck_sig = I2SI_BCK_OUT_IDX,
|
||||
.m_tx_ws_sig = I2SO_WS_OUT_IDX,
|
||||
.m_rx_ws_sig = I2SI_WS_OUT_IDX,
|
||||
|
||||
.s_tx_bck_sig = I2SO_BCK_IN_IDX,
|
||||
.s_rx_bck_sig = I2SI_BCK_IN_IDX,
|
||||
.s_tx_ws_sig = I2SO_WS_IN_IDX,
|
||||
.s_rx_ws_sig = I2SI_WS_IN_IDX,
|
||||
|
||||
.data_out_sig = I2SO_SD_OUT_IDX,
|
||||
.data_in_sig = I2SI_SD_IN_IDX,
|
||||
|
||||
.irq = ETS_I2S0_INTR_SOURCE,
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* I2S Registers to be saved during sleep retention
|
||||
* - I2S_RX_CONF_REG
|
||||
* - I2S_TX_CONF_REG
|
||||
* - I2S_RX_CONF1_REG
|
||||
* - I2S_TX_CONF1_REG
|
||||
* - I2S_TX_PCM2PDM_CONF_REG
|
||||
* - I2S_TX_PCM2PDM_CONF1_REG
|
||||
* - I2S_RX_TDM_CTRL_REG
|
||||
* - I2S_TX_TDM_CTRL_REG
|
||||
* - I2S_RXEOF_NUM_REG
|
||||
* - I2S_ETM_CONF_REG
|
||||
*/
|
||||
#define I2S_RETENTION_REGS_CNT 10
|
||||
#define I2S_RETENTION_REGS_BASE(i) I2S_RX_CONF_REG
|
||||
static const uint32_t i2s_regs_map[4] = {0x12330f, 0x0, 0x0, 0x0};
|
||||
#define I2S_SLEEP_RETENTION_ENTRIES(i2s_port) { \
|
||||
/* Save/restore the register values */ \
|
||||
[0] = { .config = REGDMA_LINK_ADDR_MAP_INIT( \
|
||||
REGDMA_I2S_LINK(0x00), \
|
||||
I2S_RETENTION_REGS_BASE(i2s_port), \
|
||||
I2S_RETENTION_REGS_BASE(i2s_port), \
|
||||
I2S_RETENTION_REGS_CNT, 0, 0, \
|
||||
i2s_regs_map[0], i2s_regs_map[1], \
|
||||
i2s_regs_map[2], i2s_regs_map[3]), \
|
||||
.owner = ENTRY(0) | ENTRY(2)}, \
|
||||
};
|
||||
|
||||
static const regdma_entries_config_t i2s0_regs_retention[] = I2S_SLEEP_RETENTION_ENTRIES(0);
|
||||
|
||||
const i2s_reg_retention_info_t i2s_reg_retention_info[SOC_I2S_ATTR(INST_NUM)] = {
|
||||
[0] = {
|
||||
.retention_module = SLEEP_RETENTION_MODULE_I2S0,
|
||||
.entry_array = i2s0_regs_retention,
|
||||
.array_size = ARRAY_SIZE(i2s0_regs_retention)
|
||||
},
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "hal/i2s_periph.h"
|
||||
#include "soc/i2s_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
|
||||
/*
|
||||
Bunch of constants for every I2S peripheral: GPIO signals, irqs, hw addr of registers etc
|
||||
*/
|
||||
const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_ATTR(INST_NUM)] = {
|
||||
{
|
||||
.mck_out_sig = I2S_MCLK_OUT_IDX,
|
||||
.mck_in_sig = I2S_MCLK_IN_IDX,
|
||||
|
||||
.m_tx_bck_sig = I2SO_BCK_OUT_IDX,
|
||||
.m_rx_bck_sig = I2SI_BCK_OUT_IDX,
|
||||
.m_tx_ws_sig = I2SO_WS_OUT_IDX,
|
||||
.m_rx_ws_sig = I2SI_WS_OUT_IDX,
|
||||
|
||||
.s_tx_bck_sig = I2SO_BCK_IN_IDX,
|
||||
.s_rx_bck_sig = I2SI_BCK_IN_IDX,
|
||||
.s_tx_ws_sig = I2SO_WS_IN_IDX,
|
||||
.s_rx_ws_sig = I2SI_WS_IN_IDX,
|
||||
|
||||
.data_out_sig = I2SO_SD_OUT_IDX,
|
||||
.data_in_sig = I2SI_SD_IN_IDX,
|
||||
|
||||
.irq = ETS_I2S_INTR_SOURCE,
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* I2S Registers to be saved during sleep retention
|
||||
* - I2S_INT_ENA_REG
|
||||
* - I2S_RX_CONF_REG
|
||||
* - I2S_TX_CONF_REG
|
||||
* - I2S_RX_CONF1_REG
|
||||
* - I2S_TX_CONF1_REG
|
||||
* - I2S_TX_PCM2PDM_CONF_REG
|
||||
* - I2S_TX_PCM2PDM_CONF1_REG
|
||||
* - I2S_RX_TDM_CTRL_REG
|
||||
* - I2S_TX_TDM_CTRL_REG
|
||||
* - I2S_RXEOF_NUM_REG
|
||||
* - I2S_ETM_CONF_REG
|
||||
* - I2S_IDEAL_CNT_REG
|
||||
* - I2S_SYNC_SW_THRES_REG
|
||||
* - I2S_SYNC_HW_THRES_REG
|
||||
* - I2S_HW_SYNC_CONF_REG
|
||||
* - I2S_HW_SYNC_DATA_REG
|
||||
*/
|
||||
|
||||
#define I2S_RETENTION_REGS_CNT 16
|
||||
#define I2S_RETENTION_REGS_BASE(i) (I2S_INT_ENA_REG(i))
|
||||
static const uint32_t i2s_regs_map[4] = {0xf191b079, 0x0, 0x0, 0x0};
|
||||
#define I2S_SLEEP_RETENTION_ENTRIES(i2s_port) { \
|
||||
[0] = { .config = REGDMA_LINK_ADDR_MAP_INIT( \
|
||||
REGDMA_I2S_LINK(0x00), \
|
||||
I2S_RETENTION_REGS_BASE(i2s_port), \
|
||||
I2S_RETENTION_REGS_BASE(i2s_port), \
|
||||
I2S_RETENTION_REGS_CNT, 0, 0, \
|
||||
i2s_regs_map[0], i2s_regs_map[1], \
|
||||
i2s_regs_map[2], i2s_regs_map[3]), \
|
||||
.owner = ENTRY(0) | ENTRY(2) }, \
|
||||
};
|
||||
static const regdma_entries_config_t i2s0_regs_retention[] = I2S_SLEEP_RETENTION_ENTRIES(0);
|
||||
|
||||
const i2s_reg_retention_info_t i2s_reg_retention_info[SOC_I2S_ATTR(INST_NUM)] = {
|
||||
[0] = {
|
||||
.retention_module = SLEEP_RETENTION_MODULE_I2S0,
|
||||
.entry_array = i2s0_regs_retention,
|
||||
.array_size = ARRAY_SIZE(i2s0_regs_retention)
|
||||
},
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "hal/i2s_periph.h"
|
||||
#include "soc/i2s_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/lp_gpio_sig_map.h"
|
||||
|
||||
/*
|
||||
Bunch of constants for every I2S peripheral: GPIO signals, irqs, hw addr of registers etc
|
||||
*/
|
||||
const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_ATTR(INST_NUM)] = {
|
||||
[0] = {
|
||||
.mck_out_sig = I2S0_MCLK_PAD_OUT_IDX,
|
||||
.mck_in_sig = I2S0_MCLK_PAD_IN_IDX,
|
||||
|
||||
.m_tx_bck_sig = I2S0_O_BCK_PAD_OUT_IDX,
|
||||
.m_rx_bck_sig = I2S0_I_BCK_PAD_OUT_IDX,
|
||||
.m_tx_ws_sig = I2S0_O_WS_PAD_OUT_IDX,
|
||||
.m_rx_ws_sig = I2S0_I_WS_PAD_OUT_IDX,
|
||||
|
||||
.s_tx_bck_sig = I2S0_O_BCK_PAD_IN_IDX,
|
||||
.s_rx_bck_sig = I2S0_I_BCK_PAD_IN_IDX,
|
||||
.s_tx_ws_sig = I2S0_O_WS_PAD_IN_IDX,
|
||||
.s_rx_ws_sig = I2S0_I_WS_PAD_IN_IDX,
|
||||
|
||||
.data_out_sigs[0] = I2S0_O_SD_PAD_OUT_IDX,
|
||||
.data_out_sigs[1] = I2S0_O_SD1_PAD_OUT_IDX,
|
||||
.data_in_sigs[0] = I2S0_I_SD_PAD_IN_IDX,
|
||||
.data_in_sigs[1] = I2S0_I_SD1_PAD_IN_IDX,
|
||||
.data_in_sigs[2] = I2S0_I_SD2_PAD_IN_IDX,
|
||||
.data_in_sigs[3] = I2S0_I_SD3_PAD_IN_IDX,
|
||||
|
||||
.irq = ETS_I2S0_INTR_SOURCE,
|
||||
},
|
||||
[1] = {
|
||||
.mck_out_sig = I2S1_MCLK_PAD_OUT_IDX,
|
||||
.mck_in_sig = I2S1_MCLK_PAD_IN_IDX,
|
||||
|
||||
.m_tx_bck_sig = I2S1_O_BCK_PAD_OUT_IDX,
|
||||
.m_rx_bck_sig = I2S1_I_BCK_PAD_OUT_IDX,
|
||||
.m_tx_ws_sig = I2S1_O_WS_PAD_OUT_IDX,
|
||||
.m_rx_ws_sig = I2S1_I_WS_PAD_OUT_IDX,
|
||||
|
||||
.s_tx_bck_sig = I2S1_O_BCK_PAD_IN_IDX,
|
||||
.s_rx_bck_sig = I2S1_I_BCK_PAD_IN_IDX,
|
||||
.s_tx_ws_sig = I2S1_O_WS_PAD_IN_IDX,
|
||||
.s_rx_ws_sig = I2S1_I_WS_PAD_IN_IDX,
|
||||
|
||||
.data_out_sigs[0] = I2S1_O_SD_PAD_OUT_IDX,
|
||||
.data_out_sigs[1] = -1,
|
||||
.data_in_sigs[0] = I2S1_I_SD_PAD_IN_IDX,
|
||||
.data_in_sigs[1] = -1,
|
||||
.data_in_sigs[2] = -1,
|
||||
.data_in_sigs[3] = -1,
|
||||
|
||||
.irq = ETS_I2S1_INTR_SOURCE,
|
||||
},
|
||||
[2] = {
|
||||
.mck_out_sig = I2S2_MCLK_PAD_OUT_IDX,
|
||||
.mck_in_sig = I2S2_MCLK_PAD_IN_IDX,
|
||||
|
||||
.m_tx_bck_sig = I2S2_O_BCK_PAD_OUT_IDX,
|
||||
.m_rx_bck_sig = I2S2_I_BCK_PAD_OUT_IDX,
|
||||
.m_tx_ws_sig = I2S2_O_WS_PAD_OUT_IDX,
|
||||
.m_rx_ws_sig = I2S2_I_WS_PAD_OUT_IDX,
|
||||
|
||||
.s_tx_bck_sig = I2S2_O_BCK_PAD_IN_IDX,
|
||||
.s_rx_bck_sig = I2S2_I_BCK_PAD_IN_IDX,
|
||||
.s_tx_ws_sig = I2S2_O_WS_PAD_IN_IDX,
|
||||
.s_rx_ws_sig = I2S2_I_WS_PAD_IN_IDX,
|
||||
|
||||
.data_out_sigs[0] = I2S2_O_SD_PAD_OUT_IDX,
|
||||
.data_out_sigs[1] = -1,
|
||||
.data_in_sigs[0] = I2S2_I_SD_PAD_IN_IDX,
|
||||
.data_in_sigs[1] = -1,
|
||||
.data_in_sigs[2] = -1,
|
||||
.data_in_sigs[3] = -1,
|
||||
|
||||
.irq = ETS_I2S2_INTR_SOURCE,
|
||||
},
|
||||
};
|
||||
|
||||
const i2s_signal_conn_t lp_i2s_periph_signal[SOC_LP_I2S_NUM] = {
|
||||
[0] = {
|
||||
.mck_out_sig = -1,
|
||||
.mck_in_sig = -1,
|
||||
|
||||
.m_tx_bck_sig = LP_I2S_O_BCK_PAD_OUT_IDX,
|
||||
.m_rx_bck_sig = LP_I2S_I_BCK_PAD_OUT_IDX,
|
||||
.m_tx_ws_sig = LP_I2S_O_WS_PAD_OUT_IDX,
|
||||
.m_rx_ws_sig = LP_I2S_I_WS_PAD_OUT_IDX,
|
||||
|
||||
.s_tx_bck_sig = LP_I2S_O_BCK_PAD_IN_IDX,
|
||||
.s_rx_bck_sig = LP_I2S_I_BCK_PAD_IN_IDX,
|
||||
.s_tx_ws_sig = LP_I2S_O_WS_PAD_IN_IDX,
|
||||
.s_rx_ws_sig = LP_I2S_I_WS_PAD_IN_IDX,
|
||||
|
||||
.data_out_sigs[0] = LP_I2S_O_SD_PAD_OUT_IDX,
|
||||
.data_out_sigs[1] = -1,
|
||||
.data_in_sigs[0] = LP_I2S_I_SD_PAD_IN_IDX,
|
||||
.data_in_sigs[1] = -1,
|
||||
.data_in_sigs[2] = -1,
|
||||
.data_in_sigs[3] = -1,
|
||||
|
||||
.irq = ETS_LP_I2S_INTR_SOURCE,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* I2S Registers to be saved during sleep retention
|
||||
* - I2S_RX_CONF_REG
|
||||
* - I2S_TX_CONF_REG
|
||||
* - I2S_RX_CONF1_REG
|
||||
* - I2S_TX_CONF1_REG
|
||||
* - I2S_TX_PCM2PDM_CONF_REG
|
||||
* - I2S_TX_PCM2PDM_CONF1_REG
|
||||
* - I2S_RX_PDM2PCM_CONF_REG
|
||||
* - I2S_RX_TDM_CTRL_REG
|
||||
* - I2S_TX_TDM_CTRL_REG
|
||||
* - I2S_RXEOF_NUM_REG
|
||||
* - I2S_ETM_CONF_REG
|
||||
*/
|
||||
#define I2S_RETENTION_REGS_CNT 11
|
||||
#define I2S_RETENTION_REGS_BASE(i) I2S_RX_CONF_REG(i)
|
||||
static const uint32_t i2s_regs_map[4] = {0x12370f, 0x0, 0x0, 0x0};
|
||||
#define I2S_SLEEP_RETENTION_ENTRIES(i2s_port) { \
|
||||
/* Save/restore the register values */ \
|
||||
[0] = { .config = REGDMA_LINK_ADDR_MAP_INIT( \
|
||||
REGDMA_I2S_LINK(0x00), \
|
||||
I2S_RETENTION_REGS_BASE(i2s_port), \
|
||||
I2S_RETENTION_REGS_BASE(i2s_port), \
|
||||
I2S_RETENTION_REGS_CNT, 0, 0, \
|
||||
i2s_regs_map[0], i2s_regs_map[1], \
|
||||
i2s_regs_map[2], i2s_regs_map[3]), \
|
||||
.owner = ENTRY(0)}, \
|
||||
};
|
||||
|
||||
static const regdma_entries_config_t i2s0_regs_retention[] = I2S_SLEEP_RETENTION_ENTRIES(0);
|
||||
static const regdma_entries_config_t i2s1_regs_retention[] = I2S_SLEEP_RETENTION_ENTRIES(1);
|
||||
static const regdma_entries_config_t i2s2_regs_retention[] = I2S_SLEEP_RETENTION_ENTRIES(2);
|
||||
|
||||
const i2s_reg_retention_info_t i2s_reg_retention_info[SOC_I2S_ATTR(INST_NUM)] = {
|
||||
[0] = {
|
||||
.retention_module = SLEEP_RETENTION_MODULE_I2S0,
|
||||
.entry_array = i2s0_regs_retention,
|
||||
.array_size = ARRAY_SIZE(i2s0_regs_retention)
|
||||
},
|
||||
[1] = {
|
||||
.retention_module = SLEEP_RETENTION_MODULE_I2S1,
|
||||
.entry_array = i2s1_regs_retention,
|
||||
.array_size = ARRAY_SIZE(i2s1_regs_retention)
|
||||
},
|
||||
[2] = {
|
||||
.retention_module = SLEEP_RETENTION_MODULE_I2S2,
|
||||
.entry_array = i2s2_regs_retention,
|
||||
.array_size = ARRAY_SIZE(i2s2_regs_retention)
|
||||
},
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,847 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "hal/i2s_periph.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
|
||||
/*
|
||||
Bunch of constants for every I2S peripheral: GPIO signals, irqs, hw addr of registers etc
|
||||
*/
|
||||
const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_ATTR(INST_NUM)] = {
|
||||
{
|
||||
.mck_out_sig = CLK_I2S_MUX_IDX,
|
||||
.mck_in_sig = -1, // Unavailable
|
||||
|
||||
.m_tx_bck_sig = I2S0O_BCK_OUT_IDX,
|
||||
.m_rx_bck_sig = I2S0I_BCK_OUT_IDX,
|
||||
.m_tx_ws_sig = I2S0O_WS_OUT_IDX,
|
||||
.m_rx_ws_sig = I2S0I_WS_OUT_IDX,
|
||||
|
||||
.s_tx_bck_sig = I2S0O_BCK_IN_IDX,
|
||||
.s_rx_bck_sig = I2S0I_BCK_IN_IDX,
|
||||
.s_tx_ws_sig = I2S0O_WS_IN_IDX,
|
||||
.s_rx_ws_sig = I2S0I_WS_IN_IDX,
|
||||
|
||||
.data_out_sig = I2S0O_DATA_OUT23_IDX,
|
||||
.data_in_sig = I2S0I_DATA_IN15_IDX,
|
||||
|
||||
.irq = ETS_I2S0_INTR_SOURCE,
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,998 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
* NOTICE
|
||||
* The hal is not public api, don't use in application code.
|
||||
* See readme.md in hal/include/hal/readme.md
|
||||
******************************************************************************/
|
||||
|
||||
// The LL layer for ESP32-S2 I2S register operations
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "hal/misc.h"
|
||||
#include "hal/i2s_periph.h"
|
||||
#include "soc/i2s_struct.h"
|
||||
#include "soc/system_reg.h"
|
||||
#include "soc/dport_access.h"
|
||||
#include "hal/i2s_types.h"
|
||||
#include "hal/hal_utils.h"
|
||||
#include "hal/assert.h"
|
||||
|
||||
#define I2S_LL_GET(_attr) I2S_LL_ ## _attr
|
||||
#define I2S_LL_BUS_WIDTH 24
|
||||
#define I2S_LL_INST_NUM 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Get I2S hardware instance with giving i2s num
|
||||
#define I2S_LL_GET_HW(num) (((num) == 0) ? (&I2S0) : NULL)
|
||||
|
||||
#define I2S_LL_BCK_MAX_PRESCALE (64)
|
||||
|
||||
#define I2S_LL_CLK_FRAC_DIV_N_MAX 256 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the N register is 8 bit-width
|
||||
#define I2S_LL_CLK_FRAC_DIV_AB_MAX 64 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the a/b register is 6 bit-width
|
||||
|
||||
#define I2S_LL_EVENT_RX_EOF BIT(9)
|
||||
#define I2S_LL_EVENT_TX_EOF BIT(12)
|
||||
#define I2S_LL_EVENT_RX_DSCR_ERR BIT(13)
|
||||
#define I2S_LL_EVENT_TX_DSCR_ERR BIT(14)
|
||||
#define I2S_INTR_MAX (UINT32_MAX)
|
||||
|
||||
#define I2S_LL_TX_EVENT_MASK I2S_LL_EVENT_TX_EOF
|
||||
#define I2S_LL_RX_EVENT_MASK I2S_LL_EVENT_RX_EOF
|
||||
|
||||
#define I2S_LL_DEFAULT_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz
|
||||
|
||||
/**
|
||||
* @brief Enable DMA descriptor owner check
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param en whether to enable owner check
|
||||
*/
|
||||
static inline void i2s_ll_dma_enable_owner_check(i2s_dev_t *hw, bool en)
|
||||
{
|
||||
hw->lc_conf.check_owner = en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable DMA descriptor write back
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param en whether to enable write back
|
||||
*/
|
||||
static inline void i2s_ll_dma_enable_auto_write_back(i2s_dev_t *hw, bool en)
|
||||
{
|
||||
hw->lc_conf.out_auto_wrback = en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2S DMA generate EOF event on data in FIFO popped out
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param en True to enable, False to disable
|
||||
*/
|
||||
static inline void i2s_ll_dma_enable_eof_on_fifo_empty(i2s_dev_t *hw, bool en)
|
||||
{
|
||||
hw->lc_conf.out_eof_mode = en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the bus clock for I2S module
|
||||
*
|
||||
* @param i2s_id The port id of I2S
|
||||
* @param enable Set true to enable the buf clock
|
||||
*/
|
||||
static inline void i2s_ll_enable_bus_clock(int i2s_id, bool enable)
|
||||
{
|
||||
(void) i2s_id;
|
||||
if (enable) {
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
|
||||
} else {
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_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 i2s_ll_enable_bus_clock(...) do { \
|
||||
(void)__DECLARE_RCC_ATOMIC_ENV; \
|
||||
i2s_ll_enable_bus_clock(__VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* @brief Reset the I2S module
|
||||
*
|
||||
* @param i2s_id The port id of I2S
|
||||
*/
|
||||
static inline void i2s_ll_reset_register(int i2s_id)
|
||||
{
|
||||
(void) i2s_id;
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN0_REG, DPORT_I2S0_RST);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN0_REG, DPORT_I2S0_RST);
|
||||
}
|
||||
|
||||
/// 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 i2s_ll_reset_register(...) do { \
|
||||
(void)__DECLARE_RCC_ATOMIC_ENV; \
|
||||
i2s_ll_reset_register(__VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* @brief I2S module general init, enable I2S clock.
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param enable set true to enable the core clock
|
||||
*/
|
||||
static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable)
|
||||
{
|
||||
if (enable && !hw->clkm_conf.clk_en) {
|
||||
hw->clkm_conf.clk_sel = 2;
|
||||
hw->clkm_conf.clk_en = 1;
|
||||
hw->conf2.val = 0;
|
||||
} else if (!enable && hw->clkm_conf.clk_en) {
|
||||
hw->clkm_conf.clk_en = 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 i2s_ll_enable_core_clock(...) do { \
|
||||
(void)__DECLARE_RCC_ATOMIC_ENV; \
|
||||
i2s_ll_enable_core_clock(__VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* @brief I2S tx msb right enable
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param enable Set true to enable tx msb right
|
||||
*/
|
||||
static inline void i2s_ll_tx_enable_msb_right(i2s_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->conf.tx_msb_right = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2S rx msb right enable
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param enable Set true to enable rx msb right
|
||||
*/
|
||||
static inline void i2s_ll_rx_enable_msb_right(i2s_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->conf.rx_msb_right = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2S tx right channel first
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param enable Set true to enable send right channel first
|
||||
*/
|
||||
static inline void i2s_ll_tx_enable_right_first(i2s_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->conf.tx_right_first = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2S rx right channel first
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param enable Set true to enable receive right channel first
|
||||
*/
|
||||
static inline void i2s_ll_rx_enable_right_first(i2s_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->conf.rx_right_first = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2S tx fifo module force enable
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param enable Set true to enable tx fifo module
|
||||
*/
|
||||
static inline void i2s_ll_tx_force_enable_fifo_mod(i2s_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->fifo_conf.tx_fifo_mod_force_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2S rx fifo module force enable
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param enable Set true to enable rx fifo module
|
||||
*/
|
||||
static inline void i2s_ll_rx_force_enable_fifo_mod(i2s_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->fifo_conf.rx_fifo_mod_force_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable I2S TX slave mode
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param slave_en Set true to enable slave mode
|
||||
*/
|
||||
static inline void i2s_ll_tx_set_slave_mod(i2s_dev_t *hw, bool slave_en)
|
||||
{
|
||||
hw->conf.tx_slave_mod = slave_en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable I2S RX slave mode
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param slave_en Set true to enable slave mode
|
||||
*/
|
||||
static inline void i2s_ll_rx_set_slave_mod(i2s_dev_t *hw, bool slave_en)
|
||||
{
|
||||
hw->conf.rx_slave_mod = slave_en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset TX module
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_tx_reset(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.tx_reset = 1;
|
||||
hw->conf.tx_reset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset RX module
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_rx_reset(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.rx_reset = 1;
|
||||
hw->conf.rx_reset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset TX FIFO
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_tx_reset_fifo(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.tx_fifo_reset = 1;
|
||||
hw->conf.tx_fifo_reset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset RX FIFO
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_rx_reset_fifo(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.rx_fifo_reset = 1;
|
||||
hw->conf.rx_fifo_reset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set TX source clock
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param src I2S source clock
|
||||
*/
|
||||
static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
|
||||
{
|
||||
hw->clkm_conf.clk_sel = (src == I2S_CLK_SRC_APLL) ? 1 : 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set RX source clock
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param src I2S source clock
|
||||
*/
|
||||
static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
|
||||
{
|
||||
hw->clkm_conf.clk_sel = (src == I2S_CLK_SRC_APLL) ? 1 : 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set I2S tx bck div num
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param val value to set tx bck div num
|
||||
*/
|
||||
static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val)
|
||||
{
|
||||
hw->sample_rate_conf.tx_bck_div_num = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure I2S module clock divider
|
||||
* @note mclk on ESP32 is shared by both TX and RX channel
|
||||
* mclk = sclk / (mclk_div + b/a)
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param mclk_div integer part of the division from sclk to mclk
|
||||
* @param a Denominator of decimal part
|
||||
* @param b Numerator of decimal part
|
||||
*/
|
||||
static inline void i2s_ll_set_raw_mclk_div(i2s_dev_t *hw, uint32_t mclk_div, uint32_t a, uint32_t b)
|
||||
{
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkm_conf, clkm_div_num, mclk_div);
|
||||
hw->clkm_conf.clkm_div_b = b;
|
||||
hw->clkm_conf.clkm_div_a = a;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure I2S TX module clock divider
|
||||
* @note mclk on ESP32 is shared by both TX and RX channel
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param mclk_div The mclk division coefficients
|
||||
*/
|
||||
static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const hal_utils_clk_div_t *mclk_div)
|
||||
{
|
||||
i2s_ll_set_raw_mclk_div(hw, mclk_div->integer, mclk_div->denominator, mclk_div->numerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set I2S rx bck div num
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param val value to set rx bck div num
|
||||
*/
|
||||
static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val)
|
||||
{
|
||||
hw->sample_rate_conf.rx_bck_div_num = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure I2S RX module clock divider
|
||||
* @note mclk on ESP32S2 is shared by both TX and RX channel
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param mclk_div The mclk division coefficients
|
||||
*/
|
||||
static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const hal_utils_clk_div_t *mclk_div)
|
||||
{
|
||||
// TX and RX channel on ESP32 shares a same mclk
|
||||
i2s_ll_tx_set_mclk(hw, mclk_div);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable interrupt by mask
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param mask Interrupt event mask
|
||||
* @param en true to enable, false to disable
|
||||
*/
|
||||
static inline void i2s_ll_enable_intr(i2s_dev_t *hw, uint32_t mask, bool en)
|
||||
{
|
||||
uint32_t int_ena_mask = hw->int_ena.val;
|
||||
if (en) {
|
||||
int_ena_mask |= mask;
|
||||
} else {
|
||||
int_ena_mask &= ~mask;
|
||||
}
|
||||
hw->int_ena.val = int_ena_mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable TX interrupt
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_tx_enable_intr(i2s_dev_t *hw)
|
||||
{
|
||||
hw->int_ena.out_eof = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable TX interrupt
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_tx_disable_intr(i2s_dev_t *hw)
|
||||
{
|
||||
hw->int_ena.out_eof = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable RX interrupt
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_rx_enable_intr(i2s_dev_t *hw)
|
||||
{
|
||||
hw->int_ena.in_suc_eof = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable RX interrupt
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_rx_disable_intr(i2s_dev_t *hw)
|
||||
{
|
||||
hw->int_ena.in_suc_eof = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get interrupt status register address
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @return interrupt status register address
|
||||
*/
|
||||
static inline volatile void *i2s_ll_get_intr_status_reg(i2s_dev_t *hw)
|
||||
{
|
||||
return &hw->int_st;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get I2S interrupt status
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @return
|
||||
* - module interrupt status
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline uint32_t i2s_ll_get_intr_status(i2s_dev_t *hw)
|
||||
{
|
||||
return hw->int_st.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get DMA interrupt status register address
|
||||
*/
|
||||
static inline volatile void *i2s_ll_get_interrupt_status_reg(i2s_dev_t *hw)
|
||||
{
|
||||
return (volatile void *)(&hw->int_st);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear I2S interrupt status
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param clr_mask Interrupt mask to be cleared.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t clr_mask)
|
||||
{
|
||||
hw->int_clr.val = clr_mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset dma out
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_tx_reset_dma(i2s_dev_t *hw)
|
||||
{
|
||||
hw->lc_conf.out_rst = 1;
|
||||
hw->lc_conf.out_rst = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset dma in
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_rx_reset_dma(i2s_dev_t *hw)
|
||||
{
|
||||
hw->lc_conf.in_rst = 1;
|
||||
hw->lc_conf.in_rst = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable I2S TX STD mode
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_tx_enable_std(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf2.val = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable I2S RX STD mode
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_rx_enable_std(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf2.val = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable I2S TX PDM mode
|
||||
* @note ESP32-S2 doesn't support pdm
|
||||
* This function is used to be compatible with those support pdm
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param pcm2pdm_en Set true to enable TX PCM to PDM filter
|
||||
*/
|
||||
static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw, bool pcm2pdm_en)
|
||||
{
|
||||
// remain empty
|
||||
(void)hw;
|
||||
(void)pcm2pdm_en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable I2S RX PDM mode
|
||||
* @note ESP32-S2 doesn't support pdm
|
||||
* This function is used to be compatible with those support pdm
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param pdm2pcm_en Set true to enable RX PDM to PCM filter
|
||||
*/
|
||||
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm2pcm_en)
|
||||
{
|
||||
// remain empty
|
||||
(void)hw;
|
||||
(void)pdm2pcm_en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start out link
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_start_out_link(i2s_dev_t *hw)
|
||||
{
|
||||
hw->out_link.start = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set I2S out link address
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param val value to set out link address
|
||||
*/
|
||||
static inline void i2s_ll_set_out_link_addr(i2s_dev_t *hw, uint32_t val)
|
||||
{
|
||||
hw->out_link.addr = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start TX module
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_tx_start(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.tx_start = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start RX module
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_rx_start(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.rx_start = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure TX DMA descriptor address and start TX DMA
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param link_addr DMA descriptor link address.
|
||||
*/
|
||||
static inline void i2s_ll_tx_start_link(i2s_dev_t *hw, uint32_t link_addr)
|
||||
{
|
||||
i2s_ll_set_out_link_addr(hw, link_addr);
|
||||
i2s_ll_start_out_link(hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure RX DMA descriptor address and start TX DMA
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param link_addr DMA descriptor link address.
|
||||
*/
|
||||
static inline void i2s_ll_rx_start_link(i2s_dev_t *hw, uint32_t link_addr)
|
||||
{
|
||||
hw->in_link.addr = link_addr;
|
||||
hw->in_link.start = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop TX module
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_tx_stop(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.tx_start = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop RX module
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_rx_stop(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.rx_start = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop out link
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_tx_stop_link(i2s_dev_t *hw)
|
||||
{
|
||||
hw->out_link.stop = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop in link
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_rx_stop_link(i2s_dev_t *hw)
|
||||
{
|
||||
hw->in_link.stop = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get I2S out eof descriptor address
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param eof_addr Pointer to accept out eof des address
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void i2s_ll_tx_get_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr)
|
||||
{
|
||||
*eof_addr = hw->out_eof_des_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get I2S in eof descriptor address
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param eof_addr Pointer to accept in eof des address
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void i2s_ll_rx_get_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr)
|
||||
{
|
||||
*eof_addr = hw->in_eof_des_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure the received length to trigger in_suc_eof interrupt
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param eof_num the byte length to trigger in_suc_eof interrupt
|
||||
*/
|
||||
static inline void i2s_ll_rx_set_eof_num(i2s_dev_t *hw, uint32_t eof_num)
|
||||
{
|
||||
hw->rx_eof_num = eof_num;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure TX chan bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param chan_bit The chan bit width
|
||||
* @param data_bit The audio data bit width
|
||||
*/
|
||||
static inline void i2s_ll_tx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit)
|
||||
{
|
||||
hw->fifo_conf.tx_fifo_mod = (chan_bit <= I2S_DATA_BIT_WIDTH_16BIT ? 0 : 2);
|
||||
hw->sample_rate_conf.tx_bits_mod = data_bit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure RX chan bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param chan_bit The chan bit width
|
||||
* @param data_bit The audio data bit width
|
||||
*/
|
||||
static inline void i2s_ll_rx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit)
|
||||
{
|
||||
hw->fifo_conf.rx_fifo_mod = (chan_bit <= I2S_DATA_BIT_WIDTH_16BIT ? 0 : 2);
|
||||
hw->sample_rate_conf.rx_bits_mod = data_bit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable I2S DMA
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param ena Set true to enable DMA
|
||||
*/
|
||||
static inline void i2s_ll_enable_dma(i2s_dev_t *hw, bool ena)
|
||||
{
|
||||
hw->fifo_conf.dscr_en = ena;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set I2S TX to philips standard
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_tx_set_format_philips(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.tx_short_sync = 0;
|
||||
hw->conf.tx_msb_shift = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set I2S RX to philips standard
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_rx_set_format_philips(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.rx_short_sync = 0;
|
||||
hw->conf.rx_msb_shift = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set I2S TX to MSB Alignment Standard
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_tx_set_format_msb_align(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.tx_short_sync = 0;
|
||||
hw->conf.tx_msb_shift = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set I2S RX to MSB Alignment Standard
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_rx_set_format_msb_align(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.rx_short_sync = 0;
|
||||
hw->conf.rx_msb_shift = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set I2S TX to PCM short standard
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_tx_set_pcm_short(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.tx_short_sync = 1;
|
||||
hw->conf.tx_msb_shift = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set I2S RX to PCM short standard
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_rx_set_pcm_short(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.rx_short_sync = 1;
|
||||
hw->conf.rx_msb_shift = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set I2S TX to PCM long standard
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_tx_set_pcm_long(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.tx_short_sync = 0;
|
||||
hw->conf.tx_msb_shift = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set I2S RX to PCM long standard
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_rx_set_pcm_long(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.rx_short_sync = 0;
|
||||
hw->conf.rx_msb_shift = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure TX WS signal width
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param width WS width in BCK cycle
|
||||
*/
|
||||
static inline void i2s_ll_tx_set_ws_width(i2s_dev_t *hw, int width)
|
||||
{
|
||||
hw->conf.tx_short_sync = width == 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure RX WS signal width
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param width WS width in BCK cycle
|
||||
*/
|
||||
static inline void i2s_ll_rx_set_ws_width(i2s_dev_t *hw, int width)
|
||||
{
|
||||
hw->conf.rx_short_sync = width == 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable TX MSB shift, the data will be launch at the first BCK clock
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param msb_shift_enable Set true to enable MSB shift
|
||||
*/
|
||||
static inline void i2s_ll_tx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable)
|
||||
{
|
||||
hw->conf.tx_msb_shift = msb_shift_enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable RX MSB shift, the data will be launch at the first BCK clock
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param msb_shift_enable Set true to enable MSB shift
|
||||
*/
|
||||
static inline void i2s_ll_rx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable)
|
||||
{
|
||||
hw->conf.rx_msb_shift = msb_shift_enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set I2S tx chan mode
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param slot_mask select slot to send data
|
||||
* @param is_mono is mono mode
|
||||
*/
|
||||
static inline void i2s_ll_tx_select_std_slot(i2s_dev_t *hw, i2s_std_slot_mask_t slot_mask, bool is_mono)
|
||||
{
|
||||
if (is_mono) {
|
||||
switch (slot_mask) {
|
||||
case I2S_STD_SLOT_RIGHT:
|
||||
hw->conf_chan.tx_chan_mod = 3;
|
||||
break;
|
||||
case I2S_STD_SLOT_LEFT:
|
||||
hw->conf_chan.tx_chan_mod = 4;
|
||||
break;
|
||||
case I2S_STD_SLOT_BOTH:
|
||||
hw->conf_chan.tx_chan_mod = 1; // 1 & 2 has same effect
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (slot_mask) {
|
||||
case I2S_STD_SLOT_RIGHT:
|
||||
hw->conf_chan.tx_chan_mod = 1;
|
||||
break;
|
||||
case I2S_STD_SLOT_LEFT:
|
||||
hw->conf_chan.tx_chan_mod = 2;
|
||||
break;
|
||||
case I2S_STD_SLOT_BOTH:
|
||||
hw->conf_chan.tx_chan_mod = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set I2S rx chan mode
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param slot_mask select slot to receive data
|
||||
*/
|
||||
static inline void i2s_ll_rx_select_std_slot(i2s_dev_t *hw, i2s_std_slot_mask_t slot_mask, bool is_msb_right)
|
||||
{
|
||||
switch (slot_mask) {
|
||||
case I2S_STD_SLOT_RIGHT:
|
||||
hw->conf_chan.rx_chan_mod = is_msb_right ? 1 : 2;
|
||||
break;
|
||||
case I2S_STD_SLOT_LEFT:
|
||||
hw->conf_chan.rx_chan_mod = is_msb_right ? 2 : 1;
|
||||
break;
|
||||
case I2S_STD_SLOT_BOTH:
|
||||
hw->conf_chan.rx_chan_mod = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set I2S tx bits mod
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param val value to set tx bits mod
|
||||
*/
|
||||
static inline void i2s_ll_tx_set_bits_mod(i2s_dev_t *hw, uint32_t val)
|
||||
{
|
||||
hw->sample_rate_conf.tx_bits_mod = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set I2S tx dma equal
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param val value to set tx dma equal
|
||||
*/
|
||||
static inline void i2s_ll_tx_enable_dma_equal(i2s_dev_t *hw, bool en)
|
||||
{
|
||||
hw->conf.tx_dma_equal = en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable TX mono mode
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param mono_ena Set true to enable mono mde.
|
||||
*/
|
||||
static inline void i2s_ll_tx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena)
|
||||
{
|
||||
int data_bit = hw->sample_rate_conf.tx_bits_mod;
|
||||
hw->fifo_conf.tx_fifo_mod = data_bit <= I2S_DATA_BIT_WIDTH_16BIT ? mono_ena : 2 + mono_ena;
|
||||
hw->conf.tx_dma_equal = mono_ena;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable RX mono mode
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param mono_ena Set true to enable mono mde.
|
||||
*/
|
||||
static inline void i2s_ll_rx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena)
|
||||
{
|
||||
int data_bit = hw->sample_rate_conf.rx_bits_mod;
|
||||
hw->fifo_conf.rx_fifo_mod = data_bit <= I2S_DATA_BIT_WIDTH_16BIT ? mono_ena : 2 + mono_ena;
|
||||
hw->conf.rx_dma_equal = mono_ena;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable I2S loopback mode
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param loopback_en Set true to share BCK and WS signal for tx module and rx module.
|
||||
*/
|
||||
static inline void i2s_ll_share_bck_ws(i2s_dev_t *hw, bool loopback_en)
|
||||
{
|
||||
hw->conf.sig_loopback = loopback_en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable I2S LCD mode
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param enable Set true to enable LCD mode.
|
||||
*/
|
||||
static inline void i2s_ll_enable_lcd(i2s_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->conf2.lcd_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set whether to continue I2S signal on bus when TX FIFO is empty
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param en whether to stop when tx fifo is empty
|
||||
*/
|
||||
static inline void i2s_ll_tx_stop_on_fifo_empty(i2s_dev_t *hw, bool en)
|
||||
{
|
||||
hw->conf1.tx_stop_en = en;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "hal/i2s_periph.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
|
||||
/*
|
||||
Bunch of constants for every I2S peripheral: GPIO signals, irqs, hw addr of registers etc
|
||||
*/
|
||||
const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_ATTR(INST_NUM)] = {
|
||||
{
|
||||
.mck_out_sig = I2S0_MCLK_OUT_IDX,
|
||||
.mck_in_sig = I2S0_MCLK_IN_IDX,
|
||||
|
||||
.m_tx_bck_sig = I2S0O_BCK_OUT_IDX,
|
||||
.m_rx_bck_sig = I2S0I_BCK_OUT_IDX,
|
||||
.m_tx_ws_sig = I2S0O_WS_OUT_IDX,
|
||||
.m_rx_ws_sig = I2S0I_WS_OUT_IDX,
|
||||
|
||||
.s_tx_bck_sig = I2S0O_BCK_IN_IDX,
|
||||
.s_rx_bck_sig = I2S0I_BCK_IN_IDX,
|
||||
.s_tx_ws_sig = I2S0O_WS_IN_IDX,
|
||||
.s_rx_ws_sig = I2S0I_WS_IN_IDX,
|
||||
|
||||
.data_out_sigs[0] = I2S0O_SD_OUT_IDX,
|
||||
.data_out_sigs[1] = I2S0O_SD1_OUT_IDX,
|
||||
.data_in_sigs[0] = I2S0I_SD_IN_IDX,
|
||||
.data_in_sigs[1] = I2S0I_SD1_IN_IDX,
|
||||
.data_in_sigs[2] = I2S0I_SD2_IN_IDX,
|
||||
.data_in_sigs[3] = I2S0I_SD3_IN_IDX,
|
||||
|
||||
.irq = ETS_I2S0_INTR_SOURCE,
|
||||
},
|
||||
{
|
||||
.mck_out_sig = I2S1_MCLK_OUT_IDX,
|
||||
.mck_in_sig = I2S1_MCLK_IN_IDX,
|
||||
|
||||
.m_tx_bck_sig = I2S1O_BCK_OUT_IDX,
|
||||
.m_rx_bck_sig = I2S1I_BCK_OUT_IDX,
|
||||
.m_tx_ws_sig = I2S1O_WS_OUT_IDX,
|
||||
.m_rx_ws_sig = I2S1I_WS_OUT_IDX,
|
||||
|
||||
.s_tx_bck_sig = I2S1O_BCK_IN_IDX,
|
||||
.s_rx_bck_sig = I2S1I_BCK_IN_IDX,
|
||||
.s_tx_ws_sig = I2S1O_WS_IN_IDX,
|
||||
.s_rx_ws_sig = I2S1I_WS_IN_IDX,
|
||||
|
||||
.data_out_sigs[0] = I2S1O_SD_OUT_IDX,
|
||||
.data_out_sigs[1] = -1,
|
||||
.data_in_sigs[0] = I2S1I_SD_IN_IDX,
|
||||
.data_in_sigs[1] = -1,
|
||||
.data_in_sigs[2] = -1,
|
||||
.data_in_sigs[3] = -1,
|
||||
|
||||
.irq = ETS_I2S1_INTR_SOURCE,
|
||||
}
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,405 @@
|
||||
/*
|
||||
* 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, ¶m0, ¶m5);
|
||||
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, ¶m0, ¶m5);
|
||||
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
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "soc/soc.h"
|
||||
#include "soc/interrupts.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/soc_caps_full.h"
|
||||
#include "soc/regdma.h"
|
||||
#if SOC_HAS(PAU)
|
||||
#include "soc/retention_periph_defs.h"
|
||||
#endif
|
||||
|
||||
#if SOC_HAS(I2S)
|
||||
#include "soc/i2s_struct.h"
|
||||
#include "soc/i2s_reg.h"
|
||||
#endif
|
||||
|
||||
#define SOC_I2S_ATTR(_attr) SOC_MODULE_ATTR(I2S, _attr)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if SOC_HAS(I2S)
|
||||
/*
|
||||
Stores a bunch of per-I2S-peripheral data.
|
||||
*/
|
||||
typedef struct {
|
||||
const uint8_t mck_out_sig;
|
||||
const uint8_t mck_in_sig;
|
||||
|
||||
const uint8_t m_tx_bck_sig;
|
||||
const uint8_t m_rx_bck_sig;
|
||||
const uint8_t m_tx_ws_sig;
|
||||
const uint8_t m_rx_ws_sig;
|
||||
|
||||
const uint8_t s_tx_bck_sig;
|
||||
const uint8_t s_rx_bck_sig;
|
||||
const uint8_t s_tx_ws_sig;
|
||||
const uint8_t s_rx_ws_sig;
|
||||
|
||||
union {
|
||||
const uint8_t data_out_sig;
|
||||
#if SOC_I2S_PDM_MAX_TX_LINES
|
||||
const uint8_t data_out_sigs[SOC_I2S_PDM_MAX_TX_LINES]; // Only valid in version 2
|
||||
#endif
|
||||
};
|
||||
|
||||
union {
|
||||
const uint8_t data_in_sig;
|
||||
#if SOC_I2S_PDM_MAX_RX_LINES
|
||||
const uint8_t data_in_sigs[SOC_I2S_PDM_MAX_RX_LINES];
|
||||
#endif
|
||||
};
|
||||
|
||||
const uint8_t irq;
|
||||
} i2s_signal_conn_t;
|
||||
|
||||
extern const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_ATTR(INST_NUM)];
|
||||
|
||||
#if SOC_LP_I2S_SUPPORTED
|
||||
extern const i2s_signal_conn_t lp_i2s_periph_signal[SOC_LP_I2S_NUM];
|
||||
#endif
|
||||
|
||||
#if SOC_HAS(PAU)
|
||||
typedef struct {
|
||||
const periph_retention_module_t retention_module;
|
||||
const regdma_entries_config_t *entry_array;
|
||||
uint32_t array_size;
|
||||
} i2s_reg_retention_info_t;
|
||||
|
||||
extern const i2s_reg_retention_info_t i2s_reg_retention_info[SOC_I2S_ATTR(INST_NUM)];
|
||||
#endif // SOC_HAS(PAU)
|
||||
#endif // SOC_HAS(I2S)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
Reference in New Issue
Block a user