Skip to content

Commit 1b1c36e

Browse files
authored
WIP; Reworked HiFreq_ADC example; Closing #6832 (#6917)
Description of Change Original code does not work (crashing) - related issue #6832 - now fixed. Extended description to be more helpful. Added options to modify the setup at the top of the code via constants. Added option do plot with Arduino Serial plotter. Even if the crashing was solved alone the ledc PWM would not output any signal. Tests scenarios Tested on ESP32 with oscilloscope and signal generator. Related links Closing #6832
1 parent 949aa27 commit 1b1c36e

File tree

1 file changed

+108
-58
lines changed

1 file changed

+108
-58
lines changed
+108-58
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,133 @@
11
/*
2-
* This is an example to read analog data at high frequency using the I2S peripheral
3-
* Run a wire between pins 27 & 32
4-
* The readings from the device will be 12bit (0-4096)
5-
*/
2+
This example demonstrates I2S ADC capability to sample high frequency analog signals.
3+
The PWM signal generated with ledc is only for ease of use when first trying out.
4+
To sample the generated signal connect default pins 27(PWM) and 32(Sampling) together.
5+
If you do not wish to generate PWM simply comment out the definition of constant GENERATE_PWM
6+
Try to change the PWM_DUTY_PERCENT and see how to averaged value changes.
7+
8+
The maximum for I2S ADC sampling frequency is 5MHz (value 5000000), however there will be many values repeated because the real
9+
sampling frequency is much lower -
10+
11+
By default this example will print values compatible with Arduino plotter
12+
1. signal - all values
13+
2. signal - averaged value
14+
15+
You can change the number of sample over which is the signal averaged by changing value of AVERAGE_EVERY_N_SAMPLES
16+
If you comment the definition altogether the averaging will not be performed nor printed.
17+
18+
If you do not wish to print every value, simply comment definition of constant PRINT_ALL_VALUES
19+
20+
Note: ESP prints messages at startup which will pollute Arduino IDE Serial plotter legend.
21+
To avoid this pollution, start the plotter after startup (op restart)
22+
*/
623
#include <driver/i2s.h>
724

8-
#define I2S_SAMPLE_RATE 78125
9-
#define ADC_INPUT ADC1_CHANNEL_4 //pin 32
10-
#define OUTPUT_PIN 27
11-
#define OUTPUT_VALUE 3800
12-
#define READ_DELAY 9000 //microseconds
25+
// I2S
26+
#define I2S_SAMPLE_RATE (277777) // Max sampling frequency = 277.777 kHz
27+
#define ADC_INPUT (ADC1_CHANNEL_4) //pin 32
28+
#define I2S_DMA_BUF_LEN (1024)
29+
30+
// PWM
31+
#define GENERATE_PWM
32+
#define OUTPUT_PIN (27)
33+
#define PWM_FREQUENCY ((I2S_SAMPLE_RATE)/4)
34+
#define PWM_DUTY_PERCENT (50)
35+
#define PWM_RESOLUTION_BITS (2) // Lower bit resolution enables higher frequency
36+
#define PWM_DUTY_VALUE ((((1<<(PWM_RESOLUTION_BITS)))*(PWM_DUTY_PERCENT))/100) // Duty value used for setup function based on resolution
1337

14-
uint16_t adc_reading;
38+
// Sample post processing
39+
#define PRINT_ALL_VALUES
40+
#define AVERAGE_EVERY_N_SAMPLES (100)
1541

16-
void i2sInit()
17-
{
18-
i2s_config_t i2s_config = {
42+
void i2sInit(){
43+
i2s_config_t i2s_config = {
1944
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN),
2045
.sample_rate = I2S_SAMPLE_RATE, // The format of the signal using ADC_BUILT_IN
2146
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // is fixed at 12bit, stereo, MSB
2247
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
23-
.communication_format = I2S_COMM_FORMAT_I2S_MSB,
48+
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
2449
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
25-
.dma_buf_count = 4,
26-
.dma_buf_len = 8,
50+
.dma_buf_count = 8,
51+
.dma_buf_len = I2S_DMA_BUF_LEN,
2752
.use_apll = false,
2853
.tx_desc_auto_clear = false,
2954
.fixed_mclk = 0
30-
};
31-
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
32-
i2s_set_adc_mode(ADC_UNIT_1, ADC_INPUT);
33-
i2s_adc_enable(I2S_NUM_0);
34-
}
55+
};
56+
Serial.printf("Attempting to setup I2S ADC with sampling frequency %d Hz\n", I2S_SAMPLE_RATE);
57+
if(ESP_OK != i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL)){
58+
Serial.printf("Error installing I2S. Halt!");
59+
while(1);
60+
}
61+
if(ESP_OK != i2s_set_adc_mode(ADC_UNIT_1, ADC_INPUT)){
62+
Serial.printf("Error setting up ADC. Halt!");
63+
while(1);
64+
}
65+
if(ESP_OK != adc1_config_channel_atten(ADC_INPUT, ADC_ATTEN_DB_11)){
66+
Serial.printf("Error setting up ADC attenuation. Halt!");
67+
while(1);
68+
}
3569

36-
void reader(void *pvParameters) {
37-
uint32_t read_counter = 0;
38-
uint64_t read_sum = 0;
39-
// The 4 high bits are the channel, and the data is inverted
40-
uint16_t offset = (int)ADC_INPUT * 0x1000 + 0xFFF;
41-
size_t bytes_read;
42-
while(1){
43-
uint16_t buffer[2] = {0};
44-
i2s_read(I2S_NUM_0, &buffer, sizeof(buffer), &bytes_read, 15);
45-
//Serial.printf("%d %d\n", offset - buffer[0], offset - buffer[1]);
46-
if (bytes_read == sizeof(buffer)) {
47-
read_sum += offset - buffer[0];
48-
read_sum += offset - buffer[1];
49-
read_counter++;
50-
} else {
51-
Serial.println("buffer empty");
52-
}
53-
if (read_counter == I2S_SAMPLE_RATE) {
54-
adc_reading = read_sum / I2S_SAMPLE_RATE / 2;
55-
//Serial.printf("avg: %d millis: ", adc_reading);
56-
//Serial.println(millis());
57-
read_counter = 0;
58-
read_sum = 0;
59-
i2s_adc_disable(I2S_NUM_0);
60-
delay(READ_DELAY);
61-
i2s_adc_enable(I2S_NUM_0);
62-
}
70+
if(ESP_OK != i2s_adc_enable(I2S_NUM_0)){
71+
Serial.printf("Error enabling ADC. Halt!");
72+
while(1);
6373
}
74+
Serial.printf("I2S ADC setup ok\n");
6475
}
6576

6677
void setup() {
6778
Serial.begin(115200);
68-
// Put a signal out on pin
69-
uint32_t freq = ledcSetup(0, I2S_SAMPLE_RATE, 10);
70-
Serial.printf("Output frequency: %d\n", freq);
71-
ledcWrite(0, OUTPUT_VALUE/4);
79+
80+
#ifdef GENERATE_PWM
81+
// PWM setup
82+
Serial.printf("Setting up PWM: frequency = %d; resolution bits %d; Duty cycle = %d; duty value = %d, Output pin = %d\n", PWM_FREQUENCY, PWM_RESOLUTION_BITS, PWM_DUTY_PERCENT, PWM_DUTY_VALUE, OUTPUT_PIN);
83+
uint32_t freq = ledcSetup(0, PWM_FREQUENCY, PWM_RESOLUTION_BITS);
84+
if(freq != PWM_FREQUENCY){
85+
Serial.printf("Error setting up PWM. Halt!");
86+
while(1);
87+
}
7288
ledcAttachPin(OUTPUT_PIN, 0);
89+
ledcWrite(0, PWM_DUTY_VALUE);
90+
Serial.printf("PWM setup ok\n");
91+
#endif
92+
7393
// Initialize the I2S peripheral
7494
i2sInit();
75-
// Create a task that will read the data
76-
xTaskCreatePinnedToCore(reader, "ADC_reader", 2048, NULL, 1, NULL, 1);
7795
}
7896

79-
void loop() {
80-
delay(1020);
81-
Serial.printf("ADC reading: %d\n", adc_reading);
82-
delay(READ_DELAY);
97+
void loop(){
98+
// The 4 high bits are the channel, and the data is inverted
99+
size_t bytes_read;
100+
uint16_t buffer[I2S_DMA_BUF_LEN] = {0};
101+
102+
#ifdef AVERAGE_EVERY_N_SAMPLES
103+
uint32_t read_counter = 0;
104+
uint32_t averaged_reading = 0;
105+
uint64_t read_sum = 0;
106+
#endif
107+
108+
while(1){
109+
i2s_read(I2S_NUM_0, &buffer, sizeof(buffer), &bytes_read, 15);
110+
//Serial.printf("read %d Bytes\n", bytes_read);
111+
112+
for(int i = 0; i < bytes_read/2; ++i){
113+
#ifdef PRINT_ALL_VALUES
114+
//Serial.printf("[%d] = %d\n", i, buffer[i] & 0x0FFF); // Print with indexes
115+
Serial.printf("Signal:%d ", buffer[i] & 0x0FFF); // Print compatible with Arduino Plotter
116+
#endif
117+
#ifdef AVERAGE_EVERY_N_SAMPLES
118+
read_sum += buffer[i] & 0x0FFF;
119+
++read_counter;
120+
if(read_counter == AVERAGE_EVERY_N_SAMPLES){
121+
averaged_reading = read_sum / AVERAGE_EVERY_N_SAMPLES;
122+
//Serial.printf("averaged_reading = %d over %d samples\n", averaged_reading, read_counter); // Print with additional info
123+
Serial.printf("Averaged_signal:%d", averaged_reading); // Print compatible with Arduino Plotter
124+
read_counter = 0;
125+
read_sum = 0;
126+
}
127+
#endif
128+
#if defined(PRINT_ALL_VALUES) || defined (AVERAGE_EVERY_N_SAMPLES)
129+
Serial.printf("\n");
130+
#endif
131+
} // for
132+
} // while
83133
}

0 commit comments

Comments
 (0)