Driver library for Microchip I2C EERAM (47x04 and 47x16) 4 kbit or 16 kbit EEPROM backed SRAM.

Dependents:   EERAM_example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers EERAM.h Source File

EERAM.h

Go to the documentation of this file.
00001 /**
00002 * @file    EERAM.h
00003 * @brief   mbed driver for Microchip I2C EERAM devices (47x04 and 47x16)
00004 * @author  Mark Peter Vargha, vmp@varghamarkpeter.hu
00005 * @version 1.4.0
00006 *
00007 * Copyright (c) 2017
00008 *
00009 * Licensed under the Apache License, Version 2.0 (the "License");
00010 * you may not use this file except in compliance with the License.
00011 * You may obtain a copy of the License at
00012 *
00013 *     http://www.apache.org/licenses/LICENSE-2.0
00014 *
00015 * Unless required by applicable law or agreed to in writing, software
00016 * distributed under the License is distributed on an "AS IS" BASIS,
00017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00018 * See the License for the specific language governing permissions and
00019 * limitations under the License.
00020 */
00021 
00022 #ifndef EERAM_h
00023 #define EERAM_h
00024 
00025 #include "mbed.h"
00026 
00027 //#define DEBUG_EERAM
00028 
00029 #ifdef DEBUG_EERAM
00030 extern Serial serial;
00031 #endif
00032 
00033 enum ProtectedMemoryArea
00034 {
00035     NONE = 0, U64, U32, U16, U8, U4, U2, ALL
00036 };
00037 
00038 /** An I2C EERAM interface to communicate with Microchip 47x04 and 47x16 devices
00039 * 4 kbit (512 byte) or 16 kbit (2048 byte) EEPROM backed I2C SRAM
00040 * The device could detect power down and stores SRAM contents in EEPROM. The SRAM is recalled from EEPROM on power up.
00041 *
00042 * <a href="http://ww1.microchip.com/downloads/en/DeviceDoc/20005371C.pdf">47x04 and 47x16 datasheet</a>
00043 * <a href="http://ww1.microchip.com/downloads/cn/AppNotes/cn588417.pdf">Recommended Usage of Microchip I2C EERAM Devices</a>
00044 * <a href="http://ww1.microchip.com/downloads/en/AppNotes/00002257A.pdf">Choosing the Right EERAM VCAP Capacitor</a>
00045 *
00046 * Example:
00047 * @code
00048 #include "mbed.h"
00049 #include "EERAM.h"
00050 
00051 EERAM eeram(PC_9, PA_8, 2048); //SDA, SCL
00052 
00053 int main()
00054 {
00055     if (!eeram.isReady(100)) //Checks device with 100 ms timeout
00056     {
00057         printf("Device is not present.");
00058         while (1);
00059     }
00060     eeram.readStatus(); //Reads status register
00061     eeram.setAutoStoreEnabled(true, true); //Set auto store on power down to true and stores if not stored before
00062     while (1)
00063     {
00064         char dataStore[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
00065         eeram.writeBytes(0x100, dataStore, 16); //We can not wear EEPROM out, so it is ok to write data to the device frequently.
00066         wait(2.0);
00067         char dataRead[16];
00068         eeram.readBytes(0x100, dataRead, 16);
00069         wait(2.0);
00070         float floatToWrite = -1.976f;
00071         const uint16_t address = 0x200;
00072         eeram.write(address, &floatToWrite);
00073         wait(2.0);
00074         float floatToRead = 0;
00075         eeram.read(address, &floatToWrite);
00076         wait(2.0);
00077     }
00078 }
00079 
00080 * @endcode
00081 */
00082 class EERAM
00083 {
00084 
00085 public:
00086 
00087     /** Create an I2C EERAM interface, connected to the specified pins, with specified size and with the specified address pins
00088     * @param SDA I2C data line pin
00089     * @param SCL I2C clock line pin
00090     * @param memorySize Size of EERAM, 512 for 47x04 and 2048 for 47x16
00091     * @param A1 EERAM A1 pin state (true = high, false = low)
00092     * @param A2 EERAM A2 pin state (true = high, false = low)
00093     */
00094 //    EERAM(PinName SDA, PinName SCL, uint16_t memorySize, bool A1 = false, bool A2 = false) :
00095 //        _i2c(SDA, SCL),
00096 //        _memorySize(memorySize)
00097 //    {
00098 //        initialize(A1, A2);
00099 //    };
00100 
00101     /** Create an I2C EERAM interface, connected to the I2C, with specified size and with the specified address pins.
00102     * @param 12c I2C
00103     * @param memorySize Size of EERAM, 512 for 47x04 and 2048 for 47x16
00104     * @param A1 EERAM A1 pin state (true = high, false = low)
00105     * @param A2 EERAM A2 pin state (true = high, false = low)
00106     */
00107     EERAM(I2C &i2c, uint16_t memorySize, bool A1 = false, bool A2 = false) :
00108         _i2c(i2c),
00109         _memorySize(memorySize)
00110     {
00111         initialize(A1, A2);
00112     };
00113 
00114     /** Puts the given 16 bit SRAM address into the first two bytes of the given buffer. The buffer size shall be minimum two bytes. No length check.
00115     */
00116     static void putAddressIntoBuffer(uint16_t address, char *data);
00117 
00118     /** Copies the bytes from the given memory area to the given buffer. Uses the size of T to determine write length.
00119     * @param buffer Buffer to put bytes into
00120     * @param source Pointer to the memory location
00121     *
00122     * @return Number of written bytes.
00123     */
00124     template <typename T>
00125     static int putIntoBuffer(char *buffer, const int bufferSize, T *source)
00126     {
00127         const int length = sizeof(T);
00128         if (length <= bufferSize)
00129         {
00130             char *bytes = static_cast<char*>(static_cast<void*>(source));
00131             memcpy(buffer, bytes, length);
00132             return length;
00133         }
00134         else
00135         {
00136             return 0;
00137         }
00138     }
00139 
00140     /** Copies the bytes from the given buffer to the given memory area. Uses the size of T to determine read length.
00141     * @param buffer Buffer to get bytes from
00142     * @param destination Pointer to the memory location
00143     *
00144     * @return Number of read bytes.
00145     */
00146     template <typename T>
00147     static int getFromBuffer(char *buffer, const int bufferSize, T *destination)
00148     {
00149         const int length = sizeof(T);
00150         if (length <= bufferSize)
00151         {
00152             char *bytes = static_cast<char*>(static_cast<void*>(destination));
00153             memcpy(bytes, buffer, length);
00154             return length;
00155         }
00156         else
00157         {
00158             return 0;
00159         }
00160     }
00161 
00162     /** Copies the bytes from the given memory area to the given EERAM address. Uses the size of T and the length to determine write length. Allowed types: Primitives, fixed arrays and structs without pointers.
00163     * @param source Pointer to memory where copy from.
00164     * @param length Length of the array. Pass 1 here if it is not an array.
00165     *
00166     * @return Number of written bytes.
00167     */
00168     template <typename T>
00169     int write(uint16_t address, T *source, const int length = 1)
00170     {
00171         bool success = false;
00172         const int typeLength = sizeof(T);
00173         const int writeLength = typeLength * length;
00174         const int addressLength = sizeof(uint16_t);
00175         char *sourceAsBytes = static_cast<char*>(static_cast<void*>(source));
00176         success = checkAddressRange(address, writeLength);
00177         if (success) //Address range check
00178         {
00179             uint16_t addressPtr = address;
00180             int sourcePtr = 0;
00181             for (int i = 0; i < length; i++)
00182             {
00183                 const int bufferSize = typeLength + addressLength;
00184                 char buffer[bufferSize];
00185                 putAddressIntoBuffer(addressPtr, buffer);
00186                 memcpy(buffer + addressLength, sourceAsBytes + sourcePtr, typeLength);
00187                 success = writeBytes(buffer, bufferSize);
00188                 if (success) //Write to I2C
00189                 {
00190                     addressPtr += typeLength;
00191                     sourcePtr += typeLength;
00192                 }
00193                 else
00194                 {
00195                     break;
00196                 }
00197             }
00198         }
00199         return success ? writeLength : 0;
00200     }
00201 
00202     /** Copies the bytes from the given EERAM address to the given memory area. Uses the size of T and the length to determine read length. Allowed types: Primitives, fixed arrays and structs without pointers. Destination shall be allocated.
00203     * @param destination Pointer to memory where copy to.
00204     * @param length Length of the array. Pass 1 here if it is not an array.
00205     * @param direct Applicable only when length > 1. If true reads all items of the array in one I2C read, otherwise read them in blocks.
00206     *
00207     * @return Number of read bytes.
00208     */
00209     template <typename T>
00210     int read(uint16_t address, T *destination, const int length = 1, bool direct = false)
00211     {
00212         bool success = false;
00213         const int typeLength = sizeof(T);
00214         const int readLength = typeLength * length;
00215         char *destinationAsBytes = static_cast<char*>(static_cast<void*>(destination));
00216         success = checkAddressRange(address, readLength);
00217         if (success) success = setMemoryPointer(address, true);
00218         if (success)
00219         {
00220             if (direct)
00221             {
00222                 success = _i2c.read(_sramAddressRead, destinationAsBytes, readLength) == 0;
00223             }
00224             else
00225             {
00226                 uint16_t addressPtr = address;
00227                 int destinationPtr = 0;
00228                 for (int i = 0; i < length; i++)
00229                 {
00230                     const int bufferSize = typeLength;
00231                     char buffer[bufferSize];
00232                     success = readBytes(addressPtr, buffer, bufferSize);
00233                     if (success)
00234                     {
00235                         memcpy(destinationAsBytes + destinationPtr, buffer, bufferSize);
00236                         addressPtr += typeLength;
00237                         destinationPtr += typeLength;
00238                     }
00239                     else
00240                     {
00241                         break;
00242                     }
00243                 }
00244             }
00245         }
00246         return success ? readLength : 0;
00247     }
00248 
00249     /** Writes bytes to the specified address.
00250     * @param address The 16 bit destination address
00251     * @param data Pointer to the data buffer to read from
00252     * @param length Data length
00253     *
00254     * @return
00255     *   true on success
00256     *   false on fail
00257     */
00258     bool writeBytes(uint16_t address, char *data, int length);
00259 
00260     /** Writes data to the SRAM. The first two bytes shall be the address.
00261     * @param data Pointer to the data buffer to read from
00262     * @param length Data length
00263     *
00264     * @return
00265     *   true on success
00266     *   false on fail
00267     */
00268     bool writeBytes(char *data, int length);
00269 
00270     /** Reads data from the specified address.
00271     * @param address The 16 bit source address
00272     * @param data Pointer to the data buffer to read to
00273     * @param length Data length
00274     *
00275     * @return
00276     *   true on success
00277     *   false on fail
00278     */
00279     bool readBytes(uint16_t address, char *data, int length);
00280 
00281     /** Reads data to the specified buffer. The first two bytes shall be the address. These bytes will be unchanged.
00282     * @param data Pointer to the data buffer to read to
00283     * @param length Data length
00284     *
00285     * @return
00286     *   true on success
00287     *   false on fail
00288     */
00289     bool readBytes(char *data, int length);
00290 
00291     /** Fills memory with the specified byte from the specified address
00292     * @param address The 16 bit destination address
00293     * @param data The byte to write
00294     * @param length Memory are to fill with the data byte
00295     *
00296     * @return
00297     *   true on success
00298     *   false on fail
00299     */
00300     bool fillMemory(uint16_t address, char data, int length);
00301 
00302     /** Fills the whole memory with the specified byte
00303     * @param data The byte to write
00304     *
00305     * @return
00306     *   true on success
00307     *   false on fail
00308     */
00309     bool fillMemory(char data);
00310 
00311     /** Continuously checks I2C EERAM device till ready or reaches timeout
00312     * @param timeout_ms Timeout for busy-wait I2C device polling
00313     *
00314     * @return
00315     *   true on ready
00316     *   false on timeout
00317     */
00318     bool isReady(int timeout_ms);
00319 
00320     /** Checks I2C EERAM device one time
00321     *
00322     * @return
00323     *   true on ready
00324     *   false on not ready
00325     */
00326     bool isReady();
00327 
00328     /** Store SRAM in EEPROM
00329     * @param block If true, busy waits for operation end.
00330     *
00331     * @return
00332     *   true on success
00333     *   false on fail
00334     */
00335     bool store(bool block);
00336 
00337     /** Recall SRAM from EEPROM
00338     * @param block If true, busy waits for operation end.
00339     *
00340     * @return
00341     *   true on success
00342     *   false on fail
00343     */
00344     bool recall(bool block);
00345 
00346     /** Reads status register
00347     *
00348     * @return
00349     *   true on success
00350     *   false on fail
00351     */
00352     bool readStatus();
00353 
00354     /** Gets status register
00355     *
00356     * @return The content of the 8 bit status register
00357     */
00358     inline uint8_t getStatus() const
00359     {
00360         return _status;
00361     }
00362 
00363     /** Writes the 8 bit status register to the I2C device
00364     * @param block If true, busy waits for operation end.
00365     *
00366     * @return
00367     *   true on success
00368     *   false on fail
00369     */
00370     bool writeStatus(bool block);
00371 
00372     /** Writes the 8 bit status register to the I2C device if changed
00373     * @param block If true, busy waits for operation end.
00374     */
00375     void writeStatusIfChanged(bool block);
00376 
00377     /** Sets protected memory area. The selected area will be write protected.
00378     * @param protectedMemoryArea The enum represents the area from NONE through upper 64, 32, 16, 8, 4, 2 to ALL
00379     * @param store If true, calls writeStatusIfChanged()
00380     */
00381     void setProtectedMemoryArea(ProtectedMemoryArea protectedMemoryArea, bool store = false);
00382 
00383     /** Gets protected memory area
00384     *   Have to call readStatus() to read register's fresh value.
00385     */
00386     ProtectedMemoryArea getProtectedMemoryArea();
00387 
00388     /** Gets Memory Modified
00389     *   Have to call readStatus() to read register's fresh value.
00390     * @return
00391     *   true The SRAM memory have been modified since the last store or recall operation
00392     *   false The SRAM memory have not been modified since the last store or recall operation
00393     */
00394     bool isMemoryModified();
00395 
00396     /** Sets Auto Store Enabled
00397     * @param enabled Auto store SRAM to EEPROM on power down enabled
00398     * @param store If true, calls writeStatusIfChanged()
00399     */
00400     void setAutoStoreEnabled(bool enabled, bool store = false);
00401 
00402     /** Gets Auto Store Enabled
00403     *   Have to call readStatus() to read register's fresh value.
00404     * @return
00405     *   true Auto Store is Enabled
00406     *   false Auto Store is not Enabled
00407     */
00408     bool isAutoStoreEnabled();
00409 
00410     /** Sets event detected
00411     * @param detected The value of the detected bit
00412     * @param store If true, calls writeStatusIfChanged()
00413     */
00414     void setEventDetected(bool detected, bool store);
00415 
00416     /** Gets event detected
00417     *   Have to call readStatus() to read register's fresh value.
00418     * @return
00419     *   true External store event detected (The HS pin pulled up)
00420     *   false External event not detected
00421     */
00422     bool isEventDetected();
00423 
00424     /** Prints the SRAM content from the given address to the given serial port in human readable format in 1-32 byte long lines
00425     * @param serial The port to print to
00426     */
00427     void dump(Serial &serial, uint16_t start, uint16_t length, int lineSize = 16);
00428 
00429     /** Prints the whole SRAM content to the given serial port in human readable format in 16 byte long lines
00430     * @param serial The port to print to
00431     */
00432     void dump(Serial &serial);
00433 
00434     /** Prints the 8 bit status register's contents to the given serial port in human readable format
00435     * @param serial The port to print to
00436     */
00437     void dumpRegisters(Serial &serial);
00438 
00439 private:
00440     static const uint8_t RW_BIT = 0;
00441     static const uint8_t A1_BIT = 2;
00442     static const uint8_t A2_BIT = 3;
00443     static const uint8_t STATUS_AM_BIT = 7;
00444     static const uint8_t STATUS_ASE_BIT = 1;
00445     static const uint8_t STATUS_EVENT_BIT = 0;
00446     static const uint8_t OPCODE_SRAM = 0b10100000;
00447     static const uint8_t OPCODE_CONTROL = 0b00110000;
00448     static const uint8_t REGISTER_STATUS = 0x0;
00449     static const uint8_t REGISTER_COMMAND = 0x55;
00450     static const uint8_t COMMAND_STORE = 0b00110011;
00451     static const uint8_t COMMAND_RECALL = 0b11011101;
00452     static const int TIME_RECALL_16_MS = 5;
00453     static const int TIME_RECALL_04_MS = 2;
00454     static const int TIME_STORE_16_MS = 25;
00455     static const int TIME_STORE_04_MS = 8;
00456     static const int TIME_STORE_STATUS_MS = 1;
00457     I2C &_i2c;
00458     uint16_t _memorySize;
00459     uint8_t _sramAddressWrite;
00460     uint8_t _sramAddressRead;
00461     uint8_t _controlAddressWrite;
00462     uint8_t _controlAddressRead;
00463     uint8_t _status;
00464     uint8_t _statusToWrite;
00465     void initialize(bool A1 = false, bool A2 = false);
00466     bool checkAddressRange(uint16_t start, uint16_t length);
00467     bool writeRegister(uint8_t registerAddress, uint8_t data);
00468     bool setMemoryPointer(uint16_t address, bool stop = true);
00469     bool setMemoryPointer(uint8_t address_0, uint8_t address_1, bool stop = true);
00470 };
00471 
00472 #endif //EERAM_h