/* Arduino SPIFlash Library v.2.2.0 * Copyright (C) 2015 by Prajwal Bhattaram * Modified by Prajwal Bhattaram - 24/11/2015 * * This file is part of the Arduino SPIFlash Library. This library is for * Winbond NOR flash memory modules. In its current form it enables reading * and writing individual data variables, structs and arrays from and to various locations; * reading and writing pages; continuous read functions; sector, block and chip erase; * suspending and resuming programming/erase and powering down for low power operation. * * This Library is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This Library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License v3.0 * along with the Arduino SPIFlash Library. If not, see * . */ #ifndef SPIFLASH_H #define SPIFLASH_H #include class SPIFlash { public: //----------------------------------------------Constructor-----------------------------------------------// SPIFlash(uint8_t cs = 10, bool overflow = true); //----------------------------------------Initial / Chip Functions----------------------------------------// void begin(); uint16_t getManID(); uint32_t getJEDECID(); bool getAddress(uint16_t size, uint16_t &page_number, uint8_t &offset); uint32_t getAddress(uint16_t size); uint16_t getChipName(); uint16_t sizeofStr(String &inputStr); uint32_t getCapacity(); uint32_t getMaxPage(); //-------------------------------------------Write / Read Bytes-------------------------------------------// bool writeByte(uint32_t address, uint8_t data, bool errorCheck = true); bool writeByte(uint16_t page_number, uint8_t offset, uint8_t data, bool errorCheck = true); uint8_t readByte(uint16_t page_number, uint8_t offset, bool fastRead = false); uint8_t readByte(uint32_t address, bool fastRead = false); //----------------------------------------Write / Read Byte Arrays----------------------------------------// bool writeByteArray(uint32_t address, uint8_t *data_buffer, uint16_t bufferSize, bool errorCheck = true); bool writeByteArray(uint16_t page_number, uint8_t offset, uint8_t *data_buffer, uint16_t bufferSize, bool errorCheck = true); uint8_t readByteArray(uint32_t address, uint8_t *data_buffer, uint16_t bufferSize, bool fastRead = false); uint8_t readByteArray(uint16_t page_number, uint8_t offset, uint8_t *data_buffer, uint16_t bufferSize, bool fastRead = false); //-------------------------------------------Write / Read Chars-------------------------------------------// bool writeChar(uint32_t address, int8_t data, bool errorCheck = true); bool writeChar(uint16_t page_number, uint8_t offset, int8_t data, bool errorCheck = true); int8_t readChar(uint32_t address, bool fastRead = false); int8_t readChar(uint16_t page_number, uint8_t offset, bool fastRead = false); //----------------------------------------Write / Read Char Arrays----------------------------------------// bool writeCharArray(uint32_t address, char *data_buffer, uint16_t bufferSize, bool errorCheck = true); bool writeCharArray(uint16_t page_number, uint8_t offset, char *data_buffer, uint16_t bufferSize, bool errorCheck = true); uint8_t readCharArray(uint32_t address, char *data_buffer, uint16_t buffer_size, bool fastRead = false); uint8_t readCharArray(uint16_t page_number, uint8_t offset, char *data_buffer, uint16_t buffer_size, bool fastRead = false); //------------------------------------------Write / Read Shorts------------------------------------------// bool writeShort(uint32_t address, int16_t data, bool errorCheck = true); bool writeShort(uint16_t page_number, uint8_t offset, int16_t data, bool errorCheck = true); int16_t readShort(uint32_t address, bool fastRead = false); int16_t readShort(uint16_t page_number, uint8_t offset, bool fastRead = false); //-------------------------------------------Write / Read Words-------------------------------------------// bool writeWord(uint32_t address, uint16_t data, bool errorCheck = true); bool writeWord(uint16_t page_number, uint8_t offset, uint16_t data, bool errorCheck = true); uint16_t readWord(uint32_t address, bool fastRead = false); uint16_t readWord(uint16_t page_number, uint8_t offset, bool fastRead = false); //-------------------------------------------Write / Read Longs-------------------------------------------// bool writeLong(uint32_t address, int32_t data, bool errorCheck = true); bool writeLong(uint16_t page_number, uint8_t offset, int32_t data, bool errorCheck = true); int32_t readLong(uint32_t address, bool fastRead = false); int32_t readLong(uint16_t page_number, uint8_t offset, bool fastRead = false); //--------------------------------------Write / Read Unsigned Longs---------------------------------------// bool writeULong(uint32_t address, uint32_t data, bool errorCheck = true); bool writeULong(uint16_t page_number, uint8_t offset, uint32_t data, bool errorCheck = true); uint32_t readULong(uint32_t address, bool fastRead = false); uint32_t readULong(uint16_t page_number, uint8_t offset, bool fastRead = false); //-------------------------------------------Write / Read Floats------------------------------------------// bool writeFloat(uint32_t address, float data, bool errorCheck = true); bool writeFloat(uint16_t page_number, uint8_t offset, float data, bool errorCheck = true); float readFloat(uint32_t address, bool fastRead = false); float readFloat(uint16_t page_number, uint8_t offset, bool fastRead = false); //------------------------------------------Write / Read Strings------------------------------------------// bool writeStr(uint32_t address, String &inputStr, bool errorCheck = true); bool writeStr(uint16_t page_number, uint8_t offset, String &inputStr, bool errorCheck = true); bool readStr(uint32_t address, String &outStr, bool fastRead = false); bool readStr(uint16_t page_number, uint8_t offset, String &outStr, bool fastRead = false); //-------------------------------------------Write / Read Pages-------------------------------------------// bool writePage(uint16_t page_number, uint8_t *data_buffer, bool errorCheck = true); bool readPage(uint16_t page_number, uint8_t *data_buffer, bool fastRead = false); //------------------------------------------Write / Read Anything-----------------------------------------// template bool writeAnything(uint32_t address, const T& value, bool errorCheck = true); template bool writeAnything(uint16_t page_number, uint8_t offset, const T& value, bool errorCheck = true); template bool readAnything(uint32_t address, T& value, bool fastRead = false); template bool readAnything(uint16_t page_number, uint8_t offset, T& value, bool fastRead = false); //--------------------------------------------Erase functions---------------------------------------------// bool eraseSector(uint32_t address); bool eraseSector(uint16_t page_number, uint8_t offset); bool eraseBlock32K(uint32_t address); bool eraseBlock32K(uint16_t page_number, uint8_t offset); bool eraseBlock64K(uint32_t address); bool eraseBlock64K(uint16_t page_number, uint8_t offset); bool eraseChip(void); //---------------------------------------------Power functions--------------------------------------------// bool suspendProg(void); bool resumeProg(void); bool powerDown(void); bool powerUp(void); //--------------------------------------------Private functions-------------------------------------------// private: void _troubleshoot(uint8_t error); void _cmd(uint8_t cmd, bool _continue = true, uint8_t cs = 0); void _endProcess(void); void _errorCodeCheck(void); void _beginRead(uint32_t address); void _beginFastRead(uint32_t address); bool _noSuspend(void); bool _notBusy(uint32_t timeout = 10L); bool _notPrevWritten(uint32_t address, uint8_t size = 1); bool _addressCheck(uint32_t address); bool _beginWrite(uint32_t address); bool _writeNextByte(uint8_t c, bool _continue = true); bool _writeEnable(void); bool _writeDisable(void); bool _getJedecId(uint8_t *b1, uint8_t *b2, uint8_t *b3); bool _getManId(uint8_t *b1, uint8_t *b2); bool _chipID(void); uint8_t _readStat1(void); uint8_t _readNextByte(bool _continue = true); uint32_t _getAddress(uint16_t page_number, uint8_t offset = 0); uint32_t _prepRead(uint32_t address); uint32_t _prepRead(uint16_t page_number, uint8_t offset = 0); uint32_t _prepWrite(uint32_t address); uint32_t _prepWrite(uint16_t page_number, uint8_t offset = 0); template bool _writeErrorCheck(uint32_t address, const T& value); //-------------------------------------------Private variables------------------------------------------// bool pageOverflow; volatile uint8_t *cs_port; uint8_t cs_mask, csPin, errorcode; uint16_t name; uint32_t capacity, maxPage; uint32_t currentAddress = 1; const uint8_t devType[10] = {0x5, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17}; const uint32_t memSize[10] = {64L * 1024L, 128L * 1024L, 256L * 1024L, 512L * 1024L, 1L * 1024L * 1024L, 2L * 1024L * 1024L, 4L * 1024L * 1024L, 8L * 1024L * 1024L, 16L * 1024L * 1024L}; const uint16_t chipName[10] = {05, 10, 20, 40, 80, 16, 32, 64, 128, 256}; }; //--------------------------------------------Templates-------------------------------------------// // Writes any type of data to a specific location in the flash memory. // Has two variants: // A. Takes two arguments - // 1. address --> Any address from 0 to maxAddress // 2. T& value --> Variable to return data into // 4. errorCheck --> Turned on by default. Checks for writing errors // B. Takes three arguments - // 1. page --> Any page number from 0 to maxPage // 2. offset --> Any offset within the page - from 0 to 255 // 3. const T& value --> Variable with the data to be written // 4. errorCheck --> Turned on by default. Checks for writing errors // WARNING: You can only write to previously erased memory locations (see datasheet). // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) // Variant A template bool SPIFlash::writeAnything(uint32_t address, const T& value, bool errorCheck) { if (!_prepWrite(address)) return false; else { const byte* p = (const byte*)(const void*)&value; _beginWrite(address); for (uint16_t i = 0; i < sizeof(value); i++) { #if defined (__arm__) && defined (__SAM3X8E__) if (i == sizeof(value)-1) _writeNextByte(*p++, false); #endif _writeNextByte(*p++); } _endProcess(); } if (!errorCheck) return true; else return _writeErrorCheck(address, value); } // Variant B template bool SPIFlash::writeAnything(uint16_t page_number, uint8_t offset, const T& value, bool errorCheck) { uint32_t address = _getAddress(page_number, offset); return writeAnything(address, value, errorCheck); } // Reads any type of data from a specific location in the flash memory. // Has two variants: // A. Takes two arguments - // 1. address --> Any address from 0 to maxAddress // 2. T& value --> Variable to return data into // 2. fastRead --> defaults to false - executes _beginFastRead() if set to true // B. Takes three arguments - // 1. page --> Any page number from 0 to maxPage // 2. offset --> Any offset within the page - from 0 to 255 // 3. T& value --> Variable to return data into // 3. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A template bool SPIFlash::readAnything(uint32_t address, T& value, bool fastRead) { if (!_prepRead(address)) return false; byte* p = (byte*)(void*)&value; if(!fastRead) _beginRead(address); else _beginFastRead(address); for (uint16_t i = 0; i < sizeof(value); i++) { #if defined (__arm__) && defined (__SAM3X8E__) if (i == sizeof(value)-1) *p++ = _readNextByte(false); #endif *p++ =_readNextByte(); } _endProcess(); return true; } // Variant B template bool SPIFlash::readAnything(uint16_t page_number, uint8_t offset, T& value, bool fastRead) { uint32_t address = _getAddress(page_number, offset); return readAnything(address, value, fastRead); } // Private template to check for errors in writing to flash memory template bool SPIFlash::_writeErrorCheck(uint32_t address, const T& value) { if (!_prepRead(address)) return false; const byte* p = (const byte*)(const void*)&value; _beginRead(address); for(uint16_t i = 0; i < sizeof(value);i++) { #if defined (__arm__) && defined (__SAM3X8E__) if (i == sizeof(value)-1) { if (*p++ != _readNextByte(false)) return false; else return true; } else if (*p++ != _readNextByte()) return false; #elif defined (__AVR__) if (*p++ != _readNextByte()) return false; #endif } _endProcess(); return true; } #endif // _SPIFLASH_H_