unknown work 1
This commit is contained in:
parent
935911fd2c
commit
32bdb169b7
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -16,6 +16,9 @@
|
|||||||
"tuple": "cpp",
|
"tuple": "cpp",
|
||||||
"type_traits": "cpp",
|
"type_traits": "cpp",
|
||||||
"vector": "cpp",
|
"vector": "cpp",
|
||||||
"string": "cpp"
|
"string": "cpp",
|
||||||
|
"__string": "cpp",
|
||||||
|
"string_view": "cpp",
|
||||||
|
"__split_buffer": "cpp"
|
||||||
}
|
}
|
||||||
}
|
}
|
8
Makefile
8
Makefile
@ -645,6 +645,14 @@ OBJECTS += ./src/drivers/MPU6000.o
|
|||||||
OBJECTS += ./src/drivers/MS5611.o
|
OBJECTS += ./src/drivers/MS5611.o
|
||||||
OBJECTS += ./src/drivers/stepper.o
|
OBJECTS += ./src/drivers/stepper.o
|
||||||
OBJECTS += ./src/drivers/servo.o
|
OBJECTS += ./src/drivers/servo.o
|
||||||
|
OBJECTS += ./src/drivers/SerialFlash/M25PDevice.o
|
||||||
|
OBJECTS += ./src/drivers/SerialFlash/M25PDeviceImpl.o
|
||||||
|
OBJECTS += ./src/drivers/SerialFlash/MbedSPICommand.o
|
||||||
|
OBJECTS += ./src/drivers/SerialFlash/SerialFlashDeviceCreator.o
|
||||||
|
OBJECTS += ./src/drivers/SerialFlash/SST25Device.o
|
||||||
|
OBJECTS += ./src/drivers/SerialFlash/SST25DeviceImpl.o
|
||||||
|
OBJECTS += ./src/drivers/M25P16.o
|
||||||
|
OBJECTS += ./src/drivers/SpiFlash25.o
|
||||||
OBJECTS += ./src/control/ImuFusion.o
|
OBJECTS += ./src/control/ImuFusion.o
|
||||||
OBJECTS += ./src/control/PID.o
|
OBJECTS += ./src/control/PID.o
|
||||||
OBJECTS += ./src/math/Utilities.o
|
OBJECTS += ./src/math/Utilities.o
|
||||||
|
Binary file not shown.
128
main.cpp
128
main.cpp
@ -14,10 +14,15 @@
|
|||||||
#include "src/drivers/MPU6000.h"
|
#include "src/drivers/MPU6000.h"
|
||||||
#include "src/drivers/stepper.h"
|
#include "src/drivers/stepper.h"
|
||||||
#include "src/drivers/servo.h"
|
#include "src/drivers/servo.h"
|
||||||
|
#include "src/drivers/M25P16.h"
|
||||||
// Control
|
// Control
|
||||||
#include "src/control/lpf.h"
|
#include "src/control/lpf.h"
|
||||||
#include "src/control/PID.h"
|
#include "src/control/PID.h"
|
||||||
#include "src/control/ImuFusion.h"
|
#include "src/control/ImuFusion.h"
|
||||||
|
// Flash Memory - TODO: This component is not correctly implemented yet
|
||||||
|
#include "src/drivers/SerialFlash/MbedSPICommand.h"
|
||||||
|
#include "src/drivers/SerialFlash/SerialFlashDeviceCreator.h"
|
||||||
|
#include "src/drivers/SpiFlash25.h"
|
||||||
|
|
||||||
#define WHEEL_SIZE 0.09f
|
#define WHEEL_SIZE 0.09f
|
||||||
|
|
||||||
@ -32,8 +37,14 @@ EventQueue queue;
|
|||||||
Serial serialMotorOutputs(PA_2, PA_3, 115200);
|
Serial serialMotorOutputs(PA_2, PA_3, 115200);
|
||||||
|
|
||||||
// MPU setup
|
// MPU setup
|
||||||
SPI spi(PA_7, PA_6, PA_5); //define the SPI (mosi, miso, sclk). Default frequency is 1Mhz
|
SPI spiImu(PA_7, PA_6, PA_5); //define the SPI (mosi, miso, sclk). Default frequency is 1Mhz
|
||||||
mpu6000_spi imu(spi,PA_4); //define the mpu6000 object
|
mpu6000_spi imu(spiImu,PA_4); //define the mpu6000 object
|
||||||
|
|
||||||
|
// Flash setup
|
||||||
|
//SPI spiFlash(PC_12, PC_11, PC_10, PA_15);
|
||||||
|
//SPI spiFlash(PC_12, PC_11, PC_10, PB_3);
|
||||||
|
//M25P16 memory(spiFlash, PB_3);
|
||||||
|
//DigitalOut radioCS(PA_15);
|
||||||
|
|
||||||
PwmOut ledBlue(D4);
|
PwmOut ledBlue(D4);
|
||||||
DigitalOut ledOrg(D5);
|
DigitalOut ledOrg(D5);
|
||||||
@ -48,7 +59,7 @@ InterruptIn gyroINT(PC_4);
|
|||||||
|
|
||||||
Timer timer;
|
Timer timer;
|
||||||
|
|
||||||
// TODO: Figure out some good values
|
// Throttle PI Controller with some acceptable values
|
||||||
controllerPI throttleControl(0.0025, 0.01, 5, 0); // 0.065, 0.05, 12, 40
|
controllerPI throttleControl(0.0025, 0.01, 5, 0); // 0.065, 0.05, 12, 40
|
||||||
|
|
||||||
// TODO: Figure out some good values
|
// TODO: Figure out some good values
|
||||||
@ -174,6 +185,74 @@ void pulseLedContext()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testFlash()
|
||||||
|
{
|
||||||
|
ISPICommand* pSPICommand = new MbedSPICommand(PC_12, PC_11, PC_10, PB_3); // MOSI, MISO, SCK, CS
|
||||||
|
ISerialFlashDevice* pDevice = SerialFlashDeviceCreator::Create(pSPICommand);
|
||||||
|
|
||||||
|
if (pDevice == NULL)
|
||||||
|
{
|
||||||
|
printf("Unsupported device");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::string deviceName = pDevice->GetDeviceName();
|
||||||
|
// printf("%s\n", deviceName);
|
||||||
|
int capacity = pDevice->GetCapacity() / 1024;
|
||||||
|
printf("%dK x 8\n", capacity);
|
||||||
|
|
||||||
|
// int *a[3];
|
||||||
|
// *a[0] = 1;
|
||||||
|
// *a[1] = 2;
|
||||||
|
// *a[2] = 3;
|
||||||
|
|
||||||
|
// int *b[3];
|
||||||
|
|
||||||
|
int result;
|
||||||
|
|
||||||
|
// result = pDevice->Write(100, a, sizeof(a));
|
||||||
|
|
||||||
|
// result = pDevice->Read(100, b, sizeof(b));
|
||||||
|
|
||||||
|
uint8_t c(-1), d(0);
|
||||||
|
|
||||||
|
result = pDevice->Read(200, &c, sizeof(c));
|
||||||
|
|
||||||
|
wait(1);
|
||||||
|
|
||||||
|
c += 4;
|
||||||
|
|
||||||
|
result = pDevice->Write(200, &c, sizeof(c));
|
||||||
|
|
||||||
|
wait(1);
|
||||||
|
|
||||||
|
result = pDevice->Read(200, &d, sizeof(d));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void testFlash2()
|
||||||
|
{
|
||||||
|
SpiFlash25 flash(PC_12, PC_11, PC_10, PB_3);
|
||||||
|
|
||||||
|
char* k = flash.read_id();
|
||||||
|
|
||||||
|
char f = flash.read_status();
|
||||||
|
|
||||||
|
char a[] = "Hej och ha";
|
||||||
|
|
||||||
|
bool result;
|
||||||
|
|
||||||
|
result = flash.write(0, strlen(a), a);
|
||||||
|
|
||||||
|
char b[20];
|
||||||
|
|
||||||
|
result = flash.read(0, strlen(a), b);
|
||||||
|
|
||||||
|
printf("result");
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// main() runs in its own thread
|
// main() runs in its own thread
|
||||||
int main() {
|
int main() {
|
||||||
|
|
||||||
@ -182,6 +261,49 @@ int main() {
|
|||||||
Thread serialThread;
|
Thread serialThread;
|
||||||
serialThread.start(callback(&readSerialContext));
|
serialThread.start(callback(&readSerialContext));
|
||||||
|
|
||||||
|
// Init memory
|
||||||
|
DigitalOut radioCS(PA_15);
|
||||||
|
radioCS = 1; // Disable radio chip. May not be necessary
|
||||||
|
//SPI spiFlash(PC_12, PC_11, PC_10);
|
||||||
|
|
||||||
|
testFlash2();
|
||||||
|
|
||||||
|
// M25P16 memory(spiFlash, PB_3);
|
||||||
|
// bool memoryUp = memory.init();
|
||||||
|
|
||||||
|
//printf("Initialization of onboard memory " + memoryUp ? "succeded" : "failed");
|
||||||
|
|
||||||
|
//memory.chipErase();
|
||||||
|
int start = 0;
|
||||||
|
|
||||||
|
int values[3];
|
||||||
|
//memory.read(start, &values, sizeof(values));
|
||||||
|
|
||||||
|
|
||||||
|
values[0]++;
|
||||||
|
//values[1]++;
|
||||||
|
values[2]++;
|
||||||
|
|
||||||
|
//memory.write(start, values, sizeof(values));
|
||||||
|
|
||||||
|
|
||||||
|
// int values2[3];
|
||||||
|
// memory.read(start, values2, sizeof(values2));
|
||||||
|
|
||||||
|
// memory.read(0, values2, sizeof(values2));
|
||||||
|
|
||||||
|
// values[0]++;
|
||||||
|
// values[1]++;
|
||||||
|
// values[2]++;
|
||||||
|
|
||||||
|
// start += sizeof(values);
|
||||||
|
// memory.write(0, values, sizeof(values));
|
||||||
|
|
||||||
|
// memory.read(0, values2, sizeof(values2));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// MPU startup at 100hz
|
// MPU startup at 100hz
|
||||||
if(imu.init(10,BITS_DLPF_CFG_188HZ)){
|
if(imu.init(10,BITS_DLPF_CFG_188HZ)){
|
||||||
printf("\nCouldn't initialize MPU6000 via SPI!");
|
printf("\nCouldn't initialize MPU6000 via SPI!");
|
||||||
|
259
src/drivers/M25P16.cpp
Normal file
259
src/drivers/M25P16.cpp
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
#include "M25P16.h"
|
||||||
|
|
||||||
|
namespace drivers {
|
||||||
|
|
||||||
|
M25P16::M25P16(SPI& spi, PinName cs)
|
||||||
|
: m_spi(spi)
|
||||||
|
, m_cs(cs)
|
||||||
|
, m_property()
|
||||||
|
{
|
||||||
|
m_property.deviceName = "M25P16";
|
||||||
|
m_property.capacity = 16384 * 1024 / 8;
|
||||||
|
m_property.blockProtectionMask = 0xe3;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool M25P16::init()
|
||||||
|
{
|
||||||
|
//clearBlockProtection();
|
||||||
|
|
||||||
|
int manufacturerId;
|
||||||
|
int memoryType;
|
||||||
|
int memoryCapacity;
|
||||||
|
|
||||||
|
readId(manufacturerId, memoryType, memoryCapacity);
|
||||||
|
|
||||||
|
clearBlockProtection();
|
||||||
|
|
||||||
|
// If we get the expected values from the bus then we are good
|
||||||
|
return manufacturerId == 0x20
|
||||||
|
&& memoryType == 0x20
|
||||||
|
&& memoryCapacity == 0x15;
|
||||||
|
}
|
||||||
|
|
||||||
|
void M25P16::readId(int& manufacturerId, int& memoryType, int& memoryCapacity)
|
||||||
|
{
|
||||||
|
m_spi.frequency(46000000);
|
||||||
|
|
||||||
|
unsigned char id[3];
|
||||||
|
readSPI(0x9f, id, sizeof(id));
|
||||||
|
manufacturerId = id[0];
|
||||||
|
memoryType = id[1];
|
||||||
|
memoryCapacity = id[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
int M25P16::read(int address, void* buffer, int length)
|
||||||
|
{
|
||||||
|
if (address >= getCapacity())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (address + length > getCapacity())
|
||||||
|
{
|
||||||
|
length = getCapacity() - address;
|
||||||
|
}
|
||||||
|
if (length == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char param[] = {0, 0, 0, 0xff};
|
||||||
|
fillAddress(param, address);
|
||||||
|
readSPI(0x0b, param, sizeof(param), buffer, length);
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
void M25P16::fillAddress(char* pBuffer, int address)
|
||||||
|
{
|
||||||
|
*(pBuffer + 0) = (address & 0xff0000) >> 16;
|
||||||
|
*(pBuffer + 1) = (address & 0x00ff00) >> 8;
|
||||||
|
*(pBuffer + 2) = (address & 0x0000ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
int M25P16::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 M25P16::select()
|
||||||
|
{
|
||||||
|
m_cs = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void M25P16::deselect()
|
||||||
|
{
|
||||||
|
m_cs = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int M25P16::whoami()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int M25P16::getCapacity() const
|
||||||
|
{
|
||||||
|
return m_property.capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string M25P16::getDeviceName() const
|
||||||
|
{
|
||||||
|
return m_property.deviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
int M25P16::readStatusRegister(void)
|
||||||
|
{
|
||||||
|
unsigned char status;
|
||||||
|
readSPI(0x05, &status, 1);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void M25P16::writeStatusRegister(int value)
|
||||||
|
{
|
||||||
|
char vb = static_cast<char>(value);
|
||||||
|
writeSPI(0x01, &vb, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void M25P16::writeEnable()
|
||||||
|
{
|
||||||
|
writeSPI(0x06);
|
||||||
|
}
|
||||||
|
|
||||||
|
void M25P16::writeDisable()
|
||||||
|
{
|
||||||
|
writeSPI(0x04);
|
||||||
|
}
|
||||||
|
|
||||||
|
void M25P16::clearBlockProtection()
|
||||||
|
{
|
||||||
|
writeEnable();
|
||||||
|
|
||||||
|
int status = readStatusRegister();
|
||||||
|
status &= m_property.blockProtectionMask;
|
||||||
|
writeStatusRegister(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
void M25P16::writeSPI(int command)
|
||||||
|
{
|
||||||
|
m_cs = 0;
|
||||||
|
m_spi.write(command);
|
||||||
|
m_cs = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void M25P16::writeSPI(int command, const void* pParam, int length)
|
||||||
|
{
|
||||||
|
m_cs = 0;
|
||||||
|
m_spi.write(command);
|
||||||
|
|
||||||
|
const char*p = static_cast<const char*>(pParam);
|
||||||
|
for (int i = 0; i < length; ++i)
|
||||||
|
{
|
||||||
|
m_spi.write(*p++);
|
||||||
|
}
|
||||||
|
m_cs = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void M25P16::readSPI(int command, void* pRead, int readLength)
|
||||||
|
{
|
||||||
|
m_cs = 0;
|
||||||
|
m_spi.write(command);
|
||||||
|
|
||||||
|
char* pReadByte = static_cast<char*>(pRead);
|
||||||
|
for (int i = 0; i < readLength; ++i)
|
||||||
|
{
|
||||||
|
*pReadByte++ = m_spi.write(0xff);
|
||||||
|
}
|
||||||
|
m_cs = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void M25P16::readSPI(int command, const void* pParam, int paramLength, void* pReaded, int readLength)
|
||||||
|
{
|
||||||
|
m_cs = 0;
|
||||||
|
m_spi.write(command);
|
||||||
|
|
||||||
|
const char* pParamByte = static_cast<const char*>(pParam);
|
||||||
|
for (int i = 0; i < paramLength; ++i)
|
||||||
|
{
|
||||||
|
m_spi.write(*pParamByte++);
|
||||||
|
}
|
||||||
|
char* pReadedByte = static_cast<char*>(pReaded);
|
||||||
|
for (int i = 0; i < readLength; ++i)
|
||||||
|
{
|
||||||
|
*pReadedByte++ = m_spi.write(0xff);
|
||||||
|
}
|
||||||
|
m_cs = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void M25P16::chipErase()
|
||||||
|
{
|
||||||
|
writeEnable();
|
||||||
|
|
||||||
|
writeSPI(0xc7);
|
||||||
|
|
||||||
|
while (readStatusRegister() & 0x01);
|
||||||
|
|
||||||
|
clearBlockProtection();
|
||||||
|
}
|
||||||
|
|
||||||
|
void M25P16::pageProgram(int address, const void* buffer)
|
||||||
|
{
|
||||||
|
writeEnable();
|
||||||
|
|
||||||
|
char param[256 + 3];
|
||||||
|
fillAddress(param, address);
|
||||||
|
memcpy(param + 3, buffer, 256);
|
||||||
|
writeSPI(0x02, param, sizeof(param));
|
||||||
|
|
||||||
|
while (readStatusRegister() & 0x01);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace drivers
|
74
src/drivers/M25P16.h
Normal file
74
src/drivers/M25P16.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#include "mbed.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace drivers {
|
||||||
|
|
||||||
|
class M25P16 {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
M25P16(SPI& spi, PinName cs);
|
||||||
|
|
||||||
|
bool init();
|
||||||
|
|
||||||
|
int read(int address, void* buffer, int length);
|
||||||
|
|
||||||
|
int write(int address, const void* buffer, int length);
|
||||||
|
|
||||||
|
void chipErase();
|
||||||
|
|
||||||
|
unsigned int whoami();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
SPI& m_spi;
|
||||||
|
DigitalOut m_cs;
|
||||||
|
|
||||||
|
struct DeviceProperty
|
||||||
|
{
|
||||||
|
std::string deviceName;
|
||||||
|
int capacity;
|
||||||
|
int blockProtectionMask;
|
||||||
|
} m_property;
|
||||||
|
|
||||||
|
// Returns the size of the memory
|
||||||
|
int getCapacity() const;
|
||||||
|
|
||||||
|
void readId(int& manufacturerId, int& memoryType, int& memoryCapacity);
|
||||||
|
|
||||||
|
std::string getDeviceName() const;
|
||||||
|
|
||||||
|
void fillAddress(char* pBuffer, int address);
|
||||||
|
|
||||||
|
int readStatusRegister();
|
||||||
|
|
||||||
|
void writeStatusRegister(int value);
|
||||||
|
|
||||||
|
void writeEnable();
|
||||||
|
|
||||||
|
void writeDisable();
|
||||||
|
|
||||||
|
void clearBlockProtection();
|
||||||
|
|
||||||
|
void select();
|
||||||
|
|
||||||
|
void deselect();
|
||||||
|
|
||||||
|
void writeSPI(int command);
|
||||||
|
|
||||||
|
void writeSPI(int command, const void* pParam, int length);
|
||||||
|
|
||||||
|
void readSPI(int command, void* pRead, int readLength);
|
||||||
|
|
||||||
|
void readSPI(int command, const void* pParam, int paramLength, void* pReaded, int readLength);
|
||||||
|
|
||||||
|
void pageProgram(int address, const void* buffer);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MYBIT 0x00
|
||||||
|
|
||||||
|
} // namespace drivers
|
26
src/drivers/SPICommand/main.cpp
Normal file
26
src/drivers/SPICommand/main.cpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include "mbed.h"
|
||||||
|
#include "MbedSPICommand.h"
|
||||||
|
#include "SerialFlashDeviceCreator.h"
|
||||||
|
|
||||||
|
DigitalOut myled(LED1);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
ISPICommand* pSPICommand = new MbedSPICommand(p11, p12, p13, p14); // MOSI, MISO, SCK, CS
|
||||||
|
|
||||||
|
ISerialFlashDevice* pDevice = SerialFlashDeviceCreator::Create(pSPICommand);
|
||||||
|
if (pDevice == NULL)
|
||||||
|
{
|
||||||
|
printf("Unsupported device");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("%s\n", pDevice->GetDeviceName());
|
||||||
|
printf("%dK x 8\n", pDevice->GetCapacity() / 1024);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
myled = 1;
|
||||||
|
wait(0.2);
|
||||||
|
myled = 0;
|
||||||
|
wait(0.2);
|
||||||
|
}
|
||||||
|
}
|
1
src/drivers/SPICommand/mbed.bld
Normal file
1
src/drivers/SPICommand/mbed.bld
Normal file
@ -0,0 +1 @@
|
|||||||
|
http://mbed.org/users/mbed_official/code/mbed/builds/6473597d706e
|
14
src/drivers/SerialFlash/ISPICommand.h
Normal file
14
src/drivers/SerialFlash/ISPICommand.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class ISPICommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual ~ISPICommand() {}
|
||||||
|
virtual void SetMaxFrequency(int frequency) = 0;
|
||||||
|
|
||||||
|
virtual void Write(int command) = 0;
|
||||||
|
virtual void Write(int command, const void* pParam, int length) = 0;
|
||||||
|
virtual void Read(int command, void* pReaded, int readLength) = 0;
|
||||||
|
virtual void Read(int command, const void* pParam, int paramLength, void* pReaded, int readLength) = 0;
|
||||||
|
};
|
14
src/drivers/SerialFlash/ISerialFlashDevice.h
Normal file
14
src/drivers/SerialFlash/ISerialFlashDevice.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class ISerialFlashDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~ISerialFlashDevice(void) { }
|
||||||
|
virtual std::string GetDeviceName(void) const = 0;
|
||||||
|
virtual int GetCapacity(void) const = 0;
|
||||||
|
virtual void ChipErase(void) = 0;
|
||||||
|
virtual int Read(int address, void* buffer, int length) = 0;
|
||||||
|
virtual int Write(int address, const void* buffer, int length) = 0;
|
||||||
|
};
|
50
src/drivers/SerialFlash/M25PDevice.cpp
Normal file
50
src/drivers/SerialFlash/M25PDevice.cpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#include "mbed.h"
|
||||||
|
#include "M25PDeviceImpl.h"
|
||||||
|
#include "M25PDevice.h"
|
||||||
|
|
||||||
|
bool M25PDevice::IsSupported(ISPICommand* pSPICommand)
|
||||||
|
{
|
||||||
|
return M25PDeviceImpl::IsSupported(pSPICommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
M25PDevice* M25PDevice::Create(ISPICommand* pSPICommand)
|
||||||
|
{
|
||||||
|
M25PDeviceImpl* pImpl = M25PDeviceImpl::Create(pSPICommand);
|
||||||
|
if (pImpl == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return new M25PDevice(pImpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
M25PDevice::M25PDevice(M25PDeviceImpl* pImpl)
|
||||||
|
: _pImpl(pImpl)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
string M25PDevice::GetDeviceName(void) const
|
||||||
|
{
|
||||||
|
return _pImpl->GetDeviceName();
|
||||||
|
}
|
||||||
|
|
||||||
|
int M25PDevice::GetCapacity(void) const
|
||||||
|
{
|
||||||
|
return _pImpl->GetCapacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
void M25PDevice::ChipErase(void)
|
||||||
|
{
|
||||||
|
_pImpl->BulkErase();
|
||||||
|
}
|
||||||
|
|
||||||
|
int M25PDevice::Read(int address, void* buffer, int length)
|
||||||
|
{
|
||||||
|
return _pImpl->Read(address, buffer, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
int M25PDevice::Write(int address, const void* buffer, int length)
|
||||||
|
{
|
||||||
|
return _pImpl->Write(address, buffer, length);
|
||||||
|
}
|
25
src/drivers/SerialFlash/M25PDevice.h
Normal file
25
src/drivers/SerialFlash/M25PDevice.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include "ISerialFlashDevice.h"
|
||||||
|
|
||||||
|
class ISPICommand;
|
||||||
|
class M25PDeviceImpl;
|
||||||
|
|
||||||
|
class M25PDevice : public ISerialFlashDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static M25PDevice* Create(ISPICommand* pSPICommand);
|
||||||
|
static bool IsSupported(ISPICommand* pSPICommand);
|
||||||
|
|
||||||
|
virtual std::string GetDeviceName(void) const;
|
||||||
|
virtual int GetCapacity(void) const;
|
||||||
|
virtual void ChipErase(void);
|
||||||
|
virtual int Read(int address, void* buffer, int length);
|
||||||
|
virtual int Write(int address, const void* buffer, int length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::auto_ptr<M25PDeviceImpl> _pImpl;
|
||||||
|
M25PDevice(M25PDeviceImpl* pImpl);
|
||||||
|
};
|
235
src/drivers/SerialFlash/M25PDeviceImpl.cpp
Normal file
235
src/drivers/SerialFlash/M25PDeviceImpl.cpp
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
#include "ISPICommand.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include "M25PDeviceImpl.h"
|
||||||
|
|
||||||
|
const M25PDeviceImpl::DeviceProperty* M25PDeviceImpl::findMatchDevice(ISPICommand* pSPICommand)
|
||||||
|
{
|
||||||
|
int manufacturerId;
|
||||||
|
int memoryType;
|
||||||
|
int memoryCapacity;
|
||||||
|
readId(pSPICommand, 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(ISPICommand* pSPICommand)
|
||||||
|
{
|
||||||
|
return findMatchDevice(pSPICommand) != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
M25PDeviceImpl* M25PDeviceImpl::Create(ISPICommand* pSPICommand)
|
||||||
|
{
|
||||||
|
const DeviceProperty* property = findMatchDevice(pSPICommand);
|
||||||
|
if (property == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return new M25PDeviceImpl(pSPICommand, *property);
|
||||||
|
}
|
||||||
|
|
||||||
|
M25PDeviceImpl::M25PDeviceImpl(ISPICommand* pSPICommand, const DeviceProperty& property)
|
||||||
|
: _pSPICommand(pSPICommand)
|
||||||
|
, _property(property)
|
||||||
|
{
|
||||||
|
clearBlockProtection();
|
||||||
|
}
|
||||||
|
|
||||||
|
M25PDeviceImpl::~M25PDeviceImpl(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void M25PDeviceImpl::readId(ISPICommand* pSPICommand, int& manufacturerId, int& memoryType, int& memoryCapacity)
|
||||||
|
{
|
||||||
|
const static int DefaultOperationFrequency = 20000000;
|
||||||
|
pSPICommand->SetMaxFrequency(DefaultOperationFrequency);
|
||||||
|
|
||||||
|
unsigned char id[3];
|
||||||
|
pSPICommand->Read(0x9f, id, sizeof(id));
|
||||||
|
manufacturerId = id[0];
|
||||||
|
memoryType = id[1];
|
||||||
|
memoryCapacity = id[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
int M25PDeviceImpl::readStatusRegister(void)
|
||||||
|
{
|
||||||
|
unsigned char status;
|
||||||
|
_pSPICommand->Read(0x05, &status, 1);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void M25PDeviceImpl::writeStatusRegister(int value)
|
||||||
|
{
|
||||||
|
char vb = static_cast<char>(value);
|
||||||
|
_pSPICommand->Write(0x01, &vb, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void M25PDeviceImpl::writeEnable()
|
||||||
|
{
|
||||||
|
_pSPICommand->Write(0x06);
|
||||||
|
}
|
||||||
|
|
||||||
|
void M25PDeviceImpl::writeDisable()
|
||||||
|
{
|
||||||
|
_pSPICommand->Write(0x04);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
char param[] = { 0, 0, 0, 0xff };
|
||||||
|
fillAddress(param, address);
|
||||||
|
_pSPICommand->Read(0x0b, param, sizeof(param), buffer, length);
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
void M25PDeviceImpl::fillAddress(char* pBuffer, int address)
|
||||||
|
{
|
||||||
|
*(pBuffer + 0) = (address & 0xff0000) >> 16;
|
||||||
|
*(pBuffer + 1) = (address & 0x00ff00) >> 8;
|
||||||
|
*(pBuffer + 2) = (address & 0x0000ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
_pSPICommand->Write(0xc7);
|
||||||
|
|
||||||
|
while (readStatusRegister() & 0x01);
|
||||||
|
|
||||||
|
clearBlockProtection();
|
||||||
|
}
|
||||||
|
|
||||||
|
void M25PDeviceImpl::pageProgram(int address, const void* buffer)
|
||||||
|
{
|
||||||
|
writeEnable();
|
||||||
|
|
||||||
|
char param[256 + 3];
|
||||||
|
fillAddress(param, address);
|
||||||
|
memcpy(param + 3, buffer, 256);
|
||||||
|
_pSPICommand->Write(0x02, param, sizeof(param));
|
||||||
|
|
||||||
|
while (readStatusRegister() & 0x01);
|
||||||
|
}
|
41
src/drivers/SerialFlash/M25PDeviceImpl.h
Normal file
41
src/drivers/SerialFlash/M25PDeviceImpl.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class ISPICommand;
|
||||||
|
|
||||||
|
class M25PDeviceImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static bool IsSupported(ISPICommand* pSPICommand);
|
||||||
|
static M25PDeviceImpl* Create(ISPICommand* pSPICommand);
|
||||||
|
~M25PDeviceImpl(void);
|
||||||
|
|
||||||
|
std::string GetDeviceName() const;
|
||||||
|
int GetCapacity() const;
|
||||||
|
int Read(int address, void* buffer, int length);
|
||||||
|
int Write(int address, const void* buffer, int length);
|
||||||
|
void BulkErase(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ISPICommand* _pSPICommand;
|
||||||
|
int _operationFrequency;
|
||||||
|
struct DeviceProperty
|
||||||
|
{
|
||||||
|
std::string deviceName;
|
||||||
|
int capacity;
|
||||||
|
int blockProtectionMask;
|
||||||
|
} const& _property;
|
||||||
|
static const DeviceProperty* findMatchDevice(ISPICommand* pSPI);
|
||||||
|
|
||||||
|
M25PDeviceImpl(ISPICommand* pSPICommand, const DeviceProperty& property);
|
||||||
|
static void readId(ISPICommand* pSPICommand, int& manufacturerId, int& memoryType, int& memoryCapacity);
|
||||||
|
static void fillAddress(char* pBuffer, int address);
|
||||||
|
|
||||||
|
int readStatusRegister(void);
|
||||||
|
void clearBlockProtection(void);
|
||||||
|
void writeStatusRegister(int value);
|
||||||
|
void writeEnable(void);
|
||||||
|
void writeDisable(void);
|
||||||
|
void pageProgram(int address, const void* buffer);
|
||||||
|
};
|
71
src/drivers/SerialFlash/MbedSPICommand.cpp
Normal file
71
src/drivers/SerialFlash/MbedSPICommand.cpp
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#include "MbedSPICommand.h"
|
||||||
|
|
||||||
|
MbedSPICommand::MbedSPICommand(PinName mosi, PinName miso, PinName sck, PinName cs)
|
||||||
|
: _spi(mosi, miso, sck)
|
||||||
|
, _cs(cs)
|
||||||
|
{
|
||||||
|
//CS inactive
|
||||||
|
_cs = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MbedSPICommand::SetMaxFrequency(int frequency)
|
||||||
|
{
|
||||||
|
static const int LPC1768MaxFrequency = 46000000;
|
||||||
|
|
||||||
|
if (frequency > LPC1768MaxFrequency)
|
||||||
|
{
|
||||||
|
frequency = LPC1768MaxFrequency;
|
||||||
|
}
|
||||||
|
_spi.frequency(frequency);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MbedSPICommand::Write(int command)
|
||||||
|
{
|
||||||
|
_cs = 0;
|
||||||
|
_spi.write(command);
|
||||||
|
_cs = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MbedSPICommand::Write(int command, const void* pParam, int length)
|
||||||
|
{
|
||||||
|
_cs = 0;
|
||||||
|
_spi.write(command);
|
||||||
|
|
||||||
|
const char*p = static_cast<const char*>(pParam);
|
||||||
|
for (int i = 0; i < length; ++i)
|
||||||
|
{
|
||||||
|
_spi.write(*p++);
|
||||||
|
}
|
||||||
|
_cs = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MbedSPICommand::Read(int command, void* pReaded, int readLength)
|
||||||
|
{
|
||||||
|
_cs = 0;
|
||||||
|
_spi.write(command);
|
||||||
|
|
||||||
|
char* pReadedByte = static_cast<char*>(pReaded);
|
||||||
|
for (int i = 0; i < readLength; ++i)
|
||||||
|
{
|
||||||
|
*pReadedByte++ = _spi.write(0xff);
|
||||||
|
}
|
||||||
|
_cs = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MbedSPICommand::Read(int command, const void* pParam, int paramLength, void* pReaded, int readLength)
|
||||||
|
{
|
||||||
|
_cs = 0;
|
||||||
|
_spi.write(command);
|
||||||
|
|
||||||
|
const char* pParamByte = static_cast<const char*>(pParam);
|
||||||
|
for (int i = 0; i < paramLength; ++i)
|
||||||
|
{
|
||||||
|
_spi.write(*pParamByte++);
|
||||||
|
}
|
||||||
|
char* pReadedByte = static_cast<char*>(pReaded);
|
||||||
|
for (int i = 0; i < readLength; ++i)
|
||||||
|
{
|
||||||
|
*pReadedByte++ = _spi.write(0xff);
|
||||||
|
}
|
||||||
|
_cs = 1;
|
||||||
|
}
|
22
src/drivers/SerialFlash/MbedSPICommand.h
Normal file
22
src/drivers/SerialFlash/MbedSPICommand.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ISPICommand.h"
|
||||||
|
#include "mbed.h"
|
||||||
|
|
||||||
|
class MbedSPICommand : public ISPICommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MbedSPICommand(PinName mosi, PinName miso, PinName sck, PinName cs);
|
||||||
|
|
||||||
|
virtual void SetMaxFrequency(int frequency);
|
||||||
|
|
||||||
|
virtual void Write(int command);
|
||||||
|
virtual void Write(int command, const void* pParam, int length);
|
||||||
|
virtual void Read(int command, void* pReaded, int readLength);
|
||||||
|
virtual void Read(int command, const void* pParam, int paramLength, void* pReaded, int readLength);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SPI _spi;
|
||||||
|
DigitalOut _cs;
|
||||||
|
};
|
||||||
|
|
50
src/drivers/SerialFlash/SST25Device.cpp
Normal file
50
src/drivers/SerialFlash/SST25Device.cpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#include "mbed.h"
|
||||||
|
#include "SST25DeviceImpl.h"
|
||||||
|
#include "SST25Device.h"
|
||||||
|
|
||||||
|
bool SST25Device::IsSupported(ISPICommand* pSPICommand)
|
||||||
|
{
|
||||||
|
return SST25DeviceImpl::IsSupported(pSPICommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
SST25Device* SST25Device::Create(ISPICommand* pSPICommand)
|
||||||
|
{
|
||||||
|
SST25DeviceImpl* pImpl = SST25DeviceImpl::Create(pSPICommand);
|
||||||
|
if (pImpl == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return new SST25Device(pImpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SST25Device::SST25Device(SST25DeviceImpl* pImpl)
|
||||||
|
: _pImpl(pImpl)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
string SST25Device::GetDeviceName(void) const
|
||||||
|
{
|
||||||
|
return _pImpl->GetDeviceName();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SST25Device::GetCapacity(void) const
|
||||||
|
{
|
||||||
|
return _pImpl->GetCapacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SST25Device::ChipErase(void)
|
||||||
|
{
|
||||||
|
_pImpl->ChipErase();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SST25Device::Read(int address, void* buffer, int length)
|
||||||
|
{
|
||||||
|
return _pImpl->Read(address, buffer, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SST25Device::Write(int address, const void* buffer, int length)
|
||||||
|
{
|
||||||
|
return _pImpl->Write(address, buffer, length);
|
||||||
|
}
|
25
src/drivers/SerialFlash/SST25Device.h
Normal file
25
src/drivers/SerialFlash/SST25Device.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include "ISerialFlashDevice.h"
|
||||||
|
|
||||||
|
class ISPICommand;
|
||||||
|
class SST25DeviceImpl;
|
||||||
|
|
||||||
|
class SST25Device : public ISerialFlashDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static SST25Device* Create(ISPICommand* pSPICommand);
|
||||||
|
static bool IsSupported(ISPICommand* pSPICommand);
|
||||||
|
|
||||||
|
virtual std::string GetDeviceName(void) const;
|
||||||
|
virtual int GetCapacity(void) const;
|
||||||
|
virtual void ChipErase(void);
|
||||||
|
virtual int Read(int address, void* buffer, int length);
|
||||||
|
virtual int Write(int address, const void* buffer, int length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::auto_ptr<SST25DeviceImpl> _pImpl;
|
||||||
|
SST25Device(SST25DeviceImpl* pImpl);
|
||||||
|
};
|
444
src/drivers/SerialFlash/SST25DeviceImpl.cpp
Normal file
444
src/drivers/SerialFlash/SST25DeviceImpl.cpp
Normal file
@ -0,0 +1,444 @@
|
|||||||
|
#include "ISPICommand.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include "SST25DeviceImpl.h"
|
||||||
|
|
||||||
|
const SST25DeviceImpl::DeviceProperty* SST25DeviceImpl::findMatchDevice(ISPICommand* pSPICommand)
|
||||||
|
{
|
||||||
|
int manufacturersId;
|
||||||
|
int deviceId;
|
||||||
|
readId(pSPICommand, 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,
|
||||||
|
50000000
|
||||||
|
},
|
||||||
|
},
|
||||||
|
//SST25xF080B 8MBit (1MByte)
|
||||||
|
{ 0xbf, 0x8e,
|
||||||
|
{
|
||||||
|
"SST25xF080B",
|
||||||
|
8192 * 1024 / 8,
|
||||||
|
0xe3,
|
||||||
|
1,
|
||||||
|
&SST25DeviceImpl::writeAAIWord,
|
||||||
|
50000000
|
||||||
|
},
|
||||||
|
},
|
||||||
|
//SST25xF016B 16MBit (2MByte)
|
||||||
|
{ 0xbf, 0x41,
|
||||||
|
{
|
||||||
|
"SST25xF016B",
|
||||||
|
16384 * 1024 / 8,
|
||||||
|
0xe3,
|
||||||
|
1,
|
||||||
|
&SST25DeviceImpl::writeAAIWord,
|
||||||
|
50000000
|
||||||
|
},
|
||||||
|
},
|
||||||
|
//SST25xF032B 32MBit (4MByte)
|
||||||
|
{ 0xbf, 0x4a,
|
||||||
|
{
|
||||||
|
"SST25xF032B",
|
||||||
|
32768 * 1024 / 8,
|
||||||
|
0xc3,
|
||||||
|
1,
|
||||||
|
&SST25DeviceImpl::writeAAIWord,
|
||||||
|
50000000
|
||||||
|
},
|
||||||
|
},
|
||||||
|
//SST25xF064C 64MBit (8MByte)
|
||||||
|
{ 0xbf, 0x4b,
|
||||||
|
{
|
||||||
|
"SST25xF064C",
|
||||||
|
65536 * 1024 / 8,
|
||||||
|
0xc3,
|
||||||
|
256,
|
||||||
|
&SST25DeviceImpl::writePage,
|
||||||
|
50000000
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
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(ISPICommand* pSPICommand)
|
||||||
|
{
|
||||||
|
return findMatchDevice(pSPICommand) != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SST25DeviceImpl* SST25DeviceImpl::Create(ISPICommand* pSPICommand)
|
||||||
|
{
|
||||||
|
const DeviceProperty* property = findMatchDevice(pSPICommand);
|
||||||
|
if (property == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return new SST25DeviceImpl(pSPICommand, *property);
|
||||||
|
}
|
||||||
|
|
||||||
|
SST25DeviceImpl::SST25DeviceImpl(ISPICommand* pSPICommand, const DeviceProperty& property)
|
||||||
|
: _pSPICommand(pSPICommand)
|
||||||
|
, _property(property)
|
||||||
|
{
|
||||||
|
_pSPICommand->SetMaxFrequency(_property.operationClkHz);
|
||||||
|
}
|
||||||
|
|
||||||
|
SST25DeviceImpl::~SST25DeviceImpl(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SST25DeviceImpl::readId(ISPICommand* pSPICommand, int& manufacturersId, int& deviceId)
|
||||||
|
{
|
||||||
|
const static int DefaultOperationFrequency = 20000000;
|
||||||
|
pSPICommand->SetMaxFrequency(DefaultOperationFrequency);
|
||||||
|
|
||||||
|
unsigned char read[2];
|
||||||
|
char param[3];
|
||||||
|
fillAddress(param, 0x000000);
|
||||||
|
pSPICommand->Read(0x90, param, sizeof(param), read, sizeof(read));
|
||||||
|
manufacturersId = read[0];
|
||||||
|
deviceId = read[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
int SST25DeviceImpl::readStatusRegister(void)
|
||||||
|
{
|
||||||
|
unsigned char read;
|
||||||
|
_pSPICommand->Read(0x05, &read, 1);
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SST25DeviceImpl::writeStatusRegister(int value)
|
||||||
|
{
|
||||||
|
_pSPICommand->Write(0x50);
|
||||||
|
|
||||||
|
char vb = static_cast<char>(value);
|
||||||
|
_pSPICommand->Write(0x01, &vb, sizeof(vb));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SST25DeviceImpl::writeEnable()
|
||||||
|
{
|
||||||
|
int status = readStatusRegister();
|
||||||
|
status &= _property.blockProtectionMask;
|
||||||
|
writeStatusRegister(status);
|
||||||
|
_pSPICommand->Write(0x06);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SST25DeviceImpl::writeDisable()
|
||||||
|
{
|
||||||
|
_pSPICommand->Write(0x04);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
_pSPICommand->SetMaxFrequency(_property.operationClkHz);
|
||||||
|
|
||||||
|
char param[] = { 0, 0, 0, 0xff };
|
||||||
|
fillAddress(param, address);
|
||||||
|
_pSPICommand->Read(0x0b, param, sizeof(param), buffer, length);
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
_pSPICommand->SetMaxFrequency(_property.operationClkHz);
|
||||||
|
|
||||||
|
writeEnable();
|
||||||
|
_pSPICommand->Write(0x60);
|
||||||
|
waitForReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SST25DeviceImpl::byteProgram(int address, int value)
|
||||||
|
{
|
||||||
|
_pSPICommand->SetMaxFrequency(_property.operationClkHz);
|
||||||
|
|
||||||
|
writeEnable();
|
||||||
|
|
||||||
|
char param[] = { 0, 0, 0, value };
|
||||||
|
fillAddress(param, address);
|
||||||
|
_pSPICommand->Write(0x02, param, sizeof(param));
|
||||||
|
|
||||||
|
waitForReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SST25DeviceImpl::beginAAIProgram(int address, int data)
|
||||||
|
{
|
||||||
|
_pSPICommand->SetMaxFrequency(_property.operationClkHz);
|
||||||
|
|
||||||
|
writeEnable();
|
||||||
|
|
||||||
|
char param[] = { 0, 0, 0, data };
|
||||||
|
fillAddress(param, address);
|
||||||
|
_pSPICommand->Write(0xaf, param, sizeof(param));
|
||||||
|
|
||||||
|
waitForReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SST25DeviceImpl::nextAAIProgram(int data)
|
||||||
|
{
|
||||||
|
char param = static_cast<char>(data);
|
||||||
|
_pSPICommand->Write(0xaf, ¶m, 1);
|
||||||
|
|
||||||
|
waitForReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SST25DeviceImpl::endAAIProgram(void)
|
||||||
|
{
|
||||||
|
_pSPICommand->Write(0x04);
|
||||||
|
waitForReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SST25DeviceImpl::beginAAIWordProgram(int address, int data)
|
||||||
|
{
|
||||||
|
_pSPICommand->SetMaxFrequency(_property.operationClkHz);
|
||||||
|
|
||||||
|
writeEnable();
|
||||||
|
char param[] = { 0, 0, 0, (data & 0xff00) >> 8, data & 0xff };
|
||||||
|
fillAddress(param, address);
|
||||||
|
_pSPICommand->Write(0xad, param, sizeof(param));
|
||||||
|
waitForReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SST25DeviceImpl::nextAAIWordProgram(int data)
|
||||||
|
{
|
||||||
|
char param[] = { (data & 0xff00) >> 8, data & 0xff };
|
||||||
|
_pSPICommand->Write(0xad, param, sizeof(param));
|
||||||
|
waitForReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SST25DeviceImpl::fillAddress(char* pBuffer, int address)
|
||||||
|
{
|
||||||
|
*(pBuffer + 0) = (address & 0xff0000) >> 16;
|
||||||
|
*(pBuffer + 1) = (address & 0x00ff00) >> 8;
|
||||||
|
*(pBuffer + 2) = (address & 0x0000ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SST25DeviceImpl::pageProgram(int address, const void* buffer)
|
||||||
|
{
|
||||||
|
_pSPICommand->SetMaxFrequency(_property.operationClkHz);
|
||||||
|
|
||||||
|
writeEnable();
|
||||||
|
|
||||||
|
char param[256 + 3];
|
||||||
|
fillAddress(param, address);
|
||||||
|
memcpy(param + 3, buffer, 256);
|
||||||
|
_pSPICommand->Write(0x02, param, sizeof(param));
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
57
src/drivers/SerialFlash/SST25DeviceImpl.h
Normal file
57
src/drivers/SerialFlash/SST25DeviceImpl.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class ISPICommand;
|
||||||
|
|
||||||
|
class SST25DeviceImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static bool IsSupported(ISPICommand* pSPICommand);
|
||||||
|
static SST25DeviceImpl* Create(ISPICommand* pSPICommand);
|
||||||
|
~SST25DeviceImpl(void);
|
||||||
|
|
||||||
|
std::string GetDeviceName() const;
|
||||||
|
int GetCapacity() const;
|
||||||
|
int Read(int address, void* buffer, int length);
|
||||||
|
int Write(int address, const void* buffer, int length);
|
||||||
|
void ChipErase(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ISPICommand* const _pSPICommand;
|
||||||
|
int _operationFrequency;
|
||||||
|
struct DeviceProperty
|
||||||
|
{
|
||||||
|
std::string deviceName;
|
||||||
|
int capacity;
|
||||||
|
int blockProtectionMask;
|
||||||
|
int pageSize;
|
||||||
|
void (SST25DeviceImpl::*pfnWriter)(int address, const void* buffer, int length);
|
||||||
|
|
||||||
|
int operationClkHz;
|
||||||
|
} const& _property;
|
||||||
|
static const DeviceProperty* findMatchDevice(ISPICommand* pSPICommand);
|
||||||
|
|
||||||
|
SST25DeviceImpl(ISPICommand* pSPICommand, const DeviceProperty& property);
|
||||||
|
static void readId(ISPICommand* pSPICommand, int& manufacturersId, int& deviceId);
|
||||||
|
static void fillAddress(char* pBuffer, int address);
|
||||||
|
|
||||||
|
int readStatusRegister(void);
|
||||||
|
void writeStatusRegister(int value);
|
||||||
|
void writeEnable(void);
|
||||||
|
void writeDisable(void);
|
||||||
|
void waitForReady(void);
|
||||||
|
|
||||||
|
void byteProgram(int address, int value);
|
||||||
|
void pageProgram(int address, const void* buffer);
|
||||||
|
void beginAAIProgram(int address, int data);
|
||||||
|
void nextAAIProgram(int data);
|
||||||
|
void endAAIProgram(void);
|
||||||
|
void beginAAIWordProgram(int address, int data);
|
||||||
|
void nextAAIWordProgram(int data);
|
||||||
|
|
||||||
|
void writeBytes(int address, const void* buffer, int length);
|
||||||
|
void writeAAI(int address, const void* buffer, int length);
|
||||||
|
void writeAAIWord(int address, const void* buffer, int length);
|
||||||
|
void writePage(int address, const void* buffer, int length);
|
||||||
|
};
|
17
src/drivers/SerialFlash/SerialFlashDeviceCreator.cpp
Normal file
17
src/drivers/SerialFlash/SerialFlashDeviceCreator.cpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#include "ISerialFlashDevice.h"
|
||||||
|
#include "SST25Device.h"
|
||||||
|
#include "M25PDevice.h"
|
||||||
|
#include "SerialFlashDeviceCreator.h"
|
||||||
|
|
||||||
|
ISerialFlashDevice* SerialFlashDeviceCreator::Create(ISPICommand* pSPICommand)
|
||||||
|
{
|
||||||
|
if (M25PDevice::IsSupported(pSPICommand))
|
||||||
|
{
|
||||||
|
return M25PDevice::Create(pSPICommand);
|
||||||
|
}
|
||||||
|
if (SST25Device::IsSupported(pSPICommand))
|
||||||
|
{
|
||||||
|
return SST25Device::Create(pSPICommand);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
11
src/drivers/SerialFlash/SerialFlashDeviceCreator.h
Normal file
11
src/drivers/SerialFlash/SerialFlashDeviceCreator.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ISerialFlashDevice.h"
|
||||||
|
|
||||||
|
class ISPICommand;
|
||||||
|
|
||||||
|
class SerialFlashDeviceCreator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static ISerialFlashDevice* Create(ISPICommand* pSPICommand);
|
||||||
|
};
|
189
src/drivers/SpiFlash25.cpp
Normal file
189
src/drivers/SpiFlash25.cpp
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
/* Library for SPI flash 25* devices.
|
||||||
|
* Copyright (c) 2014 Multi-Tech Systems
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SpiFlash25.h"
|
||||||
|
|
||||||
|
SpiFlash25::SpiFlash25(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName W, PinName HOLD, int page_size)
|
||||||
|
: _spi(mosi, miso, sclk),
|
||||||
|
_cs(cs),
|
||||||
|
_page_size(page_size)
|
||||||
|
{
|
||||||
|
|
||||||
|
wakeup();
|
||||||
|
|
||||||
|
_cs.write(1);
|
||||||
|
_spi.format(8, 3);
|
||||||
|
_spi.frequency(75000000);
|
||||||
|
|
||||||
|
if (W != NC) {
|
||||||
|
_w = new DigitalOut(W);
|
||||||
|
_w->write(1);
|
||||||
|
}
|
||||||
|
if (HOLD != NC) {
|
||||||
|
_hold = new DigitalOut(HOLD);
|
||||||
|
_hold->write(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
_cs.write(0);
|
||||||
|
_spi.write(READ_IDENTIFICATION);
|
||||||
|
_id[ID_MANUFACTURER] = _spi.write(0x00);
|
||||||
|
_id[ID_MEM_TYPE] = _spi.write(0x00);
|
||||||
|
_id[ID_MEM_SIZE] = _spi.write(0x00);
|
||||||
|
_cs.write(1);
|
||||||
|
|
||||||
|
_mem_size = 1 << _id[ID_MEM_SIZE];
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpiFlash25::format(int bits, int mode) {
|
||||||
|
_spi.format(bits, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpiFlash25::frequency(int hz) {
|
||||||
|
_spi.frequency(hz);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SpiFlash25::read(int addr, int len, char* data) {
|
||||||
|
if (addr + len > _mem_size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
enable_write();
|
||||||
|
|
||||||
|
_cs.write(0);
|
||||||
|
_spi.write(READ_DATA);
|
||||||
|
_spi.write(high_byte(addr));
|
||||||
|
_spi.write(mid_byte(addr));
|
||||||
|
_spi.write(low_byte(addr));
|
||||||
|
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
data[i] = _spi.write(0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
_cs.write(1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SpiFlash25::write(int addr, int len, const char* data) {
|
||||||
|
if (addr + len > _mem_size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int written = 0;
|
||||||
|
int write_size = 0;
|
||||||
|
|
||||||
|
while (written < len) {
|
||||||
|
write_size = _page_size - ((addr + written) % _page_size);
|
||||||
|
if (written + write_size > len) {
|
||||||
|
write_size = len - written;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! write_page(addr + written, write_size, data + written)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
written += write_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* SpiFlash25::read_id() {
|
||||||
|
return _id;
|
||||||
|
}
|
||||||
|
|
||||||
|
char SpiFlash25::read_status() {
|
||||||
|
char status;
|
||||||
|
|
||||||
|
_cs.write(0);
|
||||||
|
_spi.write(READ_STATUS);
|
||||||
|
status = _spi.write(0x00);
|
||||||
|
_cs.write(1);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpiFlash25::clear_sector(int addr) {
|
||||||
|
enable_write();
|
||||||
|
|
||||||
|
_cs.write(0);
|
||||||
|
_spi.write(SECTOR_ERASE);
|
||||||
|
_spi.write(high_byte(addr));
|
||||||
|
_spi.write(mid_byte(addr));
|
||||||
|
_spi.write(low_byte(addr));
|
||||||
|
_cs.write(1);
|
||||||
|
|
||||||
|
wait_for_write();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpiFlash25::clear_mem() {
|
||||||
|
enable_write();
|
||||||
|
|
||||||
|
_cs.write(0);
|
||||||
|
_spi.write(BULK_ERASE);
|
||||||
|
_cs.write(1);
|
||||||
|
|
||||||
|
wait_for_write();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SpiFlash25::write_page(int addr, int len, const char* data) {
|
||||||
|
enable_write();
|
||||||
|
|
||||||
|
_cs.write(0);
|
||||||
|
_spi.write(PAGE_PROGRAM);
|
||||||
|
_spi.write(high_byte(addr));
|
||||||
|
_spi.write(mid_byte(addr));
|
||||||
|
_spi.write(low_byte(addr));
|
||||||
|
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
_spi.write(data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
_cs.write(1);
|
||||||
|
wait_for_write();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpiFlash25::enable_write() {
|
||||||
|
_cs.write(0);
|
||||||
|
_spi.write(WRITE_ENABLE);
|
||||||
|
_cs.write(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpiFlash25::wait_for_write() {
|
||||||
|
while (read_status() & STATUS_WIP) {
|
||||||
|
wait_us(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpiFlash25::deep_power_down() {
|
||||||
|
_cs.write(0);
|
||||||
|
_spi.write(DEEP_POWER_DOWN);
|
||||||
|
_cs.write(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpiFlash25::wakeup() {
|
||||||
|
_cs.write(0);
|
||||||
|
_spi.write(DEEP_POWER_DOWN_RELEASE);
|
||||||
|
_cs.write(1);
|
||||||
|
}
|
107
src/drivers/SpiFlash25.h
Normal file
107
src/drivers/SpiFlash25.h
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/* Library for SPI flash 25* devices.
|
||||||
|
* Copyright (c) 2014 Multi-Tech Systems
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SPIFLASH25_H
|
||||||
|
#define SPIFLASH25_H
|
||||||
|
|
||||||
|
#include "mbed.h"
|
||||||
|
|
||||||
|
class SpiFlash25 {
|
||||||
|
public:
|
||||||
|
SpiFlash25(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName W = NC, PinName HOLD = NC, int page_size = 256);
|
||||||
|
|
||||||
|
/* Set the page size (default 256) */
|
||||||
|
void set_page_size(int size);
|
||||||
|
|
||||||
|
/* Set up the internal SPI object */
|
||||||
|
void format(int bits, int mode);
|
||||||
|
void frequency(int hz);
|
||||||
|
|
||||||
|
/* Reads and writes can be across page boundaries */
|
||||||
|
bool read(int addr, int len, char* data);
|
||||||
|
bool write(int addr, int len, const char* data);
|
||||||
|
|
||||||
|
/* Read ID and status registers */
|
||||||
|
char* read_id();
|
||||||
|
char read_status();
|
||||||
|
|
||||||
|
/* Erase methods */
|
||||||
|
void clear_sector(int addr);
|
||||||
|
void clear_mem();
|
||||||
|
|
||||||
|
void deep_power_down();
|
||||||
|
void wakeup();
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum {
|
||||||
|
WRITE_ENABLE = 0x06,
|
||||||
|
WRITE_DISABLE = 0x04,
|
||||||
|
READ_IDENTIFICATION = 0x9F,
|
||||||
|
READ_STATUS = 0x05,
|
||||||
|
WRITE_STATUS = 0x01,
|
||||||
|
READ_DATA = 0x03,
|
||||||
|
READ_DATA_FAST = 0x0B,
|
||||||
|
PAGE_PROGRAM = 0x02,
|
||||||
|
SECTOR_ERASE = 0xD8,
|
||||||
|
BULK_ERASE = 0xC7,
|
||||||
|
DEEP_POWER_DOWN = 0xB9,
|
||||||
|
DEEP_POWER_DOWN_RELEASE = 0xAB,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
STATUS_SRWD = 0x80, // 0b 1000 0000
|
||||||
|
STATUS_BP2 = 0x10, // 0b 0001 0000
|
||||||
|
STATUS_BP1 = 0x08, // 0b 0000 1000
|
||||||
|
STATUS_BP0 = 0x04, // 0b 0000 0100
|
||||||
|
STATUS_WEL = 0x02, // 0b 0000 0010
|
||||||
|
STATUS_WIP = 0x01, // 0b 0000 0001
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ID_MANUFACTURER = 0,
|
||||||
|
ID_MEM_TYPE = 1,
|
||||||
|
ID_MEM_SIZE = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool write_page(int addr, int len, const char* data);
|
||||||
|
void enable_write();
|
||||||
|
void wait_for_write();
|
||||||
|
|
||||||
|
static inline char high_byte(int addr) {
|
||||||
|
return ((addr & 0xff0000) >> 16);
|
||||||
|
}
|
||||||
|
static inline char mid_byte(int addr) {
|
||||||
|
return ((addr & 0xff00) >> 8);
|
||||||
|
}
|
||||||
|
static inline char low_byte(int addr) {
|
||||||
|
return (addr & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPI _spi;
|
||||||
|
DigitalOut _cs;
|
||||||
|
DigitalOut* _w;
|
||||||
|
DigitalOut* _hold;
|
||||||
|
int _mem_size;
|
||||||
|
int _page_size;
|
||||||
|
char _id[3];
|
||||||
|
};
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user