尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

AC696X BR25系列(Jieli) 如何以音乐模式播放存储在 SPIFlash 中的 MP3 文件?

AC696X BR25系列(Jieli) 如何以音乐模式播放存储在 SPIFlash 中的 MP3 文件? 本文收录于 《全栈 Bug 调优实战版》 专栏。专栏聚焦真实项目中的各类疑难 Bug从成因剖析 → 排查路径 → 解决方案 → 预防优化全链路拆解形成一套可复用、可沉淀的实战知识体系。无论你是初入职场的开发者还是负责复杂项目的资深工程师都可以在这里构建一套属于自己的「问题诊断与性能调优」方法论助你稳步进阶、放大技术价值。特别说明文中问题案例来源于真实生产环境与公开技术社区并结合多位一线资深工程师与架构师的长期实践经验经过人工筛选与AI系统化智能整理后输出。文中的解决方案并非唯一“标准答案”而是兼顾可行性、可复现性与思路启发性的实践参考供你在实际项目中灵活运用与演进。欢迎订阅本专栏一次订阅后专栏内所有文章可永久免费阅读后续更新内容皆不用再次订阅持续更新中。 问题描述详细问题描述如下AC696X BR25系列Jieli 如何以音乐模式播放存储在 SPIFlash 中的 MP3 文件如何在以 PC 模式启动的设备上将 MP3 文件存储在 SPIFlash 中然后在音乐模式下播放全文目录 问题描述 请知悉如下方案不保证一定适配你的问题✅️问题理解✅️问题解决方案方案 A把 SPIFlash 作为 FAT 音乐盘PC 模式写入音乐模式直接播放最推荐1先把 SPIFlash 这件事做对不是“裸 Flash”而是“可挂载的外部设备”2硬件和下载配置先保证外挂 SPIFlash 真能被系统识别3PC 模式要做的事把 EXTFLASH 枚举成 U 盘4第一次使用时必须让 SPIFlash 上有 FAT 文件系统5音乐模式不要自己重新发明轮子优先复用官方音乐模式的“设备切换 文件切换”框架6如果你要自己写 C 代码推荐按“两层写法”来做第一层模式切换层第二层文件播放层7一份可落地的 C 代码骨架偏“通用自定义播放器”8如果你要做“音乐模式扫描整个 SPIFlash”就用 FAT 扫描接口不要自己递归目录9模式切换必须做资源互斥PC 模式和音乐模式不能同时抢这块盘10如果你已经有官方 music mode那最推荐的“接法”其实是下面这样方案 B量产时预置 MP3 到 SPIFlash然后音乐模式直接播放方案 C不接完整 music mode自己挂 FAT 后按路径直接播放适合快速验证✅️问题延伸1sydfs只读资源系统2norfs循环覆盖型3fatfs最适合你现在这个需求4EXTFLASH✅️问题预测预测 1PC 已经能看到盘但音乐模式就是扫不到 MP3预测 2PC 模式能写切到音乐模式后 mount 失败预测 3复制进去的是歌但播放时报文件错误/同步错误预测 4外挂 Flash 烧录没问题但 PC 模式完全看不到盘预测 5你会想直接用 flash_read_buff() 去播 MP3预测 6你后面会遇到“到底走现成 music mode还是自己写播放逻辑”的选择✅️小结 结语 互动说明 文末福利技术成长加速包 Who am I? 请知悉如下方案不保证一定适配你的问题如下是针对上述问题进行专业角度剖析答疑不喜勿喷仅供参考✅️问题理解先确认一句你现在手里用的是AC696X/BR25 的 soundbox/mbox 类工程还是 earphone 类工程下面我先按最常见、最符合你这个需求的 soundbox/mbox 架构来回答因为杰理同体系公开文档里“音乐模式 USB 从机 本地文件播放 extflash/FAT”这条链路就是这么设计的。你这个问题本质上不是“怎么单纯解码一个 MP3”而是要打通一整条双模式共享存储链路PC 模式启动时把 SPIFlash 暴露给电脑最好表现成一个USB Mass StorageU 盘电脑把 MP3 文件复制进去SPIFlash 上形成FAT 文件系统切到音乐模式后设备再把这块 SPIFlash 作为本地音乐设备挂载、扫描、建立播放列表然后调用解码器播放 MP3。杰理同体系文档里明确给出了可以把一段 Flash 空间作为EXTFLASH设备EXTFLASH 可以挂到文件系统还可以枚举成mass_storage让 PC 直接读写音乐模式在同体系应用里支持从内置 flash / 外置 flash / SD / U 盘播放音频文件音频解码则通过decoder_io()并支持BIT_MP3_ST/BIT_WAV这类控制位。所以正确方向不是“把 MP3 当资源硬编码进程序里”也不是“PC 模式下自己写裸地址再让音乐模式生啃原始 flash 数据”而是把 SPIFlash 做成可挂载的 FAT 设备PC 模式负责写文件音乐模式负责扫文件并播放。这是最稳、最像官方思路、也最适合后续量产和维护的方案。✅️问题解决方案下面我先给出结论推荐落地路线方案 ASPIFlash → EXTFLASH/FAT → PC 模式枚举为 U 盘 → 电脑拷 MP3 → 切音乐模式 → 扫 FAT → 播放这个方案和杰理同体系官方“EXTFLASH 文件系统 USB mass_storage 音乐模式”的设计最一致。方案 A把 SPIFlash 作为 FAT 音乐盘PC 模式写入音乐模式直接播放最推荐这是最标准、最工程化的做法。适合你现在说的“以 PC 模式启动先存 MP3再切到音乐模式播放”。✨1先把 SPIFlash 这件事做对不是“裸 Flash”而是“可挂载的外部设备”杰理同体系文档说明Flash 的一段空间可以被截出来作为EXTFLASH 设备这个设备既能被文件系统读写也能被 USB 枚举为mass_storage。官方示例代码路径给的是apps/common/fat_nor/extflash.c配置上需要启用TCFG_EXTFLASH_ENABLE并配置EXTFLASH_ADR / EXTFLASH_LEN / EXTFLASH_OPT这类参数。这意味着你的 SPIFlash 在架构上要被当成一个“设备”上面挂一个 FAT 文件系统PC 模式把它当 U 盘音乐模式把它当本地音乐源而不是简单flash_read_buff()读一坨原始字节。原始读写 API 适合做底层调试、参数区、固定资源区不适合做“PC 可写 音乐模式可扫描播放”的音乐盘。2硬件和下载配置先保证外挂 SPIFlash 真能被系统识别杰理官方量产工具文档里针对部分AC696X SDK给出了外挂 Flash 的配置方式包括EX_FLASH...EX_FLASH_IO...以及不同 1/2/4 线模式下的引脚配置格式。例如官方文档里给出的格式是这类EX_FLASHPA03_1C_PC01; EX_FLASH_IO4_PC06_PB07_PB08_PB09_PB10; ; 4线 EX_FLASH_IO2_PC06_PB07_PB08_NULL_NULL; ; 2线 EX_FLASH_IO0_PC06_PB07_PB07_NULL_NULL; ; 单线半双工这些配置的含义官方也写了EX_FLASH是CS_SPI端口_供电脚EX_FLASH_IO是width_CLK_DO_DI_D2_D3。如果你用的是 AC696N/BR25 的 soundbox SDK社区实战里常见还会在app_config.h里配硬件 SPI例如启用TCFG_HW_SPI1_ENABLE、设置TCFG_HW_SPI1_PORT、TCFG_HW_SPI1_BAUD、TCFG_HW_SPI1_MODE、TCFG_HW_SPI1_ROLE。这部分很像你实际工程会看到的东西但因为这是社区文章不是杰理官方 AC696X 公开文档所以你要把它当“参考样式”不要照抄引脚必须以你手里 BR25/AC696X 具体板级和芯片资料为准。3PC 模式要做的事把 EXTFLASH 枚举成 U 盘这一步是关键中的关键。官方文档明确说如果要让 EXTFLASH 插到电脑后可读写需要使能TCFG_EXTFLASH_UDISK_ENABLE再通过TCFG_PC_ENABLE打开 USB 从机并让USB_DEVICE_CLASS_CONFIG包含MASSSTORAGE_CLASS。也就是说PC 模式的目标不是“自己实现一个上位机协议把 MP3 传进来”而是更简单直接#defineTCFG_PC_ENABLE1#defineTCFG_EXTFLASH_UDISK_ENABLE1#defineUSB_DEVICE_CLASS_CONFIG(MASSSTORAGE_CLASS)如果你的工程里同时还挂了别的 USB 类比如 CDC那么就按官方示例那样做组合#defineUSB_DEVICE_CLASS_CONFIG(CDC_CLASS|MASSSTORAGE_CLASS)这个组合在官方文档里就是存在的。效果就是设备以 PC 模式启动后电脑会把这块 SPIFlash 当成一个盘。你把xxx.mp3、yyy.mp3拖进去即可。4第一次使用时必须让 SPIFlash 上有 FAT 文件系统音乐模式要扫歌本质上靠的是文件系统不是靠“按地址找 MP3 帧头”。同体系文件系统文档写得很清楚要先fs_init()再fs_mount(..., fat)然后才能fs_openbypath()/fs_select()/fs_read()。支持的 FAT 体系包括FAT12/16/32、EXFAT。所以第一次空片上电时一般有两条路最省事PC 模式枚举成 U 盘后直接在 Windows 里格式化成 FAT再拷歌量产预置提前做好镜像/资源再烧进外挂 Flash。如果只是调试第一条最轻松。如果是量产我后面讲方案 B。5音乐模式不要自己重新发明轮子优先复用官方音乐模式的“设备切换 文件切换”框架同体系小音箱/音乐模式文档里官方已经把音乐模式写成了一个完整的设备/文件控制框架核心接口包括music_play_control(MBOX_MUSIC_CMD cmd, u32 index, DEC_STOP_WAIT mode)mbox_simple_play_file(u8 dindex, u32 findex)并且命令里已经有DEV_CMD_SEL_NEW_DEVFILE_CMD_PLAY_BY_INDEXFILE_CMD_NEXTFILE_CMD_PREV等。这件事非常重要如果你的 BR25/AC696X 工程本身就是 soundbox/mbox 路线那么最稳的方式不是自己手搓一个播放器状态机而是把“SPIFlash 对应的设备索引”纳入现有 music mode 设备表。也就是说你真正该改的是音乐模式设备枚举列表里加上 extflash 设备让DEV_CMD_SEL_NEW_DEV能切到它让文件扫描对这个设备生效让FILE_CMD_PLAY_BY_INDEX能从这个设备打开文件这样一来上一曲/下一曲/循环/断点续播/按键逻辑很多都能沿用现成框架。6如果你要自己写 C 代码推荐按“两层写法”来做第一层模式切换层职责PC 模式启动 USB mass_storage暴露 SPIFlash切音乐模式前关闭 USB确保文件系统状态干净音乐模式挂 FAT扫歌播放第二层文件播放层职责挂载 FAT打开 MP3 文件调decoder_io()官方文档里解码器的通用流程是decoder_init()获取文件句柄decoder_io(pfile, dec_ctl, dbuff, loop)其中dec_ctl可以包含BIT_MP3_ST、BIT_WAV等。7一份可落地的 C 代码骨架偏“通用自定义播放器”下面这份代码不是照搬某个公开 BR25 工程文件而是严格按照杰理同体系公开 API 组织出来的落地骨架其中“设备句柄怎么拿”这一步要替换成你 SDK 里 extflash 的实际设备获取方式。这一点我明确告诉你不装懂。#includesystem/includes.h#includefs/fs.h#includeapp_config.h// 你的工程里通常会有解码相关头文件// #include decoder/decoder_api.hstaticvoid*g_pfsNULL;staticvoid*g_pfileNULL;staticdec_obj*g_decNULL;/* 这里不要死抠设备名字符串实际以你的SDK为准 * - 有的工程是 extflash 设备 * - 有的工程走 mbox 设备表 / dindex * - 有的工程在 extflash.c 里注册 */staticvoid*get_extflash_device(void){void*devNULL;// 伪代码替换成你工程里的真实获取方式// dev device_open(extflash);// 或者通过 mbox 的设备枚举拿 device// 或者调用 extflash 初始化后返回的句柄returndev;}intextflash_mount_fat(void){void*devget_extflash_device();if(!dev){printf(extflash device open fail\n);return-1;}fs_init();if(fs_mount(g_pfs,dev,fat)){printf(mount fat fail\n);g_pfsNULL;return-2;}printf(extflash fat mount ok\n);return0;}intextflash_open_and_play(constchar*path){if(!g_pfs){if(extflash_mount_fat()){return-1;}}if(fs_openbypath(g_pfs,g_pfile,path)){printf(open file fail: %s\n,path);return-2;}decoder_init();// 播放 MP3 / WAVloop0 表示播完不续播g_decdecoder_io(g_pfile,BIT_MP3_ST|BIT_WAV,NULL,0);if(!g_dec){printf(decoder start fail\n);fs_file_close(g_pfile);g_pfileNULL;return-3;}printf(play start: %s\n,path);return0;}voidextflash_stop_play(void){if(g_dec){decoder_stop(g_dec,NEED_WAIT);g_decNULL;}if(g_pfile){fs_file_close(g_pfile);g_pfileNULL;}}voidextflash_close_fs(void){extflash_stop_play();if(g_pfs){fs_fs_close(g_pfs);g_pfsNULL;}}这套代码依赖的 API 和流程和官方文档给出的文件系统/解码器接口是一致的fs_init()、fs_mount()、fs_openbypath()、fs_file_close()、fs_fs_close()、decoder_init()、decoder_io()、decoder_stop()。8如果你要做“音乐模式扫描整个 SPIFlash”就用 FAT 扫描接口不要自己递归目录官方 FAT 文件系统接口里已经给了vfs_fscan_new()并且参数写得很清楚-tMP1MP2MP3WAVTXT表示扫描哪些后缀-sn按文件号排序-st按时间排序-r递归子目录。所以你扫描 MP3/WAV 的典型参数可以写成staticconstcharscan_arg[]-tMP1MP2MP3WAV -sn -r;如果你希望/MUSIC目录和子目录全部参与就递归扫如果只扫根目录就别加-r。这一步和“为什么复制进去了却找不到歌”直接相关。9模式切换必须做资源互斥PC 模式和音乐模式不能同时抢这块盘同体系小音箱文档明确提到不同模式之间有资源互斥进入模式时初始化资源退出模式时释放资源。这在你这里的现实含义就是PC 模式时USB 正在把 SPIFlash 当盘给电脑用音乐模式时本机自己要挂 FAT 并打开 MP3 文件这两个状态不能并发。所以切模式的正确顺序一定是通知退出 PC 模式关闭 USB mass storage等待 PC 端写入完成 / 断开本机重新 mount FAT扫描并播放这个顺序不对就会出现“电脑刚写完设备一切模式就文件坏掉”“mount 失败”“歌单为空”等问题。10如果你已经有官方 music mode那最推荐的“接法”其实是下面这样如果你工程里已经有music_play_control()这种现成音乐模式控制接口那你不要绕过它。你只需要给 extflash 分配一个设备号EXTFLASH_INDEX在设备表里注册它让音乐模式选择这个设备再按文件序号播放代码逻辑可以是boolplay_extflash_by_music_mode(u8 extflash_dev_index,u32 file_index){if(!music_play_control(DEV_CMD_SEL_NEW_DEV,extflash_dev_index,NEED_WAIT)){returnfalse;}if(!music_play_control(FILE_CMD_PLAY_BY_INDEX,file_index,NEED_WAIT)){returnfalse;}returntrue;}这里的music_play_control()、DEV_CMD_SEL_NEW_DEV、FILE_CMD_PLAY_BY_INDEX都是官方同体系 music mode 文档里明确存在的接口/命令。你真正要补的是“extflash_dev_index 在你 BR25 工程里对应哪个设备号”。方案 B量产时预置 MP3 到 SPIFlash然后音乐模式直接播放如果你不是“每次都让 PC 往里拷歌”而是希望出厂时 SPIFlash 已经带好 MP3那就走量产预置。这个方案非常适合工厂批量烧录。官方文档已经给出外挂 Flash 资源烧写链路用packres.exe再通过-ex_flash xxx烧到外挂 Flash外挂 Flash 的引脚和 IO 宽度通过EX_FLASH/EX_FLASH_IO配置。官方示例里甚至直接说明了download.bat支持-ex_flash准备下载到外挂 Flash 的文件需要先用packres.exe指定地址再打包例如把dir_song打成dir_song_ext再-ex_flash dir_song_ext烧进去。所以量产版通常是在 PC 上准备 FAT 镜像/目录包用工具打包通过-ex_flash烧入 SPIFlash设备启动到音乐模式后直接扫歌播放这个方案的优点是不依赖终端用户先进入 PC 模式再拷歌出厂就是带内容的生产一致性更高缺点是后续改歌需要重新做镜像/重烧开发期不如方案 A 灵活方案 C不接完整 music mode自己挂 FAT 后按路径直接播放适合快速验证如果你只是想先把“SPIFlash 里的 MP3 播出来”验证通不想一上来就接整套音乐模式设备管理那可以先走“按路径播放”这条轻量路线。原因很简单文件系统层负责fs_mount()/fs_openbypath()解码层负责decoder_init()/decoder_io()官方文档已经把这两部分 API 给全了。也就是说你可以先固定规定PC 模式把文件放到/MUSIC/001.MP3音乐模式一进来直接播放/MUSIC/001.MP3等路径打通后再接入完整歌单扫描、上一曲、下一曲、断点续播。这个方案适合先验证 SPIFlash/FAT/解码链路先排除 USB、SPI、FAT、MP3 解码到底是哪层有问题快速做 demo但它不适合长期产品化因为你最终还是会想要完整的音乐模式行为。✅️问题延伸你这个场景里最容易混淆的是4 种“Flash 里的音频存放方式”。我帮你彻底捋顺一下1sydfs只读资源系统它本质更像“固件资源区”适合放固定资源不适合做“PC 拷 MP3 再播”。官方文件系统文档里把它定义为只读文件系统。2norfs循环覆盖型它更适合录音、日志、循环覆盖数据不是给用户当 U 盘拖 MP3 的。官方文档把它定义为针对 norflash 的循环覆盖可读写文件系统。3fatfs最适合你现在这个需求因为你的需求是PC 能拖文件进去音乐模式能扫目录能按文件名/路径/序号选择这些全是 FAT 场景。官方文档里 fatfs 支持搜索、支持 FAT12/16/32 和 EXFAT并给了完整扫描接口。4EXTFLASH它不是文件系统而是“被拿出来的一块 Flash 设备”。你需要在这个设备之上再挂fat然后它才能成为“音乐盘”或“PC 盘”。官方文档正是这么描述的先把 Flash 空间作为 EXTFLASH 设备再挂文件系统甚至再枚举成 mass_storage。所以一句话总结EXTFLASH 是设备层FAT 是文件系统层music mode 是应用层decoder 是解码层。你要的是把这四层串起来而不是把它们混成一层。✅️问题预测下面我直接预测你后面最容易踩的坑并把原因讲透。预测 1PC 已经能看到盘但音乐模式就是扫不到 MP3这通常不是解码器问题而是扫描路径 / 扫描参数 / 文件系统挂载对象的问题。重点检查音乐模式挂的到底是不是SPIFlash 对应的 FAT 设备扫描路径是不是/或/MUSIC有没有加-r递归子目录扫描参数里有没有把MP3后缀加进去。官方 FAT 扫描参数就是这么定义的。预测 2PC 模式能写切到音乐模式后 mount 失败大概率是下面几类问题模式切换时 USB 资源没完全退出PC 还没安全完成写入你就切模式了SPIFlash 根本没按 FAT 格式化EXTFLASH 指向的地址范围不对因为官方模式管理本身就强调“模式间资源互斥”同时 EXTFLASH 也明确依赖正确的EXTFLASH_ADR / EXTFLASH_LEN配置。预测 3复制进去的是歌但播放时报文件错误/同步错误这时你要重点看decoder_io()的dec_ctl有没有带BIT_MP3_ST打开的是否真的是.mp3文件文件句柄是不是 FAT 打开的文件而不是错误设备上的路径是否用了错误的文件名/路径官方文档说明decoder_io()会根据你给的控制位参与相应格式解码其中标准 MP3 是通过BIT_MP3_ST进入轮询的。预测 4外挂 Flash 烧录没问题但 PC 模式完全看不到盘这类问题更偏底层EX_FLASH/EX_FLASH_IO配错数据宽度 0/2/4 选错SPI 引脚接错供电脚配置不对板级 SPI 端口和下载工具配置不一致官方文档已经把EX_FLASH和EX_FLASH_IO的格式定义清楚了如果这层错了上层全白搭。预测 5你会想直接用flash_read_buff()去播 MP3这个方向能不能做理论上能但不适合你当前目标。因为你当前目标是PC 模式可写音乐模式可扫后面还能上一曲/下一曲/目录播放这天然就是文件系统播放器而不是“原始 flash 流播放器”。官方底层 flash API 更适合做裸读写测试、参数区、固定地址数据不是你现在这条产品链路的最佳入口。预测 6你后面会遇到“到底走现成 music mode还是自己写播放逻辑”的选择我给你非常明确的判断标准产品要做完整功能走现成music_play_control()/mbox_simple_play_file()路线只是先验证链路先写fs_openbypath() decoder_io()的轻量验证代码因为官方 music mode 已经把设备切换、文件切换、播放控制做成现成框架了。你如果本来就在 soundbox/mbox 工程上开发复用它的成本远低于自己重写一套。✅️小结把这件事浓缩成一句最实用的话在 AC696X/BR25 上要实现“PC 模式写 MP3 到 SPIFlash音乐模式播放”最佳实践就是把 SPIFlash 做成 EXTFLASH FAT 设备在 PC 模式下枚举成 USB 大容量存储电脑把 MP3 拷进去切到音乐模式后再把同一设备挂成 FAT扫描 MP3最后通过decoder_io()或现成music_play_control()播放。真正落地时你最该优先做的 4 件事是先确认 SPIFlash 硬件和EX_FLASH / EX_FLASH_IO配置没错PC 模式把它成功枚举成 U 盘确认 FAT 挂载和文件扫描 OK最后再接 music mode 的设备表和播放控制 结语 互动说明希望以上分析与解决思路能为你当前的问题提供一些有效线索或直接可用的操作路径。若你按文中步骤执行后仍未解决不必焦虑或抱怨这很常见——复杂问题往往由多重因素叠加引起欢迎你将最新报错信息、关键代码片段、环境说明等补充到评论区我会在力所能及的范围内结合大家的反馈一起帮你继续定位 如果你有更优或更通用的解法非常欢迎在评论区分享你的实践经验或改进方案你的这份补充可能正好帮到更多正在被类似问题困扰的同学正所谓「赠人玫瑰手有余香」也算是为技术社区持续注入正向循环 文末福利技术成长加速包 文中部分问题来自本人项目实践部分来自读者反馈与公开社区案例也有少量经由全网社区与智能问答平台整理而来。若你尝试后仍没完全解决问题还请多一点理解、少一点苛责——技术问题本就复杂多变没有任何人能给出对所有场景都 100% 套用的方案。如果你已经找到更适合自己项目现场的做法非常建议你沉淀成文档或教程这不仅是对他人的帮助更是对自己认知的再升级。如果你还在持续查 Bug、找方案可以顺便逛逛我专门整理的 Bug 专栏《全栈 Bug 调优实战版》️这里收录的都是在真实场景中踩过的坑希望能帮你少走弯路节省更多宝贵时间。✍️如果这篇文章对你有一点点帮助欢迎给 bug菌 来个一键三连关注 点赞 收藏你的支持是我持续输出高质量实战内容的最大动力。同时也欢迎关注我的硬核公众号 「猿圈奇妙屋」获取第一时间更新的技术干货、BAT 等互联网公司最新面试真题、4000G 技术 PDF 电子书、简历 / PPT 模板、技术文章 Markdown 模板等资料通通免费领取。你能想到的绝大部分学习资料我都尽量帮你准备齐全剩下的只需要你愿意迈出那一步来拿。 Who am I?我是 bug菌热活跃于 CSDN | 掘金 | InfoQ | 51CTO | 华为云 | 阿里云 | 腾讯云 等技术社区CSDN 博客之星 Top30、华为云多年度十佳博主/卓越贡献者、掘金多年度人气作者 Top40掘金、InfoQ、51CTO 等平台签约及优质作者全网粉丝累计30w。更多高质量技术内容及成长资料可查看这个合集入口 点击查看 ️硬核技术公众号「猿圈奇妙屋」期待你的加入一起进阶、一起打怪升级。- End -
返回列表