Hexiwear 8MB NOR flash memory library.

Dependents:   HexiHeart_Main

W25Q64FV.cpp

Committer:
DimiterK
Date:
2016-10-09
Revision:
0:b71060e03299

File content as of revision 0:b71060e03299:

#include "W25Q64FV.h"

W25Q64FV::W25Q64FV(PinName mosi, PinName miso, PinName sclk, PinName cs, int frequency)
{

    this->cs = new DigitalOut(cs);    
    this->cs->write(true);
    this->frequency = frequency;

    spi = new SPI(mosi, miso, sclk);    
    spi->format(8, 0);
    spi->frequency(frequency);
}

W25Q64FV::~W25Q64FV()
{
    delete spi;
    delete cs;
}

uint16_t W25Q64FV::Id()
{
    cs->write(0);
    spi->write(CMD_MANU_ID);
    spi->write(0);
    spi->write(0);
    spi->write(0);
    unsigned id = (spi->write(0) << 8) | spi->write(0);
    cs->write(1);
    return id;
}

uint32_t W25Q64FV::JEDECId()
{
    cs->write(0);
    spi->write(CMD_JEDEC_ID);
    unsigned id = (spi->write(0) << 16) | (spi->write(0) << 8) | spi->write(0);
    cs->write(1);
    return id;
}

void W25Q64FV::writeEnable(void)
{
    cs->write(0);
    spi->write(CMD_WREN);
    cs->write(1);
}
 
void W25Q64FV::writeDisable(void)
{
    cs->write(0);
    spi->write(CMD_WR_DISABLE) ;
    cs->write(1);
}   

uint8_t W25Q64FV::readStatus(void)
{   
    uint8_t data ;
    cs->write(0);
    spi->write(CMD_RDSR1) ;
    data = spi->write(DUMMY) ;                     // dummy
    cs->write(1);
    return( data ) ;
}

void W25Q64FV::writeStatusReg(int addr)            // Write SR cmd 01h + 3B data
{   
    cs->write(0);
    spi->write(CMD_WRSR1) ;                         // Write SR cmd 01h
    spi->write((addr >> 16)&0xFF) ;                // address
    spi->write((addr >>  8)&0xFF) ;
    spi->write(addr & 0xFF) ;
    cs->write(1);
}

void W25Q64FV::writeSecurityReg(int addr)          // WRSCUR cmd 2Fh + 1B data
{   
    cs->write(0);
   // spi->write(CMD_WRSCUR) ;                         // Write SR cmd 01h
    spi->write(addr & 0xFF) ;
    cs->write(1);
}


uint8_t W25Q64FV::readByte(int addr)                  // Single Byte Read
{
    uint8_t data ;    
    cs->write(0);
    spi->write(CMD_READ_DATA) ;                         // send 03h
    spi->write((addr >> 16)&0xFF) ;
    spi->write((addr >>  8)&0xFF) ;
    spi->write(addr & 0xFF) ;
    data = spi->write(DUMMY) ;                     // write data is dummy 
    cs->write(1);
    return( data ) ;                                // return 1 byte 
}
 
bool W25Q64FV::read(uint32_t addr, uint8_t* dst, uint32_t len)
{
    cs->write(0);
    spi->write(0x03);
    spi->write((addr >> 16) & 0xff);
    spi->write((addr >> 8) & 0xff);
    spi->write(addr & 0xff);
    for (uint32_t i=0; i<len; ++i)
        dst[i] = spi->write(0);
    cs->write(1);
    
    return true;
}

void W25Q64FV::hsread(uint32_t addr, uint8_t* dst, uint32_t len, int frequency)
{
    int save_frequency = this->frequency;
    spi->frequency(frequency);
    cs->write(0);
    spi->write(0x0B);
    spi->write((addr >> 16) & 0xff);
    spi->write((addr >> 8) & 0xff);
    spi->write(addr & 0xff);
    spi->write(0); // dummy
    for (uint32_t i=0; i<len; ++i)
        dst[i] = spi->write(0);
    cs->write(1);
    spi->frequency(save_frequency);
}

uint8_t W25Q64FV::readSFDP(int addr)               // Read SFDP
{
    uint8_t data ;    
    cs->write(0);
    spi->write(CMD_READ_SFDP) ;                       // send cmd 5Ah
    spi->write((addr >> 16)&0xFF) ;                // address[23:16]
    spi->write((addr >>  8)&0xFF) ;                // address[15:8]
    spi->write(addr & 0xFF) ;                      // address[7:0]
    spi->write(DUMMY) ;                            // dummy cycle
    data = spi->write(DUMMY) ;                     // return 1 byte 
    cs->write(1);
    return( data ) ;
}

uint8_t W25Q64FV::wait_while_busy(void)
{
    uint8_t temp = 0;
    cs->write(0);           //Enable device
    spi->write(CMD_RDSR1);   //Send RDSR command
    temp = spi->write(DUMMY);
    cs->write(1);          //Disable
    if (temp & 0x01) return 1;
    else return 0;
}


bool W25Q64FV::page_program(uint32_t addr, uint8_t* write_buffer, uint8_t len)
{
    // no point in writing FF as an empty sector already has those
    // (and if not empty, write won't succeed)
    bool skipped = false;
    while (len > 0 && *write_buffer == 0xFF)
    {
        ++write_buffer;
        --len;
        ++addr;
        skipped = true;
    }
    if (len == 0 && skipped)
        return true; // special case when succeeds when nothing to do

    if (len < 1 || len > 256)
        return false;
        
    // write enable
    writeEnable();

    cs->write(0);
    spi->write(0x02);
    spi->write((uint8_t)(addr >> 16));
    spi->write((uint8_t)(addr >> 8));
    spi->write((uint8_t)addr);
    for (uint16_t i=0; i<len; ++i)
        spi->write(write_buffer[i]);
    cs->write(1);
    wait_while_busy();
    
    return true;
}

void W25Q64FV::sector_erase_4k(uint32_t addr)
{
    cs->write(0);
    spi->write(CMD_ERASE_SECTOR);
    spi->write((uint8_t)(addr >> 16));
    spi->write((uint8_t)(addr >> 8));
    spi->write((uint8_t)addr);
    cs->write(1);
    wait_while_busy();
}

void W25Q64FV::block_erase_32k(uint32_t addr)
{
    cs->write(0);
    spi->write(CMD_ERASE_BLOCK32);
    spi->write((uint8_t)(addr >> 16));
    spi->write((uint8_t)(addr >> 8));
    spi->write((uint8_t)addr);
    cs->write(1);
    wait_while_busy();
}    

void W25Q64FV::block_erase_64k(uint32_t addr)
{
    cs->write(0);
    spi->write(CMD_ERASE_BLOCK64);
    spi->write((uint8_t)(addr >> 16));
    spi->write((uint8_t)(addr >> 8));
    spi->write((uint8_t)addr);
    cs->write(1);
    wait_while_busy();
}    

void W25Q64FV::chip_erase()
{
    cs->write(0);
    spi->write(CMD_ERASE_CHIP);
    cs->write(1);
    wait_while_busy();
}






void W25Q64FV::writeArray(uint32_t address, uint8_t* pData, uint32_t arrayLength)
{
    unsigned int i = 0;
    cs->write(0);                        //Enable device
    spi->write(CMD_WREN);                //Send WREN command
    cs->write(1);                      //Disable device

    cs->write(0);                        //Enable device
    spi->write(CMD_PAGEPROG);            //Send Byte Program command
    spi->write((uint8_t)(address >> 16) & 0xFF);
    spi->write((uint8_t)(address >>  8) & 0xFF);
    spi->write(0x00);

    for (i=0;i<arrayLength;i++)
    {
        spi->write(pData[i]);            //Send byte to be programmed 
    }
    cs->write(1);              //Disable device
 
    //Wait Busy
    while ((readStatus() & 0x01) == 0x01) //Waste time until not busy
    {
    }
}


void W25Q64FV::readArray(uint32_t address, uint8_t* pData, uint32_t arrayLength)
{
    unsigned int i = 0;

    cs->write(0);                                    //Enable device
    spi->write(CMD_READ_DATA);                       //Read command
    spi->write((uint8_t)(address >> 16));
    spi->write((uint8_t)(address >>  8));
    spi->write((uint8_t) address);

    for (i = 0; i <arrayLength; i++)                //Read until no_bytes is reached
    {
        pData[i] = spi->write(DUMMY);                      //Receive bytes
    }
    cs->write(1);                                  //Disable device

    //Wait Busy
    while (readStatus() & 0x01)      //Waste time until not busy
    {
    }
}