diff --git a/Tools/autotest/ardusub.py b/Tools/autotest/ardusub.py index 3a330d87ff7eb2..56f8385627f305 100644 --- a/Tools/autotest/ardusub.py +++ b/Tools/autotest/ardusub.py @@ -1143,6 +1143,34 @@ def SHT3X(self): if m is None: raise NotAchievedException("Did not get good TEMP message") + def MCP9808(self): + '''test for the MCP9808 temperature driver''' + + self.set_parameters({ + 'TEMP1_TYPE': 11, # Replace with your MCP9808 enum + 'TEMP1_ADDR': 0x18, # MCP9808 default I2C address + 'TEMP1_BUS': 0, # Bus used by your SITL simulator + 'TEMP_LOG': 1, + }) + self.reboot_sitl() + self.context_push() + self.set_parameter('LOG_DISARMED', 1) + self.delay_sim_time(10, reason="temperature data to be logged") + self.context_pop() + + dfreader = self.dfreader_for_current_onboard_log() + + while True: + m = dfreader.recv_match(type='TEMP') + if m is None: + break + self.progress(m) + # Check for a reasonable temperature + if 30 < m.Temp < 90: + return + + raise NotAchievedException("Did not get valid MCP9808 TEMP message") + def MAV_mgs(self): '''test individual GCS backends timestamps''' self.reboot_sitl() @@ -1644,6 +1672,7 @@ def tests(self): self.INA3221, self.PosHoldBounceBack, self.SHT3X, + self.MCP9808, self.SurfaceSensorless, self.GPSForYaw, self.WaterDepth, diff --git a/Tools/scripts/build_options.py b/Tools/scripts/build_options.py index 8e48fe9e4c8c13..ee0c1c6f5bf337 100644 --- a/Tools/scripts/build_options.py +++ b/Tools/scripts/build_options.py @@ -404,6 +404,7 @@ def config_option(self): Feature('Sensors', 'TEMP_MLX90614', 'AP_TEMPERATURE_SENSOR_MLX90614_ENABLED', 'Enable Temp Sensor - MLX90614', 0, "TEMP"), Feature('Sensors', 'TEMP_SHT3X', 'AP_TEMPERATURE_SENSOR_SHT3X_ENABLED', 'Enable Temp Sensor - SHT3x', 0, "TEMP"), Feature('Sensors', 'TEMP_TMP119', 'AP_TEMPERATURE_SENSOR_TMP119_ENABLED', 'Enable Temp Sensor - TMP119', 0, "TEMP"), + Feature('Sensors', 'TEMP_MCP9808', 'AP_TEMPERATURE_SENSOR_MCP9808_ENABLED', 'Enable Temp Sensor - MCP9808', 0, "TEMP"), Feature('Sensors', 'AIRSPEED', 'AP_AIRSPEED_ENABLED', 'Enable Airspeed Sensors', 1, None), # Default to enabled to not annoy Plane users # NOQA: E501 Feature('Sensors', 'BEACON', 'AP_BEACON_ENABLED', 'Enable Beacon', 0, None), diff --git a/libraries/AP_TemperatureSensor/AP_TemperatureSensor.cpp b/libraries/AP_TemperatureSensor/AP_TemperatureSensor.cpp index ccfc10b769442e..dd6922b2c63e61 100644 --- a/libraries/AP_TemperatureSensor/AP_TemperatureSensor.cpp +++ b/libraries/AP_TemperatureSensor/AP_TemperatureSensor.cpp @@ -35,6 +35,7 @@ #include "AP_TemperatureSensor_MLX90614.h" #include "AP_TemperatureSensor_SHT3x.h" #include "AP_TemperatureSensor_TMP119.h" +#include "AP_TemperatureSensor_MCP9808.h" #include #include @@ -344,6 +345,11 @@ void AP_TemperatureSensor::init() case AP_TemperatureSensor_Params::Type::TMP119: drivers[instance] = NEW_NOTHROW AP_TemperatureSensor_TMP119(*this, _state[instance], _params[instance]); break; +#endif +#if AP_TEMPERATURE_SENSOR_MCP9808_ENABLED + case AP_TemperatureSensor_Params::Type::MCP9808: + drivers[instance] = NEW_NOTHROW AP_TemperatureSensor_MCP9808(*this, _state[instance], _params[instance]); + break; #endif case AP_TemperatureSensor_Params::Type::NONE: default: diff --git a/libraries/AP_TemperatureSensor/AP_TemperatureSensor.h b/libraries/AP_TemperatureSensor/AP_TemperatureSensor.h index 6504fbb3f386d3..50fd7c125fabf9 100644 --- a/libraries/AP_TemperatureSensor/AP_TemperatureSensor.h +++ b/libraries/AP_TemperatureSensor/AP_TemperatureSensor.h @@ -29,6 +29,7 @@ class AP_TemperatureSensor_TSYS03; class AP_TemperatureSensor_Analog; class AP_TemperatureSensor_MLX90614; class AP_TemperatureSensor_TMP119; +class AP_TemperatureSensor_MCP9808; class AP_TemperatureSensor { @@ -41,6 +42,7 @@ class AP_TemperatureSensor friend class AP_TemperatureSensor_DroneCAN; friend class AP_TemperatureSensor_MLX90614; friend class AP_TemperatureSensor_TMP119; + friend class AP_TemperatureSensor_MCP9808; public: diff --git a/libraries/AP_TemperatureSensor/AP_TemperatureSensor_MCP9808.cpp b/libraries/AP_TemperatureSensor/AP_TemperatureSensor_MCP9808.cpp new file mode 100644 index 00000000000000..60b7d5b6e3c5da --- /dev/null +++ b/libraries/AP_TemperatureSensor/AP_TemperatureSensor_MCP9808.cpp @@ -0,0 +1,100 @@ +/* + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include "AP_TemperatureSensor_config.h" + +#if AP_TEMPERATURE_SENSOR_MCP9808_ENABLED + +#include "AP_TemperatureSensor_MCP9808.h" +#include +#include +#include + +extern const AP_HAL::HAL &hal; + +// MCP9808 register addresses +#define MCP9808_REG_AMBIENT_TEMP 0x05 // ambient temperature register +#define MCP9808_REG_RESOLUTION 0x08 // resolution register +// Resolution register - 0.25°C resolution (65ms conversion time) +#define MCP9808_RESOLUTION_VALUE 0x01 + +void AP_TemperatureSensor_MCP9808::init() +{ + _params.bus_address.set_default(AP_TEMPERATURE_SENSOR_MCP9808_DEFAULT_I2C_ADDR); + _dev = hal.i2c_mgr->get_device_ptr( _params.bus, _params.bus_address); + if (_dev == nullptr) { + return; + } + WITH_SEMAPHORE(_dev->get_semaphore()); + // Increase retries during startup + _dev->set_retries(10); + // Configure sensor resolution + if (!write_register8(MCP9808_REG_RESOLUTION, MCP9808_RESOLUTION_VALUE)) { + return; + } + // Reduce retries during normal operation + _dev->set_retries(3); + // Poll temperature at 10Hz (100ms) + _dev->register_periodic_callback(100 * AP_USEC_PER_MSEC, FUNCTOR_BIND_MEMBER(&AP_TemperatureSensor_MCP9808::_timer, void)); +} + +void AP_TemperatureSensor_MCP9808::_timer(void) +{ + uint16_t raw; + if (!read_registers(MCP9808_REG_AMBIENT_TEMP, raw)) { + return; + } + // MCP9808 temperature register format: + // bit15 : Alert flag + // bit14-13 : Temperature alert status + // bit12 : Sign bit + // bit11-0 : Temperature data + // + // Temperature register LSB is always 0.0625°C + int16_t temp_raw = raw & 0x1FFF; + // Sign extend negative temperature values + if (temp_raw & 0x1000) { + temp_raw |= 0xE000; + } + float temp = temp_raw * 0.0625f; + set_temperature(temp); +} + +bool AP_TemperatureSensor_MCP9808::read_registers(uint8_t reg, uint16_t &value) const +{ + uint8_t val[2]; + if (!_dev->transfer(®, 1, val, sizeof(val))) { + return false; + } + // MCP9808 registers are 16-bit big endian + value = UINT16_VALUE(val[0], val[1]); + return true; +} + +bool AP_TemperatureSensor_MCP9808::write_register8(uint8_t reg, uint8_t value) const +{ + // Registers are 8-bit big endian + uint8_t buf[2] = {reg, value}; + return _dev->transfer(buf, sizeof(buf), nullptr, 0); +} + +bool AP_TemperatureSensor_MCP9808::write_register(uint8_t reg, uint16_t value) const +{ + // Registers are 16-bit big endian + uint8_t buf[3] {reg, uint8_t(value >> 8), uint8_t(value & 0xFF)}; + return _dev->transfer(buf, sizeof(buf), nullptr, 0); +} + +#endif // AP_TEMPERATURE_SENSOR_MCP9808_ENABLED diff --git a/libraries/AP_TemperatureSensor/AP_TemperatureSensor_MCP9808.h b/libraries/AP_TemperatureSensor/AP_TemperatureSensor_MCP9808.h new file mode 100644 index 00000000000000..ef0c31514c3928 --- /dev/null +++ b/libraries/AP_TemperatureSensor/AP_TemperatureSensor_MCP9808.h @@ -0,0 +1,55 @@ +/* + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +/* + * I2C driver for Microchip MCP9808 high-accuracy digital temperature sensor. + * + * The MCP9808 is a digital temperature sensor with 0.0625°C resolution. + * It communicates over I2C and provides a 16-bit ambient temperature register. + */ + +#pragma once +#include "AP_TemperatureSensor_Backend.h" + +#if AP_TEMPERATURE_SENSOR_MCP9808_ENABLED + +#ifndef AP_TEMPERATURE_SENSOR_MCP9808_DEFAULT_I2C_ADDR +#define AP_TEMPERATURE_SENSOR_MCP9808_DEFAULT_I2C_ADDR 0x18 +#endif + + +class AP_TemperatureSensor_MCP9808 : public AP_TemperatureSensor_Backend { + using AP_TemperatureSensor_Backend::AP_TemperatureSensor_Backend; +public: + + __INITFUNC__ void init(void) override; + + void update() override {}; + +private: + // update the temperature, called at 20Hz + void _timer(void); + + // read a 16-bit big-endian register + bool read_registers(uint8_t reg, uint16_t &value) const; + + // write a 16-bit big-endian register + bool write_register(uint8_t reg, uint16_t value) const; + + // write a 8-bit big-endian register + bool write_register8(uint8_t reg, uint8_t value) const; +}; + +#endif // AP_TEMPERATURE_SENSOR_MCP9808_ENABLED \ No newline at end of file diff --git a/libraries/AP_TemperatureSensor/AP_TemperatureSensor_Params.cpp b/libraries/AP_TemperatureSensor/AP_TemperatureSensor_Params.cpp index 09c1790c6ef4f9..285c77963efca3 100644 --- a/libraries/AP_TemperatureSensor/AP_TemperatureSensor_Params.cpp +++ b/libraries/AP_TemperatureSensor/AP_TemperatureSensor_Params.cpp @@ -34,7 +34,7 @@ const AP_Param::GroupInfo AP_TemperatureSensor_Params::var_info[] = { // @Param: TYPE // @DisplayName: Temperature Sensor Type // @Description: Enables temperature sensors - // @Values: 0:Disabled, 1:TSYS01, 2:MCP9600, 3:MAX31865 2 or 4 wire, 4:TSYS03, 5:Analog, 6:DroneCAN, 7:MLX90614, 8:SHT3x, 9:MAX31865 3 wire, 10:TMP119 + // @Values: 0:Disabled, 1:TSYS01, 2:MCP9600, 3:MAX31865 2 or 4 wire, 4:TSYS03, 5:Analog, 6:DroneCAN, 7:MLX90614, 8:SHT3x, 9:MAX31865 3 wire, 10:TMP119 ,11:MCP9808 // @User: Standard // @RebootRequired: True AP_GROUPINFO_FLAGS("TYPE", 1, AP_TemperatureSensor_Params, type, (float)Type::NONE, AP_PARAM_FLAG_ENABLE), diff --git a/libraries/AP_TemperatureSensor/AP_TemperatureSensor_Params.h b/libraries/AP_TemperatureSensor/AP_TemperatureSensor_Params.h index 37533ad53a84ad..3bec75cacd1397 100644 --- a/libraries/AP_TemperatureSensor/AP_TemperatureSensor_Params.h +++ b/libraries/AP_TemperatureSensor/AP_TemperatureSensor_Params.h @@ -38,6 +38,7 @@ class AP_TemperatureSensor_Params { SHT3x = 8, MAX31865_3_wire = 9, TMP119 = 10, + MCP9808 = 11, }; // option to map to another system component diff --git a/libraries/AP_TemperatureSensor/AP_TemperatureSensor_config.h b/libraries/AP_TemperatureSensor/AP_TemperatureSensor_config.h index edfa5586f1170b..161e5946b46cc7 100644 --- a/libraries/AP_TemperatureSensor/AP_TemperatureSensor_config.h +++ b/libraries/AP_TemperatureSensor/AP_TemperatureSensor_config.h @@ -47,6 +47,11 @@ #define AP_TEMPERATURE_SENSOR_TMP119_ENABLED AP_TEMPERATURE_SENSOR_BACKEND_DEFAULT_ENABLED #endif // AP_TEMPERATURE_SENSOR_TMP119_ENABLED + +#ifndef AP_TEMPERATURE_SENSOR_MCP9808_ENABLED +#define AP_TEMPERATURE_SENSOR_MCP9808_ENABLED AP_TEMPERATURE_SENSOR_BACKEND_DEFAULT_ENABLED +#endif // AP_TEMPERATURE_SENSOR_MCP9808_ENABLED + // maximum number of Temperature Sensors #ifndef AP_TEMPERATURE_SENSOR_MAX_INSTANCES #define AP_TEMPERATURE_SENSOR_MAX_INSTANCES 3 diff --git a/libraries/SITL/SIM_I2C.cpp b/libraries/SITL/SIM_I2C.cpp index 235e4859e2417c..0bd6a723488304 100644 --- a/libraries/SITL/SIM_I2C.cpp +++ b/libraries/SITL/SIM_I2C.cpp @@ -45,6 +45,7 @@ #include "SIM_Temperature_SHT3x.h" #include "SIM_Temperature_TSYS01.h" #include "SIM_Temperature_TSYS03.h" +#include "SIM_Temperature_MCP9808.h" #include "SIM_TeraRangerI2C.h" #include "SIM_TFS20L.h" #include "SIM_ToshibaLED.h" @@ -98,6 +99,9 @@ static TSYS03 tsys03; #if AP_SIM_TEMPERATURE_MCP9600_ENABLED static MCP9600 mcp9600; #endif +#if AP_SIM_TEMPERATURE_MCP9808_ENABLED +static MCP9808 mcp9808; +#endif #if AP_SIM_ICM40609_ENABLED static ICM40609 icm40609; #endif @@ -162,6 +166,9 @@ struct i2c_device_at_address { #if AP_SIM_TEMPERATURE_MCP9600_ENABLED { 0, 0x60, mcp9600 }, // 0x60 is low address #endif +#if AP_SIM_TEMPERATURE_MCP9808_ENABLED + { 0, 0x18, mcp9808 }, // MCP9808 default address +#endif #if AP_SIM_MAXSONAR_I2C_XL_ENABLED { 0, 0x71, maxsonari2cxl_2 }, // RNGFNDx_TYPE = 2, RNGFNDx_ADDR = 113 #endif diff --git a/libraries/SITL/SIM_Temperature_MCP9808.cpp b/libraries/SITL/SIM_Temperature_MCP9808.cpp new file mode 100644 index 00000000000000..c2751e27c10567 --- /dev/null +++ b/libraries/SITL/SIM_Temperature_MCP9808.cpp @@ -0,0 +1,84 @@ +/* + * SITL simulation for MCP9808 temperature sensor + */ + +#include "SIM_config.h" + +#if AP_SIM_TEMPERATURE_MCP9808_ENABLED + +#include "SIM_Temperature_MCP9808.h" +#include +#include +using namespace SITL; + +void MCP9808::init() +{ + set_debug(true); + // Configuration register + add_register("CONFIG", MCP9808DevReg::CONFIG, 2, I2CRegisters::RegMode::RDWR); + set_register(MCP9808DevReg::CONFIG, uint16_t(htobe16(0x0000))); + // Ambient temperature register + add_register("AMBIENT_TEMP", MCP9808DevReg::AMBIENT_TEMP, 2, I2CRegisters::RegMode::RDONLY); + // Resolution register + add_register("RESOLUTION", MCP9808DevReg::RESOLUTION, 1, I2CRegisters::RegMode::RDWR); + // Default power-up resolution + // 0x03 = 0.0625°C, 250 ms + set_register(MCP9808DevReg::RESOLUTION, uint8_t(0x03)); +} + +void MCP9808::update(const Aircraft &aircraft) +{ + const uint32_t now_ms = AP_HAL::millis(); + // Read current resolution selected by ArduPilot + uint8_t resolution; + get_reg_value(MCP9808DevReg::RESOLUTION, resolution); + + uint32_t conversion_time_ms = 250; + + switch (resolution) + { + case 0x00: + conversion_time_ms = 30; + break; + + case 0x01: + conversion_time_ms = 65; + break; + + case 0x02: + conversion_time_ms = 130; + break; + + case 0x03: + default: + conversion_time_ms = 250; + break; + } + + if ((now_ms - last_temperature_update_ms) < conversion_time_ms) { + return; + } + + last_temperature_update_ms = now_ms; + + const float period_s = 10.0f; // One complete cycle every 10 sec + const float phase = (2.0f * M_PI * (now_ms * 0.001f)) / period_s; + const float temperature = 60.0f + 35.0f * sinf(phase); + + // MCP9808 resolution = 0.0625°C + int16_t raw_temperature = int16_t(temperature / 0.0625f); + uint16_t value = uint16_t(raw_temperature & 0x0FFF); + + if (temperature < 0) { + value |= (1 << 12); + } + set_register( + MCP9808DevReg::AMBIENT_TEMP, uint16_t(htobe16(value))); +} + +int MCP9808::rdwr(I2C::i2c_rdwr_ioctl_data *&data) +{ + return I2CRegisters_ConfigurableLength::rdwr(data); +} + +#endif // AP_SIM_TEMPERATURE_MCP9808_ENABLED \ No newline at end of file diff --git a/libraries/SITL/SIM_Temperature_MCP9808.h b/libraries/SITL/SIM_Temperature_MCP9808.h new file mode 100644 index 00000000000000..e77585753991b8 --- /dev/null +++ b/libraries/SITL/SIM_Temperature_MCP9808.h @@ -0,0 +1,44 @@ +#include "SIM_config.h" + +#if AP_SIM_TEMPERATURE_MCP9808_ENABLED + +#include "SIM_I2CDevice.h" + +/* + Simulator for the MCP9808 temperature sensor + + Datasheet: + https://ww1.microchip.com/downloads/en/DeviceDoc/25095A.pdf + +*/ + +namespace SITL { + +class MCP9808DevReg : public I2CRegEnum { +public: + static constexpr uint8_t CONFIG { 0x01 }; + static constexpr uint8_t AMBIENT_TEMP { 0x05 }; + static constexpr uint8_t RESOLUTION { 0x08 }; +}; + +class MCP9808 : public I2CDevice, private I2CRegisters_ConfigurableLength +{ +public: + + void init() override; + + void update(const class Aircraft &aircraft) override; + + int rdwr(I2C::i2c_rdwr_ioctl_data *&data) override; + +private: + + // should be a call on aircraft: + float some_temperature = 25; + + uint32_t last_temperature_update_ms; +}; + +} // namespace SITL + +#endif // AP_SIM_TEMPERATURE_MCP9808_ENABLED \ No newline at end of file diff --git a/libraries/SITL/SIM_config.h b/libraries/SITL/SIM_config.h index 0e70d1b5182e6b..81379ae979a151 100644 --- a/libraries/SITL/SIM_config.h +++ b/libraries/SITL/SIM_config.h @@ -311,6 +311,10 @@ #define AP_SIM_TEMPERATURE_TSYS01_ENABLED (CONFIG_HAL_BOARD == HAL_BOARD_SITL) #endif +#ifndef AP_SIM_TEMPERATURE_MCP9808_ENABLED +#define AP_SIM_TEMPERATURE_MCP9808_ENABLED (CONFIG_HAL_BOARD == HAL_BOARD_SITL) +#endif + #ifndef AP_SIM_VOLZ_ENABLED #define AP_SIM_VOLZ_ENABLED AP_SIM_ENABLED #endif // AP_SIM_VOLZ_ENABLED