feat(app): 使用传感器驱动重构电池和模式切换模块
- 将电池模块从ADC直接采样改为使用sensor子系统,通过battery_sense传感器获取电压 - 将模式切换模块从ADC采样改为使用mode_sense传感器获取模式电压 - 移除GPIO控制的电池使能脚,改用传感器的PM管理机制 - 更新DTS配置,移除大量设备状态设置,添加boot-mode保留内存支持 perf(pm): 调整分区大小以支持单应用引导模式 - 将mcuboot分区从0xc000扩大到0x100,为单应用模式提供更大空间 - 相应调整app分区地址布局,确保内存分配合理 - 移除secondary镜像相关配置,优化flash使用 refactor(boot): 添加MCUBOOT单应用模式配置 - 在sysbuild中启用单应用模式支持 - 为引导加载程序添加保留内存和启动模式配置 - 配置CDC ACM串口用于引导模式通信
This commit is contained in:
71
app.overlay
71
app.overlay
@@ -2,16 +2,7 @@
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
zephyr,display = &st7789v3;
|
||||
};
|
||||
|
||||
aliases {
|
||||
backlight = &backlight;
|
||||
};
|
||||
|
||||
zephyr,user {
|
||||
vbat-en-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
|
||||
io-channels = <&adc 5>, <&adc 7>;
|
||||
zephyr,boot-mode = &boot_mode0;
|
||||
};
|
||||
|
||||
hid_dev_0: hid_dev_0 {
|
||||
@@ -45,64 +36,12 @@
|
||||
};
|
||||
};
|
||||
|
||||
&gpio0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpio1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpiote {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&led_0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&led_1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
/* 使能 SAADC,mode_switch_module 使用 channel 7 采样模式拨码电压。 */
|
||||
&adc {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2c1 {
|
||||
&gpregret1 {
|
||||
status = "okay";
|
||||
|
||||
ip5305: pmic@75 {
|
||||
boot_mode0: boot_mode@0 {
|
||||
compatible = "zephyr,retention";
|
||||
status = "okay";
|
||||
keepalive-interval-ms = <10000>;
|
||||
reg = <0x0 0x1>;
|
||||
};
|
||||
};
|
||||
|
||||
&usbd {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
qdec: &qdec {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&spi3 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&mipi_dbi {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&st7789v3 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pwm_leds {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pwm0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -1,37 +1,31 @@
|
||||
mcuboot:
|
||||
address: 0x0
|
||||
end_address: 0xc000
|
||||
end_address: 0x10000
|
||||
region: flash_primary
|
||||
size: 0xc000
|
||||
size: 0x10000
|
||||
|
||||
mcuboot_pad:
|
||||
address: 0xc000
|
||||
end_address: 0xc200
|
||||
address: 0x10000
|
||||
end_address: 0x10200
|
||||
region: flash_primary
|
||||
size: 0x200
|
||||
|
||||
app:
|
||||
address: 0xc200
|
||||
end_address: 0x82000
|
||||
address: 0x10200
|
||||
end_address: 0xf8000
|
||||
region: flash_primary
|
||||
size: 0x75e00
|
||||
size: 0xe7e00
|
||||
|
||||
mcuboot_primary:
|
||||
address: 0xc000
|
||||
end_address: 0x82000
|
||||
address: 0x10000
|
||||
end_address: 0xf8000
|
||||
orig_span: &id001
|
||||
- mcuboot_pad
|
||||
- app
|
||||
region: flash_primary
|
||||
size: 0x76000
|
||||
size: 0xe8000
|
||||
span: *id001
|
||||
|
||||
mcuboot_secondary:
|
||||
address: 0x82000
|
||||
end_address: 0xf8000
|
||||
region: flash_primary
|
||||
size: 0x76000
|
||||
|
||||
settings_storage:
|
||||
address: 0xf8000
|
||||
end_address: 0x100000
|
||||
|
||||
4
prj.conf
4
prj.conf
@@ -16,6 +16,10 @@ CONFIG_MCUMGR_GRP_OS=n
|
||||
CONFIG_IMG_MANAGER=n
|
||||
CONFIG_STREAM_FLASH=n
|
||||
|
||||
CONFIG_RETAINED_MEM=y
|
||||
CONFIG_RETENTION=y
|
||||
CONFIG_RETENTION_BOOT_MODE=y
|
||||
|
||||
CONFIG_BT=y
|
||||
CONFIG_BT_PERIPHERAL=y
|
||||
CONFIG_BT_SMP=y
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/adc.h>
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/drivers/power/ip5305.h>
|
||||
#include <zephyr/drivers/sensor.h>
|
||||
#include <zephyr/pm/device.h>
|
||||
#include <zephyr/sys/atomic.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
@@ -20,11 +20,8 @@
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(MODULE);
|
||||
|
||||
#define BATTERY_USER_NODE DT_PATH(zephyr_user)
|
||||
#define BATTERY_ADC_IO_CH_IDX 1
|
||||
#define BATTERY_SENSE_NODE DT_NODELABEL(battery_sense)
|
||||
#define BATTERY_SAMPLE_INTERVAL_MS 1000
|
||||
#define BATTERY_VDIV_NUM 2
|
||||
#define BATTERY_VDIV_DEN 1
|
||||
#define BATTERY_MV_WINDOW_SIZE 10
|
||||
|
||||
/*
|
||||
@@ -35,18 +32,26 @@ LOG_MODULE_REGISTER(MODULE);
|
||||
#define BATTERY_EMPTY_MV 3300
|
||||
#define BATTERY_FULL_MV 4100
|
||||
|
||||
static const struct adc_dt_spec battery_adc =
|
||||
ADC_DT_SPEC_GET_BY_IDX(BATTERY_USER_NODE, BATTERY_ADC_IO_CH_IDX);
|
||||
static const struct device *const ip5305_dev = DEVICE_DT_GET(DT_NODELABEL(ip5305));
|
||||
static const struct device *const battery_sensor_dev = DEVICE_DT_GET(BATTERY_SENSE_NODE);
|
||||
|
||||
/*
|
||||
* 电池采样使能脚从 zephyr,user/vbat-en-gpios 读取,避免把引脚号硬编码在 C 里。
|
||||
* 后续板级改脚位只需改 DTS,不需要改固件代码。
|
||||
* 板级电源采样结果:
|
||||
* - 由 board provider 负责给出“原始但可用”的充电状态与电压值;
|
||||
* - 本模块基于这些采样结果做滤波、SOC 估算和事件发布。
|
||||
*/
|
||||
static const struct gpio_dt_spec battery_en_gpio =
|
||||
GPIO_DT_SPEC_GET(BATTERY_USER_NODE, vbat_en_gpios);
|
||||
|
||||
static const struct device *const ip5305_dev = DEVICE_DT_GET(DT_NODELABEL(ip5305));
|
||||
struct board_power_sample
|
||||
{
|
||||
int32_t voltage_mv;
|
||||
bool charging;
|
||||
bool full;
|
||||
};
|
||||
|
||||
/*
|
||||
* 对外上报状态:
|
||||
* - 保持现有 battery_status_event 语义不变;
|
||||
* - 只承载业务层需要的 charging/full/soc 三元组。
|
||||
*/
|
||||
struct battery_status
|
||||
{
|
||||
bool charging;
|
||||
@@ -62,10 +67,16 @@ struct battery_filter_state
|
||||
size_t index;
|
||||
};
|
||||
|
||||
/*
|
||||
* 模块上下文:
|
||||
* - sample_work 周期性拉取 board power sample;
|
||||
* - filter 负责平滑电池电压;
|
||||
* - last_status 用于抑制重复事件;
|
||||
* - pm_restrict_level 跟踪当前对 power manager 的限制等级。
|
||||
*/
|
||||
struct battery_ctx
|
||||
{
|
||||
struct k_work_delayable sample_work;
|
||||
int16_t adc_sample_buffer;
|
||||
atomic_t active;
|
||||
struct battery_status last_status;
|
||||
bool has_last_status;
|
||||
@@ -77,17 +88,14 @@ static struct battery_ctx battery = {
|
||||
.pm_restrict_level = POWER_MANAGER_LEVEL_MAX,
|
||||
};
|
||||
|
||||
static void battery_module_resume(void);
|
||||
|
||||
/* 线性 SOC 估算:把平滑后的电池电压映射到 0~100%。 */
|
||||
static uint8_t soc_from_mv(int32_t mv)
|
||||
{
|
||||
if (mv <= BATTERY_EMPTY_MV)
|
||||
{
|
||||
if (mv <= BATTERY_EMPTY_MV) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mv >= BATTERY_FULL_MV)
|
||||
{
|
||||
if (mv >= BATTERY_FULL_MV) {
|
||||
return 100;
|
||||
}
|
||||
|
||||
@@ -95,109 +103,126 @@ static uint8_t soc_from_mv(int32_t mv)
|
||||
return (uint8_t)CLAMP(soc, 0, 100);
|
||||
}
|
||||
|
||||
static int adc_sample_once_mv(int32_t *mv)
|
||||
/* 初始化/恢复时清空滤波器,避免旧样本影响新一轮估算。 */
|
||||
static void battery_filter_reset(void)
|
||||
{
|
||||
struct adc_sequence sequence = {0};
|
||||
int err = adc_sequence_init_dt(&battery_adc, &sequence);
|
||||
if (err)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
sequence.buffer = &battery.adc_sample_buffer;
|
||||
sequence.buffer_size = sizeof(battery.adc_sample_buffer);
|
||||
|
||||
err = adc_read_dt(&battery_adc, &sequence);
|
||||
if (err)
|
||||
{
|
||||
LOG_WRN("adc_read_dt failed (err=%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
*mv = battery.adc_sample_buffer;
|
||||
err = adc_raw_to_millivolts_dt(&battery_adc, mv);
|
||||
if (err)
|
||||
{
|
||||
LOG_WRN("adc_raw_to_millivolts_dt failed (err=%d raw=%d)",
|
||||
err, battery.adc_sample_buffer);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int read_battery_mv(int32_t *mv)
|
||||
{
|
||||
int err;
|
||||
int32_t sensed_mv;
|
||||
|
||||
err = adc_sample_once_mv(&sensed_mv);
|
||||
if (err)
|
||||
{
|
||||
return err;
|
||||
battery.filter.sum = 0;
|
||||
battery.filter.count = 0;
|
||||
battery.filter.index = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 板级电池检测存在分压,ADC 读到的是分压后电压。
|
||||
* 这里按分压比还原电池端真实电压,供 SOC 估算与事件上报使用。
|
||||
* 将最新电压样本写入固定窗口平均滤波器。
|
||||
* 返回值始终是“窗口平均后的电池电压”,供上层做 SOC 估算。
|
||||
*/
|
||||
int32_t battery_mv = (sensed_mv * BATTERY_VDIV_NUM) / BATTERY_VDIV_DEN;
|
||||
|
||||
/*
|
||||
* 使用固定窗口平均抑制采样抖动。
|
||||
* 窗口未填满前按当前样本数求平均,填满后使用环形缓冲滚动更新。
|
||||
*/
|
||||
if (battery.filter.count < BATTERY_MV_WINDOW_SIZE)
|
||||
static int32_t battery_filter_apply(int32_t voltage_mv)
|
||||
{
|
||||
battery.filter.window[battery.filter.index] = battery_mv;
|
||||
battery.filter.sum += battery_mv;
|
||||
if (battery.filter.count < BATTERY_MV_WINDOW_SIZE) {
|
||||
battery.filter.window[battery.filter.index] = voltage_mv;
|
||||
battery.filter.sum += voltage_mv;
|
||||
battery.filter.count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
battery.filter.sum -= battery.filter.window[battery.filter.index];
|
||||
battery.filter.window[battery.filter.index] = battery_mv;
|
||||
battery.filter.sum += battery_mv;
|
||||
battery.filter.window[battery.filter.index] = voltage_mv;
|
||||
battery.filter.sum += voltage_mv;
|
||||
}
|
||||
|
||||
battery.filter.index = (battery.filter.index + 1U) % BATTERY_MV_WINDOW_SIZE;
|
||||
*mv = (int32_t)(battery.filter.sum / (int64_t)battery.filter.count);
|
||||
return (int32_t)(battery.filter.sum / (int64_t)battery.filter.count);
|
||||
}
|
||||
|
||||
/*
|
||||
* 控制 board-provided battery_sense sensor 的供电状态。
|
||||
* 这里不直接操纵 GPIO,而是走 sensor 的 PM action,让 power-gpios
|
||||
* 与 ADC runtime PM 都由 voltage-divider 驱动统一管理。
|
||||
*/
|
||||
static int board_power_monitor_set_voltage_sensor_enabled(bool enable)
|
||||
{
|
||||
return pm_device_action_run(battery_sensor_dev,
|
||||
enable ? PM_DEVICE_ACTION_RESUME :
|
||||
PM_DEVICE_ACTION_SUSPEND);
|
||||
}
|
||||
|
||||
/* 从 battery_sense 读取一次当前电池电压(单位 mV)。 */
|
||||
static int board_power_monitor_read_voltage_mv(int32_t *voltage_mv)
|
||||
{
|
||||
struct sensor_value value;
|
||||
int err = sensor_sample_fetch(battery_sensor_dev);
|
||||
|
||||
if (err) {
|
||||
LOG_WRN("sensor_sample_fetch(battery) failed (err=%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = sensor_channel_get(battery_sensor_dev, SENSOR_CHAN_VOLTAGE, &value);
|
||||
if (err) {
|
||||
LOG_WRN("sensor_channel_get(battery) failed (err=%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
*voltage_mv = (int32_t)sensor_value_to_milli(&value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 从 IP5305 读取一次充电态与满电态。 */
|
||||
static int board_power_monitor_read_charge_state(bool *charging, bool *full)
|
||||
{
|
||||
int err = ip5305_is_charging(ip5305_dev, charging);
|
||||
|
||||
if (err) {
|
||||
LOG_WRN("ip5305_is_charging failed (err=%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ip5305_is_charge_full(ip5305_dev, full);
|
||||
if (err) {
|
||||
LOG_WRN("ip5305_is_charge_full failed (err=%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_battery_status(struct battery_status *status)
|
||||
/*
|
||||
* 聚合一次完整的 board power sample:
|
||||
* 1) 先读 PMIC 状态;
|
||||
* 2) 再读 battery_sense 电压;
|
||||
* 3) 最后对电压做窗口平均,输出稳定值。
|
||||
*/
|
||||
static int board_power_monitor_collect_sample(struct board_power_sample *sample)
|
||||
{
|
||||
int err;
|
||||
int32_t mv;
|
||||
int32_t voltage_mv;
|
||||
int err = board_power_monitor_read_charge_state(&sample->charging, &sample->full);
|
||||
|
||||
err = ip5305_is_charging(ip5305_dev, &status->charging);
|
||||
if (err)
|
||||
{
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ip5305_is_charge_full(ip5305_dev, &status->full);
|
||||
if (err)
|
||||
{
|
||||
err = board_power_monitor_read_voltage_mv(&voltage_mv);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = read_battery_mv(&mv);
|
||||
if (err)
|
||||
{
|
||||
LOG_WRN("read_battery_mv failed (err=%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
status->soc = soc_from_mv(mv);
|
||||
sample->voltage_mv = battery_filter_apply(voltage_mv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 将 board sample 映射成对外 battery status。 */
|
||||
static void battery_status_from_sample(const struct board_power_sample *sample,
|
||||
struct battery_status *status)
|
||||
{
|
||||
status->charging = sample->charging;
|
||||
status->full = sample->full;
|
||||
status->soc = soc_from_mv(sample->voltage_mv);
|
||||
}
|
||||
|
||||
/* 统一封装 battery_status_event 发布,隔离事件总线细节。 */
|
||||
static void publish_battery_status_event(const struct battery_status *status)
|
||||
{
|
||||
battery_status_event_submit(status->charging, status->full, status->soc);
|
||||
}
|
||||
|
||||
/* 判断本轮状态是否值得上报,避免重复事件淹没总线。 */
|
||||
static bool battery_status_changed(const struct battery_status *lhs,
|
||||
const struct battery_status *rhs)
|
||||
{
|
||||
@@ -223,99 +248,79 @@ static void update_power_restrict_by_charging(bool charging)
|
||||
power_manager_restrict(MODULE_IDX(MODULE), target);
|
||||
}
|
||||
|
||||
/*
|
||||
* 启停采样:
|
||||
* - enable=true 时恢复 battery_sense,等待前端稳定后开始周期采样;
|
||||
* - enable=false 时停止 work 并挂起 battery_sense,避免持续耗电。
|
||||
*/
|
||||
static void battery_sampling_set_enabled(bool enable)
|
||||
{
|
||||
atomic_set(&battery.active, enable);
|
||||
(void)gpio_pin_set_dt(&battery_en_gpio, enable ? GPIO_OUTPUT_ACTIVE : GPIO_OUTPUT_INACTIVE);
|
||||
int err = board_power_monitor_set_voltage_sensor_enabled(enable);
|
||||
|
||||
if (enable)
|
||||
{
|
||||
// 延迟2s开始采样等待电池电压稳定
|
||||
k_work_reschedule(&battery.sample_work, K_MSEC(2000));
|
||||
if (err) {
|
||||
LOG_WRN("board_power_monitor_set_voltage_sensor_enabled(%d) failed (err=%d)",
|
||||
enable, err);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (enable) {
|
||||
/* 延迟开始采样,等待板上采样前端和分压网络稳定。 */
|
||||
k_work_reschedule(&battery.sample_work, K_MSEC(2000));
|
||||
} else {
|
||||
(void)k_work_cancel_delayable(&battery.sample_work);
|
||||
}
|
||||
}
|
||||
|
||||
/* 周期性读取 board power sample,并在需要时上报业务状态。 */
|
||||
static void battery_sample_fn(struct k_work *work)
|
||||
{
|
||||
ARG_UNUSED(work);
|
||||
|
||||
if (!atomic_get(&battery.active))
|
||||
{
|
||||
if (!atomic_get(&battery.active)) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct board_power_sample sample;
|
||||
struct battery_status status;
|
||||
int err = board_power_monitor_collect_sample(&sample);
|
||||
|
||||
struct battery_status sampled;
|
||||
int err = read_battery_status(&sampled);
|
||||
if (err)
|
||||
{
|
||||
if (err) {
|
||||
goto out_reschedule;
|
||||
}
|
||||
|
||||
update_power_restrict_by_charging(sampled.charging);
|
||||
battery_status_from_sample(&sample, &status);
|
||||
update_power_restrict_by_charging(status.charging);
|
||||
|
||||
/*
|
||||
* 仅在状态发生变化时上报,避免重复事件淹没总线。
|
||||
* 变化条件:充电标志、满电标志、SOC 任意一个变化。
|
||||
*/
|
||||
if (!battery.has_last_status ||
|
||||
battery_status_changed(&sampled, &battery.last_status))
|
||||
{
|
||||
battery.last_status = sampled;
|
||||
battery_status_changed(&status, &battery.last_status)) {
|
||||
battery.last_status = status;
|
||||
battery.has_last_status = true;
|
||||
publish_battery_status_event(&sampled);
|
||||
publish_battery_status_event(&status);
|
||||
}
|
||||
|
||||
out_reschedule:
|
||||
k_work_reschedule(&battery.sample_work, K_MSEC(BATTERY_SAMPLE_INTERVAL_MS));
|
||||
}
|
||||
|
||||
/* 初始化 board power monitor consumer,并拉起首轮采样。 */
|
||||
static int battery_module_init(void)
|
||||
{
|
||||
if (!device_is_ready(ip5305_dev))
|
||||
{
|
||||
if (!device_is_ready(ip5305_dev)) {
|
||||
LOG_ERR("IP5305 device not ready");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!adc_is_ready_dt(&battery_adc))
|
||||
{
|
||||
LOG_ERR("Battery ADC device not ready");
|
||||
if (!device_is_ready(battery_sensor_dev)) {
|
||||
LOG_ERR("Battery sense device not ready");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!device_is_ready(battery_en_gpio.port))
|
||||
{
|
||||
LOG_ERR("Battery EN GPIO device not ready");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int err = gpio_pin_configure_dt(&battery_en_gpio, GPIO_OUTPUT_INACTIVE);
|
||||
if (err)
|
||||
{
|
||||
LOG_ERR("Battery EN GPIO configure failed (err=%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = adc_channel_setup_dt(&battery_adc);
|
||||
if (err)
|
||||
{
|
||||
LOG_ERR("Battery ADC channel setup failed (err=%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* 默认非充电态允许进入 SUSPENDED,但禁止进入 OFF。 */
|
||||
update_power_restrict_by_charging(false);
|
||||
|
||||
k_work_init_delayable(&battery.sample_work, battery_sample_fn);
|
||||
battery.has_last_status = false;
|
||||
battery.filter.sum = 0;
|
||||
battery.filter.count = 0;
|
||||
battery.filter.index = 0;
|
||||
battery_filter_reset();
|
||||
atomic_set(&battery.active, false);
|
||||
|
||||
battery_sampling_set_enabled(true);
|
||||
@@ -323,10 +328,10 @@ static int battery_module_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 响应系统挂起:停止采样,并把本模块切到 STANDBY。 */
|
||||
static void battery_module_suspend(void)
|
||||
{
|
||||
if (!atomic_get(&battery.active))
|
||||
{
|
||||
if (!atomic_get(&battery.active)) {
|
||||
/* 已经处于挂起态,避免重复上报 STANDBY 造成 power_down 循环。 */
|
||||
return;
|
||||
}
|
||||
@@ -335,10 +340,10 @@ static void battery_module_suspend(void)
|
||||
module_set_state(MODULE_STATE_STANDBY);
|
||||
}
|
||||
|
||||
/* 响应系统唤醒:恢复电压传感器并重启周期采样。 */
|
||||
static void battery_module_resume(void)
|
||||
{
|
||||
if (atomic_get(&battery.active))
|
||||
{
|
||||
if (atomic_get(&battery.active)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -346,21 +351,18 @@ static void battery_module_resume(void)
|
||||
module_set_state(MODULE_STATE_READY);
|
||||
}
|
||||
|
||||
/* 仅处理模块 ready 和系统电源状态事件,保持模块职责单一。 */
|
||||
static bool app_event_handler(const struct app_event_header *aeh)
|
||||
{
|
||||
if (is_module_state_event(aeh))
|
||||
{
|
||||
if (is_module_state_event(aeh)) {
|
||||
const struct module_state_event *event = cast_module_state_event(aeh);
|
||||
|
||||
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY))
|
||||
{
|
||||
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
||||
int err = battery_module_init();
|
||||
if (err)
|
||||
{
|
||||
|
||||
if (err) {
|
||||
module_set_state(MODULE_STATE_ERROR);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
module_set_state(MODULE_STATE_READY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/adc.h>
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/drivers/sensor.h>
|
||||
#include <zephyr/sys/atomic.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <stdlib.h>
|
||||
@@ -18,35 +17,25 @@
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(MODULE);
|
||||
|
||||
#define MODE_USER_NODE DT_PATH(zephyr_user)
|
||||
#define MODE_ADC_IO_CH_IDX 0
|
||||
#define MODE_SENSE_NODE DT_NODELABEL(mode_sense)
|
||||
#define MODE_SAMPLE_INTERVAL_MS 50
|
||||
|
||||
static const struct adc_dt_spec mode_adc =
|
||||
ADC_DT_SPEC_GET_BY_IDX(MODE_USER_NODE, MODE_ADC_IO_CH_IDX);
|
||||
static const struct device *const mode_sensor_dev = DEVICE_DT_GET(MODE_SENSE_NODE);
|
||||
|
||||
static struct k_work_delayable mode_sample_work;
|
||||
static int16_t adc_sample_buffer;
|
||||
|
||||
static atomic_t active;
|
||||
static mode_type_t current_mode;
|
||||
static uint8_t mode_stable_status;
|
||||
|
||||
static int init_adc(void)
|
||||
static int init_mode_sensor(void)
|
||||
{
|
||||
if (!adc_is_ready_dt(&mode_adc))
|
||||
if (!device_is_ready(mode_sensor_dev))
|
||||
{
|
||||
LOG_ERR("ADC device not ready");
|
||||
LOG_ERR("Mode sense device not ready");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int err = adc_channel_setup_dt(&mode_adc);
|
||||
if (err)
|
||||
{
|
||||
LOG_ERR("ADC channel setup failed (err=%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -81,29 +70,22 @@ static mode_type_t classify_mode_from_mv(int32_t mv)
|
||||
|
||||
static int read_mode(mode_type_t *mode)
|
||||
{
|
||||
struct adc_sequence sequence = {0};
|
||||
int err = adc_sequence_init_dt(&mode_adc, &sequence);
|
||||
struct sensor_value value;
|
||||
int err = sensor_sample_fetch(mode_sensor_dev);
|
||||
if (err)
|
||||
{
|
||||
LOG_WRN("sensor_sample_fetch(mode) failed (err=%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
sequence.buffer = &adc_sample_buffer;
|
||||
sequence.buffer_size = sizeof(adc_sample_buffer);
|
||||
|
||||
err = adc_read_dt(&mode_adc, &sequence);
|
||||
if (err)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
int32_t v = adc_sample_buffer;
|
||||
err = adc_raw_to_millivolts_dt(&mode_adc, &v);
|
||||
err = sensor_channel_get(mode_sensor_dev, SENSOR_CHAN_VOLTAGE, &value);
|
||||
if (err)
|
||||
{
|
||||
LOG_WRN("sensor_channel_get(mode) failed (err=%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
int32_t v = (int32_t)sensor_value_to_milli(&value);
|
||||
*mode = classify_mode_from_mv(v);
|
||||
|
||||
return 0;
|
||||
@@ -187,7 +169,7 @@ static void init_mode_switch(void)
|
||||
if (atomic_get(&active))
|
||||
return;
|
||||
|
||||
if (init_adc())
|
||||
if (init_mode_sensor())
|
||||
{
|
||||
module_set_state(MODULE_STATE_ERROR);
|
||||
return;
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
SB_CONFIG_BOOTLOADER_MCUBOOT=y
|
||||
SB_CONFIG_MCUBOOT_MODE_SINGLE_APP=y
|
||||
|
||||
25
sysbuild/mcuboot.conf
Normal file
25
sysbuild/mcuboot.conf
Normal file
@@ -0,0 +1,25 @@
|
||||
CONFIG_LOG=n
|
||||
CONFIG_CONSOLE=n
|
||||
CONFIG_UART_CONSOLE=n
|
||||
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_UART_INTERRUPT_DRIVEN=y
|
||||
CONFIG_UART_LINE_CTRL=y
|
||||
|
||||
CONFIG_USB_DEVICE_STACK=y
|
||||
CONFIG_USB_DEVICE_REMOTE_WAKEUP=n
|
||||
CONFIG_USB_CDC_ACM=y
|
||||
CONFIG_USB_NRFX=y
|
||||
CONFIG_USB_DEVICE_PRODUCT="MCUBOOT"
|
||||
CONFIG_USB_DEVICE_MANUFACTURER="new_kbd"
|
||||
CONFIG_USB_DEVICE_VID=0x1209
|
||||
CONFIG_USB_DEVICE_PID=0x0002
|
||||
|
||||
CONFIG_RETAINED_MEM=y
|
||||
CONFIG_RETENTION=y
|
||||
CONFIG_RETENTION_BOOT_MODE=y
|
||||
|
||||
CONFIG_MCUBOOT_SERIAL=y
|
||||
CONFIG_BOOT_SERIAL_CDC_ACM=y
|
||||
CONFIG_BOOT_SERIAL_BOOT_MODE=y
|
||||
CONFIG_BOOT_SERIAL_NO_APPLICATION=y
|
||||
23
sysbuild/mcuboot.overlay
Normal file
23
sysbuild/mcuboot.overlay
Normal file
@@ -0,0 +1,23 @@
|
||||
/ {
|
||||
chosen {
|
||||
zephyr,boot-mode = &boot_mode0;
|
||||
};
|
||||
};
|
||||
|
||||
&usbd {
|
||||
status = "okay";
|
||||
|
||||
cdc_acm_uart0: cdc_acm_uart0 {
|
||||
compatible = "zephyr,cdc-acm-uart";
|
||||
};
|
||||
};
|
||||
|
||||
&gpregret1 {
|
||||
status = "okay";
|
||||
|
||||
boot_mode0: boot_mode@0 {
|
||||
compatible = "zephyr,retention";
|
||||
status = "okay";
|
||||
reg = <0x0 0x1>;
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user