【瑞萨RA6系列】CoreMark移植完全指南——UART输出和SysTick计时

news2024/10/7 18:30:42

一、CoreMark简介

什么是CoreMark?

来自CoreMark首页的解释是:

CoreMark is a simple, yet sophisticated benchmark that is designed specifically to test the functionality of a processor core. Running CoreMark produces a single-number score allowing users to make quick comparisons between processors.

翻译一下就是:

CoreMark是一个简单而又精密的基准测试程序,是专门为测试处理器核功能而设计的。运行CoreMark会产生一个“单个数字”的分数,(从而)允许用户在(不同)CPU之间进行快速比较。

简单来说,就是一个测试CPU性能的程序,类似PC上的Cinebench、CPU-Z之类的CPU性能测试工具。

了解了CoreMark是什么之后,接下来我们尝试在瑞萨FPB-RA6E1快速原型板上跑一下CoreMark,看看分数是多少。

接下来就可以开始进行CoreMark移植了,为了让移植步骤清晰明确,这里我把移植分为两大部分:

  • 基础功能支持,即创建一个支持输出和计时的项目
  • CoreMark移植,即将CoreMark源码添加到项目中,并修改CoreMark源码,使其能够正常运行

二、基础功能支持

CoreMark是一个基准测试功能程序,在MCU上运行它通常依赖两个基础功能:

  • 打印输出
    • 一般使用print打印,输出到UART串口(使用PC接收UART输出的内容)
  • 精准计时
    • 一般使用SysTick计时,精度通常为毫秒级别

2.1 创建RASC项目

首先是RASC创建项目,名为RA6E1_CoreMark,如下图所示:

image-20230528142237578

接着,选择MCU、TrustZone、RTOS,和上一篇一样即可生成Keil项目。

2.2 确认UART引脚

查阅开发板原理图,发现JLink OB和主控芯片直接只有JTAG/SWD接口的连接,没有UART接口连接。因此,只能用Arduino接口的串口了:

image-20230528143454910

可以看到,Arduino接口上:

  • D0/RX 连接在主控芯片的P109上,对应功能为TXD9
  • D1/TX 连接在主控芯片的P110上,对应功能为RXD9

查阅用户手册,和原理图中的TXD9RXD9也可以对应上:

image-20230528144122571

2.3 打开RASC配置

如果RASC没有关闭,则可以直接进行配置,无需额外操作。

如果RASC已经关闭,可以通过Manage Run-Time Environment菜单,打开已有配置,具体步骤如下图所示:

RASC_with_keil_open_config.png

以上截图自RASC帮主文档,说的比较清楚,图文并茂,这里就不翻译了。

2.4 配置UART引脚功能

默认创建的RASC项目中,P109、P110为JTAG功能,如下图所示:

image-20230528144559109

因此,将P109、P110设置为TXD、RXD功能之前,需要将调试配置从JTAG修改为SWD;否则,将其设置为UART功能时会报错。

首先,将调试模式从JTAG改为SWD,具体操作如下。

  1. 在RASC中,切换到Pins标签页;

  2. 找到System:DEBUG -> DEBUG0,将其设置修改为SWD,引脚修改为P108、P300,如下图所示:

    image-20230528145055038

    P108、P300引脚也正是和开发板原理图上的SWDIO、SWDCLK相对应。

接着,将P109、P110设置为TXD9、RXD9功能,具体操作如下:

  1. 在RASC中,在Pins标签页左侧找到Connectivity:SCI -> SCI9,并单击选中;

  2. Connectivity:SCI -> SCI9设置中,将其设置修改如下图所示:

    image-20230528145533435

修改完成后,记得Ctrl+S保存修改。

2.5 添加UART HAL组件

在RASC中,切换到Stacks标签页,依次点击“New Stack”->“Connectivity”->“UART”,添加一个uart组件,如下图所示:

image-20230528145913428

添加UART组件后,鼠标选中UART组件图标,如下图所示:

image-20230528150123567

在Properties视图中,修改如下几个属性:

image-20230528150419731

修改后Ctrl+S保存。

点击“Generate Project Content”按钮,生成Keil项目。

2.6 实现printf输出到UART

在Keil中,实现UART打印到printf需要重新实现C标准库的putc函数,具体参考下面两个资料:

  1. Keil官方文档:https://developer.arm.com/documentation/dui0475/c/the-arm-c-and-c—libraries/redefining-low-level-library-functions-to-enable-direct-use-of-high-level-library-functions
  2. 野火瑞萨教程:https://doc.embedfire.com/mcu/renesas/fsp_ra/zh/latest/doc/chapter19/chapter19.html

打开hal_entry.c,将头部代码修改为:

#include <stdio.h>
#include "hal_data.h"
#include "r_sci_uart.h"

void hal_uart9_init()
{
    R_SCI_UART_Open(&g_uart9_ctrl, &g_uart9_cfg);
}

volatile bool hal_uart_tx_done = false;

void hal_uart9_callback(uart_callback_args_t* p_args)
{
   switch (p_args->event)
   {
   	   case UART_EVENT_RX_CHAR:
           break;
       case UART_EVENT_TX_COMPLETE:
           hal_uart_tx_done = true;
           break;
       default:
           break;
   }
}

int fputc(int ch, FILE* f)
{
    (void) f;

    hal_uart_tx_done = false;
    R_SCI_UART_Write(&g_uart9_ctrl, (uint8_t *)&ch, 1);

    while (hal_uart_tx_done == false);
    return ch;
}

这里使用到的R_SCI_UART_OpenR_SCI_UART_Write是FSP的API,可以查阅FSP API参考,找到说明(或者查看头文件的注释):

  • R_SCI_UART_Open:RA Flexible Software Package Documentation: UART (r_sci_uart) (renesas.github.io)
  • R_SCI_UART_Write:RA Flexible Software Package Documentation: UART (r_sci_uart) (renesas.github.io)

这样,在hal_entry中调用了hal_uart9_init之后,就可以使用printf输出到串口了。

2.7 测试printf输出到UART

接下来,在hal_entry函数的开头添加如下代码,对以上修改进行测试:

    hal_uart9_init();
    while (1) {
        printf("Hello, RA6E1!\r\n");
        R_BSP_SoftwareDelay(500, BSP_DELAY_UNITS_MILLISECONDS);
    }

调试器设置可以参考上一篇帖子: 【瑞萨FPB-RA6E1快速原型板】简单开箱和RASC+Keil开发环境搭建。

重新编译,烧录,将开发板的Arduino扩展口的D0、D1通过USB转UART连接到PC,则可以在串口上看到输出了:

image-20230528152213742

2.8 实现基于SysTick的计时

CoreMark依赖计时功能,在基于ARM Cortex-M系列内核的MCU上,一般使用SysTick进行计时;例如RA4M2是基于Cortex-M33的。

而SysTick属于Cortex-M33的外设,关于SysTick的具体说明可以参考野火的一篇教程。

而在CMSIS(Cortex-M Software Interface Standard)软件包中,已经对Cortex-M系列内核自带的外设的操作接口进行了封装,我们在使用SysTick时一般只需要在代码中:

  1. 调用SysTick_Config函数设置SysTick中断频率;
  2. 编写SysTick_Handler函数实现SysTick中断处理;

主要实现代码如下:

#include <stdint.h>

#define TICKS_PER_SECOND 1000

volatile uint32_t g_tick_count = 0;

void hal_systick_init()
{
    SysTick_Config(SystemCoreClock / TICKS_PER_SECOND);
}

void SysTick_Handler(void)
{
    g_tick_count += 1;
}

uint32_t hal_systick_get()
{
    return g_tick_count;
}

这里,hal_systick.h中定义了宏TICKS_PER_SECOND,值为1000,也就是每秒1000次SysTick中断。

2.9 测试基于SysTick的计时

hal_entry.c中,将hal_entry函数的开头的代码修改为:

    hal_uart9_init();

    hal_systick_init();
    while (1) {
        printf("ticks: %d\n", hal_systick_get());
        R_BSP_SoftwareDelay(1000, BSP_DELAY_UNITS_MILLISECONDS);
    }

对上SysTick计时功能进行测试。

重新编译、下载后,可以看到串口输出如下:

image-20230528153225223

三、CoreMark移植

3.1 添加CoreMark源码

CoreMark代码仓:https://github.com/eembc/coremark.git

将代码下载下来之后,将其中的如下文件和目录拷贝到keil项目的src子目录下:

image-20230528153906822

拷贝完成后,重新使用RASC生成项目,RASC会自动将src目录下的源码文件添加到Keil项目。

3.2 修改CoreMark源码

CoreMark源码本身已经为了移植做了充分考虑了,移植到新的MCU裸机或OS上一般只需要修改很少代码即可,下面分别介绍。

3.2.1 修改core_portme.c文件

core_portme.c文件中,需要修改的是计时的几个宏定义,具体如下:

// 注释(或者删除)原来的这三个宏定义
//#define CORETIMETYPE               clock_t
//#define GETMYTIME(_t)              (*_t = clock())
//#define EE_TICKS_PER_SEC           (NSECS_PER_SEC / TIMER_RES_DIVIDER)

// 添加以下代码:
extern uint32_t hal_systick_get();
#define CORETIMETYPE               uint32_t
#define GETMYTIME(_t)              (*_t = hal_systick_get())
#define EE_TICKS_PER_SEC           1000

3.2.2 修改core_portme.h文件

core_portme.h文件中,需要新增几个宏定义:

#define ITERATIONS 4000    // 这个值需要保证能够运行至少10秒,可以先写一个值,运行不足10秒会报错,再回来修改
#define FLAGS_STR "-Ofast" // 这个值根据实际的编译优化选项进行填写,在最终输出种原样输出,实际上只要是字符串就行,无关紧要
#define MAIN_HAS_NOARGC 1  // coremark main不使用返回值
#define MAIN_HAS_NORETURN 1

这里我们将FLAGS_STR定义为-Ofast,编译选项也相应的修改为-Ofast

3.3 解决编译问题

完成上述修改之后,开始编译可能会遇到如下问题:

  • 头文件找不到的问题;
  • main重复定义的问题;

下面分别介绍如何解决。

首先是——头文件找不到的问题,Keil中需要通过菜单将对应文件所在目录添加到搜索列表中,具体步骤为:

  1. 通过Project视图,右击Target1之后,选中菜单“Options for Target …”;
  2. 在“Options for Target …”界面中,选中 C/C++ 标签页;
  3. 在 Include Paths 区域,点击右侧“…”;
  4. 在弹出的“Floder Setup”界面中,将srcsrc/simple子目录添加上;

然后是——main重复定义的问题,原因是FSP框架中已经定义了一个main函数。解决办法是,修改代码,具体修改为:

  1. core_portme.h中,将MAIN_HAS_NOARGC宏定义代码行修改为:

    #define MAIN_HAS_NOARGC 1

  2. core_main.c中,将main函数重命名为coremark_main

  3. coreamrk.h中,添加coremark_main声明的代码:

    #if MAIN_HAS_NOARGC
    MAIN_RETURN_TYPE
    coremark_main(void);
    #else
    MAIN_RETURN_TYPE
    coremark_main(int argc, char *argv[]);
    #endif
    
  4. hal_entry.c中,hal_entry函数中添加如下代码:

    • 添加#include "coremark.h"

    • 调用hal_systick_init()hal_uart9_init()

    • 调用coremark_main(),具体代码如下:

      void hal_entry(void)
      {
          /* TODO: add your own code here */
          hal_uart9_init();
          hal_systick_init();
      
          printf("CoreMark running on Renesas FPB-RA6E1 ...\r\n");
          printf("porting by xusiwei1236: https://bbs.elecfans.com/user/731071/\r\n");
          coremark_main();
      }
      

3.4 解决栈溢出问题

完成上面的操作步骤后,CoreMark项目就可以正常编译了。如果此时直接运行,将会发现系统复位,无法正常运行;通过断点调试,可以发现是因为栈空间不足导致的。

默认情况下,CoreMark使用的是栈内存进行的计算,而RASC默认的栈空间大小为1024字节(0x400)。需要增大栈内存大小,才可以正常运行CoreMark。

具体设置位于RASC菜单的BSP->Properties界面,将栈空间修改为4096(或者0x1000),如下图所示:

image-20230528162044646

四、CoreMark跑分

完成以上所有操作后,就可以在RA4M2上正常运行CoreMark程序了。CoreMark程序运行完成后,会输出具体跑分,如下图所示:

image-20230528162713962

跑分为:383.619450

官方跑分,可以在CoreMark项目官网的Scores页面查到,具体如下图:

image-20230528165628670

可以看到官方的跑分为790.27分,和实际测得的383差距不小。

网页上的编译选项为-Omax,Keil中也将编译选项修改为-Omax,跑分如下:

image-20230528170448291

这次测得的跑分为 466.47 ,也比网页上的要少。具体原因不太清楚,也不是本文关注的重点,本文重点介绍如何实现printf输出到UART以及基于SysTick的计时功能。

五、本篇总结

本文所有代码,以及具体修改,见代码仓:https://gitee.com/swxu/RA6E1_CoreMark.git

代码仓中的提交记录也体现了移植步骤,感兴趣的小伙伴课可以去看每个提交记录的修改。

本篇记录了完整的将CoreMark移植到RA6E1系列MCU的操作步骤,以及遇到问题的解决方法。CoreMark依赖的两个基础功能为——输出和计时,因此本篇介绍首先介绍了如何在RA6E1上实现printf输出到UART;然后介绍了如何实现基于SysTick的计时,最后才介绍CoreMark移植相关的源码修改和编译、运行问题解决。

六、参考链接

  1. **【瑞萨官网】**RA6E1参考手册(英文): https://www.renesas.com/us/en/document/dst/ra6e1-group-datasheet?r=1521986
  2. **【瑞萨官网】**RA6E1硬件手册(英文): https://www.renesas.cn/cn/zh/document/mah/ra6e1-group-users-manual-hardware?r=1521986
  3. **【RASC用户指南】**RA SC User Guide for MDK and IAR https://renesas.github.io/fsp/_s_t_a_r_t__d_e_v.html#RASC-MDK-IAR-user-guide
  4. **【Keil官方文档】**关于重定义库函数使用printf的说明:https://developer.arm.com/documentation/dui0475/c/the-arm-c-and-c—libraries/redefining-low-level-library-functions-to-enable-direct-use-of-high-level-library-functions
  5. 【野火 瑞萨RA系列FSP库开发实战指南】 SCI UART——串口通信:https://doc.embedfire.com/mcu/renesas/fsp_ra/zh/latest/doc/chapter19/chapter19.html
  6. 【野火 瑞萨RA系列FSP库开发实战指南】 SysTick——系统定时器:https://doc.embedfire.com/mcu/renesas/fsp_ra/zh/latest/doc/chapter17/chapter17.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/692129.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

tomcat进程注入

跟随上一篇《java进程注入》 这里使用memShell https://github.com/rebeyond/memShell 将agent.jar和inject.jar放到tomcta的web目录下 然后输入命令注入 效果&#xff1a; 注入成功后 可以看到agent.jar文件为了防止发现&#xff0c;自动清除&#xff0c;而且重启电脑之后&…

【Python数据分析】Python中axis的理解

axis用来为超过一维的数组定义属性。 理解时从数据变化的方向入手&#xff01; 以二维数据为例&#xff0c;在二维数据中&#xff0c;1表示横轴&#xff0c;方向从左到右&#xff1b;0表示纵轴&#xff0c;方向从上到下从数轴的方向入手&#xff0c;理解数据变化&#xff0c;a…

测试这碗饭,你还拿得稳吗?

今年测试行业格外寒冷&#xff0c;大部分人为了糊口饭吃&#xff0c;紧紧地捂住了本来已经很嫌弃的饭碗&#xff0c;以便挺过寒冬迎接春天。 公司天天加班&#xff0c;新出了各种扣款制度&#xff0c;为了上老下小我忍了。 2022年度的绩效&#xff0c;2023年都要过完了&#xf…

Windows同时安装两个版本JDK,并实现动态切换

1、载安装两个版本的JDK 安装后&#xff0c;默认路径C:\Program Files\Java。 实际上JDK8有两个包一个jdk1.8.0_311&#xff0c;一个jre1.8.0_311。 JDK11只有一个jdk-11.0.16.1。 2、系统环境配置 设置JAVA_HOME 在环境变量中选中Path&#xff0c;点击编辑 点击新建&…

DARAZ使用虚拟信用卡购物教程

Daraz为阿里巴巴南亚电商平台&#xff0c;市场覆盖巴基斯坦、孟加拉、斯里兰卡、尼泊尔和缅甸超过5亿人口级别市场&#xff0c;是南亚地区最受欢迎的在线购物网站&#xff0c;购物APP NO.1。 注册一个DARAZ的买家账号。 找到需要购买的商品&#xff0c;点击Buy Now进行购买 填…

Sip通话,qq通话,微信通话,普通的通话的条件和过程描述

SiP通话 SIP电话是基于SIP&#xff08;Session Initiation Protocol&#xff0c;会话初始化协议&#xff09;协议实现的通信。SIP是一种应用层协议&#xff0c;用于建立、修改和终止多媒体会话&#xff0c;如语音通话、视频通话等。SIP电话通过SIP协议进行信令交换和媒体流传输…

【MySQL学习笔记】(二)MySQL操作库基础

库的操作 1 创建数据库2 关于字符集和校验规则2.1 查看系统字符集以及校验规则2.2 查看数据支持的字符集2.3 查看数据库支持的字符集校验规则3 删除数据库4 查看并使用数据库5 修改数据库6 查看连接情况7 备份和恢复 1 创建数据库 1&#xff09;创建数据库 在学习笔记&#xf…

ChatGLM-6b本地安装手把手教学

什么是ChatGLM-6B ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型&#xff0c;基于 General Language Model (GLM) 架构&#xff0c;具有 62 亿参数。结合模型量化技术&#xff0c;用户可以在消费级的显卡上进行本地部署&#xff08;INT4 量化级别下最低只需 6GB 显存&…

Redis【入门篇】---- Redis的Java客户端-SpringDataRedis

Redis【入门篇】---- Redis的Java客户端-SpringDataRedis 1. 快速入门1. 导入pom坐标2. 配置文件3. 测试代码 2. 数据序列化器3. StringRedisTemplate4. Hash结构操作 SpringData是Spring中数据操作的模块&#xff0c;包含对各种数据库的集成&#xff0c;其中对Redis的集成模块…

网络安全|渗透测试入门学习,从零基础入门到精通—静态分析技术详解

目录 前言 1、文件类型分析 2、反汇编引擎 2.1、OllyDbg的ODDisasm 2.2、BeaEngine 2.3、Udis86 2.5、AsmJit 2.6、Keystone 2.7、小结 前言 用高级语言编写的程序有两种形式。一种程序是被编译成机器语言在CPU上执行的&#xff0c;例如Visual C。机器语言与汇编语言几乎…

【Docker】docker启动oracle11g并初始化数据,部署和使用

前提&#xff1a;已经在docker中安装好Oracle 1.启动docker&#xff1a; docker run --name oracle11 -p 1521:1521 -e ORACLE_ALLOW_REMOTEtrue -e ORACLE_PWDoracle -d oracleinanutshell/oracle-xe-11g出现问题&#xff0c;请查看&#xff1a;Exited 139解决Window下docke…

web漏洞-反序列化之JAVA全解(38)

首先第一个就是概念。第二个是他的利用&#xff0c;一个好用的工具ysoserial&#xff0c;主要用来生成工具的paload&#xff0c;修复大差不差。 #概念&#xff1a;我们有时候需要保存某一个对象的信息&#xff0c;会进行一些操作&#xff0c;类似于反序列化&#xff0c;序列化…

Mysql 逗号‘,’拼接的字符串怎么查询包含的匹配数据?

上数据 &#xff1a; 可以看到sn 存储的方式的逗号拼接的方式。 那么怎么去做sn这个字段的匹配查找呢&#xff1f; ① like &#xff08;不考虑&#xff09; 首先 like 是不行的&#xff0c; 除非你能保证 你的 逗号拼接这里面的数据不包含 重复的值&#xff0c; 比如 1 和…

Unreal 5 实现骨骼网格体转静态网格体顶点动画

如果需要大批量的渲染具有动作的模型&#xff0c;如果使用骨骼网格体渲染模型&#xff0c;量级上去以后&#xff0c;性能肯定扛不住的。如果需要实现大批量的渲染相同的带有动画的模型&#xff0c;我们需要实现将骨骼网格体烘焙成静态网格体&#xff0c;然后将骨骼网格体动画转…

D. Dot(思维+记忆化搜索dfs)

翻译&#xff1a; D. 点 时间限制&#xff1a;3秒 内存限制&#xff1a;256兆字节 输入&#xff1a;标准输入 输出&#xff1a;标准输出 Anton和Dasha喜欢在棋盘纸上玩不同的游戏。到11年级时&#xff0c;他们成功玩过了所有这类游戏&#xff0c;并请程序员Vova想出一个新…

基于 Leaflet 的缩放功能:在最后一层瓦片缺失时进行优化

这里写自定义目录标题 第一种方式第二种方式第三种方式 引言&#xff1a;Leaflet 是一个广泛使用的开源 JavaScript 库&#xff0c;用于创建交互式、可定制的地图应用程序。在 Leaflet 中&#xff0c;默认情况下&#xff0c;瓦片地图是通过切分成多个瓦片来展示的&#xff0c;这…

华为防火墙之NAT技术

1.源NAT 源NAT技术对IP报文的源地址进行转换&#xff0c;将私网IP地址转换成公网IP地址&#xff0c;使大量私网用户可以利用少量公网IP地址访问Internet&#xff0c;大大减少了对公网IP地址的消耗。 源NAT转换的过程如下图所示&#xff0c;当私网用户访问Internet的报文到达防…

Ubuntu终端最大化的3种方法

摘要&#xff1a;Ubuntu 系统下&#xff0c;使用Ctrl Alt T 快捷键唤醒终端时默认大小为 80 列 x 24 行。在某些测试中我们需要更大的窗口&#xff0c;而通过鼠标将窗口最大化太慢了&#xff0c;所以本文介绍了快速实现终端窗口最大化的 3 种方法。 声明&#xff1a;本文所有…

java安全——Java 默认沙箱

Java安全 Java 默认沙箱 程序设计者或者管理员通过改变沙箱的参数从而完成权限的变动更新 Java默认沙箱的设计目的是为了保护系统和用户的安全。Java虚拟机提供了一种机制&#xff0c;让Java应用程序在一个受限的环境中运行&#xff0c;也就是“沙箱”。这个沙箱能够在应用程序…

微信支付证书过期了怎么办

什么是商户API证书&#xff1f;如何获取商户API证书&#xff1f; 微信原文档&#xff1a;https://kf.qq.com/faq/161222NneAJf161222U7fARv.html 注&#xff1a;正常情况下&#xff0c;微信商户平台的密钥不需要更新重置&#xff0c;站点妥善保存密钥&#xff0c;定期更新证书即…