01、前言
在STM32H5微控制器中,EDATA(高寿命数据区100k cycles)功能允许用户配置Flash存储器的高寿命数据区。EDATA功能的主要目的是提供一个专门的存储区域,可以进行频繁写入或擦除,用来模拟EEPROM。通过配置EDATA Size参数,用户可以启用或禁用不同数量的EDATA扇区,从而更灵活的对存储空间进行配置。当然在使用时还要注意以下几点,以便更顺利的使用此功能。
02、注意事项
1)选项字节的配置
通过对EDATA(1/2)_EN和EDATA(1/2)_STAT对两个BANK的ETADA空间进行配置。根据项目需要配置空间大小。

可以通过STM32CubeProgrammer直接对选项字节进行配置。

注意,通过Programmer配置时,EDATA(1/2)_STAT的取值范围是0~7。0代表这个BANK的最后1个扇区,7代表最后8个扇区。也可以直接通过代码的方式进行配置。代码中可以先读取OB,检查是否已经配置过EDATA区域,再根据情况判断是否重新配置。

也可以直接通过代码的方式进行配置。代码中可以先读取OB,检查是否已经配置过EDATA区域,再根据情况判断是否重新配置。
HAL_FLASH_OB_Unlock();
FLASH_OBInitStruct.OptionType = OPTIONBYTE_EDATA;
FLASH_OBInitStruct.Banks = FLASH_BANK; // FLASH_BANK_1 or FLASH_BANK_2
HAL_FLASHEx_OBGetConfig(&FLASH_OBInitStruct);
if(FLASH_OBInitStruct.EDATASize != 8)
{
//config OB and erase the sectors at first time
FLASH_OBInitStruct.OptionType = OPTIONBYTE_EDATA;
FLASH_OBInitStruct.Banks = FLASH_BANK; // FLASH_BANK_1 or FLASH_BANK_2
FLASH_OBInitStruct.EDATASize = 8;
if(HAL_FLASHEx_OBProgram(&FLASH_OBInitStruct) != HAL_OK)
{
Error_Handler();
}
HAL_FLASH_OB_Launch();
}
HAL_FLASH_OB_Lock();通过代码配置时,EDATASize的取值范围为0~8,0代表Disable所有的EDAT扇区,即选项字节的EDATA(1/2)_EN=0;1~8对应1~8个扇区,即对应选项字节的EDATA(1/2)_EN=1,EDATA(1/2)_STAT=0~7。

2)MPU的配置
由于EDATA区域是通过AHB总线访问的,在默认情况下,所有的AHB内存区域属性都是cacheable的,但是EDATA是不可缓存的,必须通过MPU设置为non-cacheable。如果不配置,则在代码访问到此区域时,会产生HardFault。

根据实际要使用的EDATA区域及大小情况,我们以两个BANK的最大区域(BANK1:48KB,BANK2:48KB)为例进行配置,即BANK1和BANK2都设置8个扇区的空间。

不考虑BANK SWAP的情况,根据下图,我们可以知道,BANK1的8个EDATA扇区的空间为0x0900 0000~0x900 BFFF,BANK2为0x0900 C000~0x0901 7FFF,每个扇区大小为6K,带6bit ECC校验。

通过STM32CubeMX对EDATA区域的内存属性进行配置。

3)ECC错误的处理
由于EDATA区域ECC的纠错机制,对于未写过数据的区域,ECC的值也是没有写过的,所以在读取时就会产生NMI中断。

当然我们可以在操作流程中去保证先写再读。如果一定要先读取数据来进行判断,也可以在产生NMI中断中后,去判断由于未曾写过此区域而产生的ECC错误还是一个真正ECC的错误,如果是读取未写过的EDATA区域产生的NMI,则可以在中断服务程序中对其进行首次的擦写操作。STM32H5的HAL库中提供了相应的API可以获取到产生ECC错误时的访问地址以及这个地址的数据。
void NMI_Handler(void)
{
/* USER CODE BEGIN NonMaskableInt_IRQn 0 */
HAL_FLASHEx_ECCD_IRQHandler();
/* USER CODE END NonMaskableInt_IRQn 0 */
/* USER CODE BEGIN NonMaskableInt_IRQn 1 */
while (1)
{
if(RealECCErr == 0)
{
break;
}
}
/* USER CODE END NonMaskabl
}FLASH_OBProgramInitTypeDef FLASH_OBInitStruct;
static FLASH_EraseInitTypeDef EraseInitStruct;
uint32_t Address = 0, SectorError = 0;
uint16_t FlashHalfWord[1] = { 0XA55A };
uint32_t offset = 2;
FLASH_EccInfoTypeDef EccInfo;
uint8_t RealECCErr=0;
void HAL_FLASHEx_EccDetectionCallback(void)
{
HAL_FLASHEx_GetEccInfo(&EccInfo);
if(EccInfo.Address == EDATA_USER_START_ADDR)
{
if(EccInfo.Data == 0xffff)
{
HAL_FLASH_Unlock();
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
EraseInitStruct.Banks = FLASH_BANK;
EraseInitStruct.Sector = FLASH_SECTOR_120;
EraseInitStruct.NbSectors = 8;
//Erase
if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK)
{
Error_Handler();
}
//Program
Address = EDATA_USER_START_ADDR;
while(Address < EDATA_USER_END_ADDR)
{
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD_EDATA, Address, (uint32_t)FlashHalfWord) == HAL_OK)
{
Address = Address + offset; /* increment for the next Flash word*/
}
else
{
/* Error occurred while half word Programming */
Error_Handler();
}
}
HAL_FLASH_Lock();
RealECCErr = 0;
}
else
{
RealECCErr = 1;
}
}
}04、BANK区域的使用规划
推荐在一个BANK中运行代码,在另一个BANK里存取EDATA数据,这样可以做到RWW(Read While Write),即在执行代码的同时访问另外一个BANK的数据,以达到最高的访问效率。

05、在Trust Zone工程中使用
在使用CubeMX生成的Trust Zone工程中,安全区和非安全区相互调用的函数默认是存储在Flash的最后一个扇区,与EDATA区域相同,所以同时使用TZ和EDATA时,要注意修改工程的分散加载文件,以避免地址冲突。
06、总结
本文介绍了STM32H5系列MCU在使用EDATA区域时的一些注意事项,可以让用户使用此功能时,更加快速和高效。其中MPU配置及ECC部分,不仅在访问EDATA时会碰到,在访问OTP、RO等地址时也是相同的原理,可以以类似的方式处理。
来源:STM32
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。