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

【经验分享】 STM32F412擦除内部FLASH时间过长

[复制链接]
STMCU小助手 发布时间:2022-1-9 20:00
1 前言     
3 y4 q. C) B2 t, p: Y0 v3 e  客户反馈在使用STM32F412的时候,擦除sector 8~11发现时间过长,从而导致意外触发IWDG复位。0 Y4 W/ F; j; _# V, z5 m  t5 s0 ?) f

/ S1 s) [2 q( Q9 A8 R( G7 m2 问题分析
* ?* R% h4 _. z1 c& D0 I8 ^8 {6 n6 E4 W2.1 问题详情
* T" C- E; z$ N- ^6 T     通过与客户邮件和电话沟通,了解到客户主要是想使用内部FLASH暂时保存IAP升级时的程序数据,在IAP升级的过程中,需要首先擦除内部FLASH中一块足够大的空间,然后再写入升级数据。客户的工程中有使用到IWDG,喂狗间隔大约1.5S,客户的通过SysTick的方式计算出擦除Sector8大约需要2ms,因此认为若一次擦除sector8~11大约需要8ms,于是在代码中一次性擦除sector8~11后最后再来喂狗,但是,这样会触发IWDG复位,这个与预期不一致,固此产生疑问。; ]' e0 H1 w7 B* X+ V. h3 l- Z. Q

7 I9 y& F% l  @0 g7 `2.2 问题重现
* e  v* k; S% n2 F# [6 Z      使用NUCLEO-F412ZG板尝试重现客户问题,主要代码如下:
  1. int main(void)6 V  [  u5 @8 }2 ]
  2. {
    ; t/ w# H7 H1 i3 [+ q
  3.   /* USER CODE BEGIN 1 */+ y) |1 _$ y. ?& C
  4. uint32_t beginTick =0,endTick =0;3 R; b; ?1 F. ?, v4 [9 t
  5. uint32_t curSysTick=0,endSysTick =0;
    : O0 P% A( O% n- m8 L
  6.   /* USER CODE END 1 */
    7 x3 V1 X' ^( [* H8 w! i
  7.   /* MCU Configuration----------------------------------------------------------*/: J" I% S7 l6 B5 J9 o2 s7 g
  8.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    6 v  {+ G1 i( C8 B& w
  9.   HAL_Init();
    ! P& m0 f7 M) O4 n. p
  10.   /* Configure the system clock */2 X& ]; E2 P8 }3 S  T( g
  11.   SystemClock_Config();  r& d+ Z/ m' A# O  X) m
  12.   /* Initialize all configured peripherals */  I9 `# I' W9 f2 D
  13.   MX_GPIO_Init();
    $ t9 {& J5 s7 \- u" e
  14.   MX_IWDG_Init();1 l1 w9 P9 U; M1 `
  15.   /* USER CODE BEGIN 2 */" w, \( u9 E! h6 T/ x7 t
  16. if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST) != RESET) //如果是看门狗复位
    ; Q" o! R0 `' H4 n+ J1 l; O
  17.   {
    0 u' V* v8 ?4 T6 s) t
  18.     /* Clear reset flags */
    # V* s3 y" f3 R4 `# d* F* E
  19. HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7,GPIO_PIN_SET);  F3 J* N+ S" o  L$ C( _7 x
  20.     __HAL_RCC_CLEAR_RESET_FLAGS();3 |1 h% x( v4 J' i
  21. Error_Handler();  ~4 I9 B" v) ]( w' D
  22.   }
    & Y3 ]. `1 z+ P9 H6 n$ z5 _2 x
  23.     HAL_FLASH_Unlock();* i9 \" {6 |/ V: N% t" O$ F
  24.   /* Fill EraseInit structure*/$ o2 s4 f. A4 f9 }
  25.   EraseInitStruct.TypeErase     = FLASH_TYPEERASE_SECTORS;+ V4 {- l0 C, L" [& y6 S
  26.   EraseInitStruct.VoltageRange  = FLASH_VOLTAGE_RANGE_3;$ l) q1 u. [8 j) |* ^( y
  27.   EraseInitStruct.Sector        = FLASH_SECTOR_8;) ^& x, x$ R) O: K! }" X  i' Q
  28.   EraseInitStruct.NbSectors     = 1;
    $ h; U% ]* n( n$ l
  29. //  if(HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError) != HAL_OK)0 i( G" t, K9 f" \+ X
  30. //  {% |, {; R! v* d( J* E
  31. //      Error_Handler();) V* T) p& ~" p9 h
  32. //  }
    * Z9 o/ v; O1 c1 A0 l: U
  33. beginTick =HAL_GetTick();0 Z9 D1 }3 {3 D
  34. HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_SET);8 i1 a+ \2 ]9 u* W- n) s
  35. curSysTick =SysTick->VAL;+ Z3 B/ i: T+ ~( r6 ?$ u0 _
  36. if(HAL_FLASHEx_Erase_IT(&EraseInitStruct)!= HAL_OK) //擦除sector8
    - v; ?  Z& i6 U  ^$ g+ D
  37. {* w1 z' Q$ U6 B. I
  38.     Error_Handler();
    . o" I  j: d; W# f2 y
  39. }. R# ?, c' H6 |$ G
  40. endSysTick =SysTick->VAL; // curSysTick, endSysTick保存着SysTick寄存器的值
    7 W/ F3 \; K3 n7 Z2 ^9 B0 l: ]* A" K
  41. HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_RESET); //PC8波形表示擦除FLASH的时间间隔
    ' p6 ~2 e1 k* C
  42. endTick =HAL_GetTick();     // beginTick, endTick保存着全局变量Tick的值  Z# ~( a4 E5 l4 g0 K2 a- z
  43. g_TickCount =endTick -beginTick; //变量Tick的时间差2 ]. T$ G. J% `8 ?# O9 T1 v) p4 @; p
  44. HAL_IWDG_Refresh(&hiwdg);
    ' ~$ M2 p9 q' Y* a  D
  45.   /* USER CODE END 2 */" t& {) c- K+ i- P
  46.   /* Infinite loop */
    & G- A& l2 K; J9 `, B' [
  47.   /* USER CODE BEGIN WHILE */
    , ~1 k; ?/ V6 |8 G1 j' {2 \' g
  48.   while (1)
    + H/ H2 V& |/ k( R8 c0 h
  49.   {! F7 ?$ k0 A; [5 t" n: q6 t. j
  50.   /* USER CODE END WHILE */
    . S1 r2 O/ ]& N, {
  51.   /* USER CODE BEGIN 3 */
    9 g$ t" x$ V& W) i* Y
  52. if (HAL_IWDG_Refresh(&hiwdg) != HAL_OK)
    + b" m3 `5 y/ J
  53.     {- i4 j7 |$ f+ u( i! M
  54.       /* Refresh Error */! o' a" n! X, L' p3 S
  55.       Error_Handler();
    ) [7 O: y- D3 H4 L2 \- r# K2 Q
  56.     }9 j5 O) N3 X" k$ M4 B( q8 \
  57. HAL_Delay(10);3 ?: ^9 @) L- A) L
  58.   }: i3 }! \0 x% b# o2 `7 j
  59.   /* USER CODE END 3 */
    * N+ ?9 d& r% M4 m
  60. }
复制代码

6 A4 @7 i' R+ r( I& {   此外,同时在每个SysTick中断输出一个波形,用来检测SysTick是否正常:

. K2 X& |7 O% `: x
  1. void HAL_SYSTICK_Callback(void)* |! ^! _5 |; o/ g5 O" U& h' g
  2. {
    / Z" ~( z0 C# m9 X3 _3 u' W/ K
  3.     HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_11);//用PA11来检测SysTick波形/ k7 p7 b" ~+ U2 f# m: a
  4. }
复制代码
& u' q' z9 f3 g  W' n& i1 {* u$ [
   
' s- E& L1 n/ }7 w" \: o   最终得出如下波形* |+ a' ?% m" b! K0 y$ K
图1 擦除FLASH时间与SysTick输出波形
" Z+ Q" K( E$ u) G' w/ X$ Z" A, z+ P
        如上图,黄色为PC8脚波形,表示擦除FLASH的时间,下面蓝色为PA11管脚波形,表示SysTick波形。! K7 t2 {6 G9 M. U- G. `
   从上图可以看出擦除sector8所需要的时间是800ms,这个与客户认为的2ms是不一致的。查看STM32F412的数据手册,在第6.3.12节中可以看到如下信息:
: n$ v4 }8 f1 E' [# R( F

1 r  i/ X6 i( e: l1 C' I$ t8 }
图2 擦除FLASH扇区所需要的时间

( G6 z; X6 V+ W+ n, J! p6 W  h        如上图,在PSIZE=32时,擦除一个128K的扇区需要大概1S(典型值)的时间,而我们从图1中实际测出的为800ms,这个基本相差不大,单与客户认为的2ms相去甚远,基本上我们认为这里的800ms是正确的结果,但是这个又是什么原因导致客户通过SysTick测出的值是错误的呢?5 z; P* i7 j. L5 S) R0 z+ V
7 |: ^3 g" [6 S/ N% C# l- Y
   实际上,从图1我们也可以看出,在擦除FLASH的期间,SysTick是没有波形的(见图1下面蓝色波形),同时在参考手册3.5节中有如下信息:2 _3 o* O- y& b: g' O3 j9 D! V* _% ~
( R3 @+ j+ |. f4 q' q) I; m2 Q' \
图3 参考手册中关于擦除扇区的描述

: j4 H" |$ ^( L. Y! N) r% B      这句话的意思是说,在擦除FLASH的期间,若尝试读取FLASH,则会被暂停,实际这个”读取”是指取指,我们都知道,程序的执行首先得通过从FLASH中通过I-BUS取出指令后才可以执行。这里SysTick之所以会被暂停掉,就是因为在擦除FLASH期间,为了执行SysTick中断例程,内核会尝试从FLASH取指,从而导致被暂停掉,进而全局变量uwTick的值没有机会增加。下图是调试界面:) f2 V& Y1 g! T* r4 V/ }( n! b* b
* u$ O1 l- y: S9 C# V" X
图4 调试
) d5 A( B# X1 W, i6 W, z# E: `) E; ?
       如上图,在执行擦除扇区后,SysTick的全局变量uwTick就增加了1,但SysTick在内核中的寄存器还是有变化的。这个与我们的预想一致。; F3 G  K* i& j0 L* t

1 n- j  K6 k, r" p* E   最后客户通过每擦除一个扇区喂一次狗的方式解决了问题,而在此期间不能依靠SysTick的值来计算时间。
+ x7 f" J/ t- P) o1 |
% G& q' @# H9 j; r$ O0 m
3 结论( S! [' X/ L/ H! }
       在擦除FLASH期间,取指操作会被暂停掉,且SysTick所对应的全局变量uwTick值是不会增加的。另外,通过函数HAL_FLASHEx_Erase_IT()来执行擦除FLASH和通过函数HAL_FLASHEx_Erase()所花费时间没有差别,只不过前者在擦除完成后会产生一个中断,而后者没有。可以通过外设RTC来计算擦除FLASH的时间,从而
% B6 p0 B5 b, ?
3 G. E/ F" I) @6 i' v; S
收藏 评论0 发布时间:2022-1-9 20:00

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版