2019-07-17 20:26:09 u010164190 阅读数 1364
  • 韦东山升级版嵌入式视频之快速入门

    韦东山老师为啥要录升级版嵌入式视频? 200x年左右,嵌入式Linux在全世界、在中国刚刚兴起。 我记得我2005年进入中兴时,全部门的人正在努力学习Linux。 在2008年,我写了一本书《嵌入式Linux应用开发完全手册》。 它的大概内容是:裸机、U-boot、Linux内核、Linux设备驱动。 那时还没有这样讲解整个系统的书, 芯片厂家Linux开发包也还不完善,从bootloader到内核,再到设备驱动都不完善。 有全系统开发能力的人也很少。 于是这书也就恰逢其时,变成了畅销书。 我也根据这个思路录制了视频:裸机、U-boot、Linux内核、Linux设备驱动。 收获些许名声,带领很多人进入Linux世界。 11年过去了,嵌入式Linux世界发生了翻天覆地的变化 ① 基本系统能用 芯片厂家都会提供完整的U-boot、Linux内核、芯片上硬件资源的驱动。 方案厂家会做一些定制,比如加上某个WIFI模块,会添加这个WIFI模块的驱动。 你可以使用厂家的原始方案,或是使用/借鉴方案商的方案,做出一个“能用”的产品。 ② 基础驱动弱化;高级驱动专业化 基础的驱动,比如GPIO、UART、SPI、I2C、LCD、MMC等,有了太多的书籍、视频、示例代码,修修改改总是可以用的。 很多所谓的驱动工程师,实际上就是“调参工程师”。 我们群里有名的火哥,提出了一个概念:这些驱动就起一个“hardware enable”的作用。 高级的驱动,比如USB、PCIE、HDMI、MIPI、GPU、WIFI、蓝牙、摄像头、声卡。 体系非常复杂,很少有人能讲清楚,很多时候只是一笔带过。 配置一下应用层工具就了事,能用就成。 这些高级驱动,工作中需要专门的人来负责,非常专业。 他们是某一块的专家,比如摄像头专家、音频专家。 ③ 项目为王 你到一个公司,目的是把产品做出来,会涉及APP到内核到驱动全流程。 中小公司玩不起华为中兴的配置,需要的是全面手。 大公司里,只负责很小很小一块的镙丝钉,位置也不太稳固啊。 所以,如果你不是立志成为某方面的专家,那就做一个全栈工程师吧。 ④ 调试很重要 都说代码是3分写7分调,各种调试调优技术,可以为你的升职加薪加一把火。 基于上述4点,我录制的全新视频将有这些特点: 1. 快速入门, 2. 实战项目, 3. 驱动大全, 4. 专题, 5. 授人以渔, 6. 要做任务 另外,我们会使用多款芯片同时录制,先讲通用的原理,再单独讲各个板子的操作。 这些芯片涵盖主流芯片公司的主流芯片,让你学习工作无缝对接。 1.快速入门 入门讲究的是快速,入门之后再慢慢深入, 特别是对于急着找工作的学生,对于业余时间挑灯夜读的工作了的人,一定要快! 再从裸机、U-boot、内核、驱动这样的路线学习就不适合了,时间就拉得太长了。 搞不好学了后面忘了前面。 并且实际工作中并不需要你去弄懂U-boot,会用就行:U-boot比驱动还复杂。 讲哪些内容? 怎么讲呢? 混着讲 比如先讲LED APP,知道APP怎么调用驱动,再讲LED硬件原理和裸机,最后讲驱动的编写。 这样可以快速掌握嵌入式Linux的整套开发流程, 不必像以前那样光学习裸机就花上1、2个月。 而里面的裸机课程,也会让你在掌握硬件操作的同时,把单片机也学会了。 讲基础技能 中断、休眠-唤醒、异步通知、阻塞、内存映射等等机制,会配合驱动和APP来讲解。 这些技能是嵌入式Linux开发的基础。 而这些驱动,只会涉及LED、按制、LCD等几个驱动。 掌握了这些输入、输出的驱动和对应的APP后,你已经具备基本的开发能力了。 讲配置 我们从厂家、从方案公司基本上都可以拿到一套完整的开发环境,怎么去配置它? 需要懂shell和python等配置脚本。 效果效率优先 以前我都是现场写代码、现场写文档,字写得慢,降低了学习效率。 这次,效果与效率统一考虑,不再追求所有东西都现场写。 容易的地方可先写好代码文档,难的地方现场写。 2.实战项目 会讲解这样的涉及linux网关/服务器相关项目(不限于,请多提建议):                      定位为:快速掌握项目开发经验,丰满简历。 涉及的每一部分都会讲,比如如果涉及蓝牙,在这里只会讲怎么使用,让你能写出程序;如果要深入,可以看后面的蓝牙专题。 3. 驱动大全 包括基础驱动、高级驱动。 这些驱动都是独立成章,深入讲解。 虽然基础驱动弱化了,但是作为Linux系统开发人员,这是必备技能,并且从驱动去理解内核是一个好方法。 在讲解这些驱动时,会把驱动的运行环境,比如内核调度,进程线程等概念也讲出来,这样就可以搭建一个知识体系。 没有这些知识体系的话,对驱动的理解就太肤浅了,等于在Linux框架下写裸机,一叶障目,不见泰山。 定位为:工具、字典,用到再学习。 4. 专题 想深入学习的任何内容,都可独立为专题。 比如U-boot专题、内核内存管理专题、systemtap调试专题。

    4924 人正在学习 去看看 韦东山
1.Linux 4中休眠模式
# echo standby >/sys/power/state //CPU和RAM在运行
# echo mem > /sys/power/state  //挂起到内存(待机),关闭硬 盘、外设等设备
# echo disk > /sys/power/state //挂起到硬盘(休眠),关闭硬盘、外设等设备,进入关机状态。此时计算机
完全关闭,不耗电 
# echo on > /sys/power/state  //退出休眠
# echo +10 > /sys/class/rtc/rtc0/wakealarm //10s后rtc唤醒cpu

- On(on)                  S0 -  Working
- Standby (standby)       S1 -  CPU and RAM are powered but not executed
- Suspend to RAM(mem)      S3 -  RAM is powered and the running content is saved to RAM
- Suspend to Disk,Hibernation(disk) S4 -  All content is saved to Disk and power down

2.查看电源状态
//查看当前睡眠情况
# cat /sys/power/state

//查看当前那些占用了阻止深度睡眠的wake lock                                                                           
# cat /sys/power/wake_lock      

//查看wake lock状态情况                                                           
# cat /sys/proc/wakelocks

//手动释放一次名称为“PowerManagerSerivce”的wake lock引用次数-1,为0时进入睡眠                                                                     
#cat "PowerManagerService" > /sys/power/wake_unlock             

2014-12-21 20:02:05 hellomxj1 阅读数 1918
  • 韦东山升级版嵌入式视频之快速入门

    韦东山老师为啥要录升级版嵌入式视频? 200x年左右,嵌入式Linux在全世界、在中国刚刚兴起。 我记得我2005年进入中兴时,全部门的人正在努力学习Linux。 在2008年,我写了一本书《嵌入式Linux应用开发完全手册》。 它的大概内容是:裸机、U-boot、Linux内核、Linux设备驱动。 那时还没有这样讲解整个系统的书, 芯片厂家Linux开发包也还不完善,从bootloader到内核,再到设备驱动都不完善。 有全系统开发能力的人也很少。 于是这书也就恰逢其时,变成了畅销书。 我也根据这个思路录制了视频:裸机、U-boot、Linux内核、Linux设备驱动。 收获些许名声,带领很多人进入Linux世界。 11年过去了,嵌入式Linux世界发生了翻天覆地的变化 ① 基本系统能用 芯片厂家都会提供完整的U-boot、Linux内核、芯片上硬件资源的驱动。 方案厂家会做一些定制,比如加上某个WIFI模块,会添加这个WIFI模块的驱动。 你可以使用厂家的原始方案,或是使用/借鉴方案商的方案,做出一个“能用”的产品。 ② 基础驱动弱化;高级驱动专业化 基础的驱动,比如GPIO、UART、SPI、I2C、LCD、MMC等,有了太多的书籍、视频、示例代码,修修改改总是可以用的。 很多所谓的驱动工程师,实际上就是“调参工程师”。 我们群里有名的火哥,提出了一个概念:这些驱动就起一个“hardware enable”的作用。 高级的驱动,比如USB、PCIE、HDMI、MIPI、GPU、WIFI、蓝牙、摄像头、声卡。 体系非常复杂,很少有人能讲清楚,很多时候只是一笔带过。 配置一下应用层工具就了事,能用就成。 这些高级驱动,工作中需要专门的人来负责,非常专业。 他们是某一块的专家,比如摄像头专家、音频专家。 ③ 项目为王 你到一个公司,目的是把产品做出来,会涉及APP到内核到驱动全流程。 中小公司玩不起华为中兴的配置,需要的是全面手。 大公司里,只负责很小很小一块的镙丝钉,位置也不太稳固啊。 所以,如果你不是立志成为某方面的专家,那就做一个全栈工程师吧。 ④ 调试很重要 都说代码是3分写7分调,各种调试调优技术,可以为你的升职加薪加一把火。 基于上述4点,我录制的全新视频将有这些特点: 1. 快速入门, 2. 实战项目, 3. 驱动大全, 4. 专题, 5. 授人以渔, 6. 要做任务 另外,我们会使用多款芯片同时录制,先讲通用的原理,再单独讲各个板子的操作。 这些芯片涵盖主流芯片公司的主流芯片,让你学习工作无缝对接。 1.快速入门 入门讲究的是快速,入门之后再慢慢深入, 特别是对于急着找工作的学生,对于业余时间挑灯夜读的工作了的人,一定要快! 再从裸机、U-boot、内核、驱动这样的路线学习就不适合了,时间就拉得太长了。 搞不好学了后面忘了前面。 并且实际工作中并不需要你去弄懂U-boot,会用就行:U-boot比驱动还复杂。 讲哪些内容? 怎么讲呢? 混着讲 比如先讲LED APP,知道APP怎么调用驱动,再讲LED硬件原理和裸机,最后讲驱动的编写。 这样可以快速掌握嵌入式Linux的整套开发流程, 不必像以前那样光学习裸机就花上1、2个月。 而里面的裸机课程,也会让你在掌握硬件操作的同时,把单片机也学会了。 讲基础技能 中断、休眠-唤醒、异步通知、阻塞、内存映射等等机制,会配合驱动和APP来讲解。 这些技能是嵌入式Linux开发的基础。 而这些驱动,只会涉及LED、按制、LCD等几个驱动。 掌握了这些输入、输出的驱动和对应的APP后,你已经具备基本的开发能力了。 讲配置 我们从厂家、从方案公司基本上都可以拿到一套完整的开发环境,怎么去配置它? 需要懂shell和python等配置脚本。 效果效率优先 以前我都是现场写代码、现场写文档,字写得慢,降低了学习效率。 这次,效果与效率统一考虑,不再追求所有东西都现场写。 容易的地方可先写好代码文档,难的地方现场写。 2.实战项目 会讲解这样的涉及linux网关/服务器相关项目(不限于,请多提建议):                      定位为:快速掌握项目开发经验,丰满简历。 涉及的每一部分都会讲,比如如果涉及蓝牙,在这里只会讲怎么使用,让你能写出程序;如果要深入,可以看后面的蓝牙专题。 3. 驱动大全 包括基础驱动、高级驱动。 这些驱动都是独立成章,深入讲解。 虽然基础驱动弱化了,但是作为Linux系统开发人员,这是必备技能,并且从驱动去理解内核是一个好方法。 在讲解这些驱动时,会把驱动的运行环境,比如内核调度,进程线程等概念也讲出来,这样就可以搭建一个知识体系。 没有这些知识体系的话,对驱动的理解就太肤浅了,等于在Linux框架下写裸机,一叶障目,不见泰山。 定位为:工具、字典,用到再学习。 4. 专题 想深入学习的任何内容,都可独立为专题。 比如U-boot专题、内核内存管理专题、systemtap调试专题。

    4924 人正在学习 去看看 韦东山

功耗调试之如何调试功耗(一)

导航制导与控制实验室

   2015年01月01日

本文就开始讨论功耗的调试步骤和方法。

本文主要的内容如下:

一、明确调试的目标

二、明确调试的内容

三、参照电路框图找出我们需要检测的输出

四、找出或引出需测试的输出

五、功耗测试的步骤流程图

一、明确调试的目标

明确调试的目标,即在满足当前的需求情况下,尽最大的可能去降低各种状态下、各路模块的功耗值。一般情况下,功耗越低要求也就越严格。例如:某设备的电池为300mAh,假设一种情境下休眠功耗电池端为0.8mA,另一种情境下功耗电池端为1mA,显然仅仅相差200uA(出现这种状态的情况就比较多了,有可能是GPIO口的状态不对,也有可能是外设漏电引起,还有可能是电源管理配置有问题。)通过计算可以算出来0.8mA待机375小时,而1mA待机300小时,相差75小时,这对一个设备来说是很重要的。


二、明确调试的内容


我们为了更好的调试功耗,必须做一个简洁并且一目了然的表格用来记录我们的测量结果,总的来说测试表格的内容几乎就是我们测试的内容;

概况的说,包括需要调试6种状态和5个电路模块的功耗,其中

6种状态是指:

第一、开机后的空闲状态(开机亮屏状态下,不进行任何操作,即,后台几乎没有CPU资源占用率高的进程);

第二、关闭显示屏,但不休眠的状态;

第三、进入休眠过程中(early_suspend)的状态;

第三、完全进入休眠的状态;

第四、完成关机的状态;

第五、其他状态下(比如视频播放、蓝牙通信、WiFi连接、游戏运行等),该状态只是用来评估CPU内部模块,或者某个特定的外设工作时的功耗。

5个电路模块是指:

Battery(电池供电的电路,是设备总的功耗);

cpu_core(给处理器内部的逻辑电路供电的电路);

cpu_memory(给SDRAM(DDR)以及处理器DDR phy供电的电路);

vddio(给处理的VDDIO以及一些处理器内部的外设控制器,外部的外设供电的电路);

其他的外设(包括其他全部的外设,例如wifi、bluetooth、tp以及lcd等,这个可以列出多种调试状况)。


测试的内容当然可以根据当前情况进行有目的测试,比如下图就是我在测试是做的表格:

注:如果测试的数据值是正确的,我们还需要记录下测试所用的代码版本,所用的软件资源,测试时间,测试人员,以及主频,外频等情况。


三、参照电路框图找出我们需要检测的输出

由newton的框架图可知:

(1)     CPU_core由OUT1(1.2V)供电;

(2)     CPU_mem由OUT2(1.8V)供电;

(4)     OUT6(3.3V)给EVG供电;

(5)     OUT9(3.3V)和OUT17(1.8V)给TP供电;

(6)     OUT10(1.8V)给MIC供电;

(7)     OUT11(3.3V)给sensor供电;

(8)     OUT12(3.3V)给MOTOR供电;

(9)     OUT13(3.3V)和OUT14(1.8V)给LCD供电;

(10)   OUT16(3.3V)给sensors供电;

(11)   OUT19(1.8V)给wifi供电;

进而我们了解了整块板的基本供电情况,从而测量各个模块的电流情况。

这里我们用到regulator,但是很多开发板或者设备没有regulator,这时我们就得在电路图中获得每个模块的供电情况。

注:像君正的newton开发板是具有regulator的,在板级中我们能看到regulator的简单配置,还有一些基本的配置,regulator参数的调试也是属于功耗调试的,如果木有的话,就算了。


四、找出或引出需测试的输出

1、电源端比较容易测量;

2、其他测试点:我们需要借助altium designer、99SE、DXP、PADS等工具,找出易测量的点或者飞线,这里就省了如何查找的步骤;

下面我们就开始介绍下测试的步骤了?!

2020-01-06 08:58:45 qipeng39623 阅读数 21
  • 韦东山升级版嵌入式视频之快速入门

    韦东山老师为啥要录升级版嵌入式视频? 200x年左右,嵌入式Linux在全世界、在中国刚刚兴起。 我记得我2005年进入中兴时,全部门的人正在努力学习Linux。 在2008年,我写了一本书《嵌入式Linux应用开发完全手册》。 它的大概内容是:裸机、U-boot、Linux内核、Linux设备驱动。 那时还没有这样讲解整个系统的书, 芯片厂家Linux开发包也还不完善,从bootloader到内核,再到设备驱动都不完善。 有全系统开发能力的人也很少。 于是这书也就恰逢其时,变成了畅销书。 我也根据这个思路录制了视频:裸机、U-boot、Linux内核、Linux设备驱动。 收获些许名声,带领很多人进入Linux世界。 11年过去了,嵌入式Linux世界发生了翻天覆地的变化 ① 基本系统能用 芯片厂家都会提供完整的U-boot、Linux内核、芯片上硬件资源的驱动。 方案厂家会做一些定制,比如加上某个WIFI模块,会添加这个WIFI模块的驱动。 你可以使用厂家的原始方案,或是使用/借鉴方案商的方案,做出一个“能用”的产品。 ② 基础驱动弱化;高级驱动专业化 基础的驱动,比如GPIO、UART、SPI、I2C、LCD、MMC等,有了太多的书籍、视频、示例代码,修修改改总是可以用的。 很多所谓的驱动工程师,实际上就是“调参工程师”。 我们群里有名的火哥,提出了一个概念:这些驱动就起一个“hardware enable”的作用。 高级的驱动,比如USB、PCIE、HDMI、MIPI、GPU、WIFI、蓝牙、摄像头、声卡。 体系非常复杂,很少有人能讲清楚,很多时候只是一笔带过。 配置一下应用层工具就了事,能用就成。 这些高级驱动,工作中需要专门的人来负责,非常专业。 他们是某一块的专家,比如摄像头专家、音频专家。 ③ 项目为王 你到一个公司,目的是把产品做出来,会涉及APP到内核到驱动全流程。 中小公司玩不起华为中兴的配置,需要的是全面手。 大公司里,只负责很小很小一块的镙丝钉,位置也不太稳固啊。 所以,如果你不是立志成为某方面的专家,那就做一个全栈工程师吧。 ④ 调试很重要 都说代码是3分写7分调,各种调试调优技术,可以为你的升职加薪加一把火。 基于上述4点,我录制的全新视频将有这些特点: 1. 快速入门, 2. 实战项目, 3. 驱动大全, 4. 专题, 5. 授人以渔, 6. 要做任务 另外,我们会使用多款芯片同时录制,先讲通用的原理,再单独讲各个板子的操作。 这些芯片涵盖主流芯片公司的主流芯片,让你学习工作无缝对接。 1.快速入门 入门讲究的是快速,入门之后再慢慢深入, 特别是对于急着找工作的学生,对于业余时间挑灯夜读的工作了的人,一定要快! 再从裸机、U-boot、内核、驱动这样的路线学习就不适合了,时间就拉得太长了。 搞不好学了后面忘了前面。 并且实际工作中并不需要你去弄懂U-boot,会用就行:U-boot比驱动还复杂。 讲哪些内容? 怎么讲呢? 混着讲 比如先讲LED APP,知道APP怎么调用驱动,再讲LED硬件原理和裸机,最后讲驱动的编写。 这样可以快速掌握嵌入式Linux的整套开发流程, 不必像以前那样光学习裸机就花上1、2个月。 而里面的裸机课程,也会让你在掌握硬件操作的同时,把单片机也学会了。 讲基础技能 中断、休眠-唤醒、异步通知、阻塞、内存映射等等机制,会配合驱动和APP来讲解。 这些技能是嵌入式Linux开发的基础。 而这些驱动,只会涉及LED、按制、LCD等几个驱动。 掌握了这些输入、输出的驱动和对应的APP后,你已经具备基本的开发能力了。 讲配置 我们从厂家、从方案公司基本上都可以拿到一套完整的开发环境,怎么去配置它? 需要懂shell和python等配置脚本。 效果效率优先 以前我都是现场写代码、现场写文档,字写得慢,降低了学习效率。 这次,效果与效率统一考虑,不再追求所有东西都现场写。 容易的地方可先写好代码文档,难的地方现场写。 2.实战项目 会讲解这样的涉及linux网关/服务器相关项目(不限于,请多提建议):                      定位为:快速掌握项目开发经验,丰满简历。 涉及的每一部分都会讲,比如如果涉及蓝牙,在这里只会讲怎么使用,让你能写出程序;如果要深入,可以看后面的蓝牙专题。 3. 驱动大全 包括基础驱动、高级驱动。 这些驱动都是独立成章,深入讲解。 虽然基础驱动弱化了,但是作为Linux系统开发人员,这是必备技能,并且从驱动去理解内核是一个好方法。 在讲解这些驱动时,会把驱动的运行环境,比如内核调度,进程线程等概念也讲出来,这样就可以搭建一个知识体系。 没有这些知识体系的话,对驱动的理解就太肤浅了,等于在Linux框架下写裸机,一叶障目,不见泰山。 定位为:工具、字典,用到再学习。 4. 专题 想深入学习的任何内容,都可独立为专题。 比如U-boot专题、内核内存管理专题、systemtap调试专题。

    4924 人正在学习 去看看 韦东山

Linux 系统休眠
常用的休眠方式有freeze,standby, mem, disk

freeze: 冻结I/O设备,将它们置于低功耗状态,使处理器进入空闲状态,唤醒最快,耗电比其它standby, mem, disk方式高
standby:除了冻结I/O设备外,还会暂停系统,唤醒较快,耗电比其它 mem, disk方式高
mem: 将运行状态数据存到内存,并关闭外设,进入等待模式,唤醒较慢,耗电比disk方式高
disk: 将运行状态数据存到硬盘,然后关机,唤醒最慢
cat /sys/power/state
freeze statndby mem

system("echo freeze > /sys/power/state");

system("echo standby > /sys/power/state");

system("echo mem > /sys/power/state");

参考:https://www.cnblogs.com/lifexy/p/9629699.html

2018-04-18 16:55:28 zpcindy 阅读数 703
  • 韦东山升级版嵌入式视频之快速入门

    韦东山老师为啥要录升级版嵌入式视频? 200x年左右,嵌入式Linux在全世界、在中国刚刚兴起。 我记得我2005年进入中兴时,全部门的人正在努力学习Linux。 在2008年,我写了一本书《嵌入式Linux应用开发完全手册》。 它的大概内容是:裸机、U-boot、Linux内核、Linux设备驱动。 那时还没有这样讲解整个系统的书, 芯片厂家Linux开发包也还不完善,从bootloader到内核,再到设备驱动都不完善。 有全系统开发能力的人也很少。 于是这书也就恰逢其时,变成了畅销书。 我也根据这个思路录制了视频:裸机、U-boot、Linux内核、Linux设备驱动。 收获些许名声,带领很多人进入Linux世界。 11年过去了,嵌入式Linux世界发生了翻天覆地的变化 ① 基本系统能用 芯片厂家都会提供完整的U-boot、Linux内核、芯片上硬件资源的驱动。 方案厂家会做一些定制,比如加上某个WIFI模块,会添加这个WIFI模块的驱动。 你可以使用厂家的原始方案,或是使用/借鉴方案商的方案,做出一个“能用”的产品。 ② 基础驱动弱化;高级驱动专业化 基础的驱动,比如GPIO、UART、SPI、I2C、LCD、MMC等,有了太多的书籍、视频、示例代码,修修改改总是可以用的。 很多所谓的驱动工程师,实际上就是“调参工程师”。 我们群里有名的火哥,提出了一个概念:这些驱动就起一个“hardware enable”的作用。 高级的驱动,比如USB、PCIE、HDMI、MIPI、GPU、WIFI、蓝牙、摄像头、声卡。 体系非常复杂,很少有人能讲清楚,很多时候只是一笔带过。 配置一下应用层工具就了事,能用就成。 这些高级驱动,工作中需要专门的人来负责,非常专业。 他们是某一块的专家,比如摄像头专家、音频专家。 ③ 项目为王 你到一个公司,目的是把产品做出来,会涉及APP到内核到驱动全流程。 中小公司玩不起华为中兴的配置,需要的是全面手。 大公司里,只负责很小很小一块的镙丝钉,位置也不太稳固啊。 所以,如果你不是立志成为某方面的专家,那就做一个全栈工程师吧。 ④ 调试很重要 都说代码是3分写7分调,各种调试调优技术,可以为你的升职加薪加一把火。 基于上述4点,我录制的全新视频将有这些特点: 1. 快速入门, 2. 实战项目, 3. 驱动大全, 4. 专题, 5. 授人以渔, 6. 要做任务 另外,我们会使用多款芯片同时录制,先讲通用的原理,再单独讲各个板子的操作。 这些芯片涵盖主流芯片公司的主流芯片,让你学习工作无缝对接。 1.快速入门 入门讲究的是快速,入门之后再慢慢深入, 特别是对于急着找工作的学生,对于业余时间挑灯夜读的工作了的人,一定要快! 再从裸机、U-boot、内核、驱动这样的路线学习就不适合了,时间就拉得太长了。 搞不好学了后面忘了前面。 并且实际工作中并不需要你去弄懂U-boot,会用就行:U-boot比驱动还复杂。 讲哪些内容? 怎么讲呢? 混着讲 比如先讲LED APP,知道APP怎么调用驱动,再讲LED硬件原理和裸机,最后讲驱动的编写。 这样可以快速掌握嵌入式Linux的整套开发流程, 不必像以前那样光学习裸机就花上1、2个月。 而里面的裸机课程,也会让你在掌握硬件操作的同时,把单片机也学会了。 讲基础技能 中断、休眠-唤醒、异步通知、阻塞、内存映射等等机制,会配合驱动和APP来讲解。 这些技能是嵌入式Linux开发的基础。 而这些驱动,只会涉及LED、按制、LCD等几个驱动。 掌握了这些输入、输出的驱动和对应的APP后,你已经具备基本的开发能力了。 讲配置 我们从厂家、从方案公司基本上都可以拿到一套完整的开发环境,怎么去配置它? 需要懂shell和python等配置脚本。 效果效率优先 以前我都是现场写代码、现场写文档,字写得慢,降低了学习效率。 这次,效果与效率统一考虑,不再追求所有东西都现场写。 容易的地方可先写好代码文档,难的地方现场写。 2.实战项目 会讲解这样的涉及linux网关/服务器相关项目(不限于,请多提建议):                      定位为:快速掌握项目开发经验,丰满简历。 涉及的每一部分都会讲,比如如果涉及蓝牙,在这里只会讲怎么使用,让你能写出程序;如果要深入,可以看后面的蓝牙专题。 3. 驱动大全 包括基础驱动、高级驱动。 这些驱动都是独立成章,深入讲解。 虽然基础驱动弱化了,但是作为Linux系统开发人员,这是必备技能,并且从驱动去理解内核是一个好方法。 在讲解这些驱动时,会把驱动的运行环境,比如内核调度,进程线程等概念也讲出来,这样就可以搭建一个知识体系。 没有这些知识体系的话,对驱动的理解就太肤浅了,等于在Linux框架下写裸机,一叶障目,不见泰山。 定位为:工具、字典,用到再学习。 4. 专题 想深入学习的任何内容,都可独立为专题。 比如U-boot专题、内核内存管理专题、systemtap调试专题。

    4924 人正在学习 去看看 韦东山

Linux 电源管理机制为设备低功耗的实现提供了方法。
在不同内核版本Linux、Android,休眠机制、流程有所差异。这里DLT-RK3288 Android 5.1 源码为例。


标准Linux 的电源状态:
- On(on)                                               S0 -  Working  
                                                                      - 正常的工作状态
- Standby (standby)                              S1 -  CPU and RAM are powered but not executed   
                                                                        - CPU和DDR都供着电,但没执行任何命令。
- Suspend to RAM(mem)                        S3 -  RAM is powered and the running content is saved to RAM
                                                                        -  挂起到内存,简称待机。CPU、EMMC、LCD等都断了电,只有DDR供着电,以保存休眠前的工作状态。
- Suspend to Disk,Hibernation(disk)    S4 -  All content is saved to Disk and power down
                                                                        -  挂起到硬盘,简称休眠。机器运行状态保存到硬盘中,并关机。


DLT-RK3288的 kernel/include/linux/suspend.h 中 可以看到常用的几种状态
1. #define PM_SUSPEND_ON                ((__force suspend_state_t) 0)
2. #define PM_SUSPEND_FREEZE        ((__force suspend_state_t) 1)
3. #define PM_SUSPEND_STANDBY        ((__force suspend_state_t) 2)
4. #define PM_SUSPEND_MEM                ((__force suspend_state_t) 3)


休眠相关内核源码:
kernel/kernel/power/main.c
kernel/kernel/power/suspend.c
kernel/kernel/power/wakelock.c
kernel/kernel/power/autosleep.c
main.c 主要是向用户空间提供文件接口。文件接口有以下:

 


 

suspend.c 是进入休眠前所执行的代码。主要函数调用流程: pm_suspend -- enter_state -- suspend_prepare -- suspend_devices_and_enter 。
autosleep.c 主要负责自动进入休眠流程。
低版本的linux内核 还有earlysuspend.c,earlysuspend是假休眠(只关闭部分外设的电源)的一种机制,linux 3.10中已被抛弃。


如何进入休眠?
1、当autosleep开启,当所有wakelock都释放时,自动进入休眠。
     autosleep.c 中,try_to_suspend 函数调用 pm_get_wakeup_count ,执行:
1.  for (;;) {
2.                prepare_to_wait(&wakeup_count_wait_queue, &wait,
3.               TASK_INTERRUPTIBLE);


    可以看出,一直等到wakelock 被释放,pm_get_wakeup_count 才返回。进入调用 pm_suspend或hibernate休眠。
2、echo mem > /sys/power/state ,强制进入休眠。
       执行该命令,系统会直接进入休眠,不再判断是否有没释放的wakelock。(低版本内核中,执行该命令,仍需要等待wakelock释放)。


wakelock 是为休眠唤醒而存在的。可以查询相关资料进一步了解。
cat /sys/power/wake_lock可以看到当前哪个Android锁处于激活状态。(/sys/power/wake_lock 并不统计内核的锁)。


如何禁止自动进入休眠?
1、在驱动源码中,初始化一个wakelock,并上锁,不释放。
1. #include <linux/wakelock.h>
2. struct wake_lock no_suspend_lock;


内核中的锁类型很简单,只有WAKE_LOCK_SUSPEND。(低版本内核中多了WAKE_LOCK_IDLE)。
   缺点: 只能保证不进入休眠,屏幕却被灭了。


2、在Android中加锁
Android 定义了以下几种WakeLock类型:
       *  FULL_WAKE_LOCK    保持屏幕全亮、键盘背光灯点亮和CPU运行。
        *  SCREEN_BRIGHT_WAKE_LOCK   保持屏幕全亮和CPU运行。
        *  SCREEN_DIM_WAKE_LOCK   保持屏幕开启(但是让它变暗)和CPU运行。


        *  PARTIAL_WAKE_LOCK   保持CPU运行。

可以根据需要,申请不同的锁类型。




2020-02-03 13:27:10 TommyMusk 阅读数 45
  • 韦东山升级版嵌入式视频之快速入门

    韦东山老师为啥要录升级版嵌入式视频? 200x年左右,嵌入式Linux在全世界、在中国刚刚兴起。 我记得我2005年进入中兴时,全部门的人正在努力学习Linux。 在2008年,我写了一本书《嵌入式Linux应用开发完全手册》。 它的大概内容是:裸机、U-boot、Linux内核、Linux设备驱动。 那时还没有这样讲解整个系统的书, 芯片厂家Linux开发包也还不完善,从bootloader到内核,再到设备驱动都不完善。 有全系统开发能力的人也很少。 于是这书也就恰逢其时,变成了畅销书。 我也根据这个思路录制了视频:裸机、U-boot、Linux内核、Linux设备驱动。 收获些许名声,带领很多人进入Linux世界。 11年过去了,嵌入式Linux世界发生了翻天覆地的变化 ① 基本系统能用 芯片厂家都会提供完整的U-boot、Linux内核、芯片上硬件资源的驱动。 方案厂家会做一些定制,比如加上某个WIFI模块,会添加这个WIFI模块的驱动。 你可以使用厂家的原始方案,或是使用/借鉴方案商的方案,做出一个“能用”的产品。 ② 基础驱动弱化;高级驱动专业化 基础的驱动,比如GPIO、UART、SPI、I2C、LCD、MMC等,有了太多的书籍、视频、示例代码,修修改改总是可以用的。 很多所谓的驱动工程师,实际上就是“调参工程师”。 我们群里有名的火哥,提出了一个概念:这些驱动就起一个“hardware enable”的作用。 高级的驱动,比如USB、PCIE、HDMI、MIPI、GPU、WIFI、蓝牙、摄像头、声卡。 体系非常复杂,很少有人能讲清楚,很多时候只是一笔带过。 配置一下应用层工具就了事,能用就成。 这些高级驱动,工作中需要专门的人来负责,非常专业。 他们是某一块的专家,比如摄像头专家、音频专家。 ③ 项目为王 你到一个公司,目的是把产品做出来,会涉及APP到内核到驱动全流程。 中小公司玩不起华为中兴的配置,需要的是全面手。 大公司里,只负责很小很小一块的镙丝钉,位置也不太稳固啊。 所以,如果你不是立志成为某方面的专家,那就做一个全栈工程师吧。 ④ 调试很重要 都说代码是3分写7分调,各种调试调优技术,可以为你的升职加薪加一把火。 基于上述4点,我录制的全新视频将有这些特点: 1. 快速入门, 2. 实战项目, 3. 驱动大全, 4. 专题, 5. 授人以渔, 6. 要做任务 另外,我们会使用多款芯片同时录制,先讲通用的原理,再单独讲各个板子的操作。 这些芯片涵盖主流芯片公司的主流芯片,让你学习工作无缝对接。 1.快速入门 入门讲究的是快速,入门之后再慢慢深入, 特别是对于急着找工作的学生,对于业余时间挑灯夜读的工作了的人,一定要快! 再从裸机、U-boot、内核、驱动这样的路线学习就不适合了,时间就拉得太长了。 搞不好学了后面忘了前面。 并且实际工作中并不需要你去弄懂U-boot,会用就行:U-boot比驱动还复杂。 讲哪些内容? 怎么讲呢? 混着讲 比如先讲LED APP,知道APP怎么调用驱动,再讲LED硬件原理和裸机,最后讲驱动的编写。 这样可以快速掌握嵌入式Linux的整套开发流程, 不必像以前那样光学习裸机就花上1、2个月。 而里面的裸机课程,也会让你在掌握硬件操作的同时,把单片机也学会了。 讲基础技能 中断、休眠-唤醒、异步通知、阻塞、内存映射等等机制,会配合驱动和APP来讲解。 这些技能是嵌入式Linux开发的基础。 而这些驱动,只会涉及LED、按制、LCD等几个驱动。 掌握了这些输入、输出的驱动和对应的APP后,你已经具备基本的开发能力了。 讲配置 我们从厂家、从方案公司基本上都可以拿到一套完整的开发环境,怎么去配置它? 需要懂shell和python等配置脚本。 效果效率优先 以前我都是现场写代码、现场写文档,字写得慢,降低了学习效率。 这次,效果与效率统一考虑,不再追求所有东西都现场写。 容易的地方可先写好代码文档,难的地方现场写。 2.实战项目 会讲解这样的涉及linux网关/服务器相关项目(不限于,请多提建议):                      定位为:快速掌握项目开发经验,丰满简历。 涉及的每一部分都会讲,比如如果涉及蓝牙,在这里只会讲怎么使用,让你能写出程序;如果要深入,可以看后面的蓝牙专题。 3. 驱动大全 包括基础驱动、高级驱动。 这些驱动都是独立成章,深入讲解。 虽然基础驱动弱化了,但是作为Linux系统开发人员,这是必备技能,并且从驱动去理解内核是一个好方法。 在讲解这些驱动时,会把驱动的运行环境,比如内核调度,进程线程等概念也讲出来,这样就可以搭建一个知识体系。 没有这些知识体系的话,对驱动的理解就太肤浅了,等于在Linux框架下写裸机,一叶障目,不见泰山。 定位为:工具、字典,用到再学习。 4. 专题 想深入学习的任何内容,都可独立为专题。 比如U-boot专题、内核内存管理专题、systemtap调试专题。

    4924 人正在学习 去看看 韦东山

写在前面

为了理清新平台系统休眠和唤醒的流程,通过学习其他平台的电源管理方法,曲径通幽, 达到目的.

刚接手新平台,且相应的资料不多,很容易让人力不从心;我在网上寻找了学习资源,发现韦东山对S3C2440的驱动讲解有相关的内容,口碑也不错,可以作为一个切入点.

不同平台一定会有平台的差异,不同的Linux内核版本之间也会有相应的差异,但思路是一致的,可以总结出来,帮助理解电源管理的开发使用.

本文总结关于系统休眠和唤醒的流程以及开发方法.

Linux电源管理基本框架

下图所示为Linux电源管理基本框架. 详细请参考Linux电源管理(1)_整体架构
本文重点介绍关于Generic PM的使用.

图1
Generic PM,就是Power Management,如Power Off、
Suspend to RAM、Suspend to Disk、Hibernate等.

关于Suspend, Linux内核提供了四种Suspend: Freeze、Standby、STR(Suspend to RAM)和STD(Suspend to Disk),如下表 . 在用户空间向”/sys/power/state”文件分别写入”freeze”、”standby”、”mem”和"disk",即可触发它们。

模式 描述
freeze 冻结I/O设备,将它们置于低功耗状态,使处理器进入空闲状态,唤醒最快,耗电比其它standby, mem, disk方式高
standby 除了冻结I/O设备外,还会暂停系统,唤醒较快,耗电比其它 mem, disk方式高
mem 将运行状态数据存到内存,并关闭外设,进入等待模式,唤醒较慢,耗电比disk方式高
disk 将运行状态数据存到硬盘,然后关机,唤醒最慢. 对于嵌入式系统,由于没有硬盘,所以一般不支持

Linux内核提供的电源管理框架引入了面向对象的思想,理解起来会困难.为此,很有必要在抛开复杂框架的基础上,通过实验验证suspend的结果,总结suspend的流程后,帮助理解linux的supend流程.

S3C2440 Sleep模式进入与唤醒

对于S3C2440 的power manager有三种模式,如下图所示,
在这里插入图片描述

我们选择在u-boot中实现Sleep mode作为suspend, 也就是对应Linux内核实现的mem模式的suspend. 实验的效果是:在u-boot命令行运行suspend指令后系统进入Sleep Mode; 当按下按键后,系统唤醒,继续接着休眠前的地方执行下去.

进入Sleep Mode的流程

在这里插入图片描述

实现代码如下:

/*
 * weidongshan@qq.com, www.100ask.net
 *
 */

#include <common.h>
#include <command.h>
#include <def.h>
#include <nand.h>
#include <s3c24x0.h>

extern void s3c2440_cpu_suspend(void);
int do_suspend (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);

U_BOOT_CMD(
    suspend,    1,    0,    do_suspend,
    "suspend - suspend the board\n",
    " - suspend the board"
);
int do_suspend (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
    /* 休眠的实现: */
    
    /* 对于NAND启动: 要设置EINT23,22,21为输入引脚 */
    rGPGCON &= ~((3<<30) | (3<<28) | (3<<26));
   /* 1. 配置GPIO模式,用于唤醒CPU的引脚要设为中断功能 */
    /* JZ2440只有S2/S3/S4可用作唤醒源,设置它们对应的GPIO用于中断模式 */
    /*这几个IO对于着按键,也就是实现按键唤醒*/
    /* EINT0 EINT2*/                                                                                                                                                               
    rGPFCON &= ~((3<<0) | (3<<4));
    rGPFCON |= ((2<<0) | (2<<4));
    /*EINT11*/
    rGPGCON &= ~(3<<6);
    rGPGCON |= (2<<6);

    /* 2. 设置INTMSK屏蔽所有中断: 在sleep模式下,这些引脚只是用于唤醒系统,当CPU正常运行时可以重新设置INTMSK让这些引脚用于中断功能 */
    rINTMSK = ~0;

    /* 3. 配置唤醒源 , 为了能在休眠模式下被唤醒*/
    rEXTINT0 |= (6<<0) | (6<<8); /* EINT0,2双边沿触发 */
    rEXTINT1 |= (6<<12);   /* EINT11双边沿触发 */

    /* 4. 设置MISCCR[13:12]=11b, 使得USB模块进入休眠 */
    rMISCCR |= (3<<12);

    /* 5. 在GSTATUS[4:3]保存某值, 它们可以在系统被唤醒时使用 */
    //rGSTATUS3 = ;  /* 唤醒时首先执行的函数的地址 */
    //rGSTATUS4 = ;  /*  */

    /* 6. 设置 MISCCR[1:0] 使能数据总线的上拉电阻 */
    rMISCCR &= ~(3);

    /* 7. 清除 LCDCON1.ENVID 以停止LCD */
    rLCDCON1 &= ~1;

    /* 8~12使用汇编在s3c2440_cpu_suspend函数来实现,参考内核源码:
     *    arch\arm\mach-s3c2410\sleep.S
    */

    /* 8. 读这2个寄存器: rREFRESH and rCLKCON, 以便填充TLB
     *    如果不使用MMU的话,这个目的可以忽略
     */
/* 9. 设置 REFRESH[22]=1b,让SDRAM进入self-refresh mode */

    /* 10. 等待SDRAM成功进入self-refresh mode  */

    /* 11.设置 MISCCR[19:17]=111b以保护SDRAM信号(SCLK0,SCLK1 and SCKE) */

    /* 12. 设置CLKCON的SLEEP位让系统进入sleep mode */
    printf("suspend ...");
    delay(1000000); //保证printf打印完整
    s3c2440_cpu_suspend();  /* 执行到这里就不会返回,直到CPU被唤醒 */

    /* 恢复运行: 重新初始化硬件 */
    serial_init();
    printf("wake up\n");


    return 0;
}

代码解释

  1. 对于进入Sleep Mode的第5步,主要目的是保存休眠前的PC指针到GSTATUS寄存器,以便唤醒后恢复现场. 这一步的实现,放到 s3c2440_cpu_suspend函数中.

其中s3c2440_cpu_suspend函数的功能是让系统真正进入休眠状态,实现流程如下:

    /* suspend.S  weidongshan@qq.com, www.100ask.net
     * s3c2410_cpu_suspend
     * put the cpu into sleep mode
    */
#define S3C2440_REFRESH_SELF        (1<<22)
#define S3C2440_MISCCR_SDSLEEP        (7<<17)
#define S3C2440_CLKCON_POWER         (1<<3)

#define GSTATUS2       (0x560000B4)
#define GSTATUS3       (0x560000B8)
#define GSTATUS4       (0x560000BC)

#define REFRESH        (0x48000024)
#define MISCCR         (0x56000080)
#define CLKCON         (0x4C00000C)

.globl s3c2440_cpu_suspend @将s3c2440_cpu_suspend函数声明为全局函数
    @@ prepare cpu to sleep
s3c2440_cpu_suspend:
    stmdb    sp!, { r4-r12,lr }  @保存寄存器r4 - r12到栈中

    /* GSTATUS3中存放唤醒时要执行的函数 */
    ldr r0, =s3c2440_do_resume
    ldr r1, =GSTATUS3
    str r0, [r1]
    /* GSTATUS4中存放休眠前的栈信息 */
    ldr r1, =GSTATUS4
    str sp, [r1]
  /* 8. 读这2个寄存器: rREFRESH and rCLKCON, 以便填充TLB
     *    如果不使用MMU的话,这个目的可以忽略
     */
 /* 9. 设置 REFRESH[22]=1b,让SDRAM进入self-refresh mode */

    /* 10. 等待SDRAM成功进入self-refresh mode  */

    /* 11.设置 MISCCR[19:17]=111b以保护SDRAM信号(SCLK0,SCLK1 and SCKE) */

    /* 12. 设置CLKCON的SLEEP位让系统进入sleep mode */
    ldr    r4, =REFRESH
    ldr    r5, =MISCCR
    ldr    r6, =CLKCON
    ldr    r7, [ r4 ]        @ get REFRESH
    ldr    r8, [ r5 ]        @ get MISCCR
    ldr    r9, [ r6 ]        @ get CLKCON

    orr    r7, r7, #S3C2440_REFRESH_SELF    @ SDRAM sleep command
    orr    r8, r8, #S3C2440_MISCCR_SDSLEEP @ SDRAM power-down signals
    orr    r9, r9, #S3C2440_CLKCON_POWER    @ power down command

    teq    pc, #0            @ first as a trial-run to load cache
    bl    s3c2440_do_sleep
    teq    r0, r0            @ now do it for real
    b    s3c2440_do_sleep    @   

    @@ align next bit of code to cache line
    .align    5   
s3c2440_do_sleep:
    streq    r7, [ r4 ]            @ SDRAM sleep command
    streq    r8, [ r5 ]            @ SDRAM power-down config
    streq    r9, [ r6 ]            @ CPU sleep
1:    beq    1b
    mov    pc, r14

s3c2440_do_resume:
    /* 从start.S的wake_up返回到s3c2440_do_resume函数 */
    /* 从GSTATUS4取出栈信息 */
    ldr r1, =GSTATUS4
    ldr sp, [r1]
  /*恢复栈*/
    ldmia    sp!,     { r4-r12,pc }

唤醒流程

在这里插入图片描述
从以上的描述中的第2点可以得知, 系统从Sleep模式退出是需要重新启动u-boot的, 区别是power-up还是wake-up的方法是读取GSTATUS2寄存器.如果值为1,代表是从Sleep Mode过来的,就会执行相应的流程恢复休眠前的现场; 反之,则执行正常启动流程.
在这里插入图片描述
下面是关于u-boot启动代码的修改

/*cpu/arm920t/start.S*/
+#define GSTATUS2       (0x560000B4)
+#define GSTATUS3       (0x560000B8)
+#define GSTATUS4       (0x560000BC)
+
+#define REFRESH        (0x48000024)
+#define MISCCR         (0x56000080)
+#define CLKCON         (0x4C00000C)
 
 .globl _start
 _start:        b       reset
@@ -167,6 +178,25 @@ reset:
 #endif
 #endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */
 
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+               /* 在u-boot未改动前,clock_init C函数的执行
+                  需要在SDRAM设置栈以后, 由于
+            Sleep模式SDRAM处于自刷新状态,为了避免破环状态,
+            我们提前调用clock_init, 
+                   并把栈设置在片内内存,
+                   设置SP指向片内内存SRAM */
+               /*对于nand启动,可以这么设置*/
+               ldr sp, =4092
+              /*通过判断指向4092的内存能否读写成功来判断是nand启动还是nor启动.如果是nand启动,sp指向4092,如果是nor启动,sp指向0x40000000+4096*/
+               ldr r0, =0x12345678
+               str r0, [sp]
+               ldr r1, [sp]
+               cmp r0, r1
+         /*对于nor启动, 可以这么设置*/
+               ldrne sp, =0x40000000+4096
+               bl clock_init
+#endif    
+
+       /* 2. 根据 GSTATUS2[1]判断是复位还是唤醒 */     
+       ldr r0, =GSTATUS2
+       ldr r1, [r0]
+       tst r1, #(1<<1)  /* r1 & (1<<1) */
+       bne wake_up     
+
+
+
        /*
         * we do sys-critical inits only at reboot,
         * not when booting from ram!
@@ -190,7 +220,7 @@ stack_setup:
        sub     sp, r0, #12             /* leave 3 words for abort-stack    */
 
 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
-    bl clock_init
+//    bl clock_init
 #endif    
 
 #ifndef CONFIG_SKIP_RELOCATE_UBOOT
@@ -260,6 +290,31 @@ SetLoadFlag:
 
 _start_armboot:        .word start_armboot
 
+/* 1. 按下按键 */
+wake_up:
      str r1, [r0]  /* clear GSTATUS2 */
+       /* 3. 设置 MISCCR[19:17]=000b, 以释放SDRAM信号 */
+       ldr r0, =MISCCR
+       ldr r1, [r0]
+       bic r1, r1, #(7<<17)
+       str r1, [r0]
+               
+       /* 4. 配置s3c2440的memory controller */
+       bl      cpu_init_crit
+       
+       /* 5. 等待SDRAM退出self-refresh mode */
+       mov r0, #1000
+1:     subs r0, r0, #1
+       cmp r0, #0
+       bne 1b
+       
+       /* 6. 根据GSTATUS[3:4]的值来运行休眠前的函数 PC指针指向 s3c2440_do_resume
+        */
+       ldr r0, =GSTATUS3
+       ldr r1, [r0]
+       mov pc, r1
+       
+

实验现象

在u-boot命令行下,
进入suspend模式,休眠.
在这里插入图片描述
按下按键,退出suspend模式,唤醒.
在这里插入图片描述

S3C2440 Generic PM之suspend

在了解S3C2440 u-boot下添加休眠和唤醒的流程后,总结下来也就是两幅图:
在这里插入图片描述
在这里插入图片描述
对于Linux的Generic PM框架,本质是也就是把上面这部分与板级(platform)有关的内容放置到框架的相应位置(也就是下图的Platform dependent PM的位置),就可以实现在Linux下的suspend和resume了.

介绍一下Generic PM框架,参考Linux电源管理(6)_Generic PM之Suspend功能
在这里插入图片描述
下面以suspend to RAM为例,分析从用户空间ehco > mem /sys/power/state进入休眠再到按键执行唤醒的过程. 参考Linux电源管理

suspend流程

如下图所示,实际上写入文件调用的函数就是state_store.
在这里插入图片描述
驱动程序里休眠相关的电源管理函数的调用过程:prepare—>suspend—>suspend_late—>suspend_noirq
其中图中最下面的一行:suspend_ops->enter就是对应platform dependent PM相关的代码,把u-boot中进入休眠模式的代码移植过来即可.
在S3C2440中对应的platform depend PM代码在arch/arm/plat-samsung/pm.c

Platform dependent PM(针对CPU芯片相关)

//arch/arm/plat-samsung/pm.c  kernel version:3.4.2
...
static const struct platform_suspend_ops s3c_pm_ops = {
    .enter        = s3c_pm_enter,
    .prepare    = s3c_pm_prepare, //对应图中的suspend_ops->enter,系统进入休眠模式调用的platform dependent PM相关的代码
    .finish        = s3c_pm_finish,
    .valid        = suspend_valid_only_mem,
};
static int s3c_pm_enter(suspend_state_t state)
{
    /* ensure the debug is initialised (if enabled) */

    s3c_pm_debug_init();

    S3C_PMDBG("%s(%d)\n", __func__, state);

    if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) {
        printk(KERN_ERR "%s: error: no cpu sleep function\n", __func__);
        return -EINVAL;
    }

    /* check if we have anything to wake-up with... bad things seem
     * to happen if you suspend with no wakeup (system will often
     * require a full power-cycle)
    */

    if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) &&
        !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) {
        printk(KERN_ERR "%s: No wake-up sources!\n", __func__);
        printk(KERN_ERR "%s: Aborting sleep\n", __func__);
        return -EINVAL;
    }

    /* save all necessary core registers not covered by the drivers */

    samsung_pm_save_gpios();
    samsung_pm_saved_gpios();
    s3c_pm_save_uarts();
    s3c_pm_save_core();

    /* set the irq configuration for wake */

    s3c_pm_configure_extint();

    S3C_PMDBG("sleep: irq wakeup masks: %08lx,%08lx\n",
        s3c_irqwake_intmask, s3c_irqwake_eintmask);

    s3c_pm_arch_prepare_irqs();

    /* call cpu specific preparation */
    pm_cpu_prep();

    /* flush cache back to ram */

    flush_cache_all();

    s3c_pm_check_store();

    /* send the cpu to sleep... */

    s3c_pm_arch_stop_clocks();

    /* this will also act as our return point from when
     * we resume as it saves its own register state and restores it
     * during the resume.  */

    cpu_suspend(0, pm_cpu_sleep);

    /* restore the system state */

    s3c_pm_restore_core();
    s3c_pm_restore_uarts();
    samsung_pm_restore_gpios();
    s3c_pm_restored_gpios();

    s3c_pm_debug_init();

    /* check what irq (if any) restored the system */

    s3c_pm_arch_show_resume_irqs();

    S3C_PMDBG("%s: post sleep, preparing to return\n", __func__);

    /* LEDs should now be 1110 */
    s3c_pm_debug_smdkled(1 << 1, 0);
 s3c_pm_check_restore();

    /* ok, let's return from sleep */

    S3C_PMDBG("S3C PM Resume (post-restore)\n");
    return 0;
}

代码说明:
其中27-32行, 检查是否设置了唤醒源,如果没有,就直接退出,禁止进入休眠模式. 对于设置唤醒源,在后面按键驱动中会介绍如何设置唤醒源.
34-67行, 按照进入Sleep Mode的流程执行相应的工作,一旦调用到67行,跳转到pm_cpu_sleep, 系统进入休眠状态. 直到有唤醒源,才能唤醒,继续往下执行.

resume流程

在这里插入图片描述
驱动程序里唤醒相关的电源管理函数的调用过程:resume_noirq—>resume_early—>resume->complete
对于上面arch/arm/plat-samsung/pm.c中的代码的71-90行,就是完成上图的resume过程.

修改按键驱动中增加唤醒源

/* 参考drivers\input\keyboard\gpio_keys.c */
/*参考www.100ask.com*/
#include <linux/module.h>
#include <linux/version.h>

#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/irq.h>

#include <asm/gpio.h>
#include <asm/io.h>
//#include <asm/arch/regs-gpio.h>

struct pin_desc{
    int irq;
    char *name;
    unsigned int pin;
    unsigned int key_val;
};

struct pin_desc pins_desc[4] = {
    {IRQ_EINT0,  "S2", S3C2410_GPF(0),   KEY_L},
    {IRQ_EINT2,  "S3", S3C2410_GPF(2),   KEY_S},
    {IRQ_EINT11, "S4", S3C2410_GPG(3),   KEY_ENTER},
    {IRQ_EINT19, "S5",  S3C2410_GPG(11), KEY_LEFTSHIFT},
};

static struct input_dev *buttons_dev;
static struct pin_desc *irq_pd;
static struct timer_list buttons_timer;

static irqreturn_t buttons_irq(int irq, void *dev_id)
{
    /* 10ms后启动定时器 */
    irq_pd = (struct pin_desc *)dev_id;
    mod_timer(&buttons_timer, jiffies+HZ/100);
    return IRQ_RETVAL(IRQ_HANDLED);
}

static void buttons_timer_function(unsigned long data)
{
struct pin_desc * pindesc = irq_pd;
    unsigned int pinval;

    if (!pindesc)
        return;

    pinval = s3c2410_gpio_getpin(pindesc->pin);

    if (pinval)
    {
        /* 松开 : 最后一个参数: 0-松开, 1-按下 */
        input_event(buttons_dev, EV_KEY, pindesc->key_val, 0);
        input_sync(buttons_dev);
    }
    else
    {
        /* 按下 */
        input_event(buttons_dev, EV_KEY, pindesc->key_val, 1);
        input_sync(buttons_dev);
    }
}

static int buttons_init(void)
{
    int i;

    /* 1. 分配一个input_dev结构体 */
    buttons_dev = input_allocate_device();;

    /* 2. 设置 */
    /* 2.1 能产生哪类事件 */
    set_bit(EV_KEY, buttons_dev->evbit);
    set_bit(EV_REP, buttons_dev->evbit);

    /* 2.2 能产生这类操作里的哪些事件: L,S,ENTER,LEFTSHIT */
    set_bit(KEY_L, buttons_dev->keybit);
    set_bit(KEY_S, buttons_dev->keybit);
    set_bit(KEY_ENTER, buttons_dev->keybit);
    set_bit(KEY_LEFTSHIFT, buttons_dev->keybit);

    /* 3. 注册 */
    input_register_device(buttons_dev);

    /* 4. 硬件相关的操作 */
    init_timer(&buttons_timer);
    buttons_timer.function = buttons_timer_function;   
    add_timer(&buttons_timer);

    for (i = 0; i < 4; i++)
    {
        request_irq(pins_desc[i].irq, buttons_irq, (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING), pins_desc[i].name, &pins_desc[i]);
    }

    /* 指定这些中断可以用于唤醒系统 */
    irq_set_irq_wake(IRQ_EINT0, 1);
    irq_set_irq_wake(IRQ_EINT2, 1);
    irq_set_irq_wake(IRQ_EINT11, 1);

    return 0;
}

static void buttons_exit(void)
{
    int i;

    irq_set_irq_wake(IRQ_EINT0, 0);
    irq_set_irq_wake(IRQ_EINT2, 0);
    irq_set_irq_wake(IRQ_EINT11, 0);

    for (i = 0; i < 4; i++)
    {
        free_irq(pins_desc[i].irq, &pins_desc[i]);
    }

    del_timer(&buttons_timer);
    input_unregister_device(buttons_dev);
    input_free_device(buttons_dev);
}

module_init(buttons_init);

module_exit(buttons_exit);

MODULE_LICENSE("GPL");
                  

代码说明
设置唤醒源最主要的是105 -107行的函数irq_set_irq_wake.
这个函数本质上是通过api设置寄存器使能中断功能. (注意:这些中断引脚是支持唤醒功能的)

Device PM(针对每一个驱动)

上面针对suspend流程的实现是修改Platform dependent PM相关的代码(针对CPU芯片相关), 在休眠时只是执行datasheet中的必要要求,对于一些外设,比如网卡、声卡等并没有关闭.

对于外设级别的电源管理,Linux Generic PM框架提供了相应的接口,只要在注册设备时加入相应参数,即可实现系统休眠或者唤醒时会调用各个驱动所注册的suspend或者resume回调函数.

下面以LCD为例,加入外设电源管理,使得在系统进入Mem休眠模式后,能关闭LCD背光灯,唤醒时打开LCD背光灯重新显示.

//Lcd.c
...//头文件
static struct dev_pm_ops lcd_pm = {
    .suspend = lcd_suspend,
    .resume  = lcd_resume,                                                                                                                                                         
};

struct platform_driver lcd_drv = { 
    .probe        = lcd_probe,
    .remove        = lcd_remove,
    .driver        = { 
        .name    = "mylcd",
        .pm     = &lcd_pm,
    }   
};
static int lcd_probe(struct platform_device *pdev)
{
    return 0;
}
static int lcd_remove(struct platform_device *pdev)
{
    return 0;
}
static int lcd_suspend(struct device *dev)
{
   ...
    *gpbdat &= ~1;     /* 关闭背光 */
    return 0;
}
static int lcd_resume(struct device *dev)
{
  ...
    *gpbdat |= 1;     /* 输出高电平, 使能背光 */
    return 0;
}
static int lcd_init(void)
{
    platform_device_register(&lcd_dev);
    platform_driver_register(&lcd_drv);
    ...//LCD相应的初始化
    return 0;
}
static void lcd_exit(void)
{
  ...//LCD相应的注销
   platform_device_unregister(&lcd_dev);
    platform_driver_unregister(&lcd_drv);
}

module_init(lcd_init);
module_exit(lcd_exit);

MODULE_LICENSE("GPL");

代码分析

  1. 在LCD驱动的基础上注册了一个平台设备和驱动,当系统进入休眠模式时会调用lcd_suspend函数关闭灯光,当唤醒退出休眠模式时会调用lcd_resume打开灯光.
  2. 重点在于第13行的结构体.

总结

上面介绍的是系统休眠或唤醒模式下的电源管理, 对于不同平台,都需要按照DataSheet的说明选择休眠模式,修改u-boot和kernel.
那在正常运行模式下,能否单独对设备进行电源管理呢,请期待下一节更新Linux电源管理-Runtime PM

linux功耗分析

阅读数 26

没有更多推荐了,返回首页