Statistics
| Branch: | Tag: | Revision:

amiro-os / include / amiro / power / ina219.hpp @ 1d9e5660

History | View | Annotate | Download (6.286 KB)

1 58fe0e0b Thomas Schöpping
/*
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 b4885314 Thomas Schöpping
    public:
144 58fe0e0b Thomas Schöpping
      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 b4885314 Thomas Schöpping
    private:
154 58fe0e0b Thomas Schöpping
      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 b4885314 Thomas Schöpping
    protected:
210 58fe0e0b Thomas Schöpping
      virtual msg_t main(void);
211
212 b4885314 Thomas Schöpping
    public:
213 58fe0e0b Thomas Schöpping
      msg_t readRegister(const RegisterAddress reg, uint16_t& dst);
214
      msg_t writeRegister(const RegisterAddress reg, const uint16_t& val);
215
216 b4885314 Thomas Schöpping
    private:
217 58fe0e0b Thomas Schöpping
      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_ */