samples: sensor: veml6046: add attribution test application
- Test all attribute combinations of Vishay RGBIR color sensor VEML6046.
- Print OVERFLOW in case of saturation of sensor.
- This small program is intended to be helping when finding appropriate
attributes for an application of the sensor.
Signed-off-by: Andreas Klinger <ak@it-klinger.de>
diff --git a/samples/sensor/veml6046/CMakeLists.txt b/samples/sensor/veml6046/CMakeLists.txt
new file mode 100644
index 0000000..4aa3e0a
--- /dev/null
+++ b/samples/sensor/veml6046/CMakeLists.txt
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: Apache-2.0
+
+cmake_minimum_required(VERSION 3.20.0)
+find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
+project(veml6046)
+
+target_sources(app PRIVATE src/main.c)
diff --git a/samples/sensor/veml6046/README.rst b/samples/sensor/veml6046/README.rst
new file mode 100644
index 0000000..12f34ed
--- /dev/null
+++ b/samples/sensor/veml6046/README.rst
@@ -0,0 +1,61 @@
+.. zephyr:code-sample:: veml6046
+ :name: VEML6046 RGBIR Color Sensor
+ :relevant-api: sensor_interface
+
+ Get red, green, blue and IR light data from a VEML6046 sensor (polling
+ mode).
+
+Overview
+********
+
+ This sample measures the red, green, blue and IR light for all possible
+ combinations of sensor attributes. They are:
+
+ - integration time
+ - effective photodiode size
+ - gain
+
+ These attributes can be used to put the sensor in an optimal working area.
+ When the light value reaches the maximum raw value (0xFFFF), an error is
+ returned to indicate the out of bounds situation to the user program.
+ With this program the raw value is also printed out together with the
+ attributes to be able to select good attribute values.
+ Interrupt and trigger modes are not supported so far, but planned for future
+ development.
+
+Requirements
+************
+
+ This sample uses the VEML6046 sensor controlled using the I2C-2 interface of
+ the Olimex-STM32-E407 board on Feather connector pins PF0 and PF1.
+
+References
+**********
+
+ - VEML6046: https://www.vishay.com/docs/80173/veml6046x00.pdf
+ - Application note: https://www.vishay.com/docs/80410/designingveml6046x00.pdf
+
+Building and Running
+********************
+
+ This project outputs sensor data to the console. It requires a VEML6046
+ sensor to be connected to the desired board.
+
+ .. zephyr-app-commands::
+ :zephyr-app: samples/sensor/veml6046/
+ :goals: build flash
+ :board: olimex_stm32_e407
+
+
+Sample Output
+=============
+
+ .. code-block:: console
+
+ Test all attributes for a good guess of attribute usage away of saturation.
+ Red: 68 lx ( 51) green: 68 lx ( 84) blue: 68 lx ( 51) IR: 68 lx ( 27) it: 0 pdd: 0 gain: 0 --
+ Red: 121 lx ( 181) green: 121 lx ( 347) blue: 121 lx ( 240) IR: 121 lx ( 53) it: 0 pdd: 0 gain: 1 --
+ Red: 215 lx ( 106) green: 215 lx ( 226) blue: 215 lx ( 160) IR: 215 lx ( 19) it: 0 pdd: 0 gain: 2 --
+ Red: 201 lx ( 75) green: 201 lx ( 156) blue: 201 lx ( 112) IR: 201 lx ( 14) it: 0 pdd: 0 gain: 3 --
+ [...]
+ Test finished.
diff --git a/samples/sensor/veml6046/boards/olimex_stm32_e407.overlay b/samples/sensor/veml6046/boards/olimex_stm32_e407.overlay
new file mode 100644
index 0000000..1960223
--- /dev/null
+++ b/samples/sensor/veml6046/boards/olimex_stm32_e407.overlay
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2025 Andreas Klinger
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+&pinctrl {
+ i2c2_sda_pf0: i2c2_sda_pf0 {
+ pinmux = < 0xa04 >;
+ bias-pull-up;
+ drive-open-drain;
+ };
+ i2c2_scl_pf1: i2c2_scl_pf1 {
+ pinmux = < 0xa24 >;
+ bias-pull-up;
+ drive-open-drain;
+ };
+};
+
+&i2c2 {
+ pinctrl-0 = < &i2c2_scl_pf1 &i2c2_sda_pf0 >;
+ pinctrl-names = "default";
+ status = "okay";
+
+ rgbir: rgbir@29 {
+ compatible = "vishay,veml6046";
+ reg = <0x29>;
+ };
+};
diff --git a/samples/sensor/veml6046/prj.conf b/samples/sensor/veml6046/prj.conf
new file mode 100644
index 0000000..42fcd3c
--- /dev/null
+++ b/samples/sensor/veml6046/prj.conf
@@ -0,0 +1 @@
+CONFIG_SENSOR=y
diff --git a/samples/sensor/veml6046/sample.yaml b/samples/sensor/veml6046/sample.yaml
new file mode 100644
index 0000000..fe27043
--- /dev/null
+++ b/samples/sensor/veml6046/sample.yaml
@@ -0,0 +1,10 @@
+sample:
+ name: VEML6046 Sensor Sample
+tests:
+ sample.sensor.veml6046:
+ harness: sensor
+ platform_allow: olimex_stm32_e407
+ integration_platforms:
+ - olimex_stm32_e407
+ tags: sensors
+ filter: dt_compat_enabled("vishay,veml6046")
diff --git a/samples/sensor/veml6046/src/main.c b/samples/sensor/veml6046/src/main.c
new file mode 100644
index 0000000..aec830e
--- /dev/null
+++ b/samples/sensor/veml6046/src/main.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2025 Andreas Klinger
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr/kernel.h>
+
+#include <zephyr/sys/printk.h>
+#include <stdio.h>
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/sensor.h>
+
+#include <zephyr/drivers/sensor/veml6046.h>
+
+static void read_with_attr(const struct device *dev, int it, int pdd, int gain)
+{
+ int ret;
+ struct sensor_value red, green, blue, ir;
+ struct sensor_value red_raw, green_raw, blue_raw, ir_raw;
+ struct sensor_value sen;
+ char result[10];
+
+ sen.val2 = 0;
+
+ sen.val1 = it;
+ ret = sensor_attr_set(dev, SENSOR_CHAN_LIGHT,
+ (enum sensor_attribute)SENSOR_ATTR_VEML6046_IT, &sen);
+ if (ret) {
+ printf("Failed to set it attribute ret: %d\n", ret);
+ }
+ sen.val1 = pdd;
+ ret = sensor_attr_set(dev, SENSOR_CHAN_LIGHT,
+ (enum sensor_attribute)SENSOR_ATTR_VEML6046_PDD, &sen);
+ if (ret) {
+ printf("Failed to set pdd attribute ret: %d\n", ret);
+ }
+ sen.val1 = gain;
+ ret = sensor_attr_set(dev, SENSOR_CHAN_LIGHT,
+ (enum sensor_attribute)SENSOR_ATTR_VEML6046_GAIN, &sen);
+ if (ret) {
+ printf("Failed to set gain attribute ret: %d\n", ret);
+ }
+
+ ret = sensor_sample_fetch(dev);
+ if ((ret < 0) && (ret != -E2BIG)) {
+ printf("sample update error. ret: %d\n", ret);
+ }
+
+ sensor_channel_get(dev, SENSOR_CHAN_RED, &red);
+ sensor_channel_get(dev, (enum sensor_channel)SENSOR_CHAN_VEML6046_RED_RAW_COUNTS,
+ &red_raw);
+
+ sensor_channel_get(dev, SENSOR_CHAN_GREEN, &green);
+ sensor_channel_get(dev, (enum sensor_channel)SENSOR_CHAN_VEML6046_GREEN_RAW_COUNTS,
+ &green_raw);
+
+ sensor_channel_get(dev, SENSOR_CHAN_BLUE, &blue);
+ sensor_channel_get(dev, (enum sensor_channel)SENSOR_CHAN_VEML6046_BLUE_RAW_COUNTS,
+ &blue_raw);
+
+ sensor_channel_get(dev, SENSOR_CHAN_IR, &ir);
+ sensor_channel_get(dev, (enum sensor_channel)SENSOR_CHAN_VEML6046_IR_RAW_COUNTS,
+ &ir_raw);
+
+ if (ret == -E2BIG) {
+ snprintf(result, sizeof(result), "OVERFLOW");
+ } else if (ret) {
+ snprintf(result, sizeof(result), "ERROR");
+ } else {
+ snprintf(result, sizeof(result), "");
+ }
+
+ printf("Red: %6d lx (%6d) green: %6d lx (%6d) "
+ "blue: %6d lx (%6d) IR: %6d lx (%6d) "
+ " it: %d pdd: %d gain: %d -- %s\n",
+ red.val1, red_raw.val1,
+ green.val1, green_raw.val1,
+ blue.val1, blue_raw.val1,
+ ir.val1, ir_raw.val1,
+ it, pdd, gain,
+ result);
+}
+
+static void read_with_all_attr(const struct device *dev)
+{
+ for (int it = VEML6046_IT_3_125; it <= VEML6046_IT_400; it++) {
+ for (int pdd = VEML6046_SIZE_2_2; pdd <= VEML6046_SIZE_1_2; pdd++) {
+ for (int gain = VEML6046_GAIN_1; gain <= VEML6046_GAIN_0_5; gain++) {
+ read_with_attr(dev, it, pdd, gain);
+ }
+ }
+ }
+}
+
+int main(void)
+{
+ const struct device *const veml = DEVICE_DT_GET(DT_NODELABEL(rgbir));
+
+ if (!device_is_ready(veml)) {
+ printk("sensor: device not ready.\n");
+ return 0;
+ }
+
+ printf("Test all attributes for a good guess of attribute usage away of saturation.\n");
+ read_with_all_attr(veml);
+ printf("Test finished.\n");
+
+ return 0;
+}