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

Dependents:   EERAM_example

Revision:
1:6028bc22d82f
Parent:
0:19f9af07424a
Child:
2:bdbf9de0e985
--- a/EERAM.cpp	Tue Apr 25 15:05:37 2017 +0000
+++ b/EERAM.cpp	Tue Apr 25 16:22:53 2017 +0000
@@ -1,6 +1,6 @@
 /**
-* @file    eeram_main.cpp
-* @brief   Example program for Microchip I2C EERAM devices (47x04 and 47x16)
+* @file    EERAM.cpp
+* @brief   mbed driver for Microchip I2C EERAM devices (47x04 and 47x16)
 * @author  Mark Peter Vargha, vmp@varghamarkpeter.hu
 * @version 1.0.0
 *
@@ -19,126 +19,277 @@
 * limitations under the License.
 */
 
-#include "mbed.h"
 #include "EERAM.h"
 
-#define PIN_I2C_SDA PC_9
-#define PIN_I2C_SCL PA_8
-
-#define I2C_FREQUENCY 1000000
-
-Serial serial(PA_9, PA_10);  //Tx, Rx
-I2C i2c(PIN_I2C_SDA, PIN_I2C_SCL); //SDA, SCL
-EERAM eeram(i2c, 2048);
+void EERAM::initialize(bool A1, bool A2)
+{
+    _sramAddressWrite = OPCODE_SRAM;
+    _sramAddressWrite ^= (-A1 ^ _sramAddressWrite) & (1 << A1_BIT);
+    _sramAddressWrite ^= (-A2 ^ _sramAddressWrite) & (1 << A2_BIT);
+    _sramAddressRead = _sramAddressWrite;
+    _sramAddressRead ^= (-true ^ _sramAddressRead) & (1 << RW_BIT);
 
-void printI2C()
+    _controlAddressWrite = OPCODE_CONTROL;
+    _controlAddressWrite ^= (-A1 ^ _controlAddressWrite) & (1 << A1_BIT);
+    _controlAddressWrite ^= (-A2 ^ _controlAddressWrite) & (1 << A2_BIT);
+    _controlAddressRead = _controlAddressWrite;
+    _controlAddressRead ^= (-true ^ _controlAddressWrite) & (1 << RW_BIT);
+}
+
+bool EERAM::checkAddressRange(uint16_t start, uint16_t length)
 {
-    //0x41  Discovery Touch
-    //0x18  EERAM control
-    //0x50  EERAM memory
-
-    int error;
-    int address;
-    int nDevices = 0;
+    return start < _memorySize && start + length <= _memorySize && length > 0;
+}
 
-    serial.printf("Scanning I2C devices...\r\n");
-
-    for(address = 1; address < 127; address++ )
+bool EERAM::write(uint16_t address, char *data, int length)
+{
+    bool success = false;
+    success = checkAddressRange(address, length);
+    if (success) success = setMemoryPointer(address, false);
+    int index = 0;
+    while (index < length && success)
     {
-        i2c.start();
-        error = i2c.write(address << 1); //We shift it left because mbed takes in 8 bit addreses
-        i2c.stop();
-        if (error == 1)
-        {
-            serial.printf("I2C device found at address 0x%X\r\n", address); //Returns 7-bit addres
-            nDevices++;
-        }
+        success = _i2c.write(data[index]) == 1;
+        index++;
+    }
+    _i2c.stop();
+    return success;
+}
 
-    }
-    serial.printf("I2C scan finished.\r\n");
-    if (nDevices == 0)
+bool EERAM::read(uint16_t address, char *data, int length)
+{
+    bool success = checkAddressRange(address, length);
+    if (success) success = setMemoryPointer(address, true);
+    if (success)
     {
-        serial.printf("No I2C devices found.\r\n");
+        success = _i2c.read(_sramAddressRead, data, length, false) == 0;
     }
+    _i2c.stop();
+    return success;
+}
 
+bool EERAM::writeRegister(uint8_t registerAddress, uint8_t data)
+{
+    _i2c.start();
+    bool success = _i2c.write(_controlAddressWrite) == 1;
+    if (success) success = _i2c.write(registerAddress) == 1;
+    if (success) success = _i2c.write(data) == 1;
+    _i2c.stop();
+    return success;
 }
 
-void fillTestData(char data[], uint8_t start, int length)
+bool EERAM::store(bool block)
+{
+    bool success = writeRegister(REGISTER_COMMAND, COMMAND_STORE);
+    if (success && block)
+    {
+        isReady((_memorySize <= 512 ? TIME_STORE_04_MS: TIME_STORE_16_MS) * 2);
+    }
+    return success;
+}
+
+bool EERAM::recall(bool block)
+{
+    bool success = writeRegister(REGISTER_COMMAND, COMMAND_RECALL);
+    if (success && block)
+    {
+        isReady((_memorySize <= 512 ? TIME_RECALL_04_MS: TIME_RECALL_16_MS) * 2);
+    }
+    return success;
+}
+
+bool EERAM::readStatus()
+{
+    _i2c.start();
+    bool success = _i2c.write(_controlAddressRead) == 1;
+    if (success)
+    {
+        _status = _i2c.read(false);
+        _statusToWrite = _status;
+    }
+    _i2c.stop();
+    return success;
+}
+
+bool EERAM::writeStatus(bool block)
 {
-    for (int i = 0; i < length; i++) data[i] = start + i;
+    bool success = writeRegister(REGISTER_STATUS, _statusToWrite);
+    if (success)
+    {
+        _status = _statusToWrite;
+        if (block) isReady(TIME_STORE_STATUS_MS * 2);
+    }
+    return success;
+}
+
+void EERAM::writeStatusIfChanged(bool block)
+{
+    if (_statusToWrite != _status) writeStatus(block);
+}
+
+void EERAM::setProtectedMemoryArea(ProtectedMemoryArea protectedMemoryArea, bool store)
+{
+    const uint8_t mask = 0b00011100;
+    _statusToWrite = (_statusToWrite & ~mask) | ((protectedMemoryArea << 2) & mask);
+    if (store) writeStatusIfChanged(false);
+}
+
+ProtectedMemoryArea EERAM::getProtectedMemoryArea()
+{
+    return (ProtectedMemoryArea) ((_status >> 2) & ~(-1 << 3));
+}
+
+bool EERAM::isMemoryModified()
+{
+    return (_status >> STATUS_AM_BIT) & 1;
+}
+
+void EERAM::setAutoStoreEnabled(bool enabled, bool store)
+{
+    _statusToWrite ^= (-enabled ^ _statusToWrite) & (1 << STATUS_ASE_BIT);
+    if (store) writeStatusIfChanged(false);
+}
+
+bool EERAM::isAutoStoreEnabled()
+{
+    return (_status >> STATUS_ASE_BIT) & 1;
 }
 
-void eeramDataTest()
+void EERAM::setEventDetected(bool detected, bool store)
+{
+    _statusToWrite ^= (-detected ^ _statusToWrite) & (1 << STATUS_EVENT_BIT);
+    if (store) writeStatusIfChanged(false);
+}
+
+bool EERAM::isEventDetected()
 {
-    const int testDataLength = 16;
-    char data[testDataLength];
+    return (_status >> STATUS_EVENT_BIT) & 1;
+}
 
-    //Write
-    //eeram.fillMemory(0xFF);
+bool EERAM::isReady()
+{
+    bool ready = false;
+    _i2c.start();
+    ready = _i2c.write(_controlAddressWrite) == 1;
+    _i2c.stop();
+    return ready;
+}
 
-    fillTestData(data, 0x0, testDataLength);
-    serial.printf("Write %d bytes to 0x0: %d\r\n", testDataLength, eeram.write(0x0, data, testDataLength));
+bool EERAM::isReady(int timeout_ms)
+{
+    bool ready = false;
+    Timer timeoutTimer;
+    timeoutTimer.start();
+    while (!ready && timeoutTimer.read_ms() < timeout_ms)
+    {
+        ready = isReady();
+        if (ready)
+        {
+            break;
+        }
+    }
+    return ready;
+}
 
-    fillTestData(data, 0x50, testDataLength);
-    serial.printf("Write %d bytes to 0x500: %d\r\n", testDataLength, eeram.write(0x500, data, testDataLength));
-
-    fillTestData(data, 0x70, testDataLength);
-    serial.printf("Write %d bytes to 0x700: %d\r\n", testDataLength, eeram.write(0x700, data, testDataLength));
+void EERAM::dump(Serial &serial, uint16_t start, uint16_t length, int lineSize)
+{
+    const int lineMaxSize = 32;
+    if (!checkAddressRange(start, length) || lineSize > lineMaxSize)
+    {
+        serial.printf("Invalid parameters for memory dump.\r\n");
+        return;
+    }
+    if (!setMemoryPointer(start, true))
+    {
+        serial.printf("Could not set start address for memory dump.\r\n");
+        return;
+    }
+    char buffer[lineMaxSize];
+    int lastLineLength = length % lineSize;
+    int segments = length / lineSize + (lastLineLength > 0 ? 1 : 0);
+    lastLineLength = lastLineLength == 0 ? lineSize : lastLineLength;
+    for (int i = 0; i < segments; i++)
+    {
+        serial.printf("%.4X", start + lineSize * i);
+        _i2c.read(_sramAddressRead, buffer, lineSize, false);
+        for (int j = 0; j < (i == segments - 1 ? lastLineLength : lineSize); j++)
+        {
+            serial.printf(" %.2X", buffer[j]);
+        }
+        serial.printf("\r\n");
+    }
+}
 
-    //Dump
-    serial.printf("Dump contents 0x0, 16\r\n");
-    eeram.dump(serial, 0x0, testDataLength);
-    serial.printf("Dump contents 0x500, 16\r\n");
-    eeram.dump(serial, 0x500, testDataLength);
-    serial.printf("Dump contents 0x700, 16\r\n");
-    eeram.dump(serial, 0x700, testDataLength);
-    //serial.printf("Dump all\r\n");
-    //eeram.dump(serial);
-    serial.printf("Dump done\r\n");
+void EERAM::dump(Serial &serial)
+{
+    dump(serial, 0, _memorySize);
+}
+
+bool EERAM::setMemoryPointer(uint16_t address, bool stop)
+{
+    int result = 0;
+    MemoryAddress location;
+    location.address = address;
+    _i2c.start();
+    result = _i2c.write(_sramAddressWrite);
+    if (result == 1) result = _i2c.write(location.bytes[1]);
+    if (result == 1) result = _i2c.write(location.bytes[0]);
+    if (stop) _i2c.stop();
+    return result == 1;
+}
+
+bool EERAM::fillMemory(uint16_t address, char data, int length)
+{
+    int result = 0;
+    result = setMemoryPointer(address, false) ? 1 : 0;
+    int index = 0;
+    while (index < length && result == 1)
+    {
+        result = _i2c.write(data);
+        index++;
+    }
+    _i2c.stop();
+    return result == 1;
+}
 
-    //Read back
-    fillTestData(data, 0x0, testDataLength);
-    serial.printf("Read back 16 bytes from 0x500: %d\r\n", eeram.read(0x500, data, testDataLength));
-    serial.printf("%.4X ", 0x500);
-    for (int i = 0; i < testDataLength; i++)
+bool EERAM::fillMemory(char data)
+{
+    return fillMemory(0, data, _memorySize);
+}
+
+void EERAM::dumpRegisters(Serial &serial)
+{
+    serial.printf("Control Register Contents\r\n");
+    serial.printf("Event detected: %d\r\n", isEventDetected());
+    serial.printf("Auto Store Enabled: %d\r\n", isAutoStoreEnabled());
+    serial.printf("Protected area: %d = ", getProtectedMemoryArea());
+    switch (getProtectedMemoryArea())
     {
-        serial.printf("%.2X ", data[i]);
+    case NONE:
+        serial.printf("None");
+        break;
+    case U64:
+        serial.printf("U64");
+        break;
+    case U32:
+        serial.printf("U32");
+        break;
+    case U16:
+        serial.printf("U16");
+        break;
+    case U8:
+        serial.printf("U8");
+        break;
+    case U4:
+        serial.printf("U4");
+        break;
+    case U2:
+        serial.printf("U2");
+        break;
+    case ALL:
+        serial.printf("All");
+        break;
     }
     serial.printf("\r\n");
-}
-
-void eeramRegisterTest()
-{
-    eeram.dumpRegisters(serial);
+    serial.printf("Memory Array Modified: %d\r\n", isMemoryModified());
 }
-
-int main()
-{
-    serial.baud(460800);
-    i2c.frequency(I2C_FREQUENCY); //Hz
-    serial.printf("\r\nI2C EERAM example\r\n");
-
-    //printI2C();
-
-    serial.printf("Is EERAM device ready?\r\n");
-    while (!eeram.isReady());
-    serial.printf("Device is ready.\r\n");
-
-    eeram.readStatus();
-    eeram.setAutoStoreEnabled(true);
-    eeram.setProtectedMemoryArea(U64);
-    eeram.writeStatusIfChanged(true);
-    serial.printf("Status: %.2X\r\n", eeram.getStatus());
-
-    eeramDataTest();
-
-    eeramRegisterTest();
-
-    //eeram.store(true);
-    //eeram.recall(true);
-
-    while (true)
-    {
-
-    }
-}