1、充电时不再叠待机绿灯;意外复位不再跳过 3s 开机按键判定

2、电机停转去掉反接刹车改自由滑行,避免电流冲击触发 LVD 复位;
3、关机直接 power_set_soft_poweroff,跳过耳机 SDK 优雅关机流程,按键关机从十几秒压到瞬间掉电
This commit is contained in:
2026-08-25 20:05:59 +08:00
parent 5e5f921a3a
commit 93c1943992
8 changed files with 72 additions and 67 deletions
+10 -10
View File
@@ -80,16 +80,16 @@ static uint8_t boot_skip_key_wait(void)
boot_delay_ms(5);
}
/* 以下都是“芯片自己意外重启了一下”,不是用户主动按开机键,
* 不能因此逼用户重新按键,否则相当于设备无故“关机”了一次 */
if (cpu_reset_by_soft() /* SDK 综合判断:是否软件复位 */
|| is_reset_source(MSYS_SOFT_RST) /* 主系统软件复位(断言/异常/OTA 后重启等) */
|| is_reset_source(P33_SOFT_RST) /* P33 软件复位,最常见的软复位入口 */
|| is_reset_source(P33_VDDIO_LVD_RST) /* VDDIO 低压复位(电机启动拉低电压误触发) */
|| is_reset_source(P11_WDT_RST)) { /* 看门狗复位(程序卡死被强制重启) */
log_info("boot reset-keep, skip key wait\n");
return 1;
}
// /* 以下都是“芯片自己意外重启了一下”,不是用户主动按开机键,
// * 不能因此逼用户重新按键,否则相当于设备无故“关机”了一次 */
// if (cpu_reset_by_soft() /* SDK 综合判断:是否软件复位 */
// || is_reset_source(MSYS_SOFT_RST) /* 主系统软件复位(断言/异常/OTA 后重启等) */
// || is_reset_source(P33_SOFT_RST) /* P33 软件复位,最常见的软复位入口 */
// || is_reset_source(P33_VDDIO_LVD_RST) /* VDDIO 低压复位(电机启动拉低电压误触发) */
// || is_reset_source(P11_WDT_RST)) { /* 看门狗复位(程序卡死被强制重启) */
// log_info("boot reset-keep, skip key wait\n");
// return 1;
// }
return 0;
}
+1 -1
View File
@@ -91,7 +91,7 @@ void app_function_poll(void)
void app_function_tick_1ms(uint16_t dt)
{
if (s_func.hand_busy) {
bsp_motor_brake_tick();
bsp_motor_switch_tick();
s_func.hand_ms = app_add_ms(s_func.hand_ms, dt);
} else {
app_mode_run();
+2 -1
View File
@@ -193,7 +193,8 @@ void app_led_run(uint16_t dt, uint8_t app_power)
led_clear_function_events();
} else {
#if BOARD_LED_STANDBY_ON
if ((charge_led != 2) && !pairing && !green_busy()) {
/* 正在充电(红)或已充满(绿)时都不叠加待机绿,只有完全没接电才显示待机 */
if ((charge_led == 0) && !pairing && !green_busy()) {
LED_EventAdd(LED_EVENT_STANDBY);
} else {
LED_EventDelete(LED_EVENT_STANDBY);
+1 -1
View File
@@ -201,7 +201,7 @@ void app_mode_run(void)
{
const AppModeStep_t *tbl;
bsp_motor_brake_tick();
bsp_motor_switch_tick();
if (!s_mode.initialized || s_mode.active == 0) {
return;
}
+11 -4
View File
@@ -44,14 +44,13 @@
#include "app_mode.h"
#include "app_led.h"
#include "key_manager.h"
#include "asm/power/power_api.h"
#define LOG_TAG_CONST APP
#define LOG_TAG "[USR_JB]"
#define LOG_INFO_ENABLE
#include "debug.h"
extern void sys_enter_soft_poweroff(void *priv);
/* 向 usr_le_code 提供产品身份(换产品只改 jb_protocol.h 宏即可) */
const uint8_t g_usr_le_prodcode[USR_LE_PRODCODE_LEN] = {
JB_CATEGORY_CODE[0], JB_CATEGORY_CODE[1],
@@ -106,13 +105,21 @@ static void usr_poweroff_request_hook(void)
}
/**
* @brief 深睡请求钩子:50ms 到点,真正进入深睡(不会返回)
* @brief 深睡请求钩子:50ms 到点,真正进入深睡
* @note 不走 sys_enter_soft_poweroff():那是耳机 SDK 给"蓝牙耳机"设计的优雅关机流程
* (BLE 断连握手 + 任务切换到 idle + 尝试放关机音效),实测哪怕已经砍掉了灯效
* 动画和广播空转,走完还是要 2.5s 左右,供应商确认这对按键关机的玩具不正常。
* 本产品不用 DAC/音频(没有 dac_power_on 过),跳过 dac_power_off()——
* 它在从未打开过 DAC 的情况下会直接调 audio_dac_close() 关一个没开过的
* 句柄,没必要也没好处。跳过 BLE 优雅断连的代价是手机 App 端不会收到
* 断连通知,只能等连接超时(标准 BLE 行为,等同于直接拔电池,App 端会
* 自行处理,不影响下次重连配对)。
* @return 无
*/
static void usr_poweroff_finalize_hook(void)
{
bsp_hw_enter_sleep_io();
sys_enter_soft_poweroff(NULL);
power_set_soft_poweroff();
}
/**
-1
View File
@@ -88,7 +88,6 @@
/*============================================================================*/
#define BOARD_MOTOR_REVERSE_MS 1 /**< 换向前先松开,防 H 桥直通 */
#define BOARD_MOTOR_STOP_BRAKE_MS 30 /**< 停转先反转刹车(ms),太长会倒转 */
#define BOARD_HAND_PULSE_MS 1000 /**< 预留;手动 1/2 一直转到写 03 停止 */
#define BOARD_MOTOR_PWM_HZ 20000 /**< MCPWM 频率(Hz)20k 避开可听啸叫 */
#define BOARD_MOTOR_PWM_DUTY 8000 /**< 占空比 0~10000=0%~100%80% */
+39 -43
View File
@@ -10,6 +10,8 @@
* - V1.3.0, 2026.08.24, cyWu, 电机改 MCPWM 占空比降速
* - V1.4.0, 2026.08.24, cyWu, 增加按占空比驱动,供玩法变速
* - V1.5.0, 2026.08.25, cyWu, 空闲关闭 MCPWM 时钟
* - V1.6.0, 2026.08.25, cyWu, 去掉停转反接刹车,改自由滑行停止,避免刹车
* 电流冲击拉垮供电轨触发 LVD 复位
******************************************************************************/
#include "system/includes.h"
@@ -29,12 +31,12 @@ static uint8_t s_initialized;
/** 电机状态,替代原来散落的 7 个 static */
typedef struct {
BspMotorDir_t dir; /**< 当前实际方向(含正在刹车时的反向) */
BspMotorDir_t pending; /**< 死区/刹车结束后要切到的方向 */
BspMotorDir_t dir; /**< 当前实际方向 */
BspMotorDir_t pending; /**< 换向死区结束后要切到的方向 */
uint16_t duty; /**< 当前实际占空比 */
uint16_t pending_duty; /**< 死区/刹车结束后要用的占空比 */
uint16_t brake_ms; /**< 换向死区/反转刹车剩余时长,0=空闲 */
u32 brake_t0; /**< 死区/刹车起始时间戳 */
uint16_t pending_duty; /**< 换向死区结束后要用的占空比 */
uint16_t switch_ms; /**< 换向死区剩余时长,0=空闲/不在换向中 */
u32 switch_t0; /**< 换向死区起始时间戳 */
uint8_t pwm_clk_on; /**< 1=MCPWM 时钟已打开 */
} BspMotorCtx_t;
@@ -180,13 +182,17 @@ static void bsp_motor_gpio(BspMotorDir_t dir, uint16_t duty)
}
if ((ina_duty == 0) && (inb_duty == 0)) {
#if BOARD_MOTOR_PWM_IDLE_CLOSE
bsp_motor_pwm_clock_off();
/* 换向死区(BOARD_MOTOR_REVERSE_MS)、刹车瞬间也会短暂占空比为 0,
* 但马上(1~30ms 内)还要再驱动,不能当成“真空闲”去关时钟:
* 频繁 close/open MCPWM 外设比单纯调占空比激进得多,玩法换向越快
* 关得越勤,有卡死风险。这里只清占空比(两脚拉低,电气效果一样),
* 真正的空闲关时钟统一交给 bsp_hw_sleep_pwm_off()——它在系统真的
* 要进轻睡前才调用,并且会先查 bsp_motor_is_busy()。 */
mcpwm_set_duty(pwm_ch0, 0);
mcpwm_set_duty(pwm_ch1, 0);
return;
#endif
} else {
bsp_motor_pwm_clock_on();
}
bsp_motor_pwm_clock_on();
mcpwm_set_duty(pwm_ch0, ina_duty);
mcpwm_set_duty(pwm_ch1, inb_duty);
}
@@ -229,7 +235,7 @@ BspHw_Ret_t bsp_hw_init(void)
s_motor.pending = BSP_MOTOR_STOP;
s_motor.duty = 0;
s_motor.pending_duty = 0;
s_motor.brake_ms = 0;
s_motor.switch_ms = 0;
#if BOARD_MOTOR_PWM_IDLE_CLOSE
bsp_motor_pwm_clock_off();
#endif
@@ -290,7 +296,7 @@ void bsp_led_all_off(void)
}
/**
* @brief 设置电机方向。STOP 时若正在转,先反转刹车再滑行
* @brief 设置电机方向。STOP 时直接切断驱动,自由滑行到停(不做反接刹车)
* @param dir 收绳 / 放绳 / 停转
* @return 无
*/
@@ -320,7 +326,7 @@ void bsp_motor_set_pwm(BspMotorDir_t dir, uint16_t duty)
}
/* 同向只改占空比:直接改 PWM,不走换向死区 */
if (dir == s_motor.dir && s_motor.brake_ms == 0) {
if (dir == s_motor.dir && s_motor.switch_ms == 0) {
if (duty == s_motor.duty) {
return;
}
@@ -331,42 +337,32 @@ void bsp_motor_set_pwm(BspMotorDir_t dir, uint16_t duty)
return;
}
/* 已经在反转刹车等到停,忽略重复 STOP */
if (dir == BSP_MOTOR_STOP && s_motor.pending == BSP_MOTOR_STOP && s_motor.brake_ms) {
return;
}
/* 正在转时要停:先反向驱动再滑行,短接对此驱动无效 */
if (dir == BSP_MOTOR_STOP
&& (s_motor.dir == BSP_MOTOR_IN || s_motor.dir == BSP_MOTOR_OUT)) {
BspMotorDir_t rev = (s_motor.dir == BSP_MOTOR_OUT) ? BSP_MOTOR_IN : BSP_MOTOR_OUT;
uint16_t brake_duty = s_motor.duty ? s_motor.duty : BOARD_MOTOR_PWM_DUTY;
bsp_motor_gpio(rev, brake_duty);
s_motor.dir = rev;
s_motor.duty = brake_duty;
/* 停转:直接切断驱动,让电机自由滑行到停,不做反接刹车——反接刹车电流比
* 正常驱动大(电池要同时顶住反向驱动电流和电机反电动势),实测会把供电轨
* 拉低触发 LVD 复位。哪怕正在换向死区里,也直接取消死区改成停。 */
if (dir == BSP_MOTOR_STOP) {
s_motor.switch_ms = 0;
s_motor.dir = BSP_MOTOR_STOP;
s_motor.pending = BSP_MOTOR_STOP;
s_motor.duty = 0;
s_motor.pending_duty = 0;
s_motor.brake_ms = BOARD_MOTOR_STOP_BRAKE_MS;
s_motor.brake_t0 = timer_get_ms();
log_info("motor rev-brake %ums duty=%u\n",
(unsigned)BOARD_MOTOR_STOP_BRAKE_MS, (unsigned)brake_duty);
bsp_motor_gpio(BSP_MOTOR_STOP, 0);
return;
}
/* 换向:先松开再输出,避免 H 桥直通 */
if (dir != BSP_MOTOR_STOP && s_motor.dir != BSP_MOTOR_STOP && dir != s_motor.dir) {
if (s_motor.dir != BSP_MOTOR_STOP && dir != s_motor.dir) {
bsp_motor_gpio(BSP_MOTOR_STOP, 0);
s_motor.pending = dir;
s_motor.pending_duty = duty;
s_motor.brake_ms = BOARD_MOTOR_REVERSE_MS;
s_motor.brake_t0 = timer_get_ms();
s_motor.switch_ms = BOARD_MOTOR_REVERSE_MS;
s_motor.switch_t0 = timer_get_ms();
s_motor.dir = BSP_MOTOR_STOP;
s_motor.duty = 0;
return;
}
s_motor.brake_ms = 0;
s_motor.switch_ms = 0;
s_motor.dir = dir;
s_motor.pending = dir;
s_motor.duty = duty;
@@ -376,21 +372,21 @@ void bsp_motor_set_pwm(BspMotorDir_t dir, uint16_t duty)
}
/**
* @brief 推进换向死区与停转反转刹车,按真实毫秒计时
* @brief 推进换向死区计时,按真实毫秒计时;死区结束后切到目标方向/占空比
* @return 无
*/
void bsp_motor_brake_tick(void)
void bsp_motor_switch_tick(void)
{
#if !BOARD_MOTOR_ENABLE
return;
#else
if (s_motor.brake_ms == 0) {
if (s_motor.switch_ms == 0) {
return;
}
if ((timer_get_ms() - s_motor.brake_t0) < s_motor.brake_ms) {
if ((timer_get_ms() - s_motor.switch_t0) < s_motor.switch_ms) {
return;
}
s_motor.brake_ms = 0;
s_motor.switch_ms = 0;
s_motor.dir = s_motor.pending;
s_motor.duty = s_motor.pending_duty;
bsp_motor_gpio(s_motor.dir, s_motor.duty);
@@ -484,7 +480,7 @@ void bsp_hw_sleep_pwm_off(void)
}
/**
* @brief 电机是否还在转或刹车
* @brief 电机是否还在转或处于换向死区
* @return 1=忙碌,0=已停且 PWM 已关
*/
uint8_t bsp_motor_is_busy(void)
@@ -492,7 +488,7 @@ uint8_t bsp_motor_is_busy(void)
#if !BOARD_MOTOR_ENABLE
return 0;
#else
if (s_motor.brake_ms) {
if (s_motor.switch_ms) {
return 1;
}
if (s_motor.dir != BSP_MOTOR_STOP) {
@@ -513,7 +509,7 @@ void bsp_hw_enter_sleep_io(void)
{
bsp_motor_set(BSP_MOTOR_STOP);
#if BOARD_MOTOR_ENABLE
s_motor.brake_ms = 0;
s_motor.switch_ms = 0;
s_motor.dir = BSP_MOTOR_STOP;
s_motor.pending = BSP_MOTOR_STOP;
s_motor.duty = 0;
+8 -6
View File
@@ -2,14 +2,16 @@
* @file bsp_hw.h
* @brief CBC2 板级硬件:电机 / LED / 按键 / 充电 / 电量
* @author cyWu <1917507415@qq.com>
* @date 2026.08.24
* @version V1.5.0
* @date 2026.08.25
* @version V1.6.0
* @history
* - V1.0.0, 2026.08.21, cyWu, 首次发布
* - V1.1.0, 2026.08.24, cyWu, 停转改为反转刹车;去掉未贴件限位
* - V1.3.0, 2026.08.24, cyWu, 电机改 MCPWM 50% 占空比降速
* - V1.4.0, 2026.08.24, cyWu, 增加按占空比驱动,供玩法变速
* - V1.5.0, 2026.08.25, cyWu, 空闲关闭 MCPWM 时钟,避免待机空转耗电
* - V1.6.0, 2026.08.25, cyWu, 去掉停转反接刹车,改自由滑行停止,避免刹车
* 电流冲击拉垮供电轨触发 LVD 复位
******************************************************************************/
#ifndef __BSP_HW_H__
@@ -63,7 +65,7 @@ void bsp_led_green_set(uint8_t on);
void bsp_led_all_off(void);
/**
* @brief 设置电机方向。STOP 时若正在转,先反转刹车再滑行
* @brief 设置电机方向。STOP 时直接切断驱动,自由滑行到停(不做反接刹车)
* @note 占空比用 BOARD_MOTOR_PWM_DUTY(手动点动)
* @param dir 收绳 / 放绳 / 停转
* @return 无
@@ -79,13 +81,13 @@ void bsp_motor_set(BspMotorDir_t dir);
void bsp_motor_set_pwm(BspMotorDir_t dir, uint16_t duty);
/**
* @brief 推进换向死区与停转反转刹车,按真实毫秒计时
* @brief 推进换向死区计时,按真实毫秒计时;死区结束后切到目标方向/占空比
* @return 无
*/
void bsp_motor_brake_tick(void);
void bsp_motor_switch_tick(void);
/**
* @brief 电机是否还在转或刹车
* @brief 电机是否还在转或处于换向死区
* @return 1=忙碌,0=已停且 PWM 已关
*/
uint8_t bsp_motor_is_busy(void);