BeRTOS
|
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