Sync
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
#include <zephyr/init.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <nrfx_saadc.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
@@ -23,9 +24,64 @@ static const struct gpio_dt_spec batt_chg_status = GPIO_DT_SPEC_GET(BATT_CHG_STA
|
||||
|
||||
static bool batt_mgmt_ready;
|
||||
static int64_t batt_mgmt_last_chg_change_ms;
|
||||
static int64_t batt_mgmt_last_offset_calib_ms;
|
||||
static int32_t batt_mgmt_last_vddh_mv;
|
||||
static bool batt_mgmt_chg_interrupt_enabled;
|
||||
static K_THREAD_STACK_DEFINE(batt_monitor_stack, CONFIG_BATT_MGMT_MONITOR_THREAD_STACK_SIZE);
|
||||
static struct k_thread batt_monitor_thread_data;
|
||||
static struct k_sem batt_mgmt_saadc_calib_sem;
|
||||
static int batt_mgmt_saadc_calib_rc;
|
||||
|
||||
static void batt_mgmt_saadc_calib_handler(nrfx_saadc_evt_t const *p_event)
|
||||
{
|
||||
if ((p_event == NULL) || (p_event->type != NRFX_SAADC_EVT_CALIBRATEDONE))
|
||||
{
|
||||
batt_mgmt_saadc_calib_rc = -EIO;
|
||||
}
|
||||
else
|
||||
{
|
||||
batt_mgmt_saadc_calib_rc = 0;
|
||||
}
|
||||
|
||||
k_sem_give(&batt_mgmt_saadc_calib_sem);
|
||||
}
|
||||
|
||||
static int batt_mgmt_calibrate_offset_if_needed(bool force)
|
||||
{
|
||||
int rc;
|
||||
int64_t now_ms = k_uptime_get();
|
||||
int64_t calib_interval_ms = (int64_t)CONFIG_BATT_MGMT_STANDBY_MEASURE_INTERVAL_MIN * 60 * 1000;
|
||||
|
||||
if (!force && (now_ms - batt_mgmt_last_offset_calib_ms < calib_interval_ms))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (k_sem_take(&batt_mgmt_saadc_calib_sem, K_NO_WAIT) == 0)
|
||||
{
|
||||
}
|
||||
|
||||
batt_mgmt_saadc_calib_rc = -EIO;
|
||||
rc = nrfx_saadc_offset_calibrate(batt_mgmt_saadc_calib_handler);
|
||||
if (rc < 0)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = k_sem_take(&batt_mgmt_saadc_calib_sem, K_MSEC(100));
|
||||
if (rc < 0)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (batt_mgmt_saadc_calib_rc < 0)
|
||||
{
|
||||
return batt_mgmt_saadc_calib_rc;
|
||||
}
|
||||
|
||||
batt_mgmt_last_offset_calib_ms = k_uptime_get();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int batt_mgmt_to_adc_oversampling(uint8_t oversampling, uint8_t *adc_oversampling)
|
||||
{
|
||||
@@ -68,6 +124,12 @@ int batt_mgmt_measure_vddh_mv(uint8_t oversampling, int32_t *vddh_mv)
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
rc = batt_mgmt_calibrate_offset_if_needed(false);
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_WRN("ADC offset calibration failed before measurement: %d", rc);
|
||||
}
|
||||
|
||||
rc = batt_mgmt_to_adc_oversampling(oversampling, &adc_oversampling);
|
||||
if (rc < 0)
|
||||
{
|
||||
@@ -96,19 +158,194 @@ int batt_mgmt_measure_vddh_mv(uint8_t oversampling, int32_t *vddh_mv)
|
||||
}
|
||||
|
||||
*vddh_mv = input_mv * BATT_VDDH_DIVIDER_FACTOR;
|
||||
batt_mgmt_last_vddh_mv = *vddh_mv;
|
||||
|
||||
LOG_DBG("Battery VDDH: %d mV (raw=%d, os=%ux)", *vddh_mv, raw_sample, oversampling);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int batt_mgmt_linear_percent(int32_t mv, int32_t lo_mv, int32_t hi_mv,
|
||||
uint8_t lo_pct, uint8_t hi_pct, uint8_t *out_pct)
|
||||
{
|
||||
int32_t num;
|
||||
int32_t den;
|
||||
int32_t pct;
|
||||
|
||||
if (out_pct == NULL)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (hi_mv <= lo_mv)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (mv <= lo_mv)
|
||||
{
|
||||
*out_pct = lo_pct;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mv >= hi_mv)
|
||||
{
|
||||
*out_pct = hi_pct;
|
||||
return 0;
|
||||
}
|
||||
|
||||
num = (mv - lo_mv) * (int32_t)(hi_pct - lo_pct);
|
||||
den = hi_mv - lo_mv;
|
||||
pct = (int32_t)lo_pct + (num / den);
|
||||
|
||||
if (pct < 0)
|
||||
{
|
||||
pct = 0;
|
||||
}
|
||||
else if (pct > 100)
|
||||
{
|
||||
pct = 100;
|
||||
}
|
||||
|
||||
*out_pct = (uint8_t)pct;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int batt_mgmt_get_display_voltage_mv(int32_t *vddh_mv)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (vddh_mv == NULL)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!batt_mgmt_ready)
|
||||
{
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (batt_mgmt_last_vddh_mv <= 0)
|
||||
{
|
||||
rc = batt_mgmt_measure_vddh_mv(BATT_MGMT_OVERSAMPLING_16X, &batt_mgmt_last_vddh_mv);
|
||||
if (rc < 0)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
*vddh_mv = batt_mgmt_last_vddh_mv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int batt_mgmt_get_battery_level(uint8_t *level)
|
||||
{
|
||||
int32_t mv;
|
||||
int rc;
|
||||
|
||||
if (level == NULL)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = batt_mgmt_get_display_voltage_mv(&mv);
|
||||
if (rc < 0)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (mv >= CONFIG_BATT_MGMT_FULL_THRESHOLD)
|
||||
{
|
||||
*level = 4U;
|
||||
}
|
||||
else if (mv >= CONFIG_BATT_MGMT_80P_THRESHOLD)
|
||||
{
|
||||
*level = 3U;
|
||||
}
|
||||
else if (mv >= CONFIG_BATT_MGMT_50P_THRESHOLD)
|
||||
{
|
||||
*level = 2U;
|
||||
}
|
||||
else if (mv >= CONFIG_BATT_MGMT_20P_THRESHOLD)
|
||||
{
|
||||
*level = 1U;
|
||||
}
|
||||
else
|
||||
{
|
||||
*level = 0U;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int batt_mgmt_get_battery_percent(uint8_t *percent)
|
||||
{
|
||||
int32_t mv;
|
||||
int rc;
|
||||
|
||||
if (percent == NULL)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = batt_mgmt_get_display_voltage_mv(&mv);
|
||||
if (rc < 0)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (mv <= CONFIG_BATT_MGMT_EMPTY_THRESHOLD)
|
||||
{
|
||||
*percent = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mv >= CONFIG_BATT_MGMT_FULL_THRESHOLD)
|
||||
{
|
||||
*percent = 100;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mv < CONFIG_BATT_MGMT_20P_THRESHOLD)
|
||||
{
|
||||
return batt_mgmt_linear_percent(mv,
|
||||
CONFIG_BATT_MGMT_EMPTY_THRESHOLD,
|
||||
CONFIG_BATT_MGMT_20P_THRESHOLD,
|
||||
0, 20, percent);
|
||||
}
|
||||
|
||||
if (mv < CONFIG_BATT_MGMT_50P_THRESHOLD)
|
||||
{
|
||||
return batt_mgmt_linear_percent(mv,
|
||||
CONFIG_BATT_MGMT_20P_THRESHOLD,
|
||||
CONFIG_BATT_MGMT_50P_THRESHOLD,
|
||||
20, 50, percent);
|
||||
}
|
||||
|
||||
if (mv < CONFIG_BATT_MGMT_80P_THRESHOLD)
|
||||
{
|
||||
return batt_mgmt_linear_percent(mv,
|
||||
CONFIG_BATT_MGMT_50P_THRESHOLD,
|
||||
CONFIG_BATT_MGMT_80P_THRESHOLD,
|
||||
50, 80, percent);
|
||||
}
|
||||
|
||||
return batt_mgmt_linear_percent(mv,
|
||||
CONFIG_BATT_MGMT_80P_THRESHOLD,
|
||||
CONFIG_BATT_MGMT_FULL_THRESHOLD,
|
||||
80, 100, percent);
|
||||
}
|
||||
|
||||
static void batt_mgmt_chg_interrupt_handler(const struct device *dev,
|
||||
struct gpio_callback *cb,
|
||||
uint32_t pins)
|
||||
{
|
||||
int64_t now_ms = k_uptime_get();
|
||||
int64_t delta_ms = now_ms - batt_mgmt_last_chg_change_ms;
|
||||
ARG_UNUSED(dev);
|
||||
ARG_UNUSED(cb);
|
||||
ARG_UNUSED(pins);
|
||||
|
||||
#ifdef CONFIG_BATT_MGMT_BLINK_INTERVAL_LOGGING
|
||||
int64_t delta_ms = now_ms - batt_mgmt_last_chg_change_ms;
|
||||
LOG_DBG("CHG interrupt: delta=%lld ms", delta_ms);
|
||||
#endif
|
||||
|
||||
@@ -227,6 +464,37 @@ batt_mgmt_state_t batt_mgmt_get_battery_state(void)
|
||||
return BATT_STATE_DISCHARGING;
|
||||
}
|
||||
|
||||
int batt_mgmt_get_info(batt_mgmt_info_t *info)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (info == NULL)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = batt_mgmt_get_display_voltage_mv(&info->voltage_mv);
|
||||
if (rc < 0)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = batt_mgmt_get_battery_level(&info->level);
|
||||
if (rc < 0)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = batt_mgmt_get_battery_percent(&info->percent);
|
||||
if (rc < 0)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
info->state = batt_mgmt_get_battery_state();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void batt_mgmt_monitor_thread(void *unused1, void *unused2, void *unused3)
|
||||
{
|
||||
(void)unused1;
|
||||
@@ -288,8 +556,17 @@ static int batt_mgmt_init(void)
|
||||
return rc;
|
||||
}
|
||||
|
||||
k_sem_init(&batt_mgmt_saadc_calib_sem, 0, 1);
|
||||
batt_mgmt_last_offset_calib_ms = 0;
|
||||
|
||||
batt_mgmt_ready = true;
|
||||
|
||||
rc = batt_mgmt_calibrate_offset_if_needed(true);
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_WRN("Initial ADC offset calibration failed: %d", rc);
|
||||
}
|
||||
|
||||
rc = batt_mgmt_measure_vddh_mv(BATT_MGMT_OVERSAMPLING_16X, &boot_vddh_mv);
|
||||
if (rc < 0)
|
||||
{
|
||||
@@ -297,6 +574,7 @@ static int batt_mgmt_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
batt_mgmt_last_vddh_mv = boot_vddh_mv;
|
||||
LOG_DBG("Initial battery VDDH: %d mV", boot_vddh_mv);
|
||||
|
||||
k_thread_create(&batt_monitor_thread_data,
|
||||
|
||||
Reference in New Issue
Block a user