X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fdrv%2Feeprom.c;h=82fb9590f6126524ce8d63a76290df2ab1f706b9;hb=ee28b0a27ccfcf160e6cde5632bb5966608bbc90;hp=fd644e4c995317750f04036aa6d0c078fbc37e07;hpb=9dbdea90d95eeabf964c1ba519fcd17e0efd3729;p=bertos.git diff --git a/bertos/drv/eeprom.c b/bertos/drv/eeprom.c index fd644e4c..82fb9590 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() @@ -81,6 +82,24 @@ static const EepromInfo mem_info[] = .blk_size = 0x10, .e2_size = 0x800, }, + { + /* 24XX32 */ + .has_dev_addr = true, + .blk_size = 0x20, + .e2_size = 0x1000, + }, + { + /* 24XX64 */ + .has_dev_addr = true, + .blk_size = 0x20, + .e2_size = 0x2000, + }, + { + /* 24XX128 */ + .has_dev_addr = true, + .blk_size = 0x40, + .e2_size = 0x4000, + }, { /* 24XX256 */ .has_dev_addr = true, @@ -105,140 +124,74 @@ static const EepromInfo mem_info[] = STATIC_ASSERT(countof(mem_info) == EEPROM_CNT); +#define CHUNCK_SIZE 16 + /** - * 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. + * Erase EEPROM. + * \param eep is the Kblock context. + * \param addr eeprom address where start to erase + * \param size number of byte to erase */ -bool eeprom_verify(Eeprom *fd, const void *buf, size_t count) +bool eeprom_erase(Eeprom *eep, e2addr_t addr, e2_size_t size) { - uint8_t verify_buf[16]; - bool result = true; + uint8_t tmp[CHUNCK_SIZE] = { [0 ... (CHUNCK_SIZE - 1)] = 0xFF }; - /* Save seek position */ - kfile_off_t prev_seek = fd->fd.seek_pos; - - 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. + * Verify EEPROM. + * \param eep is the Kblock context. + * \param addr eeprom address where start to verify. + * \param buf buffer of data to compare with eeprom data read. + * \param size number of byte to verify. */ -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; + if (memcmp(buf, verify_buf, ret_len) != 0) + { + LOG_ERR("Data mismatch!\n"); + return false; + } + + size -= ret_len; + addr += ret_len; + buf = ((const char *)buf) + ret_len; } - fd->fd.seek_pos = prev_off; - return res; + return true; } -/** - * 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) +static size_t eeprom_write(KBlock *blk, block_idx_t idx, const void *buf, size_t offset, size_t size) { - 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; - - fd->fd.seek = kfile_genericSeek; -} - - -static size_t eeprom_writeDirect(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; @@ -246,14 +199,13 @@ static size_t eeprom_writeDirect(KBlock *blk, block_idx_t idx, const void *buf, STATIC_ASSERT(countof(addr_buf) <= sizeof(e2addr_t)); - /* clamp size to memory limit (otherwise may roll back) */ - ASSERT(idx <= blk->blk_cnt); + ASSERT(idx < blk->priv.blk_start + 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 +214,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 +225,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); @@ -296,7 +247,7 @@ static size_t eeprom_readDirect(struct KBlock *_blk, block_idx_t idx, void *_buf STATIC_ASSERT(countof(addr_buf) <= sizeof(e2addr_t)); /* clamp size to memory limit (otherwise may roll back) */ - ASSERT(idx <= blk->blk.blk_cnt); + ASSERT(idx < blk->blk.priv.blk_start + blk->blk.blk_cnt); size = MIN(size, blk->blk.blk_size - offset); e2dev_addr_t dev_addr; @@ -329,6 +280,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; @@ -346,26 +343,28 @@ static const KBlockVTable eeprom_unbuffered_vt = /** * Initialize EEPROM module. - * \param b is the Kblock context. + * \param eep is the Kblock context. * \param type is the eeprom device we want to initialize (\see EepromType) * \param i2c context for i2c channel * \param addr is the i2c devide address (usually pins A0, A1, A2). + * \param verify enable the write check. */ -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; }