main/task_adc.c

Sun, 13 Oct 2019 19:27:12 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Sun, 13 Oct 2019 19:27:12 +0200
changeset 12
7dc9003f86a8
parent 0
88d965579617
child 37
358bbd5b608e
permissions
-rw-r--r--

ADC1 source code cleanup. Switched to 12 bit resolution again. Multisample set to 128. Improved adc-state structure locking. Improved ADC read error detection. DS18B20 extra error logging. MQTT better publish counter locking.

/**
 * @file task_adc.c
 * @brief The FreeRTOS task to query the pressure sensors on 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)
#define PRESSURE_2      	(CONFIG_PRESSURE_2)
#define PRESSURE_3      	(CONFIG_PRESSURE_3)
#define BATT_CHANNEL		(CONFIG_BATT_CHANNEL)
#define	BATT_ACTOR		(CONFIG_BATT_ACTOR)


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

const int TASK_ADC_REQUEST_PRESSURE = BIT0;			///< Request temperature measurements
const int TASK_ADC_REQUEST_DONE = BIT1;				///< Request is completed



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)
{
    int		i, adc_reading;
    adc_atten_t	atten = ADC_ATTEN_DB_0;

    ESP_LOGI(TAG, "Starting task ADC sensors");
    adc_state = malloc(sizeof(ADC_State));
    for (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;

    //Characterize ADC
    esp_adc_cal_characteristics_t *adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t));    

    /* 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_LOGI(TAG, "Requested ADC readings");
	    adc1_config_width(ADC_WIDTH_BIT_12);

	    for (i = 0; i < 3; i++) {
		adc_reading = 0;
		atten = ADC_ATTEN_DB_0;
		
		/*
		 * Autoranging the ADC conversion
		 */
		while (1) {
		    esp_adc_cal_characterize(ADC_UNIT_1, atten, ADC_WIDTH_BIT_12, DEFAULT_VREF, adc_chars);
                    adc1_config_channel_atten((adc1_channel_t)adc_state->Pressure[i].channel, atten);
		    int raw = adc1_get_raw((adc1_channel_t)adc_state->Pressure[i].channel);
		    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++) {
			int tmp = adc1_get_raw((adc1_channel_t)adc_state->Pressure[i].channel);
			if (tmp < 0) {
			    adc_reading = -1;
			    break;
			}
			adc_reading += tmp;
		}
		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_state->Pressure[i].voltage = esp_adc_cal_raw_to_voltage(adc_reading, adc_chars); // voltage in mV
			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);
	    }

	    /*
	     * 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.
	    esp_adc_cal_characterize(ADC_UNIT_1, atten, ADC_WIDTH_BIT_12, DEFAULT_VREF, adc_chars);
            adc1_config_channel_atten((adc1_channel_t)BATT_CHANNEL, atten);
	    for (int j = 0; j < NO_OF_SAMPLES; j++) {
            	int tmp = adc1_get_raw((adc1_channel_t)BATT_CHANNEL);
		if (tmp < 0) {
                    adc_reading = -1;
                    break;
                }
                adc_reading += tmp;
            }
	    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_state->Batt_voltage = esp_adc_cal_raw_to_voltage(adc_reading, adc_chars) * 2; // Chip supply voltage in mV
                    adc_state->Batt_error = ADC_ERR_NONE;
	    	}
		xSemaphoreGive(xSemaphoreADC);
	    } else {
		ESP_LOGE(TAG, "Missed lock 2");
	    }

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

mercurial