ZHCADD5B November   2023  – August 2025 F29H850TU , F29H859TU-Q1 , 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. 软件说明
  8. 乒乓仿真
    1. 5.1 用户配置
      1. 5.1.1 EEPROM_PingPong_Config.h
      2. 5.1.2 F28P65x_EEPROM_PingPong.c
    2. 5.2 测试示例
  9. EEPROM 函数
    1. 6.1  EEPROM_Config_Check
    2. 6.2  Configure_Protection_Masks
    3. 6.3  EEPROM_Write
    4. 6.4  EEPROM_Read
    5. 6.5  EEPROM_Erase
      1. 6.5.1 Erase_Bank
    6. 6.6  EEPROM_GetValidBank
    7. 6.7  EEPROM_UpdateBankStatus
    8. 6.8  EEPROM_UpdatePageStatus
    9. 6.9  EEPROM_UpdatePageData
    10. 6.10 EEPROM_Get_64_Bit_Data_Address
    11. 6.11 EEPROM_Program_64_Bits
    12. 6.12 EEPROM_CheckStatus
    13. 6.13 ClearFSMStatus
  10. 单存储单元仿真
    1. 7.1 用户配置
      1. 7.1.1 EEPROM_Config.h
      2. 7.1.2 F28P65x_EEPROM.c
    2. 7.2 EEPROM 函数
      1. 7.2.1  EEPROM_Config_Check
      2. 7.2.2  Configure_Protection_Masks
      3. 7.2.3  EEPROM_Write
      4. 7.2.4  EEPROM_Read
      5. 7.2.5  EEPROM_Erase
      6. 7.2.6  EEPROM_GetValidBank
      7. 7.2.7  EEPROM_Get_64_Bit_Data_Address
      8. 7.2.8  EEPROM_UpdateBankStatus
      9. 7.2.9  EEPROM_UpdatePageStatus
      10. 7.2.10 EEPROM_UpdatePageData
      11. 7.2.11 EEPROM_Get_64_Bit_Data_Address
      12. 7.2.12 EEPROM_Program_64_Bits
      13. 7.2.13 EEPROM_CheckStatus
      14. 7.2.14 ClearFSMStatus
    3. 7.3 测试示例
  11. 应用集成
    1. 8.1 软件功能和流程
  12. 适配其他第 3 代 C2000 MCU
  13. 10闪存 API
    1. 10.1 闪存 API 检查清单
      1. 10.1.1 使用闪存 API 时的注意事项
  14. 11源文件清单
  15. 12排查
    1. 12.1 通用
  16. 13结语
  17. 14参考资料
  18. 15修订历史记录

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 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 is used (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;