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 [url=home.php?mod=space&uid=144993]@ref[/url] 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对齐,否则会出错。
!!!!这个代码的对其方式怎么跟贴代码之前不一样呢,完全左对齐了!!!
|