本帖最后由 aimejia 于 2018-5-23 11:31 编辑
3 h/ b6 T$ D2 I$ b/ S l L7 f6 P! z% }3 D" h
1 前言
( G# o9 V4 B% m# h& [ k7 U0 C 客户反馈在使用STM32F412的时候,擦除sector 8~11发现时间过长,从而导致意外触发IWDG复位。6 u1 `! h# h- w
5 a' \+ g4 C6 F/ |% R
2 问题分析
4 B& V& i" k* m6 M1 g( v8 S# P, R* F) `2.1 问题详情
6 X' v* S+ a) ^1 Z- _/ S 通过与客户邮件和电话沟通,了解到客户主要是想使用内部FLASH暂时保存IAP升级时的程序数据,在IAP升级的过程中,需要首先擦除内部FLASH中一块足够大的空间,然后再写入升级数据。客户的工程中有使用到IWDG,喂狗间隔大约1.5S,客户的通过SysTick的方式计算出擦除Sector8大约需要2ms,因此认为若一次擦除sector8~11大约需要8ms,于是在代码中一次性擦除sector8~11后最后再来喂狗,但是,这样会触发IWDG复位,这个与预期不一致,固此产生疑问。
/ O2 c- h# T1 X( Q1 t2 X0 a: V0 t7 [) t1 U, j! l% [
2.2 问题重现
% }* t6 D2 G% ]. l 使用NUCLEO-F412ZG板尝试重现客户问题,主要代码如下:* ~2 h/ |9 E' h
- int main(void)
7 f) |. V$ j3 K1 H - {0 T( I+ O' \+ h4 N9 T w K, \' N
- j0 m! f6 K$ }7 T8 O5 l4 W8 v; ?- /* USER CODE BEGIN 1 */5 r+ W. K# Y. X
- uint32_t beginTick =0,endTick =0;
6 s5 E& H* m% }* W1 F; `/ v - uint32_t curSysTick=0,endSysTick =0;
, ], b* a, a# m3 g4 u/ Q: n - /* USER CODE END 1 */2 \7 o; J& E2 J
/ ]( [0 n8 p8 R& X" ]) K- /* MCU Configuration----------------------------------------------------------*/7 j/ ^' n2 `+ R2 ~+ q, O
- ! a$ D5 O$ F1 x% i1 \
- /* Reset of all peripherals, Initializes the Flash interface and the Systick. */# P% L) Z- O" [- P8 n/ w% D' T6 o
- HAL_Init();
4 i( H2 t, Q2 V+ E% w
/ V. {0 k l4 K6 [" u- l- /* Configure the system clock */
0 ]% c+ j; s- y. n* w - SystemClock_Config();
' r N& c6 e! w1 Z: _; f/ F& v2 M9 [ - ; D" |( ~2 f1 _2 Z* T
- /* Initialize all configured peripherals */
( k: l- `9 V' [1 ~2 B6 o - MX_GPIO_Init();
3 [3 ]0 q8 Q. K n { - MX_IWDG_Init();$ k& u) M$ G! ?& i& N
- 1 O* Q, Y+ ~2 z8 t: i' b0 C l7 _
- /* USER CODE BEGIN 2 */
6 V- i5 ?6 ^2 {7 z2 C* M- V5 ^ - if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST) != RESET) //如果是看门狗复位9 _1 G6 {( b% v" p( `# d4 w
- {5 r8 Z$ g! J" ~4 `5 W
- /* Clear reset flags */9 s. {0 `, ~, L/ B1 e
- HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7,GPIO_PIN_SET); Z; [0 a5 F! y
- __HAL_RCC_CLEAR_RESET_FLAGS();% \ \' d; _5 g- e' o
- Error_Handler();" L2 J4 V8 s" |" U
- }
9 A* s6 b; \" a/ H. ?7 G - 2 ^1 t+ ]$ R+ j g
- HAL_FLASH_Unlock();
6 d* R7 U+ q- {' A' u" {6 _5 D2 M - /* Fill EraseInit structure*/& v7 H. M* N/ L3 R a( ^' E+ J U7 I
- EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;! ?) V' G3 A! c- r, Y# a6 e
- EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;) t' m* n* X$ h) {5 l" [4 [
- EraseInitStruct.Sector = FLASH_SECTOR_8;
, W) q5 b. W" x$ o2 h/ f - EraseInitStruct.NbSectors = 1;
2 k9 T' ?; I" D: W0 d$ W6 @- z
$ S( o. G/ ^5 H$ V$ q% V7 ?- // if(HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError) != HAL_OK)
5 ?& w' N8 j' e% G i' ?; d# m - // {2 L0 S: e P% ]6 R- U
- // Error_Handler();
0 C$ F3 @# S( y - // }
/ v2 j0 C- t' ]# m- N3 H- x0 m$ k
6 \& q: j" g1 Z2 ~4 P+ ~# C- beginTick =HAL_GetTick();8 R" P# z! }2 |5 ~; j
- HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_SET); J q% U2 D* t3 E6 Y
- curSysTick =SysTick->VAL;; p# \ s% F) g( c" j. q/ N: M
- if(HAL_FLASHEx_Erase_IT(&EraseInitStruct)!= HAL_OK) //擦除sector80 d( V4 _% E% K. C
- {6 r8 g K1 f- G1 G- E
- Error_Handler(); ]2 l3 H% e w; c: O9 C
- }- g+ y( }4 G' }, v, N
- endSysTick =SysTick->VAL; // curSysTick, endSysTick保存着SysTick寄存器的值
* s8 _* D, P% ?4 K - HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_RESET); //PC8波形表示擦除FLASH的时间间隔
9 }. f7 q( G8 U& ?8 R; B - endTick =HAL_GetTick(); // beginTick, endTick保存着全局变量Tick的值# |! a4 {: y0 A7 [4 g
- g_TickCount =endTick -beginTick; //变量Tick的时间差+ i8 ]. E. M& M6 X( }& N
- HAL_IWDG_Refresh(&hiwdg);$ q% u) k8 [3 x% i
- /* USER CODE END 2 */- J0 _8 e# L1 T5 y+ V
- 2 l- b9 y7 o. {
- /* Infinite loop */
# x. F. e! G9 a9 u7 [9 {: M, D. w - /* USER CODE BEGIN WHILE */
* o& D! o4 V' z4 J9 k6 p - while (1)
8 t6 p' F+ n( r0 s+ `. Q, ~( k - {3 a0 g' f; X6 d. \
- /* USER CODE END WHILE */
0 Q4 U9 [& ]9 K2 M( y8 n9 u - - u; b1 h1 L$ V# N7 J
- /* USER CODE BEGIN 3 */" Q3 D% M# m" D% K- e! V% p
- if (HAL_IWDG_Refresh(&hiwdg) != HAL_OK)
q6 _2 Y, G$ E - {
* A2 |1 l# F$ ~ ` - /* Refresh Error */
; A8 N" U# O" F! Z% o S. f - Error_Handler();
8 Q- e; A v+ f3 A, r. j. y4 V; L - }
! E/ q" A7 v; u4 c - HAL_Delay(10);
+ N0 O- E+ \' I3 L. q9 p - }2 f1 V; k) `& F C3 r1 E
- /* USER CODE END 3 */
& t9 f: g' n0 \0 Z) Y% ^ - }
复制代码 此外,同时在每个SysTick中断输出一个波形,用来检测SysTick是否正常:- void HAL_SYSTICK_Callback(void)4 b% X3 Q$ Q! H" }3 |3 E
- {
8 F/ V0 @& Q! Y5 x9 T - HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_11);//用PA11来检测SysTick波形
$ W' d, f1 x& @: X ~& }, [8 { - }
复制代码
9 j! \7 c/ ], f0 _2 M) R7 G: P 最终得出如下波形9 t+ W: S# a/ z8 M% r
图1 擦除FLASH时间与SysTick输出波形
' A: ]# \) d' t6 u$ p" ? 如上图,黄色为PC8脚波形,表示擦除FLASH的时间,下面蓝色为PA11管脚波形,表示SysTick波形。
; L, S F* c5 U 从上图可以看出擦除sector8所需要的时间是800ms,这个与客户认为的2ms是不一致的。查看STM32F412的数据手册,在第6.3.12节中可以看到如下信息: 6 z0 _7 |8 ?# N& g
/ `+ J9 | c9 M) p3 X4 w
图2 擦除FLASH扇区所需要的时间
% o! g( ]+ D& Q8 f: r 如上图,在PSIZE=32时,擦除一个128K的扇区需要大概1S(典型值)的时间,而我们从图1中实际测出的为800ms,这个基本相差不大,单与客户认为的2ms相去甚远,基本上我们认为这里的800ms是正确的结果,但是这个又是什么原因导致客户通过SysTick测出的值是错误的呢?
% C/ E2 \$ L+ p4 E6 ?/ C0 x) F9 x( o; O2 K% b1 _
实际上,从图1我们也可以看出,在擦除FLASH的期间,SysTick是没有波形的(见图1下面蓝色波形),同时在参考手册3.5节中有如下信息:
+ Z% z- r' {2 N/ ~( m9 U" E
7 p9 z- M) F p! ` n N n图3 参考手册中关于擦除扇区的描述
7 J, _+ q3 `! I( |0 i' W 这句话的意思是说,在擦除FLASH的期间,若尝试读取FLASH,则会被暂停,实际这个”读取”是指取指,我们都知道,程序的执行首先得通过从FLASH中通过I-BUS取出指令后才可以执行。这里SysTick之所以会被暂停掉,就是因为在擦除FLASH期间,为了执行SysTick中断例程,内核会尝试从FLASH取指,从而导致被暂停掉,进而全局变量uwTick的值没有机会增加。下图是调试界面: 7 J) L9 ]7 s& G) g1 Z
6 G" L o" L3 a3 U# O# b2 k
图4 调试 " c' H: |1 {2 {2 |/ f9 b
如上图,在执行擦除扇区后,SysTick的全局变量uwTick就增加了1,但SysTick在内核中的寄存器还是有变化的。这个与我们的预想一致。
: l' t4 o% J+ c3 @' g7 k0 C8 i
' I6 i) t n& V1 I, d 最后客户通过每擦除一个扇区喂一次狗的方式解决了问题,而在此期间不能依靠SysTick的值来计算时间。% D1 ? A6 S/ w) l) N$ o0 A
) r6 T/ R9 X8 B
3 结论9 q$ [! U/ _2 C4 y9 j6 O* \/ P
在擦除FLASH期间,取指操作会被暂停掉,且SysTick所对应的全局变量uwTick值是不会增加的。另外,通过函数HAL_FLASHEx_Erase_IT()来执行擦除FLASH和通过函数HAL_FLASHEx_Erase()所花费时间没有差别,只不过前者在擦除完成后会产生一个中断,而后者没有。可以通过外设RTC来计算擦除FLASH的时间,从而绕开限制。# h S0 I' }4 U9 m* K, f$ E' \
' f# u. V; h6 l6 S
' L. U: _ p( X8 D% @. R. O
% T/ v3 G' W/ H) d! h) c转载自flydream0
" i& L( s( G* }0 B) e+ k7 e8 O/ R1 s6 H- ~( ]9 D) A
7 O& D1 |" Q: b+ P6 ^& b% _, h
/ Y1 |# n+ R$ [& C; m- o) u2 I/ x, `0 [+ G
/ g0 ^: q7 z% @( j6 a: q3 ], |' D% F4 R1 S- J
" k5 E* `6 o3 N( w; c% t
+ w0 M5 h" f; S; H/ J; D" f
1 m! \2 N r. a v9 p+ c! Q5 F6 `2 e V' k2 C
1 A. n# W% v! }* B' b* {# n o1 r
$ q* Z# S. v) b% c, A+ X" h
& j) E8 J& }! |& M+ @ |
好的,已经进行一下调整了。
已经调整了一下哦
这个应该就是官网提供的