Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmake/pg_struct_sizes.reference.db
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
adcChannelConfig_t 4 0
armingConfig_t 6 3
barometerConfig_t 8 5
batteryMetersConfig_t 24 2
batteryMetersConfig_t 24 3
beeperConfig_t 12 2
blackboxConfig_t 16 4
compassConfig_t 24 6
Expand Down
18 changes: 14 additions & 4 deletions docs/Settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -634,11 +634,11 @@ This sets the output voltage to current scaling for the current sensor in 0.1 mV

### current_meter_type

ADC, VIRTUAL, FAKE, ESC, SMARTPORT, NONE. The virtual current sensor, once calibrated, estimates the current value from throttle position.
ADC, VIRTUAL, FAKE, ESC, SMARTPORT, INA226, NONE. The virtual current sensor, once calibrated, estimates the current value from throttle position.

| Default | Min | Max |
| --- | --- | --- |
| ADC | | |
| _target default_ | | |

---

Expand Down Expand Up @@ -2072,6 +2072,16 @@ Power draw at zero throttle used for remaining flight time/distance estimation i

---

### ina_shunt_res_uohm

INA226 shunt resistor value in micro-ohms.

| Default | Min | Max |
| --- | --- | --- |
| _target default_ | 1 | 4294967295 |

---

### inav_allow_dead_reckoning

Defines if INAV will dead-reckon over short GPS outages. May also be useful for indoors OPFLOW navigation
Expand Down Expand Up @@ -6594,11 +6604,11 @@ Maximum voltage per cell in 0.01V units, default is 4.20V

### vbat_meter_type

Vbat voltage source. Possible values: `NONE`, `ADC`, `SMARTPORT`, `ESC`. `ESC` requires ESC telemetry enabled and running. `SMARTPORT` requires SmartPort Master enabled and running.
Vbat voltage source. Possible values: `NONE`, `ADC`, `SMARTPORT`, `ESC`, `INA226`. `ESC` requires ESC telemetry enabled and running. `SMARTPORT` requires SmartPort Master enabled and running. `INA226` requires an INA226 I2C sensor.

| Default | Min | Max |
| --- | --- | --- |
| ADC | | |
| _target default_ | | |

---

Expand Down
3 changes: 3 additions & 0 deletions src/main/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ main_sources(COMMON_SRC
drivers/adc.c
drivers/adc.h

drivers/ina226.c
drivers/ina226.h

drivers/barometer/barometer.h
drivers/barometer/barometer_bmp085.c
drivers/barometer/barometer_bmp085.h
Expand Down
6 changes: 5 additions & 1 deletion src/main/blackbox/blackbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -1911,10 +1911,14 @@ static bool blackboxWriteSysinfo(void)
BLACKBOX_PRINT_HEADER_LINE("motorOutput", "%d,%d", getThrottleIdleValue(),getMaxThrottle());
BLACKBOX_PRINT_HEADER_LINE("acc_1G", "%u", acc.dev.acc_1G);

#ifdef USE_ADC
#ifdef USE_BATTERY_VOLTAGE_SENSOR
BLACKBOX_PRINT_HEADER_LINE_CUSTOM(
if (testBlackboxCondition(FLIGHT_LOG_FIELD_CONDITION_VBAT)) {
#ifdef USE_ADC
blackboxPrintfHeaderLine("vbat_scale", "%u", batteryMetersConfig()->voltage.scale / 10);
#else
blackboxPrintfHeaderLine("vbat_scale", "%u", 0);
#endif
} else {
xmitState.headerIndex += 2; // Skip the next two vbat fields too
}
Expand Down
1 change: 1 addition & 0 deletions src/main/drivers/bus.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ typedef enum {
DEVHW_SDCARD, // Generic SD-Card
DEVHW_IRLOCK, // IR-Lock visual positioning hardware
DEVHW_PCF8574, // 8-bit I/O expander
DEVHW_INA226, // I2C current and voltage monitor
} devHardwareType_e;

typedef enum {
Expand Down
128 changes: 128 additions & 0 deletions src/main/drivers/ina226.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/*
* This file is part of INAV.
*
* INAV is free software: you can redistribute it and/or modify this software
* 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.
*
* INAV 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.
*/

#include <stddef.h>
#include <stdint.h>

#include "platform.h"

#if defined(USE_INA226)

#include "drivers/ina226.h"

#define INA226_REG_SHUNT_VOLTAGE 0x01
#define INA226_REG_BUS_VOLTAGE 0x02
#define INA226_REG_MANUFACTURER_ID 0xFE
#define INA226_REG_DIE_ID 0xFF

#define INA226_MANUFACTURER_ID 0x5449
#define INA226_DIE_ID 0x2260
#define INA226_DIE_ID_MASK 0xFFF0

static bool ina226ReadRegister(ina226Dev_t *dev, uint8_t reg, uint16_t *value)
{
if (!dev || !dev->busDev || !value) {
return false;
}

uint8_t buffer[2];
if (!busReadBuf(dev->busDev, reg, buffer, sizeof(buffer))) {
return false;
}

*value = ((uint16_t)buffer[0] << 8) | buffer[1];
return true;
}

uint16_t ina226BusVoltageToCentivolts(uint16_t rawBusVoltage)
{
// INA226 bus voltage LSB is 1.25mV: raw * 125 / 1000 = centivolts.
return ((uint32_t)rawBusVoltage * 125 + 500) / 1000;
}

int16_t ina226ShuntVoltageToCentiamps(int16_t rawShuntVoltage, uint32_t shuntMicroOhm)
{
if (shuntMicroOhm == 0) {
return 0;
}

const int32_t centiAmps = (int32_t)rawShuntVoltage * 250 / (int32_t)shuntMicroOhm;

if (centiAmps > INT16_MAX) {
return INT16_MAX;
}

if (centiAmps < INT16_MIN) {
return INT16_MIN;
}

return centiAmps;
}

bool ina226Detect(ina226Dev_t *dev)
{
uint16_t manufacturerId;
uint16_t dieId;

return ina226ReadRegister(dev, INA226_REG_MANUFACTURER_ID, &manufacturerId)
&& ina226ReadRegister(dev, INA226_REG_DIE_ID, &dieId)
&& manufacturerId == INA226_MANUFACTURER_ID
&& (dieId & INA226_DIE_ID_MASK) == INA226_DIE_ID;
}

bool ina226Init(ina226Dev_t *dev)
{
if (!dev) {
return false;
}

dev->busDev = busDeviceInit(BUSTYPE_I2C, DEVHW_INA226, 0, OWNER_CURRENT_METER);

if (!dev->busDev) {
return false;
}

if (!ina226Detect(dev)) {
busDeviceDeInit(dev->busDev);
dev->busDev = NULL;
return false;
}

return true;
}

bool ina226ReadBusVoltage(ina226Dev_t *dev, uint16_t *centiVolts)
{
uint16_t rawBusVoltage;

if (!centiVolts || !ina226ReadRegister(dev, INA226_REG_BUS_VOLTAGE, &rawBusVoltage)) {
return false;
}

*centiVolts = ina226BusVoltageToCentivolts(rawBusVoltage);
return true;
}

bool ina226ReadShuntCurrent(ina226Dev_t *dev, uint32_t shuntMicroOhm, int16_t *centiAmps)
{
uint16_t rawShuntVoltage;

if (!centiAmps || !ina226ReadRegister(dev, INA226_REG_SHUNT_VOLTAGE, &rawShuntVoltage)) {
return false;
}

*centiAmps = ina226ShuntVoltageToCentiamps((int16_t)rawShuntVoltage, shuntMicroOhm);
return true;
}

#endif
33 changes: 33 additions & 0 deletions src/main/drivers/ina226.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* This file is part of INAV.
*
* INAV is free software: you can redistribute it and/or modify this software
* 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.
*
* INAV 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.
*/

#pragma once

#include <stdbool.h>
#include <stdint.h>

#include "drivers/bus.h"

#define INA226_DEFAULT_I2C_ADDRESS 0x40

typedef struct ina226Dev_s {
busDevice_t *busDev;
} ina226Dev_t;

bool ina226Init(ina226Dev_t *dev);
bool ina226Detect(ina226Dev_t *dev);
bool ina226ReadBusVoltage(ina226Dev_t *dev, uint16_t *centiVolts);
bool ina226ReadShuntCurrent(ina226Dev_t *dev, uint32_t shuntMicroOhm, int16_t *centiAmps);

uint16_t ina226BusVoltageToCentivolts(uint16_t rawBusVoltage);
int16_t ina226ShuntVoltageToCentiamps(int16_t rawShuntVoltage, uint32_t shuntMicroOhm);
2 changes: 1 addition & 1 deletion src/main/drivers/resource.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const char * const ownerNames[OWNER_TOTAL_COUNT] = {
"RANGEFINDER", "SYSTEM", "SPI", "QUADSPI", "I2C", "SDCARD", "FLASH", "USB", "BEEPER", "OSD",
"BARO", "MPU", "INVERTER", "LED STRIP", "LED", "RECEIVER", "TRANSMITTER",
"VTX", "SPI_PREINIT", "COMPASS", "TEMPERATURE", "1-WIRE", "AIRSPEED", "OLED DISPLAY",
"PINIO", "IRLOCK"
"PINIO", "IRLOCK", "CURRENT METER"
};

const char * const resourceNames[RESOURCE_TOTAL_COUNT] = {
Expand Down
1 change: 1 addition & 0 deletions src/main/drivers/resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ typedef enum {
OWNER_OLED_DISPLAY,
OWNER_PINIO,
OWNER_IRLOCK,
OWNER_CURRENT_METER,
OWNER_TOTAL_COUNT
} resourceOwner_e;

Expand Down
32 changes: 32 additions & 0 deletions src/main/fc/fc_msp.c
Original file line number Diff line number Diff line change
Expand Up @@ -866,8 +866,12 @@ static bool mspFcProcessOutCommand(uint16_t cmdMSP, sbuf_t *dst, mspPostProcessF
sbufWriteU16(dst, 0);
#endif

#ifdef USE_BATTERY_VOLTAGE_SENSOR
#ifdef USE_ADC
sbufWriteU8(dst, batteryMetersConfig()->voltage.scale / 10);
#else
sbufWriteU8(dst, 0);
#endif
sbufWriteU8(dst, currentBatteryProfile->voltage.cellMin / 10);
sbufWriteU8(dst, currentBatteryProfile->voltage.cellMax / 10);
sbufWriteU8(dst, currentBatteryProfile->voltage.cellWarning / 10);
Expand Down Expand Up @@ -905,8 +909,12 @@ static bool mspFcProcessOutCommand(uint16_t cmdMSP, sbuf_t *dst, mspPostProcessF
sbufWriteU16(dst, 0);
#endif

#ifdef USE_BATTERY_VOLTAGE_SENSOR
#ifdef USE_ADC
sbufWriteU16(dst, batteryMetersConfig()->voltage.scale);
#else
sbufWriteU16(dst, 0);
#endif
sbufWriteU8(dst, batteryMetersConfig()->voltageSource);
sbufWriteU8(dst, currentBatteryProfile->cells);
sbufWriteU16(dst, currentBatteryProfile->voltage.cellDetect);
Expand Down Expand Up @@ -941,8 +949,12 @@ static bool mspFcProcessOutCommand(uint16_t cmdMSP, sbuf_t *dst, mspPostProcessF
break;

case MSP2_INAV_BATTERY_CONFIG:
#ifdef USE_BATTERY_VOLTAGE_SENSOR
#ifdef USE_ADC
sbufWriteU16(dst, batteryMetersConfig()->voltage.scale);
#else
sbufWriteU16(dst, 0);
#endif
sbufWriteU8(dst, batteryMetersConfig()->voltageSource);
sbufWriteU8(dst, currentBatteryProfile->cells);
sbufWriteU16(dst, currentBatteryProfile->voltage.cellDetect);
Expand Down Expand Up @@ -1081,8 +1093,12 @@ static bool mspFcProcessOutCommand(uint16_t cmdMSP, sbuf_t *dst, mspPostProcessF
break;

case MSP_VOLTAGE_METER_CONFIG:
#ifdef USE_BATTERY_VOLTAGE_SENSOR
#ifdef USE_ADC
sbufWriteU8(dst, batteryMetersConfig()->voltage.scale / 10);
#else
sbufWriteU8(dst, 0);
#endif
sbufWriteU8(dst, currentBatteryProfile->voltage.cellMin / 10);
sbufWriteU8(dst, currentBatteryProfile->voltage.cellMax / 10);
sbufWriteU8(dst, currentBatteryProfile->voltage.cellWarning / 10);
Expand Down Expand Up @@ -2159,8 +2175,12 @@ static mspResult_e mspFcProcessInCommand(uint16_t cmdMSP, sbuf_t *src)
sbufReadU16(src);
#endif

#ifdef USE_BATTERY_VOLTAGE_SENSOR
#ifdef USE_ADC
batteryMetersConfigMutable()->voltage.scale = sbufReadU8(src) * 10;
#else
sbufReadU8(src);
#endif
currentBatteryProfileMutable->voltage.cellMin = sbufReadU8(src) * 10; // vbatlevel_warn1 in MWC2.3 GUI
currentBatteryProfileMutable->voltage.cellMax = sbufReadU8(src) * 10; // vbatlevel_warn2 in MWC2.3 GUI
currentBatteryProfileMutable->voltage.cellWarning = sbufReadU8(src) * 10; // vbatlevel when buzzer starts to alert
Expand Down Expand Up @@ -2204,8 +2224,12 @@ static mspResult_e mspFcProcessInCommand(uint16_t cmdMSP, sbuf_t *src)
sbufReadU16(src);
#endif

#ifdef USE_BATTERY_VOLTAGE_SENSOR
#ifdef USE_ADC
batteryMetersConfigMutable()->voltage.scale = sbufReadU16(src);
#else
sbufReadU16(src);
#endif
batteryMetersConfigMutable()->voltageSource = sbufReadU8(src);
currentBatteryProfileMutable->cells = sbufReadU8(src);
currentBatteryProfileMutable->voltage.cellDetect = sbufReadU16(src);
Expand Down Expand Up @@ -2247,8 +2271,12 @@ static mspResult_e mspFcProcessInCommand(uint16_t cmdMSP, sbuf_t *src)

case MSP2_INAV_SET_BATTERY_CONFIG:
if (dataSize == 29) {
#ifdef USE_BATTERY_VOLTAGE_SENSOR
#ifdef USE_ADC
batteryMetersConfigMutable()->voltage.scale = sbufReadU16(src);
#else
sbufReadU16(src);
#endif
batteryMetersConfigMutable()->voltageSource = sbufReadU8(src);
currentBatteryProfileMutable->cells = sbufReadU8(src);
currentBatteryProfileMutable->voltage.cellDetect = sbufReadU16(src);
Expand Down Expand Up @@ -3140,8 +3168,12 @@ static mspResult_e mspFcProcessInCommand(uint16_t cmdMSP, sbuf_t *src)

case MSP_SET_VOLTAGE_METER_CONFIG:
if (dataSize == 4) {
#ifdef USE_BATTERY_VOLTAGE_SENSOR
#ifdef USE_ADC
batteryMetersConfigMutable()->voltage.scale = sbufReadU8(src) * 10;
#else
sbufReadU8(src);
#endif
currentBatteryProfileMutable->voltage.cellMin = sbufReadU8(src) * 10;
currentBatteryProfileMutable->voltage.cellMax = sbufReadU8(src) * 10;
currentBatteryProfileMutable->voltage.cellWarning = sbufReadU8(src) * 10;
Expand Down
4 changes: 2 additions & 2 deletions src/main/fc/fc_tasks.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,15 +135,15 @@ void taskUpdateBattery(timeUs_t currentTimeUs)
#endif
}

#ifdef USE_ADC
#ifdef USE_BATTERY_VOLTAGE_SENSOR
if (feature(FEATURE_VBAT)) {
batteryUpdate(BatMonitoringTimeSinceLastServiced);
}

if (feature(FEATURE_VBAT) && isAmperageConfigured()) {
powerMeterUpdate(BatMonitoringTimeSinceLastServiced);
sagCompensatedVBatUpdate(currentTimeUs, BatMonitoringTimeSinceLastServiced);
#if defined(USE_POWER_LIMITS) && defined(USE_ADC)
#if defined(USE_POWER_LIMITS) && defined(USE_BATTERY_VOLTAGE_SENSOR)
powerLimiterUpdate(BatMonitoringTimeSinceLastServiced);
#endif
}
Expand Down
Loading
Loading