痞子衡嵌入式:恩智浦i.MX RTxxx系列MCU特性介绍(2)- RT685EVKA性能实测(Dhrystone) (2)

  上一节里已经将dhry_1.c里面的main函数形参int argc, char *argv[]改成了void,由于dhrystone.c(原hello_world.c)里已有main函数,且该main函数中含有板级初始化代码,所以我们需要将dhry_1.c里的main函数更名(比如可更名为dhrystone()),使dhrystone源码作为子程序来调用,这样便于往不同MCU平台移植,最后直接dhrystone.c里的main函数中增加dhrystone()的调用即可。

// dhry_1.c文件中 void main (void) // 需更改为void dhrystone(void) { ... } // dhrystone.c文件中 int main(void) { /* Init board hardware. */ BOARD_InitPins(); BOARD_BootClockRUN(); BOARD_InitDebugConsole(); // 增加的dhrystone函数调用 dhrystone(); while (1) { } } 2.2.3 计时功能

  原dhry_1.c文件里的关于计时部分的代码应该做一些微调整,time.h头文件的包含应该去除,这是Windows系统里的头文件,start_time(), end_time()是基于time.h里clock_gettime()函数而封装的API,secs是用于记录时间差的变量,这些API和全局变量都可以保留,但需要用MCU里的计时器重新实现。

#include <time.h> // 需删除 void dhrystone (void) { // ... do { start_time(); // ... end_time(); User_Time = secs; } while (count >0); }

  关于计时器,第一个想到的自然是Cortex-M内核里的SysTick,不过考虑到Dhrystone程序是要跑在300MHz的主频下,而SysTick计时器只有24bit,也就是说即使SysTick->LOAD设最大的reload值0xFFFFFF,也将每隔0.05592s(0x1000000/300MHz)产生一次SysTick中断,而Dhrystone程序至少要跑2s以上,在Dhrystone运行的2s内会产生35次(2/0.05592)SysTick中断,这无疑会降低Dhrystone得分,所以SysTick直接被pass。(备注:SysTick->CTRL[2]用于选择SysTick的时钟源,默认1'b0为Core Clock,1'b1为外部clock,暂未研究这里的外部clock在i.MXRT105x上是否能用)。
  翻看i.MXRT685的参考手册,其支持的计时器种类很多,有CTIMER、SCT、MRT、UTICK、WWDT,就选择比较常用的32bit计时器CTIMER吧。
  之前下载的软件包里也有CTIMER的例程\SDK_2.5.0_EVK-MIMXRT685\boards\evkimxrt685\driver_examples\ctimer,打开simple_match_interrupt.c文件将其中CTIMER初始化相关代码放入新定义的timer_ctimer_init()函数中并在start_time()中调用timer_ctimer_init()一次以完成CTIMER初始化。
  此外还需要添加定义#define CLOCKS_PER_SEC (16000000),因为CTIMER选择的时钟源是16MHz。

#define CLOCKS_PER_SEC (16000000) volatile uint32_t s_timerHighCounter = 0; void ctimer_match0_callback(uint32_t flags) { s_timerHighCounter++; } void timer_ctimer_init(void) { ctimer_config_t config; /* Use 16 MHz clock for the Ctimer2 */ CLOCK_AttachClk(kSFRO_to_CTIMER2); CTIMER_GetDefaultConfig(&config); CTIMER_Init(CTIMER, &config); /* Configuration 0 */ matchConfig0.enableCounterReset = true; matchConfig0.enableCounterStop = false; matchConfig0.matchValue = (uint32_t)~0; matchConfig0.outControl = kCTIMER_Output_Toggle; matchConfig0.outPinInitState = false; matchConfig0.enableInterrupt = true; CTIMER_RegisterCallBack(CTIMER, &ctimer_callback_table[0], kCTIMER_SingleCallback); CTIMER_SetupMatch(CTIMER, CTIMER_MAT0_OUT, &matchConfig0); CTIMER_StartTimer(CTIMER); } void start_time(void) { timer_ctimer_init(); s_timerHighCounter = 0; } void end_time(void) { uint64_t retVal; uint32_t high; uint32_t low; do { high = s_timerHighCounter; low = CTIMER_GetTimerCountValue(CTIMER); } while (high != s_timerHighCounter); retVal = ((uint64_t)high << 32U) + low; CTIMER_StopTimer(CTIMER); secs = retVal / (CLOCKS_PER_SEC * 1.0); } 2.2.4 串口打印功能

  串口打印功能的改动比较简单,直接把原dhry_1.c文件里的printf()全部替换成PRINTF()即可,PRINTF函数在原hello world工程里已经实现了。

2.3 Dhrystone参数配置

  痞子衡在Dhrystone标准的基本知识介绍里说过,Dhrystone几乎没有参数配置,唯一需要注意的就是REG,Cortex-M33平台支持register关键字,所以我们在IAR工程option里宏定义框内加上 REG=register。
  此外我们还需要在宏定义框内设置额外两个宏 NUMBER_OF_RUNS、CORE_FREQ_MHz,前者代表跑dhrystone核心算法程序的总次数,后者是当前MCU实际运行主频。最后还需要设置一下IAR的优化选项,如下图所示:

痞子衡嵌入式:恩智浦i.MX RTxxx系列MCU特性介绍(2)- RT685EVKA性能实测(Dhrystone)

2.4 输出Dhrystone结果

  到这里Dhrystone的移植工作就完全结束了,此时Dhrystone工程也应该能正常编译了。为得到最高的Dhrystone得分,最后需要再确定两件事:一、Core Clock是否确定配置为300MHz;二、工程代码段/数据段是否放在了SRAM。
  打开clock_config.c文件,查看BOARD_BootClockRUN()函数,ARM Core/AHB时钟仅保守地配了250MHz,让我们修改Pfd0的分频系数,从19修改为16,直接超频到300MHz。

void BOARD_BootClockRUN(void) { // ... CLOCK_InitSysPll(&g_configSysPll); /* Configure system PLL to 528Mhz. */ /* Valid PFD values are decimal 12-35. */ // 将分频系数修改16 // CLOCK_InitSysPfd(kCLOCK_Pfd0, 19); /* Enable main PLL clock 500MHz. */ CLOCK_InitSysPfd(kCLOCK_Pfd0, 16); /* Enable main PLL clock 594MHz. */ // ... /* Let CPU run on SYS PLL PFD0 with divider 2. */ CLOCK_SetClkDiv(kCLOCK_DivSysCpuAhbClk, 2); CLOCK_AttachClk(kMAIN_PLL_to_MAIN_CLK); // ... }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zydzjz.html