-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbq27220.h
267 lines (240 loc) · 8.98 KB
/
bq27220.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
/**
* @file bq27220.h
*
* Quite problematic chip with quite bad documentation.
*
* Couple things to keep in mind:
*
* - Datasheet and technical reference manual are full of bullshit
* - bqstudio is ignoring them
* - bqstudio i2c exchange tracing gives some ideas on timings that works, but there is a catch
* - bqstudio timings contradicts to gm.fs file specification
* - it's impossible to reproduce all situations in bqstudio
* - experiments with blackbox can not cover all edge cases
* - final timings are kinda blend between all of those sources
* - device behavior differs depending on i2c clock speed
* - The Hero Himmel would not have used this gauge in the first place
*
* Couple advises if you'll need to modify this driver:
* - Reset and wait for INITCOMP if something is not right.
* - Do not do partial config update, it takes unpredictable amount of time to apply.
* - Don't forget to reset chip before writing new config.
* - If something fails at config update stage, wait for 4 seconds before doing next cycle.
* - If you can program and lock chip at factory stage - do it. It will save you a lot of time.
* - Keep sealed or strange things may happen.
* - There is a condition when it may stuck at INITCOMP state, just "press reset button".
*
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <furi_hal_i2c.h>
#define BQ27220_ERROR 0x0
#define BQ27220_SUCCESS 0x1
typedef struct {
// Low byte, Low bit first
uint8_t BATT_ID : 3; /**< Battery Identification */
bool SNOOZE : 1; /**< SNOOZE mode is enabled */
bool BCA : 1; /**< fuel gauge board calibration routine is active */
bool CCA : 1; /**< Coulomb Counter Calibration routine is active */
uint8_t RSVD0 : 2; /**< Reserved */
// High byte, Low bit first
uint8_t RSVD1; /**< Reserved */
} Bq27220ControlStatus;
typedef struct {
// Low byte, Low bit first
bool DSG : 1; /**< The device is in DISCHARGE */
bool SYSDWN : 1; /**< System down bit indicating the system should shut down */
bool TDA : 1; /**< Terminate Discharge Alarm */
bool BATTPRES : 1; /**< Battery Present detected */
bool AUTH_GD : 1; /**< Detect inserted battery */
bool OCVGD : 1; /**< Good OCV measurement taken */
bool TCA : 1; /**< Terminate Charge Alarm */
bool RSVD : 1; /**< Reserved */
// High byte, Low bit first
bool CHGINH : 1; /**< Charge inhibit */
bool FC : 1; /**< Full-charged is detected */
bool OTD : 1; /**< Overtemperature in discharge condition is detected */
bool OTC : 1; /**< Overtemperature in charge condition is detected */
bool SLEEP : 1; /**< Device is operating in SLEEP mode when set */
bool OCVFAIL : 1; /**< Status bit indicating that the OCV reading failed due to current */
bool OCVCOMP : 1; /**< An OCV measurement update is complete */
bool FD : 1; /**< Full-discharge is detected */
} Bq27220BatteryStatus;
typedef enum {
Bq27220OperationStatusSecSealed = 0b11,
Bq27220OperationStatusSecUnsealed = 0b10,
Bq27220OperationStatusSecFull = 0b01,
} Bq27220OperationStatusSec;
typedef struct {
// Low byte, Low bit first
bool CALMD : 1; /**< Calibration mode enabled */
uint8_t SEC : 2; /**< Current security access */
bool EDV2 : 1; /**< EDV2 threshold exceeded */
bool VDQ : 1; /**< Indicates if Current discharge cycle is NOT qualified or qualified for an FCC updated */
bool INITCOMP : 1; /**< gauge initialization is complete */
bool SMTH : 1; /**< RemainingCapacity is scaled by smooth engine */
bool BTPINT : 1; /**< BTP threshold has been crossed */
// High byte, Low bit first
uint8_t RSVD1 : 2; /**< Reserved */
bool CFGUPDATE : 1; /**< Gauge is in CONFIG UPDATE mode */
uint8_t RSVD0 : 5; /**< Reserved */
} Bq27220OperationStatus;
typedef struct {
// Low byte, Low bit first
bool FD : 1; /**< Full Discharge */
bool FC : 1; /**< Full Charge */
bool TD : 1; /**< Terminate Discharge */
bool TC : 1; /**< Terminate Charge */
bool RSVD0 : 1; /**< Reserved */
bool EDV : 1; /**< Cell voltage is above or below EDV0 threshold */
bool DSG : 1; /**< DISCHARGE or RELAXATION */
bool CF : 1; /**< Battery conditioning is needed */
// High byte, Low bit first
uint8_t RSVD1 : 2; /**< Reserved */
bool FCCX : 1; /**< fcc1hz clock going into CC: 0 = 1 Hz, 1 = 16 Hz*/
uint8_t RSVD2 : 2; /**< Reserved */
bool EDV1 : 1; /**< Cell voltage is above or below EDV1 threshold */
bool EDV2 : 1; /**< Cell voltage is above or below EDV2 threshold */
bool VDQ : 1; /**< Charge cycle FCC update qualification */
} Bq27220GaugingStatus;
_Static_assert(sizeof(Bq27220GaugingStatus) == 2, "Incorrect Bq27220GaugingStatus structure size");
typedef struct BQ27220DMData BQ27220DMData;
/** Initialize Driver
*
* This routine performs a lot of things under the hood:
* - Verifies that gauge is present on i2c bus and got correct ID(0220)
* - Unseals gauge
* - Checks various internal statuses
* - Checks that current profile is 0
* - Checks configuration again provided data_memory
* - Reset gauge if something on previous stages was fishy
* - Updates configuration if needed
* - Sealing gauge to prevent configuration and state from accidental damage
*
* @param handle The I2C Bus handle
* @param[in] data_memory The data memory to be uploaded into gauge
*
* @return true on success, false otherwise
*/
bool bq27220_init(FuriHalI2cBusHandle* handle, const BQ27220DMData* data_memory);
/** Reset gauge
*
* @param handle The I2C Bus handle
*
* @return true on success, false otherwise
*/
bool bq27220_reset(FuriHalI2cBusHandle* handle);
/** Seal gauge access
*
* @param handle The I2C Bus handle
*
* @return true on success, false otherwise
*/
bool bq27220_seal(FuriHalI2cBusHandle* handle);
/** Unseal gauge access
*
* @param handle The I2C Bus handle
*
* @return true on success, false otherwise
*/
bool bq27220_unseal(FuriHalI2cBusHandle* handle);
/** Get full access
*
* @warning must be done in unsealed state
*
* @param handle The I2C Bus handle
*
* @return true on success, false otherwise
*/
bool bq27220_full_access(FuriHalI2cBusHandle* handle);
/** Get battery voltage
*
* @param handle The I2C Bus handle
*
* @return voltage in mV or BQ27220_ERROR
*/
uint16_t bq27220_get_voltage(FuriHalI2cBusHandle* handle);
/** Get current
*
* @param handle The I2C Bus handle
*
* @return current in mA or BQ27220_ERROR
*/
int16_t bq27220_get_current(FuriHalI2cBusHandle* handle);
/** Get control status
*
* @param handle The handle
* @param control_status The control status
*
* @return true on success, false otherwise
*/
bool bq27220_get_control_status(FuriHalI2cBusHandle* handle, Bq27220ControlStatus* control_status);
/** Get battery status
*
* @param handle The handle
* @param battery_status The battery status
*
* @return true on success, false otherwise
*/
bool bq27220_get_battery_status(FuriHalI2cBusHandle* handle, Bq27220BatteryStatus* battery_status);
/** Get operation status
*
* @param handle The handle
* @param operation_status The operation status
*
* @return true on success, false otherwise
*/
bool bq27220_get_operation_status(
FuriHalI2cBusHandle* handle,
Bq27220OperationStatus* operation_status);
/** Get gauging status
*
* @param handle The handle
* @param gauging_status The gauging status
*
* @return true on success, false otherwise
*/
bool bq27220_get_gauging_status(FuriHalI2cBusHandle* handle, Bq27220GaugingStatus* gauging_status);
/** Get temperature
*
* @param handle The I2C Bus handle
*
* @return temperature in units of 0.1°K
*/
uint16_t bq27220_get_temperature(FuriHalI2cBusHandle* handle);
/** Get compensated full charge capacity
*
* @param handle The I2C Bus handle
*
* @return full charge capacity in mAh or BQ27220_ERROR
*/
uint16_t bq27220_get_full_charge_capacity(FuriHalI2cBusHandle* handle);
/** Get design capacity
*
* @param handle The I2C Bus handle
*
* @return design capacity in mAh or BQ27220_ERROR
*/
uint16_t bq27220_get_design_capacity(FuriHalI2cBusHandle* handle);
/** Get remaining capacity
*
* @param handle The I2C Bus handle
*
* @return remaining capacity in mAh or BQ27220_ERROR
*/
uint16_t bq27220_get_remaining_capacity(FuriHalI2cBusHandle* handle);
/** Get predicted remaining battery capacity
*
* @param handle The I2C Bus handle
*
* @return state of charge in percents or BQ27220_ERROR
*/
uint16_t bq27220_get_state_of_charge(FuriHalI2cBusHandle* handle);
/** Get ratio of full charge capacity over design capacity
*
* @param handle The I2C Bus handle
*
* @return state of health in percents or BQ27220_ERROR
*/
uint16_t bq27220_get_state_of_health(FuriHalI2cBusHandle* handle);