本文测试 L051 flash的读写,用来处理以后应用中的掉电数据保存。 1、STM32L051内部存储模块地址范围开始找到F103的FLASH图复习了一遍,然后L051C8T6,64KB的flash, 然后我惊奇的发现还有2KB的EEPROM。发现L051系列的地址与F103完全不同,F103的flash每页的长度有1KB(小容量<=64KB)和2KB(大容量128KB起)查看各种资料, 查了2个小时, 还是不知道L051的flash 每页长度是 128Byte 还是256Byte????????????????????????还是请教了一下大佬,发现直接在J-Flash中可以找到答案,先上个F103的图: 7 v l6 K' ~1 V
8 b& U2 b/ G/ F* B
8 B* D, v2 B' r0 X- ?
然后来看个L051的图: 图中64KB 的flash 和2KB的EEPROM都能都明显的看出地址,flash 512页,每页128bytes,EEPROM只有4页,每页512bytes.知道了基本的地址,就可以操作起来了。 最后还需要确定的一点事,最小擦除单元是128bytes,还是256bytes,按以前的认知,删除是按照一个Sector擦除的,也就是128bytes,但是我查看了一些网上的例子和资料,有的是说256bytes,所以后面需要自己确定一下 其实在HAL库的 stm32l0xx_hal_flash.h 文件中有过 FLASH_PAGE_SIZE 的定义,就是128bytes :
+ }3 r8 G! \: }7 l0 M, Z6 r& M
- #define FLASH_SIZE (uint32_t)((*((uint32_t *)FLASHSIZE_BASE)&0xFFFF) * 1024U)5 H1 Z& {( B. P
- #define FLASH_PAGE_SIZE ((uint32_t)128U) /*!< FLASH Page Size in bytes */
复制代码
# u$ u. E. }. K3 ^( v- q4 |- e对于flash的操作,有一些基础知识补充一下: Read interface organized by word, half-word or byte in every area • Programming in the Flash memory performed by word or half-page • Programming in the Option bytes area performed by word • Programming in the data EEPROM performed by word, half-word or byte • Erase operation performed by page (in Flash memory, data EEPROM and Option bytes) STM32L051写Flash必须字,读 字节、半字、字都支持。(这句话也是错误的,这是以前哪里看到的,实际测试写可以根据字,半字,字节来写) 一些基本概念:定义字是根据处理器的特性决定的。首先ARM是32bit处理器,所以它的字是32bit的。半字自然就是16bit;字节不论在哪个CPU上都是8bit。1 Byte = 8 bits(即 1B=8b) 1 KB = 1024 Bytes Bit意为“位”或“比特”,是计算机运算的基础,属于二进制的范畴;Byte意为“字节”,是计算机文件大小的基本计算单位; " B+ q/ V6 R* ^& W1 [2 \1 ?
2、读写函数的设计HAL库中肯定是有对flash和EEPROM进行操作的函数,我们这里新建一个stml0_flash.c 和stml0_flash.h 函数分别放在对应位置,进行自己的函数设计。库中Flash与EEPROM的函数看样子是分别放在 stm32l0xx_hal_flash.c 和 stm32l0xx_hal_flash_ex.c 中的,我们先使用EEPROM,因为提供EEPROM,就是让用户可以保存一些掉电后的数据的嘛,测试完EEPROM,再去测试下flash,因为怕有时候数据不够放……
0 A8 m% k# J( {- [6 {2 g6 a2.1 读取函数- //读取指定地址的半字(16位数据)$ A! r% R& F/ c0 F8 k! m
- uint16_t FLASH_ReadHalfWord(uint32_t address)
' q0 x+ u$ A; x1 `- m - {0 i1 K; a/ Y$ K3 ~: z
- return *(__IO uint16_t*)address; / z0 s' I0 p. z
- }
6 w5 P M0 b& Q" f
3 j, W6 f: [* D# J+ ?# ~- //读取指定地址的全字(32位数据)
) R$ b% V" K z1 D - uint32_t FLASH_ReadWord(uint32_t address)
$ h$ Q- V7 T3 c4 T# H - {+ n/ v4 J4 s. t5 K
- return *(__IO uint32_t*)address;
. z* b: F: ?' c+ K) f0 X - }
复制代码
9 h5 P0 u% M6 m3 M4 ?- f1 U5 D) v! l! {
简单测试一下: - u32 read_data1=0XFFFFFFFF;+ [+ K. b* M" d" c& ?9 D, G% Q' n& ^2 {
- u32 read_data2=0XFFFFFFFF;
3 O5 i. J( F+ f! R7 h3 B - .... Y5 H: N8 W( f; Z V
- read_data1 = FLASH_ReadWord(DATA_EEPROM_START_ADDR);$ w8 f9 U- a3 d7 t% h
- printf("the DATA_EEPROM_START_ADDR is: 0x %x \r\n",read_data1);
# Q' [' F5 ~4 W8 E1 P7 M - read_data2 = FLASH_ReadWord(DATA_EEPROM_START_ADDR + EEPROM_PAGE_SIZE);3 _- x h& M. L/ T8 U6 ]* b
- printf("the EEPROM sceond page test data is: 0x %x \r\n",read_data2);
复制代码 8 A; v( R+ `2 N( q
没有写入数据读取的值应该都是0。
0 w" Q6 r. w/ n0 R2.2 EEPROM写函数对EEPROM的写函数:stm32l0xx_hal_flash_ex.h中函数如下: - HAL_StatusTypeDef HAL_FLASHEx_DATAEEPROM_Unlock(void);9 S! Z% t+ t) J$ H( Z- G
- HAL_StatusTypeDef HAL_FLASHEx_DATAEEPROM_Lock(void);1 [1 G2 t1 {/ M
$ C4 s6 F% v4 D! Y/ n) u7 T2 u- HAL_StatusTypeDef HAL_FLASHEx_DATAEEPROM_Erase(uint32_t Address);3 Q+ u. T' c% I; p
- HAL_StatusTypeDef HAL_FLASHEx_DATAEEPROM_Program(uint32_t TypeProgram, uint32_t Address, uint32_t Data);
复制代码
. f ?% O5 x! W' U通过函数看来,可以直接用,但是这里有一个问题 需要测试一下,擦除是否会擦除整个扇区,有待验证!! 答:EEPROM的擦除可以直接擦除某个地址的字,不会擦除整个片区 EEPROM的操作相对Flash,比较简单,直接使用HAL库中的函数即可完成 - HAL_FLASHEx_DATAEEPROM_Unlock();: Z' h( O- p( w( Y1 s" G
- HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_WORD, DATA_EEPROM_START_ADDR, write_data1);) E2 I' H( P$ ^/ s/ c& ^, L7 b: Q
- HAL_FLASHEx_DATAEEPROM_Lock();
# h3 V2 X7 e6 t; A - ...
" I1 p( t; [6 o6 p. l - if(btn_getState(&K1_BUTTON_150mS) == BTN_EDGE2){# G6 t) p% Y$ b) G3 B, _
- printf(" K1 150ms button!,EEPROM_Erase test\r\n");" r' T9 A7 h7 m% U7 u- t; e% c
- HAL_FLASHEx_DATAEEPROM_Unlock();
. c: b1 U! d9 i4 O9 l - HAL_FLASHEx_DATAEEPROM_Erase(DATA_EEPROM_START_ADDR+4);3 o6 W. o% f) J2 ^, u4 H. D7 [2 i
- HAL_FLASHEx_DATAEEPROM_Lock();9 T9 Y2 W1 I% r* P6 l# { ?7 P! A
- HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);/ u2 n& W# Y4 v6 }2 |! c
- }! f3 [2 v [ {. u8 E) x
- .... ^! Q6 _% ?0 i" J: u- e# b
- if(btn_getState(&K2_BUTTON_150mS) == BTN_EDGE2){) Z: w1 W/ j) T; P5 F- A. Y) Z5 f
- printf(" K2 150ms button!EEPROM_read test\r\n"); g( D% S2 D/ M2 b" G
- read_data1 = FLASH_ReadWord(DATA_EEPROM_START_ADDR);
: x2 E7 G4 J5 z" o - printf("the DATA_EEPROM_START_ADDR is: 0x %x \r\n",read_data1);
w" P7 O* _2 h$ J - }
复制代码 ( _$ B, a* m9 S; C4 f9 U
按照上面的例子,擦除DATA_EEPROM_START_ADDR+4的地址不会影响DATA_EEPROM_START_ADDR地址的开始写入的数据 写入一样,如果不在意以前的数据,直接写入就可以。 总结来说EEPROM的使用还是很好用而且简单的。而且EEPROM是可以按照字节,半字,全字写入的,测试了一下,是右对齐 右对齐什么意思呢,打个比方就是如果在地址 addr 中,本来写入全字 0x12345678 然后直接在EEPROM 的 addr 这个地址,写入半字 0xFFFF, 再读取全字的话,addr 地址的全字就变成了 0x1234FFFF ,这个具体的为什么在地址写入半字,不会直接从地址开始占用2个字节,是因为地址的类型为 uint32_t ,所以该地址就是 4个字节类型的数。 + R. |: ]2 I q" h9 }. ]
写入问题说明修改2021/11/23 修改说明 上面一段的解释有误,这里修改一下,不是因为地址类型为uint32_t,地址类型永远是这个,是因为定义的数据类型为uint32_t ,然后STM32又是小端模式,所以保存的方式是从地址的最后开始保存,4个字节的全字,第一个字节放在地址开始+4 的位置,第二个字节放在地址开始+3的位置,所以如果调用HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_WORD, DATA_EEPROM_START_ADDR, write_data1);关键在于FLASH_TYPEPROGRAMDATA_WORD以全字方式写入半字,那么内核会自动分配4个字节的宽度,半字的第一个字节放在写入地址+4 的位置,第二个字节放在写入地址+3的位置,所以导致了上面的结果 - HAL_FLASHEx_DATAEEPROM_Unlock();) i; |0 R) \/ Z. r6 `% l9 J* I
- HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_BYTE, DATA_EEPROM_START_ADDR, 0X88);
. l1 U. A5 K& ^( [9 M; i/ O# _ - HAL_FLASHEx_DATAEEPROM_Lock();
& O0 W- O5 ` \ [+ n - read_data1 = FLASH_ReadWord(DATA_EEPROM_START_ADDR);6 V; x, }: d- u0 I8 R9 H7 ^
- printf("the DATA_EEPROM_START_ADDR is: 0x %x \r\n",read_data1);
复制代码
$ v9 X4 u9 Q( d8 r最后在 stml0_flash.h 中把函数完善声明一下,使得主函数中的程序更加简洁。 - void MY_DATAEEPROM_Program(uint32_t TypeProgram, uint32_t Address, uint32_t Data) ' u0 R' x& R( }4 {
- {
) h; [; r% ]* Y* J5 U - HAL_FLASHEx_DATAEEPROM_Unlock();
# u* J* m, G1 S7 \: k - HAL_FLASHEx_DATAEEPROM_Program(TypeProgram, Address, Data);
9 y0 D! q, o. B4 O - HAL_FLASHEx_DATAEEPROM_Lock();
2 y* ?! E1 u. ~7 ~+ a$ f* X0 _ - }
复制代码
! D9 e, T: w* D) D0 [那么L051 的EEPROM的测试就到这里,其实有EEPROM,在项目中的保存数据的功能就问题不大了,但是我们既然开始了,就把L051 Flash的读写也测试一下。
% P0 S) e8 }4 @! E/ G& P2.3 Flash写函数Flash的读取其实和EEPROM一样,主要是写函数,来看一下stm32l0xx_hal_flash.h 中有哪些函数 - /* IO operation functions *****************************************************/. [$ G) M" c" F7 l
- HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint32_t Data);
( d) j1 Z3 }* E+ g1 S6 t% @$ R2 U. X/ B - HAL_StatusTypeDef HAL_FLASH_Program_IT(uint32_t TypeProgram, uint32_t Address, uint32_t Data);
. T9 W! c' {- @! x" n - 4 M4 z& c9 D/ U8 r+ t H, q& X) U
- /* FLASH IRQ handler function */8 X `. E" h& t7 E6 b+ r( `7 S
- void HAL_FLASH_IRQHandler(void);! n2 a; p- Q/ c; ?
- /* Callbacks in non blocking modes */
7 h1 y, h" Z- Z$ J) I - void HAL_FLASH_EndOfOperationCallback(uint32_t ReturnValue);1 I% v+ K/ T# D/ i7 \$ x
- void HAL_FLASH_OperationErrorCallback(uint32_t ReturnValue);/ c) K; [8 r* _2 \' o$ Z4 }0 `
; {) l! S8 F/ v6 d) N4 P* Y- /**
" I, Z4 ?/ e# t; y7 f4 Z! U+ D: h. L; s - * @}9 N% G% s: G5 W. W) ~2 u
- */
) ]* L% |7 ~* m% s0 ]! q
; n7 a! b" W% [6 S, A8 _+ p- /** @addtogroup FLASH_Exported_Functions_Group2
+ e3 _- S9 |. l; z - * @{
& m& c9 Z$ j8 I4 s; ~ - */# _. Q, s0 `5 E# @5 R; D* A
- /* Peripheral Control functions ***********************************************/, u- M' q7 G8 P* ?' P
- HAL_StatusTypeDef HAL_FLASH_Unlock(void);
, [2 T+ h( a* G, b" P- O - HAL_StatusTypeDef HAL_FLASH_Lock(void);) K8 \1 {8 h) v, Z
- HAL_StatusTypeDef HAL_FLASH_OB_Unlock(void);
, Q' w8 f* z+ s m! y9 l9 V - HAL_StatusTypeDef HAL_FLASH_OB_Lock(void);5 Y2 l& K" s- j L) D" G3 q I) \
- HAL_StatusTypeDef HAL_FLASH_OB_Launch(void);
复制代码
* J5 K$ Z B: i/ s- p有点忙,Flash的后面再也,看了几个demo,只需要做几个测试就可以;
5 _7 `8 |# ~" I/ f8 X% H% f2021.8.5 今天有空来接着测试一下L051 Flash的读写,看了下HAL_FLASH_Program函数:
* }! S: O5 j" R4 {' M/ v- HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint32_t Data)
I! W k* n% z0 ~/ _ - {& j5 O2 ~+ j) J1 e
- HAL_StatusTypeDef status = HAL_ERROR;
o- e# |" t _( Y - + u3 t) |* u! M+ Z* s& U6 V
- /* Process Locked */$ c* T, h; y8 x$ }0 V7 e
- __HAL_LOCK(&pFlash);4 d" v/ Q! E9 m" x
- + G$ K) }% v; Y5 `. K! |+ B
- /* Check the parameters */
' S, C: A. L j* k$ r8 O - assert_param(IS_FLASH_TYPEPROGRAM(TypeProgram));
# B2 F# A9 a* ~; f( `2 H4 E - assert_param(IS_FLASH_PROGRAM_ADDRESS(Address));
. n y" I- n9 S# F5 Q& r - / \3 e- v" G+ {+ ~3 c
- /* Wait for last operation to be completed */9 @9 z5 {5 b1 @4 F6 x' K
- status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
9 i! ]3 \3 ]* R) x( b2 _ -
8 ]4 G! T0 F: Q; h2 i5 C5 F - if(status == HAL_OK): Q2 p3 z) M( C( M$ A
- {% s1 f/ F# [8 g3 F
- /* Clean the error context */
2 w5 G7 R, S' y( w- u - pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
: a4 _; _1 I# B
5 O, f; d! ~' P- /*Program word (32-bit) at a specified address.*/- F) E/ |0 Q% D1 n9 S$ B
- *(__IO uint32_t *)Address = Data;
& D* W" z( o5 s4 d( n- N/ W - 1 R! T! \1 i5 Y0 M
- /* Wait for last operation to be completed */5 `/ W8 q2 \& ^+ [; f9 g5 \
- status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
- d# R2 o5 s+ w. b: n - }7 p2 x1 N: H& |6 d% o% I7 g$ J
- 2 V- e. E* G2 J5 {
- /* Process Unlocked */
/ R# b2 {9 a4 }2 X7 I1 p) u- E9 n - __HAL_UNLOCK(&pFlash);
' b6 \1 A$ Z" h* F) N
" _5 G# H. m3 X% h4 Z- return status;
. H& }) N0 A3 i' ?) o' H0 r - }6 |( l9 W" i; x; ~3 K8 c
复制代码
0 J: ^: u( u/ h9 c/ S; y这里也再次说明了,L051的写必须以字的方式写入。 不管了,先测试一下,不擦除直接写入,这里先定义一下写入的地址,前面我们已经知道了L051 flash一共 512页,每页128bytes,所以我们直接拿最后面的几页来测试 - #define ADDR_FLASH_PAGE_505 0X08000000 + 128*504 //; m8 c9 o" J/ q8 a/ _4 J
- #define ADDR_FLASH_PAGE_506 0X08000000 + 128*505 //" R% @% V% J/ [) z+ ~9 s% H
- #define ADDR_FLASH_PAGE_507 0X08000000 + 128*506 //
9 y n9 z: O$ o - #define ADDR_FLASH_PAGE_508 0X08000000 + 128*507 //! Z' e9 b& l u; A$ J6 _6 \
- #define ADDR_FLASH_PAGE_509 0X08000000 + 128*508 //% h3 u' U6 r1 R" M) |- m
- #define ADDR_FLASH_PAGE_510 0X08000000 + 128*509 //1 |: ~) D# o7 r: E9 w
- #define ADDR_FLASH_PAGE_511 0X08000000 + 128*510 //
% |1 Y7 {) p" P/ j6 T: \ - #define ADDR_FLASH_PAGE_512 0X08000000 + 128*511 //最后一页
复制代码开始先不擦除,直接在最后一页写入一个字读取一下试试,整理一下写入函数: - void MY_DATAFLASH_Program(uint32_t Address, uint32_t Data) * ~& b4 H( w/ i+ c0 o
- {- `. O! n3 f4 g7 P7 h7 B" U
- HAL_FLASH_Unlock(); b) }6 y' ~) ~0 H( \& }1 U
- if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, Data) == HAL_OK){
0 [5 q6 }8 z8 `- v; s& \! M1 ] - printf("write data 0x%x OK\n", Data);
0 r, |6 F8 ^# D0 P0 K+ w; Z - }. z+ L$ Q6 P/ d' i3 M1 E2 Q# p
- else{
3 J5 q, {5 B& l ?3 S7 j - printf("failed!!!\n");
* i7 V; ~1 Q% Z$ L - }
$ {9 c# |4 c1 A. C$ j2 d - HAL_FLASH_Lock();
: E. f/ Z5 |3 `/ A! e+ \! ? - }
复制代码
+ X9 A7 l+ e% d测试一下; - MY_DATAFLASH_Program(ADDR_FLASH_PAGE_512,write_data2);1 `- B) J% T+ X4 d4 w
- read_data1 = FLASH_ReadWord(ADDR_FLASH_PAGE_512);: j+ }& R3 u3 p/ R3 O
- printf("the ADDR_FLASH_PAGE_512 is: 0x %x \r\n",read_data1);
复制代码
& [# k) }* P# P4 A4 _2 v在没有写入flash之前,该地址读出来的数据为0,写入后读出来是正常写入的数据这里有个疑问,按理来说,flash存储器有个特点,就是只能写0,不能写1,所以flash的写入,比需先擦除,或者至少检查一下该数据区是否可以写入,但是L051 怎么初始的时候读出来是0? 难道L051的有区别,需要测试一下 先在一个地址写0XFFFFFFFF ,然后写完了再写一次别的数据看看能否直接写入,结果是写入了0XFFFFFFFF ,不能继续直接写数据,说明,估计L051是相反的,这里具体是不是我只看测试结果,结论的话我自己知道就可以应用,希望有权威大神指正。 这里我们得用到一个关键的函数 ,这个函数是在stm32l0xx_hal_flash_ex.c 这个文件中的,是flash的擦除函数:HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *PageError) 所以这里我们知道了以后,可以优化一下写入函数,我们项目中用到的是可以直接对某个地址的写入,然后也不需要保存,此页其他的数据,所以我们把函数改成如下: - void MY_DATAFLASH_Program(uint32_t Address, uint32_t Data)
8 L6 ]" A( J" p" T% I; l - {4 y& Y6 |& Z9 z6 {, V: z
- FLASH_EraseInitTypeDef EraseInitStruct;+ W" v& W0 z% v9 d" M
- uint32_t checkdata;# E1 }: Z7 ?( I$ B+ Y
- uint32_t PAGEError = 0;% ] c# J4 ?+ ]/ t
- checkdata = FLASH_ReadWord(Address);
+ v( _; A2 I' n( d: O - HAL_FLASH_Unlock(); 9 F2 h( X7 w' C0 j/ w
- /*如果是0,直接写*/
! |4 r! S2 @5 B5 d& [. i - if(checkdata == 0){ # ~% [ R9 P8 O0 r; ], k) a2 p3 y
- if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, Data) == HAL_OK){
; E- |- P8 z( @0 ^ - printf("write data 0x%x OK\n", Data);9 r8 `6 d( l E" y
- }3 T2 x( c( M. Y
- else{, g4 {6 q6 l0 ^3 R# F) j% u- ^0 v
- printf("failed!!!\n");; M, Z" s4 V) P/ w! c
- }: g+ I8 y( H+ A) |3 g: B
- }
' l) {+ {2 N: o' ~. w, B6 Q - /*否则擦除再写*/3 t1 v! e( G$ z& K% v1 g
- else{% ], `) R6 v9 B4 |2 Q Z' L( `$ v
- __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);: {; _' B, x/ A8 B( c, W8 `8 ~& v2 Y
- x& V9 Y' n; m0 D# e: L5 J
- EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; // 刷除方式
1 n5 a# E4 \* R0 q' X - EraseInitStruct.PageAddress = Address; // 起始地址4 z3 o% i7 _# `- V9 i% t2 x
- EraseInitStruct.NbPages = 1;
7 s: D0 ~( O. W% }7 F - ( L" s/ i- @( \
- if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)8 C, @: G: q% M# e' d/ }
- {
5 j+ U" O8 b) ?* y* r$ c - // 如果刷除错误
: O+ V5 `- Z+ R - printf("\r\n FLASH Erase Fail\r\n");- v# G' l* k5 O1 f. h
- printf("Fail Code:%d\r\n",HAL_FLASH_GetError());
, i2 l5 _& M R4 A" E - printf("Fail Page:%d\r\n",PAGEError);
, }. z3 M( _! p7 @) F - }+ g- p5 X) L9 A9 n4 s
, d. ^0 T0 `8 F/ E4 E- if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, Data) == HAL_OK){) Z3 ^9 \# i# m
- printf("write data 0x%x OK\n", Data);
. N- d" V! V- G" O - }
/ m9 J8 h. Y3 a) D; a - else{
( k% D0 U8 I( M; ? - printf("failed!!!\n");
3 L" _) G1 k% @$ y7 b2 n - }
9 {- C3 @. ?2 G4 Q& |0 t
! d4 i+ y! A0 c }/ r% |- }
' i4 `( p0 j* p" N' M( y6 V) }) o - HAL_FLASH_Lock();
* D9 S' {& ?8 M6 m& w4 S% Q - }
复制代码 " Z) Z! _( C! H7 E
自己修改了一个函数, 改成这样以后,就能直接在想写入的地方写入数据了,到这里,flash足够我项目中的使用了。但是还有最后一个疑问,就是擦除的一页到底是不是128bytes我来验证一下。 - u32 write_data1 = 0X12345678;
. z& k9 O# z! I9 \9 G, ^ - u32 write_data2 = 0X87654321;
' Z2 z: a( ]% a - u32 write_data3 = 0XFFFFFFFF;
. X7 n7 w1 P5 c - + C% y2 Q$ M) t+ E) q, g
- MY_DATAFLASH_Program(ADDR_FLASH_PAGE_508 + 124,0X508508FF);$ _. X* H, X' ?6 A" T, F
- MY_DATAFLASH_Program(ADDR_FLASH_PAGE_509,write_data3);
" Q* ~7 i s+ W/ ^: r7 J) ? - MY_DATAFLASH_Program(ADDR_FLASH_PAGE_509+4,write_data2);
+ @- D4 \2 ~. l- O4 w3 l2 V6 o - MY_DATAFLASH_Program(ADDR_FLASH_PAGE_509+8,write_data1);
6 |* l: e; S4 U/ S' K - MY_DATAFLASH_Program(ADDR_FLASH_PAGE_510,0X510510FF);
8 y+ Y4 B: V- k; ~* j _2 E
`0 g7 l' F2 \7 Y' A- read_data1 = FLASH_ReadWord(ADDR_FLASH_PAGE_508 + 124);
6 Q5 m' x. R, i& i% n - printf("the ADDR_FLASH_PAGE_508 last is: 0x %x \r\n",read_data1);8 p8 I6 D( Y; C* e; k& c
- read_data1 = FLASH_ReadWord(ADDR_FLASH_PAGE_509);
/ E- J6 {. y; G8 {3 I - printf("the ADDR_FLASH_PAGE_509 1 is: 0x %x \r\n",read_data1);( b: H/ p5 U8 p, Z# A5 d: P+ P
- read_data1 = FLASH_ReadWord(ADDR_FLASH_PAGE_509 + 4);
# l6 `1 R7 p, ~; a& u) }! @ - printf("the ADDR_FLASH_PAGE_509 2 is: 0x %x \r\n",read_data1);
! n' A3 x `1 g W6 y9 r - read_data1 = FLASH_ReadWord(ADDR_FLASH_PAGE_509 + 8);
" j- O- p- A9 ^) y$ ^" a1 L - printf("the ADDR_FLASH_PAGE_509 3 is: 0x %x \r\n",read_data1);
' g' k% @- {3 _0 [8 ?1 m$ g3 Q/ R8 z8 i' E - read_data1 = FLASH_ReadWord(ADDR_FLASH_PAGE_510);/ W2 y* L5 h9 R
- printf("the ADDR_FLASH_PAGE_510 first is: 0x %x \r\n",read_data1);4 Y1 h; p$ {9 l+ _ k
- _- L' ]9 M, o, f6 L4 K5 _- if(btn_getState(&K2_BUTTON_150mS) == BTN_EDGE2){
8 F1 q/ L" U7 n- n$ I& s - printf(" K2 150ms button!EEPROM_read test\r\n");
5 i' V) P$ i0 R5 x' l - read_data1 = FLASH_ReadWord(ADDR_FLASH_PAGE_508 + 124);5 L4 C9 G$ N, z- q K9 }6 e
- printf("the ADDR_FLASH_PAGE_508 last is: 0x %x \r\n",read_data1);
% A* x$ L- ^) E1 d1 N - read_data1 = FLASH_ReadWord(ADDR_FLASH_PAGE_509);
$ Y8 ?8 y' u' g% b8 i5 P$ i - printf("the ADDR_FLASH_PAGE_509 1 is: 0x %x \r\n",read_data1);
' y% p5 e. T. d. D - read_data1 = FLASH_ReadWord(ADDR_FLASH_PAGE_509 + 4);2 K, B' A+ t! F- }6 M- l
- printf("the ADDR_FLASH_PAGE_509 2 is: 0x %x \r\n",read_data1);
, `7 }+ s2 s* k, V0 y0 ]7 i - read_data1 = FLASH_ReadWord(ADDR_FLASH_PAGE_509 + 8);+ @$ b( u3 ?9 E
- printf("the ADDR_FLASH_PAGE_509 3 is: 0x %x \r\n",read_data1);
- C( t6 @$ C8 D - read_data1 = FLASH_ReadWord(ADDR_FLASH_PAGE_510);
' p# |5 u _( L3 z8 d5 w. p+ v - printf("the ADDR_FLASH_PAGE_510 first is: 0x %x \r\n",read_data1);
- Z! n; d9 r- k+ r7 w
c/ C. c1 a8 @9 R- }6 ]9 D6 M" A |8 O. ~+ W
- if(btn_getState(&K1_BUTTON_150mS) == BTN_EDGE2){
6 x7 e* Z9 L x2 B3 f - // printf(" K1 150ms button!,EEPROM_Erase test\r\n");. V5 G6 q% F/ l1 R
- // MY_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_WORD, DATA_EEPROM_START_ADDR, write_data1);, L+ G7 W X" n/ w t5 i# i6 P
- printf(" K1 150ms button!,flash write test\r\n");& n8 D+ Y3 z# v# R4 Y
- MY_DATAFLASH_Program(ADDR_FLASH_PAGE_509,0X33333333);+ L6 E4 z- E( A! C) U y
- HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);4 y. [% ~, x8 k/ R9 L
- }
复制代码 , D, y' Z, K: ~* m- G$ r2 l: [
因为地址位置如果有数据的话会擦除一页再写入,所以我们看了一下508页最后一个地址,和510页的第一个地址数据,对509页的数据进行了操作,结果发现不会改变508 和510的数据,509页的数据会全部清除!
" X+ e' l7 Q; _8 v: |4 p
Q& f+ P* {& D
$ u- J0 O9 ^1 E. ^2 E所以得出的结论显而易见,flash擦除按照一页一页擦除, 在L051上面一页为128bytes,而且擦除后数据全部为 0; % ?+ E. z3 K% {
2.4 读写EEPROM的后续问题最近有一个项目,因为缺货 STM32L051R系列缺货,买了 STM32L071RBT6 替代:
( F4 i! v: ~ A5 m8 i6 d
+ E V9 Z+ F" h" R' U% E看了一下地址,其实我们上面所有的测试代码基本都是可以直接用的,代码直接用STM32L051的代码也是可以的,实际项目中,还是使用EEPROM比较方便,所以在使用EEPROM的时候,发现了一个问题(并不是换了芯片的问题),还是数据读取和写入的问题。 8 r1 `, l& d I
2.4.1 问题的出现和解决下面程序的硬件平台是 STM32L071RBT6,首先在程序中,有一个写ID的函数:
) p# o& {) ^: j3 r L; p
5 O4 n- Z3 q* @& ~1 A
写入IO是通过字节的方式 byte 写入的,写了6个字节(蓝牙设备的ID)。 然后最初读取的函数用的是:
, M+ U- _5 Q) I. ]8 Q! u ~' A
1 H/ G1 S1 U# X6 ]3 o- C! H6 p0 E
使用这个读ID的函数,问题就出来了。上图代码中,我读取ID使用的是半字读取,处理方式是把读到的半字前面8位给ID1, 后面8位给ID2, 但是测试中发现 数据读出来与想要的相反,什么意思呢,看下面的测试说明: 上电打印出EEPROM中读取的一个地址的,每个ID(每个ID是uint8_t类型)的数据,在代码开始定义了测试数据: - BlueID_STRUCT test; N4 d7 Y! R$ U3 w3 O
- ...7 C @2 @9 E3 Y* o* s
- /*
! K+ R* M9 x2 N, X8 c- Z - CHBlueID_STRUCT Flash_PowerOn_BlueCheck()0 i5 N# u/ C& i- u9 v% H- S( c
- {4 d# F6 Z7 V( e
- 3 t( G" V. n1 {9 M/ a
- CHBlueID_STRUCT PowerOn_ID;2 a$ ]7 z' [0 W1 Y4 S
- PowerOn_ID.CH1ID = FLASH_blueIDRead(CH1_ID_ADDR);
! Q$ K7 K+ [: q! l/ N1 A - PowerOn_ID.CH2ID = FLASH_blueIDRead(CH2_ID_ADDR);7 O4 l8 r2 r! {
- PowerOn_ID.CH3ID = FLASH_blueIDRead(CH3_ID_ADDR);4 z8 A8 q' \, L8 x2 v( m0 L
- PowerOn_ID.CH4ID = FLASH_blueIDRead(CH4_ID_ADDR);
0 d) [5 f: t3 G/ d2 ]8 c - PowerOn_ID.CH5ID = FLASH_blueIDRead(CH5_ID_ADDR);
5 v( J" o8 V. t& \6 f# n# }% t - PowerOn_ID.CH6ID = FLASH_blueIDRead(CH6_ID_ADDR);
\, J6 B6 p2 \7 t2 U - PowerOn_ID.CH7ID = FLASH_blueIDRead(CH7_ID_ADDR);/ E9 N0 I% w( S% S
- PowerOn_ID.CH8ID = FLASH_blueIDRead(CH8_ID_ADDR);, @4 ]& q) k4 k) Y" y. J
- PowerOn_ID.CH9ID = FLASH_blueIDRead(CH9_ID_ADDR);( o* G* X- p% r% c) {
- PowerOn_ID.CH10ID = FLASH_blueIDRead(CH10_ID_ADDR);4 e/ O' z& }$ s. y7 ~1 H* O' Q9 e3 y2 a
- ~, _ q5 q$ s4 f( ]# r
- return PowerOn_ID;
8 t/ [, ~* O1 B. M# t u6 J - }+ b' q$ l9 j/ X! @; T y( t( l
- */
- z \" |" L* p4 V" k - BlueChipID = Flash_PowerOn_BlueCheck(); //上电先把ID读出来做比较
) A# ?5 a$ d0 Q: I& z - //打印一个出来测试,看结果6 B: }9 V) ^& U' J4 g
- printf("BlueChipID.CH1ID is 0x%x,0x%x,0x%x,0x%x,0x%x,0x%x\r\n",BlueChipID.CH1ID.ID1,BlueChipID.CH1ID.ID2,BlueChipID.CH1ID.ID3,BlueChipID.CH1ID.ID4,BlueChipID.CH1ID.ID5,BlueChipID.CH1ID.ID6);
$ d& w* ^( i4 G3 ^2 E1 x V# S
5 w4 z; L% n% ?+ v* R3 C- test.ID1= 0XFF; //结构体每个元素是 uint8_t 类型5 `; [' p: z" c8 K; k4 c
- test.ID2= 0XEE;; q/ N) t+ M; ^* w- L. m/ V3 C' _
- test.ID3= 0XDD;
3 G( B* U7 v5 J - test.ID4= 0XCC;
. `( U# @0 W# N! N* o$ J - test.ID5= 0XBB;0 S. Y; m+ ^) f0 J, h
- test.ID6= 0XAA;
0 F7 X3 }5 T* F& u - ) t2 q! V0 K5 F8 k
- while (1){...}
复制代码 0 I0 U/ v; _5 e" y2 E$ I# o
在程序中通过操作,写入测试数据,调用上面提到过的写ID的函数,写ID的函数是每个字节每个字节写的:
+ B4 {7 C/ ^; C0 L
, N9 w# S9 ~7 w S1 q/ j2 K3 w按我们希望的结果来说,读出来按照顺序打印,应该是:0xff,0xee,0xdd,0xcc,0xbb,0xaa 。测试实际上是:
) t& K8 p6 v1 W% a% ~
0 j: `2 [! \' T7 h5 H为了确实是读的问题还是写的问题,添加了读字节的函数: 
) H6 P8 \& W4 y8 i/ d- t+ B
. Y8 c, B9 n6 B7 m+ x; A; Z
6 c& e8 t; v3 |2 `( {
打印的结果: 6 O* f) d) c; W% ]3 R2 t7 C
5 Y( W0 q# \- r7 k说明确实是ID的读取函数出的问题,是因为使用的半字读取,问题处理不麻烦,我们把读取函数修改一下: - BlueID_STRUCT FLASH_blueIDRead(uint32_t address)& a( C4 k0 [# z6 i' u y3 {
- {! ~0 U- Z1 ^9 v- C7 K0 K! q# \
- BlueID_STRUCT u48id;
1 m5 k0 ?6 }# d- z - // uint16_t temp1,temp2,temp3; /**(__IO uint16_t*)address; */
( h9 p! A, t T! Z/ {/ N+ L7 r - // temp1=*(__IO uint16_t*)address;
6 v; T) z0 ~0 h; d; J6 r& ?* a. P# F - // u48id.ID1 = (uint8_t)(temp1>>8);0 ]( J: ?+ ^( Q" B$ l
- // u48id.ID2 = (uint8_t)(temp1&0X00FF);8 E/ D& \4 x# ~. _
- // temp2=*(__IO uint16_t*)(address+2);% I3 Z# W" ~; ~7 [7 ~) a0 E2 M
- // u48id.ID3 = (uint8_t)(temp2>>8);
- \! w5 b; q q9 E+ {4 `( U4 S - // u48id.ID4 = (uint8_t)(temp2&0X00FF);% m$ s; G, X, `" _
- // temp3=*(__IO uint16_t*)(address+4);: R' z4 Q7 i! \( h
- // u48id.ID5 = (uint8_t)(temp3>>8);( K" @' P7 {( J
- // u48id.ID6 = (uint8_t)(temp3&0X00FF); ) [" }7 r& y8 n
0 p* X5 r7 M6 `8 W6 e) E- u48id.ID1 = FLASH_Readbyte(address);
$ q; L. I; |( A) p9 q* H1 y - u48id.ID2 = FLASH_Readbyte(address+1);" f$ W* I: }+ R! J: `( H8 D
- u48id.ID3 = FLASH_Readbyte(address+2);
3 t1 f& u) T; ~4 R* J2 h - u48id.ID4 = FLASH_Readbyte(address+3);4 X1 V, H5 j' }1 C0 e: d" C6 H
- u48id.ID5 = FLASH_Readbyte(address+4);9 ~$ v8 [2 n4 `$ o% E0 q
- u48id.ID6 = FLASH_Readbyte(address+5);
: I4 F1 |' ]7 X/ g; o
g2 b. }! q2 d0 z: i. @' E$ x- return u48id;- m5 @ b# I$ q. e" c
- }
复制代码 . Y) e9 t' A: v0 B9 g. X% i
测试结果才正常了,如下图:
/ W+ c4 q$ i# S0 D% S! f8 P
( H5 e+ t# c+ k: Q: m2.4.2 问题的分析(大小端模式数据格式)出现上面的问题,其实是和我们经常说的大端模式和小端模式有关的。 STM32使用的是小端模式,简单介绍一下大端模式小端模式数据存放的方式,如下图:
) B6 i$ w1 Q: Y$ p1 M& x
( ^7 I1 f: o5 S3 b. G知道上面的知识,我们在开始的读取函数中是直接读取的半字(__IO uint16_t*)address; ,但是我们写入的时候是一个字节一个字节写入,上面的例子所以我们内存中的数据实际上如下图所示:
1 s, {* {! X4 i, p
% r9 H4 V' W$ Z0 g. s9 M
使用(__IO uint16_t*)address; 去读取,读取出来的数值一个uint16_t类型的数值: 假设是 a,a=*(__IO uint16_t*)addr; 会有 a = 0xEEFF; 所以高8位变成了 0xEE。OK!解释清楚!问题解决! 至此,我们基本上把STM32L051 的EEPROM 和Flash 功能都测试过了,把工程中需要用到的功能做了测试,也学到了一些新的知识,还是实践出结论啊,当初没有自己测试之前看了网上的有关类似的介绍,还是很多误解,这下全部清晰了。 % P$ `$ I) v: C8 {& t* m' |
2.4.3 STM32L071RBT6 EEPROM读写全字问题8 Y6 \; W4 e7 o4 z* L
读问题的出现前面其实测试过,读取全字是可以的,直接使用return *(__IO uint32_t*)address;:便可以读到该地址的全字: - uint32_t FLASH_ReadWord(uint32_t address)
% C" f1 m" Q: w/ @/ @ - {& q: f2 f! [1 L1 A
- return *(__IO uint32_t*)address;
) t W- e9 m# Q% D* c - }
复制代码
: k1 X) _0 A! @, R所以在后面使用过程中,有这么一个函数:
" {6 }5 P7 q: [1 _) c9 K
4 D7 o3 A. W( A8 m7 B# @6 t一开始还真的不知道哪里出了问题?折腾了好一阵才发现调用函数读取ID时就会卡死。
2 m+ P4 m( j) L& y' A) n问题的解决: 因为还有另外一个蓝牙版本的产品,如果是蓝牙设备的ID,因为蓝牙设备的ID是6位的,所以当时读取蓝牙的ID的时候使用的是(蓝牙版本是没问题的):
, Q8 ~! Q( F% D! X
! j! I' y& w9 m0 {" ]% e
其实折腾了好一会儿,后来想着蓝牙是读一个字节,要不要试着把 全字 分为 4个字节,单独读取试一试? 于是学蓝牙把程序分为4个字节读取:
9 e8 l2 Q0 h( _0 l/ l% G( i
: Y0 _6 T* g" \5 S' H( F" C2 A代码也放一下,方便复制: - u32 FLASH_ReadEnoceanID(uint32_t address)
$ f8 O+ e; Z* k+ [ - {% K& @; F8 S1 O' h& N# K9 y+ f# R
- u32 keepid;
1 R7 W' u) i0 q - u8 i;* D' k0 y4 `, J! ` e/ s* ^6 s4 ]
- keepid = FLASH_Readbyte(address);& s7 o+ b2 E6 q, H" {, I
- i = FLASH_Readbyte(address + 1);
0 F& B7 ~5 q( G" a+ c - keepid = (i<<8)|keepid;
2 q) w1 I y7 F! i - i = FLASH_Readbyte(address + 2);/ ` R! w, @4 @/ y7 F3 ~9 p; U
- keepid = (i<<16)|keepid;# Y& h/ ~# O) [6 h- T l
- i = FLASH_Readbyte(address + 3);
9 \: v7 w8 I( g& R1 a - keepid = (i<<24)|keepid;
1 ~9 H6 e- M" M( X" { - return keepid;6 h/ u2 y% ^+ `5 m3 A9 e$ I
- }/ V. j5 T' h# [
9 c9 M8 |! G8 \) e6 ]' S) x0 ^- CHID_STRUCT Flash_PowerOn_Check()+ n6 Y) \( F* K9 V8 y4 g, G4 }
- {& Y2 w3 B, x; ]
' Z" Q7 J( h+ n- CHID_STRUCT PowerOn_ID;
2 L, U+ P! P* ?8 Y$ ~# ~( h - PowerOn_ID.CH1ID = FLASH_ReadEnoceanID(CH1_ID_ADDR);/ h9 a# \ N6 m
- PowerOn_ID.CH2ID = FLASH_ReadEnoceanID(CH2_ID_ADDR);( K5 y1 C) T/ S. w# I3 j
- PowerOn_ID.CH3ID = FLASH_ReadEnoceanID(CH3_ID_ADDR);' e! L- c* Q p. }8 m
- PowerOn_ID.CH4ID = FLASH_ReadEnoceanID(CH4_ID_ADDR);0 Q- }" X1 g4 |0 _. s E
- PowerOn_ID.CH5ID = FLASH_ReadEnoceanID(CH5_ID_ADDR);" `3 G9 Q( v' v3 l8 H' I1 i
- PowerOn_ID.CH6ID = FLASH_ReadEnoceanID(CH6_ID_ADDR);
& t' O+ E! b0 ?& C6 o0 G - PowerOn_ID.CH7ID = FLASH_ReadEnoceanID(CH7_ID_ADDR);
" f$ d1 K( r O6 e - PowerOn_ID.CH8ID = FLASH_ReadEnoceanID(CH8_ID_ADDR);
- X; g/ g- x; I7 ~9 k! G; b( [ - PowerOn_ID.CH9ID = FLASH_ReadEnoceanID(CH9_ID_ADDR);
" S0 @0 T0 W7 J$ c# F3 B; p/ c3 y( N9 L - PowerOn_ID.CH10ID = FLASH_ReadEnoceanID(CH10_ID_ADDR); T2 X8 M% R7 T4 b0 m, O% a- _
- : [4 M9 N5 q/ P- R: s9 E
- return PowerOn_ID;
7 S7 Q0 q8 O' @/ }, f& j% q - }
复制代码 8 ?8 I: |- [. S4 y
测试一下,发现就好了,至于原因,目前还不知道为什么……(最后问题解决有说明,内存字节对齐问题) 6 w& o0 Q' C3 {( X, i' v. G) ?
写问题的出现本来以为解决了上面问题OK了,可是后面测试的时候发现写的时候也有问题: 一直用的写全字函数为: - FLASH_Status FLASH_WriteWord(uint32_t Address, uint32_t Data)5 j1 Y2 D! s4 z' B) l9 |3 a
- {
- T* l% m/ ?# Z- y6 V$ G6 h8 ~
9 \0 A$ Q3 [8 ?; d2 N+ u2 ?, j" K- FLASH_Status i = FLASH_COMPLETE;* t0 d5 V7 y7 Z1 R B5 U
- 3 y. u) X" X0 ^0 D% \2 N
- HAL_FLASHEx_DATAEEPROM_Unlock();
7 f& o2 O: `" i, J6 X1 Z; B7 t - while(HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_WORD, Address, Data) != HAL_OK);
) T+ M8 S5 H1 f. l$ d - HAL_FLASHEx_DATAEEPROM_Lock();' x" p Q4 R$ m
- A$ d% c9 ?! G* h- return i;
- e' `7 b( N$ O6 E* j( i# G - }
复制代码 D& G/ Y1 M2 _# b% R0 M7 H
在程序中会调用此函数进行 ID 保存:
( W; c, Z1 o# L/ v0 ]
8 o8 u+ I* x) I+ @; S但是使用时候发现:
2 Y# c& `6 p8 t& m% a
7 c, ~* V9 o7 z5 v/ w6 ^, i问题的解决: 其实这个问题也莫名其妙,真是说不出来为什么,估计是得详细的查看数据手册,但是还是 因为 在蓝牙的版本上面没有此类问题: 6 l- K- h0 q- [2 ]# n7 T
" } w3 u) [3 ~, Y# ]6 v: j0 o6 z所以这里还是尝试改成 以 字节 方式写入: - FLASH_Status FLASH_WriteWord(uint32_t Address, uint32_t Data)
6 D G/ {+ M7 g! v: F - { F+ ^' P& w2 Q% I! |/ I- d
- - q* P4 A1 ~* j! }
- FLASH_Status state = FLASH_COMPLETE;
! O& |. M8 P+ ~, p7 H1 I - u8 i = 0;
9 T# ?9 [( C0 l# C$ u6 b - u8 writedata[6]={0};
) ?2 N" e& v2 B* F3 E7 I: i) _ - ; j' C9 U3 N( T7 _- U
- writedata[0] = (u8)Data;9 A- Y0 v1 y/ _* u* r
- writedata[1] = (u8)(Data>>8);. r( c' F7 H% |. E1 R+ A# }
- writedata[2] = (u8)(Data>>16);6 Z: L3 C) P$ V# }2 P
- writedata[3] = (u8)(Data>>24);
3 S1 S8 l4 P L0 y3 R - ( T) h# u: I. ~& X+ H; C
- HAL_FLASHEx_DATAEEPROM_Unlock();
% B7 r6 w- c* g: i' [6 b - for(i=0; i<4; i++){+ N0 L( {0 p. M$ B! b+ i
- while(HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_BYTE, Address + i, writedata[i]) != HAL_OK);/ O6 a3 L* W" B b
- }1 [0 s2 C- x: G8 z; F* E
- HAL_FLASHEx_DATAEEPROM_Lock();# q8 Y! U% ]" U) F. C5 C
- 3 E2 g5 c4 U! j" c; Z
- return state;
" y N+ p7 u+ \% S7 G/ G - }
复制代码使用此种方式写入,就不会出现问题! 其实也可以尝试修改地址,使得成为 4 的倍数,可能也不会出问题,这里就不测试了(最后问题解决有还是测试了,内存字节对齐问题) 2.4.3小结使用的芯片为 STM32L071RBT6
! \( |# {, q# i: }- B1 O, D3 m0 M最后问题的解决先直接说结论,就是EEPROM地址定义的问题,应该是4字节对齐(4的整数倍),读取全字的操作才能正常! 上面 STM32L071RBT6 EEPROM 读写全字问题的关键在于,存储地址的定义上,如上面一张图所示:(我在EEPROM区域定义了10个地址,用来存放无线设备的ID数据,如果是蓝牙芯片,那么ID为6个字节,如果是Enocean芯片,那么ID为4个字节,为了保持代码的统一,我在使用保存4个字节的ID数据的地址定义时候沿用的是蓝牙的 EEPROM区域定义)
& r6 y& p8 L8 u& T
7 i6 E- y( p" P* w( k) a* C
那么正如我图中猜想的一样,蓝牙的 ID 6个字节,我是都是通过一个字节一个字节操作,组合起来进行的,所以一切正常。但是对于 4个字节的 ID ,期初是用的 全字的方式,就出问题了,换成一个字节一个字节的操作,看上去是解决问题了。 但是实际上多了一些隐藏问题,暂时也说不清楚,在产品使用的时候,读写ID还是会有莫名其妙的问题,最终还是对当初的这个猜想,地址是不是也需要4字节对齐?进行了修改测试,于是乎,对于 4 个字节 ID的处理,地址改成: % z# A, U+ A: [7 i: ~
4 r" Y4 }* h. P- V! [把地址修改成 4 的倍数以后,上面的读取全字的两个函数便可以正常使用,而不会出上面莫名其妙的问题。 2 W8 q- b' f" p( F/ _
|