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

相关推荐
SEP50101 年前
eCos GPIO读写及其中断处理
ecos