driver: support I2S on ESP32-S3 & ESP32-C3

1. refactor I2S driver.
  2. support TDM mode for esp2s3 & esp32c3.
This commit is contained in:
houwenxiang
2020-06-01 09:47:48 +08:00
committed by laokaiyao
parent 12c76b4c5c
commit 2f1247e1c4
29 changed files with 2929 additions and 3076 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
// Copyright 2020 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.
@@ -39,19 +39,148 @@ extern "C" {
#define I2S_INTR_OUT_DSCR_ERR BIT(14)
#define I2S_INTR_MAX (0xFFFFFFFF)
/* I2S clock configuration structure */
typedef struct {
uint16_t mclk_div; // I2S module clock devider, Fmclk = Fsclk /(mclk_div+b/a)
uint16_t a;
uint16_t b; // The decimal part of module clock devider, the decimal is: b/a
uint16_t bck_div; // The BCK devider, Fbck = Fmclk / bck_div
} i2s_clk_cal_t;
/**
* @brief Reset rx fifo
* @brief Calculate the closest sample rate clock configuration.
* clock relationship:
* Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a)
*
* @param hw Peripheral I2S hardware instance address.
* @param fsclk I2S source clock freq.
* @param fbck BCK freuency.
* @param bck_div The BCK devider of bck. Generally, set bck_div to 8.
* @param cal Point to `i2s_clk_cal_t` structure.
*/
static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw)
static inline void i2s_ll_clk_cal(uint32_t fsclk, uint32_t fbck, int bck_div, i2s_clk_cal_t *cal)
{
hw->conf.rx_fifo_reset = 1;
hw->conf.rx_fifo_reset = 0;
int ma = 0;
int mb = 0;
uint32_t mclk = fbck*bck_div;
cal->mclk_div = fsclk / mclk;
cal->bck_div = bck_div;
cal->a = 1;
cal->b = 0;
uint32_t freq_diff = fsclk - mclk * cal->mclk_div;
uint32_t min = ~0;
if (freq_diff == 0) {
return;
}
for (int a = 2; a <= 63; a++) {
for (int b = 1; b < a; b++) {
ma = freq_diff*a;
mb = mclk*b;
if (ma == mb) {
cal->a = a;
cal->b = b;
return;
}
if (abs((mb - ma)) < min) {
cal->a = a;
cal->b = b;
min = abs(mb - ma);
}
}
}
}
/**
* @brief Reset tx fifo
* @brief I2S module general init, enable I2S clock.
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_general_init(i2s_dev_t *hw)
{
if (hw->clkm_conf.clk_en == 0) {
hw->clkm_conf.clk_sel = 2;
hw->clkm_conf.clk_en = 1;
hw->conf2.val = 0;
}
}
/**
* @brief I2S TX module general init.
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_tx_gen_init(i2s_dev_t *hw)
{
hw->conf.tx_start = 0;
hw->conf.tx_reset = 1;
hw->conf.tx_reset = 0;
hw->conf.tx_msb_right = 0;
hw->conf.tx_right_first = 0;
hw->conf.tx_slave_mod = 0;
hw->fifo_conf.tx_fifo_mod_force_en = 1;
}
/**
* @brief I2S RX module general init.
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_rx_gen_init(i2s_dev_t *hw)
{
hw->conf.rx_start = 0;
hw->conf.rx_reset = 1;
hw->conf.rx_reset = 0;
hw->conf.rx_msb_right = 0;
hw->conf.rx_right_first = 0;
hw->conf.rx_slave_mod = 0;
hw->fifo_conf.rx_fifo_mod_force_en = 1;
}
/**
* @brief Enable I2S TX slave mode
*
* @param hw Peripheral I2S hardware instance address.
* @param slave_en Set true to enable slave mode
*/
static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, bool slave_en)
{
hw->conf.tx_slave_mod = slave_en;
}
/**
* @brief Enable I2S RX slave mode
*
* @param hw Peripheral I2S hardware instance address.
* @param slave_en Set true to enable slave mode
*/
static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, bool slave_en)
{
hw->conf.rx_slave_mod = slave_en;
}
/**
* @brief Reset TX module
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_reset_tx(i2s_dev_t *hw)
{
hw->conf.tx_reset = 1;
hw->conf.tx_reset = 0;
}
/**
* @brief Reset RX module
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_reset_rx(i2s_dev_t *hw)
{
hw->conf.rx_reset = 1;
hw->conf.rx_reset = 0;
}
/**
* @brief Reset TX FIFO
*
* @param hw Peripheral I2S hardware instance address.
*/
@@ -62,40 +191,68 @@ static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw)
}
/**
* @brief Enable rx interrupt
* @brief Reset RX FIFO
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_enable_rx_intr(i2s_dev_t *hw)
static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw)
{
hw->int_ena.in_suc_eof = 1;
hw->int_ena.in_dscr_err = 1;
hw->conf.rx_fifo_reset = 1;
hw->conf.rx_fifo_reset = 0;
}
/**
* @brief Disable rx interrupt
* @brief Set TX source clock
*
* @param hw Peripheral I2S hardware instance address.
* @param src I2S source clock
*/
static inline void i2s_ll_disable_rx_intr(i2s_dev_t *hw)
static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src)
{
hw->int_ena.in_suc_eof = 0;
hw->int_ena.in_dscr_err = 0;
hw->clkm_conf.clk_sel = (src == 1) ? 1 : 2;
}
/**
* @brief Disable tx interrupt
* @brief Set RX source clock
*
* @param hw Peripheral I2S hardware instance address.
* @param src I2S source clock
*/
static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw)
static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src)
{
hw->int_ena.out_eof = 0;
hw->int_ena.out_dscr_err = 0;
hw->clkm_conf.clk_sel = (src == 1) ? 1 : 2;
}
/**
* @brief Enable tx interrupt
* @brief Configure I2S TX clock devider
*
* @param hw Peripheral I2S hardware instance address.
* @param set Pointer to I2S clock devider configuration paramater
*/
static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set)
{
hw->clkm_conf.clkm_div_num = set->mclk_div;
hw->clkm_conf.clkm_div_b = set->b;
hw->clkm_conf.clkm_div_a = set->a;
hw->sample_rate_conf.tx_bck_div_num = set->bck_div;
}
/**
* @brief Configure I2S RX clock devider
*
* @param hw Peripheral I2S hardware instance address.
* @param set Pointer to I2S clock devider configuration paramater
*/
static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_clk_cal_t *set)
{
hw->clkm_conf.clkm_div_num = set->mclk_div;
hw->clkm_conf.clkm_div_b = set->b;
hw->clkm_conf.clkm_div_a = set->a;
hw->sample_rate_conf.rx_bck_div_num = set->bck_div;
}
/**
* @brief Enable TX interrupt
*
* @param hw Peripheral I2S hardware instance address.
*/
@@ -106,14 +263,58 @@ static inline void i2s_ll_enable_tx_intr(i2s_dev_t *hw)
}
/**
* @brief Reset dma in
* @brief Disable TX interrupt
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_reset_dma_in(i2s_dev_t *hw)
static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw)
{
hw->lc_conf.in_rst = 1;
hw->lc_conf.in_rst = 0;
hw->int_ena.out_eof = 0;
hw->int_ena.out_dscr_err = 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 Get I2S interrupt status
*
* @param hw Peripheral I2S hardware instance address.
* @param intr_mask Pointer to accept interrupt status
*/
static inline void i2s_ll_get_intr_status(i2s_dev_t *hw, uint32_t *intr_mask)
{
*intr_mask = hw->int_st.val;
}
/**
* @brief Clear I2S interrupt status
*
* @param hw Peripheral I2S hardware instance address.
* @param clr_mask Interrupt mask to be cleared.
*/
static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t clr_mask)
{
hw->int_clr.val = clr_mask;
}
/**
@@ -128,39 +329,18 @@ static inline void i2s_ll_reset_dma_out(i2s_dev_t *hw)
}
/**
* @brief Reset tx
* @brief Reset dma in
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_reset_tx(i2s_dev_t *hw)
static inline void i2s_ll_reset_dma_in(i2s_dev_t *hw)
{
hw->conf.tx_reset = 1;
hw->conf.tx_reset = 0;
hw->lc_conf.in_rst = 1;
hw->lc_conf.in_rst = 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
* @brief Start TX module
*
* @param hw Peripheral I2S hardware instance address.
*/
@@ -170,17 +350,7 @@ static inline void i2s_ll_start_tx(i2s_dev_t *hw)
}
/**
* @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
* @brief Start RX module
*
* @param hw Peripheral I2S hardware instance address.
*/
@@ -189,6 +359,50 @@ static inline void i2s_ll_start_rx(i2s_dev_t *hw)
hw->conf.rx_start = 1;
}
/**
* @brief Configure TX DMA descriptor address and start TX DMA
*
* @param hw Peripheral I2S hardware instance address.
* @param link_addr DMA descriptor link address.
*/
static inline void i2s_ll_start_tx_link(i2s_dev_t *hw, uint32_t link_addr)
{
hw->out_link.addr = link_addr;
hw->out_link.start = 1;
}
/**
* @brief Configure RX DMA descriptor address and start TX DMA
*
* @param hw Peripheral I2S hardware instance address.
* @param link_addr DMA descriptor link address.
*/
static inline void i2s_ll_start_rx_link(i2s_dev_t *hw, uint32_t link_addr)
{
hw->in_link.addr = link_addr;
hw->in_link.start = 1;
}
/**
* @brief Stop TX module
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_stop_tx(i2s_dev_t *hw)
{
hw->conf.tx_start = 0;
}
/**
* @brief Stop RX module
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_stop_rx(i2s_dev_t *hw)
{
hw->conf.rx_start = 0;
}
/**
* @brief Stop out link
*
@@ -199,16 +413,6 @@ 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
*
@@ -220,456 +424,77 @@ static inline void i2s_ll_stop_in_link(i2s_dev_t *hw)
}
/**
* @brief Stop rx
* @brief Get I2S out eof descriptor address
*
* @param hw Peripheral I2S hardware instance address.
* @param eof_addr Pointer to accept out eof des address
*/
static inline void i2s_ll_stop_rx(i2s_dev_t *hw)
static inline void i2s_ll_get_out_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr)
{
hw->conf.rx_start = 0;
*eof_addr = hw->out_eof_des_addr;
}
/**
* @brief Enable dma
* @brief Get I2S in eof descriptor address
*
* @param hw Peripheral I2S hardware instance address.
* @param eof_addr Pointer to accept in eof des address
*/
static inline void i2s_ll_enable_dma(i2s_dev_t *hw)
static inline void i2s_ll_get_in_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr)
{
//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;
*eof_addr = hw->in_eof_des_addr;
}
/**
* @brief Get I2S interrupt status
* @brief Configure the received length to trigger in_suc_eof interrupt
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get interrupt status
* @param eof_num the byte length to trigger in_suc_eof interrupt
*/
static inline void i2s_ll_get_intr_status(i2s_dev_t *hw, uint32_t *val)
static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, uint32_t eof_num)
{
*val = hw->int_st.val;
hw->rx_eof_num = eof_num;
}
/**
* @brief Clear I2S interrupt status
* @brief Congfigure TX slot bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to clear interrupt status
* @param sample_bit The slot bit width
* @param data_bit The audio data bit width
*/
static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t val)
static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit)
{
hw->int_clr.val = val;
hw->fifo_conf.tx_fifo_mod = (sample_bit <= I2S_BITS_PER_SAMPLE_16BIT ? 0 : 2);
hw->sample_rate_conf.tx_bits_mod = data_bit;
}
/**
* @brief Get I2S out eof des address
* @brief Congfigure RX slot bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get out eof des address
* @param sample_bit The slot bit width
* @param data_bit The audio data bit width
*/
static inline void i2s_ll_get_out_eof_des_addr(i2s_dev_t *hw, uint32_t *val)
static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit)
{
*val = hw->out_eof_des_addr;
hw->fifo_conf.rx_fifo_mod = (sample_bit <= I2S_BITS_PER_SAMPLE_16BIT ? 0 : 2);
hw->sample_rate_conf.rx_bits_mod = data_bit;
}
/**
* @brief Get I2S in eof des address
* @brief Enable I2S DMA
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get in eof des address
* @param ena Set true to enable DMA
*/
static inline void i2s_ll_get_in_eof_des_addr(i2s_dev_t *hw, uint32_t *val)
static inline void i2s_ll_dma_enable(i2s_dev_t *hw, bool ena)
{
*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 tx dma equal
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx dma equal
*/
static inline void i2s_ll_set_tx_dma_equal(i2s_dev_t *hw, uint32_t val)
{
hw->conf.tx_dma_equal = val;
}
/**
* @brief Set I2S rx dma equal
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx dma equal
*/
static inline void i2s_ll_set_rx_dma_equal(i2s_dev_t *hw, uint32_t val)
{
hw->conf.rx_dma_equal = 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 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 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 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 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;
if (ena && !hw->fifo_conf.dscr_en) {
hw->fifo_conf.dscr_en = 1;
} else if (!ena && hw->fifo_conf.dscr_en) {
hw->fifo_conf.dscr_en = 0;
}
}
/**
@@ -760,6 +585,53 @@ static inline void i2s_ll_set_rx_pcm_long(i2s_dev_t *hw)
hw->conf.rx_msb_shift = 0;
}
/**
* @brief Enable TX mono mode
*
* @param hw Peripheral I2S hardware instance address.
* @param mono_ena Set true to enable mono mde.
*/
static inline void i2s_ll_tx_mono_mode_ena(i2s_dev_t *hw, bool mono_ena)
{
int data_bit = hw->sample_rate_conf.tx_bits_mod;
if (data_bit <= I2S_BITS_PER_SAMPLE_16BIT) {
hw->fifo_conf.tx_fifo_mod = 0 + mono_ena;
} else {
hw->fifo_conf.tx_fifo_mod = 2 + mono_ena;
}
hw->conf.tx_dma_equal = mono_ena;
hw->conf_chan.tx_chan_mod = mono_ena;
}
/**
* @brief Enable RX mono mode
*
* @param hw Peripheral I2S hardware instance address.
* @param mono_ena Set true to enable mono mde.
*/
static inline void i2s_ll_rx_mono_mode_ena(i2s_dev_t *hw, bool mono_ena)
{
int data_bit = hw->sample_rate_conf.rx_bits_mod;
if (data_bit <= I2S_BITS_PER_SAMPLE_16BIT) {
hw->fifo_conf.rx_fifo_mod = 0 + mono_ena;
} else {
hw->fifo_conf.rx_fifo_mod = 2 + mono_ena;
}
hw->conf.rx_dma_equal = mono_ena;
hw->conf_chan.rx_chan_mod = mono_ena;
}
/**
* @brief Enable I2S loopback mode
*
* @param hw Peripheral I2S hardware instance address.
* @param loopback_en Set true to enable loopback mode.
*/
static inline void i2s_ll_loop_back_ena(i2s_dev_t *hw, bool loopback_en)
{
hw->conf.sig_loopback = loopback_en;
}
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
// Copyright 2020 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.
@@ -12,230 +12,291 @@
// 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 "soc/soc_caps.h"
#include "soc/gdma_channel.h"
#include "hal/i2s_hal.h"
#define I2S_TX_PDM_FP_DEF 960 // Set to the recommended value(960) in TRM
#define I2S_RX_PDM_DSR_DEF 0
#define I2S_MODE_I2S (I2S_MODE_MASTER|I2S_MODE_SLAVE|I2S_MODE_TX|I2S_MODE_RX) /*!< I2S normal mode*/
void i2s_hal_set_tx_mode(i2s_hal_context_t *hal, i2s_channel_t ch, i2s_bits_per_sample_t bits)
void i2s_hal_reset_tx(i2s_hal_context_t *hal)
{
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);
#if SOC_I2S_SUPPORTS_DMA_EQUAL
i2s_ll_set_tx_dma_equal(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1);
#endif
}
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);
#if SOC_I2S_SUPPORTS_DMA_EQUAL
i2s_ll_set_rx_dma_equal(hal->dev, (ch == I2S_CHANNEL_STEREO) ? 0 : 1);
#endif
}
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);
}
#if SOC_I2S_SUPPORTS_PDM
void i2s_hal_tx_pdm_cfg(i2s_hal_context_t *hal, uint32_t fp, uint32_t fs)
{
i2s_ll_tx_pdm_cfg(hal->dev, fp, fs);
}
void i2s_hal_get_tx_pdm(i2s_hal_context_t *hal, uint32_t *fp, uint32_t *fs)
{
i2s_ll_get_tx_pdm(hal->dev, fp, fs);
}
void i2s_hal_rx_pdm_cfg(i2s_hal_context_t *hal, uint32_t dsr)
{
i2s_ll_rx_pdm_cfg(hal->dev, dsr);
}
void i2s_hal_get_rx_pdm(i2s_hal_context_t *hal, uint32_t *dsr)
{
i2s_ll_get_rx_pdm(hal->dev, dsr);
}
#endif
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)
{
// Reset I2S TX/RX module first, and then, reset DMA and FIFO.
i2s_ll_reset_tx(hal->dev);
}
void i2s_hal_reset_rx(i2s_hal_context_t *hal)
{
i2s_ll_reset_rx(hal->dev);
i2s_ll_reset_dma_in(hal->dev);
i2s_ll_reset_dma_out(hal->dev);
i2s_ll_reset_rx_fifo(hal->dev);
}
void i2s_hal_reset_tx_fifo(i2s_hal_context_t *hal)
{
i2s_ll_reset_tx_fifo(hal->dev);
}
void i2s_hal_reset_rx_fifo(i2s_hal_context_t *hal)
{
i2s_ll_reset_rx_fifo(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_format_config(i2s_hal_context_t *hal, const i2s_config_t *i2s_config)
void i2s_hal_set_tx_sample_bit(i2s_hal_context_t *hal, int slot_bit, int data_bit)
{
switch (i2s_config->communication_format) {
i2s_ll_set_tx_sample_bit(hal->dev, slot_bit, data_bit);
}
void i2s_hal_set_rx_sample_bit(i2s_hal_context_t *hal, int slot_bit, int data_bit)
{
i2s_ll_set_rx_sample_bit(hal->dev, slot_bit, data_bit);
}
void i2s_hal_set_clock_src(i2s_hal_context_t *hal, i2s_clock_src_t sel)
{
i2s_ll_set_tx_clk_src(hal->dev, sel);
i2s_ll_set_rx_clk_src(hal->dev, sel);
}
void i2s_hal_tx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbck, int factor)
{
i2s_clk_cal_t clk_set = {0};
i2s_ll_clk_cal(sclk, fbck, factor, &clk_set);
i2s_ll_set_tx_clk(hal->dev, &clk_set);
}
void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbck, int factor)
{
i2s_clk_cal_t clk_set = {0};
i2s_ll_clk_cal(sclk, fbck, factor, &clk_set);
i2s_ll_set_rx_clk(hal->dev, &clk_set);
}
void i2s_hal_set_rx_eof_num(i2s_hal_context_t *hal, uint32_t eof_byte)
{
i2s_ll_set_rx_eof_num(hal->dev, eof_byte);
}
void i2s_hal_enable_master_fd_mode(i2s_hal_context_t *hal)
{
i2s_ll_set_tx_slave_mod(hal->dev, 0); //TX master
i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave
}
void i2s_hal_enable_slave_fd_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
}
#if SOC_I2S_SUPPORTS_PCM
void i2s_hal_tx_pcm_cfg(i2s_hal_context_t *hal, i2s_pcm_cfg_t cfg)
{
i2s_ll_tx_pcm_cfg(hal->dev, cfg);
}
void i2s_hal_rx_pcm_cfg(i2s_hal_context_t *hal, i2s_pcm_cfg_t cfg)
{
i2s_ll_rx_pcm_cfg(hal->dev, cfg);
}
#endif
void i2s_hal_enable_sig_loopback(i2s_hal_context_t *hal)
{
i2s_ll_loop_back_ena(hal->dev, 1);
}
#if SOC_I2S_SUPPORTS_PDM_TX
void i2s_hal_set_tx_pdm_fpfs(i2s_hal_context_t *hal, int fp, int fs)
{
i2s_ll_set_tx_pdm_fpfs(hal->dev, fp, fs);
}
void i2s_hal_get_tx_pdm_fpfs(i2s_hal_context_t *hal, int *fp, int *fs)
{
i2s_ll_get_tx_pdm_fpfs(hal->dev, (uint32_t *)fp, (uint32_t *)fs);
}
#endif
#if SOC_I2S_SUPPORTS_PDM_RX
void i2s_hal_set_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t dsr)
{
i2s_ll_set_pdm_rx_dsr(hal->dev, dsr);
}
void i2s_hal_get_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t *dsr)
{
i2s_ll_get_pdm_rx_dsr(hal->dev, dsr);
}
#endif
void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num)
{
//Get hardware instance.
hal->dev = I2S_LL_GET_HW(i2s_num);
#if SOC_GDMA_SUPPORTED
hal->dma = &GDMA;
if (i2s_num == 0) {
hal->dma_ch = SOC_GDMA_I2S0_DMA_CHANNEL;
hal->dma_peri_sel = SOC_GDMA_TRIG_PERIPH_I2S0;
}
#if SOC_I2S_NUM > 1
if (i2s_num == 1) {
hal->dma_ch = SOC_GDMA_I2S1_DMA_CHANNEL;
hal->dma_peri_sel = SOC_GDMA_TRIG_PERIPH_I2S1;
}
#endif
gdma_ll_enable_m2m_mode(hal->dma, hal->dma_ch, false);
#endif
i2s_ll_general_init(hal->dev);
}
static void i2s_hal_format_config(i2s_hal_context_t *hal, i2s_mode_t i2s_mode, i2s_comm_format_t format, i2s_slot_channel_cfg_t slot_bit_cfg, i2s_slot_bits_cfg_t slot_ch_cfg)
{
int active_slot_num = slot_ch_cfg & 0xffff;
#if !SOC_I2S_SUPPORTS_TDM
switch (format) {
case I2S_COMM_FORMAT_STAND_MSB:
if (i2s_config->mode & I2S_MODE_TX) {
if (i2s_mode & I2S_MODE_TX) {
i2s_ll_set_tx_format_msb_align(hal->dev);
}
if (i2s_config->mode & I2S_MODE_RX) {
if (i2s_mode & I2S_MODE_RX) {
i2s_ll_set_rx_format_msb_align(hal->dev);
}
break;
case I2S_COMM_FORMAT_STAND_PCM_SHORT:
if (i2s_config->mode & I2S_MODE_TX) {
i2s_ll_set_tx_pcm_long(hal->dev);
}
if (i2s_config->mode & I2S_MODE_RX) {
i2s_ll_set_rx_pcm_long(hal->dev);
}
break;
case I2S_COMM_FORMAT_STAND_PCM_LONG:
if (i2s_config->mode & I2S_MODE_TX) {
if (i2s_mode & I2S_MODE_TX) {
i2s_ll_set_tx_pcm_short(hal->dev);
}
if (i2s_config->mode & I2S_MODE_RX) {
if (i2s_mode & I2S_MODE_RX) {
i2s_ll_set_rx_pcm_short(hal->dev);
}
break;
case I2S_COMM_FORMAT_STAND_PCM_LONG:
if (i2s_mode & I2S_MODE_TX) {
i2s_ll_set_tx_pcm_long(hal->dev);
}
if (i2s_mode & I2S_MODE_RX) {
i2s_ll_set_rx_pcm_long(hal->dev);
}
break;
default: //I2S_COMM_FORMAT_STAND_I2S
if (i2s_config->mode & I2S_MODE_TX) {
if (i2s_mode & I2S_MODE_TX) {
i2s_ll_set_tx_format_philip(hal->dev);
}
if (i2s_config->mode & I2S_MODE_RX) {
if (i2s_mode & I2S_MODE_RX) {
i2s_ll_set_rx_format_philip(hal->dev);
}
break;
}
if (active_slot_num == I2S_CHANNEL_MONO) {
if (i2s_mode & I2S_MODE_TX) {
i2s_ll_tx_mono_mode_ena(hal->dev, active_slot_num == I2S_CHANNEL_MONO);
}
if (i2s_mode & I2S_MODE_RX) {
i2s_ll_rx_mono_mode_ena(hal->dev, active_slot_num == I2S_CHANNEL_MONO);
}
}
#else
int data_bits = slot_bit_cfg & 0xffff;
int slot_bits = ((slot_bit_cfg >> SLOT_BIT_SHIFT) == I2S_BITS_PER_SLOT_SAMPLE_BIT_EQU) ? data_bits : slot_bit_cfg >> SLOT_BIT_SHIFT;
int slot_num = ((slot_ch_cfg >> SLOT_CH_SHIFT) == 0 || (active_slot_num == I2S_CHANNEL_MONO)) ? 2 : (slot_ch_cfg >> SLOT_CH_SHIFT);
bool msb_shift_en = false;
int tdm_ws_width = 0;
switch (format) {
case I2S_COMM_FORMAT_STAND_MSB:
msb_shift_en = false;
tdm_ws_width = slot_num*slot_bits/2;
break;
case I2S_COMM_FORMAT_STAND_PCM_SHORT:
msb_shift_en = false;
tdm_ws_width = 1;
break;
case I2S_COMM_FORMAT_STAND_PCM_LONG:
msb_shift_en = false;
tdm_ws_width = slot_bits;
break;
default: //I2S_COMM_FORMAT_STAND_I2S
msb_shift_en = true;
tdm_ws_width = slot_num*slot_bits/2;
break;
}
if (i2s_mode & I2S_MODE_TX) {
i2s_ll_tx_msb_shift_enable(hal->dev, msb_shift_en);
i2s_ll_set_tx_tdm_ws_width(hal->dev, tdm_ws_width);
i2s_ll_set_tx_half_sample_bit(hal->dev, slot_num*slot_bits/2);
}
if (i2s_mode & I2S_MODE_RX) {
i2s_ll_rx_msb_shift_enable(hal->dev, msb_shift_en);
i2s_ll_set_rx_tdm_ws_width(hal->dev, tdm_ws_width);
i2s_ll_set_rx_half_sample_bit(hal->dev, slot_num*slot_bits/2);
}
#endif
}
void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_t *i2s_config)
void i2s_hal_samples_config(i2s_hal_context_t *hal, i2s_mode_t i2s_mode, i2s_comm_format_t communication_format, i2s_slot_channel_cfg_t slot_bit_cfg, i2s_slot_bits_cfg_t slot_ch_cfg)
{
//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_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);
int active_slot_num = slot_ch_cfg & 0xffff;
int data_bits = slot_bit_cfg & 0xffff;
int slot_bits = ((slot_bit_cfg >> SLOT_BIT_SHIFT) == I2S_BITS_PER_SLOT_SAMPLE_BIT_EQU) ? data_bits : slot_bit_cfg >> SLOT_BIT_SHIFT;
int slot_num = ((slot_ch_cfg >> SLOT_CH_SHIFT) == 0 || (active_slot_num == I2S_CHANNEL_MONO)) ? 2 : (slot_ch_cfg >> SLOT_CH_SHIFT);
#if SOC_I2S_SUPPORTS_TDM
if (i2s_mode & I2S_MODE_TX) {
i2s_ll_set_tx_slot_mun(hal->dev, slot_num);
i2s_ll_set_tx_sample_bit(hal->dev, slot_bits, data_bits);
}
if (i2s_mode & I2S_MODE_RX) {
i2s_ll_set_rx_slot_mun(hal->dev, slot_num);
i2s_ll_set_rx_sample_bit(hal->dev, slot_bits, data_bits);
}
#else
if (i2s_mode & I2S_MODE_TX) {
i2s_ll_set_tx_sample_bit(hal->dev, slot_bits, data_bits);
}
if (i2s_mode & I2S_MODE_RX) {
i2s_ll_set_rx_sample_bit(hal->dev, slot_bits, data_bits);
}
#endif
//I2S standards config: Philip, MSB or PCM, Only I2S mode should do this configuration.
if ((i2s_mode & (~(I2S_MODE_I2S))) == 0) {
i2s_hal_format_config(hal, i2s_mode, communication_format, slot_bit_cfg, slot_ch_cfg);
}
}
void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_param_t *i2s_config)
{
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);
i2s_ll_tx_gen_init(hal->dev);
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);
i2s_ll_rx_gen_init(hal->dev);
if (i2s_config->mode & I2S_MODE_SLAVE) {
i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave
}
}
#if SOC_I2S_SUPPORTS_PDM
if (!(i2s_config->mode & I2S_MODE_PDM)) {
i2s_ll_set_rx_pdm_en(hal->dev, 0);
i2s_ll_set_tx_pdm_en(hal->dev, 0);
} else {
if (i2s_config->mode & I2S_MODE_TX) {
i2s_ll_tx_pdm_cfg(hal->dev, I2S_TX_PDM_FP_DEF, i2s_config->sample_rate/100);
}
if(i2s_config->mode & I2S_MODE_RX) {
i2s_ll_rx_pdm_cfg(hal->dev, I2S_RX_PDM_DSR_DEF);
}
// PDM mode have nothing to do with communication format configuration.
return;
}
#endif
#if SOC_I2S_SUPPORTS_ADC_DAC
if (i2s_config->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) {
if (i2s_config->mode & I2S_MODE_DAC_BUILT_IN) {
@@ -243,32 +304,54 @@ void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_t *i2s_config
}
if (i2s_config->mode & I2S_MODE_ADC_BUILT_IN) {
i2s_ll_build_in_adc_ena(hal->dev);
i2s_ll_set_rx_chan_mod(hal->dev, 1);
i2s_ll_set_rx_fifo_mod(hal->dev, 1);
i2s_ll_set_rx_mono(hal->dev, 0);
}
// Buildin ADC and DAC have nothing to do with communication format configuration.
return;
}
#endif
i2s_hal_format_config(hal, i2s_config);
}
#if SOC_I2S_SUPPORTS_PDM
if (!(i2s_config->mode & I2S_MODE_PDM)) {
#if SOC_I2S_SUPPORTS_PDM_RX
if (i2s_config->mode & I2S_MODE_RX) {
i2s_ll_set_rx_pdm_en(hal->dev, false);
}
#endif
#if SOC_I2S_SUPPORTS_PDM_TX
if (i2s_config->mode & I2S_MODE_TX) {
i2s_ll_set_tx_pdm_en(hal->dev, false);
}
#endif
} else {
#if SOC_I2S_SUPPORTS_PDM_TX
if (i2s_config->mode & I2S_MODE_TX) {
i2s_ll_tx_pdm_cfg(hal->dev, i2s_config->sample_rate);
}
#endif
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
}
#if SOC_I2S_SUPPORTS_PDM_RX
if(i2s_config->mode & I2S_MODE_RX) {
i2s_ll_rx_pdm_cfg(hal->dev);
}
#endif
}
#endif
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
}
#if SOC_I2S_SUPPORTS_TDM
if (i2s_config->mode & I2S_MODE_TX) {
i2s_ll_set_tx_active_slot_mask(hal->dev, i2s_config->active_slot_mask);
i2s_ll_tx_left_align_enable(hal->dev, i2s_config->left_align_en);
i2s_ll_tx_big_endian_enable(hal->dev, i2s_config->big_edin_en);
i2s_ll_tx_set_bit_order(hal->dev, i2s_config->bit_order_msb_en);
}
if (i2s_config->mode & I2S_MODE_RX) {
i2s_ll_set_rx_active_slot_mask(hal->dev, i2s_config->active_slot_mask);
i2s_ll_rx_left_align_enable(hal->dev, i2s_config->left_align_en);
i2s_ll_rx_big_endian_enable(hal->dev, i2s_config->big_edin_en);
i2s_ll_rx_set_bit_order(hal->dev, i2s_config->bit_order_msb_en);
}
#endif
void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num)
{
//Get hardware instance.
hal->dev = I2S_LL_GET_HW(i2s_num);
//Configure I2S slot number,sample bit.
i2s_hal_samples_config(hal, i2s_config->mode, i2s_config->communication_format, i2s_config->slot_bits_cfg, i2s_config->slot_channel_cfg);
}

View File

@@ -1,4 +1,4 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
// Copyright 2020 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.
@@ -25,8 +25,11 @@
#include "soc/i2s_periph.h"
#include "soc/soc_caps.h"
#include "hal/i2s_ll.h"
#include "hal/i2s_types.h"
#include "hal/i2s_ll.h"
#if SOC_GDMA_SUPPORTED
#include "hal/gdma_ll.h"
#endif
#ifdef __cplusplus
extern "C" {
@@ -37,162 +40,91 @@ extern "C" {
*/
typedef struct {
i2s_dev_t *dev;
#if SOC_GDMA_SUPPORTED
gdma_dev_t *dma;
int dma_ch;
int dma_peri_sel;
#endif
uint32_t version;
} i2s_hal_context_t;
/**
* @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
* @brief Reset I2S TX channel
*
* @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)
void i2s_hal_reset_tx(i2s_hal_context_t *hal);
/**
* @brief Get I2S out eof des address
* @brief Reset I2S TX fifo
*
* @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)
void i2s_hal_reset_tx_fifo(i2s_hal_context_t *hal);
/**
* @brief Get I2S in eof des address
* @brief Reset I2S RX channel
*
* @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)
void i2s_hal_reset_rx(i2s_hal_context_t *hal);
/**
* @brief Enable I2S rx interrupt
* @brief Reset I2S RX fifo
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_enable_rx_intr(hal) i2s_ll_enable_rx_intr((hal)->dev)
void i2s_hal_reset_rx_fifo(i2s_hal_context_t *hal);
/**
* @brief Disable I2S rx interrupt
* @brief Init the I2S hal. 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)
*/
#define i2s_hal_disable_rx_intr(hal) i2s_ll_disable_rx_intr((hal)->dev)
void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num);
/**
* @brief Disable I2S tx interrupt
* @brief Configure I2S source clock
*
* @param hal Context of the HAL layer
* @param sel The source clock index
*/
#define i2s_hal_disable_tx_intr(hal) i2s_ll_disable_tx_intr((hal)->dev)
void i2s_hal_set_clock_src(i2s_hal_context_t *hal, i2s_clock_src_t sel);
/**
* @brief Enable I2S tx interrupt
* @brief Configure communication format
*
* @param hal Context of the HAL layer
* @param i2s_mode I2S mode. Using the ored mask of I2S_MODE_MASTER, I2S_MODE_SLAVE, I2S_MODE_TX, I2S_MODE_RX
* @param communication_format I2S communication format. Can be a value of `i2s_comm_format_t`.
* @param slot_bit_cfg I2S slot bit configuration
* @param slot_ch_cfg I2S slot channel configuration
*/
#define i2s_hal_enable_tx_intr(hal) i2s_ll_enable_tx_intr((hal)->dev)
void i2s_hal_samples_config(i2s_hal_context_t *hal, i2s_mode_t i2s_mode, i2s_comm_format_t communication_format, i2s_slot_channel_cfg_t slot_bit_cfg, i2s_slot_bits_cfg_t slot_ch_cfg);
/**
* @brief Set I2S tx mode
* @brief Config I2S param
*
* @param hal Context of the HAL layer
* @param ch i2s channel
* @param bits bits per sample
* @param i2s_config I2S paramater configuration structer, refer to `i2s_config_param_t`
*/
void i2s_hal_set_tx_mode(i2s_hal_context_t *hal, i2s_channel_t ch, i2s_bits_per_sample_t bits);
void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_param_t *i2s_config);
/**
* @brief Set I2S rx mode
* @brief Enable I2S master full-duplex 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);
void i2s_hal_enable_master_fd_mode(i2s_hal_context_t *hal);
/**
* @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 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 & RX module, including DMA and FIFO
* @brief Enable I2S slave full-duplex mode
*
* @param hal Context of the HAL layer
*/
void i2s_hal_reset(i2s_hal_context_t *hal);
void i2s_hal_enable_slave_fd_mode(i2s_hal_context_t *hal);
/**
* @brief Start I2S tx
@@ -223,76 +155,256 @@ void i2s_hal_stop_tx(i2s_hal_context_t *hal);
void i2s_hal_stop_rx(i2s_hal_context_t *hal);
/**
* @brief Config I2S param
* @brief Set the received data length to trigger `in_suc_eof` interrupt.
*
* @param hal Context of the HAL layer
* @param i2s_config I2S configurations - see i2s_config_t struct
* @param eof_byte The byte length that trigger in_suc_eof interrupt.
*/
void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_t *i2s_config);
void i2s_hal_set_rx_eof_num(i2s_hal_context_t *hal, uint32_t eof_byte);
/**
* @brief Enable I2S sig loopback
* @brief Set I2S TX sample bit
*
* @param hal Context of the HAL layer
* @param slot_bit I2S TX slot bit
* @param data_bit The sample data bit lengh.
*/
#define i2s_hal_enable_sig_loopback(hal) i2s_ll_set_sig_loopback((hal)->dev, 1)
void i2s_hal_set_tx_sample_bit(i2s_hal_context_t *hal, int slot_bit, int data_bit);
/**
* @brief Enable I2S master mode
* @brief Set I2S RX sample bit
*
* @param hal Context of the HAL layer
* @param slot_bit I2S RX slot bit
* @param data_bit The sample data bit lengh.
*/
void i2s_hal_enable_master_mode(i2s_hal_context_t *hal);
void i2s_hal_set_rx_sample_bit(i2s_hal_context_t *hal, int slot_bit, int data_bit);
/**
* @brief Enable I2S slave mode
* @brief Configure I2S TX module clock devider
*
* @param hal Context of the HAL layer
* @param sclk I2S source clock freq
* @param fbck I2S bck freq
* @param factor bck factor, factor=sclk/fbck
*/
void i2s_hal_enable_slave_mode(i2s_hal_context_t *hal);
void i2s_hal_tx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbck, int factor);
/**
* @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
* @brief Configure I2S RX module clock devider
*
* @param hal Context of the HAL layer
* @param i2s_num The uart port number, the max port number is (I2S_NUM_MAX -1)
* @param sclk I2S source clock freq
* @param fbck I2S bck freq
* @param factor bck factor, factor=sclk/fbck
*/
void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num);
void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbck, int factor);
#if SOC_I2S_SUPPORTS_PDM
#if SOC_I2S_SUPPORTS_PCM
/**
* @brief Set I2S tx pdm
* @brief Configure I2S TX PCM encoder or decoder.
*
* @param hal Context of the HAL layer
* @param fp tx pdm fp
* @param fs tx pdm fs
* @param cfg PCM configure paramater, refer to `i2s_pcm_cfg_t`
*/
void i2s_hal_tx_pdm_cfg(i2s_hal_context_t *hal, uint32_t fp, uint32_t fs);
void i2s_hal_tx_pcm_cfg(i2s_hal_context_t *hal, i2s_pcm_cfg_t cfg);
/**
* @brief Get I2S tx pdm
* @brief Configure I2S RX PCM encoder or decoder.
*
* @param hal Context of the HAL layer
* @param dsr rx pdm dsr
* @param cfg PCM configure paramater, refer to `i2s_pcm_cfg_t`
*/
void i2s_hal_rx_pdm_cfg(i2s_hal_context_t *hal, uint32_t dsr);
void i2s_hal_rx_pcm_cfg(i2s_hal_context_t *hal, i2s_pcm_cfg_t cfg);
#endif
/**
* @brief Get I2S tx pdm configuration
* @brief Enable loopback mode
*
* @param hal Context of the HAL layer
* @param fp Pointer to receive tx PDM fp configuration
* @param fs Pointer to receive tx PDM fs configuration
*/
void i2s_hal_get_tx_pdm(i2s_hal_context_t *hal, uint32_t *fp, uint32_t *fs);
void i2s_hal_enable_sig_loopback(i2s_hal_context_t *hal);
#if SOC_I2S_SUPPORTS_PDM_TX
/**
* @brief Configure I2S TX PDM sample rate
* Fpdm = 64*Fpcm*fp/fs
*
* @param hal Context of the HAL layer
* @param fp TX PDM fp paramater configuration
* @param fs TX PDM fs paramater configuration
*/
void i2s_hal_set_tx_pdm_fpfs(i2s_hal_context_t *hal, int fp, int fs);
/**
* @brief Get I2S rx pdm configuration
* @brief Get I2S TX PDM configuration
*
* @param hal Context of the HAL layer
* @param dsr rx pdm dsr
* @param fp Pointer to accept TX PDM fp paramater configuration
* @param fs Pointer to accept TX PDM fs paramater configuration
*/
void i2s_hal_get_rx_pdm(i2s_hal_context_t *hal, uint32_t *dsr);
void i2s_hal_get_tx_pdm_fpfs(i2s_hal_context_t *hal, int *fp, int *fs);
#endif
#if SOC_I2S_SUPPORTS_PDM_RX
/**
* @brief Configure RX PDM downsample
*
* @param hal Context of the HAL layer
* @param dsr PDM downsample configuration paramater
*/
void i2s_hal_set_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t dsr);
/**
* @brief Get RX PDM downsample configuration
*
* @param hal Context of the HAL layer
* @param dsr Pointer to accept PDM downsample configuration
*/
void i2s_hal_get_rx_pdm_dsr(i2s_hal_context_t *hal, i2s_pdm_dsr_t *dsr);
#endif
#if !SOC_GDMA_SUPPORTED
/**
* @brief Enable I2S TX DMA
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_attach_tx_dma(hal) i2s_ll_dma_enable((hal)->dev,true)
/**
* @brief Enable I2S RX DMA
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_attach_rx_dma(hal) i2s_ll_dma_enable((hal)->dev,true)
/**
* @brief Get I2S interrupt status
*
* @param hal Context of the HAL layer
* @param status Pointer to accept I2S interrupt status
*/
#define i2s_hal_get_intr_status(hal, status) i2s_ll_get_intr_status((hal)->dev, status)
/**
* @brief Get I2S interrupt status
*
* @param hal Context of the HAL layer
* @param mask Interrupt mask to be cleared.
*/
#define i2s_hal_clear_intr_status(hal, mask) i2s_ll_clear_intr_status((hal)->dev, mask)
/**
* @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 Configure TX DMA descriptor address and start TX DMA
*
* @param hal Context of the HAL layer
* @param link_addr DMA descriptor link address.
*/
#define i2s_hal_start_tx_link(hal, link_addr) i2s_ll_start_tx_link((hal)->dev, link_addr)
/**
* @brief Configure RX DMA descriptor address and start RX DMA
*
* @param hal Context of the HAL layer
* @param link_addr DMA descriptor link address.
*/
#define i2s_hal_start_rx_link(hal, link_addr) i2s_ll_start_rx_link((hal)->dev, link_addr)
/**
* @brief Stop TX DMA link
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_stop_tx_link(hal) i2s_ll_stop_out_link((hal)->dev)
/**
* @brief Stop RX DMA link
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_stop_rx_link(hal) i2s_ll_stop_in_link((hal)->dev)
/**
* @brief Reset RX DMA
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_reset_rxdma(hal) i2s_ll_reset_dma_in((hal)->dev)
/**
* @brief Reset TX DMA
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_reset_txdma(hal) i2s_ll_reset_dma_out((hal)->dev)
/**
* @brief Get I2S out eof descriptor address
*
* @param hal Context of the HAL layer
* @param addr Pointer to accept 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 suc eof descriptor address
*
* @param hal Context of the HAL layer
* @param addr Pointer to accept in suc eof des address
*/
#define i2s_hal_get_in_eof_des_addr(hal, addr) i2s_ll_get_in_eof_des_addr((hal)->dev, addr)
#else
#define i2s_hal_attach_tx_dma(hal) gdma_ll_tx_connect_to_periph((hal)->dma, (hal)->dma_ch, (hal)->dma_peri_sel)
#define i2s_hal_attach_rx_dma(hal) gdma_ll_rx_connect_to_periph((hal)->dma, (hal)->dma_ch, (hal)->dma_peri_sel)
#define i2s_hal_get_intr_status(hal, status) (*status = (gdma_ll_get_interrupt_status((hal)->dma, (hal)->dma_ch)))
#define i2s_hal_clear_intr_status(hal, mask) gdma_ll_clear_interrupt_status((hal)->dma, (hal)->dma_ch, mask)
#define i2s_hal_enable_rx_intr(hal) gdma_ll_enable_interrupt((hal)->dma, (hal)->dma_ch, I2S_INTR_IN_DSCR_ERR|I2S_INTR_IN_SUC_EOF, 1)
#define i2s_hal_disable_rx_intr(hal) gdma_ll_enable_interrupt((hal)->dma, (hal)->dma_ch, I2S_INTR_IN_DSCR_ERR|I2S_INTR_IN_SUC_EOF, 0)
#define i2s_hal_enable_tx_intr(hal) gdma_ll_enable_interrupt((hal)->dma, (hal)->dma_ch, I2S_INTR_OUT_DSCR_ERR|I2S_INTR_OUT_EOF, 1)
#define i2s_hal_disable_tx_intr(hal) gdma_ll_enable_interrupt((hal)->dma, (hal)->dma_ch, I2S_INTR_OUT_DSCR_ERR|I2S_INTR_OUT_EOF, 0)
#define i2s_hal_start_tx_link(hal, link_addr) do{\
gdma_ll_tx_set_desc_addr((hal)->dma,(hal)->dma_ch,link_addr);\
gdma_ll_tx_start((hal)->dma,(hal)->dma_ch);}while(0)
#define i2s_hal_start_rx_link(hal, link_addr) do{\
gdma_ll_rx_set_desc_addr((hal)->dma,(hal)->dma_ch,link_addr);\
gdma_ll_rx_start((hal)->dma,(hal)->dma_ch);}while(0)
#define i2s_hal_stop_tx_link(hal) gdma_ll_tx_stop((hal)->dma,(hal)->dma_ch)
#define i2s_hal_stop_rx_link(hal) gdma_ll_rx_stop((hal)->dma, (hal)->dma_ch)
#define i2s_hal_reset_rxdma(hal) gdma_ll_rx_reset_channel((hal)->dma, (hal)->dma_ch)
#define i2s_hal_reset_txdma(hal) gdma_ll_tx_reset_channel((hal)->dma, (hal)->dma_ch)
#define i2s_hal_get_out_eof_des_addr(hal, addr) (*addr = (gdma_ll_tx_get_eof_desc_addr((hal)->dma, (hal)->dma_ch)))
#define i2s_hal_get_in_eof_des_addr(hal, addr) (*addr = (gdma_ll_rx_get_success_eof_desc_addr((hal)->dma, (hal)->dma_ch)))
#endif
#ifdef __cplusplus

View File

@@ -1,4 +1,4 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
// Copyright 2020 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.
@@ -16,6 +16,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stddef.h>
#include "soc/soc_caps.h"
@@ -39,12 +40,47 @@ typedef enum {
*
*/
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_8BIT = 8,
I2S_BITS_PER_SAMPLE_16BIT = 16,
I2S_BITS_PER_SAMPLE_24BIT = 24,
I2S_BITS_PER_SAMPLE_32BIT = 32,
} i2s_bits_per_sample_t;
/**
* @brief I2S bit width per slot.
*
*/
typedef enum {
I2S_BITS_PER_SLOT_8BIT = (8), /*!< slot bit 8*/
I2S_BITS_PER_SLOT_16BIT = (16), /*!< slot bit 16*/
I2S_BITS_PER_SLOT_24BIT = (24), /*!< slot bit 24*/
I2S_BITS_PER_SLOT_32BIT = (32), /*!< slot bit 32*/
I2S_BITS_PER_SLOT_SAMPLE_BIT_EQU = (0), /*!< slot bit equals to data bit*/
} i2s_bits_per_slot_t;
#define SLOT_BIT_SHIFT (16) //slot bit shift
#define SLOT_CH_SHIFT (16) //slot channel shift
/**
* @brief I2S slot bit configuration paramater. The low 16bit is the audio_data_bit_width and the high 16bit is the slot_bit_width.
* e.g.: If set to (I2S_BITS_PER_SLOT_24BIT << SLOT_BIT_SHIFT) | I2S_BITS_PER_SAMPLE_16BIT, the audio data bit is 16bit and the slot bit is 24bit.
*
*
* @note: If the slot_bit_width is set to `I2S_BITS_PER_SLOT_SAMPLE_BIT_EQU`, then the slot_bit_width equals to audio_data_bit_width.
*
*/
typedef uint32_t i2s_slot_bits_cfg_t; /*!< slot bit configuration*/
/**
* @brief I2S slot channel configuration paramater. The low 16bit is the active_slot_number and the high 16bit is the total_slot_num.
* The audio data only launch in active slot, otherwise, launch 0 or single data in inactive slot.
* e.g.: If set to (4 << SLOT_CH_SHIFT) | 2, the active_slot_number is 2 and the total_slot_num 4.
*
* @note: If the total_slot_num is set to 0, then the total_slot_num equals to active_slot_number.
*
*/
typedef uint32_t i2s_slot_channel_cfg_t; /*!< slot channel configuration*/
/**
* @brief I2S channel.
*
@@ -54,25 +90,46 @@ typedef enum {
I2S_CHANNEL_STEREO = 2 /*!< I2S 2 channel (stereo)*/
} i2s_channel_t;
#if SOC_I2S_SUPPORTS_TDM
/**
* @brief Bit map of active slot.
* For TX module, only the active slot send the audio data, the inactive slot send a constant(configurable).
* For RX module, only receive the audio data in active slot, the data in inactive slot will be ignored.
*
* @note the bit map of active slot can not exceed (0x1<<total_slot_num).
* e.g: active_slot_mask = (I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1), total_slot_num = 4, active_slot_number = 2.
*/
typedef enum {
I2S_TDM_ACTIVE_CH0 = (0x1 << 0),
I2S_TDM_ACTIVE_CH1 = (0x1 << 1),
I2S_TDM_ACTIVE_CH2 = (0x1 << 2),
I2S_TDM_ACTIVE_CH3 = (0x1 << 3),
I2S_TDM_ACTIVE_CH4 = (0x1 << 4),
I2S_TDM_ACTIVE_CH5 = (0x1 << 5),
I2S_TDM_ACTIVE_CH6 = (0x1 << 6),
I2S_TDM_ACTIVE_CH7 = (0x1 << 7),
I2S_TDM_ACTIVE_CH8 = (0x1 << 8),
I2S_TDM_ACTIVE_CH9 = (0x1 << 9),
I2S_TDM_ACTIVE_CH10 = (0x1 << 10),
I2S_TDM_ACTIVE_CH11 = (0x1 << 11),
I2S_TDM_ACTIVE_CH12 = (0x1 << 12),
I2S_TDM_ACTIVE_CH13 = (0x1 << 13),
I2S_TDM_ACTIVE_CH14 = (0x1 << 14),
I2S_TDM_ACTIVE_CH15 = (0x1 << 15),
} i2s_tdm_active_slot_t;
#endif
/**
* @brief I2S communication standard format
*
*/
typedef enum {
// In order to keep compatibility, remain the old definitions and introduce new definitions,
I2S_COMM_FORMAT_STAND_I2S = 0X01, /*!< I2S communication I2S Philips standard, data launch at second BCK*/
I2S_COMM_FORMAT_STAND_MSB = 0X03, /*!< I2S communication MSB alignment standard, data launch at first BCK*/
I2S_COMM_FORMAT_STAND_MSB = 0X02, /*!< I2S communication MSB alignment standard, data launch at first BCK*/
I2S_COMM_FORMAT_STAND_PCM_SHORT = 0x04, /*!< PCM Short standard, also known as DSP mode. The period of synchronization signal (WS) is 1 bck cycle.*/
I2S_COMM_FORMAT_STAND_PCM_LONG = 0x0C, /*!< PCM Long standard. The period of synchronization signal (WS) is channel_bit*bck cycles.*/
I2S_COMM_FORMAT_STAND_MAX, /*!< standard max*/
//old definition will be removed in the future.
I2S_COMM_FORMAT_I2S __attribute__((deprecated)) = 0x01, /*!< I2S communication format I2S, correspond to `I2S_COMM_FORMAT_STAND_I2S`*/
I2S_COMM_FORMAT_I2S_MSB __attribute__((deprecated)) = 0x01, /*!< I2S format MSB, (I2S_COMM_FORMAT_I2S |I2S_COMM_FORMAT_I2S_MSB) correspond to `I2S_COMM_FORMAT_STAND_I2S`*/
I2S_COMM_FORMAT_I2S_LSB __attribute__((deprecated)) = 0x02, /*!< I2S format LSB, (I2S_COMM_FORMAT_I2S |I2S_COMM_FORMAT_I2S_LSB) correspond to `I2S_COMM_FORMAT_STAND_MSB`*/
I2S_COMM_FORMAT_PCM __attribute__((deprecated)) = 0x04, /*!< I2S communication format PCM, correspond to `I2S_COMM_FORMAT_STAND_PCM_SHORT`*/
I2S_COMM_FORMAT_PCM_SHORT __attribute__((deprecated)) = 0x04, /*!< PCM Short, (I2S_COMM_FORMAT_PCM | I2S_COMM_FORMAT_PCM_SHORT) correspond to `I2S_COMM_FORMAT_STAND_PCM_SHORT`*/
I2S_COMM_FORMAT_PCM_LONG __attribute__((deprecated)) = 0x08, /*!< PCM Long, (I2S_COMM_FORMAT_PCM | I2S_COMM_FORMAT_PCM_LONG) correspond to `I2S_COMM_FORMAT_STAND_PCM_LONG`*/
} i2s_comm_format_t;
/**
@@ -87,10 +144,7 @@ typedef enum {
} i2s_channel_fmt_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.
*
* @brief I2S Mode
*/
typedef enum {
I2S_MODE_MASTER = 1, /*!< Master mode*/
@@ -98,17 +152,18 @@ typedef enum {
I2S_MODE_TX = 4, /*!< TX mode*/
I2S_MODE_RX = 8, /*!< RX mode*/
#if SOC_I2S_SUPPORTS_ADC_DAC
//built-in DAC functions are only supported on I2S0 for ESP32 chip.
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*/
#endif
#if SOC_I2S_SUPPORTS_PDM
I2S_MODE_PDM = 64, /*!< PDM mode*/
//PDM functions are only supported on I2S0.
I2S_MODE_PDM = 64, /*!< I2S PDM mode*/
#endif
} i2s_mode_t;
/**
* @brief I2S source clock
*
*/
typedef enum {
I2S_CLK_D2CLK = 0, /*!< Clock from PLL_D2_CLK(160M)*/
@@ -116,39 +171,31 @@ typedef enum {
} i2s_clock_src_t;
/**
* @brief I2S configuration parameters for i2s_param_config function
* @brief I2S bit width per sample.
*
* @note: The chip of ESP32 and ESP32S2 only needs to initialize the fields out side the `SOC_I2S_SUPPORTS_TDM` macro.
* The chip of ESP32-S3, ESP32-C3 and the later chip, all this fields should be initialized.
*/
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_mode_t mode; /*!< I2S work mode, using ored mask of `i2s_mode_t`*/
uint32_t sample_rate; /*!< I2S sample rate*/
i2s_slot_bits_cfg_t slot_bits_cfg; /*!< slot bit configuration, low 16bit is the audio data bit; high 16bit is the slot bit, if set to 0, total slot bit equals to audio data bit*/
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;
#if SOC_I2S_SUPPORTS_TDM
i2s_slot_channel_cfg_t slot_channel_cfg; /*!< slot number configuration, low 16bit is the valid slot number; high 16bit is the total slot number, if set to 0, total slot number equals to valid slot number*/
uint32_t active_slot_mask; /*!< active slot bit mask, using the ored mask of `i2s_tdm_active_slot_t`*/
bool left_align_en; /*!< Set to enable left aligment*/
bool big_edin_en; /*!< Set to enable big edin*/
bool bit_order_msb_en; /*!< Set to enable msb order*/
#endif
} i2s_config_param_t;
#if SOC_I2S_SUPPORTS_ADC_DAC
/**
* @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.
* @note 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*/
@@ -159,15 +206,6 @@ typedef enum {
} i2s_dac_mode_t;
#endif //SOC_I2S_SUPPORTS_ADC_DAC
/**
* @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
*
@@ -179,7 +217,21 @@ typedef struct {
int data_in_num; /*!< DATA in pin*/
} i2s_pin_config_t;
#if SOC_I2S_SUPPORTS_PDM
#if SOC_I2S_SUPPORTS_PCM
/**
* @brief A/U-law decompress or compress configuration.
*
*/
typedef enum {
I2S_PCM_A_DECOMPRESS=0, /*!< A-law decompress*/
I2S_PCM_A_COMPRESS, /*!< A-law compress*/
I2S_PCM_U_DECOMPRESS, /*!< U-law decompress*/
I2S_PCM_U_COMPRESS, /*!< U-law compress*/
I2S_PCM_DISABLE, /*!< Disable A/U law decopress or compress*/
} i2s_pcm_cfg_t;
#endif
#if SOC_I2S_SUPPORTS_PDM_RX
/**
* @brief I2S PDM RX downsample mode
*/
@@ -188,7 +240,9 @@ typedef enum {
I2S_PDM_DSR_16S, /*!< downsampling number is 16 for PDM RX mode*/
I2S_PDM_DSR_MAX,
} i2s_pdm_dsr_t;
#endif
#if SOC_I2S_SUPPORTS_PDM
/**
* @brief PDM PCM convter enable/disable.
*