从Var Tick角度来对CE电源管理

 Var Tick角度来对CE电源管理

一.相关的基础知识如下

1OALTimer相关函数说明

1> OALTimerInit

参数:

msecPerSysTick: 每个系统调度Tick对应多少ms

countsPerMSec: TimerCounter变化多少为1ms,其值为TimerBase Clock/1000       margin:任何时钟源都有其偏差,该值指出偏差为多少,单位为Tick

功能:

         初始化系统Timer中断以及初始化系统时间的一些变量,如g_oalTimer/curridlehigh/ curridlelow,以及函数指针变量pQueryPerformanceFrequencypQueryPerformanceCounter等。

2> OALTimerIntrHandler

参数:    

         无。

功能:

         系统Timer中断Handle

         其返回值是系统SYSINTER,可能的值有SYSINTR_RESCHEDSYSINTR_NOP。如果是SYSINTR_RESCHED则说明当前的系统需要一次任务调度,如果是后者则不需要做任何处理。

3>  OEMIdle

参数:

         无。

功能:

当系统进入System Idle的时候会调用该函数,主要完成的功能是使CPU进入低功耗模式。

2OAL中相关变量说明

CurMSec

该全局变量表示在系统启动以后,过了多少毫秒。一般在OAL中有两个地方会用到该变量,一个是在系统TimerISR中断中要更新该变量,还有就是在OEMIdle中,当然这取决于你如何实现OEMIdle函数。用户调用GetTickCount函数的时候,实际上也是获得该变量的值。在MIPS架构的处理器上该变量名为AddrCurMSec

 

dwReschedTime

该变量指WinCE系统下一次调度的时间,它会和CurMSec配合使用,也是在系统TimerISROEMIdle中被用到。在系统TimerISR中,if((CurMSec - dwReschedTime) >= 0)则返回SYSINTR_RESCHED,否则返回SYSINTR_NOP。这个很好理解,如果当前时间大于系统下一次调度的时间就进行系统调度。在OEMIdle中,if ((dwReschedTime - CurMSec) > 0)则处理器进入Idle状态,否则立即返回。就是说当前距离下一次调度还有一段时间,则处理器可以进入Idle状态。

curridlelowcurridlehigh

两个变量组成一个64bit的计数器,一个表示低32bit,一个表示高32bit。这两个遍两会在Timer初始化的时候被设置为0,会在OEMIdle函数中被更新,用于记录WinCE运行时的Idle时间,支持GetIdleTime函数。

dwDefaultThreadQuantum

表示线程的时间片大小,默认值好像是100毫秒,可以在OEMInit函数中修改。

3.系统的工作模式

         CE主要应用在嵌入式设备中,由于多未移动设备或者体积很小,因此对系统的待机时间和工作时间有较多的考虑。

         大概从3.0开始,CE引入了电源管理。

与其它模块的通信方式如下:

         标准的CE系统工作模式由下面5种:On/system idle/user idle/suspend/off。其中进入system idle的条件是当前系统中不存在RunningThread,当进入该模式后,系统中的电源管理模块会去调用OEM_Idle,使系统进入低功耗模式。

         其中idle模式的说明如下“When there are no threads ready to run, kernel  will call OEMIdle to save power. For S3C2443X platform and our BSP, we let CPU go into “IDLE” state in OEMIdle. The clock to CPU core is stopped when in IDLE mode. When exceptions occur, CPU recovers and returns to normal mode before IRQHandler calls OEMInterruptHandler, OEMIdle just does busy loop. If OEMInterruptHandler is called, OEMIdle returns. In our platform, CPU is running in NORMAL mode unless in IDLE or SLEEP mode. Certain interrupt sources we configured in OEMPowerOff turn the CPU from SLEEP back into NORMAL again.

二.VAR Tick介绍

1Tick的概念

CE的任务调度的最小单位是Tick,一个Tick又可以对应一个或者多个MS,可以在OALTimerInit中通过配置g_oalTimer.msecPerSysTick来确定它们的对应关系。

2Fixed TickVAR Tick的概念

         这里都是引用Microsoft的概念,所以有必要解释一下。Fixed TickVAR Tick差别在于,一个Tick包含固定多个MS还是可变多个MS。对于Fixed TickTick的长度在函数OALTimerInit中确定,对于VAR Tick,其长度在函数OALTimerInitOEM_Idle中确定。

         无论是Fixed Tick还是VAR Tick,系统在System Idle的时候都回去调用OEM_Idle进入低功耗模式。对于Fixed Tick情况,OEM_Idle函数会去配置系统在1 Tick之后唤醒。对于VAR TickOEM_Idle函数会计算需要多久才开始下一次系统调用,假设需要10 Tick才会开始下一次系统调度的话,则会配置Timer Controller,使其10 Tick单位后使系统唤醒。

         这么说可能有点拗口,代码如下:

void OEMIdle(DWORD idleParam)

{

     UINT32 baseMSec, idleMSec, idleSysTicks;

     INT32 usedCounts, idleCounts;

     ULARGE_INTEGER idle;

     // Get current system timer counter

     baseMSec = CurMSec;

 

     // Compute the remaining idle time

     // 计算距离下次系统调度的时间,如果需要马上开始调度,则立即返回

     idleMSec = dwReschedTime - baseMSec;

 

     // Idle time has expired - we need to return

     if ((INT32)idleMSec <= 0) return;

 

     // Limit the maximum idle time to what is supported. 

     // Counter size is the limiting parameter.  When kernel

     // profiler or interrupt latency timing is active it is set

     // to one system tick.

     // 是不是大于当前OAL中配置的Timer所支持的最大时间,如果大于它,则取最大值

     // 其实这个最大值就是g_oalTimer.maxPeriodMSec,在OALTimerInit中配置,计算方法可以参照

     // TimerSpec,该值越大越好

     if (idleMSec > g_oalTimer.maxPeriodMSec) {

         idleMSec = g_oalTimer.maxPeriodMSec;

     }

 

     // We can wait only full systick

     idleSysTicks = idleMSec/g_oalTimer.msecPerSysTick;

 

     // This is idle time in hi-res ticks

     idleCounts = idleSysTicks * g_oalTimer.countsPerSysTick;

 

     // Find how many hi-res ticks was already used

     // 计算当前用了多少个Counter,即过了多少个Timer Base Clock的时钟周期

     usedCounts = OALTimerCountsSinceSysTick();

 

     if (usedCounts == g_oalTimer.countsPerSysTick)

     {

         return;

     }

 

     // Prolong beat period to idle time -- don't do it idle time isn't

     // longer than one system tick. Even if OALTimerExtendSysTick function

     // should accept this value it can cause problems if kernel profiler

     // or interrupt latency timing is active.

     if (idleSysTicks > 1) {

         // Extend timer period

          // 根据计算出来的值重新配置Timer Counter的初始值,也即配置系统中断唤醒的时间。

          // 如果计算出来的时间等于一个Tick的时间长,则不用进行配置

         OALTimerUpdate(idleCounts-usedCounts, g_oalTimer.countsMargin);

         // Update value for timer interrupt which wakeup from idle

          // 更新系统Tick的时间长,以MS为单位,可以看到此处更新的是actualMSecPerSysTick的值

          // msecPerSysTick的值并不变化

          // 随之夜更新actualCountsPerSysTick的值

         g_oalTimer.actualMSecPerSysTick = idleMSec;

         g_oalTimer.actualCountsPerSysTick = idleCounts;

     }

 

     g_idleMSec = idleMSec;

 

     // Move SoC/CPU to idle mode

     OALCPUIdle();

 

     // Return system tick period back to original. Don't call when idle

     // time was one system tick. See comment above.

     if (idleSysTicks > 1) {

         // If there wasn't timer interrupt we have to update CurMSec&curCounts

         if (CurMSec == baseMSec) {

              // Return system tick period back to original

              // 这个需要特别注意,否则系统的CPU Loading会计算错误

              idleCounts = OALTimerUpdate(g_oalTimer.countsPerSysTick, g_oalTimer.countsMargin)+usedCounts;

 

              g_idleMSec = g_oalTimer.msecPerSysTick;

              //            RETAILMSG(1,(TEXT("(%x)"), idleSysTicks));

 

              // Restore original values

              g_oalTimer.actualMSecPerSysTick = g_oalTimer.msecPerSysTick;

              g_oalTimer.actualCountsPerSysTick = g_oalTimer.countsPerSysTick;

 

              // Fix system tick counters & idle counter

              // 这个地方一定要注意,否则系统的调度会出现问题

              CurMSec += idleCounts/g_oalTimer.countsPerMSec;

 

              g_oalTimer.curCounts += idleCounts;

              idleCounts += OALTimerCountsSinceSysTick();

              usedCounts = 0;

         }

     } else {

         if (CurMSec == baseMSec) {

              // Update actual idle counts, if there wasn't timer interrupt

              idleCounts = OALTimerCountsSinceSysTick();

              usedCounts = 0;

         }

     }

 

     // Get real idle value. If result is negative we didn't idle at all.

     idleCounts -= usedCounts;

 

     if (idleCounts < 0) idleCounts = 0;

 

     //   RETAILMSG(1,(TEXT("(%x, %x)"), idleCounts, (CurMSec - baseMSec)*g_oalTimer.countsPerSysTick));

 

     // Update idle counters

     // idle.QuadPart的值其实就是GetIdleTime的时间

     idle.LowPart = curridlelow;

     idle.HighPart = curridlehigh;

     idle.QuadPart += idleCounts;

     curridlelow  = idle.LowPart;

     curridlehigh = idle.HighPart;

}

3VAR Tick的优点

         省电。

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/243301.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

变量初始化的确定性

变量初始化的确定性 SystemVerilog初始化顺序 SystemVerilog标准增强了变量的内嵌初始化。SystemVerilog规定所有内嵌初始化先于仿真时刻0执行的事件。这就保证了如果Initial或者always过程块读取具有内嵌初始值的变量时取得正确的初始值&#xff0c;这个确定行为消除了Verilo…

很好的Android论坛

需要的兄弟可以看一下 http://www.eoeandroid.com/?fromuid9379

用户自定义和枚举数据类型

用户自定义和枚举数据类型 用户自定义 1、typedef定义用户自定义类型 SystemVerilog同C一样&#xff0c;使用typedef关键字来建立用户自定义类型。用户自定义类型允许使用现有的数据类型建立新的数据类型。新的数据类型定义后&#xff0c;可以声明这个类型的变量 typedef int…

Keyboard驱动介绍

Keyboard驱动介绍 最近手里面没啥事&#xff0c;就想看看一些Driver的MDD层。 以前改过Keyboard Driver的PDD层&#xff0c;但是对它的MDD层还真是一片空白&#xff0c;这两天随便看了看Keyboard的MDD层&#xff0c;赶紧把东西记录下来&#xff0c;以防以过段时间忘记了。 很多…

GDI+不同的地方

研究了GDI处理图像的地方&#xff0c;发现它一些与众不同的地方&#xff0c;被它坑了一天。。。。。1、GDI的像素的原点默认你在左下角的&#xff0c;所以读取像素的顺序是从最低一行开始的(bottom-left)&#xff0c;其他一般的图像处理软件&#xff0c;像Photoshop&#xff0c…

关于结构体的内容

关于结构体的内容 结构体使用类似于C语言的语法来定义 结构体使用struct关键字声明。结构体内的成员可以是任何数据类型&#xff0c;包括用户自定义类型和其他的结构体类型。 struct{int a,b; //32位变量opcode_t opcode;//用户定义类型logic [23:0] adress;//24位变量bit er…

Pushing Policy Failed because Checkpoint Firewall “Load on module failed – no memory”

One day when pushing firewall policy from Checkpoint management server to UTM 272 cluster gateways, it failed and I got error message “Load on module failed – no memory” on one of cluster members. “Network Security Policy ‘Montreal_DMZ’ was prepared …

电池驱动介绍

电池驱动介绍 一&#xff0e;整体框架 电池驱动代码量很小&#xff0c;可是麻雀虽小&#xff0c;五脏俱全。与其他的很多Driver一样&#xff0c;分为PDDMDD层&#xff0c;双层之间通过PDD的如下导出接口相联系。 Programming element Description BatteryDrvrGetLevels…

将1bpp的bmp图像存储为1bpp或者2bpp的tiff格式

// 将1bpp的位图转换为 1bit/2bit tiff /** 参数&#xff1a;BYTE *src 二值图像的像素数据&#xff0c;不包含头部信息&#xff0c; 1bpp, int src_width 原图的宽度, in pixles,int src_height 原图的高度, in pixlesint bpp 转换tiff指定的bpp */ static BYTE *BW2Tif(…

关于联合体的内容

关于联合体的内容 联合体只储存一个值 联合体只存储一个元素&#xff0c;但这个元素可以有多种表示方法&#xff0c;每种表示可以是不同的数据类型。 联合体的声明语法类似于结构体&#xff0c;联合体的成员的引用也跟结构体一样。 union{int i;int unsigned u; }data; ... d…

Point-BERT:一种基于Transformer架构的点云深度网络

目录 1. 前言 2. Point Tokenization 3. Transformer Backbone 4. Masked Point Modeling 5. Experiments Reference 1. 前言 从PointNet [1] 开始&#xff0c;点云深度网络逐渐成为解决点云特征提取与语义分析的主要研究方向。尤其在OpenAI的GPT模型获得了突破性成果后&#…

GNS3 VoIP Lab (Cisco 3725 and CME 4.3)

Here is a simple VoIP Lab in GNS3 environment. It is only used for my lab test and recorded here for future reference. 1. Topology: GNS3 Topology:Logic Topology:xp(192.168.2.60)——–C3725 Router(192.168.2.10) 2. Enviroment: ESXi 5.5 (or Vmware Workstation…

谁知道这个代码片段干嘛的

int value 0xAAAA;for (int i0; i<8; i){int tmp value & 0x3; // 取出第两个比特位置if (tmp 0x0){//}else if (tmp 0x1){//}else if (tmp 0x2){//}else if(tmp 0x3){TRACE0("???");}TRACE1("tmp0x%x\n\n", tmp);value >> 2;}

关于数组的内容

关于数组的内容 Verilog数组声明的基本语法 <data_type><vector_size><array_name><array_dimension> 例如&#xff1a; reg[15:0] RAM [0:4095];//储存器数组SystemVerilog允许任何数据类型的非压缩数组 SystemVerilog将非压缩数组的声明进行了扩展…

Touch Driver介绍

Touch Driver介绍 一&#xff0e;相关知识介绍 1&#xff0e;Touch Driver的加载过程 GWES到[HKEY_LOCAL_MACHINE/HARDWARE/DEVICEMAP/TOUCH]的“Driver name”获取Driver DLL的名字&#xff0c;如果没有找到该键值&#xff0c;则使用默认名字Touch.dll。 Touch Driver的加…

BreadCrumb控件

BreadCrumb控件&#xff0c;如上图所示&#xff0c;即面包屑导航控件&#xff0c;类似于TreeCtrl&#xff0c;但不是一次显示所有的Item&#xff0c;VC 2010可以编译通过&#xff0c;稍微修改一下其他的也可以编译&#xff0c;源代码下载&#xff1a; http://download.csdn.net…

foreach数组循环结构体

foreach数组循环结构体 foreach循环遍历任何维数的数组 Systemverilog增加了foreach循环&#xff0c;它可用来对一维或多维数组中的元素进行迭代&#xff0c;而不必指定数组每个维度的宽度。foreach循环的自变量是数组名&#xff0c;它后面是方括号内用逗号隔开的循环变量列表…

Android简介

最近Android很火&#xff0c;小弟也想了解一下它的结构。跟CE或者Mobile比起来&#xff0c;它的结构是有点凌乱&#xff0c;也难怪&#xff0c;毕竟是基于别人的内核在上层开发了一些应用 ---------------------------------------------------------------------------------…

说不尽的刘恒

认识刘恒快三十年了&#xff0c;作为曾经的同事和他小说的责任编辑&#xff0c;我只写过他一篇文章&#xff0c;还是在二十多年前。有时候特别熟悉的人反而不知道从何写起&#xff0c;因为一想起往事&#xff0c;各种记忆像开闸的水一样涌满眼前&#xff0c;让人很难落笔。1985…

印前处理的“发动机”——RIP

对于许多印刷厂来说&#xff0c;数字印前技术仍是个谜&#xff0c;尤其是光栅处理器RIP。除了RIP之处&#xff0c;我们也总听说打印机的内置控制单元。其实&#xff0c;RIP与内置控制单元在本质上是一样的&#xff0c;但也有所不同。听说起来好像有些玄乎&#xff0c;下面我们来…