简介:本资源为Dialog Semiconductor DA14585系列蓝牙低功耗SoC专用SDK开发包(v6.0.22.1401),面向嵌入式IoT开发者、可穿戴设备工程师及BLE固件初学者,用于快速构建低功耗蓝牙应用、协议栈移植与硬件驱动开发。压缩包共1441个文件,涵盖352个C源码、776个头文件(.h)、30个Keil工程(.uvprojx/.uvoptx)、47个二进制镜像(.bin/.hex)、22个链接脚本(.sct/.lds)及配套ICF生成脚本、量产测试固件(如prod_test_585.bin)和静态库(da14585_586.a等),完整支撑DA145xx全系芯片的编译、调试与烧录全流程。资源大小15.7MB,结构规范,含示例项目、API文档框架与基础工具链配置。已有471人学习下载,适合需直接上手DA14585 BLE开发、理解SDK目录组织逻辑、复用官方驱动模块及开展量产测试验证的实践型开发者。
1. DA14585 SDK 6.0.22.1401:不是“拿来就能跑”的蓝牙协议栈,而是需要亲手拧紧每一颗螺丝的嵌入式黑匣子
你拿到SDK-6.0.22.1401.zip,解压后看到projects/下密密麻麻的ble_app_开头文件夹,心里一热——“终于有官方例程了!”结果make一敲,报错ERROR: Cannot find DA14585 device in JTAG chain;换台电脑再试,又卡在keil: undefined symbol 'arch_set_sleep_mode';好不容易烧进芯片,手机连不上服务,Wireshark 抓包一看,连 ADV_IND 都没发出来。这不是 SDK,这是套带说明书的迷宫。DA14585 是 Dialog(现 Renesas)推出的超低功耗 BLE SoC,而这个 SDK 版本(6.0.22.1401)是其生命周期中最后一个完整支持 Keil MDK-ARM v5.27+ 与 Segger J-Link V6.42+ 的稳定分支,它不兼容新 IDE 的默认配置,也不自动适配现代 Windows 10/11 的 USB 调试驱动策略。它适合谁?适合正在维护某医疗贴片设备、某工业传感器节点、或某高校低功耗通信课程设计的工程师——你得懂寄存器级唤醒流程、能改.sct分散加载脚本、敢动arch_system.c里的时钟树初始化顺序。它不是教学玩具,是产线级代码基线,所有 BLE 5.0 以下特性(包括私有广播、GATT 多连接、OTA 升级框架)都已固化在ble_stack模块里,但每一块砖都得你自己砌。
2. 从 ZIP 到可烧录 HEX:环境链路必须闭环,缺一不可
2.1 硬件准备:J-Link、DA14585 EVK 与供电的三重校验
DA14585 对调试接口电平极其敏感。常见翻车点不是代码写错,而是硬件握手失败。必须确认三点:
- J-Link 型号为J-Link EDU Mini 或 J-Link BASE(V6.42 或 V6.44 固件);J-Link PRO 或新版 V6.50+ 固件会因 SWD 时序微调导致
JTAG scan chain detection failed; - EVK 板跳线
JP1(VDD_SEL)必须置于3.0V 档(非 1.8V),否则DA14585内部 LDO 无法启动,J-Link 读不到 Device ID; - 使用原装 Micro-USB 数据线(非充电线),且 PC 端 USB 口需提供 ≥500mA 电流——曾有 A 同学用笔记本 USB-C 扩展坞供电,导致
J-Link Commander中exec flash_erase命令执行一半中断,芯片变砖。
提示:执行
JLinkExe -device DA14585 -if SWD -speed 1000后,若返回Found SW-DP with ID 0x0BB11477,说明物理链路通;若卡在Connecting to target via SWD...,立即检查 JP1 和 USB 供电。
2.2 工具链版本锁定:Keil MDK 必须是 v5.27(Build 279)
该 SDK 的build\keil\目录下所有.uvprojx文件均硬编码依赖 Keil v5.27 的 ARMCC 编译器行为。v5.30+ 会触发error: #137: expression must be a modifiable lvalue(因__packed结构体成员对齐规则变更)。安装步骤:
- 卸载所有 Keil 版本;
- 安装
MDK527.exe(官方存档版,非官网最新); - 手动覆盖
ARM\ARMCC\Bin\armcc.exe为armcc.exe.bak,并复制 SDK 包内tools\armcc_v5.27\armcc.exe过去(SDK 自带编译器副本,经 Dialog QA 验证); - 在 Keil →
Options for Target → C/C++ → Misc Controls中添加--c99 --no_multibyte_chars,否则ble_att.h中 Unicode 字符宏报错。
2.3 工程导入与路径修复:三个关键宏定义不能错
打开projects\target_apps\ble\ble_app_peripheral\keil\ble_app_peripheral.uvprojx后,必须手动修正:
Options for Target → C/C++ → Define中,确保含DA14585, __UVISION_VERSION=527, CFG_DEVELOPMENT;Options for Target → Asm → Define中,添加DA14585(汇编层需识别芯片型号);Options for Target → Linker → Scatter File指向projects\target_apps\ble\ble_app_peripheral\keil\scatter\DA14585_scatter.sct—— 此文件定义了 ROM/RAM 分区,若误用DA14531_scatter.sct,keil编译通过但烧录后复位即死机(因ROM_CODE地址越界)。
2.4 编译与烧录全流程命令行验证
即使 Keil GUI 能编译,也建议用命令行复现以排除 IDE 缓存干扰:
# 进入工程目录 cd projects\target_apps\ble\ble_app_peripheral\keil # 调用 Keil 编译器(路径需替换为你的 Keil 安装路径) "C:\Keil_v5\UV4\UV4.exe" -b ble_app_peripheral.uvprojx -t "DA14585" # 生成 HEX(Keil 默认输出 AXF,需额外转换) "C:\Keil_v5\ARM\ARMCC\Bin\fromelf.exe" --i32combined --output ble_app_peripheral.hex ble_app_peripheral.axf # 使用 J-Link 烧录(注意:必须指定 -if SWD -speed 1000) JLinkExe -device DA14585 -if SWD -speed 1000 -autoconnect 1 -CommanderScript "loadfile ble_app_peripheral.hex; r; g; exit"逻辑说明:-b参数强制命令行构建,-t "DA14585"指定目标设备模板;fromelf.exe是 ARM 官方格式转换工具,--i32combined生成 Intel Hex 格式(兼容所有烧录器);J-Link 脚本中r; g;表示复位并运行,避免烧录后需手动按板载 RESET 键。
3. BLE 协议栈初始化失败的五大血泪坑:现象、根因与硬核解法
3.1 现象:main()执行到app_main()就卡死,串口无任何日志
原因:DA14585的SystemInit()函数中,SetSysClock()默认尝试启用外部 32kHz 晶振(XTAL32K),但 EVK 板默认焊接的是内部 RC 振荡器(IRC32K)。若未在system_da14585.c中注释掉CLK->CLK_AMBA_REG |= CLK_AMBA_REG_XTAL32K_EN_Msk;,芯片将无限等待晶振起振超时,进入while(1)。
解决:打开platform\da14585\system\system_da14585.c,定位void SetSysClock(void)函数,在// Enable XTAL32K注释下方,将整段CLK->CLK_AMBA_REG |= ...行用/* */包裹禁用,并取消// Use IRC32K as system clock source下方CLK->CLK_AMBA_REG &= ~CLK_AMBA_REG_XTAL32K_EN_Msk;的注释。
3.2 现象:Keil 编译通过,但 J-Link 烧录时报Error: Flash download failed – Target DLL has been cancelled
原因:SDK 6.0.22.1401 的flash_programmer工程使用旧版JLinkARM.dll(v6.42),而你系统 PATH 中存在 v6.50+ 的同名 DLL,Keil 加载时优先取新版,导致 Flash 算法不匹配。
解决:在 Keil 安装目录C:\Keil_v5\ARM\Flash\下,找到Dialog\DA14585\DA14585.FLM文件,用记事本打开,确认其[COMMON]段中DllName="JLinkARM.dll"未被修改;然后将C:\Keil_v5\ARM\Flash\Dialog\DA14585\添加到系统环境变量PATH的最前端,并重启 Keil。
3.3 现象:手机扫描到设备名(如DA14585_PERIPHERAL),但连接后立即断开,Log 显示ATT_ERROR_INSUFFICIENT_AUTHENTICATION
原因:ble_app_peripheral示例默认启用配对(Bonding),但user_config.h中CFG_SEC_REQ宏设为SECURITY_REQUESTED,而手机端未完成配对流程就发起 GATT 读写。
解决:打开projects\target_apps\ble\ble_app_peripheral\inc\user_config.h,将#define CFG_SEC_REQ (SECURITY_REQUESTED)改为#define CFG_SEC_REQ (SECURITY_NOT_REQUIRED);若需安全连接,必须在app_sec.c中实现app_sec_request_handler()并调用gapc_bond_req_ind(),而非仅靠宏开关。
3.4 现象:ble_app_proximity工程编译报错undefined reference to 'proxm_update_alert_level'
原因:proxm服务依赖ble_service模块,但ble_app_proximity.uvprojx的Options for Target → Linker → Object/Library中未添加ble_service.lib路径。
解决:在 Keil 中右键工程 →Options for Target → Linker → Object/Library→ 点击Add,选择projects\libraries\ble_service\keil\ble_service.lib;同时在C/C++ → Include Paths中添加projects\libraries\ble_service\inc。
3.5 现象:使用ble_app_battery时,ADC 读取电压始终为 0,BATT_LEVEL_UPDATE_INTERVAL设置无效
原因:DA14585的 ADC 通道 0(BATMON)需在arch_system.c中显式使能ANA->ANA_CTRL_REG |= ANA_CTRL_REG_ADC_EN_Msk;,但 SDK 示例中此行被注释。
解决:打开platform\da14585\arch\arch_system.c,在void arch_init(void)函数末尾(arch_ble_init();之后),插入:
// Enable ADC for battery monitoring ANA->ANA_CTRL_REG |= ANA_CTRL_REG_ADC_EN_Msk; // Configure ADC channel 0 for BATMON ANA->ANA_ADC_CTRL_REG = (ANA_ADC_CTRL_REG_ADC_CHN_Msk & (0 << ANA_ADC_CTRL_REG_ADC_CHN_Pos)) | (ANA_ADC_CTRL_REG_ADC_RES_Msk & (2 << ANA_ADC_CTRL_REG_ADC_RES_Pos));参数说明:ADC_CHN=0指定电池监测通道;ADC_RES=2表示 10-bit 分辨率(0=8bit, 1=9bit, 2=10bit),精度越高采样时间越长,此处取平衡值。
4. GATT 服务定制实战:从添加自定义 Characteristic 到 OTA 升级框架打通
4.1 在ble_app_peripheral中注入自定义服务:四步原子操作
假设需添加一个名为MySensor的服务,含Temperature(Read)、Humidity(Notify)两个 Characteristic。
Step 1:定义 UUID 与属性
在projects\target_apps\ble\ble_app_peripheral\inc\user_service.h中添加:
// 128-bit UUID for MySensor service #define MYSENSOR_SERVICE_UUID_128 {0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF,0x00} // 16-bit UUID for Temperature characteristic #define TEMP_CHAR_UUID 0x2A6E // 16-bit UUID for Humidity characteristic #define HUMID_CHAR_UUID 0x2A6FStep 2:声明服务结构体
在user_service.c中定义:
// Temperature Characteristic value (16-bit signed) static uint16_t temp_val = 2500; // 25.00°C // Humidity Characteristic value (16-bit unsigned) static uint16_t humid_val = 4500; // 45.00% // GATT database definition const struct gatt_db_att mysensor_att_db[] = { // Service Declaration [MYSENSOR_IDX_SVC] = {ATT_UUID_16_LEN, ATT_UUID_SERV_PRI, PROPERTY_READ, 0, 0}, // Temperature Characteristic Declaration [MYSENSOR_IDX_TEMP_CHAR] = {ATT_UUID_16_LEN, ATT_UUID_CHAR_DECL, PROPERTY_READ, 0, 0}, // Temperature Characteristic Value [MYSENSOR_IDX_TEMP_VAL] = {ATT_UUID_16_LEN, TEMP_CHAR_UUID, PROPERTY_READ, 0, (uint16_t)&temp_val}, // Humidity Characteristic Declaration [MYSENSOR_IDX_HUMID_CHAR] = {ATT_UUID_16_LEN, ATT_UUID_CHAR_DECL, PROPERTY_READ | PROPERTY_NOTIFY, 0, 0}, // Humidity Characteristic Value [MYSENSOR_IDX_HUMID_VAL] = {ATT_UUID_16_LEN, HUMID_CHAR_UUID, PROPERTY_READ | PROPERTY_NOTIFY, 0, (uint16_t)&humid_val}, // Client Characteristic Configuration Descriptor (for Notify) [MYSENSOR_IDX_HUMID_NTF_CFG] = {ATT_UUID_16_LEN, ATT_UUID_CHAR_CLIENT_CONFIG, PROPERTY_READ | PROPERTY_WRITE_REQ, 0, 0}, };逻辑说明:PROPERTY_NOTIFY必须搭配ATT_UUID_CHAR_CLIENT_CONFIG描述符,否则手机无法开启通知;&temp_val是值地址,SDK 栈通过指针直接读取内存,无需回调函数。
Step 3:注册服务到 BLE 栈
在user_service.c的user_svc_init()函数中:
// Add MySensor service to GATT database struct gatt_svc_desc svc_desc; svc_desc.uuid_type = ATT_UUID_128; memcpy(svc_desc.uuid, MYSENSOR_SERVICE_UUID_128, ATT_UUID_128_LEN); svc_desc.start_hdl = MYSENSOR_IDX_SVC; svc_desc.end_hdl = MYSENSOR_IDX_HUMID_NTF_CFG; gatt_svc_add(&svc_desc, mysensor_att_db, sizeof(mysensor_att_db)/sizeof(struct gatt_db_att));参数说明:start_hdl和end_hdl是服务在 GATT 数据库中的句柄范围,必须与mysensor_att_db[]数组索引严格对应,否则手机读取时返回ATT_ERROR_INVALID_HANDLE。
Step 4:实现 Notify 发送逻辑
在user_service.c中添加:
void mysensor_send_humidity(uint16_t value) { humid_val = value; // Send notification to all subscribed clients struct gatt_notify_req *req = KE_MSG_ALLOC(GATT_NOTIFY_REQ, TASK_ID_GATTM, TASK_ID_GATTM, gatt_notify_req); req->handle = MYSENSOR_IDX_HUMID_VAL; req->length = sizeof(uint16_t); memcpy(req->value, &humid_val, sizeof(uint16_t)); ke_msg_send(req); }调用时机:在 ADC 采样完成中断中调用mysensor_send_humidity(humid_raw)即可触发通知。
4.2 OTA 升级框架复用:ble_app_ota的三大改造点
ble_app_ota是 SDK 内置的空中升级模板,但默认只支持DA14585的主 Flash(0x00000000~0x0001FFFF),需扩展至双 Bank(Bank A/B)以支持无缝升级。
改造点 1:修改 Flash 分区表
编辑projects\target_apps\ble\ble_app_ota\keil\scatter\DA14585_scatter.sct,将ER_FLASH段拆分为:
ER_FLASH_A +0 { *(InRoot$$Sections) .text +0 *(.text) ... *(.data) } ER_FLASH_B 0x00020000 { *(.ota_image) }逻辑说明:ER_FLASH_A存放当前运行固件(0x00000000 起),ER_FLASH_B为 OTA 接收区(0x00020000 起),大小需 ≥ 主程序 HEX 文件尺寸。
改造点 2:启用 Bank 切换标志
在ble_app_ota.c的ota_start()函数中,添加:
// Set Bank B as active after successful OTA NVDS_PUT(NVDS_TAG_OTA_BANK, (void*)&bank_b_flag, sizeof(uint8_t)); // Trigger hardware reset to boot from Bank B NVIC_SystemReset();参数说明:NVDS_TAG_OTA_BANK是 SDK 预留的 NVDS 标签,用于存储启动 Bank 标识;NVDS_PUT将bank_b_flag=1写入 Flash,Bootloader 读取后跳转至 Bank B 执行。
改造点 3:定制 Bootloader 启动逻辑
SDK 未提供源码 Bootloader,但bootloader.bin已预编译在projects\bootloader\da14585\bin\。需用nrfutil工具将其合并到最终 HEX:
# 合并 bootloader + app "C:\Keil_v5\ARM\ARMCC\Bin\fromelf.exe" --i32combined --output bootloader_app.hex bootloader.bin ble_app_ota.hex注意:
bootloader.bin必须与 SDK 版本严格匹配,6.0.22.1401 对应bootloader_da14585_v6.0.22.1401.bin,混用会导致启动失败。
5. 信号链路深度验证:用逻辑分析仪抓取 RF 波形,定位广播/连接失败真因
5.1 硬件连接:PA_OUT 引脚与逻辑分析仪的阻抗匹配
DA14585的 RF 输出引脚PA_OUT(GPIO P0_3)在 2.4GHz 频段输出功率约 +4dBm,直接接逻辑分析仪 50Ω 输入会严重失配,导致波形畸变甚至损坏探头。正确做法:
- 使用10dB 衰减器(50Ω 输入/输出)串联在 PA_OUT 与逻辑分析仪之间;
- 逻辑分析仪通道设置为AC 耦合、500MHz 带宽、1GS/s 采样率;
- 触发条件设为
Rising Edge > 100mV,避免噪声误触发。
5.2 解析广播包时序:从ADV_IND到SCAN_RSP的毫秒级窗口
执行ble_app_peripheral后,用 Saleae Logic 抓取波形,关键观察点:
| 时间点 | 事件 | 正常表现 | 异常表现 |
|---|---|---|---|
| T0 | ADV_IND起始 | 脉冲宽度 ≈ 120μs(含前导码+接入地址) | <100μs:ble_gap_adv_start()未正确配置adv_data |
| T0+1.5ms | SCAN_REQ响应窗口 | 逻辑分析仪显示PA_OUT电平保持高(空闲) | 持续低电平:scan_rsp_data为空或长度超限(≤31字节) |
| T0+2.5ms | SCAN_RSP发送 | 脉冲宽度 ≈ 80μs(含接入地址+响应数据) | 无脉冲:gapc_scan_req_ind()未被调用,检查CFG_SCAN_RSP_EN宏是否启用 |
提示:若
ADV_IND正常但SCAN_RSP缺失,在app_gap.c中检查gapc_scan_req_ind_handler()是否返回KE_MSG_CONSUMED,否则消息被丢弃。
5.3 连接建立阶段 RF 波形诊断:CONNECT_REQ与LL_DATA的握手节奏
成功连接后,PA_OUT应呈现规律性短脉冲(每个连接事件一次):
- 连接事件间隔(CONN_INTERVAL):SDK 默认 32ms(0x0020),波形上相邻脉冲间距应为 32±2ms;
- 每个事件内数据包数:
DA14585支持单事件多包(Multi-PDU),若conn_param_update_req中max_tx_num设为 3,则一个连接事件内应出现 3 组脉冲(每组含 LL_HEADER+PAYLOAD); - 异常模式:脉冲间隔忽长忽短(如 32ms→120ms→32ms),表明
LL层发生Connection Supervision Timeout,需检查conn_sup_to参数(单位:10ms),默认 400(即 4s),若设为 100(1s)则易超时。
5.4 用 Wireshark + nRF Sniffer 验证协议栈行为:比逻辑分析仪更懂 BLE
逻辑分析仪看“有没有”,Wireshark 看“对不对”。需配合 Nordic nRF52840 Sniffer Dongle:
- 将 Sniffer Dongle 插入 PC,运行
nRF Sniffer for Bluetooth LE; - 在 Wireshark 中选择
nRF52840接口,Filter 输入btle.advertising_header.pdu_type == 0x00(只看 ADV_IND); - 关键字段验证:
Advertising Address:应与DA14585的 BD_ADDR(烧录时写入 OTP)一致;Advertising Data:Flags字节必须含LE General Discoverable Mode(0x02),否则 iOS 设备不扫描;Company Identifier:若使用自定义 UUID,AD Structure Type应为0xFF(Manufacturer Data),且Company ID与你注册的 IEEE OUI 匹配。
从那以后我每次调试 BLE 连接问题,都强制走一遍“逻辑分析仪看 RF 波形 → Wireshark 看协议字段 → Keil 查看ke_msg_queue状态”三步链路。因为DA14585的 BLE 栈是高度状态机驱动的,任何一个环节的时序偏差(比如gapc_connection_req_ind()处理延迟 5ms)都会导致整个连接流程坍塌,而这些细节,永远藏在波形和协议包的毫秒级抖动里。希望帮到你。
本文还有配套的精品资源,点击获取