-
Notifications
You must be signed in to change notification settings - Fork 7.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
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
- Loading branch information
1 parent
949aa27
commit 1b1c36e
Showing
1 changed file
with
108 additions
and
58 deletions.
There are no files selected for viewing
166 changes: 108 additions & 58 deletions
166
libraries/ESP32/examples/I2S/HiFreq_ADC/HiFreq_ADC.ino
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,83 +1,133 @@ | ||
/* | ||
* 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 | ||
} |