Commit 53de8b4b authored by Birte Kristina Friesel's avatar Birte Kristina Friesel
Browse files

add VEML6075 driver

parent 095e405c
Loading
Loading
Loading
Loading
+84 −0
Original line number Diff line number Diff line
/*
 * Copyright 2021 Daniel Friesel
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */
#ifndef VEML6075_H
#define VEML6075_H

#include <stdint.h>

/**
 * Driver for VEML6075 UV Sensor.
 */
class VEML6075 {
	private:
		VEML6075(const VEML6075 &copy);
		unsigned char const address;
		unsigned char txbuf[2];
		unsigned char rxbuf[2];

		/*
		 * Calibration data from <https://cdn.sparkfun.com/assets/3/9/d/4/1/designingveml6075.pdf>,
		 * used to remove the visible and infrared response from UVA / UVB readings.
		 */
		const float uva_a_coef = 2.22;
		const float uva_b_coef = 1.33;
		const float uvb_c_coef = 2.95;
		const float uvb_d_coef = 1.74;

		/*
		 * Datasheet values for counts → µW/cm² conversion at 50ms integration time.
		 * I'm not sure whether this is before or after adjusting for visible and IR response.
		 */
		const float uva_counts_per_uwcm2 = 0.93;
		const float uvb_counts_per_uwcm2 = 2.1;

		/*
		 * Responsivity for UV Index calculation from <https://cdn.sparkfun.com/assets/3/9/d/4/1/designingveml6075.pdf>.
		 * Used after visible/IR compensation.
		 */
		const float uva_uvi_response = 0.001461;
		const float uvb_uvi_response = 0.002591;

		bool readUVCounts(float *uva, float *uvb);

	public:
		/**
		 * Create a new VEML6075 object for the specified I2C address.
		 * This is a no-op; the sensor is not initialized. In its default
		 * configuration, it takes a light reading every 800ms and uses
		 * auto-ranging to select a suitable measurement range.
		 *
		 * @param addr I2C address of light sensor, default 0x4a
		 */
		VEML6075(unsigned char const addr = 0x10) : address(addr) {}

		/**
		 * Initialize VEML6075 to power on, normal mode, normal dynamic, 50ms
		 * integration time.
		 * @return true if initialization was successful.
		 */
		bool init();

		/**
		 * Read UVA/UVB irradiance.
		 * @param uva UVA irradiance [µW/cm²]
		 * @param uvb UVB irradiance [µW/cm²]
		 * @return true if readout was successful.
		 */
		bool readUV(float *uva, float *uvb);

		/**
		 * Read UVA/UVB Index. 0 is no UV, higher values indicate increased UV exposure.
		 * The overall UV index is mean(UVA Index, UV Index) == (UVA Index + UVB Index)/2.
		 * @param uva UVA Index
		 * @param uvb UVB Index
		 * @return true if readout was successful.
		 */
		bool readUVI(float *uva, float *uvb);
};

extern VEML6075 veml6075;

#endif
+18 −0
Original line number Diff line number Diff line
@@ -54,6 +54,9 @@
#ifdef CONFIG_driver_scd4x
#include "driver/scd4x.h"
#endif
#ifdef CONFIG_driver_veml6075
#include "driver/veml6075.h"
#endif

void loop(void)
{
@@ -195,6 +198,17 @@ void loop(void)
	kout.printf_float((100.0 * scd4x.rawHumidity) / 65536);
	kout << " %" << endl;
#endif

#ifdef CONFIG_driver_veml6075
	float uva, uvb;
	if (veml6075.readUV(&uva, &uvb)) {
		kout << "VEML6075 UVA: " << uva << " µW / cm²" << endl;
		kout << "VEML6075 UVB: " << uvb << " µW / cm²" << endl;
	}
	if (veml6075.readUVI(&uva, &uvb)) {
		kout << "VEML6075 UV Index: " << (uva + uvb)/2 << endl;
	}
#endif
}

int main(void)
@@ -299,6 +313,10 @@ int main(void)
	scd4x.start();
#endif

#ifdef CONFIG_driver_veml6075
	veml6075.init();
#endif

	arch.idle_loop();

	return 0;
+4 −0
Original line number Diff line number Diff line
@@ -95,6 +95,10 @@ config driver_scd4x
bool "Sensirion SCD4x CO2 Sensor"
depends on meta_driver_i2c

config driver_veml6075
bool "VEML6075 UV Sensor"
depends on meta_driver_i2c

config driver_sharp96
bool "sharp LS013B4DN 96x96px Transflective LC Display"
depends on ( arch_msp430fr5969lp || arch_msp430fr5994lp ) && meta_driver_spi

src/driver/veml6075.cc

0 → 100644
+82 −0
Original line number Diff line number Diff line
/*
 * Copyright 2020 Daniel Friesel
 *
 * SPDX-License-Identifier: BSD-2-Clause
 *
 * Driver for VEML6075 Ambient Light Sensor.
 */
#include "driver/veml6075.h"
#if defined(CONFIG_meta_driver_hardware_i2c)
#include "driver/i2c.h"
#elif defined(CONFIG_driver_softi2c)
#include "driver/soft_i2c.h"
#endif

bool VEML6075::init()
{
	txbuf[0] = 0x00;
	txbuf[1] = 0x00; // 50ms integration time, normal dynamic
	if (i2c.xmit(address, 2, txbuf, 0, rxbuf) != 0) {
		return false;
	}
	return true;
}

bool VEML6075::readUVCounts(float *uva, float *uvb)
{
	uint16_t uva_counts, uvb_counts, comp_visible, comp_ir;
	txbuf[0] = 0x07;
	if (i2c.xmit(address, 2, txbuf, 2, rxbuf) != 0) {
		return false;
	}
	uva_counts = ((uint16_t)rxbuf[1] << 8) + rxbuf[0];

	txbuf[0] = 0x09;
	if (i2c.xmit(address, 2, txbuf, 2, rxbuf) != 0) {
		return false;
	}
	uvb_counts = ((uint16_t)rxbuf[1] << 8) + rxbuf[0];

	txbuf[0] = 0x0a;
	if (i2c.xmit(address, 2, txbuf, 2, rxbuf) != 0) {
		return false;
	}
	comp_visible = ((uint16_t)rxbuf[1] << 8) + rxbuf[0];

	txbuf[0] = 0x0b;
	if (i2c.xmit(address, 2, txbuf, 2, rxbuf) != 0) {
		return false;
	}
	comp_ir = ((uint16_t)rxbuf[1] << 8) + rxbuf[0];

	*uva = uva_counts - uva_a_coef * comp_visible - uva_b_coef * comp_ir;
	*uvb = uvb_counts - uvb_c_coef * comp_visible - uvb_d_coef * comp_ir;

	return true;
}

bool VEML6075::readUV(float *uva, float *uvb)
{
	float uva_counts, uvb_counts;
	if (!readUVCounts(&uva_counts, &uvb_counts)) {
		return false;
	}

	*uva = uva_counts * uva_counts_per_uwcm2;
	*uvb = uvb_counts * uvb_counts_per_uwcm2;
	return true;
}

bool VEML6075::readUVI(float *uva, float *uvb)
{
	float uva_counts, uvb_counts;
	if (!readUVCounts(&uva_counts, &uvb_counts)) {
		return false;
	}

	*uva = uva_counts * uva_uvi_response;
	*uvb = uvb_counts * uvb_uvi_response;
	return true;
}

VEML6075 veml6075(0x10);