批处理

什么是批处理?

“批处理”是指将传感器事件存储在硬件 FIFO 中,然后通过 HAL 报告它们,而非立即进行报告。

批处理不会唤醒 SoC 来接收每个事件,而会将事件分组到一起进行处理,从而节省大量电量。

FIFO 越大,节省的电量也越多。实施批处理是一种以牺牲硬件内存来降低功耗的做法。

当传感器配有硬件 FIFO (sensor_t.fifoMaxEventCount > 0) 时,便会进行批处理,并且会出现以下两种情况之一:

  • max_report_latency > 0,这意味着此特定传感器的传感器事件最长可延迟 max_report_latency 再通过 HAL 进行报告。
  • 或 SoC 处于挂起模式且该传感器为非唤醒传感器,这意味着在等待 SoC 唤醒时必须存储事件。

有关详情,请参阅 HAL 批处理函数一节。

与批处理相对的是轮询操作,其中事件不经过缓冲而立即被报告。轮询操作对应于以下情况:

  • max_report_latency = 0 且可将事件传递给应用时,这意味着:
    • SoC 处于唤醒状态
    • 或传感器是唤醒传感器
  • 或者,当传感器没有硬件 FIFO (sensor_t.fifoMaxEventCount = 0) 时,在这种情况下:
    • 如果 SoC 处于唤醒状态或传感器是唤醒传感器,则会报告事件
    • 如果 SoC 处于休眠状态并且传感器不是唤醒传感器,则会丢失事件

唤醒 FIFO 和非唤醒 FIFO

来自唤醒传感器的传感器事件必须存储到唤醒 FIFO 中。可以是每个传感器配一个唤醒 FIFO,或者更常见的情况是,使用一个较大的共享唤醒 FIFO,来自所有唤醒传感器的事件交错存储于该 FIFO 中。也可使用其他方案,例如一些唤醒传感器具有专用的 FIFO,其余唤醒传感器则共用同一个 FIFO。

同样,来自非唤醒传感器的传感器事件必须存储在非唤醒 FIFO 中,并且可以有一个或多个非唤醒 FIFO。

在所有情况下,唤醒传感器事件和非唤醒传感器事件都不能交错存储在同一个 FIFO 中。唤醒事件进入唤醒 FIFO,非唤醒事件进入非唤醒 FIFO。

对于唤醒 FIFO,“一个较大的共享 FIFO”设计可带来最佳的能耗效益。对于非唤醒 FIFO,使用“一个较大的共享 FIFO”和“几个较小的预留 FIFO”之间没有优劣之分。有关如何确定每个 FIFO 的规格,请参阅 FIFO 分配优先级一节。

非挂起模式下的行为

当 SoC 处于唤醒状态(未处于挂起模式)时,只要事件延迟不超过 max_report_latency,则可将事件临时存储在其 FIFO 中。

只要 SoC 不进入挂起模式,事件就不会被丢弃或丢失。如果内部硬件 FIFO 在达到 max_report_latency 之前就已存满,则会在该时间点报告事件,以确保无事件丢失。

当多个传感器共用一个 FIFO 时,如果其中一个传感器已达到 max_report_latency,则会立即报告来自该 FIFO 的所有事件,即使其他传感器尚未达到 max_report_latency 也是如此。总的来说,就是要减少按批次报告事件的次数,因此当有一个事件必须报告时,就可以报告来自所有传感器的所有事件。

例如,如果以下传感器处于启用状态:

  • max_report_latency = 20s 时进行批处理的加速度计
  • max_report_latency = 5s 时进行批处理的陀螺仪

那么,在报告陀螺仪批次(每 5 秒钟)的同时就可以报告加速度计批次,即使加速度计和陀螺仪未共用同一个 FIFO 也可以报告。

挂起模式下的行为

如果希望在不使 SoC 保持唤醒的情况下从后台收集传感器数据,则采用批处理特别有用。由于传感器驱动程序和 HAL 实现被禁止持有唤醒锁*,因此 SoC 可在收集传感器数据时进入挂起模式。

SoC 挂起时的传感器行为取决于传感器是否为唤醒传感器。有关详情,请参阅唤醒传感器一节。

当非唤醒 FIFO 存满时,它必须环绕并像环形缓冲区一样运作,覆盖较旧的事件:即新事件替换旧事件。 在挂起模式下,max_report_latency 对非唤醒 FIFO 没有影响。

当唤醒 FIFO 存满时,或者当其中一个唤醒传感器的 max_report_latency 已过时,硬件必须唤醒 SoC 并报告数据。

在这两种情况下(唤醒和非唤醒),只要 SoC 退出挂起模式,即使一些传感器的 max_report_latency 未过,也会产生一个包含所有 FIFO 内容的批处理。这样可最大限度地降低 SoC 再次挂起而必须重新将其唤醒的风险。这进而可以最大限度地降低功耗。

*不允许驱动程序持有唤醒锁的一个明显例外情况是,在 max_report_latency 小于 1 秒时,启用轮询报告模式的唤醒传感器。在此情况下,驱动程序可以持有唤醒锁,这是因为 SoC 在进入挂起模式前会被唤醒事件唤醒,因此没有机会进入挂起模式。

批处理唤醒传感器时的注意事项

根据设备不同,SoC 可能需要几毫秒才能完全退出挂起模式并开始刷新 FIFO。因此必须在 FIFO 中分配足够的头空间,才能让设备完全退出挂起状态,而不造成唤醒 FIFO 溢出。不得丢失任何事件,并且必须遵照 max_report_latency

批处理采用 On-change 触发方式的非唤醒传感器时的注意事项

采用 On-change 触发方式的传感器仅在测量值发生变化时才会生成事件。如果测量值在 SoC 处于挂起模式时发生变化,则应用预计会在 SoC 唤醒时立即收到事件。因此,如果采用 On-change 触发方式的非唤醒传感器与其他传感器共用 FIFO,则在执行该传感器事件的批处理时,必须小心。每个采用 On-change 触发方式的传感器所生成的最后一个事件都必须保存在共享 FIFO 之外,使其永远不会被其他事件覆盖。当 SoC 唤醒时,在报告 FIFO 中的所有事件后,还必须报告最后一个采用 On-change 触发方式的传感器事件。

以下是我们希望避免的情况:

  1. 应用同时注册到共用同一个 FIFO 的非唤醒计步器(采用 On-change 触发方式)和非唤醒加速度计(轮询模式)
  2. 应用收到一个计步器事件“step_count = 1000 步”
  3. SoC 转至挂起状态
  4. 用户步行 20 步,导致计步器和加速度计事件交错存储,最后的计步器事件为 “step_count = 1020 步”
  5. 用户长时间不动,导致加速度计事件在 FIFO 中继续累积,最终覆盖共享 FIFO 中的各 step_count 事件
  6. SoC 唤醒并将 FIFO 中的所有事件发送到应用
  7. 应用只收到了加速度计事件,并认为用户没有走步(糟糕!)

通过将最后的计步器事件保存在 FIFO 之外的存储区,即使所有其他计步器事件都被加速度计事件覆盖,HAL 仍可以在 SoC 唤醒时报告最后的事件。这样,当 SoC 唤醒时,应用就会收到“step_count = 1020 步”。

实现批处理

批处理无法在软件中模拟,而必须借助硬件 FIFO 完全在硬件中实现。批处理尤其不能在 SoC 上实现(例如在 HAL 中实现),因为这样会产生相反效果。进行批处理是为了大幅节省电量。批处理必须在不借助 SoC 的情况下实现。在批处理期间应允许 SoC 处于挂起模式。

可随时修改 max_report_latency,特别是在已启用指定传感器的情况下;并且该操作不应导致事件丢失。

FIFO 分配优先级

在硬件 FIFO 大小有限的平台上,系统设计人员可能必须选择为各传感器预留多少 FIFO 空间。为便于选择,下面列出了在不同传感器上实现批量处理时可能有帮助的应用。

高值:低功率行人航位推算

目标批处理时间:1 到 10 分钟

待批处理的传感器:

  • 唤醒步测器
  • 唤醒游戏旋转矢量传感器(频率 5 Hz)
  • 唤醒气压计(频率 5 Hz)
  • 唤醒未校准磁力计(频率 5 Hz)

批处理此类数据,可在 SoC 处于挂起模式时执行行人航位推算。

高值:中等功率间歇性动作/手势识别

目标批处理时间:3 秒

带批处理的传感器:非唤醒加速度计(频率 50 Hz)

批处理此类数据,可定期识别任意动作和手势,而无需在收集数据时保持 SoC 处于唤醒状态。

中等值:中等功率连续动作/手势识别

目标批处理时间:1 到 3 分钟

待批处理的传感器:唤醒加速度计(频率 50Hz)

批处理此类数据,可持续识别任意动作和手势,而无需在收集数据时保持 SoC 处于唤醒状态。

中高值:减少中断负载

目标批处理时间:小于 1 秒

待批处理的传感器:任意高频传感器(通常为非唤醒传感器)。

如果陀螺仪设置为 240 Hz,仅仅批处理 10 个陀螺仪事件就可以将中断次数从 240 次/秒减少到 24 次/秒。

中等值:连续低频数据采集

目标批处理时间:1 到 10 分钟

待批处理的传感器:

  • 唤醒气压计(频率 1 Hz)
  • 唤醒湿度传感器(频率 1 Hz)
  • 其他类似频率的低频唤醒传感器

可创建低功耗的监控应用。

中低值:连续全传感器采集

目标批处理时间:1 到 10 分钟

待批处理的传感器:所有唤醒传感器(在高频下运行)

允许在 SoC 处于挂起模式的情况下,完整收集传感器数据。只需考虑 FIFO 空间是否构成问题。