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.

TMS320F280039C: Memcpy函数

Part Number: TMS320F280039C

工程师好,

          如以下代码红色部分,在配置时钟后增加Memcpy函数,重新拷贝至RAM,这个时候其执行时间才有900us,而前一个Memcpy函数执行时间却是30ms,想知道为什么会有这种差异,900us

执行时间的Memcpy函数是否真的拷贝成功了呢?

void Device_Init(void)
{
//
// Disable the watchdog
//
SysCtl_disableWatchdog();

#ifdef _FLASH
//
// Copy time critical code and flash setup code to RAM. This includes the
// following functions: InitFlash();
//
// The RamfuncsLoadStart, RamfuncsLoadSize, and RamfuncsRunStart symbols
// are created by the linker. Refer to the device .cmd file.
//

memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize); //测试此函数执行时间约30ms

//
// Call Flash Initialization to setup flash waitstates. This function must
// reside in RAM.
//
Flash_initModule(FLASH0CTRL_BASE, FLASH0ECC_BASE, DEVICE_FLASH_WAITSTATES); // InitFlash();
#endif

//
// Set up PLL control and clock dividers
//设置晶振源
SysCtl_setClock(DEVICE_SETCLOCK_CFG);

//
// Make sure the LSPCLK divider is set to the default (divide by 4)
//
SysCtl_setLowSpeedClock(SYSCTL_LSPCLK_PRESCALE_4);

//
// These asserts will check that the #defines for the clock rates in
// device.h match the actual rates that have been configured. If they do
// not match, check that the calculations of DEVICE_SYSCLK_FREQ and
// DEVICE_LSPCLK_FREQ are accurate. Some examples will not perform as
// expected if these are not correct.
//
ASSERT(SysCtl_getClock(DEVICE_OSCSRC_FREQ) == DEVICE_SYSCLK_FREQ);
ASSERT(SysCtl_getLowSpeedClock(DEVICE_OSCSRC_FREQ) == DEVICE_LSPCLK_FREQ);

#ifndef _FLASH
//
// Call Device_cal function when run using debugger
// This function is called as part of the Boot code. The function is called
// in the Device_Init function since during debug time resets, the boot code
// will not be executed and the gel script will reinitialize all the
// registers and the calibrated values will be lost.
// Sysctl_deviceCal is a wrapper function for Device_Cal
//
SysCtl_deviceCal();
#endif

//
// Turn on all peripherals
//
Device_enableAllPeripherals();

//
// Lock VREGCTL Register
// The register VREGCTL is not supported in this device. It is locked to
// prevent any writes to this register
//
ASysCtl_lockVREG();

memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize); //测试此函数执行时间约900us,为什么这里重新拷贝至RAM的执行时间那么少,想知道这里是否拷贝成功了?

//
// Configure GPIO20 and GPIO21 as digital pins
//
// GPIO_setAnalogMode(20U, GPIO_ANALOG_DISABLED);
// GPIO_setAnalogMode(21U, GPIO_ANALOG_DISABLED);
}

期待您的回复,感谢!

  • memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize); //测试此函数执行时间约900us,为什么这里重新拷贝至RAM的执行时间那么少,想知道这里是否拷贝成功了?

    红色代码这里,是完全没有必要再次执行的。

    #ifdef _FLASH
    //
    // Copy time critical code and flash setup code to RAM. This includes the
    // following functions: InitFlash();
    //
    // The RamfuncsLoadStart, RamfuncsLoadSize, and RamfuncsRunStart symbols
    // are created by the linker. Refer to the device .cmd file.
    //

    memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize); //测试此函数执行时间约30ms

    //
    // Call Flash Initialization to setup flash waitstates. This function must
    // reside in RAM.
    //
    Flash_initModule(FLASH0CTRL_BASE, FLASH0ECC_BASE, DEVICE_FLASH_WAITSTATES); // InitFlash();
    #endif

    你看这里是条件编译,只有在FLASH中运行的时候,才会参与编译。

    因为一些函数,诸如Flash的初始化函数,us延迟函数,必须运行在RAM中。所以当器件从FLASH运行时,才需要在运行这些函数前,将代码搬移到RAM中。

    Ramfuncs段中,所有需要从FLASH搬移到RAM的函数都被放置在了这里,这个是通过类似:

    #pragma CODE_SECTION(函数名字, "ramfuncs")

    语句实现的。

    搬移具体需要多少时间,取决于代码量。对FLASH的操作速度是比较慢的。900us确实有点小。

    综上,无论从原理上,还是结果上,这个操作和结果都是不合理的。

  • 您好,感谢您的回复,我理解您说的memcpy函数不需要再次执行,但我在实际应用过程中确实遇到了类似的情况,详细如下:

            在参考280039C的不掉电升级例程中,其代码一共分成了三个独立的工程(即有3个codestart),从FLASH中执行,上电默认从0x80000这个codestart地址执行(简称这个工程为BOOT区,该区域直接在codestart中执行函数,不会跳转至main函数),我在这个codestart中定义了一个BANK选择逻辑,里面通过一些逻辑去选择是跳转至BANK0的codestart还是跳转至BANK1的codestart(简称这两个独立的工程为APP区)。

           由于在BOOT区中需要使用FLASH_API函数,我便在BOOT区的codestart里使用memcpy函数将FLASH_API函数搬运至RAMGS2中(测试其执行时间为30ms),并进行了时钟配置,详细如下代码:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    //
    // bankSelect - Located at the beginning of bank 0 (0x80000),
    // Bank_Select branches to the most recently programmed
    // bank after execution of the Live DFU command.
    // If a bank has not been programmed using the Live
    // DFU command, it branches to the kernel setup so that
    // the command can be used to program bank 1.
    //
    #ifdef __cplusplus
    #pragma CODE_SECTION("codestart");
    #else
    #pragma CODE_SECTION(bankSelect, "codestart");
    #endif
    void bankSelect(void)
    {
    uint32_t REV_BANK0 = HWREG((uint32_t)B0_REV_ADD); // Read the revision value of bank 0
    uint32_t REV_BANK1 = HWREG((uint32_t)B1_REV_ADD); // Read the revision value of bank 1
    Device_Init(); //FLASH_APIRAMGS2
    Flash_Init(); // Initialize the Flash API
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

            从BOOT区的codestart跳转至APP区(BANK0的codestart或者是BANK1的codestart)时,正常进行_c_int00然后跳转至mian函数,由于这个是独立的工程,在main函数中又需要使用memcpy函数,将FLASH_API函数以及自定义的一些函数,包括中断函数搬运至RAMGS0_GS1中,执行到此处时就出现了最开始的那个问题,即测试这个时候的memcpy函数执行时间才900us,这个执行时间有点不合理,所以就比较担心是否真的搬运成功了,要是没有搬运成功,就可能会有程序跑飞的风险,这个是我比较担心的问题。

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    //
    // Note that the watchdog is disabled in codestartbranch.asm
    // for this project. This is to prevent it from expiring while
    // c_init routine initializes the global variables before
    // reaching the main()
    //
    void main(void) //APPmain
    {
    // read the LFUCPU register bit to determine if an LFU switchover is currently in progress
    // if it is, skip all initializations except the necessary ones
    lfu_cpu = LFU_getLFUCPU(LFU_BASE);
    if(lfu_cpu != LFU_CPU)
    {
    //Clear all interrupt, initialize PIE vector table:Disable CPU interrupt
    DINT;
    //
    // Set up the basic device configuration such as initializing PLL,
    // copying code from FLASH to RAM, and initializing the CPU timers that
    // are used in the background A, B, C tasks
    //
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    //
    // Note that the watchdog is disabled in codestartbranch.asm
    // for this project. This is to prevent it from expiring while
    // c_init routine initializes the global variables before
    // reaching the main()
    //
    void main(void) //APPmain
    {
    // read the LFUCPU register bit to determine if an LFU switchover is currently in progress
    // if it is, skip all initializations except the necessary ones
    lfu_cpu = LFU_getLFUCPU(LFU_BASE);
    if(lfu_cpu != LFU_CPU)
    {
    //Clear all interrupt, initialize PIE vector table:Disable CPU interrupt
    DINT;
    //
    // Set up the basic device configuration such as initializing PLL,
    // copying code from FLASH to RAM, and initializing the CPU timers that
    // are used in the background A, B, C tasks
    //
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  • 除了copy之外的部分工作是正常的吗?

    有没有比较一下两个copy操作copy的代码量?

  • 第一个copy的代码量:FLASH_API

    第二个copy的代码量:FLASH_API、部分自定义的需要放RAM的函数、中断函数,总共大约是第一个copy代码量的两倍

    除了第二个copy外其他代码工作正常,暂未发现其他异常

  • 补充测试项:将BOOT区的Device_Init()和Flash_Init()屏蔽,即BOOT区的codestart里不进行copy和时钟配置,那么跳转至APP区后,APP区的copy函数执行时间则是正常的,大约46ms左右

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    //
    // bankSelect - Located at the beginning of bank 0 (0x80000),
    // Bank_Select branches to the most recently programmed
    // bank after execution of the Live DFU command.
    // If a bank has not been programmed using the Live
    // DFU command, it branches to the kernel setup so that
    // the command can be used to program bank 1.
    //
    #ifdef __cplusplus
    #pragma CODE_SECTION("codestart");
    #else
    #pragma CODE_SECTION(bankSelect, "codestart");
    #endif
    void bankSelect(void)
    {
    uint32_t REV_BANK0 = HWREG((uint32_t)B0_REV_ADD); // Read the revision value of bank 0
    uint32_t REV_BANK1 = HWREG((uint32_t)B1_REV_ADD); // Read the revision value of bank 1
    // Device_Init(); //FLASH_APIRAMGS2
    // Flash_Init(); // Initialize the Flash API
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  • 被搬移的代码运行的位置相同吗?也就是说使用的是相同的RAM区域吗?

    如果是的话,试着在再次搬移前初始化或者清一下相应的RAM区域。

    这个时候其执行时间才有900us,
    大约46ms左右

    两次执行的差异如此巨大,第二次可能确实没有执行。函数或许检测到一些错误,所以中断了执行。

    有关初始化或清RAM,请参考:

    https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1206262/tms320f28374d-how-to-initialize-or-clear-a-specified-ram-area

    https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1266791/tms320f280039-support-need-to-add-the-codes-to-clear-ram-after-the-reset

    https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1199435/tmdscncd28388d-the-difference-between-ram-init-and-clear-ram-for-boot-stack

  • 被搬移的代码运行的位置不相同,BOOT区放在GS2,APP区放在GS0和GS1。另外在APP区的codestart中是有清零所有RAM的操作的,见如下代码:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    ***********************************************************************
    * Function: wd_disable
    *
    * Description: Disables the watchdog timer
    ***********************************************************************
    .if WD_DISABLE == 1
    .text
    wd_disable:
    SETC OBJMODE ;Set OBJMODE for 28x object code
    EALLOW ;Enable EALLOW protected register access
    MOVZ DP, #7029h>>6 ;Set data page for WDCR register
    MOV @7029h, #0068h ;Set WDDIS bit in WDCR to disable WD
    EDIS ;Disable EALLOW protected register access
    ; POR Only - Initialize All RAMS
    EALLOW
    ; MemCfgRegs.DxINIT.all = 0x0003 (RAMs M0, M1)
    MOVB ACC, #0x3
    MOVW DP, #0x17d0 ;Set DP to MemCfgRegs
    MOVL @0x12, ACC ;Write 0x3 to MemCfgRegs.DxINIT.all
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  • 方便上传一下cmd文件和map文件吗?

  • 上传的BOOT的map文件里反而显示的是.TI.ramfunc未初始化成功。是因为上面所说的屏蔽了相应的操作吗:

    补充测试项:将BOOT区的Device_Init()和Flash_Init()屏蔽,即BOOT区的codestart里不进行copy和时钟配置,那么跳转至APP区后,APP区的copy函数执行时间则是正常的,大约46ms左右

    我的想法是,一些公共的项,比如Device_Init()和Flash_Init(),因为设备并没有复位或重新上电,执行一次就可以了;APP中的copy只需要将FLASH API等用到的函数或者BOOT中没有copy的部分搬移就好。

  • 抱歉,是的,屏蔽了相应的操作没有修改回来,以下map文件已修改回来:

    BOOT_BANK0.map

    两个工程搬移的位置不同,应该是都需要搬移的吧,并且APP的codestart会将RAM全部清零,没有完全搬移是否会出问题

  • 但是搬移的代码中对器件的初始化操作已经执行了