Seiji Ainoguchi / SerialFlash

Dependents:   SerialFlashTest

Fork of SerialFlash by Seiji Ainoguchi

SST25DeviceImpl.cpp

Committer:
s_ain
Date:
2011-03-02
Revision:
1:385965a14c7c
Parent:
0:d0117f54a7ee
Child:
2:6f8ab876b516

File content as of revision 1:385965a14c7c:

#include "ISPI.h"
#include <string.h>
#include "SST25DeviceImpl.h"

const SST25DeviceImpl::DeviceProperty* SST25DeviceImpl::findMatchDevice(ISPI* pSPI)
{
    int manufacturersId;
    int deviceId;
    readId(pSPI, manufacturersId, deviceId);

    struct SupportedDevice
    {
        int manufacturersId;
        int deviceId;
        DeviceProperty property;
    } static const supportedDevices[] =
    {
        //SST25xF512A 512KBit (64KByte)
        { 0xbf, 0x48,
            {
              "SST25xF512A",
              512 * 1024 / 8,
              0xf3,
              1,
              &SST25DeviceImpl::writeAAI,
              33000000
            },
        },
        //SST25xF010A 1MBit (128KByte)
        { 0xbf, 0x49,
            {
              "SST25xF010A",
              1024 * 1024 / 8,
              0xf3,
              1,
              &SST25DeviceImpl::writeAAI,
              33000000
           },
        },
        //SST25xF020A 2MBit (256KByte)
        { 0xbf, 0x43,
            {
              "SST25xF020A",
              2048 * 1024 / 8,
              0xf3,
              1,
              &SST25DeviceImpl::writeAAI,
              33000000
           },
        },
        //SST25xF040B 4MBit (512KByte)
        { 0xbf, 0x8d,
            {
              "SST25xF040B",
              4096 * 1024 / 8,
              0xe3,
              1,
              &SST25DeviceImpl::writeAAIWord,
              46000000
            },
        },
        //SST25xF080B 8MBit (1MByte)
        { 0xbf, 0x8e,
            {
              "SST25xF080B",
              8192 * 1024 / 8,
              0xe3,
              1,
              &SST25DeviceImpl::writeAAIWord,
              46000000
            },
        },
        //SST25xF016B 16MBit (2MByte)
        { 0xbf, 0x41,
            {
              "SST25xF016B",
              16384 * 1024 / 8,
              0xe3,
              1,
              &SST25DeviceImpl::writeAAIWord,
              46000000
            },
        },
        //SST25xF032B 32MBit (4MByte)
        { 0xbf, 0x4a,
            {
              "SST25xF032B",
              32768 * 1024 / 8,
              0xc3,
              1,
              &SST25DeviceImpl::writeAAIWord,
              46000000
            },
        },
        //SST25xF064C 64MBit (8MByte)
        { 0xbf, 0x4b,
            {
              "SST25xF064C",
              65536 * 1024 / 8,
              0xc3,              
              256,
              &SST25DeviceImpl::writePage,
              46000000
            },
        }
    };
    int count = sizeof(supportedDevices) / sizeof(supportedDevices[0]);
    for (int i = 0; i < count; ++i)
    {
        const SupportedDevice& device = supportedDevices[i];
        if (device.manufacturersId == manufacturersId && device.deviceId == deviceId)
        {
            return &device.property;
        }
    }
    return NULL;
}

bool SST25DeviceImpl::IsSupported(ISPI* pSPI)
{
    return findMatchDevice(pSPI) != NULL;
}

SST25DeviceImpl* SST25DeviceImpl::Create(ISPI* pSPI)
{
    const DeviceProperty* property = findMatchDevice(pSPI);
    if (property == NULL)
    {
        return NULL;
    }
    return new SST25DeviceImpl(pSPI, *property);
}

SST25DeviceImpl::SST25DeviceImpl(ISPI* pSPI, const DeviceProperty& property)
 : _pSPI(pSPI)
 , _property(property)
{
    _pSPI->ChangeCS(ISPI::High);
    _pSPI->SetFrequency(_property.operationClkHz);
}

SST25DeviceImpl::~SST25DeviceImpl(void)
{

}

void SST25DeviceImpl::readId(ISPI* pSPI, int& manufacturersId, int& deviceId)
{
    const static int DefaultOperationFrequency = 20000000;
    pSPI->SetFrequency(DefaultOperationFrequency);

    pSPI->ChangeCS(ISPI::Low);
    pSPI->Write(0x90);
    pSPI->Write(0x00);
    pSPI->Write(0x00);
    pSPI->Write(0x00);
    manufacturersId = pSPI->Read();
    deviceId = pSPI->Read();
    pSPI->ChangeCS(ISPI::High);
}

int SST25DeviceImpl::readStatusRegister(void)
{
    _pSPI->ChangeCS(ISPI::Low);
    _pSPI->Write(0x05);
    int result = _pSPI->Read();
    _pSPI->ChangeCS(ISPI::High);
    return result;
}

void SST25DeviceImpl::writeStatusRegister(int value)
{
    _pSPI->ChangeCS(ISPI::Low);
    _pSPI->Write(0x50);
    _pSPI->ChangeCS(ISPI::High);

    _pSPI->ChangeCS(ISPI::Low);
    _pSPI->Write(0x01);
    _pSPI->Write(value);
    _pSPI->ChangeCS(ISPI::High);
}

void SST25DeviceImpl::writeEnable()
{
    int status = readStatusRegister();
    status &= _property.blockProtectionMask;
    writeStatusRegister(status);

    _pSPI->ChangeCS(ISPI::Low);
    _pSPI->Write(0x06);
    _pSPI->ChangeCS(ISPI::High);
}

void SST25DeviceImpl::writeDisable()
{
    _pSPI->ChangeCS(ISPI::Low);
    _pSPI->Write(0x04);
    _pSPI->ChangeCS(ISPI::High);
}

void SST25DeviceImpl::waitForReady()
{
    while (readStatusRegister() & 0x01)
        ;
}

std::string SST25DeviceImpl::GetDeviceName(void) const
{
    return _property.deviceName;
}

int SST25DeviceImpl::GetCapacity(void) const
{
    return _property.capacity;
}

int SST25DeviceImpl::Read(int address, void* buffer, int length)
{
    if (address >= GetCapacity())
    {
        return 0;
    }
    if (address + length > GetCapacity())
    {
        length = GetCapacity() - address;
    }
    if (length == 0)
    {
        return 0;
    }

    _pSPI->SetFrequency(_property.operationClkHz);

    _pSPI->ChangeCS(ISPI::Low);
    _pSPI->Write(0x0b);
    writeAddress(address);
    _pSPI->Write(0xff);
    _pSPI->Read(buffer, length);
    _pSPI->ChangeCS(ISPI::High);
    return length;
}

int SST25DeviceImpl::Write(int address, const void* buffer, int length)
{
    if (address >= GetCapacity())
    {
        return 0;
    }
    if (address + length > GetCapacity())
    {
        length = GetCapacity() - address;
    }
    if (length == 0)
    {
        return 0;
    }
    (this->*_property.pfnWriter)(address, buffer, length);
    return length;
}

void SST25DeviceImpl::ChipErase()
{
    _pSPI->SetFrequency(_property.operationClkHz);

    writeEnable();

    _pSPI->ChangeCS(ISPI::Low);
    _pSPI->Write(0x60);
    _pSPI->ChangeCS(ISPI::High);
    waitForReady();
}

void SST25DeviceImpl::byteProgram(int address, int value)
{
    _pSPI->SetFrequency(_property.operationClkHz);

    writeEnable();

    _pSPI->ChangeCS(ISPI::Low);
    _pSPI->Write(0x02);
    writeAddress(address);
    _pSPI->Write(value);
    _pSPI->ChangeCS(ISPI::High);
    waitForReady();
}

void SST25DeviceImpl::beginAAIProgram(int address, int data)
{
    _pSPI->SetFrequency(_property.operationClkHz);

    writeEnable();

    _pSPI->ChangeCS(ISPI::Low);
    _pSPI->Write(0xaf);
    writeAddress(address);
    _pSPI->Write(data);
    _pSPI->ChangeCS(ISPI::High);
    waitForReady();
}

void SST25DeviceImpl::nextAAIProgram(int data)
{
    _pSPI->ChangeCS(ISPI::Low);
    _pSPI->Write(0xaf);
    _pSPI->Write(data);
    _pSPI->ChangeCS(ISPI::High);
    waitForReady();
}

void SST25DeviceImpl::endAAIProgram(void)
{
    _pSPI->ChangeCS(ISPI::Low);
    _pSPI->Write(0x04);
    _pSPI->ChangeCS(ISPI::High);
    waitForReady();
}

void SST25DeviceImpl::beginAAIWordProgram(int address, int data)
{
    _pSPI->SetFrequency(_property.operationClkHz);

    writeEnable();

    _pSPI->ChangeCS(ISPI::Low);
    _pSPI->Write(0xad);
    writeAddress(address);
    _pSPI->Write((data & 0xff00) >> 8);
    _pSPI->Write(data & 0xff);
    _pSPI->ChangeCS(ISPI::High);
    waitForReady();
}

void SST25DeviceImpl::nextAAIWordProgram(int data)
{
    _pSPI->ChangeCS(ISPI::Low);
    _pSPI->Write(0xad);
    _pSPI->Write((data & 0xff00) >> 8);
    _pSPI->Write(data & 0xff);
    _pSPI->ChangeCS(ISPI::High);
    waitForReady();
}

void SST25DeviceImpl::writeAddress(int address)
{
    _pSPI->Write((address & 0xff0000) >> 16);
    _pSPI->Write((address & 0xff00) >> 8);
    _pSPI->Write(address & 0xff);
}

void SST25DeviceImpl::pageProgram(int address, const void* buffer)
{
    _pSPI->SetFrequency(_property.operationClkHz);

    writeEnable();

    _pSPI->ChangeCS(ISPI::Low);
    _pSPI->Write(0x02);
    writeAddress(address);
    _pSPI->Write(buffer, 256);
    _pSPI->ChangeCS(ISPI::High);
    waitForReady();
}

void SST25DeviceImpl::writePage(int address, const void* buffer, int length)
{   
    int pageSize = _property.pageSize;
    int pageSizeMask = pageSize - 1;
    int pageAddressMask = ~pageSizeMask;

    if (length <= 0)
    {
        return;
    }
    const unsigned char* p = static_cast<const unsigned char*>(buffer);
    if ((address & pageSizeMask) != 0)
    {
        int readLen = address & pageSizeMask;
        int copyLen = pageSize - readLen;
        if (copyLen > length)
        {
            copyLen = length;
        }
        char buf[pageSize];
        int writeAddress = address & pageAddressMask;
        Read(writeAddress, buf, readLen);
        memcpy(&buf[address & pageSizeMask], buffer, copyLen);
        pageProgram(writeAddress, buf);
        p += readLen;
        address += pageSize - readLen;
        length -= copyLen;
    }
    while (length >= pageSize)
    {
        pageProgram(address, p);
        address += pageSize;
        p += pageSize;
        length -= pageSize;
    }
    if (length != 0)
    {
        char buf[pageSize];
        memcpy(buf, p, length);
        memset(&buf[length], 0xff, pageSize - length);
        pageProgram(address, buf);
    }
}

void SST25DeviceImpl::writeBytes(int address, const void* buffer, int length)
{
    const unsigned char* p = static_cast<const unsigned char*>(buffer);
    while (length-- >= 0)
    {
        byteProgram(address++, *p++);
    }
}

void SST25DeviceImpl::writeAAI(int address, const void* buffer, int length)
{
    if (length <= 0)
    {
        return;
    }

    const unsigned char* p = static_cast<const unsigned char*>(buffer);
    if (length < 2)
    {
        byteProgram(address, *p);
        return;
    }

    beginAAIProgram(address, *p++);
    while (--length != 0)
    {
        nextAAIProgram(*p++);
    }
    endAAIProgram();
}

void SST25DeviceImpl::writeAAIWord(int address, const void* buffer, int length)
{
    if (length <= 0)
    {
        return;
    }

    const unsigned char* p = static_cast<const unsigned char*>(buffer);
    if ((address & 0x1) != 0)
    {
        byteProgram(address++, *p++);
        length--;
    }

    if (length < 4)
    {
        writeBytes(address, p, length);
        return;
    }

    beginAAIWordProgram(address, (*p << 8) | *(p + 1)); 
    address += length & ~0x1;
    p += 2;
    length -= 2;

    do
    {
        nextAAIWordProgram((*p << 8) | *(p + 1));
        p += 2;
        length -= 2;
    } while (length >= 2);
    endAAIProgram();

    if (length != 0)
    {
        byteProgram(address, *p);
    }
}