2.11 低功耗框架(power management)
2.11.1 概念
CPU电源管理的目的在于节约CPU的运行消耗功率,当CPU不执行任务时,进入idle task, idle task通常的做法是一个while(1)循环,但当CPU电源管理功能启用时,这个while(1)循环将被替换成将CPU设置为睡眠模式,从而节省CPU的功率消耗。CPU睡眠模式依据睡眠深度和节电程度,可以分成不同的几个睡眠状态,这种睡眠状态,我们称之为C状态。C状态包含以下状态:
(1)C0:可运行指令状态,CPU的电源保持供给,时钟也保持跳动。
(2)C1:不执行指令状态,CPU电源/时钟保持供给。所有的CPU都支持这种状态,这种状态可以通过执行一条CPU的指令来进入(WFI for ARM, HLT for IA 32-bit processors)。
(3)C2:可选,不执行指令状态,每种CPU进入C2的方法是不一样的,具体请参考CPU或SOC的用户手册,C2必须比C1更加省电。
(4)C3:可选,不执行指令状态,每种CPU进入C3的方法是不一样的,具体请参考CPU或SOC的用户手册,C3必须比C2更加省电。
(5)C4~Cn:可选,不执行指令状态。
2.11.2 TICKLESS
当CPU决定进入睡眠状态时,同时关闭系统tick中断,并在醒来时恢复系统tick中断并补偿tick到内核的做法,我们称之为TICKLESS。
1.关闭系统tick中断
关闭系统tick中断的目的是为了更加省电,当系统进入睡眠状态后,没有必要再保持系统tick中断的周期性发送,可以让CPU睡得更长,否则每个tick中断到来时,CPU需要周期性处理tick中断;另外,系统tick中断的周期性发生本身也耗电。
对于单核系统来说,当CPU决定睡眠前,就是关闭系统tick中断的时机。对于多核系统来说,情况稍微复杂一点,系统tick中断是一种全局性的操作系统资源,整个操作系统依赖中断来驱动一些操作系统事务,比如任务延迟、信号量延迟等待等跟时间相关的事务。所以,不是每一个core都能在决定睡眠前关闭系统tick,只有当所有core决定睡眠后,最后一个进入睡眠的core负责关闭系统tick。
2.唤醒TICKLESS睡眠状态下的CPU
依据CPU的睡眠程度不同,唤醒CPU的唤醒源也不同,一般来说,当CPU处于C1状态下,任务中断都能唤醒CPU,而当CPU处于深度睡眠,只有那些特定的唤醒源才能将其唤醒CPU。
one-shot中断可以由任何外设来编程产生。一般而言,硬件时钟天然支持产生one-shot中断,比如硬件timer或者RTC。one-shot中断的来源也可以是外部sensor,比如红外感应器,当感应到有人时就产生一个中断来唤醒CPU,这种机制可以应用在门铃等方案上。
3.进入TICKLESS睡眠时选择C状态
C1状态是天然支持TICKLESS工作的,但依据实际的方案不同,最终产品不一定会选取C1来工作。其他的C状态(如C2, C3, C4, …)依据硬件而定,C1状态是CPU天然支持的,而C2以及Cn(n=3,4,5, …)状态则完全由硬件制造商来决定。例如对STM32L496G-DISCO而言,此款板子支持C1/C2/C3/C4。
在进入TICKLESS睡眠时该选择哪个Cn状态?其基本原则是,CPU应该节省更多的电并且能够及时被唤醒来执行任务。一般地,Cn的n值越大意味着CPU从Cn状态的苏醒时间(下面将称之为latency)也越长。依据ACPI规范对C1的定义,符合ACPI标准的C1状态在返回时,系统软件可认为是没有延迟时间的,对于其他Cn状态的苏醒时间,则完全由硬件决定,但是系统软件必须考虑这个因素。
让我们来看一个案例:CPU支持三个C状态C1, C2, C3, latency of C1为0μs, latency of C2为500μs, latency of C3为1000μs。当操作系统决定进入TICKLESS睡眠模式200μs时,唯一可选的Cn状态只有C1,因为C2、C3的苏醒时间大于200μs。当操作系统决定进入TICKLESS模式550μs时,C1、C2状态都可以符合条件,如果进入C2状态,那么one-shot中断计划应该被设定到550μs-500μs=50μs,意味着CPU将睡眠50μs,然后加额外的苏醒时间500μs,整体花费时间是550μs,而另一个需要考虑的因素是C2状态比C1状态能节省更多的电力,所以在这个案例中,C2将作为最终选择。当操作系统决定进入TICKLESS状态1200μs时,将会选择C3,那么one-shot的编程产生时间将是1200μs-1000μs=200μs。