main/task_apds9930.c

Sun, 16 Apr 2023 12:27:12 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Sun, 16 Apr 2023 12:27:12 +0200
changeset 30
7448b8dd4288
parent 21
df8564c9701e
child 37
50dbb626fbab
permissions
-rw-r--r--

Preparations for BLE GATT. Added extra time after INA219 is powered on before measurement. Reduced LEDC frequency to 60 Hz, that makes the LED lights less nervous. Hardware mod on output 4, now needs external pulldown resistor.

/**
 * @file task_apds9930.c
 * @brief The FreeRTOS task to query the APDS9930 sensor.
 */


#include "config.h"


static const char		*TAG = "task_apds9930";

SemaphoreHandle_t		xSemaphoreAPDS9930 = NULL;	///< Semaphore APDS9930 task
EventGroupHandle_t		xEventGroupAPDS9930;		///< Events APDS9930 task
APDS9930_State			*apds9930_state;		///< Public state for other tasks

float				ambient_light;
uint16_t			ch0 = 0;
uint16_t			ch1 = 1;
uint16_t			ALS_maxcount;			///< Maximum ADC value
uint16_t			ALS_mincount;			///< Threshold to increase gain


extern apds9930_t		apds9930_dev;

const int TASK_APDS9930_REQUEST_DONE = BIT0;			///< All requests are done.
const int TASK_APDS9930_REQUEST_LIGHT = BIT1;			///< Request Ambient Light



void request_apds9930(void)
{
    xEventGroupClearBits(xEventGroupAPDS9930, TASK_APDS9930_REQUEST_DONE);
    xEventGroupSetBits(xEventGroupAPDS9930, TASK_APDS9930_REQUEST_LIGHT);
}



bool ready_apds9930(void)
{
    if (xEventGroupGetBits(xEventGroupAPDS9930) & TASK_APDS9930_REQUEST_DONE)
	return true;
    return false;
}



/*
 * Task to read APDS9930 sensor on request.
 */
void task_apds9930(void *pvParameter)
{
    int		tries;
    esp_err_t	err = ESP_OK;
    uint8_t	l_gain, l_aglbit;

    ESP_LOGI(TAG, "Starting task APDS9930 sda=%d scl=%d", CONFIG_I2C_MASTER_SDA, CONFIG_I2C_MASTER_SCL);
    apds9930_state = malloc(sizeof(APDS9930_State));

    apds9930_state->valid = false;
    apds9930_state->fake = (apds9930_dev.i2c_dev.addr == 0) ? true:false;
    apds9930_state->address = apds9930_dev.i2c_dev.addr;
    apds9930_state->error = APDS9930_ERR_NONE;

    /* Gain settings are saved in NVS for quick startup. */
    l_gain   = nvsio_read_u8((char *)"l_gain");
    l_aglbit = nvsio_read_u8((char *)"l_aglbit");
    ESP_LOGI(TAG, "gain %d agl: %d", l_gain, l_aglbit);

    // Calculate these for auto gain scaling.
    ALS_maxcount = (256 - APDS9930_DEFAULT_ATIME) * 1024;
    ALS_mincount = ALS_maxcount / 64;

    /* event handler and event group for this task */
    xEventGroupAPDS9930 = xEventGroupCreate();
    EventBits_t uxBits;

    /*
     * Task loop forever.
     */
    ESP_LOGI(TAG, "Starting loop APDS9930 sensor 0x%02x %d", apds9930_state->address, apds9930_state->fake);
    while (1) {

	uxBits = xEventGroupWaitBits(xEventGroupAPDS9930, TASK_APDS9930_REQUEST_LIGHT, pdFALSE, pdFALSE, portMAX_DELAY );

	if (uxBits & TASK_APDS9930_REQUEST_LIGHT) {

	    if (! apds9930_state->fake) {
		/* Real sensor is present */
                if (l_gain > 3)
                    l_gain = 0;
		ESP_ERROR_CHECK(apds9930_enableLightSensor(&apds9930_dev, false));	// Does apds9930_enablePower() too.
		ESP_ERROR_CHECK(apds9930_disableProximitySensor(&apds9930_dev));
		ESP_ERROR_CHECK(apds9930_setAmbientLightGain(&apds9930_dev, l_gain));
		ESP_ERROR_CHECK(apds9930_setAmbientGainLevel(&apds9930_dev, l_aglbit));
		vTaskDelay(200 / portTICK_PERIOD_MS);
		tries = 6;
		err = ESP_OK;

		while (tries) {
		    if (err == ESP_OK) {
			err = apds9930_readCh0Light(&apds9930_dev, &ch0);
			if (err == ESP_OK) {
			    err = apds9930_readCh1Light(&apds9930_dev, &ch1);
			}
		    }
		    if (err != ESP_OK) {
			ESP_LOGE(TAG, "read APDS-9930 values error '%s'", esp_err_to_name(err));
			break;
		    }
		    ambient_light = apds9930_floatAmbientToLux(&apds9930_dev, ch0, ch1);

		    /*
		     * Check ranges
		     */
		    if (((ch0 == ALS_maxcount) || (ch1 == ALS_maxcount)) && ((l_gain > 0) || (l_aglbit == 0))) {
			/* Looks like an internal overflow */
			if (l_gain > 0) {
			    l_gain--;
			} else {
			    l_aglbit = 1;
			}
			apds9930_setAmbientLightGain(&apds9930_dev, l_gain);
			apds9930_setAmbientGainLevel(&apds9930_dev, l_aglbit);
			vTaskDelay(200 / portTICK_PERIOD_MS);
			ESP_LOGI(TAG, "Gain decreased to %d  AGL: %d", l_gain, l_aglbit);
		    } else if ((ch0 < ALS_mincount) && (ch1 < ALS_mincount) && (l_gain < 3)) {
			/* Looks like low resolution of the ADC. */
			if ((l_gain == 0) && l_aglbit) {
			    l_aglbit = 0;
			} else {
			    l_gain++;
			}
			apds9930_setAmbientLightGain(&apds9930_dev, l_gain);
                        apds9930_setAmbientGainLevel(&apds9930_dev, l_aglbit);
                        vTaskDelay(200 / portTICK_PERIOD_MS);
                        ESP_LOGI(TAG, "Gain increased to %d  AGL: %d", l_gain, l_aglbit);
		    } else {
			if ((ch0 == ALS_maxcount) || (ch1 == ALS_maxcount)) {
			    ambient_light = -1;
			} else if (l_aglbit) {
			    ambient_light = ambient_light / 0.1666;
			}
			nvsio_write_u8((char *)"l_gain", l_gain);
			nvsio_write_u8((char *)"l_aglbit", l_aglbit);
			ESP_LOGI(TAG, "Ambient: %.2f  Ch0: %d  Ch1: %d  Gain: %d  AGL: %d", ambient_light, ch0, ch1, l_gain, l_aglbit);
			break;
		    }
		    tries--;
		}
		if (tries == 0) {
		    ESP_LOGW(TAG, "tries = 0");
		}
		apds9930_disableLightSensor(&apds9930_dev);
		apds9930_disablePower(&apds9930_dev);

		if (xSemaphoreTake(xSemaphoreAPDS9930, 25) == pdTRUE) {
		    if (err == ESP_OK) {
			apds9930_state->error = APDS9930_ERR_NONE;
			apds9930_state->valid = true;
			apds9930_state->ambient_light = ambient_light;
			apds9930_state->gain = l_gain;
			apds9930_state->aglbit = l_aglbit;
		    } else {
			apds9930_state->error = APDS9930_ERR_READ;
			apds9930_state->valid = false;
			apds9930_state->ambient_light = 12.34;
			apds9930_state->gain = 2;
			apds9930_state->aglbit = 0;
		    }
		    xSemaphoreGive(xSemaphoreAPDS9930);
		}
	    } else {
		/* Use fake values */
		if (xSemaphoreTake(xSemaphoreAPDS9930, 25) == pdTRUE) {
		    apds9930_state->error = APDS9930_ERR_NONE;
                    apds9930_state->valid = true;
		    apds9930_state->ambient_light = 12.34;
		    apds9930_state->gain = 2;
		    apds9930_state->aglbit = 0;
		    xSemaphoreGive(xSemaphoreAPDS9930);
		}
	    }

	    xEventGroupClearBits(xEventGroupAPDS9930, TASK_APDS9930_REQUEST_LIGHT);
	    xEventGroupSetBits(xEventGroupAPDS9930, TASK_APDS9930_REQUEST_DONE);
#if 0
	    ESP_LOGI(TAG, "  Light: %.2f, gain: %d, error: %d", apds9930_state->ambient_light, apds9930_state->gain, apds9930_state->error);
#endif
	}
    }
}

mercurial