For brevity, here's the full file. I'm just calling sense_init while I work out some issues.
Code: Select all
#include "sense.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"
#include "esp_adc/adc_continuous.h"
#include "esp_adc/adc_filter.h"
#include "esp_adc/adc_monitor.h"
#include "esp_check.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "pins.h"
static const char TAG[] = "sense";
#define ADC_UNIT ADC_UNIT_1
#define ADC_CHANNEL ADC_CHANNEL_0
#define ADC_ATTEN ADC_ATTEN_DB_12
#define ADC_WIDTH ADC_BITWIDTH_12
#define ADC_BUFFER_SIZE 1024
/**
* @brief The scale is wrong when using DB12 attenuation
* I think this is an ESP IDF bug:
* https://github.com/espressif/esp-idf/issues/15876
*/
#define ADC_SCALE_CORRECTION_FACTOR 2
static adc_continuous_handle_t s_adc_cont_handle = NULL;
static adc_cali_handle_t s_adc_cali_handle = NULL;
static TaskHandle_t s_task_handle;
static bool adc_calibration_init(adc_unit_t unit, adc_channel_t channel,
adc_atten_t atten,
adc_cali_handle_t *out_handle) {
esp_err_t ret = ESP_FAIL;
bool calibrated = false;
// TODO
adc_cali_scheme_ver_t scheme_ver;
adc_cali_check_scheme(&scheme_ver);
#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
if (scheme_ver == ADC_CALI_SCHEME_VER_CURVE_FITTING) {
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_WIDTH,
};
ret = adc_cali_create_scheme_curve_fitting(&cali_config, out_handle);
if (ret == ESP_OK) {
calibrated = true;
}
}
}
#endif
#if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
if (scheme_ver == ADC_CALI_SCHEME_VER_LINE_FITTING) {
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_WIDTH,
};
ret = adc_cali_create_scheme_line_fitting(&cali_config, out_handle);
if (ret == ESP_OK) {
calibrated = true;
}
}
}
#endif
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;
}
static esp_err_t sense_adc_calib_init() {
if (adc_calibration_init(ADC_UNIT, ADC_CHANNEL, ADC_ATTEN,
&s_adc_cali_handle)) {
ESP_LOGI(TAG, "ADC calibration init success");
} else {
ESP_LOGE(TAG, "ADC calibration init failed");
}
return ESP_OK;
}
static bool IRAM_ATTR handle_conv_done(adc_continuous_handle_t handle,
const adc_continuous_evt_data_t *edata,
void *user_data) {
BaseType_t mustYield = pdFALSE;
// Notify that ADC continuous driver has done enough number of conversions
vTaskNotifyGiveFromISR(s_task_handle, &mustYield);
return (mustYield == pdTRUE);
}
static void sense_read_task(void *params) {
int i = 0;
while (1) {
uint8_t res[ADC_BUFFER_SIZE] = {0};
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
uint32_t size = sizeof(res) / sizeof(uint8_t);
esp_err_t err = adc_continuous_read(s_adc_cont_handle, res, size, &size, 1);
if (err != ESP_OK) {
ESP_LOGE(TAG, "adc_continuous_read failed");
continue;
}
if (i++ % 10 == 0) {
float sum = 0;
int voltage;
float min = 100, max = 0;
for (int i = 0; i < size; i += SOC_ADC_DIGI_RESULT_BYTES) {
adc_digi_output_data_t *data = (adc_digi_output_data_t *)&res[i];
// int raw_value = data->type2.data;
int raw_value = data->type1.data;
// ESP_LOGI(TAG, "raw = %d", raw_value);
if (adc_cali_raw_to_voltage(s_adc_cali_handle, raw_value, &voltage) ==
ESP_OK) {
float fvoltage = ADC_SCALE_CORRECTION_FACTOR * voltage / 1000.0;
if (fvoltage < min) {
min = fvoltage;
}
if (fvoltage > max) {
max = fvoltage;
}
sum += fvoltage;
}
}
ESP_LOGI(TAG, "Voltage: %f", sum / (size / SOC_ADC_DIGI_RESULT_BYTES));
ESP_LOGI(TAG, "min=%.2f, max=%.2f", min, max);
}
}
}
adc_monitor_handle_t s_monitor_handle = NULL;
static bool IRAM_ATTR monitor_cb(adc_monitor_handle_t handle,
const adc_monitor_evt_data_t *event_data,
void *user_data) {
ESP_LOGI(TAG, "monitor cb called");
return false;
BaseType_t mustYield = pdFALSE;
// Notify that ADC continuous driver has done enough number of conversions
vTaskNotifyGiveFromISR(s_task_handle, &mustYield);
return (mustYield == pdTRUE);
}
esp_err_t sense_init() {
ESP_LOGI(TAG, "sense_init");
// https://github.com/espressif/esp-idf/blob/v5.4/examples/peripherals/adc/continuous_read/main/continuous_read_main.c
// https://docs.espressif.com/projects/esp-idf/en/v5.4/esp32/api-reference/peripherals/adc_continuous.html?highlight=adc
// load the calibration data
ESP_RETURN_ON_ERROR(sense_adc_calib_init(), TAG,
"adc calibration init failed");
adc_continuous_handle_cfg_t adc_config = {
.flags.flush_pool = 1,
.max_store_buf_size = 1024, // in bytes
.conv_frame_size = 256 * SOC_ADC_DIGI_DATA_BYTES_PER_CONV, // in bytes
};
ESP_RETURN_ON_ERROR(
adc_continuous_new_handle(&adc_config, &s_adc_cont_handle), TAG,
"adc_continuous_new_handle failed");
adc_continuous_config_t cont_config = {
.pattern_num = 1,
.adc_pattern =
(adc_digi_pattern_config_t[1]){
(adc_digi_pattern_config_t){
.unit = ADC_UNIT,
.channel = ADC_CHANNEL,
.atten = ADC_ATTEN,
.bit_width = ADC_WIDTH,
},
},
.sample_freq_hz = SOC_ADC_SAMPLE_FREQ_THRES_LOW,
.conv_mode = ADC_CONV_SINGLE_UNIT_1,
.format = ADC_DIGI_OUTPUT_FORMAT_TYPE1,
};
ESP_RETURN_ON_ERROR(adc_continuous_config(s_adc_cont_handle, &cont_config),
TAG, "failed to cont config");
adc_continuous_evt_cbs_t cbs = {
.on_conv_done = handle_conv_done,
};
ESP_RETURN_ON_ERROR(
adc_continuous_register_event_callbacks(s_adc_cont_handle, &cbs, NULL),
TAG, "failed to register event callbacks");
adc_monitor_config_t adc_monitor_cfg = {
.adc_unit = ADC_UNIT,
.channel = ADC_CHANNEL,
.h_threshold = 100,
.l_threshold = -1,
};
ESP_RETURN_ON_ERROR(adc_new_continuous_monitor(s_adc_cont_handle,
&adc_monitor_cfg,
&s_monitor_handle),
TAG, "failed to init cont monitor");
adc_monitor_evt_cbs_t adc_monitor_cbs = {
.on_over_high_thresh = monitor_cb,
// .on_below_low_thresh = monitor_cb,
};
ESP_RETURN_ON_ERROR(adc_continuous_monitor_register_event_callbacks(
s_monitor_handle, &adc_monitor_cbs, NULL),
TAG, "failed to register monitor cbs");
ESP_RETURN_ON_ERROR(adc_continuous_monitor_enable(s_monitor_handle), TAG,
"failed to enable cont monitor");
ESP_RETURN_ON_ERROR(adc_continuous_start(s_adc_cont_handle), TAG,
"adc cont failed to start :<");
BaseType_t ret = xTaskCreate(sense_read_task, "sense_read_task", 8192, NULL,
1, &s_task_handle);
if (ret != pdPASS) {
ESP_LOGE(TAG, "Failed to create sense_read_task");
return ESP_FAIL;
}
ESP_LOGI(TAG, "sense_init done");
return ESP_OK;
}