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.

[参考译文] TMS320F28075:从闪存读取时出现问题

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

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/570459/tms320f28075-issue-reading-from-flash

器件型号:TMS320F28075
Thread 中讨论的其他器件:controlSUITE

大家好、

为同事发布。

我要做的是:

我正在尝试将一个小数据块写入一个未使用的闪存扇区。  随意地说、我将使用 TI EEPROM 仿真函数、但对于启动器、我一直在尝试使用 API 向闪存写入少量字节、然后通过直接寻址闪存中的存储器的简单函数将其读回。  供参考-我将向闪存写入8个字节、以尝试保持数据边界正确。

 

问题是什么:

当我执行闪存读取(在闪存写入之后)时、处理器会遇到未配置的中断。  我假定这是“可纠正的错误故障”,但它似乎不是该故障。  当我尝试捕获中断并确定中断的来源时,我看不到任何指向中断来源的标志。

 

我的假设:

我一直假设我遇到 ECC 错误,但我无法证明。  我的闪存写入代码是根据 controlSUITE 提供的示例进行调整的、因此我假设它写入正确。  但是,我对闪存写法不太了解,所以我甚至不知道在出现什么问题时要问什么问题。  我注意到这个器件的器件勘误表(文档 SPRZ423D)中提到了闪存错误、但是勘误表特别声明只有当错误是由程序提取操作引起的、而不是数据读取引起的时才会发生这种情况。  我正在读取数据、因此我假设这不适用。  此外、供参考的是、我使用的是 TMS rev C 器件。

在 CCS 版本中使用客户硬件:6.1.1.00022。 修改了一个软件示例。 以下代码:

我的项目中有:F021_API_F2837xD_FPU32.lib 文件、我的项目中有 F021_F2837xD_C28.h #included in Fapi_UserDefinedFuncations.c.

void EEPROM_WRITE (void)
{

uint32 u32Index = 0;
uint16 i = 0;

Fapi_StatusType o 返回检查;
易失性 Fapi_FlashStatusType o 闪存状态;
Fapi_FlashStatusWordType oFlashStatusWord;

//禁用 ECC。 ECC 不必被禁用即可执行类似的 FSM 操作
//编程和擦除。
//但是、在 Sonata Rev. 0芯片上、由于 OTP ECC 勘误表、
//禁用 ECC 以避免在使用闪存 API 函数时出现 ECC 错误
//读取 TI-OTP

INT_DISABLE;
/*
EALLOW;
Flash0EccRegs.ecc_enable.bit.enable = 0x0;
EDIS;
*
EALLOW;

//需要此函数来根据系统初始化闪存 API
//频率才能执行任何其他闪存 API 操作

oReturnCheck = Fapi_initializeAPI (F021_CPU0_BASE_ADDRESS、120);

if (oReturnCheck!= Fapi_Status_Success)
{
//检查闪存 API 文档以了解可能的错误
Example_Error (oReturnCheck);
}

// Fapi_setActiveFlashBank 函数进一步设置闪存组和 FMC
//闪存操作将在组上执行
oReturnCheck = Fapi_setActiveFlashBank (Fapi_FlashBank0);
if (oReturnCheck!= Fapi_Status_Success)
{
//检查闪存 API 文档以了解可能的错误
Example_Error (oReturnCheck);
}



//擦除扇区 B
oReturnCheck = Fapi_issueODE19 CommandWithAddress (Fapi_EraseSector、
(uint32 *) bzero_sectorb_start);

//等待 FSM 完成擦除扇区操作
while (fapi_checkFsmForReady()!= fapi_Status_FsmReady){}
//验证 sectorb 是否被擦除。 "擦除"步骤本身的验证方式为
//可以。 此验证是可以执行的第二次验证。
oReturnCheck = Fapi_doBlankCheck ((uint32 *) Bzero_sectorb_start、
Bzero_16KSector u32length、
oFlashStatusWord (&O);

if (oReturnCheck!= Fapi_Status_Success)
{
//检查闪存 API 文档以了解可能的错误
//如果擦除命令失败,请使用 Fapi_getFsmStatus()函数
//获取 fmstat 寄存器内容
//查看 EV 位、ESUSP 位、STAT 位或 VOLTSTAT 中是否有任何一个
//位被置位(更多细节请参考 API 文档)
Example_Error (oReturnCheck);
}




//最多可向程序函数提供8个字的数据缓冲区。
//每个字都被编程,直到整个缓冲区被编程或 A
//发现问题。 但是、要对具有大于8的缓冲区进行编程
//字、程序函数可在循环中调用、以便为编程8个字
//每个循环迭代直到整个缓冲区被编程


。//
//示例:使用输出 ECC 对闪存扇区 B 中的0xFF 字节进行编程
//禁用 ECC,以便在读取闪存内容时不生成错误
//无 ECC
Flash0EccRegs.ecc_enable.bit.enable = 0x0;
*

for (i=0;i<=word_in_flash_buffer;i++)
{
Buffer[i]= i;
}

对于(i=0、u32Index = Bzero_sectorb_start;
(u32Index <(Bzero_sectorb_start + wors_in_flash_buffer)))
&&(oReturnCheck = Fapi_Status_Success);i+= 8、u32Index+= 8)
{
oReturnCheck = fapi_issueProgrammingCommand ((UINT32 *) u32Index、
Read_flash_buffer + i、
8、
0、
0、
Fapi_AutoEccGeneration);
while (fapi_checkFsmForReady ()=fapi_Status_FsmBusy);

if (oReturnCheck!= Fapi_Status_Success)
{
//检查闪存 API 文档以了解可能的错误
Example_Error (oReturnCheck);
}

//读取 fmstat 寄存器内容以了解 FSM 的状态
//在用于任何调试的程序命令之后
oFlashStatus = fapi_getFsmStatus();

//验证编程的值。 Program 步骤本身会进行验证
//进行。 此验证是可以执行的第二次验证。
oReturnCheck = fapi_doVerify (((uint32 *) u32Index、
4、
Buffer32+(I/2)、
oFlashStatusWord (&O);
if (oReturnCheck!= Fapi_Status_Success)
{
//检查闪存 API 文档以了解可能的错误
Example_Error (oReturnCheck);
}
}

EDIS;

INT_ENABLE;

}


void Example_Error (Fapi_StatusType 状态)
{
//错误代码将位于状态参数
//中 _asm (" ESTOP0");
}


void flash_read (void)
{
uint16 i;
extern UINT16 EEPROM_DATA_LOAD_START;

对于(i=0;i < word_in_flash_buffer;i++)
{
*(read_flash_buffer + i)=*(&EEPROM_DATA_load_start + i);
}

flash_pack_struct_from 缓冲区(); //从闪存取值并打包到 EEPROM_DATA_buffer 结构

中} //函数末尾 flash_read()



此代码段来自.cmd 文件,该文件调用闪存中 EEPROM_DATA 的位置。

EEPROM_DATA :LOAD = FLASHB、
load_start (_EEPROM_DATA_LOAD_START)、
load_end (_EEPROM_DATA_LOAD_END)、
PAGE = 0、ALIGN (4)

感谢您的帮助、

不需要

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

    Nate (和 Brett)、您好!

    感谢您在此处发布我的问题。  我想补充一点关于失败条件和我对这一问题的想法的信息。

    我正在使用上面附加的函数(EEPROM_WRITE())向闪存写入一个小测试模式。  虽然我注意到使用内存浏览器查看闪存时偶尔会出现位翻转、但数据似乎被正确写入闪存。  当我尝试从闪存中读取数据时、我遇到了一个问题。  CPU 进入一个不受支持的中断。  我在确定触发哪个中断时遇到了一些问题。  对于我们不使用的每个中断、我们都有一个"默认 ISR"矢量。  PIE 使能的所有功能都关闭、因此我无法确定为什么调用默认 ISR、除非存在不可屏蔽的中断、例如不可纠正的闪存错误。  我可以使用一些帮助来确定该中断来自何处。

    假设 CPU 在发生闪存 ECC 错误时被中断、我的下一个问题是为什么错误首先被写入闪存中。  但我想、在我弄清楚中断是如何触发的之后、我们可以讨论这一点。

    谢谢、

    Justin

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

    发生错误后、请通过 CCS 存储器观察窗口(或寄存器视图)检查寄存器 NMISHDFLG (0x7066)中的值、以查看是否发生 NMI (不可屏蔽中断)。

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

    我看到您正在使用 AutoEccGeneration 模式进行编程。 只要您提供具有正确对齐的地址和数据、就应该正确对 ECC 进行编程。 在代码中,我看到您使用 Fapi_doVerify()执行验证。 该结果是否通过? 如果在调用 Fapi_doVerify()之前启用了 ECC 检查(用于读取路径),并且该检查在没有给出 ECC 错误中断的情况下通过,则表示 ECC 已正确编程。

    1) 1) CPU 读取闪存之前、您使用的闪存等待状态值配置是什么?
    2) 2)您是否在寄存器视图中检查了 FlashEccRegs 并注意到在以下寄存器中捕获的任何错误地址?
    SINGLE_ERR_ADDR_LOW
    SINGLE_ERR_ADDR_HIGH
    UNC_ERR_ADDR_LOW
    UNC_ERR_ADDR_HIGH
    3) 3)您是否启用了看门狗? 您是否在为其提供服务?

    关于在存储器窗口中翻转闪存位:
    1) 1)错误的闪存等待状态值会导致这种情况。 或
    2) 2)当闪存编程或擦除操作正在进行时、不应访问闪存。 在进行编程或擦除时、您可能正在观察闪存在存储器窗口中。 尝试在闪存操作进行时关闭存储器窗口。

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

    如何检查闪存的等待状态? 应该是什么?

    错误地址寄存器显示的内容似乎不是零以外的任何内容。 但我将在不同的条件下再次尝试它、我很快就会回来。

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

    检查 FlashCtrlRegs 中的 FRDCNTL 寄存器是否存在 RWAIT 字段。 在120MHz 时、它应该被配置为2。

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

    我再次尝试它、这次我得到 NMI 的证据。 我获取单个错误和 UNC 错误寄存器中扇区 B 的地址、并获取 NMISHDBLG 寄存器中的 FLLUNCERR 位。

    我检查了 waitstate、RWAIT 字段 equals 2。 是否有可能将闪存配置为错误的频率? 我遇到了类似的情况、我为串行端口修改了一段代码、配置错误的频率、波特率混乱。 我不确定要检查哪个寄存器来检查闪存、如果有这样的配置...

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

    我已经验证了读取闪存的代码会生成一个 NMI、但是写入闪存的代码也会生成一个意外中断(但不是我可以告诉的 NMI)。 即使 ECC_ENABLE 位为零、也会执行此操作。 我恢复到稍旧的代码版本进行此测试、并复制以下函数。 EEPROM_write()函数更接近原始示例代码。 请注意、ECC_ENABLE 保持为零、这仍会导致中断。 如果你能帮我确定触发哪个中断、那就太好了!

    -Justin



    void EEPROM_WRITE (void)


    uint32 u32Index = 0;
    uint16 i = 0;

    Fapi_StatusType o 返回检查;
    易失性 Fapi_FlashStatusType o 闪存状态;
    Fapi_FlashStatusWordType oFlashStatusWord;

    //禁用 ECC。 ECC 不必被禁用即可执行类似的 FSM 操作
    //编程和擦除。
    //但是、在 Sonata Rev. 0芯片上、由于 OTP ECC 勘误表、
    //禁用 ECC 以避免在使用闪存 API 函数时出现 ECC 错误
    //读取 TI-OTP

    INT_DISABLE;

    EALLOW;
    Flash0EccRegs.ecc_enable.bit.enable = 0x0;
    EDIS;

    EALLOW;

    //需要此函数来根据系统初始化闪存 API
    //频率才能执行任何其他闪存 API 操作

    oReturnCheck = Fapi_initializeAPI (F021_CPU0_BASE_ADDRESS、120);//现在将其保留为 Out

    if (oReturnCheck!= Fapi_Status_Success)

    //检查闪存 API 文档以了解可能的错误
    Example_Error (oReturnCheck);


    // Fapi_setActiveFlashBank 函数进一步设置闪存组和 FMC
    //闪存操作将在组上执行
    oReturnCheck = Fapi_setActiveFlashBank (Fapi_FlashBank0);
    if (oReturnCheck!= Fapi_Status_Success)

    //检查闪存 API 文档以了解可能的错误
    Example_Error (oReturnCheck);




    //擦除扇区 B
    oReturnCheck = Fapi_issueODE19 CommandWithAddress (Fapi_EraseSector、
    (uint32 *) bzero_sectorb_start);

    //等待 FSM 完成擦除扇区操作
    while (fapi_checkFsmForReady()!= fapi_Status_FsmReady){}
    //验证 sectorb 是否被擦除。 "擦除"步骤本身的验证方式为
    //可以。 此验证是可以执行的第二次验证。
    oReturnCheck = Fapi_doBlankCheck ((uint32 *) Bzero_sectorb_start、
    Bzero_16KSector u32length、
    oFlashStatusWord (&O);

    if (oReturnCheck!= Fapi_Status_Success)

    //检查闪存 API 文档以了解可能的错误
    //如果擦除命令失败,请使用 Fapi_getFsmStatus()函数
    //获取 fmstat 寄存器内容
    //查看 EV 位、ESUSP 位、STAT 位或 VOLTSTAT 中是否有任何一个
    //位被置位(更多细节请参考 API 文档)
    Example_Error (oReturnCheck);





    //最多可向程序函数提供8个字的数据缓冲区。
    //每个字都被编程,直到整个缓冲区被编程或 A
    //发现问题。 但是、要对具有大于8的缓冲区进行编程
    //字、程序函数可在循环中调用、以便为编程8个字
    //每个循环迭代直到整个缓冲区被编程



    //示例:使用输出 ECC 对闪存扇区 B 中的0xFF 字节进行编程
    //禁用 ECC,以便在读取闪存内容时不生成错误
    //无 ECC
    Flash0EccRegs.ecc_enable.bit.enable = 0x0;

    for (i=0;i<=word_in_flash_buffer;i++)

    Buffer[i]= i;


    对于(i=0、u32Index = Bzero_sectorb_start;
    (u32Index <(Bzero_sectorb_start + wors_in_flash_buffer)))
    &&(oReturnCheck = Fapi_Status_Success);i+= 8、u32Index+= 8)

    oReturnCheck = fapi_issueProgrammingCommand ((UINT32 *) u32Index、
    Buffer + I、
    8、
    0、
    0、
    Fapi_DataOnly);
    while (fapi_checkFsmForReady ()=fapi_Status_FsmBusy);

    if (oReturnCheck!= Fapi_Status_Success)

    //检查闪存 API 文档以了解可能的错误
    Example_Error (oReturnCheck);


    //读取 fmstat 寄存器内容以了解 FSM 的状态
    //在用于任何调试的程序命令之后
    oFlashStatus = fapi_getFsmStatus();

    //验证编程的值。 Program 步骤本身会进行验证
    //进行。 此验证是可以执行的第二次验证。
    oReturnCheck = fapi_doVerify (((uint32 *) u32Index、
    4、
    Buffer32+(I/2)、
    oFlashStatusWord (&O);
    if (oReturnCheck!= Fapi_Status_Success)

    //检查闪存 API 文档以了解可能的错误
    Example_Error (oReturnCheck);




    EDIS;

    INT_ENABLE;

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

    Justin、

    1)阅读问题: 好的、您至今提供了两个不同的代码。  您的最新代码使用 Fapi_DataOnly 模式进行程序操作。  此模式不对 ECC 进行编程。  它仅对数据进行编程。  这就是在启用 ECC 的情况下读取时出现 ECC 错误的原因。  这样、我们可以解决您的读取问题吗?  

    2) 2)遇到新问题[您正在进行编程时收到中断、由于 ECC 已禁用、因此它不是与 ECC 错误相关的中断。  此外、您确认它不是 NMI ]:  

    A)如果您想轻松了解中断源、可以初始化整个 PIE 矢量表以指向默认 ISR 例程、如下所示(取自 controlSUITE 示例)。

    //
    //清除所有中断并初始化 PIE 矢量表:
    //禁用 CPU 中断
    //
    Dint;

    //
    //将 PIE 控制寄存器初始化为默认状态。
    //默认状态为禁用所有 PIE 中断和标志
    //被清除。
    //此函数位于 F2807x_PIECTRL.c 文件中。
    //
    InitPieCtrl();

    //
    //禁用 CPU 中断并清除所有 CPU 中断标志:
    //
    IER = 0x0000;
    IFR = 0x0000;

    //
    //使用指向 shell 中断的指针初始化 PIE 矢量表
    //服务例程(ISR)。
    //这将填充整个表,即使是中断也是如此
    //在本例中未使用。 这对于调试很有用。
    //可以在 F2807x_DefaultIsr.c 中找到 shell ISR 例程
    //此函数位于 F2807x_PieVect.c 中
    //
    InitPieVectTable();

    //
    //启用全局中断和更高优先级的实时调试事件:
    //
    EINT;//启用全局中断 INTM
    ERTM;//启用全局实时中断 DBGM

    b)您是否从闪存或 RAM 运行闪存 API 函数?  它们只能从 RAM 中执行。  当一个编程或者擦除操作正在进行中时、闪存不能被访问。  因此、F2807x 的闪存 API 只能从 RAM 中执行、如 TRM 中所述。  如果在 RAM 中加载了闪存 API 并将其设置为从 RAM 执行(通过将其分配给.TI.ramfunc),请检查是否使用 memcopy()将其复制到 RAM。  确保将 Fapi_UserDefinedFuncations.c 文件中的函数以及.TI.ramfunc 分配给 controlSUITE 示例中所示的函数。  检查您是否获得了 ITRAP (ILLEGAL_ISR)。    

    c) API 不启用任何中断。  另请注意、API 不配置(启用/禁用)看门狗。  您是否检查了是否启用了任何其他中断?  检查 PIECTRL、PIEIERx、PIEIFRx 寄存器。

    d)您没有回答我之前关于看门狗的问题。  是启用还是禁用?  如果已启用、您的应用程序是否正在为其提供服务?

    3) 3)关于您的与闪存时钟相关的问题: 只要

    (i)您可以正确配置 PLL 以获得应用所需的 SYSCLK、以及

    (ii)正确配置等待状态、然后

    (iii)将该频率值正确传递到 Fapi_initiatizeAPI ()、

    闪存时钟将由 API 正确配置。  

    谢谢、还有 regars、

    Vamsi

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

    Vamsi、

    我没有意识到旧版本的代码只对数据进行了编程、而不是 ECC。  让我将其更改为对 ECC 进行编程、我将向您介绍它的运行方式。  我还将在下一次答复中回答你的其余问题。

    谢谢、

    Justin

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

    Vamsi、

    首先、我进行了检查以确保从 RAM 调用闪存 API、然后我附加了下面.map 文件的一个片段、显示 EEPROM_write()位于'ramfuncs'中指定的其他函数中。

    全局符号:按符号地址排序

    页 地址 名称                  

    ------   ----                  

    0  00000124 _bootloader_ram_functions_load_end   

    0  00000124 _bootloader_ram_functions_load_start  

    0  00000124 _bootloader_ram_functions_run_start  

    0  00000ce0 _Cla1SoftIntRegs            

    0  00008000 _inV_loop               

    0  00008000 _ram_functions_run_start        

    0  000082ab _pFC_loop               

    0  000084b8 _EEPROM_WRITE             

    0  00008527 _EEPROM_UPDATE_PAGE_STATUS       

    0  00008528 _EEPROM_UPDATE_班 组状态       

    0  00008529 _EEPROM_GET_VALID 页         

    0  0000852a _EEPROM_ERASE             

    0  0000852b _ISR_PFC                

    0  00008565 _ISR_INV                

    其次、我验证了当闪存尚未写入时、闪存读取不会导致问题(所有 FFFF)。  当我使用自动 ECC 生成对闪存进行写入时、我仍然会收到意外中断。  按照您的建议输入所有 ISR shell、它会进入 ILLEGAL_ISR。  您是否对这种情况的发生有任何想法?

    第三、就看门狗而言、是的、它被启用、是的、它被处理。  我有一个从操作系统的任务调度程序调用的函数 watchdog_reset(),因此它会频繁运行。  我想、当调用闪存 API 时、操作系统可能会挂起、但我还不知道所有操作都需要多长时间。  安全装置复位代码如下:

    空安全装置复位(空)

    EALLOW;

    //重置看门狗计数器
    WdRegs.WDKEY。ALL = 0x0055;
    WdRegs.WDKEY。ALL = 0x00AA;

    //重置外部看门狗

    GpioDataRegs.GPBSET.bit.GPIO62=1;
    asm (" RPT #50 || NOP");
    GpioDataRegs.GPBCLEAR.bit.GPIO62=1;

    EDIS;


    -Justin

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

    ILLEGAL_ISR (ITRAP)不会由于读取而发生、而是在 CPU 获取非法操作码时发生。 确保您的应用程序没有擦除它尝试执行的闪存存储器。 检查链接器命令文件以了解您的应用程序正在使用的闪存存储器范围、并确保您没有擦除它们。

    确保执行 memcopy 以复制加载到闪存并映射到 RAM 以运行的段。

    此外、请确保堆栈不会溢出到覆盖代码或数据的其他 RAM 块。

    逐步浏览您的代码、找出导致 illeagal ISR 的代码部分、然后从此处进行调试。

    您是否了解了闪存编程示例并了解其工作原理?

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

    您好、Vamsi、

    我检查了链接器命令文件、认为我正在擦除扇区 B、程序未使用该扇区获取指令。  我应该尝试使用一个远离程序其余部分的闪存扇区吗?  就像现在一样、程序指令存储在扇区 A 和 C 中

    如何"确保堆栈不会溢出到其他 RAM 块覆盖代码或数据"?

    我是否需要确保我写入的数据在"PAGE 1"与"PAGE 0"中?

    -Justin

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

    Vamsi、

    昨天我注意到了不同的行为、我想告诉大家。  example_error()函数已留空(这是在闪存 API 失败时调用的函数,它保留在我使用的示例项目中)。  在昨天的故障排除中、我想确定闪存 API 是否出现故障。  因此我在 example_error()中输入一条语句来递增计数器。  该语句是 FLASH_WRITE_ERROR++。  现在、我得到的不是非法_ISR、而是以下错误(下图)。  你怎么看?

    -Justin

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

    Justin、

    以上不是错误。  这只是说找不到 API 函数的源代码。  这是因为 TI 提供了一个 API 库(您已链接到您的项目)、而不是 API 源。  这不是问题。  在 API 函数调用后保留一个断点、您将无法进入该断点。

    谢谢、此致、

    Vamsi

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

    好的、但是如果没有错误、为什么程序会在此时停止? 之前,CPU 将在 ILLEGAL_ISR()中停止,现在它将在上图中所示的位置停止。 如果不是错误、为什么它会在那里停止?

    此外、我昨天的问题是:

    我检查了链接器命令文件、认为我正在擦除扇区 B、程序未使用该扇区获取指令。 我应该尝试使用一个远离程序其余部分的闪存扇区吗? 就像现在一样、程序指令存储在扇区 A 和 C 中

    如何"确保堆栈不会溢出到其他 RAM 块覆盖代码或数据"?

    我是否需要确保我写入的数据在"PAGE 1"与"PAGE 0"中?

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

    1)从上面的快照中、我看到闪存 API 函数正在从闪存地址执行(正如我之前提到的、它们应该在 RAM 中执行)。 您可以共享链接器命令文件和映射文件吗?

    2) 2)关于使用另一个扇区的问题:只要您不使用扇区 B、就应该能够将其擦除。 但是、出于此调试目的、您可以尝试另一个扇区、看看问题是否已解决。 可能有分配的内容、您注意到了吗? 检查链接器命令文件和映射文件。

    3) 3)关于堆栈:尝试增大堆栈大小、看看这是否有用。 您可以在执行程序之前使用常量填入栈空间、然后检查在执行程序之后使用了多少栈空间(当遇到问题时)。 这将指示堆栈是否溢出。

    4)页面问题:是的、您可以将其设为第1页。

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

    Vamsi、

    我使用了 controlSUITE v150中的示例代码。  现在、我将查看我拥有的示例的最新版本(V210)。  我仍然看不到任何指定使用#pragma 语句将闪存 API 库复制到 ramfuncs 的位置。  从一开始、我就将调用闪存 API 的函数复制到了 RAM 中、但我不知道如何指定 API 本身驻留在 RAM 中。  请告诉我如何操作?

    -Justin

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

    Justin、

    请检查示例中使用的链接器命令文件。  您将注意到.TI.ramfunc 段和 API 库被组合在一起、以加载到闪存并从 RAM 运行。  请参阅以下从链接器命令文件获取的片段。

        组

        {

          .TI.ramfunc

          {-l F021_API_F2837xD_FPU32.lib}

        }负载= FLASHD,

         运行 = RAMLS03、

         load_start (_RamfuncsLoadStart)、

         load_size (_RamfuncsLoadSize)、

         load_end (_RamfuncsLoadEnd)、

         run_start (_RamfuncsRunStart)、

         run_size (_RamfuncsRunSize)、

         run_end (_RamfuncsRunEnd)、

         PAGE = 0   

    谢谢、此致、

    Vamsi

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

    好的、我对.cmd 文件进行了更改、并将闪存 API 也放置在 ramfuncs 中。 我只将调用 API 的函数放入 RAM 中。 现在、这些 API 也在那里。 不过、这并没有解决我的问题。 我通过将堆栈大小加倍来解决 ILLEGAL_ISR()问题。 它的长度为0x400、我使它的长度为0x800。 现在我不再得到 ILLEGAL_ISR(),但当我尝试读取闪存时,我仍然会遇到奇怪的错误(如下所述)。

    首先、我仍然启用了 ECC、我正在获取 NMI。 然后我禁用了 ECC、NMI 消失了、但我仍然会有奇怪的行为。 我定期调用 flash_read()函数,它只读取从0x82000开始的前16个存储器地址。 请参阅下面的代码段。 这将持续运行。 在我将程序写入闪存一次或两次后、闪存变得不稳定。 我的意思是:当我刷新存储器浏览器(指向0x82000)时、存储器值从顺序测试模式(0x00到0xFF)变为完全随机的16位数、并且每次刷新存储器刷新时、都会切换存储器映射中的随机位。 每次我刷新时、观察窗口中显示的数字中大约10%会发生一个十六进制字符变化、就好像一个位在切换一样(例如、C 变为4、或 E 变为 F)。 如果我不断刷新内存浏览器、我会不断地看到许多值发生变化。 这听起来像是您认为常见问题吗? 我验证了即使完全禁用闪存读取、也会发生位切换。 程序正在运行、但闪存未被写入或读取(我可以告诉您)。


    void flash_read (void)

    uint16 i;
    //extern UINT16 EEPROM_DATA_LOAD_START;

    对于(i=0;i<16;i++)

    *(READ_FLASH_buffer + I)=*((UINT16 *)(0x82000)+ I);


    }//函数末尾 flash_read()


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

    Justin、

    是否在启用 ECC 的情况下验证是否通过了程序?

    我强烈建议您首先在启用 ECC 的情况下执行闪存 API 示例、并查看是否通过验证。 完成此步骤后、我将继续为您提供支持。

    谢谢、此致、
    Vamsi

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

    我一直在尝试很多东西、但我错过了您关于检查程序是否通过验证阶段的请求。 很抱歉。

    我对你的问题的简短回答是:我不知道。 我不知道的原因是、我不相信调试器会正确设置断点、并且代码中的跟踪变量看起来运行不正常。 请允许我解释:

    当我尝试在 EEPROM_WRITE()函数中设置断点时,IDE 返回错误(在控制台中用红色字母表示)“C28xx_CPU1:设置断点时遇到问题,在0x8c43上执行“保持暂停”操作:错误0x00000008/-1066错误,期间: 断点、无法在0x00008C43"处设置/验证断点、然后在该断点的正下方、我进入控制台(用黑色字母表示)"C28xx_CPU1:断点管理器:使用 AET 断点重试"

    当我运行程序并设置一个标志以使函数运行时、如果我将程序放置在本应捕获验证阶段失败的 if 语句中、则程序不会在断点处停止。 EEPROM_WRITE()函数中还有其他位置、断点不会停止处理器。 但是 EEPROM_write()函数中有一些断点将停止程序的位置,例如在以下语句中:

    oReturnCheck = Fapi_issueODE19 CommandWithAddress (Fapi_EraseSector、 (uint32 *) bzero_sectorb_start);

    但是、代码中还有两个跟踪变量、它们看起来根本不会更新、并且具有奇怪的行为。 请允许我解释:

    在 EEPROM_WRITE()函数的开头,我递增跟踪变量 FLASH_WRITE_called。 这是为了让我知道该函数已被调用。 我还在 example_error()函数中增加了一个跟踪变量、称为 flash_write_error。 我为这两个变量都全局 uint16变量。 当我在观察窗口上查看这些变量时、它们显示为零。 当我调用 EEPROM_write()函数时,它们不会递增。 当我在观察窗口中手动更改这些变量并刷新观察窗口时、我在其中写入的值保持不变。 当我触发 EEPROM_WRITE()函数时,跟踪变量返回零! 为什么会这样呢?

    此外、在监视窗口中、查看用于使用 API 将实际数据编程到闪存中的变量"缓冲区"、当我在监视窗口中监视该变量时、它几乎总是显示为零、即使在我有证据表明 EEPROM_write()函数已成功运行后也是如此。 没有代码会清除该数组,因此一旦在 EEPROM_write()中写入该数组,它就应该保留这些值。 但在大多数情况下、数组读取观察窗口中的所有零。

    由于我在设置断点时遇到问题、成功地暂停处理器、并且跟踪变量出现异常行为、因此我对您的问题的答案不确定。 我正在尝试对其进行调试、但我不相信我的工具为我提供的答案。 如果你能说明这里发生的情况,我将非常感激。

    谢谢、
    Justin


    void EEPROM_WRITE (UINT16加法)


    uint32 u32Index = 0;
    uint16 i = 0;

    Fapi_StatusType o 返回检查;
    易失性 Fapi_FlashStatusType o 闪存状态;
    Fapi_FlashStatusWordType oFlashStatusWord;

    FLASH_WRITE_called +;

    //禁用 ECC。 ECC 不必被禁用即可执行类似的 FSM 操作
    //编程和擦除。
    //但是、在 Sonata Rev. 0芯片上、由于 OTP ECC 勘误表、
    //禁用 ECC 以避免在使用闪存 API 函数时出现 ECC 错误
    //读取 TI-OTP

    INT_DISABLE;
    DRTM;

    EALLOW;


    //擦除扇区 B
    oReturnCheck = Fapi_issueODE19 CommandWithAddress (Fapi_EraseSector、
    (uint32 *) bzero_sectorb_start);

    //等待 FSM 完成擦除扇区操作
    while (fapi_checkFsmForReady()!= fapi_Status_FsmReady){}
    //验证 sectorb 是否被擦除。 "擦除"步骤本身的验证方式为
    //可以。 此验证是可以执行的第二次验证。
    oReturnCheck = Fapi_doBlankCheck ((uint32 *) Bzero_sectorb_start、
    Bzero_16KSector u32length、
    oFlashStatusWord (&O);

    if (oReturnCheck!= Fapi_Status_Success)

    //检查闪存 API 文档以了解可能的错误
    //如果擦除命令失败,请使用 Fapi_getFsmStatus()函数
    //获取 fmstat 寄存器内容
    //查看 EV 位、ESUSP 位、STAT 位或 VOLTSTAT 中是否有任何一个
    //位被置位(更多细节请参考 API 文档)
    Example_Error (oReturnCheck);





    //最多可向程序函数提供8个字的数据缓冲区。
    //每个字都被编程,直到整个缓冲区被编程或 A
    //发现问题。 但是、要对具有大于8的缓冲区进行编程
    //字、程序函数可在循环中调用、以便为编程8个字
    //每个循环迭代直到整个缓冲区被编程



    //示例:使用输出 ECC 对闪存扇区 B 中的0xFF 字节进行编程
    //禁用 ECC,以便在读取闪存内容时不生成错误
    //无 ECC
    // Flash0EccRegs.ecc_enable.bit.enable = 0x0;

    for (i=0;i<=word_in_flash_buffer;i++)

    Buffer[i]=加法;


    对于(i=0、u32Index = Bzero_sectorb_start;
    (u32Index <(Bzero_sectorb_start + wors_in_flash_buffer)))
    &&(oReturnCheck = Fapi_Status_Success);i+= 8、u32Index+= 8)

    oReturnCheck = fapi_issueProgrammingCommand ((UINT32 *) u32Index、
    Buffer + I、
    8、
    0、
    0、
    Fapi_AutoEccGeneration);
    while (fapi_checkFsmForReady ()=fapi_Status_FsmBusy);

    if (oReturnCheck!= Fapi_Status_Success)

    //检查闪存 API 文档以了解可能的错误
    Example_Error (oReturnCheck);


    //读取 fmstat 寄存器内容以了解 FSM 的状态
    //在用于任何调试的程序命令之后
    oFlashStatus = fapi_getFsmStatus();

    //验证编程的值。 Program 步骤本身会进行验证
    //进行。 此验证是可以执行的第二次验证。
    oReturnCheck = fapi_doVerify (((uint32 *) u32Index、
    4、
    Buffer32+(I/2)、
    oFlashStatusWord (&O);
    if (oReturnCheck!= Fapi_Status_Success)

    //检查闪存 API 文档以了解可能的错误
    Example_Error (oReturnCheck);




    //启用 ECC
    Flash0EccRegs.ecc_enable.bit.enable = 0xA;

    EDIS;

    INT_ENABLE;
    ERTM;

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

    我知道。 但是、请注意我们的问题并回答这些问题、以便我们能够帮助您以最佳方式进行调试。

    我记得我在 CCSv6中遇到了断点问题。
    您是否检查了更新并安装了所有更新? 我将要求 CCS 专家查看此帖子。

    现在、您能否依赖从 verify 函数获取的返回值而不是断点和观察窗口? 您有一个 if 循环来检查从 verify 返回的值是否成功。 请告诉我,如果 loop 是否正在进入 example_error()函数。 我希望您使用启用的 ECC 进行验证。 此外、现在、如果您在构建选项中启用了优化、则禁用优化。

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

    还有两个问题:

    1) 1)如何配置引导模式引脚? 它们是否配置为引导至闪存? 如果是、您是否可以将其更改为其他内容并尝试?

    2) 2)您是否已对任何密码进行编程?

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

    Vamsi、

    请允许我在这里备份一点。 我在上一个帖子中遇到的许多问题可能是由于看门狗服务不正确导致的。 这就是跟踪变量重新初始化的原因、我认为这就是断点行为错误的原因。 我已更正了看门狗问题、现在跟踪变量正在递增、我更好地了解对您之前有关验证阶段是否失败的问题的答案。 答案是"是"、它未通过验证操作。 此测试期间启用 ECC。

    我在这里看到的另一件奇怪的事情是、当我运行 EEPROM_WRITE()函数时、我在函数"flash_write_call"顶部具有的跟踪变量会增加18倍、我计数的跟踪变量会失败验证阶段的次数也会增加18倍。 为什么整个函数运行18次? 我只调用它一次。

    我将检查 CCS 更新。

    -Justin

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

    我忘记了回答您在另一条消息中提出的这两个问题:

    1)引导模式配置为"引导至闪存"(TRST = 0、IO72 = 1、IO84 = 1)。 这在 PCB 上硬接线、无法更改。
    2) 2)未对密码进行编程。

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

    [引用 user="Vamsi Gudivada"]我记得我在 CCSv6中遇到了断点问题。

    Vasmi -我相信您所想到的问题与 ramfunc 相关、如果程序有一个段在运行时加载到闪存并提取到 RAM 中、并且在 RAM 的那个区域中设置了一个(软件)断点、则会发生该问题。 这里发生了什么?

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

    是的、我在获得断点以在加载到闪存并提取到 RAM 的函数中可靠工作时遇到困难。 是否有解决方法? 或者、我是否无法在这些函数中设置断点?

    谢谢、
    Justin
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Justin -您能解释如何/何时设置此断点以及何时发生错误吗? 当您尝试设置断点时、程序在何处停止?

    如果您可以解释调试环境的确切顺序、这将很有帮助。

    例如:
    1) 1)按"Debug"按钮启动调试器并加载程序
    2) 2)调试将在"main"停止
    3) 3)在 file.c 的第235行设置 SW 断点
    4) 4)发生错误
    (笑声)
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Justin、

    1) 1)请注意您已修复看门狗。 我要求您在12天前检查看门狗服务。

    2) 2)由于验证失败、是否可以在程序操作后检查 FMSTAT 寄存器的值? 您可以为此使用 Fapi_getFsmStatus()函数。 fmstat 寄存器的详细信息在 www.ti.com/.../spnu595.pdf 中的3.2.1 Fapi_getFsmStatus()部分中的函数说明中提供。

    3) 3)关于为什么函数被执行18次:您是否将该变量初始化为零? 您可能需要通过将应用程序剪切并逐件添加来调试应用程序。

    请注意、对于闪存单位 ECC 错误、有一个勘误表、其建议标题如下。 检查它并将阈值配置为非零值。
    通报闪存:单位 ECC 错误可能会导致对单位错误 ISR 的无限调用。

    如果您将阈值设置为0、并且存在单个位错误、您可能会进入无限循环。

    4) 4)如果您将引导模式设置为闪存、则在加电时、CPU 将从闪存取并执行它。 因此、请确保闪存中有一些有效的代码、这样 CPU 在连接仿真器之前就不会执行一些进入未知状态的垃圾回收器件。

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

    此外、我建议执行 TI 提供的闪存编程示例并查看其是否起作用。 这可帮助您了解您是否有任何设置问题/电路板问题等

    例如、很少有 F28075 QFP 用户忘记将封装底部的 PowerPAD 焊接到 PCB 的接地层。 此问题的调试像闪存 API 调试一样开始、稍后我发现用户没有将 PowerPAD 焊接到接地层。

    在另一种情况下、1.2V 电源线在闪存程序运行期间下降至低电平、从而导致故障。 一旦他们修复了电源、一切都正常。 您可能还需要检查这些内容。

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

    您好、Vamsi、

    我撕下一块备用板、将处理器焊接到 PowerPAD 上。

    我没有单独运行实际示例项目、但我已经将代码复制/粘贴到程序中、它在启动时运行。  这是可行的、并且已经运行了一段时间。  当我稍后在程序中再次尝试运行闪存编程例程(封装在我的 EEPROM_write()函数中的示例项目)时,会导致问题。

    我尚未检查电源轨。  你认为我应该这样做吗?

    -Justin

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

    我刚才注意到的一点是、当我将看门狗服务代码插入 API 的看门狗函数时、示例项目代码不再对闪存(全部为0xFFFF)进行编程、并且我获得了"验证失败"的证据。 当我删除看门狗服务代码时、我在闪存中获得了测试模式、并且没有"验证失败"的证据。

    到目前为止可能还没有清除、但我在代码中的两个位置进行了 EEPROM_WRITE()函数调用。 首先、我从初始化阶段调用它、每次程序启动时都会调用它。 然后、在程序的后面部分、在主循环中、我在收到我从调试器的观察窗口中更改的标志时调用 EEPROM_write()函数。 出于某种奇怪的原因,当看门狗服务代码未包含在 Fapi_serviceWatchdogTimer()时,我看到 CPU 在何处复位的问题只在程序稍后调用 EEPROM_write()函数时发生。 当 EEPROM_WRITE()在初始化后立即被调用时(即使不包含看门狗服务代码)、我永远不会看到看门狗复位 CPU。 当然、此时还没有启用中断。 (不过、当我稍后在程序中调用 EEPROM_write()时、我确实会关闭中断)。

    我刚才提到的任何事情对您来说是否有意义、或者对我的问题有更多的了解?

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

    Justin、

    1)关于看门狗: 请确保在看门狗服务函数主体的末尾包含一个 EALLOW、以便以后的 API 函数根据需要写入受保护的寄存器。

    Fapi_StatusType Fapi_serviceWatchdogTimer (空)

    /*用户在此处添加自己的看门狗服务代码*/

    ServiceDoG();//您自己的函数主体

    EALLOW;//添加此 EALLOW

    返回(Fapi_Status_Success);

    2)关于看门狗复位: API 调用此看门狗服务例程的频率可能不足以为看门狗提供服务。 因此、您可能需要增加看门狗失效的时间周期。  但是、由于闪存 API 在此器件上是可中断的、我建议您启用中断并根据计时器中断为看门狗提供服务。  这样、您就可以确定看门狗装置以正确的速度进行处理。  请注意、ISR 应该被复制到 RAM 中、这是因为当一个擦除或编程操作正在进行时、不应该有一个闪存访问。

    谢谢、此致、

    Vamsi  

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

    您的应用程序现在是否能够成功地进行编程和验证而不会出现任何问题?

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

    您好、Vamsi、

    是的、它现在可以工作。  从一开始就存在多个问题。  它们是:

    *这些函数是从 ISR 调用的函数中调用的。  这显然会导致问题(即使这是它在28069上运行的该固件的先前版本中的工作方式。  我认为这是导致堆栈溢出的原因。

    *首先、看门狗未被处理(用户定义的看门狗处理函数为空"。

    *然后、我需要在"用户定义的看门狗服务函数"末尾添加一条 EALLOW 语句。

    *未指定 API 库从 CMD 文件中的 RAM 运行。

    *在调试早期尚未禁用中断。

    *在调试的早期、ECC 计算不正确。

    由于我已经解决了这些问题、并且能够可靠地写入闪存、因此我一直在实施 TI EEPROM 仿真功能。  由于您似乎不能重写已经被写入的闪存字、所以它们与28075不直接兼容。  例如、组状态字在"空白"时以0xFFFF 开头、在"当前正在使用"时以0xA00A 开头、在"满"时以0x0000开头。  我发现的问题是、我无法重写0xA00A、使其成为0x0000 (我假设 ECC 字节需要更改、并且通常它不仅会将位从1更改为0)。  因此、我必须修改这些函数的操作、以仅处理"空"和"已使用"状态。  "页面状态"也是如此。  此外、不能写入单个闪存字意味着我需要占用闪存中的整个8字行来处理以前作为单个状态字的内容。  因此、与28069中的相同实现方案相比、它还使用更多的存储器。  但我已经使它正常工作了。

    感谢你的帮助。  

    -Justin

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

    好的、我们的对话有助于调试、您的应用程序现在已启动并运行。

    我要关闭此主题。

    谢谢、此致、
    Vamsi