杰理 SDK 文档中心
首页
首页
  • 概述与快速入门

    • 芯片平台与 SDK 概述
    • 环境搭建与编译工具链
    • 快速开始:选型、编译与烧录
    • 烧录与量产工具
  • 构建系统与板级工程

    • 顶层 Makefile 与编译目标
    • 板级工程与配置
    • 后处理与配置工具
  • HID 人机交互应用

    • HID 应用架构总览
    • 键盘、翻页器与遥控应用
    • 鼠标应用:单模、双模与低延迟
    • 空闲应用与初始化流程
  • BLE 透传与数传应用

    • 透传应用总览
    • 多连接与无连接传输
    • AT 命令模组应用
    • Dongle 适配器应用
  • BSP 公共模块

    • 蓝牙公共处理
    • 按键、LED 与红外
    • 传感器与编码器
    • 存储、VM 与文件系统
    • 电源管理与低功耗
    • 消息调度与通信外设
  • 协议栈与预编译库

    • 蓝牙协议栈库
    • 设备驱动与文件系统库
    • 音频、升级与其他库
  • 开发资料与补丁发布

    • 文档资料中心
    • 版本补丁与兼容性修复

透传应用总览

本文档介绍 AW31N BLE SDK 中透传应用(apps/demo/transfer)的整体架构、入口流程、示例应用(AT 透传)以及相关配置,帮助开发者快速理解透传应用如何在 BLE 与串口之间桥接数据。

目的与范围

本页面是"透传应用"系列文档的总览页,覆盖以下内容:

  • apps/demo/transfer 应用目录的整体结构与分层
  • 应用入口 app_main.c 的启动流程与应用分支选择机制
  • AT 透传示例(examples/at_char_com)的核心流程:BLE GATT 服务/客户端与 UART 双向透传
  • 低功耗管理、软关机处理等应用级行为
  • 板级配置与库配置(board/bd47、config)的作用

以下内容属于兄弟页面的范畴,本页只做定向指引、不展开细节:

  • AT 命令集的具体格式与实现 → 参见 AT 命令相关页面(at_char_cmds)
  • GATT 服务端/客户端的 Service 与 Characteristic 定义 → 参见 BLE AT 透传服务页面(ble_at_char_server / ble_at_char_client)
  • UART 驱动与帧解析细节 → 参见 UART 透传页面(at_char_uart)
  • HID 应用中的透传通道(ble_hid_transfer_channel_send/recieve)属于 HID 应用范畴,参见 HID 相关页面

概述

透传(Transparent Transmission)是 BLE SDK 中最常见的数据通路应用形态:设备通过 UART 串口接收外部数据,打包后经 BLE GATT 服务(Notify/Write)发送给对端(手机 App 或另一台设备),反之亦然。开发者只需关注"串口进来什么、BLE 发出去什么",无需关心底层协议栈细节。

在 apps/demo/transfer 中,SDK 提供了完整的可编译工程骨架:

  • 应用层:app_main.c 负责启动、内存布局与状态机;examples/at_char_com 提供可工作的 AT 透传参考实现。
  • 板级层:board/bd47 同时支持 AW31N demo 板(board_aw31n_demo.c)与 AW318N dongle(board_aw318n_dongle.c)两种硬件形态。
  • 配置层:config/ 下的 lib_btstack_config.c、lib_btctrler_config.c、lib_profile_config.c 等文件集中管理蓝牙协议栈、控制器与 profile 的裁剪开关。

透传应用的核心设计意图是消息驱动 + 状态机:app_main() 只做初始化并把控制权交给应用状态机,应用启动后进入 get_msg() 消息循环,所有事件(按键、UART 数据、BLE 事件、低功耗定时器)都以消息形式被 app_comm_process_handler() 串行处理,从而避免并发访问共享状态。

架构

flowchart TD
    subgraph sg_App["应用层 apps/demo/transfer"]
        AppMain["app_main.c<br/>入口 / 内存布局 / 状态机"]
        AtChar["examples/at_char_com<br/>AT 透传示例"]
        Board["board/bd47<br/>板级配置与驱动"]
        Cfg["config<br/>协议栈/控制器/profile 裁剪"]
    end

    subgraph sg_Stack["蓝牙协议栈"]
        Btstack["btstack<br/>BLE 协议栈"]
        Btctrler["btctrler<br/>蓝牙控制器"]
        GattSrv["ble_at_char_server<br/>GATT 服务端"]
        GattCli["ble_at_char_client<br/>GATT 客户端"]
    end

    subgraph sg_Ext["外设与系统"]
        Uart["UART 串口"]
        Wkup["P33 唤醒 IO"]
        Timer["sys_timer / sys_timeout"]
    end

    AppMain -->|"启动 / 状态切换"| AtChar
    AppMain --> Board
    AppMain --> Cfg
    AtChar --> GattSrv
    AtChar --> GattCli
    GattSrv --> Btstack
    GattCli --> Btstack
    Btstack --> Btctrler
    AtChar --> Uart
    AtChar --> Wkup
    AtChar --> Timer

各层职责

  • app_main.c:定义系统栈/堆/BT RAM 的内存段(.sstack、.ustack、.sec_sys_heap、.sec_bt_nk_ram、.sec_bt_nv_ram),配置中断优先级,并依据编译宏(CONFIG_APP_*)选择进入哪个应用分支。
  • examples/at_char_com:透传参考实现。它把 BLE GATT 服务端/客户端、AT 命令解析、UART 收发和低功耗策略组装成一个可运行的应用;源码以 #if CONFIG_APP_AT_CHAR_COM 保护,仅在该宏开启时参与编译。
  • board/bd47:硬件相关配置,区分 AW31N demo 板与 AW318N dongle 两种板型,通过 board_config.h 与各自的 *_cfg.h 暴露引脚、时钟、外设配置。
  • config/:lib_btstack_config.c、lib_btctrler_config.c、lib_profile_config.c、lib_driver_config.c、lib_system_config.c、lib_update_config.c、log_config.c,分别控制协议栈特性、控制器特性、GATT profile、驱动、系统、升级与日志的裁剪。

架构选择"消息循环 + 状态机"而非"多线程直接调用"的原因:BLE 协议栈回调与 UART 中断都可能随时触发数据到达,若直接在回调中操作共享缓冲会引入竞态;统一投递到消息队列由单个循环串行消费,既保证数据有序,也让低功耗判断(是否有活跃任务)变得集中可控。

应用入口与控制流

内存布局与启动初始化

app_main.c 在文件顶部定义了系统内存的静态分配。这些变量通过 sec_used() 链接段属性放置在固定内存区域,是链接脚本(ld.c)与蓝牙协议栈 RAM 分配的基础:

//for ld.c link
static int _sstack_space[SYS_STACK_SIZE_ALL / 4] sec_used(.sstack);
static int _ustack_space[USR_STACK_SIZE_ALL / 4] sec_used(.ustack);

static int _sys_heap_space[SYS_HEAP_SIZE / 4] sec_used(.sec_sys_heap);//最少占用
static int _bt_nk_ram_min[BT_NK_RAM_SIZE_ALL / 4] sec_used(.sec_bt_nk_ram);//最少占用
static int _bt_nv_ram_min[BT_NV_RAM_SIZE_ALL / 4] sec_used(.sec_bt_nv_ram);//最少占用

Source: app_main.c

设计意图:SYS_STACK_SIZE_ALL(系统栈)、USR_STACK_SIZE_ALL(用户栈)、SYS_HEAP_SIZE(堆)、BT_NK_RAM_SIZE_ALL / BT_NV_RAM_SIZE_ALL(蓝牙 NK/NV RAM)这些容量宏在板级配置中定义,将"多少内存给系统、多少给蓝牙"的决定权上移给板级配置,应用层只负责把宏展开成实际的静态数组。

app_main() 是透传应用(以及 SDK 中所有 demo 应用共用)的 C 入口,先打印 RAM 分配信息,再按配置决定是否检查开机键与低电压检测,最后把控制权交给状态机:

void app_main()
{
    log_info(">>>>>>>>>>>>>>>>>>>>app_main...\n");

    log_info("nk_malloc: %08x,%04x, nv_malloc: %08x,%04x", NK_RAM_MALLOC_START_ADDR, NK_RAM_MALLOC_SIZE,
             NV_RAM_MALLOC_START_ADDR, NV_RAM_MALLOC_SIZE);
    log_info("sstack:size,top= %04x, %08x,ustack:size,top= %04x, %08x", sizeof(_sstack_space), _sstack_top, sizeof(_ustack_space), _ustack_top);

#if TCFG_POWER_ON_NEED_KEY
    check_power_on_key();
#endif

#if TCFG_SYS_LVD_EN
    app_power_vbat_check();
#endif

    main_application_operation_state(NULL, APP_STA_START);
}

Source: app_main.c

应用分支选择(CONFIG_APP_*)

SDK 使用同一套 app_main.c 支撑多个 demo(透传、dongle、idle、非连接 2.4G、多连接、AT 透传),分支由编译宏决定。main_app_get_name() 是分支选择的唯一入口:

static void main_app_get_name(struct intent *it)
{
    init_intent(it);
// 选择应用分支
#if CONFIG_APP_LE_TRANS
    it->name = "le_trans";
    it->action = ACTION_LE_TRANS_MAIN;

#elif CONFIG_APP_DONGLE
    it->name = "dongle";
    it->action = ACTION_DONGLE_MAIN;

#elif CONFIG_APP_IDLE
    it->name = "idle";
    it->action = ACTION_IDLE_MAIN;

#elif CONFIG_APP_NONCONN_24G
    it->name = "nonconn_24g";
    it->action = ACTION_NOCONN_24G_MAIN;

#elif CONFIG_APP_MULTI
    it->name = "multi_conn";
    it->action = ACTION_MULTI_MAIN;

#elif CONFIG_APP_AT_CHAR_COM
    it->name = "at_com";
    it->action = ACTION_AT_COM;

#else
    ASSERT(0, "no app!!!");
#endif
}

Source: app_main.c

这段代码揭示了"意图(intent)+ 动作(action)"的应用切换机制:状态机不直接调用函数,而是通过 struct intent 携带应用名与动作码,由 main_application_operation_state() 统一分发。这样新增一个应用只需:① 在配置头文件中定义新的 CONFIG_APP_* 宏;② 在 main_app_get_name() 中加入分支;③ 在对应应用的状态机中处理 APP_STA_* 状态。

透传数据通路

AT 透传示例将数据通路拆分为两条方向相反的链路,均以 UART 为物理边界:

flowchart LR
    subgraph sg_Down["上行(设备 → 对端)"]
        U1["UART 接收"] --> C1["at_char_uart<br/>帧解析"]
        C1 --> S1["ble_at_char_server<br/>GATT Notify"]
        S1 --> P1["对端设备/手机"]
    end

    subgraph sg_Up["下行(对端 → 设备)"]
        P2["对端设备/手机"] --> C2["ble_at_char_server<br/>GATT Write 回调"]
        C2 --> S2["at_char_cmds<br/>AT 命令解析"]
        S2 --> U2["UART 发送"]
    end

    BLE["BLE 空中链路"] -.-> P1
    P2 -.-> BLE
  • 上行:外部数据从 UART 进入,经 at_char_uart 按帧组织后,由 ble_at_char_server 通过 GATT Notify 推送给已连接的 peer。
  • 下行:peer 通过 GATT Write 写入,ble_at_char_server 回调触发 at_char_cmds 的 AT 命令解析,最终结果经 UART 输出。

该通路的模块划分(at_char_uart、at_char_cmds、ble_at_char_server、ble_at_char_client 各自独立成文件)体现了关注点分离:串口协议、命令语义、GATT 承载三者可独立修改,互不耦合。

AT 透传示例(examples/at_char_com)

app_at_char_com.c 是 AT 透传示例的应用主体,整体被 #if CONFIG_APP_AT_CHAR_COM 包裹,只有开启了该宏的工程才会编译这段代码。

蓝牙启动序列

atchar_bt_start() 展示了 SDK 蓝牙初始化的固定四步:配置 PLL 参数 → 协议栈预启动 → 解析配置文件 → 初始化协议栈:

static void atchar_bt_start()
{
    uint32_t sys_clk =  clk_get("sys");
    bt_pll_para(TCFG_CLOCK_OSC_HZ, sys_clk, 0, 0);

    btstack_ble_start_before_init(NULL, 0);

    cfg_file_parse(0);
    btstack_init();
}

Source: app_at_char_com.c

  • bt_pll_para():根据系统时钟配置蓝牙 PLL,保证 RF 时序与系统时钟同步;
  • btstack_ble_start_before_init():在初始化前启动协议栈任务,注册必要的系统资源;
  • cfg_file_parse(0):解析用户配置区(如配对信息、厂商信息等);
  • btstack_init():正式初始化 BLE 协议栈,注册 GATT profile。

应用主循环

应用启动函数先设置系统时钟、初始化蓝牙,随后进入永真循环,从消息队列取消息并交给 app_comm_process_handler() 分发:

static void atchar_app_start()
{
    log_info("=======================================");
    log_info("-------------atchar_com demo---------------");
    log_info("=======================================");

    log_info("app_file: %s", __FILE__);

    clk_set("sys", TCFG_CLOCK_SYS_HZ);
    clk_set("lsb", TCFG_CLOCK_LSB_HZ);

    clock_bt_init();
    atchar_bt_start();

    int msg[4]   = {0};
    while (1) {
        get_msg(sizeof(msg) / sizeof(int), msg);
        app_comm_process_handler(msg);
    }
}

Source: app_at_char_com.c

设计要点:

  • clk_set("sys", ...) 与 clk_set("lsb", ...) 在应用层显式设定系统时钟与低功耗时钟,保证后续 BT 初始化时的时钟依赖已就绪;
  • get_msg() 是阻塞式取消息,取到后由 app_comm_process_handler() 统一分发。AT 命令、UART 数据、BLE 事件都在这里被路由到对应模块;
  • 该循环永不退出,应用退出仅通过软关机(app_power_set_soft_poweroff)路径实现。

状态机

应用状态机与 SDK 的 struct application 框架绑定,本示例处理 APP_STA_CREATE、APP_STA_START、APP_STA_PAUSE 等状态。APP_STA_START 中依据 intent 的 action 进入 atchar_app_start():

static int atchar_state_machine(struct application *app, enum app_state state, struct intent *it)
{
    switch (state) {
    case APP_STA_CREATE:
        break;

    case APP_STA_START:
        if (!it) {
            break;
        }
        switch (it->action) {
        case ACTION_AT_COM:
            atchar_app_start();
            break;
        }
        break;

    case APP_STA_PAUSE:
        break;
    ...

Source: app_at_char_com.c

源码在 APP_STA_PAUSE 之后还有其余状态与消息处理分支(本次文档未逐行展示),完整实现请直接阅读源文件。

核心时序流程

sequenceDiagram
    participant HW as 硬件上电
    participant AM as app_main
    participant SM as 应用状态机
    participant AS as atchar_app_start
    participant BT as btstack
    participant ML as 消息循环
    participant UR as UART
    participant GS as GATT 服务/客户端

    HW->>AM: 复位进入 app_main
    AM->>AM: 检查开机键 / 低电压
    AM->>SM: main_application_operation_state(APP_STA_START)
    SM->>SM: main_app_get_name 选择分支
    SM->>AS: ACTION_AT_COM
    AS->>AS: clk_set 系统/低功耗时钟
    AS->>BT: bt_pll_para + btstack_ble_start_before_init
    AS->>BT: cfg_file_parse + btstack_init
    AS->>ML: 进入 get_msg 循环
    UR->>ML: UART 数据事件消息
    ML->>GS: app_comm_process_handler 分发
    GS-->>UR: 透传结果 / AT 应答

时序上值得注意的两点:

  1. 初始化顺序有严格依赖:时钟 → BT PLL → 协议栈任务 → 配置解析 → 协议栈初始化,任何一步提前都会导致蓝牙无法正常工作。
  2. 初始化完成后立即进入消息循环:后续所有业务(包括 GATT 连接、UART 收发)都通过消息驱动,因此应用层代码无需关心中断上下文,降低编写难度。

低功耗与软关机

透传设备常驻 UART,低功耗策略需要兼顾"省电"与"随时可被串口数据唤醒"。示例通过三个函数组合实现:

软关机前先断链

void atchar_set_soft_poweroff()
{
    log_info("set_soft_poweroff\n");
#if (TCFG_LOWPOWER_PATTERN == SOFT_MODE)
    atchar_app_is_active = 1;
#endif
    //必须先主动断开蓝牙链路,否则要等链路超时断开
    btstack_ble_exit(0);
    //延时,确保BT退出链路断开

    if (ble_comm_dev_is_connected(GATT_ROLE_SERVER) || ble_comm_dev_is_connected(GATT_ROLE_CLIENT)) {
#if (TCFG_LOWPOWER_PATTERN == SOFT_MODE)
        //soft 方式非必须等链路断开
        sys_timeout_add(NULL, app_power_set_soft_poweroff, WAIT_DISCONN_TIME_MS);
#elif (TCFG_LOWPOWER_PATTERN == SOFT_BY_POWER_MODE)
        //must wait disconn
        app_power_soft.wait_disconn = 1;
#endif
    } else {
        app_power_set_soft_poweroff(NULL);
    }
}

Source: app_at_char_com.c

该函数体现了低功耗模式的两种策略差异:

  • SOFT_MODE:软关机不强制等待链路断开,通过 sys_timeout_add 延迟 WAIT_DISCONN_TIME_MS 后执行,期间链路自然断开即可;
  • SOFT_BY_POWER_MODE:必须等链路断开,置位 app_power_soft.wait_disconn = 1 让电源管理模块在断开事件到达后再执行关机。

UART 唤醒与低功耗切换

void at_char_wake_up_set(P33_IO_WKUP_EDGE edge)
{
    if (!atchar_app_is_active) {
        atchar_app_is_active = 1;
        sys_timeout_add(NULL, at_go_low_power, 1000);
    }
}

Source: app_at_char_com.c

  • at_char_wake_up_set() 由 UART 唤醒中断(P33 IO 边沿)触发,把应用标记为活跃,并用 1 秒超时定时器安排回落低功耗——即"UART 发数唤醒一秒";
  • at_go_low_power() 在超时回调中检查 atchar_force_wakeup:若期间曾调用 at_set_low_power_mode()(主动退出低功耗),则清标志并跳过本次进入低功耗,避免刚唤醒就被立刻休眠;
  • at_set_low_power_mode(enable) / at_get_low_power_mode() 提供外部模块查询/控制低功耗状态的接口。

这套机制的核心权衡是:唤醒必须快(IO 边沿中断),但进入低功耗必须稳(防抖 + 延时确认),因此在"立即休眠"与"永久活跃"之间用 1 秒窗口做缓冲。

配置选项

透传应用的配置分散在三层:应用分支宏(决定编译哪个应用)、板级配置(内存/时钟/低功耗)与库配置(协议栈裁剪)。下表汇总本次源码阅读中确认的配置项。

应用分支宏(app_main.c 选择逻辑)

配置项类型默认行为说明
CONFIG_APP_LE_TRANS宏0使能 LE 透传应用(le_trans / ACTION_LE_TRANS_MAIN)
CONFIG_APP_DONGLE宏0使能 dongle 应用(dongle / ACTION_DONGLE_MAIN)
CONFIG_APP_IDLE宏0使能 idle 应用(idle / ACTION_IDLE_MAIN)
CONFIG_APP_NONCONN_24G宏0使能非连接 2.4G 应用(nonconn_24g / ACTION_NOCONN_24G_MAIN)
CONFIG_APP_MULTI宏0使能多连接应用(multi_conn / ACTION_MULTI_MAIN)
CONFIG_APP_AT_CHAR_COM宏0使能 AT 透传应用(at_com / ACTION_AT_COM),本页核心示例
ACTION_AT_COM枚举-main_app_get_name() 为 AT 透传赋的动作码,状态机据此进入 atchar_app_start()

注意:上述分支宏按 #if / #elif 顺序互斥判断,一次编译只能选中一个应用。

板级与电源配置

配置项类型默认值说明
TCFG_POWER_ON_NEED_KEY宏0开机是否需要按键确认;开启后 check_power_on_key() 等待长按,松开则软关机
TCFG_SYS_LVD_EN宏0使能系统低电压检测,app_power_vbat_check() 在开机时执行
TCFG_LOWPOWER_PATTERN枚举-低功耗模式:SOFT_MODE(软关机不等待断链)或 SOFT_BY_POWER_MODE(必须等待断链)
TCFG_CLOCK_SYS_HZ / TCFG_CLOCK_LSB_HZ数值板级定义系统时钟 / 低功耗时钟,atchar_app_start() 中 clk_set 使用
SYS_STACK_SIZE_ALL / USR_STACK_SIZE_ALL数值板级定义系统栈 / 用户栈总大小,决定 .sstack / .ustack 数组长度
SYS_HEAP_SIZE数值板级定义系统堆大小,决定 .sec_sys_heap 数组长度
BT_NK_RAM_SIZE_ALL / BT_NV_RAM_SIZE_ALL数值板级定义蓝牙 NK/NV RAM 大小,决定 .sec_bt_nk_ram / .sec_bt_nv_ram
WAIT_DISCONN_TIME_MS数值示例定义软关机时等待链路断开的延时,经 sys_timeout_add 使用

测试与日志配置

配置项类型默认值说明
TEST_ATCHAR_AUTO_BT_OPEN宏1测试用:应用启动时自动打开蓝牙
LOG_TAG / LOG_TAG_CONST宏"[AT_COM]" / AT_COM日志标签,配合 log_config.c 的等级开关过滤输出

库配置(config/ 目录)

文件管理内容
lib_btstack_config.cBLE 协议栈特性裁剪(GATT、配对、功耗相关开关)
lib_btctrler_config.c蓝牙控制器特性(RF、连接参数等)
lib_profile_config.cGATT profile 注册与裁剪
lib_driver_config.c驱动模块裁剪
lib_system_config.c系统任务/资源配置
lib_update_config.cOTA 升级配置
log_config.c日志等级与模块开关

API 参考

以下为透传应用源码中确认的关键函数。

void app_main(void)

应用 C 入口。打印内存布局信息,按配置执行开机键检查与低电压检测,最后调用 main_application_operation_state(NULL, APP_STA_START) 启动状态机。

参数: 无

返回: 无(永不返回,控制权移交状态机/消息循环)

static void main_app_get_name(struct intent *it)

根据 CONFIG_APP_* 编译宏选择应用分支,向 struct intent 写入应用名与动作码。

参数:

  • it(struct intent *):输出参数,init_intent(it) 初始化后写入 name 与 action

返回: 无

异常: 若无任何 CONFIG_APP_* 被定义,触发 ASSERT(0, "no app!!!")

static int atchar_state_machine(struct application *app, enum app_state state, struct intent *it)

AT 透传应用状态机,处理 APP_STA_CREATE / APP_STA_START / APP_STA_PAUSE 等状态。

参数:

  • app(struct application *):应用实例
  • state(enum app_state):目标状态
  • it(struct intent *):intent,APP_STA_START 时依据 it->action == ACTION_AT_COM 进入 atchar_app_start()

返回: 状态机处理结果(int)

static void atchar_app_start(void)

应用主流程:设置系统/低功耗时钟 → clock_bt_init() → atchar_bt_start() → 进入 get_msg() + app_comm_process_handler() 永真消息循环。

参数: 无 返回: 无

static void atchar_bt_start(void)

蓝牙初始化序列:bt_pll_para() → btstack_ble_start_before_init() → cfg_file_parse(0) → btstack_init()。

参数: 无 返回: 无

void atchar_set_soft_poweroff(void)

软关机入口。先 btstack_ble_exit(0) 主动断开链路;若仍处于连接态,按 TCFG_LOWPOWER_PATTERN 决定延时关机(SOFT_MODE)或等待断开事件(SOFT_BY_POWER_MODE);未连接则直接 app_power_set_soft_poweroff(NULL)。

参数: 无 返回: 无

void at_set_low_power_mode(uint8_t enable)

外部模块控制低功耗状态:enable 为真时置 atchar_force_wakeup,阻止定时器把应用拉回低功耗。

参数:

  • enable(uint8_t):1 退出低功耗,0 允许进入

返回: 无

uint8_t at_get_low_power_mode(void)

查询当前是否处于低功耗模式。

参数: 无 返回: !atchar_app_is_active,非 0 表示处于低功耗

static void at_go_low_power(void *priv)

sys_timeout_add 超时回调。若 atchar_force_wakeup 已置位则清标志并返回(防抖),否则 atchar_app_is_active = 0 进入低功耗。

参数:

  • priv(void *):超时回调私有参数,示例中传 NULL

返回: 无

void at_char_wake_up_set(P33_IO_WKUP_EDGE edge)

UART 唤醒入口(P33 IO 边沿触发)。若当前处于低功耗,置活跃标志并用 1 秒超时安排回落低功耗。

参数:

  • edge(P33_IO_WKUP_EDGE):唤醒边沿类型

返回: 无

故障模式、边界情况与并发

故障模式

场景表现处理方式(源码依据)
软关机时 BLE 仍处于连接态若直接断电,对端会等待链路超时,体验差atchar_set_soft_poweroff() 先调用 btstack_ble_exit(0) 主动断开,再按模式决定等待策略
SOFT_MODE 下链路未及时断开软关机被延时执行通过 sys_timeout_add(NULL, app_power_set_soft_poweroff, WAIT_DISCONN_TIME_MS) 延时补偿
SOFT_BY_POWER_MODE 下链路未断开必须等待断开事件置位 app_power_soft.wait_disconn = 1,由电源管理在断开后继续关机
刚被 UART 唤醒又立即被定时器休眠数据可能来不及处理at_go_low_power() 检查 atchar_force_wakeup 防抖,跳过本次休眠
多个 CONFIG_APP_* 同时开启编译告警/行为不确定#if / #elif 顺序判断,建议每次只使能一个应用分支

边界情况

  • 唤醒窗口:at_char_wake_up_set() 使用 1 秒超时(sys_timeout_add(..., 1000))作为活跃窗口,窗口内再次收到唤醒只重置标志、不重复添加定时器;窗口结束后若无强制唤醒标志则回落低功耗。
  • 取消息大小:atchar_app_start() 中 int msg[4],get_msg(sizeof(msg) / sizeof(int), msg) 按 4 个 int 读取消息,消息结构超出会截断,属于框架约定。
  • 开机键长按:TCFG_POWER_ON_NEED_KEY 开启时,check_power_on_key() 循环清狗并延时 10ms 轮询按键,超过 70 次(约 700ms)才确认开机,期间松开立即软关机。

并发与一致性

透传应用采用单消息循环串行模型,这是其并发设计的关键:

  • app_comm_process_handler(msg) 在单线程消息循环中被调用,BLE 回调、UART 事件最终都转为消息排队处理,避免了多任务并发修改共享缓冲;
  • 中断侧(如 UART 唤醒、BLE RX)只做最小工作(投递消息/置标志),耗时逻辑全部落在循环线程;
  • 中断优先级在 app_main.c 中显式配置:IRQ_BLE_RX_IP = 5、IRQ_BTSTACK_MSG_IP = 4、IRQ_BT_TIMEBASE_IP = 6、IRQ_TICKTMR_IP = 3 等,保证蓝牙事件与系统节拍的中断延迟可控;
  • 低功耗状态由 atchar_app_is_active 单一标志位管理,读(at_get_low_power_mode)写(at_set_low_power_mode / at_go_low_power)都在消息上下文或中断回调中完成,通过 atchar_force_wakeup 防止状态翻转竞争。

性能与运维注意事项

  • 内存静态化:系统栈、堆、蓝牙 RAM 均为编译期静态数组(sec_used 链接段),运行时无动态堆碎片风险;调整容量需要同步修改板级宏并重新链接。
  • 时钟依赖:atchar_bt_start() 前必须完成 clk_set("sys"/"lsb") 与 clock_bt_init(),否则 BT PLL 参数与协议栈初始化可能失败;修改系统时钟时需同步 TCFG_CLOCK_OSC_HZ 等 PLL 参数。
  • 透传吞吐:透传吞吐受 GATT MTU、连接间隔与 UART 波特率共同限制;吞吐调优属于 BLE 透传服务页面的主题,本页不做展开。
  • 日志:LOG_TAG 为 [AT_COM],log_config.c 可裁剪各模块日志等级,量产时建议关闭 LOG_DUMP_ENABLE 级别输出以降低串口占用。

扩展点

  1. 新增应用分支:在板级配置定义新 CONFIG_APP_* 宏,在 main_app_get_name() 增加 #elif 分支,在对应模块实现 atchar_state_machine 风格的状态机即可,无需修改 app_main() 主体。
  2. 新增示例:在 apps/demo/transfer/examples/ 下新建目录,参考 at_char_com 组织 app_*.c/h,复用 app_comm_process_handler 消息分发。
  3. 自定义 AT 命令:扩展 at_char_cmds 模块,新增命令字与解析分支,数据通路(UART ↔ GATT)无需改动。
  4. 低功耗策略定制:通过 at_set_low_power_mode() / at_get_low_power_mode() 接口接入外部策略(如按键、传感器事件),或在 atchar_set_soft_poweroff() 中调整断链等待策略。
  5. 板级移植:复制 board/bd47 并按新板型修改 board_*_cfg.h 与 board_*.c,修改内存宏即可移植到其他 AW31N 系列芯片。

相关链接

  • app_main.c(应用入口与状态机)
  • app_at_char_com.c(AT 透传示例主体)
  • app_at_char_com.h(AT 透传示例头文件)
  • board/bd47 板级配置目录
  • config 库配置目录
  • AW31N_transfer.cbp(工程文件)
  • 相关兄弟页面:AT 命令详解、BLE AT 透传 GATT 服务/客户端、UART 透传、HID 透传通道(ble_hogp.c)
Next
多连接与无连接传输