Statistics
| Branch: | Tag: | Revision:

amiro-os / include / amiro / power / ina219.hpp @ 58fe0e0b

History | View | Annotate | Download (6.25 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
      enum RegisterAddress {
144
        REG_CONFIGURATION = 0x00u,
145
        REG_SHUNT_VOLTAGE = 0x01u,
146
        REG_BUS_VOLTAGE = 0x02u,
147
        REG_POWER = 0x03u,
148
        REG_CURRENT = 0x04u,
149
        REG_CALIBRATION = 0x05u
150
      };
151
152
      enum RegisterMask {
153
        MASK_CONFIGURATION = 0x3FFFu,
154
        MASK_CALIBRATION = 0xFFFEu,
155
        MASK_RESET = 0x8000u
156
      };
157
158
      I2CDriver *const i2c_driver;
159
      I2CTxParams tx_params;
160
      Configuration::Register config;
161
      uint16_t current_lsb_uA;
162
      Status status;
163
164
    public:
165
      /* constructor & destructor */
166
      explicit Driver(I2CDriver &i2c_driver, const uint8_t i2c_address);
167
      virtual ~Driver();
168
169
      /* inherited functions from BaseSensor */
170
      msg_t init(InitData* initialization_data = NULL);
171
      msg_t update();
172
      msg_t wakeup();
173
      msg_t hibernate();
174
#ifndef AMIRO_NCALIBRATION
175
      msg_t calibration(CalibData* calibration_data = NULL);
176
#endif
177
#ifndef AMIRO_NSELFTEST
178
      msg_t selftest();
179
#endif
180
181
      INA219::BusVoltage getVoltage() const
182
      {
183
        return this->busVoltageReg2uV(this->status.bus_voltage);
184
      }
185
186
      uint32_t getPower_uW() const
187
      {
188
        return this->powerReg2uW(this->status.power);
189
      }
190
191
      uint32_t getCurrent_uA() const
192
      {
193
        return this->powerReg2uW(this->status.power) / this->busVoltageReg2uV(this->status.bus_voltage).voltage_uV;
194
      }
195
196
197
198
      inline Configuration::Register readConfiguration();
199
      inline int32_t readShuntVoltage_uV();
200
      inline INA219::BusVoltage readBusVoltage();
201
      inline uint32_t readPower_uW();
202
      inline int32_t readCurrent_uA();
203
      inline uint16_t readCalibration();
204
205
      uint8_t reset();
206
207
  protected:
208
      virtual msg_t main(void);
209
210
    private:
211
      msg_t readRegister(const RegisterAddress reg, uint16_t& dst);
212
      msg_t writeRegister(const RegisterAddress reg, const uint16_t& val);
213
214
      static inline INA219::BusVoltage busVoltageReg2uV(const INA219::Driver::BusVoltage reg_val)
215
      {
216
        INA219::BusVoltage bus_voltage;
217
        bus_voltage.conversion_ready = reg_val.content.conversion_ready;
218
        bus_voltage.overflow = reg_val.content.conversion_ready;
219
        /*
220
         * The least significant bit represents 4mV.
221
         * -> Multiply with 4000 in order to convert to uV.
222
         */
223
        bus_voltage.voltage_uV = reg_val.content.voltage * 4000;
224
        return bus_voltage;
225
      }
226
227
      inline uint32_t powerReg2uW(const uint16_t reg_val) const
228
      {
229
        /*
230
         * Multiply with the value of the least significant bit for the current and the constant 20.
231
         * -> see data sheet, chapter 'Programming the INA219 power measurement engine' for details
232
         */
233
        return reg_val * 20 * this->current_lsb_uA;
234
      }
235
    };
236
237
  } // end of namespace INA219
238
239
}
240
241
#endif /* AMIRO_INA219_H_ */