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

news2024/11/16 3:17:03

【瑞萨RA4系列开发板体验】CoreMark移植完全指南——UART输出和SysTick计时的应用

文章目录

  • 【瑞萨RA4系列开发板体验】CoreMark移植完全指南——UART输出和SysTick计时的应用
    • 一、CoreMark简介
    • 二、基础功能支持
      • 2.1 创建RASC项目
      • 2.2 确认UART引脚
      • 2.3 打开RASC配置
      • 2.4 配置UART引脚功能
      • 2.5 添加UART HAL配置
      • 2.6 添加printf输出到UART支持
      • 2.7 添加SysTick计时支持
    • 三、CoreMark移植
      • 3.1 添加CoreMark源码
      • 3.2 修改CoreMark源码
        • 3.2.1 修改`core_portme.c`文件
        • 3.2.2 修改`coremark.h`文件
      • 3.3 解决编译问题
      • 3.4 解决栈溢出问题
    • 四、CoreMark跑分
    • 五、本篇总结
    • 六、参考链接

修改记录:

  • 2022-11-27 初版开始
  • 2022-12-03 初版完成

一、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是什么之后,接下来我们尝试在RA-Eco-RA4M2-100PIN开发板上跑一下CoreMark,看看分数是多少。

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

  • 基础功能支持
  • CoreMark移植

二、基础功能支持

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

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

2.1 创建RASC项目

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

RA4M2_RASC_project_new.png

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

2.2 确认UART引脚

查阅开发板原理图,找到USB转串口部分:

RA4M2_uart_sch.png

可以看到,USB转串口芯片CH340G的TXD/RXD分别连接到P110、P109.

查阅用户手册:

RA4M2_P109_P110.png

可以知道,P109、P110引脚需要将功能设置为TXD9、RXD9才可以正常和PC通信,也就是SCI9。

2.3 打开RASC配置

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

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

RASC_with_keil_open_config.png

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

2.4 配置UART引脚功能

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

RASC_P109_P110.png

因此,首先需要关闭JTAG功能,或者修改为SWD模式;否则,设置为UART功能时会报错。

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

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

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

    RASC_DEBUG0_SWD.png

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

继续找到Connectivity:SCI -> SCI9,将其设置修改如下图所示:

RASC_SCI9_CFG.png

2.5 添加UART HAL配置

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

RASC_add_uart_hal.png

鼠标选中之后,在Properties视图中,修改如下几个属性:

RASC_uart_prop_set.png

修改后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

主要实现代码如下:

#include "r_sci_uart.h"
#include "hal_data.h"

volatile bool uart_tx_done = false;

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

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

    uart_tx_done = false;

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

    return ch;
}

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

这里使用到的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 添加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>
#include "hal_data.h"

#define TICKS_PER_SECOND 1000

volatile uint32_t g_tick_count = 0;

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

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中断。

这样,在hal_entry中调用了hal_systick_init()之后,就可以使用hal_systick_get进行计时了。

使用hal_systick_getTICKS_PER_SECOND进行计时,类似于使用标准库time.h中的clock()CLOCKS_PER_SEC,如下:

uint32_t start = hal_systick_get();

// ...
// 一些需要计时的代码
// ...

uint32_t end = hal_systick_get();
float cost_secs = (end - start) / (float) TICKS_PER_SECOND;
printf("time cost: %f seconds.", cost_secs);

当然,你也可以在hal_entry.c中添加可以通过如下代码,对上述代码进行测试:

    hal_uart9_init();
    printf("uart9 init done!\n");

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

三、CoreMark移植

3.1 添加CoreMark源码

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

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

RA4M2_coremark_code.png

拷贝完成后,打开Keil,在Project视图中,通过“Add Exists Files to Group”菜单将刚刚拷贝的文件添加到项目中。

添加完成后,Project视图如下图所示:

RA4M2_Keil_coremark_project.png

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)

// 添加 以下新的宏定义:
#include "hal_systick.h"
#define CORETIMETYPE               uint32_t
#define GETMYTIME(_t)              (*_t = hal_systick_get())
#define EE_TICKS_PER_SEC              TICKS_PER_SECOND

3.2.2 修改coremark.h文件

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

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

这里我们将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函数中添加如下代码:

    • 声明void coremain_main();
    • 调用hal_systick_init();
    • 调用coremain_main();

3.4 解决栈溢出问题

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

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

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

RA4M2_RASC_Stack4K.png

四、CoreMark跑分

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

RA4M2_coremark_333.png

跑分为:333.694836

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

RA4M2_coremark_scores.png

可以看到官方的跑分为398.30分。

五、本篇总结

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

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

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

六、参考链接

  1. **【RA4M2用户手册】**RA4M2 Group User’s Manual: Hardware: https://www.renesas.cn/cn/zh/document/man/ra4m2-group-users-manual-hardware?r=1469026
  2. **【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
  3. **【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
  4. 【野火 瑞萨RA系列FSP库开发实战指南】 SCI UART——串口通信:https://doc.embedfire.com/mcu/renesas/fsp_ra/zh/latest/doc/chapter19/chapter19.html
  5. 【野火 瑞萨RA系列FSP库开发实战指南】 SysTick——系统定时器:https://doc.embedfire.com/mcu/renesas/fsp_ra/zh/latest/doc/chapter17/chapter17.html

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

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

相关文章

javac 编译期拓展之实现 CallSuper 注解功能

javac 编译期拓展之 实现 CallSuper 注解功能 背景&#xff1a; 元旦之前&#xff0c;就和朋友探讨了这么一个问题。比如我在一个父类的 a 方法里做了一些逻辑&#xff0c;这个逻辑是必须存在的&#xff0c;假如现在子类要重写这个 a 方法&#xff0c; 那么他就需要先调用父类…

docker(一):基本组成与常用命令

文章目录1. docker基本组成1.1 镜像(image)1.2 容器(container)1.3 仓库(repository)2. docker常用命令2.1 启动类命令2.2 镜像命令2.3 容器命令1. docker基本组成 1.1 镜像(image) docker镜像(image)就是一个只读的模板。镜像可以用来创建docker容器&#xff0c;一个镜像可以…

中职组网络安全2023年山东省省赛Linux 系统渗透提权

B-3:Linux 系统渗透提权 任务环境说明: 服务器场景:Server2204(关闭链接) 用户名:hacker 密码:123456 使用渗透机对服务器信息收集,并将服务器中 SSH 服务端口号作为 flag 提 交;Flag:2283/tcp 使用渗透机对服务器信息收集,并将服务器中主机名称作为 flag 提交;F…

通过keepalived实现高可用

192.168.184.128 主/heartbeat1 192.168.184.129 从/heartbeat2 192.168.184.131 漂移地址 主备基础&#xff1a;需要在128和129服务器上&#xff0c;搭建mysql主从复制 环境基础配置 128、129操作关闭防火墙 # sed -i "s/SELINUXenforcing/SELINUXdisabled/g"…

内卷加速的手机市场,如何寻找新契机?

从此前争相入局的一亿像素摄像头&#xff0c;到不断加码的快充、屏幕刷新率&#xff0c;再到眼下不那么成熟却“硬要上阵”的屏下摄像头技术&#xff0c;原本应该通过技术创新提升用户体验的手机行业&#xff0c;变得越来越内卷&#xff0c;业内人士分析认为手机内卷造成消费者…

【阶段二】Python数据分析Pandas工具使用04篇:数据预处理:数据的汇总

本篇的思维导图: 数据预处理:数据的汇总 数据透视表pivot_table()函数 透视表功能该功能的主要目的就是实现数据的汇总统计。pandas模块中的pivot_table函数就是实现透视表功能的强大函数。 代码 import numpy as

linux解压

linux中主要有.zip&#xff0c;.gz&#xff0c;.bz2及.tar.gz和.tar.bz2等压缩格式 一、.zip&#xff0c;.gz&#xff0c;.bz2格式 .zip格式语法&#xff1a; zip 压缩文件名 源文件 #压缩文件 &#xff08;也能压缩目录&#xff0c;但只会压缩第一个目录&#xff0c;目录中…

牛客网C++项目-Linux高并发服务器开发之第一章:Linux系统编程入门 学习笔记

1.1 Linux 开发环境搭建 由于仅是开发环境的搭建&#xff0c;所以只简单记述一下步骤 必备软件&#xff1a; Ubuntu 18.04 XShell-用于远程登录&#xff0c;使用SSH协议&#xff0c;TCP连接&#xff0c;端口号22 XFtp&#xff0c;本次实验中尚未用到 Visual studio code&a…

什么是蒙特卡洛学习,时序差分算法

在学习的过程中经常会看到蒙卡特洛和时序差分算法&#xff0c;到底这两个是指什么&#xff0c;今天稍微整理下&#xff0c;开始吧。蒙卡特洛1.1 蒙卡特洛方法蒙特卡罗方法又叫做统计模拟方法&#xff0c;它使用随机数(或伪随机数)来解决计算问题。比如上图&#xff0c;矩形的面…

Python全栈开发(二)——python基础语法(二)

我们昨天说了python的数据类型&#xff0c;今天说说python的缩进规则和函数、python的顺序语句结构&#xff0c;条件和分支语句以及循环语句。缩进不规范会报错&#xff08;IndentationError: unexpected indent&#xff09;&#xff0c;python的函数使用&#xff0c;从定义到实…

操作系统——进程之处理机调度

操作系统——进程之处理机调度一、处理机调度的本概念和层次1、高级调度&#xff08;作业调度&#xff09;2、中级调度&#xff08;内存调度&#xff09;3、低级调度&#xff08;进程调度&#xff09;二、进程调度的时机、切换与过程、方式1、进程调度的时机2、进程调度的方式3…

ATAC-seq分析:比对(3)

1. 质控 在比对之前&#xff0c;我们建议花一些时间查看 FASTQ 文件。一些基本的 QC 检查可以帮助我们了解您的测序是否存在任何偏差&#xff0c;例如读取质量的意外下降或非随机 GC 内容。 2. Greenleaf 在本节中&#xff0c;我们将稍微处理一下 Greenleaf 数据集。 我们将处理…

新一代OPC UA解决方案,快速实现IT与OT融合

一、OPC数据采集难题 OPC技术在现今的工业自动化中应用越来越广泛&#xff0c;为现场工业控制设备与控制软件之间的数据交换提供了统一的数据存储规范。但随着工业的不断发展&#xff0c;OPC数据采集出现了一些难题。例如&#xff0c;在传统OPC在远程连接时候一定会面临的DCOM…

Qt扫盲-Qt Designer配置QSS交互使用

Qt Designer配置QSS交互记录一、概述二、用法1. 选择2. 修改1. 菜单区2. 编辑区3. 在底部功能区4. 查询一、概述 Qt Designer {Qt Designer }是一个很好的工具来预览样式表、设置样式的效果&#xff0c;而且是所见即所得&#xff0c;用界面这种开发更快些。 我一般是在Qt Des…

【编译基础】new delete详解及内存泄漏

内存的使用&#xff0c;一文不太够 文章目录C语言1.new关键字2.delete关键字C语言1.malloc关键字2.free关键字区别内存泄漏参考博客&#x1f60a;点此到文末惊喜↩︎ C语言 1.new关键字 作用&#xff1a;C通过new关键字动态分配内存三种用法 plain new&#xff1a;最朴素的n…

JdbcUtils工具类的优化升级——通过配置文件连接mysql8.0

我之前的博文JDBC重构——JdbcUtils工具类的封装写了一个JdbcUtils的工具类&#xff0c;但是这个类也会有一个问题&#xff1a;如下图所示&#xff1a;连接数据库的代码在java中是写死的&#xff0c;如果我们想要换一个数据库进行连接&#xff0c;就会很麻烦&#xff0c;这时我…

嵌入式HLS 案例开发手册——基于Zynq-7010/20工业开发板(2)

目 录 2 led_flash 案例 19 2.1 HLS 工程说明 19 2.2 编译与仿真 20 2.3 IP 核测试 23 3 key_led_demo 案例 23 3.1 HLS 工程说明 23 3.2 编译与仿真 25 3.3 IP 核测试 27 前 言 本文主要介绍 HLS 案例的使用说明,适用开发环境: Windows 7/10 64bit、Xilinx Vivado…

从零搭建的前后端完整的直播网页方案

前言&#xff1a;由于前段时间刚租了台服务器打算自己玩玩&#xff0c;随想首页或者哪哪个页面挂个我个人的直播间应该还挺有趣的。遂探索如何在我的网站上弄一个直播。三下五除二&#xff0c;清清爽爽&#xff0c;看完此文5分钟即可直播。 整体思路 最简单直观的图解。 由上图…

VB2019创建、使用静态库(同样的使用动态库dll)

库&#xff1a; 二进制可执行文件&#xff0c;操作系统载入内存执行&#xff0c;将不怎么更改的底层打包成库后可以使整体编译更改&#xff0c;并且实现对底层的保密&#xff08;不对外或员工开放&#xff09;。库有两种&#xff1a;静态库&#xff08;.a、.lib&#xff09;和动…

【国科大模式识别】第二次作业(阉割版)

【题目一】最大似然估计也可以用来估计先验概率。假设样本是连续独立地从自然状态 ωi\omega_iωi​ 中抽取的, 每一个自然状态的概率为 P(ωi)P\left(\omega_i\right)P(ωi​) 。如果第 kkk 个样本的自然状态为 ωi\omega_iωi​, 那么就记 zik1z_{i k}1zik​1, 否则 zik0z_{i…