This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TMS570LC4357:闪存写入只能执行一次

Guru**** 2460850 points
Other Parts Discussed in Thread: TMS570LC4357

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1126309/tms570lc4357-flash-write-can-be-only-executed-once

器件型号:TMS570LC4357

您好!

我正在尝试在程序中写入闪存。 我指的是 CAN 引导加载程序示例。 我可以发现数据被编程到组1的最后一个扇区中。 但是、我发现该扇区只能编程一次。 我不能把新的项目编入这个部门。 这是我的参考代码。 是否有人可以就这个问题提供一些指导? 谢谢。

/*初始化闪存组并激活扇区*/
uint32_t fapi_Init (uint32_t ucStartBank、uint32_t ucEndBank)

   uint32_t i;

   /*SYS_CLK_FREQ 在 bl_config.h 中定义*/
   如果((Fapi_initiatalizeFlashBanks ((uint32_t) SYS_CLK_FREQ)= Fapi_Status_Success)
   {
       对于(i = ucStartBank;i <(ucEndBank + 1);i++)
       {
           (空) Fapi_setActiveFlashBank ((Fapi_FlashBankType) i);
           (空) Fapi_enableMainBankSectors (0xFFFF);                   //用于 API 2.01*/
           while (fapi_check_FSM_ready_busy!= fapi_Status_FsmReady);
           while (fapi_get_FSM_status!= fapi_Status_Success);//不必包含此项*/
       }
       G_ulBankInitialized = 1;

   }
   其他
   {
        返回(1);
   }
   返回(0);//成功


/* ulAddr 必须是一个闪存扇区的起始地址*/
uint32_t fapi_BlockErase (uint32_t ulAddr、uint32_t size)

   uint8_t i=0、ucStartSector、ucEndSector;
   uint32_t EndAddr、status;

   EndAddr = ulAddr + Size;
   对于(I = 0;I < NUMBEROFSECTORS;I++)
   {
      if (ulAddr <=(uint32_t)(flash_sector[i].start))
      {
         G_ucStartBank    = flash_sector[i].bankNumber;
         ucStartSector  = i;
         中断;
      }
   }

   对于(i = ucStartSector;i < NUMBEROFSECTORS;i++)
   {
      if (EndAddr <=(((uint32_t) flash_sector[i].start)+ flash_sector[i].length))
      {
         G_ucEndBank  = flash_sector[i].bankNumber;
         EnducSector = i;
         中断;
      }
   }

   状态= Fapi_Init (g_ucStartBank、g_ucEndBank);
   如果(status =0)       //初始化成功
   {
       对于(i = ucStartSector;i <(ucEndSector + 1);i++){
           Fapi_issue19 CommandWithAddress (Fapi_EraseSector、flash_sector[i].start);
           while (fapi_check_FSM_ready_busy =fapi_Status_FsmBusy);
           while (fapi_get_FSM_status!= fapi_Status_Success);
       }
   }

   返回(状态);


//此处的组未使用。 我们根据闪存-启动- addr 计算函数中的组
uint32_t Fapi_BlockProgram (uint32_t Flash_Address、uint32_t Data_Address、uint32_t SizeInBytes)

   寄存器 uint32_t src =数据地址;
   寄存器 uint32_t dst = Flash_Address;
   uint32_t 字节;

   IF (SizeInBytes < 16U)
      字节= SizeInBytes;
   其他
      字节= 16;

   /*闪存组已在闪存擦除函数中初始化*/
   if (g_ulBankInitialized |= 1)
   {
       Fapi_Init (g_ucStartBank、g_ucEndBank);
   }

   while (SizeInBytes >0)
   {
      fapi_issueProgrammingCommand ((uint32_t *) dst、
                           (uint8_t *) src、
                           (uint32_t)字节、
                           0、
                           0、
                           Fapi_AutoEccGeneration);

       while (fapi_check_FSM_ready_busy =fapi_Status_FsmBusy);
       while (fapi_get_FSM_status!= fapi_Status_Success);

       fapi_flushPipeline();

      src +=字节;
      dst +=字节;
      SizeInBytes --=字节;
       if (SizeInBytes < 32){
          字节= SizeInBytes;
       }
   }
   返回(0);

空 Flash_Write_Test (空)

   静态 uint8 seqFlashWrite = 1;
   uint32 dbIdx=0;
   uint32 dbCnt = FLASH_TEST_SECURE_SIZE / FLASH_WRITE_BLOCK_SIZE;
   uint32 retCode = Fapi_BlockErase (flash_test_sect_sector_base_address、flash_test_sect_sect_size);
   uint8 校验和[校验和_冗余_大小]={0};
   uint8 u8PotStringBuf[128];

   uint8数据块[flash_write_block_size];
   UINT8种子=(seqFlashWrite)% FLASH_WRITE_BLOCK_SIZE;
   uint8 i = 0;

   //如果发生访问冲突,则返回错误。
   if (retCode)
   {
       sprintf (u8PotStringBuf、"[失败]-[seq#%d]-闪存写入测试:16KB 擦除\r\n、seqFlashWrite);
       sciDisplayText (UART_Msg、u8PotStringBuf);
#ifdef debug_on
       sciDisplayText (UART_Debug、u8PotStringBuf);
#endif
       seqFlashWrite++;
       返回;
   }
   其他
   {
       sprintf (u8PotStringBuf、"[通过]-[SEQ#%d]-闪存写入测试:16KB 擦除\r\n、seqFlashWrite);
       sciDisplayText (UART_Msg、u8PotStringBuf);
#ifdef debug_on
       sciDisplayText (UART_Debug、u8PotStringBuf);
#endif
   }

   retCode = 0;

   //生成用于闪存写入的数据
   对于(I = 0;I < FLASH_WRITE_BLOCK_SIZE;I++)
       dataBlock[i]= seed++;
   for (i = 0;i < CHECKSUM_RELEASE_SIZE;i++)
       校验和[i]= checksum8_2_apy (dataBlock、flash_write_block_size);

   for (dbIdx = 0;dbIdx < dbCnt;dbIdx++)
   {
       //将 SEED 设置为数据块索引+执行序列号
       uint32地址= FLASH_TEST_SECURE_BASE_ADDRESS + dbIdx * FLASH_WRITE_BLOCK_SIZE;
       //使用数据块对闪存进行编程
       retCode = Fapi_BlockProgram (address、(uint32_t)&dataBlock[0]、flash_write_block_size);

       if (retCode)
       {
           中断;
       }
   }


   if (retCode)
   {
       sprintf (u8PotStringBuf、"[失败]-[SEQ#%d]-闪存写入测试:16KB 程序\r\n、seqFlashWrite);
       sciDisplayText (UART_Msg、u8PotStringBuf);
#ifdef debug_on
       sciDisplayText (UART_Debug、u8PotStringBuf);
#endif
   }
   其他
   {
       uint8 i = 0;
       sprintf (u8PotStringBuf、"[通过]-[SEQ#%d]-Flash 写入测试:16KB 程序。 校验和为:["、seqFlashWrite);
       sciDisplayText (UART_Msg、u8PotStringBuf);
#ifdef debug_on
       sciDisplayText (UART_Debug、u8PotStringBuf);
#endif
       //将校验和存储到冗余数据数组中
       for (i=0;<CHECKSUM_REDUNDANT_SIZE; i++)
       {
           FLASH_Checksum [i]=校验和[i];

           sprintf (u8PotStringBuf、"0x%0x"、校验和[i]);
           sciDisplayText (UART_Msg、u8PotStringBuf);
#ifdef debug_on
           sciDisplayText (UART_Debug、u8PotStringBuf);
#endif
       }

       sciDisplayText (UART_Msg、"]\r\n");
#ifdef debug_on
       sciDisplayText (UART_Debug、"]\r\n");
#endif

   }
   seqFlashWrite++;

// main.c

//初始化闪存数据以进行读取
   Flash_Write_Test ();
   //初始化 RAM 数据以进行读取
   RAM_Write_Test ();
   Flash_read_Test ();

   Flash_Write_Test ();
   Flash_read_Test ();

   Flash_Write_Test ();
   Flash_read_Test ();

   while (1)
   {

   }

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Bob:

    在闪存扇区被擦除后、闪存扇区的内容变为0xFFFFFFFF。 闪存程序操作只能将闪存位单元从1翻转为0。 因此、在将数据写入闪存扇区之前、您需要擦除该扇区以确保该扇区的内容为0xFFFFFFFF。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、QJ、

    很高兴收到编写我现在提到的准则的提交人的答复。

    是的、我执行了如下擦除操作。  实际上、所有闪存操作代码都来自 TMS570LC4357的 CAN 引导加载程序。 诀窍是:我可以看到闪存编程首次成功、但在以下序列中失败。

    请就两个问题提供帮助?

    1.是否应将 TMS570LC4357更改为监控器模式? 如果是、如何操作?

    2.我是否必须将闪存代码复制到 RAM 而不是闪存中? 如果是、我应该如何更改链接文件? 我尝试过、但遇到了这样的错误

    #10099-D 程序不能放入可用存储器中、或者该段包含需要无法为此段生成的 trampoline 的调用站点。 "flashAPI"大小为0xd74的运行定位失败

    .................................................................................................

    擦除和编程操作

    --------------------------------------------------

    空 Flash_Write_Test (空)

       静态 uint8 seqFlashWrite = 1;
       uint32 dbIdx=0;
       uint32 dbCnt = FLASH_TEST_SECURE_SIZE / FLASH_WRITE_BLOCK_SIZE;
       uint32 retCode = Fapi_BlockErase (flash_test_sect_sector_base_address、flash_test_sect_sect_size);
       uint8 校验和[校验和_冗余_大小]={0};
       uint8 u8PotStringBuf[128];

       uint8数据块[flash_write_block_size];
       UINT8种子=(seqFlashWrite)% FLASH_WRITE_BLOCK_SIZE;
       uint8 i = 0;

       //如果发生访问冲突,则返回错误。
       if (retCode)
       {
           sprintf (u8PotStringBuf、"[失败]-[seq#%d]-闪存写入测试:16KB 擦除\r\n、seqFlashWrite);
           sciDisplayText (UART_Msg、u8PotStringBuf);
    #ifdef debug_on
           sciDisplayText (UART_Debug、u8PotStringBuf);
    #endif
           seqFlashWrite++;
           返回;
       }
       其他
       {
           sprintf (u8PotStringBuf、"[通过]-[SEQ#%d]-闪存写入测试:16KB 擦除\r\n、seqFlashWrite);
           sciDisplayText (UART_Msg、u8PotStringBuf);
    #ifdef debug_on
           sciDisplayText (UART_Debug、u8PotStringBuf);
    #endif
       }

       retCode = 0;

       //生成用于闪存写入的数据
       对于(I = 0;I < FLASH_WRITE_BLOCK_SIZE;I++)
           dataBlock[i]= seed++;
       for (i = 0;i < CHECKSUM_RELEASE_SIZE;i++)
           校验和[i]= checksum8_2_apy (dataBlock、flash_write_block_size);

       for (dbIdx = 0;dbIdx < dbCnt;dbIdx++)
       {
           //将 SEED 设置为数据块索引+执行序列号
           uint32地址= FLASH_TEST_SECURE_BASE_ADDRESS + dbIdx * FLASH_WRITE_BLOCK_SIZE;
           //使用数据块对闪存进行编程
           retCode = Fapi_BlockProgram (address、(uint32_t)&dataBlock[0]、flash_write_block_size);

           if (retCode)
           {
               中断;
           }
       }


       if (retCode)
       {
           sprintf (u8PotStringBuf、"[失败]-[SEQ#%d]-闪存写入测试:16KB 程序\r\n、seqFlashWrite);
           sciDisplayText (UART_Msg、u8PotStringBuf);
    #ifdef debug_on
           sciDisplayText (UART_Debug、u8PotStringBuf);
    #endif
       }
       其他
       {
           uint8 i = 0;
           sprintf (u8PotStringBuf、"[通过]-[SEQ#%d]-Flash 写入测试:16KB 程序。 校验和为:["、seqFlashWrite);
           sciDisplayText (UART_Msg、u8PotStringBuf);
    #ifdef debug_on
           sciDisplayText (UART_Debug、u8PotStringBuf);
    #endif
           //将校验和存储到冗余数据数组中
           for (i=0;<CHECKSUM_REDUNDANT_SIZE; i++)
           {
               FLASH_Checksum [i]=校验和[i];

               sprintf (u8PotStringBuf、"0x%0x"、校验和[i]);
               sciDisplayText (UART_Msg、u8PotStringBuf);
    #ifdef debug_on
               sciDisplayText (UART_Debug、u8PotStringBuf);
    #endif
           }

           sciDisplayText (UART_Msg、"]\r\n");
    #ifdef debug_on
           sciDisplayText (UART_Debug、"]\r\n");
    #endif

       }
       seqFlashWrite++;

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    另一个注释:在第二个和写入操作之后、我可以看到擦除失败、因为 XDS110调试视图的闪存读取没有更改为0xFFFFFFF

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、QJ、

    我已经解决了链接命令文件问题。 现在、我可以将闪存操作代码复制到 RAM 中、可通过 CCS 调试窗口的"Memory"视图进行验证(参见下图)。 但是、我遇到了另一个问题。 当代码运行到 Fapi_BlockErase 时、它会崩溃并按如下方式输入代码。 那么、有人对此问题提出建议吗? 非常感谢您的参与。

    PrefetchEntry
           B  prefetchEntry

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    [~ userid="525219" URL"μ C/support/microcontrollers/arm-based microcontrollers-group/arm-based microcontrollers/f/arm-based microcontrollers-forume/1126309/tms570lc4357-flash-write-cand-co-by-by-executed-one/4178644#4178644"]

    1.是否应将 TMS570LC4357更改为监控器模式? 如果是、如何操作?

    2.我是否必须将闪存代码复制到 RAM 而不是闪存中? 如果是、我应该如何更改链接文件? 我尝试过、但遇到了这样的错误

    [/报价]

    1.是的、F021闪存 API 应在监控器模式下执行。 默认情况下、器件处于监控器模式(而不是用户模式)。

    2.真的没有。 TMS570LC43x 具有两个闪存组。 您可以从组0运行代码、并将数据编程到闪存组1。 如果您的代码位于组0中、并且也希望将数据编程到组0中的位置、则需要将与闪存 API 相关的代码复制到 SRAM、并从 SRAM 运行代码。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    [~ userid="525219" URL"/support/microcontrollers/arm-based microcontrollers-group/arm -based-microcontrollers/f/arm based-microcontrollers-forume/1126309/tms570lc4357-flash-write-cand-ce-by-only/4178764#4178764"]当代码运行并进入以下代码时、Flockapi_Erase 会崩溃。 那么、有人对此问题提出建议吗? [/报价]

    Fapi_BlockEase ()和 Fapi_BlockProgram ()是否复制到 SRAM?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    是的、已复制到 SRAM。 我猜这是由链接器提供的 trampoline 函数引起的、该函数将 far 调用视为 near 调用。 所有擦除、编程、读取函数在映射文件中被视为 trampoline 函数、如下所示。 在将代码从闪存复制到 RAM 的调试过程中、您是否遇到此问题? 非常感谢您的参与。

    far 调用 trampoline

    被调用方名称              trampoline 名称
      被叫方 addr tramp addr  调用 addr 调用信息
    --------  ------  ------  --------
    Fapi_BlockRead           $Tramp$AA$L$PI$Fapi_BlockRead
      0800209c    0000a5ec    00002590  memory_test.obj (.text)
    Fapi_BlockProgram        $Tramp$AA$L$PI$Fapi_BlockProgram
      08001f80    0000a5f4    00002378  memory_test.obj (.text)
    Fapi_BlockErase          $Tramp$AA$L$PI$Fapi_BlockErase
      08001da8    0000a5fc    0000220c  memory_test.obj (.text)

    [3个蹦床]
    [3个 trampoline 调用]

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Bob:

    trampoline 函数不会生成预取中止。  

     可以通过读取指令故障状态寄存器(IFSR)、指令故障地址寄存器(IFAR)来分析预取中止。 IFAR 包含 CPU 试图从中提取指令的地址。 IFAR 的内容对于预取中止始终有效、因为所有预取中止都是同步的。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、QJ、

    感谢您的回复。 在更多调试后、我发现编程故障可能是由擦除故障引起的。 我发现了以下现象:

    当系统上电复位时、我选择的扇区(组1中的扇区#15)被擦除至全部"0xFF"。 然后是第一个编程成功。 但是、在下一轮编程操作中、"扇区编程"之前的擦除操作不会产生效果-仍然与上次编程的数据相同(在调试模式下、我通过存储器视图检查此结果)。  如前所述、闪存只能从0xFF 更改为所需的值(只能将闪存位单元从1翻转为0)。 我认为这是根本原因。

    我检查了所有与闪存编程相关的文档、例如 SNPA241、SPNU501G、SPNA148、SPNU563a、 SPNS195C (数据表)但是、我不知道擦除操作是如何失败的。 我甚至尝试针对 F021 API 的二进制代码进行调试、但未找到任何内容。 请就此问题帮助我吗? 是否有任何错误使用或设置导致此问题?

    下面是供您参考的更多项目设置。

    1.在主程序运行期间(每2880秒),我正在尝试定期对 Bank 1的扇区15进行编程

    2.我不将闪存操作代码复制到 RAM 中

    3.所有.text 代码都很简单,足以映射到 Bank#0

    4、ECC 无特殊处理。 只需使用项目默认设置

    非常感谢大家的参与。

    此致、

    Bob

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Bob:

    您可以重复擦除闪存扇区、而不会出现任何问题。 我这样做了:

    uint32_t 成功[]={0xea0004bd、0x00000000、
    0x00000000、0x00000000、
    0x00000000、0x00000000、
    0x00000000、0x00000000、
    0x4605b538、0x2d06460c、
    0x2d08d005、0x2d0ed003、
    0x2005bf18、0x2010d108、
    0xfa34f000、0x60044803};

    状态= Fapi_BlockErase (0x03E0000、0x1000);
    状态= Fapi_BlockProgram (0x03E0000、(无符号整型)&成功、64);
    状态= Fapi_BlockErase (0x03E0000、0x1000);
    状态= Fapi_BlockProgram (0x03E0000、(无符号整型)&成功、64);

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、QJ、

    感谢您的及时回复。 请您向我分享此示例项目吗?  

    此致、

    Bob

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Bob:

    我正在使用相同的闪存代码:bl_flash.c

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    当 Fapi_BlockErase (uint32_t ulAddr、uint32_t size)调用中的闪存地址(ulAddr)等于最后一个闪存扇区的起始地址(例如、tms570lc43x 为0x3e0000)时、BL_FLASH.c 中存在一个错误。  

    更新后的代码为:

    e2e.ti.com/.../8765.bl_5F00_flash.c