// Copyright 2018-2025 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 <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "esp8266/eagle_soc.h"
#include "esp8266/pin_mux_register.h"
#include "esp8266/i2s_register.h"
#include "esp8266/i2s_struct.h"
#include "esp8266/slc_register.h"
#include "esp8266/slc_struct.h"
#include "rom/ets_sys.h"
#include "esp_attr.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_libc.h"
#include "esp_heap_caps.h"
#include "driver/i2s.h"
static const char *I2S_TAG = "i2s";
#define I2S_CHECK(a, str, ret_val) \
if (!(a)) { \
ESP_LOGE(I2S_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
return (ret_val); \
}
#define portYIELD_FROM_ISR() taskYIELD()
#define dma_intr_enable() _xt_isr_unmask(1 << ETS_SLC_INUM) // ETS_SLC_INUM
#define dma_intr_disable() _xt_isr_mask(1 << ETS_SLC_INUM)
#define dma_intr_register(a, b) _xt_isr_attach(ETS_SLC_INUM, (a), (b))
#if 0
// Define them here if we can't find them.
#ifndef i2c_bbpll
#define i2c_bbpll 0x67
#define i2c_bbpll_en_audio_clock_out 4
#define i2c_bbpll_en_audio_clock_out_msb 7
#define i2c_bbpll_en_audio_clock_out_lsb 7
#define i2c_bbpll_hostid 4
/* ROM functions which read/write internal control bus */
uint8_t rom_i2c_readReg(uint8_t block, uint8_t host_id, uint8_t reg_add);
uint8_t rom_i2c_readReg_Mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb);
void rom_i2c_writeReg(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t data);
void rom_i2c_writeReg_Mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb, uint8_t data);
#define i2c_writeReg_Mask(block, host_id, reg_add, Msb, Lsb, indata) rom_i2c_writeReg_Mask(block, host_id, reg_add, Msb, Lsb, indata)
#define i2c_readReg_Mask(block, host_id, reg_add, Msb, Lsb) rom_i2c_readReg_Mask(block, host_id, reg_add, Msb, Lsb)
#define i2c_writeReg_Mask_def(block, reg_add, indata) \
i2c_writeReg_Mask(block, block##_hostid, reg_add, reg_add##_msb, reg_add##_lsb, indata)
#define i2c_readReg_Mask_def(block, reg_add) \
i2c_readReg_Mask(block, block##_hostid, reg_add, reg_add##_msb, reg_add##_lsb)
#endif
#define I2S_CLK_ENABLE() i2c_writeReg_Mask_def(i2c_bbpll, i2c_bbpll_en_audio_clock_out, 1)
#define I2S_CLK_DISABLE() i2c_writeReg_Mask_def(i2c_bbpll, i2c_bbpll_en_audio_clock_out, 0)
#endif
#define I2S_MAX_BUFFER_SIZE (4 * 1024 * 1024) // the maximum RAM can be allocated
#define I2S_BASE_CLK (2 * APB_CLK_FREQ)
#define I2S_ENTER_CRITICAL() portENTER_CRITICAL()
#define I2S_EXIT_CRITICAL() portEXIT_CRITICAL()
#define I2S_FULL_DUPLEX_SLAVE_MODE_MASK (I2S_MODE_TX | I2S_MODE_RX | I2S_MODE_SLAVE)
#define I2S_FULL_DUPLEX_MASTER_MODE_MASK (I2S_MODE_TX | I2S_MODE_RX | I2S_MODE_MASTER)
typedef struct lldesc {
uint32_t blocksize : 12;
uint32_t datalen : 12;
uint32_t unused : 5;
uint32_t sub_sof : 1;
uint32_t eof : 1;
volatile uint32_t owner : 1; // DMA can change this value
uint32_t *buf_ptr;
struct lldesc *next_link_ptr;
} lldesc_t;
/**
* @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 S_I2S object instance
*/
typedef struct {
i2s_port_t i2s_num; /*!< S_I2S port number*/
int queue_size; /*!< S_I2S event queue size*/
QueueHandle_t i2s_queue; /*!< S_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*/
int channel_num; /*!< Number of channels*/
int bytes_per_sample; /*!< Bytes per sample*/
int bits_per_sample; /*!< Bits per sample*/
i2s_mode_t mode; /*!< S_I2S Working mode*/
uint32_t sample_rate; /*!< S_I2S sample rate */
bool tx_desc_auto_clear; /*!< S_I2S auto clear tx descriptor on underflow */
slc_struct_t *dma;
} i2s_obj_t;
static i2s_obj_t *p_i2s_obj[I2S_NUM_MAX] = {0};
static i2s_struct_t *S_I2S[I2S_NUM_MAX] = {&I2S};
static i2s_dma_t *i2s_create_dma_queue(i2s_port_t i2s_num, int dma_buf_count, int dma_buf_len);
static esp_err_t i2s_destroy_dma_queue(i2s_port_t i2s_num, i2s_dma_t *dma);
static esp_err_t i2s_reset_fifo(i2s_port_t i2s_num)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
I2S_ENTER_CRITICAL();
S_I2S[i2s_num]->conf.rx_fifo_reset = 1;
S_I2S[i2s_num]->conf.rx_fifo_reset = 0;
S_I2S[i2s_num]->conf.tx_fifo_reset = 1;
S_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_ERR_INVALID_ARG);
I2S_CHECK(p_i2s_obj[i2s_num], "S_I2S not installed yet", ESP_FAIL);
p_i2s_obj[i2s_num]->dma->int_clr.val = clr_mask;
return ESP_OK;
}
esp_err_t i2s_enable_rx_intr(i2s_port_t i2s_num)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
I2S_CHECK(p_i2s_obj[i2s_num], "S_I2S not installed yet", ESP_FAIL);
I2S_ENTER_CRITICAL();
p_i2s_obj[i2s_num]->dma->int_ena.tx_suc_eof = 1;
p_i2s_obj[i2s_num]->dma->int_ena.tx_dscr_err = 1;
I2S_EXIT_CRITICAL();
return ESP_OK;
}
esp_err_t i2s_disable_rx_intr(i2s_port_t i2s_num)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
I2S_CHECK(p_i2s_obj[i2s_num], "S_I2S not installed yet", ESP_FAIL);
I2S_ENTER_CRITICAL();
p_i2s_obj[i2s_num]->dma->int_ena.tx_suc_eof = 0;
p_i2s_obj[i2s_num]->dma->int_ena.tx_dscr_err = 0;
I2S_EXIT_CRITICAL();
return ESP_OK;
}
esp_err_t i2s_disable_tx_intr(i2s_port_t i2s_num)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
I2S_CHECK(p_i2s_obj[i2s_num], "S_I2S not installed yet", ESP_FAIL);
I2S_ENTER_CRITICAL();
p_i2s_obj[i2s_num]->dma->int_ena.rx_eof = 0;
p_i2s_obj[i2s_num]->dma->int_ena.rx_dscr_err = 0;
I2S_EXIT_CRITICAL();
return ESP_OK;
}
esp_err_t i2s_enable_tx_intr(i2s_port_t i2s_num)
{
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
I2S_CHECK(p_i2s_obj[i2s_num], "S_I2S not installed yet", ESP_FAIL);
I2S_ENTER_CRITICAL();
p_i2s_obj[i2s_num]->dma->int_ena.rx_eof = 1;
p_i2s_obj[i2s_num]->dma->int_ena.rx_dscr_err = 1;
I2S_EXIT_CRITICAL();
return ESP_OK;
}
static void IRAM_ATTR i2s_intr_handler_default(void *arg)
{
i2s_obj_t *p_i2s = (i2s_obj_t *) arg;
slc_struct_t *dma_reg = p_i2s->dma;
i2s_event_t i2s_event;
int dummy;
portBASE_TYPE high_priority_task_awoken = 0;
lldesc_t *finish_desc;
if (dma_reg->int_st.tx_dscr_err || dma_reg->int_st.rx_dscr_err) {
//ESP_EARLY_LOGE(I2S_TAG, "dma error, interrupt status: 0x%08x", dma_reg
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
收起资源包目录
esp8266-i2s驱动适配米家SDK.zip (2个子文件)
esp8266-i2s驱动适配米家SDK
i2s.c 34KB
i2s.h 10KB
共 2 条
- 1
零一2035
- 粉丝: 156
- 资源: 15
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
- 1
- 2
- 3
前往页