| name | embedded-development |
| description | 在嵌入式工作项(固件、驱动、HAL、RTOS 任务、中断处理、资源受限服务)的规格、设计、实现或评审中使用,涉及内存预算、中断上下文、实时性、硬件交互、资源生命周期或目标平台差异时。只承载嵌入式领域约束;语言级规则见适用 `<language>-coding-standards`,更专门的业务/行业领域约束由命中 description 的领域技能叠加。 |
Embedded Development
总览
嵌入式约束的共同点:违反时不报错,只在目标机上间歇性地坏。所以这些约束必须前置到规格和设计——在 spec 里有阈值、在 design 里有策略、在测试里有证据,而不是在 code review 时碰运气发现。本技能按维度给出"在哪个阶段定什么、实现红线是什么、用什么证据验证",每条红线尽量配最小正反例。语言级写法见适用 <language>-coding-standards,本文只承载嵌入式领域维度。
内存
- 规格/设计定:动态分配是否允许、允许在哪个阶段(仅初始化期 vs 运行期);静态内存预算(
.data + .bss 上限);大对象的归属(栈上限、静态池、堆)。
- 实现红线:运行期热路径不动态分配(除非设计显式批准);栈上不放大数组(参考阈值:单帧 >256 字节即审视,目标平台栈深度决定);跨边界 buffer 必传容量与所有权语义(具体写法见适用语言规范)。
void on_frame(const uint8_t *p, size_t n) {
uint8_t *tmp = malloc(n);
...
free(tmp);
}
static uint8_t s_frame_buf[MAX_FRAME];
void on_frame(const uint8_t *p, size_t n) {
if (n > sizeof(s_frame_buf)) return ERR_TOO_LARGE;
...
}
- 证据:链接 map / size 工具输出对照预算;leak 检测或静态分析报告;栈深度分析(工具或最坏路径估算)。
中断与并发
- 规格/设计定:哪些路径运行在中断上下文;ISR 与任务共享哪些数据、用什么机制保护(关中断窗口、无锁队列、原子量);锁的层级顺序。
- 实现红线:ISR 内不调用阻塞 API、不动态分配、不做长计算/IO;典型正确形态是最小采集 + 入队 + 通知,处理留给任务上下文。
void ADC_IRQHandler(void) {
pthread_mutex_lock(&g_lock);
log_info("adc=%d", read_adc());
process_and_filter(read_adc());
}
void ADC_IRQHandler(void) {
uint16_t v = ADC->DR;
ringbuf_push_isr(&g_adc_q, v);
task_notify_from_isr(g_adc_task);
}
- ISR 与任务共享的变量:要么原子类型,要么受保护的临界区;裸
volatile 不是同步手段(它只阻止编译器优化,不保证原子性和顺序)——volatile 只用于硬件寄存器映射。
volatile uint32_t g_count;
g_count++;
atomic_uint_least32_t g_count;
atomic_fetch_add(&g_count, 1);
- 关中断窗口要短且可度量;临界区里不调用可能阻塞的函数。
- 证据:静态分析的调用图检查(ISR 可达函数白名单);并发压力测试;竞态相关缺陷的复现测试。
实时性
- 规格定:关键路径的 deadline / latency 阈值(QAS 格式,见
devflow-specify),含测量环境与百分位。
- 设计定:任务优先级与调度策略;关键路径上禁止哪些操作(日志、阻塞 IO、动态分配)。
- 实现红线:硬实时路径不打印日志、不做文件 IO;周期任务的执行时间余量可观测。
- 证据:latency 直方图(p95/max 对照阈值)、最坏执行时间分析或测量。
硬件与驱动边界
- 设计定:硬件访问收口在 HAL/驱动层,业务逻辑不直接戳寄存器——这同时是可测试性的来源(业务逻辑可在 host 上用 fake HAL 单测)。
- 实现红线:寄存器操作带 datasheet 锚点注释(哪个寄存器、为什么这个序列、时序要求);轮询硬件状态必有超时与失败路径;读-改-写寄存器序列考虑中断打断。
while (!(UART->SR & TXE)) ;
uint32_t deadline = now_ms() + TX_TIMEOUT_MS;
while (!(UART->SR & TXE)) {
if (time_after(now_ms(), deadline)) return ERR_TX_TIMEOUT;
}
- 证据:host 单测覆盖业务逻辑;target/HIL 或仿真覆盖硬件交互路径;fake HAL 行为与真实硬件契约一致(评审项)。
资源生命周期
- 句柄/定时器/DMA 通道/队列等有限资源:设计阶段写清谁创建谁销毁、上限是多少、耗尽时的行为(拒绝并返回,还是降级)。
- 部分初始化失败的回滚路径必须完整(init 到第 3 步失败要回滚前 2 步)——这是嵌入式 init 代码最常见的泄漏点;具体用集中清理出口、RAII、defer、上下文管理器还是其他模式,以适用语言规范为准。
- 长生命周期设备上"很小的泄漏"会累积成现场事故:泄漏类 finding 一律 critical。
兼容与平台差异
- 公共接口签名、结构体布局、错误码集、配置项的变化都是
modify(走 devflow-specify 的基线纪律),列出已知消费者。
- 跨平台/跨编译条件的行为差异在规格中显式拆分(粒度信号 G8);条件编译分支都要能编译、关键分支都有测试。
- 字节序、对齐、字宽假设显式写出(协议解析尤其);不用
#pragma pack 的结构体直接 memcpy 网络数据。
测试与证据策略
| 层级 | 覆盖什么 | 注意 |
|---|
| host 单测(fake HAL) | 业务逻辑、协议解析、状态机、错误路径 | 主力层;fake 行为必须忠于硬件契约 |
| 仿真/SIL | 时序相关逻辑、多任务交互 | 仿真器版本与配置记录在案 |
| target/HIL | 硬件交互、实时性测量、功耗 | NFR 的 Response Measure 在这层闭环 |
- 实时性/内存类 NFR 不能只用 host 测试充数——测量必须在声明的环境进行。
- 评审时(
devflow-review):本文件各维度的"证据"项就是检查清单;适用维度无证据且无 N/A 理由 → critical。
合理化反驳
| 话术 | 现实 |
|---|
| 「目标板上应该不会触发」 | 平台假设要么有 datasheet/测量证据,要么按会触发设计 |
| 「中断里就调这一次,没事」 | 中断上下文规则不按概率豁免;一次阻塞就是一次现场死机 |
| 「泄漏很小,重启就好」 | 长生命周期设备没有"重启就好";泄漏 = critical |
| 「volatile 加上就线程安全了」 | volatile 不提供原子性与顺序;该用原子量或临界区 |
| 「实时性最后在板子上调」 | deadline 是设计输入不是调试输出;阈值前置到 QAS |
自检清单