RIOT 操作系统 DAC DDS 音频测试应用实战:用 DAC 播放正弦波、方波与语音
RIOT 操作系统 DAC DDS 音频测试应用实战用 DAC 播放正弦波、方波与语音【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT导读本篇文章围绕 RIOT 操作系统中的tests/drivers/dac_dds测试/演示应用展开完整讲解如何使用 DAC数模转换器配合定时器以直接数字合成DDS的方式输出音频波形。读完本文你将掌握dac_dds驱动模块的初始化、双缓冲播放、命令式控制等核心用法学会在本机构建并在开发板上通过 shell 命令行播放正弦波、方波、锯齿波以及一段预先录制的 8 kHz 语音。DAC DDS 是什么在 RIOT 中dac_ddsDAC Direct Digital Synthesis是一个位于 drivers/dac_dds 的驱动模块其头文件 drivers/include/dac_dds.h 中对它的定位描述是Use a DAC to play a buffer of samples即以指定采样率通过 DAC 播放一段音频样本缓冲区。它的工作方式非常直观应用把一段样本数据例如 8 位或 16 位采样交给驱动驱动借助一个周期性定时器按sample_rate的节奏把缓冲区中的每个样本逐一写入 DAC为了让音频连续播放驱动内部采用**双缓冲double buffering**机制缓冲区 A 在播放时应用可以预先填充缓冲区 BA 播完后自动切换为 B从而实现不间断的数据供给。tests/drivers/dac_dds正是这套驱动的手动测试与演示程序manual test, and demo application它默认初始化单个 DAC DDS 通道并根据命令行请求在 DAC 输出引脚上播放正弦波、方波、锯齿波或一段问候语音。构建与烧录测试应用位于 tests/drivers/dac_dds其 Makefile 默认目标板为mcb2388BOARD ? mcb2388构建时需启用dac_dds与shell两个模块USEMODULE dac_dds USEMODULE shell同时音频数据通过 RIOT 的 BLOB 机制嵌入固件BLOBS hello.rawBLOB 机制由 makefiles/blob.inc.mk 实现——它会把 BLOBS 列表中的任意文件转换成可通过#include blob/hello.raw.h直接引用的 C 头文件从而将原始音频数据静态地链接进固件。编译并烧录以native或真实开发板为例make BOARDmcb2388 -C tests/drivers/dac_dds flash term注意测试应用依赖目标板的 DAC 外设。请把耳机或扬声器连接到开发板的 DAC 输出引脚main.c的文件头注释中明确提示了这一操作要求之后即可听到生成的音频。在 shell 中使用四个核心命令应用启动后进入 RIOT shell注册了如下命令见 main.c 中的shell_commands表命令作用hello播放内置问候语音init freq [bit]以指定采样率和位深重新初始化 DAC DDSsaw freq secs播放指定频率、时长的锯齿波sine freq secs播放指定频率、时长的正弦波square freq secs播放指定频率、时长的方波README 中给出的典型用法为 hello sine 440 2第一条命令播放内置的问候语音第二条命令在默认 8000 Hz 采样率下播放 440 Hz、持续 2 秒的标准音 A4 正弦波。hello播放问候语音hello命令cmd_greeting直接把嵌入固件的hello.raw音频一次性交给 DAC DDS 播放dac_dds_set_cb(DAC_DDS_CHAN, NULL, NULL); dac_dds_play(DAC_DDS_CHAN, hello_raw, hello_raw_len);由于这段音频本身录制为 8 位/8000 Hz若当前配置的采样率或位深与其不符程序会打印警告Warning: audio clip was recoded with 8bit/8000 Hz。默认情况下该命令在编译时启用ENABLE_GREETING默认 1。init调整采样率与位深init freq bit允许动态改变播放参数dac_dds_init(DAC_DDS_CHAN, sample_rate, res_16b ? DAC_FLAG_16BIT : DAC_FLAG_8BIT, NULL, NULL);freq采样率单位 Hzbit只接受8或16分别对应DAC_FLAG_8BIT与DAC_FLAG_16BIT传入其他值会提示Only 8 and 16 bit samples supported.。sine/saw/square三种波形生成三个命令的参数格式统一为freq secs内部通过play_function(period, samples, sample_gen_t fun)完成播放周期计算为(sample_rate freq/2) / freq带四舍五入采样总数计算为secs * sample_rate16 位模式下采样数翻倍每样本占 2 字节。波形由三个独立的样本生成函数填充见 main.c正弦波_fill_sine_samples_8/_fill_sine_samples_16使用imath.h提供的fast_sini()快速查表算法按SINI_PERIOD / period的步进在一个周期内取样随后用memcpy把单个周期复制到整个缓冲区锯齿波_fill_saw_samples_8/_fill_saw_samples_16用(i * 0xFFUL) / period8 位或(i * 0xFFFFUL) / period16 位线性递增填充方波_fill_square_samples以半个周期为单位交替填0xFF与0x00。播放流程与双缓冲原理play_function展示了dac_dds驱动的推荐使用方式详见 drivers/dac_dds/dac_dds.cdac_dds_set_cb(DAC_DDS_CHAN, _unlock, lock); while (samples) { size_t len min(samples, len_aligned); samples - len; underruns !dac_dds_play(DAC_DDS_CHAN, buf, len); /* wait for buffer flip */ mutex_lock(lock); }其核心流程是先用dac_dds_set_cb()注册一个回调——这里注册的是_unlock它会在当前缓冲区播放完毕、可以提交下一块缓冲区时解锁一个互斥锁调用dac_dds_play()提交缓冲区。若此时驱动尚未开始播放返回false说明发生了一次缓冲不足underrun或刚刚启动播放若返回true表示缓冲区已排入队列、等当前块播完后自动接续随后线程阻塞在mutex_lock(lock)上直到回调解锁再提交下一块数据。驱动内部的双缓冲状态机驱动以struct dac_ctx维护每个通道的状态dac_dds.cstatic struct dac_ctx { const uint8_t *buffers[2]; /* The two sample buffers */ size_t buffer_len[2]; /* Size of the sample buffers */ size_t idx; /* Current position in the current buffer */ dac_dds_cb_t cb; /* Called when the current buffer is done */ void *cb_arg; /* Callback argument */ uint16_t sample_ticks; /* Timer ticks per sample */ uint8_t cur; /* Active sample buffer */ uint8_t playing; /* DAC is playing */ uint8_t is_16bit; /* Sample size is 16 instead of 8 bit */ } _ctx[DAC_DDS_NUMOF];初始化时驱动根据timer_hz / sample_rate计算出每个样本对应的定时器 tick 数sample_ticks并把定时器中断绑定到内部回调_timer_cb。每次定时器触发8 位模式下把buf[idx] 8写入 DAC高位对齐到 16 位 DAC 寄存器16 位模式下把低、高两个字节拼成(h 8) | l后写入当前缓冲读完后若下一块缓冲已就绪则自动切换否则停止定时器并置playing 0。dac_dds_play()在调用时只切换cur指针指向的缓冲区索引并在驱动空闲时启动timer_set_periodic()。整个设计使得数据供给与应用逻辑解耦唯一需要注意的是回调运行在定时器中断上下文头文件明确建议不要在回调里做实际的缓冲区填充或重 I/O而应仅用它唤醒一个线程由线程负责填充样本并再次调用dac_dds_play()——这正是play_function中 mutex 回调组合的用意。关于 underrun缓冲不足play_function把初始的 underrun 计数置为-1注释说明 One underrun indication is expected (for the first sample)——即首次启动播放时dac_dds_play返回false属于正常现象不计入故障。后续若实际发生缓冲供给不及时程序会打印During playback, %d underruns occurred.提示音频出现断流。默认参数与板级配置驱动的默认参数定义在 drivers/dac_dds/include/dac_dds_params.h#ifndef DAC_DDS_PARAM_DAC #define DAC_DDS_PARAM_DAC DAC_LINE(0) #endif #ifndef DAC_DDS_PARAM_TIMER #define DAC_DDS_PARAM_TIMER (TIMER_NUMOF - 1) #endif #ifndef DAC_DDS_PARAM_TIMER_HZ #define DAC_DDS_PARAM_TIMER_HZ MHZ(1) #endif即默认使用第一条 DAC 线、最后一个定时器定时器频率为 1 MHz。头文件同时给出约束定时器频率至少应为采样率的 2 倍must be at least 2x sample rate以保证定时精度。测试应用侧的可配置宏main.c包括DAC_DDS_CHAN默认0DAC DDS 通道号DAC_DDS_DAC默认DAC_DDS_PARAM_DAC使用的 DAC 外设DAC_BUF_SIZE默认2048样本缓冲区字节数ENABLE_GREETING默认1是否编译hello命令。在低内存目标板上Makefile 中指定LOW_MEMORY_BOARDS : samd10-xmini构建系统会自动把ENABLE_GREETING置为 0、将DAC_BUF_SIZE缩小到 1024以避免内存不足或烧录过慢ifneq (,$(filter $(BOARD),$(LOW_MEMORY_BOARDS))) ENABLE_GREETING ? 0 CFLAGS -DDAC_BUF_SIZE1024 else ENABLE_GREETING ? 1 endif此外play_function会校验周期不能超过缓冲区大小超限时打印Period duration exceeds sample buffer size.测试缓冲的填充也做了整周期对齐处理len_aligned DAC_BUF_SIZE - DAC_BUF_SIZE % period保证每次提交的数据块都能完整播放波形周期。音频源hello.raw 的来历与许可证hello.raw是一段由 GeoTrinity 录制的 Ahoy! 问候语音原始素材来自维基百科上的GT_Ahoi_Deutsch_GT.ogg标注采用CC-BY-SA 3.0 International许可证见 tests/drivers/dac_dds/README.md。它通过如下两条命令转换并裁剪得到先使用ffmpeg将 Ogg 音频转为单声道、8000 Hz、无符号 8 位 PCM 裸流pcm_u8再使用 Python 去除首尾的静音去除前导/尾随的0x80中值字节并补回一个尾随字节避免文件以中值静音开头$ ffmpeg -i GT_Ahoi_Deutsch_GT.ogg -ac 1 -ar 8000 -f u8 -c:a pcm_u8 hello.raw $ python3 -c s open(hello.raw, rb).read(); s s.strip(b\x80) b\x80; open(hello.raw, wb).write(s)这段转换流程本身也是一份实用的参考任何 8 位 8000 Hz 的单声道 PCM 裸数据u8/pcm_u8格式都可以通过 BLOB 机制嵌入固件作为dac_dds的播放素材。若使用其他采样率或位深的素材需结合hello命令的采样率警告机制先通过init命令将 DDS 配置到与素材一致的参数。小结tests/drivers/dac_dds虽是一个手动测试应用却完整示范了 RIOT 中 DAC 音频输出的标准做法BLOB 嵌入音频数据、dac_dds_init初始化、dac_dds_play 回调驱动的双缓冲连续播放以及基于fast_sini的嵌入式波形合成。无论你是在调试某块开发板的 DAC 音频通路还是想在自己的 RIOT 应用中实现提示音或简单音频播放都可以直接复用本测试的 shell 命令设计与play_function播放框架再结合 drivers/dac_dds/dac_dds.c 与 drivers/include/dac_dds.h 深入理解其底层机制。【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

ClickHouse v25.12.2.54-stable 版本全解读:JSON 共享数据序列化升级、文本索引与查询引擎缺陷修复

ClickHouse v25.12.2.54-stable 版本全解读:JSON 共享数据序列化升级、文本索引与查询引擎缺陷修复

ClickHouse v25.12.2.54-stable 版本全解读:JSON 共享数据序列化升级、文本索引与查询引擎缺陷修复 【免费下载链接】ClickHouse ClickHouse is a real-time analytics database management system 项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse…

2026/9/20 1:43:31 阅读更多 →
GBrain Brain-Ops 技能深度解析:知识库 Ambient Context Layer 的读写循环与记忆协议实战

GBrain Brain-Ops 技能深度解析:知识库 Ambient Context Layer 的读写循环与记忆协议实战

GBrain Brain-Ops 技能深度解析:知识库 Ambient Context Layer 的读写循环与记忆协议实战 【免费下载链接】gbrain Garrys Opinionated OpenClaw/Hermes Agent Brain 项目地址: https://gitcode.com/gh_mirrors/gb/gbrain 本指南以 gbrain 仓库中的 brain-op…

2026/9/20 1:42:30 阅读更多 →
Qwen Code 桌面品牌构建器从零到产物:用 Tauri 壳生成白标桌面安装包的完整实战

Qwen Code 桌面品牌构建器从零到产物:用 Tauri 壳生成白标桌面安装包的完整实战

Qwen Code 桌面品牌构建器从零到产物:用 Tauri 壳生成白标桌面安装包的完整实战 【免费下载链接】qwen-code An open-source AI coding agent that lives in your terminal. 项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code 本文基于 qwen-code…

2026/9/20 1:42:30 阅读更多 →

最新新闻

Podman `--no-trunc` 选项详解:关闭输出截断,获取完整容器、镜像与构件信息

Podman `--no-trunc` 选项详解:关闭输出截断,获取完整容器、镜像与构件信息

容器运行时云原生CLI 【免费下载链接】podman Podman: A tool for managing OCI containers and pods. 项目地址: https://gitcode.com/gh_mirrors/po/podman 点击查看 免费下载 导读 --no-trunc 是 Podman 列表类命令中一个虽小但非常实用的布尔选项,…

2026/9/20 2:28:51 阅读更多 →
从Codex迁移到WorkBuddy:一周真实体验对比与避坑指南

从Codex迁移到WorkBuddy:一周真实体验对比与避坑指南

1. 先说清楚:我为什么动了换掉 Codex 的心思过去两个多月,我一直是 Codex 的重度用户,日常写脚本、改业务代码、处理临时数据,几乎都丢给它。说句公道话,Codex 在复杂任务拆解和长链路代码生成上的能力确实顶&#xff…

2026/9/20 2:28:51 阅读更多 →
GetQzonehistory:5分钟导出QQ空间历史说说

GetQzonehistory:5分钟导出QQ空间历史说说

GetQzonehistory:5分钟导出QQ空间历史说说 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 上周末翻 QQ 空间,想回味 2014 年发的那些说说,却发现消息…

2026/9/20 2:28:51 阅读更多 →
Miniblink49 实战:三步嵌入桌面应用

Miniblink49 实战:三步嵌入桌面应用

Miniblink49 实战:三步嵌入桌面应用 【免费下载链接】miniblink49 a lighter, faster browser kernel of blink to integrate HTML UI in your app. 一个小巧、轻量的浏览器内核,用来取代wke和libcef 项目地址: https://gitcode.com/GitHub_Trending/m…

2026/9/20 2:28:51 阅读更多 →
webpack/lib/RuleSet 报错排查:多版本冲突与模块解析机制

webpack/lib/RuleSet 报错排查:多版本冲突与模块解析机制

1. 报错现场还原:webpack明明装了就差最后一步先说结论吧,看到ERROR Error: Cannot find module webpack/lib/RuleSet这个报错,大多数人的第一反应是去检查 webpack 到底装没装、装在哪。结果打开node_modules/webpack一看,目录好…

2026/9/20 2:28:51 阅读更多 →
idea怎么做网页注意事项

idea怎么做网页注意事项

IDEA做网页避坑指南:5步搞定备案与代码 备案流程一头雾水,是不是让你对着电脑屏幕发呆?很多刚转行做网站的新手,以为只要会写代码就能搞定一切,结果卡在工信部ICP备案系统这一步,直接懵圈。别慌,咱们今天不整虚的,直接拿IntelliJ…

2026/9/20 2:27:54 阅读更多 →

日新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/20 0:00:46 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/20 0:00:46 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/20 0:00:46 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/20 0:00:46 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/19 23:01:36 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/19 17:50:38 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →