Litthins 发表于 2021-12-26 22:54

【N32G43x】手把手教你移植CoreMark到N32G435

本帖最后由 Litthins 于 2022-2-11 18:32 编辑

#技术资源#

N32G435是国民技术新推出的通用型MCU,采用ARM Cortex-M4内核+FPU,单周期硬件乘除法,最高主频108MHz。数据手册中使用Dhrystone作为性能评价指标(135DMIPS);却没有CoreMark的相关数据。那么N32G435能跑多少分?本文介绍使用Keil将CoreMark移植到N32G43XCL-STB开发板的一般方法。

第一部分 工程创建N32G435的支持包需要单独安装,目前版本为0.9.2,pack全称“Nationstech.N32G43x_DFP.0.9.2.pack”,安装pack后使用Keil创建新工程,选择N32G435CB,如下图所示。
新建工程下是没有资源文件的,需要手动添加。依赖文件、中间件和参考例程打包在压缩文件Nationstech.N32G43x_Library中,目前的版本是1.1.0,全称“Nationstech.N32G43x_Library.1.1.0.7z”。解压后找到firmware\CMSIS\core、firmware\CMSIS\device和firmware\n32g43x_std_periph_driver,依次复制到工程目录下,从projects\n32g43x_EVAL\examples中获取main.c\main.h\n32g43x_it.c和n32g43x_it.h文件。
完成资源整理后,打开工程配置选项,设置编译器版本为V6.16,勾选使用MicroLIB。
点选C/C++选项卡,在预处理符号中添加:N32G43X, USE_STDPERIPH_DRIVER, USE_FULL_ASSERT
采用-Ofast优化,勾选优化选项中的Link-Time Optimization,资源包含路径可参考下图。
打开调试选项卡,右侧调试器选择CMSIS-DAP Debugger。点击Settings进入调试器配置页面。
在配置页面中选择CMSIS-DAP-NSLink,点击OK即可。至此新工程创建完成。

第二部分 工程测试CoreMark的测试结果最终表示为Iterations/Sec,也就是每秒迭代数,因此需要为其提供计时功能。这里使用TIM2以每1ms产生一个中断,控制PC15反转电平,使用虚拟示波器观察波形以测试工程配置是否正确。设置系统时钟为108MHz,APB1四分频27M,注意如果APB1的分频系数大于1,则TIM2的时钟频率加倍,即TIM2时钟为54M。
时钟初始化代码:
RCC_ConfigPclk1(RCC_HCLK_DIV4);
RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM2, ENABLE);
RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOC, ENABLE);定时器初始化代码:
void TIM_CFG(void)
{
    TIM_TimeBaseStructure.Period    = 1000-1;
    TIM_TimeBaseStructure.Prescaler = 54-1;
    TIM_TimeBaseStructure.ClkDiv    = 0;
    TIM_TimeBaseStructure.CntMode   = TIM_CNT_MODE_UP;

    TIM_InitTimeBase(TIM2, &TIM_TimeBaseStructure);
    TIM_ConfigInt(TIM2, TIM_INT_UPDATE, ENABLE);
}设置定时器中断:
void NVIC_CFG(void)
{
    NVIC_InitType NVIC_InitStructure;

    NVIC_InitStructure.NVIC_IRQChannel                   = TIM2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority      = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}在虚拟示波器中观察输出波形,频率为500Hz,即中断每1ms触发1次,工程测试成功。

第三部分 CoreMark移植CoreMark是衡量嵌入式系统中微控制器性能的基准。通过列表处理、矩阵处理、状态机和CRC等算法测试系统性能。测试软件是开源的,可以在官方网站EEMBC’s CoreMark®找到。网页截图如下。
解压下载好的压缩包,得到文件结构如下图左侧所示。将simple文件夹下的core_portme.c和core_portme.h复制到USER文件夹中。新建COREMARK文件夹,将core_list_join.c、core_main.c、core_matrix.c、core_state.c、core_util.c、coremark.h等文件复制进去。
完成文件复制后,新文件分组可参考下图,注意工程路径中也要添加COREMARK文件夹。
由于core_main.c文件已提供了main()函数,因此原main()函数将无法使用。作为替代,新main()函数执行时会调用core_portme.c中的portable_init()函数,移植时需要将原工程中MCU初始化代码复制到portable_init()函数中并删除原main.c文件。 相关初始化函数如下,设置时钟相关:
void RCC_CFG(void)
{
    RCC_ConfigPclk1(RCC_HCLK_DIV4);
    RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM2, ENABLE);
    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOC, ENABLE);
    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA, ENABLE);
    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_USART1,ENABLE);
}设置串口关联的GPIO:
void GPIO_CFG(void)
{
    GPIO_InitType GPIO_InitStructure;

    GPIO_InitStruct(&GPIO_InitStructure);

    /* Configure USARTx Tx as alternate function push-pull */
    GPIO_InitStructure.Pin            = GPIO_PIN_9;
    GPIO_InitStructure.GPIO_Mode      = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Alternate = GPIO_AF4_USART1;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
   
    /* Configure USARTx Rx as alternate function push-pull and pull-up */
    GPIO_InitStructure.Pin            = GPIO_PIN_10;
    GPIO_InitStructure.GPIO_Pull      = GPIO_Pull_Up;
    GPIO_InitStructure.GPIO_Alternate = GPIO_AF4_USART1;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
}设置串口:
void USART_CFG(void)
{
    USART_StructInit(&USART_InitStructure);
    USART_InitStructure.BaudRate            = 115200;
    USART_InitStructure.WordLength          = USART_WL_8B;
    USART_InitStructure.StopBits            = USART_STPB_1;
    USART_InitStructure.Parity            = USART_PE_NO;
    USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
    USART_InitStructure.Mode                = USART_MODE_RX | USART_MODE_TX;

    /* Configure USARTx */
    USART_Init(USART1, &USART_InitStructure);
    /* Enable the USARTx */
    USART_Enable(USART1, ENABLE);
}
设置定时器,每1ms一个中断:
void TIM_CFG(void)
{
    /* Time base configuration */
    TIM_TimeBaseStructure.Period    = 1000-1;
    TIM_TimeBaseStructure.Prescaler = 54-1;
    TIM_TimeBaseStructure.ClkDiv    = 0;
    TIM_TimeBaseStructure.CntMode   = TIM_CNT_MODE_UP;

    TIM_InitTimeBase(TIM2, &TIM_TimeBaseStructure);

    /* TIM2 enable update irq */
    TIM_ConfigInt(TIM2, TIM_INT_UPDATE, ENABLE);
}设置定时器中断:
void NVIC_CFG(void)
{
    NVIC_InitType NVIC_InitStructure;

    NVIC_InitStructure.NVIC_IRQChannel                   = TIM2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority      = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;

    NVIC_Init(&NVIC_InitStructure);
}printf重定向:
int fputc(int ch, FILE* f)
{
    USART_SendData(USART1, (uint8_t)ch);
    while (USART_GetFlagStatus(USART1, USART_FLAG_TXDE) == RESET)
      ;
    return (ch);
}core_portme.c中,与定时相关的函数有以下三个,在start_time()里实现定时器启动功能,在stop_time()里实现定时器停止功能,在get_time()中获取中断计数值,相关实现如下:
unsigned long time_ms_ticks=0;
void start_time(void)
{
    TIM_Enable(TIM2, ENABLE);
}
Void stop_time(void)
{
    TIM_Enable(TIM2, DISABLE);
}
CORE_TICKS get_time(void)
{
    return time_ms_ticks;
}
void TIM2_IRQHandler(void)
{
    TIM_ClrIntPendingBit(TIM2, TIM_INT_UPDATE);
    time_ms_ticks=time_ms_ticks+1;
}告知程序,每1000个tick为1s,修改以下宏定义:
#define EE_TICKS_PER_SEC         1000注释部分不使用的代码。以下代码位于core_portme.c中,需要注释掉:
//#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;运行CoreMark时,测试时间低于10s会抛出错误,经测试N32G435设置迭代次数为3000较为合适:
volatile ee_s32 seed4_volatile = 3000; 打印测试结果时,编译器优化等级在core_portme.h中通过宏COMPILER_FLAGS定义并打印。对应工程设置,修改如下:
#define COMPILER_VERSION "Clang 13.0.0"
#define COMPILER_FLAGS "-Ofast"编译并下载程序,测试结果如下图所示:
N32G435,108MHz,267.35分!参考N32G45x系列144MHz,180DMIPS,CoreMark跑分480分;N32G435在108MHz下135DMIPS,初略估算,135/180*108/144*480=270分,与测试结果接近。测试工程已通过附件分享,如有需要可下载参考。




yljon 发表于 2021-12-27 10:23

不错啊

怀揣少年梦 发表于 2021-12-27 11:45

参考一下

zhangjsh 发表于 2021-12-28 06:58

感谢分享

沧桑小草 发表于 2022-1-17 11:33

打错啦,是最高108MHz

6552918 发表于 2022-1-17 12:50

强 厉害 赞 真棒强 厉害 赞 真棒强 厉害 赞 真棒

东裕光大张浩 发表于 2022-1-17 13:36

最高108MHz,厉害

kyzhd 发表于 2022-1-26 09:20

请教这玩意测试的意义何在?不是太懂。谢谢

lazyduck 发表于 2022-1-28 15:41

不错不错,厉害了!

match007 发表于 2022-2-11 16:34

学习了,感觉好高级

youtome 发表于 2022-2-13 09:57

主要使用以下三种,MIPS、Dhrystone、Coremark

fengm 发表于 2022-2-13 11:18

有机会亲测coremark代码            

dzfansman 发表于 2022-2-13 11:27

想要尝试CoreMark的

wangdezhi 发表于 2022-3-3 22:46

还有其他的测评程序吗?

tabmone 发表于 2022-3-3 22:56

N32G435性能还可以啊。

juliestephen 发表于 2022-3-3 23:13

这个有参考依据吗?

uiint 发表于 2022-3-3 23:35

CoreMark排行榜有吗

biechedan 发表于 2022-3-4 19:48

CoreMark测评是基于什么原理

丙丁先生 发表于 2023-5-28 15:57

跑分main.c怎么写?

fengm 发表于 2023-6-13 20:53

首先通过RCC_APB2PeriphClockCmd函数使能GPIOC时钟,然后初始化PC13引脚为输出模式。在main函数中,执行CoreMark测试,并将结果打印到串口上。
页: [1] 2
查看完整版本: 【N32G43x】手把手教你移植CoreMark到N32G435