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

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

[复制链接]
STMCU小助手 发布时间:2023-6-18 11:07
1. 图形应用和低功耗7 F. V5 ?; v# v9 y  C
随着智能设备的普及,越来越多的设备会用到图形界面,而在 STM32 MCU 上使用TouchGFX,使得图形设计变得非常简单。其中智能手表、智能手环等产品对功耗要求比较高,这就需要在图形应用同时,结合芯片的低功耗模式来优化能耗。
/ _! O4 z. m  w: y$ H在图形应用中使用低功耗,一般分为两种场景,一种是在关闭屏幕时,MCU 进入 STOP 模式,能极大的降低 MCU 功耗;另一种是在屏幕亮着的状态,MCU 进入 SLEEP 模式,也能降低MCU 功耗。而在 STM32L4+芯片上,LPSLEEP 模式相比 SLEEP 模式功耗更低,本文将在STM32L4R9 芯片上,结合 TouchGFX 和 LPSLEEP 来介绍如何在亮屏状态下实现 MCU 低功耗。
: d4 M  z8 c* X4 n8 a
2. 低功耗实现原理介绍
  R' c  J# W  m# i  @  q' R在使用 TouchGFX 做图形应用时,会使用到 FreeRTOS 操作系统,使用 SysTick 定时产生 1ms的中断来作为系统 tick。在所有应用任务空闲时,系统会调度 Idle 任务。此时我们能让 MCU 进入低功耗,从而达到降低 MCU 功耗的目的。
( o% m% O1 `' w, u" Q
+ _( C3 J. x5 s: X3 e: \8 W
2.1. Tickless Idle
. d1 ~8 E: F* o+ R3 P( WFreeRTOS 提供了 Tickless Idle 配置,在 FreeRTOSConfig.h 文件中,通过配置configUSE_TICKLESS_IDLE 为不同的值来配置 FreeRTOS 是否在 Idle 任务里进入低功耗,默认为 0 表示不进入低功耗。本文中将配置为 2,自定义 Idle 任务中低功耗实现。
; C1 a& b+ G8 k& e% `% _# _+ g: J2 o/ {0 I, t7 g
MXTS%_0U37[GA{N7AIGY[DQ.png / R! x7 p& q! x% I4 ^% J, R! A

. Z( o' E' j6 J# u' m, CFreeRTOS 中进入低功耗具体是由 vPortSuppressTicksAndSleep 函数实现。配置configUSE_TICKLESS_IDLE 为 2 时,还需要重写 vPortSetupTimerInterrupt 函数。
+ k3 S! W1 R4 W+ \4 t" j# ?0 d  T
1 u- e: r* R! A/ H( b2.2. TouchGFX 渲染与进 LPSLEEP 限制
4 Z" x  b4 Q$ `- t根据参考手册描述,在进入 LPSLEEP 时要先切换到 LPRUN 模式,系统时钟要降低到2MHz,因此在进入、退出 LPSLEEP 时会有时钟的切换过程。; I/ |9 J* E. r; G; y3 e  _' W3 ]
在屏幕亮着的状态时,用户可能随时触摸屏幕,或者系统信息可能更新,因此屏幕显示的内容可能随时变化,如果此时 MCU 进入 LPSLEEP 状态,会导致系统响应不及时。另外,在屏幕内容更新时,L4R9 通过 DSI 向屏幕更新显示数据,此过程由硬件完成,在此过程中,软件也有可能会进入 LPSLEEP,这样系统时钟发生变化,会导致 DSI 更新显示数据异常,产生屏幕显示花屏的问题。9 z1 f- E( N+ I" o0 D  G
为了避免以上问题,在进入 LPSLEEP 前会检查当前状态,如果用户未操作屏幕,
5 S: y: i4 q0 d  M3 CTouchGFX 已经完成渲染,DSI 刷新过程也完成,则允许系统进入 LPSLEEP 状态。这样既保证了系统正常工作,又达到了降低功耗的目的。
6 ^! T& p0 H) @4 L# _1 m+ J4 C
1 `3 X. N9 L5 r+ g# g
3. 实现过程! Q2 }" g5 f3 p
重写 vPortSetupTimerInterrupt 函数,主要是设置与休眠时间补偿相关的变量,初始化 systick 寄存器:
6 V4 q5 s  `$ E" @  s0 c
8 [1 `+ ], R$ R. k5 t) d

7 Q( Y7 I* E0 G% e% j7 Z
  1. void vPortSetupTimerInterrupt( void )! C! c: n1 F0 s3 s7 y  O3 l
  2. {
    & d4 `4 |7 ~* u, r, u4 \& [/ J
  3. /* Calculate the constants required to configure the tick interrupt. */
    9 s- ^- H0 ~0 U" B1 s
  4. #if( configUSE_TICKLESS_IDLE == 2 )  _: j6 g% h, w  x! ~# D5 k  b. A
  5. {
    # ?$ B; u3 X+ H
  6. ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
    % Q1 r- V$ Z' v3 o4 r) R
  7. xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;  D6 y% R+ h2 Q( R5 W
  8. ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ / 4 Y# Q4 |9 ~. b: z! ]0 k* m5 q2 L5 h
  9. configSYSTICK_CLOCK_HZ );
    4 [* u, b7 }7 V6 ^
  10. }
    * Y8 m; C/ F! p2 j# L$ V/ p+ x7 X
  11. #endif /* configUSE_TICKLESS_IDLE */. J, J0 z7 N+ T$ b
  12. /* Stop and clear the SysTick. */$ {; ^3 H; \8 x+ D2 e" u
  13. portNVIC_SYSTICK_CTRL_REG = 0UL;
    ! m7 E$ j3 a# {0 F4 R% {6 D, e0 z
  14. portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;9 C5 j5 y4 f/ H& H- A5 W- o! @
  15. /* Configure SysTick to interrupt at the requested rate. */  v2 ~4 \6 H2 l' o* H! e: N5 @
  16. portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
    ! Y; H7 w, [& B1 ~' d  J+ r: Q# W
  17. portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT |
    3 x. |. g: c) [, `9 Q  ]" \
  18. portNVIC_SYSTICK_ENABLE_BIT );
    % q( y; S* |/ H. t3 A
  19. }
复制代码
! o9 w1 F! w  Y+ w
" l- t; v) N, i+ q
重写 vPortSuppressTicksAndSleep 函数。在进入 LPSLEEP 前,会停止 systick,在休眠完成后,需要补偿系统 tick 值,示例中使用 LPTIM 计时来补偿系统 tick 值。在进入 LPSLEEP 前先进行状态检查,只要有以下情况,都不进入低功耗模式:2 {$ [4 l. T0 U, l, ~" M
a) 触摸事件产生:nosleep_flg. N. |1 B, @* Z0 {' s
b) DMA2D busy 状态:isDMAbusy_a()0 B  Z$ y$ t+ }5 c& g+ S
c) DSI refreshing 状态:displayRefreshing
, l- X. m# U' I9 T5 L) x2 ^0 ^d) 渲染完成,请求 DSI 刷新:refreshRequested7 \. q3 N- L0 b! q
  1. void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )1 _* m3 C! R# A- f9 g- X
  2. {, e9 }5 X4 Z% R& p( {; X
  3. uint32_t xMaximumPossibleSuppressedTicks,ulReloadValue, ulCompleteTickPeriods,ulCount;
    1 ]0 g/ {# Z5 G: |4 O+ \
  4. xMaximumPossibleSuppressedTicks=portMAX_16_BIT_NUMBER * configTICK_RATE_HZ / lptim_CLOCK_HZ;
    # }4 `1 B( p6 Q/ |: o
  5. if(nosleep_flg || isDMAbusy_a() || displayRefreshing || refreshRequested) {- z( q& L, f" ?
  6. if(!isDMAbusy_a() && !displayRefreshing && !refreshRequested) {
    ; T5 ~7 e  C* g7 f
  7. if(osKernelSysTick() > nosleep_flg_t0 + nosleep_time)* }' J, N( O/ X  {" V3 J# C
  8. nosleep_flg = 0;1 @" `% y% N7 B* m9 P* C* v' V; Y
  9. }
    $ [' ?, m1 ~0 B
  10. return;
    ( B+ W$ ^  l, s  i1 e
  11. }
    & ~- O8 @, N' C& Y, R7 Y- `5 y
  12. if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks ) {
    # O5 m! K7 d: d/ c: ?1 i
  13. xExpectedIdleTime = xMaximumPossibleSuppressedTicks;* V: u1 X7 B" u9 {' O
  14. }& n% j/ N& @" D. _0 S
  15. portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;
    # g1 S3 G% i2 P/ l
  16. HAL_SuspendTick();  J' ?/ Y7 o) O5 _. \4 t
  17. ulReloadValue = (lptim_CLOCK_HZ * (xExpectedIdleTime - 1UL)/configTICK_RATE_HZ);
    9 t! r. w3 u8 L1 K9 ~
  18. __DSB();
    : i; v% Y" m+ d
  19. __ISB();/ z. o. j3 k' Q$ W% A  |
  20. LPTIM_ReloadMatch_flag=pdFALSE;
    / N/ o' i# g( U3 E& G
  21. if( eTaskConfirmSleepModeStatus() == eAbortSleep ) {
    8 g% i& F+ g2 I
  22. portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
    " s8 O. ~  X) r& y) R" A
  23. portNVIC_SYSTICK_LOAD_REG = configCPU_CLOCK_HZ/configTICK_RATE_HZ - 1UL;
    " k. C: y$ z4 G7 x& M
  24. HAL_ResumeTick();7 O$ g( P, }+ z4 R) T: i* c0 `
  25. } else {
    2 S, a8 [7 A0 y% e5 R! u
  26. MX_LPTIM1_Init(LPTIM_PRESCALER_DIV2, ulReloadValue);8 S$ r, g- |$ E7 u. Z
  27. if( xExpectedIdleTime > 0 ) {
    ( V' w4 G2 X2 B6 ?' m( W
  28. __DSB();) |5 l9 j" r6 @
  29. enter_lpsleep();; Z2 ?5 G8 `! H
  30. __ISB();, p/ y6 o: I2 {$ M5 Q, m
  31. }6 W/ {( `$ s4 W. s
  32. ulCount = HAL_LPTIM_ReadCounter(&Lptim1);* @1 d* c; r7 V4 Y# s. \
  33. HAL_LPTIM_TimeOut_Stop_IT(&Lptim1);
    2 P) t1 i( o( k
  34. HAL_ResumeTick();1 u# {1 c. L5 l4 F
  35. if( LPTIM_ReloadMatch_flag != pdFALSE ) {
    ( f3 i8 }! u; E7 Y& K0 f3 L# L) H$ s. P
  36. ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
    2 V0 Y2 U9 i% D, x4 A( J- ?7 |
  37. } else {
    ; f( B) N4 w: E+ ?& R
  38. ulCompleteTickPeriods = (ulCount * configTICK_RATE_HZ)/ lptim_CLOCK_HZ;0 p% K# X4 o, u# n6 c, m$ ^
  39. }
    $ m- [) y; E& ~% X3 H( `" O
  40. portENTER_CRITICAL();' y% N/ h& p" E% Z5 j, ^
  41. uwTick += ulCompleteTickPeriods;
    & d! h8 q3 u/ p/ {
  42. vTaskStepTick( ulCompleteTickPeriods );
    4 r4 H/ D$ \6 ]
  43. portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;$ i2 _0 C7 Z0 w' K$ \# e( Y/ |
  44. portNVIC_SYSTICK_LOAD_REG = configCPU_CLOCK_HZ/configTICK_RATE_HZ - 1UL;2 h4 a  N& [" p4 q% V  R
  45. portEXIT_CRITICAL();" w7 S2 G( G0 X
  46. }- e  y8 [9 d1 f" E  a
  47. }
复制代码
4 f( ?/ y8 ?" ~( ^: U9 [$ F8 |
TouchGFX 渲染过程包括两部分,CPU 渲染和 DMA2D 渲染。在 CPU 渲染过程中,TouchGFX任务处于执行状态,系统不会主动调度 Idle 任务。而在 DMA2D 渲染过 TouchGFX 会让出CPU,此时可能会切换到 Idle 任务执行,因此需要对 DMA2D 是否正在渲染进行判断。对DMA2D 是否在渲染的判断如下:
% b$ ]( o; K1 V& S; q
  1. extern "C" uint8_t isDMAbusy_a()
    * M1 Z" |) s+ x: E9 `
  2. {  g: H: [. {5 h3 o
  3. return ((TouchGFXHAL*)(touchgfx::HAL::getInstance()))->isDMAbusy();& ?# M/ ?7 D" S( O+ g( |! K- D
  4. }7 T2 Z& X- w9 ]# _" {9 B+ u+ ]
  5. uint8_t TouchGFXHAL::isDMAbusy()) p+ i; r4 n7 Z( D2 }) E
  6. {
    5 ]) n3 A& ?/ M; ~* p1 c
  7. bool dma_qe = dma.isDmaQueueEmpty();2 W0 B+ ]. r5 `% I  h9 V) a  w& S
  8. bool dma_run = dma.isDMARunning();
    - {! L; x5 i" h) {0 \* z5 p
  9. return (uint8_t)(!dma_qe || dma_run);
    . _! {. _; N+ ?" _+ e
  10. }
复制代码

9 O) H6 U: R( E5 w; n. S; C4 L( d# c9 I) F6 O
完整版请查看:附件6 h! Y6 u5 s/ t7 n. v9 ^
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 手机版