本帖最后由 stm1024 于 2019-1-18 11:15 编辑
2 H F6 s+ W9 [2 }$ v% u9 F9 W& a$ j- }7 e7 j5 t; z! Y
Flash现已成为MCU的标配,Flash的特性在决定了MCU的一些功能,如代码大小、执行效率、FDU等。了解一款MCU的Flash显得很重要,这里测试一下G071的Flash。
' k, W' f8 f3 B) V先看看和F0存在的不同。flash的大小就没必要深究了,主要的区别如下:% X+ n. A1 t( |7 a8 X+ |7 u2 f
3 J% B4 ~5 a! a6 v# P& d$ W! l1.指令缓存。Flash控制器含有一个8字节的预取指缓冲器和一个16字节的指令缓存。6 T/ I, {5 Y# M2 v+ K( Q1 x* i
2.OTP区域。所谓的OTP,也就是one time programming,这个区域可以按双字方式写入数据,而且只能写一次,如果写入的数据有一个bit不为0,则以后这个区域就不可更改了,可用于存取非擦写的用户数据。
* s/ U& U U9 m2 M3.快速编程。官方给出的数据是22ms的擦除时间和写入每双字时间为82us。0 L4 b1 C8 A" M- l, ^; i- u
4.PCROP。这个是proprietary code readout protection的缩写,用于保护代码,其代码只能用来执行,而不能被读取或写入。至于Securable Memory,则是安全储存器,该区域不能被非安全区域外访问,
: I5 M3 w0 t" c2 W: I5.ECC。ECC是Error Correction and Checking,即错误检查和纠正。能检查2 bits的错误,并能纠正1 bit翻转错误。9 [: Z6 f7 S) @5 _
" X- K' M- D+ A- k
再看看Flash的组织。见下图:; f" v3 g0 c* Z; b
8 }* x0 i0 C1 r4 ]4 b+ ~$ {Flash主要分为两块,分别是主块和信息块。主块就是常规使用的Flash,通常也是我们程序的入口地址,这一块可以随便使用。
8 L4 x1 Z/ W e# ~# R# G而信息块则包含了系统储存器,OTP区域和选项字节,Flash的操作方式按下图:' P5 H6 Q: X/ R5 B4 s' Y
( I% r* N; D! z) a. R, v
编程需要一次写入8字节,也就是粒度为64bits(实际上是72bits,还有8bits的ECC)快速编程为256字节(仅支持Main Memory),快速编程因为不检查所写入的地址,因此比标准编程快了约37%。擦除可按2KB的页或者整个擦除(128KB),但花费的时间相当。
3 z+ o. T% y+ a# \, J7 R7 Y' X% [' T. j2 y' H; }/ K
在选项字节的配置上,和F0系列没有差别(或者我还没有发现)。# d& ~8 f# v0 d3 v8 b- I3 v: w; l9 _
& N& I8 F4 \5 x
以下Flash编程测试代码:
; ~/ y7 e. o) G6 m- int main(void)+ o: S. p& ^& ?( |4 h$ |
- {" z- I$ E/ D* H+ t: L
- uint16_t i;
$ T0 g8 _5 z7 u W0 l1 _. {4 t; [ - HAL_Init();
! Y$ X5 x$ k1 c5 e# l3 L - SystemClock_Config();
& p9 s# r# J6 |5 m& L% C' K - MX_GPIO_Init();
6 F! N3 r& o% a5 {5 G% W - HAL_FLASH_Unlock();
$ O( v9 q2 X% q+ e. a/ } - EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
: i3 q. M- v X4 @9 g" M j3 d - EraseInitStruct.Page = GetPage(FLASH_USER_START_ADDR);6 D, D3 d& g, a$ N6 ?0 _1 [. @
- EraseInitStruct.NbPages = 1;4 L5 e# F2 M" i( b1 n
- HAL_FLASHEx_Erase(&EraseInitStruct, &PageError); ! @% Q: i# E* |
- //8*256=2KB,1 page # _% a+ R! _. v& @8 U2 d
- for(i=0;i<0x100;i++) u/ z3 L% p' o* o; j: G
- HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, FLASH_USER_START_ADDR+i*8, 0xefcdab8967452301);( A! j5 E) ^! u' z1 }' m; V; V0 M4 h% w
- HAL_FLASH_Lock();
( P$ `6 I+ Y* F7 ?+ E0 {# l - while (1)
$ @0 ]# R# h, R- G- ]( d* W1 _ - {8 u8 z8 f2 V0 O; [& T1 X6 @
- / i, l- h) I/ w4 ?
- }
* F% x0 J2 t$ T7 m% c: |4 J - }
复制代码 效果嘛,就是把一页的数据都改写为0x012345678abcdef这种模式,因为ARM核是Little-Endian的,所以低字节在前,高字节在后:0 F$ L5 I5 O2 m0 h9 z. [$ s
; k% x; K8 a9 b6 {/ T$ T" {
不得不说,有ST Link Utility就是好,直接Dump Flash。
) W9 p' L# j+ @此外,可以看到刚好改写数据是1页:
7 k! p& Z0 m, n, O
) I1 b! G. W4 j$ ~9 f
因为0x2000-0x1800=0x800,也就是1 Page的大小。
& z+ Q5 z& z: Z7 W( U) X4 i( l- l1 J& P# G- ~8 y% G
9 R" d, d3 A% ~; `
/ @/ L, Z1 M* q4 a( v- @+ [& b2 f8 v' F5 |/ I
|
啊,这个没复制进去。
一行代码:
这命名方式不太符合ST家的风格,而且目前从官网看,也就只有G070,G071,G081三个大系列。
这个可以参考HAL库的文档,我都是调用的HAL库函数
9 d" z2 N! W v z0 b( M
谢谢!
另外还有页设置的函数GetPage()是在哪个文件中定义的?我在编译时提示未定义。
这个问题已经解决了,编译通过了。( \' ~3 O4 Y, _; p! O0 q
额,这个还没见到过,不过一般用的好像都是F103C8T6
感谢分享
大佬过奖了~
过奖了,学了点皮毛
这个文章中的,一位买了STLINK 主控是stm32gc102cb! G: B/ u/ C0 v' G2 b