make switching on and off on battery possible
This commit is contained in:
371
src/main.c
371
src/main.c
@@ -8,6 +8,9 @@
|
|||||||
#include <zephyr/drivers/uart.h>
|
#include <zephyr/drivers/uart.h>
|
||||||
#include <zephyr/drivers/sensor.h>
|
#include <zephyr/drivers/sensor.h>
|
||||||
#include <zephyr/drivers/sensor/npm1300_charger.h>
|
#include <zephyr/drivers/sensor/npm1300_charger.h>
|
||||||
|
#include <zephyr/drivers/mfd/npm1300.h>
|
||||||
|
#include <zephyr/drivers/gpio.h>
|
||||||
|
#include <zephyr/drivers/regulator.h>
|
||||||
#include <nrf_fuel_gauge.h>
|
#include <nrf_fuel_gauge.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -17,8 +20,28 @@
|
|||||||
|
|
||||||
static const struct device *const uart_dev = DEVICE_DT_GET(UART_DEVICE_NODE);
|
static const struct device *const uart_dev = DEVICE_DT_GET(UART_DEVICE_NODE);
|
||||||
static const struct device *charger_dev;
|
static const struct device *charger_dev;
|
||||||
|
static const struct device *pmic_dev;
|
||||||
|
static const struct device *regulators_dev;
|
||||||
static int64_t ref_time;
|
static int64_t ref_time;
|
||||||
|
|
||||||
|
/* Power state machine (matches diagram)
|
||||||
|
* OFF_HIBERNATE: Device off/ship mode (not represented in code - device is off)
|
||||||
|
* ON_BATTERY: Running on battery, no USB connected
|
||||||
|
* CHARGING_ON: Running with USB connected (SW=ON)
|
||||||
|
* CHARGING_ONLY: Soft sleep with USB connected (SW=OFF)
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
POWER_STATE_ON_BATTERY,
|
||||||
|
POWER_STATE_CHARGING_ON,
|
||||||
|
POWER_STATE_CHARGING_ONLY
|
||||||
|
} power_state_t;
|
||||||
|
|
||||||
|
static power_state_t app_state = POWER_STATE_ON_BATTERY;
|
||||||
|
static struct gpio_callback pmic_cb;
|
||||||
|
static volatile bool shphld_pressed = false;
|
||||||
|
static volatile bool vbus_changed = false;
|
||||||
|
static volatile bool vbus_detected = false;
|
||||||
|
|
||||||
/* Battery model from SDK sample */
|
/* Battery model from SDK sample */
|
||||||
static const struct battery_model battery_model = {
|
static const struct battery_model battery_model = {
|
||||||
#include "battery_model.inc"
|
#include "battery_model.inc"
|
||||||
@@ -51,11 +74,9 @@ static int read_sensors(float *voltage, float *current, float *temp, int32_t *ch
|
|||||||
sensor_channel_get(charger_dev, SENSOR_CHAN_GAUGE_VOLTAGE, &value);
|
sensor_channel_get(charger_dev, SENSOR_CHAN_GAUGE_VOLTAGE, &value);
|
||||||
*voltage = (float)value.val1 + ((float)value.val2 / 1000000);
|
*voltage = (float)value.val1 + ((float)value.val2 / 1000000);
|
||||||
|
|
||||||
/* Use die temp since no thermistor connected, clamp to model range 5-45C */
|
/* Use die temp since no thermistor connected (no clamping) */
|
||||||
sensor_channel_get(charger_dev, SENSOR_CHAN_DIE_TEMP, &value);
|
sensor_channel_get(charger_dev, SENSOR_CHAN_DIE_TEMP, &value);
|
||||||
*temp = (float)value.val1 + ((float)value.val2 / 1000000);
|
*temp = (float)value.val1 + ((float)value.val2 / 1000000);
|
||||||
if (*temp < 5.0f) *temp = 5.0f;
|
|
||||||
if (*temp > 45.0f) *temp = 45.0f;
|
|
||||||
|
|
||||||
sensor_channel_get(charger_dev, SENSOR_CHAN_GAUGE_AVG_CURRENT, &value);
|
sensor_channel_get(charger_dev, SENSOR_CHAN_GAUGE_AVG_CURRENT, &value);
|
||||||
*current = (float)value.val1 + ((float)value.val2 / 1000000);
|
*current = (float)value.val1 + ((float)value.val2 / 1000000);
|
||||||
@@ -75,6 +96,210 @@ static const char *charge_status_str(int32_t chg_status)
|
|||||||
return "NOT_CHARGING";
|
return "NOT_CHARGING";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ============== Power Management State Machine ============== */
|
||||||
|
|
||||||
|
static bool is_vbus_present(void)
|
||||||
|
{
|
||||||
|
struct sensor_value val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = sensor_attr_get(charger_dev, SENSOR_CHAN_NPM1300_CHARGER_VBUS_STATUS,
|
||||||
|
SENSOR_ATTR_NPM1300_CHARGER_VBUS_PRESENT, &val);
|
||||||
|
if (ret < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return val.val1 != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void enter_ship_mode(void)
|
||||||
|
{
|
||||||
|
print_uart(">>> Entering SHIP MODE (full power off)...\r\n");
|
||||||
|
k_sleep(K_MSEC(100)); /* Allow logs to flush */
|
||||||
|
|
||||||
|
/* Use regulator_parent_ship_mode() - this is the correct API for full shutdown */
|
||||||
|
int ret = regulator_parent_ship_mode(regulators_dev);
|
||||||
|
if (ret < 0) {
|
||||||
|
char buf[64];
|
||||||
|
snprintk(buf, sizeof(buf), "ERROR: Ship mode failed! ret=%d\r\n", ret);
|
||||||
|
print_uart(buf);
|
||||||
|
}
|
||||||
|
/* If successful, device will power off immediately and won't reach here */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void enter_soft_sleep_mode(void)
|
||||||
|
{
|
||||||
|
print_uart(">>> Entering CHARGING_ONLY (powering down nRF53, charging continues)...\r\n");
|
||||||
|
k_sleep(K_MSEC(100)); /* Allow logs to flush */
|
||||||
|
|
||||||
|
/* Actually power down the nRF53 - nPM1300 will continue charging battery */
|
||||||
|
/* On SHPHLD press, device wakes and will detect VBUS -> CHARGING_ON */
|
||||||
|
int ret = regulator_parent_ship_mode(regulators_dev);
|
||||||
|
if (ret < 0) {
|
||||||
|
char buf[64];
|
||||||
|
snprintk(buf, sizeof(buf), "ERROR: Ship mode failed! ret=%d\r\n", ret);
|
||||||
|
print_uart(buf);
|
||||||
|
/* Fall back to just state change if ship mode fails */
|
||||||
|
app_state = POWER_STATE_CHARGING_ONLY;
|
||||||
|
}
|
||||||
|
/* If successful, device will power off immediately and won't reach here */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pmic_event_handler(const struct device *dev, struct gpio_callback *cb,
|
||||||
|
uint32_t pins)
|
||||||
|
{
|
||||||
|
if (pins & BIT(NPM1300_EVENT_SHIPHOLD_PRESS)) {
|
||||||
|
printk("SHPHLD PRESS\n");
|
||||||
|
shphld_pressed = true;
|
||||||
|
}
|
||||||
|
if (pins & BIT(NPM1300_EVENT_SHIPHOLD_RELEASE)) {
|
||||||
|
printk("SHPHLD RELEASE\n");
|
||||||
|
}
|
||||||
|
if (pins & BIT(NPM1300_EVENT_VBUS_DETECTED)) {
|
||||||
|
printk("VBUS DETECTED\n");
|
||||||
|
vbus_changed = true;
|
||||||
|
vbus_detected = true;
|
||||||
|
}
|
||||||
|
if (pins & BIT(NPM1300_EVENT_VBUS_REMOVED)) {
|
||||||
|
printk("VBUS REMOVED\n");
|
||||||
|
vbus_changed = true;
|
||||||
|
vbus_detected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_power_button(void)
|
||||||
|
{
|
||||||
|
char buf[MSG_SIZE];
|
||||||
|
bool vbus_connected = is_vbus_present();
|
||||||
|
|
||||||
|
const char *state_str = "UNKNOWN";
|
||||||
|
switch (app_state) {
|
||||||
|
case POWER_STATE_ON_BATTERY: state_str = "ON_BATTERY"; break;
|
||||||
|
case POWER_STATE_CHARGING_ON: state_str = "CHARGING_ON"; break;
|
||||||
|
case POWER_STATE_CHARGING_ONLY: state_str = "CHARGING_ONLY"; break;
|
||||||
|
}
|
||||||
|
snprintk(buf, sizeof(buf), "Power button pressed. VBUS=%s, State=%s\r\n",
|
||||||
|
vbus_connected ? "present" : "absent", state_str);
|
||||||
|
print_uart(buf);
|
||||||
|
|
||||||
|
if (!vbus_connected) {
|
||||||
|
/* No USB: button press -> SHIP MODE (full power off) */
|
||||||
|
print_uart("No USB power - entering ship mode...\r\n");
|
||||||
|
enter_ship_mode();
|
||||||
|
} else {
|
||||||
|
/* USB present: button press -> CHARGING_ONLY (power down nRF53, keep charging)
|
||||||
|
* Note: On wake via SHPHLD, device restarts and goes to CHARGING_ON
|
||||||
|
*/
|
||||||
|
enter_soft_sleep_mode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_vbus_change(bool vbus_present)
|
||||||
|
{
|
||||||
|
char buf[MSG_SIZE];
|
||||||
|
const char *old_state = "UNKNOWN";
|
||||||
|
switch (app_state) {
|
||||||
|
case POWER_STATE_ON_BATTERY: old_state = "ON_BATTERY"; break;
|
||||||
|
case POWER_STATE_CHARGING_ON: old_state = "CHARGING_ON"; break;
|
||||||
|
case POWER_STATE_CHARGING_ONLY: old_state = "CHARGING_ONLY"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vbus_present) {
|
||||||
|
/* USB plugged in: ON_BATTERY -> CHARGING_ON */
|
||||||
|
if (app_state == POWER_STATE_ON_BATTERY) {
|
||||||
|
snprintk(buf, sizeof(buf), ">>> VBUS detected: %s -> CHARGING_ON\r\n", old_state);
|
||||||
|
print_uart(buf);
|
||||||
|
app_state = POWER_STATE_CHARGING_ON;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* USB removed */
|
||||||
|
if (app_state == POWER_STATE_CHARGING_ON) {
|
||||||
|
/* CHARGING_ON + VBUS removed -> ON_BATTERY */
|
||||||
|
snprintk(buf, sizeof(buf), ">>> VBUS removed: %s -> ON_BATTERY\r\n", old_state);
|
||||||
|
print_uart(buf);
|
||||||
|
app_state = POWER_STATE_ON_BATTERY;
|
||||||
|
} else if (app_state == POWER_STATE_CHARGING_ONLY) {
|
||||||
|
/* CHARGING_ONLY + VBUS removed -> SHIP MODE */
|
||||||
|
print_uart(">>> VBUS removed in CHARGING_ONLY -> entering ship mode...\r\n");
|
||||||
|
enter_ship_mode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int power_mgmt_init(void)
|
||||||
|
{
|
||||||
|
char buf[MSG_SIZE];
|
||||||
|
int ret;
|
||||||
|
uint8_t pending;
|
||||||
|
|
||||||
|
/* Get PMIC device */
|
||||||
|
pmic_dev = DEVICE_DT_GET(DT_NODELABEL(npm1300));
|
||||||
|
if (!device_is_ready(pmic_dev)) {
|
||||||
|
print_uart("ERROR: PMIC device not ready\r\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
print_uart("PMIC device: OK\r\n");
|
||||||
|
|
||||||
|
/* Get regulators device (needed for ship mode) */
|
||||||
|
regulators_dev = DEVICE_DT_GET(DT_CHILD(DT_NODELABEL(npm1300), regulators));
|
||||||
|
if (!device_is_ready(regulators_dev)) {
|
||||||
|
print_uart("ERROR: Regulators device not ready\r\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
print_uart("Regulators device: OK\r\n");
|
||||||
|
|
||||||
|
/* IMPORTANT: Clear pending SHPHLD events BEFORE registering callback
|
||||||
|
* This prevents the wake-up button press from immediately triggering ship mode again
|
||||||
|
*/
|
||||||
|
if (mfd_npm1300_reg_read(pmic_dev, 0x00, 0x12, &pending) == 0 && pending != 0) {
|
||||||
|
snprintk(buf, sizeof(buf), "Clearing wake-up SHPHLD events: 0x%02x\r\n", pending);
|
||||||
|
print_uart(buf);
|
||||||
|
mfd_npm1300_reg_write(pmic_dev, 0x00, 0x13, pending);
|
||||||
|
}
|
||||||
|
/* Clear VBUS events too */
|
||||||
|
if (mfd_npm1300_reg_read(pmic_dev, 0x00, 0x16, &pending) == 0 && pending != 0) {
|
||||||
|
snprintk(buf, sizeof(buf), "Clearing pending VBUS events: 0x%02x\r\n", pending);
|
||||||
|
print_uart(buf);
|
||||||
|
mfd_npm1300_reg_write(pmic_dev, 0x00, 0x17, pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Small delay to ensure button is released after wake-up */
|
||||||
|
k_sleep(K_MSEC(500));
|
||||||
|
|
||||||
|
/* Now register callback for PMIC events */
|
||||||
|
gpio_init_callback(&pmic_cb, pmic_event_handler,
|
||||||
|
BIT(NPM1300_EVENT_SHIPHOLD_PRESS) |
|
||||||
|
BIT(NPM1300_EVENT_SHIPHOLD_RELEASE) |
|
||||||
|
BIT(NPM1300_EVENT_VBUS_DETECTED) |
|
||||||
|
BIT(NPM1300_EVENT_VBUS_REMOVED));
|
||||||
|
|
||||||
|
ret = mfd_npm1300_add_callback(pmic_dev, &pmic_cb);
|
||||||
|
if (ret < 0) {
|
||||||
|
snprintk(buf, sizeof(buf), "ERROR: Failed to add PMIC callback: %d\r\n", ret);
|
||||||
|
print_uart(buf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
print_uart("PMIC callbacks registered\r\n");
|
||||||
|
|
||||||
|
/* Clear any events that occurred during the delay */
|
||||||
|
mfd_npm1300_reg_read(pmic_dev, 0x00, 0x12, &pending);
|
||||||
|
if (pending != 0) {
|
||||||
|
mfd_npm1300_reg_write(pmic_dev, 0x00, 0x13, pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set initial state based on VBUS presence */
|
||||||
|
if (is_vbus_present()) {
|
||||||
|
app_state = POWER_STATE_CHARGING_ON;
|
||||||
|
print_uart("Initial state: CHARGING_ON (VBUS present)\r\n");
|
||||||
|
} else {
|
||||||
|
app_state = POWER_STATE_ON_BATTERY;
|
||||||
|
print_uart("Initial state: ON_BATTERY (VBUS absent)\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================ */
|
||||||
|
|
||||||
static void print_init_config(void)
|
static void print_init_config(void)
|
||||||
{
|
{
|
||||||
char buf[MSG_SIZE];
|
char buf[MSG_SIZE];
|
||||||
@@ -82,8 +307,7 @@ static void print_init_config(void)
|
|||||||
|
|
||||||
print_uart("\r\n=== nPM1300 Configuration ===\r\n");
|
print_uart("\r\n=== nPM1300 Configuration ===\r\n");
|
||||||
|
|
||||||
/* DTS Config */
|
snprintk(buf, sizeof(buf), "Battery capacity: %.0f mAh\r\n",
|
||||||
snprintk(buf, sizeof(buf), "Battery capacity: %.0f mAh (configured)\r\n",
|
|
||||||
(double)BATTERY_CAPACITY_MAH);
|
(double)BATTERY_CAPACITY_MAH);
|
||||||
print_uart(buf);
|
print_uart(buf);
|
||||||
|
|
||||||
@@ -95,22 +319,9 @@ static void print_init_config(void)
|
|||||||
DT_PROP(DT_NODELABEL(charger), current_microamp) / 1000);
|
DT_PROP(DT_NODELABEL(charger), current_microamp) / 1000);
|
||||||
print_uart(buf);
|
print_uart(buf);
|
||||||
|
|
||||||
snprintk(buf, sizeof(buf), "Discharge limit: %d mA\r\n",
|
|
||||||
DT_PROP(DT_NODELABEL(charger), dischg_limit_microamp) / 1000);
|
|
||||||
print_uart(buf);
|
|
||||||
|
|
||||||
snprintk(buf, sizeof(buf), "VBUS limit: %d mA\r\n",
|
|
||||||
DT_PROP(DT_NODELABEL(charger), vbus_limit_microamp) / 1000);
|
|
||||||
print_uart(buf);
|
|
||||||
|
|
||||||
snprintk(buf, sizeof(buf), "Thermistor: %d ohms (0=disabled)\r\n",
|
|
||||||
DT_PROP(DT_NODELABEL(charger), thermistor_ohms));
|
|
||||||
print_uart(buf);
|
|
||||||
|
|
||||||
/* Runtime config from sensor - read after fetch */
|
|
||||||
if (sensor_sample_fetch(charger_dev) == 0) {
|
if (sensor_sample_fetch(charger_dev) == 0) {
|
||||||
sensor_channel_get(charger_dev, SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT, &val);
|
sensor_channel_get(charger_dev, SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT, &val);
|
||||||
snprintk(buf, sizeof(buf), "Actual charge current limit: %d mA\r\n",
|
snprintk(buf, sizeof(buf), "Actual charge current: %d mA\r\n",
|
||||||
val.val1 * 1000 + val.val2 / 1000);
|
val.val1 * 1000 + val.val2 / 1000);
|
||||||
print_uart(buf);
|
print_uart(buf);
|
||||||
}
|
}
|
||||||
@@ -140,7 +351,6 @@ static int fuel_gauge_init_custom(void)
|
|||||||
snprintk(buf, sizeof(buf), "nRF Fuel Gauge version: %s\r\n", nrf_fuel_gauge_version);
|
snprintk(buf, sizeof(buf), "nRF Fuel Gauge version: %s\r\n", nrf_fuel_gauge_version);
|
||||||
print_uart(buf);
|
print_uart(buf);
|
||||||
|
|
||||||
/* Read initial sensor values */
|
|
||||||
ret = read_sensors(¶meters.v0, ¶meters.i0, ¶meters.t0, &chg_status);
|
ret = read_sensors(¶meters.v0, ¶meters.i0, ¶meters.t0, &chg_status);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
snprintk(buf, sizeof(buf), "Error reading sensors: %d\r\n", ret);
|
snprintk(buf, sizeof(buf), "Error reading sensors: %d\r\n", ret);
|
||||||
@@ -153,7 +363,6 @@ static int fuel_gauge_init_custom(void)
|
|||||||
charge_status_str(chg_status));
|
charge_status_str(chg_status));
|
||||||
print_uart(buf);
|
print_uart(buf);
|
||||||
|
|
||||||
/* Initialize fuel gauge */
|
|
||||||
ret = nrf_fuel_gauge_init(¶meters, NULL);
|
ret = nrf_fuel_gauge_init(¶meters, NULL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
snprintk(buf, sizeof(buf), "Fuel gauge init error: %d\r\n", ret);
|
snprintk(buf, sizeof(buf), "Fuel gauge init error: %d\r\n", ret);
|
||||||
@@ -161,7 +370,6 @@ static int fuel_gauge_init_custom(void)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set charge current limit info */
|
|
||||||
struct sensor_value val;
|
struct sensor_value val;
|
||||||
sensor_channel_get(charger_dev, SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT, &val);
|
sensor_channel_get(charger_dev, SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT, &val);
|
||||||
max_charge_current = (float)val.val1 + ((float)val.val2 / 1000000);
|
max_charge_current = (float)val.val1 + ((float)val.val2 / 1000000);
|
||||||
@@ -173,10 +381,7 @@ static int fuel_gauge_init_custom(void)
|
|||||||
nrf_fuel_gauge_ext_state_update(NRF_FUEL_GAUGE_EXT_STATE_INFO_TERM_CURRENT,
|
nrf_fuel_gauge_ext_state_update(NRF_FUEL_GAUGE_EXT_STATE_INFO_TERM_CURRENT,
|
||||||
&(union nrf_fuel_gauge_ext_state_info_data){.charge_term_current = term_charge_current});
|
&(union nrf_fuel_gauge_ext_state_info_data){.charge_term_current = term_charge_current});
|
||||||
|
|
||||||
print_uart("Fuel gauge initialized OK\r\n");
|
print_uart("Fuel gauge: OK\r\n");
|
||||||
snprintk(buf, sizeof(buf), "NOTE: Using SDK example model, capacity=%.0f mAh\r\n",
|
|
||||||
(double)BATTERY_CAPACITY_MAH);
|
|
||||||
print_uart(buf);
|
|
||||||
|
|
||||||
ref_time = k_uptime_get();
|
ref_time = k_uptime_get();
|
||||||
return 0;
|
return 0;
|
||||||
@@ -192,7 +397,7 @@ int main(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
print_uart("\r\n*** Scout Battery Test - Fuel Gauge ***\r\n");
|
print_uart("\r\n*** Scout Battery Test ***\r\n");
|
||||||
|
|
||||||
charger_dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(charger));
|
charger_dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(charger));
|
||||||
if (charger_dev == NULL || !device_is_ready(charger_dev)) {
|
if (charger_dev == NULL || !device_is_ready(charger_dev)) {
|
||||||
@@ -201,6 +406,11 @@ int main(void)
|
|||||||
}
|
}
|
||||||
print_uart("Charger device: OK\r\n");
|
print_uart("Charger device: OK\r\n");
|
||||||
|
|
||||||
|
ret = power_mgmt_init();
|
||||||
|
if (ret < 0) {
|
||||||
|
print_uart("Power management init failed\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
print_init_config();
|
print_init_config();
|
||||||
|
|
||||||
ret = fuel_gauge_init_custom();
|
ret = fuel_gauge_init_custom();
|
||||||
@@ -208,53 +418,108 @@ int main(void)
|
|||||||
print_uart("Fuel gauge init failed, continuing without SoC\r\n");
|
print_uart("Fuel gauge init failed, continuing without SoC\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
print_uart("\r\nStarting monitoring (3s interval)...\r\n\r\n");
|
print_uart("\r\nStarting monitoring (3s interval)...\r\n");
|
||||||
|
print_uart("Press SHPHLD button to test power state transitions\r\n\r\n");
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
float voltage, current, temp;
|
float voltage, current, temp;
|
||||||
int32_t chg_status;
|
int32_t chg_status;
|
||||||
struct sensor_value dietemp;
|
|
||||||
|
/* Polling fallback: check SHPHLD event register if interrupt didn't fire */
|
||||||
|
uint8_t shphld_event = 0;
|
||||||
|
if (mfd_npm1300_reg_read(pmic_dev, 0x00, 0x12, &shphld_event) == 0) {
|
||||||
|
if (shphld_event & 0x01) { /* SHPHLD press event */
|
||||||
|
if (!shphld_pressed) {
|
||||||
|
printk("SHPHLD PRESS (polled)\n");
|
||||||
|
shphld_pressed = true;
|
||||||
|
}
|
||||||
|
/* Clear the press event */
|
||||||
|
mfd_npm1300_reg_write(pmic_dev, 0x00, 0x13, 0x01);
|
||||||
|
}
|
||||||
|
if (shphld_event & 0x02) { /* SHPHLD release event - just clear it */
|
||||||
|
mfd_npm1300_reg_write(pmic_dev, 0x00, 0x13, 0x02);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Polling fallback: check VBUS event register if interrupt didn't fire */
|
||||||
|
uint8_t vbus_event = 0;
|
||||||
|
if (mfd_npm1300_reg_read(pmic_dev, 0x00, 0x16, &vbus_event) == 0) {
|
||||||
|
if (vbus_event & 0x01) { /* VBUS detected event */
|
||||||
|
printk("VBUS DETECTED (polled)\n");
|
||||||
|
mfd_npm1300_reg_write(pmic_dev, 0x00, 0x17, 0x01);
|
||||||
|
if (!vbus_changed) {
|
||||||
|
vbus_changed = true;
|
||||||
|
vbus_detected = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (vbus_event & 0x02) { /* VBUS removed event */
|
||||||
|
printk("VBUS REMOVED (polled)\n");
|
||||||
|
mfd_npm1300_reg_write(pmic_dev, 0x00, 0x17, 0x02);
|
||||||
|
if (!vbus_changed) {
|
||||||
|
vbus_changed = true;
|
||||||
|
vbus_detected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Also check actual VBUS state and correct app_state if mismatched */
|
||||||
|
bool actual_vbus = is_vbus_present();
|
||||||
|
if (actual_vbus && app_state == POWER_STATE_ON_BATTERY) {
|
||||||
|
print_uart(">>> State correction: VBUS present but ON_BATTERY -> CHARGING_ON\r\n");
|
||||||
|
app_state = POWER_STATE_CHARGING_ON;
|
||||||
|
} else if (!actual_vbus && app_state == POWER_STATE_CHARGING_ON) {
|
||||||
|
print_uart(">>> State correction: VBUS absent but CHARGING_ON -> ON_BATTERY\r\n");
|
||||||
|
app_state = POWER_STATE_ON_BATTERY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle VBUS change detected via polling */
|
||||||
|
if (vbus_changed) {
|
||||||
|
vbus_changed = false;
|
||||||
|
handle_vbus_change(vbus_detected);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle button press detected via polling */
|
||||||
|
if (shphld_pressed) {
|
||||||
|
shphld_pressed = false;
|
||||||
|
handle_power_button();
|
||||||
|
}
|
||||||
|
|
||||||
tick++;
|
tick++;
|
||||||
snprintk(buf, sizeof(buf), "[%d] ", tick);
|
|
||||||
print_uart(buf);
|
|
||||||
|
|
||||||
ret = read_sensors(&voltage, ¤t, &temp, &chg_status);
|
ret = read_sensors(&voltage, ¤t, &temp, &chg_status);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
snprintk(buf, sizeof(buf), "sensor err=%d\r\n", ret);
|
snprintk(buf, sizeof(buf), "[%d] sensor err=%d\r\n", tick, ret);
|
||||||
print_uart(buf);
|
print_uart(buf);
|
||||||
} else {
|
} else {
|
||||||
/* Get die temperature */
|
int soc_int = 0, soc_frac = 0;
|
||||||
sensor_channel_get(charger_dev, SENSOR_CHAN_DIE_TEMP, &dietemp);
|
|
||||||
|
|
||||||
/* Update fuel gauge */
|
|
||||||
float delta = (float)k_uptime_delta(&ref_time) / 1000.0f;
|
float delta = (float)k_uptime_delta(&ref_time) / 1000.0f;
|
||||||
if (delta < 0.1f) delta = 3.0f; /* Ensure minimum delta on first call */
|
if (delta < 0.1f) delta = 3.0f;
|
||||||
float soc = nrf_fuel_gauge_process(voltage, current, temp, delta, NULL);
|
float soc = nrf_fuel_gauge_process(voltage, current, temp, delta, NULL);
|
||||||
float tte = nrf_fuel_gauge_tte_get();
|
soc_int = (int)soc;
|
||||||
|
soc_frac = (int)((soc - soc_int) * 10) % 10;
|
||||||
/* Convert floats to integers for printing (avoid float printf issues) */
|
|
||||||
int soc_int = (int)soc;
|
|
||||||
int soc_frac = (int)((soc - soc_int) * 10) % 10;
|
|
||||||
if (soc_frac < 0) soc_frac = -soc_frac;
|
if (soc_frac < 0) soc_frac = -soc_frac;
|
||||||
|
|
||||||
int v_int = (int)voltage;
|
int v_int = (int)voltage;
|
||||||
int v_frac = (int)((voltage - v_int) * 1000);
|
int v_frac = (int)((voltage - v_int) * 1000);
|
||||||
int i_ma = (int)(current * 1000);
|
int i_ma = (int)(current * 1000);
|
||||||
int t_int = (int)temp;
|
int t_int = (int)temp;
|
||||||
|
|
||||||
snprintk(buf, sizeof(buf),
|
const char *state_str = "?";
|
||||||
"SoC=%d.%d%% V=%d.%03dV I=%dmA T=%dC die=%dC %s",
|
switch (app_state) {
|
||||||
soc_int, soc_frac, v_int, v_frac, i_ma, t_int,
|
case POWER_STATE_ON_BATTERY: state_str = "ON_BAT"; break;
|
||||||
dietemp.val1, charge_status_str(chg_status));
|
case POWER_STATE_CHARGING_ON: state_str = "CHG_ON"; break;
|
||||||
print_uart(buf);
|
case POWER_STATE_CHARGING_ONLY: state_str = "CHG_ONLY"; break;
|
||||||
|
|
||||||
if (tte > 0 && tte < 1000000) {
|
|
||||||
snprintk(buf, sizeof(buf), " TTE=%ds", (int)tte);
|
|
||||||
print_uart(buf);
|
|
||||||
}
|
}
|
||||||
print_uart("\r\n");
|
|
||||||
|
snprintk(buf, sizeof(buf),
|
||||||
|
"[%d] %d.%d%% %d.%03dV %dmA %dC %s [%s]\r\n",
|
||||||
|
tick, soc_int, soc_frac, v_int, v_frac, i_ma, t_int,
|
||||||
|
charge_status_str(chg_status), state_str);
|
||||||
|
print_uart(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Normal 3 second polling interval
|
||||||
|
* Note: CHARGING_ONLY state powers down the device, so we won't reach here in that state
|
||||||
|
*/
|
||||||
k_sleep(K_SECONDS(3));
|
k_sleep(K_SECONDS(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user