diff --git a/components/driver/i2s.c b/components/driver/i2s.c index 68c0f7f71..3f6279f25 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -26,6 +26,8 @@ #include "driver/gpio.h" #include "driver/i2s.h" +#include "driver/rtc_io.h" +#include "driver/dac.h" #include "esp_intr.h" #include "esp_err.h" @@ -41,7 +43,8 @@ static const char* I2S_TAG = "I2S"; #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 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) /** * @brief DMA buffer object @@ -99,6 +102,7 @@ inline static void gpio_matrix_out_check(uint32_t gpio, uint32_t signal_idx, boo //if pin = -1, do not need to configure if (gpio != -1) { PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO); + gpio_set_direction(gpio, GPIO_MODE_DEF_OUTPUT); gpio_matrix_out(gpio, signal_idx, out_inv, oen_inv); } } @@ -106,6 +110,8 @@ inline static void gpio_matrix_in_check(uint32_t gpio, uint32_t signal_idx, bool { if (gpio != -1) { PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO); + //Set direction, for some GPIOs, the input function are not enabled as default. + gpio_set_direction(gpio, GPIO_MODE_DEF_INPUT); gpio_matrix_in(gpio, signal_idx, inv); } } @@ -181,13 +187,6 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b return ESP_FAIL; } - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_DAC_BUILT_IN) { - //DAC uses bclk as sample clock, not WS. WS can be something arbitrary. - //Rate as given to this function is the intended BCLK rate; divided by bits it will - //give the real sample rate. For DAC mode, use the real sample rate as BCLK rate instead. - rate = rate / bits; - } - double clkmdiv = (double)I2S_BASE_CLK / (rate * factor); if (clkmdiv > 256) { @@ -206,15 +205,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b i2s_stop(i2s_num); p_i2s_obj[i2s_num]->channel_num = (ch == 2) ? 2 : 1; - I2S[i2s_num]->conf_chan.tx_chan_mod = (ch == 2) ? 0 : 1; // 0-two channel;1-right;2-left;3-righ;4-left - I2S[i2s_num]->fifo_conf.tx_fifo_mod = (ch == 2) ? 0 : 1; // 0-right&left channel;1-one channel - I2S[i2s_num]->conf.tx_mono = 0; - I2S[i2s_num]->conf_chan.rx_chan_mod = (ch == 2) ? 0 : 1; - I2S[i2s_num]->fifo_conf.rx_fifo_mod = (ch == 2) ? 0 : 1; - I2S[i2s_num]->conf.rx_mono = 0; - - if (bits != p_i2s_obj[i2s_num]->bits_per_sample) { //change fifo mode @@ -273,15 +264,43 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b if (save_rx) { i2s_destroy_dma_queue(i2s_num, save_rx); } - } } - clkmInteger = clkmdiv; - clkmDecimals = (clkmdiv - clkmInteger) / denom; - double mclk = clkmInteger + denom * clkmDecimals; - bck = factor/(bits * channel); + double mclk; + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_DAC_BUILT_IN) { + //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 + uint32_t b_clk = rate * 2; + int factor2 = 60; + mclk = b_clk * factor2; + clkmdiv = ((double) I2S_BASE_CLK) / mclk; + clkmInteger = clkmdiv; + clkmDecimals = (clkmdiv - clkmInteger) / denom; + bck = mclk / b_clk; + } 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) { + int fp = I2S[i2s_num]->pdm_freq_conf.tx_pdm_fp; + int fs = I2S[i2s_num]->pdm_freq_conf.tx_pdm_fs; + b_clk = rate * 64 * (fp / fs); + } else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { + b_clk = rate * 64 * (I2S[i2s_num]->pdm_conf.rx_sinc_dsr_16_en + 1); + } + int factor2 = 5 ; + mclk = b_clk * factor2; + clkmdiv = ((double) I2S_BASE_CLK) / mclk; + clkmInteger = clkmdiv; + clkmDecimals = (clkmdiv - clkmInteger) / denom; + bck = mclk / b_clk; + } else { + clkmInteger = clkmdiv; + clkmDecimals = (clkmdiv - clkmInteger) / denom; + 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; @@ -291,7 +310,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b 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; - double real_rate = (double)(I2S_BASE_CLK / (bck * bits * clkmInteger)/2); + double real_rate = (double) (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, (double)I2S_BASE_CLK / mclk, real_rate*bits*channel, 64, clkmDecimals); @@ -504,22 +523,25 @@ esp_err_t i2s_stop(i2s_port_t i2s_num) return 0; } -static esp_err_t configure_dac_pin(void) +esp_err_t i2s_set_dac_mode(i2s_dac_mode_t dac_mode) { - 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); + I2S_CHECK((dac_mode < I2S_DAC_CHANNEL_MAX), "i2s dac mode error", ESP_ERR_INVALID_ARG); + if(dac_mode == I2S_DAC_CHANNEL_DISABLE) { + dac_output_disable(DAC_CHANNEL_1); + dac_output_disable(DAC_CHANNEL_1); + dac_i2s_disable(); + } else { + dac_i2s_enable(); + } - 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); + if (dac_mode & I2S_DAC_CHANNEL_RIGHT_EN) { + //DAC1, right channel, GPIO25 + dac_output_enable(DAC_CHANNEL_1); + } + if (dac_mode & I2S_DAC_CHANNEL_LEFT_EN) { + //DAC2, left channel, GPIO26 + dac_output_enable(DAC_CHANNEL_2); + } return ESP_OK; } @@ -527,7 +549,7 @@ 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_ERR_INVALID_ARG); if (pin == NULL) { - return configure_dac_pin(); + return i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); } if (pin->bck_io_num != -1 && !GPIO_IS_VALID_GPIO(pin->bck_io_num)) { ESP_LOGE(I2S_TAG, "bck_io_num error"); @@ -547,47 +569,76 @@ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin) } int bck_sig = -1, ws_sig = -1, data_out_sig = -1, data_in_sig = -1; - //TX & RX + //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 if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) { - 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) { + if (i2s_num == I2S_NUM_0) { + bck_sig = I2S0O_BCK_OUT_IDX; + ws_sig = I2S0O_WS_OUT_IDX; + data_out_sig = I2S0O_DATA_OUT23_IDX; + } else { bck_sig = I2S1O_BCK_OUT_IDX; ws_sig = I2S1O_WS_OUT_IDX; data_out_sig = I2S1O_DATA_OUT23_IDX; } } else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_SLAVE) { - bck_sig = I2S0O_BCK_IN_IDX; - ws_sig = I2S0O_WS_IN_IDX; - data_out_sig = I2S0O_DATA_OUT23_IDX; - if (i2s_num == I2S_NUM_1) { + if (i2s_num == I2S_NUM_0) { + bck_sig = I2S0O_BCK_IN_IDX; + ws_sig = I2S0O_WS_IN_IDX; + data_out_sig = I2S0O_DATA_OUT23_IDX; + } else { bck_sig = I2S1O_BCK_IN_IDX; ws_sig = I2S1O_WS_IN_IDX; data_out_sig = I2S1O_DATA_OUT23_IDX; } } } + //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 if (p_i2s_obj[i2s_num]->mode & I2S_MODE_RX) { - if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) { + if (p_i2s_obj[i2s_num]->mode & I2S_MODE_MASTER) { + if (i2s_num == I2S_NUM_0) { + 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 = I2S1O_BCK_OUT_IDX; - ws_sig = I2S1O_WS_OUT_IDX; - data_in_sig = I2S1I_DATA_IN15_IDX; - } - } else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_SLAVE) { + } else { + bck_sig = I2S1I_BCK_OUT_IDX; + ws_sig = I2S1I_WS_OUT_IDX; + data_in_sig = I2S1I_DATA_IN15_IDX; + } + } else if (p_i2s_obj[i2s_num]->mode & I2S_MODE_SLAVE) { + if (i2s_num == I2S_NUM_0) { bck_sig = I2S0I_BCK_IN_IDX; ws_sig = I2S0I_WS_IN_IDX; data_in_sig = I2S0I_DATA_IN15_IDX; - if (i2s_num == I2S_NUM_1) { - bck_sig = I2S1I_BCK_IN_IDX; - ws_sig = I2S1I_WS_IN_IDX; - data_in_sig = I2S1I_DATA_IN15_IDX; - } + } else { + bck_sig = I2S1I_BCK_IN_IDX; + ws_sig = I2S1I_WS_IN_IDX; + data_in_sig = I2S1I_DATA_IN15_IDX; } } + } + //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) { + if (i2s_num == I2S_NUM_0) { + bck_sig = I2S0I_BCK_IN_IDX; + ws_sig = I2S0I_WS_IN_IDX; + } else { + bck_sig = I2S1I_BCK_IN_IDX; + ws_sig = I2S1I_WS_IN_IDX; + } + } else if ((p_i2s_obj[i2s_num]->mode & I2S_FULL_DUPLEX_MASTER_MODE_MASK) == I2S_FULL_DUPLEX_MASTER_MODE_MASK) { + if (i2s_num == I2S_NUM_0) { + bck_sig = I2S0O_BCK_OUT_IDX; + ws_sig = I2S0O_WS_OUT_IDX; + } else { + bck_sig = I2S1O_BCK_OUT_IDX; + ws_sig = I2S1O_WS_OUT_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); @@ -613,11 +664,13 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co { I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); I2S_CHECK((i2s_config), "param null", ESP_ERR_INVALID_ARG); + 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); @@ -671,7 +724,7 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co 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;//? + 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 @@ -682,7 +735,7 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co 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]->fifo_conf.rx_fifo_mod_force_en = 1; if (i2s_config->mode & I2S_MODE_SLAVE) { I2S[i2s_num]->conf.rx_slave_mod = 1;//RX Slave @@ -692,9 +745,26 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co 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->mode & I2S_MODE_PDM) { + I2S[i2s_num]->fifo_conf.rx_fifo_mod_force_en = 1; + I2S[i2s_num]->fifo_conf.tx_fifo_mod_force_en = 1; + + I2S[i2s_num]->pdm_freq_conf.tx_pdm_fp = 960; + I2S[i2s_num]->pdm_freq_conf.tx_pdm_fs = i2s_config->sample_rate / 1000 * 10; + I2S[i2s_num]->pdm_conf.tx_sinc_osr2 = I2S[i2s_num]->pdm_freq_conf.tx_pdm_fp / I2S[i2s_num]->pdm_freq_conf.tx_pdm_fs; + + I2S[i2s_num]->pdm_conf.rx_sinc_dsr_16_en = 0; + I2S[i2s_num]->pdm_conf.rx_pdm_en = 1; + I2S[i2s_num]->pdm_conf.tx_pdm_en = 1; + + I2S[i2s_num]->pdm_conf.pcm2pdm_conv_en = 1; + I2S[i2s_num]->pdm_conf.pdm2pcm_conv_en = 1; + } else { + I2S[i2s_num]->pdm_conf.rx_pdm_en = 0; + I2S[i2s_num]->pdm_conf.tx_pdm_en = 0; + } 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; @@ -778,6 +848,13 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, 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; + //To make sure hardware is enabled before any hardware register operations. + if (i2s_num == I2S_NUM_1) { + periph_module_enable(PERIPH_I2S1_MODULE); + } else { + periph_module_enable(PERIPH_I2S0_MODULE); + } + //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) { diff --git a/components/driver/include/driver/dac.h b/components/driver/include/driver/dac.h index ce5a90b3c..07e1ff80d 100644 --- a/components/driver/include/driver/dac.h +++ b/components/driver/include/driver/dac.h @@ -28,13 +28,31 @@ typedef enum { DAC_CHANNEL_MAX, } dac_channel_t; + +/** + * @brief Set DAC output voltage. + * + * @note Function has been deprecated, please use dac_output_voltage instead. + * This name will be removed in a future release. + * The difference is that before calling dac_output_voltage, we need to initialize the dac pad by dac_output_enable + * + * + * @param channel DAC channel + * @param dac_value DAC output value + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t dac_out_voltage(dac_channel_t channel, uint8_t dac_value) __attribute__ ((deprecated)); + /** * @brief Set DAC output voltage. * * DAC output is 8-bit. Maximum (255) corresponds to VDD. * - * @note When this function is called, function for the DAC - * channel's GPIO pin is reconfigured for RTC DAC function. + * @note Need to configure DAC pad before calling this function. + * DAC channel 1 is attached to GPIO25, DAC channel 2 is attached to GPIO26 * * @param channel DAC channel * @param dac_value DAC output value @@ -43,8 +61,35 @@ typedef enum { * - ESP_OK success * - ESP_ERR_INVALID_ARG Parameter error */ -esp_err_t dac_out_voltage(dac_channel_t channel, uint8_t dac_value); +esp_err_t dac_output_voltage(dac_channel_t channel, uint8_t dac_value); +/** + * @brief DAC pad output enable + * + * @param channel DAC channel + * @note DAC channel 1 is attached to GPIO25, DAC channel 2 is attached to GPIO26 + * I2S left channel will be mapped to DAC channel 2 + * I2S right channel will be mapped to DAC channel 1 + */ +esp_err_t dac_output_enable(dac_channel_t channel); + +/** + * @brief DAC pad output disable + * + * @param channel DAC channel + * @note DAC channel 1 is attached to GPIO25, DAC channel 2 is attached to GPIO26 + */ +esp_err_t dac_output_disable(dac_channel_t channel); + +/** + * @brief Enable DAC output data from I2S + */ +esp_err_t dac_i2s_enable(); + +/** + * @brief Disable DAC output data from I2S + */ +esp_err_t dac_i2s_disable(); #ifdef __cplusplus } #endif diff --git a/components/driver/include/driver/i2s.h b/components/driver/include/driver/i2s.h index 562f0985d..5777e34ba 100644 --- a/components/driver/include/driver/i2s.h +++ b/components/driver/include/driver/i2s.h @@ -109,13 +109,17 @@ typedef enum { /** * @brief I2S Mode, defaut is I2S_MODE_MASTER | I2S_MODE_TX * + * @note PDM and built-in DAC functions are only supported on I2S0 for current ESP32 chip. + * */ 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_DAC_BUILT_IN = 16, /*!< Output I2S data to built-in DAC, no matter the data format is 16bit or 32 bit, the DAC module will only take the 8bits from MSB*/ + //I2S_MODE_ADC_BUILT_IN = 32, /*!< Currently not supported yet, will be added for the next version*/ + I2S_MODE_PDM = 64, } i2s_mode_t; /** @@ -144,6 +148,19 @@ typedef enum { I2S_EVENT_MAX, /*!< I2S event max index*/ } i2s_event_type_t; +/** + * @brief I2S DAC mode for i2s_set_dac_mode. + * + * @note PDM and built-in DAC functions are only supported on I2S0 for current ESP32 chip. + */ +typedef enum { + I2S_DAC_CHANNEL_DISABLE = 0, /*!< Disable I2S built-in DAC signals*/ + I2S_DAC_CHANNEL_RIGHT_EN = 1, /*!< Enable I2S built-in DAC right channel, maps to DAC channel 1 on GPIO25*/ + I2S_DAC_CHANNEL_LEFT_EN = 2, /*!< Enable I2S built-in DAC left channel, maps to DAC channel 2 on GPIO26*/ + I2S_DAC_CHANNEL_BOTH_EN = 0x3, /*!< Enable both of the I2S built-in DAC channels.*/ + I2S_DAC_CHANNEL_MAX = 0x4, /*!< I2S built-in DAC mode max index*/ +} i2s_dac_mode_t; + /** * @brief Event structure used in I2S event queue * @@ -166,6 +183,7 @@ typedef struct { int data_in_num; /*!< DATA in pin*/ } i2s_pin_config_t; + typedef intr_handle_t i2s_isr_handle_t; /** * @brief Set I2S pin number @@ -181,12 +199,30 @@ typedef intr_handle_t i2s_isr_handle_t; * Inside the pin configuration structure, set I2S_PIN_NO_CHANGE for any pin where * the current configuration should not be changed. * + * @note if *pin is set as NULL, this function will initialize both of the built-in DAC channels by default. + * if you don't want this to happen and you want to initialize only one of the DAC channels, you can call i2s_set_dac_mode instead. + * * @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 Set I2S dac mode, I2S built-in DAC is disabled by default + * + * @param dac_mode DAC mode configurations - see i2s_dac_mode_t + * + * @note Built-in DAC functions are only supported on I2S0 for current ESP32 chip. + * If either of the built-in DAC channel are enabled, the other one can not + * be used as RTC DAC function at the same time. + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t i2s_set_dac_mode(i2s_dac_mode_t dac_mode); + /** * @brief Install and start I2S driver. * diff --git a/components/driver/rtc_module.c b/components/driver/rtc_module.c index 60c5d6c89..39546b614 100644 --- a/components/driver/rtc_module.c +++ b/components/driver/rtc_module.c @@ -37,6 +37,8 @@ static const char *RTC_MODULE_TAG = "RTC_MODULE"; return ESP_FAIL;\ } +#define DAC_ERR_STR_CHANNEL_ERROR "DAC channel error" + portMUX_TYPE rtc_spinlock = portMUX_INITIALIZER_UNLOCKED; static xSemaphoreHandle rtc_touch_sem = NULL; @@ -607,7 +609,8 @@ int adc1_get_voltage(adc1_channel_t channel) ---------------------------------------------------------------*/ static esp_err_t dac_pad_get_io_num(dac_channel_t channel, gpio_num_t *gpio_num) { - RTC_MODULE_CHECK(channel < DAC_CHANNEL_MAX, "DAC Channel Err", ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK((channel >= DAC_CHANNEL_1) && (channel < DAC_CHANNEL_MAX), DAC_ERR_STR_CHANNEL_ERROR, ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK(gpio_num, "Param null", ESP_ERR_INVALID_ARG); switch (channel) { case DAC_CHANNEL_1: @@ -625,7 +628,7 @@ static esp_err_t dac_pad_get_io_num(dac_channel_t channel, gpio_num_t *gpio_num) static esp_err_t dac_rtc_pad_init(dac_channel_t channel) { - RTC_MODULE_CHECK(channel < DAC_CHANNEL_MAX, "DAC Channel Err", ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK((channel >= DAC_CHANNEL_1) && (channel < DAC_CHANNEL_MAX), DAC_ERR_STR_CHANNEL_ERROR, ESP_ERR_INVALID_ARG); gpio_num_t gpio_num = 0; dac_pad_get_io_num(channel, &gpio_num); rtc_gpio_init(gpio_num); @@ -637,26 +640,64 @@ static esp_err_t dac_rtc_pad_init(dac_channel_t channel) return ESP_OK; } -static esp_err_t dac_out_enable(dac_channel_t channel) +esp_err_t dac_output_enable(dac_channel_t channel) { + RTC_MODULE_CHECK((channel >= DAC_CHANNEL_1) && (channel < DAC_CHANNEL_MAX), DAC_ERR_STR_CHANNEL_ERROR, ESP_ERR_INVALID_ARG); + dac_rtc_pad_init(channel); + portENTER_CRITICAL(&rtc_spinlock); if (channel == DAC_CHANNEL_1) { - portENTER_CRITICAL(&rtc_spinlock); SET_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_XPD_DAC | RTC_IO_PDAC1_DAC_XPD_FORCE); - portEXIT_CRITICAL(&rtc_spinlock); } else if (channel == DAC_CHANNEL_2) { - portENTER_CRITICAL(&rtc_spinlock); SET_PERI_REG_MASK(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_XPD_DAC | RTC_IO_PDAC2_DAC_XPD_FORCE); - portEXIT_CRITICAL(&rtc_spinlock); - } else { - return ESP_ERR_INVALID_ARG; } + portEXIT_CRITICAL(&rtc_spinlock); + + return ESP_OK; +} + +esp_err_t dac_output_disable(dac_channel_t channel) +{ + RTC_MODULE_CHECK((channel >= DAC_CHANNEL_1) && (channel < DAC_CHANNEL_MAX), DAC_ERR_STR_CHANNEL_ERROR, ESP_ERR_INVALID_ARG); + portENTER_CRITICAL(&rtc_spinlock); + if (channel == DAC_CHANNEL_1) { + CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_XPD_DAC | RTC_IO_PDAC1_DAC_XPD_FORCE); + } else if (channel == DAC_CHANNEL_2) { + CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_XPD_DAC | RTC_IO_PDAC2_DAC_XPD_FORCE); + } + portEXIT_CRITICAL(&rtc_spinlock); + + return ESP_OK; +} + +esp_err_t dac_output_voltage(dac_channel_t channel, uint8_t dac_value) +{ + RTC_MODULE_CHECK((channel >= DAC_CHANNEL_1) && (channel < DAC_CHANNEL_MAX), DAC_ERR_STR_CHANNEL_ERROR, ESP_ERR_INVALID_ARG); + portENTER_CRITICAL(&rtc_spinlock); + //Disable Tone + CLEAR_PERI_REG_MASK(SENS_SAR_DAC_CTRL1_REG, SENS_SW_TONE_EN); + + //Disable Channel Tone + if (channel == DAC_CHANNEL_1) { + CLEAR_PERI_REG_MASK(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_CW_EN1_M); + } else if (channel == DAC_CHANNEL_2) { + CLEAR_PERI_REG_MASK(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_CW_EN2_M); + } + + //Set the Dac value + if (channel == DAC_CHANNEL_1) { + SET_PERI_REG_BITS(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_DAC, dac_value, RTC_IO_PDAC1_DAC_S); //dac_output + } else if (channel == DAC_CHANNEL_2) { + SET_PERI_REG_BITS(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_DAC, dac_value, RTC_IO_PDAC2_DAC_S); //dac_output + } + + portEXIT_CRITICAL(&rtc_spinlock); return ESP_OK; } esp_err_t dac_out_voltage(dac_channel_t channel, uint8_t dac_value) { - RTC_MODULE_CHECK(channel < DAC_CHANNEL_MAX, "DAC Channel Err", ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK((channel >= DAC_CHANNEL_1) && (channel < DAC_CHANNEL_MAX), DAC_ERR_STR_CHANNEL_ERROR, ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&rtc_spinlock); //Disable Tone CLEAR_PERI_REG_MASK(SENS_SAR_DAC_CTRL1_REG, SENS_SW_TONE_EN); @@ -678,11 +719,27 @@ esp_err_t dac_out_voltage(dac_channel_t channel, uint8_t dac_value) portEXIT_CRITICAL(&rtc_spinlock); //dac pad init dac_rtc_pad_init(channel); - dac_out_enable(channel); + dac_output_enable(channel); return ESP_OK; } +esp_err_t dac_i2s_enable() +{ + portENTER_CRITICAL(&rtc_spinlock); + SET_PERI_REG_MASK(SENS_SAR_DAC_CTRL1_REG, SENS_DAC_DIG_FORCE_M | SENS_DAC_CLK_INV_M); + portEXIT_CRITICAL(&rtc_spinlock); + return ESP_OK; +} + +esp_err_t dac_i2s_disable() +{ + portENTER_CRITICAL(&rtc_spinlock); + CLEAR_PERI_REG_MASK(SENS_SAR_DAC_CTRL1_REG, SENS_DAC_DIG_FORCE_M | SENS_DAC_CLK_INV_M); + portEXIT_CRITICAL(&rtc_spinlock); + return ESP_OK; +} + /*--------------------------------------------------------------- HALL SENSOR ---------------------------------------------------------------*/ diff --git a/docs/api-reference/peripherals/dac.rst b/docs/api-reference/peripherals/dac.rst index ec17c31ca..905b9b21e 100644 --- a/docs/api-reference/peripherals/dac.rst +++ b/docs/api-reference/peripherals/dac.rst @@ -22,7 +22,8 @@ Setting DAC channel 1 (GPIO 25) voltage to approx 0.78 of VDD_A voltage (VDD * 2 ... - dac_out_voltage(DAC_CHANNEL_1, 200); + dac_output_enable(DAC_CHANNEL_1); + dac_output_voltage(DAC_CHANNEL_1, 200); API Reference ------------- @@ -40,6 +41,9 @@ Enumerations Functions ^^^^^^^^^ - .. doxygenfunction:: dac_out_voltage - - + .. doxygenfunction:: dac_output_voltage + .. doxygenfunction:: dac_output_enable + .. doxygenfunction:: dac_output_disable + .. doxygenfunction:: dac_i2s_enable + .. doxygenfunction:: dac_i2s_disable + \ No newline at end of file diff --git a/docs/api-reference/peripherals/i2s.rst b/docs/api-reference/peripherals/i2s.rst index 57ce422a8..3d05f129b 100644 --- a/docs/api-reference/peripherals/i2s.rst +++ b/docs/api-reference/peripherals/i2s.rst @@ -60,7 +60,7 @@ Short example configuring I2S to use internal DAC for analog output:: static const i2s_config_t i2s_config = { .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, .sample_rate = 44100, - .bits_per_sample = 8, /* must be 8 for built-in DAC */ + .bits_per_sample = 16, /* the DAC module will only take the 8bits from MSB */ .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, .communication_format = I2S_COMM_FORMAT_I2S_MSB, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority @@ -72,7 +72,10 @@ Short example configuring I2S to use internal DAC for analog output:: 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_pin(i2s_num, NULL); //for internal DAC, this will enable both of the internal channels + + //You can call i2s_set_dac_mode to set built-in DAC output mode. + //i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); i2s_set_sample_rates(i2s_num, 22050); //set sample rates @@ -112,11 +115,13 @@ Enumerations .. doxygenenum:: i2s_port_t .. doxygenenum:: i2s_mode_t .. doxygenenum:: i2s_event_type_t + .. doxygenenum:: i2s_dac_mode_t Functions ^^^^^^^^^ .. doxygenfunction:: i2s_set_pin + .. doxygenfunction:: i2s_set_dac_mode .. doxygenfunction:: i2s_driver_install .. doxygenfunction:: i2s_driver_uninstall .. doxygenfunction:: i2s_write_bytes