Add i2s driver

This commit is contained in:
Tuan PM 2016-12-29 17:29:14 +08:00
parent 8bcd341fca
commit 5462d98e5a
5 changed files with 1277 additions and 0 deletions

807
components/driver/i2s.c Normal file
View File

@ -0,0 +1,807 @@
// Copyright 2015-2016 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.
#include <string.h>
#include <esp_types.h>
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/xtensa_api.h"
#include "soc/dport_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/sens_reg.h"
#include "rom/lldesc.h"
#include "driver/gpio.h"
#include "driver/i2s.h"
#include "esp_intr.h"
#include "esp_err.h"
#include "esp_log.h"
static const char* I2S_TAG = "I2S";
#define I2S_CHECK(a, str, ret) if (!(a)) { \
ESP_LOGE(I2S_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
return (ret); \
}
#define I2S_BASE_CLK (2*APB_CLK_FREQ)
#define I2S_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&i2s_spinlock[i2s_num])
#define I2S_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&i2s_spinlock[i2s_num])
#define I2S_ENTER_CRITICAL() portENTER_CRITICAL(&i2s_spinlock[i2s_num])
#define I2S_EXIT_CRITICAL() portEXIT_CRITICAL(&i2s_spinlock[i2s_num])
#define gpio_matrix_out_check(a, b, c, d) if(a != -1) gpio_matrix_out(a, b, c, d) //if pin = -1, do not need to configure
#define gpio_matrix_in_check(a, b, c) if(a != -1) gpio_matrix_in(a, b, c)
/**
* @brief DMA buffer object
*
*/
typedef struct {
char **buf;
int buf_size;
int rw_pos;
void *curr_ptr;
SemaphoreHandle_t mux;
xQueueHandle queue;
lldesc_t **desc;
} i2s_dma_t;
/**
* @brief I2S object instance
*
*/
typedef struct {
i2s_port_t i2s_num; /*!< I2S port number*/
int queue_size; /*!< I2S event queue size*/
QueueHandle_t i2s_queue; /*!< I2S queue handler*/
int dma_buf_count; /*!< DMA buffer count, number of buffer*/
int dma_buf_len; /*!< DMA buffer length, length of each buffer*/
i2s_dma_t *rx; /*!< DMA Tx buffer*/
i2s_dma_t *tx; /*!< DMA Rx buffer*/
i2s_isr_handle_t i2s_isr_handle; /*!< I2S Interrupt handle*/
int channel_num; /*!< Number of channels*/
int bytes_per_sample; /*!< Bytes per sample*/
i2s_mode_t mode; /*!< I2S Working mode*/
} i2s_obj_t;
static i2s_obj_t *p_i2s_obj[I2S_NUM_MAX] = {0};
static i2s_dev_t* I2S[I2S_NUM_MAX] = {&I2S0, &I2S1};
static portMUX_TYPE i2s_spinlock[I2S_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED};
static esp_err_t i2s_reset_fifo(i2s_port_t i2s_num)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
I2S_ENTER_CRITICAL();
I2S[i2s_num]->conf.rx_fifo_reset = 1;
I2S[i2s_num]->conf.rx_fifo_reset = 0;
I2S[i2s_num]->conf.tx_fifo_reset = 1;
I2S[i2s_num]->conf.tx_fifo_reset = 0;
I2S_EXIT_CRITICAL();
return ESP_OK;
}
esp_err_t i2s_clear_intr_status(i2s_port_t i2s_num, uint32_t clr_mask)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
I2S[i2s_num]->int_clr.val = clr_mask;
return ESP_OK;
}
esp_err_t i2s_enable_rx_intr(i2s_port_t i2s_num)
{
I2S_ENTER_CRITICAL();
I2S[i2s_num]->int_ena.in_suc_eof = 1;
I2S[i2s_num]->int_ena.in_dscr_err = 1;
I2S_EXIT_CRITICAL();
return ESP_OK;
}
esp_err_t i2s_disable_rx_intr(i2s_port_t i2s_num)
{
I2S_ENTER_CRITICAL();
I2S[i2s_num]->int_ena.in_suc_eof = 0;
I2S[i2s_num]->int_ena.in_dscr_err = 0;
I2S_EXIT_CRITICAL();
return ESP_OK;
}
esp_err_t i2s_disable_tx_intr(i2s_port_t i2s_num)
{
I2S_ENTER_CRITICAL();
I2S[i2s_num]->int_ena.out_eof = 0;
I2S[i2s_num]->int_ena.out_dscr_err = 0;
I2S_EXIT_CRITICAL();
return ESP_OK;
}
esp_err_t i2s_enable_tx_intr(i2s_port_t i2s_num)
{
I2S_ENTER_CRITICAL();
I2S[i2s_num]->int_ena.out_eof = 1;
I2S[i2s_num]->int_ena.out_dscr_err = 1;
I2S_EXIT_CRITICAL();
return ESP_OK;
}
static esp_err_t i2s_isr_register(i2s_port_t i2s_num, uint8_t intr_alloc_flags, void (*fn)(void*), void * arg, i2s_isr_handle_t *handle)
{
return esp_intr_alloc(ETS_I2S0_INTR_SOURCE + i2s_num, intr_alloc_flags, fn, arg, handle);
}
static esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint8_t bits, bool fuzzy)
{
int factor = (256%bits)? 384 : 256; // According to hardware codec requirement(supported 256fs or 384fs)
int clkmInteger, clkmDecimals, bck = 0;
float denom = (float)1 / 64;
int channel = 2;
float clkmdiv = (float)I2S_BASE_CLK / (rate * factor);
if (clkmdiv > 256) {
ESP_LOGE(I2S_TAG, "clkmdiv is too large\r\n");
return ESP_FAIL;
}
clkmInteger = clkmdiv;
clkmDecimals = (clkmdiv - clkmInteger) / denom;
float mclk = clkmInteger + denom * clkmDecimals;
bck = factor/(bits * channel);
I2S[i2s_num]->clkm_conf.clka_en = 0;
I2S[i2s_num]->clkm_conf.clkm_div_a = 63;
I2S[i2s_num]->clkm_conf.clkm_div_b = clkmDecimals;
I2S[i2s_num]->clkm_conf.clkm_div_num = clkmInteger;
I2S[i2s_num]->sample_rate_conf.tx_bck_div_num = bck;
I2S[i2s_num]->sample_rate_conf.rx_bck_div_num = bck;
I2S[i2s_num]->sample_rate_conf.tx_bits_mod = bits;
I2S[i2s_num]->sample_rate_conf.rx_bits_mod = bits;
float real_rate = (float)(I2S_BASE_CLK / (bck * bits * clkmInteger)/2);
ESP_LOGI(I2S_TAG, "Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d",
rate, real_rate, bits, clkmInteger, bck, (float)I2S_BASE_CLK / mclk, real_rate *16*2, 64, clkmDecimals);
return ESP_OK;
}
static void IRAM_ATTR i2s_intr_handler_default(void *arg)
{
i2s_obj_t *p_i2s = (i2s_obj_t*) arg;
uint8_t i2s_num = p_i2s->i2s_num;
i2s_dev_t* i2s_reg = I2S[i2s_num];
i2s_event_t i2s_event;
int dummy;
portBASE_TYPE high_priority_task_awoken = 0;
lldesc_t *finish_desc;
if (i2s_reg->int_st.out_dscr_err || i2s_reg->int_st.in_dscr_err) {
ESP_LOGE(I2S_TAG, "out_dscr_err: %d or in_dscr_err:%d", i2s_reg->int_st.out_dscr_err == 1, i2s_reg->int_st.in_dscr_err == 1);
if (p_i2s->i2s_queue) {
i2s_event.type = I2S_EVENT_DMA_ERROR;
if (xQueueIsQueueFullFromISR(p_i2s->i2s_queue)) {
xQueueReceiveFromISR(p_i2s->i2s_queue, &dummy, &high_priority_task_awoken);
}
xQueueSendFromISR(p_i2s->i2s_queue, (void * )&i2s_event, &high_priority_task_awoken);
}
}
if (i2s_reg->int_st.out_eof && p_i2s->tx) {
finish_desc = (lldesc_t*) i2s_reg->out_eof_des_addr;
// All buffers are empty. This means we have an underflow on our hands.
if (xQueueIsQueueFullFromISR(p_i2s->tx->queue)) {
xQueueReceiveFromISR(p_i2s->tx->queue, &dummy, &high_priority_task_awoken);
}
xQueueSendFromISR(p_i2s->tx->queue, (void*)(&finish_desc->buf), &high_priority_task_awoken);
if (p_i2s->i2s_queue) {
i2s_event.type = I2S_EVENT_TX_DONE;
if (xQueueIsQueueFullFromISR(p_i2s->i2s_queue)) {
xQueueReceiveFromISR(p_i2s->i2s_queue, &dummy, &high_priority_task_awoken);
}
xQueueSendFromISR(p_i2s->i2s_queue, (void * )&i2s_event, &high_priority_task_awoken);
}
}
if (i2s_reg->int_st.in_suc_eof && p_i2s->rx) {
// All buffers are full. This means we have an overflow.
finish_desc = (lldesc_t*) i2s_reg->in_eof_des_addr;
if (xQueueIsQueueFullFromISR(p_i2s->rx->queue)) {
xQueueReceiveFromISR(p_i2s->rx->queue, &dummy, &high_priority_task_awoken);
}
xQueueSendFromISR(p_i2s->rx->queue, (void*)(&finish_desc->buf), &high_priority_task_awoken);
if (p_i2s->i2s_queue) {
i2s_event.type = I2S_EVENT_RX_DONE;
if (p_i2s->i2s_queue && xQueueIsQueueFullFromISR(p_i2s->i2s_queue)) {
xQueueReceiveFromISR(p_i2s->i2s_queue, &dummy, &high_priority_task_awoken);
}
xQueueSendFromISR(p_i2s->i2s_queue, (void * )&i2s_event, &high_priority_task_awoken);
}
}
if (high_priority_task_awoken == pdTRUE) {
portYIELD_FROM_ISR();
}
i2s_reg->int_clr.val = I2S[i2s_num]->int_st.val;
}
static esp_err_t i2s_destroy_dma_queue(i2s_port_t i2s_num, i2s_dma_t *dma)
{
int bux_idx;
if (p_i2s_obj[i2s_num] == NULL) {
ESP_LOGE(I2S_TAG, "Not initialized yet");
return ESP_FAIL;
}
if (dma == NULL) {
return ESP_FAIL;
}
for (bux_idx = 0; bux_idx < p_i2s_obj[i2s_num]->dma_buf_count; bux_idx++) {
if (dma->desc && dma->desc[bux_idx])
free(dma->desc[bux_idx]);
if (dma->buf && dma->buf[bux_idx])
free(dma->buf[bux_idx]);
}
if (dma->buf)
free(dma->buf);
if (dma->desc)
free(dma->desc);
vQueueDelete(dma->queue);
vSemaphoreDelete(dma->mux);
return ESP_OK;
}
static i2s_dma_t *i2s_create_dma_queue(i2s_port_t i2s_num, int dma_buf_count, int dma_buf_len)
{
int bux_idx;
int sample_size = p_i2s_obj[i2s_num]->bytes_per_sample * p_i2s_obj[i2s_num]->channel_num;
i2s_dma_t *dma = (i2s_dma_t*) malloc(sizeof(i2s_dma_t));
if (dma == NULL) {
ESP_LOGE(I2S_TAG, "Error malloc i2s_dma_t");
return NULL;
}
memset(dma, 0, sizeof(i2s_dma_t));
dma->buf = (char **)malloc(sizeof(char*) * dma_buf_count);
if (dma->buf == NULL) {
ESP_LOGE(I2S_TAG, "Error malloc dma buffer pointer");
return NULL;
}
memset(dma->buf, 0, sizeof(char*) * dma_buf_count);
for (bux_idx = 0; bux_idx < dma_buf_count; bux_idx++) {
dma->buf[bux_idx] = (char*) malloc(dma_buf_len * sample_size);
if (dma->buf[bux_idx] == NULL) {
ESP_LOGE(I2S_TAG, "Error malloc dma buffer");
i2s_destroy_dma_queue(i2s_num, dma);
return NULL;
}
ESP_LOGD(I2S_TAG, "Addr[%d] = %d", bux_idx, (int)dma->buf[bux_idx]);
memset(dma->buf[bux_idx], 0, dma_buf_len * sample_size);
}
dma->desc = (lldesc_t**) malloc(sizeof(lldesc_t*) * dma_buf_count);
if (dma->desc == NULL) {
ESP_LOGE(I2S_TAG, "Error malloc dma description");
i2s_destroy_dma_queue(i2s_num, dma);
return NULL;
}
for (bux_idx = 0; bux_idx < dma_buf_count; bux_idx++) {
dma->desc[bux_idx] = (lldesc_t*) malloc(sizeof(lldesc_t));
if (dma->desc[bux_idx] == NULL) {
ESP_LOGE(I2S_TAG, "Error malloc dma description entry");
i2s_destroy_dma_queue(i2s_num, dma);
return NULL;
}
}
for (bux_idx = 0; bux_idx < dma_buf_count; bux_idx++) {
dma->desc[bux_idx]->owner = 1;
dma->desc[bux_idx]->eof = 1;
dma->desc[bux_idx]->sosf = 0;
dma->desc[bux_idx]->length = dma_buf_len * sample_size;
dma->desc[bux_idx]->size = dma_buf_len * sample_size;
dma->desc[bux_idx]->buf = (uint8_t *) dma->buf[bux_idx];
dma->desc[bux_idx]->offset = 0;
dma->desc[bux_idx]->empty = (uint32_t)((bux_idx < (dma_buf_count - 1)) ? (dma->desc[bux_idx + 1]) : dma->desc[0]);
}
dma->queue = xQueueCreate(dma_buf_count - 1, sizeof(char*));
dma->mux = xSemaphoreCreateMutex();
dma->rw_pos = 0;
dma->buf_size = dma_buf_len * sample_size;
dma->curr_ptr = NULL;
ESP_LOGI(I2S_TAG, "DMA Malloc info, datalen=blocksize=%d, dma_buf_count=%d", dma_buf_len * sample_size, dma_buf_count);
return dma;
}
esp_err_t i2s_start(i2s_port_t i2s_num)
{
//start DMA link
I2S_ENTER_CRITICAL();
esp_intr_disable(p_i2s_obj[i2s_num]->i2s_isr_handle);
I2S[i2s_num]->int_clr.val = 0xFFFFFFFF;
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) {
ESP_LOGD(I2S_TAG, "I2S_MODE_TX");
i2s_enable_tx_intr(i2s_num);
I2S[i2s_num]->out_link.start = 1;
I2S[i2s_num]->conf.tx_start = 1;
}
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) {
ESP_LOGD(I2S_TAG, "I2S_MODE_RX");
i2s_enable_rx_intr(i2s_num);
I2S[i2s_num]->in_link.start = 1;
I2S[i2s_num]->conf.rx_start = 1;
}
esp_intr_enable(p_i2s_obj[i2s_num]->i2s_isr_handle);
I2S_EXIT_CRITICAL();
return ESP_OK;
}
esp_err_t i2s_stop(i2s_port_t i2s_num)
{
I2S_ENTER_CRITICAL();
esp_intr_disable(p_i2s_obj[i2s_num]->i2s_isr_handle);
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) {
I2S[i2s_num]->out_link.stop = 1;
I2S[i2s_num]->conf.tx_start = 0;
i2s_disable_tx_intr(i2s_num);
}
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) {
I2S[i2s_num]->in_link.stop = 1;
I2S[i2s_num]->conf.rx_start = 0;
i2s_disable_rx_intr(i2s_num);
}
I2S_EXIT_CRITICAL();
return 0;
}
static esp_err_t configure_dac_pin(void)
{
SET_PERI_REG_MASK(SENS_SAR_DAC_CTRL1_REG, SENS_DAC_DIG_FORCE_M);
SET_PERI_REG_MASK(SENS_SAR_DAC_CTRL1_REG, SENS_DAC_CLK_INV_M);
SET_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_DAC_XPD_FORCE_M);
SET_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_XPD_DAC_M);
CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_RUE_M);
CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_RDE_M);
SET_PERI_REG_MASK(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_DAC_XPD_FORCE_M);
SET_PERI_REG_MASK(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_XPD_DAC_M);
CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_RUE_M);
CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_RDE_M);
return ESP_OK;
}
esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
if (pin == NULL) {
return configure_dac_pin();
}
if (pin->bck_io_num != -1 && !GPIO_IS_VALID_GPIO(pin->bck_io_num)) {
ESP_LOGE(I2S_TAG, "bck_io_num error");
return ESP_FAIL;
}
if (pin->ws_io_num != -1 && !GPIO_IS_VALID_GPIO(pin->ws_io_num)) {
ESP_LOGE(I2S_TAG, "ws_io_num error");
return ESP_FAIL;
}
if (pin->data_out_num != -1 && !GPIO_IS_VALID_GPIO(pin->data_out_num)) {
ESP_LOGE(I2S_TAG, "data_out_num error");
return ESP_FAIL;
}
if (pin->data_in_num != -1 && !GPIO_IS_VALID_GPIO(pin->data_in_num)) {
ESP_LOGE(I2S_TAG, "data_in_num error");
return ESP_FAIL;
}
int bck_sig = -1, ws_sig = -1, data_out_sig = -1, data_in_sig = -1;
//TX & RX
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) {
bck_sig = I2S0I_BCK_OUT_IDX;
ws_sig = I2S0I_WS_OUT_IDX;
data_in_sig = I2S0I_DATA_IN15_IDX;
if (i2s_num == I2S_NUM_1) {
bck_sig = I2S1I_BCK_OUT_IDX;
ws_sig = I2S1I_WS_OUT_IDX;
data_in_sig = I2S1I_DATA_IN15_IDX;
}
}
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) {
bck_sig = I2S0O_BCK_OUT_IDX;
ws_sig = I2S0O_WS_OUT_IDX;
data_out_sig = I2S0O_DATA_OUT23_IDX;
if (i2s_num == I2S_NUM_1) {
bck_sig = I2S1O_BCK_OUT_IDX;
ws_sig = I2S1O_WS_OUT_IDX;
data_out_sig = I2S1O_DATA_OUT23_IDX;
}
}
gpio_matrix_out_check(pin->data_out_num, data_out_sig, 0, 0);
gpio_matrix_in_check(pin->data_in_num, data_in_sig, 0);
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) {
gpio_matrix_out_check(pin->ws_io_num, ws_sig, 0, 0);
gpio_matrix_out_check(pin->bck_io_num, bck_sig, 0, 0);
} else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_SLAVE) {
gpio_matrix_in_check(pin->ws_io_num, ws_sig, 0);
gpio_matrix_in_check(pin->bck_io_num, bck_sig, 0);
}
ESP_LOGE(I2S_TAG, "data: out %d, in: %d, ws: %d, bck: %d", data_out_sig, data_in_sig, ws_sig, bck_sig);
return ESP_OK;
}
esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
I2S_CHECK((p_i2s_obj[i2s_num]->bytes_per_sample > 0), "bits_per_sample not set", ESP_FAIL);
return i2s_set_clk(i2s_num, rate, p_i2s_obj[i2s_num]->bytes_per_sample*8, 0);
}
static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_config)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
I2S_CHECK((i2s_config), "param null", ESP_FAIL);
if (i2s_num == I2S_NUM_1) {
periph_module_enable(PERIPH_I2S1_MODULE);
} else {
periph_module_enable(PERIPH_I2S0_MODULE);
}
// configure I2S data port interface.
i2s_reset_fifo(i2s_num);
//reset i2s
I2S[i2s_num]->conf.tx_reset = 1;
I2S[i2s_num]->conf.tx_reset = 0;
I2S[i2s_num]->conf.rx_reset = 1;
I2S[i2s_num]->conf.rx_reset = 0;
//reset dma
I2S[i2s_num]->lc_conf.in_rst = 1;
I2S[i2s_num]->lc_conf.in_rst = 0;
I2S[i2s_num]->lc_conf.out_rst = 1;
I2S[i2s_num]->lc_conf.out_rst = 0;
//Enable and configure DMA
I2S[i2s_num]->lc_conf.check_owner = 0;
I2S[i2s_num]->lc_conf.out_loop_test = 0;
I2S[i2s_num]->lc_conf.out_auto_wrback = 0;
I2S[i2s_num]->lc_conf.out_data_burst_en = 0;
I2S[i2s_num]->lc_conf.outdscr_burst_en = 0;
I2S[i2s_num]->lc_conf.out_no_restart_clr = 0;
I2S[i2s_num]->lc_conf.indscr_burst_en = 0;
I2S[i2s_num]->lc_conf.out_eof_mode = 1;
I2S[i2s_num]->conf2.lcd_en = 0;
I2S[i2s_num]->conf2.camera_en = 0;
I2S[i2s_num]->pdm_conf.pcm2pdm_conv_en = 0;
I2S[i2s_num]->pdm_conf.pdm2pcm_conv_en = 0;
I2S[i2s_num]->fifo_conf.dscr_en = 0;
p_i2s_obj[i2s_num]->channel_num = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 2 : 1;
I2S[i2s_num]->conf_chan.tx_chan_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? i2s_config->channel_format : (i2s_config->channel_format >> 1); // 0-two channel;1-right;2-left;3-righ;4-left
I2S[i2s_num]->fifo_conf.tx_fifo_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1; // 0-right&left channel;1-one channel
I2S[i2s_num]->conf.tx_mono = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1; // 0-right&left channel;1-one channel
I2S[i2s_num]->conf_chan.rx_chan_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? i2s_config->channel_format : (i2s_config->channel_format >> 1); // 0-two channel;1-right;2-left;3-righ;4-left
I2S[i2s_num]->fifo_conf.rx_fifo_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1; // 0-right&left channel;1-one channel
I2S[i2s_num]->conf.rx_mono = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1; // 0-right&left channel;1-one channel
I2S[i2s_num]->fifo_conf.dscr_en = 1;//connect dma to fifo
I2S[i2s_num]->conf.tx_start = 0;
I2S[i2s_num]->conf.rx_start = 0;
if (i2s_config->mode & I2S_MODE_TX) {
I2S[i2s_num]->conf.tx_msb_right = 0;
I2S[i2s_num]->conf.tx_right_first = 0;
I2S[i2s_num]->conf.tx_slave_mod = 0; // Master
I2S[i2s_num]->fifo_conf.tx_fifo_mod_force_en = 1;//?
if (i2s_config->mode & I2S_MODE_SLAVE) {
I2S[i2s_num]->conf.tx_slave_mod = 1;//TX Slave
}
}
if (i2s_config->mode & I2S_MODE_RX) {
I2S[i2s_num]->conf.rx_msb_right = 0;
I2S[i2s_num]->conf.rx_right_first = 0;
I2S[i2s_num]->conf.rx_slave_mod = 0; // Master
I2S[i2s_num]->fifo_conf.rx_fifo_mod_force_en = 1;//?
I2S[i2s_num]->rx_eof_num = (i2s_config->dma_buf_len);
if (i2s_config->mode & I2S_MODE_SLAVE) {
I2S[i2s_num]->conf.rx_slave_mod = 1;//RX Slave
}
}
if (i2s_config->mode & I2S_MODE_DAC_BUILT_IN) {
I2S[i2s_num]->conf2.lcd_en = 1;
I2S[i2s_num]->conf.tx_right_first = 1;
I2S[i2s_num]->fifo_conf.tx_fifo_mod = 3;
}
if (i2s_config->communication_format & I2S_COMM_FORMAT_I2S) {
I2S[i2s_num]->conf.tx_short_sync = 0;
I2S[i2s_num]->conf.rx_short_sync = 0;
I2S[i2s_num]->conf.tx_msb_shift = 1;
I2S[i2s_num]->conf.rx_msb_shift = 1;
if (i2s_config->communication_format & I2S_COMM_FORMAT_I2S_LSB) {
if (i2s_config->mode & I2S_MODE_TX) {
I2S[i2s_num]->conf.tx_msb_shift = 0;
}
if (i2s_config->mode & I2S_MODE_RX) {
I2S[i2s_num]->conf.rx_msb_shift = 0;
}
}
}
if (i2s_config->communication_format & I2S_COMM_FORMAT_PCM) {
I2S[i2s_num]->conf.tx_msb_shift = 0;
I2S[i2s_num]->conf.rx_msb_shift = 0;
I2S[i2s_num]->conf.tx_short_sync = 0;
I2S[i2s_num]->conf.rx_short_sync = 0;
if (i2s_config->communication_format & I2S_COMM_FORMAT_PCM_SHORT) {
if (i2s_config->mode & I2S_MODE_TX) {
I2S[i2s_num]->conf.tx_short_sync = 1;
}
if (i2s_config->mode & I2S_MODE_RX) {
I2S[i2s_num]->conf.rx_short_sync = 1;
}
}
}
if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) && (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX)) {
I2S[i2s_num]->conf.sig_loopback = 1;
}
i2s_set_clk(i2s_num, i2s_config->sample_rate, p_i2s_obj[i2s_num]->bytes_per_sample*8, 0);
return ESP_OK;
}
esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num)
{
int total_buffer_in_bytes = p_i2s_obj[i2s_num]->dma_buf_count * p_i2s_obj[i2s_num]->dma_buf_len * p_i2s_obj[i2s_num]->bytes_per_sample * p_i2s_obj[i2s_num]->channel_num;
const uint32_t zero_sample[2] = { 0 };
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
while (total_buffer_in_bytes > 0) {
i2s_push_sample(i2s_num, (const char*) zero_sample, 10);
total_buffer_in_bytes -= p_i2s_obj[i2s_num]->bytes_per_sample * p_i2s_obj[i2s_num]->channel_num;
}
return ESP_OK;
}
esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void* i2s_queue)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
I2S_CHECK((i2s_config != NULL), "I2S configuration must not NULL", ESP_FAIL);
I2S_CHECK((i2s_config->dma_buf_count >= 2 && i2s_config->dma_buf_count <= 128), "I2S buffer count less than 128 and more than 2", ESP_FAIL);
I2S_CHECK((i2s_config->dma_buf_len >= 8 && i2s_config->dma_buf_len <= 2048), "I2S buffer length at most 2048 and more than 8", ESP_FAIL);
if (p_i2s_obj[i2s_num] == NULL) {
p_i2s_obj[i2s_num] = (i2s_obj_t*) malloc(sizeof(i2s_obj_t));
if (p_i2s_obj[i2s_num] == NULL) {
ESP_LOGE(I2S_TAG, "Malloc I2S driver error");
return ESP_FAIL;
}
p_i2s_obj[i2s_num]->i2s_num = i2s_num;
p_i2s_obj[i2s_num]->dma_buf_count = i2s_config->dma_buf_count;
p_i2s_obj[i2s_num]->dma_buf_len = i2s_config->dma_buf_len;
p_i2s_obj[i2s_num]->i2s_queue = i2s_queue;
p_i2s_obj[i2s_num]->mode = i2s_config->mode;
p_i2s_obj[i2s_num]->bytes_per_sample = i2s_config->bits_per_sample/8;
//initial dma
if (ESP_FAIL == i2s_isr_register(i2s_num, i2s_config->intr_alloc_flags, i2s_intr_handler_default, p_i2s_obj[i2s_num], &p_i2s_obj[i2s_num]->i2s_isr_handle)) {
free(p_i2s_obj[i2s_num]);
ESP_LOGE(I2S_TAG, "Register I2S Interrupt error");
return ESP_FAIL;
}
i2s_stop(i2s_num);
i2s_param_config(i2s_num, i2s_config);
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) {
p_i2s_obj[i2s_num]->tx = i2s_create_dma_queue(i2s_num, i2s_config->dma_buf_count, i2s_config->dma_buf_len);
if (p_i2s_obj[i2s_num]->tx == NULL) {
ESP_LOGE(I2S_TAG, "Failed to create tx dma buffer");
i2s_driver_uninstall(i2s_num);
return ESP_FAIL;
}
I2S[i2s_num]->out_link.addr = (uint32_t) p_i2s_obj[i2s_num]->tx->desc[0];
}
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) {
p_i2s_obj[i2s_num]->rx = i2s_create_dma_queue(i2s_num, i2s_config->dma_buf_count, i2s_config->dma_buf_len);
if (p_i2s_obj[i2s_num]->rx == NULL){
ESP_LOGE(I2S_TAG, "Failed to create rx dma buffer");
i2s_driver_uninstall(i2s_num);
return ESP_FAIL;
}
I2S[i2s_num]->in_link.addr = (uint32_t) p_i2s_obj[i2s_num]->rx->desc[0];
}
if (i2s_queue) {
p_i2s_obj[i2s_num]->i2s_queue = xQueueCreate(queue_size, sizeof(i2s_event_t));
*((QueueHandle_t*) i2s_queue) = p_i2s_obj[i2s_num]->i2s_queue;
ESP_LOGI(I2S_TAG, "queue free spaces: %d", uxQueueSpacesAvailable(p_i2s_obj[i2s_num]->i2s_queue));
} else {
p_i2s_obj[i2s_num]->i2s_queue = NULL;
}
i2s_start(i2s_num);
} else {
ESP_LOGE(I2S_TAG, "I2S driver already installed");
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
if (p_i2s_obj[i2s_num] == NULL) {
ESP_LOGI(I2S_TAG, "ALREADY NULL");
return ESP_OK;
}
i2s_stop(i2s_num);
esp_intr_free(p_i2s_obj[i2s_num]->i2s_isr_handle);
if (p_i2s_obj[i2s_num]->tx != NULL && p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) {
i2s_destroy_dma_queue(i2s_num, p_i2s_obj[i2s_num]->tx);
p_i2s_obj[i2s_num]->tx = NULL;
}
if (p_i2s_obj[i2s_num]->rx != NULL && p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) {
i2s_destroy_dma_queue(i2s_num, p_i2s_obj[i2s_num]->rx);
p_i2s_obj[i2s_num]->rx = NULL;
}
if (p_i2s_obj[i2s_num]->i2s_queue) {
vQueueDelete(p_i2s_obj[i2s_num]->i2s_queue);
p_i2s_obj[i2s_num]->i2s_queue = NULL;
}
free(p_i2s_obj[i2s_num]);
p_i2s_obj[i2s_num] = NULL;
if (i2s_num == I2S_NUM_0) {
periph_module_disable(PERIPH_I2S0_MODULE);
} else if (i2s_num == I2S_NUM_1) {
periph_module_disable(PERIPH_I2S1_MODULE);
}
return ESP_OK;
}
int i2s_write_bytes(i2s_port_t i2s_num, const char *src, size_t size, TickType_t ticks_to_wait)
{
char *data_ptr;
int bytes_can_write, bytes_writen = 0;
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
if (p_i2s_obj[i2s_num]->tx == NULL) {
return 0;
}
xSemaphoreTake(p_i2s_obj[i2s_num]->tx->mux, (portTickType)portMAX_DELAY);
while (size > 0) {
if (p_i2s_obj[i2s_num]->tx->rw_pos == p_i2s_obj[i2s_num]->tx->buf_size || p_i2s_obj[i2s_num]->tx->curr_ptr == NULL) {
if (xQueueReceive(p_i2s_obj[i2s_num]->tx->queue, &p_i2s_obj[i2s_num]->tx->curr_ptr, ticks_to_wait) == pdFALSE) {
break;
}
p_i2s_obj[i2s_num]->tx->rw_pos = 0;
}
ESP_LOGD(I2S_TAG, "size: %d, rw_pos: %d, buf_size: %d, curr_ptr: %d", size, p_i2s_obj[i2s_num]->tx->rw_pos, p_i2s_obj[i2s_num]->tx->buf_size, (int)p_i2s_obj[i2s_num]->tx->curr_ptr);
data_ptr = (char*)p_i2s_obj[i2s_num]->tx->curr_ptr;
data_ptr += p_i2s_obj[i2s_num]->tx->rw_pos;
bytes_can_write = p_i2s_obj[i2s_num]->tx->buf_size - p_i2s_obj[i2s_num]->tx->rw_pos;
if (bytes_can_write > size) {
bytes_can_write = size;
}
memcpy(data_ptr, src, bytes_can_write);
size -= bytes_can_write;
src += bytes_can_write;
p_i2s_obj[i2s_num]->tx->rw_pos += bytes_can_write;
bytes_writen += bytes_can_write;
}
xSemaphoreGive(p_i2s_obj[i2s_num]->tx->mux);
return bytes_writen;
}
int i2s_read_bytes(i2s_port_t i2s_num, char* dest, size_t size, TickType_t ticks_to_wait)
{
char *data_ptr;
int bytes_can_read, byte_read = 0;
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
if (p_i2s_obj[i2s_num]->rx == NULL) {
return 0;
}
xSemaphoreTake(p_i2s_obj[i2s_num]->rx->mux, (portTickType)portMAX_DELAY);
while (size > 0) {
if (p_i2s_obj[i2s_num]->rx->rw_pos == p_i2s_obj[i2s_num]->rx->buf_size || p_i2s_obj[i2s_num]->rx->curr_ptr == NULL) {
if (xQueueReceive(p_i2s_obj[i2s_num]->rx->queue, &p_i2s_obj[i2s_num]->rx->curr_ptr, ticks_to_wait) == pdFALSE) {
break;
}
p_i2s_obj[i2s_num]->rx->rw_pos = 0;
}
data_ptr = (char*)p_i2s_obj[i2s_num]->rx->curr_ptr;
data_ptr += p_i2s_obj[i2s_num]->rx->rw_pos;
bytes_can_read = p_i2s_obj[i2s_num]->rx->buf_size - p_i2s_obj[i2s_num]->rx->rw_pos;
if (bytes_can_read > size) {
bytes_can_read = size;
}
memcpy(dest, data_ptr, bytes_can_read);
size -= bytes_can_read;
dest += bytes_can_read;
p_i2s_obj[i2s_num]->rx->rw_pos += bytes_can_read;
byte_read += bytes_can_read;
}
xSemaphoreGive(p_i2s_obj[i2s_num]->rx->mux);
return byte_read;
}
int i2s_push_sample(i2s_port_t i2s_num, const char *sample, TickType_t ticks_to_wait)
{
int i, bytes_to_push = 0;
char *data_ptr;
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
if (p_i2s_obj[i2s_num]->tx->rw_pos == p_i2s_obj[i2s_num]->tx->buf_size || p_i2s_obj[i2s_num]->tx->curr_ptr == NULL) {
if (xQueueReceive(p_i2s_obj[i2s_num]->tx->queue, &p_i2s_obj[i2s_num]->tx->curr_ptr, ticks_to_wait) == pdFALSE) {
return 0;
}
ESP_LOGD(I2S_TAG, "rw_pos: %d, buf_size: %d, curr_ptr: %d", p_i2s_obj[i2s_num]->tx->rw_pos, p_i2s_obj[i2s_num]->tx->buf_size, (int)p_i2s_obj[i2s_num]->tx->curr_ptr);
p_i2s_obj[i2s_num]->tx->rw_pos = 0;
}
data_ptr = (char*)p_i2s_obj[i2s_num]->tx->curr_ptr;
data_ptr += p_i2s_obj[i2s_num]->tx->rw_pos;
for (i = 0; i < p_i2s_obj[i2s_num]->bytes_per_sample; i++) {
*data_ptr++ = *sample++;
bytes_to_push ++;
}
if (p_i2s_obj[i2s_num]->channel_num == 2) {
for (i = 0; i < p_i2s_obj[i2s_num]->bytes_per_sample; i++) {
*data_ptr++ = *sample++;
bytes_to_push ++;
}
}
p_i2s_obj[i2s_num]->tx->rw_pos += p_i2s_obj[i2s_num]->bytes_per_sample * p_i2s_obj[i2s_num]->channel_num;
return bytes_to_push;
}
int i2s_pop_sample(i2s_port_t i2s_num, char *sample, TickType_t ticks_to_wait)
{
int i, bytes_to_pop = 0;
char *data_ptr;
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_FAIL);
if (p_i2s_obj[i2s_num]->rx->rw_pos == p_i2s_obj[i2s_num]->rx->buf_size || p_i2s_obj[i2s_num]->rx->curr_ptr == NULL) {
if (xQueueReceive(p_i2s_obj[i2s_num]->rx->queue, &p_i2s_obj[i2s_num]->rx->curr_ptr, ticks_to_wait) == pdFALSE) {
return 0;
}
p_i2s_obj[i2s_num]->rx->rw_pos = 0;
}
data_ptr = (char*)p_i2s_obj[i2s_num]->rx->curr_ptr;
data_ptr += p_i2s_obj[i2s_num]->rx->rw_pos;
for (i = 0; i < p_i2s_obj[i2s_num]->bytes_per_sample; i++) {
*sample++ = *data_ptr++;
bytes_to_pop++;
}
if (p_i2s_obj[i2s_num]->channel_num == 2) {
for (i = 0; i < p_i2s_obj[i2s_num]->bytes_per_sample; i++) {
*sample++ = *data_ptr++;
bytes_to_pop++;
}
}
p_i2s_obj[i2s_num]->rx->rw_pos += p_i2s_obj[i2s_num]->bytes_per_sample * p_i2s_obj[i2s_num]->channel_num;
return bytes_to_pop;
}

View File

@ -0,0 +1,380 @@
// Copyright 2015-2016 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.
#ifndef _DRIVER_I2S_H_
#define _DRIVER_I2S_H_
#include "esp_err.h"
#include <esp_types.h>
#include "soc/gpio_reg.h"
#include "soc/soc.h"
#include "soc/i2s_struct.h"
#include "soc/i2s_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/io_mux_reg.h"
#include "rom/gpio.h"
#include "esp_attr.h"
#include "esp_intr_alloc.h"
#include "driver/periph_ctrl.h"
#include "freertos/semphr.h"
#ifdef __cplusplus
extern "C" {
#endif
#define I2S_PIN_NO_CHANGE (-1)
/**
* @brief I2S bit width per sample.
*
*/
typedef enum {
I2S_BITS_PER_SAMPLE_8BIT = 8, /*!< I2S bits per sample: 8-bits*/
I2S_BITS_PER_SAMPLE_16BIT = 16, /*!< I2S bits per sample: 16-bits*/
I2S_BITS_PER_SAMPLE_24BIT = 24, /*!< I2S bits per sample: 24-bits*/
I2S_BITS_PER_SAMPLE_32BIT = 32, /*!< I2S bits per sample: 32-bits*/
} i2s_bits_per_sample_t;
/**
* @brief I2S communication standard format
*
*/
typedef enum {
I2S_COMM_FORMAT_I2S = 0x01, /*!< I2S communication format I2S*/
I2S_COMM_FORMAT_I2S_MSB = 0x02, /*!< I2S format MSB*/
I2S_COMM_FORMAT_I2S_LSB = 0x04, /*!< I2S format LSB*/
I2S_COMM_FORMAT_PCM = 0x08, /*!< I2S communication format PCM*/
I2S_COMM_FORMAT_PCM_SHORT = 0x10, /*!< PCM Short*/
I2S_COMM_FORMAT_PCM_LONG = 0x20, /*!< PCM Long*/
} i2s_comm_format_t;
/**
* @brief I2S channel format type
*/
typedef enum {
I2S_CHANNEL_FMT_RIGHT_LEFT = 0x00,
I2S_CHANNEL_FMT_ALL_RIGHT,
I2S_CHANNEL_FMT_ALL_LEFT,
I2S_CHANNEL_FMT_ONLY_RIGHT,
I2S_CHANNEL_FMT_ONLY_LEFT,
} i2s_channel_fmt_t;
/**
* @brief PDM sample rate ratio, measured in Hz.
*
*/
typedef enum {
PDM_SAMPLE_RATE_RATIO_64,
PDM_SAMPLE_RATE_RATIO_128,
} pdm_sample_rate_ratio_t;
/**
* @brief PDM PCM convter enable/disable.
*
*/
typedef enum {
PDM_PCM_CONV_ENABLE,
PDM_PCM_CONV_DISABLE,
} pdm_pcm_conv_t;
/**
* @brief I2S Peripheral, 0 & 1.
*
*/
typedef enum {
I2S_NUM_0 = 0x0, /*!< I2S 0*/
I2S_NUM_1 = 0x1, /*!< I2S 1*/
I2S_NUM_MAX,
} i2s_port_t;
/**
* @brief I2S Mode, defaut is I2S_MODE_MASTER | I2S_MODE_TX
*
*/
typedef enum {
I2S_MODE_MASTER = 1,
I2S_MODE_SLAVE = 2,
I2S_MODE_TX = 4,
I2S_MODE_RX = 8,
I2S_MODE_DAC_BUILT_IN = 16
} i2s_mode_t;
/**
* @brief I2S configuration parameters for i2s_param_config function
*
*/
typedef struct {
i2s_mode_t mode; /*!< I2S work mode*/
int sample_rate; /*!< I2S sample rate*/
i2s_bits_per_sample_t bits_per_sample; /*!< I2S bits per sample*/
i2s_channel_fmt_t channel_format; /*!< I2S channel format */
i2s_comm_format_t communication_format; /*!< I2S communication format */
int intr_alloc_flags; /*!< Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info */
int dma_buf_count; /*!< I2S DMA Buffer Count */
int dma_buf_len; /*!< I2S DMA Buffer Length */
} i2s_config_t;
/**
* @brief I2S event types
*
*/
typedef enum {
I2S_EVENT_DMA_ERROR,
I2S_EVENT_TX_DONE, /*!< I2S DMA finish sent 1 buffer*/
I2S_EVENT_RX_DONE, /*!< I2S DMA finish received 1 buffer*/
I2S_EVENT_MAX, /*!< I2S event max index*/
} i2s_event_type_t;
/**
* @brief Event structure used in I2S event queue
*
*/
typedef struct {
i2s_event_type_t type; /*!< I2S event type */
size_t size; /*!< I2S data size for I2S_DATA event*/
} i2s_event_t;
/**
* @brief I2S pin number for i2s_set_pin
*
*/
typedef struct {
int bck_io_num; /*!< BCK in out pin*/
int ws_io_num; /*!< WS in out pin*/
int data_out_num; /*!< DATA out pin*/
int data_in_num; /*!< DATA in pin*/
} i2s_pin_config_t;
typedef intr_handle_t i2s_isr_handle_t;
/**
* @brief Set I2S pin number
*
* @note
* Internal signal can be output to multiple GPIO pads
* Only one GPIO pad can connect with input signal
*
* @param i2s_num I2S_NUM_0 or I2S_NUM_1
*
* @param pin I2S Pin struct, or NULL for 2-channels, 8-bits DAC pin configuration (GPIO25 & GPIO26)
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin);
/**
* @brief i2s install and start driver
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param i2s_config I2S configurations - see i2s_config_t struct
*
* @param queue_size I2S event queue size/depth.
*
* @param i2s_queue I2S event queue handle, if set NULL, driver will not use an event queue.
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
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.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num);
/**
* @brief i2s read data buffer to i2s dma buffer
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param src source address to write
*
* @param size size of data (size in bytes)
*
* @param ticks_to_wait Write timeout
*
* @return number of written bytes
*/
int i2s_write_bytes(i2s_port_t i2s_num, const char *src, size_t size, TickType_t ticks_to_wait);
/**
* @brief i2s write data buffer to i2s dma buffer
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param dest destination address to read
*
* @param size size of data (size in bytes)
*
* @param ticks_to_wait Read timeout
*
* @return number of read bytes
*/
int i2s_read_bytes(i2s_port_t i2s_num, char* dest, size_t size, TickType_t ticks_to_wait);
/**
* @brief i2s push 1 sample to i2s dma buffer, with the size parameter equal to one sample's size in bytes = bits_per_sample/8.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param sample destination address to write (depend on bits_per_sample, size of sample (in bytes) = 2*bits_per_sample/8)
*
* @param ticks_to_wait Push timeout
*
* @return number of push bytes
*/
int i2s_push_sample(i2s_port_t i2s_num, const char *sample, TickType_t ticks_to_wait);
/**
* @brief Pop 1 sample to i2s dma buffer, with the size parameter equal to one sample's size in bytes = bits_per_sample/8.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param sample destination address to write (depend on bits_per_sample, size of sample (in bytes) = 2*bits_per_sample/8)
*
* @param ticks_to_wait Pop timeout
*
* @return number of pop bytes
*/
int i2s_pop_sample(i2s_port_t i2s_num, char *sample, TickType_t ticks_to_wait);
/**
* @brief Set clock rate used for I2S RX and TX
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param rate I2S clock (ex: 8000, 44100...)
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate);
/**
* @brief Start driver
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t i2s_start(i2s_port_t i2s_num);
/**
* @brief Stop driver
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t i2s_stop(i2s_port_t i2s_num);
/**
* @brief Set the TX DMA buffer contents to all zeroes
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num);
/***************************EXAMPLE**********************************
*
*
* ----------------EXAMPLE OF I2S SETTING ---------------------
* @code{c}
*
* #include "freertos/queue.h"
* #define I2S_INTR_NUM 17 //choose one interrupt number from soc.h
* 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 = 16, //16, 32
* .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //format LEFT_RIGHT
* .communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
* .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
* .dma_buf_count = 8,
* .dma_buf_len = 64
* };
*
* i2s_pin_config_t pin_config = {
* .bck_io_num = 26,
* .ws_io_num = 25,
* .data_out_num = 22,
* .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
*
*
* i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver
*@endcode
*
* ----------------EXAMPLE USING I2S WITH DAC ---------------------
* @code{c}
*
* #include "freertos/queue.h"
* #define I2S_INTR_NUM 17 //choose one interrupt number from soc.h
* int i2s_num = 0; //i2s port number
* i2s_config_t i2s_config = {
* .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN,
* .sample_rate = 44100,
* .bits_per_sample = 8, // Only 8-bit DAC support
* .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //
* .communication_format = I2S_COMM_FORMAT_I2S_MSB,
* .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
* .dma_buf_count = 8,
* .dma_buf_len = 64
* };
*
*
* i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver
*
* i2s_set_pin(i2s_num, NULL); //for internal DAC
*
* i2s_set_sample_rates(i2s_num, 22050); //set sample rates
*
* i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver
*@endcode
*-----------------------------------------------------------------------------*
***************************END OF EXAMPLE**********************************/
#ifdef __cplusplus
}
#endif
#endif /* _DRIVER_I2S_H_ */

8
examples/22_i2s/Makefile Normal file
View File

@ -0,0 +1,8 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
VERBOSE = 1
PROJECT_NAME := esp32-i2s-driver-example
include $(IDF_PATH)/make/project.mk

View File

@ -0,0 +1,72 @@
/* I2S Example
This example code will output 100Hz sine wave and triangle wave to 2-channel of I2S driver
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "driver/i2s.h"
#include <math.h>
#define SAMPLE_RATE (36000)
#define I2S_NUM (0)
#define WAVE_FREQ_HZ (100)
#define PI 3.14159265
#define SAMPLE_PER_CYCLE (SAMPLE_RATE/WAVE_FREQ_HZ)
void app_main()
{
unsigned int i, sample_val;
float sin_float, triangle_float, triangle_step = 65536.0 / SAMPLE_PER_CYCLE;
//for 36Khz sample rates, we create 100Hz sine wave, every cycle need 36000/100 = 360 samples (4-bytes each sample)
//using 6 buffers, we need 60-samples per buffer
//2-channels, 16-bit each channel, total buffer is 360*4 = 1440 bytes
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX
.sample_rate = SAMPLE_RATE,
.bits_per_sample = 16, //16-bit per channel
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels
.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
.dma_buf_count = 6,
.dma_buf_len = 60, //
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 //Interrupt level 1
};
i2s_pin_config_t pin_config = {
.bck_io_num = 26,
.ws_io_num = 25,
.data_out_num = 22,
.data_in_num = -1 //Not used
};
nvs_flash_init();
i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
i2s_set_pin(I2S_NUM, &pin_config);
triangle_float = -32767;
for(i = 0; i < SAMPLE_PER_CYCLE; i++) {
sin_float = sin(i * PI / 180.0);
if(sin_float >= 0)
triangle_float += triangle_step;
else
triangle_float -= triangle_step;
sin_float *= 32767;
sample_val = 0;
sample_val += (short)triangle_float;
sample_val = sample_val << 16;
sample_val += (short) sin_float;
i2s_push_sample(I2S_NUM, (char *)&sample_val, portMAX_DELAY);
}
}

View File

@ -0,0 +1,10 @@
#
# Main Makefile. This is basically the same as a component makefile.
#
# This Makefile should, at the very least, just include $(SDK_PATH)/make/component.mk. By default,
# this will take the sources in the src/ directory, compile them and link them into
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
# please read the SDK documents if you need to do this.
#
COMPONENT_ADD_INCLUDEDIRS := .