单片机/MCU论坛
直播中

jf_08251207

2年用户 26经验值
擅长:可编程逻辑 电源/新能源 模拟技术 测量仪表 EMC/EMI设计 嵌入式技术 存储技术 CRF/无线 接口/总线/驱动 处理器/DSP 光电显示 控制/MCU EDA/IC设计 RF/无线
私信 关注
[文章]

【原创】【RA4M2-SENSOR开发板评测】内部flash读写测试

上一次评测内容为低功耗+USB两部分的综合测试,本次进行任务3中的内部存储器部分的测试。

RA MCU内部的 Flash 存储器包含代码闪存(Code Flash)、 数据闪存(Data Flash)、选项设置存储器(Option-Setting Memory)和工厂闪存(Factory Flash)。 其中,代码闪存用于保存用户代码,其中包含用户的 Boot 启动代码; 数据闪存用于保存用户静态数据;选项设置存储器用于保存和变更 MCU 复位后的一些状态; 工厂闪存保存了芯片出厂自带的一段固定的 BootLoader 程序,用户无法访问。

RA4M2 的 Flash 的地址分布及范围大小见下图
image.png

RA4M2 的代码闪存也是由大小为 8 Kbytes 和 32 Kbytes 的块(Block)组成。 在对代码闪存进行擦除操作时,需要按块进行擦除,也就是说至少需要擦除 8 Kbytes 或 32 Kbytes 大小的区域。 代码闪存擦除后的值为 0xFF。

RA4M2 的 Code Flash 的固定结构如下图所示:
image.png

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

RA4M2 的 Data Flash 的结构如下图所示:
image.png

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

RA4M2 内部 Flash 相关的模块框图如下图所示
image.png

内部FLASH的写入过程
1.擦除先擦除 Block。 擦除操作将擦除所提供地址所在的整个块。
2.空白检查对于 Data Flash,如果需要确认 Block 是否已经被擦除,一定是通过空白检查来判断 Block 是否空白, 而不能通过读取数据是否 0xFF 来判断,因为不能保证擦除的数据闪存块的读取值为0xFF。一般在擦除操作成功后,也可以省略掉进行空白检查的步骤,直接对已擦除的区域进行下一步编程(写入)操作。
3.编程(写入)将数据写入到 Flash。 写入操作必须在页边界上对齐,并且必须是页边界大小的倍数。

内部FLASH的读取过程
无论 Code Flash 还是 Data Flash 都支持直接通过指定地址读取其中数据。 因此在读取内部FLASH数据时,把地址转换为C语言指针进行读取即可。

使用内部 Flash 不涉及到任何引脚,因此不需要配置引脚。 打开FSP配置界面,“Stacks”配置页中加入 Flash 模块,按照如下图所示进行配置即可。
在之前的工程基础上操作,如下:
image.png

image.png

点击image.png
生成代码。

初始化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进行测试,测试函数如下:

/* Data 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;

    /* 写入测试数据到 write_buffer */
    for (index = 0; index < DATA_FLASH_TEST_DATA_SIZE; index++)
    {
        write_buffer[index] = (uint8_t) ('A' + (index % 26));
    }

    /* 擦除 Data Flash */
    logInfo("擦除 Data Flash");
    
    err = g_flash0.p_api- >erase(g_flash0.p_ctrl, DATA_FLASH_TEST_BLOCK, BLOCK_NUM);
    /* Error Handle */
    if (FSP_SUCCESS != err)
    {
        logError("Erase API failed");
        logError("Returned Error Code: %d", err);
        while(1);
    }
    logInfo("Erase successful");


    /* 如果使能了BGO功能,等待擦除完成事件标志位 */
    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");

    /* 空白检查:擦除 Data Flash 完成后,进行空白检查 */
    err = g_flash0.p_api- >blankCheck(g_flash0.p_ctrl, DATA_FLASH_TEST_BLOCK, FLASH_HP_DF_BLOCK_SIZE, &blank_check_result);
    /* Error Handle */
    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)
    {
        /* Wait for callback function to set flag */
        while (!(flash_event_not_blank || flash_event_blank));

        logInfo("BGO has enabled");
        if (flash_event_not_blank)
        {
            logError("Flash块不是空白的,不要向其中写入数据");
            /* Reset Flag */
            flash_event_not_blank = false;
            while(1);
        }
        else
        {
            logInfo("Flash块是空白的");
            /* Reset Flag */
            flash_event_blank = false;
        }
    }

    /* 写入测试数据到 Data Flash */
    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);
    /* Error Handle */
    if (FSP_SUCCESS != err)
    {
        logError("Write API failed");
        logError("Returned Error Code: %d", err);
        while(1);
    }

    /* 如果使能了BGO功能,等待写入完成事件标志位 */
    if (true == g_flash0_cfg.data_flash_bgo)
    {
        logInfo("BGO has enabled");
        while (!flash_write_complete_flag);     /* Note:如果写入没被擦除的块,会触发错误中断,会在这里卡死 */
        flash_write_complete_flag = false;
    }
    logInfo("Write successful");

    /* 读取 Data Flash 数据 */
    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");


    /* 对比 write_buffer 和 read_buffer 数据 */
    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"

/* Code Flash */
#define FLASH_HP_CF_BLOCK_SIZE_32KB (32*1024)   /* Block Size 32 KB */
#define FLASH_HP_CF_BLOCK_SIZE_8KB  (8*1024)    /* Block Size 8KB */

#define FLASH_HP_CF_BLOCK_0         0x00000000U /*   8 KB: 0x00000000 - 0x00001FFF */
#define FLASH_HP_CF_BLOCK_1         0x00002000U /*   8 KB: 0x00002000 - 0x00003FFF */
#define FLASH_HP_CF_BLOCK_2         0x00004000U /*   8 KB: 0x00004000 - 0x00005FFF */
#define FLASH_HP_CF_BLOCK_3         0x00006000U /*   8 KB: 0x00006000 - 0x00007FFF */
#define FLASH_HP_CF_BLOCK_4	        0x00008000U /*   8 KB: 0x00008000 - 0x00009FFF */
#define FLASH_HP_CF_BLOCK_5	        0x0000A000U /*   8 KB: 0x0000A000 - 0x0000BFFF */
#define FLASH_HP_CF_BLOCK_6	        0x0000C000U /*   8 KB: 0x0000C000 - 0x0000DFFF */
#define FLASH_HP_CF_BLOCK_7	        0x0000E000U /*   8 KB: 0x0000E000 - 0x0000FFFF */
#define FLASH_HP_CF_BLOCK_8         0x00010000U /*  32 KB: 0x00010000 - 0x00017FFF */
#define FLASH_HP_CF_BLOCK_9         0x00018000U /*  32 KB: 0x00018000 - 0x0001FFFF */
#define FLASH_HP_CF_BLOCK_10        0x00020000U /*  32 KB: 0x00020000 - 0x00027FFF */
#define FLASH_HP_CF_BLOCK_11        0x00028000U /*  32 KB: 0x00020000 - 0x00027FFF */
#define FLASH_HP_CF_BLOCK_12        0x00030000U /*  32 KB: 0x00020000 - 0x00027FFF */
#define FLASH_HP_CF_BLOCK_13        0x00038000U /*  32 KB: 0x00020000 - 0x00027FFF */
#define FLASH_HP_CF_BLOCK_14        0x00040000U /*  32 KB: 0x00020000 - 0x00027FFF */
//......


/* Data Flash */
#define FLASH_HP_DF_BLOCK_SIZE      (64)        /* Block Size 64B */

#define FLASH_HP_DF_BLOCK_0         0x08000000U /* 大小为 64 B:  0x08000000U - 0x0800003F */
#define FLASH_HP_DF_BLOCK_1         0x08000040U /* 大小为 64 B:  0x08000040U - 0x0800007F */
#define FLASH_HP_DF_BLOCK_2         0x08000080U /* 大小为 64 B:  0x08000080U - 0x080000BF */
#define FLASH_HP_DF_BLOCK_3         0x080000C0U /* 大小为 64 B:  0x080000C0U - 0x080000FF */


/* CODE FLASH 测试 */
#define CODE_FLASH_TEST_BLOCK       0x00100000U /* 避免覆盖程序代码数据 */
#define CODE_FLASH_TEST_DATA_SIZE   128         /* 只测试128个字节数据 */
/* DATA FLASH 测试 */
#define DATA_FLASH_TEST_BLOCK       FLASH_HP_DF_BLOCK_0
#define DATA_FLASH_TEST_DATA_SIZE   FLASH_HP_DF_BLOCK_SIZE  //测试64B

/* 擦除的 CODE/DATA FLASH 的块数 */
#define BLOCK_NUM   1   //2

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按键,观察有效果如下

image.png

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

更多回帖

发帖
×
20
完善资料,
赚取积分