A library to read and write all 25* serial SPI eeprom devices from Microchip (from 25xx010 to 25xx1024).

Dependents:   RobotRic VITI2_ihm_2

Files at this revision

API Documentation at this revision

Comitter:
hlipka
Date:
Wed Jan 26 22:14:41 2011 +0000
Child:
1:c29a67c7034d
Commit message:
initial version

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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Ser25lcxxx.cpp	Wed Jan 26 22:14:41 2011 +0000
@@ -0,0 +1,177 @@
+#include "Ser25lcxxx.h"
+#include "wait_api.h"
+
+#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() {
+    delete _enable;
+}
+
+char* Ser25LCxxx::read(unsigned int startAdr, unsigned int len) {
+    // assertion
+    if (startAdr+len>_size)
+        return NULL;
+    char* ret=(char*)malloc(len);
+    _enable->write(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));
+    } else { // 25xx1024, needs 3 byte address
+        _spi->write(0x03);
+        _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);
+    }
+    wait_us(1);
+    _enable->write(1);
+    return ret;
+}
+
+bool Ser25LCxxx::write(unsigned int startAdr, unsigned int len, const char* data) {
+    if (startAdr+len>_size)
+        return -1;
+
+    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)
+            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);
+    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]);
+    }
+    wait_us(1);
+    // disable to start physical write
+    _enable->write(1);
+    
+    waitForWrite();
+
+    return true;
+}
+
+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() {
+    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);
+    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);
+    }
+}
+
+void Ser25LCxxx::enableWrite()
+{
+    _enable->write(0);
+    wait_us(1);
+    _spi->write(0x06);
+    wait_us(1);
+    _enable->write(1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Ser25lcxxx.h	Wed Jan 26 22:14:41 2011 +0000
@@ -0,0 +1,72 @@
+#ifndef __SER25LCXXX_H__
+#define __SER25LCXXX_H__
+
+#include "mbed.h"
+
+/**
+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)
+            @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
+        */
+        Ser25LCxxx(SPI *spi, PinName enable, int bytes, int pagesize);
+        
+        /**
+            destroys the handler, and frees the /CS pin        
+        */
+        ~Ser25LCxxx();
+        
+        /**
+            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
+        */
+        char* read(unsigned int startAdr, unsigned int len);
+        
+        /**
+            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
+        */
+        bool write(unsigned int startAdr, unsigned int len, const char* data);
+        
+        /**
+            fills the given page with 0xFF
+            @param pageNum the page number to clear
+            @return if the pageNum is out of range        
+        */
+        bool clearPage(unsigned int pageNum);
+        
+        /**
+            fills the while eeprom with 0xFF
+        */
+        void clearMem();
+    private:
+        bool writePage(unsigned int startAdr, unsigned int len, const char* data);
+        int readStatus();
+        void waitForWrite();
+        void enableWrite();
+        
+
+        SPI* _spi;
+        DigitalOut* _enable;
+        int _size,_pageSize;
+        
+};
+
+
+
+#endif