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    = &regaddr;
+  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 */

Reply via email to