eeprom.c

Go to the documentation of this file.
00001 
00042 #include "eeprom.h"
00043 
00044 #include <cfg/debug.h>
00045 #include <appconfig.h>  // CONFIG_EEPROM_VERIFY
00046 #include <cfg/macros.h>  // MIN()
00047 #include <cpu/attr.h>
00048 #include CPU_HEADER(twi)
00049 #include <drv/wdt.h>
00050 #include <mware/byteorder.h> // cpu_to_be16()
00051 
00052 #include <string.h>  // memset()
00053 
00054 
00055 // Configuration sanity checks
00056 #if !defined(CONFIG_EEPROM_VERIFY) || (CONFIG_EEPROM_VERIFY != 0 && CONFIG_EEPROM_VERIFY != 1)
00057     #error CONFIG_EEPROM_VERIFY must be defined to either 0 or 1
00058 #endif
00059 
00063 #define EEPROM_ID  0xA0
00064 
00068 #define EEPROM_ADDR(x) (EEPROM_ID | (((uint8_t)(x)) << 1))
00069 
00070 
00071 
00072 
00077 static bool eeprom_writeRaw(e2addr_t addr, const void *buf, size_t count)
00078 {
00079     bool result = true;
00080     ASSERT(addr + count <= EEPROM_SIZE);
00081 
00082     while (count && result)
00083     {
00084         /*
00085          * Split write in multiple sequential mode operations that
00086          * don't cross page boundaries.
00087          */
00088         size_t size =
00089             MIN(count, (size_t)(EEPROM_BLKSIZE - (addr & (EEPROM_BLKSIZE - 1))));
00090 
00091     #if CONFIG_EEPROM_TYPE == EEPROM_24XX16
00092         /*
00093          * The 24LC16 uses the slave address as a 3-bit
00094          * block address.
00095          */
00096         uint8_t blk_addr = (uint8_t)((addr >> 8) & 0x07);
00097         uint8_t blk_offs = (uint8_t)addr;
00098 
00099         result =
00100             twi_start_w(EEPROM_ADDR(blk_addr))
00101             && twi_send(&blk_offs, sizeof blk_offs)
00102             && twi_send(buf, size);
00103 
00104     #elif CONFIG_EEPROM_TYPE == EEPROM_24XX256
00105 
00106         // 24LC256 wants big-endian addresses
00107         uint16_t addr_be = cpu_to_be16(addr);
00108 
00109         result =
00110             twi_start_w(EEPROM_ID)
00111             && twi_send((uint8_t *)&addr_be, sizeof addr_be)
00112             && twi_send(buf, size);
00113 
00114     #else
00115         #error Unknown device type
00116     #endif
00117 
00118         twi_stop();
00119 
00120         // DEBUG
00121         //kprintf("addr=%d, count=%d, size=%d, *#?=%d\n",
00122         //  addr, count, size,
00123         //  (EEPROM_BLKSIZE - (addr & (EEPROM_BLKSIZE - 1)))
00124         //);
00125 
00126         /* Update count and addr for next operation */
00127         count -= size;
00128         addr += size;
00129         buf = ((const char *)buf) + size;
00130     }
00131 
00132     if (!result)
00133         TRACEMSG("Write error!");
00134     return result;
00135 }
00136 
00137 
00138 #if CONFIG_EEPROM_VERIFY
00139 
00145 static bool eeprom_verify(e2addr_t addr, const void *buf, size_t count)
00146 {
00147     uint8_t verify_buf[16];
00148     bool result = true;
00149 
00150     while (count && result)
00151     {
00152         /* Split read in smaller pieces */
00153         size_t size = MIN(count, sizeof verify_buf);
00154 
00155         /* Read back buffer */
00156         if (eeprom_read(addr, verify_buf, size))
00157         {
00158             if (memcmp(buf, verify_buf, size) != 0)
00159             {
00160                 TRACEMSG("Data mismatch!");
00161                 result = false;
00162             }
00163         }
00164         else
00165         {
00166             TRACEMSG("Read error!");
00167             result = false;
00168         }
00169 
00170         /* Update count and addr for next operation */
00171         count -= size;
00172         addr += size;
00173         buf = ((const char *)buf) + size;
00174     }
00175 
00176     return result;
00177 }
00178 #endif /* CONFIG_EEPROM_VERIFY */
00179 
00180 
00181 bool eeprom_write(e2addr_t addr, const void *buf, size_t count)
00182 {
00183 #if CONFIG_EEPROM_VERIFY
00184     int retries = 5;
00185 
00186     while (retries--)
00187         if (eeprom_writeRaw(addr, buf, count)
00188                 && eeprom_verify(addr, buf, count))
00189             return true;
00190 
00191     return false;
00192 
00193 #else /* !CONFIG_EEPROM_VERIFY */
00194     return eeprom_writeRaw(addr, buf, count);
00195 #endif /* !CONFIG_EEPROM_VERIFY */
00196 }
00197 
00198 
00205 bool eeprom_read(e2addr_t addr, void *buf, size_t count)
00206 {
00207     ASSERT(addr + count <= EEPROM_SIZE);
00208 
00209 #if CONFIG_EEPROM_TYPE == EEPROM_24XX16
00210     /*
00211      * The 24LC16 uses the slave address as a 3-bit
00212      * block address.
00213      */
00214     uint8_t blk_addr = (uint8_t)((addr >> 8) & 0x07);
00215     uint8_t blk_offs = (uint8_t)addr;
00216 
00217     bool res =
00218         twi_start_w(EEPROM_ADDR(blk_addr))
00219         && twi_send(&blk_offs, sizeof blk_offs)
00220         && twi_start_r(EEPROM_ADDR(blk_addr))
00221         && twi_recv(buf, count);
00222 
00223 #elif CONFIG_EEPROM_TYPE == EEPROM_24XX256
00224 
00225     // 24LC256 wants big-endian addresses
00226     addr = cpu_to_be16(addr);
00227 
00228     bool res =
00229         twi_start_w(EEPROM_ID)
00230         && twi_send((uint8_t *)&addr, sizeof(addr))
00231         && twi_start_r(EEPROM_ID)
00232         && twi_recv(buf, count);
00233 #else
00234     #error Unknown device type
00235 #endif
00236 
00237     twi_stop();
00238 
00239     if (!res)
00240         TRACEMSG("Read error!");
00241     return res;
00242 }
00243 
00244 
00248 bool eeprom_write_char(e2addr_t addr, char c)
00249 {
00250     return eeprom_write(addr, &c, 1);
00251 }
00252 
00253 
00259 int eeprom_read_char(e2addr_t addr)
00260 {
00261     char c;
00262 
00263     if (eeprom_read(addr, &c, 1))
00264         return c;
00265     else
00266         return -1;
00267 }
00268 
00269 
00276 void eeprom_erase(e2addr_t addr, size_t count)
00277 {
00278     uint8_t buf[EEPROM_BLKSIZE];
00279     memset(buf, 0xFF, sizeof buf);
00280 
00281     // Clear all but struct hw_info at start of eeprom
00282     while (count)
00283     {
00284         // Long operation, reset watchdog
00285         wdt_reset();
00286 
00287         size_t size = MIN(count, sizeof buf);
00288         eeprom_write(addr, buf, size);
00289         addr += size;
00290         count -= size;
00291     }
00292 }
00293 
00294 
00298 void eeprom_init(void)
00299 {
00300     twi_init();
00301 }
00302 
00303 
00304 #ifdef _DEBUG
00305 
00306 #include <string.h>
00307 
00308 void eeprom_test(void)
00309 {
00310     static const char magic[14] = "Humpty Dumpty";
00311     char buf[sizeof magic];
00312     size_t i;
00313 
00314     // Write something to EEPROM using unaligned sequential writes
00315     for (i = 0; i < 42; ++i)
00316     {
00317         wdt_reset();
00318         eeprom_write(i * sizeof magic, magic, sizeof magic);
00319     }
00320 
00321     // Read back with single-byte reads
00322     for (i = 0; i < 42 * sizeof magic; ++i)
00323     {
00324         wdt_reset();
00325         eeprom_read(i, buf, 1);
00326         kprintf("EEPROM byte read: %c (%d)\n", buf[0], buf[0]);
00327         ASSERT(buf[0] == magic[i % sizeof magic]);
00328     }
00329 
00330     // Read back again using sequential reads
00331     for (i = 0; i < 42; ++i)
00332     {
00333         wdt_reset();
00334         memset(buf, 0, sizeof buf);
00335         eeprom_read(i * sizeof magic, buf, sizeof magic);
00336         kprintf("EEPROM seq read @ 0x%x: '%s'\n", i * sizeof magic, buf);
00337         ASSERT(memcmp(buf, magic, sizeof magic) == 0);
00338     }
00339 }
00340 
00341 #endif // _DEBUG