From ee668d15beb93a94fbb5d145284c9b39bdfa8c90 Mon Sep 17 00:00:00 2001 From: asterix Date: Thu, 5 Aug 2010 15:20:34 +0000 Subject: [PATCH] Add implement verify and erase functions and support for old api. Add cfg for eeprom. git-svn-id: https://src.develer.com/svnoss/bertos/trunk@4151 38d2e660-2303-0410-9eaa-f027e97ec537 --- bertos/cfg/cfg_eeprom.h | 64 +++++++++++ bertos/drv/eeprom.c | 248 +++++++++++++++++----------------------- bertos/drv/eeprom.h | 38 +++--- 3 files changed, 193 insertions(+), 157 deletions(-) create mode 100644 bertos/cfg/cfg_eeprom.h diff --git a/bertos/cfg/cfg_eeprom.h b/bertos/cfg/cfg_eeprom.h new file mode 100644 index 00000000..b56c1f9c --- /dev/null +++ b/bertos/cfg/cfg_eeprom.h @@ -0,0 +1,64 @@ +/** + * \file + * + * + * \brief Configuration file for the Eeprom module. + * + * \author Daniele Basile + */ + +#ifndef CFG_EEPROM_H +#define CFG_EEPROM_H + +/** + * Module logging level. + * + * $WIZ$ type = "enum" + * $WIZ$ value_list = "log_level" + */ +#define EEPROM_LOG_LEVEL LOG_LVL_INFO + +/** + * Module logging format. + * + * $WIZ$ type = "enum" + * $WIZ$ value_list = "log_format" + */ +#define EEPROM_LOG_FORMAT LOG_FMT_TERSE + +/** + * Check this to disable Eeprom deprecated API support. + * + * $WIZ$ type = "boolean" + */ +#define CONFIG_EEPROM_DISABLE_OLD_API 0 + +#endif /* CFG_EEPROM_H */ diff --git a/bertos/drv/eeprom.c b/bertos/drv/eeprom.c index fd644e4c..f66135fc 100644 --- a/bertos/drv/eeprom.c +++ b/bertos/drv/eeprom.c @@ -39,17 +39,18 @@ #include "eeprom.h" #include "cfg/cfg_i2c.h" +#include "cfg/cfg_eeprom.h" -#include // MIN() +/* Define logging setting (for cfg/log.h module). */ +#define LOG_LEVEL EEPROM_LOG_LEVEL +#define LOG_FORMAT EEPROM_LOG_FORMAT +#include #include -#include // MOD_CHECK() +#include // MIN() #include -#include - -#include -#include // cpu_to_be16() +#include #include // memset() @@ -105,140 +106,61 @@ static const EepromInfo mem_info[] = STATIC_ASSERT(countof(mem_info) == EEPROM_CNT); -/** - * Check that the contents of an EEPROM range - * match with a provided data buffer. - * - * \return true on success. - * \note Seek position of \a fd will not change. - */ -bool eeprom_verify(Eeprom *fd, const void *buf, size_t count) -{ - uint8_t verify_buf[16]; - bool result = true; +#define CHUNCK_SIZE 16 - /* Save seek position */ - kfile_off_t prev_seek = fd->fd.seek_pos; +bool eeprom_erase(Eeprom *eep, e2addr_t addr, e2_size_t size) +{ + uint8_t tmp[CHUNCK_SIZE] = { [0 ... (CHUNCK_SIZE - 1)] = 0xFF }; - while (count && result) + while (size) { - /* Split read in smaller pieces */ - size_t size = MIN(count, sizeof verify_buf); - - /* Read back buffer */ - if (eeprom_read(&fd->fd, verify_buf, size)) - { - if (memcmp(buf, verify_buf, size) != 0) - { - TRACEMSG("Data mismatch!"); - result = false; - } - } - else - { - TRACEMSG("Read error!"); - result = false; - } - - /* Update count and addr for next operation */ - count -= size; - buf = ((const char *)buf) + size; + block_idx_t idx = addr / eep->blk.blk_size; + size_t offset = addr % eep->blk.blk_size; + size_t count = MIN(size, (e2_size_t)CHUNCK_SIZE); + size_t ret_len = eep->blk.priv.vt->writeDirect((KBlock *)eep, idx, tmp, offset, count); + size -= ret_len; + addr += ret_len; + + if (ret_len != count) + return false; } - - /* Restore previous seek position */ - fd->fd.seek_pos = prev_seek; - return result; + return true; } -/** - * Erase specified part of eeprom, writing 0xFF. - * - * \a addr starting address - * \a count length of block to erase - * \note Seek position is unchanged. - * \return true if ok, false otherwise. - */ -bool eeprom_erase(Eeprom *fd, e2addr_t addr, e2_size_t count) +bool eeprom_verify(Eeprom *eep, e2addr_t addr, const void *buf, size_t size) { - e2blk_size_t blk_size = mem_info[fd->type].blk_size; - uint8_t buf[blk_size]; - kfile_off_t prev_off = fd->fd.seek_pos; - bool res = true; - size_t size; - - memset(buf, 0xFF, blk_size); - - - kfile_seek(&fd->fd, addr, KSM_SEEK_SET); - - /* - * Optimization: this first write id used to realign - * current address to block boundaries. - */ - - wdt_reset(); - size = MIN(count, (e2_size_t)(blk_size - (addr & (blk_size - 1)))); - if (kfile_write(&fd->fd, buf, size) != size) + uint8_t verify_buf[CHUNCK_SIZE]; + while (size) { - fd->fd.seek_pos = prev_off; - return false; - } - count -= size; + block_idx_t idx = addr / eep->blk.blk_size; + size_t offset = addr % eep->blk.blk_size; + size_t count = MIN(size, (size_t)CHUNCK_SIZE); - /* Clear all */ - while (count) - { - /* Long operation, reset watchdog */ - wdt_reset(); + size_t ret_len = eep->blk.priv.vt->readDirect((KBlock *)eep, idx, verify_buf, offset, count); - size = MIN(count, (e2_size_t)sizeof buf); - if (kfile_write(&fd->fd, buf, size) != size) + if (ret_len != count) { - res = false; - break; + LOG_ERR("Verify read fail.\n"); + return false; } - count -= size; - } - fd->fd.seek_pos = prev_off; - return res; -} - - -/** - * Initialize EEPROM module. - * \a fd is the Kfile context. - * \a type is the eeprom device we want to initialize (\see EepromType) - * \a addr is the i2c devide address (usually pins A0, A1, A2). - * \a verify is true if you want that every write operation will be verified. - */ -void eeprom_init(Eeprom *fd, EepromType type, e2dev_addr_t addr, bool verify) -{ - MOD_CHECK(i2c); - ASSERT(type < EEPROM_CNT); - - memset(fd, 0, sizeof(*fd)); - DB(fd->fd._type = KFT_EEPROM); - - fd->type = type; - fd->addr = addr; - fd->fd.size = mem_info[fd->type].e2_size; - - // Setup eeprom programming functions. - fd->fd.read = eeprom_read; - if (verify) - fd->fd.write = eeprom_writeVerify; - else - fd->fd.write = eeprom_writeRaw; - fd->fd.close = kfile_genericClose; + if (memcmp(buf, verify_buf, ret_len) != 0) + { + LOG_ERR("Data mismatch!\n"); + return false; + } - fd->fd.seek = kfile_genericSeek; + size -= ret_len; + addr += ret_len; + buf = ((const char *)buf) + ret_len; + } + return true; } -static size_t eeprom_writeDirect(KBlock *blk, block_idx_t idx, const void *buf, size_t offset, size_t size) +static size_t eeprom_write(KBlock *blk, block_idx_t idx, const void *buf, size_t offset, size_t size) { - Eeprom *fd = EEPROM_CAST_KBLOCK(blk); + Eeprom *eep = EEPROM_CAST_KBLOCK(blk); e2dev_addr_t dev_addr; uint8_t addr_buf[2]; uint8_t addr_len; @@ -251,9 +173,9 @@ static size_t eeprom_writeDirect(KBlock *blk, block_idx_t idx, const void *buf, ASSERT(idx <= blk->blk_cnt); size = MIN(size, blk->blk_size - offset); - if (mem_info[fd->type].has_dev_addr) + if (mem_info[eep->type].has_dev_addr) { - dev_addr = fd->addr; + dev_addr = eep->addr; addr_len = 2; } else @@ -262,7 +184,7 @@ static size_t eeprom_writeDirect(KBlock *blk, block_idx_t idx, const void *buf, addr_len = 1; } - if (mem_info[fd->type].has_dev_addr) + if (mem_info[eep->type].has_dev_addr) { addr_buf[0] = (abs_addr >> 8) & 0xFF; addr_buf[1] = (abs_addr & 0xFF); @@ -273,17 +195,16 @@ static size_t eeprom_writeDirect(KBlock *blk, block_idx_t idx, const void *buf, addr_buf[0] = (abs_addr & 0xFF); } - i2c_start_w(fd->i2c, EEPROM_ADDR(dev_addr), addr_len + size, I2C_STOP); - i2c_write(fd->i2c, addr_buf, addr_len); - i2c_write(fd->i2c, buf, size); + i2c_start_w(eep->i2c, EEPROM_ADDR(dev_addr), addr_len + size, I2C_STOP); + i2c_write(eep->i2c, addr_buf, addr_len); + i2c_write(eep->i2c, buf, size); - if (i2c_error(fd->i2c)) + if (i2c_error(eep->i2c)) return 0; return size; } - static size_t eeprom_readDirect(struct KBlock *_blk, block_idx_t idx, void *_buf, size_t offset, size_t size) { Eeprom *blk = EEPROM_CAST_KBLOCK(_blk); @@ -329,6 +250,52 @@ static size_t eeprom_readDirect(struct KBlock *_blk, block_idx_t idx, void *_buf return rd_len; } +static size_t eeprom_writeDirect(KBlock *blk, block_idx_t idx, const void *buf, size_t offset, size_t size) +{ + Eeprom *eep = EEPROM_CAST_KBLOCK(blk); + if (!eep->verify) + return eeprom_write(blk, idx, buf, offset, size); + else + { + int retries = 5; + while (retries--) + { + uint8_t verify_buf[CHUNCK_SIZE]; + size_t wr_len = 0; + size_t len = 0; + while (size) + { + /* Split read in smaller pieces */ + size_t count = MIN(size, (size_t)CHUNCK_SIZE); + if ((wr_len = eeprom_write(blk, idx, buf, offset, count)) != 0) + { + if (eeprom_readDirect(blk, idx, verify_buf, offset, count) != wr_len) + { + LOG_ERR("Verify read fail.\n"); + return 0; + } + else if (memcmp(buf, verify_buf, wr_len) != 0) + { + LOG_ERR("Data mismatch!\n"); + continue; + } + } + else + { + LOG_ERR("Write fail.\n"); + return 0; + } + size -= wr_len; + len += wr_len; + buf = ((const char *)buf) + wr_len; + } + return len; + } + } + + return 0; +} + static int kblockEeprom_dummy(UNUSED_ARG(struct KBlock *,b)) { return 0; @@ -351,21 +318,22 @@ static const KBlockVTable eeprom_unbuffered_vt = * \param i2c context for i2c channel * \param addr is the i2c devide address (usually pins A0, A1, A2). */ -void eeprom_init_5(Eeprom *blk, I2c *i2c, EepromType type, e2dev_addr_t addr, bool verify) +void eeprom_init_5(Eeprom *eep, I2c *i2c, EepromType type, e2dev_addr_t addr, bool verify) { ASSERT(type < EEPROM_CNT); - memset(blk, 0, sizeof(*blk)); - DB(blk->blk.priv.type = KBT_EEPROM); + memset(eep, 0, sizeof(*eep)); + DB(eep->blk.priv.type = KBT_EEPROM); - blk->type = type; - blk->addr = addr; - blk->i2c = i2c; + eep->type = type; + eep->addr = addr; + eep->i2c = i2c; + eep->verify = verify; - blk->blk.blk_size = mem_info[type].blk_size; - blk->blk.blk_cnt = mem_info[type].e2_size / mem_info[type].blk_size; - blk->blk.priv.flags |= KB_PARTIAL_WRITE; - blk->blk.priv.vt = &eeprom_unbuffered_vt; + eep->blk.blk_size = mem_info[type].blk_size; + eep->blk.blk_cnt = mem_info[type].e2_size / mem_info[type].blk_size; + eep->blk.priv.flags |= KB_PARTIAL_WRITE; + eep->blk.priv.vt = &eeprom_unbuffered_vt; } diff --git a/bertos/drv/eeprom.h b/bertos/drv/eeprom.h index 39da6637..ef6c58c9 100644 --- a/bertos/drv/eeprom.h +++ b/bertos/drv/eeprom.h @@ -42,7 +42,7 @@ #ifndef DRV_EEPROM_H #define DRV_EEPROM_H -#define EEPROM_OLD_API 1 +#include "cfg/cfg_eeprom.h" #include #include @@ -56,9 +56,11 @@ #include #if COMPILER_C99 - #define eeprom_init(...) PP_CAT(eeprom_init ## _, COUNT_PARMS(__VA_ARGS__)) (__VA_ARGS__) + #define eeprom_init(...) PP_CAT(eeprom_init ## _, COUNT_PARMS(__VA_ARGS__)) (__VA_ARGS__) + #define eeprom_verify(...) PP_CAT(eeprom_verify ## _, COUNT_PARMS(__VA_ARGS__)) (__VA_ARGS__) #else - #define eeprom_init(args...) PP_CAT(eeprom_init ## _, COUNT_PARMS(args)) (args) + #define eeprom_init(args...) PP_CAT(eeprom_init ## _, COUNT_PARMS(args)) (args) + #define eeprom_verify(args...) PP_CAT(eeprom_verify ## _, COUNT_PARMS(args)) (args) #endif @@ -93,17 +95,17 @@ typedef struct Eeprom EepromType type; ///< EEPROM type e2dev_addr_t addr; ///< Device address. bool verify; -#if EEPROM_OLD_API +#if !CONFIG_EEPROM_DISABLE_OLD_API union { KFile fd; KFileBlock fdblk; } DEPRECATED; -#endif +#endif /* !CONFIG_EEPROM_DISABLE_OLD_API */ } Eeprom; -#if EEPROM_OLD_API +#if !CONFIG_EEPROM_DISABLE_OLD_API STATIC_ASSERT(offsetof(Eeprom, fd) == offsetof(Eeprom, fdblk.fd)); -#endif +#endif /* !CONFIG_EEPROM_DISABLE_OLD_API */ /** * ID for eeproms. @@ -154,19 +156,21 @@ typedef struct EepromInfo e2_size_t e2_size; ///< eeprom size } EepromInfo; -void eeprom_init_5(Eeprom *blk, I2c *i2c, EepromType type, e2dev_addr_t addr, bool verify); +bool eeprom_erase(Eeprom *eep, e2addr_t addr, e2_size_t count); +bool eeprom_verify_4(Eeprom *eep, e2addr_t addr, const void *buf, size_t count); +void eeprom_init_5(Eeprom *eep, I2c *i2c, EepromType type, e2dev_addr_t addr, bool verify); -#if EEPROM_OLD_API -DEPRECATED bool eeprom_erase(Eeprom *fd, e2addr_t addr, e2_size_t count); -DEPRECATED bool eeprom_verify(Eeprom *fd, const void *buf, size_t count); +#if !CONFIG_EEPROM_DISABLE_OLD_API - -DEPRECATED INLINE void eeprom_init_4(Eeprom *ee, EepromType type, e2dev_addr_t addr, bool verify) +DEPRECATED INLINE bool eeprom_verify_3(Eeprom *eep, const void *buf, size_t count) { - eeprom_init_5(ee, &local_i2c_old_api, type, addr, verify); - kfileblock_init(&ee->fdblk, &ee->blk); + return eeprom_verify_4(eep, (e2addr_t)eep->fdblk.fd.seek_pos, buf, count); } - -#endif +DEPRECATED INLINE void eeprom_init_4(Eeprom *eep, EepromType type, e2dev_addr_t addr, bool verify) +{ + eeprom_init_5(eep, &local_i2c_old_api, type, addr, verify); + kfileblock_init(&eep->fdblk, &eep->blk); +} +#endif /* !CONFIG_EEPROM_DISABLE_OLD_API */ #endif /* DRV_EEPROM_H */ -- 2.25.1