From 4089e35805f9610682eb425250fb4a362e3fce80 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Wed, 31 May 2023 19:46:08 +0200 Subject: [PATCH] drivers/sensors: add bh1749nuc color sensor support Add support for the BH1749NUC I2C color sensor. Currently, the interrupt pin is not supported. --- drivers/sensors/Kconfig | 7 + drivers/sensors/Make.defs | 4 + drivers/sensors/bh1749nuc.c | 428 ++++++++++++++++++++++++++++++ include/nuttx/sensors/bh1749nuc.h | 86 ++++++ 4 files changed, 525 insertions(+) create mode 100644 drivers/sensors/bh1749nuc.c create mode 100644 include/nuttx/sensors/bh1749nuc.h diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig index 8e6ab080f8..22597fc161 100644 --- a/drivers/sensors/Kconfig +++ b/drivers/sensors/Kconfig @@ -117,6 +117,13 @@ config SENSORS_AS726X ---help--- Enable driver support for the AS726X Spectral Sensor. +config SENSORS_BH1749NUC + bool "Rohm BH1749NUC Color Sensor support" + default n + select I2C + ---help--- + Enable driver support for the Rohm BH1749NUC color sensor. + config SENSORS_BH1750FVI bool "Rohm BH1750FVI Ambient Light Sensor support" default n diff --git a/drivers/sensors/Make.defs b/drivers/sensors/Make.defs index 556aa588ac..56f51e75c5 100644 --- a/drivers/sensors/Make.defs +++ b/drivers/sensors/Make.defs @@ -120,6 +120,10 @@ ifeq ($(CONFIG_ADXL345_I2C),y) CSRCS += adxl345_i2c.c endif +ifeq ($(CONFIG_SENSORS_BH1749NUC),y) + CSRCS += bh1749nuc.c +endif + ifeq ($(CONFIG_SENSORS_BH1750FVI),y) CSRCS += bh1750fvi.c endif diff --git a/drivers/sensors/bh1749nuc.c b/drivers/sensors/bh1749nuc.c new file mode 100644 index 0000000000..8c1a91cad4 --- /dev/null +++ b/drivers/sensors/bh1749nuc.c @@ -0,0 +1,428 @@ +/**************************************************************************** + * drivers/sensors/bh1749nuc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define BH1749NUC_I2C_FREQ 400000 + +#define BH1749NUC_MANUFACTID 0xE0 /* Manufact ID */ +#define BH1749NUC_PARTID 0x0D /* Part ID */ + +/* BH1749NUC Registers */ + +#define BH1749NUC_SYSTEM_CONTROL 0x40 +#define BH1749NUC_MODE_CONTROL1 0x41 +#define BH1749NUC_MODE_CONTROL2 0x42 +#define BH1749NUC_RED_DATA_LSB 0x50 +#define BH1749NUC_GREEN_DATA_LSB 0x52 +#define BH1749NUC_BLUE_DATA_LSB 0x54 +#define BH1749NUC_IR_DATA_LSB 0x58 +#define BH1749NUC_GREEN2_DATA_LSB 0x5a +#define BH1749NUC_MANUFACTURER_ID 0x92 + +/* Register SYSTEM_CONTROL */ + +#define BH1749NUC_SYSTEM_CONTROL_SW_RESET (1 << 7) +#define BH1749NUC_SYSTEM_CONTROL_INT_RESET (1 << 6) + +/* Register MODE_CONTROL1 */ + +#define BH1749NUC_MODE_CONTROL1_IR_GAIN_X1 (0x20) +#define BH1749NUC_MODE_CONTROL1_IR_GAIN_X32 (0x60) +#define BH1749NUC_MODE_CONTROL1_RGB_GAIN_X1 (0x08) +#define BH1749NUC_MODE_CONTROL1_RGB_GAIN_X32 (0x18) +#define BH1749NUC_MODE_CONTROL1_MEAS_TIME160MS (0x02) + +/* Register MODE_CONTROL2 */ + +#define BH1749NUC_MODE_CONTROL2_RGBI_EN (1 << 4) + +/**************************************************************************** + * Private Type Definitions + ****************************************************************************/ + +/* Structure for bh1749nuc device */ + +struct bh1749nuc_dev_s +{ + FAR struct i2c_master_s *i2c; /* I2C interface */ + int freq; /* Frequency */ + uint8_t addr; /* I2C address */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Character driver methods */ + +static int bh1749nuc_open(FAR struct file *filep); +static int bh1749nuc_close(FAR struct file *filep); +static ssize_t bh1749nuc_read(FAR struct file *filep, + FAR char *buffer, + size_t buflen); +static ssize_t bh1749nuc_write(FAR struct file *filep, + FAR const char *buffer, + size_t buflen); +static int bh1749nuc_ioctl(FAR struct file *filep, int cmd, + unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_bh1749nucfops = +{ + bh1749nuc_open, /* open */ + bh1749nuc_close, /* close */ + bh1749nuc_read, /* read */ + bh1749nuc_write, /* write */ + NULL, /* seek */ + bh1749nuc_ioctl, /* ioctl */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bh1749nuc_getreg8 + * + * Description: + * Read from an 8-bit BH1749NUC register + * + ****************************************************************************/ + +static uint8_t bh1749nuc_getreg8(FAR struct bh1749nuc_dev_s *priv, + uint8_t regaddr) +{ + struct i2c_msg_s msg[2]; + uint8_t regval = 0; + int ret; + + msg[0].frequency = priv->freq; + msg[0].addr = priv->addr; + msg[0].flags = I2C_M_NOSTOP; + msg[0].buffer = ®addr; + msg[0].length = 1; + + msg[1].frequency = priv->freq; + msg[1].addr = priv->addr; + msg[1].flags = I2C_M_READ; + msg[1].buffer = ®val; + msg[1].length = 1; + + ret = I2C_TRANSFER(priv->i2c, msg, 2); + if (ret < 0) + { + snerr("I2C_TRANSFER failed: %d\n", ret); + } + + return regval; +} + +/**************************************************************************** + * Name: bh1749nuc_read16 + * + * Description: + * Read 16-bit register + * + ****************************************************************************/ + +static uint16_t bh1749nuc_read16(FAR struct bh1749nuc_dev_s *priv, + uint8_t regaddr) +{ + struct i2c_msg_s msg[2]; + uint8_t regval[2]; + int ret; + + msg[0].frequency = priv->freq; + msg[0].addr = priv->addr; + msg[0].flags = I2C_M_NOSTOP; + msg[0].buffer = ®addr; + msg[0].length = 1; + + msg[1].frequency = priv->freq; + msg[1].addr = priv->addr; + msg[1].flags = I2C_M_READ; + msg[1].buffer = (uint8_t *)®val; + msg[1].length = 2; + + ret = I2C_TRANSFER(priv->i2c, msg, 2); + if (ret < 0) + { + snerr("I2C_TRANSFER failed: %d\n", ret); + } + + return regval[1] << 8 | regval[0] << 0; +} + +/**************************************************************************** + * Name: bh1749nuc_putreg8 + * + * Description: + * Write to an 8-bit BH1749NUC register + * + ****************************************************************************/ + +static void bh1749nuc_putreg8(FAR struct bh1749nuc_dev_s *priv, + uint8_t regaddr, uint8_t regval) +{ + struct i2c_msg_s msg[2]; + uint8_t txbuffer[2]; + int ret; + + txbuffer[0] = regaddr; + txbuffer[1] = regval; + + msg[0].frequency = priv->freq; + msg[0].addr = priv->addr; + msg[0].flags = 0; + msg[0].buffer = txbuffer; + msg[0].length = 2; + + ret = I2C_TRANSFER(priv->i2c, msg, 1); + if (ret < 0) + { + snerr("I2C_TRANSFER failed: %d\n", ret); + } +} + +/**************************************************************************** + * Name: bh1749nuc_checkid + * + * Description: + * Read and verify the BH1749NUC chip ID + * + ****************************************************************************/ + +static int bh1749nuc_checkid(FAR struct bh1749nuc_dev_s *priv) +{ + uint8_t id; + + /* Read Manufact ID */ + + id = bh1749nuc_getreg8(priv, BH1749NUC_MANUFACTURER_ID); + if (id != BH1749NUC_MANUFACTID) + { + /* Manufact ID is not Correct */ + + snerr("Wrong Manufact ID! %02x\n", id); + return -ENODEV; + } + + /* Read Part ID */ + + id = bh1749nuc_getreg8(priv, BH1749NUC_SYSTEM_CONTROL); + if ((id & 0x3f) != BH1749NUC_PARTID) + { + /* Part ID is not Correct */ + + snerr("Wrong Part ID! %02x\n", id); + return -ENODEV; + } + + return OK; +} + +/**************************************************************************** + * Name: bh1749nuc_open + * + * Description: + * This function is called whenever the BH1749NUC device is opened. + * + ****************************************************************************/ + +static int bh1749nuc_open(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct bh1749nuc_dev_s *priv = inode->i_private; + uint8_t val; + + /* MODE_CONTROL1 */ + + val = (BH1749NUC_MODE_CONTROL1_MEAS_TIME160MS | + BH1749NUC_MODE_CONTROL1_IR_GAIN_X1 | + BH1749NUC_MODE_CONTROL1_RGB_GAIN_X1); + bh1749nuc_putreg8(priv, BH1749NUC_MODE_CONTROL1, val); + + /* MODE_CONTROL2 */ + + val = BH1749NUC_MODE_CONTROL2_RGBI_EN; + bh1749nuc_putreg8(priv, BH1749NUC_MODE_CONTROL2, val); + + return OK; +} + +/**************************************************************************** + * Name: bh1749nuc_close + * + * Description: + * This routine is called when the BH1749NUC device is closed. + * + ****************************************************************************/ + +static int bh1749nuc_close(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct bh1749nuc_dev_s *priv = inode->i_private; + uint8_t val; + + /* Stop sampling */ + + val = (BH1749NUC_SYSTEM_CONTROL_SW_RESET | + BH1749NUC_SYSTEM_CONTROL_INT_RESET); + bh1749nuc_putreg8(priv, BH1749NUC_SYSTEM_CONTROL, val); + + return OK; +} + +/**************************************************************************** + * Name: bh1749nuc_read + ****************************************************************************/ + +static ssize_t bh1749nuc_read(FAR struct file *filep, FAR char *buffer, + size_t len) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct bh1749nuc_dev_s *priv = inode->i_private; + FAR struct bh1749nuc_data_s *data = + (FAR struct bh1749nuc_data_s *) buffer; + + if (len < sizeof(struct bh1749nuc_data_s)) + { + snerr("ERROR: Not enough memory to read data sample.\n"); + return -ENOBUFS; + } + + /* Get data */ + + data->red = bh1749nuc_read16(priv, BH1749NUC_RED_DATA_LSB); + data->green = bh1749nuc_read16(priv, BH1749NUC_GREEN_DATA_LSB); + data->blue = bh1749nuc_read16(priv, BH1749NUC_BLUE_DATA_LSB); + data->ir = bh1749nuc_read16(priv, BH1749NUC_IR_DATA_LSB); + data->green2 = bh1749nuc_read16(priv, BH1749NUC_GREEN2_DATA_LSB); + + return sizeof(struct bh1749nuc_data_s); +} + +/**************************************************************************** + * Name: bh1749nuc_write + ****************************************************************************/ + +static ssize_t bh1749nuc_write(FAR struct file *filep, + FAR const char *buffer, + size_t buflen) +{ + return -ENOSYS; +} + +/**************************************************************************** + * Name: bh1749nuc_ioctl + ****************************************************************************/ + +static int bh1749nuc_ioctl(FAR struct file *filep, + int cmd, + unsigned long arg) +{ + return -ENOTTY; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bh1749nuc_register + * + * Description: + * Register the BH1749NUC character device as 'devpath' + * + * Input Parameters: + * devpath - The full path to the driver to register. E.g., "/dev/color0" + * i2c - An instance of the I2C interface to use to communicate with + * BH1749NUC + * addr - I2C address + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int bh1749nuc_register(FAR const char *devpath, FAR struct i2c_master_s *i2c, + uint8_t addr) +{ + FAR struct bh1749nuc_dev_s *priv; + int ret; + + /* Initialize the BH1749NUC device structure */ + + priv = (FAR struct bh1749nuc_dev_s *) + kmm_malloc(sizeof(struct bh1749nuc_dev_s)); + if (!priv) + { + snerr("Failed to allocate instance\n"); + return -ENOMEM; + } + + priv->i2c = i2c; + priv->addr = addr; + priv->freq = BH1749NUC_I2C_FREQ; + + /* Check Device ID */ + + ret = bh1749nuc_checkid(priv); + if (ret < 0) + { + snerr("Failed to register driver: %d\n", ret); + return ret; + } + + /* Register the character driver */ + + ret = register_driver(devpath, &g_bh1749nucfops, 0666, priv); + if (ret < 0) + { + snerr("Failed to register driver: %d\n", ret); + kmm_free(priv); + } + + sninfo("BH1749NUC driver loaded successfully!\n"); + + return ret; +} diff --git a/include/nuttx/sensors/bh1749nuc.h b/include/nuttx/sensors/bh1749nuc.h new file mode 100644 index 0000000000..33f559bade --- /dev/null +++ b/include/nuttx/sensors/bh1749nuc.h @@ -0,0 +1,86 @@ +/**************************************************************************** + * include/nuttx/sensors/bh1749nuc.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_SENSORS_BH1749NUC_H +#define __INCLUDE_NUTTX_SENSORS_BH1749NUC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct bh1749nuc_data_s +{ + uint16_t red; + uint16_t green; + uint16_t blue; + uint16_t ir; + uint16_t green2; +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: bh1749nuc_register + * + * Description: + * Register the BH1749NUC character device as 'devpath' + * + * Input Parameters: + * devpath - The full path to the driver to register. E.g., "/dev/color0" + * i2c - An instance of the I2C interface to use to communicate with + * BH1749NUC + * addr - I2C address + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int bh1749nuc_register(FAR const char *devpath, FAR struct i2c_master_s *i2c, + uint8_t addr); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_NUTTX_SENSORS_BH1749NUC_H */