Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of SerialFlash by
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)
;
}
