上一次评测内容为低功耗+USB两部分的综合测试,本次进行任务3中的内部存储器部分的测试。
RA MCU内部的 Flash 存储器包含代码闪存(Code Flash)、 数据闪存(Data Flash)、选项设置存储器(Option-Setting Memory)和工厂闪存(Factory Flash)。 其中,代码闪存用于保存用户代码,其中包含用户的 Boot 启动代码; 数据闪存用于保存用户静态数据;选项设置存储器用于保存和变更 MCU 复位后的一些状态; 工厂闪存保存了芯片出厂自带的一段固定的 BootLoader 程序,用户无法访问。
RA4M2 的 Flash 的地址分布及范围大小见下图

RA4M2 的代码闪存也是由大小为 8 Kbytes 和 32 Kbytes 的块(Block)组成。 在对代码闪存进行擦除操作时,需要按块进行擦除,也就是说至少需要擦除 8 Kbytes 或 32 Kbytes 大小的区域。 代码闪存擦除后的值为 0xFF。
RA4M2 的 Code Flash 的固定结构如下图所示:

RA4M2 的数据闪存空间大小都只有 8 Kbytes,用于保存用户数据。 两者的数据闪存都由大小为 64 Bytes 的块(Block)组成,擦除单元为 64/128/256 bytes。
RA4M2 的 Data Flash 的结构如下图所示:

RA MCU 的内部Flash模块具有后台操作(Background Operation (BGO))的功能。 比如,当使用数据闪存并启用后台操作(BGO)模式时,仍然可以访问用户 ROM、RAM 和外部存储器。
RA4M2 内部 Flash 相关的模块框图如下图所示

内部FLASH的写入过程
1.擦除先擦除 Block。 擦除操作将擦除所提供地址所在的整个块。
2.空白检查对于 Data Flash,如果需要确认 Block 是否已经被擦除,一定是通过空白检查来判断 Block 是否空白, 而不能通过读取数据是否 0xFF 来判断,因为不能保证擦除的数据闪存块的读取值为0xFF。一般在擦除操作成功后,也可以省略掉进行空白检查的步骤,直接对已擦除的区域进行下一步编程(写入)操作。
3.编程(写入)将数据写入到 Flash。 写入操作必须在页边界上对齐,并且必须是页边界大小的倍数。
内部FLASH的读取过程
无论 Code Flash 还是 Data Flash 都支持直接通过指定地址读取其中数据。 因此在读取内部FLASH数据时,把地址转换为C语言指针进行读取即可。
使用内部 Flash 不涉及到任何引脚,因此不需要配置引脚。 打开FSP配置界面,“Stacks”配置页中加入 Flash 模块,按照如下图所示进行配置即可。
在之前的工程基础上操作,如下:


点击
生成代码。
初始化flash代码如下:
logDebug("Start Open flash");
err = g_flash0.p_api- >open(g_flash0.p_ctrl,g_flash0.p_cfg);
assert(FSP_SUCCESS == err);
err = g_flash0.p_api- >startupAreaSelect(g_flash0.p_ctrl, FLASH_STARTUP_AREA_BLOCK0, true);
assert(FSP_SUCCESS == err);
logDebug("Open flash end");
由于对code flash操作有风险,有点把握不住,本次只对date_flash进行测试,测试函数如下:
void FLASH_HP_DataFlash_Operation(void)
{
fsp_err_t err;
flash_result_t blank_check_result = FLASH_RESULT_BLANK;
uint8_t write_buffer[DATA_FLASH_TEST_DATA_SIZE] = {0};
uint8_t read_buffer[DATA_FLASH_TEST_DATA_SIZE] = {0};
uint8_t index;
for (index = 0; index < DATA_FLASH_TEST_DATA_SIZE; index++)
{
write_buffer[index] = (uint8_t) ('A' + (index % 26));
}
logInfo("擦除 Data Flash");
err = g_flash0.p_api- >erase(g_flash0.p_ctrl, DATA_FLASH_TEST_BLOCK, BLOCK_NUM);
if (FSP_SUCCESS != err)
{
logError("Erase API failed");
logError("Returned Error Code: %d", err);
while(1);
}
logInfo("Erase successful");
if (true == g_flash0.p_cfg- >data_flash_bgo)
{
logInfo("BGO has enabled");
while (!flash_erase_complete_flag);
flash_erase_complete_flag = false;
}
logInfo("Erase successful");
err = g_flash0.p_api- >blankCheck(g_flash0.p_ctrl, DATA_FLASH_TEST_BLOCK, FLASH_HP_DF_BLOCK_SIZE, &blank_check_result);
if (FSP_SUCCESS != err)
{
logError("BlankCheck API failed");
logError("Returned Error Code: %d", err);
while(1);
}
if (FLASH_RESULT_BLANK == blank_check_result)
{
logInfo("Flash块是空白的");
}
else if (FLASH_RESULT_NOT_BLANK == blank_check_result)
{
logError("Flash块不是空白的,不要向其中写入数据");
while(1);
}
else if (FLASH_RESULT_BGO_ACTIVE == blank_check_result)
{
while (!(flash_event_not_blank || flash_event_blank));
logInfo("BGO has enabled");
if (flash_event_not_blank)
{
logError("Flash块不是空白的,不要向其中写入数据");
flash_event_not_blank = false;
while(1);
}
else
{
logInfo("Flash块是空白的");
flash_event_blank = false;
}
}
logInfo("写入 Data Flash: ");
err = g_flash0.p_api- >write(g_flash0.p_ctrl, (uint32_t)write_buffer, DATA_FLASH_TEST_BLOCK, DATA_FLASH_TEST_DATA_SIZE);
if (FSP_SUCCESS != err)
{
logError("Write API failed");
logError("Returned Error Code: %d", err);
while(1);
}
if (true == g_flash0_cfg.data_flash_bgo)
{
logInfo("BGO has enabled");
while (!flash_write_complete_flag);
flash_write_complete_flag = false;
}
logInfo("Write successful");
memcpy(read_buffer, (uint8_t *) DATA_FLASH_TEST_BLOCK, DATA_FLASH_TEST_DATA_SIZE);
logInfo("打印 read_buffer 里的%d字节测试数据: ", DATA_FLASH_TEST_DATA_SIZE);
for (index = 0; index < DATA_FLASH_TEST_DATA_SIZE; index++)
{
shellPrint(&shell,"%c ", read_buffer[index]);
}
shellPrint(&shell,"\r\nEnd.\r\n");
if (0 == memcmp(read_buffer, write_buffer, DATA_FLASH_TEST_DATA_SIZE))
{
logInfo("数据对比一致,Data Flash 测试成功\r\n");
}
else
{
logError("数据对比不一致,Data Flash 测试失败\r\n");
while(1);
}
}
测试函数中的各种宏定义如下:
#ifndef __INTERNAL_FLASH_H
#define __INTERNAL_FLASH_H
#include "hal_data.h"
#include "stdio.h"
#define FLASH_HP_CF_BLOCK_SIZE_32KB (32*1024)
#define FLASH_HP_CF_BLOCK_SIZE_8KB (8*1024)
#define FLASH_HP_CF_BLOCK_0 0x00000000U
#define FLASH_HP_CF_BLOCK_1 0x00002000U
#define FLASH_HP_CF_BLOCK_2 0x00004000U
#define FLASH_HP_CF_BLOCK_3 0x00006000U
#define FLASH_HP_CF_BLOCK_4 0x00008000U
#define FLASH_HP_CF_BLOCK_5 0x0000A000U
#define FLASH_HP_CF_BLOCK_6 0x0000C000U
#define FLASH_HP_CF_BLOCK_7 0x0000E000U
#define FLASH_HP_CF_BLOCK_8 0x00010000U
#define FLASH_HP_CF_BLOCK_9 0x00018000U
#define FLASH_HP_CF_BLOCK_10 0x00020000U
#define FLASH_HP_CF_BLOCK_11 0x00028000U
#define FLASH_HP_CF_BLOCK_12 0x00030000U
#define FLASH_HP_CF_BLOCK_13 0x00038000U
#define FLASH_HP_CF_BLOCK_14 0x00040000U
#define FLASH_HP_DF_BLOCK_SIZE (64)
#define FLASH_HP_DF_BLOCK_0 0x08000000U
#define FLASH_HP_DF_BLOCK_1 0x08000040U
#define FLASH_HP_DF_BLOCK_2 0x08000080U
#define FLASH_HP_DF_BLOCK_3 0x080000C0U
#define CODE_FLASH_TEST_BLOCK 0x00100000U
#define CODE_FLASH_TEST_DATA_SIZE 128
#define DATA_FLASH_TEST_BLOCK FLASH_HP_DF_BLOCK_0
#define DATA_FLASH_TEST_DATA_SIZE FLASH_HP_DF_BLOCK_SIZE
#define BLOCK_NUM 1
void FLASH_HP_CodeFlash_Operation(void);
void FLASH_HP_DataFlash_Operation(void);
#endif
我们是在之前的工程基础上进行的测试,所有将测试功能设计成由按键K3来触发,代码如下:
else if (_btn- >button_id == btn2_id) {
FLASH_HP_DataFlash_Operation();
}
将程序编译好后下载至开发板中,按下K3按键,观察有效果如下

由此可以说明内部flash读写测试正常。
至此,本次测评也就完成了。
keil完整工程如下:*附件:RA4M2_Sensor.7z