Seiji Ainoguchi / SerialFlash

Dependents:   SerialFlashTest

Fork of SerialFlash by Seiji Ainoguchi

M25PDeviceImpl.cpp

Committer:
s_ain
Date:
2011-03-01
Revision:
0:d0117f54a7ee
Child:
1:385965a14c7c

File content as of revision 0:d0117f54a7ee:

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