eCos flash模拟EEPROM实现NV系统

2024-02-03 19:20

本文主要是介绍eCos flash模拟EEPROM实现NV系统,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Flash需要擦除的原因:先擦除后写入的原因是为了工业上制作方便,即物理实现方便。

#include <cyg/infra/diag.h>

#include <cyg/io/flash.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>

// SPI flash size = 4 MB
static bool init = false;
static cyg_mutex_t nv_mutex;
static unsigned char *e2prom_buf = NULL;
static unsigned long e2prom_sz = SZ_2K;
static unsigned long logical_e2prom_cur_idx = 0;
static unsigned long nr_logical_e2prom = 1;
static unsigned long blk_sz = SZ_64K;

#include "oem-nv-lib.c"

static int program_data(void)
{
    cyg_flashaddr_t err_addr;
    cyg_flashaddr_t flash_base = NV_FLASH_BYTES_ADDR;
    int status;
    unsigned long flash_offset;

    flash_offset = logical_e2prom_cur_idx * e2prom_sz;
    oem_printf("[OEM][%s] logical_e2prom_cur_idx: %d, flash_offset: 0x%x(%dK)\n",
            __func__, logical_e2prom_cur_idx, flash_offset, (flash_offset/SZ_1K));

    // 1) Mark we will program data
    status = cyg_flash_program(flash_base + flash_offset,
            e2prom_buf, 2, &err_addr);
    if (status != CYG_FLASH_ERR_OK) {
        oem_printf("[OEM][%s] 1) flash program err!!\n", __func__);
        goto err;
    }
    // 2) Programming data
    status = cyg_flash_program(flash_base + flash_offset + SZ_E2PROM_HDR,
            e2prom_buf + SZ_E2PROM_HDR, e2prom_sz - SZ_E2PROM_HDR, &err_addr);
    if (status != CYG_FLASH_ERR_OK) {
        oem_printf("[OEM][%s] 2) flash program err!!\n", __func__);
        goto err;
    }
    // 3) Mark we have completed programming data
    status = cyg_flash_program(flash_base + flash_offset + 2,
            e2prom_buf + 2, 2, &err_addr);
    if (status != CYG_FLASH_ERR_OK) {
        oem_printf("[OEM][%s] 3) flash program err!!\n", __func__);
        goto err;
    }
    return 0;
err:
    // TODO:
    return -1;
}

static int recovery_of_sudden_power_cut(void)
{
    cyg_flashaddr_t err_addr;
    cyg_flashaddr_t flash_base = NV_FLASH_BYTES_ADDR;
    int i;
    int status;
    unsigned long flash_offset;

    for (i = logical_e2prom_cur_idx; i > 0; i--) {
        flash_offset = i * e2prom_sz;
        status = cyg_flash_read(flash_base + flash_offset, e2prom_buf, e2prom_sz, &err_addr);
        if (status != CYG_FLASH_ERR_OK) {
            oem_printf("[OEM][%s] flash read err!!\n", __func__);
            goto err;
        }

        // little endian
        //oem_printf("magic: 0x%x\n", ((unsigned int*)e2prom_buf)[0]);
        if (((unsigned int *)e2prom_buf)[0] == 0xaaaa5555) {
            oem_printf("[OEM] i: %d, logical_e2prom_cur_idx: %d\n", i, logical_e2prom_cur_idx);
            break;
        }
    }
    if (i != logical_e2prom_cur_idx) {
        oem_printf("[OEM][%s] call cyg_flash_erase()\n", __func__);
        cyg_flash_erase(flash_base, blk_sz, &err_addr);
        logical_e2prom_cur_idx = 0;
        if (program_data() < 0) {
            goto err;
        }
    }

    return 0;
err:
    return -1;
}

static void show_flash_ptn(void)
{
    // uboot
    // offset: 0, size: 192K

    // for CFG_set & CFG_get(User config, Switch parameter)
    // Bottom-Boot flsh_cfg_off: 16K, flsh_cfg_sz: 20K
    // Top-Boot flsh_cfg_off: 4M - 20K, flsh_cfg_sz: 20K
    // !!No-Boot flsh_cfg_off: 196K(0x31000), flsh_cfg_sz: 20K
    //oem_printf("[OEM] flsh_cfg_off: 0x%x, flsh_cfg_sz: 0x%x\n", flsh_cfg_off, flsh_cfg_sz);

    // for emulating eeprom to save MAC ADDR(RF parameter)
    // Bottom-Boot flsh_cfg_boot_off: 12K
    // Top-Boot flsh_cfg_boot_off: 60K
    // !!No-Boot flsh_cfg_boot_off: 256K(0x40000), size: 512B
    oem_printf("[OEM] flsh_cfg_boot_off: 0x%x(%dK)\n", flsh_cfg_boot_off,
        (flsh_cfg_boot_off/SZ_1K));

    // for eCos firmware and size
    // Bottom-Boot flsh_cfg_fwm_off: 64K, flsh_cfg_fwm_sz: 4M - 64K
    // Top-Boot flsh_cfg_fwm_off: 64K, flsh_cfg_sz: 4M - 64K - 20K
    // !!No-Boot flsh_cfg_fwm_off: 320K(0x50000), flsh_cfg_sz: 4M - 320K
    oem_printf("[OEM] flsh_cfg_fwm_off: 0x%x(%dK), flsh_cfg_fwm_sz: 0x%x(%dK)\n",
            flsh_cfg_fwm_off, (flsh_cfg_fwm_off/SZ_1K),
            flsh_cfg_fwm_sz, (flsh_cfg_fwm_sz/SZ_1K));

    // for OEM NV read & write
    oem_printf("[OEM] flsh_nv_off: 0x%x(%dK)\n", NV_FLASH_BYTES_ADDR,
            NV_FLASH_BYTES_ADDR/SZ_1K);
}

API int nv_init(void)
{
    cyg_flash_info_t cfi;
    cyg_flashaddr_t err_addr;
    cyg_flashaddr_t flash_base = NV_FLASH_BYTES_ADDR;
    int status;
    unsigned long flash_offset;

    ///
    show_flash_ptn();
    oem_printf("[OEM] nv memory used size: %d Bytes\n", get_nvm_size());
    ///

    // Initializing the FLASH library
    cyg_flash_set_global_printf((cyg_flash_printf *)&diag_printf);
    cyg_flash_init(NULL);
    if (cyg_flash_get_info(0, &cfi) == CYG_FLASH_ERR_OK) {
        if (cfi.block_info) {
            blk_sz = cfi.block_info->block_size;
            // nr_logical_e2prom should be >= 1
            nr_logical_e2prom = blk_sz / e2prom_sz;
            oem_printf("[OEM] nr_logical_e2prom: %d\n", nr_logical_e2prom);

            oem_printf("[OEM] start_addr: 0x%x, end_addr: 0x%x, num_block_infos: %d, "
                    "block_size: %d, blocks: %d\n",
                    cfi.start, cfi.end, cfi.num_block_infos,
                    cfi.block_info->block_size, cfi.block_info->blocks);

            if (!e2prom_buf) {
                e2prom_buf = (unsigned char *)malloc(e2prom_sz);
                if (!e2prom_buf) {
                    oem_printf("[OEM][%s] Can not allocate memory for e2prom_buf!!\n", __func__);
                    goto err;
                }
            }

            for (logical_e2prom_cur_idx = 0; logical_e2prom_cur_idx < nr_logical_e2prom;
                    logical_e2prom_cur_idx++) {
                flash_offset = logical_e2prom_cur_idx * e2prom_sz;
                status = cyg_flash_read(flash_base + flash_offset, e2prom_buf, e2prom_sz, &err_addr);
                if (status != CYG_FLASH_ERR_OK) {
                    logical_e2prom_cur_idx = 0;
                    oem_printf("[OEM][%s] flash read err!!\n", __func__);
                    goto err;
                }
                if (e2prom_buf[0] == 0xff &&
                    e2prom_buf[1] == 0xff &&
                    e2prom_buf[2] == 0xff &&
                    e2prom_buf[3] == 0xff) {
                    oem_printf("[OEM][%s] Got a free logical e2prom idx: %d\n",
                        __func__, logical_e2prom_cur_idx);
                    break;
                }
            }

            oem_printf("[OEM][%s] before chng, logical e2prom idx: %d\n",
                    __func__, logical_e2prom_cur_idx);
            if (logical_e2prom_cur_idx == nr_logical_e2prom) {
                cyg_flash_erase(flash_base, blk_sz, &err_addr);
                logical_e2prom_cur_idx = 0;
                if (program_data() < 0) {
                    goto err;
                }
            } else if (logical_e2prom_cur_idx > 0 && logical_e2prom_cur_idx < nr_logical_e2prom) {
                logical_e2prom_cur_idx--;
            }

            if (recovery_of_sudden_power_cut() < 0) {
                goto err;
            }

            init = true;
        }
    }

    cyg_mutex_init(&nv_mutex);
    return 0;
err:
    return -1;
}

API int nv_read(nv_items_enum_t id, u8 *buf, int len)
{
    cyg_flashaddr_t err_addr;
    // flash_base is where in the flash to read from, it is a byte address,
    // not sector address.
    cyg_flashaddr_t flash_base = NV_FLASH_BYTES_ADDR;
    int status;
    unsigned long flash_offset = 0;
    long nv_offset = NV_OFFSET(id);
    unsigned long nv_sz = NV_SZ(id);

    cyg_mutex_lock(&nv_mutex);
    if (!init) {
        if (false == nv_init()) {
            goto err;
        }
    }

    if (nv_offset < 0) {
        goto err;
    }
    if (nv_sz > len) {
        nv_sz = len;
    }

    flash_offset = logical_e2prom_cur_idx * e2prom_sz;
    status = cyg_flash_read(flash_base + flash_offset + nv_offset, (void *)buf, nv_sz, &err_addr);
    if (status != CYG_FLASH_ERR_OK) {
        oem_printf("[OEM][%s] flash read err!!\n", __func__);
        goto err;
    }
    cyg_mutex_unlock(&nv_mutex);
    oem_printf("[OEM][%s] succeeded in reading nv_%d, nv_sz: %d Bytes "
            "@logical_e2prom_cur_idx: %d\n", __func__, id, nv_sz,
            logical_e2prom_cur_idx);
    return nv_sz;
err:
    cyg_mutex_unlock(&nv_mutex);
    return -1;
}

API int nv_write(nv_items_enum_t id, u8 *buf, int len)
{
    unsigned char magic[] = {0x55, 0x55, 0xaa, 0xaa};
    cyg_flashaddr_t err_addr;
    // flash_base is where in the flash to write from, it is a byte address,
    // not sector address.
    cyg_flashaddr_t flash_base = NV_FLASH_BYTES_ADDR;
    int status;
    unsigned long flash_offset = 0;
    long nv_offset = NV_OFFSET(id);
    unsigned long nv_sz = NV_SZ(id);

    cyg_mutex_lock(&nv_mutex);
    if (!init) {
        if (false == nv_init()) {
            goto err;
        }
    }

    if (nv_offset < 0) {
        goto err;
    }
    if (nv_sz > len) {
        nv_sz = len;
    }

    flash_offset = logical_e2prom_cur_idx * e2prom_sz;
    status = cyg_flash_read(flash_base + flash_offset, e2prom_buf, e2prom_sz, &err_addr);
    if (status != CYG_FLASH_ERR_OK) {
        oem_printf("[OEM][%s] flash read err!!\n", __func__);
        goto err;
    }
    memcpy(e2prom_buf, magic, sizeof(magic));
    memcpy(e2prom_buf + nv_offset, buf, nv_sz);
#if defined(BATCH_COMMIT)
    cyg_mutex_unlock(&nv_mutex);
    return nv_sz;
#else
    // No any data in e2prom, so check here
    if (0 == logical_e2prom_cur_idx) {
        status = cyg_flash_read(flash_base, buf, 4, &err_addr);
        if (status != CYG_FLASH_ERR_OK) {
            oem_printf("[OEM][%s] Oops here, check it manually\n", __func__);
        } else if (CYG_FLASH_ERR_OK == status && buf[0] == 0xff &&
                buf[1] == 0xff &&
                buf[2] == 0xff &&
                buf[3] == 0xff) {
            oem_printf("[OEM][%s] do not add e2prom cur index\n", __func__);
        } else {
            logical_e2prom_cur_idx++;
        }
    } else {
        logical_e2prom_cur_idx++;
    }

    if (logical_e2prom_cur_idx >= nr_logical_e2prom) {
        logical_e2prom_cur_idx = 0;
        cyg_flash_erase(flash_base, blk_sz, &err_addr);
    }

    if (program_data() < 0) {
        goto err;
    }
    cyg_mutex_unlock(&nv_mutex);
    return nv_sz;
#endif
err:
    cyg_mutex_unlock(&nv_mutex);
    return -1;
}

#if defined(BATCH_COMMIT)
API int nv_commit(void)
{
    cyg_flashaddr_t err_addr;
    cyg_flashaddr_t flash_base = NV_FLASH_BYTES_ADDR;
    int status;
    u8 buf[4];

    cyg_mutex_lock(&nv_mutex);

    // No any data in e2prom, so check here
    if (0 == logical_e2prom_cur_idx) {
        status = cyg_flash_read(flash_base, buf, 4, &err_addr);
        if (status != CYG_FLASH_ERR_OK) {
            oem_printf("[OEM][%s] Oops here, check it manually\n", __func__);
        } else if (CYG_FLASH_ERR_OK == status && buf[0] == 0xff &&
                buf[1] == 0xff &&
                buf[2] == 0xff &&
                buf[3] == 0xff) {
            oem_printf("[OEM][%s] do not add e2prom cur index\n", __func__);
        } else {
            logical_e2prom_cur_idx++;
        }
    } else {
        logical_e2prom_cur_idx++;
    }

    if (logical_e2prom_cur_idx >= nr_logical_e2prom) {
        oem_printf("[OEM][%s] need erase block, logical_e2prom_cur_idx: %d\n",
                __func__, logical_e2prom_cur_idx);
        logical_e2prom_cur_idx = 0;
        cyg_flash_erase(flash_base, blk_sz, &err_addr);
    }

    // 3M = 0x300000
    // spi rd 300000 64
    // spi wr 300000 55 55 aa aa
    // spi er 300000 65536
    if (program_data() < 0) {
        goto err;
    }

    cyg_mutex_unlock(&nv_mutex);
    oem_printf("[OEM][%s] succeeded in updating logical_e2prom_cur_idx: %d\n",
            __func__, logical_e2prom_cur_idx);
    return 0;
err:
    cyg_mutex_unlock(&nv_mutex);
    return -1;
}
#else
API int nv_commit(void)
{
    return 0;
}
#endif

这篇关于eCos flash模拟EEPROM实现NV系统的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/675135

相关文章

golang版本升级如何实现

《golang版本升级如何实现》:本文主要介绍golang版本升级如何实现问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录golanwww.chinasem.cng版本升级linux上golang版本升级删除golang旧版本安装golang最新版本总结gola

SpringBoot中SM2公钥加密、私钥解密的实现示例详解

《SpringBoot中SM2公钥加密、私钥解密的实现示例详解》本文介绍了如何在SpringBoot项目中实现SM2公钥加密和私钥解密的功能,通过使用Hutool库和BouncyCastle依赖,简化... 目录一、前言1、加密信息(示例)2、加密结果(示例)二、实现代码1、yml文件配置2、创建SM2工具

Mysql实现范围分区表(新增、删除、重组、查看)

《Mysql实现范围分区表(新增、删除、重组、查看)》MySQL分区表的四种类型(范围、哈希、列表、键值),主要介绍了范围分区的创建、查询、添加、删除及重组织操作,具有一定的参考价值,感兴趣的可以了解... 目录一、mysql分区表分类二、范围分区(Range Partitioning1、新建分区表:2、分

MySQL 定时新增分区的实现示例

《MySQL定时新增分区的实现示例》本文主要介绍了通过存储过程和定时任务实现MySQL分区的自动创建,解决大数据量下手动维护的繁琐问题,具有一定的参考价值,感兴趣的可以了解一下... mysql创建好分区之后,有时候会需要自动创建分区。比如,一些表数据量非常大,有些数据是热点数据,按照日期分区MululbU

MySQL中查找重复值的实现

《MySQL中查找重复值的实现》查找重复值是一项常见需求,比如在数据清理、数据分析、数据质量检查等场景下,我们常常需要找出表中某列或多列的重复值,具有一定的参考价值,感兴趣的可以了解一下... 目录技术背景实现步骤方法一:使用GROUP BY和HAVING子句方法二:仅返回重复值方法三:返回完整记录方法四:

IDEA中新建/切换Git分支的实现步骤

《IDEA中新建/切换Git分支的实现步骤》本文主要介绍了IDEA中新建/切换Git分支的实现步骤,通过菜单创建新分支并选择是否切换,创建后在Git详情或右键Checkout中切换分支,感兴趣的可以了... 前提:项目已被Git托管1、点击上方栏Git->NewBrancjsh...2、输入新的分支的

Python实现对阿里云OSS对象存储的操作详解

《Python实现对阿里云OSS对象存储的操作详解》这篇文章主要为大家详细介绍了Python实现对阿里云OSS对象存储的操作相关知识,包括连接,上传,下载,列举等功能,感兴趣的小伙伴可以了解下... 目录一、直接使用代码二、详细使用1. 环境准备2. 初始化配置3. bucket配置创建4. 文件上传到os

关于集合与数组转换实现方法

《关于集合与数组转换实现方法》:本文主要介绍关于集合与数组转换实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、Arrays.asList()1.1、方法作用1.2、内部实现1.3、修改元素的影响1.4、注意事项2、list.toArray()2.1、方

使用Python实现可恢复式多线程下载器

《使用Python实现可恢复式多线程下载器》在数字时代,大文件下载已成为日常操作,本文将手把手教你用Python打造专业级下载器,实现断点续传,多线程加速,速度限制等功能,感兴趣的小伙伴可以了解下... 目录一、智能续传:从崩溃边缘抢救进度二、多线程加速:榨干网络带宽三、速度控制:做网络的好邻居四、终端交互

java实现docker镜像上传到harbor仓库的方式

《java实现docker镜像上传到harbor仓库的方式》:本文主要介绍java实现docker镜像上传到harbor仓库的方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录1. 前 言2. 编写工具类2.1 引入依赖包2.2 使用当前服务器的docker环境推送镜像2.2