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.
工程师好,
如以下代码红色部分,在配置时钟后增加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); }
补充测试项:将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,请参考:
被搬移的代码运行的位置不相同,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
上传的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文件已修改回来:
两个工程搬移的位置不同,应该是都需要搬移的吧,并且APP的codestart会将RAM全部清零,没有完全搬移是否会出问题