电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 基于Zephyr的STM32H7S78-DK影音系统

共1条 1/1 1 跳转至页

基于Zephyr的STM32H7S78-DK影音系统

高工
2026-11-13 14:15:51     打赏
基于 Zephyr 的 STM32H7S78-DK 影音系统

在一块 STM32H7S78-DK 开发板上,我们用 Zephyr 从零搭了一套完整的掌上影音系统: 开机进启动器,左右滑动翻页,图标点进应用——网络收音机、SD 卡 MP3 播放、 AVI 视频有声播放、逐小时天气预报,四个应用共用一套音频管道和一套 UI 框架。 本文介绍这套系统的设计思路、Zephyr 带来的开发体验,以及一路沉淀下来的编程心得。

启动器页面.jpg

一、开发板简介:小身材,全是硬货

STM32H7S78-DK 是 ST 新一代 H7RS 系列的官方开发板,几个关键资源决定了这套 系统的形态:

资源规格在系统里干了什么
MCUCortex-M7 @ 600MHz全部软件解码(MP3/JPEG)、UI 渲染
内部存储64KB BootFlash + 456KB SRAMMCUboot 引导、内核/栈/热点缓冲
外部 Flash128Mbit Octo-SPI(XiP)应用程序直接在上面执行(XiP)
PSRAM256Mbit Hexadeca-SPI(32MB)视频帧缓冲、音频块、JPEG 队列
显示800×480 RGB 屏 + LTDCLVGL 主界面
触摸GT911 电容触摸(I2C)全部交互
音频WM8904 codec + I2S6 + GPDMA48kHz 立体声输出,耳机/喇叭接口
网络10/100M 以太网收音机流、天气 API、NTP 对时
SD 卡槽SDMMC1 4bitMP3/视频片源
GPUNeoChrom(2.5D)+ DMA2D位图搬运/旋转/缩放加速(GPU 对比演示)

设计上的两个关键认识:

  1. "小内部 + 大外部"的存储结构是 H7RS 的特点。64KB 片内 flash 只够放 MCUboot,应用必须在外部 Octo-SPI Flash 上 XiP 运行;456KB SRAM 放内核、 栈和性能热点,32MB PSRAM 是所有大缓冲的家(视频双缓冲 2×240KB、 JPEG 队列 2×100KB、音频块 8×9KB 全在里面)。

  2. 外设组合天然就是一台播放器:屏+触摸做 UI,I2S+codec 出声,以太网 拿流,SD 卡存片源。软件要做的是把它们用一条干净的数据流串起来。

二、为什么是 Zephyr:这套系统里它实际帮了什么

选 Zephyr 不是因为它流行,而是这个项目里每一层都直接受益:

1. 板级支持开箱即用。 这块板在 Zephyr 官方板列表里,LTDC 显示、GT911 触摸、以太网、SDMMC、PSRAM 的设备树描述都是现成的。我们要做的只是在自己的 overlay 里补外设细节(比如给 sdmmc1 补 pinctrl 和时钟选择),不写一行 寄存器代码。

2. 统一的驱动模型。 display / input / audio codec / sdhc / phy / ethernet 全是同一套 device 抽象。应用层面对的不是某家芯片的 HAL,而是稳定 API—— 这也是后面"一条音频管道喂三种音源"能成立的前提。

3. 原生网络协议栈。 DHCP、DNS、TCP socket、SNTP 全是 Kconfig 打开就有。 网络收音机就是一个普通 socket 流;天气预报是 socket 上的 HTTP GET; 状态栏时间是 SNTP 对时。没有移植任何第三方协议栈。

4. LVGL 是官方模块。 CONFIG_LVGL=y 一行,GUI 就进来了,显示驱动和 触摸输入自动接到 LVGL 的 indev/display 框架。中文字库用 lv_font_conv 子集化生成(ASCII + 几十个汉字,24px 只有几十 KB)。

5. 内核对象让并发架构很干净。 这套系统有 7 个线程(UI、收音机解码、 MP3 解码、视频 reader、视频 decode、音频 TX、网络),全靠消息队列、 内存 slab、事件、优先级组合起来,没有一把大锁,没有共享变量乱飞。 线程模型本身就是设计文档。

6. west / sysbuild / MCUboot 生态。 --sysbuild 一条命令同时编出 MCUboot 和应用,west flash 烧外部 flash 还带 ExternalLoader。 引导 + XiP 这套在别的 RTOS 上要自己攒半天的东西,这里是默认路径。

7. Kconfig 裁剪直面资源约束。 456KB SRAM 用到了 91%,每一 KB 都要 交代:LVGL 堆 128KB、网络缓冲、字体、栈……Kconfig 让"这块内存从哪来、 给谁用"全部是显式声明。

三、系统设计思路

3.1 启动与运行形态

上电 → MCUboot(片内 64KB)→ 校验/跳转 → 应用在外部 Octo-SPI Flash XiP 运行

应用镜像约 820KB(含字体、minimp3、tjpgd),放在 128Mbit 外部 flash 的开头, 后续还可以做 OTA 双槽升级——MCUboot 的 slot 机制是现成的。

3.2 UI 框架:启动器 + 应用页,进入载入 / 离开释放

┌──────────────────────────────────────────┐
│ 悦聆   11-12 14:30   ● IP:192.168.3.27   │ ← 每页统一的顶栏(时钟/网络状态)
├──────────────────────────────────────────┤
│              Zephyr                      │
│              影音系统                     │
│  ┌────┐  ┌────┐  ┌────┐  ┌────┐         │
│  │MP3 │  │视频 │  │收音│  │天气 │  ◀ 滑动 │
│  └────┘  └────┘  └────┘  └────┘         │
└──────────────────────────────────────────┘
  • 启动器是 tileview,左右滑动翻页;每个应用是独立 screen,lv_screen_load_anim切页动画。

  • 进入载入、离开释放:主循环 100ms 跟踪页面切换,离开收音机页就停台断流 (释放音频管道和网络连接,后台不留任何活动任务),进入时自动续播上次的台。 这条规则让每个应用的资源生命周期一目了然——你在哪个页面,就只有哪个 应用在消耗 CPU/带宽。

3.3 一条音频管道,三种音源

网络收音机(HTTP 流) ┐
本地 MP3(SD 卡)     ├→ minimp3 解码 → 线性插值重采样到 48.118kHz
AVI 音轨(MP3/PCM)  ┘                          │
                          频谱分析(Goertzel 8 频带)│
                                              ▼
                              块队列(8 块 × 48ms,PSRAM)
                                              ▼
                              TX 线程 → GPDMA 循环 → I2S6 → WM8904
  • 重采样统一格式:任何音源、任何采样率/声道数,先重采样到固定的 48.118kHz 立体声,下游完全不用关心来源。

  • 反压即真实时间:队列满时 audio_write_pcm 阻塞,生产者自然贴着 播放速率走——不需要任何定时器去"算"音频节奏。视频音画同步也建立在 这个性质上(音频做主时钟,视频帧按 PTS 追它)。

  • 频谱是免费副产品:PCM 流经时顺手做 Goertzel 8 频带能量分析, 所有页面的频谱柱共用这份数据。

3.4 线程模型与优先级

线程优先级职责
音频 TX5(最高)块队列 → DMA,欠载时填静音
收音机解码 / MP3 解码6流解帧 + minimp3 + 重采样
视频 reader7读 AVI、喂音频(主时钟路径)
视频 decode9JPEG 解码、PTS 对时送显
UI 主循环10(最低)LVGL 渲染、页面管理

原则就一条:音频链条上的线程永远比 UI 优先级高。800×480 软件渲染 动辄几十毫秒,如果 UI 能抢占解码线程,声音必断。

3.5 内存布局

区域大小放什么
SRAM(91% 已用)456KB内核/栈、LVGL 堆 128KB、ETH DMA 区(nocache)、tjpgd 工作区 16KB
PSRAM32MB视频帧双缓冲、JPEG 帧队列、音频块、LTDC 显存
外部 Flash(XiP)16MBMCUboot slot + 应用镜像 ~820KB

四、主要功能

4.1 启动器:Zephyr 影音系统

深蓝灰主题,白色 "Zephyr" 48 号大字 + 青色"影音系统",四个应用图标 均布一行,tileview 左右滑动翻页,第二页留给以后的新应用。 顶栏常驻:品牌名、NTP 对时的实时时钟、网络状态圆点和 IP。 (题图即启动器页面)

4.2 网络收音机

  • 10+ 个国内台(中国之声、经济之声、各地交通/音乐台),中文台名, 点台即播,换台自动重连;掉线 3 秒自动重连。

  • 播放/暂停、停止、音量滑杆、1kHz 自测音、8 频带实时频谱柱。

  • 离开页面自动释放(停台断流),回来自动续播——后台绝不偷跑流量和 CPU。

收音机.jpg

4.3 本地 MP3 播放

  • SD 卡(FATFS)根目录扫描建库,长文件名原样显示,最多 32 首。

  • 播放/暂停(断点续播)、上一首/下一首、播完自动回卷、进度条。

  • 热插拔:拔卡自动停播卸载,插卡自动挂载重扫,列表实时重建。

MP3播放器.jpg

4.4 AVI 视频播放

  • 支持 .vid 裸 RGB565 帧流和 .avi(MJPEG 视频 + PCM/MP3 音轨), ffmpeg 一行命令转码,拷卡即播。

  • 纯软件解码:tjpgd 解 JPEG(约 15ms/帧),minimp3 解音轨, 400×300@15fps 流畅有声。

  • 音画同步:音频主时钟 + 视频 PTS 追帧,拥塞时丢帧保音频, 声音全程连续。

  • 自研 RIFF 容器解析约 300 行,无需任何外部库。

视频播放.jpg

4.5 天气预报

  • Open-Meteo API(免 key)按坐标取逐小时预报(广西资源县), 48 小时逐小时列表:时间、WMO 天气码手绘图标(晴/多云/阴/雨/雪/雷暴)、 温度(0.1°C)、中文天气描述。

  • NTP 对时后从"当前小时"开始显示并高亮标记,07:00 行单独配色。

  • 时间、联网状态、图标全部自绘,无外部图片资源。

天气预报.jpg

4.6 附赠:GPU 渲染对比演示(独立工程)

另外做了一个渲染器对比 demo:同一 LVGL 场景分别用 CPU 软渲染 / DMA2D / NeoChrom GPU 绘制,按键循环切换,日志实时输出 FPS / 单帧渲染耗时 / CPU 占用率,并支持大画布放 PSRAM 做压力测试。 直观回答了"这颗 2.5D GPU 到底快多少"。

MP3播放器.jpg

五、编程心得

1. 先把子系统用足,再自己造轮子。这套系统里我们自己写的"底层"只有两处:AVI 容器解析(300 行,因为没有 现成嵌入式库)和一个 GPDMA 循环 I2S 发送层(因为通用逐块重载驱动不合适)。 其余全部站在 Zephyr 子系统上。自己写的越少,出问题的面越小。

2. 并发设计让"反压"和"节奏"替你工作。音频不卡顿靠的不是调参,而是结构:队列满则生产者阻塞(节奏自动对齐)、 时间关键的线程优先级高于 UI、视频拥塞时丢帧而不是阻塞。把时序正确性 建立在结构上,比建立在"每次都来得及"的侥幸上可靠得多。

3. 内存规划要先行。H7RS 这种"小 SRAM + 大 PSRAM"的结构,动手之前先画内存地图:谁是性能 热点(解码工作区、LVGL 堆)留 SRAM,谁是大块头(帧缓冲、音频块、显存) 去 PSRAM。到 91% 占用才发现没规划,返工成本很高。

4. 用数据调试,不用想象调试。几乎每个关键决策都来自计数器:SD 读速基准(2MB/s)、每帧解码耗时、 音频输入/输出样本比(1.0909 = 48118/44100,证明播放速率分毫不差)、 欠载计数(silence 增量)。嵌入式调试器(GDB + openocd)不只能看崩溃, 更是最好的"示波器"——XiP 系统上记住只用变量读写和寄存器查看, 不做函数调用。

5. UI 只是众多任务之一。LVGL 很能吃 CPU(800×480 软渲染),把它当成最低优先级线程、给实时 任务让路,触摸输入队列按事件速率配深度,界面就既流畅又不影响音视频。

6. 状态机胜过标志位。每个播放器(收音机/MP3/视频)都是"NO_CARD / EMPTY / IDLE / PLAYING / PAUSED / ERROR"一张小状态表,UI 刷新只读状态字符串。页面进入/离开 时的载入释放,也只是在状态机外面包了一层。状态清晰,bug 就少一半。

六、源码结构

app/net_radio/                    # "悦聆"影音系统主工程
├── prj.conf                      # Kconfig:网络/LVGL/音频/SD/输入,全部显式声明
├── boards/…ext_flash_app.overlay # sdmmc1/ETH nocache/PLL2 等板级补丁
├── src/
│   ├── main.c                    # 启动器 + 各应用页 + 页面生命周期管理
│   ├── net_radio.c/net_stream.c  # 网络收音机(socket 流 → minimp3)
│   ├── mp3_player.c              # SD 卡 MP3(挂载/扫描/热插拔/解码线程)
│   ├── video_player.c            # 视频扫描 + PSRAM 双缓冲 + reader 线程
│   ├── avi_player.c              # AVI 容器解析 + 音画同步 + decode 线程
│   ├── audio_sai.c               # 统一音频管道(块队列 → GPDMA → I2S6/WM8904)
│   ├── pcm_util.c                # 重采样 + Goertzel 频谱
│   ├── weather.c/time_sync.c     # Open-Meteo 天气 + SNTP 对时
│   ├── tjpgd/                    # JPEG 解码器(改 RGB565 直出)
│   └── fonts/lv_font_cjk_24.c    # 中文字库(子集化生成)
└── sd_files/                     # 示例片源(demo.vid / *.avi)

整套系统从零到四个应用可用,核心代码约 5000 行,其中八成在描述 "数据怎么流",两成在描述"界面长什么样"——这大概就是用 Zephyr 做 多媒体产品最舒服的比例。

七、开源

我已经将代码开源到了gitee:lugl/stm32h7s78-zephyr






关键词: Zephyr     STM32H7S78-DK     影音     系    

共1条 1/1 1 跳转至页

回复

匿名不能发帖!请先 [ 登陆 注册 ]