main/task_adc.c

Wed, 04 Oct 2023 11:28:49 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Wed, 04 Oct 2023 11:28:49 +0200
changeset 80
715785443a95
parent 76
0432d9147682
permissions
-rw-r--r--

Version 0.3.1. Remove obsolete files from spiffs filesystem. Removed obsolete wifi stations.conf file and functions. Removed obsolete user screens.

/**
 * @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);


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;
		    }
		}

		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);	// voltage in mV
			adc_state->Pressure[i].voltage = 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
		adc_oneshot_del_unit(adc1_handle);
		if (do_calibration) {
		    adc_cali_delete_scheme_line_fitting(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.
	    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");
	    }

	    adc_oneshot_del_unit(adc1_handle);
	    if (do_calibration) {
		adc_cali_delete_scheme_line_fitting(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;
    bool calibrated = false;

    adc_cali_line_fitting_config_t cali_config = {
	.unit_id = unit,
	.atten = atten,
	.bitwidth = ADC_BITWIDTH_DEFAULT,
    };
    esp_err_t 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;
}

mercurial