main/task_ina219.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 28
5872b972e553
child 34
40231d010111
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_ina219.c
 * @brief The FreeRTOS task to query the INA219 sensors.
 */


#include "config.h"


static const char		*TAG = "task_ina219";

SemaphoreHandle_t		xSemaphoreINA219 = NULL;	///< Semaphore INA219 task
EventGroupHandle_t		xEventGroupINA219;		///< Events INA219 task
INA219_State			*ina219_state;			///< Public state for other tasks

extern ina219_t			ina219_b_dev;
extern ina219_t			ina219_s_dev;

const int TASK_INA219_REQUEST_DONE = BIT0;			///< All requests are done.
const int TASK_INA219_REQUEST_POWER = BIT1;			///< Request power readings



void request_ina219(void)
{
    xEventGroupClearBits(xEventGroupINA219, TASK_INA219_REQUEST_DONE);
    xEventGroupSetBits(xEventGroupINA219, TASK_INA219_REQUEST_POWER);
}



bool ready_ina219(void)
{
    if (xEventGroupGetBits(xEventGroupINA219) & TASK_INA219_REQUEST_DONE)
	return true;
    return false;
}



/*
 * Task to read INA219 sensors on request.
 */
void task_ina219(void *pvParameter)
{
    float	bus_voltage, shunt_voltage;

    ESP_LOGI(TAG, "Starting task INA219 sda=%d scl=%d", CONFIG_I2C_MASTER_SDA, CONFIG_I2C_MASTER_SCL);
    ina219_state = malloc(sizeof(INA219_State));

    ina219_state->Battery.valid = false;
    ina219_state->Battery.fake = (ina219_b_dev.i2c_dev.addr == 0) ? true:false;
    ina219_state->Battery.address = ina219_b_dev.i2c_dev.addr;
    ina219_state->Battery.error = INA219_ERR_NONE;
    if (ina219_b_dev.i2c_dev.addr) {
	ESP_LOGI(TAG, "Configuring INA219 Battery");
	ESP_ERROR_CHECK(ina219_configure(&ina219_b_dev, INA219_BUS_RANGE_32V, INA219_GAIN_0_125,
            INA219_RES_12BIT_1S, INA219_RES_12BIT_1S, INA219_MODE_CONT_SHUNT_BUS));
    	ESP_LOGI(TAG, "Calibrating INA219 Battery");
    	ESP_ERROR_CHECK(ina219_calibrate(&ina219_b_dev, (float)I_MAX_CURRENT, (float)I_SHUNT_RESISTOR_MILLI_OHM / 1000.0f));
    }

    ina219_state->Solar.valid = false;
    ina219_state->Solar.fake = (ina219_s_dev.i2c_dev.addr == 0) ? true:false;
    ina219_state->Solar.address = ina219_s_dev.i2c_dev.addr;
    ina219_state->Solar.error = INA219_ERR_NONE;
    if (ina219_s_dev.i2c_dev.addr) {
        ESP_LOGI(TAG, "Configuring INA219 Solar");
        ESP_ERROR_CHECK(ina219_configure(&ina219_s_dev, INA219_BUS_RANGE_32V, INA219_GAIN_0_125,
            INA219_RES_12BIT_1S, INA219_RES_12BIT_1S, INA219_MODE_CONT_SHUNT_BUS));
        ESP_LOGI(TAG, "Calibrating INA219 Solar");
        ESP_ERROR_CHECK(ina219_calibrate(&ina219_s_dev, (float)I_MAX_CURRENT, (float)I_SHUNT_RESISTOR_MILLI_OHM / 1000.0f));
    }

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

    /*
     * Task loop forever.
     */
    ESP_LOGI(TAG, "Starting loop INA219 sensors 0x%02x %d, 0x%02x %d",
		    ina219_state->Battery.address, ina219_state->Battery.fake, ina219_state->Solar.address, ina219_state->Solar.fake);
    while (1) {

	uxBits = xEventGroupWaitBits(xEventGroupINA219, TASK_INA219_REQUEST_POWER, pdFALSE, pdFALSE, portMAX_DELAY );

	if (uxBits & TASK_INA219_REQUEST_POWER) {

	    /*
	     * Four scenario's:
	     * 1. Both sensors present, just use them.
	     * 2. Only battery sensor (test environment). Use it and fake
	     *    the solar chip as if it is charging.
	     * 3. Only solar sensor. Use scenario 4, but show measured values.
	     * 4. Fake everything.
	     */
	    if (! ina219_state->Battery.fake) {
		/*
		 * We run the ESP32-C3 in Power Save mode, Dynamic Frequency Scaling.
		 * This means a wrong current measurement (too high) unless we let the CPU
		 * rest for a while. The INA219 runs in continuous mode so we get the
		 * results during the vTaskDelay().
		 */
		ESP_ERROR_CHECK(ina219_configure(&ina219_b_dev, INA219_BUS_RANGE_32V, INA219_GAIN_0_125,
		    INA219_RES_12BIT_1S, INA219_RES_12BIT_1S, INA219_MODE_CONT_SHUNT_BUS));
		vTaskDelay(20 / portTICK_PERIOD_MS);
		ESP_ERROR_CHECK(ina219_get_bus_voltage(&ina219_b_dev, &bus_voltage));
		vTaskDelay(10 / portTICK_PERIOD_MS);
		ESP_ERROR_CHECK(ina219_get_shunt_voltage(&ina219_b_dev, &shunt_voltage));
		/*
		 * We don't call ina219_get_current(&ina219_b_dev, &current) because it takes
		 * a new measurement which usual gives the same results as the shunt voltage.
		 * So just calculate the current.
		 */
		ESP_ERROR_CHECK(ina219_configure(&ina219_b_dev, INA219_BUS_RANGE_32V, INA219_GAIN_0_125,
            	    INA219_RES_12BIT_1S, INA219_RES_12BIT_1S, INA219_MODE_POWER_DOWN));
		ESP_LOGI(TAG, "Battery VBUS: %.03f V, VSHUNT: %.02f mV, IBUS: %.01f mA", bus_voltage, shunt_voltage * 1000, shunt_voltage * 10000);
	    }
	    if (xSemaphoreTake(xSemaphoreINA219, 25) == pdTRUE) {
		if (ina219_state->Battery.fake) {
		    ina219_state->Battery.volts = 13.21;
		    if (ready_WiFi()) {
			ina219_state->Battery.shunt = 0.00785;
			ina219_state->Battery.current = 78.5;
		    } else {
			ina219_state->Battery.shunt = 0.00182;
			ina219_state->Battery.current = 18.2;
		    }
		} else {
		    ina219_state->Battery.volts = bus_voltage;
		    ina219_state->Battery.shunt = shunt_voltage;
		    ina219_state->Battery.current = shunt_voltage * 10000;
		}
		ina219_state->Battery.valid = true;
		xSemaphoreGive(xSemaphoreINA219);
	    }

	    if (! ina219_state->Solar.fake) {
		ESP_ERROR_CHECK(ina219_configure(&ina219_s_dev, INA219_BUS_RANGE_32V, INA219_GAIN_0_125,
                    INA219_RES_12BIT_1S, INA219_RES_12BIT_1S, INA219_MODE_CONT_SHUNT_BUS));
		vTaskDelay(20 / portTICK_PERIOD_MS);
                ESP_ERROR_CHECK(ina219_get_bus_voltage(&ina219_s_dev, &bus_voltage));
		vTaskDelay(10 / portTICK_PERIOD_MS);
                ESP_ERROR_CHECK(ina219_get_shunt_voltage(&ina219_s_dev, &shunt_voltage));
		ESP_ERROR_CHECK(ina219_configure(&ina219_s_dev, INA219_BUS_RANGE_32V, INA219_GAIN_0_125,
                    INA219_RES_12BIT_1S, INA219_RES_12BIT_1S, INA219_MODE_POWER_DOWN));
                ESP_LOGI(TAG, "  Solar VBUS: %.03f V, VSHUNT: %.02f mV, IBUS: %.01f mA", bus_voltage, shunt_voltage * 1000, shunt_voltage * 10000);
	    }
	    if (xSemaphoreTake(xSemaphoreINA219, 25) == pdTRUE) {
		if (! ina219_state->Solar.fake && ! ina219_state->Battery.fake) {
		    ina219_state->Solar.volts = bus_voltage;
                    ina219_state->Solar.shunt = shunt_voltage;
                    ina219_state->Solar.current = shunt_voltage * 10000;
		} else if (ina219_state->Solar.fake && ! ina219_state->Battery.fake) {
		    ina219_state->Solar.volts = ina219_state->Battery.volts + 0.78;
		    ina219_state->Solar.shunt = 0.02341;
		    ina219_state->Solar.current = 234.1;
		} else {
		    ina219_state->Solar.volts = 13.98;
		    ina219_state->Solar.shunt = 0.02341;
		    ina219_state->Solar.current = 234.1;
		}
		ina219_state->Solar.valid = true;

		/*
		 * Now update the outer state
		 */
		ina219_state->valid = (ina219_state->Battery.valid && ina219_state->Solar.valid);
		ina219_state->fake = (ina219_state->Battery.fake || ina219_state->Solar.fake);
		ina219_state->error = ina219_state->Battery.error;
		if (ina219_state->error == 0)
		    ina219_state->error = ina219_state->Solar.error;
		xSemaphoreGive(xSemaphoreINA219);
	    }

	    xEventGroupClearBits(xEventGroupINA219, TASK_INA219_REQUEST_POWER);
	    xEventGroupSetBits(xEventGroupINA219, TASK_INA219_REQUEST_DONE);
	}
    }
}

mercurial