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

【经验分享】STM32掉电时存数据到FLASH

[复制链接]
STMCU小助手 发布时间:2022-1-30 01:00
一、STM32FLASH简介
  不同的STM32它的FLASH大小也是不一样的,分为大、中、小容量,容量由16K到1024K不等。这次实验用的开发板FLASH容量大小为128K。
  STM32的闪存模块由:主存储器、信息块和闪存存储器接口寄存器三部分组成。
  主存储器:该部分主要是用来存放代码和数据常数,被划分为128页,每页1K字节(小容量产品也是每页1K字节,大容量为每页2K字节)。主存储器的起始地址就是0X08000000, B0、B1都接GND的时候,就是从0X08000000开始运行代码的。
  信息块:该部分分为2个小部分,其中启动程序代码,是用来存储ST自带的启动程序,用于串口下载代码,当B0接V3.3,B1接GND的时候,运行的就是这部分代码。用户选择字节,则一般用于配置写保护、读保护等功能。
  闪存存储器接口寄存器:该部分用于控制闪存读写等,是整个闪存模块的控制机构。 
  对主存储器和信息块的写入由内嵌的闪存编程/擦除控制器(FPEC)管理;编程与擦除的高电压由内部产生。
  在执行闪存写操作时,任何对闪存的读操作都会锁住总线,在写操作完成后读操作才能正确地进行;既在进行写或擦除操作时,不能进行代码或数据的读取操作
闪存的读取
  内置闪存模块可以在通用地址空间直接寻址,任何32位数据的读操作都能访问闪存模块的内容并得到相应的数据。读接口在闪存端包含一个读控制器,还包含一个AHB接口与CPU衔接。这个接口的主要工作是产生读闪存的控制信号并预取CPU要求的指令块,预取指令块仅用于在I-Code总线上的取指操作,数据常量是通过D-Code总线访问的。这两条总线的访问目标是相同的闪存模块,访问D-Code将比预取指令优先级高。
  这里要特别留意一个闪存等待时间,因为CPU运行速度比FLASH快得多,STM32F103的FLASH最快访问速度≤24Mhz,如果CPU频率超过这个速度,那么必须加入等待时间,比如我们一般使用72Mhz的主频,那么FLASH等待周期就必须设置为2,该设置通过FLASH_ACR寄存器设置。
闪存的编程和擦除
  编程过程:
  ·检查FLASH_CR的LOCK是否解锁,如果没有则先解锁
  ·检查FLASH_SR寄存器的BSY位,以确认没有其他正在进行的编程操作
  ·设置FLASH_CR寄存器的PG位为’1’
  ·在指定的地址写入要编程的半字
  ·等待BSY位变为’0’
  ·读出写入的地址并验证数据
  擦除过程(页擦除)
  ·检查FLASH_CR的LOCK是否解锁,如果没有则先解锁
  ·检查FLASH_SR寄存器的BSY位,以确认没有其他正在进行的闪存操作
  ·设置FLASH_CR寄存器的PER位为’1’
  ·用FLASH_AR寄存器选择要擦除的页
  ·设置FLASH_CR寄存器的STRT位为’1’
  ·等待BSY位变为’0’
  ·读出被擦除的页并做验证
二、软件实现
  flash.c文件
  1. #include "flash.h"
    ! {$ v9 L5 t$ z3 l' m4 T
  2. #include "delay.h"
    5 x8 c9 w8 r; g
  3. #include "usart.h"
    / J+ }9 y! b0 s/ @; o* e7 L

  4. ; y. b4 }: w0 _; B- B" S
  5. /***flash解锁*****/( Q/ Y$ t1 N1 y+ a. J0 W
  6. void STMFLASH_Unlock(void)
    ! I% H2 _5 P0 x
  7. {
    6 k- M( l4 v/ x9 t, o: @8 Y1 D4 [
  8.   FLASH->KEYR=FLASH_KEY1;                                        //写入解锁序列4 c7 J9 J9 z- a& u  O! Z) t  M
  9.   FLASH->KEYR=FLASH_KEY2;
    & `% q+ P! K- F8 V% p4 `
  10. }
    2 N, [4 A8 d$ O. r4 f

  11. % e3 u! D. z, `' B
  12. //flash上锁' Y$ }- N2 M; h# ?( K6 ~
  13. void STMFLASH_Lock(void)
    ' p* V( E7 u" g+ z1 ^4 z
  14. {
    * d. D/ R$ t* v9 V+ m
  15.   FLASH->CR|=1<<7;                                              //上锁
    7 `3 d- R/ ?0 T% ^4 R1 o
  16. }2 A- c% {+ E& m1 O
  17. " E5 m$ m1 u3 G0 Y
  18. //得到FLASH状态7 ?9 \! U$ X8 W; `$ L# B7 F
  19. u8 STMFLASH_GetStatus(void)8 ?$ `/ s, R) w$ R
  20. {   
    ' V" N3 R) P% y' D: e/ s
  21.    u32 res;         
    - f4 j( n; h2 t( w5 r
  22. 0 y" t+ Y6 l1 u0 M& F/ f
  23.    res=FLASH->SR;0 U" N& M: H# A" Y/ x
  24.    if(res&(1<<0))return 1;                                          //忙
    - y" i; \$ B% K: t8 C* a
  25.    else if(res&(1<<2))return 2;                                     //编程错误
      s5 f- O0 x/ X. p* g
  26.    else if(res&(1<<4))return 3;                                     //写保护错误
    3 i+ C8 A% _  {
  27.    return 0;                                                        //操作完成0 p9 t9 @4 a, S; M
  28. }0 L* t# J& s- J$ \& J
  29. 8 E& p6 D4 V9 z! I& }- U' ^' V/ W
  30. //等待操作完成: y' R3 M( i( A7 j; R
  31. //time:延时长短) @7 n! ^% L7 O3 g- H- b! J7 p4 ^
  32. //返回值:状态.
    * M7 B" v3 h6 x+ _
  33. u8 STMFLASH_WaitDone(u16 time)/ k) X! t  b& [
  34. {( q0 H; s+ w- c0 Q9 m. _2 m. p
  35.    u8 res;
    2 u3 L' @/ {+ R6 z; X3 }

  36. 6 \- i, H0 @/ [/ r2 \7 o2 }1 K
  37.    do
    # N, m+ z+ _( Z0 i3 p  {
  38.    {
    5 y& V, ]  s8 z; V2 Z! D
  39.       res=STMFLASH_GetStatus();2 y0 _2 d. Y1 P" Y7 ?  Y
  40.       if(res!=1)break;                                            //非忙,无需等待,直接退出.
    3 c! h+ ~/ [# W
  41.       Delay_us(1); time--;            
    5 a6 U+ |  g2 G' }! D* O
  42.     }while(time);
    $ g9 ^6 ?- m% \- ?% M- O6 S0 z8 y8 f
  43.     if(time==0)res=0xff;                                           //TIMEOUT
    ; E. t- k( [' b! ~% o8 m
  44.     return res;
    5 d7 e) q9 }: Y, u4 v4 q
  45. }
    $ S  t) C2 q# j. p
  46. $ i4 [' E5 I  V
  47. //擦除页
    ( Q3 X( q( K. U  I7 B
  48. //paddr:页地址% u4 U) [' n) D
  49. //返回值:执行情况/ [# h- a) u/ u( b+ U9 h
  50. u8 STMFLASH_ErasePage(u32 paddr)
    ! F' l$ |9 N/ S' }; b
  51. . H( ?4 y$ g+ }8 T6 N5 B6 m
  52. {# Y+ |3 l, c3 ]; y
  53.        u8 res=0;
    , X; l* s! e% d

  54.   u+ _' @( u- M) @1 O
  55.        res=STMFLASH_WaitDone(0X5FFF);                              //等待上次操作结束,>20ms   
    ) n8 ?, O4 C0 a
  56.        if(res==0)% ?3 n) w( l& c* s! c
  57.        {
    + V' a, e6 I) K& j9 y* T6 ~" l% S
  58.               FLASH->CR|=1<<1;                                      //页擦除% q# K0 c1 S* \4 N& W
  59.               FLASH->AR=paddr;                                      //设置页地址
    * T, u( M* ?: d
  60.               FLASH->CR|=1<<6;                                      //开始擦除           & T' \* _( K, m7 i0 e
  61.               res=STMFLASH_WaitDone(0X5FFF);                       //等待操作结束,>20ms
    $ y2 n' E6 A5 J1 N- c# @! r
  62.               if(res!=1)                                             //非忙( ^' q$ Q  B* w2 |+ p
  63.               {
    5 Q# u3 K1 _: L2 `, q% M. w& q) @. z8 C
  64.                      FLASH->CR&=~(1<<1);                           //清除页擦除标志.& v1 g. G. o( Q7 N9 {
  65.               }' E+ |$ h2 y- t' }$ k: k2 M
  66.        }2 Z) G$ T9 M& O& `
  67.        return res;
    6 M& d, a3 z+ m/ O  o/ U, }$ n8 U1 F
  68. }
    & S* [( h% Z/ v0 [0 l
  69. + b: H6 V) `" `& H* w& X5 X
  70. //读出指定地址的半字(16位数据)
    * y3 E6 ~" I' Z
  71. //faddr:读地址(此地址必须为2的倍数!!). _- q) Y& p8 R6 y  W
  72. //返回值:对应数据.' o2 w  \" x4 C1 N- x
  73. u16 STMFLASH_ReadHalfWord(u32 faddr)
    ! h. ~/ _. J3 M1 \* Z9 V' |
  74. {/ a% J8 z; `) i3 {; y
  75.     return *(vu16*)faddr; 4 a0 T" D. P8 b, u2 A
  76. }
    9 B$ }5 e2 ~. [. X9 Z
  77. #if STM32_FLASH_WREN                                               //如果使能了写   & R. v( d* U* H" j! T
  78. //不检查的写入4 f; [! @1 P" c
  79. //WriteAddr:起始地址! R( S. [1 U" f) m9 z
  80. //pBuffer:数据指针
    . V' u+ S, m' l% }! C8 r
  81. //NumToWrite:半字(16位)数   8 ?- C4 b( X* P# D
  82. void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)   * d" P0 F3 w, ?4 A6 Q! }! h9 r) b$ z
  83. {                       0 j! V+ J( s" g1 |' |. j/ {
  84.     u16 i;
    - ?0 q. K0 d( B* M6 h
  85.     for(i=0;i<NumToWrite;i++)& n6 @& _' L! m
  86.     {
    9 [7 T* t5 S! d9 r9 d: i; p, T
  87.         FLASH_ProgramHalfWord(WriteAddr,pBuffer[i]);
    / L1 p! s8 H! q7 s/ H. ?
  88.         WriteAddr+=2;                                           //地址增加2.6 R% P+ H' X# J4 P( R; K
  89.     }  ) }* K: b( R( k
  90. } 3 J7 A) I' s4 b8 B# }2 m
  91. //从指定地址开始写入指定长度的数据
    $ q& ?5 d2 J! t* x; ~, i6 q
  92. //WriteAddr:起始地址(此地址必须为2的倍数!!)
    7 h4 n! m3 Y, D
  93. //pBuffer:数据指针  f9 [- F* m3 R
  94. //NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
    0 K* b3 C0 d; G1 [3 o1 O7 c# v8 t
  95. #if STM32_FLASH_SIZE<256' r! E4 K- B/ p
  96. #define STM_SECTOR_SIZE 1024                                       //字节5 v" Q1 `5 a# Y2 D% U4 t8 [
  97. #else
    3 |9 _8 F" W  A) L( v
  98. #define STM_SECTOR_SIZE    2048
    - t" Q7 S9 q3 g) `5 o) ~0 O( d
  99. #endif         
    5 z7 k) y# N- \+ z6 _
  100. u16 STMFLASH_BUF[STM_SECTOR_SIZE/2];                               //最多是2K字节5 Q8 N& |7 }0 n: h! T

  101. ' y: G  S+ x; o+ a6 }# y
  102. void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
    2 V) S' m5 M! t$ X" v" o! k
  103. {5 V( O2 o2 r3 q  {# X
  104.     u32 secpos;                                                     //扇区地址3 i& S2 v4 X3 ]' j0 i
  105.     u16 secoff;                                                     //扇区内偏移地址(16位字计算)
    7 n. r: ~' h1 N3 e& {( t- J: I
  106.     u16 secremain;                                                  //扇区内剩余地址(16位字计算)      
    ' j4 c, F; U6 E, G  b
  107.      u16 i;    ; @6 I# I) ^. o4 q# k( g9 Q9 a$ u
  108.     u32 offaddr;                                                    //去掉0X08000000后的地址
      k" W2 X" l* A! ]8 N. L
  109.    
    % R5 V  \9 [) s; ~9 \
  110.     if(WriteAddr<STM32_FLASH_BASE||(WriteAddr>=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)))return;//非法地址6 |" v9 p3 K0 t, k. q
  111.     FLASH_Unlock();                                                 //解锁
    $ i5 X9 I$ c4 M
  112.     offaddr=WriteAddr-STM32_FLASH_BASE;                             //实际偏移地址.
    # ?4 u" n$ f0 s- R2 b- {
  113.     secpos=offaddr/STM_SECTOR_SIZE;                                 //扇区地址  0~127 for STM32F103RBT6
    . i) I3 r! _' q& J
  114.     secoff=(offaddr%STM_SECTOR_SIZE)/2;                             //在扇区内的偏移(2个字节为基本单位.)% B" _. G9 i2 S6 Y" h/ D" t
  115.     secremain=STM_SECTOR_SIZE/2-secoff;                             //扇区剩余空间大小  
    4 H0 A8 m5 \, |
  116.     if(NumToWrite<=secremain)secremain=NumToWrite;                 //不大于该扇区范围
    ' d+ C8 Y: }5 m
  117.     while(1)   k2 I. J: V( D6 u2 l  o
  118.     {    $ ^( k, A! T0 X0 [& ~
  119.         STMFLASH_Read(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//读出整个扇区的内容  Z, P  c( k" e% R% K8 _1 m- t
  120.         for(i=0;i<secremain;i++)                                   //校验数据- `% Q) k3 E  w4 o7 f
  121.         {
    3 f. z7 N) p- b4 P
  122.             if(STMFLASH_BUF[secoff+i]!=0XFFFF)break;              //需要擦除      & T- \! c1 k3 N* N' W, l8 A1 M/ W( l
  123.         }3 d$ H( b- y; u: K2 `8 H
  124.         if(i<secremain)                                            //需要擦除" k/ i8 I2 x5 U& K( F. K+ A/ k" r8 N
  125.         {
    2 b9 ?* G' M' Y* \+ J
  126.             FLASH_ErasePage(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);               //擦除这个扇区
      F3 R  z3 u8 K, [; V
  127.             for(i=0;i<secremain;i++)                              //复制
    " _- i6 K2 Z+ k' S
  128.             {
    $ [1 C  D- `. v& P" k$ l3 p
  129.                 STMFLASH_BUF[i+secoff]=pBuffer[i];      
    : ?# D' D- t, e* c* H* i
  130.             }
    5 g5 T2 j6 v, h. m. F" y: [. M! u
  131.             STMFLASH_Write_NoCheck(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//写入整个扇区3 N9 H+ n0 W: j6 Y) ^
  132.         }else STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain); //写已经擦除了的,直接写入扇区剩余区间.                    : B+ n+ Y3 M' r" o4 d- C
  133.         if(NumToWrite==secremain)break;                            //写入结束了
    % P, U; b' z  ^' T
  134.         else                                                       //写入未结束, t" i9 O) o# i7 o: z  D
  135.         {
    8 m  _) a5 f7 r  q% p- K3 b  u  ^) B
  136.             secpos++;                                              //扇区地址增1
    , i% \- V% I3 H- z3 t) _
  137.             secoff=0;                                              //偏移位置为0      
    + \1 z) p- `- h
  138.                pBuffer+=secremain;                                 //指针偏移" g$ |; x  n" Z8 c! q$ n- _
  139.             WriteAddr+=secremain;                                  //写地址偏移       * {( z. W2 U7 h8 G8 b/ w( U
  140.                NumToWrite-=secremain;                              //字节(16位)数递减
    # I6 f  N" O- V7 v' A
  141.             if(NumToWrite>(STM_SECTOR_SIZE/2))secremain=STM_SECTOR_SIZE/2;//下一个扇区还是写不完* H/ h' H! t$ `& F2 G2 J
  142.             else secremain=NumToWrite;                             //下一个扇区可以写完了
    ; l$ T2 z6 s" s+ _8 j& c, x  D, C8 [
  143.         }     
    : R. A- p; g  ^* H9 B( q/ `4 o8 @
  144.     };   
    4 V& F0 ]6 m8 q& M( K+ T, N; \
  145.     FLASH_Lock();                                                  //上锁; u9 D. J3 y/ j2 v
  146. }
    ; j) z+ ?* w" \6 l
  147. #endif# d% H+ X2 ^, C+ E. F0 E, [

  148. ! o, b; I6 F" A$ E  H
  149. //从指定地址开始读取指定长度的数据
    . @4 f0 C" s( U$ ~+ h
  150. //ReadAddr:起始地址
    1 E' f$ h+ I7 y+ f( w5 t: }7 G
  151. //pBuffer:数据指针9 r( R6 m5 P& o" W& n
  152. //NumToWrite:半字(16位)数
    7 U: _0 b, P" R6 B) K. G7 H1 ]
  153. void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)) o  R! T! h0 I" q6 d% G) f
  154. {! j& H; b3 V8 r, A! @* \1 T- \
  155.     u16 i;
    0 l' d2 j3 ]( @- @! B! }
  156.     for(i=0;i<NumToRead;i++)
    6 r& P$ o: ]+ K1 U+ p- I) ]
  157.     {
    ) a6 |7 _! g% g7 r
  158.         pBuffer[i]=STMFLASH_ReadHalfWord(ReadAddr);               //读取2个字节.
    # D+ ]6 R- L( O/ G$ f( ?. A% c4 c
  159.         ReadAddr+=2;                                              //偏移2个字节. |; x* |" `3 S- L
  160.     }
    . q0 _. s7 W$ e/ x& u0 G7 y1 @
  161. }1 l3 m+ M0 ~8 P8 |" c; T
  162. 0 K6 k9 s4 C! ^9 T
  163. //////////////////////////////////////////////////////////////////////////////////////////////////////7 q( h8 F8 e# e
  164. //WriteAddr:起始地址/ o2 V# ~. J' |
  165. //WriteData:要写入的数据
    2 Y% ?8 [6 a7 D: C% R  F6 e$ I
  166. void Test_Write(u32 WriteAddr,u16 WriteData)       2 ]: ?. j) A3 c( f. Y4 Q
  167. {7 r9 d$ J& a+ u& ^& k: Q
  168.     STMFLASH_Write(WriteAddr,&WriteData,1);                       //写入一个字 : [8 x4 s* l# ^( g
  169. }
复制代码
) K8 {5 B; B0 x; a- G7 H$ s1 s/ R' Z
  flash.h文件
  1. #ifndef __FLASH_H__8 w5 _. T; A, R( ?$ S) j
  2. #define __FLASH_H__3 j9 T/ t+ Q5 i6 u6 J1 W
  3. #include <stm32f10x.h>
    : _! W2 L' ~/ u

  4. % G: s1 a) s% J& ?
  5. #define FLASH_KEY1               0X45670123( g: c. g; Z' O5 F. C
  6. #define FLASH_KEY2               0XCDEF89AB( C4 P: {* [, S9 F9 V+ s2 G: c! |

  7. . N- y4 U# U' r" h/ n7 h
  8. #define STM32_FLASH_SIZE 128                                 //所选STM32的FLASH容量大小(单位为K)
    : b" [1 O% y' d4 I, y
  9. #define STM32_FLASH_WREN 1                                       //使能FLASH写入(0,不使能;1,使能)
    ' H; {6 Q$ |4 ?
  10. //////////////////////////////////////////////////////////////////////////////////////////////////////( \6 [1 f/ a4 j
  11. 3 j- K0 j' t2 J; P/ |
  12. //FLASH起始地址  n; ]! B& C; m- o( o. @
  13. #define STM32_FLASH_BASE 0x08000000                         //STM32 FLASH的起始地址& k! s  E9 z6 Z2 l  ]9 b
  14. / _, V% ?- c! N) D, w: P

  15. , s  F, j4 \* m. S
  16. void STMFLASH_Unlock(void);                                        //解锁. F0 l6 {7 `: c- n. a# R
  17. void STMFLASH_Lock(void);                                       //上锁8 k3 V1 x* K8 S& e  V$ T
  18. u8 STMFLASH_GetStatus(void);                                       //获得状态
    % W* Y$ S: s( M8 v: g% Y
  19. u8 STMFLASH_WaitDone(u16 time);                                  //等待操作结束1 d8 F  d" Y3 l' m7 d* C* z
  20. u8 STMFLASH_ErasePage(u32 paddr);                                  //擦除页# @* o; i" M9 R+ b# i# e7 Q
  21. u16 STMFLASH_ReadHalfWord(u32 faddr);                               //读出半字  , S+ P/ m8 k' l7 k3 E
  22. void STMFLASH_WriteLenByte(u32 WriteAddr,u32 DataToWrite,u16 Len);       //指定地址开始写入指定长度的数据6 H6 p) p9 [6 w! ^4 \, O
  23. u32 STMFLASH_ReadLenByte(u32 ReadAddr,u16 Len);                       //指定地址开始读取指定长度的数据/ K  z& N2 ~$ N3 ~9 t/ U' T
  24. void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite);          //从指定地址开始写入指定长度的数据- ?$ C7 x8 Z+ P1 b+ \. o( E; B
  25. void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead);             //从指定地址开始读取指定长度的数据
    ; p( e7 o  R; j) v7 g: F5 }
  26. % C  ?( Z9 x+ Y# ^3 O
  27. //测试写入
    3 ^) F% o8 |4 o9 c$ _0 b$ ]8 \8 v
  28. void Test_Write(u32 WriteAddr,u16 WriteData);                                   - l& R. K- }( A& _
  29. #endif
复制代码

- }  t* c  q8 r5 ]" o+ B/ z

& B" |3 J9 a2 i1 X
  main.c文件
  1. #include "flash.h"
    5 y8 F0 [9 m& v, m0 w! Q) I7 L) k' z

  2. ; J6 K& X; H) M" V" r# V
  3. #define SIZE sizeof(TEXT_Buffer)                  ///数组长度
    & y6 x2 y& |* l) `2 l
  4. #define FLASH_SAVE_ADDR  0X08070000   //设置FLASH 保存地址(必须为偶数,且其值要大于本代码所占用FLASH的大小+0X08000000)
    ' L0 J  ^1 y+ T1 J

  5. ( |; E; {6 L) G
  6. const u8 TEXT_Buffer[]={"STM32 FLASH TEST"};
    1 k% [7 l0 P: l5 G' Q6 l
  7. u8 datatemp[SIZE];
    + R& X4 f+ l- _1 U
  8. 4 Y/ _' q% ~- o( C9 k2 k
  9. int main(void)
    & i0 e- i% C$ [
  10. {7 J1 N! H- x' r4 n% }" B( N
  11.      while(1)
    0 a% P8 ^: ^6 K% o3 r& \# V
  12.     {
      y( s4 R& P# v5 ~9 u& [9 |: f
  13.         if(掉电): I  x' ~; U5 k0 j8 e! J9 m
  14.      {* v# P) b: a# O
  15.           STMFLASH_Write(FLASH_SAVE_ADDR,(u16*)TEXT_Buffer,SIZE);//flash写函数
      `! c$ Y6 ?6 T  ?& @, o
  16.      }  
    % O8 b! k& L. \4 p! p
  17.            STMFLASH_Read(FLASH_SAVE_ADDR,(u16*)datatemp,SIZE);     //flash读函数   + B4 b+ Z  K5 p. U* d! T8 i5 A
  18.    }! a. Y! \" ~; |
  19. }
复制代码
' L, k& \: Z9 {; s! \' |

+ p7 V- X& S% p
  以上就是flash在掉电的时候进行读写的程序,项目用到了就记录一下,方便以后查阅学习。其中的大部分代码在库函数中都能够找到参考。

" I& u2 N* ]: V. K1 y% E9 L
赞 收藏 评论0 发布时间:2022-1-30 01:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版