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         /* 24XX32 */
00087         .has_dev_addr = true,
00088         .blk_size = 0x20,
00089         .e2_size = 0x1000,
00090     },
00091     {
00092         /* 24XX64 */
00093         .has_dev_addr = true,
00094         .blk_size = 0x20,
00095         .e2_size = 0x2000,
00096     },
00097     {
00098         /* 24XX128 */
00099         .has_dev_addr = true,
00100         .blk_size = 0x40,
00101         .e2_size = 0x4000,
00102     },
00103     {
00104         /* 24XX256 */
00105         .has_dev_addr = true,
00106         .blk_size = 0x40,
00107         .e2_size = 0x8000,
00108     },
00109     {
00110         /* 24XX512 */
00111         .has_dev_addr = true,
00112         .blk_size = 0x80,
00113         .e2_size = 0x10000,
00114     },
00115     {
00116         /* 24XX1024 */
00117         .has_dev_addr = true,
00118         .blk_size = 0x100,
00119         .e2_size = 0x20000,
00120     },
00121
00122     /* Add other memories here */
00123 };
00124
00125 STATIC_ASSERT(countof(mem_info) == EEPROM_CNT);
00126
00127 #define CHUNCK_SIZE     16
00128 
00135 bool eeprom_erase(Eeprom *eep, e2addr_t addr, e2_size_t size)
00136 {
00137     uint8_t tmp[CHUNCK_SIZE] = { [0 ... (CHUNCK_SIZE - 1)] = 0xFF };
00138
00139     while (size)
00140     {
00141         block_idx_t idx = addr / eep->blk.blk_size;
00142         size_t offset = addr % eep->blk.blk_size;
00143         size_t count = MIN(size, (e2_size_t)CHUNCK_SIZE);
00144         size_t ret_len = eep->blk.priv.vt->writeDirect((KBlock *)eep, idx, tmp, offset, count);
00145         size -= ret_len;
00146         addr += ret_len;
00147
00148         if (ret_len != count)
00149             return false;
00150     }
00151     return true;
00152 }
00153
00161 bool eeprom_verify(Eeprom *eep, e2addr_t addr, const void *buf, size_t size)
00162 {
00163     uint8_t verify_buf[CHUNCK_SIZE];
00164     while (size)
00165     {
00166         block_idx_t idx = addr / eep->blk.blk_size;
00167         size_t offset = addr % eep->blk.blk_size;
00168         size_t count = MIN(size, (size_t)CHUNCK_SIZE);
00169
00170         size_t ret_len = eep->blk.priv.vt->readDirect((KBlock *)eep, idx, verify_buf, offset, count);
00171
00172         if (ret_len != count)
00173         {
00174             LOG_ERR("Verify read fail.\n");
00175             return false;
00176         }
00177
00178         if (memcmp(buf, verify_buf, ret_len) != 0)
00179         {
00180             LOG_ERR("Data mismatch!\n");
00181             return false;
00182         }
00183
00184         size -= ret_len;
00185         addr += ret_len;
00186         buf = ((const char *)buf) + ret_len;
00187     }
00188     return true;
00189 }
00190
00191
00192 static size_t eeprom_write(KBlock *blk, block_idx_t idx, const void *buf, size_t offset, size_t size)
00193 {
00194     Eeprom *eep = EEPROM_CAST_KBLOCK(blk);
00195     e2dev_addr_t dev_addr;
00196     uint8_t addr_buf[2];
00197     uint8_t addr_len;
00198     uint32_t abs_addr = blk->blk_size * idx + offset;
00199
00200     STATIC_ASSERT(countof(addr_buf) <= sizeof(e2addr_t));
00201
00202     /* clamp size to memory limit (otherwise may roll back) */
00203     ASSERT(idx < blk->priv.blk_start + blk->blk_cnt);
00204     size = MIN(size, blk->blk_size - offset);
00205
00206     if (mem_info[eep->type].has_dev_addr)
00207     {
00208         dev_addr = eep->addr;
00209         addr_len = 2;
00210     }
00211     else
00212     {
00213         dev_addr = (e2dev_addr_t)((abs_addr >> 8) & 0x07);
00214         addr_len = 1;
00215     }
00216
00217     if (mem_info[eep->type].has_dev_addr)
00218     {
00219         addr_buf[0] = (abs_addr >> 8) & 0xFF;
00220         addr_buf[1] = (abs_addr & 0xFF);
00221     }
00222     else
00223     {
00224         dev_addr = (e2dev_addr_t)((abs_addr >> 8) & 0x07);
00225         addr_buf[0] = (abs_addr & 0xFF);
00226     }
00227
00228     i2c_start_w(eep->i2c, EEPROM_ADDR(dev_addr),  addr_len + size, I2C_STOP);
00229     i2c_write(eep->i2c, addr_buf, addr_len);
00230     i2c_write(eep->i2c, buf, size);
00231
00232     if (i2c_error(eep->i2c))
00233         return 0;
00234
00235     return size;
00236 }
00237
00238 static size_t eeprom_readDirect(struct KBlock *_blk, block_idx_t idx, void *_buf, size_t offset, size_t size)
00239 {
00240     Eeprom *blk = EEPROM_CAST_KBLOCK(_blk);
00241     uint8_t addr_buf[2];
00242     uint8_t addr_len;
00243     size_t rd_len = 0;
00244     uint8_t *buf = (uint8_t *)_buf;
00245     uint32_t abs_addr = mem_info[blk->type].blk_size * idx + offset;
00246
00247     STATIC_ASSERT(countof(addr_buf) <= sizeof(e2addr_t));
00248
00249     /* clamp size to memory limit (otherwise may roll back) */
00250     ASSERT(idx < blk->blk.priv.blk_start + blk->blk.blk_cnt);
00251     size = MIN(size, blk->blk.blk_size - offset);
00252
00253     e2dev_addr_t dev_addr;
00254     if (mem_info[blk->type].has_dev_addr)
00255     {
00256         dev_addr = blk->addr;
00257         addr_len = 2;
00258         addr_buf[0] = (abs_addr >> 8) & 0xFF;
00259         addr_buf[1] = (abs_addr & 0xFF);
00260     }
00261     else
00262     {
00263         dev_addr = (e2dev_addr_t)((abs_addr >> 8) & 0x07);
00264         addr_len = 1;
00265         addr_buf[0] = (abs_addr & 0xFF);
00266     }
00267
00268
00269     i2c_start_w(blk->i2c, EEPROM_ADDR(dev_addr),  addr_len, I2C_NOSTOP);
00270     i2c_write(blk->i2c, addr_buf, addr_len);
00271
00272     i2c_start_r(blk->i2c, EEPROM_ADDR(dev_addr), size, I2C_STOP);
00273     i2c_read(blk->i2c, buf, size);
00274
00275     if (i2c_error(blk->i2c))
00276            return rd_len;
00277
00278     rd_len += size;
00279
00280     return rd_len;
00281 }
00282
00283 static size_t eeprom_writeDirect(KBlock *blk, block_idx_t idx, const void *buf, size_t offset, size_t size)
00284 {
00285     Eeprom *eep = EEPROM_CAST_KBLOCK(blk);
00286     if (!eep->verify)
00287         return eeprom_write(blk, idx, buf, offset, size);
00288     else
00289     {
00290         int retries = 5;
00291         while (retries--)
00292         {
00293             uint8_t verify_buf[CHUNCK_SIZE];
00294             size_t wr_len = 0;
00295             size_t len = 0;
00296             while (size)
00297             {
00298                 /* Split read in smaller pieces */
00299                 size_t count = MIN(size, (size_t)CHUNCK_SIZE);
00300                 if ((wr_len = eeprom_write(blk, idx, buf, offset, count)) != 0)
00301                 {
00302                     if (eeprom_readDirect(blk, idx, verify_buf, offset, count) != wr_len)
00303                     {
00304                         LOG_ERR("Verify read fail.\n");
00305                         return 0;
00306                     }
00307                     else if (memcmp(buf, verify_buf, wr_len) != 0)
00308                     {
00309                         LOG_ERR("Data mismatch!\n");
00310                         continue;
00311                     }
00312                 }
00313                 else
00314                 {
00315                     LOG_ERR("Write fail.\n");
00316                     return 0;
00317                 }
00318                 size -= wr_len;
00319                 len += wr_len;
00320                 buf = ((const char *)buf) + wr_len;
00321             }
00322             return len;
00323         }
00324     }
00325
00326     return 0;
00327 }
00328
00329 static int kblockEeprom_dummy(UNUSED_ARG(struct KBlock *,b))
00330 {
00331     return 0;
00332 }
00333
00334
00335 static const KBlockVTable eeprom_unbuffered_vt =
00336 {
00337     .readDirect = eeprom_readDirect,
00338     .writeDirect = eeprom_writeDirect,
00339
00340     .error = kblockEeprom_dummy,
00341     .clearerr = (kblock_clearerr_t)kblockEeprom_dummy,
00342 };
00343
00352 void eeprom_init_5(Eeprom *eep, I2c *i2c, EepromType type, e2dev_addr_t addr, bool verify)
00353 {
00354     ASSERT(type < EEPROM_CNT);
00355
00356     memset(eep, 0, sizeof(*eep));
00357     DB(eep->blk.priv.type = KBT_EEPROM);
00358
00359     eep->type = type;
00360     eep->addr = addr;
00361     eep->i2c = i2c;
00362     eep->verify = verify;
00363
00364     eep->blk.blk_size = mem_info[type].blk_size;
00365     eep->blk.blk_cnt = mem_info[type].e2_size / mem_info[type].blk_size;
00366     eep->blk.priv.flags |= KB_PARTIAL_WRITE;
00367     eep->blk.priv.vt = &eeprom_unbuffered_vt;
00368 }
00369
00370