基于炬芯ATS3089X的BLE opus音频传输系统设计

PC 通过 BLE 无线接收 PCM / Opus 音频

更新日期:2026-10-16。目标工程:ATS3089P 开发板 `bt_watch`。

2026-10-16 连接修复:已定位 Windows 旧配对保留、开发板对应 LTK 不可用造成的

`Could not get GATT services: Unreachable`。上位机新增 `repair`、分阶段中文提示和 UTF-8 诊断日志。

本次修复只更新 Python 工具和说明,继续使用下列 v1 固件,无需重新烧录。

1. 功能与使用方式

Windows PC 默认按广播名称 **`zkBLE` 精确过滤**,发现第一块匹配开发板后立即连接。

执行 `record` 或 `download` 时自动完成连接、订阅、配置、开始、接收和保存,不必先手动扫描或填写 MAC。

PC 需要支持 BLE 的蓝牙适配器及正常驱动,开发板需要烧录本次固件并开启 BLE 广播。

无需 USB 数据线、USB CDC、COM 口或串口板。

支持两种用途:

| 用途 | PC 命令 | 开发板行为 | PC 文件 |

| --- | --- | --- | --- |

| 实时麦克风 PCM | `record --format pcm` | ADC0/MIC0,16kHz、16bit、小端、单声道,边录边传 | `audio.pcm`、`audio.wav`、`metadata.json` |

| 实时麦克风 Opus | `record --format opus` | 同样的 MIC PCM,CPU libopus 压缩,16kbps、20ms 帧,边录边传 | 标准 Ogg 封装的 `audio.opus`、`metadata.json` |

| 下载已有录音 | `download --remote-path /NAND:/rec.opus` | 读取 NAND 已有文件,逐字节原样发送 | 原文件名、`metadata.json` |

`record` 默认 Opus、10 秒,时长可设 1~300 秒。板端按采样数自动结束,PC 等待尾包校验。

实时传输不另外写入开发板 NAND;文件下载不重新录音、不重新编码。

这里传送的是应用定义的 BLE GATT 数据,接收软件是本 Python 工具;不是 Windows 蓝牙声卡或标准 LE Audio 音频会话。

本次实时模式固定单 MIC;以前录好的双 MIC PCM 可以原样下载,再按真实双声道参数转 WAV。

2. 固件与上位机安装

烧录:

```text

application/bt_watch/outdir/ats3089p_dev_watch/_firmware/ats3089p_dev_watch_261016_ble_audio_v1.fw

```

同目录有 `_debug.fw` 和 `ats3089p_dev_watch_261016_ble_audio_v1_SHA256.txt`。

需要同时更新固件和 Python 工具。旧固件没有新增的 `1002/1003` 特征,无法只靠更新 Python 实现。

在 PowerShell 进入 `` 工程根目录,然后安装依赖:

```powershell

cd D:\Master\6project\ATS3089C_to_ATS3089P\

python -m pip install -r .\application\bt_watch\tools\ble_audio\requirements.txt

$ble = '.\application\bt_watch\tools\ble_audio\ble_audio.py'

```

使用 Python 3.8~3.13;已固定 `bleak==0.22.3`,兼容工程 SDK 自带 Python 3.8。

Bleak 的 Windows 后端使用系统 WinRT BLE API,版本支持范围见

Bleak 0.22.3 官方包说明(https://pypi.org/project/bleak/0.22.3/)。

首次安装需要联网;正常录音与下载不需要联网。

不必先在 Windows"添加蓝牙设备"里配对,也不必安装串口驱动。

若此前有旧配对或 GATT 缓存,烧录后出现缺少特征或 `Unreachable`,关闭其它连接开发板的 App,

执行 `python $ble repair`。工具将移除扫描到的这一块板子的 Windows 配对关联,重新扫描同一地址,

完成 GATT 检查并实际查询状态;只有收到有效响应才显示"修复验证成功"。

此操作不移除其它蓝牙设备;普通 `record/status` 不自动解除配对。

多块同名板子请先 `scan`,再用 `repair --address 实际地址` 指定目标。

也可在 Windows 蓝牙设置中手动移除旧 `zkBLE`;如板子未恢复广播,再重启板子。

3. 直接执行命令

3.1 录制并无线传输 Opus(优先推荐)

```powershell

python $ble record --format opus --seconds 10 --output-dir D:\logs\ble_audio

```

默认自动找 `zkBLE`,接收后保存到独立的时间戳目录,不覆盖上次录音。

`.opus` 文件带 Ogg、OpusHead、OpusTags 和 EOS 尾页,可由支持 Opus 的播放器打开。

如果还希望保存 Opus **解码后**的 PCM/WAV:

```powershell

python -m pip install imageio-ffmpeg

python $ble record --format opus --seconds 10 --decode --output-dir D:\logs\ble_audio

```

此时得到 `audio.opus`、`audio.pcm`、`audio.wav`。PCM/WAV 来自 PC 解码后的 Opus,

不是另外并行采集的压缩前原始 PCM。`--decode` 使用本机 FFmpeg;也可自行安装 FFmpeg 并加入 PATH。

不加 `--decode` 不需要 FFmpeg。

3.2 录制并无线传输原始 PCM

```powershell

python $ble record --format pcm --seconds 10 --output-dir D:\logs\ble_audio

```

得到原始 `audio.pcm` 和带相同样本的 `audio.wav`。

PCM 播放参数:**16000Hz、16bit signed little-endian、单声道**。

10 秒有效音频为 320000 字节 PCM;ADC 启动稳定时间不计入这 10 秒。

PCM 有效数据速率为 32000 字节/秒,即 256kbps;链路还需要承担 BLE 协议开销。

实际能否持续传输取决于电脑蓝牙适配器、驱动、连接间隔、信号和同时运行的蓝牙业务。

固件提供约 4.096 秒 PCM 队列;带宽不足时会明确报错 `-139`,不会跳过数据后伪装成完整录音。

建议先验证 Opus,再验证 PCM。需要可靠取回长时间原始录音时,用原来的板内录音功能录完,再用 `download`。

3.3 下载开发板已有录音

先停止录音,确保源文件已经关闭;若正在 U 盘模式,先退出 U 盘模式。

PC 看到的 U 盘根目录对应设备路径 `/NAND:/`,此处不是 Windows 的 `E:\`。

```powershell

下载已有 Opus,保持压缩文件内容不变

python $ble download --remote-path /NAND:/rec.opus --output-dir D:\logs\ble_audio

下载已有 PCM;知道实际录音格式时,另外生成 WAV

python $ble download --remote-path /NAND:/rec.pcm --sample-rate 16000 --channels 1 --output-dir D:\logs\ble_audio

下载之前的双 MIC 立体声录音

python $ble download --remote-path /NAND:/rec1.pcm --sample-rate 16000 --channels 2 --output-dir D:\logs\ble_audio

任意编号的已有 Opus,下载后再生成试听 PCM/WAV

python $ble download --remote-path /NAND:/rec2.opus --decode --output-dir D:\logs\ble_audio

```

没有提供 `--sample-rate` 和 `--channels` 时,下载 PCM 只保存原文件,不猜测录音格式。

双声道、44.1kHz 等已有 PCM 都可原样传输,WAV 参数必须填写真实值。

Opus 的 `--decode` 试听副本统一转为 16kHz 单声道;原 Opus 文件保留。

当前文件路径限定 NAND 根目录的 `.pcm/.opus`,文件名支持字母、数字、下划线、短横线和点,

总路径最长 95 字节。下载期间不要并发覆盖源文件,也不要启动编码任务改写源文件。

本模块检查常规录音是否仍在写入、源文件大小是否变化;如检测到变化则失败,不报告完整下载。

下载期间持有文件系统存储租约,切换 USB U 盘会返回忙;完成或断链后自动释放。

3.4 按名称扫描、选择板子、查询状态

```powershell

python $ble scan # 只显示名称 zkBLE 的设备

python $ble scan --all # 排查时显示所有 BLE 设备

python $ble status # 按 zkBLE 自动连接并查询

python $ble repair # 清理这一块板子的 Windows 旧配对,再连接并查询验证

python $ble record --name zkBLE --format opus --seconds 10

有多块 zkBLE 时,使用 scan 显示的实际地址,避免连接另一块板子

python $ble record --address AA:BB:CC:DD:EE:FF --format pcm --seconds 10

```

`--scan-timeout 15` 可以扩大查找等待时间。按名称连接找到第一块匹配设备就开始连接,不等待整轮扫描结束。

默认通常只需执行一条 `record` / `download` 命令。

3.5 连接结果提示及诊断日志

不确定是否连接成功时,先运行 `python $ble status`。该命令不会开始录音,正常输出类似:

```text

17:23:07 已发现:zkBLE,地址 F4:4E:FD:00:11:22。

17:23:09 正在连接 F4:4E:FD:00:11:22 并发现 GATT 服务(第 1/2 次,最多 20 秒)...

17:23:11 BLE 连接成功:F4:4E:FD:00:11:22,ATT MTU=247;控制/音频/配置特征检查通过。

17:23:11 控制通知订阅成功。

17:23:11 开发板控制响应:op=0x00,state=0x30。

17:23:11 无线音频状态:0x30(30=空闲,31=PCM,32=Opus,34=文件下载)

17:23:14 本次 BLE 连接已释放。

```

"已发现"只表示收到广播;"BLE 连接成功"表示连接和三个 GATT 特征已就绪;

"开发板控制响应"表示双向命令链路正常。`scan` 只扫描,结束后没有连接属于正常现象。

`status` 完成查询后主动释放连接,也属于正常行为。

`record` 在此后会显示音频通知订阅、开始指令确认、已接收字节数、最终保存及 CRC 校验结果。

连接/GATT 失败最多尝试两次;每次默认 20 秒,可用 `--connect-timeout 30` 调整。

重试只用于建立连接,不重复执行录音。失败时直接给出所在阶段、原始错误和修复建议。

连接时只枚举本功能的服务,且请求不使用旧服务缓存;注意**刷新 GATT 缓存不等于清理配对密钥**。

每次运行自动生成带时间戳的 UTF-8 日志,第一行打印完整路径:

  • 录音/下载:`--output-dir` 目录下的 `connection_logs`;默认 `D:\logs\ble_audio\connection_logs`。

  • `scan/status/stop/repair`:默认 `D:\logs\ble_audio\connection_logs`。

  • 可用 `--log-file` 指定完整文件名,记录阶段提示、WinRT 会话/MTU/服务发现和异常堆栈。

```powershell

python $ble status --log-file D:\logs\ble_audio_status.log

python $ble repair --log-file D:\logs\ble_audio_repair.log

```

遇到问题,请保留此日志和同一时间段的开发板普通串口日志,便于关联分析。

3.6 停止及普通串口诊断

录音到达设定时长自动结束。异常时可以在普通串口执行:

```text

app ble_audio status

app ble_audio stop

```

也可在正在执行的 Python 窗口按 Ctrl+C:工具尝试发送停止指令并断开 BLE,板端断链回调独立保证停止。

中止的数据保留为 `received.partial`,不标为成功录音。提前停止的实时录音不会满足请求时长校验。

```powershell

python $ble stop

```

这条命令使用它自己建立的 BLE 连接。正在被另一个连接控制的传输会返回忙,避免跨连接停止别人的录音;

因此停止正在运行的 PC 任务优先用原窗口 Ctrl+C,或普通串口 `app ble_audio stop`。

串口日志示例:

```text

ble_audio: complete result=0 bytes=320000 crc=xxxxxxxx samples=160000

ble_audio: command=0x30 result=0 bytes=320000 samples=160000 queue=0 overflow=0

```

状态 `0x30` 空闲、`0x31` PCM、`0x32` Opus、`0x34` 文件下载;`result` 为上一任务的结果。

4. 实现原理与资源管理

```text

实时 PCM:MIC0 → ADC/DMA → PSRAM PCM 队列 → BLE Notify → PC 校验 → PCM/WAV

实时 Opus:MIC0 → ADC/DMA → PSRAM PCM 队列 → CPU libopus → Ogg → BLE → PC .opus

文件下载:NAND 已关闭的 PCM/Opus → 分块只读 → BLE Notify → PC 原样保存

控制:PC → 原 AA 四字节控制特征 → 主线程派发 → 独立音频传输线程

```

实时录音使用与原录音相同的 MIC0 选择和增益 `200`(20dB),固定 16kHz 单声道。

DMA 回调仅拷贝数据、统计采样数、标记溢出和唤醒线程。编码、CRC、文件读取和 BLE 发送都在线程执行。

16kHz/20ms 每帧 320 样本,Opus 16kbps CBR、复杂度 0。使用工程已经集成的 CPU libopus;

没有改动原厂 DSP 通话 AEC、音乐解码或已实现的 A2DP dump。

Opus 文件的时间戳采用规范的 48kHz granule;OpusHead 写入编码器 lookahead 对应的 pre-skip,

结束时补零冲刷编码器并用 EOS granule 裁掉补零。不会用 16kHz 采样数直接替代 Ogg 的 48kHz 时间戳。

资源仅在收到开始指令后启用:

  • 独立工作线程,PSRAM 中的 64KB 编码状态、64KB 线程栈和 128KB PCM 队列。

  • DMA 缓冲仅 1KB,放内部 SRAM;不增加紧张的 DSP SHARE_RAM 占用。

  • 任务期间申请 PARTIAL 唤醒锁和高性能频率;结束后释放。

  • 使用驱动原来的单 ADC 所有权,不抢占 ASR、其它录音或通话。资源忙时应先停止对应功能,例如 `app asr off`。

  • 来电、断链、停止、缓冲溢出、发送超时都会关闭本模块的 ADC/文件并释放连接引用及存储租约。

  • 开机只注册服务和等待线程,不自动打开麦克风,不改屏幕启动流程。

5. BLE 协议,兼容旧控制格式

服务:`7b2e1000-8e7f-4d3a-9c61-2a3089c00001`。

| 特征 | UUID 尾部对应段 | 用途 |

| --- | --- | --- |

| 原控制特征 | `7b2e1001-...` | Write with response + Notify,原 AA 四字节指令 |

| 新数据特征 | `7b2e1002-...` | Notify,音频和开始/结束记录 |

| 新配置特征 | `7b2e1003-...` | Write with response,录音秒数或文件路径分片 |

UUID 的完整后半部分都为 `8e7f-4d3a-9c61-2a3089c00001`。

旧的录音 `00~03`、Find My `10/11/20/21` 控制值继续兼容。

原广播未包含本服务 UUID,所以 PC 按 `zkBLE` 名称筛选,连接后再校验 GATT 特征。

5.1 控制帧

格式仍是 `AA op control CRC8`,CRC8:poly=07、init=00、不反射,计算前 3 字节。

| 操作 | 完整十六进制帧 |

| --- | --- |

| 查询无线音频状态 | `AA 00 30 5F` |

| 停止本连接的无线音频任务 | `AA 01 30 4A` |

| 开始实时 PCM | `AA 01 31 4D` |

| 开始实时 Opus | `AA 01 32 44` |

| 开始下载配置好的文件 | `AA 01 34 56` |

必须先订阅控制通知和数据通知。ATT 写入成功仅表示请求进入队列;控制 Notify 表示受理结果;

数据流 END 表示传输最终结果。控制错误仍用 `81` 忙、`82` 参数/IO 错误、`83` 连接/订阅失效。

同一时刻只允许一个无线音频任务。

5.2 配置特征

  • 时长:`02 seconds_le16`,例如 10 秒为 `02 0A 00`,范围 1~300。

  • 文件路径:`01 total_len offset ASCII_bytes...`。总长与偏移均为一字节。

第一片 offset=0 清空旧路径;后续 offset 必须严格连续;完整路径校验通过后才允许下载。

工具每次最多写入 20 字节,默认 MTU23 也能分片配置。

  • 正在传输时配置返回忙;断开连接后配置恢复默认 10 秒,路径清空。

5.3 数据通知和校验

每个 Notify 的前 8 字节为小端 `<2sHI>`:

```text

"BA"(2字节) + session_id(uint16) + stream_offset(uint32) + 本次数据片段

```

offset 是本会话逻辑流的累积字节偏移,第一片必须为 0。PC 检查同一会话号和偏移连续性。

每次最多通知 244 字节,并按实际 MTU 缩小。默认 MTU23 可下载文件;实时采集要求 MTU 至少 64。

Notify 队列暂时忙时有界重试;3 秒仍不能发送则失败。固件请求 7.5~15ms 连接间隔,最终由 PC 决定。

去掉每个通知头后,逻辑流由若干记录组成:`type:uint8 + reserved:0 + length:uint16 + payload`。

记录允许跨多个通知分片;主机不能把一次 Notify 当成一个音频帧。

| type | payload |

| --- | --- |

| 1 / START | 24 字节 `<BBBBIHHIII>`:协议版本1、模式1/2/3、格式1PCM/2Ogg、声道、采样率、位深、保留0、秒数、源文件大小、码率 |

| 2 / DATA | PCM 字节、完整 Ogg 页或已有文件字节;最终文件是所有 DATA 按序连接 |

| 3 / END | 16 字节 `<iIII>`:有符号结果码、总 DATA 字节数、IEEE CRC32、实际 PCM 采样数 |

文件模式不臆测裸 PCM 参数,START 的采样率/声道/位深填 0,以原文件大小校验。

CRC32 与 Python `zlib.crc32` 一致,仅计算 DATA 内容。

PC 必须收到结果码0、正确总长度和正确 CRC32 才改名为正式音频;缺少 END、丢包、错序、错误 CRC 或提前停止都不报成功。

6. 代码位置和修改方法

以下路径相对 `` 根目录。

| 文件 | 负责内容 |

| --- | --- |

| `application/bt_watch/tools/ble_audio/ble_audio.py` | 上位机完整代码:`run()` 按名称扫描、repair 和命令流程;`connected_board()` 连接/服务检查/有界重试/释放;`connection_options()` 获取实际地址类型;`report()/setup_log()` 中文提示及 UTF-8 日志;`Receiver` 拼片与校验;`pcm_to_wav()/decode_opus()` 生成试听文件;`main()` 命令行 |

| `application/bt_watch/tools/ble_audio/requirements.txt` | Windows BLE 依赖版本 |

| `application/bt_watch/src/main/ble_audio_transfer.c/.h` | 固件主实现:配置、作业所有权、ADC、CPU Opus/Ogg、已有文件读取、分片发送、断链清理 |

| `application/bt_watch/src/main/ble_record_service.c` | 在原服务末尾添加数据/配置特征;原控制特征分派音频扩展命令 |

| `application/bt_watch/src/main/ble_record_protocol.h` | 新增 `0x30/31/32/34` 合法控制值,原 CRC8 格式不变 |

| `application/bt_watch/src/main/system_app_shell.c` | 普通串口 `app ble_audio status/stop` |

| `application/bt_watch/src/main/usb_serial_runtime.c` | 文件读取租约与 USB MSC 切换的同锁互斥检查 |

| `zephyr/include/drivers/console/usb_serial_runtime.h` | 存储租约接口声明 |

| `application/bt_watch/Kconfig` | `CONFIG_APP_BLE_AUDIO_TRANSFER` 开关 |

| `application/bt_watch/src/main/CMakeLists.txt` | 模块编译接入,复用已集成的 libopus |

| `application/bt_watch/tests/ble_audio/` | ARM 生产代码仿真、PC 解析/流程测试 |

重要改动采用 `//zk+`、`//zk+-` 和中文注释;Python/CMake/Kconfig 使用对应 `#zk+/#zk+-`。

若修改采样率或声道,需要同步 ADC 参数、Opus 参数、每帧采样数、START 元数据、PC 格式检查和 WAV 参数。

不要只修改 WAV 文件头,原始 PCM 必须与声明格式一致。

7. 故障定位

| 现象 | 原因及处理 |

| --- | --- |

| 找不到 zkBLE | 打开电脑蓝牙、开发板上电;关闭手机占用 BLE 的 App;普通串口可执行 `bt ble_test on`;用 `scan --all` 核对名称 |

| `Unreachable` / 服务不可访问 | 已发现广播,但 GATT 未就绪;本次实测为旧配对密钥状态不一致,执行 `python $ble repair` 后恢复。其它情况还需检查手机占用、距离、驱动和诊断日志 |

| 缺少 1002/1003 特征 | 旧固件或 Windows GATT 缓存;烧录本版并刷新设备连接 |

| 控制错误 81 / 结果 -16 | 另一无线任务、ASR、录音、通话或 U 盘模式占用资源;停止占用后重试 |

| 结果 -139 | PCM 队列溢出,实际无线速度不足;用 Opus、改善信号或录完后下载文件 |

| 结果 -122 | 实时模式 MTU 太小;更新蓝牙驱动后重连;文件下载可在 MTU23 工作 |

| 结果 -116 | 无 ADC 数据或 BLE 发送超时;查看串口状态、检查连接 |

| 结果 -2 | `/NAND:/` 下没有指定文件;核对自动编号 rec/rec1/rec2 |

| 只有 `.partial` | 数据不完整;`metadata.json` 保存失败原因,不应当作正常音频分析 |

| PCM 播放变调/时间异常 | 裸 PCM 采样率/声道填写错误;实时固定16k单声道,下载模式按文件实际参数 |

| Opus 保存成功、转换失败 | BLE 文件已校验保存;安装 FFmpeg 后可单独解码,不必重新录制 |

7.1 本次 `log_26_10_12.txt` 的具体结论

最新故障发生在 2026-10-16 的 17:08,不能把文件前面累积的其它通话/A2DP 日志混为同一故障:

  1. `17:08:54.844 Ble connected MAC: 5bd2b7778eec`:已经建立 BLE 物理连接。

字节倒序对应 `EC:8E:77:B7:D2:5B`,与本机 Intel 蓝牙适配器地址一致。

  1. `17:08:54.999 TX: 01 1b 20 02 01 06`:HCI 命令 `0x201B`,即

`BT_HCI_OP_LE_LTK_REQ_NEG_REPLY`,开发板无法提供本次加密请求所需的长期密钥。

工程 `framework/bluetooth/bt_stack/src/bt_stack/hci_core.c` 的 `le_ltk_request()`

在 `bt_smp_request_ltk()` 失败时走此分支。

  1. `17:08:55.109 ... reason: 19` / `reason=0x13`:约 265ms 后由对端终止连接。

随后的 `Not connected / Exchange failed mtu:0` 是断链后的结果,不能据此认定 MTU 是首因。

  1. PC 查询显示该板 `IsPaired=True`。用仅枚举目标服务、禁用 GATT 缓存的方式仍复现 `Unreachable`;

单独移除该板旧配对后,立即连接成功、MTU247、三个特征齐全,状态返回 `AA 00 30 5F`。

这些结果共同确认本次问题来自 PC 留存旧配对、开发板对应密钥不可用。

此日志无法确定开发板密钥是在何时被擦除或失效;不把烧录、重置或其它操作作为已证实原因。

手机可以连接并不矛盾:手机和电脑是不同对端,持有的配对记录不同。

旧工具在 `BleakClient.aenter()` 完成 GATT 发现之后才打印"已连接",

因此失败前只看到"正在查找",缺少过程提示。新版已分别打印并记录这些阶段。

8. 编译与验证范围

v1 固件完整编译和打包成功。新增模块通过 65588 项 ARM 断言;连接修复后的上位机通过 23 项测试;

原 BLE 录音测试通过,USB 自动模式及新增存储租约通过 220 项断言。

最终资源占用:SRAM 875776 字节、PSRAM 32809952 字节、SHARE_RAM 20948 字节。

SHARE_RAM 与修改前一致;固件 SHA256 见固件目录中的同名校验文件。

```powershell

cd .\zephyr

python build.py -n -b ats3089p_dev_watch -a bt_watch

cd ..

python -X utf8 -B .\application\bt_watch\tests\ble_audio\run_tests.py

python -X utf8 -B .\application\bt_watch\tests\ble_audio\test_pc_tool.py

```

ARM 测试运行生产传输代码,替换硬件边界,覆盖全部 op/control 组合、资源忙、MTU23 文件下载、

ADC 精确样本数、启动稳定窗口、Opus 尾部封装、缓冲溢出、断链、文件失败和资源释放。

PC 测试使用 ARM 生产发送器生成的通知流验证 PCM 逐样本一致、Ogg CRC/pre-skip/EOS、跨 MTU 分片、

丢包、重复、错序、CRC 错误、无 END、自动按名称连接及异常停止。

这些测试中的 Opus 编码调用使用替身以隔离状态机,不用于宣称编码音质或 CPU 实时性能。

2026-10-16 本机实板复测已完成旧配对故障复现及定向清理、MTU247 连接、三个特征发现、

状态查询、`repair` 命令及断开后重新连接。10 秒 Opus 实际收到 34167 字节,CRC32=`155633C0`,

并用 FFmpeg 成功解码为 PCM/WAV。另一次 10 秒原始 PCM 收到 320000 字节,CRC32=`47E8B954`,

同时生成 WAV。实测文件及连接日志在 `application/bt_watch/outdir/ble_audio_hardware/`。

这次连接修复仅修改 Python 上位机及相关测试/中文说明,未改动或重新打包固件。

以上结果用于确认链路和文件完整性;未做录音音质、远距离或长时间运行评估。

相关推荐
Yiran_G2 小时前
智能家居自动化为什么会失效?从一次开灯失败看无线通信链路
嵌入式硬件·物联网·智能家居
编程圈子2 小时前
I.MX6U 裸机开发 25. PWM 与 LCD 背光
单片机·嵌入式硬件
创界工坊工作室3 小时前
35-基于AT89C51单片机的罐头生产线传送系统设计
stm32·单片机·嵌入式硬件·51单片机·proteus·生产线
qq_401700413 小时前
MCU串口接收不定长数据的三种方案,哪种最稳?
stm32·单片机·嵌入式硬件
inrichtt4 小时前
第七课时:STM32时钟系统揭秘:从零理解时钟树
c语言·数据结构·stm32·单片机·嵌入式硬件
硅基手札4 小时前
【Linux 内核专栏 17】进程间通信 IPC(上)— 管道·信号·System V IPC·mmap·文件锁
linux·运维·服务器·stm32·单片机·mcu
Zw-awa5 小时前
PID 用顺了,然后呢:增强手术与前馈
stm32
国科安芯5 小时前
无方向脚如何既快又稳:ASC0101S 自动方向感应机理与边沿加速应用研究
网络·嵌入式硬件·低轨卫星·商业航天·抗辐射
额额额对了5 小时前
Linux 驱动开发:基于 platform 总线 + misc 设备的 DS18B20 单总线温度驱动
linux·c语言·开发语言·驱动开发·嵌入式硬件