Statistics
| Branch: | Tag: | Revision:

amiro-os / include / amiro / power / bq27500.hpp @ 4d54a507

History | View | Annotate | Download (18.185 KB)

1 58fe0e0b Thomas Schöpping
/*
2
 * BQ27500 - Fuel Gauge
3
 */
4
5
#ifndef AMIRO_BQ27500_H_
6
#define AMIRO_BQ27500_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 BQ27500 {
17
18
    struct InitData {};
19
20
    struct CalibData
21
    {
22
      struct Configuration
23
      {
24
        struct Safety {
25
          enum SubclassID {SUB_ID = 2};
26
          const int16_t ot_chg = 450; // 0.1°C
27
          const uint8_t ot_chg_time = 2; // seconds
28
          const int16_t ot_chg_recovery = 400; // 0.1°C
29
          const int16_t ot_dsg = 600; // 0.1°C
30
          const uint8_t ot_dsg_time = 2; // seconds
31
          const int16_t ot_dsg_recovery = 500; // 0.1°C
32
          enum Offset {
33
            OFFSET_OtChg = 0,
34
            OFFSET_OtChgTime = 2,
35
            OFFSET_OtChgRecovery = 3,
36
            OFFSET_OtDsg = 5,
37
            OFFSET_OtDsgTime = 7,
38
            OFFSET_OtDsgRecovery = 8
39
          };
40
        } safety;
41
42
        struct ChargeInhibitConfig {
43
          enum SubclassID {SUB_ID = 32};
44
          const int16_t charge_inhibit_temp_low = 0; // 0.1°C
45
          const int16_t charge_inhibit_temp_high = 450; // 0.1°C
46
          const int16_t temp_hys = 50; // 0.1°C
47
          enum Offset {
48
            OFFSET_ChargeInhibitTempLow = 0,
49
            OFFSET_ChargeInhibitTempHigh = 2,
50
            OFFSET_TempHys = 4
51
          };
52
        } charge_inhibit_config;
53
54
        struct Charge {
55
          enum SubclassID {SUB_ID = 34};
56
          const int16_t charging_voltage = 4200; // mV
57
          const int16_t delta_temperature = 50; // 0.1°C
58
          const int16_t suspend_temperature_low = -200; // 0.1°C
59
          const int16_t suspend_temperature_high = 600; // 0.1°C
60
          enum Offset {
61
            OFFSET_ChargingVoltage = 2,
62
            OFFSET_DeltaTemperature = 4,
63
            OFFSET_SuspendTemperatureLow = 6,
64
            OFFSET_SuspendTemperatureHigh = 8
65
          };
66
        } charge;
67
68
        struct ChargeTermination {
69
          enum SubclassID {SUB_ID = 36};
70
          const int16_t taper_current = 100; // mA
71
          const int16_t minimum_taper_charge = 25; // 0.01mAh
72
          const int16_t taper_voltage = 100; // mV
73
          const uint16_t current_taper_window = 40; // seconds
74
          enum Offset {
75
            OFFSET_TaperCurrent = 2,
76
            OFFSET_MinimumTaperCharge = 4,
77
            OFFSET_TaperVoltage = 6,
78
            OFFSET_CurrentTaperWindow = 8
79
          };
80
        } charge_termination;
81
82
        struct Data {
83
          enum SubclassID {SUB_ID = 48};
84
          const int8_t initial_standby_current = -10; // mA
85
          const int16_t initial_max_load_current = -500; // mA
86
          const int16_t cc_threshold = 900; // mAh
87
          const int16_t design_capacity = 1950; // mAh
88
          const char device_name[8] = "bq27500";
89
          enum Offset {
90
            OFFSET_InitialStandbyCurrent = 4,
91
            OFFSET_InitialMaxLoadCurrent = 5,
92
            OFFSET_CCThreshold = 7,
93
            OFFSET_DesignCapacity = 10,
94
            OFFSET_DeviceName = 12
95
          };
96
        } data;
97
98
        struct Discharge {
99
          enum SublcassID {SUB_ID = 49};
100
          const uint8_t soc1_set_threshold = 150; // mAh
101
          const uint8_t soc1_clear_threshold = 175; // mAh
102
          const uint8_t socf_set_threshold = 75; // mAh
103
          const uint8_t socf_clear_threshold = 100; // mAh
104
          enum Offset {
105
            OFFSET_Soc1SetThreshold = 0,
106
            OFFSET_Soc1ClearThreshold = 1,
107
            OFFSET_SocfSetThreshold = 2,
108
            OFFSET_SocfClearThreshold = 3
109
          };
110
        } discharge;
111
112
        struct Registers {
113
          enum SubclassID {SUB_ID = 64};
114
          union OperationConfiguration {
115
            const uint16_t value = 0x0979u;
116
            struct {
117
              uint16_t temps : 1;
118
              uint16_t rsvd_1 : 1;
119
              uint16_t batg_pol : 1;
120
              uint16_t batl_pol : 1;
121
              uint16_t rmfcc : 1;
122
              uint16_t sleep : 1;
123
              uint16_t idselen : 1;
124
              uint16_t rsvd_7 : 1;
125
              uint16_t rsns : 2;
126
              uint16_t iwake : 1;
127
              uint16_t pfc : 2;
128
              uint16_t rsvd_13 : 1;
129
              uint16_t batg_ovr : 1;
130
              uint16_t rescap : 1;
131
            } content;
132
          } operation_configuration;
133
          enum Offset {
134
            OFFSET_OperationConfiguration = 0
135
          };
136
        } registers;
137
138
        struct Power {
139
          enum SubclassID {SUB_ID = 68};
140
          const int16_t flash_update_ok_voltage = 2800; // mV
141
          const int16_t sleep_current = 10; // mA
142
          const uint16_t hibernate_current = 8; // mA
143
          const uint16_t hibernate_voltage = 2550; // mV
144
          enum Offset {
145
            OFFSET_FlashUpdateOkVoltage = 0,
146
            OFFSET_SleepCurrent = 7,
147
            OFFSET_HibernateCurrent = 16,
148
            OFFSET_HibernateVoltage = 18
149
          };
150
        } power;
151
      } configuration;
152
153
      struct SystemData
154
      {
155
        struct ManufacturerInfo {
156
          enum SubclassID {SUB_ID = 57};
157
          // the very first byte is reserved as magic byte (0xAA)
158
          uint8_t version_major = 1;
159
          uint8_t version_minor = 0;
160
          enum Offset {
161
            OFFSET_VersionMajor = 1,
162
            OFFSET_VersionMinor = 2
163
          };
164
        } manufacturer_info;
165
      } system_data;
166
167
      struct FuelGauging
168
      {
169
        struct ITConfig {
170
          enum SubclassID {SUB_ID = 80};
171
          const uint8_t load_select = 1;
172
          const uint8_t load_mode = 0;
173
          const int16_t terminate_voltage = 3000; // mV
174
          const int16_t user_rate_mA = 0; // mA
175
          const int16_t user_rate_mW = 0; // mW
176
          const int16_t reserve_cap_mAh = 0; // mAh
177
          const int16_t reserve_cap_mWh = 0; // mWh
178
          enum Offset {
179
            OFFSET_LoadSelect = 0,
180
            OFFSET_LoadMode = 1,
181
            OFFSET_TerminateVoltage = 48,
182
            OFFSET_UserRate_mA = 53,
183
            OFFSET_UserRate_mW = 55,
184
            OFFSET_ReserveCap_mAh = 57,
185
            OFFSET_ReserveCap_mWh = 59
186
          };
187
        } it_config;
188
189
        struct CurrentThresholds {
190
          enum SubclassID {SUB_ID = 81};
191
          const int16_t dsg_current_threshold = 60; // mA
192
          const int16_t chg_current_threshold = 75; // mA
193
          const int16_t quit_current = 40; // mA
194
          const uint16_t dsg_relax_time = 60; // seconds
195
          const uint16_t chg_relax_time = 60; // seconds
196
          const uint8_t quit_relax_time = 1; // seconds
197
          enum Offset {
198
            OFFSET_DsgCurrentThreshold = 0,
199
            OFFSET_ChgCurrentThreshold = 2,
200
            OFFSET_QuitCurrent = 4,
201
            OFFSET_DsgRelaxTime = 6,
202
            OFFSET_ChgRelaxTime = 8,
203
            OFFSET_QuitRelaxTime = 10
204
          };
205
        } current_thresholds;
206
207
        struct State {
208
          enum SubclassID {SUB_ID = 82};
209
          const uint8_t it_enable = 0x00;
210
          const uint8_t application_status = 0x00;
211
          const int16_t qmax_0 = 1950; // mAh
212
          const uint16_t cycle_count_0 = 0;
213
          const uint8_t update_status_0 = 0x00;
214
          const int16_t qmax_1 = 1950; // mAh
215
          const uint16_t cycle_count_1 = 0;
216
          const uint8_t update_status_1 = 0x00;
217
          const int16_t avg_I_last_run = -299; // mA
218
          const int16_t avg_P_last_run = -1131; // mAh
219
          enum Offset {
220
            OFFSET_ItEnable = 0,
221
            OFFSET_ApplicationStatus = 1,
222
            OFFSET_Qmax0 = 2,
223
            OFFSET_CycleCount0 = 4,
224
            OFFSET_UpdateStatus0 = 6,
225
            OFFSET_Qmax1 = 7,
226
            OFFSET_CycleCount1 = 9,
227
            OFFSET_UpdateStatus1 = 11,
228
            OFFSET_AvgILastRun = 16,
229
            OFFSET_AvgPLastRun = 18
230
          };
231
        } state;
232
      } fuel_gauging;
233
234
      struct Security
235
      {
236
        struct Codes {
237
          enum SubclassID {SUB_ID = 112};
238
          const uint16_t unseal_key_0 = 0x3672;
239
          const uint16_t unseal_key_1 = 0x0414;
240
          const uint16_t full_access_key_0 = 0xFFFF;
241
          const uint16_t full_access_key_1 = 0xFFFF;
242
          enum Offset {
243
            OFFSET_UnsealKey0 = 0,
244
            OFFSET_UnsealKey1 = 2,
245
            OFFSET_FullAccessKey0 = 4,
246
            OFFSET_FullAccessKey1 = 6
247
          };
248
        } codes;
249
      } security;
250
251
    };
252
253
    class Driver : public BaseSensor<InitData,CalibData>, public chibios_rt::BaseStaticThread<256>
254
    {
255
    public:
256
      enum StandardCommand {
257
                                                                            //  unit    |      access
258
                                                                            //          | sealed  | unsealed
259
                                                                            // ---------+---------+----------
260
        STD_CMD_Control = 0x00u, STD_CMD_CNTL = 0x00u,                      // N/A      | R/W     | R/W
261
        STD_CMD_AtRate = 0x02u, STD_CMD_AR = 0x02u,                         // mA       | R/W     | R/W
262
        STD_CMD_AtRateTimeToEmpty = 0x04u, STD_CMD_ARTTE = 0x04u,           // minutes  | R       | R/W
263
        STD_CMD_Temperatur = 0x06u, STD_CMD_TEMP = 0x06u,                   // 0.1 K    | R       | R/W
264
        STD_CMD_Voltage = 0x08u, STD_CMD_VOLT = 0x08u,                      // mV       | R       | R/W
265
        STD_CMD_Flags = 0x0Au, STD_CMD_FLAGS = 0x0Au,                       // N/A      | R       | R/W
266
        STD_CMD_NominalAvailableCapacity = 0x0Cu, STD_CMD_NAC = 0x0Cu,      // mAh      | R       | R/W
267
        STD_CMD_FullAvailableCapacity = 0x0Eu, STD_CMD_FAC = 0x0Eu,         // mAh      | R       | R/W
268
        STD_CMD_RemainingCapacity = 0x10u, STD_CMD_RM = 0x10u,              // mAh      | R       | R/W
269
        STD_CMD_FullChargeCapacity = 0x12u, STD_CMD_FCC = 0x12u,            // mAh      | R       | R/W
270
        STD_CMD_AverageCurrent = 0x14u, STD_CMD_AI = 0x14u,                 // mA       | R       | R/W
271
        STD_CMD_TimeToEmpty = 0x16u, STD_CMD_TTE = 0x16u,                   // minutes  | R       | R/W
272
        STD_CMD_TimeToFull = 0x18u, STD_CMD_TTF = 0x18u,                    // minutes  | R       | R/W
273
        STD_CMD_StandbyCurrent = 0x1Au, STD_CMD_SI = 0x1Au,                 // mA       | R       | R/W
274
        STD_CMD_StandbyTimeToEmpty = 0x1Cu, STD_CMD_STTE = 0x1Cu,           // minutes  | R       | R/W
275
        STD_CMD_MaxLoadCurrent = 0x1Eu, STD_CMD_MLI = 0x1Eu,                // mA       | R       | R/W
276
        STD_CMD_MaxLoadTimeToEmpty = 0x20u, STD_CMD_MLTTE = 0x20u,          // minutes  | R       | R/W
277
        STD_CMD_AvailableEnergy = 0x22u, STD_CMD_AE = 0x22u,                // mWh      | R       | R/W
278
        STD_CMD_AveragePower = 0x24u, STD_CMD_AP = 0x24u,                   // mW       | R       | R/W
279
        STD_CMD_TimeToEmptyAtConstantPower = 0x26u, STD_CMD_TTECP = 0x26u,  // minutes  | R       | R/W
280
        STD_CMD_CycleCount = 0x2Au, STD_CMD_CC = 0x2Au,                     // counts   | R       | R/W
281
        STD_CMD_StateOfCharge = 0x2Cu, STD_CMD_SOC = 0x2Cu                  // %        | R       | R/W
282
      };
283
284
      enum ControlSubcommand {
285
                                            // sealed access
286
                                            // -------------
287
        SUB_CMD_CONTROL_STATUS = 0x0000u,   // yes
288
        SUB_CMD_DEVICE_TYPE = 0x0001u,      // yes
289
        SUB_CMD_FW_VERSION = 0x0002u,       // yes
290
        SUB_CMD_HW_VERSION = 0x0003u,       // yes
291
        SUB_CMD_DF_CHECKSUM = 0x0004u,      // no
292
        SUB_CMD_RESET_DATA = 0x0005u,       // yes
293
        SUB_CMD_PREV_MACWRITE = 0x0007u,    // yes
294
        SUB_CMD_CHEM_ID = 0x0008u,          // yes
295
        SUB_CMD_BOARD_OFFSET = 0x0009u,     // no
296
        SUB_CMD_CC_INT_OFFSET = 0x000Au,    // no
297
        SUB_CMD_WRITE_OFFSET = 0x000Bu,     // no
298
        SUB_CMD_SET_HIBERNATE = 0x0011u,    // yes
299
        SUB_CMD_CLEAR_HIBERNATE = 0x0012u,  // yes
300
        SUB_CMD_SET_SLEEPp = 0x0013u,       // yes
301
        SUB_CMD_CLEAR_SLEEPp = 0x0014u,     // yes
302
        SUB_CMD_SEALED = 0x0020u,           // no
303
        SUB_CMD_IT_ENABLE = 0x0021u,        // no
304
        SUB_CMD_IF_CHECKSUM = 0x0022u,      // no
305
        SUB_CMD_CAL_MODE = 0x0040u,         // no
306
        SUB_CMD_RESET = 0x0041u,            // no
307
      };
308
309
      enum ExtendedCommand {
310
                                                                    // length | unit | sealed | unsealed
311
                                                                    // -------+------+--------+----------
312
        EXT_CMD_DesignCapacity = 0x3Cu, EXT_CMD_DCAP = 0x3Cu,       //      2 |  mAh |     R  |      R
313
        EXT_CMD_DataFlashClass = 0x3Eu, EXT_CMD_DFCLS = 0x3Eu,      //      1 |  N/A |    N/A |     R/W
314
        EXT_CMD_DataFlashBlock = 0x3Fu, EXT_CMD_DFBLK = 0x3Fu,      //      1 |  N/A |    R/W |     R/W
315
        EXT_CMD_BlockData = 0x40u, EXT_CMD_DFD = 0x40u,             //     32 |  N/A |     R  |     R/W
316
        EXT_CMD_BlockDataCheckSum = 0x60u,EXT_CMD_DFDCKS = 0x60u,   //      1 |  N/A |    R/W |     R/W
317
        EXT_CMD_BlockDataControl = 0x61u, EXT_CMD_DFDCNTL = 0x61u,  //      1 |  N/A |    N/A |     R/W
318
        EXT_CMD_DeviceNameLength = 0x62u, EXT_CMD_DNAMELEN = 0x62u, //      1 |  N/A |     R  |      R
319
        EXT_CMD_DeviceName = 0x63u, EXT_CMD_DNAME = 0x63u,          //      7 |  N/A |     R  |      R
320
        EXT_CMD_ApplicationStatus = 0x6Au, EXT_CMD_APPSTAT = 0x6Au  //      1 |  N/A |     R  |      R
321
      };
322
323
      enum ExtendedCommandAccess {
324
        EXT_CMD_READ = 0,
325
        EXT_CMD_WRITE = 1,
326
      };
327
328
      enum SelftestResult {
329
        ST_OK = BaseSensor<>::OK,
330
        ST_ABORT_NO_BAT = BaseSensor<>::OK+1,
331
        ST_FAIL_ANY = BaseSensor<>::FAIL,
332
        ST_FAIL_READ_HW_VERSION = BaseSensor<>::FAIL + 1,
333
        ST_FAIL_READ_FW_VERSION = BaseSensor<>::FAIL + 2,
334
        ST_FAIL_READ_DEVICENAMELENGTH = BaseSensor<>::FAIL + 3,
335
        ST_FAIL_READ_DEVICENAME = BaseSensor<>::FAIL + 4,
336
        ST_FAIL_SET_ITENABLE = BaseSensor<>::FAIL + 5,
337
        ST_FAIL_READ_STATUS = BaseSensor<>::FAIL + 6,
338
        ST_FAIL_READ_FLAGS = BaseSensor<>::FAIL + 7,
339
        ST_FAIL_READ_TEMP = BaseSensor<>::FAIL + 8,
340
        ST_FAIL_READ_FAC = BaseSensor<>::FAIL + 9,
341
        ST_FAIL_READ_FCC = BaseSensor<>::FAIL + 10,
342
        ST_FAIL_READ_RM = BaseSensor<>::FAIL + 11,
343
        ST_FAIL_READ_SOC = BaseSensor<>::FAIL + 12,
344
        ST_FAIL_READ_VOLT = BaseSensor<>::FAIL + 13,
345
        ST_FAIL_READ_AI = BaseSensor<>::FAIL + 14,
346
        ST_FAIL_READ_AP = BaseSensor<>::FAIL + 15,
347
        ST_FAIL_READ_TTE = BaseSensor<>::FAIL + 16,
348
        ST_FAIL_READ_TTF = BaseSensor<>::FAIL + 17
349
      };
350
351
      union ControlStatus {
352
        uint16_t value = 0;
353
        struct {
354
          uint16_t qen : 1;
355
          uint16_t vok : 1;
356
          uint16_t rup_dis : 1;
357
          uint16_t ldmd : 1;
358
          uint16_t sleep : 1;
359
          uint16_t snooze : 1;
360
          uint16_t hibernate : 1;
361
          uint16_t rsvd_7_8_9 : 3;
362
          uint16_t bca : 1;
363
          uint16_t cca : 1;
364
          uint16_t csv : 1;
365
          uint16_t ss : 1;
366
          uint16_t fas : 1;
367
          uint16_t rsvd_15 : 1;
368
        } content;
369
      };
370
371
      union Flags {
372
        uint16_t value = 0;
373
        struct {
374
          uint16_t dsg : 1;
375
          uint16_t socf : 1;
376
          uint16_t soc1 : 1;
377
          uint16_t bat_det : 1;
378
          uint16_t wait_id : 1;
379
          uint16_t ocv_gd : 1;
380
          uint16_t rsvd_6_7 : 2;
381
          uint16_t chg : 1;
382
          uint16_t fc : 1;
383
          uint16_t xchg : 1;
384
          uint16_t chg_inh : 1;
385
          uint16_t rsvd_12_13 : 2;
386
          uint16_t otd : 1;
387
          uint16_t otc : 1;
388
        } content;
389
      };
390
391
      union Version {
392
        uint16_t value = 0;
393
        struct {
394
          uint16_t minor_low : 4;
395
          uint16_t minor_high : 4;
396
          uint16_t major_low : 4;
397
          uint16_t major_high : 4;
398
        } content;
399
      };
400
401
      struct UpdateData {
402
        uint16_t minutes_to_empty;
403
        uint16_t minutes_to_full;
404
        uint16_t average_power_mW;
405
        uint8_t state_of_charge; // %
406
      };
407
408
    private:
409
      enum I2CAddress {
410
        I2C_ADDR = 0x55u
411
      };
412
413
      enum DataFlashSubClassID {
414
        CONFIGURATION_Safety = 2,
415
        CONFIGURATION_ChargeInhibitConfig = 32,
416
        CONFIGURATION_Charge = 34,
417
        CONFIGURATION_ChargeTermination = 36,
418
        CONFIGURATION_Data = 48,
419
        CONFIGURATION_Discharge = 49,
420
        SYSTEM_DATA_ManufacturerInfo = 57,
421
        CONFIGURATION_Registers = 64,
422
        CONFIGURATION_Power = 68,
423
        FUEL_GAUGING_ItCfg = 80,
424
        FUEL_GAUGING_CurrentThresholds = 81,
425
        FUEL_GAUGING_State = 82,
426
        DEFAULT_RA_TABLES_Def0Ra = 87,
427
        DEFAULT_RA_TABLES_Def1Ra = 88,
428
        RA_TABLES_Pack0Ra = 91,
429
        RA_TABLES_Pack1Ra = 92,
430
        RA_TABLES_Pack0Rax = 93,
431
        RA_TABLES_Pack1Rax = 94,
432
        CALIBRATION_Data = 104,
433
        CALIBRATION_Current = 107,
434
        SECURITY_Codes = 112
435
      };
436
437
      union DataFlashBlock {
438
        uint8_t raw[33];
439
        struct Content {
440
          uint8_t data[32];
441
          uint8_t checksum;
442
        } content;
443
      };
444
445
      I2CDriver *const i2c_driver;
446
      I2CTxParams tx_params;
447
448
      chibios_rt::EvtSource eventSource;
449
450
      const GPIO_TypeDef* const batgd_pingrp;
451
      const uint8_t batgd_pin;
452
      const GPIO_TypeDef* const batlow_pingrp;
453
      const uint8_t batlow_pin;
454
455
      UpdateData status;
456
457
    public:
458
      Driver(I2CDriver &i2c_driver, const GPIO_TypeDef &batgd_pingrp, const uint8_t batgd_pin, const GPIO_TypeDef &batlow_pingrp, const uint8_t batlow_pin);
459
      virtual ~Driver();
460
461
      chibios_rt::EvtSource* getEventSource();
462
463
      msg_t init(InitData* initialization_data = NULL);
464
      msg_t update();
465
      msg_t wakeup();
466
      msg_t hibernate();
467
  #ifndef AMIRO_NCALIBRATION
468
      msg_t calibration(CalibData* calibration_data = NULL);
469
  #endif
470
  #ifndef AMIRO_NSELFTEST
471
      msg_t selftest();
472
  #endif
473
474
      bool isBatteryGood() const;
475
      bool isBatteryLow() const;
476
477
      const UpdateData& getStatus() const;
478
479
    protected:
480
      virtual msg_t main(void);
481
482
    private:
483
      msg_t stdCommand(const StandardCommand cmd, uint16_t &dst);
484
      msg_t readName();
485
      msg_t subCommand(const ControlSubcommand cmd, uint16_t* dst = NULL);
486
      msg_t extCommand(const ExtendedCommand cmd, const ExtendedCommandAccess rw, uint8_t* buf = NULL, const uint8_t length = 1, const uint8_t offset = 0);
487
488
      msg_t readDataFlashBlock(DataFlashBlock &block, const DataFlashSubClassID sub_id, const uint8_t sub_block = 0);
489
490
    };
491
492
  }
493
494
}
495
496
#endif /* AMIRO_BQ27500_H_ */