Introduction of CoreMark
CoreMark 是一项衡量嵌入式系统中微控制器(MCU)和中央处理器(CPU)性能的基准测试。运用CoreMark测试MCU核心性能时,通过计算MCU运行一定次数的标准程序算法所需要的运算时间,得到最终分数,时间越短,分数越高,MCU性能越好。Coremakr包含以下算法:
- 列表处理(查找和排序)
- 矩阵操作(常见的矩阵操作)
- 状态机(判断输入流是否包含有效数字)
- CRC(循环冗余检查)
关于CoreMark具体的介绍可以参考CoreMark官网,或是参考CoreMark github。
接下来介绍如何将Coremark移植到MM32L373上,并对它进行性能测试。
Create Project of MM32
-
打开IAR,新建一个工程
-
新建工作空间
File→New→Workspace
-
新建工程
-
Project→Create New Project
-
Tool chain默认ARM
-
Project templates默认Empty project
-
-
-
配置工程
-
芯片选择
这里选择的芯片是MM32L373PS。
-
添加bsp、lib、User文件夹,将startup和HAL_lib文件放入lib
-
配置头文件路径
在Additional include directories中添加bsp、HAL、startup以及User的头文件路径。
-
配置宏定义
在Defined Symbols中添加宏定义。
-
配置仿真器
-
选择Debugger→Setup→Driver→Third-Party Driver
-
配置第三方仿真器
-
-
-
添加工程文件
- 右键Add→AddGroup,添加bsp、lib、system、user四组
- 在每组上右键Add→AddFiles,bsp中添加bsp文件,lib中添加HAL文件,system中添加startup_mm32.c和system_mm32.c。
这样MM32的工程就新建好了,可以在user里添加main.c测试一下工程是否新建成功。
Transplant CoreMark
-
克隆CoreMark测试代码
CoreMark在github上开源了它的测试代码:eembc/coremark,首先将测试代码克隆下来。
需要用到的代码文件如下:
-
将克隆的CoreMark代码添加到MM32工程中
-
在User文件夹中新建Coremark文件夹,拷贝以下代码文件至coremark文件夹中。
-
将core_portme.c拷贝至User文件夹中,将core_portme.h拷贝至inc文件夹中。
-
-
在IAR工程中配置新添加的coremark代码文件
-
添加coremark.h的头文件路径
-
在users中添加工程文件
-
Modify Coremark Code
-
修改core_portme文件中的初始化代码
-
添加Coremark_UART1_Init()函数,用于UART1的配置及初始化
void Coremark_UART1_Init(){ COMMON_EnableIpClock(emCLOCK_UART1); UART_InitTypeDef pUARTInit; UART_StructInit(&pUARTInit); pUARTInit.BaudRate = 115200; pUARTInit.WordLength = UART_WordLength_8b; pUARTInit.StopBits = UART_StopBits_1; pUARTInit.Parity = UART_Parity_No; pUARTInit.Mode = UART_Mode_Rx | UART_Mode_Tx; pUARTInit.HWFlowControl = UART_HWFlowControl_None; UART_Init(UART1, &pUARTInit); UART_Cmd(UART1, ENABLE); BSP_UART_GPIO_CONFIGURE(UART1); }
-
添加AppTaskTick()函数,用于系统时钟配置
void AppTaskTick() { if (tickCnt++ >= 500) { tickCnt = 0; tickFlag = true; } }
-
在portable_init函数中添加时钟配置函数及UART初始化函数
/* Function : portable_init Target specific initialization code Test for some common mistakes. */ void portable_init(core_portable *p, int *argc, char *argv[]) { /* Set System Clock */ MCUID = SetSystemClock(emSYSTICK_On, AppTaskTick); /* UART Configuration & Initialization */ Coremark_UART1_Init(); if (sizeof(ee_ptr_int) != sizeof(ee_u8 *)) { ee_printf( "ERROR! Please define ee_ptr_int to a type that holds a " "pointer!\n"); } if (sizeof(ee_u32) != 4) { ee_printf("ERROR! Please define ee_u32 to a 32b unsigned type!\n"); } p->portable_id = 1; }
-
添加printf重定向,以此可以通过C语言标准库函数printf()将信息打印到串口
#ifdef __GNUC__ /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf set to 'Yes') calls __io_putchar() */ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif /* __GNUC__ */ /** * @brief Retargets the C library printf function to the USART. * @param None * @retval None */ PUTCHAR_PROTOTYPE { /* Place your implementation of fputc here */ /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */ while (UART_GetFlagStatus(UART1, UART_IT_TXIEN) == RESET); UART_ClearITPendingBit(UART1, UART_IT_TXIEN); UART_SendData(UART1, (uint8_t)ch); return ch; }
这里需要将IAR中的库选成Full,使其支持所有C/C++标准库函数。
-
在core_portme.h文件中添加头文件和函数申明
#include <inttypes.h> #include "system_mm32.h" #include "common.h" #include "HAL_uart.h" #include "bsp_uart.h" void AppTaskTick(); static void Coremark_UART1_Init(void);
-
-
修改core_portme文件中的计时代码
core_portme.c中有start_time、stop_time、get_time三个计时相关的函数,依次对他们进行修改。使用SysTick定时器进行计时,每进依次中断Tick值加1。
-
修改start_time()
void start_time(void) { Tick = 0; }
-
修改stop_time()
void stop_time(void) { /* Stop the Timer and get the encoding time */ SysTick->CTRL &= SysTick_Counter_Disable; /* Clear the SysTick Counter */ SysTick->VAL = SysTick_Counter_Clear; }
-
修改get_time()
CORE_TICKS get_time(void) { CORE_TICKS elapsed = (CORE_TICKS)Tick; return elapsed; }
-
修改宏定义
/* Comment out the Original Code */ //#define NSECS_PER_SEC CLOCKS_PER_SEC //#define CORETIMETYPE clock_t //#define GETMYTIME(_t) (*_t = clock()) //#define MYTIMEDIFF(fin, ini) ((fin) - (ini)) //#define TIMER_RES_DIVIDER 1 //#define SAMPLE_TIME_IMPLEMENTATION 1 //#define EE_TICKS_PER_SEC (NSECS_PER_SEC / TIMER_RES_DIVIDER) // ///** Define Host specific (POSIX), or target specific global time variables. */ //static CORETIMETYPE start_time_val, stop_time_val; /* Add the following code */ #define SysTick_Counter_Disable ((uint32_t)0xFFFFFFFE) #define SysTick_Counter_Enable ((uint32_t)0x00000001) #define SysTick_Counter_Clear ((uint32_t)0x00000000) #define EE_TICKS_PER_SEC 1000 __IO uint32_t Tick;
-
在system_mm32.c文件中修改SysTick的中断处理函数
每次进中断,Tick+1
void SysTick_Handler(void) { extern __IO uint32_t Tick; Tick++; }
-
-
在core_portme.h中配置CoreMark运行参数
-
添加Coremark计算迭代次数
#define ITERATIONS 10000
-
修改打印信息
// #ifndef COMPILER_FLAGS // #define COMPILER_FLAGS \ // FLAGS_STR /* "Please put compiler flags here (e.g. -o3)" */ // #endif #ifndef COMPILER_FLAGS #define COMPILER_FLAGS "-Ohs -no_size_constraints" #endif
-
-
将stack空间扩大到0x2000
-
修改程序运行优先级
选择High Speed,提升运行速度
Result
代码可以在Miao-T github上拉取。