0


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 cyg_flash_read

本文转载自: https://blog.csdn.net/zoosenpin/article/details/73550285
版权归原作者 SEP5010 所有, 如有侵权,请联系我们删除。

“eCos flash模拟EEPROM实现NV系统”的评论:

还没有评论