你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32的TouchGFX 图形应用在亮屏时的低功耗实现

[复制链接]
STMCU小助手 发布时间:2023-6-18 11:07
1. 图形应用和低功耗
' B2 m& X+ T0 u( w. W随着智能设备的普及,越来越多的设备会用到图形界面,而在 STM32 MCU 上使用TouchGFX,使得图形设计变得非常简单。其中智能手表、智能手环等产品对功耗要求比较高,这就需要在图形应用同时,结合芯片的低功耗模式来优化能耗。
9 @; _5 }2 h5 Z" C( M9 s  Q4 R在图形应用中使用低功耗,一般分为两种场景,一种是在关闭屏幕时,MCU 进入 STOP 模式,能极大的降低 MCU 功耗;另一种是在屏幕亮着的状态,MCU 进入 SLEEP 模式,也能降低MCU 功耗。而在 STM32L4+芯片上,LPSLEEP 模式相比 SLEEP 模式功耗更低,本文将在STM32L4R9 芯片上,结合 TouchGFX 和 LPSLEEP 来介绍如何在亮屏状态下实现 MCU 低功耗。, z. B7 k; I2 i  }. W
2. 低功耗实现原理介绍1 Q% \- N: E8 Y# J
在使用 TouchGFX 做图形应用时,会使用到 FreeRTOS 操作系统,使用 SysTick 定时产生 1ms的中断来作为系统 tick。在所有应用任务空闲时,系统会调度 Idle 任务。此时我们能让 MCU 进入低功耗,从而达到降低 MCU 功耗的目的。6 c" p6 n2 O4 Z# u+ a9 _% J
. h3 O/ [3 Z# d4 X, y7 i
2.1. Tickless Idle5 V1 ?/ c. r* i6 e' {
FreeRTOS 提供了 Tickless Idle 配置,在 FreeRTOSConfig.h 文件中,通过配置configUSE_TICKLESS_IDLE 为不同的值来配置 FreeRTOS 是否在 Idle 任务里进入低功耗,默认为 0 表示不进入低功耗。本文中将配置为 2,自定义 Idle 任务中低功耗实现。4 t1 F: I) U0 h, g
# S9 \1 R0 ?% m: T5 E  G
MXTS%_0U37[GA{N7AIGY[DQ.png
: y$ Z' ]6 E& J0 @$ y4 w, t' h" {' z& V$ j% B$ K+ P5 C
FreeRTOS 中进入低功耗具体是由 vPortSuppressTicksAndSleep 函数实现。配置configUSE_TICKLESS_IDLE 为 2 时,还需要重写 vPortSetupTimerInterrupt 函数。
1 u6 P8 Z) }& i  U' R* M3 v; ^+ D' k- f* `
2.2. TouchGFX 渲染与进 LPSLEEP 限制
/ M% N* l% t- o0 \/ M6 C9 [根据参考手册描述,在进入 LPSLEEP 时要先切换到 LPRUN 模式,系统时钟要降低到2MHz,因此在进入、退出 LPSLEEP 时会有时钟的切换过程。
7 r( \* [+ h/ l4 D& u3 b6 l$ g在屏幕亮着的状态时,用户可能随时触摸屏幕,或者系统信息可能更新,因此屏幕显示的内容可能随时变化,如果此时 MCU 进入 LPSLEEP 状态,会导致系统响应不及时。另外,在屏幕内容更新时,L4R9 通过 DSI 向屏幕更新显示数据,此过程由硬件完成,在此过程中,软件也有可能会进入 LPSLEEP,这样系统时钟发生变化,会导致 DSI 更新显示数据异常,产生屏幕显示花屏的问题。) w1 |: v7 _) Z
为了避免以上问题,在进入 LPSLEEP 前会检查当前状态,如果用户未操作屏幕,# c" V8 e% J+ [; g& M- [, N
TouchGFX 已经完成渲染,DSI 刷新过程也完成,则允许系统进入 LPSLEEP 状态。这样既保证了系统正常工作,又达到了降低功耗的目的。
6 H! Y. x1 {/ m# s# I. |2 r6 c0 _5 A- w, l1 k2 \
3. 实现过程
2 M/ l& S; t" X/ G/ x! O2 \6 O( s重写 vPortSetupTimerInterrupt 函数,主要是设置与休眠时间补偿相关的变量,初始化 systick 寄存器:0 Q+ d2 h0 t" M* ]/ `

. U, }3 m! }& q& i1 ~

" T: f0 p: `$ Z3 a
  1. void vPortSetupTimerInterrupt( void )9 Z% k: c' W  w8 C% S' `( \
  2. {
      C) V. Q8 q) A) J3 E& k2 B2 \
  3. /* Calculate the constants required to configure the tick interrupt. */
    . {! q% g8 m/ J
  4. #if( configUSE_TICKLESS_IDLE == 2 )# s7 u4 U4 O  X" }& K1 H
  5. {
    ; X% m) [- l, U& m( C2 Z
  6. ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );. n, ~; Y( j! E, u4 L9 i
  7. xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
    % [6 C4 l8 r2 J- u# ^
  8. ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ /
    / l* ]/ `4 W+ _
  9. configSYSTICK_CLOCK_HZ );
    1 U$ Z/ j+ m& U7 {
  10. }% ~& G9 W' ^* J9 f
  11. #endif /* configUSE_TICKLESS_IDLE */
    ) f" Y" _5 o  L1 p1 B! G9 h
  12. /* Stop and clear the SysTick. */6 z# C+ E  q/ J9 u9 t: q
  13. portNVIC_SYSTICK_CTRL_REG = 0UL;
      `, @& A9 A: `1 S; @9 z+ V
  14. portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
    / J  T  Y9 _9 U
  15. /* Configure SysTick to interrupt at the requested rate. */
    8 ~# C' y# o" p" J6 e1 l1 L
  16. portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;8 }: _5 P' w' Z5 {7 i2 L
  17. portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | & I9 n; d  e: M2 w* y
  18. portNVIC_SYSTICK_ENABLE_BIT );
    $ [; R9 B; h5 ]; Q) e2 Q
  19. }
复制代码

: H" M$ C8 u3 Q" N, g4 q( b) t5 v
& N% B% ]: e" o# d# R
重写 vPortSuppressTicksAndSleep 函数。在进入 LPSLEEP 前,会停止 systick,在休眠完成后,需要补偿系统 tick 值,示例中使用 LPTIM 计时来补偿系统 tick 值。在进入 LPSLEEP 前先进行状态检查,只要有以下情况,都不进入低功耗模式:
$ a% K) I( n6 g) G+ Ra) 触摸事件产生:nosleep_flg% z8 x6 i' u  `$ d8 C
b) DMA2D busy 状态:isDMAbusy_a()
% f! h; r& ?% y# B1 Qc) DSI refreshing 状态:displayRefreshing
- q% R1 Z/ m) s/ ]5 W5 U4 xd) 渲染完成,请求 DSI 刷新:refreshRequested) ?2 {% f8 ?, a( D9 x
  1. void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
    , V$ v) L4 Q. T" y# x
  2. {* t. G4 D$ [8 {  W) h: o% Y. \
  3. uint32_t xMaximumPossibleSuppressedTicks,ulReloadValue, ulCompleteTickPeriods,ulCount;
    3 u! W9 g0 L: W0 M0 }4 {7 ^
  4. xMaximumPossibleSuppressedTicks=portMAX_16_BIT_NUMBER * configTICK_RATE_HZ / lptim_CLOCK_HZ;: z" ]7 k; h% s2 j: V, }+ P
  5. if(nosleep_flg || isDMAbusy_a() || displayRefreshing || refreshRequested) {
    6 m9 ~# s3 k# W+ w+ P. o
  6. if(!isDMAbusy_a() && !displayRefreshing && !refreshRequested) {
    $ a) g$ `# Y( }
  7. if(osKernelSysTick() > nosleep_flg_t0 + nosleep_time)
    ! o/ x! [9 {" L- `
  8. nosleep_flg = 0;  i- S1 s1 h1 z! n- c4 `) H
  9. }
    ; a9 z9 V  H( y# r  B- V7 ?
  10. return;8 K$ t: M$ k. R8 j% o9 G
  11. }" ]8 A' H+ Q. T$ z
  12. if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks ) {
    ! _6 R% S/ N! ^* b$ `- p7 v
  13. xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
    + O0 S+ y* a1 D' n
  14. }
    ' T) L+ ^' j% Q) ?. `. w* s
  15. portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;
    ; t( ?! V& \. j5 f
  16. HAL_SuspendTick();
    6 [* O" |. Q2 ^6 r* T% K! L
  17. ulReloadValue = (lptim_CLOCK_HZ * (xExpectedIdleTime - 1UL)/configTICK_RATE_HZ);
    0 Q6 ^: ^# w+ P' L
  18. __DSB();
    6 T9 j0 w' r3 X
  19. __ISB();! d5 C$ X2 E2 w) P, ]1 N. M
  20. LPTIM_ReloadMatch_flag=pdFALSE;
      W3 p! q! R5 P6 ?; \4 `
  21. if( eTaskConfirmSleepModeStatus() == eAbortSleep ) {
    ) S2 r) ?  V7 x2 E) @0 Z
  22. portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
    # D+ Q) Y5 j9 L, s
  23. portNVIC_SYSTICK_LOAD_REG = configCPU_CLOCK_HZ/configTICK_RATE_HZ - 1UL;5 v& W& P) w7 U! G: W4 S
  24. HAL_ResumeTick();
    5 q5 q1 Z( v3 Z+ C2 D
  25. } else {& G6 Q5 k7 }9 q; H0 }  w, s
  26. MX_LPTIM1_Init(LPTIM_PRESCALER_DIV2, ulReloadValue);
    . L% x+ g" M$ b. m6 I; U1 S+ E
  27. if( xExpectedIdleTime > 0 ) {
    , P; V: B7 a, O5 d! _5 P0 `
  28. __DSB();: n  t3 X& l9 K* c, q' Z
  29. enter_lpsleep();
    . X4 H" F6 |9 @$ R) x( d% q' I
  30. __ISB();
    4 a& [% t+ R. {/ m! e/ ]! `! g' z; F
  31. }% X2 f! L! [; T  s8 X% F
  32. ulCount = HAL_LPTIM_ReadCounter(&Lptim1);1 k, r" q0 s; W
  33. HAL_LPTIM_TimeOut_Stop_IT(&Lptim1);7 S: R/ K6 a, h! J
  34. HAL_ResumeTick();8 q; H) P) G  r
  35. if( LPTIM_ReloadMatch_flag != pdFALSE ) {
    0 ~, \2 \5 }- S& X
  36. ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
    ) C2 l. m2 T! e, y( ]3 D* b1 t
  37. } else {
    # V6 i/ H# t8 I: Y7 i
  38. ulCompleteTickPeriods = (ulCount * configTICK_RATE_HZ)/ lptim_CLOCK_HZ;
    * o- P' @) ], z! k
  39. }
    4 [2 f/ p6 `! W4 y2 G
  40. portENTER_CRITICAL();  {2 U9 E4 a9 [( K9 y  N( z+ T: M
  41. uwTick += ulCompleteTickPeriods;
    ) _; M: U( ?2 [% i1 D; p
  42. vTaskStepTick( ulCompleteTickPeriods );
    $ ^9 I7 z* t' b7 a# b! o
  43. portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;7 Y3 D4 }& T& R+ R0 o2 _7 x0 v
  44. portNVIC_SYSTICK_LOAD_REG = configCPU_CLOCK_HZ/configTICK_RATE_HZ - 1UL;* m+ l: D1 E- h4 X8 ^" W
  45. portEXIT_CRITICAL();
    # c8 @. c+ N) y+ O9 a$ G
  46. }
    - r; i4 y; Y$ M
  47. }
复制代码

% x9 y1 @5 ~, ]8 M  h) rTouchGFX 渲染过程包括两部分,CPU 渲染和 DMA2D 渲染。在 CPU 渲染过程中,TouchGFX任务处于执行状态,系统不会主动调度 Idle 任务。而在 DMA2D 渲染过 TouchGFX 会让出CPU,此时可能会切换到 Idle 任务执行,因此需要对 DMA2D 是否正在渲染进行判断。对DMA2D 是否在渲染的判断如下:$ A: C0 w. Y5 P/ }
  1. extern "C" uint8_t isDMAbusy_a()* [% X+ l3 Y: `! Z
  2. {
    1 d, f" e1 n- h" f; I! R
  3. return ((TouchGFXHAL*)(touchgfx::HAL::getInstance()))->isDMAbusy();
    ; d' O$ z! Z2 Y( g
  4. }$ t4 X4 ~3 u0 \" P9 R2 ]
  5. uint8_t TouchGFXHAL::isDMAbusy()
    1 U* b) k! v1 N) D+ Y1 ~+ |: A
  6. {
    : E5 l9 |1 L& R5 @# L5 `8 z
  7. bool dma_qe = dma.isDmaQueueEmpty();  W# a) h5 L( U, X4 @6 d* f, c7 _
  8. bool dma_run = dma.isDMARunning();
    9 W3 d3 u1 }1 @0 u5 V9 E- Y5 k
  9. return (uint8_t)(!dma_qe || dma_run);& E/ w, b2 ], O' `7 W% |
  10. }
复制代码
& o& I4 |4 G+ @0 r5 D
4 H( y. z8 J" z2 @
完整版请查看:附件9 V- r' t& |  @" p9 ~
TouchGFX图形应用在亮屏时的低功耗实现.pdf (255.25 KB, 下载次数: 4)
赞 收藏 评论2 发布时间:2023-6-18 11:07

举报

2个回答
lospring 回答时间:2023-8-10 10:15:58

低功耗确实是非常需要考虑的一个点

shenxiaolin_mai 回答时间:2023-8-10 10:16:03
感谢分享!

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版