杰里AC695N蓝牙音频SoC开发实战:从环境搭建到Soundbox应用

杰里AC695N蓝牙音频SoC开发实战:从环境搭建到Soundbox应用 1. 项目概述初识杰里695N与Soundbox如果你正在寻找一款高性价比、开发便捷且功能强大的蓝牙音频SoC片上系统来打造你的智能音箱、便携式蓝牙音箱或者任何需要高品质音频处理与无线连接的产品那么杰里科技的AC695N系列绝对是一个绕不开的选项。我最近深度体验了其1.0版本的SDK感觉就像拿到了一把趁手的瑞士军刀功能齐全上手路径清晰。这个系列芯片在消费级音频市场尤其是我们常说的“Soundbox”音箱方案领域凭借其集成度高、功耗控制优秀和开发资源相对丰富已经成为了许多方案公司和初创团队的首选。简单来说杰里695N系列是一颗集成了高性能CPU、DSP、蓝牙5.0或更高版本双模射频、音频编解码器、电源管理以及丰富外设接口的单芯片。这意味着你不需要再额外搭配复杂的蓝牙模块、音频DAC和功放一颗芯片就能搞定从无线连接到声音播放、从按键检测到电量显示的大部分核心功能极大地简化了硬件设计和降低了BOM成本。而1.0 SDK则是我们与这颗芯片“对话”、让它按照我们的想法工作的软件工具箱。本次快速入门我将带你从零开始搭建开发环境跑通第一个Demo并理解其基本的工程架构让你能快速迈出基于695N进行产品开发的第一步。2. 开发环境搭建与工具链解析工欲善其事必先利其器。开发杰里695N的第一步就是准备好所有必要的软件工具。这个过程可能会遇到一些小坑但按照步骤来其实非常顺畅。2.1 核心工具获取与安装杰里的开发主要依赖于其官方的集成开发环境IDE和编译工具链。通常你需要从杰里的官方或授权渠道获取以下几个核心组件Jerry IDE这是基于Eclipse定制的专用开发环境已经集成了代码编辑、工程管理、编译、下载和调试的一体化界面。对于新手来说使用官方IDE能避免大量环境配置的麻烦。安装过程就是标准的Windows安装程序一路“下一步”即可注意安装路径不要包含中文或特殊字符。SDK开发包这就是我们所说的1.0 SDK。它是一个压缩包里面包含了芯片的所有底层驱动库、蓝牙协议栈、音频处理算法、以及大量的示例工程。解压后你会看到apps,cpu,drivers,include等目录这些构成了我们开发的基础。烧录与调试工具通常指一个USB转串口的烧录器如JLINK OB或其他兼容的调试器及其对应的PC端驱动。这个工具负责将我们编译好的程序下载到芯片的Flash中并支持在线调试设置断点、查看变量等。驱动安装成功后在设备管理器中能看到对应的COM端口。注意务必确认你获取的SDK版本与你的芯片型号如AC695N1A完全匹配。不同子型号的芯片在内存大小、外设配置上可能有细微差别使用不匹配的SDK可能导致编译失败或运行异常。2.2 工程导入与初步配置安装好IDE和SDK后我们开始创建第一个工程。最快捷的方式不是从零新建而是导入一个现有的示例工程进行修改。打开IDE导入示例工程在Jerry IDE中选择File-Import-General-Existing Projects into Workspace。然后浏览到你解压的SDK目录下的apps文件夹里面会有诸如demo_ble_audio、demo_uart、demo_key等示例。我们选择一个最简单的比如demo_led或demo_hello如果有的话作为起点。勾选“Copy projects into workspace”是个好习惯这样不会污染原始的SDK目录。认识工程结构导入后在IDE的Project Explorer中你会看到工程目录。关键文件夹包括src存放用户应用层源代码.c文件的地方你的主要逻辑代码就在这里。inc存放头文件.h。board板级支持包包含与你具体硬件板子相关的配置如LED引脚定义、按键引脚定义、晶振频率等。这是你需要根据自己硬件修改的第一个地方。output编译后生成的二进制文件.bin或.hex会放在这里用于烧录。配置编译目标在工程上右键选择Properties-C/C Build。在Builder Settings中确保Build location指向正确的输出目录。更重要的是在Tool Chain Editor中确认选择的工具链是杰里提供的交叉编译工具链如Jerry GCC。完成这些你的开发环境就基本就绪了。接下来我们可以尝试编译一下这个导入的示例工程点击IDE上的“Build”按钮通常是一个小锤子图标。如果一切顺利你会在Console窗口看到编译成功的提示并在output文件夹下找到生成的可烧录文件。3. SDK框架与关键目录深度解析仅仅能编译还不够要高效开发必须理解SDK的框架设计。杰里695N的SDK采用了一种分层架构将硬件无关的应用逻辑、硬件相关的驱动、以及蓝牙协议栈等核心系统分离开这有利于代码的复用和维护。3.1 核心目录功能剖析让我们深入SDK的根目录看看每个文件夹的职责apps/这是应用开发的“主战场”。所有你的项目工程都位于此目录或它的子目录下。每个工程文件夹都代表一个独立的可执行程序。SDK提供的丰富示例是你学习的最佳资料。cpu/包含芯片内核相关的启动文件、中断向量表、底层初始化代码和系统时钟配置。这部分代码通常由芯片原厂提供除非有特殊需求否则不建议用户修改。它负责芯片上电后最基础的硬件环境搭建。drivers/设备驱动库。这是与硬件打交道最频繁的层。里面按模块细分了GPIO通用输入输出、UART串口、I2C、SPI、PWM、ADC、音频CODEC、Flash操作等所有外设的驱动API。当你需要控制一个LED灯或者读取一个按键状态时调用的函数就来源于此。include/全局头文件目录。包含了所有驱动、协议栈、系统服务的API声明和通用数据类型定义。在你的代码中#include相关头文件才能使用对应的函数。system/系统服务层。包含任务调度、内存管理、消息队列、定时器等操作系统核心组件虽然它可能不是一个完整的RTOS但提供了类似的服务。蓝牙应用的事件处理、用户任务的定时触发都依赖于这个层。bt_stack/蓝牙协议栈。这是SDK中最核心和复杂的部分之一实现了蓝牙经典BR/EDR和低功耗BLE的协议。它处理所有无线连接、配对、数据收发等底层通信。应用层通过一系列回调函数和API接口与协议栈交互。third_party/可能包含一些第三方库比如特定的音频解码库MP3、AAC、语音唤醒引擎或其他增值算法。理解这个结构后当你需要实现一个功能时你就能快速定位到该去哪个目录下查找资料或调用接口。例如要播放一个提示音你可能需要查看drivers/audio下的代码要修改蓝牙名称则需要查看bt_stack中关于设备配置的部分。3.2 应用工程内的核心文件在一个具体的应用工程如apps/demo_audio_player内有几个文件至关重要main.c程序的唯一入口。这里会调用系统初始化函数然后创建一个主任务或进入主循环。你的应用初始化代码如创建按键检测任务、初始化音频设备通常从这里开始。app_config.h应用配置文件。这是你需要频繁修改的第二个地方。在这里你可以通过宏定义来开启或关闭某些功能模块例如#define CONFIG_BT_ENABLE 1表示启用蓝牙功能#define CONFIG_AUDIO_DAC_ENABLE 1表示启用音频输出。合理配置此文件可以优化最终固件的大小和功能。board/board_AC695X_audio_demo.c或类似名称板级配置文件。这是与你的硬件强相关的文件。你需要根据实际原理图修改里面的引脚定义。比如你的板子上的播放/暂停按键接在GPIOA5上而示例工程定义在GPIOB2那么你必须将其修改为#define BTN_PLAY_PAUSE_PIN GPIOA5。错误配置会导致硬件功能失效。4. 从零实现一个基础功能蓝牙连接与LED指示理论说得再多不如动手实践。让我们以一个最经典的需求为例让设备上电后进入蓝牙可被发现状态当手机连接成功时点亮一个LED断开连接时熄灭LED。这个例子涵盖了GPIO控制、蓝牙事件处理这两个核心知识点。4.1 硬件原理图对接与GPIO驱动使用首先假设你的开发板上有一颗LED连接在芯片的GPIOB4引脚且为高电平点亮LED阳极接GPIO阴极接地。修改板级配置找到你的工程下的board.c或board_xxx.c文件。添加或修改LED的引脚定义。// 在文件开头的宏定义区域添加 #define LED_BT_STATUS_PIN GPIOB4初始化GPIO在main.c的某个初始化函数中例如void board_init()或你自己创建的函数配置该引脚为输出模式并初始化为低电平熄灭。#include gpio.h // 包含GPIO驱动头文件 void bt_status_led_init(void) { gpio_set_direction(LED_BT_STATUS_PIN, GPIO_DIR_OUT); // 设置为输出 gpio_write(LED_BT_STATUS_PIN, 0); // 输出低电平LED灭 }控制函数封装为了方便我们可以写两个简单的函数来控制LED。void bt_led_on(void) { gpio_write(LED_BT_STATUS_PIN, 1); // 高电平点亮 } void bt_led_off(void) { gpio_write(LED_BT_STATUS_PIN, 0); // 低电平熄灭 }记得在头文件中声明这些函数。实操心得GPIO驱动是基础中的基础。务必查阅drivers/gpio.h头文件了解所有可用的API如gpio_set_pull_up、gpio_set_die等。对于按键输入还需要配置上拉电阻和中断。另外杰里芯片的GPIO通常有复用功能如果某个引脚被用作UART或I2S就不能再当作普通GPIO使用需要在配置时注意冲突。4.2 蓝牙协议栈事件回调处理杰里的蓝牙协议栈采用事件驱动模型。当蓝牙状态发生变化如连接、断开、开始配对等时协议栈会通过回调函数通知应用层。查找并注册回调函数在SDK中通常会有一个文件如bt_stack_app.c专门处理蓝牙应用层事件。我们需要找到蓝牙连接状态变化的事件回调函数。它可能叫void bt_conn_state_change_callback(uint8_t state)或类似的名字。处理连接事件在这个回调函数中会有一个参数比如state表示当前的连接状态。我们需要根据状态值来控制LED。void bt_conn_state_change_callback(uint8_t state) { switch (state) { case BT_ST_CONNECTED: // 假设这个宏表示已连接 printf(Bluetooth Connected!\n); bt_led_on(); // 连接成功点亮LED break; case BT_ST_DISCONNECTED: // 假设这个宏表示断开连接 printf(Bluetooth Disconnected.\n); bt_led_off(); // 断开连接熄灭LED break; default: break; } }确保回调被注册你需要确认这个回调函数在系统初始化时被正确注册到了协议栈。通常在主初始化函数中会有类似bt_stack_register_conn_state_callback(bt_conn_state_change_callback)的调用。如果找不到可能需要参考其他示例工程看看它们是如何注册事件回调的。完成以上代码后编译、烧录到开发板。给板上电用手机蓝牙搜索设备默认名称通常在app_config.h中定义如CFG_BT_DEVICE_NAME进行配对连接。你应该能看到连接瞬间LED点亮断开后LED熄灭。这就完成了一个完整的“感知-响应”逻辑。5. 音频播放流程初探与关键API对于Soundbox方案音频播放是灵魂。杰里695N的SDK提供了相对完善的音频管理框架。理解其数据流和控制流程至关重要。5.1 音频数据流框架音频播放大致遵循“数据源 - 解码 - 数字处理 - DAC - 输出”的路径。在SDK中这被抽象为几个组件音频输入源Audio Source可以是蓝牙A2DP手机音乐、BLE Audio、LINE-IN线路输入、SD卡中的MP3文件、或者内部提示音Beep。SDK会为每种源创建一个“通道”。解码器Decoder对于压缩格式MP3, AAC, SBC等需要对应的软件解码器将数据还原为PCM脉冲编码调制格式。杰里SDK内置了多种解码器。音频事件管理器Audio Event Manager这是一个中枢负责管理不同音频源之间的优先级和切换逻辑。例如当正在播放蓝牙音乐时插入一个提示音事件管理器会决定是打断音乐播放提示音还是混合播放。数字音频接口DAI与DAC驱动PCM数据通过I2S或类似的数字接口传输给内部的音频编解码器CODEC或外置DAC最终转换为模拟信号输出到喇叭或耳机。5.2 实现一个简单的本地提示音播放播放一个存储在芯片Flash里的简短提示音比如开机“嘀”一声是常见需求。准备音频数据你需要一个单声道或立体声的WAV格式通常为PCM格式音频文件并将其转换为C语言数组。可以使用一些音频转换工具如Audacity配合xxd命令或在线转换工具生成一个const unsigned char beep_data[] { ... };这样的数组放在你的工程里。创建音频通道调用音频API创建一个用于播放提示音的通道。#include “audio.h” // 包含音频管理头文件 int beep_chan_id; beep_chan_id audio_create_audio_channel(AUDIO_SOURCE_BEEP, ...); // 具体参数需参考API文档配置并播放设置该通道的参数采样率、位数、音量等然后将音频数据写入通道并启动播放。audio_set_channel_sample_rate(beep_chan_id, 16000); // 设置采样率需与你的音频数据匹配 audio_set_channel_volume(beep_chan_id, default_volume); // 设置音量 audio_write_data_to_channel(beep_chan_id, beep_data, sizeof(beep_data)); // 写入数据 audio_channel_start(beep_chan_id); // 开始播放处理播放完成事件播放是异步的。你需要注册一个回调函数在播放结束时释放通道资源或者进行下一步操作。void beep_play_finish_callback(int chan_id) { if (chan_id beep_chan_id) { audio_destroy_audio_channel(beep_chan_id); // 播放完毕销毁通道 beep_chan_id -1; printf(Beep play finished.\n); } } // 在创建通道后注册这个回调 audio_register_channel_finish_callback(beep_chan_id, beep_play_finish_callback);这个过程涉及较多的API调用强烈建议你从SDK中已有的音频播放示例如demo_audio_player开始先读懂它的流程再修改成自己需要的功能。直接从头编写容易因参数配置不当导致没有声音或杂音。6. 开发调试实战与常见问题排查开发过程中遇到问题是常态。掌握有效的调试方法能极大提升效率。6.1 日志输出与串口调试最基础也是最强大的调试手段就是串口打印日志。杰里SDK通常已经集成了一个简单的日志系统通过printf重定向到串口。确保串口初始化在board.c的板级初始化函数中确认UART通常是UART0已经被初始化并配置了合适的波特率如115200。使用printf和log_printf在你的代码中可以在关键位置添加printf(“Function XXX is called, value%d\n”, var);。编译烧录后使用串口调试助手如Putty、SecureCRT连接开发板的对应串口引脚TX, RX, GND就能看到打印信息。日志等级控制SDK中可能有不同的日志宏如LOG_INFO,LOG_DEBUG,LOG_WARN,LOG_ERROR。你可以在app_config.h中定义一个全局的日志级别在发布最终版本时关闭调试日志以节省资源。6.2 典型问题与解决方案速查表以下是我在开发初期常遇到的一些问题及解决思路问题现象可能原因排查步骤与解决方案编译失败提示未定义符号1. 相关源文件未加入工程编译列表。2. 头文件路径未包含。3. 对应的功能模块在app_config.h中未启用。1. 在工程属性中检查C/C Build-Settings-Tool Settings-GCC Compiler-Includes确认所有必要的头文件路径已添加。2. 检查app_config.h确保类似CONFIG_XXX_ENABLE的宏被定义为1。3. 在工程中右键Refresh一下确保文件系统同步。程序烧录后无任何反应1. 烧录的引脚接触不良或线序错误。2. 系统时钟配置错误导致芯片未运行。3. 程序在极早期如启动代码就卡死或崩溃。1. 确认烧录器与板子连接牢固TX/RX是否交叉连接。2. 使用示波器测量主晶振是否起振频率是否正确。3.最有效方法在main函数的最开始加一句printf(“Start!\n”);如果串口都看不到这个信息问题很可能在启动或时钟初始化阶段。对比一个确认正常的示例工程的系统初始化代码。蓝牙无法被搜索到1. 蓝牙功能未在配置中启用。2. 蓝牙天线电路或匹配网络有问题。3. 协议栈初始化失败。1. 确认app_config.h中CFG_BT_ENABLE为1。2. 检查原理图确认天线部分电路如π型匹配网络参数是否正确天线是否焊接良好。3. 查看串口日志协议栈初始化是否有错误码输出。有时低电压也会导致射频不稳定。播放音频有杂音或破音1. 音频数据采样率、位深与硬件配置不匹配。2. 音频数据缓冲区处理不当导致溢出或欠载。3. 电源噪声特别是功放部分的电源滤波不足。4. DAC或功放的时钟如I2S的MCLK/BCLK不稳定。1. 核对audio_set_channel_sample_rate设置的采样率是否与音频文件本身一致如16kHz文件设成了44.1kHz。2. 确保向音频通道写入数据的速度能跟上播放消耗的速度。可以在数据写入回调里加日志看缓冲区状态。3. 硬件上在DAC和功放的电源引脚就近增加钽电容和瓷片电容滤波如100uF0.1uF。4. 用示波器测量I2S相关时钟信号看波形是否干净、频率是否准确。按键响应不灵或连击1. GPIO上下拉配置错误应为上拉输入。2. 按键消抖处理太简单或太复杂。3. 按键检测任务优先级过低被其他任务阻塞。1. 确认按键GPIO配置为输入模式并启用内部上拉电阻gpio_set_pull_up。2. 实现一个可靠的软件消抖。常见做法是检测到电平变化后延时10-20ms再次检测如果状态稳定才确认为有效按键。可以在一个定时器中断或高优先级任务中处理。3. 提高按键扫描任务的优先级或者使用GPIO中断方式检测下降沿/上升沿再在中断服务程序ISR中发送消息给任务处理。调试是一个系统性工程需要结合软件日志和硬件测量万用表、示波器综合分析。养成“先确认软件配置再怀疑硬件问题”的习惯从最简单的点灯程序开始每增加一个功能就充分测试能帮你快速定位问题所在。7. 工程优化与进阶开发思路当基本功能跑通后我们就要考虑如何让产品更稳定、更省电、功能更丰富。7.1 功耗优化要点对于便携式音箱续航至关重要。杰里695N提供了多种低功耗模式。识别功耗大户在蓝牙保持连接但无音频流时主要功耗来自蓝牙射频的间歇性监听Sniff模式和CPU的 idle 运行。在深度睡眠时可以关闭大部分外设和时钟。合理配置蓝牙连接参数通过修改蓝牙协议栈的连接间隔Connection Interval、从机延迟Slave Latency等参数可以显著降低平均功耗。参数设置需要在连接稳定性和功耗之间取得平衡这通常需要在手机端和设备端协同调整。利用芯片低功耗模式在无任何操作如播放、按键一段时间后可以让系统进入“休眠”或“深度睡眠”模式。此时只有RTC和少数唤醒源如按键中断、蓝牙主机连接请求保持工作。在SDK中通常有system_sleep()或pmu_enter_sleep_mode()这样的API。关键点进入睡眠前必须妥善保存外设状态并配置好唤醒源唤醒后要恢复必要的硬件初始化。外设电源管理不用的外设模块如额外的传感器I2C、不用的GPIO要及时关闭其时钟或置于高阻态。音频功放在静音时可以将其关断Shutdown。优化功耗是一个反复测试的过程。你需要一个精密的电流计观察设备在不同状态广播、连接、播放、待机、睡眠下的电流消耗然后针对性地调整参数和代码。7.2 功能扩展与集成695N的潜力远不止播放音乐。其丰富的外设和足够的处理能力可以支持很多增值功能语音唤醒与识别可以集成离线的语音唤醒词引擎如“小杰小杰”唤醒后再进行本地简单命令识别或通过蓝牙将语音数据发送到手机APP处理。这需要占用一定的Flash空间和CPU算力。多路音频混合比如在播放蓝牙音乐的同时混合播放本地提示音或LINE-IN输入的声音。这需要深入了解SDK的音频事件管理器和混音器Mixer配置。USB声卡模式除了蓝牙还可以将芯片配置为USB Audio Device插上电脑即被识别为一个USB扬声器/麦克风。这需要在app_config.h中启用USB Audio功能并编写相应的描述符和类请求处理代码。固件升级OTA通过蓝牙或USB实现设备的无线固件升级这对于产品后期维护至关重要。杰里SDK通常支持通过特定的蓝牙服务如DFU Service进行OTA。实现OTA需要设计好Bootloader和应用程序的分区以及可靠的数据校验与更新流程。进行功能扩展时务必先研读SDK中相关的示例代码和API文档。从一个能工作的基础工程出发每次只添加一个功能并进行充分测试是避免项目陷入混乱的最佳实践。