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),并进行了时钟配置,详细如下代码:

    //
    // 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_API函数搬运至RAMGS2中,并进行了时钟配置
        Flash_Init(); // Initialize the Flash API
    
    
        if (REV_BANK1 < REV_BANK0)
        {
            asm("    LB 0x9FF00");
        }
        else
        {
            asm("    LB 0x8FF00");
        }
    }
    
    void Device_Init(void)
    {
        //
        // Disable the watchdog
        //
        SysCtl_disableWatchdog();
    
    #ifdef _FLASH
        memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);  //测试这个搬运函数执行时间约30ms
        
        Flash_initModule(FLASH0CTRL_BASE, FLASH0ECC_BASE, DEVICE_FLASH_WAITSTATES); // InitFlash();
    #endif
        
        //
        // Set up PLL control and clock dividers
        //设置晶振源
        SysCtl_setClock(DEVICE_SETCLOCK_CFG);
    
        SysCtl_setLowSpeedClock(SYSCTL_LSPCLK_PRESCALE_4);
    
        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();
    
        //
        // Configure GPIO20 and GPIO21 as digital pins
        //
      //  GPIO_setAnalogMode(20U, GPIO_ANALOG_DISABLED);
      //  GPIO_setAnalogMode(21U, GPIO_ANALOG_DISABLED);
    }

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

    //
    // 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)   //APP区main函数部分代码
    {
        // 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
            //
            //Disable CPU interrupts and clear all CPU interrupt flags
    
            IER = 0x0000;
            IFR = 0x0000;
        
            // Initialize device clock  and peripherals and flash
            Device_Init();  //在这个函数里将将FLASH_API函数搬运至RAMGS2中,并进行了时钟配置
        }
    }
    
    //*****************************************************************************
    //
    // Function to initialize the device. Primarily initializes system control to a
    // known state by disabling the watchdog, setting up the SYSCLKOUT frequency,
    // and enabling the clocks to the peripherals.
    // The function also configures the GPIO pins 20 and 21 in digital mode.
    // To configure these pins as analog pins, use the function GPIO_setAnalogMode
    //
    //*****************************************************************************
    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);
        memcpy(&isrcodefuncsRunStart, &isrcodefuncsLoadStart,
                   (size_t)&isrcodefuncsLoadSize);   //测试这两个搬运函数执行时间只有900us
        //
        // 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();
    
        //
        // Configure GPIO20 and GPIO21 as digital pins
        //
      //  GPIO_setAnalogMode(20U, GPIO_ANALOG_DISABLED);
      //  GPIO_setAnalogMode(21U, GPIO_ANALOG_DISABLED);
    }
    
    

    //
    // 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)   //APP区main函数部分代码
    {
        // 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
            //
            //Disable CPU interrupts and clear all CPU interrupt flags
    
            IER = 0x0000;
            IFR = 0x0000;
        
            // Initialize device clock  and peripherals and flash
            Device_Init();  //在这个函数里将将FLASH_API函数搬运至RAMGS2中,并进行了时钟配置
        }
    }
    
    //*****************************************************************************
    //
    // Function to initialize the device. Primarily initializes system control to a
    // known state by disabling the watchdog, setting up the SYSCLKOUT frequency,
    // and enabling the clocks to the peripherals.
    // The function also configures the GPIO pins 20 and 21 in digital mode.
    // To configure these pins as analog pins, use the function GPIO_setAnalogMode
    //
    //*****************************************************************************
    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);
        memcpy(&isrcodefuncsRunStart, &isrcodefuncsLoadStart,
                   (size_t)&isrcodefuncsLoadSize);   //测试这两个搬运函数执行时间只有900us
        //
        // 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();
    
        //
        // Configure GPIO20 and GPIO21 as digital pins
        //
      //  GPIO_setAnalogMode(20U, GPIO_ANALOG_DISABLED);
      //  GPIO_setAnalogMode(21U, GPIO_ANALOG_DISABLED);
    }
    
    

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

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

  • 第一个copy的代码量:FLASH_API

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

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

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

    //
    // 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_API函数搬运至RAMGS2中,并进行了时钟配置
    //    Flash_Init(); // Initialize the Flash API
    
    
        if (REV_BANK1 < REV_BANK0)
        {
            asm("    LB 0x9FF00");
        }
        else
        {
            asm("    LB 0x8FF00");
        }
    }

  • 被搬移的代码运行的位置相同吗?也就是说使用的是相同的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的操作的,见如下代码:

    ***********************************************************************
    * 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
    ;   MemCfgRegs.LSxINIT.all = 0x00FF (RAMS LS0 - LS7)
        MOVB    ACC, #0xFF
        MOVL    @0x32, ACC                           ;Write 0xFF to MemCfgRegs.LSxINIT.all
    ;   MemCfgRegs.GSxINIT.all = 0xF (RAM GS0-GS3)
        MOVW    DP, #0x17d1                          ;Set DP to MemCfgRegs.GSxLOCK
        MOV     ACC, #0xF
        MOVL    @0x12, ACC                           ;Write 0xF to MemCfgRegs.GSxINIT.all
    ;   MemCfgRegs.MSGxINIT.all = 0x66 (RAMS CPU1/CLA1 MSG, CLA1/DMA MSG)
        MOV     ACC, #0x66
        MOVL    @0x32, ACC                           ;Write 0x66 to MemCfgRegs.MSGxINIT.all
    
        MOV     @T,#2080                             ;Wait 2048 + 32(=buffer)cycles  8KB RAM
        RPT     @T
        || NOP
    
        LB _c_int00         ;Branch to start of boot._asm in RTS library
    
        .endif
    
    ;end wd_disable
    
        .end

  • 方便上传一下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全部清零,没有完全搬移是否会出问题

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