本文测试 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的图:
% ?8 p4 V7 F0 G" r
6 y {3 E) e ~$ A
: `! f9 {. Y' h6 M& V
然后来看个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 :
+ g0 C* ]' H) f9 d3 K
- #define FLASH_SIZE (uint32_t)((*((uint32_t *)FLASHSIZE_BASE)&0xFFFF) * 1024U)
0 l0 g0 g/ d: S+ V - #define FLASH_PAGE_SIZE ((uint32_t)128U) /*!< FLASH Page Size in bytes */
复制代码
9 X: C+ y2 B" E/ v2 D' d对于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意为“字节”,是计算机文件大小的基本计算单位; ; m: \3 ?# g; Y5 A! e/ @' Q: }
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,因为怕有时候数据不够放……
7 G7 V) z1 Q/ z1 w2.1 读取函数- //读取指定地址的半字(16位数据)
' ?7 D. Z1 t$ c& {' `, o - uint16_t FLASH_ReadHalfWord(uint32_t address)$ Y' o- Y1 s! Y# N: Y
- {
+ `" l4 g; h, X- m. d* x6 z - return *(__IO uint16_t*)address; , Z& k( [2 E' k$ q. N1 @8 F
- }7 s" c$ ?3 F: K& R( [- a* b
- 5 ~( n5 \3 F+ z! e" v
- //读取指定地址的全字(32位数据)
: f/ d: g0 O9 r ~. p/ ]! w - uint32_t FLASH_ReadWord(uint32_t address)2 [+ Q l/ w' L! T4 o* N
- {- I* {) @3 @2 w' P3 l# d. F0 l
- return *(__IO uint32_t*)address;+ _% U$ r, u. C
- }
复制代码
3 W2 F# i/ @ i- L' ^ a; G) u# Z# `( w
简单测试一下: - u32 read_data1=0XFFFFFFFF;
+ Z( F8 O/ z' \0 T* F( [1 ^ - u32 read_data2=0XFFFFFFFF;; X) A& D. Y: G9 h$ P+ Z* _: L2 s
- ...
& g0 p* E U' } - read_data1 = FLASH_ReadWord(DATA_EEPROM_START_ADDR);, z/ h) O. N: M6 V$ o3 T- t
- printf("the DATA_EEPROM_START_ADDR is: 0x %x \r\n",read_data1);
. R3 X7 x3 d P# z - read_data2 = FLASH_ReadWord(DATA_EEPROM_START_ADDR + EEPROM_PAGE_SIZE);
" `- [! X0 E- T7 L6 R6 E - printf("the EEPROM sceond page test data is: 0x %x \r\n",read_data2);
复制代码 ^3 j: V9 {" G0 \. M/ v- a* y
没有写入数据读取的值应该都是0。 ; W+ y6 O# r' D% K* _+ ]
2.2 EEPROM写函数对EEPROM的写函数:stm32l0xx_hal_flash_ex.h中函数如下: - HAL_StatusTypeDef HAL_FLASHEx_DATAEEPROM_Unlock(void);
6 Q: l; W7 h" e( q/ ^ - HAL_StatusTypeDef HAL_FLASHEx_DATAEEPROM_Lock(void);
& I) v* u: ^; n+ C- s0 Z1 k
% f9 ]" f7 e. x& L8 P0 ~# {- HAL_StatusTypeDef HAL_FLASHEx_DATAEEPROM_Erase(uint32_t Address);
* ]: Q0 H/ a& R0 V" n - HAL_StatusTypeDef HAL_FLASHEx_DATAEEPROM_Program(uint32_t TypeProgram, uint32_t Address, uint32_t Data);
复制代码 + z2 A. z) @- y4 U+ i
通过函数看来,可以直接用,但是这里有一个问题 需要测试一下,擦除是否会擦除整个扇区,有待验证!! 答:EEPROM的擦除可以直接擦除某个地址的字,不会擦除整个片区 EEPROM的操作相对Flash,比较简单,直接使用HAL库中的函数即可完成 - HAL_FLASHEx_DATAEEPROM_Unlock();
6 i# w! ?! i, _6 ? S% \) s( v- J - HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_WORD, DATA_EEPROM_START_ADDR, write_data1);" [# b& H/ R9 r. r& Q& p0 `
- HAL_FLASHEx_DATAEEPROM_Lock();( p, T, {, z# U6 v9 \
- ...
7 m8 c$ R$ P4 J2 }% o - if(btn_getState(&K1_BUTTON_150mS) == BTN_EDGE2){5 h8 V. M9 _. g- l5 p
- printf(" K1 150ms button!,EEPROM_Erase test\r\n");. [# {; c; P) ` K8 B( t
- HAL_FLASHEx_DATAEEPROM_Unlock();% J' Z; w# @- c1 P. d2 C5 J% {- m+ M
- HAL_FLASHEx_DATAEEPROM_Erase(DATA_EEPROM_START_ADDR+4);
) ~7 W g f' b/ { - HAL_FLASHEx_DATAEEPROM_Lock();
3 W7 X7 [* \8 ~4 j4 g* i - HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
9 V- A/ D e, @ - }
. s6 B: [2 I% f - ...& ^' ^$ m7 H! t6 Z* h( f
- if(btn_getState(&K2_BUTTON_150mS) == BTN_EDGE2){5 t/ \7 v* d1 i% }
- printf(" K2 150ms button!EEPROM_read test\r\n");4 Y# [: h# n4 v5 |& K
- read_data1 = FLASH_ReadWord(DATA_EEPROM_START_ADDR);
: s. J) f2 ~+ Q7 k# N/ i0 w1 p7 y - printf("the DATA_EEPROM_START_ADDR is: 0x %x \r\n",read_data1);5 P [9 Y" {/ p5 ]) q$ x* ~" _
- }
复制代码 : v' W0 j* N3 r5 l
按照上面的例子,擦除DATA_EEPROM_START_ADDR+4的地址不会影响DATA_EEPROM_START_ADDR地址的开始写入的数据 写入一样,如果不在意以前的数据,直接写入就可以。 总结来说EEPROM的使用还是很好用而且简单的。而且EEPROM是可以按照字节,半字,全字写入的,测试了一下,是右对齐 右对齐什么意思呢,打个比方就是如果在地址 addr 中,本来写入全字 0x12345678 然后直接在EEPROM 的 addr 这个地址,写入半字 0xFFFF, 再读取全字的话,addr 地址的全字就变成了 0x1234FFFF ,这个具体的为什么在地址写入半字,不会直接从地址开始占用2个字节,是因为地址的类型为 uint32_t ,所以该地址就是 4个字节类型的数。
9 S. ^1 }7 R a! _0 n( b4 L" t写入问题说明修改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();4 {1 }5 E0 y: d6 P3 P
- HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_BYTE, DATA_EEPROM_START_ADDR, 0X88);" o2 p( W' N! B" E% P6 {$ K' [4 T
- HAL_FLASHEx_DATAEEPROM_Lock();5 X; ~' U% }7 `& u% y8 i
- read_data1 = FLASH_ReadWord(DATA_EEPROM_START_ADDR);' K$ f0 u) u$ e4 q# o9 F
- printf("the DATA_EEPROM_START_ADDR is: 0x %x \r\n",read_data1);
复制代码
; |' n& P8 \2 u7 V. F ~最后在 stml0_flash.h 中把函数完善声明一下,使得主函数中的程序更加简洁。 - void MY_DATAEEPROM_Program(uint32_t TypeProgram, uint32_t Address, uint32_t Data) 9 i a* b7 N/ o6 U% S" C( V# S; m7 A
- {- M7 b$ ~; J( z0 z
- HAL_FLASHEx_DATAEEPROM_Unlock(); + e1 z2 i$ f& S: i, [6 d
- HAL_FLASHEx_DATAEEPROM_Program(TypeProgram, Address, Data);+ N1 J) S- n. Q
- HAL_FLASHEx_DATAEEPROM_Lock();9 C0 _# X+ T; W# k
- }
复制代码 4 S* o+ X$ u: ?6 F5 G/ X
那么L051 的EEPROM的测试就到这里,其实有EEPROM,在项目中的保存数据的功能就问题不大了,但是我们既然开始了,就把L051 Flash的读写也测试一下。 - N- H. {' _* B1 `" Z
2.3 Flash写函数Flash的读取其实和EEPROM一样,主要是写函数,来看一下stm32l0xx_hal_flash.h 中有哪些函数 - /* IO operation functions *****************************************************/4 r9 {! A3 ]& U
- HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint32_t Data);
, m L1 V/ V7 }/ t. o5 c7 G# X - HAL_StatusTypeDef HAL_FLASH_Program_IT(uint32_t TypeProgram, uint32_t Address, uint32_t Data);' I9 F5 x& h1 i+ ]- A
& m6 J$ Q2 v2 `/ z1 K- /* FLASH IRQ handler function */
% {5 e9 Q" m$ z; s$ v7 G/ e - void HAL_FLASH_IRQHandler(void);
# k- o. q: G' ? - /* Callbacks in non blocking modes */5 ?$ O- u. |$ K3 R
- void HAL_FLASH_EndOfOperationCallback(uint32_t ReturnValue);/ c% j3 @0 K$ _- i7 W( R
- void HAL_FLASH_OperationErrorCallback(uint32_t ReturnValue);' x9 g1 d* Y8 _+ a
- 8 _* T) Z: d+ f3 y* j: c
- /**
3 N% {+ ~# X6 q1 q% ^" B - * @}
9 M( g) m. l/ V) I9 N1 V - */
( {, }7 G3 p$ I; c! [" h
A8 w6 t. n+ v" N7 |- /** @addtogroup FLASH_Exported_Functions_Group24 R) H7 ]+ f4 V" Q+ i1 v' W. O" k
- * @{2 t% w. X. i% e0 K5 i; r
- */
# A/ L4 y( j$ s1 M0 o, p - /* Peripheral Control functions ***********************************************/+ U" h3 Y: G' M4 h3 |
- HAL_StatusTypeDef HAL_FLASH_Unlock(void);
- |! r' ^4 e+ I0 b - HAL_StatusTypeDef HAL_FLASH_Lock(void);
2 O* d9 M* q. i f8 ~; V* D& } - HAL_StatusTypeDef HAL_FLASH_OB_Unlock(void);! z, u# h) Y; D, h* P4 g$ n- D$ h& I
- HAL_StatusTypeDef HAL_FLASH_OB_Lock(void);
% H, m/ _; G! S8 A% p - HAL_StatusTypeDef HAL_FLASH_OB_Launch(void);
复制代码 ( f( F2 k7 W9 o& N, f+ F8 B3 q
有点忙,Flash的后面再也,看了几个demo,只需要做几个测试就可以;
+ Z, z6 S6 w+ ^; x$ Q# N2021.8.5 今天有空来接着测试一下L051 Flash的读写,看了下HAL_FLASH_Program函数: * ^, r( y1 q3 ?! U1 @2 V# ~
- HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint32_t Data)& B4 T! e! S8 K
- {
9 L$ L3 B# C5 o4 s. y* T5 g - HAL_StatusTypeDef status = HAL_ERROR;# e4 |0 N4 U) E. L
-
, n1 J1 L1 k K- u - /* Process Locked */# d# b$ R3 E2 t* ]1 R
- __HAL_LOCK(&pFlash);7 F% b7 O. Z' ?
- # b( v" n8 ~3 L" g V4 H( S
- /* Check the parameters */
" t/ Y" |0 `3 g# H5 ]8 m0 o - assert_param(IS_FLASH_TYPEPROGRAM(TypeProgram));# B) e- f/ h z6 S' R% O- l
- assert_param(IS_FLASH_PROGRAM_ADDRESS(Address));- x: P; x6 R2 \: x
- # U/ \* p7 R1 X$ ?1 d" N9 f
- /* Wait for last operation to be completed */- X; D% V; ^! V* x5 v9 Y
- status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
& X% G% e" R) p+ c4 r8 X. U - / S* a8 K' R9 _, p* c9 y' ~
- if(status == HAL_OK)
, e9 e9 _* k& } - {
2 P% {/ O: v8 C* h( p - /* Clean the error context */0 J% X1 f' t: A ]: ~8 X
- pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;0 r; n7 Y/ r& {4 B5 ^% J' k
- % U: l! X: k3 E3 ^. O
- /*Program word (32-bit) at a specified address.*/
% I/ L; Y- S7 U! Y# x) y - *(__IO uint32_t *)Address = Data;
5 l) A5 `6 ?" F: F; e - ) \) P; g( J* [9 ]7 h* B1 G
- /* Wait for last operation to be completed */
' x+ i& I8 \& W$ I/ z( m - status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
) S. _0 h5 ?7 C4 z - }
$ p4 h, r8 i. W/ i9 c - 8 U" v; p; a. d2 F: T# w
- /* Process Unlocked */ [! d1 h. Y F) D1 L8 ]
- __HAL_UNLOCK(&pFlash);
9 r% {* j: H: I f& d1 t
: R) ]5 k/ j5 E6 m) m, @3 q) O- j- return status;
- E) v8 N0 E+ B( V - }- s! D& Z G1 [
复制代码
, T) j8 [9 T6 E7 f: s# i- F这里也再次说明了,L051的写必须以字的方式写入。 不管了,先测试一下,不擦除直接写入,这里先定义一下写入的地址,前面我们已经知道了L051 flash一共 512页,每页128bytes,所以我们直接拿最后面的几页来测试 - #define ADDR_FLASH_PAGE_505 0X08000000 + 128*504 //
% o" D' F0 W- d7 U/ m. K - #define ADDR_FLASH_PAGE_506 0X08000000 + 128*505 //0 o4 p5 X9 u7 |/ h1 [; t7 T3 m, V
- #define ADDR_FLASH_PAGE_507 0X08000000 + 128*506 //. g/ {9 X9 F1 \' T: M) @
- #define ADDR_FLASH_PAGE_508 0X08000000 + 128*507 //- B T" P" S" ]- ]: Q
- #define ADDR_FLASH_PAGE_509 0X08000000 + 128*508 //
# R7 u, ~5 Y N; T - #define ADDR_FLASH_PAGE_510 0X08000000 + 128*509 //
- B8 `+ i; x/ O* X; n: ]* B, P - #define ADDR_FLASH_PAGE_511 0X08000000 + 128*510 //$ J7 C: \$ V2 X8 ?0 `3 X% A5 X' T$ k
- #define ADDR_FLASH_PAGE_512 0X08000000 + 128*511 //最后一页
复制代码开始先不擦除,直接在最后一页写入一个字读取一下试试,整理一下写入函数: - void MY_DATAFLASH_Program(uint32_t Address, uint32_t Data) 3 C+ n/ N" K2 I* A3 }7 H z
- {* e; R! r4 z" M; x l4 N
- HAL_FLASH_Unlock();
" s! q6 t( A2 T/ i5 ?" d% M - if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, Data) == HAL_OK){
1 {4 K$ n" a4 _6 j3 K! | - printf("write data 0x%x OK\n", Data);
, h- Y1 K1 `7 R6 x - }
0 g" Y$ i' ^% n6 }/ c, i - else{0 }2 i5 T: Z" F0 o/ F2 Q
- printf("failed!!!\n");
/ {# [5 P' J7 K/ L# \ - }
& l3 a1 R' a; u i - HAL_FLASH_Lock();
' A, `* O f* v/ q% J" i - }
复制代码 # B8 { O9 X% [0 h' \2 _
测试一下; - MY_DATAFLASH_Program(ADDR_FLASH_PAGE_512,write_data2);& U' n$ b+ l; X# T8 Z$ B
- read_data1 = FLASH_ReadWord(ADDR_FLASH_PAGE_512);8 @* I5 D- E7 _* }) \$ p; ^
- printf("the ADDR_FLASH_PAGE_512 is: 0x %x \r\n",read_data1);
复制代码 ! l+ B& R p9 J2 A
在没有写入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)
# _+ p# W; L. ~, y - {7 T/ i$ P. `0 W. V: c
- FLASH_EraseInitTypeDef EraseInitStruct;# |5 e& J* T+ v+ A* r; w& e
- uint32_t checkdata;/ i5 d) j% i. Z3 N. _0 J
- uint32_t PAGEError = 0;
# l2 z4 r. v9 c, B, w/ q - checkdata = FLASH_ReadWord(Address);7 Z3 d- ?& Q) ]9 t- P
- HAL_FLASH_Unlock();
6 A* v& q, q j1 K - /*如果是0,直接写*/
" f/ v/ f3 m( I* ~ [. X1 s - if(checkdata == 0){
& m+ i$ v% D! h - if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, Data) == HAL_OK){3 | v6 h4 y4 S# g0 F8 _3 W
- printf("write data 0x%x OK\n", Data);
: `, F8 c" ?/ ] - }. v1 _7 F. v2 u$ b% \
- else{
0 ^& g" N. c9 T - printf("failed!!!\n");7 g) o. U. n& v. ~' b! V' Z+ U
- }3 C0 @ A3 B ~) _) v$ B; a# e6 `
- }
0 N. _# i: O% c4 y! u8 a4 f* g T - /*否则擦除再写*/5 G- k4 |" }. b( x0 }7 n D* g2 f
- else{
{# }) C4 |: c' X b - __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);
+ _. K6 H- a) v
" s* l, b+ d7 U- EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; // 刷除方式3 ~5 T1 w5 ?6 g3 g9 }% d/ \6 m. e: h
- EraseInitStruct.PageAddress = Address; // 起始地址2 ^3 |' W: ^" X+ j0 v! B
- EraseInitStruct.NbPages = 1;9 ^+ F( A `7 E/ t$ {8 U( `
4 c$ N W7 p% |9 _+ |4 J7 r- if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
- V w7 ]8 L* ~+ A9 z - {. z5 o4 l7 @8 p3 ~$ W$ I* r( _- _6 e% f
- // 如果刷除错误
3 C; y7 t$ c: g$ N( @% R - printf("\r\n FLASH Erase Fail\r\n");3 c7 N: z2 `. D$ s1 Y0 a
- printf("Fail Code:%d\r\n",HAL_FLASH_GetError());
6 D4 h* ]4 v+ ~7 V - printf("Fail Page:%d\r\n",PAGEError);
. s) Q# Q+ s! O$ v' p( Y" W& ` - }
4 r, G, R' G6 n8 m2 ? - . i5 C1 @& h7 P1 a1 Z, }% t
- if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, Data) == HAL_OK){
( p1 O+ T! k% Q \" S, A4 w - printf("write data 0x%x OK\n", Data);
. k1 `% b- g5 e4 F& N4 j - }' \) \, n) z" o: G/ ~
- else{/ [: W# O' L# s9 A6 U
- printf("failed!!!\n");
! J/ Y( U0 @5 n: ~% W/ L$ Q - }
" R1 B8 V3 H/ W. \% d% K- [
1 p( w) S& N/ C3 l. u; Q- }
5 l4 [. C6 G, }8 L" D* N - HAL_FLASH_Lock();7 i- ?* M2 R6 ^; M- F
- }
复制代码
0 k# w' l! y9 _& V) F$ x2 t自己修改了一个函数, 改成这样以后,就能直接在想写入的地方写入数据了,到这里,flash足够我项目中的使用了。但是还有最后一个疑问,就是擦除的一页到底是不是128bytes我来验证一下。 - u32 write_data1 = 0X12345678;/ ]; _, C/ ^6 ?% H( t8 G) i
- u32 write_data2 = 0X87654321;) j3 g0 M+ x! ~( X
- u32 write_data3 = 0XFFFFFFFF;, p9 P" G: G: Z! d0 L$ S7 \9 r6 _
2 d2 O+ e# Y' U4 z3 H; n9 E- MY_DATAFLASH_Program(ADDR_FLASH_PAGE_508 + 124,0X508508FF);
9 |0 n: j9 a# L - MY_DATAFLASH_Program(ADDR_FLASH_PAGE_509,write_data3);& B4 G: Z) X/ o( J, H
- MY_DATAFLASH_Program(ADDR_FLASH_PAGE_509+4,write_data2);
3 t+ c! I9 C& S6 d, P8 v8 B - MY_DATAFLASH_Program(ADDR_FLASH_PAGE_509+8,write_data1);8 {' H1 \. n7 _1 N( T, N. w7 f; k3 V
- MY_DATAFLASH_Program(ADDR_FLASH_PAGE_510,0X510510FF);
( s/ o M* M5 t/ V/ n( ]" | - 9 o8 y1 f3 o9 h/ D
- read_data1 = FLASH_ReadWord(ADDR_FLASH_PAGE_508 + 124);
) `# m- D) z! u8 v - printf("the ADDR_FLASH_PAGE_508 last is: 0x %x \r\n",read_data1);, b/ T$ L+ Y" k+ c; j3 ~+ \8 g
- read_data1 = FLASH_ReadWord(ADDR_FLASH_PAGE_509);* r7 y! K; Y4 f& K. j! y. C
- printf("the ADDR_FLASH_PAGE_509 1 is: 0x %x \r\n",read_data1);% i( p m2 G2 G t/ t0 d
- read_data1 = FLASH_ReadWord(ADDR_FLASH_PAGE_509 + 4);
5 h1 g* L$ r, u0 k - printf("the ADDR_FLASH_PAGE_509 2 is: 0x %x \r\n",read_data1);3 r1 g c9 n+ i9 R+ V( I7 G
- read_data1 = FLASH_ReadWord(ADDR_FLASH_PAGE_509 + 8);$ [& L7 s8 r1 T5 ^: m( x8 _7 f
- printf("the ADDR_FLASH_PAGE_509 3 is: 0x %x \r\n",read_data1);
& c2 H7 b1 i& K8 ^ - read_data1 = FLASH_ReadWord(ADDR_FLASH_PAGE_510);
, F8 ?/ O A& h/ `3 Y, j - printf("the ADDR_FLASH_PAGE_510 first is: 0x %x \r\n",read_data1);' e" I) z4 |5 ~; w/ [+ ?6 l
5 a% x# o) v4 Z0 w/ w4 H; V- if(btn_getState(&K2_BUTTON_150mS) == BTN_EDGE2){2 T/ l: a+ Y/ {# m j$ y; H( |( M
- printf(" K2 150ms button!EEPROM_read test\r\n");
, q" w! k P( b& u }! q2 W - read_data1 = FLASH_ReadWord(ADDR_FLASH_PAGE_508 + 124);& I6 A, v$ s9 b1 h
- printf("the ADDR_FLASH_PAGE_508 last is: 0x %x \r\n",read_data1);
5 }) \- Q3 Y5 A9 i. F - read_data1 = FLASH_ReadWord(ADDR_FLASH_PAGE_509);
1 d5 m& k! i, G$ a0 h( h4 K& K( d" } - printf("the ADDR_FLASH_PAGE_509 1 is: 0x %x \r\n",read_data1);8 W) u5 A9 C& d# t; o
- read_data1 = FLASH_ReadWord(ADDR_FLASH_PAGE_509 + 4);8 L+ l2 m7 `9 ~% ~1 X
- printf("the ADDR_FLASH_PAGE_509 2 is: 0x %x \r\n",read_data1);
% l, b$ r k2 S+ Q6 y2 T - read_data1 = FLASH_ReadWord(ADDR_FLASH_PAGE_509 + 8);
8 g5 W( f; ^; N1 f( t - printf("the ADDR_FLASH_PAGE_509 3 is: 0x %x \r\n",read_data1);7 O, Z: {; x2 a4 u8 Y
- read_data1 = FLASH_ReadWord(ADDR_FLASH_PAGE_510);' ~7 N' Q" H' T7 q3 G- \4 Z8 T
- printf("the ADDR_FLASH_PAGE_510 first is: 0x %x \r\n",read_data1);. T3 M1 G- H5 o6 M9 V4 L
5 q1 }( ]( { m! ?( J$ h- }- N$ {' X) x% K3 P8 c- x4 ]8 O
- if(btn_getState(&K1_BUTTON_150mS) == BTN_EDGE2){
& p5 x& c& i/ o2 u. w - // printf(" K1 150ms button!,EEPROM_Erase test\r\n");
G+ T( Q- p5 S: g2 m/ r) { - // MY_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_WORD, DATA_EEPROM_START_ADDR, write_data1);0 q& N# P3 p, z, y7 I
- printf(" K1 150ms button!,flash write test\r\n");
, Y* ]6 M1 [8 D" V% M - MY_DATAFLASH_Program(ADDR_FLASH_PAGE_509,0X33333333);
: u, o% @ r$ e - HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
$ D% L( O; i0 K1 e/ S, o# K3 B9 h - }
复制代码
7 q2 [' C3 o$ C# ~9 I9 a( k5 J# N因为地址位置如果有数据的话会擦除一页再写入,所以我们看了一下508页最后一个地址,和510页的第一个地址数据,对509页的数据进行了操作,结果发现不会改变508 和510的数据,509页的数据会全部清除! $ h) ?3 V; p4 z% R8 F
% y4 x5 r+ b' n
) c0 K0 x1 ~" L# `
所以得出的结论显而易见,flash擦除按照一页一页擦除, 在L051上面一页为128bytes,而且擦除后数据全部为 0;
; E4 m/ p- P0 g, A; U2.4 读写EEPROM的后续问题最近有一个项目,因为缺货 STM32L051R系列缺货,买了 STM32L071RBT6 替代:
0 Q3 Q. s% `' ?% @
6 s; Q7 W; R* y0 ~看了一下地址,其实我们上面所有的测试代码基本都是可以直接用的,代码直接用STM32L051的代码也是可以的,实际项目中,还是使用EEPROM比较方便,所以在使用EEPROM的时候,发现了一个问题(并不是换了芯片的问题),还是数据读取和写入的问题。 5 a# ]; Y. u$ P2 a6 f
2.4.1 问题的出现和解决下面程序的硬件平台是 STM32L071RBT6,首先在程序中,有一个写ID的函数: k+ q2 R/ n0 f3 Q
8 s9 Y& E, n4 x' q4 W `写入IO是通过字节的方式 byte 写入的,写了6个字节(蓝牙设备的ID)。 然后最初读取的函数用的是:
" \4 L3 Y5 z0 k& F3 f
# J2 f: e z) Y) z3 ?* s. s: h使用这个读ID的函数,问题就出来了。上图代码中,我读取ID使用的是半字读取,处理方式是把读到的半字前面8位给ID1, 后面8位给ID2, 但是测试中发现 数据读出来与想要的相反,什么意思呢,看下面的测试说明: 上电打印出EEPROM中读取的一个地址的,每个ID(每个ID是uint8_t类型)的数据,在代码开始定义了测试数据: - BlueID_STRUCT test;; L) h: r$ _" ]
- ...8 L5 [7 r5 q" R A
- /*
4 a" k8 ^7 d6 k C# K; A. e6 j - CHBlueID_STRUCT Flash_PowerOn_BlueCheck(), E, H1 F% J# t1 g1 l' R8 c
- {
- u5 q. s% ]+ k6 Z - , q" U3 p! t: o* J
- CHBlueID_STRUCT PowerOn_ID;
6 G5 Z* ^# u( b( o# u. s' J - PowerOn_ID.CH1ID = FLASH_blueIDRead(CH1_ID_ADDR);7 O" L# k9 ]" f; O
- PowerOn_ID.CH2ID = FLASH_blueIDRead(CH2_ID_ADDR);
Y& b! R5 x# F( S - PowerOn_ID.CH3ID = FLASH_blueIDRead(CH3_ID_ADDR);
) }. s5 C; U% B - PowerOn_ID.CH4ID = FLASH_blueIDRead(CH4_ID_ADDR);' t. m8 r; T+ l9 y
- PowerOn_ID.CH5ID = FLASH_blueIDRead(CH5_ID_ADDR);4 ~9 k9 r% `/ Q& j. _, @7 r& {# t
- PowerOn_ID.CH6ID = FLASH_blueIDRead(CH6_ID_ADDR);8 d5 f9 M( R" A7 Z$ W S
- PowerOn_ID.CH7ID = FLASH_blueIDRead(CH7_ID_ADDR);
; n; L( S: [7 {+ P& E* W! }- E - PowerOn_ID.CH8ID = FLASH_blueIDRead(CH8_ID_ADDR); |. w8 p" t8 e& ~+ l4 A& m
- PowerOn_ID.CH9ID = FLASH_blueIDRead(CH9_ID_ADDR);
1 F- z& L3 t/ [, H2 `% O - PowerOn_ID.CH10ID = FLASH_blueIDRead(CH10_ID_ADDR);
7 m. J# J: b$ I, s$ Z - U& R! S8 w L1 W# Q# d' V. l
- return PowerOn_ID;
; F' x/ D) z; A - }! ?; p( A/ R% a& b+ K7 W0 _2 `( S, w
- */
5 m; |6 J/ { @4 F$ S! V1 I. ?! N - BlueChipID = Flash_PowerOn_BlueCheck(); //上电先把ID读出来做比较
: c, N9 G5 }% h( Q; n# i3 c - //打印一个出来测试,看结果
+ m% H- ~, `/ w" Q$ P - 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);
; A2 C# M% T: s) K! p) {" G6 G$ Q
) p4 z1 C. `5 r$ g* t0 a" v! a" ?" q- test.ID1= 0XFF; //结构体每个元素是 uint8_t 类型: v' F* i2 r& O' r: ~! W* J
- test.ID2= 0XEE;$ t1 P/ |$ t5 o/ A
- test.ID3= 0XDD;# o4 a# ?6 e4 B7 K
- test.ID4= 0XCC;
A" O% L" A5 U, B+ ?2 Y7 W - test.ID5= 0XBB;
6 M3 Y# |( Y$ D7 I9 q - test.ID6= 0XAA;
8 ]; b& W2 x0 A# ^/ I& q/ \- c
# Y: I! k; d7 W2 b6 q: b- while (1){...}
复制代码
/ d2 k8 n9 _0 q3 r+ |# n在程序中通过操作,写入测试数据,调用上面提到过的写ID的函数,写ID的函数是每个字节每个字节写的: * q Z J$ L$ J: P
5 M: r8 s( v5 N# a i d1 c按我们希望的结果来说,读出来按照顺序打印,应该是:0xff,0xee,0xdd,0xcc,0xbb,0xaa 。测试实际上是:
. m$ s1 F8 ` S: F* i( S* c
e9 D4 _/ x* v, j$ k3 V3 G为了确实是读的问题还是写的问题,添加了读字节的函数:
7 l; w2 _; k# C. d7 h* Y) w+ X
2 l& w9 ^" C, X: ^7 o' x/ o
, N% M @6 P8 w' M ~" Z
打印的结果:
3 ~& y/ g3 O# B! S
% Y/ V' C) ?% o! Y: v说明确实是ID的读取函数出的问题,是因为使用的半字读取,问题处理不麻烦,我们把读取函数修改一下: - BlueID_STRUCT FLASH_blueIDRead(uint32_t address)
. E$ x+ Q" p+ E5 ]0 i* z - {
' t* D' s7 H8 Q) F8 _ - BlueID_STRUCT u48id;
1 H. M% n5 O3 z- Z( {$ B - // uint16_t temp1,temp2,temp3; /**(__IO uint16_t*)address; */* h& m6 G) J: [7 \* k" |4 U7 \' f
- // temp1=*(__IO uint16_t*)address; 5 ]" w4 ~1 {# Q# Y: F5 ?
- // u48id.ID1 = (uint8_t)(temp1>>8);; X/ p9 I1 O' [* w
- // u48id.ID2 = (uint8_t)(temp1&0X00FF);
) w6 _: x- L; ?# X8 }% J - // temp2=*(__IO uint16_t*)(address+2);* z+ k* i% m. L& c" f% M1 q
- // u48id.ID3 = (uint8_t)(temp2>>8);
$ P2 m: }8 d' T; v e, ?3 Y - // u48id.ID4 = (uint8_t)(temp2&0X00FF);
2 y! U& T8 v' A' ^( y - // temp3=*(__IO uint16_t*)(address+4);
) s+ ?1 @1 E% ^& g. e/ O4 B+ B* B - // u48id.ID5 = (uint8_t)(temp3>>8);
B# ^+ k$ j" q; I6 {" @3 v' U - // u48id.ID6 = (uint8_t)(temp3&0X00FF); + M6 n, _# N9 z4 }' t# A/ p" |, s
- : [3 q# }$ h+ W# Y+ s' E
- u48id.ID1 = FLASH_Readbyte(address);
: y! p. L! }/ x, G, g - u48id.ID2 = FLASH_Readbyte(address+1);; J1 D7 r) D+ F, U- J* G9 g
- u48id.ID3 = FLASH_Readbyte(address+2);
2 P+ ^% V/ Q& J: h; y - u48id.ID4 = FLASH_Readbyte(address+3);4 J7 j4 V" C' M& e
- u48id.ID5 = FLASH_Readbyte(address+4);1 p4 F5 ]) V$ H/ ^! T3 t& q- |
- u48id.ID6 = FLASH_Readbyte(address+5);
+ }+ u# ~/ _ r% Z1 |; n1 ]& [ - : j6 e% K1 c1 Z: l, f" h7 D
- return u48id;
' _ ], H' n6 ?! n - }
复制代码
0 ?3 C C4 t: p* Q5 m- b# U测试结果才正常了,如下图: ! c+ ?+ e" d: }* G' Y% Y
+ g, V9 z) Z4 B+ _1 F) J3 j& _2.4.2 问题的分析(大小端模式数据格式)出现上面的问题,其实是和我们经常说的大端模式和小端模式有关的。 STM32使用的是小端模式,简单介绍一下大端模式小端模式数据存放的方式,如下图:
, }. J. B+ @$ W0 ]4 I
1 b5 c6 i' @/ n! D7 L' [! P) d
知道上面的知识,我们在开始的读取函数中是直接读取的半字(__IO uint16_t*)address; ,但是我们写入的时候是一个字节一个字节写入,上面的例子所以我们内存中的数据实际上如下图所示:
! N( X1 ~ y9 d8 g5 ]
; a! a0 w+ g2 ?* q使用(__IO uint16_t*)address; 去读取,读取出来的数值一个uint16_t类型的数值: 假设是 a,a=*(__IO uint16_t*)addr; 会有 a = 0xEEFF; 所以高8位变成了 0xEE。OK!解释清楚!问题解决! 至此,我们基本上把STM32L051 的EEPROM 和Flash 功能都测试过了,把工程中需要用到的功能做了测试,也学到了一些新的知识,还是实践出结论啊,当初没有自己测试之前看了网上的有关类似的介绍,还是很多误解,这下全部清晰了。
% A Y( Y- J/ J5 i4 Q2.4.3 STM32L071RBT6 EEPROM读写全字问题" ?9 E- g1 ~* O0 R' I
读问题的出现前面其实测试过,读取全字是可以的,直接使用return *(__IO uint32_t*)address;:便可以读到该地址的全字: - uint32_t FLASH_ReadWord(uint32_t address)
/ f3 J& w M, F( N - {0 p6 r* H) n: y& A4 o
- return *(__IO uint32_t*)address;; i! a7 k* \8 g- f
- }
复制代码 0 u2 A# I! e' R& J- k1 E' n
所以在后面使用过程中,有这么一个函数:
) K+ U* ]: w5 n5 q6 ^. w
; W- C& i3 t. k Q- V: g( R# W
一开始还真的不知道哪里出了问题?折腾了好一阵才发现调用函数读取ID时就会卡死。
% t& P$ p! j7 q/ _( o问题的解决: 因为还有另外一个蓝牙版本的产品,如果是蓝牙设备的ID,因为蓝牙设备的ID是6位的,所以当时读取蓝牙的ID的时候使用的是(蓝牙版本是没问题的): $ h6 s) T" n5 L @/ B
0 k+ m/ E" ]0 t. }9 ~/ |& F- ^其实折腾了好一会儿,后来想着蓝牙是读一个字节,要不要试着把 全字 分为 4个字节,单独读取试一试? 于是学蓝牙把程序分为4个字节读取:
' z) I* C1 N3 [! Q* D5 `
# Q: `7 j) t9 M7 v4 z- h& @代码也放一下,方便复制: - u32 FLASH_ReadEnoceanID(uint32_t address)6 p( D2 m$ x4 r2 A* |7 Y, O
- {
" R8 ^ G# h0 f; n. {+ k4 f% L - u32 keepid;
1 n8 B% P4 u# D6 o0 F, w/ a - u8 i;
6 i' b+ Z L# d' |7 T& @+ [, G - keepid = FLASH_Readbyte(address);
5 ^5 t \( L( ?- N* H+ h" ?* ? - i = FLASH_Readbyte(address + 1);
3 i' e5 u4 O9 f - keepid = (i<<8)|keepid;" d1 l5 `; y2 M% p+ ^, X& o
- i = FLASH_Readbyte(address + 2);( g7 _0 J4 l p' ^+ r0 G
- keepid = (i<<16)|keepid;1 r7 R3 D: |5 ]
- i = FLASH_Readbyte(address + 3);
" D2 x3 N# t# z - keepid = (i<<24)|keepid;; K5 g. O0 q! l3 R
- return keepid;4 M- k& b- n ? T. M
- }. K, h) w9 q8 t6 Z5 I
# a. c- q7 E1 H5 P- CHID_STRUCT Flash_PowerOn_Check()
$ X g, m2 D* |! u7 V& _+ o% B - {& a$ x+ k! z& o$ U" Y7 Z$ Z7 r
- 1 v7 r2 s1 z) X9 u3 [! p
- CHID_STRUCT PowerOn_ID;
' {$ G# @8 u, z8 w# }" ^7 z8 P - PowerOn_ID.CH1ID = FLASH_ReadEnoceanID(CH1_ID_ADDR);
6 P. f0 W# R5 Y4 x+ P2 P4 w - PowerOn_ID.CH2ID = FLASH_ReadEnoceanID(CH2_ID_ADDR);
# N+ z# X6 S$ A% a, V# I2 { - PowerOn_ID.CH3ID = FLASH_ReadEnoceanID(CH3_ID_ADDR); w* g. k1 \' ^
- PowerOn_ID.CH4ID = FLASH_ReadEnoceanID(CH4_ID_ADDR);" |: C% t- n+ B6 F6 c O
- PowerOn_ID.CH5ID = FLASH_ReadEnoceanID(CH5_ID_ADDR);
1 Y b" ], V3 d - PowerOn_ID.CH6ID = FLASH_ReadEnoceanID(CH6_ID_ADDR);
4 \ i& K$ |) ^* z9 O" W - PowerOn_ID.CH7ID = FLASH_ReadEnoceanID(CH7_ID_ADDR);. v. V* P+ x+ Y) W. }
- PowerOn_ID.CH8ID = FLASH_ReadEnoceanID(CH8_ID_ADDR);
4 l6 h" r( V6 V: k2 Z+ O# ^7 r - PowerOn_ID.CH9ID = FLASH_ReadEnoceanID(CH9_ID_ADDR);5 t s. V# k& \: L! o
- PowerOn_ID.CH10ID = FLASH_ReadEnoceanID(CH10_ID_ADDR);
' N' G) }2 N: |: E3 u& P - % |( h0 F3 U# f7 r7 J& M
- return PowerOn_ID;: Q8 d( z: G" M
- }
复制代码 7 p. v# q4 _! v
测试一下,发现就好了,至于原因,目前还不知道为什么……(最后问题解决有说明,内存字节对齐问题)
/ ?* b. R: ?, ~5 ~! ~6 A* N6 s写问题的出现本来以为解决了上面问题OK了,可是后面测试的时候发现写的时候也有问题: 一直用的写全字函数为: - FLASH_Status FLASH_WriteWord(uint32_t Address, uint32_t Data)
: I0 u* m2 x) `, Z& x5 V7 D; T - {# l/ K0 k& A" Q+ A
- $ x" p7 A: @; T
- FLASH_Status i = FLASH_COMPLETE;( r& g' P8 ^8 W% z: r S
; Y& c9 z% m9 n" F+ N- HAL_FLASHEx_DATAEEPROM_Unlock(); 7 w( G, K' r& L4 q Z: _8 F
- while(HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_WORD, Address, Data) != HAL_OK);5 t! F; M7 ?9 \. r
- HAL_FLASHEx_DATAEEPROM_Lock();
% h3 C: {/ H- z! P& F - # W+ B, @3 ]/ e$ S
- return i;! x* o: g4 H y' e7 \3 _
- }
复制代码
1 R5 c9 K: l% Y g0 x在程序中会调用此函数进行 ID 保存:
; O+ E& M+ |! ?! V# n# V
; T& l; k- q3 j7 Q: t) `% ~但是使用时候发现:
: N7 F* G3 }) s6 o; F8 d" S
- C$ v; l { g) S问题的解决: 其实这个问题也莫名其妙,真是说不出来为什么,估计是得详细的查看数据手册,但是还是 因为 在蓝牙的版本上面没有此类问题: . Q. w1 A7 k* U7 d& R' u3 m
' k1 G3 ]+ D0 N% l0 _
所以这里还是尝试改成 以 字节 方式写入: - FLASH_Status FLASH_WriteWord(uint32_t Address, uint32_t Data)
" Q0 e. b% n4 Y& [6 C3 J0 t6 X - {
* G6 w- ~- X- e* Y
. H4 s& I7 ^" V) H4 w% q- FLASH_Status state = FLASH_COMPLETE;, H0 j# o7 c# D: \& w/ u
- u8 i = 0;* w. c& h2 k% S' U& r' E- ?
- u8 writedata[6]={0};
9 l: I H @5 \8 i3 v
! `+ v- v$ { N T. Z. S$ T- writedata[0] = (u8)Data;" a9 V# m; y( U- ]2 F2 X' s
- writedata[1] = (u8)(Data>>8);9 K' A& @7 W+ o. b8 @) e ?- v& \
- writedata[2] = (u8)(Data>>16);5 n" ]& \) F3 G
- writedata[3] = (u8)(Data>>24);+ T4 a: \/ E' A- D: ~% D
# ^( U: b0 U5 x/ x- W3 D- HAL_FLASHEx_DATAEEPROM_Unlock(); 7 O) Q3 v5 H' ^* B) H7 K, M
- for(i=0; i<4; i++){& a1 g! v; \& \3 u3 R* F
- while(HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_BYTE, Address + i, writedata[i]) != HAL_OK);* Q; Y' s6 Z1 }7 d
- }0 t/ S+ R0 Q4 O1 j) n! \0 e
- HAL_FLASHEx_DATAEEPROM_Lock();
% P, I. n: F& j9 _& Z; ] i- R
7 D9 [& Q, t( p$ _# R- return state;& ?0 P. A8 t2 K) w: Q4 v
- }
复制代码使用此种方式写入,就不会出现问题! 其实也可以尝试修改地址,使得成为 4 的倍数,可能也不会出问题,这里就不测试了(最后问题解决有还是测试了,内存字节对齐问题) 2.4.3小结使用的芯片为 STM32L071RBT6 % T. x/ m* G9 `! t. {6 ]. b
最后问题的解决先直接说结论,就是EEPROM地址定义的问题,应该是4字节对齐(4的整数倍),读取全字的操作才能正常! 上面 STM32L071RBT6 EEPROM 读写全字问题的关键在于,存储地址的定义上,如上面一张图所示:(我在EEPROM区域定义了10个地址,用来存放无线设备的ID数据,如果是蓝牙芯片,那么ID为6个字节,如果是Enocean芯片,那么ID为4个字节,为了保持代码的统一,我在使用保存4个字节的ID数据的地址定义时候沿用的是蓝牙的 EEPROM区域定义)
$ \- s2 |# z4 }* @! ` ^( t
) s" w; y& \/ t) G
那么正如我图中猜想的一样,蓝牙的 ID 6个字节,我是都是通过一个字节一个字节操作,组合起来进行的,所以一切正常。但是对于 4个字节的 ID ,期初是用的 全字的方式,就出问题了,换成一个字节一个字节的操作,看上去是解决问题了。 但是实际上多了一些隐藏问题,暂时也说不清楚,在产品使用的时候,读写ID还是会有莫名其妙的问题,最终还是对当初的这个猜想,地址是不是也需要4字节对齐?进行了修改测试,于是乎,对于 4 个字节 ID的处理,地址改成:
. }3 N6 c1 w a& o# b- r" e g
$ E& k3 V6 I# l* Y1 X5 d把地址修改成 4 的倍数以后,上面的读取全字的两个函数便可以正常使用,而不会出上面莫名其妙的问题。
; H n9 M- w5 @; a0 [9 q" ^# o |