2019-06-06 09:00:03 +00:00
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
2016-12-29 09:29:14 +00:00
//
// 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
2019-07-15 06:44:15 +00:00
//
2016-12-29 09:29:14 +00:00
// 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.
2019-07-15 06:44:15 +00:00
2016-12-29 09:29:14 +00:00
# include <string.h>
2019-07-15 06:44:15 +00:00
# include <stdbool.h>
2017-08-16 08:31:11 +00:00
# include <math.h>
2016-12-29 09:29:14 +00:00
# include <esp_types.h>
# include "freertos/FreeRTOS.h"
# include "freertos/queue.h"
# include "freertos/xtensa_api.h"
2020-03-02 04:07:47 +00:00
# include "freertos/semphr.h"
2016-12-29 09:29:14 +00:00
2019-07-15 06:44:15 +00:00
# include "esp32/rom/lldesc.h"
2016-12-29 09:29:14 +00:00
# include "driver/gpio.h"
# include "driver/i2s.h"
2020-02-20 08:00:48 +00:00
# if SOC_I2S_SUPPORTS_ADC_DAC
2017-05-03 10:55:52 +00:00
# include "driver/dac.h"
2020-03-02 04:07:47 +00:00
# include "hal/i2s_hal.h"
2020-02-25 14:19:48 +00:00
# include "adc1_private.h"
2020-02-20 08:00:48 +00:00
# endif
2016-12-29 09:29:14 +00:00
2019-03-26 08:30:43 +00:00
# include "esp_intr_alloc.h"
2016-12-29 09:29:14 +00:00
# include "esp_err.h"
2020-03-02 04:07:47 +00:00
# include "esp_attr.h"
2016-12-29 09:29:14 +00:00
# include "esp_log.h"
2019-02-22 12:17:42 +00:00
# include "esp_pm.h"
2019-11-21 13:10:46 +00:00
# include "esp_efuse.h"
2016-12-29 09:29:14 +00:00
static const char * I2S_TAG = " I2S " ;
2019-02-22 12:17:42 +00:00
2016-12-29 09:29:14 +00:00
# define I2S_CHECK(a, str, ret) if (!(a)) { \
ESP_LOGE ( I2S_TAG , " %s:%d (%s):%s " , __FILE__ , __LINE__ , __FUNCTION__ , str ) ; \
return ( ret ) ; \
}
2019-07-15 06:44:15 +00:00
2018-11-27 06:10:33 +00:00
# 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])
2017-05-03 10:55:52 +00:00
# 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)
2019-07-15 06:44:15 +00:00
2016-12-29 09:29:14 +00:00
/**
* @ 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*/
2017-02-06 06:11:11 +00:00
int bits_per_sample ; /*!< Bits per sample*/
2016-12-29 09:29:14 +00:00
i2s_mode_t mode ; /*!< I2S Working mode*/
2017-12-08 12:07:19 +00:00
uint32_t sample_rate ; /*!< I2S sample rate */
2018-02-16 06:50:45 +00:00
bool use_apll ; /*!< I2S use APLL clock */
2018-05-14 09:03:45 +00:00
bool tx_desc_auto_clear ; /*!< I2S auto clear tx descriptor on underflow */
2018-02-16 06:50:45 +00:00
int fixed_mclk ; /*!< I2S fixed MLCK clock */
2019-06-19 10:36:20 +00:00
double real_rate ;
2019-02-22 12:17:42 +00:00
# ifdef CONFIG_PM_ENABLE
esp_pm_lock_handle_t pm_lock ;
# endif
2019-07-15 06:44:15 +00:00
i2s_hal_context_t hal ; /*!< I2S hal context*/
2016-12-29 09:29:14 +00:00
} i2s_obj_t ;
static i2s_obj_t * p_i2s_obj [ I2S_NUM_MAX ] = { 0 } ;
2019-07-15 06:44:15 +00:00
static portMUX_TYPE i2s_spinlock [ I2S_NUM_MAX ] ;
2020-02-20 08:00:48 +00:00
# if SOC_I2S_SUPPORTS_ADC_DAC
2017-12-08 12:07:19 +00:00
static int _i2s_adc_unit = - 1 ;
static int _i2s_adc_channel = - 1 ;
2020-02-20 08:00:48 +00:00
# endif
2017-08-16 08:31:11 +00:00
2017-02-06 06:11:11 +00:00
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 ) ;
2019-07-15 06:44:15 +00:00
2016-12-29 09:29:14 +00:00
static esp_err_t i2s_reset_fifo ( i2s_port_t i2s_num )
{
2017-02-06 06:11:11 +00:00
I2S_CHECK ( ( i2s_num < I2S_NUM_MAX ) , " i2s_num error " , ESP_ERR_INVALID_ARG ) ;
2016-12-29 09:29:14 +00:00
I2S_ENTER_CRITICAL ( ) ;
2019-07-15 06:44:15 +00:00
i2s_hal_reset_fifo ( & ( p_i2s_obj [ i2s_num ] - > hal ) ) ;
2016-12-29 09:29:14 +00:00
I2S_EXIT_CRITICAL ( ) ;
return ESP_OK ;
}
2019-12-09 07:20:41 +00:00
static inline void gpio_matrix_out_check ( uint32_t gpio , uint32_t signal_idx , bool out_inv , bool oen_inv )
2017-02-06 06:11:11 +00:00
{
//if pin = -1, do not need to configure
if ( gpio ! = - 1 ) {
PIN_FUNC_SELECT ( GPIO_PIN_MUX_REG [ gpio ] , PIN_FUNC_GPIO ) ;
2017-05-03 10:55:52 +00:00
gpio_set_direction ( gpio , GPIO_MODE_DEF_OUTPUT ) ;
2017-02-06 06:11:11 +00:00
gpio_matrix_out ( gpio , signal_idx , out_inv , oen_inv ) ;
2018-02-16 06:50:45 +00:00
}
}
2019-07-15 06:44:15 +00:00
2019-12-09 07:20:41 +00:00
static inline void gpio_matrix_in_check ( uint32_t gpio , uint32_t signal_idx , bool inv )
2017-02-06 06:11:11 +00:00
{
if ( gpio ! = - 1 ) {
PIN_FUNC_SELECT ( GPIO_PIN_MUX_REG [ gpio ] , PIN_FUNC_GPIO ) ;
2017-05-03 10:55:52 +00:00
//Set direction, for some GPIOs, the input function are not enabled as default.
gpio_set_direction ( gpio , GPIO_MODE_DEF_INPUT ) ;
2017-02-06 06:11:11 +00:00
gpio_matrix_in ( gpio , signal_idx , inv ) ;
}
}
2016-12-29 09:29:14 +00:00
esp_err_t i2s_clear_intr_status ( i2s_port_t i2s_num , uint32_t clr_mask )
{
2017-02-06 06:11:11 +00:00
I2S_CHECK ( ( i2s_num < I2S_NUM_MAX ) , " i2s_num error " , ESP_ERR_INVALID_ARG ) ;
2019-07-15 06:44:15 +00:00
i2s_hal_clear_intr_status ( & ( p_i2s_obj [ i2s_num ] - > hal ) , clr_mask ) ;
2016-12-29 09:29:14 +00:00
return ESP_OK ;
}
esp_err_t i2s_enable_rx_intr ( i2s_port_t i2s_num )
{
I2S_ENTER_CRITICAL ( ) ;
2019-07-15 06:44:15 +00:00
i2s_hal_enable_rx_intr ( & ( p_i2s_obj [ i2s_num ] - > hal ) ) ;
2016-12-29 09:29:14 +00:00
I2S_EXIT_CRITICAL ( ) ;
return ESP_OK ;
}
esp_err_t i2s_disable_rx_intr ( i2s_port_t i2s_num )
{
I2S_ENTER_CRITICAL ( ) ;
2019-07-15 06:44:15 +00:00
i2s_hal_disable_rx_intr ( & ( p_i2s_obj [ i2s_num ] - > hal ) ) ;
2016-12-29 09:29:14 +00:00
I2S_EXIT_CRITICAL ( ) ;
return ESP_OK ;
}
esp_err_t i2s_disable_tx_intr ( i2s_port_t i2s_num )
{
I2S_ENTER_CRITICAL ( ) ;
2019-07-15 06:44:15 +00:00
i2s_hal_disable_tx_intr ( & ( p_i2s_obj [ i2s_num ] - > hal ) ) ;
2016-12-29 09:29:14 +00:00
I2S_EXIT_CRITICAL ( ) ;
return ESP_OK ;
}
esp_err_t i2s_enable_tx_intr ( i2s_port_t i2s_num )
{
I2S_ENTER_CRITICAL ( ) ;
2019-07-15 06:44:15 +00:00
i2s_hal_enable_tx_intr ( & ( p_i2s_obj [ i2s_num ] - > hal ) ) ;
2016-12-29 09:29:14 +00:00
I2S_EXIT_CRITICAL ( ) ;
return ESP_OK ;
}
2019-06-19 10:36:20 +00:00
float i2s_get_clk ( i2s_port_t i2s_num )
{
I2S_CHECK ( ( i2s_num < I2S_NUM_MAX ) , " i2s_num error " , ESP_ERR_INVALID_ARG ) ;
return p_i2s_obj [ i2s_num ] - > real_rate ;
}
2018-02-07 13:14:41 +00:00
static esp_err_t i2s_isr_register ( i2s_port_t i2s_num , int intr_alloc_flags , void ( * fn ) ( void * ) , void * arg , i2s_isr_handle_t * handle )
2016-12-29 09:29:14 +00:00
{
2019-06-06 09:00:03 +00:00
return esp_intr_alloc ( i2s_periph_signal [ i2s_num ] . irq , intr_alloc_flags , fn , arg , handle ) ;
2016-12-29 09:29:14 +00:00
}
2018-02-16 06:50:45 +00:00
static float i2s_apll_get_fi2s ( int bits_per_sample , int sdm0 , int sdm1 , int sdm2 , int odir )
2017-08-16 08:31:11 +00:00
{
int f_xtal = ( int ) rtc_clk_xtal_freq_get ( ) * 1000000 ;
2019-11-21 13:10:46 +00:00
# if CONFIG_IDF_TARGET_ESP32
/* ESP32 rev0 silicon issue for APLL range/accuracy, please see ESP32 ECO document for more information on this */
if ( esp_efuse_get_chip_ver ( ) = = 0 ) {
2017-08-16 08:31:11 +00:00
sdm0 = 0 ;
sdm1 = 0 ;
}
2019-11-21 13:10:46 +00:00
# endif
2017-08-16 08:31:11 +00:00
float fout = f_xtal * ( sdm2 + sdm1 / 256.0f + sdm0 / 65536.0f + 4 ) ;
if ( fout < APLL_MIN_FREQ | | fout > APLL_MAX_FREQ ) {
2018-02-16 06:50:45 +00:00
return APLL_MAX_FREQ ;
2017-08-16 08:31:11 +00:00
}
float fpll = fout / ( 2 * ( odir + 2 ) ) ; //== fi2s (N=1, b=0, a=1)
2018-02-16 06:50:45 +00:00
return fpll / 2 ;
2017-08-16 08:31:11 +00:00
}
/**
* @ brief APLL calculate function , was described by following :
* APLL Output frequency is given by the formula :
2018-02-16 06:50:45 +00:00
*
2017-08-16 08:31:11 +00:00
* apll_freq = xtal_freq * ( 4 + sdm2 + sdm1 / 256 + sdm0 / 65536 ) / ( ( o_div + 2 ) * 2 )
* apll_freq = fout / ( ( o_div + 2 ) * 2 )
2018-02-16 06:50:45 +00:00
*
2017-08-16 08:31:11 +00:00
* The dividend in this expression should be in the range of 240 - 600 MHz .
* In rev . 0 of ESP32 , sdm0 and sdm1 are unused and always set to 0.
* * sdm0 frequency adjustment parameter , 0. .255
* * sdm1 frequency adjustment parameter , 0. .255
* * sdm2 frequency adjustment parameter , 0. .63
* * o_div frequency divider , 0. .31
2018-02-16 06:50:45 +00:00
*
* The most accurate way to find the sdm0 . .2 and odir parameters is to loop through them all ,
* then apply the above formula , finding the closest frequency to the desired one .
2017-08-16 08:31:11 +00:00
* But 256 * 256 * 64 * 32 = 134.217 .728 loops are too slow with ESP32
* 1. We will choose the parameters with the highest level of change ,
2018-02-16 06:50:45 +00:00
* With 350 MHz < fout < 500 MHz , we limit the sdm2 from 4 to 9 ,
2017-08-16 08:31:11 +00:00
* Take average frequency close to the desired frequency , and select sdm2
2018-02-16 06:50:45 +00:00
* 2. Next , we look for sequences of less influential and more detailed parameters ,
2017-08-16 08:31:11 +00:00
* also by taking the average of the largest and smallest frequencies closer to the desired frequency .
* 3. And finally , loop through all the most detailed of the parameters , finding the best desired frequency
*
2018-02-16 06:50:45 +00:00
* @ param [ in ] rate The I2S Frequency ( MCLK )
2017-08-16 08:31:11 +00:00
* @ param [ in ] bits_per_sample The bits per sample
* @ param [ out ] sdm0 The sdm 0
* @ param [ out ] sdm1 The sdm 1
* @ param [ out ] sdm2 The sdm 2
* @ param [ out ] odir The odir
*
2018-04-11 11:37:31 +00:00
* @ return ESP_ERR_INVALID_ARG or ESP_OK
2017-08-16 08:31:11 +00:00
*/
2018-02-16 06:50:45 +00:00
static esp_err_t i2s_apll_calculate_fi2s ( int rate , int bits_per_sample , int * sdm0 , int * sdm1 , int * sdm2 , int * odir )
2017-08-16 08:31:11 +00:00
{
2018-02-16 06:50:45 +00:00
int _odir , _sdm0 , _sdm1 , _sdm2 ;
2017-08-16 08:31:11 +00:00
float avg ;
float min_rate , max_rate , min_diff ;
2018-02-16 06:50:45 +00:00
if ( rate / bits_per_sample / 2 / 8 < APLL_I2S_MIN_RATE ) {
2017-11-29 05:16:26 +00:00
return ESP_ERR_INVALID_ARG ;
2017-08-16 08:31:11 +00:00
}
2018-02-16 06:50:45 +00:00
2017-08-16 08:31:11 +00:00
* sdm0 = 0 ;
* sdm1 = 0 ;
* sdm2 = 0 ;
* odir = 0 ;
2018-02-16 06:50:45 +00:00
min_diff = APLL_MAX_FREQ ;
2017-08-16 08:31:11 +00:00
for ( _sdm2 = 4 ; _sdm2 < 9 ; _sdm2 + + ) {
2018-02-16 06:50:45 +00:00
max_rate = i2s_apll_get_fi2s ( bits_per_sample , 255 , 255 , _sdm2 , 0 ) ;
min_rate = i2s_apll_get_fi2s ( bits_per_sample , 0 , 0 , _sdm2 , 31 ) ;
2017-08-16 08:31:11 +00:00
avg = ( max_rate + min_rate ) / 2 ;
2019-06-18 05:52:36 +00:00
if ( abs ( avg - rate ) < min_diff ) {
2017-08-16 08:31:11 +00:00
min_diff = abs ( avg - rate ) ;
* sdm2 = _sdm2 ;
}
}
2018-02-16 06:50:45 +00:00
min_diff = APLL_MAX_FREQ ;
2017-08-16 08:31:11 +00:00
for ( _odir = 0 ; _odir < 32 ; _odir + + ) {
2018-02-16 06:50:45 +00:00
max_rate = i2s_apll_get_fi2s ( bits_per_sample , 255 , 255 , * sdm2 , _odir ) ;
min_rate = i2s_apll_get_fi2s ( bits_per_sample , 0 , 0 , * sdm2 , _odir ) ;
2017-08-16 08:31:11 +00:00
avg = ( max_rate + min_rate ) / 2 ;
2019-06-18 05:52:36 +00:00
if ( abs ( avg - rate ) < min_diff ) {
2017-08-16 08:31:11 +00:00
min_diff = abs ( avg - rate ) ;
* odir = _odir ;
}
}
2019-06-18 05:52:36 +00:00
min_diff = APLL_MAX_FREQ ;
for ( _sdm2 = 4 ; _sdm2 < 9 ; _sdm2 + + ) {
max_rate = i2s_apll_get_fi2s ( bits_per_sample , 255 , 255 , _sdm2 , * odir ) ;
min_rate = i2s_apll_get_fi2s ( bits_per_sample , 0 , 0 , _sdm2 , * odir ) ;
avg = ( max_rate + min_rate ) / 2 ;
if ( abs ( avg - rate ) < min_diff ) {
min_diff = abs ( avg - rate ) ;
* sdm2 = _sdm2 ;
}
}
2017-08-16 08:31:11 +00:00
2018-02-16 06:50:45 +00:00
min_diff = APLL_MAX_FREQ ;
2017-08-16 08:31:11 +00:00
for ( _sdm1 = 0 ; _sdm1 < 256 ; _sdm1 + + ) {
2018-02-16 06:50:45 +00:00
max_rate = i2s_apll_get_fi2s ( bits_per_sample , 255 , _sdm1 , * sdm2 , * odir ) ;
min_rate = i2s_apll_get_fi2s ( bits_per_sample , 0 , _sdm1 , * sdm2 , * odir ) ;
2017-08-16 08:31:11 +00:00
avg = ( max_rate + min_rate ) / 2 ;
if ( abs ( avg - rate ) < min_diff ) {
min_diff = abs ( avg - rate ) ;
* sdm1 = _sdm1 ;
}
}
2018-02-16 06:50:45 +00:00
min_diff = APLL_MAX_FREQ ;
2017-08-16 08:31:11 +00:00
for ( _sdm0 = 0 ; _sdm0 < 256 ; _sdm0 + + ) {
2018-02-16 06:50:45 +00:00
avg = i2s_apll_get_fi2s ( bits_per_sample , _sdm0 , * sdm1 , * sdm2 , * odir ) ;
2017-08-16 08:31:11 +00:00
if ( abs ( avg - rate ) < min_diff ) {
min_diff = abs ( avg - rate ) ;
* sdm0 = _sdm0 ;
}
}
2018-02-16 06:50:45 +00:00
2017-08-16 08:31:11 +00:00
return ESP_OK ;
}
2019-07-15 06:44:15 +00:00
2017-02-06 06:11:11 +00:00
esp_err_t i2s_set_clk ( i2s_port_t i2s_num , uint32_t rate , i2s_bits_per_sample_t bits , i2s_channel_t ch )
2016-12-29 09:29:14 +00:00
{
int factor = ( 256 % bits ) ? 384 : 256 ; // According to hardware codec requirement(supported 256fs or 384fs)
int clkmInteger , clkmDecimals , bck = 0 ;
2017-02-06 06:11:11 +00:00
double denom = ( double ) 1 / 64 ;
2016-12-29 09:29:14 +00:00
int channel = 2 ;
2017-02-06 06:11:11 +00:00
i2s_dma_t * save_tx = NULL , * save_rx = NULL ;
I2S_CHECK ( ( i2s_num < I2S_NUM_MAX ) , " i2s_num error " , ESP_ERR_INVALID_ARG ) ;
if ( bits % 8 ! = 0 | | bits > I2S_BITS_PER_SAMPLE_32BIT | | bits < I2S_BITS_PER_SAMPLE_16BIT ) {
ESP_LOGE ( I2S_TAG , " Invalid bits per sample " ) ;
return ESP_ERR_INVALID_ARG ;
}
if ( p_i2s_obj [ i2s_num ] = = NULL ) {
ESP_LOGE ( I2S_TAG , " Not initialized yet " ) ;
2018-04-11 11:37:31 +00:00
return ESP_ERR_INVALID_ARG ;
2017-02-06 06:11:11 +00:00
}
2017-12-08 12:07:19 +00:00
p_i2s_obj [ i2s_num ] - > sample_rate = rate ;
2017-02-06 06:11:11 +00:00
double clkmdiv = ( double ) I2S_BASE_CLK / ( rate * factor ) ;
2016-12-29 09:29:14 +00:00
if ( clkmdiv > 256 ) {
ESP_LOGE ( I2S_TAG , " clkmdiv is too large \r \n " ) ;
2017-11-29 05:16:26 +00:00
return ESP_ERR_INVALID_ARG ;
2016-12-29 09:29:14 +00:00
}
2017-02-06 06:11:11 +00:00
// wait all on-going writing finish
if ( ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_TX ) & & p_i2s_obj [ i2s_num ] - > tx ) {
xSemaphoreTake ( p_i2s_obj [ i2s_num ] - > tx - > mux , ( portTickType ) portMAX_DELAY ) ;
}
if ( ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_RX ) & & p_i2s_obj [ i2s_num ] - > rx ) {
xSemaphoreTake ( p_i2s_obj [ i2s_num ] - > rx - > mux , ( portTickType ) portMAX_DELAY ) ;
}
i2s_stop ( i2s_num ) ;
2019-07-15 06:44:15 +00:00
i2s_hal_set_tx_mode ( & ( p_i2s_obj [ i2s_num ] - > hal ) , ch , bits ) ;
i2s_hal_set_rx_mode ( & ( p_i2s_obj [ i2s_num ] - > hal ) , ch , bits ) ;
2017-05-23 11:32:10 +00:00
if ( p_i2s_obj [ i2s_num ] - > channel_num ! = ch ) {
p_i2s_obj [ i2s_num ] - > channel_num = ( ch = = 2 ) ? 2 : 1 ;
}
2017-02-06 06:11:11 +00:00
if ( bits ! = p_i2s_obj [ i2s_num ] - > bits_per_sample ) {
p_i2s_obj [ i2s_num ] - > bits_per_sample = bits ;
p_i2s_obj [ i2s_num ] - > bytes_per_sample = p_i2s_obj [ i2s_num ] - > bits_per_sample / 8 ;
// Round bytes_per_sample up to next multiple of 16 bits
int halfwords_per_sample = ( p_i2s_obj [ i2s_num ] - > bits_per_sample + 15 ) / 16 ;
p_i2s_obj [ i2s_num ] - > bytes_per_sample = halfwords_per_sample * 2 ;
// Because limited of DMA buffer is 4092 bytes
if ( p_i2s_obj [ i2s_num ] - > dma_buf_len * p_i2s_obj [ i2s_num ] - > bytes_per_sample * p_i2s_obj [ i2s_num ] - > channel_num > 4092 ) {
p_i2s_obj [ i2s_num ] - > dma_buf_len = 4092 / p_i2s_obj [ i2s_num ] - > bytes_per_sample / p_i2s_obj [ i2s_num ] - > channel_num ;
}
// Re-create TX DMA buffer
if ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_TX ) {
save_tx = p_i2s_obj [ i2s_num ] - > tx ;
p_i2s_obj [ i2s_num ] - > tx = i2s_create_dma_queue ( i2s_num , p_i2s_obj [ i2s_num ] - > dma_buf_count , p_i2s_obj [ i2s_num ] - > 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 ) ;
2017-11-29 05:16:26 +00:00
return ESP_ERR_NO_MEM ;
2017-02-06 06:11:11 +00:00
}
2019-07-15 06:44:15 +00:00
i2s_hal_set_out_link_addr ( & ( p_i2s_obj [ i2s_num ] - > hal ) , ( uint32_t ) p_i2s_obj [ i2s_num ] - > tx - > desc [ 0 ] ) ;
2017-02-06 06:11:11 +00:00
//destroy old tx dma if exist
if ( save_tx ) {
i2s_destroy_dma_queue ( i2s_num , save_tx ) ;
}
}
// Re-create RX DMA buffer
if ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_RX ) {
save_rx = p_i2s_obj [ i2s_num ] - > rx ;
2018-02-16 06:50:45 +00:00
2017-02-06 06:11:11 +00:00
p_i2s_obj [ i2s_num ] - > rx = i2s_create_dma_queue ( i2s_num , p_i2s_obj [ i2s_num ] - > dma_buf_count , p_i2s_obj [ i2s_num ] - > 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 ) ;
2017-11-29 05:16:26 +00:00
return ESP_ERR_NO_MEM ;
2017-02-06 06:11:11 +00:00
}
2019-07-15 06:44:15 +00:00
i2s_hal_set_in_link ( & ( p_i2s_obj [ i2s_num ] - > hal ) , p_i2s_obj [ i2s_num ] - > dma_buf_len * p_i2s_obj [ i2s_num ] - > channel_num * p_i2s_obj [ i2s_num ] - > bytes_per_sample , ( uint32_t ) p_i2s_obj [ i2s_num ] - > rx - > desc [ 0 ] ) ;
2017-02-06 06:11:11 +00:00
//destroy old rx dma if exist
if ( save_rx ) {
i2s_destroy_dma_queue ( i2s_num , save_rx ) ;
}
}
2018-02-16 06:50:45 +00:00
2017-02-06 06:11:11 +00:00
}
2017-05-03 10:55:52 +00:00
double mclk ;
2018-11-27 06:10:33 +00:00
int sdm0 , sdm1 , sdm2 , odir , m_scale = 8 ;
int fi2s_clk = rate * channel * bits * m_scale ;
2020-02-20 08:00:48 +00:00
# if SOC_I2S_SUPPORTS_ADC_DAC
2017-08-23 15:12:56 +00:00
if ( p_i2s_obj [ i2s_num ] - > mode & ( I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN ) ) {
2020-02-20 08:00:48 +00:00
2017-05-03 10:55:52 +00:00
//DAC uses bclk as sample clock, not WS. WS can be something arbitrary.
//Rate as given to this function is the intended sample rate;
//According to the TRM, WS clk equals to the sample rate, and bclk is double the speed of WS
2018-11-27 06:10:33 +00:00
uint32_t b_clk = rate * I2S_AD_BCK_FACTOR ;
2019-12-20 06:57:34 +00:00
fi2s_clk / = I2S_AD_BCK_FACTOR ;
2017-05-03 10:55:52 +00:00
int factor2 = 60 ;
mclk = b_clk * factor2 ;
clkmdiv = ( ( double ) I2S_BASE_CLK ) / mclk ;
clkmInteger = clkmdiv ;
clkmDecimals = ( clkmdiv - clkmInteger ) / denom ;
bck = mclk / b_clk ;
2020-02-20 08:00:48 +00:00
# endif
# if SOC_I2S_SUPPORTS_PDM
2017-05-03 10:55:52 +00:00
} else if ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_PDM ) {
uint32_t b_clk = 0 ;
if ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_TX ) {
2019-07-15 06:44:15 +00:00
int fp ;
int fs ;
i2s_hal_get_tx_pdm ( & ( p_i2s_obj [ i2s_num ] - > hal ) , & fp , & fs ) ;
2018-11-27 06:10:33 +00:00
b_clk = rate * I2S_PDM_BCK_FACTOR * ( fp / fs ) ;
fi2s_clk / = ( I2S_PDM_BCK_FACTOR * ( fp / fs ) ) ;
2017-05-03 10:55:52 +00:00
} else if ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_RX ) {
2019-07-15 06:44:15 +00:00
bool en ;
i2s_hal_get_rx_sinc_dsr_16_en ( & ( p_i2s_obj [ i2s_num ] - > hal ) , & en ) ;
b_clk = rate * I2S_PDM_BCK_FACTOR * ( en ? 2 : 1 ) ;
fi2s_clk / = ( I2S_PDM_BCK_FACTOR * ( en ? 2 : 1 ) ) ;
2017-05-03 10:55:52 +00:00
}
int factor2 = 5 ;
mclk = b_clk * factor2 ;
clkmdiv = ( ( double ) I2S_BASE_CLK ) / mclk ;
clkmInteger = clkmdiv ;
clkmDecimals = ( clkmdiv - clkmInteger ) / denom ;
bck = mclk / b_clk ;
2020-02-20 08:00:48 +00:00
} else
2019-06-06 09:00:03 +00:00
# endif
2020-02-20 08:00:48 +00:00
{
2017-05-03 10:55:52 +00:00
clkmInteger = clkmdiv ;
clkmDecimals = ( clkmdiv - clkmInteger ) / denom ;
mclk = clkmInteger + denom * clkmDecimals ;
bck = factor / ( bits * channel ) ;
}
2018-11-27 06:10:33 +00:00
2018-02-16 06:50:45 +00:00
if ( p_i2s_obj [ i2s_num ] - > use_apll & & p_i2s_obj [ i2s_num ] - > fixed_mclk ) {
fi2s_clk = p_i2s_obj [ i2s_num ] - > fixed_mclk ;
m_scale = fi2s_clk / bits / rate / channel ;
}
if ( p_i2s_obj [ i2s_num ] - > use_apll & & i2s_apll_calculate_fi2s ( fi2s_clk , bits , & sdm0 , & sdm1 , & sdm2 , & odir ) = = ESP_OK ) {
ESP_LOGD ( I2S_TAG , " sdm0=%d, sdm1=%d, sdm2=%d, odir=%d " , sdm0 , sdm1 , sdm2 , odir ) ;
2017-08-16 08:31:11 +00:00
rtc_clk_apll_enable ( 1 , sdm0 , sdm1 , sdm2 , odir ) ;
2019-07-15 06:44:15 +00:00
i2s_hal_set_clk_div ( & ( p_i2s_obj [ i2s_num ] - > hal ) , 1 , 1 , 0 , m_scale , m_scale ) ;
i2s_hal_set_clock_sel ( & ( p_i2s_obj [ i2s_num ] - > hal ) , I2S_CLK_APLL ) ;
2018-02-16 06:50:45 +00:00
double fi2s_rate = i2s_apll_get_fi2s ( bits , sdm0 , sdm1 , sdm2 , odir ) ;
2019-06-19 10:36:20 +00:00
p_i2s_obj [ i2s_num ] - > real_rate = fi2s_rate / bits / channel / m_scale ;
2018-02-16 06:50:45 +00:00
ESP_LOGI ( I2S_TAG , " APLL: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK_M: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d " ,
rate , fi2s_rate / bits / channel / m_scale , bits , 1 , m_scale , fi2s_rate , fi2s_rate / 8 , 1 , 0 ) ;
2017-08-16 08:31:11 +00:00
} else {
2019-07-15 06:44:15 +00:00
i2s_hal_set_clock_sel ( & ( p_i2s_obj [ i2s_num ] - > hal ) , I2S_CLK_D2CLK ) ;
i2s_hal_set_clk_div ( & ( p_i2s_obj [ i2s_num ] - > hal ) , clkmInteger , 63 , clkmDecimals , bck , bck ) ;
2017-08-16 08:31:11 +00:00
double real_rate = ( double ) ( I2S_BASE_CLK / ( bck * bits * clkmInteger ) / 2 ) ;
2019-06-19 10:36:20 +00:00
p_i2s_obj [ i2s_num ] - > real_rate = real_rate ;
2017-08-16 08:31:11 +00:00
ESP_LOGI ( I2S_TAG , " PLL_D2: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d " ,
rate , real_rate , bits , clkmInteger , bck , ( double ) I2S_BASE_CLK / mclk , real_rate * bits * channel , 64 , clkmDecimals ) ;
}
2018-02-16 06:50:45 +00:00
2019-07-15 06:44:15 +00:00
i2s_hal_set_tx_bits_mod ( & ( p_i2s_obj [ i2s_num ] - > hal ) , bits ) ;
i2s_hal_set_rx_bits_mod ( & ( p_i2s_obj [ i2s_num ] - > hal ) , bits ) ;
2018-02-16 06:50:45 +00:00
2017-02-06 06:11:11 +00:00
// wait all writing on-going finish
if ( ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_TX ) & & p_i2s_obj [ i2s_num ] - > tx ) {
xSemaphoreGive ( p_i2s_obj [ i2s_num ] - > tx - > mux ) ;
}
if ( ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_RX ) & & p_i2s_obj [ i2s_num ] - > rx ) {
xSemaphoreGive ( p_i2s_obj [ i2s_num ] - > rx - > mux ) ;
}
i2s_start ( i2s_num ) ;
2016-12-29 09:29:14 +00:00
return ESP_OK ;
}
static void IRAM_ATTR i2s_intr_handler_default ( void * arg )
{
i2s_obj_t * p_i2s = ( i2s_obj_t * ) arg ;
2019-07-15 06:44:15 +00:00
uint32_t status ;
i2s_hal_get_intr_status ( & ( p_i2s - > hal ) , & status ) ;
if ( status = = 0 ) {
2019-06-06 09:00:03 +00:00
//Avoid spurious interrupt
return ;
}
2019-07-15 06:44:15 +00:00
2016-12-29 09:29:14 +00:00
i2s_event_t i2s_event ;
int dummy ;
portBASE_TYPE high_priority_task_awoken = 0 ;
lldesc_t * finish_desc ;
2019-07-15 06:44:15 +00:00
if ( ( status & I2S_INTR_OUT_DSCR_ERR ) | | ( status & I2S_INTR_IN_DSCR_ERR ) ) {
ESP_EARLY_LOGE ( I2S_TAG , " dma error, interrupt status: 0x%08x " , status ) ;
2016-12-29 09:29:14 +00:00
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 ) ;
}
}
2019-07-15 06:44:15 +00:00
if ( ( status & I2S_INTR_OUT_EOF ) & & p_i2s - > tx ) {
i2s_hal_get_out_eof_des_addr ( & ( p_i2s - > hal ) , ( uint32_t * ) & finish_desc ) ;
2016-12-29 09:29:14 +00:00
// 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 ) ;
2018-05-14 09:03:45 +00:00
// See if tx descriptor needs to be auto cleared:
// This will avoid any kind of noise that may get introduced due to transmission
// of previous data from tx descriptor on I2S line.
if ( p_i2s - > tx_desc_auto_clear = = true ) {
memset ( ( void * ) dummy , 0 , p_i2s - > tx - > buf_size ) ;
}
2016-12-29 09:29:14 +00:00
}
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 ) ;
}
}
2019-07-15 06:44:15 +00:00
if ( ( status & I2S_INTR_IN_SUC_EOF ) & & p_i2s - > rx ) {
2016-12-29 09:29:14 +00:00
// All buffers are full. This means we have an overflow.
2019-07-15 06:44:15 +00:00
i2s_hal_get_in_eof_des_addr ( & ( p_i2s - > hal ) , ( uint32_t * ) & finish_desc ) ;
2016-12-29 09:29:14 +00:00
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 ) ;
}
}
2019-07-15 06:44:15 +00:00
i2s_hal_clear_intr_status ( & ( p_i2s - > hal ) , status ) ;
2019-06-06 09:00:03 +00:00
2016-12-29 09:29:14 +00:00
if ( high_priority_task_awoken = = pdTRUE ) {
portYIELD_FROM_ISR ( ) ;
}
}
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 " ) ;
2018-04-11 11:37:31 +00:00
return ESP_ERR_INVALID_ARG ;
2016-12-29 09:29:14 +00:00
}
if ( dma = = NULL ) {
2018-04-11 11:37:31 +00:00
ESP_LOGE ( I2S_TAG , " dma is NULL " ) ;
return ESP_ERR_INVALID_ARG ;
2016-12-29 09:29:14 +00:00
}
for ( bux_idx = 0 ; bux_idx < p_i2s_obj [ i2s_num ] - > dma_buf_count ; bux_idx + + ) {
2018-04-11 11:37:31 +00:00
if ( dma - > desc & & dma - > desc [ bux_idx ] ) {
2016-12-29 09:29:14 +00:00
free ( dma - > desc [ bux_idx ] ) ;
2018-04-11 11:37:31 +00:00
}
if ( dma - > buf & & dma - > buf [ bux_idx ] ) {
2016-12-29 09:29:14 +00:00
free ( dma - > buf [ bux_idx ] ) ;
2018-04-11 11:37:31 +00:00
}
2016-12-29 09:29:14 +00:00
}
2018-04-11 11:37:31 +00:00
if ( dma - > buf ) {
2016-12-29 09:29:14 +00:00
free ( dma - > buf ) ;
2018-04-11 11:37:31 +00:00
}
if ( dma - > desc ) {
2016-12-29 09:29:14 +00:00
free ( dma - > desc ) ;
2018-04-11 11:37:31 +00:00
}
2016-12-29 09:29:14 +00:00
vQueueDelete ( dma - > queue ) ;
vSemaphoreDelete ( dma - > mux ) ;
2017-02-06 06:11:11 +00:00
free ( dma ) ;
2016-12-29 09:29:14 +00:00
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 " ) ;
2017-07-25 12:14:03 +00:00
free ( dma ) ;
2016-12-29 09:29:14 +00:00
return NULL ;
}
memset ( dma - > buf , 0 , sizeof ( char * ) * dma_buf_count ) ;
for ( bux_idx = 0 ; bux_idx < dma_buf_count ; bux_idx + + ) {
2018-05-10 12:30:11 +00:00
dma - > buf [ bux_idx ] = ( char * ) heap_caps_calloc ( 1 , dma_buf_len * sample_size , MALLOC_CAP_DMA ) ;
2016-12-29 09:29:14 +00:00
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 ] ) ;
}
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 + + ) {
2018-05-10 12:30:11 +00:00
dma - > desc [ bux_idx ] = ( lldesc_t * ) heap_caps_malloc ( sizeof ( lldesc_t ) , MALLOC_CAP_DMA ) ;
2016-12-29 09:29:14 +00:00
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 )
{
2017-11-29 05:16:26 +00:00
I2S_CHECK ( ( i2s_num < I2S_NUM_MAX ) , " i2s_num error " , ESP_ERR_INVALID_ARG ) ;
2016-12-29 09:29:14 +00:00
//start DMA link
I2S_ENTER_CRITICAL ( ) ;
2017-12-08 12:07:19 +00:00
i2s_reset_fifo ( i2s_num ) ;
2019-07-15 06:44:15 +00:00
i2s_hal_reset ( & ( p_i2s_obj [ i2s_num ] - > hal ) ) ;
2017-12-08 12:07:19 +00:00
2016-12-29 09:29:14 +00:00
esp_intr_disable ( p_i2s_obj [ i2s_num ] - > i2s_isr_handle ) ;
2019-07-15 06:44:15 +00:00
i2s_hal_clear_intr_status ( & ( p_i2s_obj [ i2s_num ] - > hal ) , I2S_INTR_MAX ) ;
2016-12-29 09:29:14 +00:00
if ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_TX ) {
i2s_enable_tx_intr ( i2s_num ) ;
2019-07-15 06:44:15 +00:00
i2s_hal_start_tx ( & ( p_i2s_obj [ i2s_num ] - > hal ) ) ;
2016-12-29 09:29:14 +00:00
}
if ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_RX ) {
i2s_enable_rx_intr ( i2s_num ) ;
2019-07-15 06:44:15 +00:00
i2s_hal_start_rx ( & ( p_i2s_obj [ i2s_num ] - > hal ) ) ;
2016-12-29 09:29:14 +00:00
}
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 )
{
2017-11-29 05:16:26 +00:00
I2S_CHECK ( ( i2s_num < I2S_NUM_MAX ) , " i2s_num error " , ESP_ERR_INVALID_ARG ) ;
2016-12-29 09:29:14 +00:00
I2S_ENTER_CRITICAL ( ) ;
esp_intr_disable ( p_i2s_obj [ i2s_num ] - > i2s_isr_handle ) ;
if ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_TX ) {
2019-07-15 06:44:15 +00:00
i2s_hal_stop_tx ( & ( p_i2s_obj [ i2s_num ] - > hal ) ) ;
2016-12-29 09:29:14 +00:00
i2s_disable_tx_intr ( i2s_num ) ;
}
if ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_RX ) {
2019-07-15 06:44:15 +00:00
i2s_hal_stop_rx ( & ( p_i2s_obj [ i2s_num ] - > hal ) ) ;
2016-12-29 09:29:14 +00:00
i2s_disable_rx_intr ( i2s_num ) ;
}
2019-07-15 06:44:15 +00:00
uint32_t mask ;
i2s_hal_get_intr_status ( & ( p_i2s_obj [ i2s_num ] - > hal ) , & mask ) ;
i2s_hal_clear_intr_status ( & ( p_i2s_obj [ i2s_num ] - > hal ) , mask ) ;
2016-12-29 09:29:14 +00:00
I2S_EXIT_CRITICAL ( ) ;
2017-11-29 05:16:26 +00:00
return ESP_OK ;
2016-12-29 09:29:14 +00:00
}
2020-02-20 08:00:48 +00:00
# if SOC_I2S_SUPPORTS_ADC_DAC
2017-05-03 10:55:52 +00:00
esp_err_t i2s_set_dac_mode ( i2s_dac_mode_t dac_mode )
2016-12-29 09:29:14 +00:00
{
2017-05-03 10:55:52 +00:00
I2S_CHECK ( ( dac_mode < I2S_DAC_CHANNEL_MAX ) , " i2s dac mode error " , ESP_ERR_INVALID_ARG ) ;
2017-08-16 08:31:11 +00:00
if ( dac_mode = = I2S_DAC_CHANNEL_DISABLE ) {
2017-05-03 10:55:52 +00:00
dac_output_disable ( DAC_CHANNEL_1 ) ;
2017-08-29 07:31:39 +00:00
dac_output_disable ( DAC_CHANNEL_2 ) ;
2017-05-03 10:55:52 +00:00
dac_i2s_disable ( ) ;
} else {
dac_i2s_enable ( ) ;
}
2016-12-29 09:29:14 +00:00
2017-05-03 10:55:52 +00:00
if ( dac_mode & I2S_DAC_CHANNEL_RIGHT_EN ) {
2019-12-09 07:20:41 +00:00
//DAC1, right channel
2017-05-03 10:55:52 +00:00
dac_output_enable ( DAC_CHANNEL_1 ) ;
}
if ( dac_mode & I2S_DAC_CHANNEL_LEFT_EN ) {
2019-12-09 07:20:41 +00:00
//DAC2, left channel
2017-05-03 10:55:52 +00:00
dac_output_enable ( DAC_CHANNEL_2 ) ;
}
2016-12-29 09:29:14 +00:00
return ESP_OK ;
}
2019-07-16 09:33:30 +00:00
static esp_err_t _i2s_adc_mode_recover ( void )
2017-12-08 12:07:19 +00:00
{
I2S_CHECK ( ( ( _i2s_adc_unit ! = - 1 ) & & ( _i2s_adc_channel ! = - 1 ) ) , " i2s ADC recover error, not initialized... " , ESP_ERR_INVALID_ARG ) ;
return adc_i2s_mode_init ( _i2s_adc_unit , _i2s_adc_channel ) ;
}
2017-08-23 15:12:56 +00:00
esp_err_t i2s_set_adc_mode ( adc_unit_t adc_unit , adc1_channel_t adc_channel )
{
I2S_CHECK ( ( adc_unit < ADC_UNIT_2 ) , " i2s ADC unit error, only support ADC1 for now " , ESP_ERR_INVALID_ARG ) ;
// For now, we only support SAR ADC1.
2017-12-08 12:07:19 +00:00
_i2s_adc_unit = adc_unit ;
_i2s_adc_channel = adc_channel ;
2017-08-23 15:12:56 +00:00
return adc_i2s_mode_init ( adc_unit , adc_channel ) ;
}
2020-02-20 08:00:48 +00:00
# endif
2017-08-23 15:12:56 +00:00
2016-12-29 09:29:14 +00:00
esp_err_t i2s_set_pin ( i2s_port_t i2s_num , const i2s_pin_config_t * pin )
{
2017-02-06 06:11:11 +00:00
I2S_CHECK ( ( i2s_num < I2S_NUM_MAX ) , " i2s_num error " , ESP_ERR_INVALID_ARG ) ;
2016-12-29 09:29:14 +00:00
if ( pin = = NULL ) {
2020-02-20 08:00:48 +00:00
# if SOC_I2S_SUPPORTS_ADC_DAC
2017-05-03 10:55:52 +00:00
return i2s_set_dac_mode ( I2S_DAC_CHANNEL_BOTH_EN ) ;
2020-02-20 08:00:48 +00:00
# else
return ESP_ERR_INVALID_ARG ;
# endif
2016-12-29 09:29:14 +00:00
}
2020-02-20 08:00:48 +00:00
2016-12-29 09:29:14 +00:00
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 ;
}
2017-05-17 05:12:46 +00:00
if ( pin - > data_out_num ! = - 1 & & ! GPIO_IS_VALID_OUTPUT_GPIO ( pin - > data_out_num ) ) {
2016-12-29 09:29:14 +00:00
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 ;
2017-05-03 10:55:52 +00:00
//Each IIS hw module has a RX and TX unit.
//For TX unit, the output signal index should be I2SnO_xxx_OUT_IDX
//For TX unit, the input signal index should be I2SnO_xxx_IN_IDX
2016-12-29 09:29:14 +00:00
if ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_TX ) {
2017-02-06 06:11:11 +00:00
if ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_MASTER ) {
2019-06-06 09:00:03 +00:00
bck_sig = i2s_periph_signal [ i2s_num ] . o_bck_out_sig ;
ws_sig = i2s_periph_signal [ i2s_num ] . o_ws_out_sig ;
data_out_sig = i2s_periph_signal [ i2s_num ] . o_data_out_sig ;
2017-02-06 06:11:11 +00:00
} else if ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_SLAVE ) {
2019-06-06 09:00:03 +00:00
bck_sig = i2s_periph_signal [ i2s_num ] . o_bck_in_sig ;
ws_sig = i2s_periph_signal [ i2s_num ] . o_ws_in_sig ;
data_out_sig = i2s_periph_signal [ i2s_num ] . o_data_out_sig ;
2016-12-29 09:29:14 +00:00
}
}
2017-05-03 10:55:52 +00:00
//For RX unit, the output signal index should be I2SnI_xxx_OUT_IDX
//For RX unit, the input signal index shuld be I2SnI_xxx_IN_IDX
2017-02-06 06:11:11 +00:00
if ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_RX ) {
2017-05-03 10:55:52 +00:00
if ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_MASTER ) {
2019-06-06 09:00:03 +00:00
bck_sig = i2s_periph_signal [ i2s_num ] . i_bck_out_sig ;
ws_sig = i2s_periph_signal [ i2s_num ] . i_ws_out_sig ;
data_in_sig = i2s_periph_signal [ i2s_num ] . i_data_in_sig ;
2017-05-03 10:55:52 +00:00
} else if ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_SLAVE ) {
2019-06-06 09:00:03 +00:00
bck_sig = i2s_periph_signal [ i2s_num ] . i_bck_in_sig ;
ws_sig = i2s_periph_signal [ i2s_num ] . i_ws_in_sig ;
data_in_sig = i2s_periph_signal [ i2s_num ] . i_data_in_sig ;
2017-02-06 06:11:11 +00:00
}
2017-05-03 10:55:52 +00:00
}
//For "full-duplex + slave" mode, we should select RX signal index for ws and bck.
//For "full-duplex + master" mode, we should select TX signal index for ws and bck.
if ( ( p_i2s_obj [ i2s_num ] - > mode & I2S_FULL_DUPLEX_SLAVE_MODE_MASK ) = = I2S_FULL_DUPLEX_SLAVE_MODE_MASK ) {
2019-06-06 09:00:03 +00:00
bck_sig = i2s_periph_signal [ i2s_num ] . i_bck_in_sig ;
ws_sig = i2s_periph_signal [ i2s_num ] . i_ws_in_sig ;
2017-05-03 10:55:52 +00:00
} else if ( ( p_i2s_obj [ i2s_num ] - > mode & I2S_FULL_DUPLEX_MASTER_MODE_MASK ) = = I2S_FULL_DUPLEX_MASTER_MODE_MASK ) {
2019-06-06 09:00:03 +00:00
bck_sig = i2s_periph_signal [ i2s_num ] . o_bck_out_sig ;
ws_sig = i2s_periph_signal [ i2s_num ] . o_ws_out_sig ;
2017-05-03 10:55:52 +00:00
}
2016-12-29 09:29:14 +00:00
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 ) ;
}
2017-02-06 06:11:11 +00:00
ESP_LOGD ( I2S_TAG , " data: out %d, in: %d, ws: %d, bck: %d " , data_out_sig , data_in_sig , ws_sig , bck_sig ) ;
2016-12-29 09:29:14 +00:00
return ESP_OK ;
}
esp_err_t i2s_set_sample_rates ( i2s_port_t i2s_num , uint32_t rate )
{
2017-02-06 06:11:11 +00:00
I2S_CHECK ( ( i2s_num < I2S_NUM_MAX ) , " i2s_num error " , ESP_ERR_INVALID_ARG ) ;
I2S_CHECK ( ( p_i2s_obj [ i2s_num ] - > bytes_per_sample > 0 ) , " bits_per_sample not set " , ESP_ERR_INVALID_ARG ) ;
return i2s_set_clk ( i2s_num , rate , p_i2s_obj [ i2s_num ] - > bits_per_sample , p_i2s_obj [ i2s_num ] - > channel_num ) ;
2016-12-29 09:29:14 +00:00
}
2017-08-23 15:12:56 +00:00
2020-02-20 08:00:48 +00:00
# if SOC_I2S_SUPPORTS_PDM
2018-11-27 06:10:33 +00:00
esp_err_t i2s_set_pdm_rx_down_sample ( i2s_port_t i2s_num , i2s_pdm_dsr_t dsr )
{
I2S_CHECK ( ( i2s_num < I2S_NUM_MAX ) , " i2s_num error " , ESP_ERR_INVALID_ARG ) ;
2019-07-15 06:44:15 +00:00
i2s_hal_set_pdm_rx_down_sample ( & ( p_i2s_obj [ i2s_num ] - > hal ) , dsr ) ;
2018-11-27 06:10:33 +00:00
return i2s_set_clk ( i2s_num , p_i2s_obj [ i2s_num ] - > sample_rate , p_i2s_obj [ i2s_num ] - > bits_per_sample , p_i2s_obj [ i2s_num ] - > channel_num ) ;
}
2019-06-06 09:00:03 +00:00
# endif
2018-11-27 06:10:33 +00:00
2016-12-29 09:29:14 +00:00
static esp_err_t i2s_param_config ( i2s_port_t i2s_num , const i2s_config_t * i2s_config )
{
2017-02-06 06:11:11 +00:00
I2S_CHECK ( ( i2s_num < I2S_NUM_MAX ) , " i2s_num error " , ESP_ERR_INVALID_ARG ) ;
I2S_CHECK ( ( i2s_config ) , " param null " , ESP_ERR_INVALID_ARG ) ;
2020-02-20 08:00:48 +00:00
# if SOC_I2S_SUPPORTS_ADC_DAC
2017-08-23 15:12:56 +00:00
I2S_CHECK ( ! ( ( i2s_config - > mode & I2S_MODE_ADC_BUILT_IN ) & & ( i2s_num ! = I2S_NUM_0 ) ) , " I2S ADC built-in only support on I2S0 " , ESP_ERR_INVALID_ARG ) ;
I2S_CHECK ( ! ( ( i2s_config - > mode & I2S_MODE_DAC_BUILT_IN ) & & ( i2s_num ! = I2S_NUM_0 ) ) , " I2S DAC built-in only support on I2S0 " , ESP_ERR_INVALID_ARG ) ;
2020-02-20 08:00:48 +00:00
# endif
2019-12-09 07:20:41 +00:00
I2S_CHECK ( ( ( i2s_config - > communication_format & I2S_COMM_FORMAT_I2S ) | | ( i2s_config - > communication_format & I2S_COMM_FORMAT_PCM ) ) , " I2S communication format invalid. " , ESP_ERR_INVALID_ARG ) ;
2020-02-20 08:00:48 +00:00
# if SOC_I2S_SUPPORTS_PDM
2017-08-23 15:12:56 +00:00
I2S_CHECK ( ! ( ( i2s_config - > mode & I2S_MODE_PDM ) & & ( i2s_num ! = I2S_NUM_0 ) ) , " I2S DAC PDM only support on I2S0 " , ESP_ERR_INVALID_ARG ) ;
2019-06-06 09:00:03 +00:00
# endif
periph_module_enable ( i2s_periph_signal [ i2s_num ] . module ) ;
2017-05-03 10:55:52 +00:00
2020-02-20 08:00:48 +00:00
# if SOC_I2S_SUPPORTS_ADC_DAC
2017-08-23 15:12:56 +00:00
if ( i2s_config - > mode & I2S_MODE_ADC_BUILT_IN ) {
//in ADC built-in mode, we need to call i2s_set_adc_mode to
//initialize the specific ADC channel.
//in the current stage, we only support ADC1 and single channel mode.
//In default data mode, the ADC data is in 12-bit resolution mode.
2017-12-08 12:07:19 +00:00
adc_power_always_on ( ) ;
2017-08-23 15:12:56 +00:00
}
2020-02-20 08:00:48 +00:00
# endif
2016-12-29 09:29:14 +00:00
// configure I2S data port interface.
i2s_reset_fifo ( i2s_num ) ;
2019-07-15 06:44:15 +00:00
i2s_hal_config_param ( & ( p_i2s_obj [ i2s_num ] - > hal ) , i2s_config ) ;
2016-12-29 09:29:14 +00:00
if ( ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_RX ) & & ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_TX ) ) {
2019-07-15 06:44:15 +00:00
i2s_hal_enable_sig_loopback ( & ( p_i2s_obj [ i2s_num ] - > hal ) ) ;
2017-02-06 06:11:11 +00:00
if ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_MASTER ) {
2019-07-15 06:44:15 +00:00
i2s_hal_enable_master_mode ( & ( p_i2s_obj [ i2s_num ] - > hal ) ) ;
2017-02-06 06:11:11 +00:00
} else {
2019-07-15 06:44:15 +00:00
i2s_hal_enable_slave_mode ( & ( p_i2s_obj [ i2s_num ] - > hal ) ) ;
2017-02-06 06:11:11 +00:00
}
2016-12-29 09:29:14 +00:00
}
2017-08-16 08:31:11 +00:00
p_i2s_obj [ i2s_num ] - > use_apll = i2s_config - > use_apll ;
2018-05-14 09:03:45 +00:00
p_i2s_obj [ i2s_num ] - > tx_desc_auto_clear = i2s_config - > tx_desc_auto_clear ;
2018-02-16 06:50:45 +00:00
p_i2s_obj [ i2s_num ] - > fixed_mclk = i2s_config - > fixed_mclk ;
2016-12-29 09:29:14 +00:00
return ESP_OK ;
}
esp_err_t i2s_zero_dma_buffer ( i2s_port_t i2s_num )
{
2017-02-06 06:11:11 +00:00
I2S_CHECK ( ( i2s_num < I2S_NUM_MAX ) , " i2s_num error " , ESP_ERR_INVALID_ARG ) ;
if ( p_i2s_obj [ i2s_num ] - > rx & & p_i2s_obj [ i2s_num ] - > rx - > buf ! = NULL & & p_i2s_obj [ i2s_num ] - > rx - > buf_size ! = 0 ) {
for ( int i = 0 ; i < p_i2s_obj [ i2s_num ] - > dma_buf_count ; i + + ) {
memset ( p_i2s_obj [ i2s_num ] - > rx - > buf [ i ] , 0 , p_i2s_obj [ i2s_num ] - > rx - > buf_size ) ;
}
}
if ( p_i2s_obj [ i2s_num ] - > tx & & p_i2s_obj [ i2s_num ] - > tx - > buf ! = NULL & & p_i2s_obj [ i2s_num ] - > tx - > buf_size ! = 0 ) {
2018-04-11 11:37:31 +00:00
int bytes_left = 0 ;
bytes_left = ( p_i2s_obj [ i2s_num ] - > tx - > buf_size - p_i2s_obj [ i2s_num ] - > tx - > rw_pos ) % 4 ;
2017-11-29 05:16:26 +00:00
if ( bytes_left ) {
2018-04-11 11:37:31 +00:00
size_t zero_bytes = 0 , bytes_written ;
i2s_write ( i2s_num , ( void * ) & zero_bytes , bytes_left , & bytes_written , portMAX_DELAY ) ;
2017-11-29 05:16:26 +00:00
}
2017-02-06 06:11:11 +00:00
for ( int i = 0 ; i < p_i2s_obj [ i2s_num ] - > dma_buf_count ; i + + ) {
memset ( p_i2s_obj [ i2s_num ] - > tx - > buf [ i ] , 0 , p_i2s_obj [ i2s_num ] - > tx - > buf_size ) ;
}
2016-12-29 09:29:14 +00:00
}
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 )
{
2017-02-06 06:11:11 +00:00
esp_err_t err ;
I2S_CHECK ( ( i2s_num < I2S_NUM_MAX ) , " i2s_num error " , ESP_ERR_INVALID_ARG ) ;
I2S_CHECK ( ( i2s_config ! = NULL ) , " I2S configuration must not NULL " , ESP_ERR_INVALID_ARG ) ;
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_ERR_INVALID_ARG ) ;
I2S_CHECK ( ( i2s_config - > dma_buf_len > = 8 & & i2s_config - > dma_buf_len < = 1024 ) , " I2S buffer length at most 1024 and more than 8 " , ESP_ERR_INVALID_ARG ) ;
2016-12-29 09:29:14 +00:00
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 " ) ;
2017-11-29 05:16:26 +00:00
return ESP_ERR_NO_MEM ;
2016-12-29 09:29:14 +00:00
}
2017-02-06 06:11:11 +00:00
memset ( p_i2s_obj [ i2s_num ] , 0 , sizeof ( i2s_obj_t ) ) ;
2016-12-29 09:29:14 +00:00
2019-07-15 06:44:15 +00:00
portMUX_TYPE i2s_spinlock_unlocked [ 1 ] = { portMUX_INITIALIZER_UNLOCKED } ;
for ( int x = 0 ; x < I2S_NUM_MAX ; x + + ) {
i2s_spinlock [ x ] = i2s_spinlock_unlocked [ 0 ] ;
}
//To make sure hardware is enabled before any hardware register operations.
periph_module_enable ( i2s_periph_signal [ i2s_num ] . module ) ;
i2s_hal_init ( & ( p_i2s_obj [ i2s_num ] - > hal ) , i2s_num ) ;
2016-12-29 09:29:14 +00:00
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 ;
2017-02-06 06:11:11 +00:00
p_i2s_obj [ i2s_num ] - > bits_per_sample = 0 ;
p_i2s_obj [ i2s_num ] - > bytes_per_sample = 0 ; // Not initialized yet
p_i2s_obj [ i2s_num ] - > channel_num = i2s_config - > channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 2 : 1 ;
2019-02-22 12:17:42 +00:00
# ifdef CONFIG_PM_ENABLE
2019-02-22 14:18:59 +00:00
if ( i2s_config - > use_apll ) {
err = esp_pm_lock_create ( ESP_PM_NO_LIGHT_SLEEP , 0 , " i2s_driver " , & p_i2s_obj [ i2s_num ] - > pm_lock ) ;
} else {
err = esp_pm_lock_create ( ESP_PM_APB_FREQ_MAX , 0 , " i2s_driver " , & p_i2s_obj [ i2s_num ] - > pm_lock ) ;
}
2019-02-22 12:17:42 +00:00
if ( err ! = ESP_OK ) {
2019-02-22 14:18:59 +00:00
free ( p_i2s_obj [ i2s_num ] ) ;
p_i2s_obj [ i2s_num ] = NULL ;
ESP_LOGE ( I2S_TAG , " I2S pm lock error " ) ;
2019-02-22 12:17:42 +00:00
return err ;
}
# endif //CONFIG_PM_ENABLE
2019-02-22 14:18:59 +00:00
2017-02-06 06:11:11 +00:00
//initial interrupt
err = i2s_isr_register ( i2s_num , i2s_config - > intr_alloc_flags , i2s_intr_handler_default , p_i2s_obj [ i2s_num ] , & p_i2s_obj [ i2s_num ] - > i2s_isr_handle ) ;
if ( err ! = ESP_OK ) {
2019-02-22 12:17:42 +00:00
# ifdef CONFIG_PM_ENABLE
if ( p_i2s_obj [ i2s_num ] - > pm_lock ) {
esp_pm_lock_delete ( p_i2s_obj [ i2s_num ] - > pm_lock ) ;
}
# endif
2016-12-29 09:29:14 +00:00
free ( p_i2s_obj [ i2s_num ] ) ;
2017-06-07 07:32:32 +00:00
p_i2s_obj [ i2s_num ] = NULL ;
2016-12-29 09:29:14 +00:00
ESP_LOGE ( I2S_TAG , " Register I2S Interrupt error " ) ;
2017-06-07 07:32:32 +00:00
return err ;
2016-12-29 09:29:14 +00:00
}
i2s_stop ( i2s_num ) ;
2017-08-23 15:12:56 +00:00
err = i2s_param_config ( i2s_num , i2s_config ) ;
if ( err ! = ESP_OK ) {
i2s_driver_uninstall ( i2s_num ) ;
ESP_LOGE ( I2S_TAG , " I2S param configure error " ) ;
return err ;
}
2016-12-29 09:29:14 +00:00
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 ;
}
2017-02-06 06:11:11 +00:00
//set clock and start
return i2s_set_clk ( i2s_num , i2s_config - > sample_rate , i2s_config - > bits_per_sample , p_i2s_obj [ i2s_num ] - > channel_num ) ;
2016-12-29 09:29:14 +00:00
}
2017-11-29 05:16:26 +00:00
ESP_LOGW ( I2S_TAG , " I2S driver already installed " ) ;
return ESP_OK ;
2016-12-29 09:29:14 +00:00
}
esp_err_t i2s_driver_uninstall ( i2s_port_t i2s_num )
{
2017-02-06 06:11:11 +00:00
I2S_CHECK ( ( i2s_num < I2S_NUM_MAX ) , " i2s_num error " , ESP_ERR_INVALID_ARG ) ;
2016-12-29 09:29:14 +00:00
if ( p_i2s_obj [ i2s_num ] = = NULL ) {
2017-11-29 05:16:26 +00:00
ESP_LOGI ( I2S_TAG , " already uninstalled " ) ;
2016-12-29 09:29:14 +00:00
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 ;
}
2017-08-16 08:31:11 +00:00
if ( p_i2s_obj [ i2s_num ] - > use_apll ) {
rtc_clk_apll_enable ( 0 , 0 , 0 , 0 , 0 ) ;
}
2019-02-22 12:17:42 +00:00
# ifdef CONFIG_PM_ENABLE
if ( p_i2s_obj [ i2s_num ] - > pm_lock ) {
2019-02-22 14:18:59 +00:00
esp_pm_lock_delete ( p_i2s_obj [ i2s_num ] - > pm_lock ) ;
2019-02-22 12:17:42 +00:00
}
# endif
2017-08-16 08:31:11 +00:00
2016-12-29 09:29:14 +00:00
free ( p_i2s_obj [ i2s_num ] ) ;
p_i2s_obj [ i2s_num ] = NULL ;
2019-06-06 09:00:03 +00:00
periph_module_disable ( i2s_periph_signal [ i2s_num ] . module ) ;
2016-12-29 09:29:14 +00:00
return ESP_OK ;
}
2018-04-11 11:37:31 +00:00
esp_err_t i2s_write ( i2s_port_t i2s_num , const void * src , size_t size , size_t * bytes_written , TickType_t ticks_to_wait )
{
char * data_ptr , * src_byte ;
int bytes_can_write ;
* bytes_written = 0 ;
I2S_CHECK ( ( i2s_num < I2S_NUM_MAX ) , " i2s_num error " , ESP_ERR_INVALID_ARG ) ;
I2S_CHECK ( ( size < I2S_MAX_BUFFER_SIZE ) , " size is too large " , ESP_ERR_INVALID_ARG ) ;
I2S_CHECK ( ( p_i2s_obj [ i2s_num ] - > tx ) , " tx NULL " , ESP_ERR_INVALID_ARG ) ;
2016-12-29 09:29:14 +00:00
xSemaphoreTake ( p_i2s_obj [ i2s_num ] - > tx - > mux , ( portTickType ) portMAX_DELAY ) ;
2019-02-22 12:17:42 +00:00
# ifdef CONFIG_PM_ENABLE
esp_pm_lock_acquire ( p_i2s_obj [ i2s_num ] - > pm_lock ) ;
# endif
2018-04-11 11:37:31 +00:00
src_byte = ( char * ) src ;
2016-12-29 09:29:14 +00:00
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 ;
}
2018-04-11 11:37:31 +00:00
memcpy ( data_ptr , src_byte , bytes_can_write ) ;
2016-12-29 09:29:14 +00:00
size - = bytes_can_write ;
2018-04-11 11:37:31 +00:00
src_byte + = bytes_can_write ;
2016-12-29 09:29:14 +00:00
p_i2s_obj [ i2s_num ] - > tx - > rw_pos + = bytes_can_write ;
2018-04-11 11:37:31 +00:00
( * bytes_written ) + = bytes_can_write ;
2016-12-29 09:29:14 +00:00
}
2019-02-22 12:17:42 +00:00
# ifdef CONFIG_PM_ENABLE
esp_pm_lock_release ( p_i2s_obj [ i2s_num ] - > pm_lock ) ;
# endif
2016-12-29 09:29:14 +00:00
xSemaphoreGive ( p_i2s_obj [ i2s_num ] - > tx - > mux ) ;
2018-04-11 11:37:31 +00:00
return ESP_OK ;
2016-12-29 09:29:14 +00:00
}
2020-02-20 08:00:48 +00:00
# if SOC_I2S_SUPPORTS_ADC_DAC
2017-12-08 12:07:19 +00:00
esp_err_t i2s_adc_enable ( 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 ] ! = NULL ) , " Not initialized yet " , ESP_ERR_INVALID_STATE ) ;
I2S_CHECK ( ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_ADC_BUILT_IN ) , " i2s built-in adc not enabled " , ESP_ERR_INVALID_STATE ) ;
2020-02-25 14:19:48 +00:00
adc1_dma_mode_acquire ( ) ;
2017-12-08 12:07:19 +00:00
_i2s_adc_mode_recover ( ) ;
2019-12-20 06:57:34 +00:00
i2s_hal_start_rx ( & ( p_i2s_obj [ i2s_num ] - > hal ) ) ;
i2s_hal_reset ( & ( p_i2s_obj [ i2s_num ] - > hal ) ) ;
2017-12-08 12:07:19 +00:00
return i2s_set_clk ( i2s_num , p_i2s_obj [ i2s_num ] - > sample_rate , p_i2s_obj [ i2s_num ] - > bits_per_sample , p_i2s_obj [ i2s_num ] - > channel_num ) ;
}
esp_err_t i2s_adc_disable ( 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 ] ! = NULL ) , " Not initialized yet " , ESP_ERR_INVALID_STATE ) ;
I2S_CHECK ( ( p_i2s_obj [ i2s_num ] - > mode & I2S_MODE_ADC_BUILT_IN ) , " i2s built-in adc not enabled " , ESP_ERR_INVALID_STATE ) ;
2019-12-20 06:57:34 +00:00
i2s_hal_stop_rx ( & ( p_i2s_obj [ i2s_num ] - > hal ) ) ;
2017-12-08 12:07:19 +00:00
adc1_lock_release ( ) ;
return ESP_OK ;
}
2020-02-20 08:00:48 +00:00
# endif
2017-12-08 12:07:19 +00:00
2018-04-11 11:37:31 +00:00
esp_err_t i2s_write_expand ( i2s_port_t i2s_num , const void * src , size_t size , size_t src_bits , size_t aim_bits , size_t * bytes_written , TickType_t ticks_to_wait )
2017-11-29 05:16:26 +00:00
{
char * data_ptr ;
2018-04-11 11:37:31 +00:00
int bytes_can_write , tail ;
int src_bytes , aim_bytes , zero_bytes ;
* bytes_written = 0 ;
I2S_CHECK ( ( i2s_num < I2S_NUM_MAX ) , " i2s_num error " , ESP_ERR_INVALID_ARG ) ;
I2S_CHECK ( ( size > 0 ) , " size must greater than zero " , ESP_ERR_INVALID_ARG ) ;
I2S_CHECK ( ( aim_bits * size < I2S_MAX_BUFFER_SIZE ) , " size is too large " , ESP_ERR_INVALID_ARG ) ;
2019-06-06 09:00:03 +00:00
I2S_CHECK ( ( aim_bits > = src_bits ) , " aim_bits mustn't be less than src_bits " , ESP_ERR_INVALID_ARG ) ;
2018-04-11 11:37:31 +00:00
I2S_CHECK ( ( p_i2s_obj [ i2s_num ] - > tx ) , " tx NULL " , ESP_ERR_INVALID_ARG ) ;
2017-11-29 05:16:26 +00:00
if ( src_bits < I2S_BITS_PER_SAMPLE_8BIT | | aim_bits < I2S_BITS_PER_SAMPLE_8BIT ) {
2019-06-06 09:00:03 +00:00
ESP_LOGE ( I2S_TAG , " bits mustn't be less than 8, src_bits %d aim_bits %d " , src_bits , aim_bits ) ;
2018-04-11 11:37:31 +00:00
return ESP_ERR_INVALID_ARG ;
2017-11-29 05:16:26 +00:00
}
if ( src_bits > I2S_BITS_PER_SAMPLE_32BIT | | aim_bits > I2S_BITS_PER_SAMPLE_32BIT ) {
2019-06-06 09:00:03 +00:00
ESP_LOGE ( I2S_TAG , " bits mustn't be greater than 32, src_bits %d aim_bits %d " , src_bits , aim_bits ) ;
2018-04-11 11:37:31 +00:00
return ESP_ERR_INVALID_ARG ;
2017-11-29 05:16:26 +00:00
}
if ( ( src_bits = = I2S_BITS_PER_SAMPLE_16BIT | | src_bits = = I2S_BITS_PER_SAMPLE_32BIT ) & & ( size % 2 ! = 0 ) ) {
ESP_LOGE ( I2S_TAG , " size must be a even number while src_bits is even, src_bits %d size %d " , src_bits , size ) ;
2018-04-11 11:37:31 +00:00
return ESP_ERR_INVALID_ARG ;
2017-11-29 05:16:26 +00:00
}
if ( src_bits = = I2S_BITS_PER_SAMPLE_24BIT & & ( size % 3 ! = 0 ) ) {
ESP_LOGE ( I2S_TAG , " size must be a multiple of 3 while src_bits is 24, size %d " , size ) ;
2018-04-11 11:37:31 +00:00
return ESP_ERR_INVALID_ARG ;
2017-11-29 05:16:26 +00:00
}
2018-04-11 11:37:31 +00:00
src_bytes = src_bits / 8 ;
aim_bytes = aim_bits / 8 ;
zero_bytes = aim_bytes - src_bytes ;
2017-11-29 05:16:26 +00:00
xSemaphoreTake ( p_i2s_obj [ i2s_num ] - > tx - > mux , ( portTickType ) portMAX_DELAY ) ;
size = size * aim_bytes / src_bytes ;
ESP_LOGD ( I2S_TAG , " aim_bytes %d src_bytes %d size %d " , aim_bytes , src_bytes , size ) ;
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 ;
}
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 ;
}
tail = bytes_can_write % aim_bytes ;
bytes_can_write = bytes_can_write - tail ;
memset ( data_ptr , 0 , bytes_can_write ) ;
for ( int j = 0 ; j < bytes_can_write ; j + = ( aim_bytes - zero_bytes ) ) {
j + = zero_bytes ;
2018-04-11 11:37:31 +00:00
memcpy ( & data_ptr [ j ] , ( const char * ) ( src + * bytes_written ) , aim_bytes - zero_bytes ) ;
( * bytes_written ) + = ( aim_bytes - zero_bytes ) ;
2017-11-29 05:16:26 +00:00
}
size - = bytes_can_write ;
p_i2s_obj [ i2s_num ] - > tx - > rw_pos + = bytes_can_write ;
}
xSemaphoreGive ( p_i2s_obj [ i2s_num ] - > tx - > mux ) ;
2018-04-11 11:37:31 +00:00
return ESP_OK ;
2017-11-29 05:16:26 +00:00
}
2018-04-11 11:37:31 +00:00
esp_err_t i2s_read ( i2s_port_t i2s_num , void * dest , size_t size , size_t * bytes_read , TickType_t ticks_to_wait )
{
char * data_ptr , * dest_byte ;
int bytes_can_read ;
* bytes_read = 0 ;
dest_byte = ( char * ) dest ;
I2S_CHECK ( ( i2s_num < I2S_NUM_MAX ) , " i2s_num error " , ESP_ERR_INVALID_ARG ) ;
I2S_CHECK ( ( size < I2S_MAX_BUFFER_SIZE ) , " size is too large " , ESP_ERR_INVALID_ARG ) ;
I2S_CHECK ( ( p_i2s_obj [ i2s_num ] - > rx ) , " rx NULL " , ESP_ERR_INVALID_ARG ) ;
2016-12-29 09:29:14 +00:00
xSemaphoreTake ( p_i2s_obj [ i2s_num ] - > rx - > mux , ( portTickType ) portMAX_DELAY ) ;
2019-02-22 12:17:42 +00:00
# ifdef CONFIG_PM_ENABLE
esp_pm_lock_acquire ( p_i2s_obj [ i2s_num ] - > pm_lock ) ;
# endif
2016-12-29 09:29:14 +00:00
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 ;
}
2018-04-11 11:37:31 +00:00
memcpy ( dest_byte , data_ptr , bytes_can_read ) ;
2016-12-29 09:29:14 +00:00
size - = bytes_can_read ;
2018-04-11 11:37:31 +00:00
dest_byte + = bytes_can_read ;
2016-12-29 09:29:14 +00:00
p_i2s_obj [ i2s_num ] - > rx - > rw_pos + = bytes_can_read ;
2018-04-11 11:37:31 +00:00
( * bytes_read ) + = bytes_can_read ;
2016-12-29 09:29:14 +00:00
}
2019-02-22 12:17:42 +00:00
# ifdef CONFIG_PM_ENABLE
esp_pm_lock_release ( p_i2s_obj [ i2s_num ] - > pm_lock ) ;
# endif
2016-12-29 09:29:14 +00:00
xSemaphoreGive ( p_i2s_obj [ i2s_num ] - > rx - > mux ) ;
2018-04-11 11:37:31 +00:00
return ESP_OK ;
2019-11-21 13:10:46 +00:00
}