请选择 进入手机版 | 继续访问电脑版

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

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

[复制链接]
STMCU小助手 发布时间:2022-1-9 20:00
1 前言     
* ]+ u; l" d; b2 H  客户反馈在使用STM32F412的时候,擦除sector 8~11发现时间过长,从而导致意外触发IWDG复位。! \1 o6 u6 \0 V( ?7 }$ O

+ l. t- p3 {! v  r/ f) V2 问题分析
* V, D: U1 i* x. H% A/ D; M7 Z& j2.1 问题详情
( l- t% Y( [* G+ S, ~8 t$ x. I7 k0 H     通过与客户邮件和电话沟通,了解到客户主要是想使用内部FLASH暂时保存IAP升级时的程序数据,在IAP升级的过程中,需要首先擦除内部FLASH中一块足够大的空间,然后再写入升级数据。客户的工程中有使用到IWDG,喂狗间隔大约1.5S,客户的通过SysTick的方式计算出擦除Sector8大约需要2ms,因此认为若一次擦除sector8~11大约需要8ms,于是在代码中一次性擦除sector8~11后最后再来喂狗,但是,这样会触发IWDG复位,这个与预期不一致,固此产生疑问。
6 B! \: D; M, Z1 ]& Z/ z, V% b. L
; w* x0 y- g/ _2.2 问题重现4 K, s9 ^4 e) i: L
      使用NUCLEO-F412ZG板尝试重现客户问题,主要代码如下:
  1. int main(void). W' |+ V" x, V. w( G1 n8 t) M; ^# x
  2. {
      W! s9 L3 M. J, G+ y8 p* w7 Q
  3.   /* USER CODE BEGIN 1 */- g6 {, k6 r. |2 `, ]3 f0 s9 n
  4. uint32_t beginTick =0,endTick =0;" Z' t9 }0 i- X9 Z) A
  5. uint32_t curSysTick=0,endSysTick =0;
    , b5 W; D2 j% o( o4 }
  6.   /* USER CODE END 1 */
    2 X' ]+ d# p$ _* R/ T) Q
  7.   /* MCU Configuration----------------------------------------------------------*/
    & j# T8 _  r9 `$ L
  8.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    ( g8 q4 i1 w  W: V/ a% p
  9.   HAL_Init();3 j+ ~, U) g$ `
  10.   /* Configure the system clock */
    1 |& S0 }3 l$ O2 p2 Y2 W/ v4 K
  11.   SystemClock_Config();' Y7 u( ~4 y1 o5 S- ~
  12.   /* Initialize all configured peripherals */2 x( z. K8 _4 i
  13.   MX_GPIO_Init();: u. j4 F. b# C# L. U" Q* [$ s6 a
  14.   MX_IWDG_Init();# Y) c7 w$ L- ^! o
  15.   /* USER CODE BEGIN 2 */( h& \6 p$ h2 S6 h) u4 u1 e
  16. if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST) != RESET) //如果是看门狗复位
    4 e3 [  T. J, f4 `: O1 h
  17.   {, u7 T! m8 R, k1 T! l* h
  18.     /* Clear reset flags */
    ' |$ k) T# Y( F2 z. \$ S3 n5 \3 ?
  19. HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7,GPIO_PIN_SET);
      }$ i# ~, N+ m- w! i" q+ z" p
  20.     __HAL_RCC_CLEAR_RESET_FLAGS();
    - q+ U, R4 l3 `" `. n
  21. Error_Handler();3 e+ H1 n& l2 S) X
  22.   }1 k4 K5 c6 s+ o/ R. J
  23.     HAL_FLASH_Unlock();
    1 l$ g  F! g* U! H
  24.   /* Fill EraseInit structure*/
    # W6 t6 a/ h" W7 M9 W
  25.   EraseInitStruct.TypeErase     = FLASH_TYPEERASE_SECTORS;8 g+ n0 P. r( B
  26.   EraseInitStruct.VoltageRange  = FLASH_VOLTAGE_RANGE_3;7 z/ V$ V( d; M4 a1 L
  27.   EraseInitStruct.Sector        = FLASH_SECTOR_8;; T% Y( k. R" M; F  G' d6 c
  28.   EraseInitStruct.NbSectors     = 1;& }( N0 O4 f, n0 l+ Q4 O
  29. //  if(HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError) != HAL_OK)
    8 e3 ~8 h6 [/ [9 u) I7 ?
  30. //  {8 K- v; c, o! M
  31. //      Error_Handler();
    , q7 M* O' ~2 _9 ^
  32. //  }
    ) ^0 A( |" W" T3 Q+ ^  d
  33. beginTick =HAL_GetTick();3 U; r2 O9 l5 S/ Z$ p8 i, }1 b8 ~5 h
  34. HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_SET);
    1 K& n/ U8 r/ [. @1 \
  35. curSysTick =SysTick->VAL;
    / C  p0 B! n% V3 L
  36. if(HAL_FLASHEx_Erase_IT(&EraseInitStruct)!= HAL_OK) //擦除sector8
    ' A1 v, {& W6 _0 Q2 S
  37. {
    0 H6 M' B/ U9 o/ ^
  38.     Error_Handler();
    # N$ C& b6 F0 C5 j
  39. }$ n1 c& _2 P% o7 U6 A( s
  40. endSysTick =SysTick->VAL; // curSysTick, endSysTick保存着SysTick寄存器的值
    + C9 R9 E3 H  D# Z4 f9 P  o0 S0 m
  41. HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_RESET); //PC8波形表示擦除FLASH的时间间隔
    ! P/ ^7 ^8 r# V# L7 I# }
  42. endTick =HAL_GetTick();     // beginTick, endTick保存着全局变量Tick的值
    6 [0 \# |1 ]$ ]6 f5 @1 s. J: c
  43. g_TickCount =endTick -beginTick; //变量Tick的时间差' l5 G! M. U* F7 L
  44. HAL_IWDG_Refresh(&hiwdg);
    1 `: m% X8 Z; Q5 ~+ l
  45.   /* USER CODE END 2 */
    - ]" m3 b  c# N4 f
  46.   /* Infinite loop */
    0 G1 Q! Z4 U; y0 V' k- ]
  47.   /* USER CODE BEGIN WHILE */
    7 d2 Q2 U9 |7 ]9 I$ J7 \7 w
  48.   while (1)
    2 C2 i0 T, }7 s' K! M! ^8 D
  49.   {
    / n3 O4 Y+ S2 M( z- @
  50.   /* USER CODE END WHILE */2 o! v* |2 a! W( @" V! n
  51.   /* USER CODE BEGIN 3 */* P- {0 l9 y! _$ i% Y# |* p' M
  52. if (HAL_IWDG_Refresh(&hiwdg) != HAL_OK)
    ; B. u- K- o- f7 h
  53.     {! m' P6 @6 [3 t" X- K( X8 [& N) {
  54.       /* Refresh Error */
    - X9 B) x; A4 Y  {; n; F& p9 l
  55.       Error_Handler();& U2 Y0 C' G1 W
  56.     }3 K* {4 Y9 K  G6 E& v0 E9 t( b
  57. HAL_Delay(10);7 A4 g6 X8 d) y! @
  58.   }# |4 a# i7 {: W' a, \8 A  B
  59.   /* USER CODE END 3 *// N+ F! j4 n, W7 _% r
  60. }
复制代码

. {' }/ s0 C: i5 O5 K( z   此外,同时在每个SysTick中断输出一个波形,用来检测SysTick是否正常:

8 {% l  E- r5 Q0 K! ~
  1. void HAL_SYSTICK_Callback(void)
    4 X% u! [) ]* l4 f; S
  2. {- J1 C  e8 [) }. b0 a
  3.     HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_11);//用PA11来检测SysTick波形7 P! N6 G8 U/ d0 O/ o
  4. }
复制代码
2 K, \' j: V! y7 b
   
. M& S% W- |& Z& B   最终得出如下波形) `( o6 d# ?, f, I) \2 B$ _
图1 擦除FLASH时间与SysTick输出波形

& M+ m7 o! ]% _, [1 q8 I        如上图,黄色为PC8脚波形,表示擦除FLASH的时间,下面蓝色为PA11管脚波形,表示SysTick波形。- m+ j  B& C) U- F6 i+ c
   从上图可以看出擦除sector8所需要的时间是800ms,这个与客户认为的2ms是不一致的。查看STM32F412的数据手册,在第6.3.12节中可以看到如下信息:
  g+ n" y% S; w" a4 w$ V6 i. W

- `6 N3 o2 d9 p" j; O7 ^
图2 擦除FLASH扇区所需要的时间

0 T7 u, r- }; ~  b, C        如上图,在PSIZE=32时,擦除一个128K的扇区需要大概1S(典型值)的时间,而我们从图1中实际测出的为800ms,这个基本相差不大,单与客户认为的2ms相去甚远,基本上我们认为这里的800ms是正确的结果,但是这个又是什么原因导致客户通过SysTick测出的值是错误的呢?3 _# n# T& I0 U8 [

6 O0 d" a) J  @5 j- O! {: b# h   实际上,从图1我们也可以看出,在擦除FLASH的期间,SysTick是没有波形的(见图1下面蓝色波形),同时在参考手册3.5节中有如下信息:
9 F& e3 z3 z- v3 V- W! }( K
4 ~& r6 U/ u5 H& g/ R- M
图3 参考手册中关于擦除扇区的描述
) \6 a- ]  n* \  k; F: o" e/ J
      这句话的意思是说,在擦除FLASH的期间,若尝试读取FLASH,则会被暂停,实际这个”读取”是指取指,我们都知道,程序的执行首先得通过从FLASH中通过I-BUS取出指令后才可以执行。这里SysTick之所以会被暂停掉,就是因为在擦除FLASH期间,为了执行SysTick中断例程,内核会尝试从FLASH取指,从而导致被暂停掉,进而全局变量uwTick的值没有机会增加。下图是调试界面:
. ^+ x( L5 [0 _4 t; R) A: r. H& ]. ~
图4 调试
$ o" }$ E' v4 U4 \
       如上图,在执行擦除扇区后,SysTick的全局变量uwTick就增加了1,但SysTick在内核中的寄存器还是有变化的。这个与我们的预想一致。
% S4 W8 P3 _$ _( a0 A; o* |. A5 c; g) X# c1 A9 H
   最后客户通过每擦除一个扇区喂一次狗的方式解决了问题,而在此期间不能依靠SysTick的值来计算时间。
% D/ p. a7 W3 B3 G- q8 b

! m* K3 U, @' S" \  f: a3 结论
' q. z3 P. F& B4 U1 M0 r       在擦除FLASH期间,取指操作会被暂停掉,且SysTick所对应的全局变量uwTick值是不会增加的。另外,通过函数HAL_FLASHEx_Erase_IT()来执行擦除FLASH和通过函数HAL_FLASHEx_Erase()所花费时间没有差别,只不过前者在擦除完成后会产生一个中断,而后者没有。可以通过外设RTC来计算擦除FLASH的时间,从而

1 N8 I) T9 f7 h& J' E: a5 }% h# P4 g$ Z6 W
收藏 评论0 发布时间:2022-1-9 20:00

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版