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.

[参考译文] TMS320F2800157:I2C 引导加载程序未跳转/返回到闪存

Guru**** 2873850 points

Other Parts Discussed in Thread: TMS320F2800157

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

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1631049/tms320f2800157-i2c-bootloader-not-jumping-returning-to-flash

器件型号: TMS320F2800157

您好、

我开发了一个引导加载程序、并在以下主题中获得了帮助、以克服引导模式和 BOOTPIN 问题。  我遇到了引导加载程序无法跳转/返回闪存基地址 0x80000 的问题。  我在其他问题中得到了总结、但从未解决过我的问题。

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1553977/tms320f2800157-setting-otp-bootpin-and-bootmode

我在下面附上了我的代码。   我将使用 TMS320F2800157 LaunchPad 并使用 GPIO32 作为引导模式引脚。  我设置了 Z1-GPREG1-4、可以将 LaunchPad 上的 GPIO32 切换为引导至 I2C 或闪存。  

当引导至闪存时、我的应用程序会按预期运行。  设置 I2C 后、我会看到 TMS320 将数据拉过 I2C 线路、使 LED 闪烁(在代码中)、然后重新启动。  已验证代码中的 bootflag 不等于 1。  这大约是一个 1 秒的间隔、对应于我在示波器上观察 I2C 流量的时间(还与计算出的使用我给定的时钟设置加载引导代码的时间一致)。

我已经将引导加载程序构建为 RAM 编译版本、我想知道跳转/返回到闪存 (0x80000) 是否被捕获并导致重新启动。 我可能还需要一个额外的项目限定符、但我也错过了。

如有任何建议、将不胜感激。

John

//#############################################################################
// BOOTmain.c
// Hex2000 params as follows to provide a 500 khz clock at boot:
// Specify initial value for I2CCLKH register (--i2cclkh, -i2cclkh) 10
// Specify initial value for I2CCLKL register (--i2cclkl, -i2cclkl) 10
// Specify initial value for I2CPSC register (--i2cpsc, -i2cpsc) 0


#include "driverlib.h"
#include "device.h"
#include "board.h"
#include "c2000ware_libraries.h"
#include "i2ca.h"
#include "const.h"
#include "Boot.h"

//###########################################################################
// Local functions declaration
void AppReload(void);


// Main
uint32_t main(void)
{

    uint16_t BFlag;    // BootFlag - set to reload Application Software
    
    // Step 1. Initialize System Control:
    // Enable Peripheral Clocks
    Device_init();
    
    // Step 2. Initialize GPIO:
    Device_initGPIO();

    // Step 3. Clear all interrupts and initialize PIE vector table:
    // Disable CPU interrupts
    DINT;

    // Initialize PIE and clear PIE registers. Disables CPU interrupts.
    Interrupt_initModule();

    // Initialize the PIE vector table with pointers to the shell Interrupt Service Routines (ISR).
    Interrupt_initVectorTable();

    // PinMux and Peripheral Initialization
    Board_init();

    GPIO_writePin(LED_BUSY, 1);

    // Read the BootFlag status
	I2CA_Read(I2C_EEPROM2_ADDR, ADR_FLAG_BOOT, (uint16_t *)&BFlag, 2, WORD);

    // Test BootFlag status
    if(BFlag == 0x01)
    {
	    GPIO_writePin(LED_BUSY, 0); // LED on
	    AppReload();  // Will never come back from this call - infinite loop.
    }
    else
    {
   	    GPIO_writePin(LED_BUSY, 1); //GpioDataRegs.GPACLEAR.bit.GPIO30 = 1; // LED off

        uint16_t Version = VERSION;
    
        // Read the BootLoader Version and update if needed
        I2CA_Read(I2C_EEPROM2_ADDR, ADR_VER_BOOTLOADER, &Version, 2, WORD);
        if (Version != VERSION)
        {
            Version = VERSION;
            I2CA_Write(I2C_EEPROM2_ADDR, ADR_VER_BOOTLOADER, &Version, 2, WORD);
        }
    }
    SysCtl_enableWatchdog();  // Enable watchdog module
    SysCtl_serviceWatchdog(); // Clear the WD counter

    // Use the 4 NOPs and LB 0x80000 in place of return(0x80000) as the return goes off in the weeds.
/*    asm("    NOP");
    asm("    NOP");
    asm("    NOP");
    asm("    NOP");  
    // Jump to flash
    asm("    LB 0x80000"); */
    return(0x80000);
}
// End of File
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    John、

    为了清晰起见、我将介绍外部系统发生了什么、以确保我们保持一致。

    当您要更新固件时、可通过开关或跳线将 BOOTPIN 设置为“1";“;如果希望 LED 闪烁、则手动将其更改为“0",“,以、以指示有安全时间更改引脚状态。

    I2C 更新固件后、它会发出重新启动的命令、然后根据所附的代码 、它应使 LED 变为低电平、以指示其将运行应用程序、但您永远看不到它会运行应用程序。

    如果您只是在闪存引导模式下引导、一切都正常。

    q1) 在固件更新后、即使重新启动到闪存失败、如果在引导引脚 设置为“闪存引导“的情况下对 PCB 进行下电上电、工作正常?(这意味着固件更新也很好)

    Q2) 当固件更新完成并尝试重新启动时、您如何在代码中执行此操作?  分支到 Brom 起始地址、强制 WDRSn 等?

    此致、

    Matthew

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

    尊敬的 Matt:

    感谢您的回答。 澄清、

    1. 尽管我们在此过程中支持固件更新、但问题在于从 I2C 运行引导加载程序时不会返回固件并将固件加载到闪存中。
    2. 我已经编辑了您的问题、因此它们符合预期操作。

    系统从 I2C 引导(我们计划将 BOOT 引脚保持设置为 0 以从 I2C 引导)、拉入此线程中发布的引导加载程序代码。  BFlag 位决定我们是否从 0x80000 开始更新闪存中驻留的应用程序固件。  我们可以通过将引导引脚设置为 1 来绕过引导加载程序。 LED 状态仅在引导时告知是否设置了 BFlag。

    如果未设置 BFlag、我们应该运行应用程序 (0x80000)、但我看不到它会这样做。

    如果我只是在闪存引导模式(开关设置为引导至闪存)下引导、一切都正常。

    我在使用 CCS 之前已在闪存中安装了固件、并验证它是否可以使用 CCS 调试或仅设置引导引脚开关来绕过引导加载程序。  

    我还尝试从 CCS (RAM) 运行引导加载程序、以在闪存中预加载应用程序的情况下验证其功能。  在执行返回 (0x80000) 时、我永远不会在闪存开始中看到应用程序。

    我认为这两个问题的方向不同、所以我绕过了它们。  我们会去那里。

    谢谢、

    John

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

    尊敬的 Matt:

    我花时间在 Return (0x80000) 处通过代码进行调试。 以下是反汇编。

    • MOVL XAR4、#22 位 (8F080000)
    • SubB SP、#7 位 (FE86) 栈指针在 40A 之前处于、在之后处于 402
    • MOVL loc32、XAR4 (A8A9) XAR4 -> ACC SO ACC 现在包含  0x80000
    • RETLR RPC 包含 0x009CD6 返回程序计数器

    我的代码到此结束、现在我们返回到所有 TI 锅炉板。

    • 返回到 rts2800_fpu32_eabi.lib:args_main.c 的末尾
    • LRETR RPC 包含 0x0099FB 返回程序计数器
    • 返回到 rts2800_fpu32_eabi.lib:boot28.asm.obj (.text) 的末尾
    • LCR 09414
    • 返回到 rts2800_fpu32_eabi.lib:exit.c.obj (.text)

    我看到的是、该序列从不将 0x80000 加载到 PC。  我是否加载了错误的  args_main.c 副本、因为它看起来是应该在返回后检测程序计数器“矢量“位置的例程?

    谢谢、

    John

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

    John、

    我相信您拥有的已注释汇编(使用 LB 0x0x80000)是正确的方法、这会强制跳转到闪存入口点、然后模拟任何像 c_int 这样的 BROM 调用以及对 main 的调用。  我同意这是正确的做法、而不是直接跳回固件更新后的主要部分。   

    return (0x80000); C 指令将返回值 0x80000 到主 C 运行时系统并将该值传递给 exit() 函数、这就是为什么反汇编不能完全匹配我们认为它应该做的事情。

    如果您需要更稳健一点的 功能、在 C 语言中、我们可以创建如下所示的函数:这将禁用所有 INT、清除所有待处理的 INT、然后调用您传递给它的地址。  如果您想确保进行固件更新、还可以检查非 0xFFFF 内容的传递地址、以指示闪存在跳转之前未被擦除、但这可能会根据您的固件流程溢出。

    如果我们走在正确的轨道上、请告诉我。

     

    void JumpToApplication(uint32_t address)
      {
          // Disable all interrupts
          DINT;
    
          // Disable watchdog if enabled
          SysCtl_disableWatchdog();
    
          // Clear any pending interrupts
          Interrupt_clearAllFlags();
    
          // Jump to application
          ((void (*)(void))address)();
      }

    此致、
    Matthew