Seiji Ainoguchi / SerialFlash

Dependents:   SerialFlashTest

Fork of SerialFlash by Seiji Ainoguchi

Revision:
0:d0117f54a7ee
Child:
1:385965a14c7c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SST25DeviceImpl.cpp	Tue Mar 01 15:44:13 2011 +0000
@@ -0,0 +1,478 @@
+#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);
+
+    const unsigned char* p = static_cast<const unsigned char*>(buffer);
+
+    writeEnable();
+
+    _pSPI->ChangeCS(ISPI::Low);
+    _pSPI->Write(0x02);
+    writeAddress(address);
+    _pSPI->Write(p, 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);
+    }
+}