[原创] STM32F769I-DISCO评测【6】--STM32F769和STM32F746的CoreMask移植

qwerghf   2016-12-18 04:27 楼主
本节我们进行STM32F769和STM32F746的CoreMask移植,比较其差别,看看性能差别大小,首先我们从 CoreMark 的官网上下载测试代码 。CoreMark文件包为coremark_v1.0。然后建立CoreMark STM32 工程。 CoreMark STM32 工程建立步骤: 1、打开 STM32CubeMX软件,选择新建 Project, 在接下来的窗口中选择目标 MCU 的型号。 可以通过 MCU 筛选器进行筛选, 见下图。 这里我们选择 STM32F769I。 1.png 2、选择使用外部晶振 2.png 3、配置系统时钟 第一步 :PLL source 选择外部高速时钟( HSE, 25MHz) 第二步:系统时钟源选择 PLLCLK 第三步 :HCLK 设置为 216MHz,回车后工具会自动计算出合适的 PLL 配置参数。 3.png 4.配置板子串口 本次我们测试板子为STM32F769。我们使用的 USART1( PA9, PA10 端口)。 第一步: 使能 USART1。 第二步: 将 USART1 重映射到 PA9 和 PA10 引脚。 可以在右图直接点击对应引脚,在跳出的列表中选择 USART 的第二功能。 不知道引脚的位置可以在上方的 Find 窗口内输入引脚的名称来查找引脚的位置 。 4.png 第三步 :到 Configuration 页面,对串口进行参数配置。 5.png 设置串口参数为: 波特率: 9600Bits/s 数据长度: 8bit(包括奇偶校验位) 校验: ODD 停止位: 1 bit 6.png 5、 生成 IAR工程 项目代码 如上设置后,就可以让 CubeMX 帮我们生成代码。选择 Projec-->Generate Code,在跳出的 Project 配置窗口中指定项目名称和保存路径。选择要使用的工具链,这里选择EWARM。 7.png 在之前的工程上添加 CoreMark 代码。将前面下载的 CoreMark 代码文件拷贝到新建的工程中 8.png 添加文件到工程,打开新建的工程 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 文件删除。完成后的工程文件结构如下 9.png 添加 include 路径,在 Options->C/C++ Compiler->Preprocessor 下增加 include 路径: $PROJ_DIR$\..\Src\Coremark。 10.png 配置 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 中修改迭代次数。
#define ITERATIONS 12000
(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 以达到最优的运行速度。 11.png F746依据同样的方法建立工程,得到以下结果。f746跑分结果: f746.png f769跑分结果 f769.png 从两者跑分结果来看,差别不大 点击此处,查看STM32F769I开发板官方资源。 本帖最后由 qwerghf 于 2016-12-18 04:30 编辑

回复评论 (1)

点赞  2016-12-23 13:53
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复