Unverified Commit 1b1c36ec authored by Tomáš Pilný's avatar Tomáš Pilný Committed by GitHub

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
parent 949aa27f
/*
* This is an example to read analog data at high frequency using the I2S peripheral
* Run a wire between pins 27 & 32
* The readings from the device will be 12bit (0-4096)
*/
This example demonstrates I2S ADC capability to sample high frequency analog signals.
The PWM signal generated with ledc is only for ease of use when first trying out.
To sample the generated signal connect default pins 27(PWM) and 32(Sampling) together.
If you do not wish to generate PWM simply comment out the definition of constant GENERATE_PWM
Try to change the PWM_DUTY_PERCENT and see how to averaged value changes.
The maximum for I2S ADC sampling frequency is 5MHz (value 5000000), however there will be many values repeated because the real
sampling frequency is much lower -
By default this example will print values compatible with Arduino plotter
1. signal - all values
2. signal - averaged value
You can change the number of sample over which is the signal averaged by changing value of AVERAGE_EVERY_N_SAMPLES
If you comment the definition altogether the averaging will not be performed nor printed.
If you do not wish to print every value, simply comment definition of constant PRINT_ALL_VALUES
Note: ESP prints messages at startup which will pollute Arduino IDE Serial plotter legend.
To avoid this pollution, start the plotter after startup (op restart)
*/
#include <driver/i2s.h>
#define I2S_SAMPLE_RATE 78125
#define ADC_INPUT ADC1_CHANNEL_4 //pin 32
#define OUTPUT_PIN 27
#define OUTPUT_VALUE 3800
#define READ_DELAY 9000 //microseconds
// I2S
#define I2S_SAMPLE_RATE (277777) // Max sampling frequency = 277.777 kHz
#define ADC_INPUT (ADC1_CHANNEL_4) //pin 32
#define I2S_DMA_BUF_LEN (1024)
// PWM
#define GENERATE_PWM
#define OUTPUT_PIN (27)
#define PWM_FREQUENCY ((I2S_SAMPLE_RATE)/4)
#define PWM_DUTY_PERCENT (50)
#define PWM_RESOLUTION_BITS (2) // Lower bit resolution enables higher frequency
#define PWM_DUTY_VALUE ((((1<<(PWM_RESOLUTION_BITS)))*(PWM_DUTY_PERCENT))/100) // Duty value used for setup function based on resolution
uint16_t adc_reading;
// Sample post processing
#define PRINT_ALL_VALUES
#define AVERAGE_EVERY_N_SAMPLES (100)
void i2sInit()
{
i2s_config_t i2s_config = {
void i2sInit(){
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN),
.sample_rate = I2S_SAMPLE_RATE, // The format of the signal using ADC_BUILT_IN
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // is fixed at 12bit, stereo, MSB
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_I2S_MSB,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 4,
.dma_buf_len = 8,
.dma_buf_count = 8,
.dma_buf_len = I2S_DMA_BUF_LEN,
.use_apll = false,
.tx_desc_auto_clear = false,
.fixed_mclk = 0
};
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
i2s_set_adc_mode(ADC_UNIT_1, ADC_INPUT);
i2s_adc_enable(I2S_NUM_0);
}
};
Serial.printf("Attempting to setup I2S ADC with sampling frequency %d Hz\n", I2S_SAMPLE_RATE);
if(ESP_OK != i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL)){
Serial.printf("Error installing I2S. Halt!");
while(1);
}
if(ESP_OK != i2s_set_adc_mode(ADC_UNIT_1, ADC_INPUT)){
Serial.printf("Error setting up ADC. Halt!");
while(1);
}
if(ESP_OK != adc1_config_channel_atten(ADC_INPUT, ADC_ATTEN_DB_11)){
Serial.printf("Error setting up ADC attenuation. Halt!");
while(1);
}
void reader(void *pvParameters) {
uint32_t read_counter = 0;
uint64_t read_sum = 0;
// The 4 high bits are the channel, and the data is inverted
uint16_t offset = (int)ADC_INPUT * 0x1000 + 0xFFF;
size_t bytes_read;
while(1){
uint16_t buffer[2] = {0};
i2s_read(I2S_NUM_0, &buffer, sizeof(buffer), &bytes_read, 15);
//Serial.printf("%d %d\n", offset - buffer[0], offset - buffer[1]);
if (bytes_read == sizeof(buffer)) {
read_sum += offset - buffer[0];
read_sum += offset - buffer[1];
read_counter++;
} else {
Serial.println("buffer empty");
}
if (read_counter == I2S_SAMPLE_RATE) {
adc_reading = read_sum / I2S_SAMPLE_RATE / 2;
//Serial.printf("avg: %d millis: ", adc_reading);
//Serial.println(millis());
read_counter = 0;
read_sum = 0;
i2s_adc_disable(I2S_NUM_0);
delay(READ_DELAY);
i2s_adc_enable(I2S_NUM_0);
}
if(ESP_OK != i2s_adc_enable(I2S_NUM_0)){
Serial.printf("Error enabling ADC. Halt!");
while(1);
}
Serial.printf("I2S ADC setup ok\n");
}
void setup() {
Serial.begin(115200);
// Put a signal out on pin
uint32_t freq = ledcSetup(0, I2S_SAMPLE_RATE, 10);
Serial.printf("Output frequency: %d\n", freq);
ledcWrite(0, OUTPUT_VALUE/4);
#ifdef GENERATE_PWM
// PWM setup
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);
uint32_t freq = ledcSetup(0, PWM_FREQUENCY, PWM_RESOLUTION_BITS);
if(freq != PWM_FREQUENCY){
Serial.printf("Error setting up PWM. Halt!");
while(1);
}
ledcAttachPin(OUTPUT_PIN, 0);
ledcWrite(0, PWM_DUTY_VALUE);
Serial.printf("PWM setup ok\n");
#endif
// Initialize the I2S peripheral
i2sInit();
// Create a task that will read the data
xTaskCreatePinnedToCore(reader, "ADC_reader", 2048, NULL, 1, NULL, 1);
}
void loop() {
delay(1020);
Serial.printf("ADC reading: %d\n", adc_reading);
delay(READ_DELAY);
void loop(){
// The 4 high bits are the channel, and the data is inverted
size_t bytes_read;
uint16_t buffer[I2S_DMA_BUF_LEN] = {0};
#ifdef AVERAGE_EVERY_N_SAMPLES
uint32_t read_counter = 0;
uint32_t averaged_reading = 0;
uint64_t read_sum = 0;
#endif
while(1){
i2s_read(I2S_NUM_0, &buffer, sizeof(buffer), &bytes_read, 15);
//Serial.printf("read %d Bytes\n", bytes_read);
for(int i = 0; i < bytes_read/2; ++i){
#ifdef PRINT_ALL_VALUES
//Serial.printf("[%d] = %d\n", i, buffer[i] & 0x0FFF); // Print with indexes
Serial.printf("Signal:%d ", buffer[i] & 0x0FFF); // Print compatible with Arduino Plotter
#endif
#ifdef AVERAGE_EVERY_N_SAMPLES
read_sum += buffer[i] & 0x0FFF;
++read_counter;
if(read_counter == AVERAGE_EVERY_N_SAMPLES){
averaged_reading = read_sum / AVERAGE_EVERY_N_SAMPLES;
//Serial.printf("averaged_reading = %d over %d samples\n", averaged_reading, read_counter); // Print with additional info
Serial.printf("Averaged_signal:%d", averaged_reading); // Print compatible with Arduino Plotter
read_counter = 0;
read_sum = 0;
}
#endif
#if defined(PRINT_ALL_VALUES) || defined (AVERAGE_EVERY_N_SAMPLES)
Serial.printf("\n");
#endif
} // for
} // while
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment