amiro-os / include / amiro / power / ina219.hpp @ a47d64ad
History | View | Annotate | Download (6.286 KB)
1 |
/*
|
---|---|
2 |
* INA219 - Power Monitor
|
3 |
*/
|
4 |
|
5 |
#ifndef AMIRO_INA219_H_
|
6 |
#define AMIRO_INA219_H_
|
7 |
|
8 |
#include <ch.hpp> |
9 |
#include <amiro/bus/i2c/I2CParams.hpp> |
10 |
#include <amiro/bus/i2c/I2CDriver.hpp> |
11 |
|
12 |
#include <amiro/BaseSensor.hpp> |
13 |
|
14 |
namespace amiro {
|
15 |
|
16 |
namespace INA219 {
|
17 |
|
18 |
namespace Configuration
|
19 |
{ |
20 |
union Register {
|
21 |
uint16_t value = 0;
|
22 |
struct {
|
23 |
uint16_t mode : 3;
|
24 |
uint16_t sadc : 4;
|
25 |
uint16_t badc : 4;
|
26 |
uint16_t pg : 2;
|
27 |
uint16_t brng : 1;
|
28 |
uint16_t rsvd : 1;
|
29 |
uint16_t rst : 1;
|
30 |
} content; |
31 |
}; |
32 |
|
33 |
enum BusRange {
|
34 |
BRNG_16V = 0,
|
35 |
BRNG_32V = 1, BRNG_DEFAULT = 1 |
36 |
}; |
37 |
|
38 |
enum Pga {
|
39 |
PGA_40mV = 0,
|
40 |
PGA_80mV = 1,
|
41 |
PGA_160mV = 2,
|
42 |
PGA_320mV = 3, PGA_DEFAULT = 3 |
43 |
}; |
44 |
|
45 |
enum Adc {
|
46 |
ADC_84us = 0x0u,
|
47 |
ADC_148us = 0x1u,
|
48 |
ADC_276us = 0x2u,
|
49 |
ADC_532us = 0x3u, ADC_632us_alt = 0x8u, ADC_DEFAULT = 0x3u, |
50 |
ADC_1060us = 0x9u,
|
51 |
ADC_2130us = 0xAu,
|
52 |
ADC_4260us = 0xBu,
|
53 |
ADC_8510us = 0xCu,
|
54 |
ADC_17020us = 0xDu,
|
55 |
ADC_34050us = 0xEu,
|
56 |
ADC_68100us = 0xFu
|
57 |
}; |
58 |
|
59 |
enum Mode {
|
60 |
MODE_PowerDown = 0x0u,
|
61 |
MODE_ShuntV_Triggered = 0x1u,
|
62 |
MODE_BusV_Triggered = 0x2u,
|
63 |
MODE_ShuntBus_Triggered = 0x3u,
|
64 |
MODE_AdcOff = 0x4u,
|
65 |
MODE_ShuntV_Continuous = 0x5u,
|
66 |
MODE_BusV_Continuous = 0x6u,
|
67 |
MODE_ShuntBus_Continuous = 0x7u, MODE_DEFAULT = 0x7u |
68 |
}; |
69 |
} // end of namespace Configuration
|
70 |
|
71 |
|
72 |
|
73 |
struct InitData {
|
74 |
Configuration::Register configuration; |
75 |
uint16_t calibration; |
76 |
uint16_t current_lsb_uA; |
77 |
}; |
78 |
|
79 |
struct CalibData {
|
80 |
struct CalibInput {
|
81 |
float shunt_resistance_O;
|
82 |
float max_expected_current_A;
|
83 |
uint16_t current_lsb_uA; |
84 |
Configuration::Register configuration; |
85 |
} input; |
86 |
struct CalibOutput {
|
87 |
float max_current_before_overflow_A;
|
88 |
float max_shuntvoltage_before_overflow_V;
|
89 |
uint16_t current_lsb_uA; |
90 |
uint16_t calibration_value; |
91 |
} output; |
92 |
|
93 |
uint16_t power_lsb_uW() const
|
94 |
{ |
95 |
return 20 * output.current_lsb_uA; |
96 |
} |
97 |
|
98 |
float maximum_power_W() const |
99 |
{ |
100 |
return output.max_current_before_overflow_A * ((input.configuration.content.brng == Configuration::BusRange::BRNG_32V)? 32 : 16);} |
101 |
}; |
102 |
|
103 |
struct BusVoltage {
|
104 |
uint32_t voltage_uV : 25;
|
105 |
uint32_t rsvd : 5;
|
106 |
uint32_t conversion_ready : 1;
|
107 |
uint32_t overflow : 1;
|
108 |
}; |
109 |
|
110 |
class Driver : public BaseSensor<InitData,CalibData>, public chibios_rt::BaseStaticThread<256> |
111 |
{ |
112 |
public:
|
113 |
enum SelftestResult {
|
114 |
ST_OK = BaseSensor<>::OK, |
115 |
ST_FAIL_ANY = BaseSensor<>::FAIL, |
116 |
ST_FAIL_BACKUP = BaseSensor<>::FAIL + 1,
|
117 |
ST_FAIL_RESET = BaseSensor<>::FAIL + 2,
|
118 |
ST_FAIL_IS_DEFAULT = BaseSensor<>::FAIL + 3,
|
119 |
ST_FAIL_WRITE_CONFIG = BaseSensor<>::FAIL + 4,
|
120 |
ST_FAIL_WRITE_CALIB = BaseSensor<>::FAIL + 5,
|
121 |
ST_FAIL_CHECK_CONFIG = BaseSensor<>::FAIL + 6,
|
122 |
ST_FAIL_CHECK_CALIB = BaseSensor<>::FAIL + 7
|
123 |
}; |
124 |
|
125 |
private:
|
126 |
union BusVoltage {
|
127 |
uint16_t value = 0;
|
128 |
struct {
|
129 |
uint16_t overflow : 1;
|
130 |
uint16_t conversion_ready : 1;
|
131 |
uint16_t rsvd : 1;
|
132 |
uint16_t voltage : 13;
|
133 |
} content; |
134 |
}; |
135 |
|
136 |
struct Status {
|
137 |
Driver::BusVoltage bus_voltage; |
138 |
uint16_t power; |
139 |
|
140 |
Status() {bus_voltage.value = 0; power = 0;} |
141 |
}; |
142 |
|
143 |
public:
|
144 |
enum RegisterAddress {
|
145 |
REG_CONFIGURATION = 0x00u,
|
146 |
REG_SHUNT_VOLTAGE = 0x01u,
|
147 |
REG_BUS_VOLTAGE = 0x02u,
|
148 |
REG_POWER = 0x03u,
|
149 |
REG_CURRENT = 0x04u,
|
150 |
REG_CALIBRATION = 0x05u
|
151 |
}; |
152 |
|
153 |
private:
|
154 |
enum RegisterMask {
|
155 |
MASK_CONFIGURATION = 0x3FFFu,
|
156 |
MASK_CALIBRATION = 0xFFFEu,
|
157 |
MASK_RESET = 0x8000u
|
158 |
}; |
159 |
|
160 |
I2CDriver *const i2c_driver;
|
161 |
I2CTxParams tx_params; |
162 |
Configuration::Register config; |
163 |
uint16_t current_lsb_uA; |
164 |
Status status; |
165 |
|
166 |
public:
|
167 |
/* constructor & destructor */
|
168 |
explicit Driver(I2CDriver &i2c_driver, const uint8_t i2c_address); |
169 |
virtual ~Driver();
|
170 |
|
171 |
/* inherited functions from BaseSensor */
|
172 |
msg_t init(InitData* initialization_data = NULL);
|
173 |
msg_t update(); |
174 |
msg_t wakeup(); |
175 |
msg_t hibernate(); |
176 |
#ifndef AMIRO_NCALIBRATION
|
177 |
msg_t calibration(CalibData* calibration_data = NULL);
|
178 |
#endif
|
179 |
#ifndef AMIRO_NSELFTEST
|
180 |
msg_t selftest(); |
181 |
#endif
|
182 |
|
183 |
INA219::BusVoltage getVoltage() const
|
184 |
{ |
185 |
return this->busVoltageReg2uV(this->status.bus_voltage); |
186 |
} |
187 |
|
188 |
uint32_t getPower_uW() const
|
189 |
{ |
190 |
return this->powerReg2uW(this->status.power); |
191 |
} |
192 |
|
193 |
uint32_t getCurrent_uA() const
|
194 |
{ |
195 |
return this->powerReg2uW(this->status.power) / this->busVoltageReg2uV(this->status.bus_voltage).voltage_uV; |
196 |
} |
197 |
|
198 |
|
199 |
|
200 |
inline Configuration::Register readConfiguration();
|
201 |
inline int32_t readShuntVoltage_uV();
|
202 |
inline INA219::BusVoltage readBusVoltage();
|
203 |
inline uint32_t readPower_uW();
|
204 |
inline int32_t readCurrent_uA();
|
205 |
inline uint16_t readCalibration();
|
206 |
|
207 |
uint8_t reset(); |
208 |
|
209 |
protected:
|
210 |
virtual msg_t main(void); |
211 |
|
212 |
public:
|
213 |
msg_t readRegister(const RegisterAddress reg, uint16_t& dst);
|
214 |
msg_t writeRegister(const RegisterAddress reg, const uint16_t& val); |
215 |
|
216 |
private:
|
217 |
static inline INA219::BusVoltage busVoltageReg2uV(const INA219::Driver::BusVoltage reg_val) |
218 |
{ |
219 |
INA219::BusVoltage bus_voltage; |
220 |
bus_voltage.conversion_ready = reg_val.content.conversion_ready; |
221 |
bus_voltage.overflow = reg_val.content.conversion_ready; |
222 |
/*
|
223 |
* The least significant bit represents 4mV.
|
224 |
* -> Multiply with 4000 in order to convert to uV.
|
225 |
*/
|
226 |
bus_voltage.voltage_uV = reg_val.content.voltage * 4000;
|
227 |
return bus_voltage;
|
228 |
} |
229 |
|
230 |
inline uint32_t powerReg2uW(const uint16_t reg_val) const |
231 |
{ |
232 |
/*
|
233 |
* Multiply with the value of the least significant bit for the current and the constant 20.
|
234 |
* -> see data sheet, chapter 'Programming the INA219 power measurement engine' for details
|
235 |
*/
|
236 |
return reg_val * 20 * this->current_lsb_uA; |
237 |
} |
238 |
}; |
239 |
|
240 |
} // end of namespace INA219
|
241 |
|
242 |
} |
243 |
|
244 |
#endif /* AMIRO_INA219_H_ */ |