Skip to content

Commit 451f69c

Browse files
committed
driver(i2s): fix broken i2s adc mode
1. Move i2s reset code from i2s_stop to i2s_start. 2. add RTC API to set sw mode for ADC 3. add description for adc_power_always_on() 4. add lock for i2s dma and RTC ADC functions. 5. add ADC read task in example reported from bbs: https://esp32.com/viewtopic.php?f=13&t=3490&p=17522#p17522 reported from github: #1333
1 parent 475ffe7 commit 451f69c

File tree

7 files changed

+242
-32
lines changed

7 files changed

+242
-32
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef _DRIVER_ADC1_I2S_PRIVATE_H_
16+
#define _DRIVER_ADC1_I2S_PRIVATE_H_
17+
18+
#ifdef __cplusplus
19+
extern "C" {
20+
#endif
21+
22+
#include "esp_err.h"
23+
24+
25+
/**
26+
* @brief Force power on for SAR ADC.
27+
* This function should be called for the scenario in which ADC are controlled by digital function like DMA.
28+
* When the ADC power is always on, RTC FSM can still be functional.
29+
* This is an internal API for I2S module to call to enable I2S-ADC function.
30+
* Note that adc_power_off() can still power down ADC.
31+
*/
32+
void adc_power_always_on();
33+
34+
/**
35+
* @brief For I2S dma to claim the usage of ADC1.
36+
*
37+
* Other tasks will be forbidden to use ADC1 between ``adc1_i2s_mode_acquire`` and ``adc1_i2s_release``.
38+
* The I2S module may have to wait for a short time for the current conversion (if exist) to finish.
39+
*
40+
* @return
41+
* - ESP_OK success
42+
* - ESP_ERR_TIMEOUT reserved for future use. Currently the function will wait until success.
43+
*/
44+
esp_err_t adc1_i2s_mode_acquire();
45+
46+
/**
47+
* @brief For ADC1 to claim the usage of ADC1.
48+
*
49+
* Other tasks will be forbidden to use ADC1 between ``adc1_adc_mode_acquire`` and ``adc1_i2s_release``.
50+
* The ADC1 may have to wait for some time for the I2S read operation to finish.
51+
*
52+
* @return
53+
* - ESP_OK success
54+
* - ESP_ERR_TIMEOUT reserved for future use. Currently the function will wait until success.
55+
*/
56+
esp_err_t adc1_adc_mode_acquire();
57+
58+
/**
59+
* @brief to let other tasks use the ADC1 when I2S is not work.
60+
*
61+
* Other tasks will be forbidden to use ADC1 between ``adc1_adc/i2s_mode_acquire`` and ``adc1_i2s_release``.
62+
* Call this function to release the occupation of ADC1
63+
*
64+
* @return always return ESP_OK.
65+
*/
66+
esp_err_t adc1_lock_release();
67+
68+
#ifdef __cplusplus
69+
}
70+
#endif
71+
72+
#endif /*_DRIVER_ADC1_I2S_PRIVATE_H_*/
73+

components/driver/i2s.c

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "driver/i2s.h"
3232
#include "driver/rtc_io.h"
3333
#include "driver/dac.h"
34+
#include "adc1_i2s_private.h"
3435

3536
#include "esp_intr.h"
3637
#include "esp_err.h"
@@ -83,12 +84,14 @@ typedef struct {
8384
int bits_per_sample; /*!< Bits per sample*/
8485
i2s_mode_t mode; /*!< I2S Working mode*/
8586
int use_apll; /*!< I2S use APLL clock */
87+
uint32_t sample_rate; /*!< I2S sample rate */
8688
} i2s_obj_t;
8789

8890
static i2s_obj_t *p_i2s_obj[I2S_NUM_MAX] = {0};
8991
static i2s_dev_t* I2S[I2S_NUM_MAX] = {&I2S0, &I2S1};
9092
static portMUX_TYPE i2s_spinlock[I2S_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED};
91-
93+
static int _i2s_adc_unit = -1;
94+
static int _i2s_adc_channel = -1;
9295
/**
9396
* @brief Pre define APLL parameters, save compute time
9497
* | bits_per_sample | rate | sdm0 | sdm1 | sdm2 | odir
@@ -321,12 +324,11 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
321324
return ESP_ERR_INVALID_ARG;
322325
}
323326

324-
325327
if (p_i2s_obj[i2s_num] == NULL) {
326328
ESP_LOGE(I2S_TAG, "Not initialized yet");
327329
return ESP_FAIL;
328330
}
329-
331+
p_i2s_obj[i2s_num]->sample_rate = rate;
330332
double clkmdiv = (double)I2S_BASE_CLK / (rate * factor);
331333

332334
if (clkmdiv > 256) {
@@ -645,6 +647,18 @@ esp_err_t i2s_start(i2s_port_t i2s_num)
645647
{
646648
//start DMA link
647649
I2S_ENTER_CRITICAL();
650+
i2s_reset_fifo(i2s_num);
651+
//reset dma
652+
I2S[i2s_num]->lc_conf.in_rst = 1;
653+
I2S[i2s_num]->lc_conf.in_rst = 0;
654+
I2S[i2s_num]->lc_conf.out_rst = 1;
655+
I2S[i2s_num]->lc_conf.out_rst = 0;
656+
657+
I2S[i2s_num]->conf.tx_reset = 1;
658+
I2S[i2s_num]->conf.tx_reset = 0;
659+
I2S[i2s_num]->conf.rx_reset = 1;
660+
I2S[i2s_num]->conf.rx_reset = 0;
661+
648662
esp_intr_disable(p_i2s_obj[i2s_num]->i2s_isr_handle);
649663
I2S[i2s_num]->int_clr.val = 0xFFFFFFFF;
650664
if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) {
@@ -677,17 +691,6 @@ esp_err_t i2s_stop(i2s_port_t i2s_num)
677691
i2s_disable_rx_intr(i2s_num);
678692
}
679693
I2S[i2s_num]->int_clr.val = I2S[i2s_num]->int_st.val; //clear pending interrupt
680-
i2s_reset_fifo(i2s_num);
681-
//reset dma
682-
I2S[i2s_num]->lc_conf.in_rst = 1;
683-
I2S[i2s_num]->lc_conf.in_rst = 0;
684-
I2S[i2s_num]->lc_conf.out_rst = 1;
685-
I2S[i2s_num]->lc_conf.out_rst = 0;
686-
687-
I2S[i2s_num]->conf.tx_reset = 1;
688-
I2S[i2s_num]->conf.tx_reset = 0;
689-
I2S[i2s_num]->conf.rx_reset = 1;
690-
I2S[i2s_num]->conf.rx_reset = 0;
691694
I2S_EXIT_CRITICAL();
692695
return 0;
693696
}
@@ -714,10 +717,18 @@ esp_err_t i2s_set_dac_mode(i2s_dac_mode_t dac_mode)
714717
return ESP_OK;
715718
}
716719

720+
static esp_err_t _i2s_adc_mode_recover()
721+
{
722+
I2S_CHECK(((_i2s_adc_unit != -1) && (_i2s_adc_channel != -1)), "i2s ADC recover error, not initialized...", ESP_ERR_INVALID_ARG);
723+
return adc_i2s_mode_init(_i2s_adc_unit, _i2s_adc_channel);
724+
}
725+
717726
esp_err_t i2s_set_adc_mode(adc_unit_t adc_unit, adc1_channel_t adc_channel)
718727
{
719728
I2S_CHECK((adc_unit < ADC_UNIT_2), "i2s ADC unit error, only support ADC1 for now", ESP_ERR_INVALID_ARG);
720729
// For now, we only support SAR ADC1.
730+
_i2s_adc_unit = adc_unit;
731+
_i2s_adc_channel = adc_channel;
721732
return adc_i2s_mode_init(adc_unit, adc_channel);
722733
}
723734

@@ -856,7 +867,7 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co
856867
//initialize the specific ADC channel.
857868
//in the current stage, we only support ADC1 and single channel mode.
858869
//In default data mode, the ADC data is in 12-bit resolution mode.
859-
adc_power_on();
870+
adc_power_always_on();
860871
}
861872
// configure I2S data port interface.
862873
i2s_reset_fifo(i2s_num);
@@ -1144,6 +1155,27 @@ int i2s_write_bytes(i2s_port_t i2s_num, const char *src, size_t size, TickType_t
11441155
return bytes_writen;
11451156
}
11461157

1158+
esp_err_t i2s_adc_enable(i2s_port_t i2s_num)
1159+
{
1160+
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
1161+
I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_STATE);
1162+
I2S_CHECK((p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN), "i2s built-in adc not enabled", ESP_ERR_INVALID_STATE);
1163+
1164+
adc1_i2s_mode_acquire();
1165+
_i2s_adc_mode_recover();
1166+
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);
1167+
}
1168+
1169+
esp_err_t i2s_adc_disable(i2s_port_t i2s_num)
1170+
{
1171+
I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG);
1172+
I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_STATE);
1173+
I2S_CHECK((p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN), "i2s built-in adc not enabled", ESP_ERR_INVALID_STATE);
1174+
1175+
adc1_lock_release();
1176+
return ESP_OK;
1177+
}
1178+
11471179
int i2s_read_bytes(i2s_port_t i2s_num, char* dest, size_t size, TickType_t ticks_to_wait)
11481180
{
11491181
char *data_ptr;

components/driver/include/driver/adc.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,12 +204,13 @@ int adc1_get_voltage(adc1_channel_t channel) __attribute__((deprecated));
204204
/** @endcond */
205205

206206
/**
207-
* @brief Power on SAR ADC
207+
* @brief Enable ADC power
208208
*/
209209
void adc_power_on();
210210

211211
/**
212212
* @brief Power off SAR ADC
213+
* This function will force power down for ADC
213214
*/
214215
void adc_power_off();
215216

components/driver/include/driver/i2s.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,8 @@ int i2s_write_bytes(i2s_port_t i2s_num, const char *src, size_t size, TickType_t
293293
*
294294
* Format of the data in source buffer is determined by the I2S
295295
* configuration (see i2s_config_t).
296+
* @note If the built-in ADC mode is enabled, we should call i2s_adc_start and i2s_adc_stop around the whole reading process,
297+
* to prevent the data getting corrupted.
296298
*
297299
* @return Number of bytes read, or ESP_FAIL (-1) for parameter error. If a timeout occurred, bytes read will be less than total size.
298300
*/
@@ -417,6 +419,31 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
417419
*/
418420
esp_err_t i2s_set_adc_mode(adc_unit_t adc_unit, adc1_channel_t adc_channel);
419421

422+
/**
423+
* @brief Start to use I2S built-in ADC mode
424+
* @note This function would acquire the lock of ADC to prevent the data getting corrupted
425+
* during the I2S peripheral is being used to do fully continuous ADC sampling.
426+
*
427+
* @param i2s_num i2s port index
428+
* @return
429+
* - ESP_OK Success
430+
* - ESP_ERR_INVALID_ARG Parameter error
431+
* - ESP_ERR_INVALID_STATE driver state error
432+
* - ESP_FAIL Internal driver error
433+
*/
434+
esp_err_t i2s_adc_enable(i2s_port_t i2s_num);
435+
436+
/**
437+
* @brief Stop to use I2S built-in ADC mode
438+
* @param i2s_num i2s port index
439+
* @note This function would release the lock of ADC so that other tasks can use ADC.
440+
* @return
441+
* - ESP_OK Success
442+
* - ESP_ERR_INVALID_ARG Parameter error
443+
* - ESP_ERR_INVALID_STATE driver state error
444+
*/
445+
esp_err_t i2s_adc_disable(i2s_port_t i2s_num);
446+
420447
#ifdef __cplusplus
421448
}
422449
#endif

0 commit comments

Comments
 (0)