summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomasz Moń <desowin@gmail.com>2021-07-07 08:22:50 +0200
committerTomasz Moń <desowin@gmail.com>2021-07-07 08:24:01 +0200
commit841e704fc3b5bde96ca8de4794c85198e2f12a65 (patch)
tree796859262b7398b6300d01c09782971f5ee65226
parentb87e75f768eba3ccdf422a5082c91097a0b72b5b (diff)
downloadrockbox-841e704fc3b5bde96ca8de4794c85198e2f12a65.tar.gz
rockbox-841e704fc3b5bde96ca8de4794c85198e2f12a65.zip
Sansa Connect: Read HDQ battery data
Make it possible for target to provide voltage, percentage and time to empty values. The voltage measurement is nice to have in debug menu even if the actions are taken only based on percentage. Perform battery level estimation based on voltage only if percentage is not available. Use time to empty based on actual power consumption. This makes the estimated runtime displayed in Rockbox Info to react to backlight setting. The bq27000 updates time to empty estimate every 5.12 seconds so it is possible to see the estimate with backlight off on the screen if user enters Rockbox Info, activates hold switch, waits 11 seconds and releases the hold switch. Change-Id: Iafe3fa0fb334e3428e3a0ad05b2c020d208dc934
-rw-r--r--firmware/export/config/sansaconnect.h10
-rw-r--r--firmware/powermgmt.c20
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c83
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h30
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/power-sansaconnect.c25
5 files changed, 153 insertions, 15 deletions
diff --git a/firmware/export/config/sansaconnect.h b/firmware/export/config/sansaconnect.h
index 5668d579fc..fa929f3c10 100644
--- a/firmware/export/config/sansaconnect.h
+++ b/firmware/export/config/sansaconnect.h
@@ -152,7 +152,15 @@
152#define BATTERY_CAPACITY_INC 100 /* capacity increment */ 152#define BATTERY_CAPACITY_INC 100 /* capacity increment */
153#define BATTERY_TYPES_COUNT 1 /* only one type */ 153#define BATTERY_TYPES_COUNT 1 /* only one type */
154 154
155#define CONFIG_BATTERY_MEASURE PERCENTAGE_MEASURE 155/* bq27000 provides voltage, percentage and time measure.
156 * Voltage reading is available every 2.56 seconds and does not need filtering.
157 * Read the measured voltage every 3 seconds so we are guaranteed to not read
158 * the same value twice (do not try to read every 2.56 seconds as clocks are
159 * not synchronized).
160 */
161#define CONFIG_BATTERY_MEASURE (VOLTAGE_MEASURE|PERCENTAGE_MEASURE|TIME_MEASURE)
162#define BATT_AVE_SAMPLES 1
163#define POWER_THREAD_STEP_TICKS (3*HZ)
156 164
157/* define current usage levels */ 165/* define current usage levels */
158#if 0 166#if 0
diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c
index a05e0aeb68..51ea99f6fa 100644
--- a/firmware/powermgmt.c
+++ b/firmware/powermgmt.c
@@ -88,16 +88,12 @@ static long last_event_tick = 0;
88#if (CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE) == PERCENTAGE_MEASURE 88#if (CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE) == PERCENTAGE_MEASURE
89#ifdef SIMULATOR 89#ifdef SIMULATOR
90int _battery_level(void) { return -1; } 90int _battery_level(void) { return -1; }
91int _battery_voltage(void);
92extern const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11];
93extern const unsigned short percent_to_volt_charge[11];
94#else
95int _battery_voltage(void) { return -1; }
96const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11];
97const unsigned short percent_to_volt_charge[11];
98#endif 91#endif
99#elif (CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE) == VOLTAGE_MEASURE 92#else
100int _battery_level(void) { return -1; } 93int _battery_level(void) { return -1; }
94#endif
95
96#if (CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE) == VOLTAGE_MEASURE
101/* 97/*
102 * Average battery voltage and charger voltage, filtered via a digital 98 * Average battery voltage and charger voltage, filtered via a digital
103 * exponential filter (aka. exponential moving average, scaled): 99 * exponential filter (aka. exponential moving average, scaled):
@@ -106,10 +102,8 @@ int _battery_level(void) { return -1; }
106static unsigned int avgbat; 102static unsigned int avgbat;
107/* filtered battery voltage, millivolts */ 103/* filtered battery voltage, millivolts */
108static unsigned int battery_millivolts; 104static unsigned int battery_millivolts;
109#elif (CONFIG_BATTERY_MEASURE == 0) 105#else
110int _battery_voltage(void) { return -1; } 106int _battery_voltage(void) { return -1; }
111int _battery_level(void) { return -1; }
112
113const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11]; 107const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11];
114const unsigned short percent_to_volt_charge[11]; 108const unsigned short percent_to_volt_charge[11];
115#endif 109#endif
@@ -156,9 +150,9 @@ void battery_read_info(int *voltage, int *level)
156 *voltage = millivolts; 150 *voltage = millivolts;
157 151
158 if (level) { 152 if (level) {
159 percent = voltage_to_battery_level(millivolts); 153 percent = _battery_level();
160 if (percent < 0) 154 if (percent < 0)
161 percent = _battery_level(); 155 percent = voltage_to_battery_level(millivolts);
162 *level = percent; 156 *level = percent;
163 } 157 }
164} 158}
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c
index 8ebba3a8d5..ed7dab1572 100644
--- a/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c
+++ b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c
@@ -104,8 +104,15 @@
104#define SYS_CTRL_EN_TS_THERM 0x06 104#define SYS_CTRL_EN_TS_THERM 0x06
105#define SYS_CTRL_FRESET 0x80 105#define SYS_CTRL_FRESET 0x80
106 106
107/* HDQ status codes */
108#define HDQ_STATUS_OK 0x00
109#define HDQ_STATUS_NOT_READY 0x01
110#define HDQ_STATUS_TIMEOUT 0x02
111
107/* protects spi avr commands from concurrent access */ 112/* protects spi avr commands from concurrent access */
108static struct mutex avr_mtx; 113static struct mutex avr_mtx;
114/* serializes hdq read/write and status retrieval */
115static struct mutex hdq_mtx;
109 116
110/* AVR thread events */ 117/* AVR thread events */
111#define INPUT_INTERRUPT 1 118#define INPUT_INTERRUPT 1
@@ -498,6 +505,7 @@ void avr_hid_init(void)
498 IO_SERIAL1_MODE = 0x6DB; 505 IO_SERIAL1_MODE = 0x6DB;
499 506
500 mutex_init(&avr_mtx); 507 mutex_init(&avr_mtx);
508 mutex_init(&hdq_mtx);
501} 509}
502 510
503int _battery_level(void) 511int _battery_level(void)
@@ -510,6 +518,17 @@ int _battery_level(void)
510 return avr_battery_level & BATTERY_LEVEL_PERCENTAGE_MASK; 518 return avr_battery_level & BATTERY_LEVEL_PERCENTAGE_MASK;
511} 519}
512 520
521int _battery_voltage(void)
522{
523 return avr_hid_hdq_read_short(HDQ_REG_VOLT);
524}
525
526int _battery_time(void)
527{
528 /* HDQ_REG_TTE reads as 65535 when charging */
529 return avr_hid_hdq_read_short(HDQ_REG_TTE);
530}
531
513unsigned int power_input_status(void) 532unsigned int power_input_status(void)
514{ 533{
515 if (avr_battery_status & BATTERY_STATUS_CHARGER_CONNECTED) 534 if (avr_battery_status & BATTERY_STATUS_CHARGER_CONNECTED)
@@ -524,6 +543,70 @@ bool charging_state(void)
524 return (avr_battery_status & BATTERY_STATUS_CHARGING) != 0; 543 return (avr_battery_status & BATTERY_STATUS_CHARGING) != 0;
525} 544}
526 545
546static int avr_hid_hdq_read_byte_internal(uint8_t address)
547{
548 uint8_t result[2];
549
550 if (!avr_execute_command(CMD_HDQ_READ, &address, sizeof(address)))
551 {
552 return -1;
553 }
554
555 do
556 {
557 mdelay(10);
558 if (!avr_execute_command(CMD_HDQ_STATUS, result, sizeof(result)))
559 {
560 return -1;
561 }
562 }
563 while (result[0] == HDQ_STATUS_NOT_READY);
564
565 if (result[0] != HDQ_STATUS_OK)
566 {
567 logf("HDQ read %d status %d", address, result[0]);
568 return -1;
569 }
570
571 return result[1];
572}
573
574int avr_hid_hdq_read_byte(uint8_t address)
575{
576 int retry;
577 int value = -1;
578 for (retry = 0; (retry < 3) && (value < 0); retry++)
579 {
580 mutex_lock(&hdq_mtx);
581 value = avr_hid_hdq_read_byte_internal(address);
582 mutex_unlock(&hdq_mtx);
583 }
584 return value;
585}
586
587int avr_hid_hdq_read_short(uint8_t address)
588{
589 int old_hi = -1, old_lo = -1, hi = -2, lo = -2;
590 /* Keep reading until we read the same value twice.
591 * There's no atomic 16-bit value retrieval, so keep reading
592 * until we read the same value twice. HDQ registers update
593 * no more than once per 2.56 seconds so usually there will
594 * be 4 reads and sometimes 6 reads.
595 */
596 while ((old_hi != hi) || (old_lo != lo))
597 {
598 old_hi = hi;
599 old_lo = lo;
600 hi = avr_hid_hdq_read_byte(address + 1);
601 lo = avr_hid_hdq_read_byte(address);
602 }
603 if ((hi < 0) || (lo < 0))
604 {
605 return -1;
606 }
607 return (hi << 8) | lo;
608}
609
527static void avr_hid_enable_wheel(void) 610static void avr_hid_enable_wheel(void)
528{ 611{
529 uint8_t enable = 0x01; 612 uint8_t enable = 0x01;
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h
index baa7083760..ed23e84936 100644
--- a/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h
+++ b/firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h
@@ -24,8 +24,38 @@
24 24
25#include "config.h" 25#include "config.h"
26 26
27/* HDQ (bq27000) RAM registers */
28#define HDQ_REG_CTRL 0x00
29#define HDQ_REG_MODE 0x01
30#define HDQ_REG_AR 0x02
31#define HDQ_REG_ARTTE 0x04
32#define HDQ_REG_TEMP 0x06
33#define HDQ_REG_VOLT 0x08
34#define HDQ_REG_FLAGS 0x0A
35#define HDQ_REG_RSOC 0x0B
36#define HDQ_REG_NAC 0x0C
37#define HDQ_REG_CACD 0x0E
38#define HDQ_REG_CACT 0x10
39#define HDQ_REG_LMD 0x12
40#define HDQ_REG_AI 0x14
41#define HDQ_REG_TTE 0x16
42#define HDQ_REG_TTF 0x18
43#define HDQ_REG_SI 0x1A
44#define HDQ_REG_STTE 0x1C
45#define HDQ_REG_MLI 0x1E
46#define HDQ_REG_MLTTE 0x20
47#define HDQ_REG_SAE 0x22
48#define HDQ_REG_AP 0x24
49#define HDQ_REG_TTECP 0x26
50#define HDQ_REG_CYCL 0x28
51#define HDQ_REG_CYCT 0x2A
52#define HDQ_REG_CSOC 0x2C
53
27void avr_hid_init(void); 54void avr_hid_init(void);
28 55
56int avr_hid_hdq_read_byte(uint8_t address);
57int avr_hid_hdq_read_short(uint8_t address);
58
29void avr_hid_enable_charger(void); 59void avr_hid_enable_charger(void);
30 60
31void avr_hid_wifi_pd(int high); 61void avr_hid_wifi_pd(int high);
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/power-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/power-sansaconnect.c
index ccd91c6d2f..597fb6b7e0 100644
--- a/firmware/target/arm/tms320dm320/sansa-connect/power-sansaconnect.c
+++ b/firmware/target/arm/tms320dm320/sansa-connect/power-sansaconnect.c
@@ -31,6 +31,29 @@
31#include "i2c-dm320.h" 31#include "i2c-dm320.h"
32#include "logf.h" 32#include "logf.h"
33 33
34
35const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
36{
37 3450
38};
39
40const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] =
41{
42 3400
43};
44
45/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */
46const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] =
47{
48 { 3400, 3508, 3630, 3703, 3727, 3750, 3803, 3870, 3941, 4026, 4142 }
49};
50
51/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */
52const unsigned short percent_to_volt_charge[11] =
53{
54 3540, 3788, 3860, 3890, 3916, 3956, 4016, 4085, 4164, 4180, 4190
55};
56
34/* (7-bit) address is 0x48, the LSB is read/write flag */ 57/* (7-bit) address is 0x48, the LSB is read/write flag */
35#define TPS65021_ADDR (0x48 << 1) 58#define TPS65021_ADDR (0x48 << 1)
36 59
@@ -54,7 +77,7 @@ void power_init(void)
54 77
55 /* PWM mode */ 78 /* PWM mode */
56 tps65021_write_reg(0x04, 0xB2); 79 tps65021_write_reg(0x04, 0xB2);
57 80
58 /* Set core voltage to 1.5V */ 81 /* Set core voltage to 1.5V */
59 tps65021_write_reg(0x06, 0x1C); 82 tps65021_write_reg(0x06, 0x1C);
60 83