ZHCADD5A November   2023  – April 2024 TMS320F28P650DH , TMS320F28P650DK , TMS320F28P650SH , TMS320F28P650SK , TMS320F28P659DH-Q1 , TMS320F28P659DK-Q1 , TMS320F28P659SH-Q1

 

  1.   1
  2.   摘要
  3.   商标
  4. 简介
  5. EEPROM 与片上闪存的区别
  6. 概述
    1. 3.1 基本概念
    2. 3.2 单存储单元方法
    3. 3.3 乒乓方法
    4. 3.4 创建 EEPROM 节(页)和页标识
  7. 软件说明
    1. 4.1 软件功能和流程
  8. 乒乓仿真
    1. 5.1 用户配置
      1. 5.1.1 EEPROM_PingPong_Config.h
      2. 5.1.2 F28P65x_EEPROM_PingPong.c
    2. 5.2 EEPROM 函数
      1. 5.2.1  EEPROM_Config_Check
      2. 5.2.2  Configure_Protection_Masks
      3. 5.2.3  EEPROM_Write
      4. 5.2.4  EEPROM_Read
      5. 5.2.5  EEPROM_Erase
        1. 5.2.5.1 Erase_Bank
      6. 5.2.6  EEPROM_GetValidBank
      7. 5.2.7  EEPROM_UpdateBankStatus
      8. 5.2.8  EEPROM_UpdatePageStatus
      9. 5.2.9  EEPROM_UpdatePageData
      10. 5.2.10 EEPROM_Get_64_Bit_Data_Address
      11. 5.2.11 EEPROM_Program_64_Bits
      12. 5.2.12 EEPROM_CheckStatus
      13. 5.2.13 ClearFSMStatus
    3. 5.3 测试示例
  9. 单存储单元仿真
    1. 6.1 用户配置
      1. 6.1.1 EEPROM_Config.h
      2. 6.1.2 F28P65x_EEPROM.c
    2. 6.2 EEPROM 函数
      1. 6.2.1  EEPROM_Config_Check
      2. 6.2.2  Configure_Protection_Masks
      3. 6.2.3  EEPROM_Write
      4. 6.2.4  EEPROM_Read
      5. 6.2.5  EEPROM_Erase
      6. 6.2.6  EEPROM_GetValidBank
      7. 6.2.7  EEPROM_Get_64_Bit_Data_Address
      8. 6.2.8  EEPROM_UpdateBankStatus
      9. 6.2.9  EEPROM_UpdatePageStatus
      10. 6.2.10 EEPROM_UpdatePageData
      11. 6.2.11 EEPROM_Get_64_Bit_Data_Address
      12. 6.2.12 EEPROM_Program_64_Bits
      13. 6.2.13 EEPROM_CheckStatus
      14. 6.2.14 ClearFSMStatus
    3. 6.3 测试示例
  10. 应用集成
  11. 适配其他第 3 代 C2000 MCU
  12. 闪存 API
    1. 9.1 闪存 API 检查清单
      1. 9.1.1 使用闪存 API 时的注意事项
  13. 10源文件清单
  14. 11故障排除
    1. 11.1 常见问题
  15. 12结语
  16. 13参考资料
  17. 14修订历史记录

EEPROM_Config_Check

EEPROM_Config_Check() 函数提供一般错误检查并配置闪存 API 所需的写入/擦除保护掩码。应在对仿真 EEPROM 单元进行编程或读取之前调用此函数。

第一,该函数验证选择用于 EEPROM 仿真的闪存组是否有效。有效的闪存组选择不得选择组 0 进行仿真,并且必须受特定器件型号的支持。例如,只有某些 F28p65x 型号具有闪存组 2-4,而其他型号没有。要验证该信息,请参阅特定于器件的数据表。

if (FLASH_BANK_SELECT == FlashBank0StartAddress)
{
    return 0xFFFF;
}

if (FLASH_BANK_SELECT == FlashBank2StartAddress)
{
#if !defined(F28P65xDKx) && !defined(F28P65xSKx) && !defined(F28P65xSHx)   
        return 0xFFFF;
#endif
} else if (FLASH_BANK_SELECT == FlashBank3StartAddress) // If using Bank 3
{
#if !defined(F28P65xDKx) && !defined(F28P65xSKx)   
        return 0xFFFF;
#endif
} else if (FLASH_BANK_SELECT == FlashBank4StartAddress) 
{
#if !defined(F28P65xDKx) && !defined(F28P65xSKx) && !defined(F28P65xSHx)   
        return 0xFFFF;
#endif
}

第二,检查选择用于仿真的闪存扇区的有效性。该函数检查:

  • FIRST_AND_LAST_SECTOR 是否指示两个单元具有两个不同数量的闪存扇区
    uint16 NUM_EEPROM_SECTORS_1 = FIRST_AND_LAST_SECTOR[0][1] - FIRST_AND_LAST_SECTOR[0][0] + 1;
    uint16 NUM_EEPROM_SECTORS_2 = FIRST_AND_LAST_SECTOR[1][1] - FIRST_AND_LAST_SECTOR[1][0] + 1;
    
    if (NUM_EEPROM_SECTORS_1 != NUM_EEPROM_SECTORS_2)
    {
        return 0xEEEE;
    }
  • 选择用于仿真的闪存扇区数量是否多于闪存组中可用的扇区数量
    if (NUM_EEPROM_SECTORS > NUM_FLASH_SECTORS || NUM_EEPROM_SECTORS == 0)
    {
        return 0xEEEE;
    }
  • 选择用于仿真的第一个和最后一个扇区的组合是否无效
    if (NUM_EEPROM_SECTORS > 1)
    {
        // Check if FIRST_AND_LAST_SECTOR is sorted in increasing order 
        // and doesn't have duplicates
        if (FIRST_AND_LAST_SECTOR[0][1] <= FIRST_AND_LAST_SECTOR[0][0])
        {
            return 0xEEEE;
        }
        if (FIRST_AND_LAST_SECTOR[1][1] <= FIRST_AND_LAST_SECTOR[1][0])
        {
            return 0xEEEE;
        }
    
        // Check if FIRST_AND_LAST_SECTOR contains invalid sector
        if (FIRST_AND_LAST_SECTOR[0][1] > NUM_FLASH_SECTORS - 1 || FIRST_AND_LAST_SECTOR[0][1] < 1)
        {
            return 0xEEEE;
        }
        if (FIRST_AND_LAST_SECTOR[1][1] > NUM_FLASH_SECTORS - 1 || FIRST_AND_LAST_SECTOR[1][1] < 1)
        {
            return 0xEEEE;
        }
    
    } else // If only using 1 sector
    {
    
        // Verify that only sector is valid
        if (FIRST_AND_LAST_SECTOR[0][0] > NUM_FLASH_SECTORS - 1 || 
                FIRST_AND_LAST_SECTOR[1][0] > NUM_FLASH_SECTORS - 1) {
            return 0xEEEE;
        }
    }
  • 两个单元之间是否存在重叠扇区
  • if (FIRST_AND_LAST_SECTOR[0][0] <= FIRST_AND_LAST_SECTOR[1][1] && FIRST_AND_LAST_SECTOR[1][0] <= FIRST_AND_LAST_SECTOR[0][1]) { return 0xEEEE; }

如果使用页面模式,还将检查以下各项

  • 检查 EEPROM 组 + 页面的总大小是否适合所选的闪存扇区。
    // Calculate size of each EEPROM Bank (16 bit words) Bank_Size = 8 + ((EEPROM_PAGE_DATA_SIZE + 8) * NUM_EEPROM_PAGES); // Calculate amount of available space (16 bit words) uint32 Available_Words = NUM_EEPROM_SECTORS * FLASH_SECTOR_SIZE; // Check if size of EEPROM Banks and Pages will fit in EEPROM sectors if (Bank_Size * NUM_EEPROM_BANKS > Available_Words) { return 0xCCCC; }
  • 验证两个 EEPROM 单元是否没有重叠的保护掩码
    // Verify that the two EEPROM units do not have overlapping protection 
    // masks
    // First, get sectors for both units
    uint64 WE_Protection_AB_Sectors_Unit_0 = Configure_Protection_Masks(FIRST_AND_LAST_SECTOR[0], NUM_EEPROM_SECTORS);
    uint64 WE_Protection_AB_Sectors_Unit_1 = Configure_Protection_Masks(FIRST_AND_LAST_SECTOR[1], NUM_EEPROM_SECTORS);
    
    if (WE_Protection_AB_Sectors_Unit_0 & WE_Protection_AB_Sectors_Unit_1)
    {
        return 0xEEEE;
    }
    

如果检测到以下情况之一,该函数还会通过相应的返回代码发出警告:

  • 配置 EEPROM 组和页面大小后,闪存中会保留一个或多个 EEPROM 组的空间
    // Notify for extra space (more than one EEPROM bank leftover)
    if (Available_Words - (Bank_Size * NUM_EEPROM_BANKS ) >= Bank_Size)
    {
        Warning_Flags += 1;
    }
  • 如果每个页面包含少于 5 个 16 位字(这会浪费空间,因为无需状态代码即可使用 64 位模式)
    if (EEPROM_PAGE_DATA_SIZE < 5)
    {
        Warning_Flags += 2;
    }

如果使用 32-127 范围内的扇区(对于 F28P65x 器件)并且未使用分配给写入/擦除保护掩码中单个位的全部八个扇区,则会发出警告。由 single-bit 设计的八个扇区中任何未使用的扇区都无法受到适当的擦除保护。有关写入/擦除保护掩码如何与扇区对应的更多信息,请参阅 TMS320F28P65x 闪存 API 版本 3.02.00.00 参考指南

uint16 i;
for (i = 0; i < 2; i++)
{
    // If using any sectors from 32-127
    if (FIRST_AND_LAST_SECTOR[i][1] > 31) {

        // If all sectors use protection mask B
        if (FIRST_AND_LAST_SECTOR[i][0] > 31)
        {
            // If using less than 8 sectors
            if (NUM_EEPROM_SECTORS < 8)
            {

                Warning_Flags += 4;
                break;

            } else {
                // If sectors are multiples of 8
                if ((FIRST_AND_LAST_SECTOR[i][0] % 8) != 0 || 
                       ((FIRST_AND_LAST_SECTOR[i][1] + 1) % 8 != 0))
                {
                    Warning_Flags += 4;
                    break;
            }
            }
        } else { // If only last sector is using protection mask B

            // If not a multiple of 8
            if ((FIRST_AND_LAST_SECTOR[i][1] + 1) % 8 != 0) {

                Warning_Flags += 4;
                break;
            }
        }
    }
}

该函数还通过擦除要用于编程的扇区来为仿真准备好闪存。

    // Combine sectors from both units and separate them by which 
    // protection register they use (A or B)
uint32 Combined_WE_Protection_A_Sectors = 
                               (uint32)WE_Protection_AB_Sectors_Unit_0 | 
                                 (uint32)WE_Protection_AB_Sectors_Unit_1;
uint32 Combined_WE_Protection_B_Sectors = 
                                 WE_Protection_AB_Sectors_Unit_0 >> 32 | 
                                   WE_Protection_AB_Sectors_Unit_1 >> 32;

// Create protection masks accordingly
WE_Protection_A_Mask = 0xFFFFFFFF ^ Combined_WE_Protection_A_Sectors;
WE_Protection_B_Mask = 0x00000FFF ^ Combined_WE_Protection_B_Sectors;

Erase_Bank();

最后,为活动 EEPROM 单元配置写入/擦除保护掩码。

// Configure Write/Erase Protection Masks used by the Flash API
uint64 WE_Protection_AB_Mask =     Configure_Protection_Masks(FIRST_AND_LAST_SECTOR[EEPROM_ACTIVE_UNIT], NUM_EEPROM_SECTORS);


WE_Protection_A_Mask = 0xFFFFFFFF ^ (uint32)WE_Protection_AB_Mask;
WE_Protection_B_Mask = 0x00000FFF ^ WE_Protection_AB_Mask >> 32;