Seiji Ainoguchi / SerialFlash

Dependents:   SerialFlashTest

Fork of SerialFlash by Seiji Ainoguchi

Revision:
0:d0117f54a7ee
Child:
1:385965a14c7c
diff -r 000000000000 -r d0117f54a7ee M25PDeviceImpl.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/M25PDeviceImpl.cpp	Tue Mar 01 15:44:13 2011 +0000
@@ -0,0 +1,255 @@
+#include "ISPI.h"
+#include <string.h>
+#include "M25PDeviceImpl.h"
+
+const M25PDeviceImpl::DeviceProperty* M25PDeviceImpl::findMatchDevice(ISPI* pSPI)
+{
+    int manufacturerId;
+    int memoryType;
+    int memoryCapacity;
+    readId(pSPI, manufacturerId, memoryType, memoryCapacity);
+
+    struct SupportedDevice
+    {
+        int manufacturerId;
+        int memoryType;
+        int memoryCapacity;
+        DeviceProperty property;
+    } static const supportedDevices[] =
+    {
+        //M25P16 16MBit (2MB)
+        { 0x20, 0x20, 0x15,
+            {
+              "M25P16",
+              16384 * 1024 / 8,
+              0xe3,
+            },
+        },
+        //M25P80 8MBit (1MB)
+        { 0x20, 0x20, 0x14,
+            {
+              "M25P80",
+              8192 * 1024 / 8,
+              0xe3,
+           },
+        },
+    };
+    int count = sizeof(supportedDevices) / sizeof(supportedDevices[0]);
+    for (int i = 0; i < count; ++i)
+    {
+        const SupportedDevice& device = supportedDevices[i];
+        if (device.manufacturerId == manufacturerId && device.memoryType == memoryType && device.memoryCapacity == memoryCapacity)
+        {
+            return &device.property;
+        }
+    }
+    return NULL;
+}
+
+bool M25PDeviceImpl::IsSupported(ISPI* pSPI)
+{
+    return findMatchDevice(pSPI) != NULL;
+}
+
+M25PDeviceImpl* M25PDeviceImpl::Create(ISPI* pSPI)
+{
+    const DeviceProperty* property = findMatchDevice(pSPI);
+    if (property == NULL)
+    {
+        return NULL;
+    }
+    return new M25PDeviceImpl(pSPI, *property);
+}
+
+M25PDeviceImpl::M25PDeviceImpl(ISPI* pSPI, const DeviceProperty& property)
+ : _pSPI(pSPI)
+ , _property(property)
+{
+    pSPI->ChangeCS(ISPI::High);
+    clearBlockProtection();
+}
+
+M25PDeviceImpl::~M25PDeviceImpl(void)
+{
+
+}
+
+void M25PDeviceImpl::readId(ISPI* pSPI, int& manufacturerId, int& memoryType, int& memoryCapacity)
+{
+    const static int DefaultOperationFrequency = 20000000;
+    pSPI->SetFrequency(DefaultOperationFrequency);
+
+    pSPI->ChangeCS(ISPI::Low);
+    pSPI->Write(0x9f);
+    manufacturerId = pSPI->Read();
+    memoryType = pSPI->Read();
+    memoryCapacity = pSPI->Read();
+    pSPI->ChangeCS(ISPI::High);
+}
+
+int M25PDeviceImpl::readStatusRegister(void)
+{
+    _pSPI->ChangeCS(ISPI::Low);
+    _pSPI->Write(0x05);
+    int result = _pSPI->Read();
+    _pSPI->ChangeCS(ISPI::High);
+    return result;
+}
+
+void M25PDeviceImpl::writeStatusRegister(int value)
+{
+    _pSPI->ChangeCS(ISPI::Low);
+    _pSPI->Write(0x01);
+    _pSPI->Write(value);
+    _pSPI->ChangeCS(ISPI::High);
+}
+
+void M25PDeviceImpl::writeEnable()
+{
+    _pSPI->ChangeCS(ISPI::Low);
+    _pSPI->Write(0x06);
+    _pSPI->ChangeCS(ISPI::High);
+}
+
+void M25PDeviceImpl::writeDisable()
+{
+    _pSPI->ChangeCS(ISPI::Low);
+    _pSPI->Write(0x04);
+    _pSPI->ChangeCS(ISPI::High);
+}
+
+void M25PDeviceImpl::clearBlockProtection(void)
+{
+    writeEnable();
+
+    int status = readStatusRegister();
+    status &= _property.blockProtectionMask;
+    writeStatusRegister(status);
+}
+
+std::string M25PDeviceImpl::GetDeviceName(void) const
+{
+    return _property.deviceName;
+}
+
+int M25PDeviceImpl::GetCapacity(void) const
+{
+    return _property.capacity;
+}
+
+int M25PDeviceImpl::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->ChangeCS(ISPI::Low);
+    _pSPI->Write(0x0b);
+    writeAddress(address);
+    _pSPI->Write(0xff);
+    _pSPI->Read(buffer, length);
+    _pSPI->ChangeCS(ISPI::High);
+    return length;
+}
+
+int M25PDeviceImpl::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;
+    }
+
+    int result = length;
+
+    const int pageSize = 256;
+    const int pageSizeMask = pageSize - 1;
+    const int pageAddressMask = ~pageSizeMask;
+
+    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);
+    }
+    return result;
+}
+
+void M25PDeviceImpl::BulkErase()
+{
+    writeEnable();
+
+    _pSPI->ChangeCS(ISPI::Low);
+    _pSPI->Write(0xc7);
+    _pSPI->ChangeCS(ISPI::High);
+    
+    while (readStatusRegister() & 0x01)
+        ;
+
+    clearBlockProtection();
+}
+
+void M25PDeviceImpl::writeAddress(int address)
+{
+    _pSPI->Write((address & 0xff0000) >> 16);
+    _pSPI->Write((address & 0xff00) >> 8);
+    _pSPI->Write(address & 0xff);
+}
+
+void M25PDeviceImpl::pageProgram(int address, const void* buffer)
+{
+    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);
+
+    while (readStatusRegister() & 0x01)
+        ;
+}