ZHCUAO0C November   2022  – November 2023 TMS320F280033 , TMS320F280034 , TMS320F280034-Q1 , TMS320F280036-Q1 , TMS320F280036C-Q1 , TMS320F280037 , TMS320F280037-Q1 , TMS320F280037C , TMS320F280037C-Q1 , TMS320F280038-Q1 , TMS320F280038C-Q1 , TMS320F280039 , TMS320F280039-Q1 , TMS320F280039C , TMS320F280039C-Q1

 

  1.   1
  2.   商标
  3. 1引言
    1. 1.1 参考书籍
    2. 1.2 函数清单格式
  4. 2TMS320F28003x 闪存 API 概述
    1. 2.1 引言
    2. 2.2 API 概述
    3. 2.3 使用 API
      1. 2.3.1 初始化流程
        1. 2.3.1.1 器件上电后
        2. 2.3.1.2 FMC 和存储体设置
        3. 2.3.1.3 关于系统频率变化
      2. 2.3.2 使用 API 进行构建
        1. 2.3.2.1 目标库文件
        2. 2.3.2.2 分布文件
      3. 2.3.3 闪存 API 使用的关键事实
  5. 3API 函数
    1. 3.1 初始化函数
      1. 3.1.1 Fapi_initializeAPI()
    2. 3.2 闪存状态机函数
      1. 3.2.1 Fapi_setActiveFlashBank()
      2. 3.2.2 Fapi_issueAsyncCommandWithAddress()
      3. 3.2.3 Fapi_issueBankEraseCommand()
      4. 3.2.4 Fapi_issueProgrammingCommand()
      5. 3.2.5 Fapi_issueProgrammingCommandForEccAddresses()
      6. 3.2.6 Fapi_issueFsmSuspendCommand()
      7. 3.2.7 Fapi_issueAsyncCommand()
      8. 3.2.8 Fapi_checkFsmForReady()
      9. 3.2.9 Fapi_getFsmStatus()
    3. 3.3 读取函数
      1. 3.3.1 Fapi_doBlankCheck()
      2. 3.3.2 Fapi_doVerify()
      3. 3.3.3 Fapi_calculatePsa()
      4. 3.3.4 Fapi_doPsaVerify()
    4. 3.4 信息函数
      1. 3.4.1 Fapi_getLibraryInfo()
    5. 3.5 实用功能
      1. 3.5.1 Fapi_flushPipeline()
      2. 3.5.2 Fapi_calculateEcc()
      3. 3.5.3 Fapi_isAddressEcc()
      4. 3.5.4 Fapi_remapEccAddress()
      5. 3.5.5 Fapi_calculateFletcherChecksum()
  6. 4推荐的 FSM 流程
    1. 4.1 新出厂器件
    2. 4.2 推荐的擦除流程
    3. 4.3 推荐的存储体擦除流程
    4. 4.4 推荐的编程流程
  7. 5与安全相关的软件应用程序使用假设
  8.   A 闪存状态机命令
    1.     A.1 闪存状态机命令
  9.   B 编译器版本和构建设置
  10.   C 目标库函数信息
    1.     C.1 TMS320F28003x 闪存 API 库
  11.   D typedef、定义、枚举和结构
    1.     D.1 类型定义
    2.     D.2 定义
    3.     D.3 枚举
      1.      D.3.1 Fapi_FlashProgrammingCommandsType
      2.      D.3.2 Fapi_FlashBankType
      3.      D.3.3 Fapi_FlashStateCommandsType
      4.      D.3.4 Fapi_FlashReadMarginModeType
      5.      D.3.5 Fapi_StatusType
      6.      D.3.6 Fapi_ApiProductionStatusType
    4.     D.4 结构
      1.      D.4.1 Fapi_FlashStatusWordType
      2.      D.4.2 Fapi_LibraryInfoType
  12.   E 并行签名分析 (PSA) 算法
    1.     E.1 函数详细信息
  13.   F ECC 计算算法
    1.     F.1 函数详细信息
  14.   G 勘误
  15.   修订历史记录

Fapi_issueProgrammingCommand()

设置数据并向有效的闪存或 OTP 存储器地址发出编程命令

概要

Fapi_StatusType Fapi_issueProgrammingCommand(
         uint32 *pu32StartAddress,
         uint16 *pu16DataBuffer,
         uint16  u16DataBufferSizeInWords,
         uint16 *pu16EccBuffer,
         uint16  u16EccBufferSizeInBytes,
         Fapi_FlashProgrammingCommandType oMode)

参数

pu32StartAddress [in]闪存中的起始地址,用于对数据和 ECC 进行编程
pu16DataBuffer [in]指向数据缓冲区地址的指针。数据缓冲区应为 128 位对齐。
u16DataBufferSizeInWords [in]数据缓冲区中 16 位字的数量
pu16EccBuffer [in]指向 ECC 缓冲区地址的指针
u16EccBufferSizeInBytes [in]ECC 缓冲区中的 8 位字节数
oMode [in]表示要使用的编程模式:
Fapi_DataOnly仅对数据缓冲区进行编程
Fapi_AutoEccGeneration对数据缓冲区进行编程,并自动生成 ECC 并对其进行编程。
Fapi_DataAndEcc对数据和 ECC 缓冲区进行编程
Fapi_EccOnly仅对 ECC 缓冲区进行编程
注: pu16EccBuffer 应包含与 128 位对齐主阵列/OTP 地址处的数据对应的 ECC。pu16EccBuffer 的 LSB 与主阵列的低 64 位相对应,pu16EccBuffer 的 MSB 与主阵列的高 64 位相对应。

说明

该函数根据提供的参数设置闪存状态机的编程寄存器,为用户提供了适用于不同场景的四种不同编程模式,如表 3-1 中所述。

表 3-1 不同编程模式的使用
编程模式 (oMode)使用的参数用途
Fapi_DataOnlypu32StartAddress、
pu16DataBuffer、
u16DataBufferSizeInWords
当任何自定义编程实用程序或用户应用(嵌入/使用闪存 API)必须单独对数据和相应 ECC 进行编程时使用。使用 Fapi_DataOnly 模式对数据进行编程,然后使用 Fapi_EccOnly 模式对 ECC 进行编程。通常大多数编程实用程序不会单独计算 ECC,而是使用 Fapi_AutoEccGeneration 模式。但是,某些安全应用程序可能需要在其闪存映像中插入有意的 ECC 错误(使用 Fapi_AutoEccGeneration 模式时无法实现),从而在运行时检查单错校正和双错检测 (SECDED) 模块的运行状况。在这种情况下,ECC 是单独计算的(使用AppendixF 中提供的 ECC 计算算法或使用 Fapi_calculateEcc() 函数(如适用))。应用程序可能希望根据需要在主阵列数据或 ECC 中插入错误。在这种情况下,在错误插入之后,可以使用 Fapi_DataOnly 模式和 Fapi_EccOnly 模式分别对数据和 ECC 进行编程。
Fapi_AutoEccGenerationpu32StartAddress、
pu16DataBuffer、
u16DataBufferSizeInWords
当任何自定义编程实用程序或用户应用(其在运行时嵌入/使用闪存 API 对闪存进行编程从而存储数据或进行固件更新)必须同时对数据和 ECC 进行编程而不插入任何有意错误时使用。该模式是常用的模式。
Fapi_DataAndEccpu32StartAddress、
pu16DataBuffer、
u16DataBufferSizeInWords、
pu16EccBuffer、
u16EccBufferSizeInBytes
该模式的用途与同时使用 Fapi_DataOnly 和 Fapi_EccOnly 模式的用途没有什么不同。但是,当可以同时对数据和计算出的 ECC 进行编程时,该模式会很有用。
Fapi_EccOnlypu16EccBuffer、
u16EccBufferSizeInBytes
请参阅 Fapi_DataOnly 模式的用途描述。
注: 由于 ECC 检查在上电时启用,用户必须始终为其闪存映像对 ECC 进行编程。

编程模式:

Fapi_DataOnly – 该模式将只对闪存中指定地址的数据部分进行编程。其编程范围从 1 位至 8 个 16 位字。但是,请注意该函数的限制条件中对闪存编程数据大小的限制。提供的编程起始地址加上数据缓冲区长度无法跨越 128 位对齐地址边界。使用该模式时将忽略参数 4 和 5。

Fapi_AutoEccGeneration – 该模式将对闪存中提供的数据以及自动生成的 ECC 进行编程。针对在 64 位存储器边界上对齐的每项 64 位数据计算 ECC。因此,在使用该模式时,应针对给定的 64 位对齐存储器地址,同时对所有 64 位数据进行编程。未提供的数据全部视作 1 (0xFFFF)。针对 64 位数据计算 ECC 并对其进行编程后,即使在该 64 位数据中将位从 1 编程为 0,也无法对此类 64 位数据进行重新编程(除非扇区被擦除),因为新的 ECC 值将与先前编程的 ECC 值相冲突。使用该模式时,如果起始地址进行了 128 位对齐,则可以根据需要同时对 8 个或 4 个 16 位字进行编程。如果起始地址进行了 64 位对齐而不是 128 位对齐,则只能同时对 4 个 16 位字进行编程。该选项还存在 Fapi_DataOnly 的数据限制。忽略参数 4 和 5

注: Fapi_AutoEccGeneration 模式将对闪存中提供的数据部分以及自动生成的 ECC 进行编程。针对 64 位对齐地址和相应的 64 位数据计算 ECC。未提供的任何数据将视作 0xFFFF。请注意,在编写自定义编程实用程序时,该实用程序在代码项目的输出文件中流式传输,并将各段一次编程到闪存中,这会产生实际影响。如果一个 64 位的字跨越多个段(即包含一段的末尾和另一段的开头),在对第一段进行编程时,无法针对 64 位字中缺失数据假设值为 0xFFFF。当您对第二段进行编程时,您将无法对第一个 64 位字的 ECC 进行编程,因为它已经(错误地)使用假定的 0xFFFF 对缺失值进行了计算和编程。避免该问题的一种方法是在代码项目的链接器命令文件中的 64 位边界上对齐链接到闪存的所有段。

下面我们举例说明:

SECTIONS
   {  
     .text        : > FLASH, ALIGN(4)
     .cinit       : > FLASH, ALIGN(4)
     .const       : > FLASH, ALIGN(4)
     .init_array  : > FLASH, ALIGN(4)
     .switch      : > FLASH, ALIGN(4)
   }

如果不在闪存中对齐这些段,则需要跟踪段中不完整的 64 位字,并将这些字与其他段中的字组合在一起,从而使 64 位字变得完整。这不容易做到。因此,建议将段在 64 位边界上对齐。

某些第三方闪存编程工具或 TI 闪存编程内核示例 (C2000Ware) 或任何自定义闪存编程解决方案可能假定传入数据流全部为 128 位对齐,并且可能没有预想到某段的起始地址未对齐。因此,假设提供的地址为 128 位对齐,则可能会尝试对最大可能的(128 位)字进行一次编程。当地址未对齐时,这可能会导致出现故障。因此,建议使用 ALIGN(8) 将所有段(已映射到闪存)在 128 位边界上对齐。

Fapi_DataAndEcc – 该模式将在指定地址的闪存中对提供的数据和 ECC 进行编程。提供的数据必须在 64 位存储器边界上对齐,并且数据长度必须与提供的 ECC 相关联。这意味着,如果数据缓冲区长度为 4 个 16 位字,则 ECC 缓冲区长度必须为 1 字节。如果数据缓冲区长度为 8 个 16 位字,则 ECC 缓冲区的长度必须为 2 字节。如果起始地址进行了 128 位对齐,则应根据需要同时对 8 或 4 个 16 位字进行编程。如果起始地址进行了 64 位对齐而不是 128 位对齐,则应同时对 4 个 16 位字进行编程。

pu16EccBuffer 的 LSB 与主阵列的低 64 位相对应,pu16EccBuffer 的 MSB 与主阵列的高 64 位相对应。

Fapi_calculateEcc() 函数可用于计算给定 64 位对齐地址和相应数据的 ECC。

Fapi_EccOnly – 该模式将仅在指定的地址处(应为该函数提供闪存主阵列地址,而不是相应的 ECC 地址)对闪存 ECC 存储空间中的 ECC 部分进行编程。它可以对 2 字节(ECC 存储器中某一位置的 LSB 和 MSB)或 1 字节(ECC 存储器中某一位置的 LSB)编程。

pu16EccBuffer 的 LSB 与主阵列的低 64 位相对应,pu16EccBuffer 的 MSB 与主阵列的高 64 位相对应。

使用该模式时将忽略参数二和三。

注: pu16DataBuffer 和 pu16EccBuffer 的长度分别不可超过 8 和 2。
注: 该函数在发出编程命令后不检查 FMSTAT。当 FSM 完成编程操作时,用户应用程序必须检查 FMSTAT 值。FMSTAT 指示编程操作期间是否有任何故障发生。用户应用程序可以使用 Fapi_getFsmStatus 函数来获取 FMSTAT 值。

此外,用户应用程序应使用 Fapi_doVerify() 函数来验证闪存是否已正确编程。

该函数不会等到编程操作结束;它只是发出命令并返回。因此,用户应用程序必须等待 FMC 完成编程操作,然后才能返回到任何类型的闪存访问。应将 Fapi_checkFsmForReady() 函数用于监测已发出命令的状态。

限制

  • 如上所述,该函数一次最多只能对 128 位进行编程(鉴于提供的地址进行了 128 位对齐)。如果用户想对更多位进行编程,则应循环调用该函数,从而一次对 128 位(或应用程序所需的 64 位)进行编程。
  • 主阵列闪存编程必须与 64 位地址边界对齐,并且每个 64 位字在每个写入或擦除周期只能编程一次。
  • 可以单独对数据和 ECC 进行编程。但是,每个 64 位数据字和相应的 ECC 字在每个写入或擦除周期中只能编程一次。
  • DCSM OTP 编程必须与 128 位地址边界对齐,并且每个 128 位字只能编程一次。例外包括:
    • DCSM OTP 中的 DCSM Zx-LINKPOINTER1 和 Zx-LINKPOINTER2 值应一起编程,并且可以按照 DCSM 操作的要求一次编程 1 位。
    • DCSM OTP 中的 DCSM Zx-LINKPOINTER3 值可按照 DCSM 操作的要求,一次编程 1 位。
  • 不应针对链接指针位置对 ECC 进行编程。即使用户选择 Fapi_AutoEccGeneration 模式或 Fapi_DataAndEcc 模式,API 也会为此类位置发出 Fapi_DataOnly 命令。链路指针位置不支持 Fapi_EccOnly 模式。
  • Fapi_EccOnly 模式不应该用于存储体 0 DCSM OTP 空间。如果使用,将返回错误。对于 DCSM OTP 空间,应使用 Fapi_AutoEccGeneration 或 Fapi_DataAndEcc 编程模式。

返回值

  • Fapi_Status_Success(成功)
  • Fapi_Error_InvalidBaseRegCntlAddress(失败:用户提供的闪存控制寄存器基地址与预期地址不匹配)
  • Fapi_Error_AsyncIncorrectDataBufferLength(失败:指定的数据缓冲区大小不正确。此外,如果在对存储体 0 DCSM OTP 空间进行编程时选择了 Fapi_EccOnly 模式,则会返回该错误)
  • Fapi_Error_AsyncIncorrectEccBufferLength(失败:指定的 ECC 缓冲区大小不正确)
  • Fapi_Error_AsyncDataEccBufferLengthMismatch(失败:数据缓冲区大小不是 64 位对齐的,或者数据长度跨越了 128 位对齐的存储器边界)
  • Fapi_Error_FlashRegsNotWritable(失败:闪存寄存器写入失败。用户应确保 API 从与闪存操作的目标地址相同的区域执行,或者用户应在闪存操作之前解锁。)
  • Fapi_Error_FeatureNotAvailable(失败:用户传递了不受支持的模式)
  • Fapi_Error_InvalidAddress(失败:用户提供的地址无效。有关有效地址范围的信息,请参阅 TMS320F28003x 微控制器数据手册。)

实现示例

该示例未显示擦除操作。请注意,扇区在重新编程之前应被擦除。

#include “F021_F28003x_C28x.h”
#define CPUCLK_FREQUENCY   120   /* 120 MHz System frequency */
int main(void)
{
     //     
     // Initialize System Control
     //
     Device_init();
 
     //
     // Call Flash Initialization to setup flash waitstates
     // This function must reside in RAM
     //
     Flash_initModule(FLASH0CTRL_BASE, FLASH0ECC_BASE, DEVICE_FLASH_WAITSTATES);
     
     //
     // Jump to RAM and call the Flash API functions
     //
     Example_CallFlashAPI();
}
#pragma CODE_SECTION(Example_CallFlashAPI, ramFuncSection);
void Example_CallFlashAPI(void)
{
     Fapi_StatusType oReturnCheck;
     Fapi_FlashStatusType oFlashStatus;
     uint16 au16DataBuffer[8] = {0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F};
     uint32 *DataBuffer32 = (uint32 *)au16DataBuffer;
     uint32 u32Index = 0;
     EALLOW;
     //
     // This function is required to initialize the Flash API based on 
     // System frequency before any other Flash API operation can be performed
     // Note that the FMC register base address and system frequency are passed as the parameters
     //
     oReturnCheck = Fapi_initializeAPI(F021_CPU0_BASE_ADDRESS, CPUCLK_FREQUENCY);
     if(oReturnCheck != Fapi_Status_Success)
     {
          Example_Error(oReturnCheck);
     }
 
     // 
     // Fapi_setActiveFlashBank function initializes Flash banks 
     // and FMC for erase and program operations.
     //
     oReturnCheck = Fapi_setActiveFlashBank(Fapi_FlashBank0);
      
     if(oReturnCheck != Fapi_Status_Success)
     {
          Example_Error(oReturnCheck);
     }
     //
     // Bank0 Program
     //
     
     //
     // Program 0x200 16-bit words in Bank0 Sector 4
     //
    
     for(u32Index = 0x84000; (u32Index < 0x84200) &&
                             (oReturnCheck == Fapi_Status_Success); u32Index+=8) 
     {
          // 
          // Issue program command
          // 
          oReturnCheck = Fapi_issueProgrammingCommand((uint32 *)u32Index, au16DataBuffer, 8,
                                                               0, 0, Fapi_AutoEccGeneration);
          // 
          // Wait until the Flash program operation is over
          // 
          while (Fapi_checkFsmForReady() != Fapi_Status_FsmReady){}
          if(oReturnCheck != Fapi_Status_Success)
          {
               Example_Error (oReturnCheck);
          }
          // 
          // Read FMSTAT register contents to know the status of FSM after
          // program command to see if there are any program operation related errors
          // 
          oFlashStatus = Fapi_getFsmStatus();
          if(oFlashStatus != 0)
          {
               //
               //Check FMSTAT and debug accordingly
               //   
               FMSTAT_Fail();
          }
          
          // 
          // Verify the programmed values
          // 
          oReturnCheck = Fapi_doVerify((uint32 *)u32Index, 4, DataBuffer32, &oFlashStatusWord);
          if(oReturnCheck != Fapi_Status_Success)
          {
               //
               // Check Flash API documentation for possible errors
               //   
               Example_Error(oReturnCheck);
          }
     }
     // 
     // * User code for further Bank0 flash operations *
     //
     .
     .
     .
     .
  
     //
     // Example is done here
     //
     Example_Done();
 
}