本节我们进行STM32F769和STM32F746的CoreMask移植,比较其差别,看看性能差别大小,首先我们从 CoreMark 的官网上下载测试代码 。CoreMark文件包为coremark_v1.0。然后建立CoreMark STM32 工程。 CoreMark STM32 工程建立步骤:
1、打开 STM32CubeMX软件,选择新建 Project, 在接下来的窗口中选择目标 MCU 的型号。 可以通过 MCU 筛选器进行筛选, 见下图。 这里我们选择 STM32F769I。
2、选择使用外部晶振
3、配置系统时钟
第一步 :PLL source 选择外部高速时钟( HSE, 25MHz)
第二步:系统时钟源选择 PLLCLK
第三步 :HCLK 设置为 216MHz,回车后工具会自动计算出合适的 PLL 配置参数。
4.配置板子串口
本次我们测试板子为STM32F769。我们使用的 USART1( PA9, PA10 端口)。
第一步: 使能 USART1。
第二步: 将 USART1 重映射到 PA9 和 PA10 引脚。 可以在右图直接点击对应引脚,在跳出的列表中选择 USART 的第二功能。
不知道引脚的位置可以在上方的 Find 窗口内输入引脚的名称来查找引脚的位置 。
第三步 :到 Configuration 页面,对串口进行参数配置。
设置串口参数为:
波特率: 9600Bits/s
数据长度: 8bit(包括奇偶校验位)
校验: ODD
停止位: 1 bit
5、 生成 IAR工程 项目代码
如上设置后,就可以让 CubeMX 帮我们生成代码。选择 Projec-->Generate Code,在跳出的 Project 配置窗口中指定项目名称和保存路径。选择要使用的工具链,这里选择EWARM。
在之前的工程上添加 CoreMark 代码。将前面下载的 CoreMark 代码文件拷贝到新建的工程中
添加文件到工程,打开新建的工程 Coremark_Project。 在 Application/User 目录下新建一个目录 Coremark,将 core_list_join.c
/core_main.c/core_matrix.c/core_state.c/core_util.c 这 5 个文件添加进去。( 选中左边工程中 User 目录->单击右键->Add-
>Add Group/Add Files)再将 core_portme.c 添加到 User 目录下。因为 core_main.c 文件里已经包含了一个 main 函数,所以需要在工程中将默认创建的 main.c 文件删除。完成后的工程文件结构如下
添加 include 路径,在 Options->C/C++ Compiler->Preprocessor 下增加 include 路径: $PROJ_DIR$\..\Src\Coremark。
配置 Coremark 文件,我们已经添加了所有需要的文件,但现在程序还是不能正常运行。因为默认生成的 main.c 文件已经被从项目中删除了,我们需要在 Core_portme.c 中添加初始化的代码,并根据不同的计时方法修改 Core_portme.c 中计时相关函数和代码。
添加初始化代码
(1) portable_init 函数
Core_portme.c 中的 portable_init 函数在 Core_main.c 的 main 函数中首先被调用, 平台的初始化的函数( 时钟, GPIO, 串
口, 缓存) 可以放在这里。 所以我们将 CubeMX 生成的 Main 函数中的初始化代码拷贝到 portable_init 函数中。
修改前 :
void portable_init(core_portable *p, int *argc, char *argv[])
{
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;
}
修改后:
void portable_init(core_portable *p, int *argc, char *argv[])
{
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
/* Enable I-Cache */
SCB_EnableICache();
/* Enable D-Cache */
SCB_EnableDCache();
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;
}
STM32F7 内核有 4K Bytes 的数据缓存( DCache) 和指令缓存(ICache), 程序在 Flash 中通过 AXI 总线运行时,为了达
到最高的性能需要把数据缓存和指令缓存打开。 STM32 其他的系列没有缓存也就不需要添加这部分代码。另外, 如果在
linker 文件里配置将代码放在了其他的位置,缓存也不一定要打开, 比如程序在 Flash 中通过 ITCM 总线运行, 具体看程序的
配置。
(2) 添加下面函数
将 main.c 中的 SystemClock_Config, MX_USART1_UART_Init 和 MX_GPIO_Init 函数拷贝过来。 并添将加 printf 重定向的
代码。
/** System Clock Configuration
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
/**Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 432;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/**Activate the Over-Drive mode
*/
if (HAL_PWREx_EnableOverDrive() != HAL_OK)
{
Error_Handler();
}
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7) != HAL_OK)
{
Error_Handler();
}
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USART1;
PeriphClkInitStruct.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/**Configure the Systick interrupt time
*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
/**Configure the Systick
*/
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/* USART1 init function */
static void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 9600;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_ODD;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
}
/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
static void MX_GPIO_Init(void)
{
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
}
#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 */
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
(3) 在文件开头添加函数声明和变量定义:
UART_HandleTypeDef huart1;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);(4) 添加新的 include 文件
#include
#include "system_stm32f7xx.h"
#include "stm32f7xx_hal.h"
修改计时相关代码,start_time/ stop_time/ get_time 这几个函数,是 coremark 程序运行时计算程序运行时间所用。 这里使用 system tick 进行计时, system tick 配置为 1ms 的中断间隔。 system tick 中断函数中更新 Tick 的值,每进一次中断加 1。 所以还需要修改
system tick 的中断处理函数。
(1)在 Core_portme.c 中按下表找到需要修改的地方, 并按表格的内容进行修改:
void start_time(void) {
GETMYTIME(&start_time_val );
} | void start_time(void) {
Tick = 0;
SysTick_Config(SystemCoreClock/1000);
} |
void stop_time(void) {
GETMYTIME(&stop_time_val );
} | 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;
} |
CORE_TICKS get_time(void) {
CORE_TICKS
elapsed=(CORE_TICKS)(MYTIMEDIFF(stop_time_val,
start_time_val));
return elapsed;
} | CORE_TICKS get_time(void) {
CORE_TICKS elapsed =
(CORE_TICKS)Tick;
return elapsed;
} |
#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
……
static CORETIMETYPE start_time_val,
stop_time_val; | //#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
……
//static CORETIMETYPE start_time_val,
stop_time_val; |
#define EE_TICKS_PER_SEC (NSECS_PER_SEC /
TIMER_RES_DIVIDER) | #define EE_TICKS_PER_SEC 1000 |
(2) 在 Core_portme.c 文件中添加新定义的变量和函数
#define SysTick_Counter_Disable ((uint32_t)0xFFFFFFFE)
#define SysTick_Counter_Enable ((uint32_t)0x00000001)
#define SysTick_Counter_Clear ((uint32_t)0x00000000)
__IO uint32_t Tick; |
system tick 的中断处理函数在 stm32f7xx_it.c 中。 stm32f7xx_it.c 文件包含所有中断处理入口函数。 根据不同的平台, 这个文件的名字稍有不同。 找到 SysTick_Handler 函数进行修改。
修改前:
void SysTick_Handler(void)
{
/* USER CODE BEGIN SysTick_IRQn 0 */
/* USER CODE END SysTick_IRQn 0 */
HAL_IncTick();
HAL_SYSTICK_IRQHandler();
/* USER CODE BEGIN SysTick_IRQn 1 */
/* USER CODE END SysTick_IRQn 1 */
} |
修改后:
void SysTick_Handler(void)
{
/* USER CODE BEGIN SysTick_IRQn 0 */
extern __IO uint32_t Tick;
Tick++;
/* USER CODE END SysTick_IRQn 0 */
/* USER CODE BEGIN SysTick_IRQn 1 */
/* USER CODE END SysTick_IRQn 1 */
} |
CoreMark 运行配置
(1)设置迭代次数
CoreMark 要求程序运行的最短时间至少是 10s, 根据使用的系统时钟等情况,可以在 Core_portme.h 中修改迭代次数。
(2) 设置打印信息
根据具体所用的编译器版本,优化配置进行修改。
找到 | 修改为 |
#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 |
(3)修改优化等级。
Options->C/C++ Compiler->Optimizations, 选择 High for speed 和 No size constraints 以达到最优的运行速度。
F746依据同样的方法建立工程,得到以下结果。f746跑分结果:
f769跑分结果
从两者跑分结果来看,差别不大
点击此处,查看STM32F769I开发板官方资源。 本帖最后由 qwerghf 于 2016-12-18 04:30 编辑