第二章:系统架构设计——车载音响系统硬件架构、软件分层架构、OTA升级模块在整个系统中的位置
好,咱们进入正题。这一章我打算聊聊系统架构。说实话,很多刚入行的朋友容易忽略架构设计,上来就写代码。我年轻时也犯过这毛病,结果项目后期改得想哭。你想想看,音响系统OTA升级,如果架构没搭好,后面全是坑。
2.1 车载音响系统硬件架构
先看硬件。车载音响系统不是你家那台蓝牙音箱,它复杂得多。我习惯把硬件分成三个域:
- 主控域:核心SoC,跑操作系统和上层应用。常见的有高通SA8155、瑞萨R-Car系列。OTA升级的主逻辑就在这里。
- 音频DSP域:专门处理音频算法的芯片,比如ADSP、TI的DA8xx。它负责音效、降噪、均衡器。OTA升级时,DSP固件也得跟着升。
- 功放域:功率放大芯片,直接驱动喇叭。有些高端功放也带MCU,需要独立升级。
关键点:这三个域之间通常用I2S传音频流,用I2C/SPI传控制命令。OTA升级时,主控域通过内部总线把固件分发给DSP和功放域。
我在项目中遇到过一个问题:DSP域和主控域之间的通信协议没统一,结果升级包传一半就断了。后来我们强制要求所有域都支持A/B分区升级,才彻底解决。
2.2 软件分层架构
软件架构我建议分四层。为什么是四层?因为我在多个项目里试过三层和五层,最后发现四层最舒服。
| 层级 | 职责 | OTA相关 |
|---|---|---|
| 应用层 | UI交互、音源管理、设置 | 显示升级进度、用户确认 |
| 服务层 | 音频策略、设备管理、OTA服务 | 下载管理、版本校验、回滚逻辑 |
| 中间件层 | 通信协议、文件系统、安全模块 | HTTPS下载、签名验证、分区管理 |
| 驱动层 | 硬件抽象、外设驱动 | Flash擦写、看门狗、电源管理 |
说白了,每一层只管自己的事。应用层不知道底层怎么擦Flash,驱动层也不关心用户点了什么按钮。这种解耦在OTA升级时特别重要——你想想看,如果升级过程中应用层崩溃了,底层还能继续写分区吗?
我的习惯:在服务层单独放一个OTA Manager模块。它不依赖任何UI组件,即使屏幕黑了,升级也能跑完。我曾经在一个项目里就是因为UI线程卡死,导致升级中断,车机变砖。从那以后,OTA Manager必须独立于UI进程。
2.3 OTA升级模块在整个系统中的位置
OTA升级模块不是孤立的。它像一根线,串起了整个系统。我画个逻辑图给你看:
+-------------------+ +-------------------+
| 应用层 (UI) | <---> | OTA Manager |
| - 升级进度条 | | - 下载引擎 |
| - 用户确认弹窗 | | - 版本比对 |
+-------------------+ | - 回滚控制 |
| +--------+----------+
| IPC通信 |
v v
+-------------------+ +-------------------+
| 服务层 | | 中间件层 |
| - 音频策略 | | - HTTPS下载 |
| - 设备管理 | | - 签名验证 |
+-------------------+ | - 分区管理 |
+--------+----------+
|
v
+-------------------+
| 驱动层 |
| - Flash驱动 |
| - 看门狗 |
+-------------------+
注意看,OTA Manager横跨了应用层和服务层。为什么?因为下载和校验必须在服务层做,但用户交互又离不开应用层。我建议把OTA Manager拆成两个子模块:
- OTA Core:放在服务层,负责下载、校验、分区切换。它不依赖任何UI。
- OTA UI:放在应用层,负责显示进度、处理用户确认。它通过IPC调用OTA Core。
避坑指南:我曾经把OTA Core和OTA UI放在同一个进程里,结果升级过程中UI卡死,Core也跟着挂了。后来我强制它们分进程运行,OTA Core跑在独立的守护进程里,即使UI崩溃,升级照常进行。
2.4 升级流程中的架构协作
一个完整的OTA升级流程,各层是怎么协作的?我拿实际项目举例:
- 应用层:用户点击「检查更新」,OTA UI发送请求给OTA Core。
- 服务层:OTA Core连接云端,下载升级包。同时通知中间件层准备存储空间。
- 中间件层:HTTPS下载完成后,进行签名验证。验证通过后,把固件写入备用分区。
- 驱动层:执行Flash擦写操作。注意,这里要关中断,防止写入过程中被打断。
- 回滚准备:写入完成后,OTA Core设置启动标志,指向新分区。如果下次启动失败,看门狗会触发回滚。
嗯,这里要注意:驱动层的Flash擦写是最容易出问题的环节。我建议在驱动层加一个超时保护,如果擦写超过5秒没完成,强制复位。否则一旦卡死,整个系统就瘫了。
2.5 架构设计的几个原则
最后,我总结几条原则。这些是我踩过坑后总结出来的:
- 隔离性:OTA模块必须独立于业务逻辑。业务代码可以随便改,但OTA模块的接口不能变。
- 原子性:升级要么全成功,要么全回滚。不能出现一半新一半旧的情况。
- 可观测性:每一层都要有日志输出。我习惯在驱动层、中间件层、服务层各留一个日志缓冲区,升级失败时能快速定位问题。
- 降级能力:如果升级过程中电量不足、信号丢失,系统要能优雅降级,而不是直接变砖。
一句话总结:架构设计不是为了好看,是为了让你在出问题时能睡得着觉。OTA升级模块就像汽车的刹车系统——平时用不上,但一旦需要,它必须可靠。
好,这一章就到这里。下一章我会详细讲升级包的生成和签名流程,那是另一个容易踩坑的地方。