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