embedded software architecture
软件架构设计方案
一、概述
本文档给出 Viper V2 产品中 MCU1(Cortex-M7)的软件架构设计方案。
核心分层思想:
SOC板级芯片能力在 Adapter/hal 层封装
产品外设基础能力在 Module 层实现
通用业务逻辑流程在Service 层实现
产品功能逻辑实现在 Application 层实现
目的
- 目的:为什么要对 MCU1 建立分层的软件架构,架构要解决什么问题、达成什么目标。
- 架构图与分层结构:MCU1 软件由哪几层组成,每层放什么,模块如何划分。
- 各层职责:每层的准确定位、职责清单与明确禁止事项。
- 核心设计原则:全项目统一遵守的架构约束,及其在 Viper V2 产品上的落地。
- 分层调用关系:运行期调用链、初始化装配关系、并发模型,落实高内聚、低耦合。
- 如何判断放置哪一层:新功能、新模块的落层判断方法与规则,避免后期层次腐化。
范围与边界
| 对象 | 是否在范围内 | 说明 |
|---|---|---|
| MCU1(M7) | ✅ 本文档全部覆盖 | Viper V2 的时序控制核心,承担产品业务、通用服务、外设与器件能力封装 |
| MCU0(DCLS) | ❌ 不在范围内 | 安全控制核,负责引导、镜像认证加密、时钟电源配置与上电加载 |
| Q8 DSP | ❌ 不在范围内 | 信号处理核,负责频谱与点云 peaks 解算 |
MCU1 硬件功能背景
芯片接口与板级外设
- MCU1 是 Viper V2 的时序控制核心,其使用的芯片总线接口单元包括 HSADC、CAPCOM、AWG&DAC、HKADC、HKDAC、2.5G XGMAC、I2C、SPI、UART、PVT Monitor 等;
- Viper V2 产品外设包括转镜电机与驱动板、Chirp Laser驱动板、IMU单元、主控FPGA板,电源电压/温度监控、看门狗芯片、NetWork网络单元、 LiDAR采集处理单元。

关键实时性约束
以下约束直接决定了分层中哪些能力必须下沉到 Module/Adapter 层、哪些必须留在 Application/Service 层,是架构设计的硬性输入。
| 约束 | 架构影响 |
|---|---|
| 棱镜 20Hz 扫描周期,4 个面,每面有效扫描 80°,盲区 10°/面 | 单个扫描周期内必须完成”点云输出模式 ↔ 状态信息监测模式”的硬切换,调度逻辑必须集中在 Application 的 scan_ctrl 中,且切换动作须是无阻塞、无浮点重计算的 |
| 盲区时间约 5.5ms | 盲区内要串行完成多项监测采集 + 结果输出,因此各监测采集必须模块化、可并发触发,且数据结构需预先分配 |
| 激光—采样对齐精度 ≤ 60ps | 运行时禁止切换 Acquisition PLL 派生时钟,时钟配置只能在启动阶段完成——时钟与 PLL 相关能力必须收敛在 Adapter/sdk 并加保护 |
| 点云 UDP 零拷贝低延迟传输(双 Buffer 2×1500B + 信号量) | 传输路径上禁止任何 memcpy 与阻塞等待,Payload报文组装(service/transport)与网卡发送(modules/net)必须以 Buffer 所有权交接 |
| 看门狗喂养频率 80Hz | 看门狗喂养收敛到单一服务(service/ska),禁止多处散喂 |
二、核心设计原则
职责要单一,依赖要单向,变化要隔离。
分层的本质是:通过明确各层的职责边界和依赖方向,隔离变化的传播,降低维护成本。
分层的意义是:把系统中不同类型的变化,控制在各自应该存在的边界以内;减少降低可控风险,增强系统稳定 —— 这也是软件架构真正的价值所在。
分层不是为了目录好看或显得专业,而是解决嵌入式项目长期维护的问题。
要解决的问题
| 变化类型 | 典型场景 | Viper V2 MCU1 中的收敛边界 |
|---|---|---|
| 平台变化 | SoC 更换、SDK 升级、RTOS 替换、启动文件调整、时钟树调整 | 收敛在 Adapter(sdk / hal / osif / bsp)层 |
| 板级变化 | GPIO 引脚调整、UART/SPI/I2C 实例变更、DMA 通道变化、中断映射调整 | 收敛在Module 的 driver 子层 |
| 外设变化 | IMU单元 / 电源监测芯片 / 电机驱动板/看门狗芯片切换 | 收敛在 Module 层的对应外设模块(pubif对外接口不变,driver更换实现) |
| 业务变化 | 状态机调整、扫描策略升级、监测判定逻辑变更、参数定义变更 | 收敛在 Application 与 Service 层 |
核心设计原则
- 单一职责:一个模块只做一类事,不混职责——避免一边读传感器,一边做业务判断再顺手转发协议。
- 高内聚、低耦合:内部逻辑紧密相关,对外暴露接口尽量少,改内部不影响上层功能。
- 接口清晰:通过稳定接口交互,而非 extern 全局变量到处穿透;头文件声明清晰 API,输入输出、生命周期、错误码明确。
- 隐藏实现细节:上层只关心”做什么”,不关心是 SPI 还是 I2C、是 DMA 还是轮询、是哪个 HSADC 通道。
- 禁止越层访问:不能绕过中间层下探。Application 不直接访问HAL层,Service 不直接访问寄存器,Module 不越过 HAL 触碰厂商 SDK 私有 API。
- 可替换:换 SoC 时 Application 保持不改,换外设器件时业务保持不动,换SOC板卡时 Modules/Service 尽量稳定。
- 面向接口编程:依赖稳定抽象而非具体实现——上层依赖”能力”,不依赖”某个具体实现细节”。
HAL 与 Module 的职责边界
这是最关键的一条边界规则,也是本次架构划分与传统”按芯片外设建模块”做法的根本区别。
- 芯片能力一律在 HAL:凡是芯片提供的、带有寄存器与硬件时序属性的能力(ADC 采样、波形发生、捕获比较、PVT电压温度监测、以太网收发……),一律由厂商在 BSP/SDK 给出接口,MCU侧统一在 HAL 层做二次封装。Modules 层不得直接访问 SDK 私有 API接口。
- 产品语义一律在 Module:凡是”产品要做什么”的封装,一律在 Module 层基于 HAL 接口实现。模块命名必须体现产品语义(laser、motor、chip_monitor),不得以芯片外设命名(不得出现 hsadc 模块、awg 模块、xgmac 模块)。
- 判据:把这个能力换一颗芯片还成立吗?成立 → 属 Module(如”转镜电机”);不成立 → 属 HAL(如”HW ADC 通道 3 的采样”)。
- 一份芯片能力只封装一次:同一芯片能力被多个 Module 复用时,HAL 只提供一份封装,Module 之间共享该 HAL 接口,不各自重写寄存器访问。
- Module 内部分为三层:每个模块内部按 pubif / middle / driver 三层——pubif 暴露模块能力接口,middle 承载私有协议与关键框架(可选),driver 调用 HAL 芯片能力接口并屏蔽硬件时序。
三、总体软件架构
架构总览
下面是Viper V2 MCU1 软件分层架构总览:
- 自上而下为 Application、Service、Module、Adapter 四层主链;
- 右侧为可复用的Middleware中间层,底部为硬件芯片层;
- 向下实线箭头表示标准 API 的单向调用方向,向上虚线箭头表示注册回调与事件的异步上报;
- Module 层中每个模块都展开为 pubif / middle / driver 三层,并在 driver 子层标出其依赖的 HAL 芯片能力。

分层描述:
Adapter:适配层,主要负责SOC芯片平台的硬件适配和RTOS的适配。相同芯片使用同一分支管理。
- common:芯片平台优先需要适配的基础能力,包括logger,assert,delay、cli组件和其他和芯片编译配置强相关组件。
- hal:对芯片的总线通信接口进行封装,确保对外提供的api一致,起到屏蔽硬件差异的作用。
- osif:对操作系统的能力抽象和封装,确保对外提供的api一致,起到屏蔽os差异的作用。
Middleware:使用到的第三方库和自己实现的基础能力库。所有项目使用同一分支管理。
Module:对产品外设模块的能力封装,单个modules对外提供该模块的所有能力接口,供上层调用。屏蔽相同模块不同硬件的差异。每个项目有个分支管理。
- 每个module内部可以根据实际情况从上到下分为pubif,middle,driver三层 或者pubif,driver两层。
- pubif是(public interface缩写)对外提供的接口
- middle是这个模块的协议或者关键实现框架
- driver为该模块的驱动实现
Service:可复用业务逻辑中的通用流程,作为稳定的业务支撑服务。不同项目维护不同分支。
Application:具体产品业务逻辑的不同实现,不同项目维护不同分支。
分层概述
| 层级 | 定位 | 职责 | 包含模块 | 代码路径 |
|---|---|---|---|---|
| Application应用层 | 产品业务逻辑 | 实现 Viper V2 的业务应用:状态机、扫描调度、调制与点云编排、模式切换、监测决策等 | int、sys、fsm、scan_ctrl、point_cloud、time、motor、laser、imu、ota | application/ |
| Service服务层 | 通用业务支撑服务 | 沉淀可被多个业务复用的通用流程:参数管理、数据存储、数据传输上报、固件升级、系统保活、日志上报等 | config、storage、transport、ota、ska、ptp、log | platform/service/ |
| Module模块层 | 产品外设模块能力封装 | 基于 HAL 芯片能力接口实现产品语义能力;模块内部再分 pubif / middle / driver | acquisition、laser、motor、chip_monitor、net、time、storage、imu、shm | platform/module/ |
| Middleware中间层 | 横向复用基础库 | 与业务、硬件均无关的可复用基础能力:纯 C 工具库、Debug调试库、第三方库 | micro_libs、lwip、freertos | platform/middleware/ |
| Adapter适配层 | 芯片平台与板级适配 | 硬件SOC板卡适配1. osif 抽象操作系统能力2. common 沉淀基础能力、3. hal封装芯片总线接口4. bsp 厂商板级资源包、5. sdk 厂商 SDK支持包 | hal(hsadc / awg_dac / hkadc / hkdac / ccu / pvt_mon / ethernet/.... | platform/adapter/ |
芯片能力 → HAL 封装 → 产品模块
| 产品需求 | 芯片能力 | HAL 封装 | Module 实现 |
|---|---|---|---|
| 配置 AWG 模块产生激光器的调制波形 | AWG & DAC | hal/awg_dac |
modules/laser(激光器) |
| 配置片上 PVT 监测模块完成芯片状态信息监测和管理 | PVT Monitor | hal/pvt_mon |
modules/chip_monitor(芯片状态监测) |
| 配置 CAPCOM 用于转镜电机控制和角度解析 | CAPCOM / CCU | hal/timerhal/pwm |
modules/motor(转镜电机) |
| 配置 HSADC 的采集和处理模式 | HSADC + FFT + iDMA | hal/hsadc |
modules/xxx(具体采集功能) |
| 通过 2.5G XGMAC 传输点云、配置与日志 | XGMAC | hal/ethernet |
modules/net(网络通信) |
| 通过 I2C / SPI 读取 IMU 与电源监测芯片 | I2C / SPI | hal/i2c、hal/spi |
modules/imu(IMU姿态检测) |
| 其他外设模块 | UART | hal/uart |
modules/xxx(具体功能模块) |
| 与外部计算单元交换采集数据与解算结果 | 共享内存 / IPC | hal/ipc |
modules/shm(数据交互) |
四、各层职责详解
application ** —— **应用层
职责:实现 Viper V2 的产品业务应用——系统初始化上电、产品状态机、扫描调度、调制与点云编排、数据模式切换、监测任务决策、故障状态机、ota升级等。
| 模块 | 中文名 | 职责 | 主要依赖 |
|---|---|---|---|
init |
启动装配 | 系统入口与初始化编排:按 Adapter → Module → Service → Application 顺序完成各层初始化,再进入业务主循环;只做装配与顺序编排,不含业务决策 | adapter、module、service |
sys |
系统服务 | 系统级公共业务:系统上电启动逻辑,电源管理逻辑,数据模式切换(ADC Raw Samples / FFT Amplitude / Point Cloud)、整机健康状态判定 | service/config、service/log、module/chip_monitor |
fsm |
产品状态机 | 切换 MCU1 在配置态、点云输出模式、状态信息监测模式、Recovery 模式、OTA升级态之间的迁移;负责迁移前置条件检查、超时保护与失败回退 | service/config、service/ska_monitor、module/* |
scan_ctrl |
扫描调度 | 维护棱镜扫描角度与 4 面 80° 探测区 / 10° 盲区的映射关系;按当前角度决定处于点云输出模式还是状态信息监测模式;生成触发时序请求 | module/motor、service/ska_monitor |
point_cloud |
点云业务 | 接收经 module/shm 得到的解算结果,结合扫描角度组装点云业务对象并提交上报 | module/shm、module/motor、service/transport |
time |
时间基准业务 | 为点云与诊断数据打时间戳;校验业务时间与主时钟的一致性,异常时触发重新同步 | service/gptp、module/time |
motor |
电机业务 | 转镜电机运行策略:转速设定、启停与相位对齐的策略决策下发;电机异常时决定降级运行还是停机 | module/motor |
laser |
激光器业务 | 调制波形的业务参数编排:波形选择、加载时机与生效原子性的策略层决策 | module/laser、service/config |
imu |
IMU 业务 | IMU 数据的业务消费:80Hz 采集节拍的业务触发、姿态异常的业务判定与上报 | module/imu、service/ska_monitor |
IAP |
升级业务 | 升级流程编排:接收升级包、校验结果处理、升级完成复位跳转与 recovery 判定 | service/ota、module/storage |
service **—— **服务层
职责:为应用层提供可复用的通用服务能力——参数管理、数据存储、协议处理与上报、固件升级、系统保活、日志上报等。
| 模块 | 中文名 | 职责 | 主要依赖 |
|---|---|---|---|
config |
参数配置 | 运行参数的定义、默认值、合法性校验、运行时修改与固化写入非易失存储区;上电时从 Flash 加载参数到内存 | module/storage、middleware/micro_libs |
storage |
数据存储 | 通用记录型数据存储抽象:故障记录、统计、运行日志的落盘与查询 | module/storage |
transport |
点云与上报 | 对外通信的统一出口:点云 Payload 组装、状态信息重新组包、参数下发与升级镜像接收;双 Buffer(2×1500B)+ 信号量驱动零拷贝发送 | module/net、middleware/lwip |
iap |
IAP固件升级 | IAP 流程:经 RGMII 自定义 UDP 接收固件镜像、CRC32 完整性校验、写入 Flash 指定扇区、升级完成复位跳转;Recovery 模式判定 | module/net、module/storage、middleware/micro_libs |
ska |
系统保活监控 | 统一监控 RTOS 各系统任务的运行保活状态:按周期采集各任务的存活标志与运行时长,识别超时、阻塞与异常退出的任务并上报告警;集中管理看门狗喂狗——所有对外看门狗喂狗动作只由本服务一处执行,禁止各业务自行散喂 | module/watchdog_ic、adapter/osif、service/log |
monitor |
状态监测调度 | 多速率任务调度:20Hz 监测周期、80Hz IMU 与看门狗周期、盲区窗口时间计算;按窗口派发各项状态监测采集并汇总结果提交交叉验证 | module/motor、module/chip_monitor、module/imu、module/power_mon、module/temp_sensor、module/motor_board、module/chirp_laser_board、module/watchdog_ic |
gptp |
时间同步服务 | 接收外部 gPTP/PTP 时间报文并校准系统主时钟,对外提供统一的时间基准与时间戳查询接口 | module/time、module/net |
log |
日志诊断 | 分级日志、故障码、运行诊断信息(含内存、任务栈水位、复位原因)的采集与上报 | adapter/common、module/storage |
module **—— **模块层
职责:基于 HAL 芯片能力接口实现产品外设功能能力。单个 module 对外提供该模块的所有能力接口,供上层调用,屏蔽相同产品能力在不同硬件实现上的差异。
模块内部三层
| 子层 | 定位 | Viper V2 示例 |
|---|---|---|
| pubif | 对外提供的接口(public interface) | md_laser_pubif.h:加载调制波形、启动输出、设置调制参数;md_motor_pubif.h:设置转速、电机启动、读取角度 |
| middle | 本模块的协议或关键实现框架 | ABI 脉冲解码与角度标定、电机驱动板私有协议解析、调制波形管理与链式策略 |
| driver | 本模块的驱动,调用 HAL 芯片能力接口 | 调用 hal/awg_dac 完成波形内存写入与触发;调用hal/timer与 hal/pwm 配置 PWM 与捕获;调用 hal/hsadc 与 hal/dma 配置ADC采集与搬运 |
特别说明:并非每个模块都必须三层齐全——简单模块可只保留 pubif + driver,但对外暴露面必须统一收敛在 pubif。
具体模块
| 模块 | 中文名 | 职责 | 依赖的 HAL 能力 | 形态 | 备注 |
|---|---|---|---|---|---|
acquisition |
采集链 | HSADC 采集与处理模式配置:16 通道 1.25G、单次 5120 点、2× 降采样至 2560 点、4096 点 FFT;采集内存与 iDMA 取数通道管理;对外提供采集数据接入通道 | hal/hsadc、hal/dma | SoC 片上 | 需要 |
laser |
激光器 | 激光器调制能力:波形内存加载、链式触发、幅度斜坡调制、偏置/增益输出配置;为 AWG&DAC 提供产品语义的调制封装 | hal/awg_dac、hal/hkdac | SoC 片上 | 需要 |
motor |
转镜 / 多边形控制 | 转镜电机控制与角度解析:PWM 波形驱动电机稳定匀速转动、ABI 脉冲解码、角度标定与相位映射;对应硬件框图中的 Polygon control 与 Scanning angle parser,板件为 Polygon Control Board;角度是扫描调度与盲区判定的基础 | hal/timer、hal/pwm | SoC 片上 + 板级 | 需要 |
chip_monitor |
芯片状态监测 | 片上芯片状态监测与管理:PVT 供电轨电压与 die 温度采集、HKADC 监测信号采样、越限判定与告警上报;盲区内按需提供监测信号采样能力 | hal/pvt_mon、hal/hkadc | SoC 片上 | 暂不需要 |
net |
网络通信 | 2.5G 以太网通信能力:网卡初始化、描述符环管理、零拷贝双缓冲收发、IEEE1588 时间戳获取与 MACsec 状态 | hal/ethernet | SoC 片上 | 需要 |
time |
时间同步 | 时间同步能力:接收外部 gPTP/PTP 时间报文并校准系统主时钟;维护高精度时间戳,为点云数据打时间戳 | hal/ptp_ts、hal/ethernet | SoC 片上 | 暂不需要 |
storage |
非易失存储 | 固件镜像与参数区的页级读写、擦除、完整性校验;向上提供镜像区与参数区的语义化读写接口 | hal/flash | 板级 | 需要 |
imu |
惯性单元 | IMU 设备封装:I2C 读取 IMU0/IMU1 状态与姿态数据,80Hz 采集 | hal/i2c | 板级 | 暂不需要 |
shm |
数据交互 | 与外部计算单元的数据通道:共享内存缓冲区管理、双向数据交换、跨核中断通知 | hal/ipc | SoC 内部 | 需要 |
timer_manager |
系统时基定时器 | 稳定系统的时间保证 | hal/timer | SoC 片上 | 需要 |
middleware **—— **库层
职责:沉淀与业务、硬件均无关的可复用基础能力,是横向复用层,不在垂直调用链上——Application、Service、Module、Adapter 均可直接引用;库之间禁止互相耦合。
| 库 | 内容 | 约束 |
|---|---|---|
micro_libs |
ringbuf、crc32、序列化与字节序、定点与浮点数学、FIR/IIR/匹配滤波、内存池、FSM 状态机框架、软定时器、事件分发器、字符串处理 | 纯 C 实现,不依赖特定 OS 与硬件,可单独编译成静态库 |
diagnosis |
内存监控、backtrace异常回溯、coredump调试手段 | 只依赖 adapter/common 与 middleware 自身实现,不含任何产品语义 |
third_party |
lwIP(UDP/IP 协议栈)、FreeRTOS操作系统 | 第三方源码原样引入,仅在 third_party 目录,不做任何改动 |
adapter **—— **适配层
职责:主要负责芯片平台的硬件适配和 RTOS 的适配;相同芯片使用同一分支管理,确保对外提供的 API 一致,屏蔽底层差异。
hal —— 芯片能力封装
HAL 是芯片能力与上层之间的唯一通道。芯片能力由 Broadcom 在 BSP/SDK 中提供接口,MCU1 侧统一封装成平台无关、语义清晰的能力接口,module 层只依赖这些接口。
| HAL 封装 | 覆盖的芯片能力 | 厂商依赖 | 备注 |
|---|---|---|---|
hal/hsadc |
16 通道 1.25G 高速 ADC、FIR 与抽取、采集内存、FFT 加速器、TXSLZR 激光脉冲发生器、HSREF / HSAFE、NSU 触发网络 | hsadc_helper、hsref / hsafe / txslzr / nsu / acqcmn | 需要 |
hal/awg_dac |
任意波形发生、DDS 相位累加、波形内存、通道链式、AWG-DAC、幅度斜坡调制器 | awg_helper | 需要 |
hal/hkadc |
Housekeeping ADC、通道分工、ADC 6/7 序列器、触发与数据流 | hkadc_helper | 暂缓 |
hal/hkdac |
8 个 Housekeeping DAC、触发矩阵、组内同步输出、软件输出与 DMA | hkdac | 不需要 |
hal/timer |
CAPCOM 捕获比较定时器、CCT 输出、输入捕获、计数与定时、外部接口与触发矩阵 | ccu_helper | 需要 |
hal/pwm |
PWM 输出:频率/占空比配置、输出极性与同步 | ccu_helper | 需要 |
hal/pvt_mon |
PVT Monitor 电压温度监控、监控矩阵、转换与标度、数字/模拟比较器、越限信号路由 | — | 不需要 |
hal/ethernet |
1.0G XGMAC、速率路径、SGMII/HSGMII、描述符环、收发特性、IEEE1588 / 802.1as 时间戳、MACsec | xgmac_helper、ethernet | 需要 |
hal/i2c |
I2C 主/从模式、时钟产生、中断、寄存器映射 | i2c | 需要 |
hal/spi |
SPI 主机 / 从机 | — | 不需要 |
hal/uart |
UART 收发、中断、FIFO | — | 需要 |
hal/gpio |
GPIO 输入输出、电平、方向、外部中断 | 不需要 | |
hal/flash |
SPI / QSPI Flash 读写擦除 | — | 需要 |
hal/wdt |
内部看门狗 | — | 需要 |
hal/ptp_ts |
IEEE1588 / 802.1as 时间戳生成与读取 | — | 不需要 |
hal/ipc |
共享内存缓冲区、中断通知与跨核同步 | — | 需要 |
osif/ common/ bsp / sdk
| 子层 | 定位 | 内容 |
|---|---|---|
osif |
操作系统能力抽象 | task、queue、semaphore、mutex、event group、timer、ipc/shm、memory、irq context;对外提供一致 API,屏蔽 OS 差异 |
common |
平台优先适配的基础能力 | logger、assert、delay、cli/shell,以及其他与芯片编译配置强相关的组件 |
bsp |
板级支持 | 引脚与外设实例映射、器件互联拓扑、中断与 DMA 通道分配、板级初始化、GPIO 电平与方向等板级细节 |
sdk |
厂商 SDK 适配 | BCM89158 寄存器定义与官方驱动库、启动代码、链接脚本、时钟与电源初始化;仅 HAL 层可访问,上层不得直接使用 |
五、各层调用关系
运行时调用关系
运行期调用关系遵循”自上而下单向依赖 + 必要回调”:
- 上层通过下层的公开API接口发起接口调用
- 下层在完成处理后以callback回调或事件的方式异步通知上层;
- 下层绝不能直接反向持有上层逻辑。

各层间的依赖约束
白名单是强制约束:每层代码只能调用白名单所列层的接口,未列出的层一律禁止调用;
同层模块之间禁止直接耦合。
后期将该规则由 include 依赖检查py脚本,在 build构建中强制约束检查,否则编译失败。
| 当前层 | 允许调用 | 禁止 |
|---|---|---|
| Application | service、module、middleware、adapter | 直接访问 hal / sdk 私有 API;跨模块调用其他 module 的内部实现;同层模块之间互相耦合 |
| Service | module、middleware、adapter | 调用 application;直接访问寄存器;绕过 module 直接调用 hal |
| Module | adapter(hal / osif / common)、middleware | 调用 service、application;直接访问 sdk / 厂商 BSP 私有 API;模块之间互相耦合 |
| Middleware | adapter(仅必要接口) | 依赖特定 OS 或硬件环境;库之间互相耦合;反向依赖上层 |
| Adapter / hal | sdk / 厂商 BSP | 向上暴露 sdk 私有 API |
初始化装配关系 ≠ 运行期调用关系
运行期调用关系和初始化装配关系不是一回事。
初始化应由统一入口编排,而不是让业务层自己拉起底层。
init |
初始化与运行期调用是两条不同的链路:运行期由上层主动调用下层接口;而初始化则由统一入口 init 按 Adapter → Middleware → Module → Service → Application 的固定顺序自下而上装配,每层只初始化自身职责范围内的东西,不反向依赖上层。
高内聚、低耦合
- 头文件单向可达:每个模块只暴露 pubif 头文件,middle 与 driver 的头文件不进入 include 搜索路径,杜绝”顺手 include 到了内部实现”。
- HAL 是唯一硬件入口:module 层不允许出现厂商 SDK / BSP 的头文件 include 与私有 API 调用,依赖检查脚本对此单独设规则。
- 同层零耦合:module 与 service 的模块之间不允许互相 include;需要协作时通过 Service 编排或事件回调。
- 依赖检查进 CI:对每个源文件计算其所属层与被包含头文件所属层,与依赖白名单比对,违规即构建失败。
- 接口稳定性评审:pubif 头文件变更需架构评审,禁止暴露结构体内存布局以外的实现细节,禁止跨核共享结构体不做版本管理。
- 模块可独立测试:pubif 接口必须可在无真实硬件的情况下打桩测试;middle 层算法(ABI 解码、角度标定、峰值判定)必须可离线单元测试。
六、如何判断放置哪一层
问答判断法
新功能进来时,按下表逐条自问,命中即落层;全部不命中说明需求尚未澄清,应回到产品需求层面先厘清。
| 判断问题 | 归属层 | Viper V2 举例 |
|---|---|---|
| 是不是厂商库、寄存器访问、启动代码、RTOS 本体? | adapter / sdk | BCM89158 寄存器定义、FreeRTOS 任务创建、时钟树初始化 |
| 是不是芯片自带的能力(外设采样、波形发生、捕获比较、电压温度监测、以太网收发)? | adapter / hal | HSADC 采样配置、AWG 波形写入、CAPCOM 捕获、PVT 读数、XGMAC 收发 |
| 是不是在封装操作系统能力? | adapter / osif | 任务、队列、信号量、事件组 |
| 是不是这块板子的资源映射(哪个引脚、哪个实例、哪路通道)? | adapter / bsp | 看门狗芯片接 GPIO_xx、电机驱动板接 UART0 |
| 是不是与业务和硬件都无关、可独立复用的基础能力? | middleware | CRC32、环形缓冲、点云 Payload 编码 |
| 是不是在封装一个产品外设模块能力? | module | 转镜电机、激光器调制、芯片状态监测、IMU 封装 |
| 是不是给多个业务提供公共能力(协议、存储、诊断、调度)? | service | 参数管理、UDP 上报、状态监测调度、交叉验证、系统保活与看门狗 |
| 是不是独立业务流程逻辑? | application | 工作模式切换、状态机迁移、探测区/盲区判定、命令执行流程 |
判断优先级与仲裁规则
如果一个模块”好像哪层都能放”,按此顺序判断:先看职责,再看依赖,最后看复用性。
看它本质在解决什么问题、依赖哪些层、未来是否需要复用。
- 先用上层已有能力解决,就不要新建模块:例如点云时间戳,优先用 module/time,而不是在 module/net 里再加一套时间逻辑。
- 同一能力只允许有一个归属:若发现同一功能在两层各有一份实现,说明分层已腐化,必须合并到唯一层。
- 策略与机制分离:机制(怎么算角度、怎么收包、怎么写波形)放 module 与 service,策略(何时算、算完做什么)放 application。
- 单一模块协议单独****封装:某个器件的特殊协议只允许出现在该器件对应的 module模块 的 middle 层中,不得在 application 中再次进行解析。
七、代码目录结构
viper_v2/ |
八、强制约束
以下约束对 MCU1 全部代码强制生效,由代码评审与 CI/CD 依赖检查共同保障;
违反任一条即视为架构违规,必须在合入前整改。
编程范式与分层约束
- 面向接口编程,采用面向对象封装:每个模块、每个对外接口都封装为一个独立对象(结构体实例 + 一组操作函数),状态私有、行为公开;上层只持有句柄与接口指针,不感知内部实现,禁止用全局变量或裸函数跨层暴露数据。
- 禁止跨层级调用:严格遵守第五章的层间依赖白名单。application 不得直接调用 hal;service 不得直接访问寄存器;module 不得越过 hal 触碰 SDK 私有 API;同层模块之间禁止互相 include 或直接调用。
- 接口命名清晰、职责单一:接口函数名必须动词开头、语义完整、可自解释(如
md_motor_start、md_motor_get_angle),不得使用含糊缩写;一个函数只做一件事,参数与返回值需有明确的类型与错误码定义。 - 每层接口函数统一前缀:各层对外函数按层加前缀,从命名上即可看出归属,杜绝同名混淆。
接口命名前缀约定
| 层级 | 函数命名前缀 | 示例 |
|---|---|---|
| application | app_ |
app_fsm_start、app_scan_ctrl_tick |
| service | svc_ |
svc_config_get、svc_transport_send_pointcloud |
| module | md_ |
md_motor_start、md_laser_load_waveform |
| middleware | middle``_ |
middle``_ringbuf_push、middle``_crc32_calc |
| adapter / hal | adapter_``hal_ |
adapter_``hal_hsadc_config、adapter_``h``al_awg_dac_write_waveform |
| adapter / osif | adapter_``osif_ |
adapter_``osif_task_create、adapter_``o``sif_queue_send |
| adapter / common | adapter_``com_ |
adapter_``com_log_printf、adapter_``c``om_assert |
命名与目录约束
- 模块命名体现产品语义:module 目录与模块名必须体现产品能力(laser、motor、chip_monitor),禁止以芯片外设命名(禁止出现 hsadc 模块、awg 模块、xgmac 模块)。
- 头文件与源文件同名对应:模块按
module/<name>/组织,内部固定pubif / middle / driver三层目录;公开头文件命名md_<name>_pubif.h。 - 常量、类型与变量命名:宏与常量用大写下划线(
MD_MOTOR_MAX_RPM),类型用小写下划线加模块缩写(md_motor_cfg_t),局部变量与参数用短小写下划线(rpm、angle_deg)。 - 注释与文档:所有 pubif 接口须有函数级注释,说明功能、参数、返回值与错误码;模块 pubif 头文件须标注所属层与依赖的 HAL 能力,采用doxgen方式,示例:
/** |

