本帖最后由 creep 于 2018-1-9 16:18 编辑
STM32L的EEPROM支持字、半字和字节的读写操作。写操作之前自动擦除,如果写的数据为0,则只执行擦除操作。
使用STM32Cube库对自带的EEPROM进行操作,代码如下:
- #define EPROM_WR_TYPE_BYTE ((UNS8)0x00)
- #define EPROM_WR_TYPE_HALF_WORD ((UNS8)0x01)
- #define EPROM_WR_TYPE_WORD ((UNS8)0x02)
- #define EPROM_TEST_ADDR (STM_EPROM_ADDR_BASE + 12)
- #define EPROM_TESTE_ADDR (STM_EPROM_ADDR_BASE + 32)
- #define EPROM_TESTEE_ADDR (STM_EPROM_ADDR_BASE + 61)
- //// Unlocks the data memory and FLASH_PECR register access
- //// ret :
- //// OK = 0x00U,
- //// ERROR = 0x01U,
- //// BUSY = 0x02U,
- //// TIMEOUT = 0x03U
- UNS8 StmL0xxEpromUnlock(void)
- {
- UNS8 ret=0;
-
- ret = (UNS8)HAL_FLASHEx_DATAEEPROM_Unlock();
-
- return ret;
- }
- //// Locks the Data memory and FLASH_PECR register access
- //// ret :
- //// OK = 0x00U,
- //// ERROR = 0x01U,
- //// BUSY = 0x02U,
- //// TIMEOUT = 0x03U
- UNS8 StmL0xxEpromLock(void)
- {
- UNS8 ret=0;
-
- ret = (UNS8)HAL_FLASHEx_DATAEEPROM_Lock();
-
- return ret;
- }
- //// Erase a word in data memory.
- //// To correctly run this function, the @ref StmL0xxEpromUnlock() function
- //// must be called before.
- //// addr -- specifies the address to be erased.
- //// ret :
- //// OK = 0x00U,
- //// ERROR = 0x01U,
- //// BUSY = 0x02U,
- //// TIMEOUT = 0x03U
- UNS8 StmL0xxEpromWordErase(UNS32 addr)
- {
- UNS8 ret=0;
-
- if ( (STM_EPROM_ADDR_BASE>addr) || (STM_EPROM_ADDR_END<addr) )
- {
- return ret;
- }
-
- ret = (UNS8)HAL_FLASHEx_DATAEEPROM_Erase(addr);
-
- return ret;
- }
- //// Program data at a specified address
- //// type :
- //// Byte -- 0x00
- //// HalfWord -- 0x01
- //// Word -- 0x02
- //// addr -- specifies the address to be erased.
- //// ret :
- //// OK = 0x00U,
- //// ERROR = 0x01U,
- //// BUSY = 0x02U,
- //// TIMEOUT = 0x03U
- UNS8 StmL0xxEpromSingleWrite(UNS8 type, UNS32 addr, UNS32 data)
- {
- UNS8 ret=0;
-
- if ( (STM_EPROM_ADDR_BASE>addr) || (STM_EPROM_ADDR_END<addr) )
- {
- return ret;
- }
-
- StmL0xxEpromUnlock();
- ret = (UNS8)HAL_FLASHEx_DATAEEPROM_Program((UNS32)type, addr, data); //// 库函数
- StmL0xxEpromLock();
-
- return ret;
- }
- //// read a byte at a specified address
- //// addr -- specifies the address to be erased.
- //// ret :
- //// OK = 0x00U,
- //// ERROR = 0x01U,
- //// BUSY = 0x02U,
- //// TIMEOUT = 0x03U
- void StmL0xxEpromSingleByteRead(UNS32 addr, UNS8 *data)
- {
-
- if ( (STM_EPROM_ADDR_BASE>addr) || (STM_EPROM_ADDR_END<addr) )
- {
- return ;
- }
-
- StmL0xxEpromUnlock();
- *data = *(volatile uint8_t *)(addr);
- StmL0xxEpromLock();
- }
复制代码 测试代码如下:
- void EpromTest(void)
- {
- UNS8 tmp[8] = {1, 2, 3, 4, 5, 6, 7, 8};
- UNS8 read[8] = {0}, num=0, time=1;
-
- while(5>time)
- {
- for (num=0; num<8; num++)
- {
- tmp[num] *= time;
- StmL0xxEpromSingleWrite(EPROM_WR_TYPE_BYTE, EPROM_TEST_ADDR+num, (uint32_t)tmp[num]);
- }
-
- for (num=0; num<8; num++)
- {
- StmL0xxEpromSingleByteRead(EPROM_TEST_ADDR+num, &read[num]);
- if (tmp[num]!=read[num])
- {
- time = 10;
- }
- }
-
- //// StmL0xxEpromSingleWrite(EPROM_WR_TYPE_HALF_WORD, EPROM_TESTEE_ADDR, *(uint16_t *)(&tmp[0])); //// 进入异常中断
- //// StmL0xxEpromSingleWrite(EPROM_WR_TYPE_WORD, EPROM_TESTEE_ADDR, *(uint32_t *)(&tmp[0]));//// 进入异常中断
- StmL0xxEpromSingleWrite(EPROM_WR_TYPE_WORD, EPROM_TESTE_ADDR, *(uint32_t *)(&tmp[0]));
- StmL0xxEpromSingleWrite(EPROM_WR_TYPE_WORD, EPROM_TESTE_ADDR+4, *(uint32_t *)(&tmp[4]));
- StmL0xxEpromSingleByteRead(EPROM_TESTE_ADDR+0, (UNS32*)(&read[0]));
- StmL0xxEpromSingleByteRead(EPROM_TESTE_ADDR+4, (UNS32*)(&read[4]));
-
- time ++;
- }
- }
复制代码 总结:
1. 字节操作时,传入任何地址参数都可以,读写操作正常;
2. 但是当半字操作时,如果地址不是2对齐的,则调用函数StmL0xxEpromSingleWrite时进入HardFault中断;
3. 但是当字操作时,如果地址不是4对齐的,则调用函数StmL0xxEpromSingleWrite时进入HardFault中断;
调试发现调用HAL_FLASHEx_DATAEEPROM_Program函数时进入异常中断。
原因是EEPROM在内存结构上实际是以字为单位的:
虽然可以进行字节、半字的参数,但是必须保证地址的对其方式——半字操作以2对齐,字操作以4对齐,否则会出错。
!!!!这个代码的对其方式怎么跟贴代码之前不一样呢,完全左对齐了!!!
|
https://www.stmcu.org.cn/module/forum/thread-614550-1-1.html