BeRTOS
eeprom.c
Go to the documentation of this file.
00001 
00039 #include "eeprom.h"
00040 
00041 #include "cfg/cfg_i2c.h"
00042 #include "cfg/cfg_eeprom.h"
00043 
00044 /* Define logging setting (for cfg/log.h module). */
00045 #define LOG_LEVEL         EEPROM_LOG_LEVEL
00046 #define LOG_FORMAT        EEPROM_LOG_FORMAT
00047 #include <cfg/log.h>
00048 #include <cfg/debug.h>
00049 #include <cfg/macros.h>  // MIN()
00050 
00051 #include <cpu/attr.h>
00052 
00053 #include <drv/i2c.h>
00054 
00055 #include <string.h>  // memset()
00056 
00060 #define EEPROM_ID  0xA0
00061 
00065 #define EEPROM_ADDR(x) (EEPROM_ID | (((uint8_t)((x) & 0x07)) << 1))
00066 
00067 
00071 static const EepromInfo mem_info[] =
00072 {
00073     {
00074         /* 24XX08 */
00075         .has_dev_addr = false,
00076         .blk_size = 0x10,
00077         .e2_size = 0x400,
00078     },
00079     {
00080         /* 24XX16 */
00081         .has_dev_addr = false,
00082         .blk_size = 0x10,
00083         .e2_size = 0x800,
00084     },
00085     {
00086         /* 24XX256 */
00087         .has_dev_addr = true,
00088         .blk_size = 0x40,
00089         .e2_size = 0x8000,
00090     },
00091     {
00092         /* 24XX512 */
00093         .has_dev_addr = true,
00094         .blk_size = 0x80,
00095         .e2_size = 0x10000,
00096     },
00097     {
00098         /* 24XX1024 */
00099         .has_dev_addr = true,
00100         .blk_size = 0x100,
00101         .e2_size = 0x20000,
00102     },
00103 
00104     /* Add other memories here */
00105 };
00106 
00107 STATIC_ASSERT(countof(mem_info) == EEPROM_CNT);
00108 
00109 #define CHUNCK_SIZE     16
00110 
00117 bool eeprom_erase(Eeprom *eep, e2addr_t addr, e2_size_t size)
00118 {
00119     uint8_t tmp[CHUNCK_SIZE] = { [0 ... (CHUNCK_SIZE - 1)] = 0xFF };
00120 
00121     while (size)
00122     {
00123         block_idx_t idx = addr / eep->blk.blk_size;
00124         size_t offset = addr % eep->blk.blk_size;
00125         size_t count = MIN(size, (e2_size_t)CHUNCK_SIZE);
00126         size_t ret_len = eep->blk.priv.vt->writeDirect((KBlock *)eep, idx, tmp, offset, count);
00127         size -= ret_len;
00128         addr += ret_len;
00129 
00130         if (ret_len != count)
00131             return false;
00132     }
00133     return true;
00134 }
00135 
00143 bool eeprom_verify(Eeprom *eep, e2addr_t addr, const void *buf, size_t size)
00144 {
00145     uint8_t verify_buf[CHUNCK_SIZE];
00146     while (size)
00147     {
00148         block_idx_t idx = addr / eep->blk.blk_size;
00149         size_t offset = addr % eep->blk.blk_size;
00150         size_t count = MIN(size, (size_t)CHUNCK_SIZE);
00151 
00152         size_t ret_len = eep->blk.priv.vt->readDirect((KBlock *)eep, idx, verify_buf, offset, count);
00153 
00154         if (ret_len != count)
00155         {
00156             LOG_ERR("Verify read fail.\n");
00157             return false;
00158         }
00159 
00160         if (memcmp(buf, verify_buf, ret_len) != 0)
00161         {
00162             LOG_ERR("Data mismatch!\n");
00163             return false;
00164         }
00165 
00166         size -= ret_len;
00167         addr += ret_len;
00168         buf = ((const char *)buf) + ret_len;
00169     }
00170     return true;
00171 }
00172 
00173 
00174 static size_t eeprom_write(KBlock *blk, block_idx_t idx, const void *buf, size_t offset, size_t size)
00175 {
00176     Eeprom *eep = EEPROM_CAST_KBLOCK(blk);
00177     e2dev_addr_t dev_addr;
00178     uint8_t addr_buf[2];
00179     uint8_t addr_len;
00180     uint32_t abs_addr = blk->blk_size * idx + offset;
00181 
00182     STATIC_ASSERT(countof(addr_buf) <= sizeof(e2addr_t));
00183 
00184     /* clamp size to memory limit (otherwise may roll back) */
00185     ASSERT(idx < blk->priv.blk_start + blk->blk_cnt);
00186     size = MIN(size, blk->blk_size - offset);
00187 
00188     if (mem_info[eep->type].has_dev_addr)
00189     {
00190         dev_addr = eep->addr;
00191         addr_len = 2;
00192     }
00193     else
00194     {
00195         dev_addr = (e2dev_addr_t)((abs_addr >> 8) & 0x07);
00196         addr_len = 1;
00197     }
00198 
00199     if (mem_info[eep->type].has_dev_addr)
00200     {
00201         addr_buf[0] = (abs_addr >> 8) & 0xFF;
00202         addr_buf[1] = (abs_addr & 0xFF);
00203     }
00204     else
00205     {
00206         dev_addr = (e2dev_addr_t)((abs_addr >> 8) & 0x07);
00207         addr_buf[0] = (abs_addr & 0xFF);
00208     }
00209 
00210     i2c_start_w(eep->i2c, EEPROM_ADDR(dev_addr),  addr_len + size, I2C_STOP);
00211     i2c_write(eep->i2c, addr_buf, addr_len);
00212     i2c_write(eep->i2c, buf, size);
00213 
00214     if (i2c_error(eep->i2c))
00215         return 0;
00216 
00217     return size;
00218 }
00219 
00220 static size_t eeprom_readDirect(struct KBlock *_blk, block_idx_t idx, void *_buf, size_t offset, size_t size)
00221 {
00222     Eeprom *blk = EEPROM_CAST_KBLOCK(_blk);
00223     uint8_t addr_buf[2];
00224     uint8_t addr_len;
00225     size_t rd_len = 0;
00226     uint8_t *buf = (uint8_t *)_buf;
00227     uint32_t abs_addr = mem_info[blk->type].blk_size * idx + offset;
00228 
00229     STATIC_ASSERT(countof(addr_buf) <= sizeof(e2addr_t));
00230 
00231     /* clamp size to memory limit (otherwise may roll back) */
00232     ASSERT(idx < blk->blk.priv.blk_start + blk->blk.blk_cnt);
00233     size = MIN(size, blk->blk.blk_size - offset);
00234 
00235     e2dev_addr_t dev_addr;
00236     if (mem_info[blk->type].has_dev_addr)
00237     {
00238         dev_addr = blk->addr;
00239         addr_len = 2;
00240         addr_buf[0] = (abs_addr >> 8) & 0xFF;
00241         addr_buf[1] = (abs_addr & 0xFF);
00242     }
00243     else
00244     {
00245         dev_addr = (e2dev_addr_t)((abs_addr >> 8) & 0x07);
00246         addr_len = 1;
00247         addr_buf[0] = (abs_addr & 0xFF);
00248     }
00249 
00250 
00251     i2c_start_w(blk->i2c, EEPROM_ADDR(dev_addr),  addr_len, I2C_NOSTOP);
00252     i2c_write(blk->i2c, addr_buf, addr_len);
00253 
00254     i2c_start_r(blk->i2c, EEPROM_ADDR(dev_addr), size, I2C_STOP);
00255     i2c_read(blk->i2c, buf, size);
00256 
00257     if (i2c_error(blk->i2c))
00258            return rd_len;
00259 
00260     rd_len += size;
00261 
00262     return rd_len;
00263 }
00264 
00265 static size_t eeprom_writeDirect(KBlock *blk, block_idx_t idx, const void *buf, size_t offset, size_t size)
00266 {
00267     Eeprom *eep = EEPROM_CAST_KBLOCK(blk);
00268     if (!eep->verify)
00269         return eeprom_write(blk, idx, buf, offset, size);
00270     else
00271     {
00272         int retries = 5;
00273         while (retries--)
00274         {
00275             uint8_t verify_buf[CHUNCK_SIZE];
00276             size_t wr_len = 0;
00277             size_t len = 0;
00278             while (size)
00279             {
00280                 /* Split read in smaller pieces */
00281                 size_t count = MIN(size, (size_t)CHUNCK_SIZE);
00282                 if ((wr_len = eeprom_write(blk, idx, buf, offset, count)) != 0)
00283                 {
00284                     if (eeprom_readDirect(blk, idx, verify_buf, offset, count) != wr_len)
00285                     {
00286                         LOG_ERR("Verify read fail.\n");
00287                         return 0;
00288                     }
00289                     else if (memcmp(buf, verify_buf, wr_len) != 0)
00290                     {
00291                         LOG_ERR("Data mismatch!\n");
00292                         continue;
00293                     }
00294                 }
00295                 else
00296                 {
00297                     LOG_ERR("Write fail.\n");
00298                     return 0;
00299                 }
00300                 size -= wr_len;
00301                 len += wr_len;
00302                 buf = ((const char *)buf) + wr_len;
00303             }
00304             return len;
00305         }
00306     }
00307 
00308     return 0;
00309 }
00310 
00311 static int kblockEeprom_dummy(UNUSED_ARG(struct KBlock *,b))
00312 {
00313     return 0;
00314 }
00315 
00316 
00317 static const KBlockVTable eeprom_unbuffered_vt =
00318 {
00319     .readDirect = eeprom_readDirect,
00320     .writeDirect = eeprom_writeDirect,
00321 
00322     .error = kblockEeprom_dummy,
00323     .clearerr = (kblock_clearerr_t)kblockEeprom_dummy,
00324 };
00325 
00334 void eeprom_init_5(Eeprom *eep, I2c *i2c, EepromType type, e2dev_addr_t addr, bool verify)
00335 {
00336     ASSERT(type < EEPROM_CNT);
00337 
00338     memset(eep, 0, sizeof(*eep));
00339     DB(eep->blk.priv.type = KBT_EEPROM);
00340 
00341     eep->type = type;
00342     eep->addr = addr;
00343     eep->i2c = i2c;
00344     eep->verify = verify;
00345 
00346     eep->blk.blk_size = mem_info[type].blk_size;
00347     eep->blk.blk_cnt = mem_info[type].e2_size / mem_info[type].blk_size;
00348     eep->blk.priv.flags |= KB_PARTIAL_WRITE;
00349     eep->blk.priv.vt = &eeprom_unbuffered_vt;
00350 }
00351 
00352