跳转到主要内容

STM32H5使用EDATA时的注意事项

cathy 提交于

01、前言

在STM32H5微控制器中,EDATA(高寿命数据区100k cycles)功能允许用户配置Flash存储器的高寿命数据区。EDATA功能的主要目的是提供一个专门的存储区域,可以进行频繁写入或擦除,用来模拟EEPROM。通过配置EDATA Size参数,用户可以启用或禁用不同数量的EDATA扇区,从而更灵活的对存储空间进行配置。当然在使用时还要注意以下几点,以便更顺利的使用此功能。

02、注意事项

1)选项字节的配置

通过对EDATA(1/2)_EN和EDATA(1/2)_STAT对两个BANK的ETADA空间进行配置。根据项目需要配置空间大小。

1779867999354326.png

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

1779868006254145.png

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

1779868013201325.png

也可以直接通过代码的方式进行配置。代码中可以先读取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。

1779868028125673.png

2)MPU的配置

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

1779868592711562.png

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

1779868580837116.png

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

1779868571857047.png

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

1779868565153648.png

3)ECC错误的处理

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

1779868548491956.png

当然我们可以在操作流程中去保证先写再读。如果一定要先读取数据来进行判断,也可以在产生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的数据,以达到最高的访问效率。

1779868490548416.png

05、在Trust Zone工程中使用

在使用CubeMX生成的Trust Zone工程中,安全区和非安全区相互调用的函数默认是存储在Flash的最后一个扇区,与EDATA区域相同,所以同时使用TZ和EDATA时,要注意修改工程的分散加载文件,以避免地址冲突。

06、总结

本文介绍了STM32H5系列MCU在使用EDATA区域时的一些注意事项,可以让用户使用此功能时,更加快速和高效。其中MPU配置及ECC部分,不仅在访问EDATA时会碰到,在访问OTP、RO等地址时也是相同的原理,可以以类似的方式处理。

来源:STM32

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

Tags