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
![(please configure the [header_logo] section in trac.ini)](/chrome/site/bertos_logo.png)