Enhanced EEPROM 25LCxxx driver
Fork of 25LCxxx_SPI by
Revision 3:be69a9f6f738, committed 2015-07-17
- Comitter:
- mariob
- Date:
- Fri Jul 17 09:47:32 2015 +0000
- Parent:
- 2:3a3404dbd3eb
- Commit message:
- added fix in writing function; fixed write check; added features (protection bits); changed interfaces
Changed in this revision
Ser25lcxxx.cpp | Show annotated file Show diff for this revision Revisions of this file |
Ser25lcxxx.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r 3a3404dbd3eb -r be69a9f6f738 Ser25lcxxx.cpp --- a/Ser25lcxxx.cpp Sat Feb 19 18:29:20 2011 +0000 +++ b/Ser25lcxxx.cpp Fri Jul 17 09:47:32 2015 +0000 @@ -24,177 +24,204 @@ #include "Ser25lcxxx.h" #include "wait_api.h" -#define HIGH(x) ((x&0xff00)>>8) -#define LOW(x) (x&0xff) +#define HIGH(x) ((x&0xff00)>>8) +#define LOW(x) (x&0xff) -Ser25LCxxx::Ser25LCxxx(SPI *spi, PinName enable, int bytes, int pagesize) { - _spi=spi; - _enable=new DigitalOut(enable); - _size=bytes; - _pageSize=pagesize; - _enable->write(1); +Ser25LCxxx::Ser25LCxxx (PinName sck, PinName si, PinName so, PinName enable, + int pagenumber, int pagesize): + spi(si, so, sck), cs(enable) { + spi.format(8,3); + spi.frequency(EEPROM_SPI_SPEED); + size = pagesize*pagesize; + pageSize = pagesize; + pageNumber = pagenumber; + cs.write(1); } -Ser25LCxxx::~Ser25LCxxx() { - delete _enable; +unsigned int Ser25LCxxx::read (unsigned int startAdr, unsigned int len, + unsigned char* buf) { + // assertion + if ((startAdr+len) > size) + return 0; + + //active the device + cs = 0; + wait_us(1); + + //send command and address + if (size<512) { // 256 and 128 bytes + spi.write(EEPROM_CMD_READ); + spi.write(LOW(startAdr)); + } else if (512==size) { // 4k variant adds 9th address bit to command + spi.write(startAdr>255?0xb:EEPROM_CMD_READ); + spi.write(LOW(startAdr)); + } else if (size<131072) { // everything up to 512k + spi.write(EEPROM_CMD_READ); + spi.write(HIGH(startAdr)); + spi.write(LOW(startAdr)); + } else { // 25xx1024, needs 3 byte address + spi.write(EEPROM_CMD_READ); + spi.write(startAdr>>16); + spi.write(HIGH(startAdr)); + spi.write(LOW(startAdr)); + } + + //read data into buffer + for (int i=0; i<len; i++) + buf[i] = spi.write(0); + wait_us(1); + + cs = 1; + + return len; +} + +unsigned int Ser25LCxxx::write (unsigned int startAdr, unsigned int len, + const unsigned char* data) { + if ((startAdr+len) > size) + return 0; + + unsigned int remaining = len; + unsigned int count = 0; + + while (remaining > 0) { + // calculate amount of data to write into current page + int page_left = pageSize - (startAdr % pageSize); + int to_be_written = (remaining > page_left)? page_left : remaining; + if (writePage(startAdr, to_be_written, data+count) != to_be_written) + return count; + // and switch to next page + count += to_be_written; + remaining -= to_be_written; + startAdr += to_be_written; + } + return count; } -char* Ser25LCxxx::read(unsigned int startAdr, unsigned int len) { - // assertion - if (startAdr+len>_size) - return NULL; - char* ret=(char*)malloc(len); - _enable->write(0); +unsigned int Ser25LCxxx::writePage (unsigned int startAdr, unsigned int len, + const unsigned char* data) { + //deactivate write-protection latch + enableWrite(); + + //activate eeprom + cs = 0; wait_us(1); - // send address - if (_size<512) { // 256 and 128 bytes - _spi->write(0x03); - _spi->write(LOW(startAdr)); - } else if (512==_size) { // 4k variant adds 9th address bit to command - _spi->write(startAdr>255?0xb:0x3); - _spi->write(LOW(startAdr)); - } else if (_size<131072) { // everything up to 512k - _spi->write(0x03); - _spi->write(HIGH(startAdr)); - _spi->write(LOW(startAdr)); + + //send command and address + if (size<512) { // 256 and 128 bytes + spi.write(EEPROM_CMD_WRITE); + spi.write(LOW(startAdr)); + } else if (512==size) { // 4k variant adds 9th address bit to command + spi.write(startAdr>255?0xa:EEPROM_CMD_WRITE); + spi.write(LOW(startAdr)); + } else if (size<131072) { // everything up to 512k + spi.write(EEPROM_CMD_WRITE); + spi.write(HIGH(startAdr)); + spi.write(LOW(startAdr)); } else { // 25xx1024, needs 3 byte address - _spi->write(0x03); - _spi->write(startAdr>>16); - _spi->write(HIGH(startAdr)); - _spi->write(LOW(startAdr)); + spi.write(EEPROM_CMD_WRITE); + spi.write(startAdr>>16); + spi.write(HIGH(startAdr)); + spi.write(LOW(startAdr)); } - // read data into buffer - for (int i=0;i<len;i++) { - ret[i]=_spi->write(0); - } + + //write data + for (int i=0; i<len; i++) + spi.write(data[i]); wait_us(1); - _enable->write(1); - return ret; + + //disable eeprom + cs = 1; + + //wait until write operation ends + if (!waitForWrite()) + return 0; + + return len; } -bool Ser25LCxxx::write(unsigned int startAdr, unsigned int len, const char* data) { - if (startAdr+len>_size) - return -1; +unsigned int Ser25LCxxx::clearPage (unsigned int pageNum) { + unsigned char s[pageSize]; + memset(s, EEPROM_CLEAN_BYTE, pageSize); + + return writePage(pageSize*pageNum, pageSize, s); +} + +unsigned int Ser25LCxxx::clearMem () { + /* the implementation does not exploit clearPage to optimize the use + of the buffer s - it is not set for each page but just once for the + whole eeprom memory */ + unsigned char s[pageSize]; + unsigned int counter = 0; + + memset(s, EEPROM_CLEAN_BYTE, pageSize); + + for (int i=0; i<pageNumber; i++) { + if (writePage(pageSize*i, pageSize, s) != pageSize) + return counter; + counter += pageSize; + } + + return counter; +} - int ofs=0; - while (ofs<len) { - // calculate amount of data to write into current page - int pageLen=_pageSize-((startAdr+ofs)%_pageSize); - if (ofs+pageLen>len) - pageLen=len-ofs; - // write single page - bool b=writePage(startAdr+ofs,pageLen,data+ofs); - if (!b) +int Ser25LCxxx::readStatus() { + //activate eeprom + cs = 0; + wait_us(1); + + //send command + spi.write(EEPROM_CMD_RDSR); + + //read value + int status = spi.write(0x00); + wait_us(1); + + //deactivate eeprom + cs = 1; + + return status; +} + +bool Ser25LCxxx::waitForWrite() { + unsigned int counter = 0; + + while (isWriteInProgress()) { + wait_us(10); + if ((++counter) > 500) return false; - // and switch to next page - ofs+=pageLen; } + return true; } -bool Ser25LCxxx::writePage(unsigned int startAdr, unsigned int len, const char* data) { - enableWrite(); - - _enable->write(0); +void Ser25LCxxx::enableWrite () { + //enable eeprom + cs = 0; wait_us(1); - if (_size<512) { // 256 and 128 bytes - _spi->write(0x02); - _spi->write(LOW(startAdr)); - } else if (512==_size) { // 4k variant adds 9th address bit to command - _spi->write(startAdr>255?0xa:0x2); - _spi->write(LOW(startAdr)); - } else if (_size<131072) { // everything up to 512k - _spi->write(0x02); - _spi->write(HIGH(startAdr)); - _spi->write(LOW(startAdr)); - } else { // 25xx1024, needs 3 byte address - _spi->write(0x02); - _spi->write(startAdr>>16); - _spi->write(HIGH(startAdr)); - _spi->write(LOW(startAdr)); - } - - // do real write - for (int i=0;i<len;i++) { - _spi->write(data[i]); - } + //send command + spi.write(EEPROM_CMD_WREN); wait_us(1); - // disable to start physical write - _enable->write(1); - waitForWrite(); - - return true; + //disable eeprom + cs = 1; } -bool Ser25LCxxx::clearPage(unsigned int pageNum) { - enableWrite(); - if (_size<65535) { - char* s=(char*)malloc(_pageSize); - for (int i=0;i<_pageSize;i++) { - s[i]=0xff; - } - bool b=writePage(_pageSize*pageNum,_pageSize,s); - delete s; - return b; - } else { - _enable->write(0); - wait_us(1); - _spi->write(0x42); - _spi->write(HIGH(_pageSize*pageNum)); - _spi->write(LOW(_pageSize*pageNum)); - wait_us(1); - _enable->write(1); - - waitForWrite(); - } - return true; -} - -void Ser25LCxxx::clearMem() { +void Ser25LCxxx::writeStatus (unsigned char val) { enableWrite(); - if (_size<65535) { - for (int i=0;i<_size/_pageSize;i++) { - if (!clearPage(i)) - break; - } - } - else - { - _enable->write(0); - wait_us(1); - _spi->write(0xc7); - wait_us(1); - _enable->write(1); - waitForWrite(); - } -} - -int Ser25LCxxx::readStatus() { - _enable->write(0); + //enable eeprom + cs = 0; wait_us(1); - _spi->write(0x5); - int status=_spi->write(0x00); - wait_us(1); - _enable->write(1); - return status; -} -void Ser25LCxxx::waitForWrite() { - while (true) { - if (0==readStatus()&1) - break; - wait_us(10); - } -} + //send command + spi.write(EEPROM_CMD_WRSR); + + //write stautus + spi.write(val); + wait_us(1); -void Ser25LCxxx::enableWrite() -{ - _enable->write(0); - wait_us(1); - _spi->write(0x06); - wait_us(1); - _enable->write(1); + //disable eeprom + cs = 1; }
diff -r 3a3404dbd3eb -r be69a9f6f738 Ser25lcxxx.h --- a/Ser25lcxxx.h Sat Feb 19 18:29:20 2011 +0000 +++ b/Ser25lcxxx.h Fri Jul 17 09:47:32 2015 +0000 @@ -26,70 +26,182 @@ #include "mbed.h" -/** -A class to read and write all 25* serial SPI eeprom devices from Microchip (from 25xx010 to 25xx1024). + +#define EEPROM_CMD_READ 0x03 +#define EEPROM_CMD_WRITE 0x02 +#define EEPROM_CMD_WRDI 0x04 +#define EEPROM_CMD_WREN 0x06 +#define EEPROM_CMD_RDSR 0x05 +#define EEPROM_CMD_WRSR 0x01 + + +#define EEPROM_SPI_SPEED 1000000 -One needs to provide total size and page size, since this cannot be read from the devices, -and the page size differs even by constant size (look up the data sheet for your part!) +#define EEPROM_CLEAN_BYTE 0xff + + +/** +A class to read and write all 25* serial SPI eeprom devices from Microchip +(from 25xx010 to 25xx1024). + +One needs to provide total size and page size, since this cannot be read from +the devices, and the page size differs even by constant size (look up the data +sheet for your part!) */ class Ser25LCxxx { public: + /** - create the handler class - @param spi the SPI port where the eeprom is connected. Must be set to format(8,3), and with a speed matching the one of your device (up to 5MHz should work) + Create the handler class + + @param sck clock pin of the spi where the eeprom is connected + @param si input pin of the spi where the eeprom is connected + @param so output pin of the spi where the eeprom is connected @param enable the pin name for the port where /CS is connected - @param bytes the size of you eeprom in bytes (NOT bits, eg. a 25LC010 has 128 bytes) - @param pagesize the size of a single page, to provide overruns + @param pagenumber number of pages + @param pagesize the size of each page */ - Ser25LCxxx(SPI *spi, PinName enable, int bytes, int pagesize); + Ser25LCxxx(PinName sck, PinName si, PinName so, PinName enable, + int pagenumber, int pagesize); + + /** + Destroy the handler + */ + ~Ser25LCxxx() {}; /** - destroys the handler, and frees the /CS pin + Read from the eeprom memory + + @param startAdr the adress where to start reading + @param len the number of bytes to read + @param buf destination buffer + @return number of read bytes */ - ~Ser25LCxxx(); + unsigned int read(unsigned int startAdr, unsigned int len, + unsigned char* buf); /** - read a part of the eeproms memory. The buffer will be allocated here, and must be freed by the user - @param startAdr the adress where to start reading. Doesn't need to match a page boundary - @param len the number of bytes to read (must not exceed the end of memory) - @return NULL if the adresses are out of range, the pointer to the data otherwise + Writes the give buffer into the eeprom memory + + @param startAdr the eeprom adress where to start writing (it + doesn't have to match a page boundary) + @param len number of bytes to write + @param data data to write + @return the number of written bytes */ - char* read(unsigned int startAdr, unsigned int len); + unsigned int write(unsigned int startAdr, unsigned int len, + const unsigned char* data); + + /** + Fills the given page with EEPROM_CLEAN_BYTE + + @param pageNum the page to clear + @return the number of written bytes (it should be the page size) + */ + unsigned int clearPage(unsigned int pageNum); /** - writes the give buffer into the memory. This function handles dividing the write into - pages, and waites until the phyiscal write has finished - @param startAdr the adress where to start writing. Doesn't need to match a page boundary - @param len the number of bytes to read (must not exceed the end of memory) - @return false if the adresses are out of range + Fills the whole eeprom with EEPROM_CLEAN_BYTE + + @return the number of written bytes (it should be the eeprom size) + */ + unsigned int clearMem(); + + /** + Return TRUE if a write is performing + */ + bool isWriteInProgress() { + return (readStatus()&0x01)!=0x00; + } + + /** + Return TRUE if the entire eeprom memory is writable + */ + bool isFullyWritable() { + return (readStatus()&0x0C)==0x00; + } + + /** + Return TRUE if only the first half of the eeprom memory is writable */ - bool write(unsigned int startAdr, unsigned int len, const char* data); - + bool isHalfWritable() { + return (readStatus()&0x0C)==0x08; + } + + /** + Return TRUE if the eeprom memory is not writable + */ + bool isNotWritable() { + return (readStatus()&0x0C)==0x0C; + } + /** - fills the given page with 0xFF - @param pageNum the page number to clear - @return if the pageNum is out of range + Set the eeprom memory not writable */ - bool clearPage(unsigned int pageNum); + void setNotWritable () { + writeStatus(0x0C); + } + + /** + Set the eeprom memory fully writable + */ + void setFullyWritable () { + writeStatus(0x00); + } /** - fills the while eeprom with 0xFF + Set only the first half of the eeprom memory as writable */ - void clearMem(); + void setHalfWritable() { + writeStatus(0x08); + } + private: - bool writePage(unsigned int startAdr, unsigned int len, const char* data); + + /** + Write data within an eeprom page + + @param startAdr destination address of the eeprm memory + @param len number of bytes to write + @param data data to be written in the eeprom memory + @return number of written bytes + */ + unsigned int writePage(unsigned int startAdr, unsigned int len, + const unsigned char* data); + + /** + Read the status register of the eeprom memory + + @return status register + */ int readStatus(); - void waitForWrite(); - void enableWrite(); + /** + Write the status register + + @param val status register + */ + void writeStatus(unsigned char val); - SPI* _spi; - DigitalOut* _enable; - int _size,_pageSize; + /** + Wait until a write procedure ends or an interval of 5ms is expired + + @return TRUE if the write procedure has successfully terminated, + FALSE if the interval is expired + */ + bool waitForWrite(); + /** + Enable the write procedure + */ + void enableWrite(); + + SPI spi; + DigitalOut cs; + int size; + int pageSize; + int pageNumber; }; - - #endif