drivers/sensors: Wrote a driver for the MCP9600 thermocouple amplifier.

This commit is contained in:
Matteo Golin
2025-01-06 22:54:58 -05:00
committed by Xiang Xiao
parent cf66a1d5ce
commit 36507cc7b2
6 changed files with 1235 additions and 0 deletions
@@ -0,0 +1,146 @@
MCP9600
=======
Contributed by Matteo Golin.
The MCP9600 is a thermocouple EMF to temperature converter made by Microchip. It is also sold as a `breakout board module
by Adafruit <https://learn.adafruit.com/adafruit-mcp9600-i2c-thermocouple-amplifier>`_.
Application Programming Interface
==================================
The header file for the MCP9600 driver interface can be included using:
.. code-block:: c
#include <nuttx/sensors/mcp9600.h>
The MCP9600 registration function allows the driver to be registered as a POSIX
character driver.
The standard POSIX `read()` operation will return the device information in
plain-text, which is useful when debugging/testing the driver using `cat` from
the shell.
The `write()` operation is not implemented for this sensor.
Specific operations the sensor offers can be performed via the POSIX `ioctl`
operation. The supported commands are:
* :c:macro:`SNIOC_WHO_AM_I`
* :c:macro:`SNIOC_READ_RAW_DATA`
* :c:macro:`SNIOC_CHECK_STATUS_REG`
* :c:macro:`SNIOC_CONFIGURE`
* :c:macro:`SNIOC_WRITECONF`
* :c:macro:`SNIOC_READTEMP`
* :c:macro:`SNIOC_SHUTDOWN`
* :c:macro:`SNIOC_START`
``SNIOC_WHO_AM_I``
------------------
This command reads the device ID register of the MCP9600 sensor. The device ID,
major and minor revision numbers are returned in the argument, which must be of
type ``struct mcp9600_devinfo_s *``.
.. code-block:: c
struct mcp9600_devinfo_s devinfo;
err = ioctl(sensor, SNIOC_WHO_AM_I, &devinfo);
uint8_t revision_minor = MCP9600_REV_MINOR(devinfo.revision);
uint8_t revision_major = MCP9600_REV_MAJOR(devinfo.revision);
``SNIOC_READ_RAW_DATA``
-----------------------
This command allows the caller to read the raw data returned from the sensor's
ADC.
The argument to this command must be an ``int32_t`` pointer. The raw data will
be returned here. The process to convert the raw ADC data depends on the
configured resolution; consult the data sheet.
.. code-block:: c
int32_t raw;
err = ioctl(sensor, SNIOC_READ_RAW_DATA, &raw);
``SNIOC_CHECK_STATUS_REG``
--------------------------
This command lets you check the status register of the device. The argument to
this command must be a pointer to type ``struct mcp9600_status_s``.
.. code-block:: c
struct mcp9600_status_s status;
err = ioctl(sensor, SNIOC_CHECK_STATUS_REG, &status);
``SNIOC_CONFIGURE``
-------------------
This command lets you configure the MCP9600's operation, including thermocouple
type, operating mode, ADC resolution, etc.
The argument to this command must be a pointer to type ``struct
mcp9600_devconf_s``.
.. code-block:: c
struct mcp9600_devconf_s conf = {
.thermo_type = MCP9600_THERMO_TYPE_K,
.resolution = MCP9600_ADC_RES_18,
/* More fields ... */
};
err = ioctl(sensor, SNIOC_CONFIGURE, &conf);
``SNIOC_WRITECONF``
-------------------
This command lets you configure the MCP9600's alerts on a per-alert basis.
The argument to this command must be a pointer to type ``struct
mcp9600_alertconf_s``.
.. code-block:: c
struct mcp9600_alertconf_s conf = {
.alert = MCP9600_ALERT1,
.enable = true,
.limit = 40 / 0.25,
/* More fields ... */
};
err = ioctl(sensor, SNIOC_WRITECONF, &conf);
``SNIOC_READTEMP``
------------------
This command lets you read the three different types of temperature that the
MCP9600 can measure. The argument to this command must be a pointer to type
``struct mcp9600_temp_s``.
.. code-block:: c
struct mcp9600_temp_s temps;
err = ioctl(sensor, SNIOC_READTEMP, &temps);
printf("Temperature: %d C\n", temps.hot_junc);
``SNIOC_SHUTDOWN``
------------------
This command shuts down the sensor. It takes no arguments.
.. code-block:: c
err = ioctl(sensor, SNIOC_SHUTDOWN, NULL);
``SNIOC_START``
---------------
This command starts the sensor in normal mode. It takes no arguments.
.. code-block:: c
err = ioctl(sensor, SNIOC_START, NULL);
@@ -75,6 +75,11 @@
#include "rp2040_i2c.h"
#endif
#ifdef CONFIG_SENSORS_MCP9600
#include <nuttx/sensors/mcp9600.h>
#include "rp2040_i2c.h"
#endif
#ifdef CONFIG_SENSORS_MAX6675
#include <nuttx/sensors/max6675.h>
#include "rp2040_max6675.h"
@@ -538,6 +543,16 @@ int rp2040_common_bringup(void)
}
#endif
#ifdef CONFIG_SENSORS_MCP9600
/* Try to register MCP9600 device as /dev/thermo0 at I2C0. */
ret = mcp9600_register("/dev/thermo0", rp2040_i2cbus_initialize(0), 0x60);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: couldn't initialize MCP9600: %d\n", ret);
}
#endif
#ifdef CONFIG_VIDEO_FB
ret = fb_register(0, 0);
if (ret < 0)
+17
View File
@@ -950,6 +950,23 @@ config MLX90614_CRC
endif # SENSORS_MLX90614
config SENSORS_MCP9600
bool "MCP9600 Thermocouple Amplifier"
default n
select I2C
---help---
Enable driver support for the MCP9600 thermocouple amplifier
if SENSORS_MCP9600
config MCP9600_I2C_FREQUENCY
int "MCP9600 I2C frequency"
default 100000
range 10000 100000
depends on SENSORS_MCP9600
endif # SENSORS_MCP9600
config SENSORS_MCP9844
bool "MCP9844 Temperature Sensor"
default n
+4
View File
@@ -224,6 +224,10 @@ ifeq ($(CONFIG_SENSORS_MB7040),y)
CSRCS += mb7040.c
endif
ifeq ($(CONFIG_SENSORS_MCP9600),y)
CSRCS += mcp9600.c
endif
ifeq ($(CONFIG_SENSORS_MCP9844),y)
CSRCS += mcp9844.c
endif
File diff suppressed because it is too large Load Diff
+197
View File
@@ -0,0 +1,197 @@
/****************************************************************************
* include/nuttx/sensors/mcp9600.h
*
* Contributed by Matteo Golin
*
* 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_MCP9600_H
#define __INCLUDE_NUTTX_SENSORS_MCP9600_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/sensors/ioctl.h>
#include <stdbool.h>
#include <stdint.h>
/****************************************************************************
* Pre-processor definitions
****************************************************************************/
#define MCP9600_REV_MAJOR(rev) (((rev) & 0xf0) >> 4) /* Major revision */
#define MCP9600_REV_MINOR(rev) ((rev) & 0x0f) /* Minor revision */
/****************************************************************************
* Public Types
****************************************************************************/
struct i2c_master_s; /* Forward reference */
/* Alerts */
enum mcp9600_alert_e
{
MCP9600_ALERT1 = 0, /* Alert 1 */
MCP9600_ALERT2 = 1, /* Alert 2 */
MCP9600_ALERT3 = 2, /* Alert 3 */
MCP9600_ALERT4 = 3, /* Alert 4 */
};
/* Thermocouple types */
enum mcp9600_thermocouple_e
{
MCP9600_THERMO_TYPE_K = 0x0,
MCP9600_THERMO_TYPE_J = 0x1,
MCP9600_THERMO_TYPE_T = 0x2,
MCP9600_THERMO_TYPE_N = 0x3,
MCP9600_THERMO_TYPE_S = 0x4,
MCP9600_THERMO_TYPE_E = 0x5,
MCP9600_THERMO_TYPE_B = 0x6,
MCP9600_THERMO_TYPE_R = 0x7,
};
/* ADC resolution */
enum mcp9600_resolution_e
{
MCP9600_ADC_RES_12 = 0x3, /* 12 bits */
MCP9600_ADC_RES_14 = 0x2, /* 14 bits */
MCP9600_ADC_RES_16 = 0x1, /* 16 bits */
MCP9600_ADC_RES_18 = 0x0, /* 18 bits */
};
/* Number of samples */
enum mcp9600_samples_e
{
MCP9600_SAMPLE_1 = 0x0,
MCP9600_SAMPLE_2 = 0x1,
MCP9600_SAMPLE_4 = 0x2,
MCP9600_SAMPLE_8 = 0x3,
MCP9600_SAMPLE_16 = 0x4,
MCP9600_SAMPLE_32 = 0x5,
MCP9600_SAMPLE_64 = 0x6,
MCP9600_SAMPLE_128 = 0x7,
};
/* Shutdown mode options */
enum mcp9600_modes_e
{
MCP9600_MODE_NORMAL = 0x0, /* Normal mode */
MCP9600_MODE_SHUTDOWN = 0x1, /* Shutdown mode */
MCP9600_MODE_BURST = 0x2, /* Burst mode */
};
/* Cold junction resolutions */
enum mcp9600_cold_res_e
{
MCP9600_COLDRES_25 = 1, /* 0.25 degrees Celsius */
MCP9600_COLDRES_0625 = 0, /* 0.0625 degrees Celsius */
};
/* Alert configuration */
struct mcp9600_alert_conf_s
{
enum mcp9600_alert_e
alert; /* The alert associated with this configuration */
int16_t limit; /* The temperature limit for the alert, in 0.25 degrees
* Celsius/LSB */
uint8_t temp; /* The temperature for the hysteresis threshold, in degrees
* Celsius. */
bool cold_junc; /* True to monitor cold junction, false to monitor
* thermocouple */
bool falling_temp; /* True to monitor for falling temperature, false to
* monitor rising */
bool active_high; /* False for active low */
bool int_mode; /* Interrupt mode, or false for comparator mode */
bool enable; /* Enable alert output */
};
/* Device configuration of the MCP9600 */
struct mcp9600_devconf_s
{
enum mcp9600_thermocouple_e thermo_type; /* Thermocouple type */
uint8_t filter_coeff; /* Filter coefficient */
enum mcp9600_resolution_e resolution; /* ADC resolution */
enum mcp9600_samples_e num_samples; /* Number of samples */
enum mcp9600_modes_e mode; /* Mode of operation */
enum mcp9600_cold_res_e cold_res; /* Resolution of the cold
* junction */
};
/* Device information of the MCP9600 */
struct mcp9600_devinfo_s
{
uint8_t devid; /* Device ID */
uint8_t revision; /* Revision number; major 4 MSBs, minor 3 LSBs */
};
/* Device status */
struct mcp9600_status_s
{
bool burst_complete; /* Burst mode conversions complete */
bool temp_update; /* Temperature updated */
bool temp_exceeded; /* Temperature range exceeded */
bool alerts[4]; /* Alert statuses for alerts 1-4 (0-3) */
};
/* Temperature readings */
struct mcp9600_temp_s
{
int16_t temp_delta; /* Temperature delta in degrees Celsius */
int16_t hot_junc; /* Hot junction temperature in degrees Celsius */
int16_t cold_junc; /* Cold junction temperature in degrees Celsius */
};
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: mcp9600_register
*
* Description:
* Register the MCP9600 character device as 'devpath'
*
* Input Parameters:
* devpath - The full path to the driver to register. E.g., "/dev/temp0"
* i2c - An instance of the I2C interface to use to communicate with
* the MCP9600
* addr - The I2C address of the MCP9600, between 0x60 and 0x67
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int mcp9600_register(FAR const char *devpath, FAR struct i2c_master_s *i2c,
uint8_t addr);
#endif /* __INCLUDE_NUTTX_SENSORS_MCP9600_H */