main/task_adc.c

Tue, 03 Oct 2023 17:24:06 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Tue, 03 Oct 2023 17:24:06 +0200
changeset 77
15dc572a7fcb
parent 76
0432d9147682
permissions
-rw-r--r--

Version 0.3.0. Backported network code from experimental roaming project. Will now connect after reset to the strongest AP. Id the signal level drops below -67, extra scans are done to see for a better AP. Nothing is done yet. Removed config.conf file, all info is taken from the project menu and live tests. Better log the board type and send it via json mqtt. Send bssid and current channel too.

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