Phumphathai Chansriwong / 25LCxxx_SPI

Ser25lcxxx.cpp

Committer:
mariob
Date:
2015-07-17
Revision:
3:be69a9f6f738
Parent:
2:3a3404dbd3eb
Child:
4:9ac3c5c3a4c6

File content as of revision 3:be69a9f6f738:

/*
* Ser25lcxxx library
* Copyright (c) 2010 Hendrik Lipka
* 
* 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 "Ser25lcxxx.h"
#include "wait_api.h"

#define HIGH(x)     ((x&0xff00)>>8)
#define LOW(x)      (x&0xff)

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

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

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 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(EEPROM_CMD_WRITE);
        spi.write(startAdr>>16);
        spi.write(HIGH(startAdr));
        spi.write(LOW(startAdr));
    }

    //write data
    for (int i=0; i<len; i++)
        spi.write(data[i]);
    wait_us(1);

    //disable eeprom
    cs = 1;

    //wait until write operation ends
    if (!waitForWrite())
        return 0;

    return len;
}

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 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;
    }
    
    return true;
}

void Ser25LCxxx::enableWrite () {
    //enable eeprom
    cs = 0;
    wait_us(1);

    //send command
    spi.write(EEPROM_CMD_WREN);
    wait_us(1);
    
    //disable eeprom
    cs = 1;
}

void Ser25LCxxx::writeStatus (unsigned char val) {
    enableWrite();

    //enable eeprom
    cs = 0;
    wait_us(1);

    //send command
    spi.write(EEPROM_CMD_WRSR);
    
    //write stautus
    spi.write(val);
    wait_us(1);

    //disable eeprom
    cs = 1;
}