Line data Source code
1 : /* 2 : * Copyright (C) 2022 Kraus Hamdani Aerospace Inc. All rights reserved. 3 : * 4 : * This file is free software: you can redistribute it and/or modify it 5 : * under the terms of the GNU General Public License as published by the 6 : * Free Software Foundation, either version 3 of the License, or 7 : * (at your option) any later version. 8 : * 9 : * This file is distributed in the hope that it will be useful, but 10 : * WITHOUT ANY WARRANTY; without even the implied warranty of 11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 : * See the GNU General Public License for more details. 13 : * 14 : * You should have received a copy of the GNU General Public License along 15 : * with this program. If not, see <http://www.gnu.org/licenses/>. 16 : * 17 : * Code by Tom Pittenger 18 : */ 19 : /* 20 : Implements I2C driver for Microchip MCP9600 and MCP9601 digital thermocouple EMF to Temperature converter 21 : */ 22 : 23 : #include "AP_TemperatureSensor_MCP9600.h" 24 : 25 : #if AP_TEMPERATURE_SENSOR_MCP9600_ENABLED 26 : 27 : #include <stdio.h> 28 : #include <AP_HAL/I2CDevice.h> 29 : #include <AP_Math/AP_Math.h> 30 : #include <GCS_MAVLink/GCS.h> 31 : 32 : extern const AP_HAL::HAL &hal; 33 : 34 : static const uint8_t MCP9600_CMD_HOT_JUNCT_TEMP = 0x00; // thermocoupler temp 35 : //static const uint8_t MCP9600_CMD_JUNCT_TEMP_DELTA = 0x01; 36 : //static const uint8_t MCP9600_CMD_COLD_JUNCT_TEMP = 0x02; // ambient temp 37 : //static const uint8_t MCP9600_CMD_RAW_DATA_ADC = 0x03; 38 : static const uint8_t MCP9600_CMD_STATUS = 0x04; 39 : static const uint8_t MCP9600_CMD_SENSOR_CFG = 0x05; 40 : //static const uint8_t MCP9600_CMD_DEVICE_CFG = 0x06; 41 : static const uint8_t MCP9600_CMD_DEVICE_ID_REV = 0x20; // to fetch WHOAMI 42 : 43 : static const uint8_t MCP9600_CMD_STATUS_UPDATE_READY = 0x40; 44 : 45 : static const uint8_t MCP9600_WHOAMI = 0x40; 46 : static const uint8_t MCP9601_WHOAMI = 0x41; 47 : 48 : 49 : #define MCP9600_ADDR_LOW 0x60 // ADDR pin pulled low 50 : #define MCP9600_ADDR_HIGH 0x67 // ADDR pin pulled high 51 : 52 : #define AP_TemperatureSensor_MCP9600_UPDATE_INTERVAL_MS 500 53 : #define AP_TemperatureSensor_MCP9600_SCALE_FACTOR (0.0625f) 54 : 55 : #ifndef AP_TemperatureSensor_MCP9600_ADDR_DEFAULT 56 : #define AP_TemperatureSensor_MCP9600_ADDR_DEFAULT MCP9600_ADDR_LOW 57 : #endif 58 : 59 : #ifndef AP_TemperatureSensor_MCP9600_Filter 60 : #define AP_TemperatureSensor_MCP9600_Filter 2 // can be values 0 through 7 where 0 is no filtering (fast) and 7 is lots of smoothing (very very slow) 61 : #endif 62 : 63 0 : void AP_TemperatureSensor_MCP9600::init() 64 : { 65 0 : constexpr char name[] = "MCP9600"; 66 : 67 0 : _dev = hal.i2c_mgr->get_device_ptr(_params.bus, _params.bus_address); 68 0 : if (!_dev) { 69 : // device not found 70 0 : return; 71 : } 72 : 73 0 : WITH_SEMAPHORE(_dev->get_semaphore()); 74 : 75 0 : _dev->set_retries(10); 76 : 77 : uint8_t buf; 78 0 : if (!_dev->read_registers(MCP9600_CMD_DEVICE_ID_REV, &buf, 1)) { 79 0 : printf("%s failed to get WHOAMI", name); 80 0 : return; 81 : } 82 0 : if (buf != MCP9600_WHOAMI && buf != MCP9601_WHOAMI) { 83 0 : printf("%s Got wrong WHOAMI: detected 0x%2X", name, (unsigned)buf); 84 0 : return; 85 : } 86 0 : if (!set_config(ThermocoupleType::K, AP_TemperatureSensor_MCP9600_Filter)) { 87 0 : printf("%s unable to configure", name); 88 0 : return; 89 : } 90 : 91 : // lower retries for run 92 0 : _dev->set_retries(3); 93 : 94 : /* Request 5Hz update */ 95 0 : _dev->register_periodic_callback(200 * AP_USEC_PER_MSEC, 96 : FUNCTOR_BIND_MEMBER(&AP_TemperatureSensor_MCP9600::_timer, void)); 97 0 : } 98 : 99 0 : void AP_TemperatureSensor_MCP9600::_timer() 100 : { 101 : float temperature; 102 0 : if (read_temperature(temperature)) { 103 0 : set_temperature(temperature); 104 : } 105 0 : } 106 : 107 0 : bool AP_TemperatureSensor_MCP9600::set_config(const ThermocoupleType thermoType, const uint8_t filter) 108 : { 109 0 : const uint8_t data = (uint8_t)thermoType << 4 | (filter & 0x7); 110 0 : if (!_dev->write_register(MCP9600_CMD_SENSOR_CFG, data)) { 111 0 : return false; 112 : } 113 0 : return true; 114 : } 115 : 116 0 : bool AP_TemperatureSensor_MCP9600::read_temperature(float &temperature) 117 : { 118 : // confirm new temperature is available and then read it 119 : 120 : // First, read STATUS register: 121 : uint8_t data[2]; 122 0 : if (!_dev->read_registers(MCP9600_CMD_STATUS, data, 1)) { 123 0 : return false; 124 : } 125 : // check UPDATE bit for new temperature data ready: 126 0 : if ((data[0] & MCP9600_CMD_STATUS_UPDATE_READY) == 0) { 127 0 : return false; 128 : } 129 : // read temperature: 130 0 : if (!_dev->read_registers(MCP9600_CMD_HOT_JUNCT_TEMP, data, 2)) { 131 0 : return false; 132 : } 133 : // clear update bit: 134 0 : if (!_dev->write_register(0x04, data[0] & ~MCP9600_CMD_STATUS_UPDATE_READY)) { 135 0 : return false; 136 : } 137 : 138 : // scale temperature: 139 0 : temperature = int16_t(UINT16_VALUE(data[0], data[1])) * AP_TemperatureSensor_MCP9600_SCALE_FACTOR; 140 : 141 0 : return true; 142 : } 143 : #endif // AP_TEMPERATURE_SENSOR_MCP9600_ENABLED 144 :