mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/support_i2s_on_p4' into 'master'
feat(i2s): support i2s on esp32p4 Closes IDF-6508 See merge request espressif/esp-idf!24280
This commit is contained in:
commit
4c6f4b39f1
@ -111,6 +111,7 @@ endif()
|
||||
# I2S related source files
|
||||
if(CONFIG_SOC_I2S_SUPPORTED)
|
||||
list(APPEND srcs "i2s/i2s_common.c"
|
||||
"i2s/i2s_platform.c"
|
||||
"i2s/i2s_std.c"
|
||||
"deprecated/i2s_legacy.c")
|
||||
if(CONFIG_SOC_I2S_SUPPORTS_PDM)
|
||||
@ -236,7 +237,7 @@ else()
|
||||
# Can be removed together with legacy drivers)
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS ${includes}
|
||||
PRIV_REQUIRES efuse esp_timer
|
||||
PRIV_REQUIRES efuse esp_timer esp_mm
|
||||
REQUIRES esp_pm esp_ringbuf freertos soc hal esp_hw_support
|
||||
LDFRAGMENTS ${ldfragments}
|
||||
)
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "hal/adc_ll.h"
|
||||
#include "hal/i2s_hal.h"
|
||||
#include "hal/i2s_types.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "soc/i2s_periph.h"
|
||||
#include "../dac_priv_dma.h"
|
||||
#include "esp_private/i2s_platform.h"
|
||||
@ -46,7 +47,7 @@ static const char *TAG = "DAC_DMA";
|
||||
static uint32_t s_dac_set_apll_freq(uint32_t mclk)
|
||||
{
|
||||
/* Calculate the expected APLL */
|
||||
int div = (int)((SOC_APLL_MIN_HZ / mclk) + 1);
|
||||
int div = (int)((CLK_LL_APLL_MIN_HZ / mclk) + 1);
|
||||
/* apll_freq = mclk * div
|
||||
* when div = 1, hardware will still divide 2
|
||||
* when div = 0, hardware will divide 255
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "hal/dac_ll.h"
|
||||
#include "hal/adc_ll.h"
|
||||
#include "hal/hal_utils.h"
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "soc/lldesc.h"
|
||||
#include "soc/soc.h"
|
||||
#include "soc/soc_caps.h"
|
||||
@ -75,9 +76,9 @@ static esp_err_t s_dac_dma_periph_set_clock(uint32_t freq_hz, bool is_apll){
|
||||
uint32_t digi_ctrl_freq; // Digital controller clock
|
||||
if (is_apll) {
|
||||
/* Theoretical frequency range (due to the limitation of DAC, the maximum frequency may not reach):
|
||||
* SOC_APLL_MAX_HZ: 119.24 Hz ~ 67.5 MHz
|
||||
* SOC_APLL_MIN_HZ: 5.06 Hz ~ 2.65 MHz */
|
||||
digi_ctrl_freq = s_dac_set_apll_freq(freq_hz < 120 ? SOC_APLL_MIN_HZ :SOC_APLL_MAX_HZ);
|
||||
* CLK_LL_APLL_MAX_HZ: 119.24 Hz ~ 67.5 MHz
|
||||
* CLK_LL_APLL_MIN_HZ: 5.06 Hz ~ 2.65 MHz */
|
||||
digi_ctrl_freq = s_dac_set_apll_freq(freq_hz < 120 ? CLK_LL_APLL_MIN_HZ :CLK_LL_APLL_MAX_HZ);
|
||||
ESP_RETURN_ON_FALSE(digi_ctrl_freq, ESP_ERR_INVALID_ARG, TAG, "set APLL coefficients failed");
|
||||
} else {
|
||||
digi_ctrl_freq = APB_CLK_FREQ;
|
||||
|
@ -25,6 +25,10 @@
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "driver/i2s_types_legacy.h"
|
||||
#include "hal/i2s_hal.h"
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#endif
|
||||
|
||||
#if SOC_I2S_SUPPORTS_DAC
|
||||
#include "hal/dac_ll.h"
|
||||
#include "hal/dac_types.h"
|
||||
@ -48,6 +52,7 @@
|
||||
#include "esp_pm.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "esp_private/i2s_platform.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_private/esp_clk.h"
|
||||
|
||||
@ -58,6 +63,18 @@ static const char *TAG = "i2s(legacy)";
|
||||
#define I2S_ENTER_CRITICAL(i2s_num) portENTER_CRITICAL(&i2s_spinlock[i2s_num])
|
||||
#define I2S_EXIT_CRITICAL(i2s_num) portEXIT_CRITICAL(&i2s_spinlock[i2s_num])
|
||||
|
||||
#if SOC_PERIPH_CLK_CTRL_SHARED
|
||||
#define I2S_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC()
|
||||
#else
|
||||
#define I2S_CLOCK_SRC_ATOMIC()
|
||||
#endif
|
||||
|
||||
#if !SOC_RCC_IS_INDEPENDENT
|
||||
#define I2S_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
|
||||
#else
|
||||
#define I2S_RCC_ATOMIC()
|
||||
#endif
|
||||
|
||||
#define I2S_DMA_BUFFER_MAX_SIZE 4092
|
||||
|
||||
#if SOC_I2S_SUPPORTS_ADC_DAC
|
||||
@ -134,9 +151,6 @@ typedef struct {
|
||||
uint32_t total_slot; /*!< Total slot number */
|
||||
} i2s_obj_t;
|
||||
|
||||
// Record the component name that using I2S peripheral
|
||||
static const char *comp_using_i2s[SOC_I2S_NUM] = {[0 ... SOC_I2S_NUM - 1] = NULL};
|
||||
|
||||
// Global I2S object pointer
|
||||
static i2s_obj_t *p_i2s[SOC_I2S_NUM] = {
|
||||
[0 ... SOC_I2S_NUM - 1] = NULL,
|
||||
@ -147,11 +161,6 @@ static portMUX_TYPE i2s_spinlock[SOC_I2S_NUM] = {
|
||||
[0 ... SOC_I2S_NUM - 1] = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED,
|
||||
};
|
||||
|
||||
|
||||
__attribute__((weak)) esp_err_t i2s_platform_acquire_occupation(int id, const char *comp_name);
|
||||
|
||||
__attribute__((weak)) esp_err_t i2s_platform_release_occupation(int id);
|
||||
|
||||
/*-------------------------------------------------------------
|
||||
I2S DMA operation
|
||||
-------------------------------------------------------------*/
|
||||
@ -633,7 +642,7 @@ static uint32_t i2s_config_source_clock(i2s_port_t i2s_num, bool use_apll, uint3
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
if (use_apll) {
|
||||
/* Calculate the expected APLL */
|
||||
int div = (int)((SOC_APLL_MIN_HZ / mclk) + 1);
|
||||
int div = (int)((CLK_LL_APLL_MIN_HZ / mclk) + 1);
|
||||
/* apll_freq = mclk * div
|
||||
* when div = 1, hardware will still divide 2
|
||||
* when div = 0, the final mclk will be unpredictable
|
||||
@ -654,12 +663,12 @@ static uint32_t i2s_config_source_clock(i2s_port_t i2s_num, bool use_apll, uint3
|
||||
/* In APLL mode, there is no sclk but only mclk, so return 0 here to indicate APLL mode */
|
||||
return real_freq;
|
||||
}
|
||||
return I2S_LL_DEFAULT_PLL_CLK_FREQ;
|
||||
return I2S_LL_DEFAULT_CLK_FREQ;
|
||||
#else
|
||||
if (use_apll) {
|
||||
ESP_LOGW(TAG, "APLL not supported on current chip, use I2S_CLK_SRC_DEFAULT as default clock source");
|
||||
}
|
||||
return I2S_LL_DEFAULT_PLL_CLK_FREQ;
|
||||
return I2S_LL_DEFAULT_CLK_FREQ;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1021,6 +1030,7 @@ static void i2s_set_clock_legacy(i2s_port_t i2s_num)
|
||||
i2s_clk_config_t *clk_cfg = &p_i2s[i2s_num]->clk_cfg;
|
||||
i2s_hal_clock_info_t clk_info;
|
||||
i2s_calculate_clock(i2s_num, &clk_info);
|
||||
I2S_CLOCK_SRC_ATOMIC() {
|
||||
if (p_i2s[i2s_num]->dir & I2S_DIR_TX) {
|
||||
i2s_hal_set_tx_clock(&(p_i2s[i2s_num]->hal), &clk_info, clk_cfg->clk_src);
|
||||
}
|
||||
@ -1028,6 +1038,7 @@ static void i2s_set_clock_legacy(i2s_port_t i2s_num)
|
||||
i2s_hal_set_rx_clock(&(p_i2s[i2s_num]->hal), &clk_info, clk_cfg->clk_src);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float i2s_get_clk(i2s_port_t i2s_num)
|
||||
{
|
||||
@ -1479,17 +1490,6 @@ static esp_err_t i2s_init_legacy(i2s_port_t i2s_num, int intr_alloc_flag)
|
||||
ESP_RETURN_ON_ERROR(i2s_realloc_dma_buffer(i2s_num, p_i2s[i2s_num]->rx), TAG, "Allocate I2S dma rx buffer failed");
|
||||
}
|
||||
|
||||
/* Initialize I2S DMA object */
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
/* Enable tx/rx submodule clock */
|
||||
if (p_i2s[i2s_num]->dir & I2S_DIR_TX) {
|
||||
i2s_ll_tx_enable_clock(p_i2s[i2s_num]->hal.dev);
|
||||
}
|
||||
if (p_i2s[i2s_num]->dir & I2S_DIR_RX) {
|
||||
i2s_ll_rx_enable_clock(p_i2s[i2s_num]->hal.dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -1538,12 +1538,14 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num)
|
||||
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
if (obj->use_apll) {
|
||||
I2S_CLOCK_SRC_ATOMIC() {
|
||||
// switch back to PLL clock source
|
||||
if (obj->dir & I2S_DIR_TX) {
|
||||
i2s_ll_tx_clk_set_src(obj->hal.dev, I2S_CLK_SRC_DEFAULT);
|
||||
i2s_hal_set_tx_clock(&obj->hal, NULL, I2S_CLK_SRC_DEFAULT);
|
||||
}
|
||||
if (obj->dir & I2S_DIR_RX) {
|
||||
i2s_ll_rx_clk_set_src(obj->hal.dev, I2S_CLK_SRC_DEFAULT);
|
||||
i2s_hal_set_rx_clock(&obj->hal, NULL, I2S_CLK_SRC_DEFAULT);
|
||||
}
|
||||
}
|
||||
periph_rtc_apll_release();
|
||||
}
|
||||
@ -1556,12 +1558,14 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num)
|
||||
}
|
||||
#endif
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
I2S_CLOCK_SRC_ATOMIC() {
|
||||
if (obj->dir & I2S_DIR_TX) {
|
||||
i2s_ll_tx_disable_clock(obj->hal.dev);
|
||||
}
|
||||
if (obj->dir & I2S_DIR_RX) {
|
||||
i2s_ll_rx_disable_clock(obj->hal.dev);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Disable module clock */
|
||||
i2s_platform_release_occupation(i2s_num);
|
||||
@ -1896,37 +1900,6 @@ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2s_platform_acquire_occupation(int id, const char *comp_name)
|
||||
{
|
||||
esp_err_t ret = ESP_ERR_NOT_FOUND;
|
||||
ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id");
|
||||
portENTER_CRITICAL(&i2s_spinlock[id]);
|
||||
if (!comp_using_i2s[id]) {
|
||||
ret = ESP_OK;
|
||||
comp_using_i2s[id] = comp_name;
|
||||
periph_module_enable(i2s_periph_signal[id].module);
|
||||
i2s_ll_enable_clock(I2S_LL_GET_HW(id));
|
||||
}
|
||||
portEXIT_CRITICAL(&i2s_spinlock[id]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t i2s_platform_release_occupation(int id)
|
||||
{
|
||||
esp_err_t ret = ESP_ERR_INVALID_STATE;
|
||||
ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id");
|
||||
portENTER_CRITICAL(&i2s_spinlock[id]);
|
||||
if (comp_using_i2s[id]) {
|
||||
ret = ESP_OK;
|
||||
comp_using_i2s[id] = NULL;
|
||||
/* Disable module clock */
|
||||
periph_module_disable(i2s_periph_signal[id].module);
|
||||
i2s_ll_disable_clock(I2S_LL_GET_HW(id));
|
||||
}
|
||||
portEXIT_CRITICAL(&i2s_spinlock[id]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function will be called during start up, to check that the new i2s driver is not running along with the legacy i2s driver
|
||||
*/
|
||||
|
@ -25,17 +25,21 @@
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "hal/i2s_hal.h"
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
#include "hal/cache_hal.h"
|
||||
#include "hal/cache_ll.h"
|
||||
#endif
|
||||
|
||||
#if SOC_I2S_SUPPORTS_ADC_DAC
|
||||
#include "hal/adc_ll.h"
|
||||
#include "driver/adc_i2s_legacy.h"
|
||||
#endif
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
#include "hal/clk_tree_ll.h"
|
||||
#include "clk_ctrl_os.h"
|
||||
#endif
|
||||
|
||||
#include "esp_private/i2s_platform.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_private/esp_clk.h"
|
||||
|
||||
#include "driver/gpio.h"
|
||||
@ -47,6 +51,10 @@
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_dma_utils.h"
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
#include "esp_cache.h"
|
||||
#endif
|
||||
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "esp_memory_utils.h"
|
||||
@ -55,18 +63,15 @@
|
||||
* Set 4092 here to align with 4-byte, so that the position of the slot data in the buffer will be relatively fixed */
|
||||
#define I2S_DMA_BUFFER_MAX_SIZE (4092)
|
||||
|
||||
/**
|
||||
* @brief Global i2s platform object
|
||||
* @note For saving all the I2S related information
|
||||
*/
|
||||
i2s_platform_t g_i2s = {
|
||||
.spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED,
|
||||
.controller[0 ... (SOC_I2S_NUM - 1)] = NULL, // groups will be lazy installed
|
||||
.comp_name[0 ... (SOC_I2S_NUM - 1)] = NULL,
|
||||
};
|
||||
|
||||
static const char *TAG = "i2s_common";
|
||||
|
||||
__attribute__((always_inline))
|
||||
inline void *i2s_dma_calloc(size_t num, size_t size, uint32_t caps, size_t *actual_size) {
|
||||
void *ptr = NULL;
|
||||
esp_dma_calloc(num, size, caps, &ptr, actual_size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
I2S Static APIs
|
||||
----------------------------------------------------------------------------
|
||||
@ -261,6 +266,7 @@ static esp_err_t i2s_register_channel(i2s_controller_t *i2s_obj, i2s_dir_t dir,
|
||||
new_chan->callbacks.on_send_q_ovf = NULL;
|
||||
new_chan->dma.rw_pos = 0;
|
||||
new_chan->dma.curr_ptr = NULL;
|
||||
new_chan->dma.curr_desc = NULL;
|
||||
new_chan->start = NULL;
|
||||
new_chan->stop = NULL;
|
||||
|
||||
@ -292,6 +298,11 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef __cplusplus
|
||||
/* To make sure the i2s_event_callbacks_t is same size as i2s_event_callbacks_internal_t */
|
||||
_Static_assert(sizeof(i2s_event_callbacks_t) == sizeof(i2s_event_callbacks_internal_t), "Invalid size of i2s_event_callbacks_t structure");
|
||||
#endif
|
||||
|
||||
esp_err_t i2s_channel_register_event_callback(i2s_chan_handle_t handle, const i2s_event_callbacks_t *callbacks, void *user_data)
|
||||
{
|
||||
I2S_NULL_POINTER_CHECK(TAG, handle);
|
||||
@ -330,6 +341,26 @@ uint32_t i2s_get_buf_size(i2s_chan_handle_t handle, uint32_t data_bit_width, uin
|
||||
uint32_t bytes_per_sample = ((data_bit_width + 15) / 16) * 2;
|
||||
uint32_t bytes_per_frame = bytes_per_sample * active_chan;
|
||||
uint32_t bufsize = dma_frame_num * bytes_per_frame;
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
/* bufsize need to align with cache line size */
|
||||
uint32_t alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
|
||||
uint32_t aligned_frame_num = dma_frame_num;
|
||||
/* To make the buffer aligned with the cache line size, search for the ceil aligned size first,
|
||||
If the buffer size exceed the max DMA buffer size, toggle the sign to search for the floor aligned size */
|
||||
for (int sign = 1; bufsize % alignment != 0; aligned_frame_num += sign) {
|
||||
bufsize = aligned_frame_num * bytes_per_frame;
|
||||
/* If the buffer size exceed the max dma size */
|
||||
if (bufsize > I2S_DMA_BUFFER_MAX_SIZE) {
|
||||
sign = -1; // toggle the search sign
|
||||
aligned_frame_num = dma_frame_num; // Reset the frame num
|
||||
bufsize = aligned_frame_num * bytes_per_frame; // Reset the bufsize
|
||||
}
|
||||
}
|
||||
if (bufsize / bytes_per_frame != dma_frame_num) {
|
||||
ESP_LOGW(TAG, "dma frame num is adjusted to %"PRIu32" to algin the dma buffer with %"PRIu32
|
||||
", bufsize = %"PRIu32, bufsize / bytes_per_frame, alignment, bufsize);
|
||||
}
|
||||
#endif
|
||||
/* Limit DMA buffer size if it is out of range (DMA buffer limitation is 4092 bytes) */
|
||||
if (bufsize > I2S_DMA_BUFFER_MAX_SIZE) {
|
||||
uint32_t frame_num = I2S_DMA_BUFFER_MAX_SIZE / bytes_per_frame;
|
||||
@ -348,18 +379,21 @@ esp_err_t i2s_free_dma_desc(i2s_chan_handle_t handle)
|
||||
for (int i = 0; i < handle->dma.desc_num; i++) {
|
||||
if (handle->dma.bufs[i]) {
|
||||
free(handle->dma.bufs[i]);
|
||||
handle->dma.bufs[i] = NULL;
|
||||
}
|
||||
if (handle->dma.desc[i]) {
|
||||
free(handle->dma.desc[i]);
|
||||
handle->dma.desc[i] = NULL;
|
||||
}
|
||||
}
|
||||
if (handle->dma.bufs) {
|
||||
free(handle->dma.bufs);
|
||||
handle->dma.bufs = NULL;
|
||||
}
|
||||
if (handle->dma.desc) {
|
||||
free(handle->dma.desc);
|
||||
}
|
||||
handle->dma.desc = NULL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -376,9 +410,10 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu
|
||||
handle->dma.desc = (lldesc_t **)heap_caps_calloc(num, sizeof(lldesc_t *), I2S_MEM_ALLOC_CAPS);
|
||||
ESP_GOTO_ON_FALSE(handle->dma.desc, ESP_ERR_NO_MEM, err, TAG, "create I2S DMA decriptor array failed");
|
||||
handle->dma.bufs = (uint8_t **)heap_caps_calloc(num, sizeof(uint8_t *), I2S_MEM_ALLOC_CAPS);
|
||||
size_t desc_size = 0;
|
||||
for (int i = 0; i < num; i++) {
|
||||
/* Allocate DMA descriptor */
|
||||
handle->dma.desc[i] = (lldesc_t *) heap_caps_calloc(1, sizeof(lldesc_t), I2S_DMA_ALLOC_CAPS);
|
||||
handle->dma.desc[i] = (lldesc_t *) i2s_dma_calloc(1, sizeof(lldesc_t), I2S_DMA_ALLOC_CAPS, &desc_size);
|
||||
ESP_GOTO_ON_FALSE(handle->dma.desc[i], ESP_ERR_NO_MEM, err, TAG, "allocate DMA description failed");
|
||||
handle->dma.desc[i]->owner = 1;
|
||||
handle->dma.desc[i]->eof = 1;
|
||||
@ -386,15 +421,18 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu
|
||||
handle->dma.desc[i]->length = bufsize;
|
||||
handle->dma.desc[i]->size = bufsize;
|
||||
handle->dma.desc[i]->offset = 0;
|
||||
handle->dma.bufs[i] = (uint8_t *) heap_caps_calloc(1, bufsize * sizeof(uint8_t), I2S_DMA_ALLOC_CAPS);
|
||||
handle->dma.bufs[i] = (uint8_t *) i2s_dma_calloc(1, bufsize * sizeof(uint8_t), I2S_DMA_ALLOC_CAPS, NULL);
|
||||
ESP_GOTO_ON_FALSE(handle->dma.bufs[i], ESP_ERR_NO_MEM, err, TAG, "allocate DMA buffer failed");
|
||||
handle->dma.desc[i]->buf = handle->dma.bufs[i];
|
||||
ESP_GOTO_ON_FALSE(handle->dma.desc[i]->buf, ESP_ERR_NO_MEM, err, TAG, "allocate DMA buffer failed");
|
||||
ESP_LOGV(TAG, "desc addr: %8p\tbuffer addr:%8p", handle->dma.desc[i], handle->dma.bufs[i]);
|
||||
}
|
||||
/* Connect DMA descriptor as a circle */
|
||||
for (int i = 0; i < num; i++) {
|
||||
/* Link to the next descriptor */
|
||||
STAILQ_NEXT(handle->dma.desc[i], qe) = (i < (num - 1)) ? (handle->dma.desc[i + 1]) : handle->dma.desc[0];
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
esp_cache_msync(handle->dma.desc[i], desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
|
||||
#endif
|
||||
}
|
||||
if (handle->dir == I2S_DIR_RX) {
|
||||
i2s_ll_rx_set_eof_num(handle->controller->hal.dev, bufsize);
|
||||
@ -410,14 +448,14 @@ err:
|
||||
static uint32_t i2s_set_get_apll_freq(uint32_t mclk_freq_hz)
|
||||
{
|
||||
/* Calculate the expected APLL */
|
||||
int mclk_div = (int)((SOC_APLL_MIN_HZ / mclk_freq_hz) + 1);
|
||||
int mclk_div = (int)((CLK_LL_APLL_MIN_HZ / mclk_freq_hz) + 1);
|
||||
/* apll_freq = mclk * div
|
||||
* when div = 1, hardware will still divide 2
|
||||
* when div = 0, the final mclk will be unpredictable
|
||||
* So the div here should be at least 2 */
|
||||
mclk_div = mclk_div < 2 ? 2 : mclk_div;
|
||||
uint32_t expt_freq = mclk_freq_hz * mclk_div;
|
||||
if (expt_freq > SOC_APLL_MAX_HZ) {
|
||||
if (expt_freq > CLK_LL_APLL_MAX_HZ) {
|
||||
ESP_LOGE(TAG, "The required APLL frequency exceed its maximum value");
|
||||
return 0;
|
||||
}
|
||||
@ -459,6 +497,9 @@ static bool IRAM_ATTR i2s_dma_rx_callback(gdma_channel_handle_t dma_chan, gdma_e
|
||||
uint32_t dummy;
|
||||
|
||||
finish_desc = (lldesc_t *)event_data->rx_eof_desc_addr;
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
esp_cache_msync((void *)finish_desc->buf, handle->dma.buf_size, ESP_CACHE_MSYNC_FLAG_INVALIDATE);
|
||||
#endif
|
||||
i2s_event_data_t evt = {
|
||||
.data = &(finish_desc->buf),
|
||||
.size = handle->dma.buf_size,
|
||||
@ -487,7 +528,7 @@ static bool IRAM_ATTR i2s_dma_tx_callback(gdma_channel_handle_t dma_chan, gdma_e
|
||||
lldesc_t *finish_desc;
|
||||
uint32_t dummy;
|
||||
|
||||
finish_desc = (lldesc_t *)(event_data->tx_eof_desc_addr);
|
||||
finish_desc = (lldesc_t *)event_data->tx_eof_desc_addr;
|
||||
i2s_event_data_t evt = {
|
||||
.data = &(finish_desc->buf),
|
||||
.size = handle->dma.buf_size,
|
||||
@ -505,6 +546,9 @@ static bool IRAM_ATTR i2s_dma_tx_callback(gdma_channel_handle_t dma_chan, gdma_e
|
||||
if (handle->dma.auto_clear) {
|
||||
uint8_t *sent_buf = (uint8_t *)finish_desc->buf;
|
||||
memset(sent_buf, 0, handle->dma.buf_size);
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
esp_cache_msync(sent_buf, handle->dma.buf_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
|
||||
#endif
|
||||
}
|
||||
xQueueSendFromISR(handle->msg_queue, &(finish_desc->buf), &need_yield2);
|
||||
|
||||
@ -646,7 +690,7 @@ esp_err_t i2s_init_dma_intr(i2s_chan_handle_t handle, int intr_flag)
|
||||
gdma_register_rx_event_callbacks(handle->dma.dma_chan, &cb, handle);
|
||||
}
|
||||
#else
|
||||
intr_flag |= ESP_INTR_FLAG_SHARED;
|
||||
intr_flag |= handle->intr_prio_flags;
|
||||
/* Initialize I2S module interrupt */
|
||||
if (handle->dir == I2S_DIR_TX) {
|
||||
esp_intr_alloc_intrstatus(i2s_periph_signal[port_id].irq, intr_flag,
|
||||
@ -663,10 +707,10 @@ esp_err_t i2s_init_dma_intr(i2s_chan_handle_t handle, int intr_flag)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void i2s_gpio_check_and_set(gpio_num_t gpio, uint32_t signal_idx, bool is_input, bool is_invert)
|
||||
void i2s_gpio_check_and_set(int gpio, uint32_t signal_idx, bool is_input, bool is_invert)
|
||||
{
|
||||
/* Ignore the pin if pin = I2S_GPIO_UNUSED */
|
||||
if (gpio != I2S_GPIO_UNUSED) {
|
||||
if (gpio != (int)I2S_GPIO_UNUSED) {
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO);
|
||||
if (is_input) {
|
||||
/* Set direction, for some GPIOs, the input function are not enabled as default */
|
||||
@ -679,9 +723,9 @@ void i2s_gpio_check_and_set(gpio_num_t gpio, uint32_t signal_idx, bool is_input,
|
||||
}
|
||||
}
|
||||
|
||||
void i2s_gpio_loopback_set(gpio_num_t gpio, uint32_t out_sig_idx, uint32_t in_sig_idx)
|
||||
void i2s_gpio_loopback_set(int gpio, uint32_t out_sig_idx, uint32_t in_sig_idx)
|
||||
{
|
||||
if (gpio != I2S_GPIO_UNUSED) {
|
||||
if (gpio != (int)I2S_GPIO_UNUSED) {
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO);
|
||||
gpio_set_direction(gpio, GPIO_MODE_INPUT_OUTPUT);
|
||||
esp_rom_gpio_connect_out_signal(gpio, out_sig_idx, 0, 0);
|
||||
@ -689,9 +733,9 @@ void i2s_gpio_loopback_set(gpio_num_t gpio, uint32_t out_sig_idx, uint32_t in_si
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t i2s_check_set_mclk(i2s_port_t id, gpio_num_t gpio_num, i2s_clock_src_t clk_src, bool is_invert)
|
||||
esp_err_t i2s_check_set_mclk(i2s_port_t id, int gpio_num, i2s_clock_src_t clk_src, bool is_invert)
|
||||
{
|
||||
if (gpio_num == I2S_GPIO_UNUSED) {
|
||||
if (gpio_num == (int)I2S_GPIO_UNUSED) {
|
||||
return ESP_OK;
|
||||
}
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
@ -740,6 +784,7 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t *
|
||||
I2S_NULL_POINTER_CHECK(TAG, tx_handle || rx_handle);
|
||||
ESP_RETURN_ON_FALSE(chan_cfg->id < SOC_I2S_NUM || chan_cfg->id == I2S_NUM_AUTO, ESP_ERR_INVALID_ARG, TAG, "invalid I2S port id");
|
||||
ESP_RETURN_ON_FALSE(chan_cfg->dma_desc_num >= 2, ESP_ERR_INVALID_ARG, TAG, "there should be at least 2 DMA buffers");
|
||||
ESP_RETURN_ON_FALSE(chan_cfg->intr_priority >= 0 && chan_cfg->intr_priority <= 7, ESP_ERR_INVALID_ARG, TAG, "intr_priority should be within 0~7");
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
i2s_controller_t *i2s_obj = NULL;
|
||||
@ -771,6 +816,7 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t *
|
||||
ESP_GOTO_ON_ERROR(i2s_register_channel(i2s_obj, I2S_DIR_TX, chan_cfg->dma_desc_num),
|
||||
err, TAG, "register I2S tx channel failed");
|
||||
i2s_obj->tx_chan->role = chan_cfg->role;
|
||||
i2s_obj->tx_chan->intr_prio_flags = chan_cfg->intr_priority ? BIT(chan_cfg->intr_priority) : ESP_INTR_FLAG_LOWMED;
|
||||
i2s_obj->tx_chan->dma.auto_clear = chan_cfg->auto_clear;
|
||||
i2s_obj->tx_chan->dma.desc_num = chan_cfg->dma_desc_num;
|
||||
i2s_obj->tx_chan->dma.frame_num = chan_cfg->dma_frame_num;
|
||||
@ -784,6 +830,7 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t *
|
||||
ESP_GOTO_ON_ERROR(i2s_register_channel(i2s_obj, I2S_DIR_RX, chan_cfg->dma_desc_num),
|
||||
err, TAG, "register I2S rx channel failed");
|
||||
i2s_obj->rx_chan->role = chan_cfg->role;
|
||||
i2s_obj->rx_chan->intr_prio_flags = chan_cfg->intr_priority ? BIT(chan_cfg->intr_priority) : ESP_INTR_FLAG_LOWMED;
|
||||
i2s_obj->rx_chan->dma.desc_num = chan_cfg->dma_desc_num;
|
||||
i2s_obj->rx_chan->dma.frame_num = chan_cfg->dma_frame_num;
|
||||
i2s_obj->rx_chan->start = i2s_rx_channel_start;
|
||||
@ -821,11 +868,13 @@ esp_err_t i2s_del_channel(i2s_chan_handle_t handle)
|
||||
bool is_bound = true;
|
||||
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
I2S_CLOCK_SRC_ATOMIC() {
|
||||
if (dir == I2S_DIR_TX) {
|
||||
i2s_ll_tx_disable_clock(handle->controller->hal.dev);
|
||||
} else {
|
||||
i2s_ll_rx_disable_clock(handle->controller->hal.dev);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
if (handle->apll_en) {
|
||||
@ -978,6 +1027,7 @@ esp_err_t i2s_channel_disable(i2s_chan_handle_t handle)
|
||||
xSemaphoreTake(handle->binary, portMAX_DELAY);
|
||||
/* Reset the descriptor pointer */
|
||||
handle->dma.curr_ptr = NULL;
|
||||
handle->dma.curr_desc = NULL;
|
||||
handle->dma.rw_pos = 0;
|
||||
handle->stop(handle);
|
||||
#if CONFIG_PM_ENABLE
|
||||
@ -1005,11 +1055,11 @@ esp_err_t i2s_channel_preload_data(i2s_chan_handle_t tx_handle, const void *src,
|
||||
xSemaphoreTake(tx_handle->mutex, portMAX_DELAY);
|
||||
|
||||
/* The pre-load data will be loaded from the first descriptor */
|
||||
if (tx_handle->dma.curr_ptr == NULL) {
|
||||
tx_handle->dma.curr_ptr = tx_handle->dma.desc[0];
|
||||
if (tx_handle->dma.curr_desc == NULL) {
|
||||
tx_handle->dma.curr_desc = tx_handle->dma.desc[0];
|
||||
tx_handle->dma.curr_ptr = (void *)tx_handle->dma.desc[0]->buf;
|
||||
tx_handle->dma.rw_pos = 0;
|
||||
}
|
||||
lldesc_t *desc_ptr = (lldesc_t *)tx_handle->dma.curr_ptr;
|
||||
|
||||
/* Loop until no bytes in source buff remain or the descriptors are full */
|
||||
while (remain_bytes) {
|
||||
@ -1020,7 +1070,10 @@ esp_err_t i2s_channel_preload_data(i2s_chan_handle_t tx_handle, const void *src,
|
||||
break;
|
||||
}
|
||||
/* Load the data from the last loaded position */
|
||||
memcpy((uint8_t *)(desc_ptr->buf + tx_handle->dma.rw_pos), data_ptr, bytes_can_load);
|
||||
memcpy((uint8_t *)(tx_handle->dma.curr_ptr + tx_handle->dma.rw_pos), data_ptr, bytes_can_load);
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
esp_cache_msync(tx_handle->dma.curr_ptr + tx_handle->dma.rw_pos, bytes_can_load, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
|
||||
#endif
|
||||
data_ptr += bytes_can_load; // Move forward the data pointer
|
||||
total_loaded_bytes += bytes_can_load; // Add to the total loaded bytes
|
||||
remain_bytes -= bytes_can_load; // Update the remaining bytes to be loaded
|
||||
@ -1030,9 +1083,9 @@ esp_err_t i2s_channel_preload_data(i2s_chan_handle_t tx_handle, const void *src,
|
||||
/* If the next descriptor is not the first descriptor, keep load to the first descriptor
|
||||
* otherwise all descriptor has been loaded, break directly, the dma buffer position
|
||||
* will remain at the end of the last dma buffer */
|
||||
if (STAILQ_NEXT(desc_ptr, qe) != tx_handle->dma.desc[0]) {
|
||||
desc_ptr = STAILQ_NEXT(desc_ptr, qe);
|
||||
tx_handle->dma.curr_ptr = (void *)desc_ptr;
|
||||
if (STAILQ_NEXT((lldesc_t *)tx_handle->dma.curr_desc, qe) != tx_handle->dma.desc[0]) {
|
||||
tx_handle->dma.curr_desc = STAILQ_NEXT((lldesc_t *)tx_handle->dma.curr_desc, qe);
|
||||
tx_handle->dma.curr_ptr = (void *)(((lldesc_t *)tx_handle->dma.curr_desc)->buf);
|
||||
tx_handle->dma.rw_pos = 0;
|
||||
} else {
|
||||
break;
|
||||
@ -1077,6 +1130,9 @@ esp_err_t i2s_channel_write(i2s_chan_handle_t handle, const void *src, size_t si
|
||||
bytes_can_write = size;
|
||||
}
|
||||
memcpy(data_ptr, src_byte, bytes_can_write);
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
esp_cache_msync(data_ptr, bytes_can_write, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
|
||||
#endif
|
||||
size -= bytes_can_write;
|
||||
src_byte += bytes_can_write;
|
||||
handle->dma.rw_pos += bytes_can_write;
|
||||
@ -1131,55 +1187,24 @@ esp_err_t i2s_channel_read(i2s_chan_handle_t handle, void *dest, size_t size, si
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
I2S Platform APIs
|
||||
----------------------------------------------------------------------------
|
||||
Scope: This file and ADC/DAC/LCD driver
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
esp_err_t i2s_platform_acquire_occupation(int id, const char *comp_name)
|
||||
#if SOC_I2S_SUPPORTS_TX_SYNC_CNT
|
||||
uint32_t i2s_sync_get_bclk_count(i2s_chan_handle_t tx_handle)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
const char *occupied_comp = NULL;
|
||||
ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id");
|
||||
portENTER_CRITICAL(&g_i2s.spinlock);
|
||||
if ((!g_i2s.controller[id]) && (g_i2s.comp_name[id] == NULL)) {
|
||||
g_i2s.comp_name[id] = comp_name;
|
||||
/* Enable module clock */
|
||||
periph_module_enable(i2s_periph_signal[id].module);
|
||||
i2s_ll_enable_clock(I2S_LL_GET_HW(id));
|
||||
} else {
|
||||
occupied_comp = g_i2s.comp_name[id];
|
||||
ret = ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
portEXIT_CRITICAL(&g_i2s.spinlock);
|
||||
if (occupied_comp != NULL) {
|
||||
ESP_LOGW(TAG, "i2s controller %d has been occupied by %s", id, occupied_comp);
|
||||
}
|
||||
return ret;
|
||||
return i2s_ll_tx_get_bclk_sync_count(tx_handle->controller->hal.dev);
|
||||
}
|
||||
|
||||
esp_err_t i2s_platform_release_occupation(int id)
|
||||
uint32_t i2s_sync_get_fifo_count(i2s_chan_handle_t tx_handle)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id");
|
||||
portENTER_CRITICAL(&g_i2s.spinlock);
|
||||
if (!g_i2s.controller[id]) {
|
||||
g_i2s.comp_name[id] = NULL;
|
||||
/* Disable module clock */
|
||||
periph_module_disable(i2s_periph_signal[id].module);
|
||||
i2s_ll_disable_clock(I2S_LL_GET_HW(id));
|
||||
} else {
|
||||
ret = ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
portEXIT_CRITICAL(&g_i2s.spinlock);
|
||||
return ret;
|
||||
return i2s_ll_tx_get_fifo_sync_count(tx_handle->controller->hal.dev);
|
||||
}
|
||||
|
||||
// Only used in `test_i2s_iram.c` to write DMA buffer directly
|
||||
size_t inline i2s_platform_get_dma_buffer_offset(void)
|
||||
void i2s_sync_reset_bclk_count(i2s_chan_handle_t tx_handle)
|
||||
{
|
||||
/* Force to transfer address '0' into 'i2s_chan_handle_t' type,
|
||||
* then find the corresponding field , the address of this field is the offset of this type */
|
||||
return (size_t)&(((i2s_chan_handle_t)0)->dma.bufs);
|
||||
i2s_ll_tx_reset_bclk_sync_counter(tx_handle->controller->hal.dev);
|
||||
}
|
||||
|
||||
void i2s_sync_reset_fifo_count(i2s_chan_handle_t tx_handle)
|
||||
{
|
||||
i2s_ll_tx_reset_fifo_sync_counter(tx_handle->controller->hal.dev);
|
||||
}
|
||||
#endif // SOC_I2S_SUPPORTS_TX_SYNC_CNT
|
||||
|
@ -70,7 +70,9 @@ static esp_err_t i2s_pdm_tx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_tx
|
||||
|
||||
portENTER_CRITICAL(&g_i2s.spinlock);
|
||||
/* Set clock configurations in HAL*/
|
||||
I2S_CLOCK_SRC_ATOMIC() {
|
||||
i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src);
|
||||
}
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
/* Work around for PDM TX clock, overwrite the raw division directly to reduce the noise
|
||||
* This set of coefficients is a special division to reduce the background noise in PDM TX mode */
|
||||
@ -187,10 +189,7 @@ esp_err_t i2s_channel_init_pdm_tx_mode(i2s_chan_handle_t handle, const i2s_pdm_t
|
||||
ESP_GOTO_ON_ERROR(i2s_init_dma_intr(handle, I2S_INTR_ALLOC_FLAGS), err, TAG, "initialize dma interrupt failed");
|
||||
|
||||
i2s_ll_tx_enable_pdm(handle->controller->hal.dev);
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
/* Enable clock to start outputting mclk signal. Some codecs will reset once mclk stop */
|
||||
i2s_ll_tx_enable_clock(handle->controller->hal.dev);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX;
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
@ -357,7 +356,9 @@ static esp_err_t i2s_pdm_rx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_rx
|
||||
|
||||
portENTER_CRITICAL(&g_i2s.spinlock);
|
||||
/* Set clock configurations in HAL*/
|
||||
I2S_CLOCK_SRC_ATOMIC() {
|
||||
i2s_hal_set_rx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src);
|
||||
}
|
||||
portEXIT_CRITICAL(&g_i2s.spinlock);
|
||||
|
||||
/* Update the mode info: clock configuration */
|
||||
@ -467,10 +468,7 @@ esp_err_t i2s_channel_init_pdm_rx_mode(i2s_chan_handle_t handle, const i2s_pdm_r
|
||||
ESP_GOTO_ON_ERROR(i2s_init_dma_intr(handle, I2S_INTR_ALLOC_FLAGS), err, TAG, "initialize dma interrupt failed");
|
||||
|
||||
i2s_ll_rx_enable_pdm(handle->controller->hal.dev);
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
/* Enable clock to start outputting mclk signal. Some codecs will reset once mclk stop */
|
||||
i2s_ll_rx_enable_clock(handle->controller->hal.dev);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX;
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
|
78
components/driver/i2s/i2s_platform.c
Normal file
78
components/driver/i2s/i2s_platform.c
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "esp_check.h"
|
||||
#include "i2s_private.h"
|
||||
|
||||
static const char *TAG = "i2s_platform";
|
||||
|
||||
/**
|
||||
* @brief Global i2s platform object
|
||||
* @note For saving all the I2S related information
|
||||
*/
|
||||
i2s_platform_t g_i2s = {
|
||||
.spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED,
|
||||
.controller[0 ... (SOC_I2S_NUM - 1)] = NULL, // groups will be lazy installed
|
||||
.comp_name[0 ... (SOC_I2S_NUM - 1)] = NULL,
|
||||
};
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
I2S Platform APIs
|
||||
----------------------------------------------------------------------------
|
||||
Scope: This file and ADC/DAC/LCD driver
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
esp_err_t i2s_platform_acquire_occupation(int id, const char *comp_name)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
const char *occupied_comp = NULL;
|
||||
ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id");
|
||||
portENTER_CRITICAL(&g_i2s.spinlock);
|
||||
if ((!g_i2s.controller[id]) && (g_i2s.comp_name[id] == NULL)) {
|
||||
g_i2s.comp_name[id] = comp_name;
|
||||
/* Enable module clock */
|
||||
I2S_RCC_ATOMIC() {
|
||||
i2s_ll_enable_bus_clock(id, true);
|
||||
i2s_ll_reset_register(id);
|
||||
i2s_ll_enable_core_clock(I2S_LL_GET_HW(id), true);
|
||||
}
|
||||
} else {
|
||||
occupied_comp = g_i2s.comp_name[id];
|
||||
ret = ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
portEXIT_CRITICAL(&g_i2s.spinlock);
|
||||
if (occupied_comp != NULL) {
|
||||
ESP_LOGW(TAG, "i2s controller %d has been occupied by %s", id, occupied_comp);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t i2s_platform_release_occupation(int id)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id");
|
||||
portENTER_CRITICAL(&g_i2s.spinlock);
|
||||
if (!g_i2s.controller[id]) {
|
||||
g_i2s.comp_name[id] = NULL;
|
||||
/* Disable module clock */
|
||||
I2S_RCC_ATOMIC() {
|
||||
i2s_ll_enable_bus_clock(id, false);
|
||||
i2s_ll_enable_core_clock(I2S_LL_GET_HW(id), false);
|
||||
}
|
||||
} else {
|
||||
ret = ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
portEXIT_CRITICAL(&g_i2s.spinlock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Only used in `test_i2s_iram.c` to write DMA buffer directly
|
||||
size_t i2s_platform_get_dma_buffer_offset(void)
|
||||
{
|
||||
/* Force to transfer address '0' into 'i2s_chan_handle_t' type,
|
||||
* then find the corresponding field , the address of this field is the offset of this type */
|
||||
return (size_t)&(((i2s_chan_handle_t)0)->dma.bufs);
|
||||
}
|
@ -9,15 +9,17 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "soc/lldesc.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/i2s_types.h"
|
||||
#include "hal/i2s_hal.h"
|
||||
#include "driver/i2s_types.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#if SOC_GDMA_SUPPORTED
|
||||
#include "esp_private/gdma.h"
|
||||
#endif
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_pm.h"
|
||||
#include "esp_err.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -26,14 +28,26 @@ extern "C" {
|
||||
// If ISR handler is allowed to run whilst cache is disabled,
|
||||
// Make sure all the code and related variables used by the handler are in the SRAM
|
||||
#if CONFIG_I2S_ISR_IRAM_SAFE
|
||||
#define I2S_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED)
|
||||
#define I2S_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED)
|
||||
#define I2S_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||
#else
|
||||
#define I2S_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED)
|
||||
#define I2S_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED)
|
||||
#define I2S_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
||||
#endif //CONFIG_I2S_ISR_IRAM_SAFE
|
||||
#define I2S_DMA_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)
|
||||
|
||||
#if SOC_PERIPH_CLK_CTRL_SHARED
|
||||
#define I2S_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC()
|
||||
#else
|
||||
#define I2S_CLOCK_SRC_ATOMIC()
|
||||
#endif
|
||||
|
||||
#if !SOC_RCC_IS_INDEPENDENT
|
||||
#define I2S_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
|
||||
#else
|
||||
#define I2S_RCC_ATOMIC()
|
||||
#endif
|
||||
|
||||
#define I2S_NULL_POINTER_CHECK(tag, p) ESP_RETURN_ON_FALSE((p), ESP_ERR_INVALID_ARG, tag, "input parameter '"#p"' is NULL")
|
||||
|
||||
/**
|
||||
@ -45,6 +59,28 @@ typedef enum {
|
||||
I2S_CHAN_STATE_RUNNING, /*!< i2s channel is idling (initialized and enabled) */
|
||||
} i2s_state_t;
|
||||
|
||||
/**
|
||||
* @brief Group of I2S callbacks
|
||||
* @note The callbacks are all running under ISR environment
|
||||
* @note When CONFIG_I2S_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM.
|
||||
* The variables used in the function should be in the SRAM as well.
|
||||
* @note Declare the internal type to remove the dependency of `i2s_common.h`
|
||||
*/
|
||||
typedef struct {
|
||||
i2s_isr_callback_t on_recv; /**< Callback of data received event, only for rx channel
|
||||
* The event data includes DMA buffer address and size that just finished receiving data
|
||||
*/
|
||||
i2s_isr_callback_t on_recv_q_ovf; /**< Callback of receiving queue overflowed event, only for rx channel
|
||||
* The event data includes buffer size that has been overwritten
|
||||
*/
|
||||
i2s_isr_callback_t on_sent; /**< Callback of data sent event, only for tx channel
|
||||
* The event data includes DMA buffer address and size that just finished sending data
|
||||
*/
|
||||
i2s_isr_callback_t on_send_q_ovf; /**< Callback of sending queue overflowed event, only for tx channel
|
||||
* The event data includes buffer size that has been overwritten
|
||||
*/
|
||||
} i2s_event_callbacks_internal_t;
|
||||
|
||||
/**
|
||||
* @brief i2s channel level configurations
|
||||
* @note It performs as channel handle
|
||||
@ -61,6 +97,7 @@ typedef struct {
|
||||
bool auto_clear; /*!< Set to auto clear DMA TX descriptor, i2s will always send zero automatically if no data to send */
|
||||
uint32_t rw_pos; /*!< reading/writing pointer position */
|
||||
void *curr_ptr; /*!< Pointer to current dma buffer */
|
||||
void *curr_desc; /*!< Pointer to current dma descriptor used for pre-load */
|
||||
lldesc_t **desc; /*!< dma descriptor array */
|
||||
uint8_t **bufs; /*!< dma buffer array */
|
||||
} i2s_dma_t;
|
||||
@ -88,6 +125,7 @@ struct i2s_channel_obj_t {
|
||||
i2s_dma_t dma; /*!< i2s dma object */
|
||||
i2s_state_t state; /*!< i2s driver state. Ensuring the driver working in a correct sequence */
|
||||
/* Stored configurations */
|
||||
int intr_prio_flags;/*!< i2s interrupt priority flags */
|
||||
void *mode_info; /*!< Slot, clock and gpio information of each mode */
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
bool apll_en; /*!< Flag of wether APLL enabled */
|
||||
@ -101,7 +139,7 @@ struct i2s_channel_obj_t {
|
||||
esp_pm_lock_handle_t pm_lock; /*!< Power management lock, to avoid apb clock frequency changes while i2s is working */
|
||||
#endif
|
||||
QueueHandle_t msg_queue; /*!< Message queue handler, used for transporting data between interrupt and read/write task */
|
||||
i2s_event_callbacks_t callbacks; /*!< Callback functions */
|
||||
i2s_event_callbacks_internal_t callbacks; /*!< Callback functions */
|
||||
void *user_data; /*!< User data for callback functions */
|
||||
void (*start)(i2s_chan_handle_t); /*!< start tx/rx channel */
|
||||
void (*stop)(i2s_chan_handle_t); /*!< stop tx/rx channel */
|
||||
@ -117,7 +155,7 @@ typedef struct {
|
||||
const char *comp_name[SOC_I2S_NUM]; /*!< The component name that occupied i2s controller */
|
||||
} i2s_platform_t;
|
||||
|
||||
extern i2s_platform_t g_i2s;
|
||||
extern i2s_platform_t g_i2s; /*!< Global i2s instance for driver internal use */
|
||||
|
||||
/**
|
||||
* @brief Initialize I2S DMA interrupt
|
||||
@ -184,7 +222,7 @@ uint32_t i2s_get_source_clk_freq(i2s_clock_src_t clk_src, uint32_t mclk_freq_hz)
|
||||
* @param is_input Is input gpio
|
||||
* @param is_invert Is invert gpio
|
||||
*/
|
||||
void i2s_gpio_check_and_set(gpio_num_t gpio, uint32_t signal_idx, bool is_input, bool is_invert);
|
||||
void i2s_gpio_check_and_set(int gpio, uint32_t signal_idx, bool is_input, bool is_invert);
|
||||
|
||||
/**
|
||||
* @brief Check gpio validity and output mclk signal
|
||||
@ -197,7 +235,7 @@ void i2s_gpio_check_and_set(gpio_num_t gpio, uint32_t signal_idx, bool is_input,
|
||||
* - ESP_OK Set mclk output gpio success
|
||||
* - ESP_ERR_INVALID_ARG Invalid GPIO number
|
||||
*/
|
||||
esp_err_t i2s_check_set_mclk(i2s_port_t id, gpio_num_t gpio_num, i2s_clock_src_t clk_src, bool is_invert);
|
||||
esp_err_t i2s_check_set_mclk(i2s_port_t id, int gpio_num, i2s_clock_src_t clk_src, bool is_invert);
|
||||
|
||||
/**
|
||||
* @brief Attach data out signal and data in signal to a same gpio
|
||||
@ -206,7 +244,7 @@ esp_err_t i2s_check_set_mclk(i2s_port_t id, gpio_num_t gpio_num, i2s_clock_src_t
|
||||
* @param out_sig_idx Data out signal index
|
||||
* @param in_sig_idx Data in signal index
|
||||
*/
|
||||
void i2s_gpio_loopback_set(gpio_num_t gpio, uint32_t out_sig_idx, uint32_t in_sig_idx);
|
||||
void i2s_gpio_loopback_set(int gpio, uint32_t out_sig_idx, uint32_t in_sig_idx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -77,11 +77,13 @@ static esp_err_t i2s_std_set_clock(i2s_chan_handle_t handle, const i2s_std_clk_c
|
||||
|
||||
portENTER_CRITICAL(&g_i2s.spinlock);
|
||||
/* Set clock configurations in HAL*/
|
||||
I2S_CLOCK_SRC_ATOMIC() {
|
||||
if (handle->dir == I2S_DIR_TX) {
|
||||
i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src);
|
||||
} else {
|
||||
i2s_hal_set_rx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src);
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL(&g_i2s.spinlock);
|
||||
|
||||
/* Update the mode info: clock configuration */
|
||||
@ -226,10 +228,8 @@ esp_err_t i2s_channel_init_std_mode(i2s_chan_handle_t handle, const i2s_std_conf
|
||||
/* Enable clock to start outputting mclk signal. Some codecs will reset once mclk stop */
|
||||
if (handle->dir == I2S_DIR_TX) {
|
||||
i2s_ll_tx_enable_std(handle->controller->hal.dev);
|
||||
i2s_ll_tx_enable_clock(handle->controller->hal.dev);
|
||||
} else {
|
||||
i2s_ll_rx_enable_std(handle->controller->hal.dev);
|
||||
i2s_ll_rx_enable_clock(handle->controller->hal.dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -79,11 +79,13 @@ static esp_err_t i2s_tdm_set_clock(i2s_chan_handle_t handle, const i2s_tdm_clk_c
|
||||
|
||||
portENTER_CRITICAL(&g_i2s.spinlock);
|
||||
/* Set clock configurations in HAL*/
|
||||
I2S_CLOCK_SRC_ATOMIC() {
|
||||
if (handle->dir == I2S_DIR_TX) {
|
||||
i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src);
|
||||
} else {
|
||||
i2s_hal_set_rx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src);
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL(&g_i2s.spinlock);
|
||||
|
||||
/* Update the mode info: clock configuration */
|
||||
@ -232,10 +234,8 @@ esp_err_t i2s_channel_init_tdm_mode(i2s_chan_handle_t handle, const i2s_tdm_conf
|
||||
/* Enable clock to start outputting mclk signal. Some codecs will reset once mclk stop */
|
||||
if (handle->dir == I2S_DIR_TX) {
|
||||
i2s_ll_tx_enable_tdm(handle->controller->hal.dev);
|
||||
i2s_ll_tx_enable_clock(handle->controller->hal.dev);
|
||||
} else {
|
||||
i2s_ll_rx_enable_tdm(handle->controller->hal.dev);
|
||||
i2s_ll_rx_enable_clock(handle->controller->hal.dev);
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
@ -275,12 +275,12 @@ esp_err_t i2s_channel_reconfig_tdm_clock(i2s_chan_handle_t handle, const i2s_tdm
|
||||
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
/* Enable APLL and acquire its lock when the clock source is changed to APLL */
|
||||
if (clk_cfg->clk_src == I2S_CLK_SRC_APLL && clk_cfg->clk_cfg.clk_src != I2S_CLK_SRC_APLL) {
|
||||
if (clk_cfg->clk_src == I2S_CLK_SRC_APLL && tdm_cfg->clk_cfg.clk_src != I2S_CLK_SRC_APLL) {
|
||||
periph_rtc_apll_acquire();
|
||||
handle->apll_en = true;
|
||||
}
|
||||
/* Disable APLL and release its lock when clock source is changed to 160M_PLL */
|
||||
if (clk_cfg->clk_src != I2S_CLK_SRC_APLL && clk_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) {
|
||||
if (clk_cfg->clk_src != I2S_CLK_SRC_APLL && tdm_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) {
|
||||
periph_rtc_apll_release();
|
||||
handle->apll_en = false;
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ extern "C" {
|
||||
.dma_desc_num = 6, \
|
||||
.dma_frame_num = 240, \
|
||||
.auto_clear = false, \
|
||||
.intr_priority = 0, \
|
||||
}
|
||||
|
||||
#define I2S_GPIO_UNUSED GPIO_NUM_NC /*!< Used in i2s_gpio_config_t for signals which are not used */
|
||||
@ -63,6 +64,7 @@ typedef struct {
|
||||
* it should be the multiple of '3' when the data bit width is 24.
|
||||
*/
|
||||
bool auto_clear; /*!< Set to auto clear DMA TX buffer, i2s will always send zero automatically if no data to send */
|
||||
int intr_priority; /*!< I2S interrupt priority, range [0, 7], if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) */
|
||||
} i2s_chan_config_t;
|
||||
|
||||
/**
|
||||
|
@ -23,6 +23,23 @@ extern "C" {
|
||||
|
||||
#if SOC_I2S_SUPPORTS_PDM_RX
|
||||
|
||||
#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
|
||||
/**
|
||||
* @brief PDM format in 2 slots(RX)
|
||||
* @param bits_per_sample i2s data bit width, only support 16 bits for PDM mode
|
||||
* @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
|
||||
*/
|
||||
#define I2S_PDM_RX_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
|
||||
.data_bit_width = bits_per_sample, \
|
||||
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
|
||||
.slot_mode = mono_or_stereo, \
|
||||
.slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \
|
||||
I2S_PDM_SLOT_LEFT : I2S_PDM_SLOT_BOTH, \
|
||||
.hp_en = true, \
|
||||
.hp_cut_off_freq_hz = 35.5, \
|
||||
.amplify_num = 1, \
|
||||
}
|
||||
#else
|
||||
/**
|
||||
* @brief PDM format in 2 slots(RX)
|
||||
* @param bits_per_sample i2s data bit width, only support 16 bits for PDM mode
|
||||
@ -35,6 +52,7 @@ extern "C" {
|
||||
.slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \
|
||||
I2S_PDM_SLOT_LEFT : I2S_PDM_SLOT_BOTH, \
|
||||
}
|
||||
#endif // SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
|
||||
|
||||
/**
|
||||
* @brief i2s default pdm rx clock configuration
|
||||
@ -48,6 +66,8 @@ extern "C" {
|
||||
.bclk_div = 8, \
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief I2S slot configuration for pdm rx mode
|
||||
*/
|
||||
@ -58,6 +78,15 @@ typedef struct {
|
||||
i2s_slot_mode_t slot_mode; /*!< Set mono or stereo mode with I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO */
|
||||
/* Particular fields */
|
||||
i2s_pdm_slot_mask_t slot_mask; /*!< Choose the slots to activate */
|
||||
#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
|
||||
bool hp_en; /*!< High pass filter enable */
|
||||
float hp_cut_off_freq_hz; /*!< High pass filter cut-off frequency, range 23.3Hz ~ 185Hz, see cut-off frequency sheet above */
|
||||
uint32_t amplify_num; /*!< The amplification number of the final conversion result.
|
||||
* The data that have converted from PDM to PCM module, will time 'amplify_num' additionally to amplify the final result.
|
||||
* Note that it's only a multiplier of the digital PCM data, not the gain of the analog signal
|
||||
* range 1~15, default 1 */
|
||||
#endif // SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
|
||||
|
||||
} i2s_pdm_rx_slot_config_t;
|
||||
|
||||
/**
|
||||
|
71
components/driver/include/esp_private/i2s_sync.h
Normal file
71
components/driver/include/esp_private/i2s_sync.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
// DO NOT USE THESE APIS IN YOUR APPLICATIONS
|
||||
// The following APIs are for internal use, public to other IDF components, but not for users' applications.
|
||||
|
||||
/**
|
||||
* This file is used for getting the bclk and fifo sending count
|
||||
* for the synchronization among different I2S ports.
|
||||
*
|
||||
* The APIs in this file might be called frequently, so they are made light-weight and flexible to be called
|
||||
*
|
||||
* NOTE: These APIs are private for ESP internal usages.
|
||||
* Please be aware of the risk that APIs might be changed regarding the use case.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "driver/i2s_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if SOC_I2S_SUPPORTS_TX_SYNC_CNT
|
||||
|
||||
/**
|
||||
* @brief Get the counter number of BCLK ticks
|
||||
* @note The BCLK tick count reflects the real data that have sent on line
|
||||
*
|
||||
* @param[in] tx_handle The I2S tx channel handle
|
||||
* @return
|
||||
* - BCLK tick count
|
||||
*/
|
||||
uint32_t i2s_sync_get_bclk_count(i2s_chan_handle_t tx_handle);
|
||||
|
||||
/**
|
||||
* @brief Get the counter number of fifo
|
||||
* @note The FIFO count reflects how many slots have processed
|
||||
* Normally, fifo_cnt = slot_bit_width * bclk_cnt
|
||||
* If fifo_cnt < slot_bit_width * bclk_cnt, that means some data are still stuck in the I2S controller
|
||||
*
|
||||
* @param[in] tx_handle The I2S tx channel handle
|
||||
* @return
|
||||
* - FIFO slot count
|
||||
*/
|
||||
uint32_t i2s_sync_get_fifo_count(i2s_chan_handle_t tx_handle);
|
||||
|
||||
/**
|
||||
* @brief Reset the bclk counter
|
||||
*
|
||||
* @param[in] tx_handle The I2S tx channel handle
|
||||
*/
|
||||
void i2s_sync_reset_bclk_count(i2s_chan_handle_t tx_handle);
|
||||
|
||||
/**
|
||||
* @brief Reset the fifo counter
|
||||
*
|
||||
* @param[in] tx_handle The I2S tx channel handle
|
||||
*/
|
||||
void i2s_sync_reset_fifo_count(i2s_chan_handle_t tx_handle);
|
||||
|
||||
#endif // SOC_I2S_SUPPORTS_TX_SYNC_CNT
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -33,15 +33,27 @@ components/driver/test_apps/i2c_test_apps:
|
||||
components/driver/test_apps/i2s_test_apps:
|
||||
disable:
|
||||
- if: SOC_I2S_SUPPORTED != 1
|
||||
disable_test:
|
||||
- if: IDF_TARGET == "esp32p4"
|
||||
temporary: true
|
||||
reason: lack of runners
|
||||
|
||||
components/driver/test_apps/i2s_test_apps/i2s:
|
||||
disable:
|
||||
- if: SOC_I2S_SUPPORTED != 1
|
||||
disable_test:
|
||||
- if: IDF_TARGET == "esp32p4"
|
||||
temporary: true
|
||||
reason: lack of runners
|
||||
|
||||
components/driver/test_apps/i2s_test_apps/i2s_multi_dev:
|
||||
disable:
|
||||
- if: SOC_I2S_SUPPORTED != 1
|
||||
- if: SOC_I2S_HW_VERSION_2 != 1
|
||||
disable_test:
|
||||
- if: IDF_TARGET == "esp32p4"
|
||||
temporary: true
|
||||
reason: lack of runners
|
||||
|
||||
components/driver/test_apps/i2s_test_apps/legacy_i2s_adc_dac:
|
||||
disable:
|
||||
@ -50,6 +62,10 @@ components/driver/test_apps/i2s_test_apps/legacy_i2s_adc_dac:
|
||||
components/driver/test_apps/i2s_test_apps/legacy_i2s_driver:
|
||||
disable:
|
||||
- if: SOC_I2S_SUPPORTED != 1
|
||||
disable_test:
|
||||
- if: IDF_TARGET == "esp32p4"
|
||||
temporary: true
|
||||
reason: lack of runners
|
||||
|
||||
components/driver/test_apps/ledc:
|
||||
disable:
|
||||
|
@ -1,2 +1,2 @@
|
||||
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
|
||||
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "esp_err.h"
|
||||
@ -775,7 +776,7 @@ static void i2s_test_common_sample_rate(i2s_chan_handle_t rx_chan, i2s_std_clk_c
|
||||
// pcnt will count the pulse number on WS signal in 100ms
|
||||
TEST_ESP_OK(pcnt_unit_clear_count(pcnt_unit));
|
||||
TEST_ESP_OK(pcnt_unit_start(pcnt_unit));
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_I2S_PERIOD_MS));
|
||||
esp_rom_delay_us(100 * 1000);
|
||||
TEST_ESP_OK(pcnt_unit_stop(pcnt_unit));
|
||||
TEST_ESP_OK(pcnt_unit_get_count(pcnt_unit, &real_pulse));
|
||||
printf("[%"PRIu32" Hz] %d pulses, expected %d, err %d\n", test_freq[i], real_pulse, expt_pulse, real_pulse - expt_pulse);
|
||||
@ -803,7 +804,10 @@ TEST_CASE("I2S_default_PLL_clock_test", "[i2s]")
|
||||
TEST_ESP_OK(i2s_new_channel(&chan_cfg, NULL, &rx_handle));
|
||||
TEST_ESP_OK(i2s_channel_init_std_mode(rx_handle, &std_cfg));
|
||||
|
||||
// ESP32-P4 has no PLL except XTAL
|
||||
#if !CONFIG_IDF_TARGET_ESP32P4
|
||||
i2s_test_common_sample_rate(rx_handle, &std_cfg.clk_cfg);
|
||||
#endif // CONFIG_IDF_TARGET_ESP32P4
|
||||
#if SOC_I2S_SUPPORTS_XTAL
|
||||
std_cfg.clk_cfg.clk_src = I2S_CLK_SRC_XTAL;
|
||||
i2s_test_common_sample_rate(rx_handle, &std_cfg.clk_cfg);
|
||||
@ -880,7 +884,6 @@ TEST_CASE("I2S_package_lost_test", "[i2s]")
|
||||
for (i = 0; i < test_num; i++) {
|
||||
printf("Testing %"PRIu32" Hz sample rate\n", test_freq[i]);
|
||||
std_cfg.clk_cfg.sample_rate_hz = test_freq[i];
|
||||
std_cfg.clk_cfg.sample_rate_hz = test_freq[i];
|
||||
TEST_ESP_OK(i2s_channel_reconfig_std_clock(rx_handle, &std_cfg.clk_cfg));
|
||||
TEST_ESP_OK(i2s_channel_enable(rx_handle));
|
||||
for (int j = 0; j < 10; j++) {
|
||||
|
@ -13,6 +13,9 @@
|
||||
#include "driver/i2s_std.h"
|
||||
#include "esp_attr.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32P4
|
||||
#include "rom/cache.h"
|
||||
#endif
|
||||
#include "esp_private/i2s_platform.h"
|
||||
#include "esp_private/spi_flash_os.h"
|
||||
#include "../../test_inc/test_i2s.h"
|
||||
@ -39,9 +42,13 @@ static void IRAM_ATTR test_i2s_iram_write(i2s_chan_handle_t tx_handle)
|
||||
// disable cache and non-iram ISR handlers
|
||||
spi_flash_guard_get()->start();
|
||||
// write data into dma buffer directly, the data in dma buffer will be sent automatically
|
||||
for (int i=0; i < 100; i++) {
|
||||
dma_bufs[0][i] = i + 1;
|
||||
for (int i = 0; i < 400; i++) {
|
||||
dma_bufs[0][i] = i % 100 + 1;
|
||||
}
|
||||
#if CONFIG_IDF_TARGET_ESP32P4
|
||||
// TODO: need to consider PSRAM if I2S driver supports EDMA
|
||||
Cache_WriteBack_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)dma_bufs[0], 400);
|
||||
#endif
|
||||
// enable cache and non-iram ISR handlers
|
||||
spi_flash_guard_get()->end();
|
||||
}
|
||||
@ -52,8 +59,8 @@ TEST_CASE("i2s_iram_interrupt_safe", "[i2s]")
|
||||
i2s_chan_handle_t rx_chan = NULL;
|
||||
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
|
||||
chan_cfg.dma_desc_num = 6;
|
||||
chan_cfg.dma_frame_num = 200;
|
||||
chan_cfg.dma_desc_num = 2;
|
||||
chan_cfg.dma_frame_num = 100;
|
||||
TEST_ESP_OK(i2s_new_channel(&chan_cfg, &tx_chan, &rx_chan));
|
||||
i2s_std_config_t std_cfg = {
|
||||
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(16000),
|
||||
@ -73,14 +80,14 @@ TEST_CASE("i2s_iram_interrupt_safe", "[i2s]")
|
||||
};
|
||||
TEST_ESP_OK(i2s_channel_init_std_mode(tx_chan, &std_cfg));
|
||||
TEST_ESP_OK(i2s_channel_init_std_mode(rx_chan, &std_cfg));
|
||||
int is_triggerred = 0;
|
||||
int is_triggered = 0;
|
||||
i2s_event_callbacks_t cbs = {
|
||||
.on_recv = NULL,
|
||||
.on_recv_q_ovf = NULL,
|
||||
.on_sent = test_i2s_tx_done_callback,
|
||||
.on_send_q_ovf = NULL,
|
||||
};
|
||||
TEST_ESP_OK(i2s_channel_register_event_callback(tx_chan, &cbs, &is_triggerred));
|
||||
TEST_ESP_OK(i2s_channel_register_event_callback(tx_chan, &cbs, &is_triggered));
|
||||
TEST_ESP_OK(i2s_channel_enable(tx_chan));
|
||||
TEST_ESP_OK(i2s_channel_enable(rx_chan));
|
||||
|
||||
@ -92,7 +99,7 @@ TEST_CASE("i2s_iram_interrupt_safe", "[i2s]")
|
||||
for (int retry = 0; retry < 3; retry++) {
|
||||
i2s_channel_read(rx_chan, recv_buf, 2000, &r_bytes, pdMS_TO_TICKS(1000));
|
||||
for (i = 0; i < 2000 - 100; i++) {
|
||||
if (recv_buf[i] != 0) {
|
||||
if (recv_buf[i] == 1 && recv_buf[i + 1] == 2) {
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
@ -107,7 +114,7 @@ finish:
|
||||
for (int j = 1; j <= 100; j++) {
|
||||
TEST_ASSERT_EQUAL_UINT8(recv_buf[i++], j);
|
||||
}
|
||||
TEST_ASSERT(is_triggerred);
|
||||
TEST_ASSERT(is_triggered);
|
||||
free(recv_buf);
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 |
|
||||
| ----------------- | -------- | -------- | -------- | -------- |
|
||||
| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S3 |
|
||||
| ----------------- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
|
@ -1,2 +1,2 @@
|
||||
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
|
||||
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -44,6 +44,14 @@ extern "C" {
|
||||
#define SLAVE_WS_IO 15
|
||||
#define DATA_IN_IO 19
|
||||
#define DATA_OUT_IO 18
|
||||
#elif CONFIG_IDF_TARGET_ESP32P4
|
||||
#define MASTER_MCK_IO 34
|
||||
#define MASTER_BCK_IO 35
|
||||
#define MASTER_WS_IO 48
|
||||
#define SLAVE_BCK_IO 10
|
||||
#define SLAVE_WS_IO 11
|
||||
#define DATA_IN_IO 12
|
||||
#define DATA_OUT_IO 49
|
||||
#else
|
||||
#define MASTER_MCK_IO 0
|
||||
#define MASTER_BCK_IO 4
|
||||
|
@ -54,7 +54,7 @@ void periph_rtc_apll_release(void);
|
||||
* @brief Calculate and set APLL coefficients by given frequency
|
||||
* @note Have to call 'periph_rtc_apll_acquire' to enable APLL power before setting frequency
|
||||
* @note This calculation is based on the inequality:
|
||||
* xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= SOC_APLL_MULTIPLIER_OUT_MIN_HZ(350 MHz)
|
||||
* xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= CLK_LL_APLL_MULTIPLIER_MIN_HZ(350 MHz)
|
||||
* It will always calculate the minimum coefficients that can satisfy the inequality above, instead of loop them one by one.
|
||||
* which means more appropriate coefficients are likely to exist.
|
||||
* But this algorithm can meet almost all the cases and the accuracy can be guaranteed as well.
|
||||
|
@ -217,7 +217,7 @@ uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm
|
||||
* i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= 350 MHz, '+1' in the following code is to get the ceil value.
|
||||
* With this condition, as we know the 'o_div' can't be greater than 31, then we can calculate the APLL minimum support frequency is
|
||||
* 350 MHz / ((31 + 2) * 2) = 5303031 Hz (for ceil) */
|
||||
o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MIN_HZ / (float)(freq * 2) + 1) - 2;
|
||||
o_div = (int)(CLK_LL_APLL_MULTIPLIER_MIN_HZ / (float)(freq * 2) + 1) - 2;
|
||||
if (o_div > 31) {
|
||||
ESP_HW_LOGE(TAG, "Expected frequency is too small");
|
||||
return 0;
|
||||
@ -227,7 +227,7 @@ uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm
|
||||
* i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) <= 500 MHz, we need to get the floor value in the following code.
|
||||
* With this condition, as we know the 'o_div' can't be smaller than 0, then we can calculate the APLL maximum support frequency is
|
||||
* 500 MHz / ((0 + 2) * 2) = 125000000 Hz */
|
||||
o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MAX_HZ / (float)(freq * 2)) - 2;
|
||||
o_div = (int)(CLK_LL_APLL_MULTIPLIER_MAX_HZ / (float)(freq * 2)) - 2;
|
||||
if (o_div < 0) {
|
||||
ESP_HW_LOGE(TAG, "Expected frequency is too big");
|
||||
return 0;
|
||||
|
@ -368,6 +368,22 @@ uint32_t rtc_clk_apb_freq_get(void)
|
||||
return rtc_clk_ahb_freq_get() / clk_ll_apb_get_divider() * MHZ;
|
||||
}
|
||||
|
||||
void rtc_clk_apll_enable(bool enable)
|
||||
{
|
||||
// TODO: IDF-7526
|
||||
}
|
||||
|
||||
uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm0, uint32_t *_sdm1, uint32_t *_sdm2)
|
||||
{
|
||||
// TODO: IDF-7526
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rtc_clk_apll_coeff_set(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2)
|
||||
{
|
||||
// TODO: IDF-7526
|
||||
}
|
||||
|
||||
void rtc_dig_clk8m_enable(void)
|
||||
{
|
||||
clk_ll_rc_fast_digi_enable();
|
||||
|
@ -119,7 +119,7 @@ uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm
|
||||
* i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= 350 MHz, '+1' in the following code is to get the ceil value.
|
||||
* With this condition, as we know the 'o_div' can't be greater than 31, then we can calculate the APLL minimum support frequency is
|
||||
* 350 MHz / ((31 + 2) * 2) = 5303031 Hz (for ceil) */
|
||||
o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MIN_HZ / (float)(freq * 2) + 1) - 2;
|
||||
o_div = (int)(CLK_LL_APLL_MULTIPLIER_MIN_HZ / (float)(freq * 2) + 1) - 2;
|
||||
if (o_div > 31) {
|
||||
ESP_HW_LOGE(TAG, "Expected frequency is too small");
|
||||
return 0;
|
||||
@ -129,7 +129,7 @@ uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm
|
||||
* i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) <= 500 MHz, we need to get the floor value in the following code.
|
||||
* With this condition, as we know the 'o_div' can't be smaller than 0, then we can calculate the APLL maximum support frequency is
|
||||
* 500 MHz / ((0 + 2) * 2) = 125000000 Hz */
|
||||
o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MAX_HZ / (float)(freq * 2)) - 2;
|
||||
o_div = (int)(CLK_LL_APLL_MULTIPLIER_MAX_HZ / (float)(freq * 2)) - 2;
|
||||
if (o_div < 0) {
|
||||
ESP_HW_LOGE(TAG, "Expected frequency is too big");
|
||||
return 0;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -73,6 +73,15 @@ extern "C" {
|
||||
#define CLK_LL_XTAL_32K_BOOTSTRAP_DRES_VAL 3
|
||||
#define CLK_LL_XTAL_32K_BOOTSTRAP_DBIAS_VAL 0
|
||||
|
||||
/* APLL multiplier output frequency range */
|
||||
// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)
|
||||
#define CLK_LL_APLL_MULTIPLIER_MIN_HZ (350000000) // 350 MHz
|
||||
#define CLK_LL_APLL_MULTIPLIER_MAX_HZ (500000000) // 500 MHz
|
||||
|
||||
/* APLL output frequency range */
|
||||
#define CLK_LL_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
|
||||
#define CLK_LL_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
|
||||
|
||||
/**
|
||||
* @brief XTAL32K_CLK enable modes
|
||||
*/
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "hal/misc.h"
|
||||
#include "soc/i2s_periph.h"
|
||||
#include "soc/i2s_struct.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "hal/i2s_types.h"
|
||||
#include "hal/hal_utils.h"
|
||||
|
||||
@ -48,7 +49,7 @@ extern "C" {
|
||||
#define I2S_LL_RX_EVENT_MASK I2S_LL_EVENT_RX_EOF
|
||||
|
||||
#define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz
|
||||
#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
|
||||
#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
|
||||
|
||||
/**
|
||||
* @brief Enable DMA descriptor owner check
|
||||
@ -84,30 +85,73 @@ static inline void i2s_ll_dma_enable_eof_on_fifo_empty(i2s_dev_t *hw, bool en)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2S module general init, enable I2S clock.
|
||||
* @brief Enable the bus clock for I2S module
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param i2s_id The port id of I2S
|
||||
* @param enable Set true to enable the buf clock
|
||||
*/
|
||||
static inline void i2s_ll_enable_clock(i2s_dev_t *hw)
|
||||
static inline void i2s_ll_enable_bus_clock(int i2s_id, bool enable)
|
||||
{
|
||||
if (hw->clkm_conf.clk_en == 0) {
|
||||
hw->clkm_conf.clk_en = 1;
|
||||
hw->conf2.val = 0;
|
||||
if (enable) {
|
||||
if (i2s_id == 0) {
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
|
||||
} else {
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN);
|
||||
}
|
||||
} else if (i2s_id == 1) {
|
||||
if (i2s_id == 0) {
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
|
||||
} else {
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_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(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_bus_clock(__VA_ARGS__)
|
||||
|
||||
|
||||
/**
|
||||
* @brief I2S module disable clock.
|
||||
* @brief Reset the I2S module
|
||||
*
|
||||
* @param i2s_id The port id of I2S
|
||||
*/
|
||||
static inline void i2s_ll_reset_register(int i2s_id)
|
||||
{
|
||||
if (i2s_id == 0) {
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
|
||||
} else if (i2s_id == 1) {
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_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(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_reset_register(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @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_disable_clock(i2s_dev_t *hw)
|
||||
static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable)
|
||||
{
|
||||
if (hw->clkm_conf.clk_en == 1) {
|
||||
if (enable && !hw->clkm_conf.clk_en) {
|
||||
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(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_core_clock(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief I2S tx msb right enable
|
||||
*
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "hal/assert.h"
|
||||
#include "soc/i2s_periph.h"
|
||||
#include "soc/i2s_struct.h"
|
||||
#include "soc/system_struct.h"
|
||||
#include "hal/i2s_types.h"
|
||||
#include "hal/hal_utils.h"
|
||||
|
||||
@ -34,27 +35,56 @@ extern "C" {
|
||||
#define I2S_LL_CLK_FRAC_DIV_AB_MAX 512 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the a/b register is 9 bit-width
|
||||
|
||||
#define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz
|
||||
#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
|
||||
#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
|
||||
|
||||
|
||||
/**
|
||||
* @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;
|
||||
SYSTEM.perip_clk_en0.reg_i2s1_clk_en = enable;
|
||||
}
|
||||
|
||||
/// 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(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_bus_clock(__VA_ARGS__)
|
||||
|
||||
|
||||
/**
|
||||
* @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;
|
||||
SYSTEM.perip_rst_en0.reg_i2s1_rst = 1;
|
||||
SYSTEM.perip_rst_en0.reg_i2s1_rst = 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_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_reset_register(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @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_clock(i2s_dev_t *hw)
|
||||
static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->tx_clkm_conf.clk_en = 1;
|
||||
hw->tx_clkm_conf.clk_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2S module disable I2S clock.
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_disable_clock(i2s_dev_t *hw)
|
||||
{
|
||||
hw->tx_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(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_core_clock(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Enable I2S tx module clock
|
||||
|
@ -35,28 +35,42 @@ extern "C" {
|
||||
#define I2S_LL_CLK_FRAC_DIV_AB_MAX 512 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the a/b register is 9 bit-width
|
||||
|
||||
#define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz
|
||||
#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
|
||||
#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
|
||||
|
||||
/**
|
||||
*
|
||||
* @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;
|
||||
PCR.i2s_conf.i2s_clk_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
PCR.i2s_conf.i2s_rst_en = 1;
|
||||
PCR.i2s_conf.i2s_rst_en = 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_clock(i2s_dev_t *hw)
|
||||
static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable)
|
||||
{
|
||||
// The clock gate enabling is moved to `periph_module_enable`
|
||||
(void)hw;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2S module disable I2S clock.
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_disable_clock(i2s_dev_t *hw)
|
||||
{
|
||||
// The clock gate disabling is moved to `periph_module_disable`
|
||||
(void)hw;
|
||||
(void)enable;
|
||||
// No need to do anything
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -36,28 +36,42 @@ extern "C" {
|
||||
|
||||
#define I2S_LL_PLL_F96M_CLK_FREQ (96 * 1000000) // PLL_F96M_CLK: 96MHz
|
||||
#define I2S_LL_PLL_F64M_CLK_FREQ (64 * 1000000) // PLL_F64M_CLK: 64MHz
|
||||
#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F96M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
|
||||
#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F96M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
|
||||
|
||||
/**
|
||||
*
|
||||
* @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;
|
||||
PCR.i2s_conf.i2s_clk_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
PCR.i2s_conf.i2s_rst_en = 1;
|
||||
PCR.i2s_conf.i2s_rst_en = 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_clock(i2s_dev_t *hw)
|
||||
static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable)
|
||||
{
|
||||
// The clock gate enabling is moved to `periph_module_enable`
|
||||
(void)hw;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2S module disable I2S clock.
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_disable_clock(i2s_dev_t *hw)
|
||||
{
|
||||
// The clock gate disabling is moved to `periph_module_disable`
|
||||
(void)hw;
|
||||
(void)enable;
|
||||
// No need to do anything
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -36,12 +36,6 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph)
|
||||
return HP_SYS_CLKRST_REG_I2C0_APB_CLK_EN;
|
||||
case PERIPH_I2C1_MODULE:
|
||||
return HP_SYS_CLKRST_REG_I2C1_APB_CLK_EN;
|
||||
case PERIPH_I2S0_MODULE:
|
||||
return HP_SYS_CLKRST_REG_I2S0_TX_CLK_EN | HP_SYS_CLKRST_REG_I2S0_RX_CLK_EN;
|
||||
case PERIPH_I2S1_MODULE:
|
||||
return HP_SYS_CLKRST_REG_I2S1_RX_CLK_EN | HP_SYS_CLKRST_REG_I2S1_TX_CLK_EN;
|
||||
case PERIPH_I2S2_MODULE:
|
||||
return HP_SYS_CLKRST_REG_I2S2_RX_CLK_EN | HP_SYS_CLKRST_REG_I2S2_TX_CLK_EN;
|
||||
case PERIPH_LCD_MODULE:
|
||||
return HP_SYS_CLKRST_REG_LCD_CLK_EN;
|
||||
case PERIPH_UART0_MODULE:
|
||||
@ -151,12 +145,6 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en
|
||||
return HP_SYS_CLKRST_REG_RST_EN_CAN2;
|
||||
case PERIPH_LEDC_MODULE:
|
||||
return HP_SYS_CLKRST_REG_RST_EN_LEDC;
|
||||
case PERIPH_I2S0_MODULE:
|
||||
return HP_SYS_CLKRST_REG_RST_EN_I2S0_APB;
|
||||
case PERIPH_I2S1_MODULE:
|
||||
return HP_SYS_CLKRST_REG_RST_EN_I2S1_APB;
|
||||
case PERIPH_I2S2_MODULE:
|
||||
return HP_SYS_CLKRST_REG_RST_EN_I2S2_APB;
|
||||
case PERIPH_GPSPI2_MODULE:
|
||||
return HP_SYS_CLKRST_REG_RST_EN_SPI2;
|
||||
case PERIPH_GPSPI3_MODULE:
|
||||
@ -294,10 +282,6 @@ static inline uint32_t periph_ll_get_rst_en_reg(periph_module_t periph)
|
||||
case PERIPH_TWAI1_MODULE:
|
||||
case PERIPH_TWAI2_MODULE:
|
||||
case PERIPH_LEDC_MODULE:
|
||||
case PERIPH_I2S0_MODULE:
|
||||
return HP_SYS_CLKRST_HP_RST_EN1_REG;
|
||||
case PERIPH_I2S1_MODULE:
|
||||
case PERIPH_I2S2_MODULE:
|
||||
case PERIPH_GPSPI2_MODULE:
|
||||
case PERIPH_GPSPI3_MODULE:
|
||||
case PERIPH_CAM_MODULE:
|
||||
|
@ -30,6 +30,16 @@ extern "C" {
|
||||
|
||||
#define CLK_LL_PLL_480M_FREQ_MHZ (480)
|
||||
|
||||
/* APLL multiplier output frequency range */
|
||||
// TODO: IDF-7526 check if the APLL frequency range is same as before
|
||||
// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)
|
||||
#define CLK_LL_APLL_MULTIPLIER_MIN_HZ (350000000) // 350 MHz
|
||||
#define CLK_LL_APLL_MULTIPLIER_MAX_HZ (500000000) // 500 MHz
|
||||
|
||||
/* APLL output frequency range */
|
||||
#define CLK_LL_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
|
||||
#define CLK_LL_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
|
||||
|
||||
#define CLK_LL_XTAL32K_CONFIG_DEFAULT() { \
|
||||
.dac = 3, \
|
||||
.dres = 3, \
|
||||
|
1402
components/hal/esp32p4/include/hal/i2s_ll.h
Normal file
1402
components/hal/esp32p4/include/hal/i2s_ll.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -47,6 +47,15 @@ extern "C" {
|
||||
#define CLK_LL_APLL_CAL_DELAY_2 0x3f
|
||||
#define CLK_LL_APLL_CAL_DELAY_3 0x1f
|
||||
|
||||
/* APLL multiplier output frequency range */
|
||||
// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)
|
||||
#define CLK_LL_APLL_MULTIPLIER_MIN_HZ (350000000) // 350 MHz
|
||||
#define CLK_LL_APLL_MULTIPLIER_MAX_HZ (500000000) // 500 MHz
|
||||
|
||||
/* APLL output frequency range */
|
||||
#define CLK_LL_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
|
||||
#define CLK_LL_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
|
||||
|
||||
#define CLK_LL_XTAL32K_CONFIG_DEFAULT() { \
|
||||
.dac = 3, \
|
||||
.dres = 3, \
|
||||
|
@ -18,6 +18,8 @@
|
||||
#include "hal/misc.h"
|
||||
#include "soc/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"
|
||||
|
||||
@ -45,7 +47,7 @@ extern "C" {
|
||||
#define I2S_LL_RX_EVENT_MASK I2S_LL_EVENT_RX_EOF
|
||||
|
||||
#define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz
|
||||
#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
|
||||
#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
|
||||
|
||||
/**
|
||||
* @brief Enable DMA descriptor owner check
|
||||
@ -81,31 +83,73 @@ static inline void i2s_ll_dma_enable_eof_on_fifo_empty(i2s_dev_t *hw, bool en)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2S module general init, enable I2S clock.
|
||||
* @brief Enable the bus clock for I2S module
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param i2s_id The port id of I2S
|
||||
* @param enable Set true to enable the buf clock
|
||||
*/
|
||||
static inline void i2s_ll_enable_clock(i2s_dev_t *hw)
|
||||
static inline void i2s_ll_enable_bus_clock(int i2s_id, bool enable)
|
||||
{
|
||||
if (hw->clkm_conf.clk_en == 0) {
|
||||
hw->clkm_conf.clk_sel = 2;
|
||||
hw->clkm_conf.clk_en = 1;
|
||||
hw->conf2.val = 0;
|
||||
if (enable) {
|
||||
if (i2s_id == 0) {
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
|
||||
} else {
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN);
|
||||
}
|
||||
} else {
|
||||
if (i2s_id == 0) {
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
|
||||
} else {
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_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(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_bus_clock(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief I2S module disable clock.
|
||||
* @brief Reset the I2S module
|
||||
*
|
||||
* @param i2s_id The port id of I2S
|
||||
*/
|
||||
static inline void i2s_ll_reset_register(int i2s_id)
|
||||
{
|
||||
if (i2s_id == 0) {
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
|
||||
} else {
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_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(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_reset_register(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @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_disable_clock(i2s_dev_t *hw)
|
||||
static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable)
|
||||
{
|
||||
if (hw->clkm_conf.clk_en == 1) {
|
||||
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(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_core_clock(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief I2S tx msb right enable
|
||||
*
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "hal/assert.h"
|
||||
#include "soc/i2s_periph.h"
|
||||
#include "soc/i2s_struct.h"
|
||||
#include "soc/system_struct.h"
|
||||
#include "hal/i2s_types.h"
|
||||
#include "hal/hal_utils.h"
|
||||
|
||||
@ -35,27 +36,62 @@ extern "C" {
|
||||
#define I2S_LL_CLK_FRAC_DIV_AB_MAX 512 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the a/b register is 9 bit-width
|
||||
|
||||
#define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz
|
||||
#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
|
||||
#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
|
||||
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
if (i2s_id == 0) {
|
||||
SYSTEM.perip_clk_en0.i2s0_clk_en = enable;
|
||||
} else if (i2s_id == 1) {
|
||||
SYSTEM.perip_clk_en0.i2s1_clk_en = enable;
|
||||
}
|
||||
}
|
||||
|
||||
/// 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(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_bus_clock(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Reset the I2S module
|
||||
*
|
||||
* @param i2s_id The port id of I2S
|
||||
*/
|
||||
static inline void i2s_ll_reset_register(int i2s_id)
|
||||
{
|
||||
if (i2s_id == 0) {
|
||||
SYSTEM.perip_rst_en0.i2s0_rst = 1;
|
||||
SYSTEM.perip_rst_en0.i2s0_rst = 0;
|
||||
} else if (i2s_id == 1) {
|
||||
SYSTEM.perip_rst_en0.i2s1_rst = 1;
|
||||
SYSTEM.perip_rst_en0.i2s1_rst = 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_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_reset_register(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @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_clock(i2s_dev_t *hw)
|
||||
static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->tx_clkm_conf.clk_en = 1;
|
||||
hw->tx_clkm_conf.clk_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2S module disable I2S clock.
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_disable_clock(i2s_dev_t *hw)
|
||||
{
|
||||
hw->tx_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(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_core_clock(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Enable I2S tx module clock
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include "soc/soc.h"
|
||||
#include "hal/i2s_hal.h"
|
||||
|
||||
#if SOC_I2S_HW_VERSION_2 && SOC_I2S_SUPPORTS_PDM_TX
|
||||
#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; [1]: param0; [2]: param5 */
|
||||
static const float cut_off_coef[21][3] = {
|
||||
@ -22,6 +22,22 @@ static const float cut_off_coef[21][3] = {
|
||||
{63, 4, 7}, {58, 5, 6}, {49, 5, 7},
|
||||
{46, 6, 6}, {35.5, 6, 7}, {23.3, 7, 7}
|
||||
};
|
||||
|
||||
static void s_i2s_hal_get_cut_off_coef(float freq, uint32_t *param0, uint32_t *param5)
|
||||
{
|
||||
uint8_t cnt = 0;
|
||||
float min = 1000;
|
||||
/* Find the closest cut-off frequency and its coefficients */
|
||||
for (int i = 0; i < 21; i++) {
|
||||
float 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
|
||||
|
||||
/**
|
||||
@ -49,8 +65,9 @@ void i2s_hal_init(i2s_hal_context_t *hal, int port_id)
|
||||
hal->dev = I2S_LL_GET_HW(port_id);
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
{
|
||||
if (clk_info) {
|
||||
hal_utils_clk_div_t mclk_div = {};
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
i2s_ll_tx_enable_clock(hal->dev);
|
||||
@ -60,10 +77,14 @@ void i2s_hal_set_tx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *cl
|
||||
i2s_hal_calc_mclk_precise_division(clk_info->sclk, clk_info->mclk, &mclk_div);
|
||||
i2s_ll_tx_set_mclk(hal->dev, &mclk_div);
|
||||
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)
|
||||
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)
|
||||
{
|
||||
if (clk_info) {
|
||||
hal_utils_clk_div_t mclk_div = {};
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
i2s_ll_rx_enable_clock(hal->dev);
|
||||
@ -73,6 +94,9 @@ void i2s_hal_set_rx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *cl
|
||||
i2s_hal_calc_mclk_precise_division(clk_info->sclk, clk_info->mclk, &mclk_div);
|
||||
i2s_ll_rx_set_mclk(hal->dev, &mclk_div);
|
||||
i2s_ll_rx_set_bck_div_num(hal->dev, clk_info->bclk_div);
|
||||
} else {
|
||||
i2s_ll_rx_clk_set_src(hal->dev, clk_src);
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
@ -183,20 +207,12 @@ void i2s_hal_pdm_set_tx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_ha
|
||||
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);
|
||||
uint8_t cnt = 0;
|
||||
float min = 1000;
|
||||
float expt_cut_off = slot_cfg->pdm_tx.hp_cut_off_freq_hz;
|
||||
/* Find the closest cut-off frequency and its coefficients */
|
||||
for (int i = 0; i < 21; i++) {
|
||||
float tmp = cut_off_coef[i][0] < expt_cut_off ? expt_cut_off - cut_off_coef[i][0] : cut_off_coef[i][0] - expt_cut_off;
|
||||
if (tmp < min) {
|
||||
min = tmp;
|
||||
cnt = i;
|
||||
}
|
||||
}
|
||||
uint32_t param0;
|
||||
uint32_t param5;
|
||||
s_i2s_hal_get_cut_off_coef(slot_cfg->pdm_tx.hp_cut_off_freq_hz, ¶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, cut_off_coef[cnt][1]);
|
||||
i2s_ll_tx_set_pdm_hp_filter_param5(hal->dev, cut_off_coef[cnt][2]);
|
||||
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
|
||||
@ -233,7 +249,18 @@ void i2s_hal_pdm_set_rx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_ha
|
||||
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_SUPPORTS_PDM_RX
|
||||
#endif // SOC_I2S_HW_VERSION_1
|
||||
|
||||
#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
|
||||
uint32_t param0;
|
||||
uint32_t param5;
|
||||
s_i2s_hal_get_cut_off_coef(slot_cfg->pdm_rx.hp_cut_off_freq_hz, ¶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)
|
||||
|
@ -91,7 +91,13 @@ typedef struct {
|
||||
/* PDM TX configurations */
|
||||
struct {
|
||||
i2s_pdm_slot_mask_t slot_mask; /*!< Choose the slots to activate */
|
||||
} pdm_rx; /*!< Specific configurations for PDM TX mode */
|
||||
#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
|
||||
bool hp_en; /*!< High pass filter enable */
|
||||
float hp_cut_off_freq_hz; /*!< High pass filter cut-off frequency, range 23.3Hz ~ 185Hz, see cut-off frequency sheet above */
|
||||
uint32_t amplify_num; /*!< The amplification number of the final conversion result */
|
||||
#endif // SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
|
||||
|
||||
} pdm_rx; /*!< Specific configurations for PDM RX mode */
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -136,20 +142,35 @@ void i2s_hal_calc_mclk_precise_division(uint32_t sclk, uint32_t mclk, hal_utils_
|
||||
* @brief Set tx channel clock
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param clk_info clock information
|
||||
* @param clk_info clock information, if it is NULL, only set the clock source
|
||||
* @param clk_src clock source
|
||||
*/
|
||||
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);
|
||||
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);
|
||||
|
||||
#if SOC_PERIPH_CLK_CTRL_SHARED
|
||||
/// 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_hal_set_tx_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _i2s_hal_set_tx_clock(__VA_ARGS__)
|
||||
#else
|
||||
#define i2s_hal_set_tx_clock(...) _i2s_hal_set_tx_clock(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Set rx channel clock
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param clk_info clock information
|
||||
* @param clk_info clock information, if it is NULL, only set the clock source
|
||||
* @param clk_src clock source
|
||||
*/
|
||||
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);
|
||||
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);
|
||||
|
||||
#if SOC_PERIPH_CLK_CTRL_SHARED
|
||||
/// 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_hal_set_rx_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _i2s_hal_set_rx_clock(__VA_ARGS__)
|
||||
#else
|
||||
#define i2s_hal_set_rx_clock(...) _i2s_hal_set_rx_clock(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
| STD configuration |
|
||||
|
@ -811,22 +811,6 @@ config SOC_CLK_APLL_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_APLL_MULTIPLIER_OUT_MIN_HZ
|
||||
int
|
||||
default 350000000
|
||||
|
||||
config SOC_APLL_MULTIPLIER_OUT_MAX_HZ
|
||||
int
|
||||
default 500000000
|
||||
|
||||
config SOC_APLL_MIN_HZ
|
||||
int
|
||||
default 5303031
|
||||
|
||||
config SOC_APLL_MAX_HZ
|
||||
int
|
||||
default 125000000
|
||||
|
||||
config SOC_CLK_RC_FAST_D256_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
@ -1,6 +1,6 @@
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -399,11 +399,6 @@
|
||||
|
||||
/*-------------------------- CLOCK SUBSYSTEM CAPS ----------------------------------------*/
|
||||
#define SOC_CLK_APLL_SUPPORTED (1)
|
||||
// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)
|
||||
#define SOC_APLL_MULTIPLIER_OUT_MIN_HZ (350000000) // 350 MHz
|
||||
#define SOC_APLL_MULTIPLIER_OUT_MAX_HZ (500000000) // 500 MHz
|
||||
#define SOC_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
|
||||
#define SOC_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
|
||||
|
||||
#define SOC_CLK_RC_FAST_D256_SUPPORTED (1)
|
||||
#define SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256 (1)
|
||||
|
@ -29,7 +29,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
|
||||
.data_out_sigs[1] = I2SO_SD1_OUT_IDX,
|
||||
.data_in_sig = I2SI_SD_IN_IDX,
|
||||
|
||||
.irq = -1,
|
||||
.irq = ETS_I2S1_INTR_SOURCE,
|
||||
.module = PERIPH_I2S1_MODULE,
|
||||
}
|
||||
};
|
||||
|
@ -29,7 +29,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
|
||||
.data_out_sigs[1] = I2SO_SD1_OUT_IDX,
|
||||
.data_in_sig = I2SI_SD_IN_IDX,
|
||||
|
||||
.irq = -1,
|
||||
.irq = ETS_I2S1_INTR_SOURCE,
|
||||
.module = PERIPH_I2S1_MODULE,
|
||||
}
|
||||
};
|
||||
|
@ -240,34 +240,6 @@ typedef union {
|
||||
uint32_t val;
|
||||
} i2s_rx_conf1_reg_t;
|
||||
|
||||
/** Type of rx_clkm_conf register
|
||||
* I2S RX clock configure register
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
/** rx_clkm_div_num : R/W; bitpos: [7:0]; default: 2;
|
||||
* Integral I2S clock divider value
|
||||
*/
|
||||
uint32_t rx_clkm_div_num:8;
|
||||
uint32_t reserved_8:18;
|
||||
/** rx_clk_active : R/W; bitpos: [26]; default: 0;
|
||||
* I2S Rx module clock enable signal.
|
||||
*/
|
||||
uint32_t rx_clk_active:1;
|
||||
/** rx_clk_sel : R/W; bitpos: [28:27]; default: 0;
|
||||
* Select I2S Rx module source clock. 0: XTAL clock. 1: PLL240M. 2: PLL160M. 3: I2S_MCLK_in.
|
||||
*/
|
||||
uint32_t rx_clk_sel:2;
|
||||
/** mclk_sel : R/W; bitpos: [29]; default: 0;
|
||||
* 0: UseI2S Tx module clock as I2S_MCLK_OUT. 1: UseI2S Rx module clock as
|
||||
* I2S_MCLK_OUT.
|
||||
*/
|
||||
uint32_t mclk_sel:1;
|
||||
uint32_t reserved_30:2;
|
||||
};
|
||||
uint32_t val;
|
||||
} i2s_rx_clkm_conf_reg_t;
|
||||
|
||||
/** Type of tx_pcm2pdm_conf register
|
||||
* I2S TX PCM2PDM configuration register
|
||||
*/
|
||||
@ -609,37 +581,6 @@ typedef union {
|
||||
uint32_t val;
|
||||
} i2s_tx_conf1_reg_t;
|
||||
|
||||
/** Type of tx_clkm_conf register
|
||||
* I2S TX clock configure register
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
/** tx_clkm_div_num : R/W; bitpos: [7:0]; default: 2;
|
||||
* Integral I2S TX clock divider value. f_I2S_CLK = f_I2S_CLK_S/(N+b/a). There will be
|
||||
* (a-b) * n-div and b * (n+1)-div. So the average combination will be: for b <=
|
||||
* a/2, z * [x * n-div + (n+1)-div] + y * n-div. For b > a/2, z * [n-div + x *
|
||||
* (n+1)-div] + y * (n+1)-div.
|
||||
*/
|
||||
uint32_t tx_clkm_div_num:8;
|
||||
uint32_t reserved_8:18;
|
||||
/** tx_clk_active : R/W; bitpos: [26]; default: 0;
|
||||
* I2S Tx module clock enable signal.
|
||||
*/
|
||||
uint32_t tx_clk_active:1;
|
||||
/** tx_clk_sel : R/W; bitpos: [28:27]; default: 0;
|
||||
* Select I2S Tx module source clock. 0: XTAL clock. 1: PLL240M. 2: PLL160M. 3:
|
||||
* I2S_MCLK_in.
|
||||
*/
|
||||
uint32_t tx_clk_sel:2;
|
||||
/** clk_en : R/W; bitpos: [29]; default: 0;
|
||||
* Set this bit to enable clk gate
|
||||
*/
|
||||
uint32_t clk_en:1;
|
||||
uint32_t reserved_30:2;
|
||||
};
|
||||
uint32_t val;
|
||||
} i2s_tx_clkm_conf_reg_t;
|
||||
|
||||
/** Type of tx_tdm_ctrl register
|
||||
* I2S TX TDM mode control register
|
||||
*/
|
||||
@ -742,36 +683,6 @@ typedef union {
|
||||
|
||||
|
||||
/** Group: RX clock and timing registers */
|
||||
/** Type of rx_clkm_div_conf register
|
||||
* I2S RX module clock divider configure register
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
/** rx_clkm_div_z : R/W; bitpos: [8:0]; default: 0;
|
||||
* For b <= a/2, the value of I2S_RX_CLKM_DIV_Z is b. For b > a/2, the value of
|
||||
* I2S_RX_CLKM_DIV_Z is (a-b).
|
||||
*/
|
||||
uint32_t rx_clkm_div_z:9;
|
||||
/** rx_clkm_div_y : R/W; bitpos: [17:9]; default: 1;
|
||||
* For b <= a/2, the value of I2S_RX_CLKM_DIV_Y is (a%b) . For b > a/2, the value of
|
||||
* I2S_RX_CLKM_DIV_Y is (a%(a-b)).
|
||||
*/
|
||||
uint32_t rx_clkm_div_y:9;
|
||||
/** rx_clkm_div_x : R/W; bitpos: [26:18]; default: 0;
|
||||
* For b <= a/2, the value of I2S_RX_CLKM_DIV_X is (a/b) - 1. For b > a/2, the value
|
||||
* of I2S_RX_CLKM_DIV_X is (a/(a-b)) - 1.
|
||||
*/
|
||||
uint32_t rx_clkm_div_x:9;
|
||||
/** rx_clkm_div_yn1 : R/W; bitpos: [27]; default: 0;
|
||||
* For b <= a/2, the value of I2S_RX_CLKM_DIV_YN1 is 0 . For b > a/2, the value of
|
||||
* I2S_RX_CLKM_DIV_YN1 is 1.
|
||||
*/
|
||||
uint32_t rx_clkm_div_yn1:1;
|
||||
uint32_t reserved_28:4;
|
||||
};
|
||||
uint32_t val;
|
||||
} i2s_rx_clkm_div_conf_reg_t;
|
||||
|
||||
/** Type of rx_timing register
|
||||
* I2S RX timing control register
|
||||
*/
|
||||
@ -813,36 +724,6 @@ typedef union {
|
||||
|
||||
|
||||
/** Group: TX clock and timing registers */
|
||||
/** Type of tx_clkm_div_conf register
|
||||
* I2S TX module clock divider configure register
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
/** tx_clkm_div_z : R/W; bitpos: [8:0]; default: 0;
|
||||
* For b <= a/2, the value of I2S_TX_CLKM_DIV_Z is b. For b > a/2, the value of
|
||||
* I2S_TX_CLKM_DIV_Z is (a-b).
|
||||
*/
|
||||
uint32_t tx_clkm_div_z:9;
|
||||
/** tx_clkm_div_y : R/W; bitpos: [17:9]; default: 1;
|
||||
* For b <= a/2, the value of I2S_TX_CLKM_DIV_Y is (a%b) . For b > a/2, the value of
|
||||
* I2S_TX_CLKM_DIV_Y is (a%(a-b)).
|
||||
*/
|
||||
uint32_t tx_clkm_div_y:9;
|
||||
/** tx_clkm_div_x : R/W; bitpos: [26:18]; default: 0;
|
||||
* For b <= a/2, the value of I2S_TX_CLKM_DIV_X is (a/b) - 1. For b > a/2, the value
|
||||
* of I2S_TX_CLKM_DIV_X is (a/(a-b)) - 1.
|
||||
*/
|
||||
uint32_t tx_clkm_div_x:9;
|
||||
/** tx_clkm_div_yn1 : R/W; bitpos: [27]; default: 0;
|
||||
* For b <= a/2, the value of I2S_TX_CLKM_DIV_YN1 is 0 . For b > a/2, the value of
|
||||
* I2S_TX_CLKM_DIV_YN1 is 1.
|
||||
*/
|
||||
uint32_t tx_clkm_div_yn1:1;
|
||||
uint32_t reserved_28:4;
|
||||
};
|
||||
uint32_t val;
|
||||
} i2s_tx_clkm_div_conf_reg_t;
|
||||
|
||||
/** Type of tx_timing register
|
||||
* I2S TX timing control register
|
||||
*/
|
||||
@ -993,10 +874,7 @@ typedef struct i2s_dev_t {
|
||||
volatile i2s_tx_conf_reg_t tx_conf;
|
||||
volatile i2s_rx_conf1_reg_t rx_conf1;
|
||||
volatile i2s_tx_conf1_reg_t tx_conf1;
|
||||
volatile i2s_rx_clkm_conf_reg_t rx_clkm_conf;
|
||||
volatile i2s_tx_clkm_conf_reg_t tx_clkm_conf;
|
||||
volatile i2s_rx_clkm_div_conf_reg_t rx_clkm_div_conf;
|
||||
volatile i2s_tx_clkm_div_conf_reg_t tx_clkm_div_conf;
|
||||
uint32_t reserved_030[4];
|
||||
volatile i2s_tx_pcm2pdm_conf_reg_t tx_pcm2pdm_conf;
|
||||
volatile i2s_tx_pcm2pdm_conf1_reg_t tx_pcm2pdm_conf1;
|
||||
uint32_t reserved_048[2];
|
||||
|
@ -28,7 +28,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
|
||||
.data_out_sig = I2SO_SD_OUT_IDX,
|
||||
.data_in_sig = I2SI_SD_IN_IDX,
|
||||
|
||||
.irq = -1,
|
||||
.irq = ETS_I2S1_INTR_SOURCE,
|
||||
.module = PERIPH_I2S1_MODULE,
|
||||
}
|
||||
};
|
||||
|
@ -240,34 +240,6 @@ typedef union {
|
||||
uint32_t val;
|
||||
} i2s_rx_conf1_reg_t;
|
||||
|
||||
/** Type of rx_clkm_conf register
|
||||
* I2S RX clock configure register
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
/** rx_clkm_div_num : R/W; bitpos: [7:0]; default: 2;
|
||||
* Integral I2S clock divider value
|
||||
*/
|
||||
uint32_t rx_clkm_div_num:8;
|
||||
uint32_t reserved_8:18;
|
||||
/** rx_clk_active : R/W; bitpos: [26]; default: 0;
|
||||
* I2S Rx module clock enable signal.
|
||||
*/
|
||||
uint32_t rx_clk_active:1;
|
||||
/** rx_clk_sel : R/W; bitpos: [28:27]; default: 0;
|
||||
* Select I2S Rx module source clock. 0: no clock. 1: APLL. 2: CLK160. 3: I2S_MCLK_in.
|
||||
*/
|
||||
uint32_t rx_clk_sel:2;
|
||||
/** mclk_sel : R/W; bitpos: [29]; default: 0;
|
||||
* 0: UseI2S Tx module clock as I2S_MCLK_OUT. 1: UseI2S Rx module clock as
|
||||
* I2S_MCLK_OUT.
|
||||
*/
|
||||
uint32_t mclk_sel:1;
|
||||
uint32_t reserved_30:2;
|
||||
};
|
||||
uint32_t val;
|
||||
} i2s_rx_clkm_conf_reg_t;
|
||||
|
||||
/** Type of tx_pcm2pdm_conf register
|
||||
* I2S TX PCM2PDM configuration register
|
||||
*/
|
||||
@ -607,37 +579,6 @@ typedef union {
|
||||
uint32_t val;
|
||||
} i2s_tx_conf1_reg_t;
|
||||
|
||||
/** Type of tx_clkm_conf register
|
||||
* I2S TX clock configure register
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
/** tx_clkm_div_num : R/W; bitpos: [7:0]; default: 2;
|
||||
* Integral I2S TX clock divider value. f_I2S_CLK = f_I2S_CLK_S/(N+b/a). There will be
|
||||
* (a-b) * n-div and b * (n+1)-div. So the average combination will be: for b <=
|
||||
* a/2, z * [x * n-div + (n+1)-div] + y * n-div. For b > a/2, z * [n-div + x *
|
||||
* (n+1)-div] + y * (n+1)-div.
|
||||
*/
|
||||
uint32_t tx_clkm_div_num:8;
|
||||
uint32_t reserved_8:18;
|
||||
/** tx_clk_active : R/W; bitpos: [26]; default: 0;
|
||||
* I2S Tx module clock enable signal.
|
||||
*/
|
||||
uint32_t tx_clk_active:1;
|
||||
/** tx_clk_sel : R/W; bitpos: [28:27]; default: 0;
|
||||
* Select I2S Tx module source clock. 0: XTAL clock. 1: APLL. 2: CLK160. 3:
|
||||
* I2S_MCLK_in.
|
||||
*/
|
||||
uint32_t tx_clk_sel:2;
|
||||
/** clk_en : R/W; bitpos: [29]; default: 0;
|
||||
* Set this bit to enable clk gate
|
||||
*/
|
||||
uint32_t clk_en:1;
|
||||
uint32_t reserved_30:2;
|
||||
};
|
||||
uint32_t val;
|
||||
} i2s_tx_clkm_conf_reg_t;
|
||||
|
||||
/** Type of tx_tdm_ctrl register
|
||||
* I2S TX TDM mode control register
|
||||
*/
|
||||
@ -740,36 +681,6 @@ typedef union {
|
||||
|
||||
|
||||
/** Group: RX clock and timing registers */
|
||||
/** Type of rx_clkm_div_conf register
|
||||
* I2S RX module clock divider configure register
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
/** rx_clkm_div_z : R/W; bitpos: [8:0]; default: 0;
|
||||
* For b <= a/2, the value of I2S_RX_CLKM_DIV_Z is b. For b > a/2, the value of
|
||||
* I2S_RX_CLKM_DIV_Z is (a-b).
|
||||
*/
|
||||
uint32_t rx_clkm_div_z:9;
|
||||
/** rx_clkm_div_y : R/W; bitpos: [17:9]; default: 1;
|
||||
* For b <= a/2, the value of I2S_RX_CLKM_DIV_Y is (a%b) . For b > a/2, the value of
|
||||
* I2S_RX_CLKM_DIV_Y is (a%(a-b)).
|
||||
*/
|
||||
uint32_t rx_clkm_div_y:9;
|
||||
/** rx_clkm_div_x : R/W; bitpos: [26:18]; default: 0;
|
||||
* For b <= a/2, the value of I2S_RX_CLKM_DIV_X is (a/b) - 1. For b > a/2, the value
|
||||
* of I2S_RX_CLKM_DIV_X is (a/(a-b)) - 1.
|
||||
*/
|
||||
uint32_t rx_clkm_div_x:9;
|
||||
/** rx_clkm_div_yn1 : R/W; bitpos: [27]; default: 0;
|
||||
* For b <= a/2, the value of I2S_RX_CLKM_DIV_YN1 is 0 . For b > a/2, the value of
|
||||
* I2S_RX_CLKM_DIV_YN1 is 1.
|
||||
*/
|
||||
uint32_t rx_clkm_div_yn1:1;
|
||||
uint32_t reserved_28:4;
|
||||
};
|
||||
uint32_t val;
|
||||
} i2s_rx_clkm_div_conf_reg_t;
|
||||
|
||||
/** Type of rx_timing register
|
||||
* I2S RX timing control register
|
||||
*/
|
||||
@ -811,36 +722,6 @@ typedef union {
|
||||
|
||||
|
||||
/** Group: TX clock and timing registers */
|
||||
/** Type of tx_clkm_div_conf register
|
||||
* I2S TX module clock divider configure register
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
/** tx_clkm_div_z : R/W; bitpos: [8:0]; default: 0;
|
||||
* For b <= a/2, the value of I2S_TX_CLKM_DIV_Z is b. For b > a/2, the value of
|
||||
* I2S_TX_CLKM_DIV_Z is (a-b).
|
||||
*/
|
||||
uint32_t tx_clkm_div_z:9;
|
||||
/** tx_clkm_div_y : R/W; bitpos: [17:9]; default: 1;
|
||||
* For b <= a/2, the value of I2S_TX_CLKM_DIV_Y is (a%b) . For b > a/2, the value of
|
||||
* I2S_TX_CLKM_DIV_Y is (a%(a-b)).
|
||||
*/
|
||||
uint32_t tx_clkm_div_y:9;
|
||||
/** tx_clkm_div_x : R/W; bitpos: [26:18]; default: 0;
|
||||
* For b <= a/2, the value of I2S_TX_CLKM_DIV_X is (a/b) - 1. For b > a/2, the value
|
||||
* of I2S_TX_CLKM_DIV_X is (a/(a-b)) - 1.
|
||||
*/
|
||||
uint32_t tx_clkm_div_x:9;
|
||||
/** tx_clkm_div_yn1 : R/W; bitpos: [27]; default: 0;
|
||||
* For b <= a/2, the value of I2S_TX_CLKM_DIV_YN1 is 0 . For b > a/2, the value of
|
||||
* I2S_TX_CLKM_DIV_YN1 is 1.
|
||||
*/
|
||||
uint32_t tx_clkm_div_yn1:1;
|
||||
uint32_t reserved_28:4;
|
||||
};
|
||||
uint32_t val;
|
||||
} i2s_tx_clkm_div_conf_reg_t;
|
||||
|
||||
/** Type of tx_timing register
|
||||
* I2S TX timing control register
|
||||
*/
|
||||
@ -991,10 +872,7 @@ typedef struct {
|
||||
volatile i2s_tx_conf_reg_t tx_conf;
|
||||
volatile i2s_rx_conf1_reg_t rx_conf1;
|
||||
volatile i2s_tx_conf1_reg_t tx_conf1;
|
||||
volatile i2s_rx_clkm_conf_reg_t rx_clkm_conf;
|
||||
volatile i2s_tx_clkm_conf_reg_t tx_clkm_conf;
|
||||
volatile i2s_rx_clkm_div_conf_reg_t rx_clkm_div_conf;
|
||||
volatile i2s_tx_clkm_div_conf_reg_t tx_clkm_div_conf;
|
||||
uint32_t reserved_030[4];
|
||||
volatile i2s_tx_pcm2pdm_conf_reg_t tx_pcm2pdm_conf;
|
||||
volatile i2s_tx_pcm2pdm_conf1_reg_t tx_pcm2pdm_conf1;
|
||||
uint32_t reserved_048[2];
|
||||
|
@ -11,4 +11,76 @@
|
||||
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_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,
|
||||
.module = PERIPH_I2S0_MODULE,
|
||||
},
|
||||
[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,
|
||||
.module = PERIPH_I2S1_MODULE,
|
||||
},
|
||||
[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,
|
||||
.module = PERIPH_I2S2_MODULE,
|
||||
},
|
||||
};
|
||||
|
@ -67,6 +67,10 @@ config SOC_RMT_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_I2S_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_I2C_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
@ -433,7 +437,7 @@ config SOC_I2C_SUPPORT_RTC
|
||||
|
||||
config SOC_I2S_NUM
|
||||
int
|
||||
default 1
|
||||
default 3
|
||||
|
||||
config SOC_I2S_HW_VERSION_2
|
||||
bool
|
||||
@ -443,7 +447,7 @@ config SOC_I2S_SUPPORTS_XTAL
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_I2S_SUPPORTS_PLL_F160M
|
||||
config SOC_I2S_SUPPORTS_APLL
|
||||
bool
|
||||
default y
|
||||
|
||||
@ -451,10 +455,42 @@ config SOC_I2S_SUPPORTS_PCM
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_I2S_SUPPORTS_PDM
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_I2S_SUPPORTS_PDM_TX
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_I2S_SUPPORTS_PDM_RX
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_I2S_SUPPORTS_TX_SYNC_CNT
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_I2S_SUPPORTS_TDM
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_I2S_PDM_MAX_TX_LINES
|
||||
int
|
||||
default 2
|
||||
|
||||
config SOC_I2S_PDM_MAX_RX_LINES
|
||||
int
|
||||
default 4
|
||||
|
||||
config SOC_I2S_TDM_FULL_DATA_WIDTH
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_LEDC_SUPPORT_PLL_DIV_CLOCK
|
||||
bool
|
||||
default y
|
||||
@ -1095,6 +1131,10 @@ config SOC_MODEM_CLOCK_IS_INDEPENDENT
|
||||
bool
|
||||
default n
|
||||
|
||||
config SOC_CLK_APLL_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_CLK_XTAL32K_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
@ -150,6 +150,7 @@ typedef enum {
|
||||
SOC_MOD_CLK_XTAL32K, /*!< XTAL32K_CLK comes from the external 32kHz crystal, passing a clock gating to the peripherals */
|
||||
SOC_MOD_CLK_RC_FAST, /*!< RC_FAST_CLK comes from the internal 20MHz rc oscillator, passing a clock gating to the peripherals */
|
||||
SOC_MOD_CLK_XTAL, /*!< XTAL_CLK comes from the external 40MHz crystal */
|
||||
SOC_MOD_CLK_APLL, /*!< Audio PLL is sourced from PLL, and its frequency is configurable through APLL configuration registers */
|
||||
SOC_MOD_CLK_INVALID, /*!< Indication of the end of the available module clock sources */
|
||||
} soc_module_clk_t;
|
||||
|
||||
@ -334,6 +335,21 @@ typedef enum {
|
||||
|
||||
///////////////////////////////////////////////// I2S //////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @brief Array initializer for all supported clock sources of I2S
|
||||
*/
|
||||
#define SOC_I2S_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_APLL, I2S_CLK_SRC_EXTERNAL}
|
||||
|
||||
/**
|
||||
* @brief I2S clock source enum
|
||||
*/
|
||||
typedef enum {
|
||||
I2S_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the default source clock */
|
||||
I2S_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */
|
||||
I2S_CLK_SRC_APLL = SOC_MOD_CLK_APLL, /*!< Select APLL as the source clock */
|
||||
I2S_CLK_SRC_EXTERNAL = -1, /*!< Select external clock as source clock */
|
||||
} soc_periph_i2s_clk_src_t;
|
||||
|
||||
/////////////////////////////////////////////////I2C////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
|
@ -277,6 +277,92 @@ typedef union {
|
||||
uint32_t val;
|
||||
} i2s_rx_pdm2pcm_conf_reg_t;
|
||||
|
||||
/** Type of tx_pcm2pdm_conf register
|
||||
* I2S TX PCM2PDM configuration register
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
/** tx_pdm_hp_bypass : R/W; bitpos: [0]; default: 0;
|
||||
* I2S TX PDM bypass hp filter or not. The option has been removed.
|
||||
*/
|
||||
uint32_t tx_pdm_hp_bypass:1;
|
||||
/** tx_pdm_sinc_osr2 : R/W; bitpos: [4:1]; default: 2;
|
||||
* I2S TX PDM OSR2 value
|
||||
*/
|
||||
uint32_t tx_pdm_sinc_osr2:4;
|
||||
/** tx_pdm_prescale : R/W; bitpos: [12:5]; default: 0;
|
||||
* I2S TX PDM prescale for sigmadelta
|
||||
*/
|
||||
uint32_t tx_pdm_prescale:8;
|
||||
/** tx_pdm_hp_in_shift : R/W; bitpos: [14:13]; default: 1;
|
||||
* I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4
|
||||
*/
|
||||
uint32_t tx_pdm_hp_in_shift:2;
|
||||
/** tx_pdm_lp_in_shift : R/W; bitpos: [16:15]; default: 1;
|
||||
* I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4
|
||||
*/
|
||||
uint32_t tx_pdm_lp_in_shift:2;
|
||||
/** tx_pdm_sinc_in_shift : R/W; bitpos: [18:17]; default: 1;
|
||||
* I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4
|
||||
*/
|
||||
uint32_t tx_pdm_sinc_in_shift:2;
|
||||
/** tx_pdm_sigmadelta_in_shift : R/W; bitpos: [20:19]; default: 1;
|
||||
* I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4
|
||||
*/
|
||||
uint32_t tx_pdm_sigmadelta_in_shift:2;
|
||||
/** tx_pdm_sigmadelta_dither2 : R/W; bitpos: [21]; default: 0;
|
||||
* I2S TX PDM sigmadelta dither2 value
|
||||
*/
|
||||
uint32_t tx_pdm_sigmadelta_dither2:1;
|
||||
/** tx_pdm_sigmadelta_dither : R/W; bitpos: [22]; default: 1;
|
||||
* I2S TX PDM sigmadelta dither value
|
||||
*/
|
||||
uint32_t tx_pdm_sigmadelta_dither:1;
|
||||
/** tx_pdm_dac_2out_en : R/W; bitpos: [23]; default: 0;
|
||||
* I2S TX PDM dac mode enable
|
||||
*/
|
||||
uint32_t tx_pdm_dac_2out_en:1;
|
||||
/** tx_pdm_dac_mode_en : R/W; bitpos: [24]; default: 0;
|
||||
* I2S TX PDM dac 2channel enable
|
||||
*/
|
||||
uint32_t tx_pdm_dac_mode_en:1;
|
||||
/** pcm2pdm_conv_en : R/W; bitpos: [25]; default: 0;
|
||||
* I2S TX PDM Converter enable
|
||||
*/
|
||||
uint32_t pcm2pdm_conv_en:1;
|
||||
uint32_t reserved_26:6;
|
||||
};
|
||||
uint32_t val;
|
||||
} i2s_tx_pcm2pdm_conf_reg_t;
|
||||
|
||||
/** Type of tx_pcm2pdm_conf1 register
|
||||
* I2S TX PCM2PDM configuration register
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
/** tx_pdm_fp : R/W; bitpos: [9:0]; default: 960;
|
||||
* I2S TX PDM Fp
|
||||
*/
|
||||
uint32_t tx_pdm_fp:10;
|
||||
/** tx_pdm_fs : R/W; bitpos: [19:10]; default: 480;
|
||||
* I2S TX PDM Fs
|
||||
*/
|
||||
uint32_t tx_pdm_fs:10;
|
||||
/** tx_iir_hp_mult12_5 : R/W; bitpos: [22:20]; default: 7;
|
||||
* The fourth parameter of PDM TX IIR_HP filter stage 2 is (504 +
|
||||
* I2S_TX_IIR_HP_MULT12_5[2:0])
|
||||
*/
|
||||
uint32_t tx_iir_hp_mult12_5:3;
|
||||
/** tx_iir_hp_mult12_0 : R/W; bitpos: [25:23]; default: 7;
|
||||
* The fourth parameter of PDM TX IIR_HP filter stage 1 is (504 +
|
||||
* I2S_TX_IIR_HP_MULT12_0[2:0])
|
||||
*/
|
||||
uint32_t tx_iir_hp_mult12_0:3;
|
||||
uint32_t reserved_26:6;
|
||||
};
|
||||
uint32_t val;
|
||||
} i2s_tx_pcm2pdm_conf1_reg_t;
|
||||
|
||||
/** Type of rx_tdm_ctrl register
|
||||
* I2S TX TDM mode control register
|
||||
*/
|
||||
@ -371,7 +457,7 @@ typedef union {
|
||||
uint32_t val;
|
||||
} i2s_rx_tdm_ctrl_reg_t;
|
||||
|
||||
/** Type of rxeof_num register
|
||||
/** Type of rx_eof_num register
|
||||
* I2S RX data number control register.
|
||||
*/
|
||||
typedef union {
|
||||
@ -384,7 +470,7 @@ typedef union {
|
||||
uint32_t reserved_12:20;
|
||||
};
|
||||
uint32_t val;
|
||||
} i2s_rxeof_num_reg_t;
|
||||
} i2s_rx_eof_num_reg_t;
|
||||
|
||||
|
||||
/** Group: TX Control and configuration registers */
|
||||
@ -530,89 +616,6 @@ typedef union {
|
||||
uint32_t val;
|
||||
} i2s_tx_conf1_reg_t;
|
||||
|
||||
/** Type of tx_pcm2pdm_conf register
|
||||
* I2S TX PCM2PDM configuration register
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t reserved_0:1;
|
||||
/** tx_pdm_sinc_osr2 : R/W; bitpos: [4:1]; default: 2;
|
||||
* I2S TX PDM OSR2 value
|
||||
*/
|
||||
uint32_t tx_pdm_sinc_osr2:4;
|
||||
/** tx_pdm_prescale : R/W; bitpos: [12:5]; default: 0;
|
||||
* I2S TX PDM prescale for sigmadelta
|
||||
*/
|
||||
uint32_t tx_pdm_prescale:8;
|
||||
/** tx_pdm_hp_in_shift : R/W; bitpos: [14:13]; default: 1;
|
||||
* I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4
|
||||
*/
|
||||
uint32_t tx_pdm_hp_in_shift:2;
|
||||
/** tx_pdm_lp_in_shift : R/W; bitpos: [16:15]; default: 1;
|
||||
* I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4
|
||||
*/
|
||||
uint32_t tx_pdm_lp_in_shift:2;
|
||||
/** tx_pdm_sinc_in_shift : R/W; bitpos: [18:17]; default: 1;
|
||||
* I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4
|
||||
*/
|
||||
uint32_t tx_pdm_sinc_in_shift:2;
|
||||
/** tx_pdm_sigmadelta_in_shift : R/W; bitpos: [20:19]; default: 1;
|
||||
* I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4
|
||||
*/
|
||||
uint32_t tx_pdm_sigmadelta_in_shift:2;
|
||||
/** tx_pdm_sigmadelta_dither2 : R/W; bitpos: [21]; default: 0;
|
||||
* I2S TX PDM sigmadelta dither2 value
|
||||
*/
|
||||
uint32_t tx_pdm_sigmadelta_dither2:1;
|
||||
/** tx_pdm_sigmadelta_dither : R/W; bitpos: [22]; default: 1;
|
||||
* I2S TX PDM sigmadelta dither value
|
||||
*/
|
||||
uint32_t tx_pdm_sigmadelta_dither:1;
|
||||
/** tx_pdm_dac_2out_en : R/W; bitpos: [23]; default: 0;
|
||||
* I2S TX PDM dac mode enable
|
||||
*/
|
||||
uint32_t tx_pdm_dac_2out_en:1;
|
||||
/** tx_pdm_dac_mode_en : R/W; bitpos: [24]; default: 0;
|
||||
* I2S TX PDM dac 2channel enable
|
||||
*/
|
||||
uint32_t tx_pdm_dac_mode_en:1;
|
||||
/** pcm2pdm_conv_en : R/W; bitpos: [25]; default: 0;
|
||||
* I2S TX PDM Converter enable
|
||||
*/
|
||||
uint32_t pcm2pdm_conv_en:1;
|
||||
uint32_t reserved_26:6;
|
||||
};
|
||||
uint32_t val;
|
||||
} i2s_tx_pcm2pdm_conf_reg_t;
|
||||
|
||||
/** Type of tx_pcm2pdm_conf1 register
|
||||
* I2S TX PCM2PDM configuration register
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
/** tx_pdm_fp : R/W; bitpos: [9:0]; default: 960;
|
||||
* I2S TX PDM Fp
|
||||
*/
|
||||
uint32_t tx_pdm_fp:10;
|
||||
/** tx_pdm_fs : R/W; bitpos: [19:10]; default: 480;
|
||||
* I2S TX PDM Fs
|
||||
*/
|
||||
uint32_t tx_pdm_fs:10;
|
||||
/** tx_iir_hp_mult12_5 : R/W; bitpos: [22:20]; default: 7;
|
||||
* The fourth parameter of PDM TX IIR_HP filter stage 2 is (504 +
|
||||
* I2S_TX_IIR_HP_MULT12_5[2:0])
|
||||
*/
|
||||
uint32_t tx_iir_hp_mult12_5:3;
|
||||
/** tx_iir_hp_mult12_0 : R/W; bitpos: [25:23]; default: 7;
|
||||
* The fourth parameter of PDM TX IIR_HP filter stage 1 is (504 +
|
||||
* I2S_TX_IIR_HP_MULT12_0[2:0])
|
||||
*/
|
||||
uint32_t tx_iir_hp_mult12_0:3;
|
||||
uint32_t reserved_26:6;
|
||||
};
|
||||
uint32_t val;
|
||||
} i2s_tx_pcm2pdm_conf1_reg_t;
|
||||
|
||||
/** Type of tx_tdm_ctrl register
|
||||
* I2S TX TDM mode control register
|
||||
*/
|
||||
@ -845,7 +848,7 @@ typedef union {
|
||||
uint32_t val;
|
||||
} i2s_lc_hung_conf_reg_t;
|
||||
|
||||
/** Type of conf_sigle_data register
|
||||
/** Type of conf_single_data register
|
||||
* I2S signal data register
|
||||
*/
|
||||
typedef union {
|
||||
@ -856,7 +859,7 @@ typedef union {
|
||||
uint32_t single_data:32;
|
||||
};
|
||||
uint32_t val;
|
||||
} i2s_conf_sigle_data_reg_t;
|
||||
} i2s_conf_single_data_reg_t;
|
||||
|
||||
|
||||
/** Group: TX status registers */
|
||||
@ -986,8 +989,8 @@ typedef struct {
|
||||
volatile i2s_rx_timing_reg_t rx_timing;
|
||||
volatile i2s_tx_timing_reg_t tx_timing;
|
||||
volatile i2s_lc_hung_conf_reg_t lc_hung_conf;
|
||||
volatile i2s_rxeof_num_reg_t rxeof_num;
|
||||
volatile i2s_conf_sigle_data_reg_t conf_sigle_data;
|
||||
volatile i2s_rx_eof_num_reg_t rx_eof_num;
|
||||
volatile i2s_conf_single_data_reg_t conf_single_data;
|
||||
volatile i2s_state_reg_t state;
|
||||
volatile i2s_etm_conf_reg_t etm_conf;
|
||||
volatile i2s_fifo_cnt_reg_t fifo_cnt;
|
||||
@ -996,6 +999,9 @@ typedef struct {
|
||||
volatile i2s_date_reg_t date;
|
||||
} i2s_dev_t;
|
||||
|
||||
extern i2s_dev_t I2S0;
|
||||
extern i2s_dev_t I2S1;
|
||||
extern i2s_dev_t I2S2;
|
||||
|
||||
#ifndef __cplusplus
|
||||
_Static_assert(sizeof(i2s_dev_t) == 0x84, "Invalid size of i2s_dev_t structure");
|
||||
|
@ -486,6 +486,44 @@ bool rtc_dig_8m_enabled(void);
|
||||
*/
|
||||
uint32_t rtc_clk_freq_cal(uint32_t cal_val);
|
||||
|
||||
/**
|
||||
* @brief Enable or disable APLL
|
||||
*
|
||||
* Output frequency is given by the formula:
|
||||
* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2)
|
||||
*
|
||||
* The dividend in this expression should be in the range of 240 - 600 MHz.
|
||||
*
|
||||
* In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0.
|
||||
*
|
||||
* @param enable true to enable, false to disable
|
||||
*/
|
||||
void rtc_clk_apll_enable(bool enable);
|
||||
|
||||
/**
|
||||
* @brief Calculate APLL clock coeffifcients
|
||||
*
|
||||
* @param freq expected APLL frequency
|
||||
* @param o_div frequency divider, 0..31
|
||||
* @param sdm0 frequency adjustment parameter, 0..255
|
||||
* @param sdm1 frequency adjustment parameter, 0..255
|
||||
* @param sdm2 frequency adjustment parameter, 0..63
|
||||
*
|
||||
* @return
|
||||
* - 0 Failed
|
||||
* - else Sucess
|
||||
*/
|
||||
uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm0, uint32_t *_sdm1, uint32_t *_sdm2);
|
||||
|
||||
/**
|
||||
* @brief Set APLL clock coeffifcients
|
||||
*
|
||||
* @param o_div frequency divider, 0..31
|
||||
* @param sdm0 frequency adjustment parameter, 0..255
|
||||
* @param sdm1 frequency adjustment parameter, 0..255
|
||||
* @param sdm2 frequency adjustment parameter, 0..63
|
||||
*/
|
||||
void rtc_clk_apll_coeff_set(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2);
|
||||
|
||||
// -------------------------- CLOCK TREE DEFS ALIAS ----------------------------
|
||||
// **WARNING**: The following are only for backwards compatibility.
|
||||
|
@ -48,8 +48,9 @@
|
||||
// #define SOC_EFUSE_SUPPORTED 1 //TODO: IDF-7512
|
||||
#define SOC_RTC_FAST_MEM_SUPPORTED 1
|
||||
#define SOC_RTC_MEM_SUPPORTED 1
|
||||
// #define SOC_I2S_SUPPORTED 1 //TODO: IDF-6508
|
||||
#define SOC_RMT_SUPPORTED 1
|
||||
#define SOC_I2S_SUPPORTED 1
|
||||
// #define SOC_RMT_SUPPORTED 1 //TODO: IDF-7476
|
||||
// #define SOC_SDM_SUPPORTED 1 //TODO: IDF-7551
|
||||
// #define SOC_GPSPI_SUPPORTED 1 //TODO: IDF-7502, TODO: IDF-7503
|
||||
// #define SOC_LEDC_SUPPORTED 1 //TODO: IDF-6510
|
||||
@ -240,16 +241,20 @@
|
||||
#define SOC_I2C_SUPPORT_RTC (1)
|
||||
|
||||
/*-------------------------- I2S CAPS ----------------------------------------*/
|
||||
//TODO: IDF-6508
|
||||
#define SOC_I2S_NUM (1U)
|
||||
#define SOC_I2S_NUM (3U)
|
||||
#define SOC_I2S_HW_VERSION_2 (1)
|
||||
#define SOC_I2S_SUPPORTS_XTAL (1)
|
||||
#define SOC_I2S_SUPPORTS_PLL_F160M (1)
|
||||
#define SOC_I2S_SUPPORTS_APLL (1)
|
||||
#define SOC_I2S_SUPPORTS_PCM (1)
|
||||
// #define SOC_I2S_SUPPORTS_PDM (1)
|
||||
// #define SOC_I2S_SUPPORTS_PDM_TX (1)
|
||||
#define SOC_I2S_PDM_MAX_TX_LINES (2)
|
||||
// #define SOC_I2S_SUPPORTS_TDM (1)
|
||||
#define SOC_I2S_SUPPORTS_PDM (1)
|
||||
#define SOC_I2S_SUPPORTS_PDM_TX (1)
|
||||
#define SOC_I2S_SUPPORTS_PDM_RX (1)
|
||||
#define SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER (1)
|
||||
#define SOC_I2S_SUPPORTS_TX_SYNC_CNT (1)
|
||||
#define SOC_I2S_SUPPORTS_TDM (1)
|
||||
#define SOC_I2S_PDM_MAX_TX_LINES (2) // On I2S0
|
||||
#define SOC_I2S_PDM_MAX_RX_LINES (4) // On I2S0
|
||||
#define SOC_I2S_TDM_FULL_DATA_WIDTH (1) /*!< No limitation to data bit width when using multiple slots */
|
||||
|
||||
/*-------------------------- LEDC CAPS ---------------------------------------*/
|
||||
#define SOC_LEDC_SUPPORT_PLL_DIV_CLOCK (1)
|
||||
@ -510,6 +515,7 @@
|
||||
#define SOC_CLK_RC_FAST_SUPPORT_CALIBRATION (0)
|
||||
#define SOC_MODEM_CLOCK_IS_INDEPENDENT (0)
|
||||
|
||||
#define SOC_CLK_APLL_SUPPORTED (1) /*!< Support Audio PLL */
|
||||
#define SOC_CLK_XTAL32K_SUPPORTED (1) /*!< Support to connect an external low frequency crystal */
|
||||
#define SOC_CLK_OSC_SLOW_SUPPORTED (1) /*!< Support to connect an external oscillator, not a crystal */
|
||||
#define SOC_CLK_RC32K_SUPPORTED (1) /*!< Support an internal 32kHz RC oscillator */
|
||||
|
@ -1035,22 +1035,6 @@ config SOC_CLK_APLL_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_APLL_MULTIPLIER_OUT_MIN_HZ
|
||||
int
|
||||
default 350000000
|
||||
|
||||
config SOC_APLL_MULTIPLIER_OUT_MAX_HZ
|
||||
int
|
||||
default 500000000
|
||||
|
||||
config SOC_APLL_MIN_HZ
|
||||
int
|
||||
default 5303031
|
||||
|
||||
config SOC_APLL_MAX_HZ
|
||||
int
|
||||
default 125000000
|
||||
|
||||
config SOC_CLK_RC_FAST_D256_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
@ -446,11 +446,6 @@
|
||||
|
||||
/*-------------------------- CLOCK SUBSYSTEM CAPS ----------------------------------------*/
|
||||
#define SOC_CLK_APLL_SUPPORTED (1)
|
||||
// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)
|
||||
#define SOC_APLL_MULTIPLIER_OUT_MIN_HZ (350000000) // 350 MHz
|
||||
#define SOC_APLL_MULTIPLIER_OUT_MAX_HZ (500000000) // 500 MHz
|
||||
#define SOC_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
|
||||
#define SOC_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
|
||||
|
||||
#define SOC_CLK_RC_FAST_D256_SUPPORTED (1)
|
||||
#define SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256 (1)
|
||||
|
@ -32,7 +32,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
|
||||
.data_in_sigs[2] = I2S0I_SD2_IN_IDX,
|
||||
.data_in_sigs[3] = I2S0I_SD3_IN_IDX,
|
||||
|
||||
.irq = -1,
|
||||
.irq = ETS_I2S0_INTR_SOURCE,
|
||||
.module = PERIPH_I2S0_MODULE,
|
||||
},
|
||||
{
|
||||
@ -56,7 +56,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
|
||||
.data_in_sigs[2] = -1,
|
||||
.data_in_sigs[3] = -1,
|
||||
|
||||
.irq = -1,
|
||||
.irq = ETS_I2S1_INTR_SOURCE,
|
||||
.module = PERIPH_I2S1_MODULE,
|
||||
}
|
||||
};
|
||||
|
@ -3,7 +3,6 @@ api-guides/coexist
|
||||
api-guides/cplusplus
|
||||
api-guides/dfu
|
||||
api-guides/index
|
||||
api-reference/peripherals/i2s
|
||||
api-reference/peripherals/spi_features
|
||||
api-reference/peripherals/sdio_slave
|
||||
api-reference/peripherals/adc_calibration
|
||||
|
@ -111,7 +111,6 @@ api-reference/peripherals/gpio.rst
|
||||
api-reference/peripherals/sdspi_host.rst
|
||||
api-reference/peripherals/dac.rst
|
||||
api-reference/peripherals/spi_slave.rst
|
||||
api-reference/peripherals/i2s.rst
|
||||
api-reference/peripherals/touch_element.rst
|
||||
api-reference/peripherals/lcd.rst
|
||||
api-reference/peripherals/ana_cmpr.rst
|
||||
|
@ -116,6 +116,7 @@ ESP32-C3 I2S 0 I2S 0 none I2S 0 none none
|
||||
ESP32-C6 I2S 0 I2S 0 none I2S 0 none none
|
||||
ESP32-S3 I2S 0/1 I2S 0 I2S 0 I2S 0/1 none none
|
||||
ESP32-H2 I2S 0 I2S 0 none I2S 0 none none
|
||||
ESP32-P4 I2S 0~2 I2S 0 I2S 0 I2S 0~2 none none
|
||||
========= ======== ======== ======== ======== ======== ==========
|
||||
|
||||
Standard Mode
|
||||
|
@ -54,27 +54,49 @@ examples/peripherals/i2c/i2c_tools:
|
||||
|
||||
examples/peripherals/i2s/i2s_basic/i2s_pdm:
|
||||
disable:
|
||||
- if: SOC_I2S_SUPPORTS_PDM != 1
|
||||
- if: SOC_I2S_SUPPORTS_PDM != 1 or IDF_TARGET == "esp32p4"
|
||||
disable_test:
|
||||
- if: IDF_TARGET == "esp32p4"
|
||||
temporary: true
|
||||
reason: lack of runners
|
||||
|
||||
examples/peripherals/i2s/i2s_basic/i2s_std:
|
||||
disable:
|
||||
- if: SOC_I2S_SUPPORTED != 1
|
||||
- if: SOC_I2S_SUPPORTED != 1 or IDF_TARGET == "esp32p4"
|
||||
disable_test:
|
||||
- if: IDF_TARGET == "esp32p4"
|
||||
temporary: true
|
||||
reason: lack of runners
|
||||
|
||||
examples/peripherals/i2s/i2s_basic/i2s_tdm:
|
||||
disable:
|
||||
- if: SOC_I2S_SUPPORTS_TDM != 1
|
||||
- if: SOC_I2S_SUPPORTS_TDM != 1 or IDF_TARGET == "esp32p4"
|
||||
disable_test:
|
||||
- if: IDF_TARGET == "esp32p4"
|
||||
temporary: true
|
||||
reason: lack of runners
|
||||
|
||||
examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm:
|
||||
disable:
|
||||
- if: SOC_I2S_SUPPORTS_TDM != 1 or (SOC_I2C_SUPPORTED != 1 or SOC_GPSPI_SUPPORTED != 1)
|
||||
reason: rely on I2S TDM mode to receive audio, I2C to config es7210 and SPI to save audio to SD card
|
||||
disable_test:
|
||||
- if: IDF_TARGET == "esp32p4"
|
||||
temporary: true
|
||||
reason: lack of runners
|
||||
|
||||
examples/peripherals/i2s/i2s_codec/i2s_es8311:
|
||||
disable:
|
||||
- if: SOC_I2S_SUPPORTED != 1 or SOC_I2C_SUPPORTED != 1
|
||||
- if: (SOC_I2S_SUPPORTED != 1 or SOC_I2C_SUPPORTED != 1)
|
||||
reason: rely on I2S STD mode and I2C to config es7210
|
||||
disable_test:
|
||||
- if: IDF_TARGET == "esp32p4"
|
||||
temporary: true
|
||||
reason: lack of runners
|
||||
|
||||
examples/peripherals/i2s/i2s_recorder:
|
||||
disable:
|
||||
- if: SOC_SDMMC_HOST_SUPPORTED != 1 or IDF_TARGET == "esp32p4"
|
||||
enable:
|
||||
- if: SOC_I2S_SUPPORTS_PDM_RX > 0
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
|
||||
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# I2S ES8311 Example
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user