Sampling multiple channels via ADC DMA
Posted: Sun Jan 03, 2021 1:28 pm
I have a problem using the pattern table in SARADC_SAR1_PATT_TAB1_REG. Whatever I specify as a pattern, the ESP32 only samples the channel that I have set in the i2s_set_adc_mode function. Does anyone have a working example on how to scan multiple channels with the DIG SAR ADC controller?
Sample code:
Sample code:
Code: Select all
void adc_handler(void* parameter) {
#define adc_tag "ADC_Task"
esp_log_level_set(adc_tag, ESP_LOG_DEBUG);
ESP_LOGI(adc_tag, "Starting the adc handler task.");
static i2s_config_t i2s_config = {
.mode = (i2s_mode_t) (I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN),
.sample_rate = adc_sample_rate,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = I2S_COMM_FORMAT_I2S_MSB,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 2,
.dma_buf_len = adc_dma_buf_len,
.use_apll = true
};
static adc_i2s_pattern_t adc_i2c_pattern[] = {
{ {.atten = ADC_ATTEN_DB_0, .bits = ADC_WIDTH_12Bit, .channel = ADC1_CHANNEL_0 } },
{ {.atten = ADC_ATTEN_DB_0, .bits = ADC_WIDTH_12Bit, .channel = ADC1_CHANNEL_3 } },
{ {.atten = ADC_ATTEN_DB_0, .bits = ADC_WIDTH_12Bit, .channel = ADC1_CHANNEL_4 } },
{ {.atten = ADC_ATTEN_DB_0, .bits = ADC_WIDTH_12Bit, .channel = ADC1_CHANNEL_6 } }
};
// install and start i2s driver
i2s_driver_install(i2s_num, &i2s_config, 2, &i2s_event_queue);
i2s_set_adc_mode(ADC_UNIT_1, ADC1_CHANNEL_MAX);
// config adc atten and width
ESP_LOGD(adc_tag, "adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_0db);\n");
adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_0db);
adc1_config_channel_atten(ADC1_CHANNEL_3, ADC_ATTEN_0db);
adc1_config_channel_atten(ADC1_CHANNEL_4, ADC_ATTEN_0db);
adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_0db);
ESP_LOGD(adc_tag, "adc1_config_width(ADC_WIDTH_12Bit);\n");
adc1_config_width(ADC_WIDTH_12Bit);
// Scan multiple channels.
ESP_LOGD(adc_tag, "SET_PERI_REG_BITS(0x%08x, 0x%02x, 3, 0x%02x);\n", SYSCON_SARADC_CTRL_REG, SYSCON_SARADC_SAR1_PATT_LEN, SYSCON_SARADC_SAR1_PATT_LEN_S);
SET_PERI_REG_BITS(SYSCON_SARADC_CTRL_REG, SYSCON_SARADC_SAR1_PATT_LEN, 3, SYSCON_SARADC_SAR1_PATT_LEN_S);
// This 32 bit register has 4 bytes for the first set of channels to scan.
// Each byte consists of:
// [7:4] Channel
// [3:2] Bit Width; 3=12bit, 2=11bit, 1=10bit, 0=9bit
// [1:0] Attenuation; 3=11dB, 2=6dB, 1=2.5dB, 0=0dB
ESP_LOGD(adc_tag, "WRITE_PERI_REG(0x%08x, 0x%02x, 0x%02x, 0x%02x, 0x%02x);\n",SYSCON_SARADC_SAR1_PATT_TAB1_REG,adc_i2c_pattern[0].val,adc_i2c_pattern[1].val,adc_i2c_pattern[2].val,adc_i2c_pattern[3].val);
WRITE_PERI_REG(SYSCON_SARADC_SAR1_PATT_TAB1_REG, adc_i2c_pattern);
// The raw ADC data is written to DMA in inverted form. Invert back.
ESP_LOGD(adc_tag, "SET_PERI_REG_MASK(0x%08x, 0x%08x);\n", SYSCON_SARADC_CTRL2_REG, SYSCON_SARADC_SAR1_INV);
SET_PERI_REG_MASK(SYSCON_SARADC_CTRL2_REG, SYSCON_SARADC_SAR1_INV);
// Delay for 5 seconds to allow the ADC to start-up
delay(5000);
ESP_LOGD(adc_tag, "i2s_adc_enable(0x%02x);\n", i2s_num);
i2s_adc_enable(i2s_num);
int i2s_read_len = adc_dma_buf_len * sizeof(uint16_t);
struct i2s_buffer_t {
unsigned int timestamp;
uint16_t buffer[adc_dma_buf_len];
} i2s_buffer;
while (1)
{
system_event_t event;
size_t bytes_read;
// vTaskDelayUntil(&xLastWakeTime, xDelay);
if (xQueueReceive(i2s_event_queue, &event, portMAX_DELAY) == pdPASS) {
if (event.event_id == 2) {
i2s_buffer.timestamp = esp_timer_get_time();
i2s_read(i2s_num, (char*) i2s_buffer.buffer, i2s_read_len, &bytes_read, portMAX_DELAY);
if (socket_adc_connected) {
if (digitalRead(boot) == LOW) ESP_LOGD(adc_tag, "Socket Connected, Timestamp : %i, [%04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x]", i2s_buffer.timestamp, i2s_buffer.buffer[0], i2s_buffer.buffer[1], i2s_buffer.buffer[2], i2s_buffer.buffer[3], i2s_buffer.buffer[4], i2s_buffer.buffer[5], i2s_buffer.buffer[6], i2s_buffer.buffer[7]);
unsigned int temp = i2s_buffer.timestamp;
ws_adc.binaryAll((uint8_t *)&temp, sizeof(temp));
} else {
if (digitalRead(boot) == LOW) ESP_LOGD(adc_tag, "Socket Not Connected, Timestamp : %i, [%04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x]", i2s_buffer.timestamp, i2s_buffer.buffer[0], i2s_buffer.buffer[1], i2s_buffer.buffer[2], i2s_buffer.buffer[3], i2s_buffer.buffer[4], i2s_buffer.buffer[5], i2s_buffer.buffer[6], i2s_buffer.buffer[7]);
}
}
}
}
vTaskDelete(NULL);
}