Skip to content

ADC drivers for esp32 #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions adc_esp/adc_esp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#include "adc_esp.h"
#include <string.h>

// Calibration characteristics
static esp_adc_cal_characteristics_t adc_chars;

adc_bits_width_t adc2_width = ADC_WIDTH_BIT_12; // Since ADC2 can't be configured directly, we set the width here

esp_err_t esp32_adc_init(ESP32_ADC_Config* config) {
esp_err_t ret = ESP_OK;

// Configure ADC unit
if (config->unit == ADC_UNIT_1) {
ret = adc1_config_width(config->width);
if (ret != ESP_OK) return ret;
}
else if (config->unit == ADC_UNIT_2) {
adc2_width = config->width;
} else {
return ESP_ERR_INVALID_ARG;
}

// Characterize ADC for calibration
esp_adc_cal_characterize(config->unit, config->attenuation,
config->width, config->vref, &adc_chars);

return ESP_OK;
}

esp_err_t esp32_adc_config_channel(adc_unit_t unit, adc_channel_t channel, adc_atten_t attenuation) {
if (unit == ADC_UNIT_1) {
return adc1_config_channel_atten((adc1_channel_t)channel, attenuation);
} else if (unit == ADC_UNIT_2) {
return adc2_config_channel_atten((adc2_channel_t)channel, attenuation);
}
return ESP_ERR_INVALID_ARG;
}

int esp32_adc_read_voltage(adc_unit_t unit, adc_channel_t channel, ESP32_ADC_Config* config) {
int raw_value = esp32_adc_read_raw(unit, channel);
if (raw_value < 0) return -1;

// Convert raw value to voltage
uint32_t voltage = esp_adc_cal_raw_to_voltage(raw_value, &adc_chars);
return voltage;
}

int esp32_adc_read_raw(adc_unit_t unit, adc_channel_t channel) {
int raw_value;

if (unit == ADC_UNIT_1) {
// Configure the channel attenuation if not already done
// This should ideally be done during initialization for each channel
adc1_channel_t adc1_channel = (adc1_channel_t)channel;
raw_value = adc1_get_raw(adc1_channel);
} else if (unit == ADC_UNIT_2) {
// ADC2 can't be used when Wi-Fi is active
esp_err_t ret = adc2_get_raw((adc2_channel_t)channel, adc2_width, &raw_value);
if (ret != ESP_OK) {
return -1;
}
} else {
return -1; // Invalid ADC unit
}

return raw_value;
}

float esp32_adc_normalize(int raw_value, ESP32_ADC_Config* config) {
if (raw_value < 0) return -1.0f;

int max_value;
switch (config->width) {
case ADC_WIDTH_BIT_9: max_value = 511; break;
case ADC_WIDTH_BIT_10: max_value = 1023; break;
case ADC_WIDTH_BIT_11: max_value = 2047; break;
case ADC_WIDTH_BIT_12: max_value = 4095; break;
default: return -1.0f;
}

return (float)raw_value / max_value;
}

esp_err_t esp32_adc_gpio_to_channel(int gpio_pin, adc_unit_t* unit, adc_channel_t* channel) {
// Map GPIO pin to ADC channel
// ADC1 channels
if (gpio_pin == 36) { *unit = ADC_UNIT_1; *channel = (adc_channel_t)ADC1_CHANNEL_0; return ESP_OK; }
if (gpio_pin == 37) { *unit = ADC_UNIT_1; *channel = (adc_channel_t)ADC1_CHANNEL_1; return ESP_OK; }
if (gpio_pin == 38) { *unit = ADC_UNIT_1; *channel = (adc_channel_t)ADC1_CHANNEL_2; return ESP_OK; }
if (gpio_pin == 39) { *unit = ADC_UNIT_1; *channel = (adc_channel_t)ADC1_CHANNEL_3; return ESP_OK; }
if (gpio_pin == 32) { *unit = ADC_UNIT_1; *channel = (adc_channel_t)ADC1_CHANNEL_4; return ESP_OK; }
if (gpio_pin == 33) { *unit = ADC_UNIT_1; *channel = (adc_channel_t)ADC1_CHANNEL_5; return ESP_OK; }
if (gpio_pin == 34) { *unit = ADC_UNIT_1; *channel = (adc_channel_t)ADC1_CHANNEL_6; return ESP_OK; }
if (gpio_pin == 35) { *unit = ADC_UNIT_1; *channel = (adc_channel_t)ADC1_CHANNEL_7; return ESP_OK; }

// ADC2 channels
if (gpio_pin == 4) { *unit = ADC_UNIT_2; *channel = (adc_channel_t)ADC2_CHANNEL_0; return ESP_OK; }
if (gpio_pin == 0) { *unit = ADC_UNIT_2; *channel = (adc_channel_t)ADC2_CHANNEL_1; return ESP_OK; }
if (gpio_pin == 2) { *unit = ADC_UNIT_2; *channel = (adc_channel_t)ADC2_CHANNEL_2; return ESP_OK; }
if (gpio_pin == 15) { *unit = ADC_UNIT_2; *channel = (adc_channel_t)ADC2_CHANNEL_3; return ESP_OK; }
if (gpio_pin == 13) { *unit = ADC_UNIT_2; *channel = (adc_channel_t)ADC2_CHANNEL_4; return ESP_OK; }
if (gpio_pin == 12) { *unit = ADC_UNIT_2; *channel = (adc_channel_t)ADC2_CHANNEL_5; return ESP_OK; }
if (gpio_pin == 14) { *unit = ADC_UNIT_2; *channel = (adc_channel_t)ADC2_CHANNEL_6; return ESP_OK; }
if (gpio_pin == 27) { *unit = ADC_UNIT_2; *channel = (adc_channel_t)ADC2_CHANNEL_7; return ESP_OK; }
if (gpio_pin == 25) { *unit = ADC_UNIT_2; *channel = (adc_channel_t)ADC2_CHANNEL_8; return ESP_OK; }
if (gpio_pin == 26) { *unit = ADC_UNIT_2; *channel = (adc_channel_t)ADC2_CHANNEL_9; return ESP_OK; }

return ESP_ERR_NOT_FOUND;
}
65 changes: 65 additions & 0 deletions adc_esp/adc_esp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#ifndef ESP32_ADC_H
#define ESP32_ADC_H

#include <driver/adc.h>
#include <esp_adc_cal.h>

// ADC configuration struct
typedef struct {
adc_unit_t unit; // ADC unit (ADC1 or ADC2)
adc_bits_width_t width; // ADC bit width (9-12 bits)
adc_atten_t attenuation; // ADC attenuation
uint32_t vref; // Reference voltage in mV (typically 1100mV)
} ESP32_ADC_Config;

/**
* Initialize ADC with the given configuration
* @param config ADC configuration
* @return ESP_OK on success, error code otherwise
*/
esp_err_t esp32_adc_init(ESP32_ADC_Config* config);

/**
* Configure a specific ADC channel with the given attenuation
* @param unit ADC unit (ADC1 or ADC2)
* @param channel ADC channel
* @param attenuation Attenuation level
* @return ESP_OK on success, error code otherwise
*/
esp_err_t esp32_adc_config_channel(adc_unit_t unit, adc_channel_t channel, adc_atten_t attenuation);

/**
* Read ADC value from the specified channel
* @param unit ADC unit (ADC1 or ADC2)
* @param channel ADC channel
* @param config ADC configuration used for calibration
* @return Voltage in millivolts, or -1 on error
*/
int esp32_adc_read_voltage(adc_unit_t unit, adc_channel_t channel, ESP32_ADC_Config* config);

/**
* Read raw ADC value from the specified channel
* @param unit ADC unit (ADC1 or ADC2)
* @param channel ADC channel
* @return Raw ADC value (0-4095 for 12-bit), or -1 on error
*/
int esp32_adc_read_raw(adc_unit_t unit, adc_channel_t channel);

/**
* Convert raw ADC value to normalized float (0.0-1.0)
* @param raw_value Raw ADC value
* @param config ADC configuration for bit width
* @return Normalized value between 0.0 and 1.0
*/
float esp32_adc_normalize(int raw_value, ESP32_ADC_Config* config);

/**
* Get ADC channel for a GPIO pin
* @param gpio_pin GPIO pin number
* @param unit Pointer to store the ADC unit
* @param channel Pointer to store the ADC channel
* @return ESP_OK if mapping successful, error code otherwise
*/
esp_err_t esp32_adc_gpio_to_channel(int gpio_pin, adc_unit_t* unit, adc_channel_t* channel);

#endif // ESP32_ADC_H