Tue, 26 Sep 2023 14:59:06 +0200
Migrated to isp-idf v5.1
/** * @file task_adc.c * @brief The FreeRTOS task to query the pressure sensors connected to ADC inputs. * The task will update the ADC_State structure. */ #include "config.h" #define DEFAULT_VREF 1093 ///< Use adc2_vref_to_gpio() to obtain a better estimate #define NO_OF_SAMPLES 128 ///< Multisampling #define PRESSURE_1 (CONFIG_PRESSURE_1) ///< ADC channel pressure sensor 1 #define PRESSURE_2 (CONFIG_PRESSURE_2) ///< ADC channel pressure sensor 2 #define PRESSURE_3 (CONFIG_PRESSURE_3) ///< ADC channel pressure sensor 3 #define BATT_CHANNEL (CONFIG_BATT_CHANNEL) ///< ADC channel half battery voltage static const char *TAG = "task_adc"; SemaphoreHandle_t xSemaphoreADC = NULL; ///< Semaphire ADC task EventGroupHandle_t xEventGroupADC; ///< Events ADC task ADC_State *adc_state; ///< Public state for other tasks bool do_calibration = false; const int TASK_ADC_REQUEST_PRESSURE = BIT0; ///< Request temperature measurements const int TASK_ADC_REQUEST_DONE = BIT1; ///< Request is completed static bool adc_calibration_init(adc_unit_t unit, adc_atten_t atten, adc_cali_handle_t *out_handle); static void adc_calibration_deinit(adc_cali_handle_t handle); void request_adc(void) { xEventGroupClearBits(xEventGroupADC, TASK_ADC_REQUEST_DONE); xEventGroupSetBits(xEventGroupADC, TASK_ADC_REQUEST_PRESSURE); } bool ready_adc(void) { if (xEventGroupGetBits(xEventGroupADC) & TASK_ADC_REQUEST_DONE) return true; return false; } /* * Task to read pressure sensors and battery voltage on request. */ void task_adc(void *pvParameter) { adc_cali_handle_t adc1_cali_handle = NULL; adc_unit_t channel; adc_oneshot_chan_cfg_t config_adc = { .bitwidth = ADC_BITWIDTH_DEFAULT, .atten = ADC_ATTEN_DB_0, }; ESP_LOGI(TAG, "Starting task ADC sensors"); adc_state = malloc(sizeof(ADC_State)); for (int i = 0; i < 3; i++) { adc_state->Pressure[i].valid = false; adc_state->Pressure[i].atten = ADC_ATTEN_DB_0; adc_state->Pressure[i].voltage = 0; adc_state->Pressure[i].error = ADC_ERR_NONE; } adc_state->Pressure[0].channel = PRESSURE_1; adc_state->Pressure[1].channel = PRESSURE_2; adc_state->Pressure[2].channel = PRESSURE_3; adc_state->Batt_voltage = 0; adc_state->Batt_error = ADC_ERR_NONE; /* event handler and event group for this task */ xEventGroupADC = xEventGroupCreate(); EventBits_t uxBits; /* * Task loop forever. */ while (1) { uxBits = xEventGroupWaitBits(xEventGroupADC, TASK_ADC_REQUEST_PRESSURE, pdFALSE, pdFALSE, portMAX_DELAY ); if (uxBits & TASK_ADC_REQUEST_PRESSURE) { ESP_LOGD(TAG, "Requested ADC readings"); int adc_reading, raw, tmp, voltage; adc_atten_t atten = ADC_ATTEN_DB_0; adc_oneshot_unit_handle_t adc1_handle; adc_oneshot_unit_init_cfg_t init_config1 = { .unit_id = ADC_UNIT_1, }; for (int i = 0; i < 3; i++) { ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &adc1_handle)); atten = config_adc.atten = ADC_ATTEN_DB_0, channel = adc_state->Pressure[i].channel; ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, channel, &config_adc)); adc_reading = 0; /* * Autoranging the ADC conversion */ while (1) { config_adc.bitwidth = ADC_BITWIDTH_DEFAULT; config_adc.atten = atten; adc_oneshot_config_channel(adc1_handle, channel, &config_adc); ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, channel, &raw)); // ESP_LOGI(TAG, "bottle %d channel %d raw %d atten %d", i, channel, raw, atten); if (atten == ADC_ATTEN_DB_0 && raw > 3700) atten = ADC_ATTEN_DB_2_5; else if (atten == ADC_ATTEN_DB_2_5 && raw > 3700) atten = ADC_ATTEN_DB_6; else if (atten == ADC_ATTEN_DB_6 && raw > 3700) atten = ADC_ATTEN_DB_11; else break; } /* * Now that he have the best attenuation, multisample the real value. */ for (int j = 0; j < NO_OF_SAMPLES; j++) { if (adc_oneshot_read(adc1_handle, channel, &tmp) == ESP_OK) { adc_reading += tmp; } else { adc_reading = -1; break; } } adc1_cali_handle = NULL; do_calibration = adc_calibration_init(ADC_UNIT_1, atten, &adc1_cali_handle); if (xSemaphoreTake(xSemaphoreADC, 10) == pdTRUE) { if (adc_reading < 0) { adc_state->Pressure[i].error = ADC_ERR_READ; adc_state->Pressure[i].voltage = 0; } else { adc_reading /= NO_OF_SAMPLES; adc_cali_raw_to_voltage(adc1_cali_handle, adc_reading, &voltage); adc_state->Pressure[i].voltage = voltage; //adc_state->Pressure[i].voltage = esp_adc_cal_raw_to_voltage(adc_reading, adc_chars); // voltage in mV // ESP_LOGI(TAG, "Voltage %d %d", i, voltage); adc_state->Pressure[i].error = ADC_ERR_NONE; } xSemaphoreGive(xSemaphoreADC); } else { ESP_LOGE(TAG, "Missed lock 1"); } ESP_LOGI(TAG, "Pressure %d raw: %4d, atten: %d, %.3f volt, error: %d", i, adc_reading, atten, (adc_state->Pressure[i].voltage / 1000.0), adc_state->Pressure[i].error); //Tear Down ESP_ERROR_CHECK(adc_oneshot_del_unit(adc1_handle)); if (do_calibration) { adc_calibration_deinit(adc1_cali_handle); } do_calibration = false; } /* * Read VDD by reading 1/2 VDD from a precision ladder. */ adc_reading = 0; atten = ADC_ATTEN_DB_6; // Don't use DB_11, it has a bad linearity. adc1_cali_handle = NULL; channel = (adc_unit_t)BATT_CHANNEL; ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &adc1_handle)); do_calibration = adc_calibration_init(ADC_UNIT_1, atten, &adc1_cali_handle); config_adc.bitwidth = ADC_BITWIDTH_DEFAULT; config_adc.atten = atten; adc_oneshot_config_channel(adc1_handle, (adc_unit_t)BATT_CHANNEL, &config_adc); ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, (adc_unit_t)BATT_CHANNEL, &raw)); for (int j = 0; j < NO_OF_SAMPLES; j++) { if (adc_oneshot_read(adc1_handle, channel, &tmp) == ESP_OK) { adc_reading += tmp; } else { adc_reading = -1; break; } } if (xSemaphoreTake(xSemaphoreADC, 10) == pdTRUE) { if (adc_reading < 0) { adc_state->Batt_voltage = 3.3; adc_state->Batt_error = ADC_ERR_READ; } else { adc_reading /= NO_OF_SAMPLES; adc_cali_raw_to_voltage(adc1_cali_handle, adc_reading, &voltage); /* Multiply by 2, measured on a ladder. */ adc_state->Batt_voltage = voltage * 2; // Chip supply voltage in mV adc_state->Batt_error = ADC_ERR_NONE; } xSemaphoreGive(xSemaphoreADC); } else { ESP_LOGE(TAG, "Missed lock 2"); } ESP_ERROR_CHECK(adc_oneshot_del_unit(adc1_handle)); if (do_calibration) { adc_calibration_deinit(adc1_cali_handle); } do_calibration = false; xEventGroupClearBits(xEventGroupADC, TASK_ADC_REQUEST_PRESSURE); xEventGroupSetBits(xEventGroupADC, TASK_ADC_REQUEST_DONE); #if 1 ESP_LOGI(TAG, "Battery raw: %4d, atten: %d %.3f volt, error: %d", adc_reading, atten, adc_state->Batt_voltage / 1000.0, adc_state->Batt_error); #endif } } } /*--------------------------------------------------------------- ADC Calibration ---------------------------------------------------------------*/ static bool adc_calibration_init(adc_unit_t unit, adc_atten_t atten, adc_cali_handle_t *out_handle) { adc_cali_handle_t handle = NULL; esp_err_t ret = ESP_FAIL; bool calibrated = false; if (!calibrated) { adc_cali_line_fitting_config_t cali_config = { .unit_id = unit, .atten = atten, .bitwidth = ADC_BITWIDTH_DEFAULT, }; ret = adc_cali_create_scheme_line_fitting(&cali_config, &handle); if (ret == ESP_OK) { calibrated = true; } } *out_handle = handle; if (ret == ESP_ERR_NOT_SUPPORTED || !calibrated) { ESP_LOGW(TAG, "eFuse not burnt, skip software calibration"); } else if (ret != ESP_OK) { ESP_LOGE(TAG, "Invalid arg or no memory"); } return calibrated; } static void adc_calibration_deinit(adc_cali_handle_t handle) { ESP_ERROR_CHECK(adc_cali_delete_scheme_line_fitting(handle)); }