mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-04 21:24:32 +02:00
Merge branch 'feature/esp32s3_i2s_support' into 'master'
Feature(I2S): Support esp32s3 & esp32c3 I2S driver Closes IDF-1769, IDF-2098, IDF-3271, IDF-2337, and IDF-3463 See merge request espressif/esp-idf!10655
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,6 @@
|
||||
#include "soc/i2s_periph.h"
|
||||
#include "soc/rtc_periph.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/i2s_hal.h"
|
||||
#include "hal/i2s_types.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
@@ -28,7 +27,119 @@ extern "C" {
|
||||
|
||||
#define I2S_PIN_NO_CHANGE (-1) /*!< Use in i2s_pin_config_t for pins which should not be changed */
|
||||
|
||||
typedef intr_handle_t i2s_isr_handle_t;
|
||||
/**
|
||||
* @brief I2S port number, the max port number is (I2S_NUM_MAX -1).
|
||||
*/
|
||||
typedef enum {
|
||||
I2S_NUM_0 = 0, /*!< I2S port 0 */
|
||||
#if SOC_I2S_NUM > 1
|
||||
I2S_NUM_1 = 1, /*!< I2S port 1 */
|
||||
#endif
|
||||
I2S_NUM_MAX, /*!< I2S port max */
|
||||
} i2s_port_t;
|
||||
|
||||
#if SOC_I2S_SUPPORTS_PCM
|
||||
/**
|
||||
* @brief I2S PCM configuration
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
i2s_pcm_compress_t pcm_type; /*!< I2S PCM a/u-law decompress or compress type */
|
||||
} i2s_pcm_cfg_t;
|
||||
#endif
|
||||
|
||||
#if SOC_I2S_SUPPORTS_PDM_TX
|
||||
/**
|
||||
* @brief Default I2S PDM Up-Sampling Rate configuration
|
||||
*/
|
||||
#define I2S_PDM_DEFAULT_UPSAMPLE_CONFIG(rate) { \
|
||||
.sample_rate = rate, \
|
||||
.fp = 960, \
|
||||
.fs = (rate) / 100, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I2S PDM up-sample rate configuration
|
||||
* @note TX PDM can only be set to the following two upsampling rate configurations:
|
||||
* 1: fp = 960, fs = sample_rate / 100, in this case, Fpdm = 128*48000
|
||||
* 2: fp = 960, fs = 480, in this case, Fpdm = 128*Fpcm = 128*sample_rate
|
||||
* If the pdm receiver do not care the pdm serial clock, it's recommended set Fpdm = 128*48000.
|
||||
* Otherwise, the second configuration should be applied.
|
||||
*/
|
||||
typedef struct {
|
||||
int sample_rate; /*!< I2S PDM sample rate */
|
||||
int fp; /*!< I2S PDM TX upsampling paramater. Normally it should be set to 960 */
|
||||
int fs; /*!< I2S PDM TX upsampling paramater. When it is set to 480, the pdm clock frequency Fpdm = 128 * sample_rate, when it is set to sample_rate / 100, Fpdm will be fixed to 128*48000 */
|
||||
} i2s_pdm_tx_upsample_cfg_t;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief I2S pin number for i2s_set_pin
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
int mck_io_num; /*!< MCK in out pin*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* @brief I2S driver configuration parameters
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
|
||||
i2s_mode_t mode; /*!< I2S work mode */
|
||||
uint32_t sample_rate; /*!< I2S sample rate */
|
||||
i2s_bits_per_sample_t bits_per_sample; /*!< I2S sample bits in one channel */
|
||||
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. If fixed_mclk set, mclk_multiple won't take effect */
|
||||
i2s_mclk_multiple_t mclk_multiple; /*!< The multiple of I2S master clock(MCLK) to sample rate */
|
||||
i2s_bits_per_chan_t bits_per_chan; /*!< I2S total bits in one channel, only take effect when larger than 'bits_per_sample', default '0' means equal to 'bits_per_sample' */
|
||||
|
||||
#if SOC_I2S_SUPPORTS_TDM
|
||||
i2s_channel_t chan_mask; /*!< I2S active channel bit mask, set value in `i2s_channel_t` to enable specific channel, the bit map of active channel can not exceed (0x1<<total_chan). */
|
||||
uint32_t total_chan; /*!< I2S Total number of channels. If it is smaller than the biggest active channel number, it will be set to this number automatically. */
|
||||
bool left_align; /*!< Set to enable left alignment */
|
||||
bool big_edin; /*!< Set to enable big edin */
|
||||
bool bit_order_msb; /*!< Set to enable msb order */
|
||||
bool skip_msk; /*!< Set to enable skip mask. If it is enabled, only the data of the enabled channels will be sent, otherwise all data stored in DMA TX buffer will be sent */
|
||||
#endif // SOC_I2S_SUPPORTS_TDM
|
||||
|
||||
} i2s_driver_config_t;
|
||||
|
||||
typedef i2s_driver_config_t i2s_config_t; // for backward compatible
|
||||
typedef intr_handle_t i2s_isr_handle_t; // for backward compatible
|
||||
|
||||
/**
|
||||
* @brief I2S event queue 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_TX_Q_OVF, /*!< I2S DMA sent queue overflow*/
|
||||
I2S_EVENT_RX_Q_OVF, /*!< I2S DMA receive queue overflow*/
|
||||
I2S_EVENT_MAX, /*!< I2S event max index*/
|
||||
} i2s_event_type_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 Set I2S pin number
|
||||
@@ -54,7 +165,7 @@ typedef intr_handle_t i2s_isr_handle_t;
|
||||
*/
|
||||
esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin);
|
||||
|
||||
#if SOC_I2S_SUPPORTS_PDM
|
||||
#if SOC_I2S_SUPPORTS_PDM_RX
|
||||
/**
|
||||
* @brief Set PDM mode down-sample rate
|
||||
* In PDM RX mode, there would be 2 rounds of downsample process in hardware.
|
||||
@@ -62,7 +173,7 @@ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin);
|
||||
* In the second downsample process, the sampling number is fixed as 8.
|
||||
* So the clock frequency in PDM RX mode would be (fpcm * 64) or (fpcm * 128) accordingly.
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
* @param dsr i2s RX down sample rate for PDM mode.
|
||||
* @param downsample i2s RX down sample rate for PDM mode.
|
||||
*
|
||||
* @note After calling this function, it would call i2s_set_clk inside to update the clock frequency.
|
||||
* Please call this function after I2S driver has been initialized.
|
||||
@@ -72,7 +183,25 @@ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin);
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NO_MEM Out of memory
|
||||
*/
|
||||
esp_err_t i2s_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t dsr);
|
||||
esp_err_t i2s_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t downsample);
|
||||
#endif
|
||||
|
||||
#if SOC_I2S_SUPPORTS_PDM_TX
|
||||
/**
|
||||
* @brief Set TX PDM mode up-sample rate
|
||||
* @note If you have set PDM mode while calling 'i2s_driver_install',
|
||||
* default PDM TX upsample parameters have already been set,
|
||||
* no need to call this function again if you don't have to change the default configuration
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
* @param upsample_cfg Set I2S PDM up-sample rate configuration
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NO_MEM Out of memory
|
||||
*/
|
||||
esp_err_t i2s_set_pdm_tx_up_sample(i2s_port_t i2s_num, const i2s_pdm_tx_upsample_cfg_t *upsample_cfg);
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -93,7 +222,7 @@ esp_err_t i2s_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t dsr);
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NO_MEM Out of memory
|
||||
*/
|
||||
esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void* i2s_queue);
|
||||
esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void *i2s_queue);
|
||||
|
||||
/**
|
||||
* @brief Uninstall I2S driver.
|
||||
@@ -243,25 +372,51 @@ esp_err_t i2s_start(i2s_port_t i2s_num);
|
||||
*/
|
||||
esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num);
|
||||
|
||||
#if SOC_I2S_SUPPORTS_PCM
|
||||
/**
|
||||
* @brief Configure I2S a/u-law decompress or compress
|
||||
*
|
||||
* @note This function should be called after i2s driver installed
|
||||
* Only take effecttive when the i2s 'communication_format' is set to 'I2S_COMM_FORMAT_STAND_PCM_SHORT' or 'I2S_COMM_FORMAT_STAND_PCM_LONG'
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0
|
||||
*
|
||||
* @param pcm_cfg including mode selection and a/u-law decompress or compress configuration paramater
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t i2s_pcm_config(i2s_port_t i2s_num, const i2s_pcm_cfg_t *pcm_cfg);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Set clock & bit width used for I2S RX and TX.
|
||||
*
|
||||
* Similar to i2s_set_sample_rates(), but also sets bit width.
|
||||
*
|
||||
* 1. stop i2s;
|
||||
* 2. calculate mclk, bck, bck_factor
|
||||
* 3. malloc dma buffer;
|
||||
* 4. start i2s
|
||||
*
|
||||
* @param i2s_num I2S_NUM_0, I2S_NUM_1
|
||||
*
|
||||
* @param rate I2S sample rate (ex: 8000, 44100...)
|
||||
*
|
||||
* @param bits I2S bit width (I2S_BITS_PER_SAMPLE_16BIT, I2S_BITS_PER_SAMPLE_24BIT, I2S_BITS_PER_SAMPLE_32BIT)
|
||||
* @param bits_cfg I2S bits configuration
|
||||
* the low 16 bits is for data bits per sample in one channel (see 'i2s_bits_per_sample_t')
|
||||
* the high 16 bits is for total bits in one channel (see 'i2s_bits_per_chan_t')
|
||||
* high 16bits =0 means same as the bits per sample.
|
||||
*
|
||||
* @param ch I2S channel, (I2S_CHANNEL_MONO, I2S_CHANNEL_STEREO)
|
||||
* @param ch I2S channel, (I2S_CHANNEL_MONO, I2S_CHANNEL_STEREO or specific channel in TDM mode)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NO_MEM Out of memory
|
||||
*/
|
||||
esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t bits, i2s_channel_t ch);
|
||||
esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_channel_t ch);
|
||||
|
||||
/**
|
||||
* @brief get clock set on particular port number.
|
||||
|
@@ -21,22 +21,51 @@
|
||||
#include "math.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
|
||||
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3, ESP32C3)
|
||||
|
||||
#define SAMPLE_RATE (36000)
|
||||
#define SAMPLE_BITS (16)
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define MASTER_BCK_IO 15
|
||||
#define MASTER_WS_IO 25
|
||||
#define SLAVE_BCK_IO 19
|
||||
#define SLAVE_WS_IO 26
|
||||
#define DATA_IN_IO 21
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define MASTER_WS_IO 25
|
||||
#define DATA_OUT_IO 22
|
||||
#define ADC1_CHANNEL_4_IO 32
|
||||
#define I2S0_DATA_OUT_IDX I2S0O_DATA_OUT23_IDX
|
||||
#define I2S0_DATA_IN_IDX I2S0I_DATA_IN15_IDX
|
||||
#define I2S1_DATA_OUT_IDX I2S1O_DATA_OUT23_IDX
|
||||
#define I2S1_DATA_IN_IDX I2S1I_DATA_IN15_IDX
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define MASTER_BCK_IO 15
|
||||
#define MASTER_WS_IO 28
|
||||
#define SLAVE_BCK_IO 19
|
||||
#define SLAVE_WS_IO 26
|
||||
#define DATA_IN_IO 21
|
||||
#define DATA_OUT_IO 20
|
||||
#define I2S0_DATA_OUT_IDX I2S0O_DATA_OUT23_IDX
|
||||
#define I2S0_DATA_IN_IDX I2S0I_DATA_IN15_IDX
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
// TODO: change pins
|
||||
#define MASTER_BCK_IO 4
|
||||
#define MASTER_WS_IO 5
|
||||
#define SLAVE_BCK_IO 14
|
||||
#define SLAVE_WS_IO 15
|
||||
#define DATA_IN_IO 19
|
||||
#define DATA_OUT_IO 18
|
||||
#define I2S0_DATA_OUT_IDX I2SO_SD_OUT_IDX
|
||||
#define I2S0_DATA_IN_IDX I2SI_SD_IN_IDX
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#define MASTER_BCK_IO 4
|
||||
#define MASTER_WS_IO 5
|
||||
#define SLAVE_BCK_IO 14
|
||||
#define SLAVE_WS_IO 15
|
||||
#define DATA_IN_IO 19
|
||||
#define DATA_OUT_IO 18
|
||||
#define I2S0_DATA_OUT_IDX I2S0O_SD_OUT_IDX
|
||||
#define I2S0_DATA_IN_IDX I2S0I_SD_IN_IDX
|
||||
#define I2S1_DATA_OUT_IDX I2S1O_SD_OUT_IDX
|
||||
#define I2S1_DATA_IN_IDX I2S1I_SD_IN_IDX
|
||||
#endif
|
||||
|
||||
#define PERCENT_DIFF 0.0001
|
||||
@@ -67,8 +96,8 @@ static void i2s_test_io_config(int mode)
|
||||
esp_rom_gpio_connect_out_signal(MASTER_WS_IO, I2S0I_WS_OUT_IDX, 0, 0);
|
||||
esp_rom_gpio_connect_in_signal(MASTER_WS_IO, I2S1O_WS_IN_IDX, 0);
|
||||
|
||||
esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S1O_DATA_OUT23_IDX, 0, 0);
|
||||
esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S0I_DATA_IN15_IDX, 0);
|
||||
esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S1_DATA_OUT_IDX, 0, 0);
|
||||
esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S0_DATA_IN_IDX, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -79,14 +108,14 @@ static void i2s_test_io_config(int mode)
|
||||
esp_rom_gpio_connect_out_signal(MASTER_WS_IO, I2S0O_WS_OUT_IDX, 0, 0);
|
||||
esp_rom_gpio_connect_in_signal(MASTER_WS_IO, I2S1I_WS_IN_IDX, 0);
|
||||
|
||||
esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S0O_DATA_OUT23_IDX, 0, 0);
|
||||
esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S1I_DATA_IN15_IDX, 0);
|
||||
esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S0_DATA_OUT_IDX, 0, 0);
|
||||
esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S1_DATA_IN_IDX, 0);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case I2S_TEST_MODE_LOOPBACK: {
|
||||
esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S0O_DATA_OUT23_IDX, 0, 0);
|
||||
esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S0I_DATA_IN15_IDX, 0);
|
||||
esp_rom_gpio_connect_out_signal(DATA_OUT_IO, I2S0_DATA_OUT_IDX, 0, 0);
|
||||
esp_rom_gpio_connect_in_signal(DATA_OUT_IO, I2S0_DATA_IN_IDX, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -115,18 +144,9 @@ TEST_CASE("I2S basic driver install, uninstall, set pin test", "[i2s]")
|
||||
.dma_buf_count = 6,
|
||||
.dma_buf_len = 60,
|
||||
.use_apll = 0,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 ,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
|
||||
};
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
//install and start i2s driver
|
||||
TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL));
|
||||
//for internal DAC, this will enable both of the internal channels
|
||||
TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, NULL));
|
||||
//stop & destroy i2s driver
|
||||
TEST_ESP_OK(i2s_driver_uninstall(I2S_NUM_0));
|
||||
#endif
|
||||
|
||||
// normal i2s
|
||||
i2s_pin_config_t pin_config = {
|
||||
.bck_io_num = MASTER_BCK_IO,
|
||||
@@ -160,7 +180,7 @@ TEST_CASE("I2S Loopback test(master tx and rx)", "[i2s]")
|
||||
.dma_buf_count = 6,
|
||||
.dma_buf_len = 100,
|
||||
.use_apll = 0,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 ,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
|
||||
};
|
||||
i2s_pin_config_t master_pin_config = {
|
||||
.bck_io_num = MASTER_BCK_IO,
|
||||
@@ -173,29 +193,28 @@ TEST_CASE("I2S Loopback test(master tx and rx)", "[i2s]")
|
||||
i2s_test_io_config(I2S_TEST_MODE_LOOPBACK);
|
||||
printf("\r\nheap size: %d\n", esp_get_free_heap_size());
|
||||
|
||||
uint8_t* data_wr = (uint8_t*)malloc(sizeof(uint8_t)*400);
|
||||
uint8_t *data_wr = (uint8_t *)malloc(sizeof(uint8_t) * 400);
|
||||
size_t i2s_bytes_write = 0;
|
||||
size_t bytes_read = 0;
|
||||
int length = 0;
|
||||
uint8_t *i2s_read_buff = (uint8_t*)malloc(sizeof(uint8_t)*10000);
|
||||
uint8_t *i2s_read_buff = (uint8_t *)malloc(sizeof(uint8_t) * 10000);
|
||||
|
||||
for(int i=0; i<100; i++) {
|
||||
data_wr[i] = i+1;
|
||||
for (int i = 0; i < 100; i++) {
|
||||
data_wr[i] = i + 1;
|
||||
}
|
||||
int flag=0; // break loop flag
|
||||
int flag = 0; // break loop flag
|
||||
int end_position = 0;
|
||||
// write data to slave
|
||||
i2s_write(I2S_NUM_0, data_wr, sizeof(uint8_t)*400, &i2s_bytes_write, 1000 / portTICK_PERIOD_MS);
|
||||
while(!flag){
|
||||
i2s_write(I2S_NUM_0, data_wr, sizeof(uint8_t) * 400, &i2s_bytes_write, 1000 / portTICK_PERIOD_MS);
|
||||
while (!flag) {
|
||||
if (length >= 10000 - 500) {
|
||||
break;
|
||||
}
|
||||
i2s_read(I2S_NUM_0, i2s_read_buff + length, sizeof(uint8_t)*500, &bytes_read, 1000/portMAX_DELAY);
|
||||
if(bytes_read>0) {
|
||||
printf("read data size: %d\n", bytes_read);
|
||||
for(int i=length; i<length + bytes_read; i++) {
|
||||
if(i2s_read_buff[i] == 100) {
|
||||
flag=1;
|
||||
i2s_read(I2S_NUM_0, i2s_read_buff + length, sizeof(uint8_t) * 500, &bytes_read, 1000 / portMAX_DELAY);
|
||||
if (bytes_read > 0) {
|
||||
for (int i = length; i < length + bytes_read; i++) {
|
||||
if (i2s_read_buff[i] == 100) {
|
||||
flag = 1;
|
||||
end_position = i;
|
||||
break;
|
||||
}
|
||||
@@ -204,70 +223,16 @@ TEST_CASE("I2S Loopback test(master tx and rx)", "[i2s]")
|
||||
length = length + bytes_read;
|
||||
}
|
||||
// test the read data right or not
|
||||
for(int i=end_position-99; i<=end_position; i++) {
|
||||
TEST_ASSERT_EQUAL_UINT8((i-end_position+100), *(i2s_read_buff + i));
|
||||
for (int i = end_position - 99; i <= end_position; i++) {
|
||||
TEST_ASSERT_EQUAL_UINT8((i - end_position + 100), *(i2s_read_buff + i));
|
||||
}
|
||||
free(data_wr);
|
||||
free(i2s_read_buff);
|
||||
i2s_driver_uninstall(I2S_NUM_0);
|
||||
}
|
||||
|
||||
#if !DISABLED_FOR_TARGETS(ESP32S2)
|
||||
/* ESP32S2 has only single I2S port and hence following test cases are not applicable */
|
||||
TEST_CASE("I2S adc test", "[i2s]")
|
||||
{
|
||||
// init I2S ADC
|
||||
i2s_config_t i2s_config = {
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN,
|
||||
.sample_rate = SAMPLE_RATE,
|
||||
.bits_per_sample = SAMPLE_BITS,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||
.intr_alloc_flags = 0,
|
||||
.dma_buf_count = 2,
|
||||
.dma_buf_len = 1024,
|
||||
.use_apll = 0,
|
||||
};
|
||||
// install and start I2S driver
|
||||
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
|
||||
// init ADC pad
|
||||
i2s_set_adc_mode(ADC_UNIT_1, ADC1_CHANNEL_4);
|
||||
// enable adc sampling, ADC_WIDTH_BIT_12, ADC_ATTEN_DB_11 hard-coded in adc_i2s_mode_init
|
||||
i2s_adc_enable(I2S_NUM_0);
|
||||
// init read buffer
|
||||
uint16_t* i2sReadBuffer = (uint16_t*)calloc(1024, sizeof(uint16_t));
|
||||
size_t bytesRead;
|
||||
|
||||
for (int loop = 0; loop < 10; loop++) {
|
||||
for (int level = 0; level <= 1; level++) {
|
||||
if (level == 0) {
|
||||
gpio_set_pull_mode(ADC1_CHANNEL_4_IO, GPIO_PULLDOWN_ONLY);
|
||||
} else {
|
||||
gpio_set_pull_mode(ADC1_CHANNEL_4_IO, GPIO_PULLUP_ONLY);
|
||||
}
|
||||
vTaskDelay(200 / portTICK_RATE_MS);
|
||||
// read data from adc, will block until buffer is full
|
||||
i2s_read(I2S_NUM_0, (void*)i2sReadBuffer, 1024 * sizeof(uint16_t), &bytesRead, portMAX_DELAY);
|
||||
|
||||
// calc average
|
||||
int64_t adcSumValue = 0;
|
||||
for (size_t i = 0; i < 1024; i++) {
|
||||
adcSumValue += i2sReadBuffer[i] & 0xfff;
|
||||
}
|
||||
int adcAvgValue = adcSumValue / 1024;
|
||||
printf("adc average val: %d\n", adcAvgValue);
|
||||
|
||||
if (level == 0) {
|
||||
TEST_ASSERT_LESS_THAN(100, adcAvgValue);
|
||||
} else {
|
||||
TEST_ASSERT_GREATER_THAN(4000, adcAvgValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
i2s_adc_disable(I2S_NUM_0);
|
||||
free(i2sReadBuffer);
|
||||
i2s_driver_uninstall(I2S_NUM_0);
|
||||
}
|
||||
|
||||
#if SOC_I2S_NUM > 1
|
||||
/* ESP32S2 and ESP32C3 has only single I2S port and hence following test cases are not applicable */
|
||||
TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]")
|
||||
{
|
||||
// master driver installed and send data
|
||||
@@ -280,7 +245,7 @@ TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]")
|
||||
.dma_buf_count = 6,
|
||||
.dma_buf_len = 100,
|
||||
.use_apll = 0,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 ,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
|
||||
};
|
||||
i2s_pin_config_t master_pin_config = {
|
||||
.bck_io_num = MASTER_BCK_IO,
|
||||
@@ -302,7 +267,7 @@ TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]")
|
||||
.dma_buf_count = 6,
|
||||
.dma_buf_len = 100,
|
||||
.use_apll = 0,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 ,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
|
||||
};
|
||||
i2s_pin_config_t slave_pin_config = {
|
||||
.bck_io_num = SLAVE_BCK_IO,
|
||||
@@ -316,26 +281,27 @@ TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]")
|
||||
i2s_test_io_config(I2S_TEST_MODE_MASTER_TO_SLAVE);
|
||||
printf("\r\nheap size: %d\n", esp_get_free_heap_size());
|
||||
|
||||
uint8_t* data_wr = (uint8_t*)malloc(sizeof(uint8_t)*400);
|
||||
uint8_t *data_wr = (uint8_t *)malloc(sizeof(uint8_t) * 400);
|
||||
size_t i2s_bytes_write = 0;
|
||||
size_t bytes_read = 0;
|
||||
int length = 0;
|
||||
uint8_t *i2s_read_buff = (uint8_t*)malloc(sizeof(uint8_t)*10000);
|
||||
uint8_t *i2s_read_buff = (uint8_t *)malloc(sizeof(uint8_t) * 10000);
|
||||
|
||||
for(int i=0; i<100; i++) {
|
||||
data_wr[i] = i+1;
|
||||
for (int i = 0; i < 100; i++) {
|
||||
data_wr[i] = i + 1;
|
||||
}
|
||||
int flag=0; // break loop flag
|
||||
int flag = 0; // break loop flag
|
||||
int end_position = 0;
|
||||
// write data to slave
|
||||
i2s_write(I2S_NUM_0, data_wr, sizeof(uint8_t)*400, &i2s_bytes_write, 1000 / portTICK_PERIOD_MS);
|
||||
while(!flag){
|
||||
i2s_read(I2S_NUM_1, i2s_read_buff + length, sizeof(uint8_t)*500, &bytes_read, 1000/portMAX_DELAY);
|
||||
if(bytes_read>0) {
|
||||
i2s_write(I2S_NUM_0, data_wr, sizeof(uint8_t) * 400, &i2s_bytes_write, 1000 / portTICK_PERIOD_MS);
|
||||
printf("write data size: %d\n", i2s_bytes_write);
|
||||
while (!flag) {
|
||||
i2s_read(I2S_NUM_1, i2s_read_buff + length, sizeof(uint8_t) * 500, &bytes_read, 1000 / portTICK_PERIOD_MS);
|
||||
if (bytes_read > 0) {
|
||||
printf("read data size: %d\n", bytes_read);
|
||||
for(int i=length; i<length + bytes_read; i++) {
|
||||
if(i2s_read_buff[i] == 100) {
|
||||
flag=1;
|
||||
for (int i = length; i < length + bytes_read; i++) {
|
||||
if (i2s_read_buff[i] == 100) {
|
||||
flag = 1;
|
||||
end_position = i;
|
||||
break;
|
||||
}
|
||||
@@ -344,8 +310,8 @@ TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]")
|
||||
length = length + bytes_read;
|
||||
}
|
||||
// test the readed data right or not
|
||||
for(int i=end_position-99; i<=end_position; i++) {
|
||||
TEST_ASSERT_EQUAL_UINT8((i-end_position+100), *(i2s_read_buff + i));
|
||||
for (int i = end_position - 99; i <= end_position; i++) {
|
||||
TEST_ASSERT_EQUAL_UINT8((i - end_position + 100), *(i2s_read_buff + i));
|
||||
}
|
||||
free(data_wr);
|
||||
free(i2s_read_buff);
|
||||
@@ -365,7 +331,7 @@ TEST_CASE("I2S write and read test(master rx and slave tx)", "[i2s]")
|
||||
.dma_buf_count = 6,
|
||||
.dma_buf_len = 100,
|
||||
.use_apll = 1,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 ,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
|
||||
};
|
||||
i2s_pin_config_t master_pin_config = {
|
||||
.bck_io_num = MASTER_BCK_IO,
|
||||
@@ -387,7 +353,7 @@ TEST_CASE("I2S write and read test(master rx and slave tx)", "[i2s]")
|
||||
.dma_buf_count = 6,
|
||||
.dma_buf_len = 100,
|
||||
.use_apll = 1,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 ,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
|
||||
};
|
||||
i2s_pin_config_t slave_pin_config = {
|
||||
.bck_io_num = SLAVE_BCK_IO,
|
||||
@@ -399,28 +365,29 @@ TEST_CASE("I2S write and read test(master rx and slave tx)", "[i2s]")
|
||||
TEST_ESP_OK(i2s_driver_install(I2S_NUM_1, &slave_i2s_config, 0, NULL));
|
||||
TEST_ESP_OK(i2s_set_pin(I2S_NUM_1, &slave_pin_config));
|
||||
i2s_test_io_config(I2S_TEST_MODE_SLAVE_TO_MAXTER);
|
||||
printf("\r\nheap size: %d\n", esp_get_free_heap_size());
|
||||
|
||||
uint8_t* data_wr = (uint8_t*)malloc(sizeof(uint8_t)*400);
|
||||
uint8_t *data_wr = (uint8_t *)malloc(sizeof(uint8_t) * 400);
|
||||
size_t i2s_bytes_write = 0;
|
||||
size_t bytes_read = 0;
|
||||
int length = 0;
|
||||
uint8_t *i2s_read_buff = (uint8_t*)malloc(sizeof(uint8_t)*100000);
|
||||
uint8_t *i2s_read_buff = (uint8_t *)malloc(sizeof(uint8_t) * 10000);
|
||||
|
||||
for(int i=0; i<100; i++) {
|
||||
data_wr[i] = i+1;
|
||||
for (int i = 0; i < 100; i++) {
|
||||
data_wr[i] = i + 1;
|
||||
}
|
||||
// slave write data to master
|
||||
i2s_write(I2S_NUM_1, data_wr, sizeof(uint8_t)*400, &i2s_bytes_write, 1000 / portTICK_PERIOD_MS);
|
||||
|
||||
int flag=0; // break loop flag
|
||||
i2s_write(I2S_NUM_1, data_wr, sizeof(uint8_t) * 400, &i2s_bytes_write, 1000 / portTICK_PERIOD_MS);
|
||||
printf("write data size: %d\n", i2s_bytes_write);
|
||||
int flag = 0; // break loop flag
|
||||
int end_position = 0;
|
||||
// write data to slave
|
||||
while(!flag){
|
||||
TEST_ESP_OK(i2s_read(I2S_NUM_0, i2s_read_buff + length, 10000-length, &bytes_read, 1000/portMAX_DELAY));
|
||||
if(bytes_read > 0) {
|
||||
for(int i=length; i<length+bytes_read; i++) {
|
||||
if(i2s_read_buff[i] == 100) {
|
||||
flag=1;
|
||||
while (!flag) {
|
||||
TEST_ESP_OK(i2s_read(I2S_NUM_0, i2s_read_buff + length, 10000 - length, &bytes_read, 1000 / portTICK_PERIOD_MS));
|
||||
if (bytes_read > 0) {
|
||||
for (int i = length; i < length + bytes_read; i++) {
|
||||
if (i2s_read_buff[i] == 100) {
|
||||
flag = 1;
|
||||
end_position = i;
|
||||
break;
|
||||
}
|
||||
@@ -429,8 +396,8 @@ TEST_CASE("I2S write and read test(master rx and slave tx)", "[i2s]")
|
||||
length = length + bytes_read;
|
||||
}
|
||||
// test the readed data right or not
|
||||
for(int i=end_position-99; i<=end_position; i++) {
|
||||
TEST_ASSERT_EQUAL_UINT8((i-end_position+100), *(i2s_read_buff + i));
|
||||
for (int i = end_position - 99; i <= end_position; i++) {
|
||||
TEST_ASSERT_EQUAL_UINT8((i - end_position + 100), *(i2s_read_buff + i));
|
||||
}
|
||||
free(data_wr);
|
||||
free(i2s_read_buff);
|
||||
@@ -450,7 +417,7 @@ TEST_CASE("I2S memory leaking test", "[i2s]")
|
||||
.dma_buf_count = 6,
|
||||
.dma_buf_len = 100,
|
||||
.use_apll = 0,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 ,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
|
||||
};
|
||||
i2s_pin_config_t master_pin_config = {
|
||||
.bck_io_num = MASTER_BCK_IO,
|
||||
@@ -464,7 +431,7 @@ TEST_CASE("I2S memory leaking test", "[i2s]")
|
||||
i2s_driver_uninstall(I2S_NUM_0);
|
||||
int initial_size = esp_get_free_heap_size();
|
||||
|
||||
for(int i=0; i<100; i++) {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &master_i2s_config, 0, NULL));
|
||||
TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &master_pin_config));
|
||||
i2s_driver_uninstall(I2S_NUM_0);
|
||||
@@ -496,7 +463,9 @@ TEST_CASE("I2S APLL clock variation test", "[i2s]")
|
||||
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
|
||||
.dma_buf_count = 6,
|
||||
.dma_buf_len = 60,
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
.use_apll = true,
|
||||
#endif
|
||||
.intr_alloc_flags = 0,
|
||||
};
|
||||
|
||||
@@ -508,14 +477,14 @@ TEST_CASE("I2S APLL clock variation test", "[i2s]")
|
||||
uint32_t sample_rate_arr[8] = { 10675, 11025, 16000, 22050, 32000, 44100, 48000, 96000 };
|
||||
int bits_per_sample_arr[3] = { 16, 24, 32 };
|
||||
|
||||
for (int i = 0; i < (sizeof(sample_rate_arr)/sizeof(sample_rate_arr[0])); i++) {
|
||||
for (int j = 0; j < (sizeof(bits_per_sample_arr)/sizeof(bits_per_sample_arr[0])); j++) {
|
||||
for (int i = 0; i < (sizeof(sample_rate_arr) / sizeof(sample_rate_arr[0])); i++) {
|
||||
for (int j = 0; j < (sizeof(bits_per_sample_arr) / sizeof(bits_per_sample_arr[0])); j++) {
|
||||
i2s_config.sample_rate = sample_rate_arr[i];
|
||||
i2s_config.bits_per_sample = bits_per_sample_arr[j];
|
||||
|
||||
TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL));
|
||||
TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &pin_config));
|
||||
TEST_ASSERT((fabs((i2s_get_clk(I2S_NUM_0) - sample_rate_arr[i]))/(sample_rate_arr[i]))*100 < PERCENT_DIFF);
|
||||
TEST_ASSERT((fabs((i2s_get_clk(I2S_NUM_0) - sample_rate_arr[i])) / (sample_rate_arr[i])) * 100 < PERCENT_DIFF);
|
||||
TEST_ESP_OK(i2s_driver_uninstall(I2S_NUM_0));
|
||||
TEST_ASSERT(initial_size == esp_get_free_heap_size());
|
||||
}
|
||||
@@ -525,4 +494,93 @@ TEST_CASE("I2S APLL clock variation test", "[i2s]")
|
||||
TEST_ASSERT(initial_size == esp_get_free_heap_size());
|
||||
}
|
||||
|
||||
#if SOC_I2S_SUPPORTS_ADC_DAC
|
||||
/* Only ESP32 need I2S adc/dac test */
|
||||
TEST_CASE("I2S adc test", "[i2s]")
|
||||
{
|
||||
// init I2S ADC
|
||||
i2s_config_t i2s_config = {
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN,
|
||||
.sample_rate = SAMPLE_RATE,
|
||||
.bits_per_sample = SAMPLE_BITS,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||
.intr_alloc_flags = 0,
|
||||
.dma_buf_count = 2,
|
||||
.dma_buf_len = 1024,
|
||||
.use_apll = 0,
|
||||
};
|
||||
// install and start I2S driver
|
||||
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
|
||||
// init ADC pad
|
||||
i2s_set_adc_mode(ADC_UNIT_1, ADC1_CHANNEL_4);
|
||||
// enable adc sampling, ADC_WIDTH_BIT_12, ADC_ATTEN_DB_11 hard-coded in adc_i2s_mode_init
|
||||
i2s_adc_enable(I2S_NUM_0);
|
||||
// init read buffer
|
||||
uint16_t *i2sReadBuffer = (uint16_t *)calloc(1024, sizeof(uint16_t));
|
||||
size_t bytesRead;
|
||||
|
||||
for (int loop = 0; loop < 10; loop++) {
|
||||
for (int level = 0; level <= 1; level++) {
|
||||
if (level == 0) {
|
||||
gpio_set_pull_mode(ADC1_CHANNEL_4_IO, GPIO_PULLDOWN_ONLY);
|
||||
} else {
|
||||
gpio_set_pull_mode(ADC1_CHANNEL_4_IO, GPIO_PULLUP_ONLY);
|
||||
}
|
||||
vTaskDelay(200 / portTICK_RATE_MS);
|
||||
// read data from adc, will block until buffer is full
|
||||
i2s_read(I2S_NUM_0, (void *)i2sReadBuffer, 1024 * sizeof(uint16_t), &bytesRead, portMAX_DELAY);
|
||||
|
||||
// calc average
|
||||
int64_t adcSumValue = 0;
|
||||
for (size_t i = 0; i < 1024; i++) {
|
||||
adcSumValue += i2sReadBuffer[i] & 0xfff;
|
||||
}
|
||||
int adcAvgValue = adcSumValue / 1024;
|
||||
printf("adc average val: %d\n", adcAvgValue);
|
||||
|
||||
if (level == 0) {
|
||||
if (adcAvgValue > 100) {
|
||||
i2s_adc_disable(I2S_NUM_0);
|
||||
free(i2sReadBuffer);
|
||||
i2s_driver_uninstall(I2S_NUM_0);
|
||||
TEST_ASSERT_LESS_THAN(100, adcAvgValue);
|
||||
}
|
||||
} else {
|
||||
if (adcAvgValue < 4000) {
|
||||
i2s_adc_disable(I2S_NUM_0);
|
||||
free(i2sReadBuffer);
|
||||
i2s_driver_uninstall(I2S_NUM_0);
|
||||
TEST_ASSERT_GREATER_THAN(4000, adcAvgValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i2s_adc_disable(I2S_NUM_0);
|
||||
free(i2sReadBuffer);
|
||||
i2s_driver_uninstall(I2S_NUM_0);
|
||||
}
|
||||
|
||||
TEST_CASE("I2S dac test", "[i2s]")
|
||||
{
|
||||
// dac, adc i2s
|
||||
i2s_config_t i2s_config = {
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
|
||||
.sample_rate = SAMPLE_RATE,
|
||||
.bits_per_sample = SAMPLE_BITS,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
|
||||
.dma_buf_count = 6,
|
||||
.dma_buf_len = 60,
|
||||
.use_apll = 0,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
|
||||
};
|
||||
|
||||
//install and start i2s driver
|
||||
TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL));
|
||||
//for internal DAC, this will enable both of the internal channels
|
||||
TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, NULL));
|
||||
//stop & destroy i2s driver
|
||||
TEST_ESP_OK(i2s_driver_uninstall(I2S_NUM_0));
|
||||
}
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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,263 +12,269 @@
|
||||
// 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 "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)
|
||||
/**
|
||||
* @brief Calculate the closest sample rate clock configuration.
|
||||
* clock relationship:
|
||||
* Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a)
|
||||
*
|
||||
* @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_ll_clk_cal_t` structure.
|
||||
*/
|
||||
static void i2s_hal_clk_cal(uint32_t fsclk, uint32_t fbck, int bck_div, i2s_ll_clk_cal_t *cal)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
i2s_ll_reset_tx_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)
|
||||
{
|
||||
switch (i2s_config->communication_format) {
|
||||
case I2S_COMM_FORMAT_STAND_MSB:
|
||||
if (i2s_config->mode & I2S_MODE_TX) {
|
||||
i2s_ll_set_tx_format_msb_align(hal->dev);
|
||||
}
|
||||
if (i2s_config->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) {
|
||||
i2s_ll_set_tx_pcm_short(hal->dev);
|
||||
}
|
||||
if (i2s_config->mode & I2S_MODE_RX) {
|
||||
i2s_ll_set_rx_pcm_short(hal->dev);
|
||||
}
|
||||
break;
|
||||
default: //I2S_COMM_FORMAT_STAND_I2S
|
||||
if (i2s_config->mode & I2S_MODE_TX) {
|
||||
i2s_ll_set_tx_format_philip(hal->dev);
|
||||
}
|
||||
if (i2s_config->mode & I2S_MODE_RX) {
|
||||
i2s_ll_set_rx_format_philip(hal->dev);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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_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 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.
|
||||
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;
|
||||
}
|
||||
#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) {
|
||||
i2s_ll_build_in_dac_ena(hal->dev);
|
||||
}
|
||||
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.
|
||||
for (int a = 2; a <= I2S_LL_MCLK_DIVIDER_MAX; 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;
|
||||
}
|
||||
#endif
|
||||
|
||||
i2s_hal_format_config(hal, i2s_config);
|
||||
if (abs((mb - ma)) < min) {
|
||||
cal->a = a;
|
||||
cal->b = b;
|
||||
min = abs(mb - ma);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void i2s_hal_enable_master_mode(i2s_hal_context_t *hal)
|
||||
void i2s_hal_set_clock_src(i2s_hal_context_t *hal, i2s_clock_src_t sel)
|
||||
{
|
||||
i2s_ll_set_tx_slave_mod(hal->dev, 0); //MASTER Slave
|
||||
i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave
|
||||
i2s_ll_tx_clk_set_src(hal->dev, sel);
|
||||
i2s_ll_rx_clk_set_src(hal->dev, sel);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
i2s_ll_set_tx_slave_mod(hal->dev, 1); //TX Slave
|
||||
i2s_ll_set_rx_slave_mod(hal->dev, 1); //RX Slave
|
||||
i2s_ll_clk_cal_t clk_set = {0};
|
||||
i2s_hal_clk_cal(sclk, fbck, factor, &clk_set);
|
||||
i2s_ll_tx_set_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_ll_clk_cal_t clk_set = {0};
|
||||
i2s_hal_clk_cal(sclk, fbck, factor, &clk_set);
|
||||
i2s_ll_rx_set_clk(hal->dev, &clk_set);
|
||||
}
|
||||
|
||||
void i2s_hal_enable_master_fd_mode(i2s_hal_context_t *hal)
|
||||
{
|
||||
i2s_ll_tx_set_slave_mod(hal->dev, 0); //TX master
|
||||
i2s_ll_rx_set_slave_mod(hal->dev, 1); //RX Slave
|
||||
}
|
||||
|
||||
void i2s_hal_enable_slave_fd_mode(i2s_hal_context_t *hal)
|
||||
{
|
||||
i2s_ll_tx_set_slave_mod(hal->dev, 1); //TX Slave
|
||||
i2s_ll_rx_set_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);
|
||||
i2s_ll_enable_clock(hal->dev);
|
||||
}
|
||||
|
||||
void i2s_hal_tx_set_pdm_mode_default(i2s_hal_context_t *hal, uint32_t sample_rate)
|
||||
{
|
||||
#if SOC_I2S_SUPPORTS_PDM_TX
|
||||
/* enable pdm tx mode */
|
||||
i2s_ll_tx_enable_pdm(hal->dev, true);
|
||||
/* set pdm tx default presacle */
|
||||
i2s_ll_tx_set_pdm_prescale(hal->dev, 0);
|
||||
/* set pdm tx default sacle of high pass filter */
|
||||
i2s_ll_tx_set_pdm_hp_scale(hal->dev, I2S_PDM_SIG_SCALING_MUL_1);
|
||||
/* set pdm tx default sacle of low pass filter */
|
||||
i2s_ll_tx_set_pdm_lp_scale(hal->dev, I2S_PDM_SIG_SCALING_MUL_1);
|
||||
/* set pdm tx default sacle of sinc filter */
|
||||
i2s_ll_tx_set_pdm_sinc_scale(hal->dev, I2S_PDM_SIG_SCALING_MUL_1);
|
||||
/* set pdm tx default sacle of sigma-delta filter */
|
||||
i2s_ll_tx_set_pdm_sd_scale(hal->dev, I2S_PDM_SIG_SCALING_MUL_1);
|
||||
/* set pdm tx sample rate */
|
||||
i2s_ll_tx_set_pdm_fpfs(hal->dev, 960, sample_rate / 100);
|
||||
|
||||
#if SOC_I2S_SUPPORTS_PDM_CODEC
|
||||
/* enable pdm high pass filter */
|
||||
i2s_ll_tx_enable_pdm_hp_filter(hal->dev, true);
|
||||
/* set pdm tx high pass filter parameters */
|
||||
i2s_ll_tx_set_pdm_hp_filter_param0(hal->dev, 6);
|
||||
i2s_ll_tx_set_pdm_hp_filter_param5(hal->dev, 7);
|
||||
/* enable pdm sigma-delta codec */
|
||||
i2s_ll_tx_enable_pdm_sd_codec(hal->dev, true);
|
||||
/* set pdm tx sigma-delta codec dither */
|
||||
i2s_ll_tx_set_pdm_sd_dither(hal->dev, 0);
|
||||
i2s_ll_tx_set_pdm_sd_dither2(hal->dev, 0);
|
||||
|
||||
#endif // SOC_I2S_SUPPORTS_PDM_CODEC
|
||||
#endif // SOC_I2S_SUPPORTS_PDM_TX
|
||||
}
|
||||
|
||||
void i2s_hal_rx_set_pdm_mode_default(i2s_hal_context_t *hal)
|
||||
{
|
||||
#if SOC_I2S_SUPPORTS_PDM_RX
|
||||
/* enable pdm rx mode */
|
||||
i2s_ll_rx_enable_pdm(hal->dev, true);
|
||||
/* set pdm rx downsample number */
|
||||
i2s_ll_rx_set_pdm_dsr(hal->dev, I2S_PDM_DSR_8S);
|
||||
#endif // SOC_I2S_SUPPORTS_PDM_RX
|
||||
}
|
||||
|
||||
|
||||
void i2s_hal_tx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg)
|
||||
{
|
||||
/* disable pdm tx mode */
|
||||
i2s_ll_tx_enable_pdm(hal->dev, false);
|
||||
|
||||
#if SOC_I2S_SUPPORTS_TDM
|
||||
i2s_ll_tx_enable_clock(hal->dev);
|
||||
i2s_ll_tx_clk_set_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default
|
||||
i2s_ll_mclk_use_tx_clk(hal->dev);
|
||||
|
||||
i2s_ll_tx_set_active_chan_mask(hal->dev, hal_cfg->chan_mask);
|
||||
i2s_ll_tx_enable_left_align(hal->dev, hal_cfg->left_align);
|
||||
i2s_ll_tx_enable_big_endian(hal->dev, hal_cfg->big_edin);
|
||||
i2s_ll_tx_set_bit_order(hal->dev, hal_cfg->bit_order_msb);
|
||||
i2s_ll_tx_set_skip_mask(hal->dev, hal_cfg->skip_msk);
|
||||
#else
|
||||
i2s_ll_tx_enable_msb_right(hal->dev, false);
|
||||
i2s_ll_tx_enable_right_first(hal->dev, false);
|
||||
i2s_ll_tx_force_enable_fifo_mod(hal->dev, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void i2s_hal_rx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg)
|
||||
{
|
||||
/* disable pdm rx mode */
|
||||
i2s_ll_rx_enable_pdm(hal->dev, false);
|
||||
|
||||
#if SOC_I2S_SUPPORTS_TDM
|
||||
i2s_ll_rx_enable_clock(hal->dev);
|
||||
i2s_ll_rx_clk_set_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default
|
||||
i2s_ll_mclk_use_rx_clk(hal->dev);
|
||||
|
||||
i2s_ll_rx_set_active_chan_mask(hal->dev, hal_cfg->chan_mask);
|
||||
i2s_ll_rx_enable_left_align(hal->dev, hal_cfg->left_align);
|
||||
i2s_ll_rx_enable_big_endian(hal->dev, hal_cfg->big_edin);
|
||||
i2s_ll_rx_set_bit_order(hal->dev, hal_cfg->bit_order_msb);
|
||||
#else
|
||||
i2s_ll_rx_enable_msb_right(hal->dev, false);
|
||||
i2s_ll_rx_enable_right_first(hal->dev, false);
|
||||
i2s_ll_rx_force_enable_fifo_mod(hal->dev, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint32_t i2s_hal_get_ws_bit(i2s_comm_format_t fmt, uint32_t chan_num, uint32_t chan_bits)
|
||||
{
|
||||
switch (fmt) {
|
||||
case I2S_COMM_FORMAT_STAND_MSB:
|
||||
return chan_num * chan_bits / 2;
|
||||
case I2S_COMM_FORMAT_STAND_PCM_SHORT:
|
||||
return 1;
|
||||
case I2S_COMM_FORMAT_STAND_PCM_LONG:
|
||||
return chan_bits;
|
||||
default: //I2S_COMM_FORMAT_STAND_I2S
|
||||
return chan_num * chan_bits / 2;
|
||||
}
|
||||
}
|
||||
|
||||
void i2s_hal_tx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg)
|
||||
{
|
||||
uint32_t chan_num = 2;
|
||||
uint32_t chan_bits = hal_cfg->bits_cfg.chan_bits;
|
||||
uint32_t data_bits = hal_cfg->bits_cfg.sample_bits;
|
||||
|
||||
/* Set channel number and valid data bits */
|
||||
#if SOC_I2S_SUPPORTS_TDM
|
||||
chan_num = hal_cfg->total_chan;
|
||||
i2s_ll_tx_set_chan_num(hal->dev, chan_num);
|
||||
#endif
|
||||
i2s_ll_tx_set_sample_bit(hal->dev, chan_bits, data_bits);
|
||||
|
||||
/* Set communication format */
|
||||
bool shift_en = hal_cfg->comm_fmt == I2S_COMM_FORMAT_STAND_I2S ? true : false;
|
||||
uint32_t ws_width = i2s_hal_get_ws_bit(hal_cfg->comm_fmt, chan_num, chan_bits);
|
||||
i2s_ll_tx_enable_msb_shift(hal->dev, shift_en);
|
||||
i2s_ll_tx_set_ws_width(hal->dev, ws_width);
|
||||
#if SOC_I2S_SUPPORTS_TDM
|
||||
i2s_ll_tx_set_half_sample_bit(hal->dev, chan_num * chan_bits / 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
void i2s_hal_rx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg)
|
||||
{
|
||||
uint32_t chan_num = 2;
|
||||
uint32_t chan_bits = hal_cfg->bits_cfg.chan_bits;
|
||||
uint32_t data_bits = hal_cfg->bits_cfg.sample_bits;
|
||||
|
||||
#if SOC_I2S_SUPPORTS_TDM
|
||||
chan_num = hal_cfg->total_chan;
|
||||
i2s_ll_rx_set_chan_num(hal->dev, chan_num);
|
||||
#endif
|
||||
i2s_ll_rx_set_sample_bit(hal->dev, chan_bits, data_bits);
|
||||
|
||||
/* Set communication format */
|
||||
bool shift_en = hal_cfg->comm_fmt == I2S_COMM_FORMAT_STAND_I2S ? true : false;
|
||||
uint32_t ws_width = i2s_hal_get_ws_bit(hal_cfg->comm_fmt, chan_num, chan_bits);
|
||||
i2s_ll_rx_enable_msb_shift(hal->dev, shift_en);
|
||||
i2s_ll_rx_set_ws_width(hal->dev, ws_width);
|
||||
#if SOC_I2S_SUPPORTS_TDM
|
||||
i2s_ll_rx_set_half_sample_bit(hal->dev, chan_num * chan_bits / 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg)
|
||||
{
|
||||
if (hal_cfg->mode & I2S_MODE_TX) {
|
||||
i2s_ll_tx_stop(hal->dev);
|
||||
i2s_ll_tx_reset(hal->dev);
|
||||
i2s_ll_tx_set_slave_mod(hal->dev, (hal_cfg->mode & I2S_MODE_SLAVE) != 0); //TX Slave
|
||||
if (hal_cfg->mode & I2S_MODE_PDM) {
|
||||
/* Set tx pdm mode */
|
||||
i2s_hal_tx_set_pdm_mode_default(hal, hal_cfg->sample_rate);
|
||||
} else {
|
||||
/* Set tx common mode */
|
||||
i2s_hal_tx_set_common_mode(hal, hal_cfg);
|
||||
i2s_hal_tx_set_channel_style(hal, hal_cfg);
|
||||
}
|
||||
}
|
||||
if (hal_cfg->mode & I2S_MODE_RX) {
|
||||
i2s_ll_rx_stop(hal->dev);
|
||||
i2s_ll_rx_reset(hal->dev);
|
||||
i2s_ll_rx_set_slave_mod(hal->dev, (hal_cfg->mode & I2S_MODE_SLAVE) != 0); //RX Slave
|
||||
if (hal_cfg->mode & I2S_MODE_PDM) {
|
||||
/* Set rx pdm mode */
|
||||
i2s_hal_rx_set_pdm_mode_default(hal);
|
||||
} else {
|
||||
/* Set rx common mode */
|
||||
i2s_hal_rx_set_common_mode(hal, hal_cfg);
|
||||
i2s_hal_rx_set_channel_style(hal, hal_cfg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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,13 +25,45 @@
|
||||
|
||||
#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"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief I2S channel bits configurations
|
||||
*
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t sample_bits : 16; /*!< I2S sample bits in one channel */
|
||||
uint32_t chan_bits : 16; /*!< I2S total bits in one channel. Should not be smaller than 'sample_bits', default '0' means equal to 'sample_bits' */
|
||||
};
|
||||
uint32_t val; /*!< I2S cannel bits configiration value */
|
||||
} i2s_hal_bits_cfg_t;
|
||||
|
||||
/**
|
||||
* @brief I2S HAL configurations
|
||||
*/
|
||||
typedef struct {
|
||||
i2s_mode_t mode; /*!< I2S work mode, using ored mask of `i2s_mode_t`*/
|
||||
uint32_t sample_rate; /*!< I2S sample rate*/
|
||||
i2s_channel_t ch; /*!< I2S channels*/
|
||||
i2s_comm_format_t comm_fmt; /*!< I2S communication format */
|
||||
i2s_channel_fmt_t chan_fmt; /*!< I2S channel format, there are total 16 channels in TDM mode.*/
|
||||
i2s_hal_bits_cfg_t bits_cfg; /*!< Channel bits configuration*/
|
||||
#if SOC_I2S_SUPPORTS_TDM
|
||||
uint32_t total_chan; /*!< Total number of I2S channels */
|
||||
uint32_t chan_mask; /*!< Active channel bit mask, set value in `i2s_channel_t` to enable specific channel, the bit map of active channel can not exceed (0x1<<total_chan_num). */
|
||||
bool left_align; /*!< Set to enable left aligment */
|
||||
bool big_edin; /*!< Set to enable big edin */
|
||||
bool bit_order_msb; /*!< Set to enable msb order */
|
||||
bool skip_msk; /*!< Set to enable skip mask. If it is enabled, only the data of the enabled channels will be sent, otherwise all data stored in DMA TX buffer will be sent */
|
||||
#endif
|
||||
} i2s_hal_config_t;
|
||||
|
||||
/**
|
||||
* Context that should be maintained by both the driver and the HAL
|
||||
*/
|
||||
@@ -41,258 +73,431 @@ typedef struct {
|
||||
} 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
|
||||
*
|
||||
* @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
|
||||
* @brief Reset I2S TX channel
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
#define i2s_hal_enable_rx_intr(hal) i2s_ll_enable_rx_intr((hal)->dev)
|
||||
#define i2s_hal_reset_tx(hal) i2s_ll_tx_reset((hal)->dev)
|
||||
|
||||
/**
|
||||
* @brief Disable I2S rx interrupt
|
||||
* @brief Reset I2S TX fifo
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
#define i2s_hal_disable_rx_intr(hal) i2s_ll_disable_rx_intr((hal)->dev)
|
||||
#define i2s_hal_reset_tx_fifo(hal) i2s_ll_tx_reset_fifo((hal)->dev)
|
||||
|
||||
/**
|
||||
* @brief Disable I2S tx interrupt
|
||||
* @brief Reset I2S RX channel
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
#define i2s_hal_disable_tx_intr(hal) i2s_ll_disable_tx_intr((hal)->dev)
|
||||
#define i2s_hal_reset_rx(hal) i2s_ll_rx_reset((hal)->dev)
|
||||
|
||||
/**
|
||||
* @brief Enable I2S tx interrupt
|
||||
* @brief Reset I2S RX fifo
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
#define i2s_hal_enable_tx_intr(hal) i2s_ll_enable_tx_intr((hal)->dev)
|
||||
#define i2s_hal_reset_rx_fifo(hal) i2s_ll_rx_reset_fifo((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 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
|
||||
*
|
||||
* @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 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
|
||||
* @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)
|
||||
*/
|
||||
void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num);
|
||||
|
||||
#if SOC_I2S_SUPPORTS_PDM
|
||||
/**
|
||||
* @brief Set I2S tx pdm
|
||||
* @brief Configure I2S source clock
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param fp tx pdm fp
|
||||
* @param fs tx pdm fs
|
||||
* @param sel The source clock index
|
||||
*/
|
||||
void i2s_hal_tx_pdm_cfg(i2s_hal_context_t *hal, uint32_t fp, uint32_t fs);
|
||||
void i2s_hal_set_clock_src(i2s_hal_context_t *hal, i2s_clock_src_t sel);
|
||||
|
||||
/**
|
||||
* @brief Get I2S tx pdm
|
||||
* @brief Set Tx channel style
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param dsr rx pdm dsr
|
||||
* @param hal_cfg I2S hal configuration structer, refer to `i2s_hal_config_t`
|
||||
*/
|
||||
void i2s_hal_rx_pdm_cfg(i2s_hal_context_t *hal, uint32_t dsr);
|
||||
void i2s_hal_tx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg);
|
||||
|
||||
/**
|
||||
* @brief Get I2S tx pdm configuration
|
||||
* @brief Set Rx channel style
|
||||
*
|
||||
* @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
|
||||
* @param hal_cfg I2S hal configuration structer, refer to `i2s_hal_config_t`
|
||||
*/
|
||||
void i2s_hal_get_tx_pdm(i2s_hal_context_t *hal, uint32_t *fp, uint32_t *fs);
|
||||
void i2s_hal_rx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg);
|
||||
|
||||
/**
|
||||
* @brief Get I2S rx pdm configuration
|
||||
* @brief Config I2S param
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param dsr rx pdm dsr
|
||||
* @param hal_cfg I2S hal configuration structer, refer to `i2s_hal_config_t`
|
||||
*/
|
||||
void i2s_hal_get_rx_pdm(i2s_hal_context_t *hal, uint32_t *dsr);
|
||||
void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg);
|
||||
|
||||
/**
|
||||
* @brief Enable I2S master full-duplex mode
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
void i2s_hal_enable_master_fd_mode(i2s_hal_context_t *hal);
|
||||
|
||||
/**
|
||||
* @brief Enable I2S slave full-duplex mode
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
void i2s_hal_enable_slave_fd_mode(i2s_hal_context_t *hal);
|
||||
|
||||
/**
|
||||
* @brief Start I2S tx
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
#define i2s_hal_start_tx(hal) i2s_ll_tx_start((hal)->dev)
|
||||
|
||||
/**
|
||||
* @brief Start I2S rx
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
#define i2s_hal_start_rx(hal) i2s_ll_rx_start((hal)->dev)
|
||||
|
||||
/**
|
||||
* @brief Stop I2S tx
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
#define i2s_hal_stop_tx(hal) i2s_ll_tx_stop((hal)->dev)
|
||||
|
||||
/**
|
||||
* @brief Stop I2S rx
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
#define i2s_hal_stop_rx(hal) i2s_ll_rx_stop((hal)->dev)
|
||||
|
||||
/**
|
||||
* @brief Set the received data length to trigger `in_suc_eof` interrupt.
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param eof_byte The byte length that trigger in_suc_eof interrupt.
|
||||
*/
|
||||
#define i2s_hal_set_rx_eof_num(hal, eof_byte) i2s_ll_rx_set_eof_num((hal)->dev, eof_byte)
|
||||
|
||||
/**
|
||||
* @brief Set I2S TX sample bit
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param chan_bit I2S TX chan bit
|
||||
* @param data_bit The sample data bit length.
|
||||
*/
|
||||
#define i2s_hal_set_tx_sample_bit(hal, chan_bit, data_bit) i2s_ll_tx_set_sample_bit((hal)->dev, chan_bit, data_bit)
|
||||
|
||||
/**
|
||||
* @brief Set I2S RX sample bit
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param chan_bit I2S RX chan bit
|
||||
* @param data_bit The sample data bit length.
|
||||
*/
|
||||
#define i2s_hal_set_rx_sample_bit(hal, chan_bit, data_bit) i2s_ll_rx_set_sample_bit((hal)->dev, chan_bit, data_bit)
|
||||
|
||||
/**
|
||||
* @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_tx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbck, int factor);
|
||||
|
||||
/**
|
||||
* @brief Configure I2S RX 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_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbck, int factor);
|
||||
|
||||
#if SOC_I2S_SUPPORTS_PCM
|
||||
/**
|
||||
* @brief Configure I2S TX PCM encoder or decoder.
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param cfg PCM configure paramater, refer to `i2s_pcm_compress_t`
|
||||
*/
|
||||
#define i2s_hal_tx_pcm_cfg(hal, cfg) i2s_ll_tx_set_pcm_type((hal)->dev, cfg)
|
||||
|
||||
/**
|
||||
* @brief Configure I2S RX PCM encoder or decoder.
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param cfg PCM configure paramater, refer to `i2s_pcm_compress_t`
|
||||
*/
|
||||
#define i2s_hal_rx_pcm_cfg(hal, cfg) i2s_ll_rx_set_pcm_type((hal)->dev, cfg)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable loopback mode
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
#define i2s_hal_enable_sig_loopback(hal) i2s_ll_enable_loop_back((hal)->dev, true)
|
||||
|
||||
/**
|
||||
* @brief Set I2S configuration for common TX mode
|
||||
* @note Common mode is for non-PDM mode like philip/MSB/PCM
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param hal_cfg hal configuration structure
|
||||
*/
|
||||
void i2s_hal_tx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg);
|
||||
|
||||
/**
|
||||
* @brief Set I2S configuration for common RX mode
|
||||
* @note Common mode is for non-PDM mode like philip/MSB/PCM
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param hal_cfg hal configuration structure
|
||||
*/
|
||||
void i2s_hal_rx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg);
|
||||
|
||||
#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
|
||||
*/
|
||||
#define i2s_hal_set_tx_pdm_fpfs(hal, fp, fs) i2s_ll_tx_set_pdm_fpfs((hal)->dev, fp, fs)
|
||||
|
||||
/**
|
||||
* @brief Get I2S TX PDM fp
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @return
|
||||
* - fp configuration paramater
|
||||
*/
|
||||
#define i2s_hal_get_tx_pdm_fp(hal) i2s_ll_tx_get_pdm_fp((hal)->dev)
|
||||
|
||||
/**
|
||||
* @brief Get I2S TX PDM fs
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @return
|
||||
* - fs configuration paramater
|
||||
*/
|
||||
#define i2s_hal_get_tx_pdm_fs(hal) i2s_ll_tx_get_pdm_fs((hal)->dev)
|
||||
|
||||
/**
|
||||
* @brief Set I2S default configuration for PDM TX mode
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param sample_rate PDM sample rate
|
||||
*/
|
||||
void i2s_hal_tx_set_pdm_mode_default(i2s_hal_context_t *hal, uint32_t sample_rate);
|
||||
#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
|
||||
*/
|
||||
#define i2s_hal_set_rx_pdm_dsr(hal, dsr) i2s_ll_rx_set_pdm_dsr((hal)->dev, dsr)
|
||||
|
||||
/**
|
||||
* @brief Get RX PDM downsample configuration
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @param dsr Pointer to accept PDM downsample configuration
|
||||
*/
|
||||
#define i2s_hal_get_rx_pdm_dsr(hal, dsr) i2s_ll_rx_get_pdm_dsr((hal)->dev, dsr)
|
||||
|
||||
/**
|
||||
* @brief Set I2S default configuration for PDM R mode
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
void i2s_hal_rx_set_pdm_mode_default(i2s_hal_context_t *hal);
|
||||
#endif
|
||||
|
||||
#if !SOC_GDMA_SUPPORTED
|
||||
/**
|
||||
* @brief Enable I2S TX DMA
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
#define i2s_hal_enable_tx_dma(hal) i2s_ll_enable_dma((hal)->dev,true)
|
||||
|
||||
/**
|
||||
* @brief Enable I2S RX DMA
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
#define i2s_hal_enable_rx_dma(hal) i2s_ll_enable_dma((hal)->dev,true)
|
||||
|
||||
/**
|
||||
* @brief Disable I2S TX DMA
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
#define i2s_hal_disable_tx_dma(hal) i2s_ll_enable_dma((hal)->dev,false)
|
||||
|
||||
/**
|
||||
* @brief Disable I2S RX DMA
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
#define i2s_hal_disable_rx_dma(hal) i2s_ll_enable_dma((hal)->dev,false)
|
||||
|
||||
/**
|
||||
* @brief Get I2S interrupt status
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
* @return
|
||||
* - module interrupt status
|
||||
*/
|
||||
#define i2s_hal_get_intr_status(hal) i2s_ll_get_intr_status((hal)->dev)
|
||||
|
||||
/**
|
||||
* @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_rx_enable_intr((hal)->dev)
|
||||
|
||||
/**
|
||||
* @brief Disable I2S RX interrupt
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
#define i2s_hal_disable_rx_intr(hal) i2s_ll_rx_disable_intr((hal)->dev)
|
||||
|
||||
/**
|
||||
* @brief Disable I2S TX interrupt
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
#define i2s_hal_disable_tx_intr(hal) i2s_ll_tx_disable_intr((hal)->dev)
|
||||
|
||||
/**
|
||||
* @brief Enable I2S TX interrupt
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
#define i2s_hal_enable_tx_intr(hal) i2s_ll_tx_enable_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_tx_start_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_rx_start_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_tx_stop_link((hal)->dev)
|
||||
|
||||
/**
|
||||
* @brief Stop RX DMA link
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
#define i2s_hal_stop_rx_link(hal) i2s_ll_rx_stop_link((hal)->dev)
|
||||
|
||||
/**
|
||||
* @brief Reset RX DMA
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
#define i2s_hal_reset_rxdma(hal) i2s_ll_rx_reset_dma((hal)->dev)
|
||||
|
||||
/**
|
||||
* @brief Reset TX DMA
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
#define i2s_hal_reset_txdma(hal) i2s_ll_tx_reset_dma((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_tx_get_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_rx_get_eof_des_addr((hal)->dev, addr)
|
||||
#endif
|
||||
|
||||
#if SOC_I2S_SUPPORTS_ADC_DAC
|
||||
/**
|
||||
* @brief Enable Builtin DAC
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
#define i2s_hal_enable_builtin_dac(hal) i2s_ll_enable_builtin_dac((hal)->dev, true);
|
||||
|
||||
/**
|
||||
* @brief Enable Builtin ADC
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
#define i2s_hal_enable_builtin_adc(hal) i2s_ll_enable_builtin_adc((hal)->dev, true);
|
||||
|
||||
/**
|
||||
* @brief Disable Builtin DAC
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
#define i2s_hal_disable_builtin_dac(hal) i2s_ll_enable_builtin_dac((hal)->dev, false);
|
||||
|
||||
/**
|
||||
* @brief Disable Builtin ADC
|
||||
*
|
||||
* @param hal Context of the HAL layer
|
||||
*/
|
||||
#define i2s_hal_disable_builtin_adc(hal) i2s_ll_enable_builtin_adc((hal)->dev, false);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@@ -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"
|
||||
|
||||
@@ -23,35 +24,60 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief I2S port number, the max port number is (I2S_NUM_MAX -1).
|
||||
*/
|
||||
typedef enum {
|
||||
I2S_NUM_0 = 0, /*!< I2S port 0 */
|
||||
#if SOC_I2S_NUM > 1
|
||||
I2S_NUM_1 = 1, /*!< I2S port 1 */
|
||||
#endif
|
||||
I2S_NUM_MAX, /*!< I2S port max */
|
||||
} i2s_port_t;
|
||||
|
||||
/**
|
||||
* @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_8BIT = 8, /*!< data bit-width: 8 */
|
||||
I2S_BITS_PER_SAMPLE_16BIT = 16, /*!< data bit-width: 16 */
|
||||
I2S_BITS_PER_SAMPLE_24BIT = 24, /*!< data bit-width: 24 */
|
||||
I2S_BITS_PER_SAMPLE_32BIT = 32, /*!< data bit-width: 32 */
|
||||
} i2s_bits_per_sample_t;
|
||||
|
||||
/**
|
||||
* @brief I2S bit width per chan.
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
I2S_BITS_PER_CHAN_DEFAULT = (0), /*!< channel bit-width equals to data bit-width */
|
||||
I2S_BITS_PER_CHAN_8BIT = (8), /*!< channel bit-width: 8 */
|
||||
I2S_BITS_PER_CHAN_16BIT = (16), /*!< channel bit-width: 16 */
|
||||
I2S_BITS_PER_CHAN_24BIT = (24), /*!< channel bit-width: 24 */
|
||||
I2S_BITS_PER_CHAN_32BIT = (32), /*!< channel bit-width: 32 */
|
||||
} i2s_bits_per_chan_t;
|
||||
|
||||
/**
|
||||
* @brief I2S channel.
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
I2S_CHANNEL_MONO = 1, /*!< I2S 1 channel (mono)*/
|
||||
I2S_CHANNEL_STEREO = 2 /*!< I2S 2 channel (stereo)*/
|
||||
I2S_CHANNEL_MONO = (0x01 << 31) | 0x03, /*!< I2S channel (mono), two channel enabled. In this mode, you only need to send one channel data but the fifo will copy same data for another channel automatically, then both channels will transmit same data. The highest bit is for differentiating I2S_CHANNEL_STEREO since they both use two channels */
|
||||
I2S_CHANNEL_STEREO = 0x03, /*!< I2S channel (stereo), two channel enabled. In this mode, two channels will transmit different data. */
|
||||
#if SOC_I2S_SUPPORTS_TDM
|
||||
// Bit map of active chan.
|
||||
// There are 16 channels in TDM mode.
|
||||
// For TX module, only the active channel send the audio data, the inactive channel send a constant(configurable) or will be skiped if 'skip_msk' is set.
|
||||
// For RX module, only receive the audio data in active channels, the data in inactive channels will be ignored.
|
||||
// the bit map of active channel can not exceed (0x1<<total_chan_num).
|
||||
// e.g: active_chan_mask = (I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH3), here the active_chan_number is 2 and total_chan_num is not supposed to be smaller than 4.
|
||||
I2S_TDM_ACTIVE_CH0 = (0x1 << 0), /*!< I2S channel 0 enabled */
|
||||
I2S_TDM_ACTIVE_CH1 = (0x1 << 1), /*!< I2S channel 1 enabled */
|
||||
I2S_TDM_ACTIVE_CH2 = (0x1 << 2), /*!< I2S channel 2 enabled */
|
||||
I2S_TDM_ACTIVE_CH3 = (0x1 << 3), /*!< I2S channel 3 enabled */
|
||||
I2S_TDM_ACTIVE_CH4 = (0x1 << 4), /*!< I2S channel 4 enabled */
|
||||
I2S_TDM_ACTIVE_CH5 = (0x1 << 5), /*!< I2S channel 5 enabled */
|
||||
I2S_TDM_ACTIVE_CH6 = (0x1 << 6), /*!< I2S channel 6 enabled */
|
||||
I2S_TDM_ACTIVE_CH7 = (0x1 << 7), /*!< I2S channel 7 enabled */
|
||||
I2S_TDM_ACTIVE_CH8 = (0x1 << 8), /*!< I2S channel 8 enabled */
|
||||
I2S_TDM_ACTIVE_CH9 = (0x1 << 9), /*!< I2S channel 9 enabled */
|
||||
I2S_TDM_ACTIVE_CH10 = (0x1 << 10), /*!< I2S channel 10 enabled */
|
||||
I2S_TDM_ACTIVE_CH11 = (0x1 << 11), /*!< I2S channel 11 enabled */
|
||||
I2S_TDM_ACTIVE_CH12 = (0x1 << 12), /*!< I2S channel 12 enabled */
|
||||
I2S_TDM_ACTIVE_CH13 = (0x1 << 13), /*!< I2S channel 13 enabled */
|
||||
I2S_TDM_ACTIVE_CH14 = (0x1 << 14), /*!< I2S channel 14 enabled */
|
||||
I2S_TDM_ACTIVE_CH15 = (0x1 << 15), /*!< I2S channel 15 enabled */
|
||||
#endif
|
||||
} i2s_channel_t;
|
||||
|
||||
/**
|
||||
@@ -59,9 +85,8 @@ typedef enum {
|
||||
*
|
||||
*/
|
||||
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*/
|
||||
@@ -79,76 +104,59 @@ typedef enum {
|
||||
* @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_RIGHT_LEFT, /*!< Separated left and right channel */
|
||||
I2S_CHANNEL_FMT_ALL_RIGHT, /*!< Load right channel data in both two channels */
|
||||
I2S_CHANNEL_FMT_ALL_LEFT, /*!< Load left channel data in both two channels */
|
||||
I2S_CHANNEL_FMT_ONLY_RIGHT, /*!< Only load data in right channel */
|
||||
I2S_CHANNEL_FMT_ONLY_LEFT, /*!< Only load data in left channel */
|
||||
#if SOC_I2S_SUPPORTS_TDM
|
||||
// Multiple channels are available with TDM feature
|
||||
I2S_CHANNEL_FMT_MULTIPLE, /*!< More than two channels are used */
|
||||
#endif
|
||||
} 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*/
|
||||
I2S_MODE_SLAVE = 2, /*!< Slave mode*/
|
||||
I2S_MODE_TX = 4, /*!< TX mode*/
|
||||
I2S_MODE_RX = 8, /*!< RX mode*/
|
||||
I2S_MODE_MASTER = (0x1 << 0), /*!< Master mode*/
|
||||
I2S_MODE_SLAVE = (0x1 << 1), /*!< Slave mode*/
|
||||
I2S_MODE_TX = (0x1 << 2), /*!< TX mode*/
|
||||
I2S_MODE_RX = (0x1 << 3), /*!< RX mode*/
|
||||
#if SOC_I2S_SUPPORTS_ADC_DAC
|
||||
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*/
|
||||
//built-in DAC functions are only supported on I2S0 for ESP32 chip.
|
||||
I2S_MODE_DAC_BUILT_IN = (0x1 << 4), /*!< 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 = (0x1 << 5), /*!< Input I2S data from built-in ADC, each data can be 12-bit width at most*/
|
||||
#endif
|
||||
// PDM functions are only supported on I2S0 (all chips).
|
||||
I2S_MODE_PDM = (0x1 << 6), /*!< I2S PDM mode*/
|
||||
} i2s_mode_t;
|
||||
|
||||
/**
|
||||
* @brief I2S source clock
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
I2S_CLK_D2CLK = 0, /*!< Clock from PLL_D2_CLK(160M)*/
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
I2S_CLK_APLL, /*!< Clock from APLL*/
|
||||
#endif
|
||||
} i2s_clock_src_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
|
||||
*
|
||||
* @brief The multiple of mclk to sample rate
|
||||
*/
|
||||
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;
|
||||
I2S_MCLK_MULTIPLE_DEFAULT = 0, /*!< Default value. mclk = sample_rate * 256 */
|
||||
I2S_MCLK_MULTIPLE_128 = 128, /*!< mclk = sample_rate * 128 */
|
||||
I2S_MCLK_MULTIPLE_256 = 256, /*!< mclk = sample_rate * 256 */
|
||||
I2S_MCLK_MULTIPLE_384 = 384, /*!< mclk = sample_rate * 384 */
|
||||
} i2s_mclk_multiple_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,27 +167,21 @@ typedef enum {
|
||||
} i2s_dac_mode_t;
|
||||
#endif //SOC_I2S_SUPPORTS_ADC_DAC
|
||||
|
||||
#if SOC_I2S_SUPPORTS_PCM
|
||||
/**
|
||||
* @brief Event structure used in I2S event queue
|
||||
* @brief A/U-law decompress or compress configuration.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
i2s_event_type_t type; /*!< I2S event type */
|
||||
size_t size; /*!< I2S data size for I2S_DATA event*/
|
||||
} i2s_event_t;
|
||||
typedef enum {
|
||||
I2S_PCM_DISABLE = 0, /*!< Disable A/U law decopress or compress*/
|
||||
I2S_PCM_A_DECOMPRESS, /*!< A-law decompress*/
|
||||
I2S_PCM_A_COMPRESS, /*!< A-law compress*/
|
||||
I2S_PCM_U_DECOMPRESS, /*!< U-law decompress*/
|
||||
I2S_PCM_U_COMPRESS, /*!< U-law compress*/
|
||||
} i2s_pcm_compress_t;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @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_SUPPORTS_PDM
|
||||
#if SOC_I2S_SUPPORTS_PDM_RX
|
||||
/**
|
||||
* @brief I2S PDM RX downsample mode
|
||||
*/
|
||||
@@ -188,17 +190,16 @@ typedef enum {
|
||||
I2S_PDM_DSR_16S, /*!< downsampling number is 16 for PDM RX mode*/
|
||||
I2S_PDM_DSR_MAX,
|
||||
} i2s_pdm_dsr_t;
|
||||
|
||||
/**
|
||||
* @brief PDM PCM convter enable/disable.
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
PDM_PCM_CONV_ENABLE, /*!< Enable PDM PCM convert*/
|
||||
PDM_PCM_CONV_DISABLE, /*!< Disable PDM PCM convert*/
|
||||
} pdm_pcm_conv_t;
|
||||
#endif
|
||||
|
||||
#if SOC_I2S_SUPPORTS_PDM_TX
|
||||
typedef enum {
|
||||
I2S_PDM_SIG_SCALING_DIV_2 = 0, /*!< I2S TX PDM sigmadelta signal scaling: /2 */
|
||||
I2S_PDM_SIG_SCALING_MUL_1 = 1, /*!< I2S TX PDM sigmadelta signal scaling: x1 */
|
||||
I2S_PDM_SIG_SCALING_MUL_2 = 2, /*!< I2S TX PDM sigmadelta signal scaling: x2 */
|
||||
I2S_PDM_SIG_SCALING_MUL_4 = 3, /*!< I2S TX PDM sigmadelta signal scaling: x4 */
|
||||
} i2s_pdm_sig_scale_t;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@@ -1,9 +1,9 @@
|
||||
// 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.
|
||||
// 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
|
||||
@@ -20,30 +20,24 @@
|
||||
*/
|
||||
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,
|
||||
.o_bck_out_sig = I2S0O_BCK_OUT_IDX,
|
||||
.o_ws_out_sig = I2S0O_WS_OUT_IDX,
|
||||
.o_data_out_sig = I2S0O_DATA_OUT23_IDX,
|
||||
.i_bck_in_sig = I2S0I_BCK_OUT_IDX,
|
||||
.i_ws_in_sig = I2S0I_WS_OUT_IDX,
|
||||
.i_bck_out_sig = I2S0I_BCK_IN_IDX,
|
||||
.i_ws_out_sig = I2S0I_WS_IN_IDX,
|
||||
.i_data_in_sig = I2S0I_DATA_IN15_IDX,
|
||||
.mck_out_sig = -1, // Unavailable
|
||||
.rx_bck_sig = I2S0I_BCK_IN_IDX,
|
||||
.tx_bck_sig = I2S0O_BCK_OUT_IDX,
|
||||
.tx_ws_sig = I2S0O_WS_OUT_IDX,
|
||||
.rx_ws_sig = I2S0I_WS_IN_IDX,
|
||||
.data_out_sig = I2S0O_DATA_OUT23_IDX,
|
||||
.data_in_sig = I2S0I_DATA_IN15_IDX,
|
||||
.irq = ETS_I2S0_INTR_SOURCE,
|
||||
.module = PERIPH_I2S0_MODULE,
|
||||
},
|
||||
{
|
||||
.o_bck_in_sig = I2S1O_BCK_IN_IDX,
|
||||
.o_ws_in_sig = I2S1O_WS_IN_IDX,
|
||||
.o_bck_out_sig = I2S1O_BCK_OUT_IDX,
|
||||
.o_ws_out_sig = I2S1O_WS_OUT_IDX,
|
||||
.o_data_out_sig = I2S1O_DATA_OUT23_IDX,
|
||||
.i_bck_in_sig = I2S1I_BCK_OUT_IDX,
|
||||
.i_ws_in_sig = I2S1I_WS_OUT_IDX,
|
||||
.i_bck_out_sig = I2S1I_BCK_IN_IDX,
|
||||
.i_ws_out_sig = I2S1I_WS_IN_IDX,
|
||||
.i_data_in_sig = I2S1I_DATA_IN15_IDX,
|
||||
.mck_out_sig = -1, // Unavailable
|
||||
.rx_bck_sig = I2S1I_BCK_IN_IDX,
|
||||
.tx_bck_sig = I2S1O_BCK_OUT_IDX,
|
||||
.tx_ws_sig = I2S1O_WS_OUT_IDX,
|
||||
.rx_ws_sig = I2S1I_WS_IN_IDX,
|
||||
.data_out_sig = I2S1O_DATA_OUT23_IDX,
|
||||
.data_in_sig = I2S1I_DATA_IN15_IDX,
|
||||
.irq = ETS_I2S1_INTR_SOURCE,
|
||||
.module = PERIPH_I2S1_MODULE,
|
||||
}
|
||||
|
@@ -136,12 +136,11 @@
|
||||
/*-------------------------- I2S CAPS ----------------------------------------*/
|
||||
// ESP32 have 2 I2S
|
||||
#define SOC_I2S_NUM (2)
|
||||
|
||||
#define SOC_I2S_SUPPORTS_PDM (1) // ESP32 support PDM
|
||||
#define SOC_I2S_SUPPORTS_PDM_TX (1)
|
||||
#define SOC_I2S_SUPPORTS_PDM_RX (1)
|
||||
#define SOC_I2S_SUPPORTS_ADC_DAC (1) // ESP32 support ADC and DAC
|
||||
|
||||
#define SOC_I2S_MAX_BUFFER_SIZE (4 * 1024 * 1024) //the maximum RAM can be allocated
|
||||
|
||||
#define SOC_I2S_SUPPORTS_APLL (1)// ESP32 support APLL
|
||||
#define SOC_I2S_APLL_MIN_FREQ (250000000)
|
||||
#define SOC_I2S_APLL_MAX_FREQ (500000000)
|
||||
#define SOC_I2S_APLL_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware
|
||||
|
@@ -20,19 +20,14 @@
|
||||
*/
|
||||
const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
|
||||
{
|
||||
// TODO ESP32-C3 IDF-2098
|
||||
|
||||
// .o_bck_in_sig = I2S0O_BCK_IN_IDX,
|
||||
// .o_ws_in_sig = I2S0O_WS_IN_IDX,
|
||||
// .o_bck_out_sig = I2S0O_BCK_OUT_IDX,
|
||||
// .o_ws_out_sig = I2S0O_WS_OUT_IDX,
|
||||
// .o_data_out_sig = I2S0O_SD_OUT_IDX,
|
||||
// .i_bck_in_sig = I2S0I_BCK_OUT_IDX,
|
||||
// .i_ws_in_sig = I2S0I_WS_OUT_IDX,
|
||||
// .i_bck_out_sig = I2S0I_BCK_IN_IDX,
|
||||
// .i_ws_out_sig = I2S0I_WS_IN_IDX,
|
||||
// .i_data_in_sig = I2S0I_SD_IN_IDX,
|
||||
.irq = ETS_I2S1_INTR_SOURCE,
|
||||
.mck_out_sig = I2S_MCLK_OUT_IDX,
|
||||
.rx_bck_sig = I2SI_BCK_IN_IDX,
|
||||
.tx_bck_sig = I2SO_BCK_OUT_IDX,
|
||||
.tx_ws_sig = I2SO_WS_OUT_IDX,
|
||||
.rx_ws_sig = I2SI_WS_IN_IDX,
|
||||
.data_out_sig = I2SO_SD_OUT_IDX,
|
||||
.data_in_sig = I2SI_SD_IN_IDX,
|
||||
.irq = -1,
|
||||
.module = PERIPH_I2S1_MODULE,
|
||||
}
|
||||
};
|
||||
|
@@ -109,11 +109,10 @@
|
||||
|
||||
/*-------------------------- I2S CAPS ----------------------------------------*/
|
||||
#define SOC_I2S_NUM (1)
|
||||
|
||||
#define SOC_I2S_APLL_MIN_FREQ (250000000)
|
||||
#define SOC_I2S_APLL_MAX_FREQ (500000000)
|
||||
#define SOC_I2S_APLL_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware
|
||||
#define SOC_I2S_MAX_BUFFER_SIZE (4 * 1024 * 1024) //the maximum RAM can be allocated
|
||||
#define SOC_I2S_SUPPORTS_PCM (1)
|
||||
#define SOC_I2S_SUPPORTS_PDM_TX (1)
|
||||
#define SOC_I2S_SUPPORTS_PDM_CODEC (1)
|
||||
#define SOC_I2S_SUPPORTS_TDM (1)
|
||||
|
||||
/*-------------------------- LEDC CAPS ---------------------------------------*/
|
||||
#define SOC_LEDC_SUPPORT_XTAL_CLOCK (1)
|
||||
|
@@ -7,7 +7,7 @@ PROVIDE ( SIGMADELTA = 0x60004f00 );
|
||||
PROVIDE ( RTCCNTL = 0x60008000 );
|
||||
PROVIDE ( RTCIO = 0x60008400 );
|
||||
PROVIDE ( HINF = 0x6000B000 );
|
||||
PROVIDE ( I2S1 = 0x6002d000 );
|
||||
PROVIDE ( I2S0 = 0x6002d000 );
|
||||
PROVIDE ( I2C0 = 0x60013000 );
|
||||
PROVIDE ( UHCI0 = 0x60014000 );
|
||||
PROVIDE ( UHCI1 = 0x6000c000 );
|
||||
|
@@ -106,11 +106,10 @@
|
||||
|
||||
/*-------------------------- I2S CAPS ----------------------------------------*/
|
||||
#define SOC_I2S_NUM (1)
|
||||
|
||||
#define SOC_I2S_APLL_MIN_FREQ (250000000)
|
||||
#define SOC_I2S_APLL_MAX_FREQ (500000000)
|
||||
#define SOC_I2S_APLL_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware
|
||||
#define SOC_I2S_MAX_BUFFER_SIZE (4 * 1024 * 1024) //the maximum RAM can be allocated
|
||||
#define SOC_I2S_SUPPORTS_PCM (1)
|
||||
#define SOC_I2S_SUPPORTS_PDM_TX (1)
|
||||
#define SOC_I2S_SUPPORTS_PDM_CODEC (1)
|
||||
#define SOC_I2S_SUPPORTS_TDM (1)
|
||||
|
||||
/*-------------------------- LEDC CAPS ---------------------------------------*/
|
||||
#define SOC_LEDC_SUPPORT_XTAL_CLOCK (1)
|
||||
|
@@ -7,7 +7,7 @@ PROVIDE ( SIGMADELTA = 0x60004f00 );
|
||||
PROVIDE ( RTCCNTL = 0x60008000 );
|
||||
PROVIDE ( RTCIO = 0x60008400 );
|
||||
PROVIDE ( HINF = 0x6000B000 );
|
||||
PROVIDE ( I2S1 = 0x6002d000 );
|
||||
PROVIDE ( I2S0 = 0x6002d000 );
|
||||
PROVIDE ( I2C0 = 0x60013000 );
|
||||
PROVIDE ( UHCI0 = 0x60014000 );
|
||||
PROVIDE ( UHCI1 = 0x6000c000 );
|
||||
|
@@ -1,9 +1,9 @@
|
||||
// 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.
|
||||
// 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
|
||||
@@ -20,16 +20,13 @@
|
||||
*/
|
||||
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,
|
||||
.o_bck_out_sig = I2S0O_BCK_OUT_IDX,
|
||||
.o_ws_out_sig = I2S0O_WS_OUT_IDX,
|
||||
.o_data_out_sig = I2S0O_DATA_OUT23_IDX,
|
||||
.i_bck_in_sig = I2S0I_BCK_OUT_IDX,
|
||||
.i_ws_in_sig = I2S0I_WS_OUT_IDX,
|
||||
.i_bck_out_sig = I2S0I_BCK_IN_IDX,
|
||||
.i_ws_out_sig = I2S0I_WS_IN_IDX,
|
||||
.i_data_in_sig = I2S0I_DATA_IN15_IDX,
|
||||
.mck_out_sig = CLK_I2S_MUX_IDX,
|
||||
.rx_bck_sig = I2S0I_BCK_IN_IDX,
|
||||
.tx_bck_sig = I2S0O_BCK_OUT_IDX,
|
||||
.tx_ws_sig = I2S0O_WS_OUT_IDX,
|
||||
.rx_ws_sig = I2S0I_WS_IN_IDX,
|
||||
.data_out_sig = I2S0O_DATA_OUT23_IDX,
|
||||
.data_in_sig = I2S0I_DATA_IN15_IDX,
|
||||
.irq = ETS_I2S0_INTR_SOURCE,
|
||||
.module = PERIPH_I2S0_MODULE,
|
||||
}
|
||||
|
@@ -135,13 +135,9 @@
|
||||
#define SOC_I2C_SUPPORT_APB (1)
|
||||
|
||||
/*-------------------------- I2S CAPS ----------------------------------------*/
|
||||
// ESP32-S2 have 2 I2S
|
||||
// ESP32-S2 have 1 I2S
|
||||
#define SOC_I2S_NUM (1)
|
||||
|
||||
#define SOC_I2S_SUPPORTS_DMA_EQUAL (1) // ESP32-S2 need dma equal
|
||||
|
||||
#define SOC_I2S_MAX_BUFFER_SIZE (4 * 1024 * 1024) //the maximum RAM can be allocated
|
||||
|
||||
#define SOC_I2S_SUPPORTS_APLL (1)// ESP32-S2 support APLL
|
||||
#define SOC_I2S_APLL_MIN_FREQ (250000000)
|
||||
#define SOC_I2S_APLL_MAX_FREQ (500000000)
|
||||
#define SOC_I2S_APLL_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware
|
||||
|
@@ -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.
|
||||
@@ -20,17 +20,25 @@
|
||||
*/
|
||||
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,
|
||||
.o_bck_out_sig = I2S0O_BCK_OUT_IDX,
|
||||
.o_ws_out_sig = I2S0O_WS_OUT_IDX,
|
||||
.o_data_out_sig = I2S0O_SD_OUT_IDX,
|
||||
.i_bck_in_sig = I2S0I_BCK_OUT_IDX,
|
||||
.i_ws_in_sig = I2S0I_WS_OUT_IDX,
|
||||
.i_bck_out_sig = I2S0I_BCK_IN_IDX,
|
||||
.i_ws_out_sig = I2S0I_WS_IN_IDX,
|
||||
.i_data_in_sig = I2S0I_SD_IN_IDX,
|
||||
.irq = ETS_I2S0_INTR_SOURCE,
|
||||
.mck_out_sig = I2S0_MCLK_OUT_IDX,
|
||||
.rx_bck_sig = I2S0I_BCK_IN_IDX,
|
||||
.tx_bck_sig = I2S0O_BCK_OUT_IDX,
|
||||
.tx_ws_sig = I2S0O_WS_OUT_IDX,
|
||||
.rx_ws_sig = I2S0I_WS_IN_IDX,
|
||||
.data_out_sig = I2S0O_SD_OUT_IDX,
|
||||
.data_in_sig = I2S0I_SD_IN_IDX,
|
||||
.irq = -1,
|
||||
.module = PERIPH_I2S0_MODULE,
|
||||
},
|
||||
{
|
||||
.mck_out_sig = I2S1_MCLK_OUT_IDX,
|
||||
.rx_bck_sig = I2S1I_BCK_IN_IDX,
|
||||
.tx_bck_sig = I2S1O_BCK_OUT_IDX,
|
||||
.tx_ws_sig = I2S1O_WS_OUT_IDX,
|
||||
.rx_ws_sig = I2S1I_WS_IN_IDX,
|
||||
.data_out_sig = I2S1O_SD_OUT_IDX,
|
||||
.data_in_sig = I2S1I_SD_IN_IDX,
|
||||
.irq = -1,
|
||||
.module = PERIPH_I2S1_MODULE,
|
||||
}
|
||||
};
|
||||
|
@@ -1,23 +0,0 @@
|
||||
// Copyright 2015-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.
|
||||
// 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
|
||||
|
||||
#define SOC_I2S_APLL_MIN_FREQ (250000000)
|
||||
#define SOC_I2S_APLL_MAX_FREQ (500000000)
|
||||
#define SOC_I2S_APLL_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware
|
||||
#define SOC_I2S_MAX_BUFFER_SIZE (4 * 1024 * 1024) //the maximum RAM can be allocated
|
||||
|
||||
// ESP32-S3 have 1 I2S
|
||||
#define SOC_I2S_NUM (1)
|
@@ -318,8 +318,8 @@ typedef volatile struct {
|
||||
uint32_t reserved12 : 20; /* Reserved*/
|
||||
};
|
||||
uint32_t val;
|
||||
} rxeof_num;
|
||||
uint32_t conf_sigle_data;
|
||||
} rx_eof_num;
|
||||
uint32_t conf_single_data; /*the right channel or left channel put out constant value stored in this register according to tx_chan_mod and reg_tx_msb_right*/
|
||||
union {
|
||||
struct {
|
||||
uint32_t tx_idle : 1; /*1: i2s_tx is idle state. 0: i2s_tx is working.*/
|
||||
|
@@ -63,7 +63,12 @@
|
||||
#include "i2c_caps.h"
|
||||
|
||||
/*-------------------------- I2S CAPS ----------------------------------------*/
|
||||
#include "i2s_caps.h"
|
||||
#define SOC_I2S_NUM (2)
|
||||
#define SOC_I2S_SUPPORTS_PCM (1)
|
||||
#define SOC_I2S_SUPPORTS_PDM_TX (1)
|
||||
#define SOC_I2S_SUPPORTS_PDM_RX (1)
|
||||
#define SOC_I2S_SUPPORTS_PDM_CODEC (1)
|
||||
#define SOC_I2S_SUPPORTS_TDM (1)
|
||||
|
||||
/*-------------------------- LEDC CAPS ---------------------------------------*/
|
||||
#include "ledc_caps.h"
|
||||
|
@@ -8,6 +8,7 @@ PROVIDE ( RTCIO = 0x60008400 );
|
||||
PROVIDE ( SENS = 0x60008800 );
|
||||
PROVIDE ( HINF = 0x6000B000 );
|
||||
PROVIDE ( I2S0 = 0x6000F000 );
|
||||
PROVIDE ( I2S1 = 0x6002D000 );
|
||||
PROVIDE ( UART1 = 0x60010000 );
|
||||
PROVIDE ( I2C0 = 0x60013000 );
|
||||
PROVIDE ( UHCI0 = 0x60014000 );
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 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.
|
||||
@@ -27,16 +27,13 @@ extern "C" {
|
||||
Stores a bunch of per-I2S-peripheral data.
|
||||
*/
|
||||
typedef struct {
|
||||
const uint8_t o_bck_in_sig;
|
||||
const uint8_t o_ws_in_sig;
|
||||
const uint8_t o_bck_out_sig;
|
||||
const uint8_t o_ws_out_sig;
|
||||
const uint8_t o_data_out_sig;
|
||||
const uint8_t i_bck_in_sig;
|
||||
const uint8_t i_ws_in_sig;
|
||||
const uint8_t i_bck_out_sig;
|
||||
const uint8_t i_ws_out_sig;
|
||||
const uint8_t i_data_in_sig;
|
||||
const uint8_t mck_out_sig;
|
||||
const uint8_t tx_bck_sig;
|
||||
const uint8_t rx_bck_sig;
|
||||
const uint8_t tx_ws_sig;
|
||||
const uint8_t rx_ws_sig;
|
||||
const uint8_t data_out_sig;
|
||||
const uint8_t data_in_sig;
|
||||
const uint8_t irq;
|
||||
const periph_module_t module;
|
||||
} i2s_signal_conn_t;
|
||||
|
@@ -1,27 +1,18 @@
|
||||
I2S
|
||||
===
|
||||
|
||||
.. only:: esp32c3
|
||||
|
||||
.. warning::
|
||||
|
||||
This document is not updated for ESP32-C3 yet.
|
||||
{IDF_TARGET_I2S_NUM:default="two", esp32s2="one", esp32c3="one"}
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
I2S (Inter-IC Sound) is a serial, synchronous communication protocol that is usually used for transmitting audio data between two digital audio devices.
|
||||
|
||||
.. only:: esp32
|
||||
|
||||
{IDF_TARGET_NAME} contains two I2S peripherals. These peripherals can be configured to input and output sample data via the I2S driver.
|
||||
|
||||
.. only:: esp32s2
|
||||
|
||||
{IDF_TARGET_NAME} contains one I2S peripheral. These peripherals can be configured to input and output sample data via the I2S driver.
|
||||
{IDF_TARGET_NAME} contains {IDF_TARGET_I2S_NUM} I2S peripheral(s). These peripherals can be configured to input and output sample data via the I2S driver.
|
||||
|
||||
An I2S bus consists of the following lines:
|
||||
|
||||
- Master clock line (operational)
|
||||
- Bit clock line
|
||||
- Channel select line
|
||||
- Serial data line
|
||||
@@ -30,23 +21,27 @@ Each I2S controller has the following features that can be configured using the
|
||||
|
||||
- Operation as system master or slave
|
||||
- Capable of acting as transmitter or receiver
|
||||
- Dedicated DMA controller that allows for streaming sample data without requiring the CPU to copy each data sample
|
||||
- DMA controller that allows for streaming sample data without requiring the CPU to copy each data sample
|
||||
|
||||
Each controller can operate in half-duplex communication mode. Thus, the two controllers can be combined to establish full-duplex communication.
|
||||
|
||||
I2S0 output can be routed directly to the digital-to-analog converter's (DAC) output channels (GPIO 25 & GPIO 26) to produce direct analog output without involving any external I2S codecs. I2S0 can also be used for transmitting PDM (Pulse-density modulation) signals.
|
||||
|
||||
The I2S peripherals also support LCD mode for communicating data over a parallel bus, as used by some LCD displays and camera modules. LCD mode has the following operational modes:
|
||||
|
||||
- LCD master transmitting mode
|
||||
- Camera slave receiving mode
|
||||
- ADC/DAC mode
|
||||
|
||||
.. only:: esp32
|
||||
|
||||
I2S0 output can be routed directly to the digital-to-analog converter's (DAC) output channels (GPIO 25 & GPIO 26) to produce direct analog output without involving any external I2S codecs. I2S0 can also be used for transmitting PDM (Pulse-density modulation) signals.
|
||||
|
||||
.. only:: esp32 or esp32s2
|
||||
|
||||
The I2S peripherals also support LCD mode for communicating data over a parallel bus, as used by some LCD displays and camera modules. LCD mode has the following operational modes:
|
||||
|
||||
- LCD master transmitting mode
|
||||
- Camera slave receiving mode
|
||||
- ADC/DAC mode
|
||||
|
||||
For more information, see *{IDF_TARGET_NAME} Technical Reference Manual* > *I2S Controller (I2S)* > LCD Mode [`PDF <{IDF_TARGET_TRM_EN_URL}#camlcdctrl>`__].
|
||||
|
||||
.. note::
|
||||
.. only:: SOC_I2S_SUPPORTS_APLL
|
||||
|
||||
.. note::
|
||||
|
||||
For high accuracy clock applications, use the APLL_CLK clock source, which has the frequency range of 16 ~ 128 MHz. You can enable the APLL_CLK clock source by setting :cpp:member:`i2s_config_t::use_apll` to ``TRUE``.
|
||||
|
||||
@@ -68,26 +63,50 @@ Install the I2S driver by calling the function :cpp:func`i2s_driver_install` and
|
||||
- The structure :cpp:type:`i2s_config_t` with defined communication parameters
|
||||
- Event queue size and handle
|
||||
|
||||
Once :cpp:func`i2s_driver_install` returns ``ESP_OK``, it means I2S has started.
|
||||
|
||||
Configuration example:
|
||||
|
||||
.. code-block:: c
|
||||
.. only:: not SOC_I2S_SUPPORTS_TDM
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static const int i2s_num = 0; // i2s port number
|
||||
|
||||
static const i2s_config_t i2s_config = {
|
||||
i2s_config_t i2s_config = {
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
|
||||
.sample_rate = 44100,
|
||||
.bits_per_sample = 16,
|
||||
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
|
||||
.intr_alloc_flags = 0, // default interrupt priority
|
||||
.communication_format = I2S_COMM_FORMAT_STAND_I2S
|
||||
.tx_desc_auto_clear = false,
|
||||
.dma_buf_count = 8,
|
||||
.dma_buf_len = 64,
|
||||
.use_apll = false
|
||||
.use_apll = false,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 // Interrupt level 1, default 0
|
||||
};
|
||||
|
||||
i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
|
||||
|
||||
.. only:: SOC_I2S_SUPPORTS_TDM
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static const int i2s_num = 0; // i2s port number
|
||||
|
||||
i2s_config_t i2s_config = {
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
|
||||
.sample_rate = 44100,
|
||||
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
|
||||
.tx_desc_auto_clear = false,
|
||||
.dma_buf_count = 8,
|
||||
.dma_buf_len = 64,
|
||||
.bits_per_chan = I2S_BITS_PER_SAMPLE_16BIT
|
||||
};
|
||||
|
||||
i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
|
||||
|
||||
Setting Communication Pins
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -95,20 +114,24 @@ Setting Communication Pins
|
||||
Once the driver is installed, configure physical GPIO pins to which signals will be routed. For this, call the function :cpp:func`i2s_set_pin` and pass the following arguments to it:
|
||||
|
||||
- Port number
|
||||
- The structure :cpp:type:`i2s_pin_config_t` defining the GPIO pin numbers to which the driver should route the BCK, WS, DATA out, and DATA in signals. If you want to keep a currently allocated pin number for a specific signal, or if this signal is unused, then pass the macro :c:macro:`I2S_PIN_NO_CHANGE`. See the example below.
|
||||
- The structure :cpp:type:`i2s_pin_config_t` defining the GPIO pin numbers to which the driver should route the MCK, BCK, WS, DATA out, and DATA in signals. If you want to keep a currently allocated pin number for a specific signal, or if this signal is unused, then pass the macro :c:macro:`I2S_PIN_NO_CHANGE`. See the example below.
|
||||
|
||||
.. note::
|
||||
|
||||
MCK only takes effect in `I2S_MODE_MASTER` mode.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static const i2s_pin_config_t pin_config = {
|
||||
.bck_io_num = 26,
|
||||
.ws_io_num = 25,
|
||||
.data_out_num = 22,
|
||||
.mck_io_num = 0,
|
||||
.bck_io_num = 4,
|
||||
.ws_io_num = 5,
|
||||
.data_out_num = 18,
|
||||
.data_in_num = I2S_PIN_NO_CHANGE
|
||||
};
|
||||
|
||||
i2s_set_pin(i2s_num, &pin_config);
|
||||
|
||||
|
||||
Running I2S Communication
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -117,14 +140,17 @@ To perform a transmission:
|
||||
- Prepare the data for sending
|
||||
- Call the function :cpp:func:`i2s_write` and pass the data buffer address and data length to it
|
||||
|
||||
The function will write the data to the I2S DMA Tx buffer, and then the data will be transmitted automatically.
|
||||
The function will write the data to the DMA Tx buffer, and then the data will be transmitted automatically.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
i2s_write(I2S_NUM, samples_data, ((bits+8)/16)*SAMPLE_PER_CYCLE*4, &i2s_bytes_write, 100);
|
||||
|
||||
To retrieve received data, use the function :cpp:func:`i2s_read`. It will retrieve the data from the DMA Rx buffer, once the data is received by the I2S controller.
|
||||
|
||||
To retrieve received data, use the function :cpp:func:`i2s_read`. It will retrieve the data from the I2S DMA Rx buffer, once the data is received by the I2S controller.
|
||||
.. code-block:: c
|
||||
|
||||
i2s_read(I2S_NUM, data_recv, ((bits+8)/16)*SAMPLE_PER_CYCLE*4, &i2s_bytes_read, 100);
|
||||
|
||||
You can temporarily stop the I2S driver by calling the function :cpp:func:`i2s_stop`, which will disable the I2S Tx/Rx units until the function :cpp:func:`i2s_start` is called. If the function :cpp:func`i2s_driver_install` is used, the driver will start up automatically eliminating the need to call :cpp:func:`i2s_start`.
|
||||
|
||||
@@ -140,53 +166,156 @@ Application Example
|
||||
|
||||
A code example for the I2S driver can be found in the directory :example:`peripherals/i2s`.
|
||||
|
||||
In addition, there are two short configuration examples for the I2S driver.
|
||||
.. only:: SOC_I2S_SUPPORTS_ADC_DAC
|
||||
|
||||
In addition, there are two short configuration examples for the I2S driver.
|
||||
|
||||
.. only:: not SOC_I2S_SUPPORTS_ADC_DAC
|
||||
|
||||
In addition, there is a short configuration examples for the I2S driver.
|
||||
|
||||
I2S configuration
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: c
|
||||
Example for general usage.
|
||||
|
||||
.. only:: not SOC_I2S_SUPPORTS_TDM
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include "driver/i2s.h"
|
||||
#include "freertos/queue.h"
|
||||
|
||||
static const int i2s_num = 0; // i2s port number
|
||||
|
||||
static const i2s_config_t i2s_config = {
|
||||
i2s_config_t i2s_config = {
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
|
||||
.sample_rate = 44100,
|
||||
.bits_per_sample = 16,
|
||||
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
|
||||
.intr_alloc_flags = 0, // default interrupt priority
|
||||
.communication_format = I2S_COMM_FORMAT_STAND_I2S
|
||||
.tx_desc_auto_clear = false,
|
||||
.dma_buf_count = 8,
|
||||
.dma_buf_len = 64,
|
||||
.use_apll = false
|
||||
.use_apll = false,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 // Interrupt level 1, default 0
|
||||
};
|
||||
|
||||
static const i2s_pin_config_t pin_config = {
|
||||
.bck_io_num = 26,
|
||||
.ws_io_num = 25,
|
||||
.data_out_num = 22,
|
||||
.bck_io_num = 4,
|
||||
.ws_io_num = 5,
|
||||
.data_out_num = 18,
|
||||
.data_in_num = I2S_PIN_NO_CHANGE
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver
|
||||
|
||||
i2s_set_pin(i2s_num, &pin_config);
|
||||
|
||||
i2s_set_sample_rates(i2s_num, 22050); //set sample rates
|
||||
...
|
||||
/* You can reset parameters by calling 'i2s_set_clk'
|
||||
*
|
||||
* The low 16 bits are the valid data bits in one chan and the high 16 bits are
|
||||
* the total bits in one chan. If high 16 bits is smaller than low 16 bits, it will
|
||||
* be set to a same value as low 16 bits.
|
||||
*/
|
||||
uint32_t bits_cfg = (I2S_BITS_PER_CHAN_32BIT << 16) | I2S_BITS_PER_SAMPLE_16BIT;
|
||||
i2s_set_clk(i2s_num, 22050, bits_cfg, I2S_CHANNEL_STEREO);
|
||||
...
|
||||
|
||||
i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver
|
||||
|
||||
.. only:: SOC_I2S_SUPPORTS_TDM
|
||||
|
||||
Configuring I2S to use internal DAC for analog output
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
.. code-block:: c
|
||||
|
||||
.. code-block:: c
|
||||
#include "driver/i2s.h"
|
||||
|
||||
static const int i2s_num = 0; // i2s port number
|
||||
|
||||
i2s_config_t i2s_config = {
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
|
||||
.sample_rate = 44100,
|
||||
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||
.communication_format = I2S_COMM_FORMAT_STAND_I2S
|
||||
.tx_desc_auto_clear = false,
|
||||
.dma_buf_count = 8,
|
||||
.dma_buf_len = 64
|
||||
};
|
||||
|
||||
static const i2s_pin_config_t pin_config = {
|
||||
.bck_io_num = 4,
|
||||
.ws_io_num = 5,
|
||||
.data_out_num = 18,
|
||||
.data_in_num = I2S_PIN_NO_CHANGE
|
||||
};
|
||||
|
||||
i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver
|
||||
i2s_set_pin(i2s_num, &pin_config);
|
||||
|
||||
...
|
||||
/* You can reset parameters by calling 'i2s_set_clk'
|
||||
*
|
||||
* The low 16 bits are the valid data bits in one chan and the high 16 bits are
|
||||
* the total bits in one chan. If high 16 bits is smaller than low 16 bits, it will
|
||||
* be set to a same value as low 16 bits.
|
||||
*/
|
||||
uint32_t bits_cfg = (I2S_BITS_PER_CHAN_32BIT << 16) | I2S_BITS_PER_SAMPLE_16BIT;
|
||||
i2s_set_clk(i2s_num, 22050, bits_cfg, I2S_CHANNEL_STEREO);
|
||||
...
|
||||
|
||||
i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver
|
||||
|
||||
I2S on {IDF_TARGET_NAME} support TDM mode, up to 16 channels are available in TDM mode. If you want to use TDM mode, set field ``channel_format`` of :cpp:type:`i2s_config_t` to ``I2S_CHANNEL_FMT_MULTIPLE``. Then enable the channels by setting ``chan_mask`` using masks in :cpp:type:`i2s_channel_t`, the number of active channels and total channels will be calculate automatically. Also you can set a particular total channel number for it, but it shouldn't be smaller than the largest channel you use.
|
||||
|
||||
If active channels are discrete, the inactive channels within total channels will be filled by a constant automatically. But if ``skip_msk`` is enabled, these inactive channels will be skiped.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include "driver/i2s.h"
|
||||
|
||||
static const int i2s_num = 0; // i2s port number
|
||||
|
||||
i2s_config_t i2s_config = {
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
|
||||
.sample_rate = 44100,
|
||||
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
|
||||
.channel_format = I2S_CHANNEL_FMT_MULTIPLE,
|
||||
.communication_format = I2S_COMM_FORMAT_STAND_I2S
|
||||
.tx_desc_auto_clear = false,
|
||||
.dma_buf_count = 8,
|
||||
.dma_buf_len = 64,
|
||||
.chan_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH2
|
||||
};
|
||||
|
||||
static const i2s_pin_config_t pin_config = {
|
||||
.bck_io_num = 4,
|
||||
.ws_io_num = 5,
|
||||
.data_out_num = 18,
|
||||
.data_in_num = I2S_PIN_NO_CHANGE
|
||||
};
|
||||
|
||||
i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver
|
||||
i2s_set_pin(i2s_num, &pin_config);
|
||||
|
||||
...
|
||||
/* You can reset parameters by calling 'i2s_set_clk'
|
||||
*
|
||||
* The low 16 bits are the valid data bits in one chan and the high 16 bits are
|
||||
* the total bits in one chan. If high 16 bits is smaller than low 16 bits, it will
|
||||
* be set to a same value as low 16 bits.
|
||||
*/
|
||||
uint32_t bits_cfg = (I2S_BITS_PER_CHAN_32BIT << 16) | I2S_BITS_PER_SAMPLE_16BIT;
|
||||
i2s_set_clk(i2s_port_t i2s_num, 22050, bits_cfg, I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1); // set clock
|
||||
...
|
||||
|
||||
i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver
|
||||
|
||||
.. only:: SOC_I2S_SUPPORTS_ADC_DAC
|
||||
|
||||
Configuring I2S to use internal DAC for analog output
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include "driver/i2s.h"
|
||||
#include "freertos/queue.h"
|
||||
|
@@ -15,6 +15,7 @@
|
||||
#include "driver/i2s.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include <math.h>
|
||||
|
||||
|
||||
@@ -22,13 +23,15 @@
|
||||
#define I2S_NUM (0)
|
||||
#define WAVE_FREQ_HZ (100)
|
||||
#define PI (3.14159265)
|
||||
#define I2S_BCK_IO (GPIO_NUM_13)
|
||||
#define I2S_WS_IO (GPIO_NUM_15)
|
||||
#define I2S_DO_IO (GPIO_NUM_21)
|
||||
#define I2S_BCK_IO (GPIO_NUM_4)
|
||||
#define I2S_WS_IO (GPIO_NUM_5)
|
||||
#define I2S_DO_IO (GPIO_NUM_18)
|
||||
#define I2S_DI_IO (-1)
|
||||
|
||||
#define SAMPLE_PER_CYCLE (SAMPLE_RATE/WAVE_FREQ_HZ)
|
||||
|
||||
static const char* TAG = "i2s_example";
|
||||
|
||||
static void setup_triangle_sine_waves(int bits)
|
||||
{
|
||||
int *samples_data = malloc(((bits+8)/16)*SAMPLE_PER_CYCLE*4);
|
||||
@@ -64,7 +67,7 @@ static void setup_triangle_sine_waves(int bits)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "set clock");
|
||||
i2s_set_clk(I2S_NUM, SAMPLE_RATE, bits, 2);
|
||||
//Using push
|
||||
// for(i = 0; i < SAMPLE_PER_CYCLE; i++) {
|
||||
@@ -74,6 +77,7 @@ static void setup_triangle_sine_waves(int bits)
|
||||
// i2s_push_sample(0, &samples_data[i*2], 100);
|
||||
// }
|
||||
// or write
|
||||
ESP_LOGI(TAG, "write data");
|
||||
i2s_write(I2S_NUM, samples_data, ((bits+8)/16)*SAMPLE_PER_CYCLE*4, &i2s_bytes_write, 100);
|
||||
|
||||
free(samples_data);
|
||||
@@ -87,10 +91,10 @@ void app_main(void)
|
||||
//if 2-channels, 16-bit each channel, total buffer is 360*4 = 1440 bytes
|
||||
//if 2-channels, 24/32-bit each channel, total buffer is 360*8 = 2880 bytes
|
||||
i2s_config_t i2s_config = {
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
|
||||
.sample_rate = SAMPLE_RATE,
|
||||
.bits_per_sample = 16,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels
|
||||
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||
.communication_format = I2S_COMM_FORMAT_STAND_MSB,
|
||||
.dma_buf_count = 6,
|
||||
.dma_buf_len = 60,
|
||||
|
Reference in New Issue
Block a user