refactor(i2s): add hal i2s driver

This commit is contained in:
xiongyu 2019-07-15 14:44:15 +08:00
parent a74988ae3b
commit 8c76a3c10d
14 changed files with 2530 additions and 447 deletions

View file

@ -3,7 +3,7 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
@ -11,22 +11,19 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include <stdbool.h>
#include <math.h>
#include <esp_types.h>
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/xtensa_api.h"
#include "soc/i2s_periph.h"
#include "soc/rtc_periph.h"
#include "soc/rtc.h"
#include "soc/efuse_periph.h"
#include "esp32/rom/lldesc.h"
#include "esp32/rom/lldesc.h"
#include "driver/gpio.h"
#include "driver/i2s.h"
#include "driver/rtc_io.h"
#include "driver/dac.h"
#include "adc1_i2s_private.h"
@ -34,8 +31,6 @@
#include "esp_err.h"
#include "esp_log.h"
#include "esp_pm.h"
#include "sdkconfig.h"
static const char* I2S_TAG = "I2S";
@ -43,19 +38,14 @@ static const char* I2S_TAG = "I2S";
ESP_LOGE(I2S_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
return (ret); \
}
#define I2S_MAX_BUFFER_SIZE (4 * 1024 * 1024) //the maximum RAM can be allocated
#define I2S_BASE_CLK (2*APB_CLK_FREQ)
#define I2S_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&i2s_spinlock[i2s_num])
#define I2S_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&i2s_spinlock[i2s_num])
#define I2S_ENTER_CRITICAL() portENTER_CRITICAL(&i2s_spinlock[i2s_num])
#define I2S_EXIT_CRITICAL() portEXIT_CRITICAL(&i2s_spinlock[i2s_num])
#define I2S_FULL_DUPLEX_SLAVE_MODE_MASK (I2S_MODE_TX | I2S_MODE_RX | I2S_MODE_SLAVE)
#define I2S_FULL_DUPLEX_MASTER_MODE_MASK (I2S_MODE_TX | I2S_MODE_RX | I2S_MODE_MASTER)
#define APLL_MIN_FREQ (250000000)
#define APLL_MAX_FREQ (500000000)
#define APLL_I2S_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware
#define I2S_AD_BCK_FACTOR (2)
#define I2S_PDM_BCK_FACTOR (64)
/**
* @brief DMA buffer object
*
@ -95,29 +85,23 @@ typedef struct {
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_handle_t pm_lock;
#endif
i2s_hal_context_t hal; /*!< I2S hal context*/
} i2s_obj_t;
static i2s_obj_t *p_i2s_obj[I2S_NUM_MAX] = {0};
#ifdef CONFIG_IDF_TARGET_ESP32
static i2s_dev_t* I2S[I2S_NUM_MAX] = {&I2S0, &I2S1};
static portMUX_TYPE i2s_spinlock[I2S_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED,portMUX_INITIALIZER_UNLOCKED};
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
static i2s_dev_t* I2S[I2S_NUM_MAX] = {&I2S0};
static portMUX_TYPE i2s_spinlock[I2S_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED};
#endif
static portMUX_TYPE i2s_spinlock[I2S_NUM_MAX];
static int _i2s_adc_unit = -1;
static int _i2s_adc_channel = -1;
static i2s_dma_t *i2s_create_dma_queue(i2s_port_t i2s_num, int dma_buf_count, int dma_buf_len);
static esp_err_t i2s_destroy_dma_queue(i2s_port_t i2s_num, i2s_dma_t *dma);
static esp_err_t i2s_reset_fifo(i2s_port_t i2s_num)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
I2S_ENTER_CRITICAL();
I2S[i2s_num]->conf.rx_fifo_reset = 1;
I2S[i2s_num]->conf.rx_fifo_reset = 0;
I2S[i2s_num]->conf.tx_fifo_reset = 1;
I2S[i2s_num]->conf.tx_fifo_reset = 0;
i2s_hal_reset_fifo(&(p_i2s_obj[i2s_num]->hal));
I2S_EXIT_CRITICAL();
return ESP_OK;
}
@ -131,6 +115,7 @@ inline static void gpio_matrix_out_check(uint32_t gpio, uint32_t signal_idx, boo
gpio_matrix_out(gpio, signal_idx, out_inv, oen_inv);
}
}
inline static void gpio_matrix_in_check(uint32_t gpio, uint32_t signal_idx, bool inv)
{
if (gpio != -1) {
@ -141,11 +126,10 @@ inline static void gpio_matrix_in_check(uint32_t gpio, uint32_t signal_idx, bool
}
}
esp_err_t i2s_clear_intr_status(i2s_port_t i2s_num, uint32_t clr_mask)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
I2S[i2s_num]->int_clr.val = clr_mask;
i2s_hal_clear_intr_status(&(p_i2s_obj[i2s_num]->hal), clr_mask);
return ESP_OK;
}
@ -153,8 +137,7 @@ esp_err_t i2s_enable_rx_intr(i2s_port_t i2s_num)
{
I2S_ENTER_CRITICAL();
I2S[i2s_num]->int_ena.in_suc_eof = 1;
I2S[i2s_num]->int_ena.in_dscr_err = 1;
i2s_hal_enable_rx_intr(&(p_i2s_obj[i2s_num]->hal));
I2S_EXIT_CRITICAL();
return ESP_OK;
}
@ -162,8 +145,7 @@ esp_err_t i2s_enable_rx_intr(i2s_port_t i2s_num)
esp_err_t i2s_disable_rx_intr(i2s_port_t i2s_num)
{
I2S_ENTER_CRITICAL();
I2S[i2s_num]->int_ena.in_suc_eof = 0;
I2S[i2s_num]->int_ena.in_dscr_err = 0;
i2s_hal_disable_rx_intr(&(p_i2s_obj[i2s_num]->hal));
I2S_EXIT_CRITICAL();
return ESP_OK;
}
@ -171,8 +153,7 @@ esp_err_t i2s_disable_rx_intr(i2s_port_t i2s_num)
esp_err_t i2s_disable_tx_intr(i2s_port_t i2s_num)
{
I2S_ENTER_CRITICAL();
I2S[i2s_num]->int_ena.out_eof = 0;
I2S[i2s_num]->int_ena.out_dscr_err = 0;
i2s_hal_disable_tx_intr(&(p_i2s_obj[i2s_num]->hal));
I2S_EXIT_CRITICAL();
return ESP_OK;
}
@ -180,8 +161,7 @@ esp_err_t i2s_disable_tx_intr(i2s_port_t i2s_num)
esp_err_t i2s_enable_tx_intr(i2s_port_t i2s_num)
{
I2S_ENTER_CRITICAL();
I2S[i2s_num]->int_ena.out_eof = 1;
I2S[i2s_num]->int_ena.out_dscr_err = 1;
i2s_hal_enable_tx_intr(&(p_i2s_obj[i2s_num]->hal));
I2S_EXIT_CRITICAL();
return ESP_OK;
}
@ -197,20 +177,15 @@ static esp_err_t i2s_isr_register(i2s_port_t i2s_num, int intr_alloc_flags, void
return esp_intr_alloc(i2s_periph_signal[i2s_num].irq, intr_alloc_flags, fn, arg, handle);
}
static float i2s_apll_get_fi2s(int bits_per_sample, int sdm0, int sdm1, int sdm2, int odir)
{
int f_xtal = (int)rtc_clk_xtal_freq_get() * 1000000;
#ifdef CONFIG_IDF_TARGET_ESP32
uint32_t is_rev0 = (GET_PERI_REG_BITS2(EFUSE_BLK0_RDATA3_REG, 1, 15) == 0);
if (is_rev0) {
uint32_t rev;
i2s_hal_get_rev(&(p_i2s_obj[0]->hal), &rev); // I2S hardware instance address will not be used
if (rev) {
sdm0 = 0;
sdm1 = 0;
}
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
sdm0 = 0;
sdm1 = 0;
#endif
float fout = f_xtal * (sdm2 + sdm1 / 256.0f + sdm0 / 65536.0f + 4);
if (fout < APLL_MIN_FREQ || fout > APLL_MAX_FREQ) {
return APLL_MAX_FREQ;
@ -320,6 +295,7 @@ static esp_err_t i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm
return ESP_OK;
}
esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t bits, i2s_channel_t ch)
{
int factor = (256%bits)? 384 : 256; // According to hardware codec requirement(supported 256fs or 384fs)
@ -357,29 +333,13 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
i2s_stop(i2s_num);
uint32_t cur_mode = 0;
i2s_hal_set_tx_mode(&(p_i2s_obj[i2s_num]->hal), ch, bits);
i2s_hal_set_rx_mode(&(p_i2s_obj[i2s_num]->hal), ch, bits);
if (p_i2s_obj[i2s_num]->channel_num != ch) {
p_i2s_obj[i2s_num]->channel_num = (ch == 2) ? 2 : 1;
cur_mode = I2S[i2s_num]->fifo_conf.tx_fifo_mod;
I2S[i2s_num]->fifo_conf.tx_fifo_mod = (ch == 2) ? cur_mode - 1 : cur_mode + 1;
cur_mode = I2S[i2s_num]->fifo_conf.rx_fifo_mod;
I2S[i2s_num]->fifo_conf.rx_fifo_mod = (ch == 2) ? cur_mode -1 : cur_mode + 1;
I2S[i2s_num]->conf_chan.tx_chan_mod = (ch == 2) ? 0 : 1;
I2S[i2s_num]->conf_chan.rx_chan_mod = (ch == 2) ? 0 : 1;
}
if (bits != p_i2s_obj[i2s_num]->bits_per_sample) {
//change fifo mode
if (p_i2s_obj[i2s_num]->bits_per_sample <= 16 && bits > 16) {
I2S[i2s_num]->fifo_conf.tx_fifo_mod += 2;
I2S[i2s_num]->fifo_conf.rx_fifo_mod += 2;
} else if (p_i2s_obj[i2s_num]->bits_per_sample > 16 && bits <= 16) {
I2S[i2s_num]->fifo_conf.tx_fifo_mod -= 2;
I2S[i2s_num]->fifo_conf.rx_fifo_mod -= 2;
}
p_i2s_obj[i2s_num]->bits_per_sample = bits;
p_i2s_obj[i2s_num]->bytes_per_sample = p_i2s_obj[i2s_num]->bits_per_sample / 8;
@ -402,7 +362,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
i2s_driver_uninstall(i2s_num);
return ESP_ERR_NO_MEM;
}
I2S[i2s_num]->out_link.addr = (uint32_t) p_i2s_obj[i2s_num]->tx->desc[0];
i2s_hal_set_out_link_addr(&(p_i2s_obj[i2s_num]->hal), (uint32_t) p_i2s_obj[i2s_num]->tx->desc[0]);
//destroy old tx dma if exist
if (save_tx) {
@ -420,15 +380,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
i2s_driver_uninstall(i2s_num);
return ESP_ERR_NO_MEM;
}
#ifdef CONFIG_IDF_TARGET_ESP32
//On ESP32S2, the eof_num count in words.
I2S[i2s_num]->rx_eof_num = (p_i2s_obj[i2s_num]->dma_buf_len * p_i2s_obj[i2s_num]->channel_num * p_i2s_obj[i2s_num]->bytes_per_sample)/4;
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
//On ESP32S2, the eof_num count in bytes.
I2S[i2s_num]->rx_eof_num = (p_i2s_obj[i2s_num]->dma_buf_len * p_i2s_obj[i2s_num]->channel_num * p_i2s_obj[i2s_num]->bytes_per_sample);
#endif
I2S[i2s_num]->in_link.addr = (uint32_t) p_i2s_obj[i2s_num]->rx->desc[0];
i2s_hal_set_in_link(&(p_i2s_obj[i2s_num]->hal), p_i2s_obj[i2s_num]->dma_buf_len * p_i2s_obj[i2s_num]->channel_num * p_i2s_obj[i2s_num]->bytes_per_sample, (uint32_t) p_i2s_obj[i2s_num]->rx->desc[0]);
//destroy old rx dma if exist
if (save_rx) {
i2s_destroy_dma_queue(i2s_num, save_rx);
@ -456,13 +408,16 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
} else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_PDM) {
uint32_t b_clk = 0;
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) {
int fp = I2S[i2s_num]->pdm_freq_conf.tx_pdm_fp;
int fs = I2S[i2s_num]->pdm_freq_conf.tx_pdm_fs;
int fp;
int fs;
i2s_hal_get_tx_pdm(&(p_i2s_obj[i2s_num]->hal), &fp, &fs);
b_clk = rate * I2S_PDM_BCK_FACTOR * (fp / fs);
fi2s_clk /= (I2S_PDM_BCK_FACTOR * (fp / fs));
} else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) {
b_clk = rate * I2S_PDM_BCK_FACTOR * (I2S[i2s_num]->pdm_conf.rx_sinc_dsr_16_en + 1);
fi2s_clk /= (I2S_PDM_BCK_FACTOR * (I2S[i2s_num]->pdm_conf.rx_sinc_dsr_16_en + 1));
bool en;
i2s_hal_get_rx_sinc_dsr_16_en(&(p_i2s_obj[i2s_num]->hal), &en);
b_clk = rate * I2S_PDM_BCK_FACTOR * (en ? 2 : 1);
fi2s_clk /= (I2S_PDM_BCK_FACTOR * (en ? 2 : 1));
}
int factor2 = 5 ;
mclk = b_clk * factor2;
@ -485,39 +440,23 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
if(p_i2s_obj[i2s_num]->use_apll && i2s_apll_calculate_fi2s(fi2s_clk, bits, &sdm0, &sdm1, &sdm2, &odir) == ESP_OK) {
ESP_LOGD(I2S_TAG, "sdm0=%d, sdm1=%d, sdm2=%d, odir=%d", sdm0, sdm1, sdm2, odir);
rtc_clk_apll_enable(1, sdm0, sdm1, sdm2, odir);
I2S[i2s_num]->clkm_conf.clkm_div_num = 1;
I2S[i2s_num]->clkm_conf.clkm_div_b = 0;
I2S[i2s_num]->clkm_conf.clkm_div_a = 1;
I2S[i2s_num]->sample_rate_conf.tx_bck_div_num = m_scale;
I2S[i2s_num]->sample_rate_conf.rx_bck_div_num = m_scale;
#ifdef CONFIG_IDF_TARGET_ESP32
I2S[i2s_num]->clkm_conf.clka_en = 1;
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
I2S[i2s_num]->clkm_conf.clk_sel = 1;
#endif
i2s_hal_set_clk_div(&(p_i2s_obj[i2s_num]->hal), 1, 1, 0, m_scale, m_scale);
i2s_hal_set_clock_sel(&(p_i2s_obj[i2s_num]->hal), I2S_CLK_APLL);
double fi2s_rate = i2s_apll_get_fi2s(bits, sdm0, sdm1, sdm2, odir);
p_i2s_obj[i2s_num]->real_rate = fi2s_rate/bits/channel/m_scale;
ESP_LOGI(I2S_TAG, "APLL: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK_M: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d",
rate, fi2s_rate/bits/channel/m_scale, bits, 1, m_scale, fi2s_rate, fi2s_rate/8, 1, 0);
} else {
#ifdef CONFIG_IDF_TARGET_ESP32
I2S[i2s_num]->clkm_conf.clka_en = 0;
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
I2S[i2s_num]->clkm_conf.clk_sel = 2;
#endif
I2S[i2s_num]->clkm_conf.clkm_div_a = 63;
I2S[i2s_num]->clkm_conf.clkm_div_b = clkmDecimals;
I2S[i2s_num]->clkm_conf.clkm_div_num = clkmInteger;
I2S[i2s_num]->sample_rate_conf.tx_bck_div_num = bck;
I2S[i2s_num]->sample_rate_conf.rx_bck_div_num = bck;
i2s_hal_set_clock_sel(&(p_i2s_obj[i2s_num]->hal), I2S_CLK_D2CLK);
i2s_hal_set_clk_div(&(p_i2s_obj[i2s_num]->hal), clkmInteger, 63, clkmDecimals, bck, bck);
double real_rate = (double) (I2S_BASE_CLK / (bck * bits * clkmInteger) / 2);
p_i2s_obj[i2s_num]->real_rate = real_rate;
ESP_LOGI(I2S_TAG, "PLL_D2: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d",
rate, real_rate, bits, clkmInteger, bck, (double)I2S_BASE_CLK / mclk, real_rate*bits*channel, 64, clkmDecimals);
}
I2S[i2s_num]->sample_rate_conf.tx_bits_mod = bits;
I2S[i2s_num]->sample_rate_conf.rx_bits_mod = bits;
i2s_hal_set_tx_bits_mod(&(p_i2s_obj[i2s_num]->hal), bits);
i2s_hal_set_rx_bits_mod(&(p_i2s_obj[i2s_num]->hal), bits);
// wait all writing on-going finish
if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) && p_i2s_obj[i2s_num]->tx) {
@ -533,15 +472,13 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
static void IRAM_ATTR i2s_intr_handler_default(void *arg)
{
i2s_obj_t *p_i2s = (i2s_obj_t*) arg;
uint8_t i2s_num = p_i2s->i2s_num;
i2s_dev_t* i2s_reg = I2S[i2s_num];
typeof(i2s_reg->int_st) int_st_val = i2s_reg->int_st;
if(int_st_val.val == 0) {
uint32_t status;
i2s_hal_get_intr_status(&(p_i2s->hal), &status);
if(status == 0) {
//Avoid spurious interrupt
return;
}
i2s_event_t i2s_event;
int dummy;
@ -549,8 +486,8 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg)
lldesc_t *finish_desc;
if (int_st_val.out_dscr_err || int_st_val.in_dscr_err) {
ESP_EARLY_LOGE(I2S_TAG, "dma error, interrupt status: 0x%08x", int_st_val.val);
if ((status & I2S_INTR_OUT_DSCR_ERR) || (status & I2S_INTR_IN_DSCR_ERR)) {
ESP_EARLY_LOGE(I2S_TAG, "dma error, interrupt status: 0x%08x", status);
if (p_i2s->i2s_queue) {
i2s_event.type = I2S_EVENT_DMA_ERROR;
if (xQueueIsQueueFullFromISR(p_i2s->i2s_queue)) {
@ -560,8 +497,8 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg)
}
}
if (int_st_val.out_eof && p_i2s->tx) {
finish_desc = (lldesc_t*) i2s_reg->out_eof_des_addr;
if ((status & I2S_INTR_OUT_EOF) && p_i2s->tx) {
i2s_hal_get_out_eof_des_addr(&(p_i2s->hal), (uint32_t *)&finish_desc);
// All buffers are empty. This means we have an underflow on our hands.
if (xQueueIsQueueFullFromISR(p_i2s->tx->queue)) {
xQueueReceiveFromISR(p_i2s->tx->queue, &dummy, &high_priority_task_awoken);
@ -582,9 +519,9 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg)
}
}
if (int_st_val.in_suc_eof && p_i2s->rx) {
if ((status & I2S_INTR_IN_SUC_EOF) && p_i2s->rx) {
// All buffers are full. This means we have an overflow.
finish_desc = (lldesc_t*) i2s_reg->in_eof_des_addr;
i2s_hal_get_in_eof_des_addr(&(p_i2s->hal), (uint32_t *)&finish_desc);
if (xQueueIsQueueFullFromISR(p_i2s->rx->queue)) {
xQueueReceiveFromISR(p_i2s->rx->queue, &dummy, &high_priority_task_awoken);
}
@ -597,7 +534,7 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg)
xQueueSendFromISR(p_i2s->i2s_queue, (void * )&i2s_event, &high_priority_task_awoken);
}
}
i2s_reg->int_clr.val = int_st_val.val;
i2s_hal_clear_intr_status(&(p_i2s->hal), status);
if (high_priority_task_awoken == pdTRUE) {
portYIELD_FROM_ISR();
@ -698,35 +635,24 @@ static i2s_dma_t *i2s_create_dma_queue(i2s_port_t i2s_num, int dma_buf_count, in
return dma;
}
esp_err_t i2s_start(i2s_port_t i2s_num)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
//start DMA link
I2S_ENTER_CRITICAL();
i2s_reset_fifo(i2s_num);
//reset dma
I2S[i2s_num]->lc_conf.in_rst = 1;
I2S[i2s_num]->lc_conf.in_rst = 0;
I2S[i2s_num]->lc_conf.out_rst = 1;
I2S[i2s_num]->lc_conf.out_rst = 0;
I2S[i2s_num]->conf.tx_reset = 1;
I2S[i2s_num]->conf.tx_reset = 0;
I2S[i2s_num]->conf.rx_reset = 1;
I2S[i2s_num]->conf.rx_reset = 0;
i2s_hal_reset(&(p_i2s_obj[i2s_num]->hal));
esp_intr_disable(p_i2s_obj[i2s_num]->i2s_isr_handle);
I2S[i2s_num]->int_clr.val = 0xFFFFFFFF;
i2s_hal_clear_intr_status(&(p_i2s_obj[i2s_num]->hal), I2S_INTR_MAX);
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) {
i2s_enable_tx_intr(i2s_num);
I2S[i2s_num]->out_link.start = 1;
I2S[i2s_num]->conf.tx_start = 1;
i2s_hal_start_tx(&(p_i2s_obj[i2s_num]->hal));
}
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) {
i2s_enable_rx_intr(i2s_num);
I2S[i2s_num]->in_link.start = 1;
I2S[i2s_num]->conf.rx_start = 1;
i2s_hal_start_rx(&(p_i2s_obj[i2s_num]->hal));
}
esp_intr_enable(p_i2s_obj[i2s_num]->i2s_isr_handle);
I2S_EXIT_CRITICAL();
@ -739,16 +665,16 @@ esp_err_t i2s_stop(i2s_port_t i2s_num)
I2S_ENTER_CRITICAL();
esp_intr_disable(p_i2s_obj[i2s_num]->i2s_isr_handle);
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) {
I2S[i2s_num]->out_link.stop = 1;
I2S[i2s_num]->conf.tx_start = 0;
i2s_hal_stop_tx(&(p_i2s_obj[i2s_num]->hal));
i2s_disable_tx_intr(i2s_num);
}
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) {
I2S[i2s_num]->in_link.stop = 1;
I2S[i2s_num]->conf.rx_start = 0;
i2s_hal_stop_rx(&(p_i2s_obj[i2s_num]->hal));
i2s_disable_rx_intr(i2s_num);
}
I2S[i2s_num]->int_clr.val = I2S[i2s_num]->int_st.val; //clear pending interrupt
uint32_t mask;
i2s_hal_get_intr_status(&(p_i2s_obj[i2s_num]->hal), &mask);
i2s_hal_clear_intr_status(&(p_i2s_obj[i2s_num]->hal), mask);
I2S_EXIT_CRITICAL();
return ESP_OK;
}
@ -875,7 +801,7 @@ esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate)
esp_err_t i2s_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t dsr)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
I2S[i2s_num]->pdm_conf.rx_sinc_dsr_16_en = dsr;
i2s_hal_set_pdm_rx_down_sample(&(p_i2s_obj[i2s_num]->hal), dsr);
return i2s_set_clk(i2s_num, p_i2s_obj[i2s_num]->sample_rate, p_i2s_obj[i2s_num]->bits_per_sample, p_i2s_obj[i2s_num]->channel_num);
}
#endif
@ -900,137 +826,13 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co
}
// configure I2S data port interface.
i2s_reset_fifo(i2s_num);
//reset i2s
I2S[i2s_num]->conf.tx_reset = 1;
I2S[i2s_num]->conf.tx_reset = 0;
I2S[i2s_num]->conf.rx_reset = 1;
I2S[i2s_num]->conf.rx_reset = 0;
//reset dma
I2S[i2s_num]->lc_conf.in_rst = 1;
I2S[i2s_num]->lc_conf.in_rst = 0;
I2S[i2s_num]->lc_conf.out_rst = 1;
I2S[i2s_num]->lc_conf.out_rst = 0;
//Enable and configure DMA
I2S[i2s_num]->lc_conf.check_owner = 0;
I2S[i2s_num]->lc_conf.out_loop_test = 0;
I2S[i2s_num]->lc_conf.out_auto_wrback = 0;
I2S[i2s_num]->lc_conf.out_data_burst_en = 0;
I2S[i2s_num]->lc_conf.outdscr_burst_en = 0;
I2S[i2s_num]->lc_conf.out_no_restart_clr = 0;
I2S[i2s_num]->lc_conf.indscr_burst_en = 0;
I2S[i2s_num]->lc_conf.out_eof_mode = 1;
I2S[i2s_num]->conf2.lcd_en = 0;
I2S[i2s_num]->conf2.camera_en = 0;
I2S[i2s_num]->pdm_conf.pcm2pdm_conv_en = 0;
I2S[i2s_num]->pdm_conf.pdm2pcm_conv_en = 0;
I2S[i2s_num]->fifo_conf.dscr_en = 0;
I2S[i2s_num]->conf_chan.tx_chan_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? i2s_config->channel_format : (i2s_config->channel_format >> 1); // 0-two channel;1-right;2-left;3-righ;4-left
I2S[i2s_num]->fifo_conf.tx_fifo_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1; // 0-right&left channel;1-one channel
I2S[i2s_num]->conf.tx_mono = 0;
I2S[i2s_num]->conf_chan.rx_chan_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? i2s_config->channel_format : (i2s_config->channel_format >> 1); // 0-two channel;1-right;2-left;3-righ;4-left
I2S[i2s_num]->fifo_conf.rx_fifo_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1; // 0-right&left channel;1-one channel
I2S[i2s_num]->conf.rx_mono = 0;
I2S[i2s_num]->fifo_conf.dscr_en = 1;//connect dma to fifo
I2S[i2s_num]->conf.tx_start = 0;
I2S[i2s_num]->conf.rx_start = 0;
if (i2s_config->mode & I2S_MODE_TX) {
I2S[i2s_num]->conf.tx_msb_right = 1;
I2S[i2s_num]->conf.tx_right_first = 0;
I2S[i2s_num]->conf.tx_slave_mod = 0; // Master
I2S[i2s_num]->fifo_conf.tx_fifo_mod_force_en = 1;
if (i2s_config->mode & I2S_MODE_SLAVE) {
I2S[i2s_num]->conf.tx_slave_mod = 1;//TX Slave
}
}
if (i2s_config->mode & I2S_MODE_RX) {
I2S[i2s_num]->conf.rx_msb_right = 1;
I2S[i2s_num]->conf.rx_right_first = 0;
I2S[i2s_num]->conf.rx_slave_mod = 0; // Master
I2S[i2s_num]->fifo_conf.rx_fifo_mod_force_en = 1;
if (i2s_config->mode & I2S_MODE_SLAVE) {
I2S[i2s_num]->conf.rx_slave_mod = 1;//RX Slave
}
}
if (i2s_config->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) {
I2S[i2s_num]->conf2.lcd_en = 1;
I2S[i2s_num]->conf.tx_right_first = 1;
I2S[i2s_num]->conf2.camera_en = 0;
}
#if SOC_I2S_SUPPORT_PDM
if (i2s_config->mode & I2S_MODE_PDM) {
I2S[i2s_num]->fifo_conf.rx_fifo_mod_force_en = 1;
I2S[i2s_num]->fifo_conf.tx_fifo_mod_force_en = 1;
I2S[i2s_num]->pdm_freq_conf.tx_pdm_fp = 960;
I2S[i2s_num]->pdm_freq_conf.tx_pdm_fs = i2s_config->sample_rate / 1000 * 10;
I2S[i2s_num]->pdm_conf.tx_sinc_osr2 = I2S[i2s_num]->pdm_freq_conf.tx_pdm_fp / I2S[i2s_num]->pdm_freq_conf.tx_pdm_fs;
I2S[i2s_num]->pdm_conf.rx_sinc_dsr_16_en = 0;
I2S[i2s_num]->pdm_conf.rx_pdm_en = 1;
I2S[i2s_num]->pdm_conf.tx_pdm_en = 1;
I2S[i2s_num]->pdm_conf.pcm2pdm_conv_en = 1;
I2S[i2s_num]->pdm_conf.pdm2pcm_conv_en = 1;
} else {
I2S[i2s_num]->pdm_conf.rx_pdm_en = 0;
I2S[i2s_num]->pdm_conf.tx_pdm_en = 0;
}
#else
I2S[i2s_num]->pdm_conf.rx_pdm_en = 0;
I2S[i2s_num]->pdm_conf.tx_pdm_en = 0;
#endif
if (i2s_config->communication_format & I2S_COMM_FORMAT_I2S) {
I2S[i2s_num]->conf.tx_short_sync = 0;
I2S[i2s_num]->conf.rx_short_sync = 0;
I2S[i2s_num]->conf.tx_msb_shift = 1;
I2S[i2s_num]->conf.rx_msb_shift = 1;
if (i2s_config->communication_format & I2S_COMM_FORMAT_I2S_LSB) {
if (i2s_config->mode & I2S_MODE_TX) {
I2S[i2s_num]->conf.tx_msb_shift = 0;
}
if (i2s_config->mode & I2S_MODE_RX) {
I2S[i2s_num]->conf.rx_msb_shift = 0;
}
}
}
if (i2s_config->communication_format & I2S_COMM_FORMAT_PCM) {
I2S[i2s_num]->conf.tx_msb_shift = 0;
I2S[i2s_num]->conf.rx_msb_shift = 0;
I2S[i2s_num]->conf.tx_short_sync = 0;
I2S[i2s_num]->conf.rx_short_sync = 0;
if (i2s_config->communication_format & I2S_COMM_FORMAT_PCM_SHORT) {
if (i2s_config->mode & I2S_MODE_TX) {
I2S[i2s_num]->conf.tx_short_sync = 1;
}
if (i2s_config->mode & I2S_MODE_RX) {
I2S[i2s_num]->conf.rx_short_sync = 1;
}
}
}
i2s_hal_config_param(&(p_i2s_obj[i2s_num]->hal), i2s_config);
if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) && (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX)) {
I2S[i2s_num]->conf.sig_loopback = 1;
i2s_hal_enable_sig_loopback(&(p_i2s_obj[i2s_num]->hal));
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) {
I2S[i2s_num]->conf.tx_slave_mod = 0; //MASTER Slave
I2S[i2s_num]->conf.rx_slave_mod = 1; //RX Slave
i2s_hal_enable_master_mode(&(p_i2s_obj[i2s_num]->hal));
} else {
I2S[i2s_num]->conf.tx_slave_mod = 1; //RX Slave
I2S[i2s_num]->conf.rx_slave_mod = 1; //RX Slave
i2s_hal_enable_slave_mode(&(p_i2s_obj[i2s_num]->hal));
}
}
@ -1077,6 +879,14 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config,
}
memset(p_i2s_obj[i2s_num], 0, sizeof(i2s_obj_t));
portMUX_TYPE i2s_spinlock_unlocked[1] = {portMUX_INITIALIZER_UNLOCKED};
for (int x = 0; x < I2S_NUM_MAX; x++) {
i2s_spinlock[x] = i2s_spinlock_unlocked[0];
}
//To make sure hardware is enabled before any hardware register operations.
periph_module_enable(i2s_periph_signal[i2s_num].module);
i2s_hal_init(&(p_i2s_obj[i2s_num]->hal), i2s_num);
p_i2s_obj[i2s_num]->i2s_num = i2s_num;
p_i2s_obj[i2s_num]->dma_buf_count = i2s_config->dma_buf_count;
p_i2s_obj[i2s_num]->dma_buf_len = i2s_config->dma_buf_len;
@ -1101,9 +911,6 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config,
}
#endif //CONFIG_PM_ENABLE
//To make sure hardware is enabled before any hardware register operations.
periph_module_enable(i2s_periph_signal[i2s_num].module);
//initial interrupt
err = i2s_isr_register(i2s_num, i2s_config->intr_alloc_flags, i2s_intr_handler_default, p_i2s_obj[i2s_num], &p_i2s_obj[i2s_num]->i2s_isr_handle);
if (err != ESP_OK) {
@ -1342,4 +1149,4 @@ esp_err_t i2s_read(i2s_port_t i2s_num, void *dest, size_t size, size_t *bytes_re
#endif
xSemaphoreGive(p_i2s_obj[i2s_num]->rx->mux);
return ESP_OK;
}
}

View file

@ -12,14 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _DRIVER_I2S_H_
#define _DRIVER_I2S_H_
#pragma once
#include "esp_err.h"
#include <esp_types.h>
#include "soc/soc.h"
#include "soc/gpio_periph.h"
#include "soc/i2s_periph.h"
#include "soc/rtc_periph.h"
#include "soc/i2s_caps.h"
#include "esp32/rom/gpio.h"
#include "esp_attr.h"
#include "esp_intr_alloc.h"
@ -27,183 +28,15 @@
#include "driver/adc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "hal/i2s_hal.h"
#include "hal/i2s_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief I2S bit width per sample.
*
*/
typedef enum {
I2S_BITS_PER_SAMPLE_8BIT = 8, /*!< I2S bits per sample: 8-bits*/
I2S_BITS_PER_SAMPLE_16BIT = 16, /*!< I2S bits per sample: 16-bits*/
I2S_BITS_PER_SAMPLE_24BIT = 24, /*!< I2S bits per sample: 24-bits*/
I2S_BITS_PER_SAMPLE_32BIT = 32, /*!< I2S bits per sample: 32-bits*/
} i2s_bits_per_sample_t;
/**
* @brief I2S channel.
*
*/
typedef enum {
I2S_CHANNEL_MONO = 1, /*!< I2S 1 channel (mono)*/
I2S_CHANNEL_STEREO = 2 /*!< I2S 2 channel (stereo)*/
} i2s_channel_t;
/**
* @brief I2S communication standard format
*
*/
typedef enum {
I2S_COMM_FORMAT_I2S = 0x01, /*!< I2S communication format I2S*/
I2S_COMM_FORMAT_I2S_MSB = 0x02, /*!< I2S format MSB*/
I2S_COMM_FORMAT_I2S_LSB = 0x04, /*!< I2S format LSB*/
I2S_COMM_FORMAT_PCM = 0x08, /*!< I2S communication format PCM*/
I2S_COMM_FORMAT_PCM_SHORT = 0x10, /*!< PCM Short*/
I2S_COMM_FORMAT_PCM_LONG = 0x20, /*!< PCM Long*/
} i2s_comm_format_t;
/**
* @brief I2S channel format type
*/
typedef enum {
I2S_CHANNEL_FMT_RIGHT_LEFT = 0x00,
I2S_CHANNEL_FMT_ALL_RIGHT,
I2S_CHANNEL_FMT_ALL_LEFT,
I2S_CHANNEL_FMT_ONLY_RIGHT,
I2S_CHANNEL_FMT_ONLY_LEFT,
} i2s_channel_fmt_t;
/**
* @brief PDM sample rate ratio, measured in Hz.
*
*/
typedef enum {
PDM_SAMPLE_RATE_RATIO_64,
PDM_SAMPLE_RATE_RATIO_128,
} pdm_sample_rate_ratio_t;
/**
* @brief PDM PCM convter enable/disable.
*
*/
typedef enum {
PDM_PCM_CONV_ENABLE,
PDM_PCM_CONV_DISABLE,
} pdm_pcm_conv_t;
/**
* @brief I2S Peripheral, 0 & 1.
*
*/
typedef enum {
I2S_NUM_0 = 0x0, /*!< I2S 0*/
#if SOC_I2S_PERIPH_NUM > 1
I2S_NUM_1, /*!< I2S 1*/
#endif
I2S_NUM_MAX,
} i2s_port_t;
/**
* @brief I2S Mode, defaut is I2S_MODE_MASTER | I2S_MODE_TX
*
* @note PDM and built-in DAC functions are only supported on I2S0 for current ESP32 chip.
*
*/
typedef enum {
I2S_MODE_MASTER = 1,
I2S_MODE_SLAVE = 2,
I2S_MODE_TX = 4,
I2S_MODE_RX = 8,
I2S_MODE_DAC_BUILT_IN = 16, /*!< Output I2S data to built-in DAC, no matter the data format is 16bit or 32 bit, the DAC module will only take the 8bits from MSB*/
I2S_MODE_ADC_BUILT_IN = 32, /*!< Input I2S data from built-in ADC, each data can be 12-bit width at most*/
#if SOC_I2S_SUPPORT_PDM
I2S_MODE_PDM = 64,
#endif
} i2s_mode_t;
/**
* @brief I2S configuration parameters for i2s_param_config function
*
*/
typedef struct {
i2s_mode_t mode; /*!< I2S work mode*/
int sample_rate; /*!< I2S sample rate*/
i2s_bits_per_sample_t bits_per_sample; /*!< I2S bits per sample*/
i2s_channel_fmt_t channel_format; /*!< I2S channel format */
i2s_comm_format_t communication_format; /*!< I2S communication format */
int intr_alloc_flags; /*!< Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info */
int dma_buf_count; /*!< I2S DMA Buffer Count */
int dma_buf_len; /*!< I2S DMA Buffer Length */
bool use_apll; /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */
bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor if there is underflow condition (helps in avoiding noise in case of data unavailability) */
int fixed_mclk; /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0, then the clock output for i2s is fixed and equal to the fixed_mclk value.*/
} i2s_config_t;
/**
* @brief I2S event types
*
*/
typedef enum {
I2S_EVENT_DMA_ERROR,
I2S_EVENT_TX_DONE, /*!< I2S DMA finish sent 1 buffer*/
I2S_EVENT_RX_DONE, /*!< I2S DMA finish received 1 buffer*/
I2S_EVENT_MAX, /*!< I2S event max index*/
} i2s_event_type_t;
/**
* @brief I2S DAC mode for i2s_set_dac_mode.
*
* @note PDM and built-in DAC functions are only supported on I2S0 for current ESP32 chip.
*/
typedef enum {
I2S_DAC_CHANNEL_DISABLE = 0, /*!< Disable I2S built-in DAC signals*/
I2S_DAC_CHANNEL_RIGHT_EN = 1, /*!< Enable I2S built-in DAC right channel, maps to DAC channel 1 on GPIO25*/
I2S_DAC_CHANNEL_LEFT_EN = 2, /*!< Enable I2S built-in DAC left channel, maps to DAC channel 2 on GPIO26*/
I2S_DAC_CHANNEL_BOTH_EN = 0x3, /*!< Enable both of the I2S built-in DAC channels.*/
I2S_DAC_CHANNEL_MAX = 0x4, /*!< I2S built-in DAC mode max index*/
} i2s_dac_mode_t;
/**
* @brief Event structure used in I2S event queue
*
*/
typedef struct {
i2s_event_type_t type; /*!< I2S event type */
size_t size; /*!< I2S data size for I2S_DATA event*/
} i2s_event_t;
#define I2S_PIN_NO_CHANGE (-1) /*!< Use in i2s_pin_config_t for pins which should not be changed */
/**
* @brief I2S pin number for i2s_set_pin
*
*/
typedef struct {
int bck_io_num; /*!< BCK in out pin*/
int ws_io_num; /*!< WS in out pin*/
int data_out_num; /*!< DATA out pin*/
int data_in_num; /*!< DATA in pin*/
} i2s_pin_config_t;
#if SOC_I2S_SUPPORT_PDM
/**
* @brief I2S PDM RX downsample mode
*/
typedef enum {
I2S_PDM_DSR_8S = 0, /*!< downsampling number is 8 for PDM RX mode*/
I2S_PDM_DSR_16S, /*!< downsampling number is 16 for PDM RX mode*/
I2S_PDM_DSR_MAX,
} i2s_pdm_dsr_t;
#endif
typedef intr_handle_t i2s_isr_handle_t;
/**
* @brief Set I2S pin number
*
@ -498,5 +331,3 @@ esp_err_t i2s_adc_disable(i2s_port_t i2s_num);
#ifdef __cplusplus
}
#endif
#endif /* _DRIVER_I2S_H_ */

View file

@ -18,6 +18,7 @@ list(APPEND srcs
"src/hal/spi_slave_hal_iram.c"
"src/soc_include_legacy_warn.c"
"src/hal/pcnt_hal.c"
"src/hal/i2s_hal.c"
)
# TODO: SPI Flash HAL for ESP32S2Beta also

View file

@ -18,7 +18,7 @@
/*
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_PERIPH_NUM] = {
const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
{
.o_bck_in_sig = I2S0O_BCK_IN_IDX,
.o_ws_in_sig = I2S0O_WS_IN_IDX,

View file

@ -0,0 +1,837 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in soc/include/hal/readme.md
******************************************************************************/
// The LL layer for ESP32 I2S register operations
#pragma once
#include <stdbool.h>
#include "soc/rtc_periph.h"
#include "soc/rtc.h"
#include "soc/efuse_periph.h"
#include "soc/i2s_periph.h"
#include "hal/i2s_types.h"
#ifdef __cplusplus
extern "C" {
#endif
// Get I2S hardware instance with giving i2s num
#define I2S_LL_GET_HW(num) (((num) == 0) ? (&I2S0) : (((num) == 1) ? (&I2S1) : NULL))
#define I2S_INTR_IN_SUC_EOF BIT(9)
#define I2S_INTR_OUT_EOF BIT(12)
#define I2S_INTR_IN_DSCR_ERR BIT(13)
#define I2S_INTR_OUT_DSCR_ERR BIT(14)
#define I2S_INTR_MAX (0xFFFFFFFF)
/**
* @brief Reset rx fifo
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw)
{
hw->conf.rx_fifo_reset = 1;
hw->conf.rx_fifo_reset = 0;
}
/**
* @brief Reset tx fifo
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw)
{
hw->conf.tx_fifo_reset = 1;
hw->conf.tx_fifo_reset = 0;
}
/**
* @brief Enable rx interrupt
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_enable_rx_intr(i2s_dev_t *hw)
{
hw->int_ena.in_suc_eof = 1;
hw->int_ena.in_dscr_err = 1;
}
/**
* @brief Disable rx interrupt
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_disable_rx_intr(i2s_dev_t *hw)
{
hw->int_ena.in_suc_eof = 0;
hw->int_ena.in_dscr_err = 0;
}
/**
* @brief Disable tx interrupt
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw)
{
hw->int_ena.out_eof = 0;
hw->int_ena.out_dscr_err = 0;
}
/**
* @brief Enable tx interrupt
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_enable_tx_intr(i2s_dev_t *hw)
{
hw->int_ena.out_eof = 1;
hw->int_ena.out_dscr_err = 1;
}
/**
* @brief Reset dma in
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_reset_dma_in(i2s_dev_t *hw)
{
hw->lc_conf.in_rst = 1;
hw->lc_conf.in_rst = 0;
}
/**
* @brief Reset dma out
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_reset_dma_out(i2s_dev_t *hw)
{
hw->lc_conf.out_rst = 1;
hw->lc_conf.out_rst = 0;
}
/**
* @brief Reset tx
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_reset_tx(i2s_dev_t *hw)
{
hw->conf.tx_reset = 1;
hw->conf.tx_reset = 0;
}
/**
* @brief Reset rx
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_reset_rx(i2s_dev_t *hw)
{
hw->conf.rx_reset = 1;
hw->conf.rx_reset = 0;
}
/**
* @brief Start out link
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_start_out_link(i2s_dev_t *hw)
{
hw->out_link.start = 1;
}
/**
* @brief Start tx
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_start_tx(i2s_dev_t *hw)
{
hw->conf.tx_start = 1;
}
/**
* @brief Start in link
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_start_in_link(i2s_dev_t *hw)
{
hw->in_link.start = 1;
}
/**
* @brief Start rx
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_start_rx(i2s_dev_t *hw)
{
hw->conf.rx_start = 1;
}
/**
* @brief Stop out link
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_stop_out_link(i2s_dev_t *hw)
{
hw->out_link.stop = 1;
}
/**
* @brief Stop tx
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_stop_tx(i2s_dev_t *hw)
{
hw->conf.tx_start = 0;
}
/**
* @brief Stop in link
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_stop_in_link(i2s_dev_t *hw)
{
hw->in_link.stop = 1;
}
/**
* @brief Stop rx
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_stop_rx(i2s_dev_t *hw)
{
hw->conf.rx_start = 0;
}
/**
* @brief Enable dma
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_enable_dma(i2s_dev_t *hw)
{
//Enable and configure DMA
typeof(hw->lc_conf) lc_conf;
lc_conf.val = 0;
lc_conf.out_eof_mode = 1;
hw->lc_conf.val = lc_conf.val;
}
/**
* @brief Get I2S revision
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get revision
*/
static inline void i2s_ll_get_rev(i2s_dev_t *hw, uint32_t *val)
{
if (GET_PERI_REG_BITS2(EFUSE_BLK0_RDATA3_REG, 1, 15) == 0) {
*val = 1;
}
}
/**
* @brief Get I2S interrupt status
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get interrupt status
*/
static inline void i2s_ll_get_intr_status(i2s_dev_t *hw, uint32_t *val)
{
*val = hw->int_st.val;
}
/**
* @brief Clear I2S interrupt status
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to clear interrupt status
*/
static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t val)
{
hw->int_clr.val = val;
}
/**
* @brief Get I2S out eof des address
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get out eof des address
*/
static inline void i2s_ll_get_out_eof_des_addr(i2s_dev_t *hw, uint32_t *val)
{
*val = hw->out_eof_des_addr;
}
/**
* @brief Get I2S in eof des address
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get in eof des address
*/
static inline void i2s_ll_get_in_eof_des_addr(i2s_dev_t *hw, uint32_t *val)
{
*val = hw->in_eof_des_addr;
}
/**
* @brief Get I2S tx fifo mode
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get tx fifo mode
*/
static inline void i2s_ll_get_tx_fifo_mod(i2s_dev_t *hw, uint32_t *val)
{
*val = hw->fifo_conf.tx_fifo_mod;
}
/**
* @brief Set I2S tx fifo mode
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx fifo mode
*/
static inline void i2s_ll_set_tx_fifo_mod(i2s_dev_t *hw, uint32_t val)
{
hw->fifo_conf.tx_fifo_mod = val;
}
/**
* @brief Get I2S rx fifo mode
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get rx fifo mode
*/
static inline void i2s_ll_get_rx_fifo_mod(i2s_dev_t *hw, uint32_t *val)
{
*val = hw->fifo_conf.rx_fifo_mod;
}
/**
* @brief Set I2S rx fifo mode
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx fifo mode
*/
static inline void i2s_ll_set_rx_fifo_mod(i2s_dev_t *hw, uint32_t val)
{
hw->fifo_conf.rx_fifo_mod = val;
}
/**
* @brief Set I2S tx chan mode
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx chan mode
*/
static inline void i2s_ll_set_tx_chan_mod(i2s_dev_t *hw, uint32_t val)
{
hw->conf_chan.tx_chan_mod = val;
}
/**
* @brief Set I2S rx chan mode
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx chan mode
*/
static inline void i2s_ll_set_rx_chan_mod(i2s_dev_t *hw, uint32_t val)
{
hw->conf_chan.rx_chan_mod = val;
}
/**
* @brief Set I2S out link address
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set out link address
*/
static inline void i2s_ll_set_out_link_addr(i2s_dev_t *hw, uint32_t val)
{
hw->out_link.addr = val;
}
/**
* @brief Set I2S in link address
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set in link address
*/
static inline void i2s_ll_set_in_link_addr(i2s_dev_t *hw, uint32_t val)
{
hw->in_link.addr = val;
}
/**
* @brief Set I2S rx eof num
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx eof num
*/
static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, uint32_t val)
{
// On ESP32, the eof_num count in words.
hw->rx_eof_num = val / 4;
}
/**
* @brief Get I2S tx pdm fp
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get tx pdm fp
*/
static inline void i2s_ll_get_tx_pdm_fp(i2s_dev_t *hw, uint32_t *val)
{
*val = hw->pdm_freq_conf.tx_pdm_fp;
}
/**
* @brief Get I2S tx pdm fs
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get tx pdm fs
*/
static inline void i2s_ll_get_tx_pdm_fs(i2s_dev_t *hw, uint32_t *val)
{
*val = hw->pdm_freq_conf.tx_pdm_fs;
}
/**
* @brief Set I2S tx pdm fp
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx pdm fp
*/
static inline void i2s_ll_set_tx_pdm_fp(i2s_dev_t *hw, uint32_t val)
{
hw->pdm_freq_conf.tx_pdm_fp = val;
}
/**
* @brief Set I2S tx pdm fs
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx pdm fs
*/
static inline void i2s_ll_set_tx_pdm_fs(i2s_dev_t *hw, uint32_t val)
{
hw->pdm_freq_conf.tx_pdm_fs = val;
}
/**
* @brief Get I2S rx sinc dsr 16 en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get rx sinc dsr 16 en
*/
static inline void i2s_ll_get_rx_sinc_dsr_16_en(i2s_dev_t *hw, bool *val)
{
*val = hw->pdm_conf.rx_sinc_dsr_16_en;
}
/**
* @brief Set I2S clkm div num
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set clkm div num
*/
static inline void i2s_ll_set_clkm_div_num(i2s_dev_t *hw, uint32_t val)
{
hw->clkm_conf.clkm_div_num = val;
}
/**
* @brief Set I2S clkm div b
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set clkm div b
*/
static inline void i2s_ll_set_clkm_div_b(i2s_dev_t *hw, uint32_t val)
{
hw->clkm_conf.clkm_div_b = val;
}
/**
* @brief Set I2S clkm div a
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set clkm div a
*/
static inline void i2s_ll_set_clkm_div_a(i2s_dev_t *hw, uint32_t val)
{
hw->clkm_conf.clkm_div_a = val;
}
/**
* @brief Set I2S tx bck div num
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx bck div num
*/
static inline void i2s_ll_set_tx_bck_div_num(i2s_dev_t *hw, uint32_t val)
{
hw->sample_rate_conf.tx_bck_div_num = val;
}
/**
* @brief Set I2S rx bck div num
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx bck div num
*/
static inline void i2s_ll_set_rx_bck_div_num(i2s_dev_t *hw, uint32_t val)
{
hw->sample_rate_conf.rx_bck_div_num = val;
}
/**
* @brief Set I2S clk sel
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set clk sel
*/
static inline void i2s_ll_set_clk_sel(i2s_dev_t *hw, uint32_t val)
{
hw->clkm_conf.clka_en = (val == 1) ? 1 : 0;
}
/**
* @brief Set I2S tx bits mod
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx bits mod
*/
static inline void i2s_ll_set_tx_bits_mod(i2s_dev_t *hw, uint32_t val)
{
hw->sample_rate_conf.tx_bits_mod = val;
}
/**
* @brief Set I2S rx bits mod
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx bits mod
*/
static inline void i2s_ll_set_rx_bits_mod(i2s_dev_t *hw, uint32_t val)
{
hw->sample_rate_conf.rx_bits_mod = val;
}
/**
* @brief Set I2S rx sinc dsr 16 en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx sinc dsr 16 en
*/
static inline void i2s_ll_set_rx_sinc_dsr_16_en(i2s_dev_t *hw, bool val)
{
hw->pdm_conf.rx_sinc_dsr_16_en = val;
}
/**
* @brief Set I2S dscr en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set dscr en
*/
static inline void i2s_ll_set_dscr_en(i2s_dev_t *hw, bool val)
{
hw->fifo_conf.dscr_en = val;
}
/**
* @brief Set I2S lcd en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set lcd en
*/
static inline void i2s_ll_set_lcd_en(i2s_dev_t *hw, bool val)
{
hw->conf2.lcd_en = val;
}
/**
* @brief Set I2S camera en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set camera en
*/
static inline void i2s_ll_set_camera_en(i2s_dev_t *hw, bool val)
{
hw->conf2.camera_en = val;
}
/**
* @brief Set I2S pcm2pdm conv en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set pcm2pdm conv en
*/
static inline void i2s_ll_set_pcm2pdm_conv_en(i2s_dev_t *hw, bool val)
{
hw->pdm_conf.pcm2pdm_conv_en = val;
}
/**
* @brief Set I2S pdm2pcm conv en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set pdm2pcm conv en
*/
static inline void i2s_ll_set_pdm2pcm_conv_en(i2s_dev_t *hw, bool val)
{
hw->pdm_conf.pdm2pcm_conv_en = val;
}
/**
* @brief Set I2S rx pdm en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx pdm en
*/
static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool val)
{
hw->pdm_conf.rx_pdm_en = val;
}
/**
* @brief Set I2S tx pdm en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx pdm en
*/
static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool val)
{
hw->pdm_conf.tx_pdm_en = val;
}
/**
* @brief Set I2S tx msb shift
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx msb shift
*/
static inline void i2s_ll_set_tx_msb_shift(i2s_dev_t *hw, uint32_t val)
{
hw->conf.tx_msb_shift = val;
}
/**
* @brief Set I2S rx msb shift
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx msb shift
*/
static inline void i2s_ll_set_rx_msb_shift(i2s_dev_t *hw, uint32_t val)
{
hw->conf.rx_msb_shift = val;
}
/**
* @brief Set I2S tx short sync
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx short sync
*/
static inline void i2s_ll_set_tx_short_sync(i2s_dev_t *hw, uint32_t val)
{
hw->conf.tx_short_sync = val;
}
/**
* @brief Set I2S rx short sync
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx short sync
*/
static inline void i2s_ll_set_rx_short_sync(i2s_dev_t *hw, uint32_t val)
{
hw->conf.rx_short_sync = val;
}
/**
* @brief Set I2S tx fifo mod force en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx fifo mod force en
*/
static inline void i2s_ll_set_tx_fifo_mod_force_en(i2s_dev_t *hw, bool val)
{
hw->fifo_conf.tx_fifo_mod_force_en = val;
}
/**
* @brief Set I2S rx fifo mod force en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx fifo mod force en
*/
static inline void i2s_ll_set_rx_fifo_mod_force_en(i2s_dev_t *hw, bool val)
{
hw->fifo_conf.rx_fifo_mod_force_en = val;
}
/**
* @brief Set I2S tx right first
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx right first
*/
static inline void i2s_ll_set_tx_right_first(i2s_dev_t *hw, uint32_t val)
{
hw->conf.tx_right_first = val;
}
/**
* @brief Set I2S rx right first
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx right first
*/
static inline void i2s_ll_set_rx_right_first(i2s_dev_t *hw, uint32_t val)
{
hw->conf.rx_right_first = val;
}
/**
* @brief Set I2S tx slave mod
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx slave mod
*/
static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, uint32_t val)
{
hw->conf.tx_slave_mod = val;
}
/**
* @brief Set I2S rx slave mod
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx slave mod
*/
static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, uint32_t val)
{
hw->conf.rx_slave_mod = val;
}
/**
* @brief Get I2S tx msb right
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get tx msb right
*/
static inline void i2s_ll_get_tx_msb_right(i2s_dev_t *hw, uint32_t *val)
{
*val = hw->conf.tx_msb_right;
}
/**
* @brief Get I2S rx msb right
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get rx msb right
*/
static inline void i2s_ll_get_rx_msb_right(i2s_dev_t *hw, uint32_t *val)
{
*val = hw->conf.rx_msb_right;
}
/**
* @brief Set I2S tx msb right
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx msb right
*/
static inline void i2s_ll_set_tx_msb_right(i2s_dev_t *hw, uint32_t val)
{
hw->conf.tx_msb_right = val;
}
/**
* @brief Set I2S rx msb right
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx msb right
*/
static inline void i2s_ll_set_rx_msb_right(i2s_dev_t *hw, uint32_t val)
{
hw->conf.rx_msb_right = val;
}
/**
* @brief Set I2S tx mono
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx mono
*/
static inline void i2s_ll_set_tx_mono(i2s_dev_t *hw, uint32_t val)
{
hw->conf.tx_mono = val;
}
/**
* @brief Set I2S rx mono
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx mono
*/
static inline void i2s_ll_set_rx_mono(i2s_dev_t *hw, uint32_t val)
{
hw->conf.rx_mono = val;
}
/**
* @brief Set I2S tx sinc osr2
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx sinc osr2
*/
static inline void i2s_ll_set_tx_sinc_osr2(i2s_dev_t *hw, uint32_t val)
{
hw->pdm_conf.tx_sinc_osr2 = val;
}
/**
* @brief Set I2S sig loopback
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set sig loopback
*/
static inline void i2s_ll_set_sig_loopback(i2s_dev_t *hw, uint32_t val)
{
hw->conf.sig_loopback = val;
}
#ifdef __cplusplus
}
#endif

View file

@ -3,7 +3,6 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
@ -14,5 +13,26 @@
#pragma once
#define SOC_I2S_PERIPH_NUM (2) //ESP32 have 2 I2S
#ifdef __cplusplus
extern "C" {
#endif
#define APLL_MIN_FREQ (250000000)
#define APLL_MAX_FREQ (500000000)
#define APLL_I2S_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware
#define I2S_AD_BCK_FACTOR (2)
#define I2S_PDM_BCK_FACTOR (64)
#define I2S_MAX_BUFFER_SIZE (4 * 1024 * 1024) //the maximum RAM can be allocated
#define I2S_BASE_CLK (2*APB_CLK_FREQ)
// ESP32 have 2 I2S
#define I2S_NUM_0 (0) /*!< I2S port 0 */
#define I2S_NUM_1 (1) /*!< I2S port 0 */
#define I2S_NUM_MAX (2) /*!< I2S port max */
#define SOC_I2S_NUM (I2S_NUM_MAX)
#define SOC_I2S_SUPPORT_PDM (1) //ESP32 support PDM
#ifdef __cplusplus
}
#endif

View file

@ -18,7 +18,7 @@
/*
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_PERIPH_NUM] = {
const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
{
.o_bck_in_sig = I2S0O_BCK_IN_IDX,
.o_ws_in_sig = I2S0O_WS_IN_IDX,

View file

@ -0,0 +1,831 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in soc/include/hal/readme.md
******************************************************************************/
// The LL layer for ESP32-S2 I2S register operations
#pragma once
#include <stdbool.h>
#include "soc/i2s_periph.h"
#include "hal/i2s_types.h"
#ifdef __cplusplus
extern "C" {
#endif
// Get I2S hardware instance with giving i2s num
#define I2S_LL_GET_HW(num) (((num) == 0) ? (&I2S0) : NULL)
#define I2S_INTR_IN_SUC_EOF BIT(9)
#define I2S_INTR_OUT_EOF BIT(12)
#define I2S_INTR_IN_DSCR_ERR BIT(13)
#define I2S_INTR_OUT_DSCR_ERR BIT(14)
#define I2S_INTR_MAX (0xFFFFFFFF)
/**
* @brief Reset rx fifo
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw)
{
hw->conf.rx_fifo_reset = 1;
hw->conf.rx_fifo_reset = 0;
}
/**
* @brief Reset tx fifo
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw)
{
hw->conf.tx_fifo_reset = 1;
hw->conf.tx_fifo_reset = 0;
}
/**
* @brief Enable rx interrupt
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_enable_rx_intr(i2s_dev_t *hw)
{
hw->int_ena.in_suc_eof = 1;
hw->int_ena.in_dscr_err = 1;
}
/**
* @brief Disable rx interrupt
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_disable_rx_intr(i2s_dev_t *hw)
{
hw->int_ena.in_suc_eof = 0;
hw->int_ena.in_dscr_err = 0;
}
/**
* @brief Disable tx interrupt
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw)
{
hw->int_ena.out_eof = 0;
hw->int_ena.out_dscr_err = 0;
}
/**
* @brief Enable tx interrupt
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_enable_tx_intr(i2s_dev_t *hw)
{
hw->int_ena.out_eof = 1;
hw->int_ena.out_dscr_err = 1;
}
/**
* @brief Reset dma in
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_reset_dma_in(i2s_dev_t *hw)
{
hw->lc_conf.in_rst = 1;
hw->lc_conf.in_rst = 0;
}
/**
* @brief Reset dma out
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_reset_dma_out(i2s_dev_t *hw)
{
hw->lc_conf.out_rst = 1;
hw->lc_conf.out_rst = 0;
}
/**
* @brief Reset tx
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_reset_tx(i2s_dev_t *hw)
{
hw->conf.tx_reset = 1;
hw->conf.tx_reset = 0;
}
/**
* @brief Reset rx
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_reset_rx(i2s_dev_t *hw)
{
hw->conf.rx_reset = 1;
hw->conf.rx_reset = 0;
}
/**
* @brief Start out link
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_start_out_link(i2s_dev_t *hw)
{
hw->out_link.start = 1;
}
/**
* @brief Start tx
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_start_tx(i2s_dev_t *hw)
{
hw->conf.tx_start = 1;
}
/**
* @brief Start in link
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_start_in_link(i2s_dev_t *hw)
{
hw->in_link.start = 1;
}
/**
* @brief Start rx
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_start_rx(i2s_dev_t *hw)
{
hw->conf.rx_start = 1;
}
/**
* @brief Stop out link
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_stop_out_link(i2s_dev_t *hw)
{
hw->out_link.stop = 1;
}
/**
* @brief Stop tx
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_stop_tx(i2s_dev_t *hw)
{
hw->conf.tx_start = 0;
}
/**
* @brief Stop in link
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_stop_in_link(i2s_dev_t *hw)
{
hw->in_link.stop = 1;
}
/**
* @brief Stop rx
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_stop_rx(i2s_dev_t *hw)
{
hw->conf.rx_start = 0;
}
/**
* @brief Enable dma
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_enable_dma(i2s_dev_t *hw)
{
//Enable and configure DMA
typeof(hw->lc_conf) lc_conf;
lc_conf.val = 0;
lc_conf.out_eof_mode = 1;
hw->lc_conf.val = lc_conf.val;
}
/**
* @brief Get I2S revision
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get revision
*/
static inline void i2s_ll_get_rev(i2s_dev_t *hw, uint32_t *val)
{
*val = 1;
}
/**
* @brief Get I2S interrupt status
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get interrupt status
*/
static inline void i2s_ll_get_intr_status(i2s_dev_t *hw, uint32_t *val)
{
*val = hw->int_st.val;
}
/**
* @brief Clear I2S interrupt status
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to clear interrupt status
*/
static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t val)
{
hw->int_clr.val = val;
}
/**
* @brief Get I2S out eof des address
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get out eof des address
*/
static inline void i2s_ll_get_out_eof_des_addr(i2s_dev_t *hw, uint32_t *val)
{
*val = hw->out_eof_des_addr;
}
/**
* @brief Get I2S in eof des address
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get in eof des address
*/
static inline void i2s_ll_get_in_eof_des_addr(i2s_dev_t *hw, uint32_t *val)
{
*val = hw->in_eof_des_addr;
}
/**
* @brief Get I2S tx fifo mode
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get tx fifo mode
*/
static inline void i2s_ll_get_tx_fifo_mod(i2s_dev_t *hw, uint32_t *val)
{
*val = hw->fifo_conf.tx_fifo_mod;
}
/**
* @brief Set I2S tx fifo mode
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx fifo mode
*/
static inline void i2s_ll_set_tx_fifo_mod(i2s_dev_t *hw, uint32_t val)
{
hw->fifo_conf.tx_fifo_mod = val;
}
/**
* @brief Get I2S rx fifo mode
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get rx fifo mode
*/
static inline void i2s_ll_get_rx_fifo_mod(i2s_dev_t *hw, uint32_t *val)
{
*val = hw->fifo_conf.rx_fifo_mod;
}
/**
* @brief Set I2S rx fifo mode
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx fifo mode
*/
static inline void i2s_ll_set_rx_fifo_mod(i2s_dev_t *hw, uint32_t val)
{
hw->fifo_conf.rx_fifo_mod = val;
}
/**
* @brief Set I2S tx chan mode
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx chan mode
*/
static inline void i2s_ll_set_tx_chan_mod(i2s_dev_t *hw, uint32_t val)
{
hw->conf_chan.tx_chan_mod = val;
}
/**
* @brief Set I2S rx chan mode
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx chan mode
*/
static inline void i2s_ll_set_rx_chan_mod(i2s_dev_t *hw, uint32_t val)
{
hw->conf_chan.rx_chan_mod = val;
}
/**
* @brief Set I2S out link address
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set out link address
*/
static inline void i2s_ll_set_out_link_addr(i2s_dev_t *hw, uint32_t val)
{
hw->out_link.addr = val;
}
/**
* @brief Set I2S in link address
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set in link address
*/
static inline void i2s_ll_set_in_link_addr(i2s_dev_t *hw, uint32_t val)
{
hw->in_link.addr = val;
}
/**
* @brief Set I2S rx eof num
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx eof num
*/
static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, uint32_t val)
{
hw->rx_eof_num = val;
}
/**
* @brief Get I2S tx pdm fp
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get tx pdm fp
*/
static inline void i2s_ll_get_tx_pdm_fp(i2s_dev_t *hw, uint32_t *val)
{
*val = hw->pdm_freq_conf.tx_pdm_fp;
}
/**
* @brief Get I2S tx pdm fs
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get tx pdm fs
*/
static inline void i2s_ll_get_tx_pdm_fs(i2s_dev_t *hw, uint32_t *val)
{
*val = hw->pdm_freq_conf.tx_pdm_fs;
}
/**
* @brief Set I2S tx pdm fp
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx pdm fp
*/
static inline void i2s_ll_set_tx_pdm_fp(i2s_dev_t *hw, uint32_t val)
{
hw->pdm_freq_conf.tx_pdm_fp = val;
}
/**
* @brief Set I2S tx pdm fs
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx pdm fs
*/
static inline void i2s_ll_set_tx_pdm_fs(i2s_dev_t *hw, uint32_t val)
{
hw->pdm_freq_conf.tx_pdm_fs = val;
}
/**
* @brief Get I2S rx sinc dsr 16 en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get rx sinc dsr 16 en
*/
static inline void i2s_ll_get_rx_sinc_dsr_16_en(i2s_dev_t *hw, bool *val)
{
*val = hw->pdm_conf.rx_sinc_dsr_16_en;
}
/**
* @brief Set I2S clkm div num
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set clkm div num
*/
static inline void i2s_ll_set_clkm_div_num(i2s_dev_t *hw, uint32_t val)
{
hw->clkm_conf.clkm_div_num = val;
}
/**
* @brief Set I2S clkm div b
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set clkm div b
*/
static inline void i2s_ll_set_clkm_div_b(i2s_dev_t *hw, uint32_t val)
{
hw->clkm_conf.clkm_div_b = val;
}
/**
* @brief Set I2S clkm div a
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set clkm div a
*/
static inline void i2s_ll_set_clkm_div_a(i2s_dev_t *hw, uint32_t val)
{
hw->clkm_conf.clkm_div_a = val;
}
/**
* @brief Set I2S tx bck div num
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx bck div num
*/
static inline void i2s_ll_set_tx_bck_div_num(i2s_dev_t *hw, uint32_t val)
{
hw->sample_rate_conf.tx_bck_div_num = val;
}
/**
* @brief Set I2S rx bck div num
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx bck div num
*/
static inline void i2s_ll_set_rx_bck_div_num(i2s_dev_t *hw, uint32_t val)
{
hw->sample_rate_conf.rx_bck_div_num = val;
}
/**
* @brief Set I2S clk sel
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set clk sel
*/
static inline void i2s_ll_set_clk_sel(i2s_dev_t *hw, uint32_t val)
{
hw->clkm_conf.clk_sel = (val == 1) ? 1 : 2;
}
/**
* @brief Set I2S tx bits mod
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx bits mod
*/
static inline void i2s_ll_set_tx_bits_mod(i2s_dev_t *hw, uint32_t val)
{
hw->sample_rate_conf.tx_bits_mod = val;
}
/**
* @brief Set I2S rx bits mod
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx bits mod
*/
static inline void i2s_ll_set_rx_bits_mod(i2s_dev_t *hw, uint32_t val)
{
hw->sample_rate_conf.rx_bits_mod = val;
}
/**
* @brief Set I2S rx sinc dsr 16 en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx sinc dsr 16 en
*/
static inline void i2s_ll_set_rx_sinc_dsr_16_en(i2s_dev_t *hw, bool val)
{
hw->pdm_conf.rx_sinc_dsr_16_en = val;
}
/**
* @brief Set I2S dscr en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set dscr en
*/
static inline void i2s_ll_set_dscr_en(i2s_dev_t *hw, bool val)
{
hw->fifo_conf.dscr_en = val;
}
/**
* @brief Set I2S lcd en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set lcd en
*/
static inline void i2s_ll_set_lcd_en(i2s_dev_t *hw, bool val)
{
hw->conf2.lcd_en = val;
}
/**
* @brief Set I2S camera en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set camera en
*/
static inline void i2s_ll_set_camera_en(i2s_dev_t *hw, bool val)
{
hw->conf2.camera_en = val;
}
/**
* @brief Set I2S pcm2pdm conv en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set pcm2pdm conv en
*/
static inline void i2s_ll_set_pcm2pdm_conv_en(i2s_dev_t *hw, bool val)
{
hw->pdm_conf.pcm2pdm_conv_en = val;
}
/**
* @brief Set I2S pdm2pcm conv en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set pdm2pcm conv en
*/
static inline void i2s_ll_set_pdm2pcm_conv_en(i2s_dev_t *hw, bool val)
{
hw->pdm_conf.pdm2pcm_conv_en = val;
}
/**
* @brief Set I2S rx pdm en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx pdm en
*/
static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool val)
{
hw->pdm_conf.rx_pdm_en = val;
}
/**
* @brief Set I2S tx pdm en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx pdm en
*/
static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool val)
{
hw->pdm_conf.tx_pdm_en = val;
}
/**
* @brief Set I2S tx msb shift
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx msb shift
*/
static inline void i2s_ll_set_tx_msb_shift(i2s_dev_t *hw, uint32_t val)
{
hw->conf.tx_msb_shift = val;
}
/**
* @brief Set I2S rx msb shift
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx msb shift
*/
static inline void i2s_ll_set_rx_msb_shift(i2s_dev_t *hw, uint32_t val)
{
hw->conf.rx_msb_shift = val;
}
/**
* @brief Set I2S tx short sync
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx short sync
*/
static inline void i2s_ll_set_tx_short_sync(i2s_dev_t *hw, uint32_t val)
{
hw->conf.tx_short_sync = val;
}
/**
* @brief Set I2S rx short sync
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx short sync
*/
static inline void i2s_ll_set_rx_short_sync(i2s_dev_t *hw, uint32_t val)
{
hw->conf.rx_short_sync = val;
}
/**
* @brief Set I2S tx fifo mod force en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx fifo mod force en
*/
static inline void i2s_ll_set_tx_fifo_mod_force_en(i2s_dev_t *hw, bool val)
{
hw->fifo_conf.tx_fifo_mod_force_en = val;
}
/**
* @brief Set I2S rx fifo mod force en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx fifo mod force en
*/
static inline void i2s_ll_set_rx_fifo_mod_force_en(i2s_dev_t *hw, bool val)
{
hw->fifo_conf.rx_fifo_mod_force_en = val;
}
/**
* @brief Set I2S tx right first
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx right first
*/
static inline void i2s_ll_set_tx_right_first(i2s_dev_t *hw, uint32_t val)
{
hw->conf.tx_right_first = val;
}
/**
* @brief Set I2S rx right first
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx right first
*/
static inline void i2s_ll_set_rx_right_first(i2s_dev_t *hw, uint32_t val)
{
hw->conf.rx_right_first = val;
}
/**
* @brief Set I2S tx slave mod
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx slave mod
*/
static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, uint32_t val)
{
hw->conf.tx_slave_mod = val;
}
/**
* @brief Set I2S rx slave mod
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx slave mod
*/
static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, uint32_t val)
{
hw->conf.rx_slave_mod = val;
}
/**
* @brief Get I2S tx msb right
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get tx msb right
*/
static inline void i2s_ll_get_tx_msb_right(i2s_dev_t *hw, uint32_t *val)
{
*val = hw->conf.tx_msb_right;
}
/**
* @brief Get I2S rx msb right
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get rx msb right
*/
static inline void i2s_ll_get_rx_msb_right(i2s_dev_t *hw, uint32_t *val)
{
*val = hw->conf.rx_msb_right;
}
/**
* @brief Set I2S tx msb right
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx msb right
*/
static inline void i2s_ll_set_tx_msb_right(i2s_dev_t *hw, uint32_t val)
{
hw->conf.tx_msb_right = val;
}
/**
* @brief Set I2S rx msb right
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx msb right
*/
static inline void i2s_ll_set_rx_msb_right(i2s_dev_t *hw, uint32_t val)
{
hw->conf.rx_msb_right = val;
}
/**
* @brief Set I2S tx mono
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx mono
*/
static inline void i2s_ll_set_tx_mono(i2s_dev_t *hw, uint32_t val)
{
hw->conf.tx_mono = val;
}
/**
* @brief Set I2S rx mono
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx mono
*/
static inline void i2s_ll_set_rx_mono(i2s_dev_t *hw, uint32_t val)
{
hw->conf.rx_mono = val;
}
/**
* @brief Set I2S tx sinc osr2
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx sinc osr2
*/
static inline void i2s_ll_set_tx_sinc_osr2(i2s_dev_t *hw, uint32_t val)
{
hw->pdm_conf.tx_sinc_osr2 = val;
}
/**
* @brief Set I2S sig loopback
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set sig loopback
*/
static inline void i2s_ll_set_sig_loopback(i2s_dev_t *hw, uint32_t val)
{
hw->conf.sig_loopback = val;
}
#ifdef __cplusplus
}
#endif

View file

@ -14,5 +14,17 @@
#pragma once
#define SOC_I2S_PERIPH_NUM (1) //ESP32-S2 have 1 I2S
#define SOC_I2S_SUPPORT_PDM (0) //ESP32-S2 do not support PDM
#define APLL_MIN_FREQ (250000000)
#define APLL_MAX_FREQ (500000000)
#define APLL_I2S_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware
#define I2S_AD_BCK_FACTOR (2)
#define I2S_PDM_BCK_FACTOR (64)
#define I2S_MAX_BUFFER_SIZE (4 * 1024 * 1024) //the maximum RAM can be allocated
#define I2S_BASE_CLK (2*APB_CLK_FREQ)
// ESP32-S2 have 2 I2S
#define I2S_NUM_0 (0) /*!< I2S port 0 */
#define I2S_NUM_MAX (1) /*!< I2S port max */
#define SOC_I2S_NUM (I2S_NUM_MAX)
#define SOC_I2S_SUPPORT_PDM (0) // ESP32-S2 do not support PDM

View file

@ -0,0 +1,304 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in soc/include/hal/readme.md
******************************************************************************/
// The HAL layer for I2S.
// There is no parameter check in the hal layer, so the caller must ensure the correctness of the parameters.
#pragma once
#include "soc/i2s_periph.h"
#include "soc/i2s_caps.h"
#include "hal/i2s_ll.h"
#include "hal/i2s_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Context that should be maintained by both the driver and the HAL
*/
typedef struct {
i2s_dev_t *dev;
uint32_t version;
} i2s_hal_context_t;
/**
* @brief Reset I2S fifo
*
* @param hal Context of the HAL layer
*/
void i2s_hal_reset_fifo(i2s_hal_context_t *hal);
/**
* @brief Get I2S revision
*
* @param hal Context of the HAL layer
* @param rev I2S revision
*/
#define i2s_hal_get_rev(hal, rev) i2s_ll_get_rev((hal)->dev, rev)
/**
* @brief Get I2S interrupt status
*
* @param hal Context of the HAL layer
* @param status interrupt status
*/
#define i2s_hal_get_intr_status(hal, status) i2s_ll_get_intr_status((hal)->dev, status)
/**
* @brief Clear I2S interrupt status
*
* @param hal Context of the HAL layer
* @param mask interrupt status mask
*/
#define i2s_hal_clear_intr_status(hal, mask) i2s_ll_clear_intr_status((hal)->dev, mask)
/**
* @brief Get I2S out eof des address
*
* @param hal Context of the HAL layer
* @param addr out eof des address
*/
#define i2s_hal_get_out_eof_des_addr(hal, addr) i2s_ll_get_out_eof_des_addr((hal)->dev, addr)
/**
* @brief Get I2S in eof des address
*
* @param hal Context of the HAL layer
* @param addr in eof des address
*/
#define i2s_hal_get_in_eof_des_addr(hal, addr) i2s_ll_get_in_eof_des_addr((hal)->dev, addr)
/**
* @brief Enable I2S rx interrupt
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_enable_rx_intr(hal) i2s_ll_enable_rx_intr((hal)->dev)
/**
* @brief Disable I2S rx interrupt
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_disable_rx_intr(hal) i2s_ll_disable_rx_intr((hal)->dev)
/**
* @brief Disable I2S tx interrupt
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_disable_tx_intr(hal) i2s_ll_disable_tx_intr((hal)->dev)
/**
* @brief Enable I2S tx interrupt
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_enable_tx_intr(hal) i2s_ll_enable_tx_intr((hal)->dev)
/**
* @brief Set I2S tx mode
*
* @param hal Context of the HAL layer
* @param ch i2s channel
* @param bits bits per sample
*/
void i2s_hal_set_tx_mode(i2s_hal_context_t *hal, i2s_channel_t ch, i2s_bits_per_sample_t bits);
/**
* @brief Set I2S rx mode
*
* @param hal Context of the HAL layer
* @param ch i2s channel
* @param bits bits per sample
*/
void i2s_hal_set_rx_mode(i2s_hal_context_t *hal, i2s_channel_t ch, i2s_bits_per_sample_t bits);
/**
* @brief Set I2S out link address
*
* @param hal Context of the HAL layer
* @param addr out link address
*/
#define i2s_hal_set_out_link_addr(hal, addr) i2s_ll_set_out_link_addr((hal)->dev, addr)
/**
* @brief Set I2S out link address
*
* @param hal Context of the HAL layer
* @param addr out link address
*/
#define i2s_hal_set_out_link_addr(hal, addr) i2s_ll_set_out_link_addr((hal)->dev, addr)
/**
* @brief Set I2S out link address
*
* @param hal Context of the HAL layer
* @param addr out link address
*/
#define i2s_hal_set_out_link_addr(hal, addr) i2s_ll_set_out_link_addr((hal)->dev, addr)
/**
* @brief Set I2S in link
*
* @param hal Context of the HAL layer
* @param rx_eof_num in link eof num
* @param addr in link address
*/
void i2s_hal_set_in_link(i2s_hal_context_t *hal, uint32_t rx_eof_num, uint32_t addr);
/**
* @brief Get I2S tx pdm
*
* @param hal Context of the HAL layer
* @param fp tx pdm fp
* @param fs tx pdm fs
*/
void i2s_hal_get_tx_pdm(i2s_hal_context_t *hal, int *fp, int *fs);
/**
* @brief Get I2S rx sinc dsr 16 en
*
* @param hal Context of the HAL layer
* @param en 0: disable, 1: enable
*/
#define i2s_hal_get_rx_sinc_dsr_16_en(hal, en) i2s_ll_get_rx_sinc_dsr_16_en((hal)->dev, en)
/**
* @brief Set I2S clk div
*
* @param hal Context of the HAL layer
* @param div_num i2s clkm div num
* @param div_a i2s clkm div a
* @param div_b i2s clkm div b
* @param tx_bck_div tx bck div num
* @param rx_bck_div rx bck div num
*/
void i2s_hal_set_clk_div(i2s_hal_context_t *hal, int div_num, int div_a, int div_b, int tx_bck_div, int rx_bck_div);
/**
* @brief Set I2S clock sel
*
* @param hal Context of the HAL layer
* @param sel clock sel
*/
#define i2s_hal_set_clock_sel(hal, sel) i2s_ll_set_clk_sel((hal)->dev, sel)
/**
* @brief Set I2S tx bits mod
*
* @param hal Context of the HAL layer
* @param bits bit width per sample.
*/
void i2s_hal_set_tx_bits_mod(i2s_hal_context_t *hal, i2s_bits_per_sample_t bits);
/**
* @brief Set I2S rx bits mod
*
* @param hal Context of the HAL layer
* @param bits bit width per sample.
*/
void i2s_hal_set_rx_bits_mod(i2s_hal_context_t *hal, i2s_bits_per_sample_t bits);
/**
* @brief Reset I2S tx
*
* @param hal Context of the HAL layer
*/
void i2s_hal_reset(i2s_hal_context_t *hal);
/**
* @brief Start I2S tx
*
* @param hal Context of the HAL layer
*/
void i2s_hal_start_tx(i2s_hal_context_t *hal);
/**
* @brief Start I2S rx
*
* @param hal Context of the HAL layer
*/
void i2s_hal_start_rx(i2s_hal_context_t *hal);
/**
* @brief Stop I2S tx
*
* @param hal Context of the HAL layer
*/
void i2s_hal_stop_tx(i2s_hal_context_t *hal);
/**
* @brief Stop I2S rx
*
* @param hal Context of the HAL layer
*/
void i2s_hal_stop_rx(i2s_hal_context_t *hal);
/**
* @brief Set I2S pdm rx down sample
*
* @param hal Context of the HAL layer
* @param dsr 0:disable, 1: enable
*/
#define i2s_hal_set_pdm_rx_down_sample(hal, dsr) i2s_ll_set_rx_sinc_dsr_16_en((hal)->dev, dsr)
/**
* @brief Config I2S param
*
* @param hal Context of the HAL layer
* @param i2s_config I2S configurations - see i2s_config_t struct
*/
void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_t *i2s_config);
/**
* @brief Enable I2S sig loopback
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_enable_sig_loopback(hal) i2s_ll_set_sig_loopback((hal)->dev, 1)
/**
* @brief Enable I2S master mode
*
* @param hal Context of the HAL layer
*/
void i2s_hal_enable_master_mode(i2s_hal_context_t *hal);
/**
* @brief Enable I2S slave mode
*
* @param hal Context of the HAL layer
*/
void i2s_hal_enable_slave_mode(i2s_hal_context_t *hal);
/**
* @brief Init the I2S hal and set the I2S to the default configuration. This function should be called first before other hal layer function is called
*
* @param hal Context of the HAL layer
* @param i2s_num The uart port number, the max port number is (I2S_NUM_MAX -1)
*/
void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,195 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include <stddef.h>
#include "soc/i2s_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief I2S port number, the max port number is (I2S_NUM_MAX -1).
*/
typedef int i2s_port_t;
#define I2S_PIN_NO_CHANGE (-1) /*!< Use in i2s_pin_config_t for pins which should not be changed */
/**
* @brief I2S bit width per sample.
*
*/
typedef enum {
I2S_BITS_PER_SAMPLE_8BIT = 8, /*!< I2S bits per sample: 8-bits*/
I2S_BITS_PER_SAMPLE_16BIT = 16, /*!< I2S bits per sample: 16-bits*/
I2S_BITS_PER_SAMPLE_24BIT = 24, /*!< I2S bits per sample: 24-bits*/
I2S_BITS_PER_SAMPLE_32BIT = 32, /*!< I2S bits per sample: 32-bits*/
} i2s_bits_per_sample_t;
/**
* @brief I2S channel.
*
*/
typedef enum {
I2S_CHANNEL_MONO = 1, /*!< I2S 1 channel (mono)*/
I2S_CHANNEL_STEREO = 2 /*!< I2S 2 channel (stereo)*/
} i2s_channel_t;
/**
* @brief I2S communication standard format
*
*/
typedef enum {
I2S_COMM_FORMAT_I2S = 0x01, /*!< I2S communication format I2S*/
I2S_COMM_FORMAT_I2S_MSB = 0x02, /*!< I2S format MSB*/
I2S_COMM_FORMAT_I2S_LSB = 0x04, /*!< I2S format LSB*/
I2S_COMM_FORMAT_PCM = 0x08, /*!< I2S communication format PCM*/
I2S_COMM_FORMAT_PCM_SHORT = 0x10, /*!< PCM Short*/
I2S_COMM_FORMAT_PCM_LONG = 0x20, /*!< PCM Long*/
} i2s_comm_format_t;
/**
* @brief I2S channel format type
*/
typedef enum {
I2S_CHANNEL_FMT_RIGHT_LEFT = 0x00,
I2S_CHANNEL_FMT_ALL_RIGHT,
I2S_CHANNEL_FMT_ALL_LEFT,
I2S_CHANNEL_FMT_ONLY_RIGHT,
I2S_CHANNEL_FMT_ONLY_LEFT,
} i2s_channel_fmt_t;
/**
* @brief PDM sample rate ratio, measured in Hz.
*
*/
typedef enum {
PDM_SAMPLE_RATE_RATIO_64,
PDM_SAMPLE_RATE_RATIO_128,
} pdm_sample_rate_ratio_t;
/**
* @brief PDM PCM convter enable/disable.
*
*/
typedef enum {
PDM_PCM_CONV_ENABLE,
PDM_PCM_CONV_DISABLE,
} pdm_pcm_conv_t;
/**
* @brief I2S Mode, defaut is I2S_MODE_MASTER | I2S_MODE_TX
*
* @note PDM and built-in DAC functions are only supported on I2S0 for current ESP32 chip.
*
*/
typedef enum {
I2S_MODE_MASTER = 1,
I2S_MODE_SLAVE = 2,
I2S_MODE_TX = 4,
I2S_MODE_RX = 8,
I2S_MODE_DAC_BUILT_IN = 16, /*!< Output I2S data to built-in DAC, no matter the data format is 16bit or 32 bit, the DAC module will only take the 8bits from MSB*/
I2S_MODE_ADC_BUILT_IN = 32, /*!< Input I2S data from built-in ADC, each data can be 12-bit width at most*/
#if SOC_I2S_SUPPORT_PDM
I2S_MODE_PDM = 64,
#endif
} i2s_mode_t;
/**
* @brief I2S configuration parameters for i2s_param_config function
*
*/
typedef struct {
i2s_mode_t mode; /*!< I2S work mode*/
int sample_rate; /*!< I2S sample rate*/
i2s_bits_per_sample_t bits_per_sample; /*!< I2S bits per sample*/
i2s_channel_fmt_t channel_format; /*!< I2S channel format */
i2s_comm_format_t communication_format; /*!< I2S communication format */
int intr_alloc_flags; /*!< Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info */
int dma_buf_count; /*!< I2S DMA Buffer Count */
int dma_buf_len; /*!< I2S DMA Buffer Length */
bool use_apll; /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */
bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor if there is underflow condition (helps in avoiding noise in case of data unavailability) */
int fixed_mclk; /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0, then the clock output for i2s is fixed and equal to the fixed_mclk value.*/
} i2s_config_t;
/**
* @brief I2S event types
*
*/
typedef enum {
I2S_EVENT_DMA_ERROR,
I2S_EVENT_TX_DONE, /*!< I2S DMA finish sent 1 buffer*/
I2S_EVENT_RX_DONE, /*!< I2S DMA finish received 1 buffer*/
I2S_EVENT_MAX, /*!< I2S event max index*/
} i2s_event_type_t;
/**
* @brief I2S DAC mode for i2s_set_dac_mode.
*
* @note PDM and built-in DAC functions are only supported on I2S0 for current ESP32 chip.
*/
typedef enum {
I2S_DAC_CHANNEL_DISABLE = 0, /*!< Disable I2S built-in DAC signals*/
I2S_DAC_CHANNEL_RIGHT_EN = 1, /*!< Enable I2S built-in DAC right channel, maps to DAC channel 1 on GPIO25*/
I2S_DAC_CHANNEL_LEFT_EN = 2, /*!< Enable I2S built-in DAC left channel, maps to DAC channel 2 on GPIO26*/
I2S_DAC_CHANNEL_BOTH_EN = 0x3, /*!< Enable both of the I2S built-in DAC channels.*/
I2S_DAC_CHANNEL_MAX = 0x4, /*!< I2S built-in DAC mode max index*/
} i2s_dac_mode_t;
/**
* @brief Event structure used in I2S event queue
*
*/
typedef struct {
i2s_event_type_t type; /*!< I2S event type */
size_t size; /*!< I2S data size for I2S_DATA event*/
} i2s_event_t;
/**
* @brief I2S pin number for i2s_set_pin
*
*/
typedef struct {
int bck_io_num; /*!< BCK in out pin*/
int ws_io_num; /*!< WS in out pin*/
int data_out_num; /*!< DATA out pin*/
int data_in_num; /*!< DATA in pin*/
} i2s_pin_config_t;
#if SOC_I2S_SUPPORT_PDM
/**
* @brief I2S PDM RX downsample mode
*/
typedef enum {
I2S_PDM_DSR_8S = 0, /*!< downsampling number is 8 for PDM RX mode*/
I2S_PDM_DSR_16S, /*!< downsampling number is 16 for PDM RX mode*/
I2S_PDM_DSR_MAX,
} i2s_pdm_dsr_t;
#endif
typedef enum {
I2S_CLK_D2CLK = 0,
I2S_CLK_APLL,
} i2s_clock_src_t;
#ifdef __cplusplus
}
#endif

View file

@ -41,7 +41,7 @@ typedef struct {
const periph_module_t module;
} i2s_signal_conn_t;
extern const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_PERIPH_NUM];
extern const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM];
#ifdef __cplusplus
}

View file

@ -0,0 +1,244 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The HAL layer for I2S (common part)
#include "soc/soc.h"
#include "esp_log.h"
#include "hal/i2s_hal.h"
void i2s_hal_reset_fifo(i2s_hal_context_t *hal)
{
i2s_ll_reset_rx_fifo(hal->dev);
i2s_ll_reset_tx_fifo(hal->dev);
}
void i2s_hal_set_tx_mode(i2s_hal_context_t *hal, i2s_channel_t ch, i2s_bits_per_sample_t bits)
{
if (bits <= I2S_BITS_PER_SAMPLE_16BIT) {
i2s_ll_set_tx_fifo_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1);
} else {
i2s_ll_set_tx_fifo_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 2 : 3);
}
i2s_ll_set_tx_chan_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1);
}
void i2s_hal_set_rx_mode(i2s_hal_context_t *hal, i2s_channel_t ch, i2s_bits_per_sample_t bits)
{
if (bits <= I2S_BITS_PER_SAMPLE_16BIT) {
i2s_ll_set_rx_fifo_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1);
} else {
i2s_ll_set_rx_fifo_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 2 : 3);
}
i2s_ll_set_rx_chan_mod(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1);
}
void i2s_hal_set_in_link(i2s_hal_context_t *hal, uint32_t bytes_num, uint32_t addr)
{
i2s_ll_set_in_link_addr(hal->dev, addr);
i2s_ll_set_rx_eof_num(hal->dev, bytes_num);
}
void i2s_hal_get_tx_pdm(i2s_hal_context_t *hal, int *fp, int *fs)
{
i2s_ll_get_tx_pdm_fp(hal->dev, (uint32_t *)fp);
i2s_ll_get_tx_pdm_fs(hal->dev, (uint32_t *)fs);
}
void i2s_hal_set_clk_div(i2s_hal_context_t *hal, int div_num, int div_a, int div_b, int tx_bck_div, int rx_bck_div)
{
i2s_ll_set_clkm_div_num(hal->dev, div_num);
i2s_ll_set_clkm_div_a(hal->dev, div_a);
i2s_ll_set_clkm_div_b(hal->dev, div_b);
i2s_ll_set_tx_bck_div_num(hal->dev, tx_bck_div);
i2s_ll_set_rx_bck_div_num(hal->dev, rx_bck_div);
}
void i2s_hal_set_tx_bits_mod(i2s_hal_context_t *hal, i2s_bits_per_sample_t bits)
{
i2s_ll_set_tx_bits_mod(hal->dev, bits);
}
void i2s_hal_set_rx_bits_mod(i2s_hal_context_t *hal, i2s_bits_per_sample_t bits)
{
i2s_ll_set_rx_bits_mod(hal->dev, bits);
}
void i2s_hal_reset(i2s_hal_context_t *hal)
{
i2s_ll_reset_dma_in(hal->dev);
i2s_ll_reset_dma_out(hal->dev);
i2s_ll_reset_tx(hal->dev);
i2s_ll_reset_rx(hal->dev);
}
void i2s_hal_start_tx(i2s_hal_context_t *hal)
{
i2s_ll_start_out_link(hal->dev);
i2s_ll_start_tx(hal->dev);
}
void i2s_hal_start_rx(i2s_hal_context_t *hal)
{
i2s_ll_start_in_link(hal->dev);
i2s_ll_start_rx(hal->dev);
}
void i2s_hal_stop_tx(i2s_hal_context_t *hal)
{
i2s_ll_stop_out_link(hal->dev);
i2s_ll_stop_tx(hal->dev);
}
void i2s_hal_stop_rx(i2s_hal_context_t *hal)
{
i2s_ll_stop_in_link(hal->dev);
i2s_ll_stop_rx(hal->dev);
}
void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_t *i2s_config)
{
//reset i2s
i2s_ll_reset_tx(hal->dev);
i2s_ll_reset_rx(hal->dev);
//reset dma
i2s_ll_reset_dma_in(hal->dev);
i2s_ll_reset_dma_out(hal->dev);
i2s_ll_enable_dma(hal->dev);
i2s_ll_set_lcd_en(hal->dev, 0);
i2s_ll_set_camera_en(hal->dev, 0);
i2s_ll_set_pcm2pdm_conv_en(hal->dev, 0);
i2s_ll_set_pdm2pcm_conv_en(hal->dev, 0);
i2s_ll_set_dscr_en(hal->dev, 0);
i2s_ll_set_tx_chan_mod(hal->dev, i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? i2s_config->channel_format : (i2s_config->channel_format >> 1)); // 0-two channel;1-right;2-left;3-righ;4-left
i2s_ll_set_tx_fifo_mod(hal->dev, i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1); // 0-right&left channel;1-one channel
i2s_ll_set_tx_mono(hal->dev, 0);
i2s_ll_set_rx_chan_mod(hal->dev, i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? i2s_config->channel_format : (i2s_config->channel_format >> 1)); // 0-two channel;1-right;2-left;3-righ;4-left
i2s_ll_set_rx_fifo_mod(hal->dev, i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1); // 0-right&left channel;1-one channel
i2s_ll_set_rx_mono(hal->dev, 0);
i2s_ll_set_dscr_en(hal->dev, 1); //connect dma to fifo
i2s_ll_stop_tx(hal->dev);
i2s_ll_stop_rx(hal->dev);
if (i2s_config->mode & I2S_MODE_TX) {
i2s_ll_set_tx_msb_right(hal->dev, 0);
i2s_ll_set_tx_right_first(hal->dev, 0);
i2s_ll_set_tx_slave_mod(hal->dev, 0); // Master
i2s_ll_set_tx_fifo_mod_force_en(hal->dev, 1);
if (i2s_config->mode & I2S_MODE_SLAVE) {
i2s_ll_set_tx_slave_mod(hal->dev, 1); //TX Slave
}
}
if (i2s_config->mode & I2S_MODE_RX) {
i2s_ll_set_rx_msb_right(hal->dev, 0);
i2s_ll_set_rx_right_first(hal->dev, 0);
i2s_ll_set_rx_slave_mod(hal->dev, 0); // Master
i2s_ll_set_rx_fifo_mod_force_en(hal->dev, 1);
if (i2s_config->mode & I2S_MODE_SLAVE) {
i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave
}
}
if (i2s_config->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) {
i2s_ll_set_lcd_en(hal->dev, 1);
i2s_ll_set_tx_right_first(hal->dev, 1);
i2s_ll_set_camera_en(hal->dev, 0);
}
#if SOC_I2S_SUPPORT_PDM
if (i2s_config->mode & I2S_MODE_PDM) {
i2s_ll_set_rx_fifo_mod_force_en(hal->dev, 1);
i2s_ll_set_tx_fifo_mod_force_en(hal->dev, 1);
i2s_ll_set_tx_pdm_fp(hal->dev, 960);
i2s_ll_set_tx_pdm_fs(hal->dev, i2s_config->sample_rate / 1000 * 10);
uint32_t fp, fs;
i2s_ll_get_tx_pdm_fp(hal->dev, &fp);
i2s_ll_get_tx_pdm_fs(hal->dev, &fs);
i2s_ll_set_tx_sinc_osr2(hal->dev, fp / fs);
i2s_ll_set_rx_sinc_dsr_16_en(hal->dev, 0);
i2s_ll_set_rx_pdm_en(hal->dev, 1);
i2s_ll_set_tx_pdm_en(hal->dev, 1);
i2s_ll_set_pcm2pdm_conv_en(hal->dev, 1);
i2s_ll_set_pdm2pcm_conv_en(hal->dev, 1);
} else {
i2s_ll_set_rx_pdm_en(hal->dev, 0);
i2s_ll_set_tx_pdm_en(hal->dev, 0);
}
#else
i2s_ll_set_rx_pdm_en(hal->dev, 0);
i2s_ll_set_tx_pdm_en(hal->dev, 0);
#endif
if (i2s_config->communication_format & I2S_COMM_FORMAT_I2S || i2s_config->communication_format & I2S_COMM_FORMAT_I2S_MSB || i2s_config->communication_format & I2S_COMM_FORMAT_I2S_LSB) {
i2s_ll_set_tx_short_sync(hal->dev, 0);
i2s_ll_set_rx_short_sync(hal->dev, 0);
i2s_ll_set_tx_msb_shift(hal->dev, 1);
i2s_ll_set_rx_msb_shift(hal->dev, 1);
if (i2s_config->communication_format & I2S_COMM_FORMAT_I2S_LSB) {
if (i2s_config->mode & I2S_MODE_TX) {
i2s_ll_set_tx_msb_shift(hal->dev, 0);
}
if (i2s_config->mode & I2S_MODE_RX) {
i2s_ll_set_rx_msb_shift(hal->dev, 0);
}
}
}
if (i2s_config->communication_format & I2S_COMM_FORMAT_PCM || i2s_config->communication_format & I2S_COMM_FORMAT_PCM_LONG || i2s_config->communication_format & I2S_COMM_FORMAT_PCM_SHORT) {
i2s_ll_set_tx_msb_shift(hal->dev, 0);
i2s_ll_set_rx_msb_shift(hal->dev, 0);
i2s_ll_set_tx_short_sync(hal->dev, 0);
i2s_ll_set_rx_short_sync(hal->dev, 0);
if (i2s_config->communication_format & I2S_COMM_FORMAT_PCM_SHORT) {
if (i2s_config->mode & I2S_MODE_TX) {
i2s_ll_set_tx_short_sync(hal->dev, 1);
}
if (i2s_config->mode & I2S_MODE_RX) {
i2s_ll_set_rx_short_sync(hal->dev, 1);
}
}
}
}
void i2s_hal_enable_master_mode(i2s_hal_context_t *hal)
{
i2s_ll_set_tx_slave_mod(hal->dev, 0); //MASTER Slave
i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave
}
void i2s_hal_enable_slave_mode(i2s_hal_context_t *hal)
{
i2s_ll_set_tx_slave_mod(hal->dev, 1); //TX Slave
i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave
}
void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num)
{
//Get hardware instance.
hal->dev = I2S_LL_GET_HW(i2s_num);
}

View file

@ -105,6 +105,7 @@ INPUT = \
../../components/esp_adc_cal/include/esp_adc_cal.h \
../../components/soc/include/hal/spi_types.h \
../../components/soc/include/hal/pcnt_types.h \
../../components/soc/include/hal/i2s_types.h \
../../components/soc/esp32/include/soc/adc_channel.h \
../../components/soc/esp32/include/soc/dac_channel.h \
../../components/soc/esp32/include/soc/touch_channel.h \