2025 / 02 / 12
RA8 Cortex-M85 Helium动手实践

本文将演示基于FSP来使用瑞萨RA8系列MCU的Helium基本功能,如果曾经学习和了解过先前发布的“RA8 Cortex M85 Helium入门指南”系列文章,学习效果会更佳。


工程代码链接:

https://gitee.com/recn-mcu-ae/ra8d1cpkcorheliumdemollvm


本实验选用
CPKCOR-RA8D1,介绍如何使用J-Link OB CDC进行printf调试输出,以及Helium intrinsic技术的编程示例和调试。


开发环境:

  • FSP 5.1.0及其以上 (本文以FSP5.2.0为例)

  • e2 studio 2023-10及其以上 (本文以e2 studio 2024-01为例)

  • Renesas.RA_board_ra8d1_cpkcor.5.1.0.pack (该文件可以在上述工程代码gitee链接中找到)

  • Tera Term (其他的串口调试工具也可以)

  • 开发板CPKCOR-RA8D1

CPKCOR-RA8D1总览图


1. 导入RA_board_ra8d1_cpkcor.5.1.0.pack文件

打开e2 studio,点击菜单中的 “File” → “import…”。


在弹出的“Import”对话框中,选择“General” →“CMSIS Pack”,点击“Next”。注意检查选中的工程描述是“Import a CMSIS Pack into e2 studio”。


在弹出的“Import CMSIS Pack”对话框中,点击“Specify pack file”右侧“...”,指定需要添加的Renesas.RA_board_ra8d1_cpkcor.5.1.0.pack文件。


导入完成后,点击“OK”。


2. 创建工程

打开e2 studio,点击菜单中的 “File” → “New” → “Renesas C/C++ Project” → “Renesas RA”。来创建新的C/C++工程。


填写创建的项目名称后,再按下图所示进行相关设置。

FSP选择"5.2.0",Board选择“CPK-RA8D1B Core Board”,Toolchains选择"LLVM Embedded Toolchain for Arm: 17.0.1"


本次示例中,我们建立基于RA8D1的裸机系统,选择Flat (Non-TrustZone) Project。


选择“No RTOS”,然后运行“Next”。


选择“Bare Metal – Minimal”,然后运行“Finish”。


工程创建后,默认会打开configuration.xml文件。切换到Stack选项卡后,选择New Stack → Connectivity>UART(r_sci_b_uart)。


此时会出现一个错误信息,是因为没有使能SCICLK造成的。


切换到Clocks选项卡并使能SCICLK。SCICLK时钟源是PLL1P。确保SCICLK为120MHz后,保存配置。


切换到Stack并确定之前错误已经被解决。


在“Properties”中选择 g_uart0 UART (r_sci_b_uart)。

更新配置按照下面所示:

General

Name:             g_uart3

Channel:         3

Interrupts

Callback:         user_uart3_callback


检查引脚配置:

·         RXD3                   P408

·         TXD3                   P409


在BSP设定中的"Cache settings→Data cache"选择"Enabled",由于该工程会对图片进行处理,所以会使用到比较大的RAM资源,需要事先进行堆栈设定,设置stack(栈)为"0x68000",heap(堆)为"0x1000"。


添加low_level.c,dwt.c,dwt.h,pic.h,hal_entry.c文件到工程中。提示冲突时,选择替换原来的hal_entry.c。


dwt.c和dwt.h是DWT相关的代码,DWT是(Data Watchpoint and Trace)的缩写,它是ARM cortex M中的一个32位的向上计数器,记录的是内核时钟运行个数,内核时钟跳动一次,该计数器就加1,精度非常高,用于系统调试和跟踪,也可以用来测试代码运行时间。


pic.h是一张240*160的32-bit RGBA8888图片数据。


在hal_entry.c中的第12~13行,有两个宏定义。


HELIUM_BASIC_DEMO是使能helium的基础例子的开关,它展示使用helium 原语函数(intrinsic)来进行加法,减法和乘法运算。


HELIUM_RGB_DEINTERLEAVE_DEMO 是使能helium 进行图像RGBA数据色彩数据分离例子的开关,它展示了在色彩数据分离中,普通c代码实现和通过使用helium 原语函数(intrinsic)的实现之间的效率对比。


注:HELIUM_BASIC_DEMO的优先级比HELIUM_RGB_DEINTERLEAVE_DEMO高,如果这两个宏同时定义,hal_entry.c中的第15~17行代码会自动进行
#undef HELIUM_RGB_DEINTERLEAVE_DEMO操作。


开发板上电连接与启动

  • 用USB Type-C线,一端接入CPKCOR-RA8D1板USB Type-C debugger port,另一端接入PC USB接口。

  • 左上黄色Debug LED和右上白色Power LED会常亮。


打开PC设备管理器,在端口 (COM和LPT) 中会显示“Jlink CDC UART Port(COMxx)”,表示PC已经识别到CPKCOR-RA8D1板上的JLink CDC UART。在通用总线设备中会显示“BULK interface”。


打开Tera Term,Port设置为上个步骤中的设备管理器中的JLink CDC UART(COMXX)。将波特率设定为115200,点击“New setting”,完成设置。以下是Tera Term波特率的修改界面。


本示例中使用的原语函数(intrinsic)

uint8x16_t vld1q u8(uint8 t const*base)

从内存中加载数据到uint8x16_t (16个uint8数据)类型矢量寄存器中。

void vst1q_u8(uint8_t *base,uint8x16_t value)

将uint8x16_t (16个uint8数据)类型矢量寄存器中的数据写到内存中。

uint8x16_t vaddq_u8(uint8x16_t a,uint8x16_t b)

将两个uint8x16_t (16个uint8数据)类型矢量寄存器中的数据相加,并返回计算结果。

uint8x16_t vsubq_u8(uint8x16_t a,uint8x16_t b)

将两个uint8x16_t (16个uint8数据)类型矢量寄存器中的数据相减,并返回计算结果。

uint32x4 t vld1q u32(uint32 t const*base)

从内存中加载数据到uint32x4_t (4个uint32数据)类型矢量寄存器中。

uint32x4_t vmulq_n_u32(uint32x4_t a,uint32_t b)

将两个uint32x4_t (4个uint32_t数据)类型矢量寄存器中的数据相乘,并返回计算结果。


3. 调试Helium原语函数(intrinsic)对RGBA图像色彩数据解交织工程


点击菜单栏中的“Windows” → “Show View” → “Other...”,在弹出的窗口中输入“Memory”,选择“Open”。


Memory界面显示如下。


选择Raw Image。


再选择Raw Image Format。


填入图片的格式,宽为240,高为160,编码为RGB 32bpp(8:8:8:8)。点击“OK”。


设置完成后,会在gImage_dog_240_160:0x22000000处显示彩色图片。


使用同样的方法,添加rgba_b_mve到memory中,会发现显示的图片不正常。


在图片上鼠标右键选择“Format”填入参数宽为240,高为160,编码为Monochrome 8bpp。点击“OK”。


这个时候,图片就显示正常了。因为现在这个数据是单一色彩通道的数据,所以,就是一个8位的灰度图。


实验中的图片是RGBA格式,通过使用Helium的原语函数(intrinsic),实现RGBA色彩数据分离。

在做图片处理的时候,通过读取图片的数据,在内存上按照RGBA顺序排列,如下图所示:


一般来说,我们有时候需要将RGBA四个通道数据分开,进行分别处理,常用的代码可能是下面这样的。


通过遍历图片的每行和每列中的每个像素点中的RGBA四个通道数据,再逐一提取。


注:本程序仅提取了RGB数据


在这个例子中,我们主要使用了Helium的原语函数vld4q_u8和vst1q_u8。


vld4q_u8() 是ARM NEON/HELIUM SIMD(Single Instruction, Multiple Data)指令集中的一个原语函数。这个函数通常用于在四个连续内存位置上加载无符号8位整数,并将它们打包成一个128位的寄存器。具体来说,它的功能如下:

1.加载:vld4q_u8() 会从内存中加载四个连续的8位无符号整数值。

2.打包:这四个加载的整数值会被打包成一个128位的寄存器。在这个寄存器中,每个连续的32位子寄存器中包含一个8位整数值。

这种打包的方式对于同时处理多个数据元素非常有用,因为它可以减少内存访问次数和数据移动的开销,从而提高处理效率。

总的来说,vld4q_u8() 用于加载并打包四个连续的8位无符号整数值,以便在NEON/HELIUM SIMD指令集下进行并行处理。


vst1q_u8() 是ARM NEON/HELIUM SIMD指令集中的一个函数,用于将128位寄存器中的数据存储到内存中。具体来说,它的功能如下:

1.存储:vst1q_u8() 将一个128位的寄存器中的数据存储到内存中。

2.8位整数:这个函数是针对无符号8位整数的,即每次存储的是8位的数据。

因此,vst1q_u8() 通常用于将128位的寄存器中打包的多个数据元素写入内存,例如将处理后的图像数据或其他大规模数据集存储到内存中。

隐私条款

一、接受条款 使用者(也称"您")在访问或使用本网站及其服务时,即已经表示同意并不加修改地接受本《用户协议》、本网站的《隐私声明》、《法律声明》以及其关或相链接的网页和网站的条件和条款的规定。我们强烈建议:在您阅读和接受本《用户协议》时,也应阅读并接受本《用户协议》中所提到《隐私声明》、《法律声明》及其相关或相链接网页或网站所包含的资料,因为《隐私声明》、《法律声明》及其它相关网页或网站可能包含对您适用的进一步规定。(请注意:点击划有底线的词句即可链接到上述《隐私声明》、《法律声明》及其它相关或相链接的网页和网站。

 

二、使用者的资格要求 在本网站中"使用者"指的是浏览、阅读、使用本网站信息或服务的任何个人或组织。本网站的服务仅适用于根据相关法律的规定具有签订有约束力的合同的个人或组织并仅由其使用。本网站的服务不向18周岁以下的个人使用者提供,也不向临时被本网站中止或取消使用者资格的使用者提供。如果使用者不符合本条规定,请停止使用本网站或本网站的服务。