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

Dependents:   EERAM_example

EERAM.cpp

Committer:
vargham
Date:
2017-04-27
Revision:
3:a869096d7a5d
Parent:
2:bdbf9de0e985
Child:
4:fd84e2f0d1de

File content as of revision 3:a869096d7a5d:

/**
* @file    EERAM.cpp
* @brief   mbed driver for Microchip I2C EERAM devices (47x04 and 47x16)
* @author  Mark Peter Vargha, vmp@varghamarkpeter.hu
* @version 1.2.0
*
* Copyright (c) 2017
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "EERAM.h"

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);

    _controlAddressWrite = OPCODE_CONTROL;
    _controlAddressWrite ^= (-A1 ^ _controlAddressWrite) & (1 << A1_BIT);
    _controlAddressWrite ^= (-A2 ^ _controlAddressWrite) & (1 << A2_BIT);
    _controlAddressRead = _controlAddressWrite;
    _controlAddressRead ^= (-true ^ _controlAddressWrite) & (1 << RW_BIT);
}

void EERAM::putAddressIntoBuffer(uint16_t address, char *data)
{
    MemoryAddress location;
    location.address = address;
    data[0] = location.bytes[1];
    data[1] = location.bytes[0];
}

bool EERAM::checkAddressRange(uint16_t start, uint16_t length)
{
    return start < _memorySize && start + length <= _memorySize && length > 0;
}

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)
    {
        success = _i2c.write(data[index]) == 1;
        index++;
    }
    _i2c.stop();
    return success;
}

bool EERAM::write(char *data, int length)
{
    bool success = false;
    success = _i2c.write(_sramAddressWrite, data, length) == 0;
    return success;
}

bool EERAM::read(uint16_t address, char *data, int length)
{
    bool success = checkAddressRange(address, length);
    if (success) success = setMemoryPointer(address, true);
    if (success)
    {
        success = _i2c.read(_sramAddressRead, data, length, false) == 0;
    }
    _i2c.stop();
    return success;
}

bool EERAM::read(char *data, int length)
{
    bool success = setMemoryPointer((uint8_t)data[1], (uint8_t)data[0], true);
    if (success)
    {
        success = _i2c.read(_sramAddressRead, data + 2, length - 2, 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;
}

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)
{
    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 EERAM::setEventDetected(bool detected, bool store)
{
    _statusToWrite ^= (-detected ^ _statusToWrite) & (1 << STATUS_EVENT_BIT);
    if (store) writeStatusIfChanged(false);
}

bool EERAM::isEventDetected()
{
    return (_status >> STATUS_EVENT_BIT) & 1;
}

bool EERAM::isReady()
{
    bool ready = false;
    _i2c.start();
    ready = _i2c.write(_controlAddressWrite) == 1;
    _i2c.stop();
    return ready;
}

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;
}

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");
    }
}

void EERAM::dump(Serial &serial)
{
    dump(serial, 0, _memorySize);
}

bool EERAM::setMemoryPointer(uint16_t address, bool stop)
{
    MemoryAddress location;
    location.address = address;
    return setMemoryPointer(location.bytes[0], location.bytes[1], stop);
}

bool EERAM::setMemoryPointer(uint8_t address_0, uint8_t address_1, bool stop)
{
    int result = 0;
    _i2c.start();
    result = _i2c.write(_sramAddressWrite);
    if (result == 1) result = _i2c.write(address_1);
    if (result == 1) result = _i2c.write(address_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;
}

bool EERAM::fillMemory(char data)
{
    return fillMemory(0, data, _memorySize);
}

void EERAM::dumpRegisters(Serial &serial)
{
    serial.printf("Status 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())
    {
    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");
    serial.printf("Memory Array Modified: %d\r\n", isMemoryModified());
}