EDA365电子论坛网
标题:
PM2.0外部中断唤醒后程序执行顺序异常为什么会发生这种情况呢
[打印本页]
作者:
abc66
时间:
2022-9-7 11:29
标题:
PM2.0外部中断唤醒后程序执行顺序异常为什么会发生这种情况呢
设备为stm32L071,rtt是github上下载的最新版4.1.1。在调试pm功能时遇到问题:
/ x% g, l7 C+ E4 C" `
1.可以进入STOP模式,tickless使用lptim,工作正常,软件定时器可以主动唤醒。
I4 X6 c& h! T0 ]9 Y& h( b3 Z
2.当使用外部中断唤醒stop模式后,串口工作不正常,debug发现唤醒后竟然先执行了中断服务函数,然后切换到等待信号量的线程,直到idle后才会执行中的睡眠前的代码处,这时才执行恢复时钟函数。
) z* m" }: s0 e ^4 f! @' j
pm睡眠前应该是禁用了全局中断的,只发生pending不执行ISR才对,为什么会有这种问题呢?
* l; Y# r! y+ j# i" h( G
! S$ W( E( P7 p$ o# k6 C
static void rx_thread_entry(void *param)
K! X( i% U$ ]6 ?
{
% n; h. B, k0 E$ v9 e' c2 q
while(1)
1 [5 N6 F. d1 i) j" u
{
- w4 f( n( S& s# k, {4 O. _- A
if (rt_sem_take(rx_sem, RT_WAITING_FOREVER) == RT_EOK)
/ C1 q/ @# }; M9 a9 q8 f
{
7 |/ r5 q9 `$ S+ A* h5 g" `4 q
rt_pm_sleep_request(PM_BOARD_ID, PM_SLEEP_MODE_NONE);
! n5 W r4 L- D) d
do something //此时串口异常,LOG等功能输出乱码
7 J) y1 G% C5 g- ]
rt_thread_mdelay(5); //执行到此处,才跳转到睡眠前位置,恢复时钟
- ~ t7 v5 W$ x1 M% W
rt_thread_mdelay(5000);
+ E; K; w6 v5 I- O' D& f, A
rt_pm_sleep_release(PM_BOARD_ID, PM_SLEEP_MODE_NONE);
, t6 K z% f) V0 E/ _: m0 t
}
5 I& d; M8 w% H8 C4 s4 t) V
}
2 M( M' i& l e' {, R8 i
}
) n U3 I2 `& Q
void lora_rx_irq_callback(void *parameter)
) Q% t: D2 e0 v
{
a n I( I' p
rt_sem_release(rx_sem); //先执行此行,释放信号量
" L0 n& B, H- V4 k5 A" E3 d7 e
}
' ]/ D/ N/ ]7 ^- P5 I4 o/ H. E
pm适配代码如下:
) X0 G! d0 J' ?7 [" d, f5 T
! K# B3 Z+ { Q4 C h
static void sleep(struct rt_pm *pm, uint8_t mode)
3 W, {, J+ B8 K0 b; t
{
* g! d0 K# b$ o2 j) |3 c
switch (mode)
?+ B0 Z9 y/ D1 d) }4 u
{
# G) M4 O$ L# D% Q; F, V5 Y
case PM_SLEEP_MODE_NONE:
5 V) m& b% I) M+ `& m! p
break;
6 O9 g. z3 `# e/ N
case PM_SLEEP_MODE_IDLE:
. N, Z! \7 t: c; @7 z2 M) o
case PM_SLEEP_MODE_LIGHT:
$ N* `9 a4 A7 V
/* Enter SLEEP Mode, Main regulator is ON /
+ h8 K1 [$ ]$ V, n
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
) n3 l/ O* r% P% R
break;
) s" l0 b( o7 a/ x ~( X8 Z
case PM_SLEEP_MODE_DEEP:
2 P* u- Z5 s5 D: I
/ Disable SysTick interrupt /
1 c# W% c" e) T7 h
CLEAR_BIT(SysTick->CTRL, (rt_uint32_t)SysTick_CTRL_TICKINT_Msk);
! C6 V; y. r0 {% e+ i. S& e0 |
/ Enable the Ultra Low Power mode and the fast wake up /
4 q( {% c4 _! V; p. l: _
SET_BIT(PWR->CR, PWR_CR_ULP | PWR_CR_FWU);
5 P( ^0 @5 N8 D( H9 I! R, J
/ Select HSI as system clock source after Wake Up from Stop mode /
7 p2 z: F' ]/ @& ?7 [1 v
//__HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_HSI);
} N3 N5 x" k4 @2 X
/ Enter STOP mode /
. l1 e% q1 ?, y! w. z
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
, j" ^9 {; ~$ Z( h; `7 q: L8 \. j
/ Disable the Ultra Low Power mode and the fast wake up /
& \2 ?$ G% a, S+ a) I! t# K
CLEAR_BIT(PWR->CR, PWR_CR_ULP | PWR_CR_FWU);
! I# h4 K4 k' w: i$ f
/ Enable SysTick interrupt /
8 G' h8 B/ v1 A' o% i. C
SET_BIT(SysTick->CTRL, (rt_uint32_t)SysTick_CTRL_TICKINT_Msk);
' u1 ~$ x1 w1 O* a: u
/ Re-configure the system clock /
9 ?* C0 |6 M9 g/ m+ X
SystemClock_ReConfig();
2 ^ }) `8 z8 @3 f. R& { ]
break;
2 p8 K1 _0 l, ^
case PM_SLEEP_MODE_STANDBY:
$ h! v# x u2 o1 W' z/ f0 F: Q8 l
case PM_SLEEP_MODE_SHUTDOWN:
9 M1 a' u6 Z& n/ q
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
& N: p$ h7 O9 {- A& d7 G' e
/ Enter STANDBY mode */
. H: S' y: K$ V$ J! e5 C, Q2 r
HAL_PWR_EnterSTANDBYMode();
2 {& ?2 a2 L1 t# g O/ j$ a1 K
break;
$ u* ?% Z; O/ f Q
default:
3 c: @1 `6 z8 t4 G4 W
RT_ASSERT(0);
2 V( f# K& r, I" i
break;
k- d/ }. w& d* i6 k. C: Y+ W
}
3 o+ O8 a4 ?9 B3 W; B+ o
}
5 r4 E) O; R6 r% ^) E' Y, f! }& r
+ n) h- P9 E, u& ^3 |
7 @0 J9 o, K1 x8 d; C" }: b
0
& ?: y$ R1 I W9 Y* E* y' V
; q5 G: Z" Z0 ^3 k% R
作者:
opipo
时间:
2022-9-7 13:13
那说明禁用全局中断响应 没有效果
! z' X6 v5 S4 J9 P a1 b% Z- S
作者:
lahhse
时间:
2022-9-7 14:19
rt_hw_interrupt_disable() 应该要实现 __disable_irq 的效果才对,可以查下相关的手册,ARM Cortex 相关的,不同的Cortex 核,可能不一样。
, N7 C! c1 O' k) {' |
作者:
Blah
时间:
2022-9-7 14:36
主要问题是中断唤醒后代码执行顺序问题。
- p4 u; }9 n. N
看了您的PM设计思想和代码,我理解的预期唤醒后执行顺序是:
4 [& n, f; D$ ]
1.外部中断Pending
7 `* u3 x, D1 t& r5 Y
2.MCU唤醒,按照睡眠前代码位置继续执行sleep函数中的HAL_PWR_EnterSTOPMode()后续代码,恢复时钟,补偿systick,开启全局中断
. Q3 B0 K, I" @9 N. R
3.执行ISR,释放信号量,通知等待信号量的线程
) Z6 Y6 L' q8 M7 N3 l
4.执行线程代码
( V5 D% H$ ^( _- ]
W" j/ p- v3 U3 p& g! I
但实际加断点debug测出的执行顺序为:
+ K* S+ X/ m# H) v, b8 t4 O
1.外部中断Pending
6 h* a1 w. `& A0 B
2.执行ISR,释放信号量,通知等待信号量的线程
K2 ~/ ^( A. j1 Z: w! U
3.执行线程代码
z$ u( P, q. m* S/ P6 H
4.等待idle,如延时函数,按照睡眠前代码位置继续执行sleep函数中的HAL_PWR_EnterSTOPMode()后续代码,恢复时钟,补偿systick,开启全局中断
5 t+ G1 r; R: |
% A: K% k3 r2 D( [& R% G% V; v
这就导致唤醒后时钟不对,且第一个延时函数会因为tick补偿直接超时,不会产生延时效果(1s、2s、3s、5s都测过不生效),我尝试加两次延时解决了。
作者:
Jame33
时间:
2022-9-7 14:59
楼上说的很不错
6 b% {8 N' a) [. F2 h
欢迎光临 EDA365电子论坛网 (https://bbs.eda365.com/)
Powered by Discuz! X3.2