Skip to content

Commit b6548a3

Browse files
committed
drv/battery/battery_adc: improve accuracy
ADC scaling is tweaked based on experimental measurements. Also current is now taken into account in the voltage measurement as it has been shown to contribute significantly (more than 0.1 V) due to the fact that the voltage is measured after the resettable fuses on the hubs. Issue: pybricks/pybricks-micropython#5
1 parent 28811e7 commit b6548a3

File tree

5 files changed

+89
-30
lines changed

5 files changed

+89
-30
lines changed

lib/pbio/drv/battery/battery_adc.c

Lines changed: 65 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,32 @@
33

44
// Battery driver that uses an ADC to read battery voltage and current
55

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+
632
#include <pbdrv/config.h>
733

834
#if PBDRV_CONFIG_BATTERY_ADC
@@ -17,36 +43,63 @@
1743
void pbdrv_battery_init() {
1844
}
1945

20-
pbio_error_t pbdrv_battery_get_voltage_now(uint16_t *value) {
46+
pbio_error_t pbdrv_battery_get_current_now(uint16_t *value) {
2147
uint16_t raw;
2248
pbio_error_t err;
2349

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);
2553
if (err != PBIO_SUCCESS) {
2654
return err;
2755
}
2856

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;
3369

3470
return PBIO_SUCCESS;
3571
}
3672

37-
pbio_error_t pbdrv_battery_get_current_now(uint16_t *value) {
73+
pbio_error_t pbdrv_battery_get_voltage_now(uint16_t *value) {
3874
uint16_t raw;
3975
pbio_error_t err;
4076

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);
4478
if (err != PBIO_SUCCESS) {
4579
return err;
4680
}
4781

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(&current);
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;
50103

51104
return PBIO_SUCCESS;
52105
}

lib/pbio/platform/city_hub/pbdrvconfig.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@
1212
#define PBDRV_CONFIG_BATTERY (1)
1313
#define PBDRV_CONFIG_BATTERY_ADC (1)
1414
#define PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_CH 11
15-
#define PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_RAW_MAX 3893
16-
#define PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_SCALED_MAX 9600
15+
#define PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_RAW_MAX 4096
16+
#define PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_SCALED_MAX 10100
17+
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_CORRECTION 12
1718
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_CH 10
18-
// FIXME: these values come from LEGO firmware, but seem to be 2x current
19-
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_RAW_MAX 4095
20-
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_SCALED_MAX 2444
19+
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_RAW_OFFSET 130
20+
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_RAW_MAX 4096
21+
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_SCALED_MAX 2448
2122

2223
#define PBDRV_CONFIG_BUTTON (1)
2324
#define PBDRV_CONFIG_BUTTON_GPIO (1)

lib/pbio/platform/move_hub/pbdrvconfig.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@
1212
#define PBDRV_CONFIG_BATTERY (1)
1313
#define PBDRV_CONFIG_BATTERY_ADC (1)
1414
#define PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_CH 11
15-
#define PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_RAW_MAX 3893
16-
#define PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_SCALED_MAX 9600
15+
#define PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_RAW_MAX 4096
16+
#define PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_SCALED_MAX 10100
17+
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_CORRECTION 12
1718
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_CH 10
18-
// FIXME: these values come from LEGO firmware, but seem to be 2x current
19-
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_RAW_MAX 4095
20-
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_SCALED_MAX 2444
19+
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_RAW_OFFSET 0
20+
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_RAW_MAX 4096
21+
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_SCALED_MAX 2448
2122

2223
#define PBDRV_CONFIG_BLUETOOTH (1)
2324

lib/pbio/platform/prime_hub/pbdrvconfig.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919
#define PBDRV_CONFIG_BATTERY (1)
2020
#define PBDRV_CONFIG_BATTERY_ADC (1)
2121
#define PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_CH 1
22-
#define PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_RAW_MAX 4095
23-
#define PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_SCALED_MAX 9615
22+
#define PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_RAW_MAX 4096
23+
#define PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_SCALED_MAX 9900
24+
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_CORRECTION 3
2425
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_CH 0
25-
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_RAW_MAX 4095
26-
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_SCALED_MAX 4175
26+
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_RAW_OFFSET 0
27+
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_RAW_MAX 4096
28+
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_SCALED_MAX 7300
2729

2830
#define PBDRV_CONFIG_BUTTON (1)
2931
#define PBDRV_CONFIG_BUTTON_ADC (1)

lib/pbio/platform/technic_hub/pbdrvconfig.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717
#define PBDRV_CONFIG_BATTERY (1)
1818
#define PBDRV_CONFIG_BATTERY_ADC (1)
1919
#define PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_CH 0
20-
#define PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_RAW_MAX 4095
21-
#define PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_SCALED_MAX 9615
20+
#define PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_RAW_MAX 4096
21+
#define PBDRV_CONFIG_BATTERY_ADC_VOLTAGE_SCALED_MAX 9618
22+
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_CORRECTION 12
2223
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_CH 1
23-
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_RAW_MAX 4095
24-
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_SCALED_MAX 4175
24+
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_RAW_OFFSET 20
25+
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_RAW_MAX 4096
26+
#define PBDRV_CONFIG_BATTERY_ADC_CURRENT_SCALED_MAX 4178
2527

2628
#define PBDRV_CONFIG_BLUETOOTH (1)
2729

0 commit comments

Comments
 (0)