Changed AMS1117 with TPS63001(1.2A max buck/boost convertor)

main
noah metz 2026-06-25 01:31:10 -06:00
parent 21ecc5ab16
commit 5e45d07eb0
8 changed files with 6785 additions and 3820 deletions

@ -7,8 +7,8 @@
#define BTN_BACK_GPIO 13 #define BTN_BACK_GPIO 13
// ── RGB LED ─────────────────────────────────────────────────────────────────── // ── RGB LED ───────────────────────────────────────────────────────────────────
#define LED_R_GPIO 16 #define LED_R_GPIO 17
#define LED_G_GPIO 17 #define LED_G_GPIO 16
#define LED_B_GPIO 4 #define LED_B_GPIO 4
// ── I2C / OLED ──────────────────────────────────────────────────────────────── // ── I2C / OLED ────────────────────────────────────────────────────────────────
@ -105,7 +105,11 @@ extern const char *counter_names[NUM_COUNTERS];
// ── Battery ADC (GPIO34, ADC1 Channel 6) ────────────────────────────────────── // ── Battery ADC (GPIO34, ADC1 Channel 6) ──────────────────────────────────────
#define BATT_LOW_PCT 10 // flash battery indicator below this #define BATT_LOW_PCT 10 // flash battery indicator below this
#define BATT_SAMPLE_TICKS 500 // sample every 500 × 10ms = 5s #define BATT_SAMPLE_TICKS 50 // sample every 50 × 10ms = 0.5s
#define BATT_CHARGE_GPIO 23 // low when charger is connected (active-low)
#define BATT_FULL_GPIO 19 // low when battery is full (active-low)
#define BATT_LOAD_COMP_BLE_MV 200 // voltage sag offset (mV) when BLE is active
#define BATT_LOAD_COMP_MV 50 // voltage sag offset (mV) when BLE is off
// ── Auto-sleep ──────────────────────────────────────────────────────────────── // ── Auto-sleep ────────────────────────────────────────────────────────────────
#define SLEEP_TIMEOUT_DEF 60 // default auto-sleep timeout (minutes) #define SLEEP_TIMEOUT_DEF 60 // default auto-sleep timeout (minutes)

@ -153,11 +153,13 @@ void oled_draw_header(void)
} }
// Slot 5 (cols 80-95): percentage text, page 0 // Slot 5 (cols 80-95): percentage text, page 0
// Slot 6 (cols 96-111): vertical battery icon, nub at top, fill from bottom // Slot 6 (cols 96-111): vertical battery icon, nub at top, fill from bottom
// or lightning bolt when charging
if (g_battery_pct >= 0) { if (g_battery_pct >= 0) {
int show = (g_battery_pct >= BATT_LOW_PCT || (g_tick / 50) % 2 == 0); int show = (g_battery_pct >= BATT_LOW_PCT || (g_tick / 50) % 2 == 0);
if (show) { if (show) {
// ── Percentage text, vertically centered (rows 4-11) ───────────── if (!g_charging && !g_batt_full) {
// ── Percentage text, vertically centered (rows 4-11) ─────────
char pct_str[5]; char pct_str[5];
int plen = snprintf(pct_str, sizeof(pct_str), "%d", g_battery_pct); int plen = snprintf(pct_str, sizeof(pct_str), "%d", g_battery_pct);
int tx = 5 * SEG_W + (SEG_W - plen * 5) / 2; int tx = 5 * SEG_W + (SEG_W - plen * 5) / 2;
@ -167,36 +169,70 @@ void oled_draw_header(void)
const uint8_t *glyph = font5x8[c - FONT_BASE]; const uint8_t *glyph = font5x8[c - FONT_BASE];
for (int sc = 0; sc < 5; sc++, tx++) { for (int sc = 0; sc < 5; sc++, tx++) {
if (tx < 0 || tx >= OLED_WIDTH) continue; if (tx < 0 || tx >= OLED_WIDTH) continue;
pages[0][tx] &= ~(uint8_t)(glyph[sc] << 4); // font bits 0-3 → rows 4-7 pages[0][tx] &= ~(uint8_t)(glyph[sc] << 4);
pages[1][tx] &= ~(uint8_t)(glyph[sc] >> 4); // font bits 4-7 → rows 8-11 pages[1][tx] &= ~(uint8_t)(glyph[sc] >> 4);
}
} }
} }
// ── Vertical battery icon ───────────────────────────────────────── // ── Vertical battery icon ─────────────────────────────────────────
// 1px inset from slot edges: body cols 2-13, rows 3-14. // Body: cols 2-13, rows 3-14. Nub: cols 5-10, rows 1-2.
// Nub: cols 5-10, rows 1-2. // Inner: cols 3-12, rows 4-13 (10 rows).
// Inner: cols 3-12, rows 4-13 (10 rows). Fill rises from bottom. int bbase = 6 * SEG_W;
if (g_batt_full) {
// Fully filled battery body; no percentage text.
for (int x = 0; x < 16; x++) {
uint8_t p0 = 0, p1 = 0;
if (x == 2 || x == 13) {
p0 = 0xF8; p1 = 0x7F;
} else if (x >= 3 && x <= 12) {
p0 = 0xF8; p1 = 0x7F;
}
if (x >= 5 && x <= 10) p0 |= 0x06;
pages[0][bbase + x] &= ~p0;
pages[1][bbase + x] &= ~p1;
}
} else if (g_charging) {
// Lightning bolt inside body; no fill level or percentage.
// Per-column page masks for rows 4-13 within the 16-wide slot:
// p0 bits 4-7 → rows 4-7; p1 bits 0-5 → rows 8-13
static const uint8_t bp0[16] = {0,0,0,0,0,0x80,0x80,0xC0,0xF0,0x90,0x10,0,0,0,0,0};
static const uint8_t bp1[16] = {0,0,0,0,0,0x19,0x0D,0x03,0x01,0x01,0x00,0,0,0,0,0};
for (int x = 0; x < 16; x++) {
uint8_t p0 = bp0[x], p1 = bp1[x];
if (x == 2 || x == 13) {
p0 |= 0xF8; p1 |= 0x7F;
} else if (x >= 3 && x <= 12) {
p0 |= 0x08; // top border row 3
p1 |= 0x40; // bottom border row 14
}
if (x >= 5 && x <= 10) p0 |= 0x06; // nub rows 1-2
pages[0][bbase + x] &= ~p0;
pages[1][bbase + x] &= ~p1;
}
} else {
// Fill level rising from bottom.
int fill_rows = g_battery_pct * 10 / 100; int fill_rows = g_battery_pct * 10 / 100;
int fill_start = 14 - fill_rows; // first filled inner row int fill_start = 14 - fill_rows;
uint8_t p0_fill = 0, p1_fill = 0; uint8_t p0_fill = 0, p1_fill = 0;
for (int r = 4; r <= 7; r++) if (r >= fill_start) p0_fill |= (1 << r); for (int r = 4; r <= 7; r++) if (r >= fill_start) p0_fill |= (1 << r);
for (int r = 8; r <= 13; r++) if (r >= fill_start) p1_fill |= (1 << (r-8)); for (int r = 8; r <= 13; r++) if (r >= fill_start) p1_fill |= (1 << (r-8));
int bbase = 6 * SEG_W;
for (int x = 0; x < 16; x++) { for (int x = 0; x < 16; x++) {
uint8_t p0 = 0, p1 = 0; uint8_t p0 = 0, p1 = 0;
if (x == 2 || x == 13) { if (x == 2 || x == 13) {
p0 = 0xF8; p1 = 0x7F; // side borders rows 3-14 p0 = 0xF8; p1 = 0x7F;
} else if (x >= 3 && x <= 12) { } else if (x >= 3 && x <= 12) {
p0 = 0x08 | p0_fill; // top border (row 3) + fill p0 = 0x08 | p0_fill;
p1 = 0x40 | p1_fill; // bottom border (row 14) + fill p1 = 0x40 | p1_fill;
} }
if (x >= 5 && x <= 10) p0 |= 0x06; // nub rows 1-2 if (x >= 5 && x <= 10) p0 |= 0x06;
pages[0][bbase + x] &= ~p0; pages[0][bbase + x] &= ~p0;
pages[1][bbase + x] &= ~p1; pages[1][bbase + x] &= ~p1;
} }
} }
} }
}
for (int p = 0; p < HEADER_PAGES; p++) oled_write_page(p, pages[p]); for (int p = 0; p < HEADER_PAGES; p++) oled_write_page(p, pages[p]);
} }

@ -24,6 +24,8 @@
// ── Global state ────────────────────────────────────────────────────────────── // ── Global state ──────────────────────────────────────────────────────────────
int g_sleep_mode = 0; int g_sleep_mode = 0;
int g_battery_pct = -1; int g_battery_pct = -1;
int g_charging = 0;
int g_batt_full = 0;
int g_sleep_timeout_min = SLEEP_TIMEOUT_DEF; int g_sleep_timeout_min = SLEEP_TIMEOUT_DEF;
static adc_oneshot_unit_handle_t s_adc; static adc_oneshot_unit_handle_t s_adc;
@ -78,6 +80,7 @@ int g_dice_rolled = 0;
int g_dice_sum = 0; int g_dice_sum = 0;
// ── Serial command task ─────────────────────────────────────────────────────── // ── Serial command task ───────────────────────────────────────────────────────
#ifdef DEBUG
static void serial_print_state(void) static void serial_print_state(void)
{ {
printf("DBG STATE life=%d poison=%u cmdr=[%d,%d,%d,%d] counters=[%d,%d,%d] menu=%d ble=%d eliminated=%d\n", printf("DBG STATE life=%d poison=%u cmdr=[%d,%d,%d,%d] counters=[%d,%d,%d] menu=%d ble=%d eliminated=%d\n",
@ -150,6 +153,7 @@ static void serial_cmd_task(void *arg)
} }
} }
} }
#endif // DEBUG
// ── app_main ────────────────────────────────────────────────────────────────── // ── app_main ──────────────────────────────────────────────────────────────────
void app_main(void) void app_main(void)
@ -200,12 +204,21 @@ void app_main(void)
}; };
gpio_config(&gpio_cfg); gpio_config(&gpio_cfg);
gpio_config_t charge_cfg = {
.pin_bit_mask = (1ULL<<BATT_CHARGE_GPIO) | (1ULL<<BATT_FULL_GPIO),
.mode=GPIO_MODE_INPUT, .pull_up_en=GPIO_PULLUP_ENABLE,
.pull_down_en=GPIO_PULLDOWN_DISABLE, .intr_type=GPIO_INTR_DISABLE,
};
gpio_config(&charge_cfg);
ble_init(); ble_init();
#ifdef DEBUG
uart_driver_install(UART_NUM_0, 256, 0, 0, NULL, 0); uart_driver_install(UART_NUM_0, 256, 0, 0, NULL, 0);
esp_vfs_dev_uart_use_driver(0); esp_vfs_dev_uart_use_driver(0);
setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdin, NULL, _IONBF, 0);
xTaskCreate(serial_cmd_task, "serial_cmd", 4096, NULL, 3, NULL); xTaskCreate(serial_cmd_task, "serial_cmd", 4096, NULL, 3, NULL);
#endif
oled_draw_header(); oled_draw_header();
oled_draw_life(); oled_draw_life();
@ -717,15 +730,37 @@ void app_main(void)
if (g_battery_pct >= 0 && g_battery_pct < BATT_LOW_PCT && g_tick % 50 == 0) if (g_battery_pct >= 0 && g_battery_pct < BATT_LOW_PCT && g_tick % 50 == 0)
oled_draw_header(); oled_draw_header();
// Update charging/full state every 50 ticks (0.5s); redraw header on change
if (g_tick % 50 == 0) {
int charging = !gpio_get_level(BATT_CHARGE_GPIO);
int batt_full = !gpio_get_level(BATT_FULL_GPIO);
if (charging != g_charging || batt_full != g_batt_full) {
g_charging = charging;
g_batt_full = batt_full;
oled_draw_header();
}
}
if (++batt_tick >= BATT_SAMPLE_TICKS) { if (++batt_tick >= BATT_SAMPLE_TICKS) {
batt_tick = 0; batt_tick = 0;
int raw, voltage_mv; static int batt_raw_buf[100];
static int batt_raw_idx = 0;
static int batt_raw_count = 0;
int raw;
adc_oneshot_read(s_adc, ADC_CHANNEL_6, &raw); adc_oneshot_read(s_adc, ADC_CHANNEL_6, &raw);
batt_raw_buf[batt_raw_idx] = raw;
batt_raw_idx = (batt_raw_idx + 1) % 100;
if (batt_raw_count < 100) batt_raw_count++;
int sum = 0;
for (int i = 0; i < batt_raw_count; i++) sum += batt_raw_buf[i];
int avg_raw = sum / batt_raw_count;
int voltage_mv;
if (s_adc_cali_ok) if (s_adc_cali_ok)
adc_cali_raw_to_voltage(s_adc_cali, raw, &voltage_mv); adc_cali_raw_to_voltage(s_adc_cali, avg_raw, &voltage_mv);
else else
voltage_mv = raw * 3100 / 4095; voltage_mv = avg_raw * 3100 / 4095;
int cell_mv = voltage_mv * 2; // 100k/100k voltage divider int comp_mv = g_ble_enabled ? BATT_LOAD_COMP_BLE_MV : BATT_LOAD_COMP_MV;
int cell_mv = voltage_mv * 2 + comp_mv; // 100k/100k divider + load compensation
// LiPo discharge curve: piecewise linear interpolation. // LiPo discharge curve: piecewise linear interpolation.
// Voltage stays flat ~3.7-4.2V through most of charge; linear // Voltage stays flat ~3.7-4.2V through most of charge; linear
// mapping reads too high. Table derived from typical LiPo OCV curve. // mapping reads too high. Table derived from typical LiPo OCV curve.

@ -35,6 +35,8 @@ extern ble_peer_t g_peers[MAX_BLE_PEERS];
// Battery / power // Battery / power
extern int g_battery_pct; // -1 = not yet sampled extern int g_battery_pct; // -1 = not yet sampled
extern int g_charging; // 1 when charger is connected (BATT_CHARGE_GPIO low)
extern int g_batt_full; // 1 when battery is full (BATT_FULL_GPIO low)
extern int g_sleep_timeout_min; // 0 = disabled extern int g_sleep_timeout_min; // 0 = disabled
// Timing // Timing

File diff suppressed because it is too large Load Diff

@ -1,7 +1,7 @@
{ {
"board": { "board": {
"active_layer": 0, "active_layer": 2,
"active_layer_preset": "All Layers", "active_layer_preset": "Back Layers",
"auto_track_width": true, "auto_track_width": true,
"hidden_netclasses": [], "hidden_netclasses": [],
"hidden_nets": [], "hidden_nets": [],
@ -53,7 +53,7 @@
"board_outline_area", "board_outline_area",
"ly_points" "ly_points"
], ],
"visible_layers": "ffffffff_ffffffff_ffffffff_ffffffff", "visible_layers": "00000000_00000000_00000002_2200888c",
"zone_display_mode": 0 "zone_display_mode": 0
}, },
"git": { "git": {

@ -691,7 +691,7 @@
"uuid": "4f1ddaab-5ed8-4280-ae9f-5da3efc5b3b5" "uuid": "4f1ddaab-5ed8-4280-ae9f-5da3efc5b3b5"
} }
], ],
"used_designators": "#PWR16-17,#PWR44-45,R23-26,D3", "used_designators": "",
"variants": [] "variants": []
}, },
"sheets": [ "sheets": [

File diff suppressed because it is too large Load Diff