|
3 | 3 |
|
4 | 4 | // Battery driver that uses an ADC to read battery voltage and current
|
5 | 5 |
|
| 6 | +// Configuration parameters: |
| 7 | +// |
| 8 | +// PBDRV_CONFIG_BATTERY_ADC: |
| 9 | +// enable/disable driver. |
| 10 | +// PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_CH: |
| 11 | +// ADC channel that measures battery voltage. |
| 12 | +// PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_RAW_MAX: |
| 13 | +// The max size of the raw value, e.g. 4096 for 12-bit ADC. Prefer power |
| 14 | +// of 2 for smaller code size, e.g. use 4096 instead of 4095. |
| 15 | +// PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_SCALED_MAX: |
| 16 | +// The voltage in mV that corresponds that would result in the raw measured |
| 17 | +// value PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_RAW_MAX being read on the ADC. |
| 18 | +// PBDRV_CONFIG_BATTERY_ADC_CURRENT_CORRECTION: |
| 19 | +// Current correction factor applied to measured battery voltage. Units are |
| 20 | +// 1/16 Ω, e.g. 12 => 12/16 Ω = 0.75 Ω. |
| 21 | +// PBDRV_CONFIG_BATTERY_ADC_CURRENT_CH: |
| 22 | +// ADC channel that measures battery current. |
| 23 | +// PBDRV_CONFIG_BATTERY_ADC_CURRENT_RAW_OFFSET: |
| 24 | +// An offset to apply to the raw value before scaling it. |
| 25 | +// PBDRV_CONFIG_BATTERY_ADC_CURRENT_RAW_MAX: |
| 26 | +// The max size of the raw value, e.g. 4096 for 12-bit ADC. Prefer power |
| 27 | +// of 2 for smaller code size, e.g. use 4096 instead of 4095. |
| 28 | +// PBDRV_CONFIG_BATTERY_ADC_CURRENT_SCALED_MAX: |
| 29 | +// The current in mA that corresponds that would result in the raw measured |
| 30 | +// value PBDRV_CONFIG_BATTERY_ADC_CURRENT_RAW_MAX being read on the ADC. |
| 31 | + |
6 | 32 | #include <pbdrv/config.h>
|
7 | 33 |
|
8 | 34 | #if PBDRV_CONFIG_BATTERY_ADC
|
|
17 | 43 | void pbdrv_battery_init() {
|
18 | 44 | }
|
19 | 45 |
|
20 |
| -pbio_error_t pbdrv_battery_get_voltage_now(uint16_t *value) { |
| 46 | +pbio_error_t pbdrv_battery_get_current_now(uint16_t *value) { |
21 | 47 | uint16_t raw;
|
22 | 48 | pbio_error_t err;
|
23 | 49 |
|
24 |
| - err = pbdrv_adc_get_ch(PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_CH, &raw); |
| 50 | + // this is measuring the voltage across a 0.05 ohm shunt resistor probably |
| 51 | + // via an op amp with unknown gain. |
| 52 | + err = pbdrv_adc_get_ch(PBDRV_CONFIG_BATTERY_ADC_CURRENT_CH, &raw); |
25 | 53 | if (err != PBIO_SUCCESS) {
|
26 | 54 | return err;
|
27 | 55 | }
|
28 | 56 |
|
29 |
| - // REVISIT: do we want to take into account shunt resistor voltage drop |
30 |
| - // like on EV3? Probably only makes a difference of ~10mV at the most. |
31 |
| - *value = raw * PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_SCALED_MAX / |
32 |
| - PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_RAW_MAX; |
| 57 | + // REVISIT: Hubs, especial Prime and Inventor hubs seem to have an offset |
| 58 | + // that varies greatly by hub (20 or 40 mA). We could introduce a calibration |
| 59 | + // step to try to determine this offset at boot (before lights, ports, etc. |
| 60 | + // are powered on) if we find that we need more accurate current measurement. |
| 61 | + |
| 62 | + // NOTE: On Move hub, City hub and Technic hub, current measurement is |
| 63 | + // non-linear at low currents (< ~100 mA) so the reported battery current |
| 64 | + // is not accurate at low currents. |
| 65 | + |
| 66 | + *value = (raw + PBDRV_CONFIG_BATTERY_ADC_CURRENT_RAW_OFFSET) * |
| 67 | + PBDRV_CONFIG_BATTERY_ADC_CURRENT_SCALED_MAX / |
| 68 | + PBDRV_CONFIG_BATTERY_ADC_CURRENT_RAW_MAX; |
33 | 69 |
|
34 | 70 | return PBIO_SUCCESS;
|
35 | 71 | }
|
36 | 72 |
|
37 |
| -pbio_error_t pbdrv_battery_get_current_now(uint16_t *value) { |
| 73 | +pbio_error_t pbdrv_battery_get_voltage_now(uint16_t *value) { |
38 | 74 | uint16_t raw;
|
39 | 75 | pbio_error_t err;
|
40 | 76 |
|
41 |
| - // this is measuring the voltage across a 0.05 ohm shunt resistor probably |
42 |
| - // via an op amp with unknown gain. |
43 |
| - err = pbdrv_adc_get_ch(PBDRV_CONFIG_BATTERY_ADC_CURRENT_CH, &raw); |
| 77 | + err = pbdrv_adc_get_ch(PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_CH, &raw); |
44 | 78 | if (err != PBIO_SUCCESS) {
|
45 | 79 | return err;
|
46 | 80 | }
|
47 | 81 |
|
48 |
| - *value = raw * PBDRV_CONFIG_BATTERY_ADC_CURRENT_SCALED_MAX / |
49 |
| - PBDRV_CONFIG_BATTERY_ADC_CURRENT_RAW_MAX; |
| 82 | + uint16_t current; |
| 83 | + err = pbdrv_battery_get_current_now(¤t); |
| 84 | + if (err != PBIO_SUCCESS) { |
| 85 | + return err; |
| 86 | + } |
| 87 | + |
| 88 | + // REVISIT: On Technic hub, only the current to ports A/C affect the voltage |
| 89 | + // measurement since the voltage measurement is after the resettable fuse |
| 90 | + // for those ports. So currently, the battery voltage will be reported as |
| 91 | + // up to several tenths of a volt higher than it actually is if there is |
| 92 | + // high current on ports B/D. |
| 93 | + // NOTE: On Move hub, City hub and Technic hub, current measurement is |
| 94 | + // non-linear at low currents (< ~100 mA) so the reported battery voltage |
| 95 | + // will be about 0.1V lower than it actually is when the current is low. |
| 96 | + // NOTE: On Prime and Inventor hubs, the voltage is measured on the same |
| 97 | + // resettable fuse as the lights. So when all of the lights are on at full |
| 98 | + // brightness, the battery voltage will be reported as a few hunderdts of |
| 99 | + // a volt lower than it actually is, which is neglegable. |
| 100 | + *value = raw * PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_SCALED_MAX / |
| 101 | + PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_RAW_MAX + current * |
| 102 | + PBDRV_CONFIG_BATTERY_ADC_CURRENT_CORRECTION / 16; |
50 | 103 |
|
51 | 104 | return PBIO_SUCCESS;
|
52 | 105 | }
|
|
0 commit comments