修复低功耗时,RX接收不到数据的问题:把RX设置为唤醒口,但是这样子会有个问题,用户发过来的第一包数据会出现错包,利用重发机制可实现正常通讯,MCU端也可以发送数据的时候带上两个字节的0,模组可通过解析器寻头正常识别

This commit is contained in:
2026-08-11 14:21:43 +08:00
parent 4bfe10d728
commit 8581d15f46
5 changed files with 100 additions and 10 deletions
@@ -24,6 +24,7 @@
#endif
#include "norflash_sfc.h"
#include "asm/power/power_port.h"
#include "mcu_uart.h"
//#include "app_umidigi_chargestore.h"
#if TCFG_AUDIO_ANC_ENABLE
#include "audio_anc.h"
@@ -746,6 +747,17 @@ struct port_wakeup port1 = {
};
#endif
/*
* sleep 时 UART 停,用 PA8 RX 下降沿唤醒(须与 mcu_uart_init 引脚一致)。
* 模组产品可直接发协议或前导 0x00;刚醒第一包可能丢/坏,靠协议重试或前导兜底。
*/
struct port_wakeup port2 = {
.pullup_down_enable = ENABLE,
.edge = FALLING_EDGE,
.filter = PORT_FLT_4ms,
.iomap = MCU_UART_RX_PIN,
};
#if TCFG_CHARGE_ENABLE
struct port_wakeup charge_port = {
.edge = RISING_EDGE, //唤醒方式选择,可选:上升沿\下降沿\双边沿
@@ -773,6 +785,7 @@ const struct wakeup_param wk_param = {
#if (TCFG_TEST_BOX_ENABLE || TCFG_CHARGESTORE_ENABLE || TCFG_ANC_BOX_ENABLE || TCFG_UMIDIGI_BOX_ENABLE)
.port[2] = &port1,
#endif
.port[3] = &port2, /* UART RX(PA8) 唤醒,软关机时 index=3 关闭 */
#if TCFG_CHARGE_ENABLE
.aport[0] = &charge_port,
.aport[1] = &vbat_port,
@@ -991,6 +1004,9 @@ void board_set_soft_poweroff(void)
soff_gpio_protect(IO_PORTB_01);
#endif
/* 软关机关闭 UART RX 唤醒,避免误唤醒;勿 protect 该脚 */
power_wakeup_index_enable(3, 0);
board_set_soft_poweroff_common(NULL);
#if (TCFG_TEST_BOX_ENABLE || TCFG_CHARGESTORE_ENABLE || TCFG_ANC_BOX_ENABLE || TCFG_UMIDIGI_BOX_ENABLE)
@@ -1050,6 +1066,10 @@ static void port_wakeup_callback(u8 index, u8 gpio)
break;
#endif
}
if (gpio == MCU_UART_RX_PIN) {
mcu_uart_rx_keep_awake(); /* 禁止立刻再睡,等待后续串口数据 */
}
}
static void aport_wakeup_callback(u8 index, u8 gpio, u8 edge)
@@ -733,7 +733,7 @@ DAC硬件上的连接方式,可选的配置:
//*********************************************************************************//
#define TCFG_LOWPOWER_POWER_SEL PWR_LDO15//PWR_LDO15 //电源模式设置,可选DCDC和LDO
#define TCFG_LOWPOWER_BTOSC_DISABLE 0 //低功耗模式下BTOSC是否保持
/* MCU 串口方案:配合 mcu_bridge LP target,忙时保持唤醒、空闲可进低功耗 */
/* MCU 串口方案:RX 下降沿唤醒 + mcu_uart/mcu_bridge LP target,忙时保持唤醒、空闲可进 sleep */
#define TCFG_LOWPOWER_LOWPOWER_SEL SLEEP_EN//DEEP_SLEEP_EN//SLEEP_EN//DEEP_SLEEP_EN //低功耗使能,蓝牙&&系统空闲可进入低功耗
#define TCFG_LOWPOWER_VDDIOM_LEVEL VDDIOM_VOL_28V //vddiom等级
#define TCFG_LOWPOWER_OSC_TYPE OSC_TYPE_LRC //低功耗晶振类型,btosc/lrc
@@ -3,7 +3,7 @@
* @brief BLE+MCU 协议桥 P0 实现
* @author cyWu <1917507415@qq.com>
* @date 2026.08.06
* @version V1.2.0
* @version V1.3.0
* @history
* - V1.0.0, 2026.08.06, cyWu, 首次发布
* - V1.1.0, 2026.08.06, cyWu, 改为事件队列 + 独立任务驱动,
@@ -11,6 +11,7 @@
* 原 sys_timer 回调三方并发访问 s_br 的问题)
* - V1.2.0, 2026.08.10, cyWu, 注册 LP target:桥接忙时禁止进低功耗,
* 空闲可睡,配合板级 SLEEP_EN 恢复串口方案下的低功耗
* - V1.3.0, 2026.08.11, cyWu, 周期递减 UART RX 防睡标志
******************************************************************************/
#include "system/includes.h"
@@ -914,6 +915,9 @@ static void mcu_bridge_check_ble_pending(void)
*/
static void mcu_bridge_periodic(void)
{
/* 与供应商 demo 主循环一致:周期递减 usr_uart_recieve,非 0 禁止 sleep */
mcu_uart_rx_keep_awake_tick();
mcu_bridge_try_identity();
if (s_br.identity_adv_pending) {
@@ -3,20 +3,22 @@
* @brief BLE 模组与外部 MCU 的 UART 驱动(PA7 TX / PA8 RX, 9600
* @author cyWu <1917507415@qq.com>
* @date 2026.08.06
* @version V1.3.0
* @version V1.5.0
* @history
* - V1.0.0, 2026.08.06, cyWu, 首次发布
* - V1.1.0, 2026.08.07, cyWu, TX 使用静态对齐缓冲 + write()
* - V1.1.0, 2026.08.07, cyWu, TX 使用静态对齐缓冲 + copy()
* - V1.2.0, 2026.08.07, cyWu, 对齐供应商 demo:关闭低功耗
* - V1.3.0, 2026.08.07, cyWu, 发送与厂家一致,直接 write(data),去掉 TX 拷贝
* - V1.4.0, 2026.08.11, cyWu, sleep 后 RX 靠 GPIO 唤醒;收包/唤醒置位防睡 + LP target
* - V1.5.0, 2026.08.11, cyWu, 引脚固定在 init;去掉 USR_JB_UART_RX_PIN 条件编译
*
* @note 串口收发期间由 mcu_bridge 的 LP target 挡住休眠;
* 板级可开 SLEEP_EN,勿在无 LP 保护时直接开 DEEP_SLEEP。
* @note sleep 时 UART 停,PA8 RX 作下降沿唤醒;客户可直接发协议或前导 0x00。
******************************************************************************/
#include "system/includes.h"
#include "asm/uart_dev.h"
#include "asm/gpio.h"
#include "asm/power/power_api.h"
#include "mcu_uart.h"
#include "mcu_bridge.h"
#include "mcu_frame.h"
@@ -40,6 +42,12 @@ static u8 s_rx_cbuf[MCU_UART_RX_CBUF_SIZE] __attribute__((aligned(4)));
static u8 s_rx_tmp[MCU_UART_RX_CBUF_SIZE];
static OS_MUTEX s_tx_lock;
/*
* 防睡计数:唤醒口或 UART 收到数据时置 MCU_UART_RX_KEEP_AWAKE_TICKS
* 由 mcu_bridge 主循环周期递减;非 0 时 LP target 禁止进 sleep。
*/
static volatile u8 s_usr_uart_recieve = 0;
/*============================================================================*/
/* 私有函数 */
/*============================================================================*/
@@ -63,11 +71,30 @@ static void mcu_uart_rx_task(void *arg)
/* timeout=0:无数据时 pend,有 RX/OT 中断后唤醒 */
rxcnt = s_uart_bus->read(s_rx_tmp, sizeof(s_rx_tmp), 0);
if (rxcnt > 0) {
mcu_uart_rx_keep_awake(); /* 真正收到数据,禁止立刻再睡 */
log_debug("uart rx cnt=%d", rxcnt);
for (int i = 0; i < (int)rxcnt; i++) {
log_debug("uart rx data[%d]=%02X", i, s_rx_tmp[i]);
}
mcu_bridge_on_uart_rx(s_rx_tmp, (uint16_t)rxcnt);
}
}
}
/**
* @brief 低功耗空闲查询:串口防睡标志非 0 则不允许进 sleep
* @return 1=可进低功耗,0=保持唤醒
*/
static u8 mcu_uart_lp_idle_query(void)
{
return s_usr_uart_recieve ? 0 : 1;
}
REGISTER_LP_TARGET(mcu_uart_lp_target) = {
.name = "mcu_uart",
.is_idle = mcu_uart_lp_idle_query,
};
/*============================================================================*/
/* 公有函数 */
/*============================================================================*/
@@ -84,8 +111,8 @@ McuUart_Ret_t mcu_uart_init(void)
return MCU_UART_OK;
}
u_arg.tx_pin = IO_PORTA_07;
u_arg.rx_pin = IO_PORTA_08;
u_arg.tx_pin = MCU_UART_TX_PIN;
u_arg.rx_pin = MCU_UART_RX_PIN;
u_arg.rx_cbuf = s_rx_cbuf;
u_arg.rx_cbuf_size = MCU_UART_RX_CBUF_SIZE;
u_arg.frame_length = MCU_UART_RX_CBUF_SIZE;
@@ -139,3 +166,22 @@ uint8_t mcu_uart_is_ready(void)
{
return s_initialized;
}
/**
* @brief 置位 UART 防睡标志
*/
void mcu_uart_rx_keep_awake(void)
{
s_usr_uart_recieve = MCU_UART_RX_KEEP_AWAKE_TICKS;
}
/**
* @brief 周期递减防睡标志
*/
void mcu_uart_rx_keep_awake_tick(void)
{
if (s_usr_uart_recieve) {
s_usr_uart_recieve--;
log_debug("usr_uart_recieve:%d", s_usr_uart_recieve);
}
}
@@ -3,15 +3,17 @@
* @brief BLE 模组与外部 MCU 的 UART 驱动接口(PA7/PA8, 9600
* @author cyWu <1917507415@qq.com>
* @date 2026.08.06
* @version V1.0.0
* @version V1.1.0
* @history
* - V1.0.0, 2026.08.06, cyWu, 首次发布
* - V1.1.0, 2026.08.11, cyWu, 增加 sleep 唤醒防睡接口
******************************************************************************/
#ifndef __MCU_UART_H__
#define __MCU_UART_H__
#include <stdint.h>
#include "asm/gpio.h"
/*============================================================================*/
/* 宏定义 */
@@ -19,7 +21,14 @@
#define MCU_UART_BAUD (9600) /**< 协议默认波特率 */
#define MCU_UART_RX_CBUF_SIZE (512) /**< DMA 循环缓冲,须为 2 的幂 */
/* 引脚:TX=PA7(IO_PORTA_07)RX=PA8(IO_PORTA_08),在 mcu_uart.c 中配置 */
#define MCU_UART_TX_PIN IO_PORTA_07 /**< MCU 通信 UART TX */
#define MCU_UART_RX_PIN IO_PORTA_08 /**< MCU 通信 UART RXboard 唤醒口须一致) */
/*
* sleep 唤醒或串口收数后保持唤醒的 tick 数(mcu_bridge 约每 200ms 递减一次)。
* 取大一些:第一包可能在唤醒过程中丢失,留给对端协议重试窗口(约 3s)。
*/
#define MCU_UART_RX_KEEP_AWAKE_TICKS (15u)
/*============================================================================*/
/* 错误码 */
@@ -59,4 +68,15 @@ McuUart_Ret_t mcu_uart_send(const uint8_t *data, uint16_t len);
*/
uint8_t mcu_uart_is_ready(void);
/**
* @brief 置位 UART 防睡标志(唤醒回调 / 真正收到数据时调用)
* @note 等价供应商 demousr_var.usr_uart_recieve = 5
*/
void mcu_uart_rx_keep_awake(void);
/**
* @brief 主循环周期递减防睡标志(标志非 0 时 LP target 禁止进 sleep
*/
void mcu_uart_rx_keep_awake_tick(void);
#endif /* __MCU_UART_H__ */