RTC 与 LPTIM:独立时间域与请求借用

本文说明如何通过静态类型化 factory 查找和显式 Platform 生命周期使用 Native 原始日历 RTC 与有限计数 LPTIM。一份普通 TOML 装配选择独立实例;公共调用直接进入对应 provider。此 Native 主机模型范围不提供 MCU RTC/LPTIM 驱动、产品时钟服务或硬件低功耗连续性。

公共声明 rtc.h、lptim.h 和仅供主机使用的模型控制是权威合同。本文解释所有权和使用边界,不重复完整返回值参考。

当前实现与后续接入

当前实现包含公共 C 包装层和 Native provider。包装层验证接口面,再通过只读操作表把调用分发到其上下文。Native 实例共享两个只读操作表,每类设备一个;各实例保留独立状态。实现没有堆、注册表、隐藏 worker、请求队列或强制 OS 适配层。

构造属于内部接入边界。生成的 Platform 准备流程只对全新 owner 存储构造一次,复制所选 Core 时钟接口面而不调用其时间读取函数,并开放准入。已构造 owner 后续启动使用显式私有重新开放。外部产品使用公共头文件和生成头文件,不使用私有 provider 构造函数。RTC 初始保持未设置,直到显式调用公共 set。

所选 Native 主机模型现已实现显式私有重新开放和普通类型化配置装配。私有重新开放在真实撤源并完成外部 join 后改变 owner 代次,而不重新构造存储。H743 和 U575 RTC/LPTIM 适配仍是未来目标,需要独立的硬件合同和验证证据。

当前 Native RTC/LPTIM 装配、所有权与最终发布;虚线硬件分支是未来目标

FIG-21 区分当前 Native 构建期装配、运行调用和请求源推进,边上的文字说明各自关系。虚线硬件分支是目标,不建立物理驱动、IRQ、STOP/VBAT 连续性或 HIL 结果。factory 返回已有接口面,绝不执行生命周期操作。

三个域,各自承担不同含义

Core deadline 使用绝对单调微秒,通过复制的 nx_clock_t 接口面读取。原接口描述符可以按值复制,但其上下文始终被借用:装配方必须保证上下文的完整生命周期、存储不重叠、有限且单调的读数,以及调用不重入。观察到的 Core 时间大于或等于有限 deadline 时,该 deadline 到期。NX_DEADLINE_NEVER 不读取 deadline 时钟,但也不会推进日历或计数器。

RTC 使用原始年份 00..99、月/日和 24 小时时间,不包含 UTC、世纪、时区或闰秒。原始年份模 4 等于零时为闰年。星期是独立的 1..7 字段。自然发生的 99 -> 00 回绕会推进日历,但不创建新的设置域;显式设置成功会推进不回绕的代次。

RTC alarm 匹配未来某次日/时/分/秒模式,没有月/年字段或通配掩码。若模式已经匹配当前秒,提交返回 STATE;provider 不会静默把它解释为以后的重复事件。UTC 转换、日期选择、校时、重复调度与授权策略由产品负责。

LPTIM 接受一次 1..65536 tick 的有限计数。正值 tick_hz 是固定声明的单位速率,不是振荡器精度实测值。16 位采样值模 65536:完整的 65536 tick 计数可以采样为零。单凭计数器为零不能证明完成或低功耗连续性。已开放且空闲时返回零和 running=false;关闭后的公共 read/sample 返回 STATE,且不改变输出。

RTC 和 LPTIM 域包含 owner 地址与受检查的 uint64_t 代次。两者使用不同类型,也不是 Core deadline token。RTC 设置、私有重新开放和已完成的 LPTIM 撤源会使旧域失效。token 只比较身份而不解引用身份地址;它既不授予权限,也不建立跨启动身份。在结束或复用 owner 存储前,必须退役所有 token 和外部观察者。

代次不会静默回绕。Native RTC 在 UINT64_MAX 时执行 set 返回 EXHAUSTED;Native LPTIM 在该上限时会在接受请求前拒绝提交,从而保证此前已接受的计数始终能够执行预留的最终代次递增。耗尽并不授予重置已停止 owner 或丢弃借用的权限。

谁拥有存储,谁推进执行

每个实例的所有调用都由一个串行、不可重入的任务执行者负责,包括读取、模型控制和生命周期操作。接口面、操作表、私有 owner 与被借用的时钟上下文必须覆盖所有已接受请求及独立观察者/控制者的退出过程。实现没有隐式跨任务锁,也未提供 ISR 调用合同。产品若需要跨任务取消,必须在 provider 外显式提供稳定槽位/代次控制和 join。

完整请求由调用方拥有。准备请求前先初始化 Core base;只能在所有 join 完成后,准备未被借用的 READY 或结果已消费的 SETTLED 存储。prepare 复制元数据,不建立借用。请求及输入/输出范围必须对齐、不发生地址回绕,且与已知受保护对象不重叠。这些检查不是通用的无效指针或内存访问判定器;不透明上下文范围以及存储映射和生命周期仍由装配方负责。

每个实例最多接受一个请求。submit 先验证生命周期、空闲状态、当前域和设备类别的范围,再读取有限 deadline。SUCCESS 表示 ACCEPTED;拒绝不会保留请求引用或请求源效果。被拒绝的请求仍归调用方所有。可选操作表方法缺失时返回 UNSUPPORTED;公共输入格式不合法时,可以在分发到 provider 前返回 INVALID。

ACCEPTED 后,调用方必须保持请求的每个字节有效且不可修改,直到以 acquire 观察到 SETTLED;随后消费结果,并在复用前 join 所有独立控制者或观察者。取消、到期、停止、撤源失败或采样到完成标志都不会撤销该借用。

请求源推进、终止原因与最终访问

主机模型推进只改变请求源状态。RTC 每次推进限制为 0..86400 秒,最多进位一天;日历已初始化时,即使准入关闭仍可推进。LPTIM 每次推进限制为 0..65536 tick,并在计数目标处饱和;未 armed 的请求源不累计。这些 hook 既不读取 Core 时间,也不访问或结清请求。设置或清除撤源 hold 同样不会结清请求。

显式公共 service 检查谓词并推进撤源。cancel 和 stop 可以直接调用撤源过程,因此在没有 hold 时可能立即结清;service 不是唯一的最终发布者。首次 service 观察时,已到期的有限 deadline 优先于 pending 事件;更早执行的 cancel 或 stop 则可能先锁存 CANCELLED。原因一旦锁存,在等待撤源期间保持首次终止原因不变。

若撤源被 hold 阻止,请求继续被借用并保持 QUARANTINED。cancel 可以因接受取消而返回 SUCCESS,而 service/stop 返回 BUSY。解除模型 hold 只是让后续真实撤源成为可能;执行者仍须调用适当的公共 service/cancel/stop 操作。只要这些工作尚未结束,就必须保持 owner 和请求存活。

成功撤源先禁用请求源、清除 pending 状态,并从 owner 脱离请求引用。LPTIM 还会在发布前记录最终 tick 进度并推进代次。随后 provider 才以 release 发布 SETTLED,作为对请求的最终访问。RTC 的 transferred 成功时为 1,其他结果为 0。LPTIM 的 transferred 是最终观察到的 tick 数,包含 hold 阻止撤源期间继续累计的 tick;它不会在首次锁存取消/超时时冻结。

stop 会立即关闭准入,即使撤源返回 BUSY。关闭后的读取和提交仍被拒绝,而 service/cancel 仍可排空保留的借用。重复执行已完成的干净 stop 是幂等的。stop 成功不会结束 owner 存储生命周期,也不会免除外部 join。重新开放是独立的显式私有生命周期操作,不是查找、模型推进或重复调用构造函数的副作用。

显式私有重新开放保留身份与责任

构造函数在 owner 存储生命周期内只允许成功调用一次。内部 nx_native_rtc_start 和 nx_native_lptim_start 操作重新开放同一个稳定 owner;它们不是公共应用 SDK API。操作要求 owner 有效、已构造且已关闭,不保留 active 请求、armed 请求源、pending 事件或终止责任。调用方还必须证明外部控制者和观察者已经 join;检查 owner 字段不能替代这些外部 join 的证明。

完整范围验证后,保留的请求/请求源责任优先返回 BUSY,随后才判断未构造/已开放的 STATE。已关闭且完成 join 的 owner 在 UINT64_MAX 时返回 NX_ERROR_EXHAUSTED。每次拒绝都保持所有 owner 字节、请求源事实、故障状态、时钟和代次不变。start 不是幂等操作:干净且已经开放的 owner 返回 STATE。被 hold 阻止撤源的已关闭借用仍被保留并保持 QUARANTINED;start 或重复构造都不能撤销它。

成功时,私有 start 先检查代次余量,递增代次,再开放准入。它不读取 Core 时间、不推进请求源、不重新构造对象,也不增加状态字段或 owner 池。它保留 RTC 已设置/未设置状态及日历、LPTIM 固定 tick_hz、复制的时钟绑定和外部撤源 hold。其他方面已经空闲且完成 join 的 owner 上,hold 标志属于外部故障,不是活动借用;重新开放会保留该故障,而不是静默清除。

最后一次允许的重新开放可以把 UINT64_MAX - 1 推进到 UINT64_MAX;之后再次干净停止后,重新开放就会因代次耗尽而拒绝。外部仍持有的旧 READY 域保持过期,提交时被拒绝且请求不变。不得通过回绕、重置为一或隐式重新构造来修复耗尽。模型请求源推进和结果消费仍与该生命周期迁移分开。

类型化装配沿用现有配置路径

下面维护的 pair 夹具是一份完整 Native 装配。普通 [rtc.name] 和 [lptim.name] 段沿用现有不可变 ControllerIR -> provider -> factory 路径解析。calendar-alarm 没有日期或时区配置项;counter16-oneshot 要求显式、正值、uint32_t 范围内的 tick_hz。未知策略/IRQ 字段和重复控制器占用会被拒绝,而不是被自动修复。

schema = 2
board = "native_reference"
backend = "native"
clock = "model"
optimization = "Os"

[memory]
main_stack_bytes = 2048
flash_load_limit_bytes = 65536
static_ram_limit_bytes = 32768
libc_heap_bytes = 0

[factory]
capabilities = true

[rtc.calendar_a]
binding = "rtc0"
mode = "calendar-alarm"

[rtc.calendar_b]
binding = "rtc1"
mode = "calendar-alarm"

[lptim.counter_a]
binding = "lptim0"
mode = "counter16-oneshot"
tick_hz = 32768

[lptim.counter_b]
binding = "lptim1"
mode = "counter16-oneshot"
tick_hz = 1000

Native 主机模型事实提供不带引脚或 IRQ 路由的 RTC0/RTC1 和 LPTIM0/LPTIM1。两个软件 RTC 实例用于验证隔离,不代表真实芯片具有两个 RTC 外设。生成器只发射选中的静态状态、只读接口面和纯类型化查找。所选共享 deadline 适配器读取 nx_time_now_us(),不推进任何 RTC/LPTIM 请求源。空装配不发射选中的 RTC/LPTIM 状态或该适配器。

公共入口与生成入口

通过 nexus_factory.h 中的 nx_factory_rtc(id) 或 nx_factory_lptim(id) 取得接口面。ID 只属于所选装配和设备类别;无效/未选入的 ID 返回 NULL。接口面和共享操作表在启动前已经存在,但 RTC read 和 LPTIM sample 会拒绝已关闭/未构造状态下的调用。查找既不构造 owner,也不读取时钟。

外部生命周期 owner 调用 nx_platform_start(),并检查 primary、cleanup 和 remaining_effects。随后按需显式设置 RTC、复制当前域、准备调用方请求,再通过公共 port 提交。它分别推进所需模型请求源和公共 service。启动不会创建调度器,推进 Core 时间也不会推进日历或有限计数。

若 nx_platform_stop() 返回 BUSY,必须保留每个被借用的请求及其 owner,推进真实撤源、消费最终结果并 join 外部使用者,然后重试 stop。再次 start 前必须完成 Platform 停机;它不会静默重新构造对象或重新开放尚未结束的 stop。pair consumer 和 empty consumer 是维护的公共/生成入口主机验证程序,不是硬件应用示例。

成本与验证边界

公共接口面包含两个指针;每实例状态保存复制的时钟接口面、域以及设备类别专用的日历/计数状态。每次只保留一个请求。RTC 模型不按秒循环,工作量有界;LPTIM 使用有界饱和算术。此结构避免动态分配和队列容量成本,但不建立字节预算、栈上界、WCET、振荡器精度或 MCU 功耗结果。这些指标必须针对实际选择的构建与硬件测量。

本文描述的 Native 行为与显式私有重新开放以另行记录的手工验证证据为基础。phase3 manifest 不记录这些手工程序的重新执行。

phase3 开发证据绑定已冻结的含未提交修改源码元组,其 source-and-execution manifest SHA-256 为 85e01921e1bc53b81f30bff232bf3477aec3ac6d228a04ebebc3891dd21d729f。它记录配置测试、生成的 pair/empty 程序和聚焦的已安装开发 SDK consumer。它不继承 main 分支验证资格,也不建立干净的可发布 SDK、完整 SDK 矩阵、重复复现、全仓库 CI 或物理结果。

本文未建立 H743/U575 RTC 或 LPTIM provider、ARM RTC/LPTIM 执行、备份域复位/所有权、振荡器选择/校准、STOP 模式唤醒、VBAT 持久化、硬件保持或实板 HIL 结果。未来适配必须证明精确 SoC/Board/时钟/IRQ/安全域和保留存储合同;芯片数据手册中的能力或公共 API 本身都不能替代这些证明。

相关机制:请求所有权、类型化 factory、Native provider 源码和 I/O 演进合同。产品调度、协议状态、持久化策略和私有板级接线保留在外部仓库。