This is an automated email from the ASF dual-hosted git repository.
xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 1b172fb8d2e drivers/sensors: add Microchip TC74 temperature sensor
driver
1b172fb8d2e is described below
commit 1b172fb8d2eb2c2678a137a3c7470e6bd742cfd3
Author: Daniel P. Carvalho <[email protected]>
AuthorDate: Thu Sep 17 07:00:57 2026 -0300
drivers/sensors: add Microchip TC74 temperature sensor driver
Add support for the Microchip TC74 digital temperature sensor using the
Sensor Driver Framework (uORB). The TC74 is an 8-bit I2C temperature
sensor with a measurement range from -40C to +125C and a resolution
of 1C.
The driver registers as a uORB topic (/dev/uorb/sensor_temp<n>) and
polls on the low-priority work queue. It supports dynamic interval
configuration and automatically enters low-power standby mode when
the topic is deactivated.
Validated against a real TC74A5-3.3 on a custom STM32H743BI board.
Assisted-by: Gemini:gemini-3.8-pro
Signed-off-by: Daniel P. Carvalho <[email protected]>
---
.../components/drivers/special/sensors.rst | 1 +
.../drivers/special/sensors/sensors_uorb.rst | 1 +
.../components/drivers/special/sensors/tc74.rst | 46 +++
drivers/sensors/CMakeLists.txt | 4 +
drivers/sensors/Kconfig | 18 +
drivers/sensors/Make.defs | 4 +
drivers/sensors/tc74.c | 412 +++++++++++++++++++++
include/nuttx/sensors/tc74.h | 94 +++++
8 files changed, 580 insertions(+)
diff --git a/Documentation/components/drivers/special/sensors.rst
b/Documentation/components/drivers/special/sensors.rst
index 8b0efc303ba..9cd4ee931fc 100644
--- a/Documentation/components/drivers/special/sensors.rst
+++ b/Documentation/components/drivers/special/sensors.rst
@@ -37,6 +37,7 @@ tool for monitoring sensor activity at runtime.
sensors/nau7802.rst
sensors/qmi8658.rst
sensors/sht4x.rst
+ sensors/tc74.rst
sensors/tmp112.rst
sensors/lsm6dso32.rst
sensors/lsm6ds3trc.rst
diff --git a/Documentation/components/drivers/special/sensors/sensors_uorb.rst
b/Documentation/components/drivers/special/sensors/sensors_uorb.rst
index a2d5547dffd..fbccd910baf 100644
--- a/Documentation/components/drivers/special/sensors/sensors_uorb.rst
+++ b/Documentation/components/drivers/special/sensors/sensors_uorb.rst
@@ -557,6 +557,7 @@ Implemented Drivers
- :doc:`nau7802`
- :doc:`qmi8658`
- :doc:`sht4x`
+- :doc:`tc74`
- :doc:`tmp112`
- :doc:`lsm6dso32`
- :doc:`lsm6ds3trc`
diff --git a/Documentation/components/drivers/special/sensors/tc74.rst
b/Documentation/components/drivers/special/sensors/tc74.rst
new file mode 100644
index 00000000000..3888a80d82b
--- /dev/null
+++ b/Documentation/components/drivers/special/sensors/tc74.rst
@@ -0,0 +1,46 @@
+====
+TC74
+====
+
+The TC74 is a Microchip serial digital thermal sensor, specified from
+-40°C to +125°C, with an eight-bit reading of 1°C a count. Factory-programmed
+I2C addresses range from 0x48 through 0x4f (suffixes A0 through A7), allowing
+up to eight parts on the same bus.
+
+This driver uses the :doc:`uorb
+</components/drivers/special/sensors/sensors_uorb>` interface, so the reading
+appears as a topic the common sensor tools can read.
+
+Application Programming Interface
+=================================
+
+The header file for the TC74 driver interface can be included using:
+
+.. code-block:: c
+
+ #include <nuttx/sensors/tc74.h>
+
+Registering the driver creates one topic, ``sensor_temp<n>``, where ``n`` is
+the ``devno`` passed in:
+
+.. code-block:: c
+
+ int tc74_register(int devno, FAR struct i2c_master_s *i2c, uint8_t addr);
+
+For example, a part with address 0x4d (TC74A5) on I2C bus 0, published as
+``sensor_temp0``:
+
+.. code-block:: c
+
+ FAR struct i2c_master_s *i2c = board_i2cbus_initialize(0);
+
+ tc74_register(0, i2c, TC74_ADDR_A5);
+
+Reading
+=======
+
+The driver polls on the low priority work queue at whatever interval a
+consumer asks for. When activated (for example when an application subscribes
+to the sensor topic), the driver wakes the part up from standby mode. When
+deactivated (when all subscribers close the topic), it places the part back
+into low-power standby mode to save energy.
diff --git a/drivers/sensors/CMakeLists.txt b/drivers/sensors/CMakeLists.txt
index cd1236853a9..53f8d38b581 100644
--- a/drivers/sensors/CMakeLists.txt
+++ b/drivers/sensors/CMakeLists.txt
@@ -360,6 +360,10 @@ if(CONFIG_SENSORS)
endif()
endif()
+ if(CONFIG_SENSORS_TC74)
+ list(APPEND SRCS tc74.c)
+ endif()
+
# QMI8658 6-axis IMU
if(CONFIG_SENSORS_QMI8658)
diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig
index bab401daec8..8e08788fe7f 100644
--- a/drivers/sensors/Kconfig
+++ b/drivers/sensors/Kconfig
@@ -2354,6 +2354,24 @@ config SENSORS_TMP112_UORB
endif #SENSORS_TMP112
+config SENSORS_TC74
+ bool "Microchip TC74 Temperature Sensor support"
+ default n
+ select I2C
+ ---help---
+ Enable driver support for the Microchip TC74 digital
temperature sensor.
+
+if SENSORS_TC74
+
+config TC74_I2C_FREQUENCY
+ int "TC74 I2C frequency"
+ default 100000
+ range 1 100000
+ ---help---
+ I2C clock frequency for the TC74 sensor. Default is 100 kHz.
+
+endif # SENSORS_TC74
+
config SENSORS_QMI8658
bool "QST QMI8658 6-Axis IMU Sensor support"
default n
diff --git a/drivers/sensors/Make.defs b/drivers/sensors/Make.defs
index d4ef1f00858..9ad42cb74ee 100644
--- a/drivers/sensors/Make.defs
+++ b/drivers/sensors/Make.defs
@@ -354,6 +354,10 @@ else
endif
endif
+ifeq ($(CONFIG_SENSORS_TC74),y)
+ CSRCS += tc74.c
+endif
+
endif # CONFIG_I2C
# These drivers depend on SPI support
diff --git a/drivers/sensors/tc74.c b/drivers/sensors/tc74.c
new file mode 100644
index 00000000000..390e0f19015
--- /dev/null
+++ b/drivers/sensors/tc74.c
@@ -0,0 +1,412 @@
+/****************************************************************************
+ * drivers/sensors/tc74.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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 <nuttx/config.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <debug.h>
+
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/sensors/sensor.h>
+#include <nuttx/sensors/tc74.h>
+#include <nuttx/wqueue.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef CONFIG_TC74_I2C_FREQUENCY
+# define CONFIG_TC74_I2C_FREQUENCY 100000
+#endif
+
+/* TC74 Register Addresses */
+
+#define TC74_TEMP_REG 0x00 /* Temperature Register
(read-only) */
+#define TC74_CONFIG_REG 0x01 /* Configuration Register
(read/write) */
+
+/* Configuration Register Bit Definitions */
+
+#define TC74_CONFIG_STANDBY (1 << 7) /* Bit 7: 1=Standby mode, 0=Normal
mode */
+
+/* One reading a second by default until requested otherwise */
+
+#define TC74_DEFAULT_INTERVAL 1000000
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct tc74_dev_s
+{
+ struct sensor_lowerhalf_s lower; /* Must be first */
+ FAR struct i2c_master_s *i2c;
+ uint8_t addr;
+ uint32_t interval; /* Microseconds between readings */
+ struct work_s work;
+ bool enabled;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int tc74_activate(FAR struct sensor_lowerhalf_s *lower,
+ FAR struct file *filep, bool enable);
+static int tc74_set_interval(FAR struct sensor_lowerhalf_s *lower,
+ FAR struct file *filep,
+ FAR uint32_t *period_us);
+static int tc74_get_info(FAR struct sensor_lowerhalf_s *lower,
+ FAR struct file *filep,
+ FAR struct sensor_device_info_s *info);
+static void tc74_worker(FAR void *arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct sensor_ops_s g_tc74_ops =
+{
+ .activate = tc74_activate,
+ .set_interval = tc74_set_interval,
+ .get_info = tc74_get_info,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: tc74_delay
+ *
+ * Description:
+ * The requeue delay in ticks for the interval in force, never zero: a
+ * zero delay would requeue the worker without it ever yielding.
+ *
+ * Input Parameters:
+ * priv - The driver state
+ *
+ * Returned Value:
+ * The delay in clock ticks, at least one.
+ *
+ ****************************************************************************/
+
+static clock_t tc74_delay(FAR struct tc74_dev_s *priv)
+{
+ clock_t ticks = priv->interval / USEC_PER_TICK;
+
+ return ticks > 0 ? ticks : 1;
+}
+
+/****************************************************************************
+ * Name: tc74_putreg8
+ *
+ * Description:
+ * Write an 8-bit value to a TC74 register.
+ *
+ * Input Parameters:
+ * priv - The driver state
+ * regaddr - The register address
+ * regval - The value to write
+ *
+ * Returned Value:
+ * Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int tc74_putreg8(FAR struct tc74_dev_s *priv,
+ uint8_t regaddr, uint8_t regval)
+{
+ struct i2c_msg_s msg;
+ uint8_t buffer[2];
+ int ret;
+
+ buffer[0] = regaddr;
+ buffer[1] = regval;
+
+ msg.frequency = CONFIG_TC74_I2C_FREQUENCY;
+ msg.addr = priv->addr;
+ msg.flags = 0;
+ msg.buffer = buffer;
+ msg.length = 2;
+
+ ret = I2C_TRANSFER(priv->i2c, &msg, 1);
+ if (ret < 0)
+ {
+ snerr("ERROR: I2C_TRANSFER failed: %d\n", ret);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: tc74_readraw
+ *
+ * Description:
+ * Read the temperature register and return it as the signed 8-bit count.
+ *
+ * Input Parameters:
+ * priv - The driver state
+ * raw - Where to return the signed 8-bit temperature in degrees C
+ *
+ * Returned Value:
+ * Zero on success, or a negated errno on failure.
+ *
+ ****************************************************************************/
+
+static int tc74_readraw(FAR struct tc74_dev_s *priv, FAR int8_t *raw)
+{
+ struct i2c_msg_s msg[2];
+ uint8_t regaddr = TC74_TEMP_REG;
+ uint8_t val;
+ int ret;
+
+ msg[0].frequency = CONFIG_TC74_I2C_FREQUENCY;
+ msg[0].addr = priv->addr;
+ msg[0].flags = 0;
+ msg[0].buffer = ®addr;
+ msg[0].length = 1;
+
+ msg[1].frequency = CONFIG_TC74_I2C_FREQUENCY;
+ 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("ERROR: cannot read temperature: %d\n", ret);
+ return ret;
+ }
+
+ *raw = (int8_t)val;
+ return OK;
+}
+
+/****************************************************************************
+ * Name: tc74_worker
+ *
+ * Description:
+ * Take one reading and publish it, then requeue for the next.
+ *
+ * Input Parameters:
+ * arg - The driver state, as passed to work_queue()
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+static void tc74_worker(FAR void *arg)
+{
+ FAR struct tc74_dev_s *priv = arg;
+ struct sensor_temp temp;
+ int8_t raw;
+
+ DEBUGASSERT(priv != NULL);
+
+ /* Queue the next reading first, so that a failed transfer costs one
+ * sample rather than the whole stream.
+ */
+
+ work_queue(LPWORK, &priv->work, tc74_worker, priv,
+ tc74_delay(priv));
+
+ if (tc74_readraw(priv, &raw) < 0)
+ {
+ return;
+ }
+
+ temp.temperature = sensor_data_itof(raw);
+ temp.timestamp = sensor_get_timestamp();
+
+ priv->lower.push_event(priv->lower.priv, &temp, sizeof(temp));
+}
+
+/****************************************************************************
+ * Name: tc74_activate
+ *
+ * Description:
+ * Start or stop the reading stream.
+ *
+ * Input Parameters:
+ * lower - The sensor lower half
+ * filep - The file that asked, unused
+ * enable - True to start reading, false to stop
+ *
+ * Returned Value:
+ * Zero on success, or a negated errno on failure.
+ *
+ ****************************************************************************/
+
+static int tc74_activate(FAR struct sensor_lowerhalf_s *lower,
+ FAR struct file *filep, bool enable)
+{
+ FAR struct tc74_dev_s *priv = (FAR struct tc74_dev_s *)lower;
+
+ if (enable == priv->enabled)
+ {
+ return OK;
+ }
+
+ if (enable)
+ {
+ /* Wake up TC74 from standby mode */
+
+ tc74_putreg8(priv, TC74_CONFIG_REG, 0);
+
+ work_queue(LPWORK, &priv->work, tc74_worker, priv,
+ tc74_delay(priv));
+ }
+ else
+ {
+ work_cancel(LPWORK, &priv->work);
+
+ /* Place TC74 into low-power standby mode */
+
+ tc74_putreg8(priv, TC74_CONFIG_REG, TC74_CONFIG_STANDBY);
+ }
+
+ priv->enabled = enable;
+ return OK;
+}
+
+/****************************************************************************
+ * Name: tc74_set_interval
+ *
+ * Description:
+ * Set how often to read the part.
+ *
+ * Input Parameters:
+ * lower - The sensor lower half
+ * filep - The file that asked, unused
+ * period_us - The interval wanted, updated to the interval granted
+ *
+ * Returned Value:
+ * Zero on success, or a negated errno on failure.
+ *
+ ****************************************************************************/
+
+static int tc74_set_interval(FAR struct sensor_lowerhalf_s *lower,
+ FAR struct file *filep,
+ FAR uint32_t *period_us)
+{
+ FAR struct tc74_dev_s *priv = (FAR struct tc74_dev_s *)lower;
+
+ priv->interval = *period_us;
+ return OK;
+}
+
+/****************************************************************************
+ * Name: tc74_get_info
+ *
+ * Description:
+ * Describe the part: vendor, range, and resolution.
+ *
+ * Input Parameters:
+ * lower - The sensor lower half
+ * filep - The file that asked, unused
+ * info - Where to return the description
+ *
+ * Returned Value:
+ * Zero on success.
+ *
+ ****************************************************************************/
+
+static int tc74_get_info(FAR struct sensor_lowerhalf_s *lower,
+ FAR struct file *filep,
+ FAR struct sensor_device_info_s *info)
+{
+ info->version = 0;
+ info->power = 0.2f; /* 200 uA operating current */
+ info->max_range = 125.0f; /* Specified -40C to +125C */
+ info->resolution = 1.0f; /* 8-bit signed, 1C step */
+ info->min_delay = 0;
+ info->max_delay = 0;
+ info->fifo_reserved_event_count = 0;
+ info->fifo_max_event_count = 0;
+ strlcpy(info->name, "TC74", sizeof(info->name));
+ strlcpy(info->vendor, "Microchip", sizeof(info->vendor));
+ return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: tc74_register
+ *
+ * Description:
+ * Register the TC74 as a uORB temperature sensor.
+ *
+ * Input Parameters:
+ * devno - The topic number, giving /dev/uorb/sensor_temp<devno>
+ * i2c - The bus the part is on
+ * addr - The 7-bit bus address (e.g., TC74_ADDR_A0 through TC74_ADDR_A7)
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno on failure.
+ *
+ ****************************************************************************/
+
+int tc74_register(int devno, FAR struct i2c_master_s *i2c, uint8_t addr)
+{
+ FAR struct tc74_dev_s *priv;
+ int ret;
+
+ DEBUGASSERT(i2c != NULL);
+
+ priv = kmm_zalloc(sizeof(struct tc74_dev_s));
+ if (priv == NULL)
+ {
+ return -ENOMEM;
+ }
+
+ priv->i2c = i2c;
+ priv->addr = addr;
+ priv->interval = TC74_DEFAULT_INTERVAL;
+ priv->lower.ops = &g_tc74_ops;
+ priv->lower.type = SENSOR_TYPE_TEMPERATURE;
+
+ /* Put sensor in standby by default until activated */
+
+ tc74_putreg8(priv, TC74_CONFIG_REG, TC74_CONFIG_STANDBY);
+
+ ret = sensor_register(&priv->lower, devno);
+ if (ret < 0)
+ {
+ snerr("ERROR: cannot register: %d\n", ret);
+ kmm_free(priv);
+ return ret;
+ }
+
+ sninfo("TC74 at %02x registered as sensor_temp%d\n", addr, devno);
+ return OK;
+}
diff --git a/include/nuttx/sensors/tc74.h b/include/nuttx/sensors/tc74.h
new file mode 100644
index 00000000000..52d14a919e9
--- /dev/null
+++ b/include/nuttx/sensors/tc74.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+ * include/nuttx/sensors/tc74.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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_TC74_H
+#define __INCLUDE_NUTTX_SENSORS_TC74_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_TC74)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* TC74 Factory I2C Addresses (7-bit)
+ * The address is factory programmed according to the part suffix (A0-A7).
+ */
+
+#define TC74_ADDR_A0 0x48
+#define TC74_ADDR_A1 0x49
+#define TC74_ADDR_A2 0x4a
+#define TC74_ADDR_A3 0x4b
+#define TC74_ADDR_A4 0x4c
+#define TC74_ADDR_A5 0x4d
+#define TC74_ADDR_A6 0x4e
+#define TC74_ADDR_A7 0x4f
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+struct i2c_master_s;
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Name: tc74_register
+ *
+ * Description:
+ * Register the TC74 sensor as a uORB temperature sensor, appearing as
+ * /dev/uorb/sensor_temp<devno>.
+ *
+ * Input Parameters:
+ * devno - The topic number, giving /dev/uorb/sensor_temp<devno>
+ * i2c - An instance of the I2C interface to communicate with the TC74
+ * addr - The 7-bit I2C address of the TC74 (e.g., TC74_ADDR_A5)
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int tc74_register(int devno, FAR struct i2c_master_s *i2c, uint8_t addr);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CONFIG_I2C && CONFIG_SENSORS_TC74 */
+#endif /* __INCLUDE_NUTTX_SENSORS_TC74_H */