主机边界:默认使用标准库模型、C 源文件和事件序列;没有目标板也能完成计数对账、缓冲策略、deadline 和故障注入。
目标机边界:真实 NVIC 抢占、DMA 请求映射、cache、低功耗电流、唤醒原因和外设恢复必须回到当前芯片、板卡、仪器和工具链的官方资料。
01 · INTERRUPT MODEL
中断模型:事件怎样到达 CPU
中断是一条从外设事件到处理器服务代码的通知链。源事件、状态标志、请求门控、NVIC 挂起、优先级、异常入口和 ISR 清除动作共同决定最终行为。本单元先建立事件模型,再把‘触发了中断’拆成可以逐段观察的条件。
6.1.1 事件、标志与中断请求不是同一件事
外设事件、状态标志和 NVIC 请求是三个不同层次。一个 UART 可能先把字节放进接收寄存器,再置位 RXNE,最后在中断使能打开时向 NVIC 发请求;关闭请求不会抹掉已经存在的状态。初始化应先清理已知历史状态,再配置来源和使能,并写出哪些动作会自动清除标志。
6.1.2 从请求到 pending:CPU 还没有开始服务
pending 表示请求已经被控制器记录但尚未取得执行机会,active 表示处理器正在服务某个异常;二者都不能证明业务代码已经消费数据。连续事件如果只由一个电平标志表示,多个物理事件可能合并成一次服务。需要硬件计数、FIFO 深度或软件序列号来证明有没有合并。
C · IRQ SNAPSHOTuint32_t status = PERIPH_STATUS; if (status & RX_FLAG) { rx_count++; PERIPH_CLEAR = RX_FLAG; }
状态快照与清除语义必须按当前外设手册实现;共享 IRQ 还要保留未处理标志。
C · IRQ TRACETRACE_GPIO_SET = 1u; service_pending_events(); TRACE_GPIO_CLEAR = 1u;
GPIO 只能标记一段软件路径,不能单独证明物理事件到 ISR 的全部延迟。
6.1.3 向量表与 ISR 名称的最后一公里
IRQn、向量表槽位、弱符号和真实函数名必须共同核对。链接器能证明某个符号存在,却不能证明芯片把请求路由到了这个槽位,也不能证明外设标志会在进入函数时保持。保存启动文件、ELF 符号、向量表地址和现场 pending 位,才能定位‘函数没进’。
| 层次 | 应留下的证据 | 不能直接推出 |
|---|---|---|
| 事件 | 源/标志/请求 | 使能就代表事件发生 |
| 入口 | pending/active/向量 | pending 就代表业务已处理 |
| 确认 | 读取/清除/计数 | 一个 ISR 可以证明没有丢失 |
6.1.4 状态标志的读写和清除语义
不同外设的清标志协议可能完全不同:有的写一清零,有的写零清零,有的必须先读状态再读数据,有的读取捕获寄存器就会释放请求。读改写共享状态可能把刚到达的事件一并清掉。每个 IRQ handler 都应按当前参考手册列出读取、确认、搬运和退出顺序。
6.1.5 同步、异步和外部引脚事件
外部引脚边沿经过输入同步、滤波、边沿选择和外设时钟采样后,才会变成内部事件。示波器看到的物理边沿与 GPIO 状态寄存器、定时器捕获值和 ISR 翻转之间有固定或变化延迟。报告时间时要标明参考点,不能把‘引脚时间’和‘软件时间’混用。
从左到右是思考顺序,不是把事件、配置、数据、功耗和结论压缩成一个“通过”。
6.1.6 共享 IRQ:一个入口服务多个来源
共享 IRQ 的处理函数应读取一次状态快照,再按明确顺序服务各来源,并在必要时循环检查仍然挂起的标志。服务一个高频来源时可能延迟另一个来源;把所有分支都写成同样优先级会掩盖真正的预算。每个来源应有独立计数、错误计数和未处理分支。
6.1.7 事件速率、服务能力和丢失窗口
如果事件间隔短于 ISR 完成时间且外设没有 FIFO 或计数器,电平标志只能表示‘至少一个事件’。这不是软件多写一个 while 就能修复的。要么提高服务能力、改用 DMA/硬件队列,要么降低事件率并明确丢失策略;过载实验必须可停止、可恢复。
6.1.8 本节交付:事件到服务的状态图
事件状态图至少包含 source_identity、flag_rule、request_enable、irq_number、vector_symbol、pending/active、service_order、clear_rule、event_counter 和 loss_policy。它把‘中断能用’拆成可检查断言,也为后续优先级、DMA 和睡眠唤醒提供输入。
请围绕“中断模型:事件怎样到达 CPU”写出对象、事件/输入条件、状态或搬运机制、输出、一个时间或功耗约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,也要补齐芯片、IRQ、DMA、内存、供电、唤醒源、工具链、仪器和观察条件。不要用一次中断计数、电流读数或逻辑分析仪截图覆盖没有做过的验证。
02 · PRIORITY AND SHARED STATE
优先级与共享状态:抢占如何改变时序
优先级不是把重要程度写进一个数字就结束。抢占位、子优先级、屏蔽寄存器、临界区、嵌套深度、共享队列和 ISR 执行时间共同决定谁先运行、谁等待以及谁可能饿死。本单元把优先级配置和共享状态放进同一条时序线上。
6.2.1 优先级数字的方向与实现位数
Cortex-M 优先级寄存器通常只实现高位的若干位,CMSIS 会按实现宽度对齐数值;具体芯片的优先级分组还会把位拆成抢占与子优先级。比较两个十进制数字前,先确认实现位数、分组函数和 NVIC 回读值。数字相同或接近,不代表行为在所有内核上相同。
6.2.2 抢占优先级与子优先级
抢占优先级决定一个可配置异常能否打断另一个正在运行的异常,子优先级常用于多个 pending 请求的选择。两个字段的含义不是‘数值越小越重要’一句话可以覆盖的。需要记录当前分组、各 IRQ 的回读值、异常状态和是否允许嵌套。
C · PRIORITY CONTRACTNVIC_SetPriority(IRQn, encoded_priority); NVIC_EnableIRQ(IRQn); __DSB(); __ISB();
CMSIS 调用、优先级分组和屏蔽寄存器需结合具体内核与芯片确认。
C · SPSC QUEUEbool push(event_t value) { uint32_t next = (head + 1u) % CAPACITY; if (next == tail) { dropped++; return false; } queue[head] = value; head = next; return true; }
示例强调所有权和丢弃计数;原子性、屏蔽和内存顺序不能由 volatile 自动保证。
6.2.3 PRIMASK、BASEPRI 与全局关中断
PRIMASK 适合非常短的全局保护,但会延迟所有可屏蔽中断;BASEPRI 可以屏蔽低于某阈值的优先级,前提是内核支持并正确编码。关中断区长度应以最大延迟为预算,而不是以‘这几行很短’为理由。硬件唤醒和看门狗也要纳入停止条件。
| 层次 | 应留下的证据 | 不能直接推出 |
|---|---|---|
| 配置 | 分组/有效位/IRQ | 数字越小越能抢占 |
| 共享 | 所有权/原子/队列 | volatile 就是锁 |
| 预算 | 嵌套/屏蔽/最坏值 | 平均延迟就是上界 |
6.2.4 嵌套栈帧与最坏执行时间
嵌套 ISR 会叠加硬件异常帧、软件保存寄存器和栈对齐开销。入口到入口、入口到出口、低优先级事件等待时间和最大嵌套深度是不同指标。测量应在代表性高优先级负载、缓存/Flash 状态和编译选项下进行,并保留最坏样本而非只报平均。
6.2.5 ISR 与主循环共享环形队列
环形队列需要明确谁写 head、谁写 tail、索引何时发布以及满和空如何区分。单生产者/单消费者可以简化原子要求,但跨 ISR 和主循环仍需考虑编译器访问顺序、字段宽度和中断嵌套。队列溢出不能静默覆盖;至少记录丢弃计数和最近一次原因。
从左到右是思考顺序,不是把事件、配置、数据、功耗和结论压缩成一个“通过”。
6.2.6 原子性、volatile 与内存可见性
volatile 只要求编译器每次访问内存,不保证一个多字字段的原子更新,也不自动产生所需的 CPU 内存屏障。Cortex-M 的自然字宽、对齐和总线访问规则要和数据结构一起检查。读写共享状态时优先缩小所有权边界,必要时用短屏蔽或架构原子操作。
6.2.7 优先级反转、饿死与回压
优先级反转常表现为高优先级事件长期等待低优先级持有的资源;饿死则表现为某个来源的服务计数不断增长而另一个不增长。设置优先级并不能自动产生公平性。应测每类事件的等待上界、队列水位、丢弃数和恢复动作,过载时主动回压。
6.2.8 本节交付:优先级与共享状态卡
优先级与共享状态卡至少包含 priority_group、implemented_bits、irq_priority、mask_rule、nesting_depth、owner、atomicity、critical_section_us、queue_capacity、latency_bound 和 loss_action。它让一个‘重要中断’的判断可被别人复查,而不是依赖工程师记忆。
请围绕“优先级与共享状态:抢占如何改变时序”写出对象、事件/输入条件、状态或搬运机制、输出、一个时间或功耗约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,也要补齐芯片、IRQ、DMA、内存、供电、唤醒源、工具链、仪器和观察条件。不要用一次中断计数、电流读数或逻辑分析仪截图覆盖没有做过的验证。
03 · DMA DATA PATH
DMA 数据通路:搬运、缓冲与一致性
DMA 把外设与内存之间的搬运交给硬件,减少逐字节 ISR,但它引入了源地址、目的地址、传输宽度、突发、环形缓冲、半传输、完成、错误、总线仲裁和缓存一致性等新的条件。本单元把 DMA 当作一条有容量和所有权的生产线。
6.3.1 DMA 请求从哪里来
DMA 请求通常来自某个外设事件,但请求映射、通道选择、优先级和控制器实例由具体芯片决定。配置了一个合法通道不代表它连接到了目标外设。应从参考手册的 request mapping、初始化代码和现场状态三处交叉核对,并在没有请求时记录‘无传输’而不是盲目重启。
6.3.2 源地址、目的地址与传输宽度
源和目的地址的递增、数据宽度、外设数据寄存器宽度以及内存对齐共同决定缓冲内容。UART 一个字节、ADC 一个半字和 SPI 一个字的配置不能互相套用。把‘传输长度等于样本数’写进记录时,还要说明每个样本的字节数和索引单位。
C · DMA DESCRIPTORdma_cfg_t cfg = { .request = UART_RX_REQUEST, .source = &UART_RX_REG, .destination = rx_ring, .length = RING_SAMPLES, .circular = true }; dma_configure(&cfg); dma_start();
请求映射、宽度、缓存和控制器字段必须按当前 MCU 的 DMA 手册核对。
C · BUFFER PUBLISHvoid dma_half_done(void) { cache_invalidate(rx_ring, HALF_BYTES); publish_range(read_seq, HALF_SAMPLES); read_seq += HALF_SAMPLES; }
发布范围不等于数据格式有效;序列号、CRC、溢出和所有权仍需一并记录。
6.3.3 单次、循环和双缓冲
单次模式适合有限块,循环模式适合连续流,双缓冲把正在填充和正在消费的区域分开。无论选择哪种,都要定义 CPU 与 DMA 的所有权交接时刻。半传输或完成通知只表示某个范围可以被检查,不自动表示上层格式、CRC 或时间戳已经有效。
| 层次 | 应留下的证据 | 不能直接推出 |
|---|---|---|
| 请求 | 映射/通道/握手 | 开 DMA 中断就会搬运 |
| 缓冲 | 宽度/范围/所有权 | 完成标志代表数据有效 |
| 一致性 | cache/屏障/同步 | CPU 看到的就是 DMA 写入 |
6.3.4 半传输、完成与错误事件
半传输、传输完成和错误中断应携带可定位的缓冲范围。用单调序列号、生产计数、消费计数和水位记录每次交接,可以发现重复、跳号和覆盖。只打印‘DMA done’没有办法区分完成了哪一块、是否有错、CPU 是否及时消费。
6.3.5 缓存一致性:旧数据从哪里来
带数据缓存的 Cortex-M 或应用处理器上,CPU 可能继续读取自己的 cache,而 DMA 已经写入主存;反方向则可能 DMA 读到 CPU 尚未 clean 的旧内容。clean/invalidate 的范围、对齐、顺序和内存屏障要按当前内核与缓存架构确认。选择非缓存区域也有容量与性能代价。
从左到右是思考顺序,不是把事件、配置、数据、功耗和结论压缩成一个“通过”。
6.3.6 总线仲裁与实时预算
DMA 不是没有成本的后台魔法。突发长度、仲裁优先级、内存目标、Flash 等待和其他主设备都会影响 CPU 取指和外设服务。实时预算要同时看 DMA 吞吐、CPU 可用带宽、最坏服务延迟和缓冲深度;高平均带宽可能仍有尖峰阻塞。
6.3.7 缓冲区溢出、回压与恢复
缓冲溢出时可以丢弃最旧、丢弃最新、暂停源、降低采样率或复位通道,但必须选择并记录。恢复动作应先停止请求、保存错误和索引、确认 DMA 已停止,再清理或重新建立所有权。无限重启会让真正的总线或引脚故障失去证据。
6.3.8 驱动边界:DMA 不等于数据合同
DMA 通路卡应包括 request_id、controller/channel、source/destination、width、increment、burst、mode、buffer_capacity、owner、cache_policy、half/full/error_events、sequence、watermark、consumer_contract 和 recovery。它把‘硬件搬完了’与‘应用可以相信这批数据’分开。
6.3.9 本节交付:一张 DMA 数据通路卡
交付问题: 提交请求、地址、缓冲、缓存、通知、消费和限制。交付动作是“为中断协同和低功耗暂停提供清晰接口”,相应输入、输出或未执行边界必须在记录中逐项对应。
请围绕“DMA 数据通路:搬运、缓冲与一致性”写出对象、事件/输入条件、状态或搬运机制、输出、一个时间或功耗约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,也要补齐芯片、IRQ、DMA、内存、供电、唤醒源、工具链、仪器和观察条件。不要用一次中断计数、电流读数或逻辑分析仪截图覆盖没有做过的验证。
04 · LOW-POWER STATES
低功耗状态:睡眠、唤醒与时钟域
低功耗不是在循环里加一条 WFI 就结束。运行、睡眠、停止、待机等状态会关闭或切换不同的 CPU、总线、外设和 RAM 域,唤醒源、恢复时钟、保持寄存器、唤醒延迟和功耗测量共同决定行为。本单元建立状态机与证据边界。
6.4.1 WFI/WFE:睡眠指令的真实含义
WFI 让处理器等待可服务的中断,WFE 等待事件条件;它们与芯片的 Sleep-on-exit、事件寄存器和调试设置共同作用,并不自动进入最深的低功耗模式。进入指令前应说明哪些时钟仍开、哪类中断可唤醒、以及醒来后执行点在哪里。
6.4.2 功耗状态与保留矩阵
不同芯片把运行、Sleep、Stop、Standby 或 Shutdown 的关闭范围定义得不同。CPU、SRAM、Flash、外设寄存器、低速 RTC、唤醒引脚和调试域可能各自保留或掉电。比较模式时要做矩阵,不要用‘睡眠更省电’这种没有状态边界的句子。
C · SLEEP GUARDprepare_wakeup_sources(); clear_stale_pending(); __DSB(); __WFI(); restore_clock_tree();
WFI 前后的时钟、pending、唤醒原因和恢复顺序必须以当前芯片资料为准。
C · POWER RECORDpower_record_t record = { .state = STOP_MODE, .wake_reason = read_wakeup_flags(), .resume_ticks = monotonic_ticks() }; store_record(record);
记录结构不等于真实电流测量;仪器、负载和窗口必须单独保存。
6.4.3 唤醒源、pending 与误唤醒
唤醒源可能在进入低功耗前已经置位,导致立即返回;也可能在深睡眠中由低速域保留。进入前清理历史 pending、确认边沿极性和读取唤醒原因,是避免误判的必要动作。唤醒原因只能说明某条路径报告了事件,不等于业务数据已经被消费。
| 层次 | 应留下的证据 | 不能直接推出 |
|---|---|---|
| 状态 | CPU/RAM/外设/时钟 | 所有睡眠模式都一样 |
| 唤醒 | pending/源/原因 | 醒来就代表业务完成 |
| 测量 | 峰值/平均/窗口 | 一个电流数字代表整机功耗 |
6.4.4 时钟恢复与外设重新同步
唤醒后主时钟可能回到内部低速源,PLL 需要重新锁定,Flash 等待状态和总线分频也要恢复。外设若在时钟未稳定时继续访问,可能超时或产生错误帧。恢复代码应有显式状态、超时和失败分支,并在 GPIO 或日志上留下顺序证据。
6.4.5 低功耗下的 DMA 和缓冲区
DMA 是否能在睡眠中继续搬运,取决于控制器、外设、内存电源域和时钟门控;缓存一致性问题不会因睡眠消失。睡眠前应冻结或发布缓冲所有权,醒来后先确认 DMA 状态和错误,再让上层读取。跨深睡眠的指针和描述符不能默认仍然有效。
从左到右是思考顺序,不是把事件、配置、数据、功耗和结论压缩成一个“通过”。
6.4.6 唤醒延迟、抖动与 deadline
电池设备的周期不只包含任务执行时间,还包含唤醒、时钟稳定、传感器启动、无线收发和再次睡眠。把唤醒延迟看作零会让 deadline 预算虚高。测量需要区分进入、低功耗平台、唤醒、恢复和业务完成五段,并记录温度和电压。
6.4.7 电流测量:仪器读数不是一个数字
电流表、分流电阻、示波器电流探头和电源分析仪有不同带宽、采样率和接入损耗。一个稳定平均值可能掩盖毫秒级无线峰值或唤醒尖峰。报告应保存量程、带宽、触发、供电方式、负载、连接线和测量窗口,并把峰值停止阈值写出来。
6.4.8 本节交付:低功耗状态机卡
低功耗状态机卡包括 state、entry_guard、clock_domains、retained_memory、wake_sources、pending_policy、resume_sequence、wake_latency、current_window、debug_effect 和abort_condition。它把‘省电’变成可重演的状态转换,而不是一次电流截图。
请围绕“低功耗状态:睡眠、唤醒与时钟域”写出对象、事件/输入条件、状态或搬运机制、输出、一个时间或功耗约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,也要补齐芯片、IRQ、DMA、内存、供电、唤醒源、工具链、仪器和观察条件。不要用一次中断计数、电流读数或逻辑分析仪截图覆盖没有做过的验证。
05 · ISR AND DMA PIPELINE
中断与 DMA 协同:从 ISR 到批处理
中断和 DMA 是互补的服务机制:ISR 适合低速、需要即时决策的事件,DMA 适合连续数据和规则搬运;两者组合后还要处理通知粒度、缓冲水位、缓存、优先级、任务唤醒和错误恢复。本单元用生产者—消费者时间线比较不同方案。
6.5.1 每事件 ISR 与批量 DMA 的选择
低速按钮或一次性状态变化适合 ISR 直接确认,高速 ADC、UART 或 SPI 流通常需要 DMA;边界取决于事件率、数据宽度、最坏 ISR 时间、缓存和可接受延迟。选择服务方式时写出计算,而不是用‘DMA 更快’或‘中断更简单’替代合同。
6.5.2 生产者—消费者的时间线
流水线的正确顺序是外设产生请求、DMA 写入一段明确范围、控制器产生半满/完成通知、ISR 发布所有权、消费者校验并消费。任何一步提前发布都会让消费者看到半写数据;任何一步延迟过久都可能覆盖未消费区域。序列号和索引是最小证据。
C · DMA/ISR HANDOFFvoid dma_irq(void) { uint32_t range = dma_completed_range(); cache_invalidate(rx_ring + range, RANGE_BYTES); notify_consumer(range, ++sequence); }
回调只发布已完成范围;缓存维护、序列号和错误状态要按控制器规则实现。
C · OVERFLOW POLICYif (producer_seq - consumer_seq > RING_CAPACITY) { dropped += producer_seq - consumer_seq; resync_to_latest_frame(); }
过载策略要保留原始计数并可恢复,不能通过静默覆盖制造假通过。
6.5.3 半传输边界与双缓冲切换
半传输回调通常只负责前半段,完成回调负责后半段,但具体控制器可能有不同的环形指针和事件语义。把长度、元素宽度、起始索引和结束索引写进代码和记录,避免把字节偏移当样本编号。故意让消费者慢一拍,才能验证空洞和重叠检测。
| 层次 | 应留下的证据 | 不能直接推出 |
|---|---|---|
| 选择 | 事件率/批量/预算 | DMA 总比 ISR 好 |
| 交接 | 范围/序列/缓存 | 半传输就是格式有效 |
| 恢复 | 错误/回压/重同步 | 重启通道会修复所有错 |
6.5.4 通知延迟与批量大小
增大批量可以减少 ISR 次数和固定入口成本,却会增加首个样本等待时间、缓冲占用和错误重传范围。批量不是越大越好:必须满足 deadline、内存容量、睡眠周期和上层协议帧边界。记录平均、最大和 99/99.9 分位延迟,不能只看总吞吐。
6.5.5 缓存、屏障与发布顺序
发布一段 DMA 数据前,CPU 侧写入的描述符/配置可能需要屏障,读 DMA 写入的数据可能需要 invalidate;具体操作取决于是否有 cache、内存区域和架构。停止 DMA 时先关请求再确认停止,避免清理过程中又写入。所有权边界应该能在代码和日志中找到。
从左到右是思考顺序,不是把事件、配置、数据、功耗和结论压缩成一个“通过”。
6.5.6 错误传播:外设、DMA、协议和应用
错误要带范围和阶段:外设 overrun、DMA transfer error、缓存异常、格式/CRC 错误和应用队列溢出不能都叫‘接收失败’。错误恢复应决定丢弃哪一段、如何寻找下一个帧头、是否重启通道、是否降低速率,并保存原始计数与状态寄存器。
6.5.7 端到端延迟与吞吐的双指标
端到端指标至少包括输入边沿或外设时间戳、DMA 写入时间、ISR 通知时间、应用消费时间和结果发布时间。持续吞吐高不代表首包延迟低;平均延迟小也不代表偶发缓存维护或高优先级抢占不会错过 deadline。双指标和失败样本必须并列交付。
6.5.8 本节交付:中断/DMA 流水线卡
中断/DMA 流水线卡应包含 service_choice、event_rate、element_width、buffer_layout、producer_owner、consumer_owner、notify_range、cache_steps、sequence、latency_budget、throughput_target、error_propagation 和 recovery。它让换平台时只替换边界,不丢失数据合同。
请围绕“中断与 DMA 协同:从 ISR 到批处理”写出对象、事件/输入条件、状态或搬运机制、输出、一个时间或功耗约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,也要补齐芯片、IRQ、DMA、内存、供电、唤醒源、工具链、仪器和观察条件。不要用一次中断计数、电流读数或逻辑分析仪截图覆盖没有做过的验证。
06 · POWER AND REAL-TIME DELIVERY
能耗与实时交付:证据链和目标机边界
最后一个单元把本章的机制收束为交付物:对象身份、事件输入、优先级和屏蔽、DMA 缓冲、低功耗状态、唤醒原因、实时预算、功耗曲线、主机测试与目标机未验证项。交付不是把所有结果写成‘通过’,而是让读者知道哪些事实已经证明、哪些仍需在指定板卡上复核。
6.6.1 交付包的最小文件集合
最小交付包应让没有现场上下文的读者重建对象、输入、机制、输出和证据。源码、配置、工具版本、板卡照片或连接表、寄存器快照、原始波形、电流 CSV、日志和测试命令缺一不可。截图只能作为索引,原始文件和生成方式才是可复查材料。
6.6.2 对象身份和资料版本
换芯片修订、DMA 控制器、编译器、SDK、板卡电源或 PWR 模式,都可能改变优先级位数、缓存规则、请求映射和保留域。交付记录应保存访问日期、手册 URL/页码和版本字段,并标出哪些结论需要重新核对。‘同样的驱动’不是跨平台证据。
PYTHON · EVENT ACCOUNTINGfrom dataclasses import dataclass @dataclass class Counters: peripheral: int = 0 dma: int = 0 irq: int = 0 consumed: int = 0 def gaps(c): return {"dma_gap": c.peripheral - c.dma, "consumer_gap": c.dma - c.consumed}
主机模型帮助对账计数;它不能证明目标机 NVIC、DMA 总线或低功耗电流。
SHELL · DELIVERY HASHarm-none-eabi-size build/firmware.elf arm-none-eabi-objdump -h -t build/firmware.elf > build/interrupts.sections.txt sha256sum build/firmware.elf build/interrupts.sections.txt
目标工具链未安装时仍可完成主机路径;交付记录应保存命令、版本和未执行字段。
6.6.3 中断与 DMA 计数如何对账
事件计数、DMA 写入计数、ISR 通知计数和应用消费计数放在一起,才能解释重复、跳号、覆盖或消费者滞后。计数器要注明统计窗口、回绕规则和清零时刻;如果只保存最后一个样本,无法知道中间是否发生过一次短暂溢出。
| 层次 | 应留下的证据 | 不能直接推出 |
|---|---|---|
| 身份 | 芯片/板卡/版本 | 同样源码就是同样行为 |
| 事实 | 计数/波形/电流 | 一张截图覆盖全部条件 |
| 边界 | 主机/目标机/停止 | 未验证项可以省略 |
6.6.4 低功耗曲线与唤醒时间轴
低功耗时间轴至少包含最后一次业务写入、执行睡眠指令、进入平台电流、唤醒源、恢复时钟、DMA/外设重新同步和结果发布。电流曲线与事件日志要用同一触发或可对齐的 GPIO 标记;单独的一条平均电流不能解释尖峰或唤醒丢失。
6.6.5 主机路径:运行模型和故障注入
没有目标板时,读者仍可运行事件队列、DMA 索引、回绕、deadline、批量和故障策略模型,并保存测试输出。主机模型不能证明 NVIC 抢占、缓存维护、低功耗电流、目标波形或真实晶振;这些字段必须显式标为未执行,而不是留空让人误读。
从左到右是思考顺序,不是把事件、配置、数据、功耗和结论压缩成一个“通过”。
6.6.6 目标机路径:安全连接与可恢复固件
目标机实验前确认限流供电、负载额定值、调试器和探头地线、可唤醒路径、能重新下载的固件和硬件断电动作。出现异常电流、目标锁死、DMA 写越界、无法解释的温升或唤醒风暴时停止,先断电保存现场,再缩小变量。
6.6.7 单变量回归和版本差异
单变量回归可以只改 IRQ 优先级、临界区、DMA 批量、缓冲深度、cache 策略、睡眠模式或唤醒源,但不能同时换板、换输入和换仪器。先预测事件计数、端到端延迟、CPU 占用和电流曲线,再比较原始证据并记录意外变化。
6.6.8 资料卡:CMSIS、Zephyr、Linux 与 STM32
CMSIS NVIC 提供标准化的中断访问函数;Zephyr 的中断、DMA 和电源管理文档展示跨板接口;Linux DMA API 与 timers 说明另一种内核资源边界;STM32 HAL DMA/PWR 则体现厂商外设和电源模块。它们能帮助读者定位入口,却不能替代当前芯片的参考手册和板级测量。
6.6.9 本章结业:交给 UART、ADC 与 RTOS 的接口
交给后续 UART、ADC、RTOS 和联网章节的接口包括 event_source、irq_priority、mask_rule、buffer_owner、cache_policy、notify_range、deadline、wake_source、current_limit、error_counter、recovery_action 和 unverified_scope。下一章应从这些字段继续,而不是重新假设中断和 DMA 没有代价。
请围绕“能耗与实时交付:证据链和目标机边界”写出对象、事件/输入条件、状态或搬运机制、输出、一个时间或功耗约束、一个失败路径和对应证据。没有目标板时,运行主机路径并把未执行字段标为未执行;拥有目标机时,也要补齐芯片、IRQ、DMA、内存、供电、唤醒源、工具链、仪器和观察条件。不要用一次中断计数、电流读数或逻辑分析仪截图覆盖没有做过的验证。
资料卡(访问日期:2026-09-04):CMSIS NVIC、Zephyr 中断/DMA/电源管理、Linux DMA/timers 和 STM32 HAL DMA/PWR 展示不同生态的入口。通用 API 不能替代当前芯片的中断路由、缓存、低功耗域、板卡供电和测量条件。