Skip to content

Commit

Permalink
Updated ADC Implementation to support ESP-IDF 5.0 (#89)
Browse files Browse the repository at this point in the history
* Added basic idf.py v5 support

* Added basic ADC implementation. The ADC is is init and calibrated. ADC Read impl remaining.

Completed ADC Read method implementation

Changed ADC Bitwidth to 12, and removed extra config files while adding
gitignore rules for them.

Updated LSA example

* Changes requested in PR #89

* Update ADC attenuation value to ADC_ATTEN_DB_12, as per ESP-IDF 5.1.2

* Updated ADC Attenuation

* Update ADC bitwidth length and fix I2C driver reconfiguration

* Fix I2C driver configuration logging
  • Loading branch information
SuperChamp234 authored Feb 1, 2024
1 parent 619695f commit c9180ac
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 84 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
### C ###
# SDK Config files
sdkconfig

# Build folder
build/

Expand Down
13 changes: 5 additions & 8 deletions examples/lsa/main/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,13 @@ static const char* TAG = "LSA_READINGS";
void app_main(void)
{
// enable line sensor
ESP_ERROR_CHECK(enable_line_sensor());

//Union containing line sensor readings
adc_handle_t adc_handle;
ESP_ERROR_CHECK(enable_line_sensor(&adc_handle));
line_sensor_array line_sensor_readings;

while(1)
while (1)
{
// get line sensor readings
line_sensor_readings = read_line_sensor();
line_sensor_readings = read_line_sensor(adc_handle);
for(int i = 0; i < 5; i++)
{
// constrain lsa readings between BLACK_MARGIN and WHITE_MARGIN
Expand All @@ -58,6 +56,5 @@ void app_main(void)

// log final lsa readings
ESP_LOGI(TAG, "LSA_0: %d \t LSA_1: %d \t LSA_2: %d \t LSA_3: %d \t LSA_4: %d",line_sensor_readings.adc_reading[0], line_sensor_readings.adc_reading[1], line_sensor_readings.adc_reading[2], line_sensor_readings.adc_reading[3], line_sensor_readings.adc_reading[4]);

}
}
}
40 changes: 21 additions & 19 deletions include/adc.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@
#include <stdio.h>
#include <stdlib.h>

#include "driver/adc.h"
#include "esp_adc_cal.h"
#include "esp_adc/adc_oneshot.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
Expand All @@ -39,36 +40,37 @@
#include "esp_err.h"
#include "pin_defs.h"

#define DEFAULT_VREF 1100
#define ADC_ATTEN ADC_ATTEN_DB_11
#define ADC_BITWIDTH_LEN ADC_BITWIDTH_12

/**
* @brief Configure width and attenuation of ADC 1
* @brief Structure representing an ADC object.
*
* @return esp_err_t - returns ESP_OK if 11dB attenuation and 12 bit width configured to ADC 1, else it returns ESP_ERR_INVALID_ARG.
**/
esp_err_t config_adc1();
* This structure holds the handles and calibration data for an ADC.
*/
typedef struct
{
adc_oneshot_unit_handle_t adc1_handle; /**< Handle for ADC1 oneshot unit. */
adc_cali_handle_t adc1_cali_handle[5]; /**< Array of calibration handles for ADC1. */
bool do_calib[5]; /**< Array indicating whether calibration should be performed for each channel. */
} adc_obj_t;

/**
* @brief Characterize ADC 1 using either Vref or Two Point
*
* @return esp_err_t
**/
esp_err_t characterize_adc1();
typedef adc_obj_t *adc_handle_t;

/**
* @brief call function config_adc1() and characterize_adc1().
*
* @return esp_err_t - returns ESP_OK if Configuration and Characterization of adc1 is successful, else it returns ESP_ERR_INVALID_ARG.
**/
esp_err_t enable_adc1();
esp_err_t enable_adc1(adc_obj_t** adc_obj);

/**
* @brief Read raw adc value of given adc pin.
*
* @param adc_pin One of the GPIO pin to which LSA is connected (36/39/35/34)
* @brief Reads the adc value from the GPIO(channel) specified.
*
* @return esp_err_t -returns raw reading of adc pin if lsa pin is passed to function, else it returns ESP_ERR_INVALID_ARG.
* @param adc_handle_t adc_handle - pointer to adc object.
* @param int gpio - gpio pin number of the channel to be read.
* @return int - returns the adc value read from the channel.
**/
int read_adc(int adc_pin);
int read_adc(adc_handle_t adc_handle, int gpio);

#endif
4 changes: 2 additions & 2 deletions include/lsa.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ typedef union line_sensor_array
* @return esp_err_t i.e it shows if adc is initialised successfully or not
**/
esp_err_t enable_line_sensor();
esp_err_t enable_line_sensor(adc_handle_t *adc_handle);

/**
* @brief Get multisampled line sensor array readings
Expand All @@ -62,6 +62,6 @@ esp_err_t enable_line_sensor();
* @return Returns a pointer to a struct that contains multisampled adc readings
for all the pins specified in lsa_pins array
**/
line_sensor_array read_line_sensor();
line_sensor_array read_line_sensor(adc_handle_t adc_handle);

#endif
158 changes: 108 additions & 50 deletions src/adc.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,82 +24,140 @@

#include "adc.h"

static const char *TAG_ADC = "adc";
static const char *TAG = "adc";
static const int adc_io[5] = {LSA_A0, LSA_A1, LSA_A2, LSA_A3, LSA_A4};

esp_err_t config_adc1()
esp_err_t config_adc1(adc_obj_t *adc_obj)
{
// Configure ADC to 12 bit width
CHECK(adc1_config_width(ADC_WIDTH_BIT_12));

// Configure ADC to 11dB attenuation
CHECK(adc1_config_channel_atten(ADC_CHANNEL_4, ADC_ATTEN_DB_11));
CHECK(adc1_config_channel_atten(ADC_CHANNEL_7, ADC_ATTEN_DB_11));
CHECK(adc1_config_channel_atten(ADC_CHANNEL_6, ADC_ATTEN_DB_11));
CHECK(adc1_config_channel_atten(ADC_CHANNEL_3, ADC_ATTEN_DB_11));
CHECK(adc1_config_channel_atten(ADC_CHANNEL_0, ADC_ATTEN_DB_11));

ESP_LOGI(TAG_ADC, "Configured ADC_1 to 12 Bit and 11dB attenuation");
adc_oneshot_chan_cfg_t config = {
.bitwidth = ADC_BITWIDTH_LEN,
.atten = ADC_ATTEN,
};
// Assign channels to each io in adc_io
for (int i = 0; i < sizeof(adc_io) / sizeof(adc_io[0]); i++)
{
adc_channel_t channel;
adc_unit_t unit;
ESP_ERROR_CHECK(adc_oneshot_io_to_channel(adc_io[i], &unit, &channel));
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc_obj->adc1_handle, channel, &config));
}

return ESP_OK;
}

esp_err_t characterize_adc1()
static bool adc_calibration_init(adc_unit_t unit, adc_channel_t channel, adc_atten_t atten, adc_cali_handle_t *out_handle)
{
esp_adc_cal_characteristics_t adc_chars;
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, DEFAULT_VREF, &adc_chars);
adc_cali_handle_t handle = NULL;
esp_err_t ret = ESP_FAIL;
bool calibrated = false;

if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP)
{
ESP_LOGI(TAG_ADC, "eFuse Two Point: Supported");
ESP_LOGI(TAG_ADC, "Characterized using Two Point Value");
#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
if (!calibrated) {
ESP_LOGI(TAG, "calibration scheme version is %s", "Curve Fitting");
adc_cali_curve_fitting_config_t cali_config = {
.unit_id = unit,
.chan = channel,
.atten = atten,
.bitwidth = ADC_BITWIDTH_LEN,
};
ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle);
if (ret == ESP_OK) {
calibrated = true;
}
}
else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF)
{
ESP_LOGI(TAG_ADC, "eFuse Vref: Supported");
ESP_LOGI(TAG_ADC, "Characterized using eFuse Vref");
#endif

#if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
if (!calibrated) {
ESP_LOGI(TAG, "calibration scheme version is %s", "Line Fitting");
adc_cali_line_fitting_config_t cali_config = {
.unit_id = unit,
.atten = atten,
.bitwidth = ADC_BITWIDTH_LEN,
};
ret = adc_cali_create_scheme_line_fitting(&cali_config, &handle);
if (ret == ESP_OK) {
calibrated = true;
}
}
else
#endif

*out_handle = handle;
if (ret == ESP_OK) {
ESP_LOGI(TAG, "Calibration Success");
} else if (ret == ESP_ERR_NOT_SUPPORTED || !calibrated) {
ESP_LOGW(TAG, "eFuse not burnt, skip software calibration");
} else {
ESP_LOGE(TAG, "Invalid arg or no memory");
}

return calibrated;
}

esp_err_t calib_init(adc_obj_t *adc_obj)
{
for (int i = 0; i < sizeof(adc_io) / sizeof(adc_io[0]); i++)
{
ESP_LOGI(TAG_ADC, "Characterized using Default Vref");
adc_channel_t channel;
adc_unit_t unit;
ESP_ERROR_CHECK(adc_oneshot_io_to_channel(adc_io[i], &unit, &channel));
adc_obj->do_calib[i] = adc_calibration_init(ADC_UNIT_1, channel, ADC_ATTEN, &adc_obj->adc1_cali_handle[i]);
}
return ESP_OK;
}

esp_err_t enable_adc1()
esp_err_t enable_adc1(adc_obj_t** adc_obj)
{
CHECK(config_adc1());
CHECK(characterize_adc1());

ESP_LOGI(TAG_ADC, "Configured and Characterized adc 1");
adc_obj_t *ret = NULL;
ret = calloc(1, sizeof(adc_obj_t));
ESP_ERROR_CHECK(ret == NULL ? ESP_ERR_NO_MEM : ESP_OK);
adc_oneshot_unit_init_cfg_t init_config1 = {
.unit_id = ADC_UNIT_1,
};
ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &ret->adc1_handle));
config_adc1(ret);
calib_init(ret);
*adc_obj = ret;

return ESP_OK;
}

int read_adc(int adc_pin)
int read_adc(adc_handle_t adc_handle, int gpio)
{
if (adc_pin == LSA_A0)
{
return adc1_get_raw(ADC_CHANNEL_4);
}
else if (adc_pin == LSA_A1)
{
return adc1_get_raw(ADC_CHANNEL_7);
}
else if (adc_pin == LSA_A2)
{
return adc1_get_raw(ADC_CHANNEL_6);
}
else if (adc_pin == LSA_A3)
int adc_reading = 0;
int voltage = 0;
adc_channel_t channel;
adc_unit_t unit;
ESP_ERROR_CHECK(adc_oneshot_io_to_channel(gpio, &unit, &channel));
ESP_ERROR_CHECK(adc_oneshot_read(adc_handle->adc1_handle, channel, &adc_reading));
int arr_loc = 0;
switch (gpio)
{
return adc1_get_raw(ADC_CHANNEL_3);
case LSA_A0:
arr_loc = 0;
break;
case LSA_A1:
arr_loc = 1;
break;
case LSA_A2:
arr_loc = 2;
break;
case LSA_A3:
arr_loc = 3;
break;
case LSA_A4:
arr_loc = 4;
break;
default:
break;
}
else if (adc_pin == LSA_A4)
if (adc_handle->do_calib[arr_loc])
{
return adc1_get_raw(ADC_CHANNEL_0);
ESP_ERROR_CHECK(adc_cali_raw_to_voltage(adc_handle->adc1_cali_handle[arr_loc], adc_reading, &voltage));
return voltage;
}
else
{
ESP_LOGE(TAG_ADC, "Invalid adc pin");
return ESP_FAIL;
return adc_reading;
}
}
10 changes: 5 additions & 5 deletions src/lsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@

static const int line_sensor_pins[5] = {LSA_A0, LSA_A1, LSA_A2, LSA_A3, LSA_A4};

esp_err_t enable_line_sensor()
esp_err_t enable_line_sensor(adc_handle_t *adc_handle)
{
esp_err_t err = enable_adc1(line_sensor_pins);
return err;
ESP_ERROR_CHECK(enable_adc1(adc_handle));
return ESP_OK;
}

line_sensor_array read_line_sensor()
line_sensor_array read_line_sensor(adc_handle_t adc_handle)
{
line_sensor_array line_sensor_readings;

Expand All @@ -45,7 +45,7 @@ line_sensor_array read_line_sensor()
{
for (int j = 0; j < 5; j++)
{
line_sensor_readings.adc_reading[j] = line_sensor_readings.adc_reading[j] + read_adc(line_sensor_pins[j]);
line_sensor_readings.adc_reading[j] = line_sensor_readings.adc_reading[j] + read_adc(adc_handle, line_sensor_pins[j]);
}
}

Expand Down

0 comments on commit c9180ac

Please sign in to comment.