2016年我参与了一个无线充电器的项目负责固件开发。

说起来这个项目是公司的一个新产品做一款支持Qi标准的无线充电器主打快充、小巧、美观。我负责固件开发也就是无线充电器的主控芯片的程序开发。

项目初期功能都实现了能正常充电但是有一个问题很严重:响应时间很慢。从手机放上去到开始充电需要两三秒用户把手机放上去要等很久才看到充电提示体验很差。

产品经理说这个响应时间必须优化目标是1秒以内最好500毫秒以内否则用户体验太差产品没法,卖。

于是这个性能调优的任务就落到了我头上。我花了两周时间进行性能调优最终把响应时间从2500毫秒降到了500毫秒降了80%,达到了产品的要求。

今天就来聊聊这次无线充电器性能调优的经历以及嵌入式设备性能调优的一些经验。

一、问题现象

先说说问题的现象。

无线充电器的工作流程大概是这样的:

  1. 待机状态:没有手机放上去充电器处于低功耗待机状态每隔一段时间检测有没有物体放上去。
  2. 检测到物体:检测到有物体放上去开始进行异物检测和Qi协议握手。
  3. Qi协议握手:和手机进行Qi协议通信协商充电功率等参数。
  4. 开始充电:握手成功开始输出功率给手机充电。

问题就出在从检测到物体到开始充电这段时间太长了需要2500毫秒也就是2.5秒。

用户把手机放上去要等2.5秒才看到手机显示充电中体验很差感觉充电器反应很迟钝。

而且有时候用户把手机放上去位置没放对稍微动一下充电器就会重新检测重新握手又要等2.5秒体验更,差。

所以这个响应时间的问题必须解决。

二、排查过程

要优化性能首先要知道时间都花在哪里了。

我用了一个逻辑分析仪接在主控芯片的引脚上记录各个阶段的时间看看时间都花在哪里了。

经过测量各个阶段的时间大概是这样的:

  1. 待机检测间隔:500毫秒。待机状态每隔500毫秒检测一次有没有物体放上去。也就是说最坏情况下用户把手机放上去要等500毫秒才被检测到。
  2. 异物检测:300毫秒。检测到物体之后进行异物检测判断放上去的是手机还是异物(比如钥匙硬币,等)。
  3. Qi协议握手:1500毫秒。异物检测通过之后和手机进行Qi协议握手协商参数。这是耗时最长的部分。
  4. 功率输出启动:200毫秒。握手成功之后启动功率输出给手机充电。

加起来500 + 300 + 1500 + 200 = 2500毫秒正好是我们测到的响应时间。

找到了时间花在哪里就可以针对性地优化了。

其中Qi协议握手占了1500毫秒是最大的耗时部分也是优化的重点。其次是待机检测间隔500毫秒也有优化空间。异物检测和功率输出启动耗时相对少优化空间不大。

三、优化方法

找到了瓶颈就开始针对性地优化。

1. 优化待机检测间隔

原来待机状态每隔500毫秒检测一次有没有物体放上去。这个间隔太长了最坏情况下要等500毫秒才被检测到。

优化方法:

  • 缩短检测间隔从500毫秒降到100毫秒。这样最坏情况下只要等100毫秒就被检测到。
  • 但是检测间隔缩短会增加功耗因为更频繁地检测会消耗更多电量。
  • 为了平衡功耗和响应速度我们采用了动态检测间隔:平时用200毫秒的间隔检测;如果检测到有物体靠近(通过电容感应或者红外感应),就切换到50毫秒的间隔快速检测。

这样平均功耗增加不多但是响应速度提升了很多。

优化后待机检测的平均响应时间从500毫秒降到了100毫秒节省了400毫秒。

2. 优化异物检测

原来异物检测需要300毫秒。异物检测的原理是通过检测线圈的品质因数(Q值),变化来判断放上去的是手机还是异物。如果Q值变化在正常范围内就是手机;如果Q值变化异常就是异物。

原来异物检测需要多次测量取平均值来提高准确性所以耗时较长。

优化方法:

  • 优化测量算法减少测量次数从原来的10次取平均降到3次取平均同时提高单次测量的精度。
  • 采用快速判断机制:先进行一次快速测量如果明显是手机或者明显是异物就直接判断不用再测量;如果不确定再进行多次测量确认。
  • 优化ADC采样和滤波算法提高测量速度和精度。

优化后异物检测的时间从300毫秒降到了100毫秒节省了200毫秒。

3. 优化Qi协议握手(重点)

Qi协议握手是最大的耗时部分1500毫秒也是优化的重点。

Qi协议的握手过程大概是这样的:

  1. 模拟ping(Analog Ping):充电器发送一个模拟ping信号检测有没有接收器(手机)。
  2. 数字ping(Digital Ping):如果检测到接收器发送数字ping信号包含充电器的信息。
  3. 识别配置(Identification & Configuration):接收器回复识别和配置包包含接收器的信息和需求。
  4. 协商(Negotiation):双方协商充电功率等参数。
  5. 重新协商(Re-negotiation):如果需要调整功率进行重新协商。
  6. 开始充电:协商成功开始充电。

原来我们的固件严格按照Qi协议的流程一步一步来每个步骤都等对方回复超时时间也设得比较长所以耗时较长。

优化方法:

  • 优化超时时间:原来每个步骤的超时时间设得比较长比如1000毫秒实际上正常情况下对方几百毫秒就回复了。我们把超时时间缩短到300毫秒同时增加重试机制如果超时就重试一次。这样正常情况下不用等太久异常情况下也能通过重试恢复。
  • 并行处理:原来每个步骤都是串行的一个步骤完成才开始下一个。我们优化了流程一些可以并行的步骤并行处理。比如在等待对方回复的同时进行一些准备工作比如ADC校准参数计算,等。
  • 快速协商:原来协商过程比较繁琐需要多次通信。我们优化了协商算法对于常见的手机型号采用快速协商机制一次通信就协商完成不用多次通信。对于不常见的手机型号还是用标准的协商流程保证兼容性。
  • 优化协议栈:原来我们的Qi协议栈是用开源的代码改的效率不高很多地方有冗余。我们对协议栈进行了重构优化了数据结构和算法减少了内存拷贝和计算量提高了协议处理速度。
  • 优化中断处理:原来中断处理程序写得比较低效有很多冗余的操作。我们优化了中断处理程序减少了中断处理时间提高了实时性。

通过这些优化Qi协议握手的时间从1500毫秒降到了250毫秒节省了1250毫秒是优化效果最明显的部分。

4. 优化功率输出启动

原来功率输出启动需要200毫秒。启动功率输出需要逐步提高功率防止过冲和保护电路。

优化方法:

  • 优化PID控制算法提高响应速度同时保证稳定性。
  • 采用前馈控制根据协商好的功率直接设置初始占空比然后再用PID微调减少调节时间。
  • 优化软启动曲线从原来的线性软启动改成指数软启动启动更快同时不会过冲。

优化后功率输出启动的时间从200毫秒降到了50毫秒节省了150毫秒。

四、踩坑经验

在优化的过程中也踩了一些坑分享一下。

1. 优化过度导致兼容性问题

刚开始优化Qi协议握手的时候为了追求速度把超时时间设得太短而且快速协商机制也比较激进结果导致一些老款的手机或者不常见的手机无法正常充电因为它们回复比较慢或者协议实现比较特殊。

后来我们调整了策略:对于常见的手机型号用快速协商机制;对于不常见的手机型号或者快速协商失败的情况自动降级到标准的协商流程保证兼容性。

这样既保证了速度又保证了兼容性。

2. 功耗增加导致待机时间变短

优化待机检测间隔的时候把检测间隔缩短了导致待机功耗增加了一些待机时间变短了。

虽然增加的功耗不多但是对于无线充电器来说待机功耗还是很重要的因为大部分时间都是待机状态。

后来我们采用了动态检测间隔和低功耗模式在没有物体靠近的时候用较长的检测间隔和低功耗模式;检测到物体靠近再切换到快速检测和正常模式。这样平均功耗增加很少待机时间基本不变。

3. 异物检测误判

优化异物检测的时候减少了测量次数导致有时候异物检测误判把异物当成手机或者把手机当成异物。

异物检测误判是很危险的因为如果把异物(比如钥匙硬币),当成手机开始充电会导致异物发热甚至起火有安全隐患。

后来我们调整了策略:先进行快速测量如果明显是异物就直接判断不充电;如果明显是手机或者不确定就再进行多次测量确认确保安全。

而且在充电过程中也持续进行异物检测如果发现异常立即停止充电保证安全。

安全永远是第一位的不能为了追求速度而忽视安全。

4. 调试困难

嵌入式设备的调试比PC上的程序调试困难很多因为资源有限而且很多问题是时序相关的很难复现。

在优化的过程中遇到了一些奇怪的问题比如有时候响应很快有时候响应很慢没有规律。

后来我们用了逻辑分析仪和示波器记录各个信号的时序才发现问题是因为中断优先级设置不对有时候高优先级的中断打断了协议处理导致延迟。

调整了中断优先级之后问题就解决了。

嵌入式开发调试工具很重要逻辑分析仪示波器这些工具能帮我们快速定位问题。

五、最终效果

经过两周的优化最终效果如下:

阶段优化前优化后节省
待机检测500ms100ms400ms
异物检测300ms100ms200ms
Qi协议握手1500ms250ms1250ms
功率输出启动200ms50ms150ms
总计2500ms500ms2000ms

响应时间从2500毫秒降到了500毫秒降了80%,达到了产品的要求。

用户把手机放上去基本上立刻就能看到充电提示体验大幅提升。

而且兼容性也没有问题测试了几十款不同型号的手机都能正常快速充电。

功耗也基本不变待机时间没有明显缩短。

安全也有保障异物检测准确没有误判充电过程稳定安全。

产品经理和老板都很满意这个优化结果。

六、性能调优的经验

通过这次无线充电器性能调优我总结了一些嵌入式设备性能调优的经验。

1. 先测量再优化

性能调优第一步一定是测量找到瓶颈在哪里然后针对性地优化。不要凭感觉盲目优化那样可能花了很多时间效果却不好。

用合适的工具比如逻辑分析仪示波器性能分析工具等精确测量各个阶段的时间找到最大的耗时部分重点优化。

2. 抓主要矛盾

性能调优要抓主要矛盾重点优化耗时最长的部分。比如这次Qi协议握手占了60%的时间重点优化它效果最明显。

不要在耗时很短的部分花太多时间优化效果有限性价比不高。

3. 平衡性能和其他因素

性能调优不能只追求性能还要平衡其他因素比如兼容性功耗安全稳定性,等。

优化过度可能会导致兼容性问题功耗增加安全隐患等反而得不偿失。

要在保证兼容性功耗安全稳定性的前提下尽可能提高性能。

4. 分层优化

性能调优是一个系统工程需要从多个层面综合优化:

  • 硬件层:优化硬件设计选择更快的芯片更好的元器件。
  • 固件层:优化固件代码提高执行效率。
  • 协议层:优化协议实现减少通信次数缩短超时。
  • 算法层:优化算法减少计算量提高精度。
  • 应用层:优化应用逻辑减少冗余操作。

从多个层面综合优化才能达到最好的效果。

5. 持续优化

性能调优不是一蹴而就的需要持续优化不断改进。

这次优化虽然达到了目标但是还有优化空间比如进一步优化协议栈提高效率进一步优化算法提高精度,等。

而且随着新的手机型号不断出现也需要持续优化兼容性和充电速度。

所以性能调优是一个持续的过程需要不断努力。

七、写在最后

无线充电器性能调优:我把响应时间降了80%。

这次性能调优虽然只有两周时间但是收获很大不仅把产品的响应时间降了80%,提升了用户体验也学到了很多嵌入式设备性能调优的经验和方法。

嵌入式开发和PC开发不太一样资源有限实时性要求高调试困难但是也很有乐趣当你把一个设备的性能优化得很好的时候那种成就感是很强烈的。

性能调优是一个系统工程需要先测量找到瓶颈然后抓主要矛盾重点优化同时平衡性能和兼容性功耗安全等因素从多个层面综合优化才能达到最好的效果。

希望我的这些经历和经验能对大家有所帮助特别是做嵌入式开发或者性能调优的朋友。

最后用一句话结尾:

"性能不是一蹴而就的而是不断测量不断优化持续改进的结果。"

愿大家都能写出高性能的代码做出体验优秀的产品。