diff --git a/boards/px4/fmu-v5x/default.cmake b/boards/px4/fmu-v5x/default.cmake index 5f5fbcea90..4cfebb51be 100644 --- a/boards/px4/fmu-v5x/default.cmake +++ b/boards/px4/fmu-v5x/default.cmake @@ -41,7 +41,7 @@ px4_add_board( pca9685_pwm_out power_monitor/ina226 power_monitor/ina228 - power_monitor/ina23X + power_monitor/ina238 #protocol_splitter pwm_input pwm_out_sim diff --git a/boards/px4/fmu-v5x/init/rc.board_defaults b/boards/px4/fmu-v5x/init/rc.board_defaults index aa658b17da..8338abfacb 100644 --- a/boards/px4/fmu-v5x/init/rc.board_defaults +++ b/boards/px4/fmu-v5x/init/rc.board_defaults @@ -3,7 +3,7 @@ # board specific defaults #------------------------------------------------------------------------------ -param set-default SENS_EN_INA23X 0 +param set-default SENS_EN_INA238 0 param set-default SENS_EN_INA228 0 param set-default SENS_EN_INA226 1 diff --git a/boards/px4/fmu-v5x/init/rc.board_sensors b/boards/px4/fmu-v5x/init/rc.board_sensors index 73ba9d5c9a..1d1d4b0ea5 100644 --- a/boards/px4/fmu-v5x/init/rc.board_sensors +++ b/boards/px4/fmu-v5x/init/rc.board_sensors @@ -19,11 +19,11 @@ then ina228 -X -b 2 -t 2 -k start fi -if param compare SENS_EN_INA23X 1 +if param compare SENS_EN_INA238 1 then # Start Digital power monitors - ina23X -X -b 1 -t 1 -k start - ina23X -X -b 2 -t 2 -k start + ina238 -X -b 1 -t 1 -k start + ina238 -X -b 2 -t 2 -k start fi if ver hwtypecmp V5X90 V5X91 V5X92 V5Xa0 V5Xa1 V5Xa2 diff --git a/boards/px4/fmu-v6x/default.cmake b/boards/px4/fmu-v6x/default.cmake index bdede279be..cbd3d8f9d7 100644 --- a/boards/px4/fmu-v6x/default.cmake +++ b/boards/px4/fmu-v6x/default.cmake @@ -42,7 +42,7 @@ px4_add_board( pca9685_pwm_out power_monitor/ina226 power_monitor/ina228 - power_monitor/ina23X + power_monitor/ina238 #protocol_splitter pwm_out_sim pwm_out diff --git a/boards/px4/fmu-v6x/init/rc.board_defaults b/boards/px4/fmu-v6x/init/rc.board_defaults index aa658b17da..8338abfacb 100644 --- a/boards/px4/fmu-v6x/init/rc.board_defaults +++ b/boards/px4/fmu-v6x/init/rc.board_defaults @@ -3,7 +3,7 @@ # board specific defaults #------------------------------------------------------------------------------ -param set-default SENS_EN_INA23X 0 +param set-default SENS_EN_INA238 0 param set-default SENS_EN_INA228 0 param set-default SENS_EN_INA226 1 diff --git a/boards/px4/fmu-v6x/init/rc.board_sensors b/boards/px4/fmu-v6x/init/rc.board_sensors index b66b0fab77..7d6acf997a 100644 --- a/boards/px4/fmu-v6x/init/rc.board_sensors +++ b/boards/px4/fmu-v6x/init/rc.board_sensors @@ -18,11 +18,11 @@ then ina228 -X -b 2 -t 2 -k start fi -if param compare SENS_EN_INA23X 1 +if param compare SENS_EN_INA238 1 then # Start Digital power monitors - ina23X -X -b 1 -t 1 -k start - ina23X -X -b 2 -t 2 -k start + ina238 -X -b 1 -t 1 -k start + ina238 -X -b 2 -t 2 -k start fi # Internal SPI BMI088 diff --git a/src/drivers/drv_sensor.h b/src/drivers/drv_sensor.h index db3449db7d..4627a39915 100644 --- a/src/drivers/drv_sensor.h +++ b/src/drivers/drv_sensor.h @@ -182,7 +182,7 @@ #define DRV_DIST_DEVTYPE_GY_US42 0x9C #define DRV_BAT_DEVTYPE_BATMON_SMBUS 0x9d -#define DRV_POWER_DEVTYPE_INA23X 0x9E +#define DRV_POWER_DEVTYPE_INA238 0x9E #define DRV_GPIO_DEVTYPE_MCP23009 0x9F #define DRV_GPS_DEVTYPE_ASHTECH 0xA0 diff --git a/src/drivers/power_monitor/ina23X/CMakeLists.txt b/src/drivers/power_monitor/ina238/CMakeLists.txt similarity index 96% rename from src/drivers/power_monitor/ina23X/CMakeLists.txt rename to src/drivers/power_monitor/ina238/CMakeLists.txt index 8e2a966baf..311fdad662 100644 --- a/src/drivers/power_monitor/ina23X/CMakeLists.txt +++ b/src/drivers/power_monitor/ina238/CMakeLists.txt @@ -31,13 +31,13 @@ # ############################################################################ px4_add_module( - MODULE drivers__ina23X - MAIN ina23X + MODULE drivers__ina238 + MAIN ina238 COMPILE_FLAGS -Wno-cast-align # TODO: fix and enable SRCS - ina23X_main.cpp - ina23X.cpp + ina238_main.cpp + ina238.cpp DEPENDS battery px4_work_queue diff --git a/src/drivers/power_monitor/ina23X/ina23X.cpp b/src/drivers/power_monitor/ina238/ina238.cpp similarity index 65% rename from src/drivers/power_monitor/ina23X/ina23X.cpp rename to src/drivers/power_monitor/ina238/ina238.cpp index 70e16ad000..ad37040f66 100644 --- a/src/drivers/power_monitor/ina23X/ina23X.cpp +++ b/src/drivers/power_monitor/ina238/ina238.cpp @@ -32,54 +32,40 @@ ****************************************************************************/ /** - * Driver for the I2C attached INA23X + * Driver for the I2C attached INA238 */ -#include "ina23X.h" +#include "ina238.h" -INA23X::INA23X(const I2CSPIDriverConfig &config, int battery_index) : +INA238::INA238(const I2CSPIDriverConfig &config, int battery_index) : I2C(config), ModuleParams(nullptr), I2CSPIDriver(config), - _sample_perf(perf_alloc(PC_ELAPSED, "ina23X_read")), - _comms_errors(perf_alloc(PC_COUNT, "ina23X_com_err")), - _collection_errors(perf_alloc(PC_COUNT, "ina23X_collection_err")), - _measure_errors(perf_alloc(PC_COUNT, "ina23X_measurement_err")), - _config(INA23X_ADCCONFIG), - _battery(battery_index, this, INA23X_SAMPLE_INTERVAL_US) + _sample_perf(perf_alloc(PC_ELAPSED, "ina238_read")), + _comms_errors(perf_alloc(PC_COUNT, "ina238_com_err")), + _collection_errors(perf_alloc(PC_COUNT, "ina238_collection_err")), + _battery(battery_index, this, INA238_SAMPLE_INTERVAL_US) { float fvalue = DEFAULT_MAX_CURRENT; _max_current = fvalue; - param_t ph = param_find("INA23X_CURRENT"); + param_t ph = param_find("INA238_CURRENT"); if (ph != PARAM_INVALID && param_get(ph, &fvalue) == PX4_OK) { _max_current = fvalue; } - _range = _max_current > (DEFAULT_MAX_CURRENT - 1.0f) ? INA23X_ADCRANGE_HIGH : INA23X_ADCRANGE_LOW; + _range = _max_current > (DEFAULT_MAX_CURRENT - 1.0f) ? INA238_ADCRANGE_HIGH : INA238_ADCRANGE_LOW; fvalue = DEFAULT_SHUNT; _rshunt = fvalue; - ph = param_find("INA23X_SHUNT"); + ph = param_find("INA238_SHUNT"); if (ph != PARAM_INVALID && param_get(ph, &fvalue) == PX4_OK) { _rshunt = fvalue; } - ph = param_find("INA23X_CONFIG"); - int32_t value = INA23X_ADCCONFIG; - _config = (uint16_t)value; - - if (ph != PARAM_INVALID && param_get(ph, &value) == PX4_OK) { - _config = (uint16_t)value; - } - - _mode_triggered = ((_config & INA23X_MODE_MASK) >> INA23X_MODE_SHIFTS) <= - ((INA23X_MODE_TEMP_SHUNT_BUS_TRIG & INA23X_MODE_MASK) >> - INA23X_MODE_SHIFTS); - - _current_lsb = _max_current / INA23X_DN_MAX; + _current_lsb = _max_current / INA238_DN_MAX; // We need to publish immediately, to guarantee that the first instance of the driver publishes to uORB instance 0 _battery.updateBatteryStatus( @@ -93,16 +79,15 @@ INA23X::INA23X(const I2CSPIDriverConfig &config, int battery_index) : ); } -INA23X::~INA23X() +INA238::~INA238() { /* free perf counters */ perf_free(_sample_perf); perf_free(_comms_errors); perf_free(_collection_errors); - perf_free(_measure_errors); } -int INA23X::read(uint8_t address, uint16_t &data) +int INA238::read(uint8_t address, uint16_t &data) { // read desired little-endian value via I2C uint16_t received_bytes; @@ -119,13 +104,13 @@ int INA23X::read(uint8_t address, uint16_t &data) return ret; } -int INA23X::write(uint8_t address, uint16_t value) +int INA238::write(uint8_t address, uint16_t value) { uint8_t data[3] = {address, ((uint8_t)((value & 0xff00) >> 8)), (uint8_t)(value & 0xff)}; return transfer(data, sizeof(data), nullptr, 0); } -int INA23X::init() +int INA238::init() { int ret = PX4_ERROR; @@ -134,30 +119,23 @@ int INA23X::init() return ret; } - write(INA23X_REG_CONFIG, (uint16_t)(INA23X_RST_RESET | _range)); + write(INA238_REG_CONFIG, (uint16_t)(INA238_RST_RESET | _range)); - uint16_t shunt_calibration = static_cast(INA23X_CONST * _current_lsb * _rshunt); + uint16_t shunt_calibration = static_cast(INA238_CONST * _current_lsb * _rshunt); - if (_range == INA23X_ADCRANGE_LOW) { + if (_range == INA238_ADCRANGE_LOW) { shunt_calibration *= 4; } - if (write(INA23X_REG_SHUNTCAL, shunt_calibration) < 0) { + if (write(INA238_REG_SHUNTCAL, shunt_calibration) < 0) { return -3; } // Set the CONFIG for max I - write(INA23X_REG_CONFIG, (uint16_t) _range); + write(INA238_REG_CONFIG, (uint16_t) _range); - // If we run in continuous mode then start it here - - - if (!_mode_triggered) { - ret = write(INA23X_REG_ADCCONFIG, _config); - - } else { - ret = PX4_OK; - } + // Start ADC continous mode here + ret = write(INA238_REG_ADCCONFIG, (uint16_t)INA238_ADCCONFIG); start(); _sensor_ok = true; @@ -166,7 +144,7 @@ int INA23X::init() return ret; } -int INA23X::force_init() +int INA238::force_init() { int ret = init(); @@ -175,18 +153,17 @@ int INA23X::force_init() return ret; } -int INA23X::probe() +int INA238::probe() { uint16_t value{0}; - if (read(INA23X_MANUFACTURER_ID, value) != PX4_OK || value != INA23X_MFG_ID_TI) { + if (read(INA238_MANUFACTURER_ID, value) != PX4_OK || value != INA238_MFG_ID_TI) { PX4_DEBUG("probe mfgid %d", value); return -1; } - if (read(INA23X_DEVICE_ID, value) != PX4_OK || ( - INA23X_DEVICEID(value) != INA238_MFG_DIE && - INA23X_DEVICEID(value) != INA239_MFG_DIE + if (read(INA238_DEVICE_ID, value) != PX4_OK || ( + INA238_DEVICEID(value) != INA238_MFG_DIE )) { PX4_DEBUG("probe die id %d", value); return -1; @@ -195,23 +172,8 @@ int INA23X::probe() return PX4_OK; } -int INA23X::measure() -{ - int ret = PX4_OK; - if (_mode_triggered) { - ret = write(INA23X_REG_ADCCONFIG, _config); - - if (ret < 0) { - perf_count(_comms_errors); - PX4_DEBUG("i2c::transfer returned %d", ret); - } - } - - return ret; -} - -int INA23X::collect() +int INA238::collect() { perf_begin(_sample_perf); @@ -229,8 +191,8 @@ int INA23X::collect() int16_t bus_voltage{0}; int16_t current{0}; - success = success && (read(INA23X_REG_VSBUS, bus_voltage) == PX4_OK); - success = success && (read(INA23X_REG_CURRENT, current) == PX4_OK); + success = success && (read(INA238_REG_VSBUS, bus_voltage) == PX4_OK); + success = success && (read(INA238_REG_CURRENT, current) == PX4_OK); if (!success) { PX4_DEBUG("error reading from sensor"); @@ -241,7 +203,7 @@ int INA23X::collect() _battery.updateBatteryStatus( hrt_absolute_time(), - (float) bus_voltage * INA23X_VSCALE, + (float) bus_voltage * INA238_VSCALE, (float) current * _current_lsb, success, battery_status_s::BATTERY_SOURCE_POWER_MODULE, @@ -259,20 +221,20 @@ int INA23X::collect() } } -void INA23X::start() +void INA238::start() { ScheduleClear(); /* reset the report ring and state machine */ _collect_phase = false; - _measure_interval = INA23X_CONVERSION_INTERVAL; + _measure_interval = INA238_CONVERSION_INTERVAL; /* schedule a cycle to start things */ ScheduleDelayed(5); } -void INA23X::RunImpl() +void INA238::RunImpl() { if (_initialized) { if (_collect_phase) { @@ -285,27 +247,20 @@ void INA23X::RunImpl() } /* next phase is measurement */ - _collect_phase = !_mode_triggered; + _collect_phase = true; - if (_measure_interval > INA23X_CONVERSION_INTERVAL) { + if (_measure_interval > INA238_CONVERSION_INTERVAL) { /* schedule a fresh cycle call when we are ready to measure again */ - ScheduleDelayed(_measure_interval - INA23X_CONVERSION_INTERVAL); + ScheduleDelayed(_measure_interval - INA238_CONVERSION_INTERVAL); return; } } - /* Measurement phase */ - - /* Perform measurement */ - if (measure() != PX4_OK) { - perf_count(_measure_errors); - } - /* next phase is collection */ _collect_phase = true; /* schedule a fresh cycle call when the measurement is done */ - ScheduleDelayed(INA23X_CONVERSION_INTERVAL); + ScheduleDelayed(INA238_CONVERSION_INTERVAL); } else { _battery.updateBatteryStatus( @@ -319,12 +274,12 @@ void INA23X::RunImpl() ); if (init() != PX4_OK) { - ScheduleDelayed(INA23X_INIT_RETRY_INTERVAL_US); + ScheduleDelayed(INA238_INIT_RETRY_INTERVAL_US); } } } -void INA23X::print_status() +void INA238::print_status() { I2CSPIDriverBase::print_status(); @@ -336,6 +291,6 @@ void INA23X::print_status() } else { PX4_INFO("Device not initialized. Retrying every %d ms until battery is plugged in.", - INA23X_INIT_RETRY_INTERVAL_US / 1000); + INA238_INIT_RETRY_INTERVAL_US / 1000); } } diff --git a/src/drivers/power_monitor/ina238/ina238.h b/src/drivers/power_monitor/ina238/ina238.h new file mode 100644 index 0000000000..0de43edb62 --- /dev/null +++ b/src/drivers/power_monitor/ina238/ina238.h @@ -0,0 +1,370 @@ +/**************************************************************************** + * + * Copyright (C) 2021 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + + +#pragma once + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace time_literals; + +/* Configuration Constants */ +#define INA238_BASEADDR 0x45 /* 7-bit address. 8-bit address is 0x45 */ +// If initialization is forced (with the -f flag on the command line), but it fails, the drive will try again to +// connect to the INA238 every this many microseconds +#define INA238_INIT_RETRY_INTERVAL_US 500000 + +/* INA238 Registers addresses */ +#define INA238_REG_CONFIG (0x00) +#define INA238_REG_ADCCONFIG (0x01) +#define INA238_REG_SHUNTCAL (0x02) +#define INA238_REG_SHUNTTEMPCO (0x03) +#define INA238_REG_VSHUNT (0x04) +#define INA238_REG_VSBUS (0x05) +#define INA238_REG_DIETEMP (0x06) +#define INA238_REG_CURRENT (0x07) +#define INA238_REG_POWER (0x08) +#define INA238_REG_ENERGY (0x09) +#define INA238_REG_CHARGE (0x0a) +#define INA238_REG_DIAG_ALRT (0x0b) +#define INA238_REG_SOVL (0x0c) +#define INA238_REG_SUVL (0x0d) +#define INA238_REG_BOVL (0x0e) +#define INA238_REG_BUVL (0x0f) +#define INA238_REG_TEMP_LIMIT (0x10) +#define INA238_REG_TPWR_LIMIT (0x11) +#define INA238_MANUFACTURER_ID (0x3e) +#define INA238_DEVICE_ID (0x3f) + +#define INA238_MFG_ID_TI (0x5449) // TI +#define INA238_MFG_DIE (0x238) // INA237, INA238 + +/* INA238 Configuration (CONFIG) 16-bit Register (Address = 0h) [reset = 0h] */ +#define INA238_ADCRANGE_SHIFTS (4) +#define INA238_ADCRANGE_MASK (1 << INA238_ADCRANGE_SHIFTS) +#define INA238_ADCRANGE_LOW (1 << INA238_ADCRANGE_SHIFTS) // ± 40.96 mV +#define INA238_ADCRANGE_HIGH (0 << INA238_ADCRANGE_SHIFTS) // ±163.84 mV +#define INA238_TEMPCOMP_SHIFTS (5) +#define INA238_TEMPCOMP_MASK (1 << INA238_TEMPCOMP_SHIFTS) +#define INA238_TEMPCOMP_ENABLE (1 << INA238_TEMPCOMP_SHIFTS) +#define INA238_TEMPCOMP_DISABLE (0 << INA238_TEMPCOMP_SHIFTS) + +#define INA238_CONVDLY_SHIFTS (6) +#define INA238_CONVDLY_MASK (0xff << INA238_CONVDLY_SHIFTS) +#define INA238_CONVDLY2MS(n) ((n) << INA238_CONVDLY_SHIFTS) + +#define INA238_RSTACC_SHIFTS (14) +#define INA238_RSTACC_MASK (1 << INA238_RSTACC_SHIFTS) +#define INA238_RSTACC_CLEAR (1 << INA238_RSTACC_SHIFTS) +#define INA238_RSTACC_NORMAL (0 << INA238_RSTACC_SHIFTS) + +#define INA238_RST_SHIFTS (15) +#define INA238_RST_MASK (1 << INA238_RST_SHIFTS) +#define INA238_RST_RESET (1 << INA238_RST_SHIFTS) +#define INA238_RST_NORMAL (0 << INA238_RST_SHIFTS) + +/* INA238 ADC Configuration (ADC_CONFIG) 16-bit Register (Address = 1h) [reset = FB68h] */ +#define INA238_MODE_SHIFTS (12) +#define INA238_MODE_MASK (0xf << INA238_MODE_SHIFTS) +#define INA238_MODE_SHUTDOWN_TRIG (0 << INA238_MODE_SHIFTS) +#define INA238_MODE_BUS_TRIG (1 << INA238_MODE_SHIFTS) +#define INA238_MODE_SHUNT_TRIG (2 << INA238_MODE_SHIFTS) +#define INA238_MODE_SHUNT_BUS_TRIG (3 << INA238_MODE_SHIFTS) +#define INA238_MODE_TEMP_TRIG (4 << INA238_MODE_SHIFTS) +#define INA238_MODE_TEMP_BUS_TRIG (5 << INA238_MODE_SHIFTS) +#define INA238_MODE_TEMP_SHUNT_TRIG (6 << INA238_MODE_SHIFTS) +#define INA238_MODE_TEMP_SHUNT_BUS_TRIG (7 << INA238_MODE_SHIFTS) + +#define INA238_MODE_SHUTDOWN_CONT (8 << INA238_MODE_SHIFTS) +#define INA238_MODE_BUS_CONT (9 << INA238_MODE_SHIFTS) +#define INA238_MODE_SHUNT_CONT (10 << INA238_MODE_SHIFTS) +#define INA238_MODE_SHUNT_BUS_CONT (11 << INA238_MODE_SHIFTS) +#define INA238_MODE_TEMP_CONT (12 << INA238_MODE_SHIFTS) +#define INA238_MODE_TEMP_BUS_CONT (13 << INA238_MODE_SHIFTS) +#define INA238_MODE_TEMP_SHUNT_CONT (14 << INA238_MODE_SHIFTS) +#define INA238_MODE_TEMP_SHUNT_BUS_CONT (15 << INA238_MODE_SHIFTS) + +#define INA238_VBUSCT_SHIFTS (9) +#define INA238_VBUSCT_MASK (7 << INA238_VBUSCT_SHIFTS) +#define INA238_VBUSCT_50US (0 << INA238_VBUSCT_SHIFTS) +#define INA238_VBUSCT_84US (1 << INA238_VBUSCT_SHIFTS) +#define INA238_VBUSCT_150US (2 << INA238_VBUSCT_SHIFTS) +#define INA238_VBUSCT_280US (3 << INA238_VBUSCT_SHIFTS) +#define INA238_VBUSCT_540US (4 << INA238_VBUSCT_SHIFTS) +#define INA238_VBUSCT_1052US (5 << INA238_VBUSCT_SHIFTS) +#define INA238_VBUSCT_2074US (6 << INA238_VBUSCT_SHIFTS) +#define INA238_VBUSCT_4170US (7 << INA238_VBUSCT_SHIFTS) + +#define INA238_VSHCT_SHIFTS (6) +#define INA238_VSHCT_MASK (7 << INA238_VSHCT_SHIFTS) +#define INA238_VSHCT_50US (0 << INA238_VSHCT_SHIFTS) +#define INA238_VSHCT_84US (1 << INA238_VSHCT_SHIFTS) +#define INA238_VSHCT_150US (2 << INA238_VSHCT_SHIFTS) +#define INA238_VSHCT_280US (3 << INA238_VSHCT_SHIFTS) +#define INA238_VSHCT_540US (4 << INA238_VSHCT_SHIFTS) +#define INA238_VSHCT_1052US (5 << INA238_VSHCT_SHIFTS) +#define INA238_VSHCT_2074US (6 << INA238_VSHCT_SHIFTS) +#define INA238_VSHCT_4170US (7 << INA238_VSHCT_SHIFTS) + +#define INA238_VTCT_SHIFTS (3) +#define INA238_VTCT_MASK (7 << INA238_VTCT_SHIFTS) +#define INA238_VTCT_50US (0 << INA238_VTCT_SHIFTS) +#define INA238_VTCT_84US (1 << INA238_VTCT_SHIFTS) +#define INA238_VTCT_150US (2 << INA238_VTCT_SHIFTS) +#define INA238_VTCT_280US (3 << INA238_VTCT_SHIFTS) +#define INA238_VTCT_540US (4 << INA238_VTCT_SHIFTS) +#define INA238_VTCT_1052US (5 << INA238_VTCT_SHIFTS) +#define INA238_VTCT_2074US (6 << INA238_VTCT_SHIFTS) +#define INA238_VTCT_4170US (7 << INA238_VTCT_SHIFTS) + +#define INA238_AVERAGES_SHIFTS (0) +#define INA238_AVERAGES_MASK (7 << INA238_AVERAGES_SHIFTS) +#define INA238_AVERAGES_1 (0 << INA238_AVERAGES_SHIFTS) +#define INA238_AVERAGES_4 (1 << INA238_AVERAGES_SHIFTS) +#define INA238_AVERAGES_16 (2 << INA238_AVERAGES_SHIFTS) +#define INA238_AVERAGES_64 (3 << INA238_AVERAGES_SHIFTS) +#define INA238_AVERAGES_128 (4 << INA238_AVERAGES_SHIFTS) +#define INA238_AVERAGES_256 (5 << INA238_AVERAGES_SHIFTS) +#define INA238_AVERAGES_512 (6 << INA238_AVERAGES_SHIFTS) +#define INA238_AVERAGES_1024 (7 << INA238_AVERAGES_SHIFTS) + +#define INA238_ADCCONFIG (INA238_MODE_TEMP_SHUNT_BUS_CONT | INA238_VBUSCT_540US | INA238_VSHCT_540US | INA238_VTCT_540US |INA238_AVERAGES_64) + +/* INA238 Shunt Calibration (SHUNT_CAL) 16-bit Register (Address = 2h) [reset = 1000h] */ + +#define INA238_CURRLSB_SHIFTS (0) +#define INA238_CURRLSB_MASK (0x7fff << INA238_CURRLSB_SHIFTS) + +/* INA238 Shunt Temperature Coefficient (SHUNT_TEMPCO) 16-bit Register (Address = 3h) [reset = 0h] */ + +#define INA238_TEMPCO_SHIFTS (0) +#define INA238_TEMPCO_MASK (0x1fff << INA238_TEMPCO_SHIFTS) + +/* INA238 Shunt Voltage Measurement (VSHUNT) 24-bit Register (Address = 4h) [reset = 0h] */ + +#define INA238_VSHUNT_SHIFTS (4) +#define INA238_VSHUNT_MASK (UINT32_C(0xffffff) << INA238_VSHUNT_SHIFTS) + +/* INA238 Bus Voltage Measurement (VBUS) 24-bit Register (Address = 5h) [reset = 0h] */ + +#define INA238_VBUS_SHIFTS (4) +#define INA238_VBUS_MASK (UINT32_C(0xffffff) << INA238_VBUS_SHIFTS) + +/* INA238 Temperature Measurement (DIETEMP) 16-bit Register (Address = 6h) [reset = 0h] */ + +#define INA238_DIETEMP_SHIFTS (0) +#define INA238_DIETEMP_MASK (0xffff << INA238_DIETEMP_SHIFTS) + +/* INA238 Current Result (CURRENT) 24-bit Register (Address = 7h) [reset = 0h] */ + +#define INA238_CURRENT_SHIFTS (4) +#define INA238_CURRENT_MASK (UINT32_C(0xffffff) << INA238_CURRENT_SHIFTS) + +/* INA238 Power Result (POWER) 24-bit Register (Address = 8h) [reset = 0h] */ + +#define INA238_POWER_SHIFTS (0) +#define INA238_POWER_MASK (UINT32_C(0xffffff) << INA238_POWER_SHIFTS) + +/* INA238 Energy Result (ENERGY) 40-bit Register (Address = 9h) [reset = 0h] */ + +#define INA238_ENERGY_SHIFTS (0) +#define INA238_ENERGY_MASK (UINT64_C(0xffffffffff) << INA238_ENERGY_SHIFTS) + +/* INA238 Energy Result (CHARGE) 40-bit Register (Address = Ah) [reset = 0h] */ + +#define INA238_CHARGE_SHIFTS (0) +#define INA238_CHARGE_MASK (UINT64_C(0xffffffffff) << INA238_CHARGE_SHIFTS) + + +/* INA238 Diagnostic Flags and Alert (DIAG_ALRT) 16-bit Register (Address = Bh) [reset = 0001h] */ + +#define INA238_MEMSTAT (1 << 0) // This bit is set to 0 if a checksum error is detected in the device trim memory space +#define INA238_CNVRF (1 << 1) // This bit is set to 1 if the conversion is completed. When ALATCH =1 this bit is cleared by reading the register or starting a new triggered conversion. +#define INA238_POL (1 << 2) // This bit is set to 1 if the power measurement exceeds the threshold limit in the power limit register. +#define INA238_BUSUL (1 << 3) // This bit is set to 1 if the bus voltage measurement falls below the threshold limit in the bus under-limit register. +#define INA238_BUSOL (1 << 4) // This bit is set to 1 if the bus voltage measurement exceeds the threshold limit in the bus over-limit register. +#define INA238_SHNTUL (1 << 5) // This bit is set to 1 if the shunt voltage measurement falls below the threshold limit in the shunt under-limit register +#define INA238_SHNTOL (1 << 6) // This bit is set to 1 if the shunt voltage measurement exceeds the threshold limit in the shunt over-limit register. +#define INA238_TMPOL (1 << 7) // This bit is set to 1 if the temperature measurement exceeds the threshold limit in the temperature over-limit register. +#define INA238_MATHOF (1 << 9) // This bit is set to 1 if an arithmetic operation resulted in an overflow error. +#define INA238_CHARGEOF (1 << 10) // This bit indicates the health of the CHARGE register. If the 40 bit CHARGE register has overflowed this bit is set to 1. +#define INA238_ENERGYOF (1 << 11) // This bit indicates the health of the ENERGY register. If the 40 bit ENERGY register has overflowed this bit is set to 1. +#define INA238_APOL (1 << 12) // Alert Polarity bit sets the Alert pin polarity. +#define INA238_SLOWALER (1 << 13) // ALERT function is asserted on the completed averaged value. This gives the flexibility to delay the ALERT after the averaged value. +#define INA238_CNVR (1 << 14) // Setting this bit high configures the Alert pin to be asserted when the Conversion Ready Flag (bit 1) is asserted, indicating that a conversion cycle has completed +#define INA238_ALATCH (1 << 15) // When the Alert Latch Enable bit is set to Transparent mode, the Alert pin and Flag bit reset to the idle state when the fault has been +// cleared. When the Alert Latch Enable bit is set to Latch mode, the Alert pin and Alert Flag bit remain active following a fault until +// the DIAG_ALRT Register has been read. + +/* Shunt Overvoltage Threshold (SOVL) 16-bit Register (Address = Ch) [reset = 7FFFh] */ + +#define INA238_SOVL_SHIFTS (0) +#define INA238_SOVL_MASK (0xffff << INA238_SOVL_SHIFTS) + +/* Shunt Undervoltage Threshold (SUVL) 16-bit Register (Address = Dh) [reset = 8000h] */ + +#define INA238_SUVL_SHIFTS (0) +#define INA238_SUVL_MASK (0xffff << INA238_SUVL_SHIFTS) + +/* Bus Overvoltage Threshold (BOVL) 16-bit Register (Address = Eh) [reset = 7FFFh] */ + +#define INA238_BOVL_SHIFTS (0) +#define INA238_BOVL_MASK (0xffff << INA238_BOVL_SHIFTS) + +/* Bus Undervoltage Threshold (BUVL) 16-bit Register (Address = Fh) [reset = 0h] */ + +#define INA238_BUVL_SHIFTS (0) +#define INA238_BUVL_MASK (0xffff << INA238_BUVL_SHIFTS) + +/* Temperature Over-Limit Threshold (TEMP_LIMIT) 16-bit Register (Address = 10h) [reset = 7FFFh */ + +#define INA238_TEMP_LIMIT_SHIFTS (0) +#define INA238_TEMP_LIMIT_MASK (0xffff << INA238_TEMP_LIMIT_SHIFTS) + +/* Power Over-Limit Threshold (PWR_LIMIT) 16-bit Register (Address = 11h) [reset = FFFFh] */ + +#define INA238_POWER_LIMIT_SHIFTS (0) +#define INA238_POWER_LIMIT_MASK (0xffff << INA238_POWER_LIMIT_SHIFTS) + +/* Manufacturer ID (MANUFACTURER_ID) 16-bit Register (Address = 3Eh) [reset = 5449h] */ + +/* Device ID (DEVICE_ID) 16-bit Register (Address = 3Fh) [reset = 2380h] */ + +#define INA238_DEVICE_REV_ID_SHIFTS (0) +#define INA238_DEVICE_REV_ID_MASK (0xf << INA238_DEVICE_REV_ID_SHIFTS) +#define INA238_DEVICEREV_ID(v) (((v) & INA238_DEVICE_REV_ID_MASK) >> INA238_DEVICE_REV_ID_SHIFTS) +#define INA238_DEVICE_ID_SHIFTS (4) +#define INA238_DEVICE_ID_MASK (0xfff << INA238_DEVICE_ID_SHIFTS) +#define INA238_DEVICEID(v) (((v) & INA238_DEVICE_ID_MASK) >> INA238_DEVICE_ID_SHIFTS) + +#define INA238_SAMPLE_FREQUENCY_HZ 10 +#define INA238_SAMPLE_INTERVAL_US (1_s / INA238_SAMPLE_FREQUENCY_HZ) +#define INA238_CONVERSION_INTERVAL (INA238_SAMPLE_INTERVAL_US - 7) +#define INA238_DN_MAX 32768.0f /* 2^15 */ +#define INA238_CONST 819.2e6f /* is an internal fixed value used to ensure scaling is maintained properly */ +#define INA238_VSCALE 3.125e-03f /* LSB of voltage is 3.1255 mV/LSB */ + + +#define DEFAULT_MAX_CURRENT 327.68f /* Amps */ +#define DEFAULT_SHUNT 0.0003f /* Shunt is 300 uOhm */ + +#define swap16(w) __builtin_bswap16((w)) +#define swap32(d) __builtin_bswap32((d)) +#define swap64(q) __builtin_bswap64((q)) + +class INA238 : public device::I2C, public ModuleParams, public I2CSPIDriver +{ +public: + INA238(const I2CSPIDriverConfig &config, int battery_index); + virtual ~INA238(); + + static I2CSPIDriverBase *instantiate(const I2CSPIDriverConfig &config, int runtime_instance); + static void print_usage(); + + void RunImpl(); + + int init() override; + + /** + * Tries to call the init() function. If it fails, then it will schedule to retry again in + * INA238_INIT_RETRY_INTERVAL_US microseconds. It will keep retrying at this interval until initialization succeeds. + * + * @return PX4_OK if initialization succeeded on the first try. Negative value otherwise. + */ + int force_init(); + + /** + * Diagnostics - print some basic information about the driver. + */ + void print_status() override; + +protected: + int probe() override; + +private: + bool _sensor_ok{false}; + unsigned int _measure_interval{0}; + bool _collect_phase{false}; + bool _initialized{false}; + + perf_counter_t _sample_perf; + perf_counter_t _comms_errors; + perf_counter_t _collection_errors; + + // Configuration state, computed from params + float _max_current; + float _rshunt; + float _current_lsb; + int16_t _range; + + actuator_controls_s _actuator_controls{}; + + Battery _battery; + uORB::Subscription _actuators_sub{ORB_ID(actuator_controls_0)}; + uORB::SubscriptionInterval _parameter_update_sub{ORB_ID(parameter_update), 1_s}; + + int read(uint8_t address, uint16_t &data); + int write(uint8_t address, uint16_t data); + + int read(uint8_t address, int16_t &data) + { + return read(address, (uint16_t &)data); + } + + int write(uint8_t address, int16_t data) + { + return write(address, (uint16_t)data); + } + + /** + * Initialise the automatic measurement state machine and start it. + * + * @note This function is called at open and error time. It might make sense + * to make it more aggressive about resetting the bus in case of errors. + */ + void start(); + + int collect(); + +}; diff --git a/src/drivers/power_monitor/ina23X/ina23X_main.cpp b/src/drivers/power_monitor/ina238/ina238_main.cpp similarity index 88% rename from src/drivers/power_monitor/ina23X/ina23X_main.cpp rename to src/drivers/power_monitor/ina238/ina238_main.cpp index 9cfc64f1f3..879d0a0cf3 100644 --- a/src/drivers/power_monitor/ina23X/ina23X_main.cpp +++ b/src/drivers/power_monitor/ina238/ina238_main.cpp @@ -33,11 +33,11 @@ #include #include -#include "ina23X.h" +#include "ina238.h" -I2CSPIDriverBase *INA23X::instantiate(const I2CSPIDriverConfig &config, int runtime_instance) +I2CSPIDriverBase *INA238::instantiate(const I2CSPIDriverConfig &config, int runtime_instance) { - INA23X *instance = new INA23X(config, config.custom1); + INA238 *instance = new INA238(config, config.custom1); if (instance == nullptr) { PX4_ERR("alloc failed"); @@ -46,7 +46,7 @@ I2CSPIDriverBase *INA23X::instantiate(const I2CSPIDriverConfig &config, int runt if (config.keep_running) { if (instance->force_init() != PX4_OK) { - PX4_INFO("Failed to init INA23X on bus %d, but will try again periodically.", config.bus); + PX4_INFO("Failed to init INA238 on bus %d, but will try again periodically.", config.bus); } } else if (instance->init() != PX4_OK) { @@ -58,25 +58,25 @@ I2CSPIDriverBase *INA23X::instantiate(const I2CSPIDriverConfig &config, int runt } void -INA23X::print_usage() +INA238::print_usage() { PRINT_MODULE_DESCRIPTION( R"DESCR_STR( ### Description -Driver for the INA23X power monitor. +Driver for the INA238 power monitor. Multiple instances of this driver can run simultaneously, if each instance has a separate bus OR I2C address. For example, one instance can run on Bus 2, address 0x45, and one can run on Bus 2, address 0x45. -If the INA23X module is not powered, then by default, initialization of the driver will fail. To change this, use +If the INA238 module is not powered, then by default, initialization of the driver will fail. To change this, use the -f flag. If this flag is set, then if initialization fails, the driver will keep trying to initialize again every 0.5 seconds. With this flag set, you can plug in a battery after the driver starts, and it will work. Without this flag set, the battery must be plugged in before starting the driver. )DESCR_STR"); - PRINT_MODULE_USAGE_NAME("ina23X", "driver"); + PRINT_MODULE_USAGE_NAME("ina238", "driver"); PRINT_MODULE_USAGE_COMMAND("start"); PRINT_MODULE_USAGE_PARAMS_I2C_SPI_DRIVER(true, false); @@ -87,12 +87,12 @@ this flag set, the battery must be plugged in before starting the driver. } extern "C" int -ina23X_main(int argc, char *argv[]) +ina238_main(int argc, char *argv[]) { int ch; - using ThisDriver = INA23X; + using ThisDriver = INA238; BusCLIArguments cli{true, false}; - cli.i2c_address = INA23X_BASEADDR; + cli.i2c_address = INA238_BASEADDR; cli.default_i2c_frequency = 100000; cli.support_keep_running = true; cli.custom1 = 1; @@ -111,7 +111,7 @@ ina23X_main(int argc, char *argv[]) return -1; } - BusInstanceIterator iterator(MODULE_NAME, cli, DRV_POWER_DEVTYPE_INA23X); + BusInstanceIterator iterator(MODULE_NAME, cli, DRV_POWER_DEVTYPE_INA238); if (!strcmp(verb, "start")) { return ThisDriver::module_start(cli, iterator); diff --git a/src/drivers/power_monitor/ina23X/ina23X_params.c b/src/drivers/power_monitor/ina238/ina238_params.c similarity index 81% rename from src/drivers/power_monitor/ina23X/ina23X_params.c rename to src/drivers/power_monitor/ina238/ina238_params.c index 9858a35a76..585cb01512 100644 --- a/src/drivers/power_monitor/ina23X/ina23X_params.c +++ b/src/drivers/power_monitor/ina238/ina238_params.c @@ -32,29 +32,18 @@ ****************************************************************************/ /** - * Enable INA23X Power Monitor + * Enable INA238 Power Monitor * - * For systems a INA23X Power Monitor, this should be set to true + * For systems a INA238 Power Monitor, this should be set to true * * @group Sensors * @boolean * @reboot_required true */ -PARAM_DEFINE_INT32(SENS_EN_INA23X, 0); +PARAM_DEFINE_INT32(SENS_EN_INA238, 0); /** - * INA23X Power Monitor Config - * - * @group Sensors - * @min 0 - * @max 65535 - * @decimal 1 - * @increment 1 -*/ -PARAM_DEFINE_INT32(INA23X_CONFIG, 63779); - -/** - * INA23X Power Monitor Max Current + * INA238 Power Monitor Max Current * * @group Sensors * @min 0.1 @@ -62,10 +51,10 @@ PARAM_DEFINE_INT32(INA23X_CONFIG, 63779); * @decimal 2 * @increment 0.1 */ -PARAM_DEFINE_FLOAT(INA23X_CURRENT, 327.68f); +PARAM_DEFINE_FLOAT(INA238_CURRENT, 327.68f); /** - * INA23X Power Monitor Shunt + * INA238 Power Monitor Shunt * * @group Sensors * @min 0.000000001 @@ -73,4 +62,4 @@ PARAM_DEFINE_FLOAT(INA23X_CURRENT, 327.68f); * @decimal 10 * @increment .000000001 */ -PARAM_DEFINE_FLOAT(INA23X_SHUNT, 0.0003f); +PARAM_DEFINE_FLOAT(INA238_SHUNT, 0.0003f); diff --git a/src/drivers/power_monitor/ina23X/ina23X.h b/src/drivers/power_monitor/ina23X/ina23X.h deleted file mode 100644 index 255b31ec35..0000000000 --- a/src/drivers/power_monitor/ina23X/ina23X.h +++ /dev/null @@ -1,375 +0,0 @@ -/**************************************************************************** - * - * Copyright (C) 2021 PX4 Development Team. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name PX4 nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - - -#pragma once - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace time_literals; - -/* Configuration Constants */ -#define INA23X_BASEADDR 0x45 /* 7-bit address. 8-bit address is 0x45 */ -// If initialization is forced (with the -f flag on the command line), but it fails, the drive will try again to -// connect to the INA23X every this many microseconds -#define INA23X_INIT_RETRY_INTERVAL_US 500000 - -/* INA23X Registers addresses */ -#define INA23X_REG_CONFIG (0x00) -#define INA23X_REG_ADCCONFIG (0x01) -#define INA23X_REG_SHUNTCAL (0x02) -#define INA23X_REG_SHUNTTEMPCO (0x03) -#define INA23X_REG_VSHUNT (0x04) -#define INA23X_REG_VSBUS (0x05) -#define INA23X_REG_DIETEMP (0x06) -#define INA23X_REG_CURRENT (0x07) -#define INA23X_REG_POWER (0x08) -#define INA23X_REG_ENERGY (0x09) -#define INA23X_REG_CHARGE (0x0a) -#define INA23X_REG_DIAG_ALRT (0x0b) -#define INA23X_REG_SOVL (0x0c) -#define INA23X_REG_SUVL (0x0d) -#define INA23X_REG_BOVL (0x0e) -#define INA23X_REG_BUVL (0x0f) -#define INA23X_REG_TEMP_LIMIT (0x10) -#define INA23X_REG_TPWR_LIMIT (0x11) -#define INA23X_MANUFACTURER_ID (0x3e) -#define INA23X_DEVICE_ID (0x3f) - -#define INA23X_MFG_ID_TI (0x5449) // TI -#define INA238_MFG_DIE (0x238) // INA237, INA238 -#define INA239_MFG_DIE (0x239) // INA239 - -/* INA23X Configuration (CONFIG) 16-bit Register (Address = 0h) [reset = 0h] */ -#define INA23X_ADCRANGE_SHIFTS (4) -#define INA23X_ADCRANGE_MASK (1 << INA23X_ADCRANGE_SHIFTS) -#define INA23X_ADCRANGE_LOW (1 << INA23X_ADCRANGE_SHIFTS) // ± 40.96 mV -#define INA23X_ADCRANGE_HIGH (0 << INA23X_ADCRANGE_SHIFTS) // ±163.84 mV -#define INA23X_TEMPCOMP_SHIFTS (5) -#define INA23X_TEMPCOMP_MASK (1 << INA23X_TEMPCOMP_SHIFTS) -#define INA23X_TEMPCOMP_ENABLE (1 << INA23X_TEMPCOMP_SHIFTS) -#define INA23X_TEMPCOMP_DISABLE (0 << INA23X_TEMPCOMP_SHIFTS) - -#define INA23X_CONVDLY_SHIFTS (6) -#define INA23X_CONVDLY_MASK (0xff << INA23X_CONVDLY_SHIFTS) -#define INA23X_CONVDLY2MS(n) ((n) << INA23X_CONVDLY_SHIFTS) - -#define INA23X_RSTACC_SHIFTS (14) -#define INA23X_RSTACC_MASK (1 << INA23X_RSTACC_SHIFTS) -#define INA23X_RSTACC_CLEAR (1 << INA23X_RSTACC_SHIFTS) -#define INA23X_RSTACC_NORMAL (0 << INA23X_RSTACC_SHIFTS) - -#define INA23X_RST_SHIFTS (15) -#define INA23X_RST_MASK (1 << INA23X_RST_SHIFTS) -#define INA23X_RST_RESET (1 << INA23X_RST_SHIFTS) -#define INA23X_RST_NORMAL (0 << INA23X_RST_SHIFTS) - -/* INA23X ADC Configuration (ADC_CONFIG) 16-bit Register (Address = 1h) [reset = FB68h] */ -#define INA23X_MODE_SHIFTS (12) -#define INA23X_MODE_MASK (0xf << INA23X_MODE_SHIFTS) -#define INA23X_MODE_SHUTDOWN_TRIG (0 << INA23X_MODE_SHIFTS) -#define INA23X_MODE_BUS_TRIG (1 << INA23X_MODE_SHIFTS) -#define INA23X_MODE_SHUNT_TRIG (2 << INA23X_MODE_SHIFTS) -#define INA23X_MODE_SHUNT_BUS_TRIG (3 << INA23X_MODE_SHIFTS) -#define INA23X_MODE_TEMP_TRIG (4 << INA23X_MODE_SHIFTS) -#define INA23X_MODE_TEMP_BUS_TRIG (5 << INA23X_MODE_SHIFTS) -#define INA23X_MODE_TEMP_SHUNT_TRIG (6 << INA23X_MODE_SHIFTS) -#define INA23X_MODE_TEMP_SHUNT_BUS_TRIG (7 << INA23X_MODE_SHIFTS) - -#define INA23X_MODE_SHUTDOWN_CONT (8 << INA23X_MODE_SHIFTS) -#define INA23X_MODE_BUS_CONT (9 << INA23X_MODE_SHIFTS) -#define INA23X_MODE_SHUNT_CONT (10 << INA23X_MODE_SHIFTS) -#define INA23X_MODE_SHUNT_BUS_CONT (11 << INA23X_MODE_SHIFTS) -#define INA23X_MODE_TEMP_CONT (12 << INA23X_MODE_SHIFTS) -#define INA23X_MODE_TEMP_BUS_CONT (13 << INA23X_MODE_SHIFTS) -#define INA23X_MODE_TEMP_SHUNT_CONT (14 << INA23X_MODE_SHIFTS) -#define INA23X_MODE_TEMP_SHUNT_BUS_CONT (15 << INA23X_MODE_SHIFTS) - -#define INA23X_VBUSCT_SHIFTS (9) -#define INA23X_VBUSCT_MASK (7 << INA23X_VBUSCT_SHIFTS) -#define INA23X_VBUSCT_50US (0 << INA23X_VBUSCT_SHIFTS) -#define INA23X_VBUSCT_84US (1 << INA23X_VBUSCT_SHIFTS) -#define INA23X_VBUSCT_150US (2 << INA23X_VBUSCT_SHIFTS) -#define INA23X_VBUSCT_280US (3 << INA23X_VBUSCT_SHIFTS) -#define INA23X_VBUSCT_540US (4 << INA23X_VBUSCT_SHIFTS) -#define INA23X_VBUSCT_1052US (5 << INA23X_VBUSCT_SHIFTS) -#define INA23X_VBUSCT_2074US (6 << INA23X_VBUSCT_SHIFTS) -#define INA23X_VBUSCT_4170US (7 << INA23X_VBUSCT_SHIFTS) - -#define INA23X_VSHCT_SHIFTS (6) -#define INA23X_VSHCT_MASK (7 << INA23X_VSHCT_SHIFTS) -#define INA23X_VSHCT_50US (0 << INA23X_VSHCT_SHIFTS) -#define INA23X_VSHCT_84US (1 << INA23X_VSHCT_SHIFTS) -#define INA23X_VSHCT_150US (2 << INA23X_VSHCT_SHIFTS) -#define INA23X_VSHCT_280US (3 << INA23X_VSHCT_SHIFTS) -#define INA23X_VSHCT_540US (4 << INA23X_VSHCT_SHIFTS) -#define INA23X_VSHCT_1052US (5 << INA23X_VSHCT_SHIFTS) -#define INA23X_VSHCT_2074US (6 << INA23X_VSHCT_SHIFTS) -#define INA23X_VSHCT_4170US (7 << INA23X_VSHCT_SHIFTS) - -#define INA23X_VTCT_SHIFTS (3) -#define INA23X_VTCT_MASK (7 << INA23X_VTCT_SHIFTS) -#define INA23X_VTCT_50US (0 << INA23X_VTCT_SHIFTS) -#define INA23X_VTCT_84US (1 << INA23X_VTCT_SHIFTS) -#define INA23X_VTCT_150US (2 << INA23X_VTCT_SHIFTS) -#define INA23X_VTCT_280US (3 << INA23X_VTCT_SHIFTS) -#define INA23X_VTCT_540US (4 << INA23X_VTCT_SHIFTS) -#define INA23X_VTCT_1052US (5 << INA23X_VTCT_SHIFTS) -#define INA23X_VTCT_2074US (6 << INA23X_VTCT_SHIFTS) -#define INA23X_VTCT_4170US (7 << INA23X_VTCT_SHIFTS) - -#define INA23X_AVERAGES_SHIFTS (0) -#define INA23X_AVERAGES_MASK (7 << INA23X_AVERAGES_SHIFTS) -#define INA23X_AVERAGES_1 (0 << INA23X_AVERAGES_SHIFTS) -#define INA23X_AVERAGES_4 (1 << INA23X_AVERAGES_SHIFTS) -#define INA23X_AVERAGES_16 (2 << INA23X_AVERAGES_SHIFTS) -#define INA23X_AVERAGES_64 (3 << INA23X_AVERAGES_SHIFTS) -#define INA23X_AVERAGES_128 (4 << INA23X_AVERAGES_SHIFTS) -#define INA23X_AVERAGES_256 (5 << INA23X_AVERAGES_SHIFTS) -#define INA23X_AVERAGES_512 (6 << INA23X_AVERAGES_SHIFTS) -#define INA23X_AVERAGES_1024 (7 << INA23X_AVERAGES_SHIFTS) - -#define INA23X_ADCCONFIG (INA23X_MODE_TEMP_SHUNT_BUS_CONT | INA23X_VBUSCT_540US | INA23X_VSHCT_540US | INA23X_VTCT_540US |INA23X_AVERAGES_64) - -/* INA23X Shunt Calibration (SHUNT_CAL) 16-bit Register (Address = 2h) [reset = 1000h] */ - -#define INA23X_CURRLSB_SHIFTS (0) -#define INA23X_CURRLSB_MASK (0x7fff << INA23X_CURRLSB_SHIFTS) - -/* INA23X Shunt Temperature Coefficient (SHUNT_TEMPCO) 16-bit Register (Address = 3h) [reset = 0h] */ - -#define INA23X_TEMPCO_SHIFTS (0) -#define INA23X_TEMPCO_MASK (0x1fff << INA23X_TEMPCO_SHIFTS) - -/* INA23X Shunt Voltage Measurement (VSHUNT) 24-bit Register (Address = 4h) [reset = 0h] */ - -#define INA23X_VSHUNT_SHIFTS (4) -#define INA23X_VSHUNT_MASK (UINT32_C(0xffffff) << INA23X_VSHUNT_SHIFTS) - -/* INA23X Bus Voltage Measurement (VBUS) 24-bit Register (Address = 5h) [reset = 0h] */ - -#define INA23X_VBUS_SHIFTS (4) -#define INA23X_VBUS_MASK (UINT32_C(0xffffff) << INA23X_VBUS_SHIFTS) - -/* INA23X Temperature Measurement (DIETEMP) 16-bit Register (Address = 6h) [reset = 0h] */ - -#define INA23X_DIETEMP_SHIFTS (0) -#define INA23X_DIETEMP_MASK (0xffff << INA23X_DIETEMP_SHIFTS) - -/* INA23X Current Result (CURRENT) 24-bit Register (Address = 7h) [reset = 0h] */ - -#define INA23X_CURRENT_SHIFTS (4) -#define INA23X_CURRENT_MASK (UINT32_C(0xffffff) << INA23X_CURRENT_SHIFTS) - -/* INA23X Power Result (POWER) 24-bit Register (Address = 8h) [reset = 0h] */ - -#define INA23X_POWER_SHIFTS (0) -#define INA23X_POWER_MASK (UINT32_C(0xffffff) << INA23X_POWER_SHIFTS) - -/* INA23X Energy Result (ENERGY) 40-bit Register (Address = 9h) [reset = 0h] */ - -#define INA23X_ENERGY_SHIFTS (0) -#define INA23X_ENERGY_MASK (UINT64_C(0xffffffffff) << INA23X_ENERGY_SHIFTS) - -/* INA23X Energy Result (CHARGE) 40-bit Register (Address = Ah) [reset = 0h] */ - -#define INA23X_CHARGE_SHIFTS (0) -#define INA23X_CHARGE_MASK (UINT64_C(0xffffffffff) << INA23X_CHARGE_SHIFTS) - - -/* INA23X Diagnostic Flags and Alert (DIAG_ALRT) 16-bit Register (Address = Bh) [reset = 0001h] */ - -#define INA23X_MEMSTAT (1 << 0) // This bit is set to 0 if a checksum error is detected in the device trim memory space -#define INA23X_CNVRF (1 << 1) // This bit is set to 1 if the conversion is completed. When ALATCH =1 this bit is cleared by reading the register or starting a new triggered conversion. -#define INA23X_POL (1 << 2) // This bit is set to 1 if the power measurement exceeds the threshold limit in the power limit register. -#define INA23X_BUSUL (1 << 3) // This bit is set to 1 if the bus voltage measurement falls below the threshold limit in the bus under-limit register. -#define INA23X_BUSOL (1 << 4) // This bit is set to 1 if the bus voltage measurement exceeds the threshold limit in the bus over-limit register. -#define INA23X_SHNTUL (1 << 5) // This bit is set to 1 if the shunt voltage measurement falls below the threshold limit in the shunt under-limit register -#define INA23X_SHNTOL (1 << 6) // This bit is set to 1 if the shunt voltage measurement exceeds the threshold limit in the shunt over-limit register. -#define INA23X_TMPOL (1 << 7) // This bit is set to 1 if the temperature measurement exceeds the threshold limit in the temperature over-limit register. -#define INA23X_MATHOF (1 << 9) // This bit is set to 1 if an arithmetic operation resulted in an overflow error. -#define INA23X_CHARGEOF (1 << 10) // This bit indicates the health of the CHARGE register. If the 40 bit CHARGE register has overflowed this bit is set to 1. -#define INA23X_ENERGYOF (1 << 11) // This bit indicates the health of the ENERGY register. If the 40 bit ENERGY register has overflowed this bit is set to 1. -#define INA23X_APOL (1 << 12) // Alert Polarity bit sets the Alert pin polarity. -#define INA23X_SLOWALER (1 << 13) // ALERT function is asserted on the completed averaged value. This gives the flexibility to delay the ALERT after the averaged value. -#define INA23X_CNVR (1 << 14) // Setting this bit high configures the Alert pin to be asserted when the Conversion Ready Flag (bit 1) is asserted, indicating that a conversion cycle has completed -#define INA23X_ALATCH (1 << 15) // When the Alert Latch Enable bit is set to Transparent mode, the Alert pin and Flag bit reset to the idle state when the fault has been -// cleared. When the Alert Latch Enable bit is set to Latch mode, the Alert pin and Alert Flag bit remain active following a fault until -// the DIAG_ALRT Register has been read. - -/* Shunt Overvoltage Threshold (SOVL) 16-bit Register (Address = Ch) [reset = 7FFFh] */ - -#define INA23X_SOVL_SHIFTS (0) -#define INA23X_SOVL_MASK (0xffff << INA23X_SOVL_SHIFTS) - -/* Shunt Undervoltage Threshold (SUVL) 16-bit Register (Address = Dh) [reset = 8000h] */ - -#define INA23X_SUVL_SHIFTS (0) -#define INA23X_SUVL_MASK (0xffff << INA23X_SUVL_SHIFTS) - -/* Bus Overvoltage Threshold (BOVL) 16-bit Register (Address = Eh) [reset = 7FFFh] */ - -#define INA23X_BOVL_SHIFTS (0) -#define INA23X_BOVL_MASK (0xffff << INA23X_BOVL_SHIFTS) - -/* Bus Undervoltage Threshold (BUVL) 16-bit Register (Address = Fh) [reset = 0h] */ - -#define INA23X_BUVL_SHIFTS (0) -#define INA23X_BUVL_MASK (0xffff << INA23X_BUVL_SHIFTS) - -/* Temperature Over-Limit Threshold (TEMP_LIMIT) 16-bit Register (Address = 10h) [reset = 7FFFh */ - -#define INA23X_TEMP_LIMIT_SHIFTS (0) -#define INA23X_TEMP_LIMIT_MASK (0xffff << INA23X_TEMP_LIMIT_SHIFTS) - -/* Power Over-Limit Threshold (PWR_LIMIT) 16-bit Register (Address = 11h) [reset = FFFFh] */ - -#define INA23X_POWER_LIMIT_SHIFTS (0) -#define INA23X_POWER_LIMIT_MASK (0xffff << INA23X_POWER_LIMIT_SHIFTS) - -/* Manufacturer ID (MANUFACTURER_ID) 16-bit Register (Address = 3Eh) [reset = 5449h] */ - -/* Device ID (DEVICE_ID) 16-bit Register (Address = 3Fh) [reset = 23X0h] */ - -#define INA23X_DEVICE_REV_ID_SHIFTS (0) -#define INA23X_DEVICE_REV_ID_MASK (0xf << INA23X_DEVICE_REV_ID_SHIFTS) -#define INA23X_DEVICEREV_ID(v) (((v) & INA23X_DEVICE_REV_ID_MASK) >> INA23X_DEVICE_REV_ID_SHIFTS) -#define INA23X_DEVICE_ID_SHIFTS (4) -#define INA23X_DEVICE_ID_MASK (0xfff << INA23X_DEVICE_ID_SHIFTS) -#define INA23X_DEVICEID(v) (((v) & INA23X_DEVICE_ID_MASK) >> INA23X_DEVICE_ID_SHIFTS) - -#define INA23X_SAMPLE_FREQUENCY_HZ 10 -#define INA23X_SAMPLE_INTERVAL_US (1_s / INA23X_SAMPLE_FREQUENCY_HZ) -#define INA23X_CONVERSION_INTERVAL (INA23X_SAMPLE_INTERVAL_US - 7) -#define INA23X_DN_MAX 32768.0f /* 2^15 */ -#define INA23X_CONST 819.2e6f /* is an internal fixed value used to ensure scaling is maintained properly */ -#define INA23X_VSCALE 3.125e-03f /* LSB of voltage is 3.1255 mV/LSB */ - - -#define DEFAULT_MAX_CURRENT 327.68f /* Amps */ -#define DEFAULT_SHUNT 0.0003f /* Shunt is 300 uOhm */ - -#define swap16(w) __builtin_bswap16((w)) -#define swap32(d) __builtin_bswap32((d)) -#define swap64(q) __builtin_bswap64((q)) - -class INA23X : public device::I2C, public ModuleParams, public I2CSPIDriver -{ -public: - INA23X(const I2CSPIDriverConfig &config, int battery_index); - virtual ~INA23X(); - - static I2CSPIDriverBase *instantiate(const I2CSPIDriverConfig &config, int runtime_instance); - static void print_usage(); - - void RunImpl(); - - int init() override; - - /** - * Tries to call the init() function. If it fails, then it will schedule to retry again in - * INA23X_INIT_RETRY_INTERVAL_US microseconds. It will keep retrying at this interval until initialization succeeds. - * - * @return PX4_OK if initialization succeeded on the first try. Negative value otherwise. - */ - int force_init(); - - /** - * Diagnostics - print some basic information about the driver. - */ - void print_status() override; - -protected: - int probe() override; - -private: - bool _sensor_ok{false}; - unsigned int _measure_interval{0}; - bool _collect_phase{false}; - bool _initialized{false}; - - perf_counter_t _sample_perf; - perf_counter_t _comms_errors; - perf_counter_t _collection_errors; - perf_counter_t _measure_errors; - - // Configuration state, computed from params - float _max_current; - float _rshunt; - float _current_lsb; - uint16_t _config; - int16_t _range; - bool _mode_triggered; - - actuator_controls_s _actuator_controls{}; - - Battery _battery; - uORB::Subscription _actuators_sub{ORB_ID(actuator_controls_0)}; - uORB::SubscriptionInterval _parameter_update_sub{ORB_ID(parameter_update), 1_s}; - - int read(uint8_t address, uint16_t &data); - int write(uint8_t address, uint16_t data); - - int read(uint8_t address, int16_t &data) - { - return read(address, (uint16_t &)data); - } - - int write(uint8_t address, int16_t data) - { - return write(address, (uint16_t)data); - } - - /** - * Initialise the automatic measurement state machine and start it. - * - * @note This function is called at open and error time. It might make sense - * to make it more aggressive about resetting the bus in case of errors. - */ - void start(); - - int measure(); - int collect(); - -};