From 53e85ec16c6a1bb4a4bf0f997e376f5c7228f886 Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Mon, 17 Apr 2017 11:59:50 +1000 Subject: [PATCH 01/34] Updated Travis tag --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 26cda24..a26ae4c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# SPIFlash [![Build Status](https://travis-ci.org/Marzogh/SPIFlash.svg?branch=dev)](https://travis-ci.org/Marzogh/SPIFlash) [![DOI](https://zenodo.org/badge/18908/Marzogh/SPIFlash.svg)](https://zenodo.org/badge/latestdoi/18908/Marzogh/SPIFlash) +# SPIFlash [![Build Status](https://travis-ci.org/Marzogh/SPIFlash.svg?branch=multiflash-compat-w.i.p)](https://travis-ci.org/Marzogh/SPIFlash) [![DOI](https://zenodo.org/badge/18908/Marzogh/SPIFlash.svg)](https://zenodo.org/badge/latestdoi/18908/Marzogh/SPIFlash) ### Arduino library for Winbond Flash Memory Chips Download the latest stable release (v2.6.0) from here. Please report any bugs in issues. From 25efc621b374ee2dafad6dd8ba86b34818d1eae4 Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Wed, 3 May 2017 01:28:51 +1000 Subject: [PATCH 02/34] Comms with Microchip flash memory established. Need to finish troubleshooting I/O functions. --- src/FLASHIO.cpp | 458 +++++++++++++++++++++++++++++++++++++++++++++++ src/SPIFlash.cpp | 425 +------------------------------------------ src/SPIFlash.h | 10 +- src/defines.h | 1 + 4 files changed, 466 insertions(+), 428 deletions(-) create mode 100644 src/FLASHIO.cpp diff --git a/src/FLASHIO.cpp b/src/FLASHIO.cpp new file mode 100644 index 0000000..7de04bd --- /dev/null +++ b/src/FLASHIO.cpp @@ -0,0 +1,458 @@ +/* Arduino SPIFlash Library v.2.7.0 + * Copyright (C) 2017 by Prajwal Bhattaram + * Created by Prajwal Bhattaram - 02/05/2017 + * + * 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 + * . + */ + +#include "SPIFlash.h" + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +// Private functions used by read, write and erase operations // +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + +//Double checks all parameters before calling a read or write. Comes in two variants +//Variant A: Takes address and returns the address if true, else returns false. Throws an error if there is a problem. +bool SPIFlash::_prep(uint8_t opcode, uint32_t address, uint32_t size) { + switch (opcode) { + case PAGEPROG: + if (!_addressCheck(address, size)) { + return false; + } + if(!_notBusy() || !_writeEnable()){ + return false; + } + #ifndef HIGHSPEED + if(!_notPrevWritten(address, size)) { + return false; + } + #endif + return true; + break; + + default: + if (!_addressCheck(address, size)) { + return false; + } + if (!_notBusy()){ + return false; + } + return true; + break; + } +} + +//Variant B: Take the opcode, page number, offset and size of data block as arguments +bool SPIFlash::_prep(uint8_t opcode, uint32_t page_number, uint8_t offset, uint32_t size) { + uint32_t address = _getAddress(page_number, offset); + return _prep(opcode, address, size); +} + +bool SPIFlash::_transferAddress(void) { + _nextByte(_currentAddress >> 16); + _nextByte(_currentAddress >> 8); + _nextByte(_currentAddress); +} + +bool SPIFlash::_startSPIBus(void) { +#ifndef __AVR_ATtiny85__ + #ifndef SPI_HAS_TRANSACTION + noInterrupts(); + #endif + + #if defined (ARDUINO_ARCH_SAM) + _dueSPIInit(DUE_SPI_CLK); + #else + #if defined (ARDUINO_ARCH_AVR) + //save current SPI settings + _SPCR = SPCR; + _SPSR = SPSR; + #endif + #ifdef SPI_HAS_TRANSACTION + SPI.beginTransaction(_settings); + #else + SPI.setClockDivider(SPI_CLOCK_DIV_4) + SPI.setDataMode(SPI_MODE0); + SPI.setBitOrder(MSBFIRST); + #endif + #endif +#else + +#endif + SPIBusState = true; + return true; +} + +//Initiates SPI operation - but data is not transferred yet. Always call _prep() before this function (especially when it involves writing or reading to/from an address) +bool SPIFlash::_beginSPI(uint8_t opcode) { + if (!SPIBusState) { + _startSPIBus(); + } + CHIP_SELECT + switch (opcode) { + case FASTREAD: + _nextByte(opcode); + _nextByte(DUMMYBYTE); + _transferAddress(); + break; + + case READDATA: + _nextByte(opcode); + _transferAddress(); + break; + + case PAGEPROG: + _nextByte(opcode); + _transferAddress(); + break; + + default: + _nextByte(opcode); + break; + } + return true; +} +//SPI data lines are left open until _endSPI() is called + +//Reads/Writes next byte. Call 'n' times to read/write 'n' number of bytes. Should be called after _beginSPI() +uint8_t SPIFlash::_nextByte(uint8_t data) { +#if defined (ARDUINO_ARCH_SAM) + return _dueSPITransfer(data); +#else + return xfer(data); +#endif +} + +//Reads/Writes next int. Call 'n' times to read/write 'n' number of bytes. Should be called after _beginSPI() +uint16_t SPIFlash::_nextInt(uint16_t data) { + #ifndef __AVR_ATtiny85__ + return SPI.transfer16(data); + #else + uint16_t _data; + _data = xfer(data >> 0); + data = (_data << 8); + _data += xfer(data >> 8); + return _data; + #endif +} + +//Reads/Writes next data buffer. Call 'n' times to read/write 'n' number of bytes. Should be called after _beginSPI() +void SPIFlash::_nextBuf(uint8_t opcode, uint8_t *data_buffer, uint32_t size) { + uint8_t *_dataAddr = &(*data_buffer); + switch (opcode) { + case READDATA: + #if defined (ARDUINO_ARCH_SAM) + _dueSPIRecByte(&(*data_buffer), size); + #elif defined (ARDUINO_ARCH_AVR) && !defined (__AVR_ATtiny85__) + SPI.transfer(&data_buffer[0], size); + #else + for (uint16_t i = 0; i < size; i++) { + *_dataAddr = xfer(NULLBYTE); + _dataAddr++; + } + #endif + break; + + case PAGEPROG: + #if defined (ARDUINO_ARCH_SAM) + _dueSPISendByte(&(*data_buffer), size); + #elif defined (ARDUINO_ARCH_AVR) && !defined (__AVR_ATtiny85__) + SPI.transfer(&(*data_buffer), size); + #else + for (uint16_t i = 0; i < size; i++) { + xfer(*_dataAddr); + _dataAddr++; + } + #endif + break; + } +} + +//Stops all operations. Should be called after all the required data is read/written from repeated _nextByte() calls +void SPIFlash::_endSPI(void) { + CHIP_DESELECT + #ifdef SPI_HAS_TRANSACTION + SPI.endTransaction(); + #else + interrupts(); + #endif + + #if defined (ARDUINO_ARCH_AVR) && !defined (__AVR_ATtiny85__) + SPCR = _SPCR; + SPSR = _SPSR; + #endif + SPIBusState = false; +} + +// Checks if status register 1 can be accessed - used during powerdown and power up and for debugging +uint8_t SPIFlash::_readStat1(void) { + _beginSPI(READSTAT1); + uint8_t stat1 = _nextByte(); + CHIP_DESELECT + return stat1; +} + +// Checks if status register 2 can be accessed, if yes, reads and returns it +uint8_t SPIFlash::_readStat2(void) { + _beginSPI(READSTAT2); + uint8_t stat2 = _nextByte(); + stat2 = _nextByte(); + CHIP_DESELECT + return stat2; +} + +// Checks the erase/program suspend flag before enabling/disabling a program/erase suspend operation +bool SPIFlash::_noSuspend(void) { + switch (_chip.manufacturerID) { + case WINBOND_MANID: + if(_readStat2() & SUS) { + errorcode = SYSSUSPEND; + return false; + } + return true; + break; + + case MICROCHIP_MANID: + if(_readStat1() & WSE || _readStat1() & WSP) { + errorcode = SYSSUSPEND; + return false; + } + return true; + } + +} + +// Polls the status register 1 until busy flag is cleared or timeout +bool SPIFlash::_notBusy(uint32_t timeout) { + uint32_t startTime = millis(); + + do { + state = _readStat1(); + if((millis()-startTime) > timeout){ + errorcode = CHIPBUSY; + #ifdef RUNDIAGNOSTIC + _troubleshoot(); + #endif + _endSPI(); + return false; + } + } while(state & BUSY); + return true; +} + +//Enables writing to chip by setting the WRITEENABLE bit +bool SPIFlash::_writeEnable(uint32_t timeout) { + uint32_t startTime = millis(); + if (!(state & WRTEN)) { + do { + _beginSPI(WRITEENABLE); + CHIP_DESELECT + state = _readStat1(); + if((millis()-startTime) > timeout) { + errorcode = CANTENWRITE; + #ifdef RUNDIAGNOSTIC + _troubleshoot(); + #endif + _endSPI(); + return false; + } + } while (!(state & WRTEN)); + } + return true; +} + +//Disables writing to chip by setting the Write Enable Latch (WEL) bit in the Status Register to 0 +//_writeDisable() is not required under the following conditions because the Write Enable Latch (WEL) flag is cleared to 0 +// i.e. to write disable state: +// Power-up, Write Disable, Page Program, Quad Page Program, Sector Erase, Block Erase, Chip Erase, Write Status Register, +// Erase Security Register and Program Security register +bool SPIFlash::_writeDisable(void) { + _beginSPI(WRITEDISABLE); + CHIP_DESELECT + return true; +} + +//Gets address from page number and offset. Takes two arguments: +// 1. page_number --> Any page number from 0 to maxPage +// 2. offset --> Any offset within the page - from 0 to 255 +uint32_t SPIFlash::_getAddress(uint16_t page_number, uint8_t offset) { + uint32_t address = page_number; + return ((address << 8) + offset); +} + +//Checks the device ID to establish storage parameters +bool SPIFlash::_getManId(uint8_t *b1, uint8_t *b2) { + if(!_notBusy()) + return false; + _beginSPI(MANID); + _nextByte(); + _nextByte(); + _nextByte(); + *b1 = _nextByte(); + *b2 = _nextByte(); + CHIP_DESELECT + return true; +} + +//Checks for presence of chip by requesting JEDEC ID +bool SPIFlash::_getJedecId(void) { + if(!_notBusy()) { + return false; + } + _beginSPI(JEDECID); + _chip.manufacturerID = _nextByte(NULLBYTE); // manufacturer id + _chip.memoryTypeID = _nextByte(NULLBYTE); // memory type + _chip.capacityID = _nextByte(NULLBYTE); // capacity + CHIP_DESELECT + if (!_chip.manufacturerID || !_chip.memoryTypeID || !_chip.capacityID) { + errorcode = NORESPONSE; + #ifdef RUNDIAGNOSTIC + _troubleshoot(); + #endif + return false; + } + else { + return true; + } +} + +bool SPIFlash::_getSFDP(void) { + if(!_notBusy()) { + return false; + } + _beginSPI(READSFDP); + _currentAddress = 0x00; + _transferAddress(); + _nextByte(DUMMYBYTE); + for (uint8_t i = 0; i < 4; i++) { + _chip.sfdp += (_nextByte() << (8*i)); + } + CHIP_DESELECT + if (_chip.sfdp = 0x50444653) { + //Serial.print("_chip.sfdp: "); + //Serial.println(_chip.sfdp, HEX); + return true; + } + else { + return false; + } +} + +//Identifies the chip +bool SPIFlash::_chipID(void) { + //Get Manfucturer/Device ID so the library can identify the chip + //_getSFDP(); + if (!_getJedecId()) { + return false; + } + + if (_chip.manufacturerID == MICROCHIP_MANID) { + uint8_t _stat1 = _readStat1(); + _stat1 &= 0xC3; + _beginSPI(WRITESTATEN); + CHIP_DESELECT + _beginSPI(WRITESTAT); + _nextByte(_stat1); + CHIP_DESELECT + } + + // If no capacity is defined in user code + if (!_chip.capacity) { + _chip.supported = _chip.manufacturerID; + if (_chip.supported == WINBOND_MANID || _chip.supported == MICROCHIP_MANID) { + //Identify capacity + for (uint8_t i = 0; i < sizeof(_capID); i++) + { + if (_chip.capacityID == _capID[i]) { + _chip.capacity = (_memSize[i]); + _chip.eraseTime = _eraseTime[i]; + } + } + return true; + } + else { + errorcode = UNKNOWNCAP; //Error code for unidentified capacity + #ifdef RUNDIAGNOSTIC + _troubleshoot(); + #endif + return false; + } + } + else { + // If a custom chip size is defined + _chip.eraseTime = _chip.capacity/KB8; + _chip.supported = false;// This chip is not officially supported + errorcode = UNKNOWNCHIP; //Error code for unidentified chip + #ifdef RUNDIAGNOSTIC + _troubleshoot(); + #endif + //while(1); //Enable this if usercode is not meant to be run on unsupported chips + } + return true; +} + +//Checks to see if pageOverflow is permitted and assists with determining next address to read/write. +//Sets the global address variable +bool SPIFlash::_addressCheck(uint32_t address, uint32_t size) { + if (errorcode == UNKNOWNCAP || errorcode == NORESPONSE) { + #ifdef RUNDIAGNOSTIC + _troubleshoot(); + #endif + return false; + } + if (!_chip.eraseTime) { + errorcode = CALLBEGIN; + #ifdef RUNDIAGNOSTIC + _troubleshoot(); + #endif + return false; + } + + for (uint32_t i = 0; i < size; i++) { + if (address + i >= _chip.capacity) { + if (!pageOverflow) { + errorcode = OUTOFBOUNDS; + #ifdef RUNDIAGNOSTIC + _troubleshoot(); + #endif + return false; // At end of memory - (!pageOverflow) + } + else { + _currentAddress = 0x00; + return true; // At end of memory - (pageOverflow) + } + } + } + _currentAddress = address; + return true; // Not at end of memory if (address < _chip.capacity) +} + +bool SPIFlash::_notPrevWritten(uint32_t address, uint32_t size) { + _beginSPI(READDATA); + for (uint16_t i = 0; i < size; i++) { + if (_nextByte() != 0xFF) { + CHIP_DESELECT; + return false; + } + } + CHIP_DESELECT + return true; +} diff --git a/src/SPIFlash.cpp b/src/SPIFlash.cpp index f32bdbd..7aeb4b2 100644 --- a/src/SPIFlash.cpp +++ b/src/SPIFlash.cpp @@ -1,8 +1,8 @@ -/* Arduino SPIFlash Library v.2.6.0 +/* Arduino SPIFlash Library v.2.7.0 * Copyright (C) 2017 by Prajwal Bhattaram * Created by Prajwal Bhattaram - 19/05/2015 * Modified by @boseji - 02/03/2017 - * Modified by Prajwal Bhattaram - 14/04/2017 + * Modified by Prajwal Bhattaram - 02/05/2017 * * 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 @@ -54,427 +54,6 @@ SPIFlash::SPIFlash(uint8_t cs, bool overflow) { pinMode(csPin, OUTPUT); } #endif -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -// Private functions used by read, write and erase operations // -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - -//Double checks all parameters before calling a read or write. Comes in two variants -//Variant A: Takes address and returns the address if true, else returns false. Throws an error if there is a problem. -bool SPIFlash::_prep(uint8_t opcode, uint32_t address, uint32_t size) { - switch (opcode) { - case PAGEPROG: - if (!_addressCheck(address, size)) { - return false; - } - if(!_notBusy() || !_writeEnable()){ - return false; - } - #ifndef HIGHSPEED - if(!_notPrevWritten(address, size)) { - return false; - } - #endif - return true; - break; - - default: - if (!_addressCheck(address, size)) { - return false; - } - if (!_notBusy()){ - return false; - } - return true; - break; - } -} - -//Variant B: Take the opcode, page number, offset and size of data block as arguments -bool SPIFlash::_prep(uint8_t opcode, uint32_t page_number, uint8_t offset, uint32_t size) { - uint32_t address = _getAddress(page_number, offset); - return _prep(opcode, address, size); -} - -bool SPIFlash::_transferAddress(void) { - _nextByte(_currentAddress >> 16); - _nextByte(_currentAddress >> 8); - _nextByte(_currentAddress); -} - -bool SPIFlash::_startSPIBus(void) { -#ifndef __AVR_ATtiny85__ - #ifndef SPI_HAS_TRANSACTION - noInterrupts(); - #endif - - #if defined (ARDUINO_ARCH_SAM) - _dueSPIInit(DUE_SPI_CLK); - #else - #if defined (ARDUINO_ARCH_AVR) - //save current SPI settings - _SPCR = SPCR; - _SPSR = SPSR; - #endif - #ifdef SPI_HAS_TRANSACTION - SPI.beginTransaction(_settings); - #else - SPI.setClockDivider(SPI_CLOCK_DIV_4) - SPI.setDataMode(SPI_MODE0); - SPI.setBitOrder(MSBFIRST); - #endif - #endif -#else - -#endif - SPIBusState = true; - return true; -} - -//Initiates SPI operation - but data is not transferred yet. Always call _prep() before this function (especially when it involves writing or reading to/from an address) -bool SPIFlash::_beginSPI(uint8_t opcode) { - if (!SPIBusState) { - _startSPIBus(); - } - CHIP_SELECT - switch (opcode) { - case FASTREAD: - _nextByte(opcode); - _nextByte(DUMMYBYTE); - _transferAddress(); - break; - - case READDATA: - _nextByte(opcode); - _transferAddress(); - break; - - case PAGEPROG: - _nextByte(opcode); - _transferAddress(); - break; - - default: - _nextByte(opcode); - break; - } - return true; -} -//SPI data lines are left open until _endSPI() is called - -//Reads/Writes next byte. Call 'n' times to read/write 'n' number of bytes. Should be called after _beginSPI() -uint8_t SPIFlash::_nextByte(uint8_t data) { -#if defined (ARDUINO_ARCH_SAM) - return _dueSPITransfer(data); -#else - return xfer(data); -#endif -} - -//Reads/Writes next int. Call 'n' times to read/write 'n' number of bytes. Should be called after _beginSPI() -uint16_t SPIFlash::_nextInt(uint16_t data) { - #ifndef __AVR_ATtiny85__ - return SPI.transfer16(data); - #else - uint16_t _data; - _data = xfer(data >> 0); - data = (_data << 8); - _data += xfer(data >> 8); - return _data; - #endif -} - -//Reads/Writes next data buffer. Call 'n' times to read/write 'n' number of bytes. Should be called after _beginSPI() -void SPIFlash::_nextBuf(uint8_t opcode, uint8_t *data_buffer, uint32_t size) { - uint8_t *_dataAddr = &(*data_buffer); - switch (opcode) { - case READDATA: - #if defined (ARDUINO_ARCH_SAM) - _dueSPIRecByte(&(*data_buffer), size); - #elif defined (ARDUINO_ARCH_AVR) && !defined (__AVR_ATtiny85__) - SPI.transfer(&data_buffer[0], size); - #else - for (uint16_t i = 0; i < size; i++) { - *_dataAddr = xfer(NULLBYTE); - _dataAddr++; - } - #endif - break; - - case PAGEPROG: - #if defined (ARDUINO_ARCH_SAM) - _dueSPISendByte(&(*data_buffer), size); - #elif defined (ARDUINO_ARCH_AVR) && !defined (__AVR_ATtiny85__) - SPI.transfer(&(*data_buffer), size); - #else - for (uint16_t i = 0; i < size; i++) { - xfer(*_dataAddr); - _dataAddr++; - } - #endif - break; - } -} - -//Stops all operations. Should be called after all the required data is read/written from repeated _nextByte() calls -void SPIFlash::_endSPI(void) { - CHIP_DESELECT - #ifdef SPI_HAS_TRANSACTION - SPI.endTransaction(); - #else - interrupts(); - #endif - - #if defined (ARDUINO_ARCH_AVR) && !defined (__AVR_ATtiny85__) - SPCR = _SPCR; - SPSR = _SPSR; - #endif - SPIBusState = false; -} - -// Checks if status register 1 can be accessed - used during powerdown and power up and for debugging -uint8_t SPIFlash::_readStat1(void) { - _beginSPI(READSTAT1); - uint8_t stat1 = _nextByte(); - CHIP_DESELECT - return stat1; -} - -// Checks if status register 2 can be accessed, if yes, reads and returns it -uint8_t SPIFlash::_readStat2(void) { - _beginSPI(READSTAT2); - uint8_t stat2 = _nextByte(); - stat2 = _nextByte(); - CHIP_DESELECT - return stat2; -} - -// Checks the erase/program suspend flag before enabling/disabling a program/erase suspend operation -bool SPIFlash::_noSuspend(void) { - switch (_chip.manufacturerID) { - case WINBOND_MANID: - if(_readStat2() & SUS) { - errorcode = SYSSUSPEND; - return false; - } - return true; - break; - - case MICROCHIP_MANID: - if(_readStat1() & WSE || _readStat1() & WSP) { - errorcode = SYSSUSPEND; - return false; - } - return true; - } - -} - -// Polls the status register 1 until busy flag is cleared or timeout -bool SPIFlash::_notBusy(uint32_t timeout) { - uint32_t startTime = millis(); - - do { - state = _readStat1(); - if((millis()-startTime) > timeout){ - errorcode = CHIPBUSY; - #ifdef RUNDIAGNOSTIC - _troubleshoot(); - #endif - _endSPI(); - return false; - } - } while(state & BUSY); - return true; -} - -//Enables writing to chip by setting the WRITEENABLE bit -bool SPIFlash::_writeEnable(uint32_t timeout) { - uint32_t startTime = millis(); - if (!(state & WRTEN)) { - do { - _beginSPI(WRITEENABLE); - CHIP_DESELECT - state = _readStat1(); - if((millis()-startTime) > timeout) { - errorcode = CANTENWRITE; - #ifdef RUNDIAGNOSTIC - _troubleshoot(); - #endif - _endSPI(); - return false; - } - } while (!(state & WRTEN)); - } - return true; -} - -//Disables writing to chip by setting the Write Enable Latch (WEL) bit in the Status Register to 0 -//_writeDisable() is not required under the following conditions because the Write Enable Latch (WEL) flag is cleared to 0 -// i.e. to write disable state: -// Power-up, Write Disable, Page Program, Quad Page Program, Sector Erase, Block Erase, Chip Erase, Write Status Register, -// Erase Security Register and Program Security register -bool SPIFlash::_writeDisable(void) { - _beginSPI(WRITEDISABLE); - CHIP_DESELECT - return true; -} - -//Gets address from page number and offset. Takes two arguments: -// 1. page_number --> Any page number from 0 to maxPage -// 2. offset --> Any offset within the page - from 0 to 255 -uint32_t SPIFlash::_getAddress(uint16_t page_number, uint8_t offset) { - uint32_t address = page_number; - return ((address << 8) + offset); -} - -//Checks the device ID to establish storage parameters -bool SPIFlash::_getManId(uint8_t *b1, uint8_t *b2) { - if(!_notBusy()) - return false; - _beginSPI(MANID); - _nextByte(); - _nextByte(); - _nextByte(); - *b1 = _nextByte(); - *b2 = _nextByte(); - CHIP_DESELECT - return true; -} - -//Checks for presence of chip by requesting JEDEC ID -bool SPIFlash::_getJedecId(void) { - if(!_notBusy()) { - return false; - } - _beginSPI(JEDECID); - _chip.manufacturerID = _nextByte(NULLBYTE); // manufacturer id - _chip.memoryTypeID = _nextByte(NULLBYTE); // memory type - _chip.capacityID = _nextByte(NULLBYTE); // capacity - CHIP_DESELECT - if (!_chip.manufacturerID || !_chip.memoryTypeID || !_chip.capacityID) { - errorcode = NORESPONSE; - #ifdef RUNDIAGNOSTIC - _troubleshoot(); - #endif - return false; - } - else { - return true; - } -} - -bool SPIFlash::_getSFDP(void) { - if(!_notBusy()) { - return false; - } - _beginSPI(READSFDP); - _currentAddress = 0x00; - _transferAddress(); - _nextByte(DUMMYBYTE); - for (uint8_t i = 0; i < 4; i++) { - _chip.sfdp += (_nextByte() << (8*i)); - } - CHIP_DESELECT - if (_chip.sfdp = 0x50444653) { - //Serial.print("_chip.sfdp: "); - //Serial.println(_chip.sfdp, HEX); - return true; - } - else { - return false; - } -} - -//Identifies the chip -bool SPIFlash::_chipID(void) { - //Get Manfucturer/Device ID so the library can identify the chip - _getSFDP(); - if (!_getJedecId()) { - return false; - } - - // If no capacity is defined in user code - if (!_chip.capacity) { - _chip.supported = _chip.manufacturerID; - if (_chip.supported == WINBOND_MANID || _chip.supported == MICROCHIP_MANID) { - //Identify capacity - for (uint8_t i = 0; i < sizeof(_capID); i++) - { - if (_chip.capacityID == _capID[i]) { - _chip.capacity = (_memSize[i]); - _chip.eraseTime = _eraseTime[i]; - } - } - return true; - } - else { - errorcode = UNKNOWNCAP; //Error code for unidentified capacity - #ifdef RUNDIAGNOSTIC - _troubleshoot(); - #endif - return false; - } - } - else { - // If a custom chip size is defined - _chip.eraseTime = _chip.capacity/KB8; - _chip.supported = false;// This chip is not officially supported - errorcode = UNKNOWNCHIP; //Error code for unidentified chip - #ifdef RUNDIAGNOSTIC - _troubleshoot(); - #endif - //while(1); //Enable this if usercode is not meant to be run on unsupported chips - } - return true; -} - -//Checks to see if pageOverflow is permitted and assists with determining next address to read/write. -//Sets the global address variable -bool SPIFlash::_addressCheck(uint32_t address, uint32_t size) { - if (errorcode == UNKNOWNCAP || errorcode == NORESPONSE) { - #ifdef RUNDIAGNOSTIC - _troubleshoot(); - #endif - return false; - } - if (!_chip.eraseTime) { - errorcode = CALLBEGIN; - #ifdef RUNDIAGNOSTIC - _troubleshoot(); - #endif - return false; - } - - for (uint32_t i = 0; i < size; i++) { - if (address + i >= _chip.capacity) { - if (!pageOverflow) { - errorcode = OUTOFBOUNDS; - #ifdef RUNDIAGNOSTIC - _troubleshoot(); - #endif - return false; // At end of memory - (!pageOverflow) - } - else { - _currentAddress = 0x00; - return true; // At end of memory - (pageOverflow) - } - } - } - _currentAddress = address; - return true; // Not at end of memory if (address < _chip.capacity) -} - -bool SPIFlash::_notPrevWritten(uint32_t address, uint32_t size) { - _beginSPI(READDATA); - for (uint16_t i = 0; i < size; i++) { - if (_nextByte() != 0xFF) { - CHIP_DESELECT; - return false; - } - } - CHIP_DESELECT - return true; -} //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Public functions used for read, write and erase operations // diff --git a/src/SPIFlash.h b/src/SPIFlash.h index 1bd1bae..6b2919e 100644 --- a/src/SPIFlash.h +++ b/src/SPIFlash.h @@ -35,7 +35,7 @@ // // // Error codes will be generated and returned on functions // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -//#define RUNDIAGNOSTIC // +#define RUNDIAGNOSTIC // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// #endif @@ -300,10 +300,10 @@ class SPIFlash { }; chipID _chip; uint32_t currentAddress, _currentAddress = 0; - const uint8_t _capID[11] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x43}; - const uint32_t _memSize[11] = {64L * K, 128L * K, 256L * K, 512L * K, 1L * M, 2L * M, 4L * M, 8L * M, - 16L * M, 32L * M, 8L * M}; - const uint32_t _eraseTime[11] = {1L * S, 2L * S, 2L * S, 4L * S, 6L * S, 10L * S, 15L * S, 100L * S, 200L * S, 400L * S, 50L}; //Erase time in milliseconds + const uint8_t _capID[12] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x43, 0x4B}; + const uint32_t _memSize[12] = {64L * K, 128L * K, 256L * K, 512L * K, 1L * M, 2L * M, 4L * M, 8L * M, + 16L * M, 32L * M, 8L * M, 8L * M}; + const uint32_t _eraseTime[12] = {1L * S, 2L * S, 2L * S, 4L * S, 6L * S, 10L * S, 15L * S, 100L * S, 200L * S, 400L * S, 50L * S, 50L * S}; //Erase time in milliseconds }; //--------------------------------------------Templates-------------------------------------------// diff --git a/src/defines.h b/src/defines.h index 3dd9da0..6ff5d64 100644 --- a/src/defines.h +++ b/src/defines.h @@ -35,6 +35,7 @@ #define WRITEDISABLE 0x04 #define READSTAT1 0x05 #define READSTAT2 0x35 +#define WRITESTATEN 0x50 #define WRITESTAT 0x01 #define WRITEENABLE 0x06 #define SECTORERASE 0x20 From 7915d470a14efbc7054450450d9d4fca72798569 Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Sat, 6 May 2017 14:00:52 +1000 Subject: [PATCH 03/34] Fixing comms issues --- examples/FlashDiagnostics/FlashDiagnostics.ino | 2 +- examples/TestFlash/TestFlash.ino | 7 +++++++ src/defines.h | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/examples/FlashDiagnostics/FlashDiagnostics.ino b/examples/FlashDiagnostics/FlashDiagnostics.ino index 0528dfe..295774f 100644 --- a/examples/FlashDiagnostics/FlashDiagnostics.ino +++ b/examples/FlashDiagnostics/FlashDiagnostics.ino @@ -18,7 +18,7 @@ #include //Define a flash memory size (if using non-Winbond memory) according to the list in defines.h -//#define CHIPSIZE MB64 +#define CHIPSIZE MB64 #if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) // Required for Serial on Zero based boards diff --git a/examples/TestFlash/TestFlash.ino b/examples/TestFlash/TestFlash.ino index 6af1df5..09c4639 100644 --- a/examples/TestFlash/TestFlash.ino +++ b/examples/TestFlash/TestFlash.ino @@ -75,6 +75,9 @@ uint8_t offset, dataByte; uint16_t dataInt; String inputString, outputString; +//Define a flash memory size (if using non-Winbond memory) according to the list in defines.h +#define CHIPSIZE MB64 + #if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) // Required for Serial on Zero based boards #define Serial SERIAL_PORT_USBVIRTUAL @@ -97,7 +100,11 @@ void setup() { Serial.print(F(".")); } Serial.println(); +#if defined (CHIPSIZE) + flash.begin(CHIPSIZE); //use flash.begin(CHIPSIZE) if using non-Winbond flash (Refer to '#define CHIPSIZE' above) +#else flash.begin(); +#endif Serial.println(); Serial.println(); commandList(); diff --git a/src/defines.h b/src/defines.h index 6ff5d64..c966fac 100644 --- a/src/defines.h +++ b/src/defines.h @@ -104,6 +104,7 @@ #define SPI_CLK 20000000 #else #define SPI_CLK 104000000 //Hex equivalent of 104MHz +//#define SPI_CLK 4000000 //Hex equivalent of 104MHz #endif #define WRTEN 0x02 #define SUS 0x80 From cae33f20bfffb417171d3661058595d9c937b4a3 Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Sun, 7 May 2017 03:07:28 +1000 Subject: [PATCH 04/34] All functions except the array read/write and string read/write have been consolidated into writeAnything. Optimizations to code to make it run faster. --- .../FlashDiagnostics/FlashDiagnostics.ino | 2 +- src/FLASHIO.cpp | 27 +- src/SPIFlash.cpp | 586 +++--------------- src/SPIFlash.h | 193 ++++-- 4 files changed, 240 insertions(+), 568 deletions(-) diff --git a/examples/FlashDiagnostics/FlashDiagnostics.ino b/examples/FlashDiagnostics/FlashDiagnostics.ino index 295774f..0528dfe 100644 --- a/examples/FlashDiagnostics/FlashDiagnostics.ino +++ b/examples/FlashDiagnostics/FlashDiagnostics.ino @@ -18,7 +18,7 @@ #include //Define a flash memory size (if using non-Winbond memory) according to the list in defines.h -#define CHIPSIZE MB64 +//#define CHIPSIZE MB64 #if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) // Required for Serial on Zero based boards diff --git a/src/FLASHIO.cpp b/src/FLASHIO.cpp index 7de04bd..eb15e79 100644 --- a/src/FLASHIO.cpp +++ b/src/FLASHIO.cpp @@ -34,10 +34,7 @@ bool SPIFlash::_prep(uint8_t opcode, uint32_t address, uint32_t size) { switch (opcode) { case PAGEPROG: - if (!_addressCheck(address, size)) { - return false; - } - if(!_notBusy() || !_writeEnable()){ + if (!_addressCheck(address, size) || !_notBusy() || !_writeEnable()) { return false; } #ifndef HIGHSPEED @@ -49,10 +46,7 @@ bool SPIFlash::_prep(uint8_t opcode, uint32_t address, uint32_t size) { break; default: - if (!_addressCheck(address, size)) { - return false; - } - if (!_notBusy()){ + if (!_addressCheck(address, size) || !_notBusy()){ return false; } return true; @@ -66,10 +60,17 @@ bool SPIFlash::_prep(uint8_t opcode, uint32_t page_number, uint8_t offset, uint3 return _prep(opcode, address, size); } -bool SPIFlash::_transferAddress(void) { - _nextByte(_currentAddress >> 16); - _nextByte(_currentAddress >> 8); - _nextByte(_currentAddress); +bool SPIFlash::_transferAddress(uint32_t _addr) { + if (!_addr) { + _nextByte(_currentAddress >> 16); + _nextByte(_currentAddress >> 8); + _nextByte(_currentAddress); + } + else { + _nextByte(_addr >> 16); + _nextByte(_addr >> 8); + _nextByte(_addr); + } } bool SPIFlash::_startSPIBus(void) { @@ -447,7 +448,7 @@ bool SPIFlash::_addressCheck(uint32_t address, uint32_t size) { bool SPIFlash::_notPrevWritten(uint32_t address, uint32_t size) { _beginSPI(READDATA); - for (uint16_t i = 0; i < size; i++) { + for (uint32_t i = 0; i < size; i++) { if (_nextByte() != 0xFF) { CHIP_DESELECT; return false; diff --git a/src/SPIFlash.cpp b/src/SPIFlash.cpp index 7aeb4b2..cd70c89 100644 --- a/src/SPIFlash.cpp +++ b/src/SPIFlash.cpp @@ -178,31 +178,13 @@ uint16_t SPIFlash::sizeofStr(String &inputStr) { // Variant A uint8_t SPIFlash::readByte(uint32_t address, bool fastRead) { uint8_t data; - - if (!_prep(READDATA, address, sizeof(data))) { - return false; - } - switch (fastRead) { - case false: - _beginSPI(READDATA); - break; - - case true: - _beginSPI(FASTREAD); - break; - - default: - break; - } - data = _nextByte(); - _endSPI(); + readAnything(address, data, fastRead); return data; } // Variant B uint8_t SPIFlash::readByte(uint16_t page_number, uint8_t offset, bool fastRead) { - uint32_t address = _getAddress(page_number, offset); - - return readByte(address, fastRead); + uint32_t address = _getAddress(page_number, offset); + return readByte(address, fastRead); } // Reads a char of data from a specific location in a page. @@ -216,31 +198,14 @@ uint8_t SPIFlash::readByte(uint16_t page_number, uint8_t offset, bool fastRead) // 3. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A int8_t SPIFlash::readChar(uint32_t address, bool fastRead) { - int8_t data; - if (!_prep(READDATA, address, sizeof(data))) { - return false; - } - switch (fastRead) { - case false: - _beginSPI(READDATA); - break; - - case true: - _beginSPI(FASTREAD); - break; - - default: - break; - } - data = _nextByte(); - _endSPI(); + int8_t data; + readAnything(address, data, fastRead); return data; } // Variant B int8_t SPIFlash::readChar(uint16_t page_number, uint8_t offset, bool fastRead) { - uint32_t address = _getAddress(page_number, offset); - - return readChar(address, fastRead); + uint32_t address = _getAddress(page_number, offset); + return readChar(address, fastRead); } // Reads an array of bytes starting from a specific location in a page.// Has two variants: @@ -318,36 +283,14 @@ bool SPIFlash::readCharArray(uint16_t page_number, uint8_t offset, char *data_b // 3. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A uint16_t SPIFlash::readWord(uint32_t address, bool fastRead) { - const uint8_t size = sizeof(uint16_t); - union - { - uint8_t b[size]; - uint16_t I; - } data; - if (!_prep(READDATA, address, size)) { - return false; - } - switch (fastRead) { - case false: - _beginSPI(READDATA); - break; - - case true: - _beginSPI(FASTREAD); - break; - - default: - break; - } - _nextBuf(READDATA, &data.b[0], size); - _endSPI(); - return data.I; + uint16_t data; + readAnything(address, data, fastRead); + return data; } // Variant B uint16_t SPIFlash::readWord(uint16_t page_number, uint8_t offset, bool fastRead) { - uint32_t address = _getAddress(page_number, offset); - - return readWord(address, fastRead); + uint32_t address = _getAddress(page_number, offset); + return readWord(address, fastRead); } // Reads a signed int of data from a specific location in a page. @@ -361,37 +304,14 @@ uint16_t SPIFlash::readWord(uint16_t page_number, uint8_t offset, bool fastRead) // 3. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A int16_t SPIFlash::readShort(uint32_t address, bool fastRead) { - const uint8_t size = sizeof(int16_t); - union - { - byte b[size]; - int16_t s; - } data; - - if (!_prep(READDATA, address, size)) { - return false; - } - switch (fastRead) { - case false: - _beginSPI(READDATA); - break; - - case true: - _beginSPI(FASTREAD); - break; - - default: - break; - } - _nextBuf(READDATA, &data.b[0], size); - _endSPI(); - return data.s; + int16_t data; + readAnything(address, data, fastRead); + return data; } // Variant B int16_t SPIFlash::readShort(uint16_t page_number, uint8_t offset, bool fastRead) { - uint32_t address = _getAddress(page_number, offset); - - return readShort(address, fastRead); + uint32_t address = _getAddress(page_number, offset); + return readShort(address, fastRead); } // Reads an unsigned long of data from a specific location in a page. @@ -405,37 +325,14 @@ int16_t SPIFlash::readShort(uint16_t page_number, uint8_t offset, bool fastRead) // 3. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A uint32_t SPIFlash::readULong(uint32_t address, bool fastRead) { - const uint8_t size = (sizeof(uint32_t)); - union - { - uint8_t b[size]; - uint32_t l; - } data; - - if (!_prep(READDATA, address, size)) { - return false; - } - switch (fastRead) { - case false: - _beginSPI(READDATA); - break; - - case true: - _beginSPI(FASTREAD); - break; - - default: - break; - } - _nextBuf(READDATA, &data.b[0], size); - _endSPI(); - return data.l; + uint32_t data; + readAnything(address, data, fastRead); + return data; } // Variant B uint32_t SPIFlash::readULong(uint16_t page_number, uint8_t offset, bool fastRead) { - uint32_t address = _getAddress(page_number, offset); - - return readULong(address, fastRead); + uint32_t address = _getAddress(page_number, offset); + return readULong(address, fastRead); } // Reads a signed long of data from a specific location in a page. @@ -449,37 +346,14 @@ uint32_t SPIFlash::readULong(uint16_t page_number, uint8_t offset, bool fastRead // 3. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A int32_t SPIFlash::readLong(uint32_t address, bool fastRead) { - const uint8_t size = (sizeof(int32_t)); - union - { - byte b[size]; - int32_t l; - } data; - - if (!_prep(READDATA, address, size)) { - return false; - } - switch (fastRead) { - case false: - _beginSPI(READDATA); - break; - - case true: - _beginSPI(FASTREAD); - break; - - default: - break; - } - _nextBuf(READDATA, &data.b[0], size); - _endSPI(); - return data.l; + int32_t data; + readAnything(address, data, fastRead); + return data; } // Variant B int32_t SPIFlash::readLong(uint16_t page_number, uint8_t offset, bool fastRead) { - uint32_t address = _getAddress(page_number, offset); - - return readLong(address, fastRead); + uint32_t address = _getAddress(page_number, offset); + return readLong(address, fastRead); } // Reads a signed long of data from a specific location in a page. @@ -493,38 +367,14 @@ int32_t SPIFlash::readLong(uint16_t page_number, uint8_t offset, bool fastRead) // 3. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A float SPIFlash::readFloat(uint32_t address, bool fastRead) { - const uint8_t size = (sizeof(float)); - union - { - byte b[size]; - float f; - } data; - - if (!_prep(READDATA, address, size)) { - return false; - } - - switch (fastRead) { - case false: - _beginSPI(READDATA); - break; - - case true: - _beginSPI(FASTREAD); - break; - - default: - break; - } - _nextBuf(READDATA, &data.b[0], size); - _endSPI(); - return data.f; + float data; + readAnything(address, data, fastRead); + return data; } // Variant B float SPIFlash::readFloat(uint16_t page_number, uint8_t offset, bool fastRead) { - uint32_t address = _getAddress(page_number, offset); - - return readFloat(address, fastRead); + uint32_t address = _getAddress(page_number, offset); + return readFloat(address, fastRead); } // Reads a string from a specific location on a page. @@ -574,27 +424,12 @@ bool SPIFlash::readStr(uint16_t page_number, uint8_t offset, String &outStr, boo // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) // Variant A bool SPIFlash::writeByte(uint32_t address, uint8_t data, bool errorCheck) { - if(!_prep(PAGEPROG, address, sizeof(data))) { - return false; - } - - _beginSPI(PAGEPROG); - _nextByte(data); - CHIP_DESELECT - - if (!errorCheck) { - _endSPI(); - return true; - } - else { - return _writeErrorCheck(address, data); - } + return writeAnything(address, data, errorCheck); } // Variant B bool SPIFlash::writeByte(uint16_t page_number, uint8_t offset, uint8_t data, bool errorCheck) { - uint32_t address = _getAddress(page_number, offset); - - return writeByte(address, data, errorCheck); + uint32_t address = _getAddress(page_number, offset); + return writeAnything(address, data, errorCheck); } // Writes a char of data to a specific location in a page. @@ -612,27 +447,12 @@ bool SPIFlash::writeByte(uint16_t page_number, uint8_t offset, uint8_t data, boo // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) // Variant A bool SPIFlash::writeChar(uint32_t address, int8_t data, bool errorCheck) { - if(!_prep(PAGEPROG, address, sizeof(data))) { - return false; - } - - _beginSPI(PAGEPROG); - _nextByte(data); - CHIP_DESELECT - - if (!errorCheck) { - _endSPI(); - return true; - } - else { - return _writeErrorCheck(address, data); - } + return writeAnything(address, data, errorCheck); } // Variant B bool SPIFlash::writeChar(uint16_t page_number, uint8_t offset, int8_t data, bool errorCheck) { - uint32_t address = _getAddress(page_number, offset); - - return writeChar(address, data, errorCheck); + uint32_t address = _getAddress(page_number, offset); + return writeAnything(address, data, errorCheck); } // Writes an array of bytes starting from a specific location in a page. @@ -654,28 +474,36 @@ bool SPIFlash::writeByteArray(uint32_t address, uint8_t *data_buffer, uint16_t b return false; } uint16_t maxBytes = PAGESIZE-(address % PAGESIZE); // Force the first set of bytes to stay within the first page - uint16_t length = bufferSize; - uint16_t writeBufSz; - uint16_t data_offset = 0; - while (length > 0) - { - writeBufSz = (length<=maxBytes) ? length : maxBytes; + if (bufferSize <= maxBytes) { + _beginSPI(PAGEPROG); + _nextBuf(PAGEPROG, &data_buffer[0], bufferSize); + CHIP_DESELECT + } + else { + uint16_t length = bufferSize; + uint16_t writeBufSz; + uint16_t data_offset = 0; - if(!_notBusy() || !_writeEnable()){ - return false; - } + while (length > 0) + { + writeBufSz = (length<=maxBytes) ? length : maxBytes; - _beginSPI(PAGEPROG); + if(!_notBusy() || !_writeEnable()){ + return false; + } - for (uint16_t i = 0; i < writeBufSz; ++i) { - _nextByte(data_buffer[data_offset + i]); + _beginSPI(PAGEPROG); + for (uint16_t i = 0; i < writeBufSz; ++i) { + _nextByte(data_buffer[data_offset + i]); + } + CHIP_DESELECT + + _currentAddress += writeBufSz; + data_offset += writeBufSz; + length -= writeBufSz; + maxBytes = 256; // Now we can do up to 256 bytes per loop } - _currentAddress += writeBufSz; - data_offset += writeBufSz; - length -= writeBufSz; - maxBytes = 256; // Now we can do up to 256 bytes per loop - CHIP_DESELECT } if (!errorCheck) { @@ -792,61 +620,12 @@ bool SPIFlash::writeCharArray(uint16_t page_number, uint8_t offset, char *data_b // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) // Variant A bool SPIFlash::writeWord(uint32_t address, uint16_t data, bool errorCheck) { - const uint8_t size = sizeof(uint16_t); - - if(!_prep(PAGEPROG, address, size)) { - return false; - } - - union - { - uint8_t b[size]; - uint16_t w; - } var; - var.w = data; - - uint16_t maxBytes = PAGESIZE-(address % PAGESIZE); // Force the first set of bytes to stay within the first page - if (maxBytes > size) { - _beginSPI(PAGEPROG); - _nextBuf(PAGEPROG, &var.b[0], size); - CHIP_DESELECT - } - else { - uint16_t writeBufSz; - uint16_t data_offset = 0; - uint16_t _sz = size; - - while (_sz > 0) - { - writeBufSz = (_sz<=maxBytes) ? _sz : maxBytes; - if(!_notBusy() || !_writeEnable()){ - return false; - } - - _beginSPI(PAGEPROG); - for (uint16_t i = 0; i < writeBufSz; ++i) { - _nextByte(var.b[data_offset + i]); - } - _currentAddress += writeBufSz; - data_offset += writeBufSz; - _sz -= writeBufSz; - maxBytes = 256; // Now we can do up to 256 bytes per loop - CHIP_DESELECT - } - } - - if (!errorCheck) { - _endSPI(); - return true; - } - else - return _writeErrorCheck(address, data); + return writeAnything(address, data, errorCheck); } // Variant B bool SPIFlash::writeWord(uint16_t page_number, uint8_t offset, uint16_t data, bool errorCheck) { - uint32_t address = _getAddress(page_number, offset); - - return writeWord(address, data, errorCheck); + uint32_t address = _getAddress(page_number, offset); + return writeAnything(address, data, errorCheck); } // Writes a signed int as two bytes starting from a specific location in a page. @@ -864,60 +643,12 @@ bool SPIFlash::writeWord(uint16_t page_number, uint8_t offset, uint16_t data, bo // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) // Variant A bool SPIFlash::writeShort(uint32_t address, int16_t data, bool errorCheck) { - const uint8_t size = sizeof(data); - if(!_prep(PAGEPROG, address, size)) { - return false; - } - - union - { - uint8_t b[size]; - int16_t s; - } var; - var.s = data; - - uint16_t maxBytes = PAGESIZE-(address % PAGESIZE); // Force the first set of bytes to stay within the first page - if (maxBytes > size) { - _beginSPI(PAGEPROG); - _nextBuf(PAGEPROG, &var.b[0], size); - CHIP_DESELECT - } - else { - uint16_t writeBufSz; - uint16_t data_offset = 0; - uint16_t _sz = size; - - while (_sz > 0) - { - writeBufSz = (_sz<=maxBytes) ? _sz : maxBytes; - if(!_notBusy() || !_writeEnable()){ - return false; - } - - _beginSPI(PAGEPROG); - for (uint16_t i = 0; i < writeBufSz; ++i) { - _nextByte(var.b[data_offset + i]); - } - _currentAddress += writeBufSz; - data_offset += writeBufSz; - _sz -= writeBufSz; - maxBytes = 256; // Now we can do up to 256 bytes per loop - CHIP_DESELECT - } - } - - if (!errorCheck) { - _endSPI(); - return true; - } - else - return _writeErrorCheck(address, data); + return writeAnything(address, data, errorCheck); } // Variant B bool SPIFlash::writeShort(uint16_t page_number, uint8_t offset, int16_t data, bool errorCheck) { - uint32_t address = _getAddress(page_number, offset); - - return writeShort(address, data, errorCheck); + uint32_t address = _getAddress(page_number, offset); + return writeAnything(address, data, errorCheck); } // Writes an unsigned long as four bytes starting from a specific location in a page. @@ -935,62 +666,12 @@ bool SPIFlash::writeShort(uint16_t page_number, uint8_t offset, int16_t data, bo // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) // Variant A bool SPIFlash::writeULong(uint32_t address, uint32_t data, bool errorCheck) { - const uint8_t size = (sizeof(data)); - - if(!_prep(PAGEPROG, address, size)) { - return false; - } - - union - { - uint8_t b[size]; - uint32_t l; - } var; - var.l = data; - - uint16_t maxBytes = PAGESIZE-(address % PAGESIZE); // Force the first set of bytes to stay within the first page - if (maxBytes > size) { - _beginSPI(PAGEPROG); - _nextBuf(PAGEPROG, &var.b[0], size); - CHIP_DESELECT - } - else { - uint16_t writeBufSz; - uint16_t data_offset = 0; - uint16_t _sz = size; - - while (_sz > 0) - { - writeBufSz = (_sz<=maxBytes) ? _sz : maxBytes; - if(!_notBusy() || !_writeEnable()){ - return false; - } - - _beginSPI(PAGEPROG); - for (uint16_t i = 0; i < writeBufSz; ++i) { - _nextByte(var.b[data_offset + i]); - } - _currentAddress += writeBufSz; - data_offset += writeBufSz; - _sz -= writeBufSz; - maxBytes = 256; // Now we can do up to 256 bytes per loop - CHIP_DESELECT - } - } - - if (!errorCheck){ - _endSPI(); - return true; - } - else { - return _writeErrorCheck(address, data); - } + return writeAnything(address, data, errorCheck); } // Variant B bool SPIFlash::writeULong(uint16_t page_number, uint8_t offset, uint32_t data, bool errorCheck) { - uint32_t address = _getAddress(page_number, offset); - - return writeULong(address, data, errorCheck); + uint32_t address = _getAddress(page_number, offset); + return writeAnything(address, data, errorCheck); } // Writes a signed long as four bytes starting from a specific location in a page. @@ -1008,62 +689,12 @@ bool SPIFlash::writeULong(uint16_t page_number, uint8_t offset, uint32_t data, b // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) // Variant A bool SPIFlash::writeLong(uint32_t address, int32_t data, bool errorCheck) { -const uint8_t size = sizeof(data); - - if(!_prep(PAGEPROG, address, size)) { - return false; - } - - union - { - uint8_t b[size]; - int32_t l; - } var; - var.l = data; - - uint16_t maxBytes = PAGESIZE-(address % PAGESIZE); // Force the first set of bytes to stay within the first page - if (maxBytes > size) { - _beginSPI(PAGEPROG); - _nextBuf(PAGEPROG, &var.b[0], size); - CHIP_DESELECT - } - else { - uint16_t writeBufSz; - uint16_t data_offset = 0; - uint16_t _sz = size; - - while (_sz > 0) - { - writeBufSz = (_sz<=maxBytes) ? _sz : maxBytes; - if(!_notBusy() || !_writeEnable()){ - return false; - } - - _beginSPI(PAGEPROG); - for (uint16_t i = 0; i < writeBufSz; ++i) { - _nextByte(var.b[data_offset + i]); - } - _currentAddress += writeBufSz; - data_offset += writeBufSz; - _sz -= writeBufSz; - maxBytes = 256; // Now we can do up to 256 bytes per loop - CHIP_DESELECT - } - } - - if (!errorCheck){ - _endSPI(); - return true; - } - else { - return _writeErrorCheck(address, data); - } + return writeAnything(address, data, errorCheck); } // Variant B bool SPIFlash::writeLong(uint16_t page_number, uint8_t offset, int32_t data, bool errorCheck) { - uint32_t address = _getAddress(page_number, offset); - - return writeLong(address, data, errorCheck); + uint32_t address = _getAddress(page_number, offset); + return writeAnything(address, data, errorCheck); } // Writes a float as four bytes starting from a specific location in a page. @@ -1081,61 +712,12 @@ bool SPIFlash::writeLong(uint16_t page_number, uint8_t offset, int32_t data, boo // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) // Variant A bool SPIFlash::writeFloat(uint32_t address, float data, bool errorCheck) { - const uint8_t size = (sizeof(data)); - - if(!_prep(PAGEPROG, address, size)) { - return false; - } - union - { - uint8_t b[size]; - float f; - } var; - var.f = data; - - uint16_t maxBytes = PAGESIZE-(address % PAGESIZE); // Force the first set of bytes to stay within the first page - if (maxBytes > size) { - _beginSPI(PAGEPROG); - _nextBuf(PAGEPROG, &var.b[0], size); - CHIP_DESELECT - } - else { - uint16_t writeBufSz; - uint16_t data_offset = 0; - uint16_t _sz = size; - - while (_sz > 0) - { - writeBufSz = (_sz<=maxBytes) ? _sz : maxBytes; - if(!_notBusy() || !_writeEnable()){ - return false; - } - - _beginSPI(PAGEPROG); - for (uint16_t i = 0; i < writeBufSz; ++i) { - _nextByte(var.b[data_offset + i]); - } - _currentAddress += writeBufSz; - data_offset += writeBufSz; - _sz -= writeBufSz; - maxBytes = 256; // Now we can do up to 256 bytes per loop - CHIP_DESELECT - } - } - - if (!errorCheck) { - _endSPI(); - return true; - } - else { - return _writeErrorCheck(address, data); - } + return writeAnything(address, data, errorCheck); } // Variant B bool SPIFlash::writeFloat(uint16_t page_number, uint8_t offset, float data, bool errorCheck) { - uint32_t address = _getAddress(page_number, offset); - - return writeFloat(address, data, errorCheck); + uint32_t address = _getAddress(page_number, offset); + return writeAnything(address, data, errorCheck); } // Reads a string from a specific location on a page. @@ -1235,9 +817,7 @@ bool SPIFlash::eraseSector(uint32_t address) { return false; _beginSPI(SECTORERASE); - _nextByte(address >> 16); - _nextByte(address >> 8); - _nextByte(0); + _transferAddress(address); _endSPI(); if(!_notBusy(500L)) @@ -1267,9 +847,7 @@ bool SPIFlash::eraseBlock32K(uint32_t address) { return false; } _beginSPI(BLOCK32ERASE); - _nextByte(address >> 16); - _nextByte(address >> 8); - _nextByte(0); + _transferAddress(address); _endSPI(); if(!_notBusy(1*S)) @@ -1299,9 +877,7 @@ bool SPIFlash::eraseBlock64K(uint32_t address) { return false; } _beginSPI(BLOCK64ERASE); - _nextByte(address >> 16); - _nextByte(address >> 8); - _nextByte(0); + _transferAddress(address); _endSPI(); if(!_notBusy(1200L)) diff --git a/src/SPIFlash.h b/src/SPIFlash.h index 6b2919e..ad10587 100644 --- a/src/SPIFlash.h +++ b/src/SPIFlash.h @@ -197,8 +197,10 @@ class SPIFlash { 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 Anything-----------------------------------------// + template bool writeAnything(uint32_t address, const T& value, uint32_t _sz, bool errorCheck); 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, uint32_t _sz, bool fastRead = false); 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---------------------------------------------// @@ -267,7 +269,7 @@ class SPIFlash { bool _getManId(uint8_t *b1, uint8_t *b2); bool _getSFDP(void); bool _chipID(void); - bool _transferAddress(void); + bool _transferAddress(uint32_t _addr = 0); bool _addressCheck(uint32_t address, uint32_t size = 1); uint8_t _nextByte(uint8_t data = NULLBYTE); uint16_t _nextInt(uint16_t = NULLINT); @@ -276,6 +278,7 @@ class SPIFlash { uint8_t _readStat2(void); uint32_t _getAddress(uint16_t page_number, uint8_t offset = 0); template bool _writeErrorCheck(uint32_t address, const T& value); + template bool _writeErrorCheck(uint32_t address, const T& value, uint32_t _sz); //-------------------------------------------Private variables------------------------------------------// #ifdef SPI_HAS_TRANSACTION SPISettings _settings; @@ -306,7 +309,7 @@ class SPIFlash { const uint32_t _eraseTime[12] = {1L * S, 2L * S, 2L * S, 4L * S, 6L * S, 10L * S, 15L * S, 100L * S, 200L * S, 400L * S, 50L * S, 50L * S}; //Erase time in milliseconds }; -//--------------------------------------------Templates-------------------------------------------// +//----------------------------------------Public Templates----------------------------------------// // Writes any type of data to a specific location in the flash memory. // Has two variants: @@ -322,55 +325,89 @@ class SPIFlash { // 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 (!_prep(PAGEPROG, address, sizeof(value))) { - return false; - } - uint16_t maxBytes = PAGESIZE-(address % PAGESIZE); // Force the first set of bytes to stay within the first page - uint16_t length = sizeof(value); +template bool SPIFlash::writeAnything(uint32_t address, const T& value, uint32_t _sz, bool errorCheck) { + const uint8_t* p = ((const uint8_t*)(const void*)&value); - //if (maxBytes > length) { - uint32_t writeBufSz; - uint16_t data_offset = 0; - const uint8_t* p = ((const uint8_t*)(const void*)&value); - - if (!SPIBusState) { - _startSPIBus(); + //If data is only one byte (8 bits) long + if (_sz == sizeof(uint8_t)) { + if (_prep(PAGEPROG, address, _sz)) { + _beginSPI(PAGEPROG); + _nextByte(*p); + CHIP_DESELECT } - while (length > 0) - { - writeBufSz = (length<=maxBytes) ? length : maxBytes; + else { + return false; + } + } + else { //If data is longer than one byte (8 bits) + uint32_t length = _sz; + uint16_t maxBytes = PAGESIZE-(address % PAGESIZE); // Force the first set of bytes to stay within the first page - if(!_notBusy() || !_writeEnable()){ + if (maxBytes > length) { + if (_prep(PAGEPROG, address, length)) { + _beginSPI(PAGEPROG); + for (uint16_t i = 0; i < length; ++i) { + _nextByte(*p++); + } + CHIP_DESELECT + } + else { + return false; + } + } + else { + #ifndef HIGHSPEED + if(!_addressCheck(address, _sz) || !_notPrevWritten(address, _sz)) { return false; } + #else + if (!_addressCheck(address, _sz)) { + return false; + } + #endif + uint32_t writeBufSz; + uint16_t data_offset = 0; - CHIP_SELECT - (void)xfer(PAGEPROG); - _transferAddress(); + while (length > 0) + { + writeBufSz = (length<=maxBytes) ? length : maxBytes; - for (uint16_t i = 0; i < writeBufSz; ++i) { - _nextByte(*p++); + if(_notBusy() && _writeEnable()) { + _beginSPI(PAGEPROG); + for (uint16_t i = 0; i < writeBufSz; ++i) { + _nextByte(*p++); + } + CHIP_DESELECT + _currentAddress += writeBufSz; + data_offset += writeBufSz; + length -= writeBufSz; + maxBytes = 256; // Now we can do up to 256 bytes per loop + } + else { + return false; + } } - _currentAddress += writeBufSz; - data_offset += writeBufSz; - length -= writeBufSz; - maxBytes = 256; // Now we can do up to 256 bytes per loop - CHIP_DESELECT } + } if (!errorCheck) { _endSPI(); return true; } else { - return _writeErrorCheck(address, value); + return _writeErrorCheck(address, value, _sz); } } // Variant B +template bool SPIFlash::writeAnything(uint32_t address, const T& value, bool errorCheck) { + uint32_t _sizeofvalue = sizeof(value); + return writeAnything(address, value, _sizeofvalue, errorCheck); +} +// Variant C 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); + uint32_t _sizeofvalue = sizeof(value); + return writeAnything(address, value, _sizeofvalue, errorCheck); } // Reads any type of data from a specific location in the flash memory. @@ -384,46 +421,88 @@ template bool SPIFlash::writeAnything(uint16_t page_number, uint8_t of // 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 (!_prep(READDATA, address, sizeof(value))) - return false; - +// Variant C +template bool SPIFlash::readAnything(uint32_t address, T& value, uint32_t _sz, bool fastRead) { + if (_prep(READDATA, address, _sz)) { uint8_t* p = (uint8_t*)(void*)&value; - if(!fastRead) + switch (fastRead) { + case false: _beginSPI(READDATA); - else + for (uint16_t i = 0; i < _sz; i++) { + *p++ =_nextByte(); + } + _endSPI(); + break; + + case true: _beginSPI(FASTREAD); - for (uint16_t i = 0; i < sizeof(value); i++) { - *p++ =_nextByte(); + for (uint16_t i = 0; i < _sz; i++) { + *p++ =_nextByte(); + } + _endSPI(); + break; + + default: + break; + } + return true; + } + else { + return false; } - _endSPI(); - return true; } // Variant B +template bool SPIFlash::readAnything(uint32_t address, T& value, bool fastRead) { + uint32_t _sizeofvalue = sizeof(value); + return readAnything(address, value, _sizeofvalue, fastRead); +} +// Variant C 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); + uint32_t _sizeofvalue = sizeof(value); + return readAnything(address, value, _sizeofvalue, fastRead); } // Private template to check for errors in writing to flash memory template bool SPIFlash::_writeErrorCheck(uint32_t address, const T& value) { -if (!_prep(READDATA, address, sizeof(value)) && !_notBusy()) { + if (_prep(READDATA, address, sizeof(value))) { + const uint8_t* p = (const uint8_t*)(const void*)&value; + _beginSPI(READDATA); + for(uint16_t i = 0; i < sizeof(value);i++) + { + if(*p++ != _nextByte()) + { + errorcode = ERRORCHKFAIL; + #ifdef RUNDIAGNOSTIC + _troubleshoot(); + #endif + return false; + } + } + _endSPI(); + return true; + } + else { + return false; + } +} + +template bool SPIFlash::_writeErrorCheck(uint32_t address, const T& value, uint32_t _sz) { +if (!_prep(READDATA, address, _sz)) { return false; } const uint8_t* p = (const uint8_t*)(const void*)&value; _beginSPI(READDATA); - uint8_t _v; - for(uint16_t i = 0; i < sizeof(value);i++) + for(uint16_t i = 0; i < _sz;i++) { -#if defined (ARDUINO_ARCH_SAM) +/*#if defined (ARDUINO_ARCH_SAM) if(*p++ != _dueSPIRecByte()) { return false; } -#else +#else*/ if(*p++ != _nextByte()) { errorcode = ERRORCHKFAIL; @@ -432,10 +511,26 @@ if (!_prep(READDATA, address, sizeof(value)) && !_notBusy()) { #endif return false; } -#endif +//#endif } _endSPI(); return true; } +//----------------------------------------Private 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 write data from +// 3. size --> size of data +// 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) #endif // _SPIFLASH_H_ From e71bfb3eaa4d9f8d37a4254636e557eaf4e81aa3 Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Mon, 29 May 2017 19:42:28 +1000 Subject: [PATCH 05/34] Deprecations: --> flash.begin() no longer takes any variable as an argument. To define a custom CHIPSIZE to use the library with an unsupported chip - refer to 'Enhancements -> 5' --> The library no longer supports using the page number + offset combination instead of addresses. If your code requires you to use a page number + offset combination, use the following code to help address = (pagenumber << 8) + offset. _____________________________________ (32 bit) | (16 bit) | (8 bit) New Boards supported: --> Enhancements: --> Library faster than before (Refer to Library speed comparison in the extras folder for timing details): Improvements in speed in v3.0.0 when compared to v2.7.0 (values in percentage of time v3.0.0 is faster than v2.7.0) (+) writeByte-> +3% (+) writeChar -> +6% (+) writeWord-> +3% (+) writeShort -> +5% (+) writeULong -> +7% (+) writeLong | readLong-> +7% | +7% (+) writeFloat-> +7% (+) writeStr | readStr-> +57% | +61% (+) writeAnything | readAnything (struct)-> +25% | +20% (+) writeByteArray | readByteArray (256 bytes)-> +18% | +45% (+) eraseSector-> +99% (+) eraseBlock32K-> +99.4% (+) eraseBlock64K-> +99.5% (+) eraseChip-> +12% --> All functions except the Byte/Char Array Read/Write functions now call an internal _write/_read function. --> Restructured the internal _troubleshoot() function to be better human readable and easier to compile. --> Users can define RUNDIAGNOSTIC or HIGHSPEED in their code to access the library's special modes. No requirement to modify the library any more. --> No need to include CHIPSIZE in flash.begin() any more. Just defining CHIPSIZE in user code as one of the standard sizes as in defines.h will be enough. (Refer to 'Deprecations -> 1' above) --- .../FlashDiagnostics/FlashDiagnostics.ino | 15 +- examples/Struct_writer/Struct_writer.ino | 23 +- examples/TestFlash/TestFlash.ino | 2 +- extras/Changes.log | 40 ++ extras/Library speed comparisons.xlsx | Bin 47402 -> 47464 bytes library.properties | 2 +- src/FLASHIO.cpp | 161 +++--- src/SPIFlash.cpp | 492 ++++++------------ src/SPIFlash.h | 379 +++++--------- src/defines.h | 8 +- src/troubleshoot.cpp | 263 ++++------ 11 files changed, 551 insertions(+), 834 deletions(-) diff --git a/examples/FlashDiagnostics/FlashDiagnostics.ino b/examples/FlashDiagnostics/FlashDiagnostics.ino index 0528dfe..9d32024 100644 --- a/examples/FlashDiagnostics/FlashDiagnostics.ino +++ b/examples/FlashDiagnostics/FlashDiagnostics.ino @@ -2,7 +2,7 @@ |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | FlashDiagnostics.ino | | SPIFlash library | - | v 2.6.0 | + | v 3.0.0 | |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | Marzogh | | 16.04.2017 | @@ -17,8 +17,15 @@ #include +#if !defined (__AVR_ATtiny85__) +#define RUNDIAGNOSTIC //Outputs detailed diagnostic on error codes generated by library to Serial +#endif + +//Define the make of the chip being tested +#define WINBONDFLASH +//#define MICROCHIPFLASH //Define a flash memory size (if using non-Winbond memory) according to the list in defines.h -//#define CHIPSIZE MB64 +#define CHIPSIZE MB64 #if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) // Required for Serial on Zero based boards @@ -46,11 +53,7 @@ void setup() { Serial.print(F(".")); } Serial.println(); -#if defined (CHIPSIZE) - flash.begin(CHIPSIZE); //use flash.begin(CHIPSIZE) if using non-Winbond flash (Refer to '#define CHIPSIZE' above) -#else flash.begin(); -#endif Serial.println(); Serial.println(); diff --git a/examples/Struct_writer/Struct_writer.ino b/examples/Struct_writer/Struct_writer.ino index e33e2d8..f7d0698 100644 --- a/examples/Struct_writer/Struct_writer.ino +++ b/examples/Struct_writer/Struct_writer.ino @@ -54,6 +54,7 @@ struct Configuration { float RLDR; // Resistance calculation of potential divider with LDR bool light; uint8_t adc; + uint8_t arr[8]; }; Configuration configuration; @@ -85,6 +86,9 @@ void setup() { configuration.RLDR = 889.32; configuration.light = true; configuration.adc = 5; + for (uint8_t i = 0; i < 8; i++) { + configuration.arr[i] = i; + } #endif #ifdef SENSOR @@ -101,13 +105,20 @@ void setup() { Serial.println(configuration.RLDR); Serial.println(configuration.light); Serial.println(configuration.adc); - + for (uint8_t i = 0; i < 8; i++) { + Serial.print(configuration.arr[i]); + Serial.print(", "); + } + Serial.println(); Serial.println("Saved!"); configuration.lux = 0; configuration.vOut = 0; configuration.RLDR = 0; configuration.light = 0; configuration.adc = 0; + for (uint8_t i = 0; i < 8; i++) { + configuration.arr[i] = 0; + } Serial.println(); Serial.println("Local values set to 0"); Serial.println(configuration.lux); @@ -115,6 +126,11 @@ void setup() { Serial.println(configuration.RLDR); Serial.println(configuration.light); Serial.println(configuration.adc); + for (uint8_t i = 0; i < 8; i++) { + Serial.print(configuration.arr[i]); + Serial.print(", "); + } + Serial.println(); Serial.println(); flash.readAnything(_addr, configuration); flash.eraseSector(_addr, 0); @@ -125,6 +141,11 @@ void setup() { Serial.println(configuration.RLDR); Serial.println(configuration.light); Serial.println(configuration.adc); + for (uint8_t i = 0; i < 8; i++) { + Serial.print(configuration.arr[i]); + Serial.print(", "); + } + Serial.println(); } diff --git a/examples/TestFlash/TestFlash.ino b/examples/TestFlash/TestFlash.ino index 09c4639..813233e 100644 --- a/examples/TestFlash/TestFlash.ino +++ b/examples/TestFlash/TestFlash.ino @@ -76,7 +76,7 @@ uint16_t dataInt; String inputString, outputString; //Define a flash memory size (if using non-Winbond memory) according to the list in defines.h -#define CHIPSIZE MB64 +//#define CHIPSIZE MB64 #if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) // Required for Serial on Zero based boards diff --git a/extras/Changes.log b/extras/Changes.log index 5dcd0e4..2b17212 100644 --- a/extras/Changes.log +++ b/extras/Changes.log @@ -2,6 +2,46 @@ // SPIFlash Library // // Changes log // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +// Version 3.0.0 // +// Author: Prajwal Bhattaram // +// 11.05.2017 // +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +Bugs Squashed: +--> + +Deprecations: +--> flash.begin() no longer takes any variable as an argument. To define a custom CHIPSIZE to use the library with an unsupported chip - refer to 'Enhancements -> 5' +--> The library no longer supports using the page number + offset combination instead of addresses. If your code requires you to use a page number + offset combination, use the following code to help + address = (pagenumber << 8) + offset. + _____________________________________ + (32 bit) | (16 bit) | (8 bit) + +New Boards supported: +--> + +Enhancements: +--> Library faster than before (Refer to Library speed comparison in the extras folder for timing details): + + Improvements in speed in v3.0.0 when compared to v2.7.0 (values in percentage of time v3.0.0 is faster than v2.7.0) + (+) writeByte -> +3% + (+) writeChar -> +6% + (+) writeWord -> +3% + (+) writeShort -> +5% + (+) writeULong -> +7% + (+) writeLong | readLong -> +7% | +7% + (+) writeFloat -> +7% + (+) writeStr | readStr -> +57% | +61% + (+) writeAnything | readAnything (struct) -> +25% | +20% + (+) writeByteArray | readByteArray (256 bytes) -> +18% | +45% + (+) eraseSector -> +99% + (+) eraseBlock32K -> +99.4% + (+) eraseBlock64K -> +99.5% + (+) eraseChip -> +12% +--> All functions except the Byte/Char Array Read/Write functions now call an internal _write/_read function. +--> Restructured the internal _troubleshoot() function to be better human readable and easier to compile. +--> Users can define RUNDIAGNOSTIC or HIGHSPEED in their code to access the library's special modes. No requirement to modify the library any more. +--> No need to include CHIPSIZE in flash.begin() any more. Just defining CHIPSIZE in user code as one of the standard sizes as in defines.h will be enough. (Refer to 'Deprecations -> 1' above) +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Version 2.7.0 // // Author: Prajwal Bhattaram // // 17.04.2017 // diff --git a/extras/Library speed comparisons.xlsx b/extras/Library speed comparisons.xlsx index f919d7b7479eae0c2f02799ade717256adb73c62..35bfa241833d3ede7ebc702173efc5393401a523 100644 GIT binary patch delta 36764 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 Cvvc$S delta 36645 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 diff --git a/library.properties b/library.properties index 859bb18..bd79732 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SPIFlash -version=2.7.0 +version=3.0.0 author=Prajwal Bhattaram maintainer=Prajwal Bhattaram sentence=Winbond SPI flash library for Arduino. diff --git a/src/FLASHIO.cpp b/src/FLASHIO.cpp index eb15e79..30afc37 100644 --- a/src/FLASHIO.cpp +++ b/src/FLASHIO.cpp @@ -30,23 +30,32 @@ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// //Double checks all parameters before calling a read or write. Comes in two variants -//Variant A: Takes address and returns the address if true, else returns false. Throws an error if there is a problem. -bool SPIFlash::_prep(uint8_t opcode, uint32_t address, uint32_t size) { +//Takes address and returns the address if true, else returns false. Throws an error if there is a problem. +bool SPIFlash::_prep(uint8_t opcode, uint32_t _addr, uint32_t size) { switch (opcode) { case PAGEPROG: - if (!_addressCheck(address, size) || !_notBusy() || !_writeEnable()) { + #ifndef HIGHSPEED + if(!_addressCheck(_addr, size) || !_notBusy() || !_writeEnable() || !_notPrevWritten(_addr, size)) { return false; } - #ifndef HIGHSPEED - if(!_notPrevWritten(address, size)) { + #else + if (!_addressCheck(_addr, size) || !_notBusy() || !_writeEnable()) { return false; } #endif return true; break; + case ERASEFUNC: + _currentAddress = _addr; + if(!_notBusy()||!_writeEnable()) { + return false; + } + return true; + break; + default: - if (!_addressCheck(address, size) || !_notBusy()){ + if (!_addressCheck(_addr, size) || !_notBusy()){ return false; } return true; @@ -54,23 +63,11 @@ bool SPIFlash::_prep(uint8_t opcode, uint32_t address, uint32_t size) { } } -//Variant B: Take the opcode, page number, offset and size of data block as arguments -bool SPIFlash::_prep(uint8_t opcode, uint32_t page_number, uint8_t offset, uint32_t size) { - uint32_t address = _getAddress(page_number, offset); - return _prep(opcode, address, size); -} - -bool SPIFlash::_transferAddress(uint32_t _addr) { - if (!_addr) { - _nextByte(_currentAddress >> 16); - _nextByte(_currentAddress >> 8); - _nextByte(_currentAddress); - } - else { - _nextByte(_addr >> 16); - _nextByte(_addr >> 8); - _nextByte(_addr); - } +// Transfer Address. +bool SPIFlash::_transferAddress(void) { + _nextByte(_currentAddress >> 16); + _nextByte(_currentAddress >> 8); + _nextByte(_currentAddress); } bool SPIFlash::_startSPIBus(void) { @@ -109,21 +106,32 @@ bool SPIFlash::_beginSPI(uint8_t opcode) { } CHIP_SELECT switch (opcode) { - case FASTREAD: + case READDATA: _nextByte(opcode); - _nextByte(DUMMYBYTE); _transferAddress(); break; - case READDATA: + case PAGEPROG: _nextByte(opcode); _transferAddress(); break; - case PAGEPROG: + case FASTREAD: + _nextByte(opcode); + _nextByte(DUMMYBYTE); + _transferAddress(); + + case SECTORERASE: + _nextByte(opcode); + _transferAddress(); + + case BLOCK32ERASE: + _nextByte(opcode); + _transferAddress(); + + case BLOCK64ERASE: _nextByte(opcode); _transferAddress(); - break; default: _nextByte(opcode); @@ -135,11 +143,11 @@ bool SPIFlash::_beginSPI(uint8_t opcode) { //Reads/Writes next byte. Call 'n' times to read/write 'n' number of bytes. Should be called after _beginSPI() uint8_t SPIFlash::_nextByte(uint8_t data) { -#if defined (ARDUINO_ARCH_SAM) - return _dueSPITransfer(data); -#else +//#if defined (ARDUINO_ARCH_SAM) +// return _dueSPITransfer(data); +//#else return xfer(data); -#endif +//#endif } //Reads/Writes next int. Call 'n' times to read/write 'n' number of bytes. Should be called after _beginSPI() @@ -203,7 +211,7 @@ void SPIFlash::_endSPI(void) { SPIBusState = false; } -// Checks if status register 1 can be accessed - used during powerdown and power up and for debugging +// Checks if status register 1 can be accessed - used to check chip status, during powerdown and power up and for debugging uint8_t SPIFlash::_readStat1(void) { _beginSPI(READSTAT1); uint8_t stat1 = _nextByte(); @@ -225,7 +233,7 @@ bool SPIFlash::_noSuspend(void) { switch (_chip.manufacturerID) { case WINBOND_MANID: if(_readStat2() & SUS) { - errorcode = SYSSUSPEND; + _troubleshoot(SYSSUSPEND); return false; } return true; @@ -233,7 +241,7 @@ bool SPIFlash::_noSuspend(void) { case MICROCHIP_MANID: if(_readStat1() & WSE || _readStat1() & WSP) { - errorcode = SYSSUSPEND; + _troubleshoot(SYSSUSPEND); return false; } return true; @@ -243,16 +251,13 @@ bool SPIFlash::_noSuspend(void) { // Polls the status register 1 until busy flag is cleared or timeout bool SPIFlash::_notBusy(uint32_t timeout) { + _delay_us(WINBOND_WRITE_DELAY); uint32_t startTime = millis(); do { state = _readStat1(); if((millis()-startTime) > timeout){ - errorcode = CHIPBUSY; - #ifdef RUNDIAGNOSTIC - _troubleshoot(); - #endif - _endSPI(); + _troubleshoot(CHIPBUSY); return false; } } while(state & BUSY); @@ -262,21 +267,17 @@ bool SPIFlash::_notBusy(uint32_t timeout) { //Enables writing to chip by setting the WRITEENABLE bit bool SPIFlash::_writeEnable(uint32_t timeout) { uint32_t startTime = millis(); - if (!(state & WRTEN)) { + //if (!(state & WRTEN)) { do { _beginSPI(WRITEENABLE); CHIP_DESELECT state = _readStat1(); if((millis()-startTime) > timeout) { - errorcode = CANTENWRITE; - #ifdef RUNDIAGNOSTIC - _troubleshoot(); - #endif - _endSPI(); + _troubleshoot(CANTENWRITE); return false; - } - } while (!(state & WRTEN)); - } + } + } while (!(state & WRTEN)) ; + //} return true; } @@ -291,14 +292,6 @@ bool SPIFlash::_writeDisable(void) { return true; } -//Gets address from page number and offset. Takes two arguments: -// 1. page_number --> Any page number from 0 to maxPage -// 2. offset --> Any offset within the page - from 0 to 255 -uint32_t SPIFlash::_getAddress(uint16_t page_number, uint8_t offset) { - uint32_t address = page_number; - return ((address << 8) + offset); -} - //Checks the device ID to establish storage parameters bool SPIFlash::_getManId(uint8_t *b1, uint8_t *b2) { if(!_notBusy()) @@ -324,10 +317,7 @@ bool SPIFlash::_getJedecId(void) { _chip.capacityID = _nextByte(NULLBYTE); // capacity CHIP_DESELECT if (!_chip.manufacturerID || !_chip.memoryTypeID || !_chip.capacityID) { - errorcode = NORESPONSE; - #ifdef RUNDIAGNOSTIC - _troubleshoot(); - #endif + _troubleshoot(NORESPONSE); return false; } else { @@ -339,8 +329,8 @@ bool SPIFlash::_getSFDP(void) { if(!_notBusy()) { return false; } - _beginSPI(READSFDP); _currentAddress = 0x00; + _beginSPI(READSFDP); _transferAddress(); _nextByte(DUMMYBYTE); for (uint8_t i = 0; i < 4; i++) { @@ -390,10 +380,7 @@ bool SPIFlash::_chipID(void) { return true; } else { - errorcode = UNKNOWNCAP; //Error code for unidentified capacity - #ifdef RUNDIAGNOSTIC - _troubleshoot(); - #endif + _troubleshoot(UNKNOWNCAP); //Error code for unidentified capacity return false; } } @@ -401,10 +388,7 @@ bool SPIFlash::_chipID(void) { // If a custom chip size is defined _chip.eraseTime = _chip.capacity/KB8; _chip.supported = false;// This chip is not officially supported - errorcode = UNKNOWNCHIP; //Error code for unidentified chip - #ifdef RUNDIAGNOSTIC - _troubleshoot(); - #endif + _troubleshoot(UNKNOWNCHIP); //Error code for unidentified chip //while(1); //Enable this if usercode is not meant to be run on unsupported chips } return true; @@ -412,41 +396,32 @@ bool SPIFlash::_chipID(void) { //Checks to see if pageOverflow is permitted and assists with determining next address to read/write. //Sets the global address variable -bool SPIFlash::_addressCheck(uint32_t address, uint32_t size) { +bool SPIFlash::_addressCheck(uint32_t _addr, uint32_t size) { if (errorcode == UNKNOWNCAP || errorcode == NORESPONSE) { - #ifdef RUNDIAGNOSTIC - _troubleshoot(); - #endif return false; } if (!_chip.eraseTime) { - errorcode = CALLBEGIN; - #ifdef RUNDIAGNOSTIC - _troubleshoot(); - #endif + _troubleshoot(CALLBEGIN); return false; } - for (uint32_t i = 0; i < size; i++) { - if (address + i >= _chip.capacity) { - if (!pageOverflow) { - errorcode = OUTOFBOUNDS; - #ifdef RUNDIAGNOSTIC - _troubleshoot(); - #endif - return false; // At end of memory - (!pageOverflow) - } - else { - _currentAddress = 0x00; - return true; // At end of memory - (pageOverflow) - } + //for (uint32_t i = 0; i < size; i++) { + if (_addr + size >= _chip.capacity) { + if (!pageOverflow) { + _troubleshoot(OUTOFBOUNDS); + return false; // At end of memory - (!pageOverflow) + } + else { + _currentAddress = 0x00; + return true; // At end of memory - (pageOverflow) } } - _currentAddress = address; + //} + _currentAddress = _addr; return true; // Not at end of memory if (address < _chip.capacity) } -bool SPIFlash::_notPrevWritten(uint32_t address, uint32_t size) { +bool SPIFlash::_notPrevWritten(uint32_t _addr, uint32_t size) { _beginSPI(READDATA); for (uint32_t i = 0; i < size; i++) { if (_nextByte() != 0xFF) { diff --git a/src/SPIFlash.cpp b/src/SPIFlash.cpp index cd70c89..df561bc 100644 --- a/src/SPIFlash.cpp +++ b/src/SPIFlash.cpp @@ -1,8 +1,8 @@ -/* Arduino SPIFlash Library v.2.7.0 +/* Arduino SPIFlash Library v.3.0.0 * Copyright (C) 2017 by Prajwal Bhattaram * Created by Prajwal Bhattaram - 19/05/2015 * Modified by @boseji - 02/03/2017 - * Modified by Prajwal Bhattaram - 02/05/2017 + * Modified by Prajwal Bhattaram - 17/05/2017 * * 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 @@ -60,21 +60,16 @@ SPIFlash::SPIFlash(uint8_t cs, bool overflow) { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// //Identifies chip and establishes parameters -bool SPIFlash::begin(uint32_t _chipSize) { - if (_chipSize) { - _chip.capacity = _chipSize/8; - } +bool SPIFlash::begin(void) { +#ifdef CHIPSIZE + _chip.capacity = CHIPSIZE/8; +#endif BEGIN_SPI #ifdef SPI_HAS_TRANSACTION //Define the settings to be used by the SPI bus _settings = SPISettings(SPI_CLK, MSBFIRST, SPI_MODE0); #endif - if(!_chipID()) { - #ifdef RUNDIAGNOSTIC - _troubleshoot(); - #endif - return false; - } + return _chipID(); } //Allows the setting of a custom clock speed for the SPI bus to communicate with the chip. @@ -90,7 +85,7 @@ uint8_t SPIFlash::error(bool _verbosity) { return errorcode; } else { - _troubleshoot(); + _troubleshoot(errorcode, PRINTOVERRIDE); return errorcode; } } @@ -136,26 +131,16 @@ uint32_t SPIFlash::getJEDECID(void) { // All addresses in the in the sketch must be obtained via this function or not at all. // Variant A uint32_t SPIFlash::getAddress(uint16_t size) { - if (!_addressCheck(currentAddress, size)){ - errorcode = OUTOFBOUNDS; - #ifdef RUNDIAGNOSTIC - _troubleshoot(); - #endif + if (!_addressCheck(currentAddress, size)){ + _troubleshoot(OUTOFBOUNDS); return false; } else { - uint32_t address = currentAddress; + uint32_t _addr = currentAddress; currentAddress+=size; - return address; + return _addr; } } -// Variant B -bool SPIFlash::getAddress(uint16_t size, uint16_t &page_number, uint8_t &offset) { - uint32_t address = getAddress(size); - offset = (address >> 0); - page_number = (address >> 8); - return true; -} //Function for returning the size of the string (only to be used for the getAddress() function) uint16_t SPIFlash::sizeofStr(String &inputStr) { @@ -169,48 +154,40 @@ uint16_t SPIFlash::sizeofStr(String &inputStr) { // Reads a byte of data from a specific location in a page. // Has two variants: // A. Takes two arguments - -// 1. address --> Any address from 0 to capacity +// 1. _addr --> Any address from 0 to capacity // 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. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A -uint8_t SPIFlash::readByte(uint32_t address, bool fastRead) { +uint8_t SPIFlash::readByte(uint32_t _addr, bool fastRead) { uint8_t data; - readAnything(address, data, fastRead); + uint8_t _sizeofdata = sizeof(data); + _read(_addr, data, _sizeofdata, fastRead); return data; } -// Variant B -uint8_t SPIFlash::readByte(uint16_t page_number, uint8_t offset, bool fastRead) { - uint32_t address = _getAddress(page_number, offset); - return readByte(address, fastRead); -} // Reads a char of data from a specific location in a page. // Has two variants: // A. Takes two arguments - -// 1. address --> Any address from 0 to capacity +// 1. _addr --> Any address from 0 to capacity // 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. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A -int8_t SPIFlash::readChar(uint32_t address, bool fastRead) { +int8_t SPIFlash::readChar(uint32_t _addr, bool fastRead) { int8_t data; - readAnything(address, data, fastRead); + uint8_t _sizeofdata = sizeof(data); + _read(_addr, data, _sizeofdata, fastRead); return data; } -// Variant B -int8_t SPIFlash::readChar(uint16_t page_number, uint8_t offset, bool fastRead) { - uint32_t address = _getAddress(page_number, offset); - return readChar(address, fastRead); -} // Reads an array of bytes starting from a specific location in a page.// Has two variants: // A. Takes three arguments -// 1. address --> Any address from 0 to capacity +// 1. _addr --> Any address from 0 to capacity // 2. data_buffer --> The array of bytes to be read from the flash memory - starting at the address indicated // 3. fastRead --> defaults to false - executes _beginFastRead() if set to true // B. Takes four arguments @@ -219,8 +196,8 @@ int8_t SPIFlash::readChar(uint16_t page_number, uint8_t offset, bool fastRead) { // 3. data_buffer --> The array of bytes to be read from the flash memory - starting at the offset on the page indicated // 4. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A -bool SPIFlash::readByteArray(uint32_t address, uint8_t *data_buffer, uint16_t bufferSize, bool fastRead) { - if (!_prep(READDATA, address, bufferSize)) { +bool SPIFlash::readByteArray(uint32_t _addr, uint8_t *data_buffer, uint16_t bufferSize, bool fastRead) { + if (!_prep(READDATA, _addr, bufferSize)) { return false; } if(fastRead) { @@ -233,16 +210,10 @@ bool SPIFlash::readByteArray(uint32_t address, uint8_t *data_buffer, uint16_t b _endSPI(); return true; } -// Variant B -bool SPIFlash::readByteArray(uint16_t page_number, uint8_t offset, uint8_t *data_buffer, uint16_t bufferSize, bool fastRead) { - uint32_t address = _getAddress(page_number, offset); - - return readByteArray(address, data_buffer, bufferSize, fastRead); -} // Reads an array of chars starting from a specific location in a page.// Has two variants: // A. Takes three arguments -// 1. address --> Any address from 0 to capacity +// 1. _addr --> Any address from 0 to capacity // 2. data_buffer --> The array of bytes to be read from the flash memory - starting at the address indicated // 3. fastRead --> defaults to false - executes _beginFastRead() if set to true // B. Takes four arguments @@ -251,8 +222,8 @@ bool SPIFlash::readByteArray(uint16_t page_number, uint8_t offset, uint8_t *dat // 3. data_buffer --> The array of bytes to be read from the flash memory - starting at the offset on the page indicated // 4. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A -bool SPIFlash::readCharArray(uint32_t address, char *data_buffer, uint16_t bufferSize, bool fastRead) { - if (!_prep(READDATA, address, bufferSize)) { +bool SPIFlash::readCharArray(uint32_t _addr, char *data_buffer, uint16_t bufferSize, bool fastRead) { + if (!_prep(READDATA, _addr, bufferSize)) { return false; } if(fastRead) { @@ -265,122 +236,96 @@ bool SPIFlash::readCharArray(uint32_t address, char *data_buffer, uint16_t buff _endSPI(); return true; } -// Variant B -bool SPIFlash::readCharArray(uint16_t page_number, uint8_t offset, char *data_buffer, uint16_t bufferSize, bool fastRead) { - uint32_t address = _getAddress(page_number, offset); - - return readCharArray(address, data_buffer, bufferSize, fastRead); -} // Reads an unsigned int of data from a specific location in a page. // Has two variants: // A. Takes two arguments - -// 1. address --> Any address from 0 to capacity +// 1. _addr --> Any address from 0 to capacity // 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. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A -uint16_t SPIFlash::readWord(uint32_t address, bool fastRead) { +uint16_t SPIFlash::readWord(uint32_t _addr, bool fastRead) { uint16_t data; - readAnything(address, data, fastRead); + uint8_t _sizeofdata = sizeof(data); + _read(_addr, data, _sizeofdata, fastRead); return data; } -// Variant B -uint16_t SPIFlash::readWord(uint16_t page_number, uint8_t offset, bool fastRead) { - uint32_t address = _getAddress(page_number, offset); - return readWord(address, fastRead); -} // Reads a signed int of data from a specific location in a page. // Has two variants: // A. Takes two arguments - -// 1. address --> Any address from 0 to capacity +// 1. _addr --> Any address from 0 to capacity // 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. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A -int16_t SPIFlash::readShort(uint32_t address, bool fastRead) { +int16_t SPIFlash::readShort(uint32_t _addr, bool fastRead) { int16_t data; - readAnything(address, data, fastRead); + uint8_t _sizeofdata = sizeof(data); + _read(_addr, data, _sizeofdata, fastRead); return data; } -// Variant B -int16_t SPIFlash::readShort(uint16_t page_number, uint8_t offset, bool fastRead) { - uint32_t address = _getAddress(page_number, offset); - return readShort(address, fastRead); -} // Reads an unsigned long of data from a specific location in a page. // Has two variants: // A. Takes two arguments - -// 1. address --> Any address from 0 to capacity +// 1. _addr --> Any _addr from 0 to capacity // 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. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A -uint32_t SPIFlash::readULong(uint32_t address, bool fastRead) { +uint32_t SPIFlash::readULong(uint32_t _addr, bool fastRead) { uint32_t data; - readAnything(address, data, fastRead); + uint8_t _sizeofdata = sizeof(data); + _read(_addr, data, _sizeofdata, fastRead); return data; } -// Variant B -uint32_t SPIFlash::readULong(uint16_t page_number, uint8_t offset, bool fastRead) { - uint32_t address = _getAddress(page_number, offset); - return readULong(address, fastRead); -} // Reads a signed long of data from a specific location in a page. // Has two variants: // A. Takes two arguments - -// 1. address --> Any address from 0 to capacity +// 1. _addr --> Any _addr from 0 to capacity // 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. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A -int32_t SPIFlash::readLong(uint32_t address, bool fastRead) { +int32_t SPIFlash::readLong(uint32_t _addr, bool fastRead) { int32_t data; - readAnything(address, data, fastRead); + uint8_t _sizeofdata = sizeof(data); + _read(_addr, data, _sizeofdata, fastRead); return data; } -// Variant B -int32_t SPIFlash::readLong(uint16_t page_number, uint8_t offset, bool fastRead) { - uint32_t address = _getAddress(page_number, offset); - return readLong(address, fastRead); -} // Reads a signed long of data from a specific location in a page. // Has two variants: // A. Takes two arguments - -// 1. address --> Any address from 0 to capacity +// 1. _addr --> Any address from 0 to capacity // 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. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A -float SPIFlash::readFloat(uint32_t address, bool fastRead) { +float SPIFlash::readFloat(uint32_t _addr, bool fastRead) { float data; - readAnything(address, data, fastRead); + uint8_t _sizeofdata = sizeof(data); + _read(_addr, data, _sizeofdata, fastRead); return data; } -// Variant B -float SPIFlash::readFloat(uint16_t page_number, uint8_t offset, bool fastRead) { - uint32_t address = _getAddress(page_number, offset); - return readFloat(address, fastRead); -} // Reads a string from a specific location on a page. // Has two variants: // A. Takes three arguments -// 1. address --> Any address from 0 to capacity +// 1. _addr --> Any address from 0 to capacity // 2. outputString --> String variable to write the output to // 3. fastRead --> defaults to false - executes _beginFastRead() if set to true // B. Takes four arguments @@ -391,28 +336,15 @@ float SPIFlash::readFloat(uint16_t page_number, uint8_t offset, bool fastRead) { // This function first reads a short from the address to figure out the size of the String object stored and // then reads the String object data // Variant A -bool SPIFlash::readStr(uint32_t address, String &outStr, bool fastRead) { - uint16_t strLen; - //_delay_us(20); - strLen = readWord(address); - address+=(sizeof(strLen)); - char outputChar[strLen]; - - readCharArray(address, outputChar, strLen, fastRead); - - outStr = String(outputChar); - return true; -} -// Variant B -bool SPIFlash::readStr(uint16_t page_number, uint8_t offset, String &outStr, bool fastRead) { - uint32_t address = _getAddress(page_number, offset); - return readStr(address, outStr, fastRead); +bool SPIFlash::readStr(uint32_t _addr, String &outStr, bool fastRead) { + uint8_t _sizeofdata = sizeof(outStr); + return _read(_addr, outStr, _sizeofdata, fastRead); } // Writes a byte of data to a specific location in a page. // Has two variants: // A. Takes three arguments - -// 1. address --> Any address - from 0 to capacity +// 1. _addr --> Any address - from 0 to capacity // 2. data --> One byte of data to be written to a particular location on a page // 3. errorCheck --> Turned on by default. Checks for writing errors // B. Takes four arguments - @@ -423,19 +355,15 @@ bool SPIFlash::readStr(uint16_t page_number, uint8_t offset, String &outStr, boo // 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 -bool SPIFlash::writeByte(uint32_t address, uint8_t data, bool errorCheck) { - return writeAnything(address, data, errorCheck); -} -// Variant B -bool SPIFlash::writeByte(uint16_t page_number, uint8_t offset, uint8_t data, bool errorCheck) { - uint32_t address = _getAddress(page_number, offset); - return writeAnything(address, data, errorCheck); +bool SPIFlash::writeByte(uint32_t _addr, uint8_t data, bool errorCheck) { + uint8_t _sizeofdata = sizeof(data); + return _write(_addr, data, _sizeofdata, errorCheck); } // Writes a char of data to a specific location in a page. // Has two variants: // A. Takes three arguments - -// 1. address --> Any address - from 0 to capacity +// 1. _addr --> Any address - from 0 to capacity // 2. data --> One char of data to be written to a particular location on a page // 3. errorCheck --> Turned on by default. Checks for writing errors // B. Takes four arguments - @@ -446,19 +374,15 @@ bool SPIFlash::writeByte(uint16_t page_number, uint8_t offset, uint8_t data, boo // 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 -bool SPIFlash::writeChar(uint32_t address, int8_t data, bool errorCheck) { - return writeAnything(address, data, errorCheck); -} -// Variant B -bool SPIFlash::writeChar(uint16_t page_number, uint8_t offset, int8_t data, bool errorCheck) { - uint32_t address = _getAddress(page_number, offset); - return writeAnything(address, data, errorCheck); +bool SPIFlash::writeChar(uint32_t _addr, int8_t data, bool errorCheck) { + uint8_t _sizeofdata = sizeof(data); + return _write(_addr, data, _sizeofdata, errorCheck); } // Writes an array of bytes starting from a specific location in a page. // Has two variants: // A. Takes three arguments - -// 1. address --> Any address - from 0 to capacity +// 1. _addr --> Any address - from 0 to capacity // 2. data --> An array of bytes to be written to a particular location on a page // 3. errorCheck --> Turned on by default. Checks for writing errors // B. Takes four arguments - @@ -469,14 +393,16 @@ bool SPIFlash::writeChar(uint16_t page_number, uint8_t offset, int8_t data, bool // 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 -bool SPIFlash::writeByteArray(uint32_t address, uint8_t *data_buffer, uint16_t bufferSize, bool errorCheck) { - if (!_prep(PAGEPROG, address, bufferSize)) { +bool SPIFlash::writeByteArray(uint32_t _addr, uint8_t *data_buffer, uint16_t bufferSize, bool errorCheck) { + if (!_prep(PAGEPROG, _addr, bufferSize)) { return false; } - uint16_t maxBytes = PAGESIZE-(address % PAGESIZE); // Force the first set of bytes to stay within the first page + uint16_t maxBytes = PAGESIZE-(_addr % PAGESIZE); // Force the first set of bytes to stay within the first page if (bufferSize <= maxBytes) { - _beginSPI(PAGEPROG); + CHIP_SELECT + _nextByte(PAGEPROG); + _transferAddress(); _nextBuf(PAGEPROG, &data_buffer[0], bufferSize); CHIP_DESELECT } @@ -485,15 +411,12 @@ bool SPIFlash::writeByteArray(uint32_t address, uint8_t *data_buffer, uint16_t b uint16_t writeBufSz; uint16_t data_offset = 0; - while (length > 0) - { + do { writeBufSz = (length<=maxBytes) ? length : maxBytes; - if(!_notBusy() || !_writeEnable()){ - return false; - } - - _beginSPI(PAGEPROG); + CHIP_SELECT + _nextByte(PAGEPROG); + _transferAddress(); for (uint16_t i = 0; i < writeBufSz; ++i) { _nextByte(data_buffer[data_offset + i]); } @@ -503,7 +426,12 @@ bool SPIFlash::writeByteArray(uint32_t address, uint8_t *data_buffer, uint16_t b data_offset += writeBufSz; length -= writeBufSz; maxBytes = 256; // Now we can do up to 256 bytes per loop - } + + if(!_notBusy() || !_writeEnable()){ + return false; + } + + } while (length > 0); } if (!errorCheck) { @@ -514,12 +442,12 @@ bool SPIFlash::writeByteArray(uint32_t address, uint8_t *data_buffer, uint16_t b if (!_notBusy()) { return false; } - _currentAddress = address; + _currentAddress = _addr; CHIP_SELECT _nextByte(READDATA); _transferAddress(); for (uint16_t j = 0; j < bufferSize; j++) { - if (_nextByte(NULLBYTE) != data_buffer[j]) { + if (_nextByte() != data_buffer[j]) { return false; } } @@ -527,17 +455,11 @@ bool SPIFlash::writeByteArray(uint32_t address, uint8_t *data_buffer, uint16_t b return true; } } -// Variant B -bool SPIFlash::writeByteArray(uint16_t page_number, uint8_t offset, uint8_t *data_buffer, uint16_t bufferSize, bool errorCheck) { - uint32_t address = _getAddress(page_number, offset); - - return writeByteArray(address, data_buffer, bufferSize, errorCheck); -} // Writes an array of bytes starting from a specific location in a page. // Has two variants: // A. Takes three arguments - -// 1. address --> Any address - from 0 to capacity +// 1. _addr --> Any address - from 0 to capacity // 2. data --> An array of chars to be written to a particular location on a page // 3. errorCheck --> Turned on by default. Checks for writing errors // B. Takes four arguments - @@ -548,33 +470,45 @@ bool SPIFlash::writeByteArray(uint16_t page_number, uint8_t offset, uint8_t *dat // 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 -bool SPIFlash::writeCharArray(uint32_t address, char *data_buffer, uint16_t bufferSize, bool errorCheck) { - uint16_t writeBufSz; - uint16_t maxBytes = PAGESIZE-(address % PAGESIZE); // Force the first set of bytes to stay within the first page - uint16_t data_offset = 0; - uint16_t length = bufferSize; - if (!_prep(PAGEPROG, address, bufferSize)) { +bool SPIFlash::writeCharArray(uint32_t _addr, char *data_buffer, uint16_t bufferSize, bool errorCheck) { + if (!_prep(PAGEPROG, _addr, bufferSize)) { return false; } + uint16_t maxBytes = PAGESIZE-(_addr % PAGESIZE); // Force the first set of bytes to stay within the first page - while (length > 0) - { - writeBufSz = (length<=maxBytes) ? length : maxBytes; + if (bufferSize <= maxBytes) { + CHIP_SELECT + _nextByte(PAGEPROG); + _transferAddress(); + _nextBuf(PAGEPROG, &data_buffer[0], bufferSize); + CHIP_DESELECT + } + else { + uint16_t length = bufferSize; + uint16_t writeBufSz; + uint16_t data_offset = 0; - if(!_notBusy() || !_writeEnable()){ - return false; - } + do { + writeBufSz = (length<=maxBytes) ? length : maxBytes; - _beginSPI(PAGEPROG); + CHIP_SELECT + _nextByte(PAGEPROG); + _transferAddress(); + for (uint16_t i = 0; i < writeBufSz; ++i) { + _nextByte(data_buffer[data_offset + i]); + } + CHIP_DESELECT - for (uint16_t i = 0; i < writeBufSz; ++i) { - _nextByte(data_buffer[data_offset + i]); - } - _currentAddress += writeBufSz; - data_offset += writeBufSz; - length -= writeBufSz; - maxBytes = 256; // Now we can do up to 256 bytes per loop - CHIP_DESELECT + _currentAddress += writeBufSz; + data_offset += writeBufSz; + length -= writeBufSz; + maxBytes = 256; // Now we can do up to 256 bytes per loop + + if(!_notBusy() || !_writeEnable()){ + return false; + } + + } while (length > 0); } if (!errorCheck) { @@ -585,12 +519,12 @@ bool SPIFlash::writeCharArray(uint32_t address, char *data_buffer, uint16_t buff if (!_notBusy()) { return false; } - _currentAddress = address; + _currentAddress = _addr; CHIP_SELECT _nextByte(READDATA); _transferAddress(); for (uint16_t j = 0; j < bufferSize; j++) { - if (_nextByte(NULLBYTE) != data_buffer[j]) { + if (_nextByte() != data_buffer[j]) { return false; } } @@ -598,17 +532,11 @@ bool SPIFlash::writeCharArray(uint32_t address, char *data_buffer, uint16_t buff return true; } } -// Variant B -bool SPIFlash::writeCharArray(uint16_t page_number, uint8_t offset, char *data_buffer, uint16_t bufferSize, bool errorCheck) { - uint32_t address = _getAddress(page_number, offset); - - return writeCharArray(address, data_buffer, bufferSize, errorCheck); -} // Writes an unsigned int as two bytes starting from a specific location in a page. // Has two variants: // A. Takes three arguments - -// 1. address --> Any address - from 0 to capacity +// 1. _addr --> Any address - from 0 to capacity // 2. data --> One unsigned int of data to be written to a particular location on a page // 3. errorCheck --> Turned on by default. Checks for writing errors // B. Takes four arguments - @@ -619,19 +547,15 @@ bool SPIFlash::writeCharArray(uint16_t page_number, uint8_t offset, char *data_b // 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 -bool SPIFlash::writeWord(uint32_t address, uint16_t data, bool errorCheck) { - return writeAnything(address, data, errorCheck); -} -// Variant B -bool SPIFlash::writeWord(uint16_t page_number, uint8_t offset, uint16_t data, bool errorCheck) { - uint32_t address = _getAddress(page_number, offset); - return writeAnything(address, data, errorCheck); +bool SPIFlash::writeWord(uint32_t _addr, uint16_t data, bool errorCheck) { + uint8_t _sizeofdata = sizeof(data); + return _write(_addr, data, _sizeofdata, errorCheck); } // Writes a signed int as two bytes starting from a specific location in a page. // Has two variants: // A. Takes three arguments - -// 1. address --> Any address - from 0 to capacity +// 1. _addr --> Any address - from 0 to capacity // 2. data --> One signed int of data to be written to a particular location on a page // 3. errorCheck --> Turned on by default. Checks for writing errors // B. Takes four arguments - @@ -642,19 +566,15 @@ bool SPIFlash::writeWord(uint16_t page_number, uint8_t offset, uint16_t data, bo // 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 -bool SPIFlash::writeShort(uint32_t address, int16_t data, bool errorCheck) { - return writeAnything(address, data, errorCheck); -} -// Variant B -bool SPIFlash::writeShort(uint16_t page_number, uint8_t offset, int16_t data, bool errorCheck) { - uint32_t address = _getAddress(page_number, offset); - return writeAnything(address, data, errorCheck); +bool SPIFlash::writeShort(uint32_t _addr, int16_t data, bool errorCheck) { + uint8_t _sizeofdata = sizeof(data); + return _write(_addr, data, _sizeofdata, errorCheck); } // Writes an unsigned long as four bytes starting from a specific location in a page. // Has two variants: // A. Takes three arguments - -// 1. address --> Any address - from 0 to capacity +// 1. _addr --> Any address - from 0 to capacity // 2. data --> One unsigned long of data to be written to a particular location on a page // 3. errorCheck --> Turned on by default. Checks for writing errors // B. Takes four arguments - @@ -665,19 +585,15 @@ bool SPIFlash::writeShort(uint16_t page_number, uint8_t offset, int16_t data, bo // 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 -bool SPIFlash::writeULong(uint32_t address, uint32_t data, bool errorCheck) { - return writeAnything(address, data, errorCheck); -} -// Variant B -bool SPIFlash::writeULong(uint16_t page_number, uint8_t offset, uint32_t data, bool errorCheck) { - uint32_t address = _getAddress(page_number, offset); - return writeAnything(address, data, errorCheck); +bool SPIFlash::writeULong(uint32_t _addr, uint32_t data, bool errorCheck) { + uint8_t _sizeofdata = sizeof(data); + return _write(_addr, data, _sizeofdata, errorCheck); } // Writes a signed long as four bytes starting from a specific location in a page. // Has two variants: // A. Takes three arguments - -// 1. address --> Any address - from 0 to capacity +// 1. _addr --> Any address - from 0 to capacity // 2. data --> One signed long of data to be written to a particular location on a page // 3. errorCheck --> Turned on by default. Checks for writing errors // B. Takes four arguments - @@ -688,19 +604,15 @@ bool SPIFlash::writeULong(uint16_t page_number, uint8_t offset, uint32_t data, b // 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 -bool SPIFlash::writeLong(uint32_t address, int32_t data, bool errorCheck) { - return writeAnything(address, data, errorCheck); -} -// Variant B -bool SPIFlash::writeLong(uint16_t page_number, uint8_t offset, int32_t data, bool errorCheck) { - uint32_t address = _getAddress(page_number, offset); - return writeAnything(address, data, errorCheck); +bool SPIFlash::writeLong(uint32_t _addr, int32_t data, bool errorCheck) { + uint8_t _sizeofdata = sizeof(data); + return _write(_addr, data, _sizeofdata, errorCheck); } // Writes a float as four bytes starting from a specific location in a page. // Has two variants: // A. Takes three arguments - -// 1. address --> Any address - from 0 to capacity +// 1. _addr --> Any address - from 0 to capacity // 2. data --> One float of data to be written to a particular location on a page // 3. errorCheck --> Turned on by default. Checks for writing errors // B. Takes four arguments - @@ -711,19 +623,15 @@ bool SPIFlash::writeLong(uint16_t page_number, uint8_t offset, int32_t data, boo // 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 -bool SPIFlash::writeFloat(uint32_t address, float data, bool errorCheck) { - return writeAnything(address, data, errorCheck); -} -// Variant B -bool SPIFlash::writeFloat(uint16_t page_number, uint8_t offset, float data, bool errorCheck) { - uint32_t address = _getAddress(page_number, offset); - return writeAnything(address, data, errorCheck); +bool SPIFlash::writeFloat(uint32_t _addr, float data, bool errorCheck) { + uint8_t _sizeofdata = sizeof(data); + return _write(_addr, data, _sizeofdata, errorCheck); } // Reads a string from a specific location on a page. // Has two variants: // A. Takes two arguments - -// 1. address --> Any address from 0 to capacity +// 1. _addr --> Any address from 0 to capacity // 2. inputString --> String variable to write the data from // 3. errorCheck --> Turned on by default. Checks for writing errors // B. Takes four arguments - @@ -736,75 +644,10 @@ bool SPIFlash::writeFloat(uint16_t page_number, uint8_t offset, float data, bool // This function first writes the size of the string as an unsigned int to the address to figure out the size of the String object stored and // then writes the String object data. Therefore it takes up two bytes more than the size of the String itself. // Variant A -bool SPIFlash::writeStr(uint32_t address, String &inputStr, bool errorCheck) { - uint16_t inStrLen = inputStr.length() +1; - if(!_prep(PAGEPROG, address, inStrLen)) { - return false; - } - - const uint16_t size = sizeof(inStrLen); - union - { - uint8_t b[size]; - uint16_t w; - } var; - - var.w = inStrLen; - char inputChar[inStrLen]; - inputStr.toCharArray(inputChar, inStrLen); - uint16_t maxBytes = PAGESIZE-(address % PAGESIZE); // Force the first set of bytes to stay within the first page - if (maxBytes > inStrLen) { - _beginSPI(PAGEPROG); - _nextBuf(PAGEPROG, &var.b[0], size); - _nextBuf(PAGEPROG, (uint8_t*)&inputChar, inStrLen); - CHIP_DESELECT - } - else { - uint16_t writeBufSz; - uint16_t data_offset = 0; - bool strLenWritten = false; - - while (inStrLen > 0) - { - writeBufSz = (inStrLen<=maxBytes) ? inStrLen : maxBytes; - if(!_notBusy() || !_writeEnable()){ - return false; - } - - _beginSPI(PAGEPROG); - for (uint16_t i = 0; i < writeBufSz; ++i) { - if(!strLenWritten) { - for (uint8_t j = 0; j < size; j++) { - _nextByte(var.b[j]); - } - strLenWritten = true; - } - _nextByte(inputChar[data_offset + i]); - } - _currentAddress += writeBufSz; - data_offset += writeBufSz; - inStrLen -= writeBufSz; - maxBytes = 256; // Now we can do up to 256 bytes per loop - CHIP_DESELECT - } - } - - if (!errorCheck) { - _endSPI(); - return true; - } - else { - String tempStr; - readStr(address, tempStr); - return inputStr.equals(tempStr); - } +bool SPIFlash::writeStr(uint32_t _addr, String &inputStr, bool errorCheck) { + uint8_t _sizeofdata = sizeof(inputStr); + return _write(_addr, inputStr, _sizeofdata, errorCheck); } -// Variant B -bool SPIFlash::writeStr(uint16_t page_number, uint8_t offset, String &inputStr, bool errorCheck) { - uint32_t address = _getAddress(page_number, offset); - return writeStr(address, inputStr, errorCheck); -} - //Erases one 4k sector. Has two variants: // A. Takes the address as the argument and erases the sector containing the address. @@ -812,16 +655,16 @@ bool SPIFlash::writeStr(uint16_t page_number, uint8_t offset, String &inputStr, // The sectors are numbered 0 - 255 containing 16 pages each. // Page 0-15 --> Sector 0; Page 16-31 --> Sector 1;......Page 4080-4095 --> Sector 255 // Variant A -bool SPIFlash::eraseSector(uint32_t address) { - if(!_notBusy()||!_writeEnable()) - return false; - - _beginSPI(SECTORERASE); - _transferAddress(address); +bool SPIFlash::eraseSector(uint32_t _addr) { + if (!_prep(ERASEFUNC, _addr)) { + return false; + } + _beginSPI(SECTORERASE); //The address is transferred as a part of this function _endSPI(); - if(!_notBusy(500L)) - return false; //Datasheet says erasing a sector takes 400ms max + if(!_notBusy(500L)) { + return false; //Datasheet says erasing a sector takes 400ms max + } //_writeDisable(); //_writeDisable() is not required because the Write Enable Latch (WEL) flag is cleared to 0 // i.e. to write disable state upon the following conditions: @@ -830,11 +673,6 @@ bool SPIFlash::eraseSector(uint32_t address) { return true; } -// Variant B -bool SPIFlash::eraseSector(uint16_t page_number, uint8_t offset) { - uint32_t address = _getAddress(page_number, offset); - return eraseSector(address); -} //Erases one 32k block. Has two variants: // A. Takes the address as the argument and erases the block containing the address. @@ -842,16 +680,16 @@ bool SPIFlash::eraseSector(uint16_t page_number, uint8_t offset) { // The blocks are numbered 0 - 31 containing 128 pages each. // Page 0-127 --> Block 0; Page 128-255 --> Block 1;......Page 3968-4095 --> Block 31 // Variant A -bool SPIFlash::eraseBlock32K(uint32_t address) { - if(!_notBusy()||!_writeEnable()) { - return false; +bool SPIFlash::eraseBlock32K(uint32_t _addr) { + if (!_prep(ERASEFUNC, _addr)) { + return false; } _beginSPI(BLOCK32ERASE); - _transferAddress(address); _endSPI(); - if(!_notBusy(1*S)) - return false; //Datasheet says erasing a sector takes 400ms max + if(!_notBusy(1*S)) { + return false; //Datasheet says erasing a sector takes 400ms max + } //_writeDisable(); //_writeDisable() is not required because the Write Enable Latch (WEL) flag is cleared to 0 // i.e. to write disable state upon the following conditions: @@ -860,11 +698,6 @@ bool SPIFlash::eraseBlock32K(uint32_t address) { return true; } -// Variant B -bool SPIFlash::eraseBlock32K(uint16_t page_number, uint8_t offset) { - uint32_t address = _getAddress(page_number, offset); - return eraseBlock32K(address); -} //Erases one 64k block. Has two variants: // A. Takes the address as the argument and erases the block containing the address. @@ -872,16 +705,17 @@ bool SPIFlash::eraseBlock32K(uint16_t page_number, uint8_t offset) { // The blocks are numbered 0 - 15 containing 256 pages each. // Page 0-255 --> Block 0; Page 256-511 --> Block 1;......Page 3840-4095 --> Block 15 // Variant A -bool SPIFlash::eraseBlock64K(uint32_t address) { - if(!_notBusy()||!_writeEnable()) { - return false; +bool SPIFlash::eraseBlock64K(uint32_t _addr) { + if (!_prep(ERASEFUNC, _addr)) { + return false; } + _beginSPI(BLOCK64ERASE); - _transferAddress(address); _endSPI(); - if(!_notBusy(1200L)) - return false; //Datasheet says erasing a sector takes 400ms max + if(!_notBusy(1200L)) { + return false; //Datasheet says erasing a sector takes 400ms max + } //_writeDisable(); //_writeDisable() is not required because the Write Enable Latch (WEL) flag is cleared to 0 // i.e. to write disable state upon the following conditions: @@ -890,11 +724,6 @@ bool SPIFlash::eraseBlock64K(uint32_t address) { return true; } -// Variant B -bool SPIFlash::eraseBlock64K(uint16_t page_number, uint8_t offset) { - uint32_t address = _getAddress(page_number, offset); - return eraseBlock64K(address); -} //Erases whole chip. Think twice before using. bool SPIFlash::eraseChip(void) { @@ -903,8 +732,9 @@ bool SPIFlash::eraseChip(void) { _beginSPI(CHIPERASE); _endSPI(); - if(!_notBusy(_chip.eraseTime)) - return false; //Datasheet says erasing chip takes 6s max + if(!_notBusy(_chip.eraseTime)) { + return false; //Datasheet says erasing chip takes 6s max + } //_writeDisable(); //_writeDisable() is not required because the Write Enable Latch (WEL) flag is cleared to 0 // i.e. to write disable state upon the following conditions: diff --git a/src/SPIFlash.h b/src/SPIFlash.h index ad10587..62f5d1b 100644 --- a/src/SPIFlash.h +++ b/src/SPIFlash.h @@ -1,8 +1,8 @@ -/* Arduino SPIFlash Library v.2.6.0 +/* Arduino SPIFlash Library v.3.0.0 * Copyright (C) 2017 by Prajwal Bhattaram * Created by Prajwal Bhattaram - 19/05/2015 * Modified by @boseji - 02/03/2017 - * Modified by Prajwal Bhattaram - 14/04/2017 + * Modified by Prajwal Bhattaram - 17/05/2017 * * 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 @@ -27,17 +27,14 @@ #ifndef SPIFLASH_H #define SPIFLASH_H -//ATTiny85 does not have enough pins to support Serial. So, the basic troubleshooting functions of this library are not applicable. It is up to the end user to come up with a diagnostic routine for the ATTiny85. -#ifndef __AVR_ATtiny85__ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Uncomment the code below to run a diagnostic if your flash // // does not respond // // // // Error codes will be generated and returned on functions // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -#define RUNDIAGNOSTIC // +//#define RUNDIAGNOSTIC // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -#endif //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Uncomment the code below to increase the speed of the library // @@ -114,8 +111,8 @@ extern "C" { #define BEGIN_SPI SPI.begin(); #endif -#define LIBVER 2 -#define LIBSUBVER 6 +#define LIBVER 3 +#define LIBSUBVER 0 #define BUGFIXVER 0 #if defined (ARDUINO_ARCH_SAM) @@ -135,81 +132,55 @@ class SPIFlash { SPIFlash(PinName cs = CS, bool overflow = true); #endif //----------------------------------------Initial / Chip Functions----------------------------------------// - bool begin(uint32_t _chipSize = 0); + bool begin(void); void setClock(uint32_t clockSpeed); bool libver(uint8_t *b1, uint8_t *b2, uint8_t *b3); uint8_t error(bool verbosity = false); uint16_t getManID(void); uint32_t getJEDECID(void); - bool getAddress(uint16_t size, uint16_t &page_number, uint8_t &offset); uint32_t getAddress(uint16_t size); uint16_t sizeofStr(String &inputStr); uint32_t getCapacity(void); uint32_t getMaxPage(void); //-------------------------------------------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); + bool writeByte(uint32_t _addr, uint8_t data, bool errorCheck = true); + uint8_t readByte(uint32_t _addr, 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); - bool readByteArray(uint32_t address, uint8_t *data_buffer, uint16_t bufferSize, bool fastRead = false); - bool readByteArray(uint16_t page_number, uint8_t offset, uint8_t *data_buffer, uint16_t bufferSize, bool fastRead = false); + bool writeByteArray(uint32_t _addr, uint8_t *data_buffer, uint16_t bufferSize, bool errorCheck = true); + bool readByteArray(uint32_t _addr, 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); + bool writeChar(uint32_t _addr, int8_t data, bool errorCheck = true); + int8_t readChar(uint32_t _addr, 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); - bool readCharArray(uint32_t address, char *data_buffer, uint16_t buffer_size, bool fastRead = false); - bool readCharArray(uint16_t page_number, uint8_t offset, char *data_buffer, uint16_t buffer_size, bool fastRead = false); + bool writeCharArray(uint32_t _addr, char *data_buffer, uint16_t bufferSize, bool errorCheck = true); + bool readCharArray(uint32_t _addr, 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); + bool writeShort(uint32_t _addr, int16_t data, bool errorCheck = true); + int16_t readShort(uint32_t _addr, 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); + bool writeWord(uint32_t _addr, uint16_t data, bool errorCheck = true); + uint16_t readWord(uint32_t _addr, 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); + bool writeLong(uint32_t _addr, int32_t data, bool errorCheck = true); + int32_t readLong(uint32_t _addr, 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); + bool writeULong(uint32_t _addr, uint32_t data, bool errorCheck = true); + uint32_t readULong(uint32_t _addr, 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); + bool writeFloat(uint32_t _addr, float data, bool errorCheck = true); + float readFloat(uint32_t _addr, 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); + bool writeStr(uint32_t _addr, String &inputStr, bool errorCheck = true); + bool readStr(uint32_t _addr, String &outStr, bool fastRead = false); //------------------------------------------Write / Read Anything-----------------------------------------// - template bool writeAnything(uint32_t address, const T& value, uint32_t _sz, bool errorCheck); - 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, uint32_t _sz, bool fastRead = false); - 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); + template bool _write(uint32_t _addr, const T& value, uint8_t _sz, bool errorCheck); + template bool writeAnything(uint32_t _addr, const T& value, bool errorCheck = true); + template bool _read(uint32_t _addr, T& value, uint8_t _sz, bool fastRead = false); + template bool readAnything(uint32_t _addr, 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 eraseSector(uint32_t _addr); + bool eraseBlock32K(uint32_t _addr); + bool eraseBlock64K(uint32_t _addr); bool eraseChip(void); //---------------------------------------------Power functions--------------------------------------------// bool suspendProg(void); @@ -252,33 +223,31 @@ class SPIFlash { void _tinySPIbegin(); #endif //----------------------------------------Private functions----------------------------------------// - void _troubleshoot(void); + void _troubleshoot(uint8_t _code, bool printoverride = false); void _printErrorCode(void); void _printSupportLink(void); void _endSPI(void); - bool _prep(uint8_t opcode, uint32_t address, uint32_t size); - bool _prep(uint8_t opcode, uint32_t page_number, uint8_t offset, uint32_t size); + bool _prep(uint8_t opcode, uint32_t _addr, uint32_t size = 0); bool _startSPIBus(void); bool _beginSPI(uint8_t opcode); bool _noSuspend(void); bool _notBusy(uint32_t timeout = BUSY_TIMEOUT); - bool _notPrevWritten(uint32_t address, uint32_t size = 1); + bool _notPrevWritten(uint32_t _addr, uint32_t size = 1); bool _writeEnable(uint32_t timeout = 10L); bool _writeDisable(void); bool _getJedecId(void); bool _getManId(uint8_t *b1, uint8_t *b2); bool _getSFDP(void); bool _chipID(void); - bool _transferAddress(uint32_t _addr = 0); - bool _addressCheck(uint32_t address, uint32_t size = 1); + bool _transferAddress(void); + bool _addressCheck(uint32_t _addr, uint32_t size = 1); uint8_t _nextByte(uint8_t data = NULLBYTE); uint16_t _nextInt(uint16_t = NULLINT); void _nextBuf(uint8_t opcode, uint8_t *data_buffer, uint32_t size); uint8_t _readStat1(void); uint8_t _readStat2(void); - uint32_t _getAddress(uint16_t page_number, uint8_t offset = 0); - template bool _writeErrorCheck(uint32_t address, const T& value); - template bool _writeErrorCheck(uint32_t address, const T& value, uint32_t _sz); + template bool _writeErrorCheck(uint32_t _addr, const T& value); + template bool _writeErrorCheck(uint32_t _addr, const T& value, uint8_t _sz); //-------------------------------------------Private variables------------------------------------------// #ifdef SPI_HAS_TRANSACTION SPISettings _settings; @@ -291,7 +260,7 @@ class SPIFlash { #endif volatile uint8_t *cs_port; bool pageOverflow, SPIBusState; - uint8_t cs_mask, errorcode, state, _SPCR, _SPSR; + uint8_t cs_mask, errorcode, state, _SPCR, _SPSR, _a0, _a1, _a2; struct chipID { uint8_t manufacturerID; uint8_t memoryTypeID; @@ -312,173 +281,146 @@ class SPIFlash { //----------------------------------------Public 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 write data from -// 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 +// Takes three arguments - +// 1. _addr --> Any address from 0 to maxAddress +// 2. T& value --> Variable to write +// 3. 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, uint32_t _sz, bool errorCheck) { - const uint8_t* p = ((const uint8_t*)(const void*)&value); +template bool SPIFlash::writeAnything(uint32_t _addr, const T& value, bool errorCheck) { + uint8_t _sizeofvalue = sizeof(value); + return _write(_addr, value, _sizeofvalue, errorCheck); +} - //If data is only one byte (8 bits) long - if (_sz == sizeof(uint8_t)) { - if (_prep(PAGEPROG, address, _sz)) { - _beginSPI(PAGEPROG); - _nextByte(*p); - CHIP_DESELECT - } - else { +// Reads any type of data from a specific location in the flash memory. +// Takes three arguments - +// 1. _addr --> Any address from 0 to maxAddress +// 2. T& value --> Variable to return data into +// 3. fastRead --> defaults to false - executes _beginFastRead() if set to true +template bool SPIFlash::readAnything(uint32_t _addr, T& value, bool fastRead) { + uint8_t _sizeofvalue = sizeof(value); + return _read(_addr, value, _sizeofvalue, fastRead); +} + +//----------------------------------------Private Templates---------------------------------------// + +// Checks for errors in writing data to flash memory. +// Takes three arguments - +// 1. _addr --> Any address from 0 to maxAddress +// 2. const T& value --> Variable with the data to be error checked +// 3. _sz --> Size of the data variable to be error checked, in bytes (1 byte = 8 bits) +// Private template to check for errors in writing to flash memory +template bool SPIFlash::_writeErrorCheck(uint32_t _addr, const T& value, uint8_t _sz) { + if (!_notBusy()) { + return false; + } + _currentAddress = _addr; + const uint8_t* p = (const uint8_t*)(const void*)&value; + CHIP_SELECT + _nextByte(READDATA); + _transferAddress(); + for (uint16_t i = 0; i < _sz; i++) { + if (*p++ != _nextByte()) { + _troubleshoot(ERRORCHKFAIL); + _endSPI(); return false; } } + _endSPI(); + return true; +} + +// Writes any type of data to a specific location in the flash memory. +// Takes four arguments - +// 1. _addr --> Any address from 0 to maxAddress +// 2. T& value --> Variable to write +// 3. _sz --> Size of variable in bytes (1 byte = 8 bits) +// 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) + +template bool SPIFlash::_write(uint32_t _addr, const T& value, uint8_t _sz, bool errorCheck) { + if (!_prep(PAGEPROG, _addr, _sz)) { + return false; + } + const uint8_t* p = ((const uint8_t*)(const void*)&value); + + if (!SPIBusState) { + _startSPIBus(); + } + CHIP_SELECT + _nextByte(PAGEPROG); + _transferAddress(); + //If data is only one byte (8 bits) long + if (_sz == 0x01) { + _nextByte(*p); + CHIP_DESELECT + } else { //If data is longer than one byte (8 bits) uint32_t length = _sz; - uint16_t maxBytes = PAGESIZE-(address % PAGESIZE); // Force the first set of bytes to stay within the first page + uint16_t maxBytes = PAGESIZE-(_addr % PAGESIZE); // Force the first set of bytes to stay within the first page if (maxBytes > length) { - if (_prep(PAGEPROG, address, length)) { - _beginSPI(PAGEPROG); - for (uint16_t i = 0; i < length; ++i) { - _nextByte(*p++); - } - CHIP_DESELECT - } - else { - return false; + for (uint16_t i = 0; i < length; ++i) { + _nextByte(*p++); } + CHIP_DESELECT } else { - #ifndef HIGHSPEED - if(!_addressCheck(address, _sz) || !_notPrevWritten(address, _sz)) { - return false; - } - #else - if (!_addressCheck(address, _sz)) { - return false; - } - #endif uint32_t writeBufSz; uint16_t data_offset = 0; - while (length > 0) - { + do { writeBufSz = (length<=maxBytes) ? length : maxBytes; - if(_notBusy() && _writeEnable()) { - _beginSPI(PAGEPROG); - for (uint16_t i = 0; i < writeBufSz; ++i) { - _nextByte(*p++); - } - CHIP_DESELECT - _currentAddress += writeBufSz; - data_offset += writeBufSz; - length -= writeBufSz; - maxBytes = 256; // Now we can do up to 256 bytes per loop + for (uint16_t i = 0; i < writeBufSz; ++i) { + _nextByte(*p++); } - else { + CHIP_DESELECT + _currentAddress += writeBufSz; + data_offset += writeBufSz; + length -= writeBufSz; + maxBytes = 256; // Now we can do up to 256 bytes per loop + if(!_notBusy() || !_writeEnable()) { return false; } - } + } while (length > 0); } } - if (!errorCheck) { _endSPI(); return true; } else { - return _writeErrorCheck(address, value, _sz); + return _writeErrorCheck(_addr, value, _sz); } } -// Variant B -template bool SPIFlash::writeAnything(uint32_t address, const T& value, bool errorCheck) { - uint32_t _sizeofvalue = sizeof(value); - return writeAnything(address, value, _sizeofvalue, errorCheck); -} -// Variant C -template bool SPIFlash::writeAnything(uint16_t page_number, uint8_t offset, const T& value, bool errorCheck) { - uint32_t address = _getAddress(page_number, offset); - uint32_t _sizeofvalue = sizeof(value); - return writeAnything(address, value, _sizeofvalue, 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 C -template bool SPIFlash::readAnything(uint32_t address, T& value, uint32_t _sz, bool fastRead) { - if (_prep(READDATA, address, _sz)) { +// Takes four arguments - +// 1. _addr --> Any address from 0 to maxAddress +// 2. T& value --> Variable to return data into +// 3. _sz --> Size of the variable in bytes (1 byte = 8 bits) +// 4. fastRead --> defaults to false - executes _beginFastRead() if set to true +template bool SPIFlash::_read(uint32_t _addr, T& value, uint8_t _sz, bool fastRead) { + if (_prep(READDATA, _addr, _sz)) { uint8_t* p = (uint8_t*)(void*)&value; + CHIP_SELECT switch (fastRead) { case false: - _beginSPI(READDATA); - for (uint16_t i = 0; i < _sz; i++) { - *p++ =_nextByte(); - } - _endSPI(); + _nextByte(READDATA); break; case true: - _beginSPI(FASTREAD); - for (uint16_t i = 0; i < _sz; i++) { - *p++ =_nextByte(); - } - _endSPI(); + _nextByte(FASTREAD); break; default: break; } - return true; - } - else { - return false; - } -} -// Variant B -template bool SPIFlash::readAnything(uint32_t address, T& value, bool fastRead) { - uint32_t _sizeofvalue = sizeof(value); - return readAnything(address, value, _sizeofvalue, fastRead); -} -// Variant C -template bool SPIFlash::readAnything(uint16_t page_number, uint8_t offset, T& value, bool fastRead) -{ - uint32_t address = _getAddress(page_number, offset); - uint32_t _sizeofvalue = sizeof(value); - return readAnything(address, value, _sizeofvalue, fastRead); -} - -// Private template to check for errors in writing to flash memory -template bool SPIFlash::_writeErrorCheck(uint32_t address, const T& value) { - if (_prep(READDATA, address, sizeof(value))) { - const uint8_t* p = (const uint8_t*)(const void*)&value; - _beginSPI(READDATA); - for(uint16_t i = 0; i < sizeof(value);i++) - { - if(*p++ != _nextByte()) - { - errorcode = ERRORCHKFAIL; - #ifdef RUNDIAGNOSTIC - _troubleshoot(); - #endif - return false; - } + _transferAddress(); + for (uint16_t i = 0; i < _sz; i++) { + *p++ =_nextByte(); } _endSPI(); return true; @@ -488,49 +430,4 @@ template bool SPIFlash::_writeErrorCheck(uint32_t address, const T& va } } -template bool SPIFlash::_writeErrorCheck(uint32_t address, const T& value, uint32_t _sz) { -if (!_prep(READDATA, address, _sz)) { - return false; -} - - const uint8_t* p = (const uint8_t*)(const void*)&value; - _beginSPI(READDATA); - for(uint16_t i = 0; i < _sz;i++) - { -/*#if defined (ARDUINO_ARCH_SAM) - if(*p++ != _dueSPIRecByte()) - { - return false; - } -#else*/ - if(*p++ != _nextByte()) - { - errorcode = ERRORCHKFAIL; - #ifdef RUNDIAGNOSTIC - _troubleshoot(); - #endif - return false; - } -//#endif - } - _endSPI(); - return true; -} -//----------------------------------------Private 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 write data from -// 3. size --> size of data -// 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) - #endif // _SPIFLASH_H_ diff --git a/src/defines.h b/src/defines.h index c966fac..e7d7b3a 100644 --- a/src/defines.h +++ b/src/defines.h @@ -1,7 +1,7 @@ -/* Arduino SPIFlash Library v.2.6.0 +/* Arduino SPIFlash Library v.3.0.0 * Copyright (C) 2017 by Prajwal Bhattaram * Created by Prajwal Bhattaram - 19/05/2015 - * Modified by Prajwal Bhattaram - 14/04/2017 + * Modified by Prajwal Bhattaram - 17/05/2017 * * 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 @@ -92,6 +92,8 @@ //~~~~~~~~~~~~~~~~~~~~~~~~~ Winbond ~~~~~~~~~~~~~~~~~~~~~~~~~// #define WINBOND_MANID 0xEF #define PAGESIZE 0x100 + #define WINBOND_WRITE_DELAY 0x02 + #define WINBOND_WREN_TIMEOUT 10L //~~~~~~~~~~~~~~~~~~~~~~~~ Microchip ~~~~~~~~~~~~~~~~~~~~~~~~// #define MICROCHIP_MANID 0xBF @@ -119,6 +121,8 @@ #define NOOVERFLOW false #define NOERRCHK false #define VERBOSE true +#define PRINTOVERRIDE true +#define ERASEFUNC 0xEF #if defined (SIMBLEE) #define BUSY_TIMEOUT 100L #else diff --git a/src/troubleshoot.cpp b/src/troubleshoot.cpp index 7795bf9..ae81f6a 100644 --- a/src/troubleshoot.cpp +++ b/src/troubleshoot.cpp @@ -1,8 +1,7 @@ -/* Arduino SPIFlash Library v.2.6.0 +/* Arduino SPIFlash Library v.3.0.0 * Copyright (C) 2017 by Prajwal Bhattaram - * Created by Prajwal Bhattaram - 14/11/2016 - * Modified by @boseji - 02/03/2017 - * Modified by Prajwal Bhattaram - 14/04/2017 + * Created by Prajwal Bhattaram - 14/11/2016\ + * Modified by Prajwal Bhattaram - 17/05/2017 * * 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 @@ -25,162 +24,110 @@ * . */ - #include "SPIFlash.h" - - #if !defined (__AVR_ATtiny85__) - //Subfunctions for troubleshooting function - void SPIFlash::_printErrorCode(void) { - Serial.print("Error code: 0x"); - if (errorcode < 0x10) { - Serial.print("0"); - } - Serial.println(errorcode, HEX); - } - - void SPIFlash::_printSupportLink(void) { - Serial.print("If this does not help resolve/clarify this issue, "); - Serial.println("please raise an issue at http://www.github.com/Marzogh/SPIFlash/issues with the details of what your were doing when this error occurred"); - } - //Troubleshooting function. Called when #ifdef RUNDIAGNOSTIC is uncommented at the top of this file. - void SPIFlash::_troubleshoot(void) { - - switch (errorcode) { - case SUCCESS: - #if defined (ARDUINO_ARCH_AVR) || defined (__AVR_ATtiny85__) - _printErrorCode(); - #else - Serial.println("Action completed successfully"); - #endif - break; - - case NORESPONSE: - #if defined (ARDUINO_ARCH_AVR) || defined (__AVR_ATtiny85__) - _printErrorCode(); - #else - Serial.println("Check your wiring. Flash chip is non-responsive."); - _printSupportLink(); - #endif - break; - - case CALLBEGIN: - #if defined (ARDUINO_ARCH_AVR) || defined (__AVR_ATtiny85__) - _printErrorCode(); - #else - Serial.println("*constructor_of_choice*.begin() was not called in void setup()"); - _printSupportLink(); - #endif - break; - - case UNKNOWNCHIP: - #if defined (ARDUINO_ARCH_AVR) || defined (__AVR_ATtiny85__) - Serial.print("Error code: 0x0"); - Serial.println(UNKNOWNCHIP, HEX); - #else - Serial.println("Unable to identify chip. Are you sure this chip is supported?"); - _printSupportLink(); - #endif - Serial.println("Chip details:"); - Serial.print("manufacturer ID: 0x"); Serial.println(_chip.manufacturerID, HEX); - Serial.print("capacity ID: 0x");Serial.println(_chip.memoryTypeID, HEX); - Serial.print("device ID: 0x");Serial.println(_chip.capacityID, HEX); - break; - - case UNKNOWNCAP: - #if defined (ARDUINO_ARCH_AVR) || defined (__AVR_ATtiny85__) - _printErrorCode(); - #else - Serial.println("Unable to identify capacity. Is this chip officially supported? If not, please define a `CAPACITY` constant and include it in flash.begin(CAPACITY)."); - _printSupportLink(); - #endif - break; - - case CHIPBUSY: - #if defined (ARDUINO_ARCH_AVR) || defined (__AVR_ATtiny85__) - _printErrorCode(); - #else - Serial.println("Chip is busy."); - Serial.println("Make sure all pins have been connected properly"); - _printSupportLink(); - #endif - break; - - case OUTOFBOUNDS: - #if defined (ARDUINO_ARCH_AVR) || defined (__AVR_ATtiny85__) - _printErrorCode(); - #else - Serial.println("Page overflow has been disabled and the address called exceeds the memory"); - _printSupportLink(); - #endif - break; - - case CANTENWRITE: - #if defined (ARDUINO_ARCH_AVR) || defined (__AVR_ATtiny85__) - _printErrorCode(); - #else - Serial.println("Unable to Enable Writing to chip."); - Serial.println("Please make sure the HOLD & WRITEPROTECT pins are pulled up to VCC"); - _printSupportLink(); - #endif - break; - - case PREVWRITTEN: - #if defined (ARDUINO_ARCH_AVR) || defined (__AVR_ATtiny85__) - _printErrorCode(); - #else - Serial.println("This sector already contains data."); - Serial.println("Please make sure the sectors being written to are erased."); - _printSupportLink(); - #endif - break; - - case LOWRAM: - #if defined (ARDUINO_ARCH_AVR) || defined (__AVR_ATtiny85__) - _printErrorCode(); - #else - Serial.println("You are running low on SRAM. Please optimise your program for better RAM usage"); - /*#if defined (ARDUINO_ARCH_SAM) - Serial.print("Current Free SRAM: "); - Serial.println(freeRAM()); - #endif*/ - _printSupportLink(); - #endif - break; - - case SYSSUSPEND: - #if defined (ARDUINO_ARCH_AVR) || defined (__AVR_ATtiny85__) - _printErrorCode(); - #else - Serial.println("Unable to suspend/resume operation."); - _printSupportLink(); - #endif - break; - - case UNSUPPORTED: - #if defined (ARDUINO_ARCH_AVR) || defined (__AVR_ATtiny85__) - _printErrorCode(); - #else - Serial.println("This function is not supported by the current flash IC."); - _printSupportLink(); - #endif - break; - - case ERRORCHKFAIL: -#if defined (ARDUINO_ARCH_AVR) || defined (__AVR_ATtiny85__) - _printErrorCode(); +#include "SPIFlash.h" + +//ATTiny85 does not have enough pins to support Serial. So, the basic troubleshooting functions of this library are not applicable. It is up to the end user to come up with a diagnostic routine for the ATTiny85. +#if !defined (__AVR_ATtiny85__) +//Subfunctions for troubleshooting function +void SPIFlash::_printErrorCode(void) { + Serial.print("Error code: 0x"); + if (errorcode < 0x10) { + Serial.print("0"); + } + Serial.println(errorcode, HEX); +} + +void SPIFlash::_printSupportLink(void) { + Serial.print("If this does not help resolve/clarify this issue, "); + Serial.println("please raise an issue at http://www.github.com/Marzogh/SPIFlash/issues with the details of what your were doing when this error occurred"); +} +//Troubleshooting function. Called when #ifdef RUNDIAGNOSTIC is uncommented at the top of this file. +void SPIFlash::_troubleshoot(uint8_t _code, bool printoverride) { + bool _printoverride; + errorcode = _code; +#ifdef RUNDIAGNOSTIC + _printoverride = true; #else - Serial.println("Write Function has failed errorcheck."); - _printSupportLink(); + _printoverride = printoverride; #endif - break; - - default: - #if defined (ARDUINO_ARCH_AVR) || defined (__AVR_ATtiny85__) + if (_printoverride) { + #if defined (ARDUINO_ARCH_AVR) _printErrorCode(); #else - Serial.println("Unknown error"); - _printSupportLink(); + switch (_code) { + case SUCCESS: + Serial.println("Action completed successfully"); + break; + + case NORESPONSE: + Serial.println("Check your wiring. Flash chip is non-responsive."); + break; + + case CALLBEGIN: + Serial.println("*constructor_of_choice*.begin() was not called in void setup()"); + break; + + case UNKNOWNCHIP: + Serial.println("Unable to identify chip. Are you sure this chip is supported?"); + Serial.println("Chip details:"); + Serial.print("manufacturer ID: 0x"); Serial.println(_chip.manufacturerID, HEX); + Serial.print("capacity ID: 0x"); Serial.println(_chip.memoryTypeID, HEX); + Serial.print("device ID: 0x"); Serial.println(_chip.capacityID, HEX); + break; + + case UNKNOWNCAP: + Serial.println("Unable to identify capacity. Is this chip officially supported? If not, please define a `CAPACITY` constant and include it in flash.begin(CAPACITY)."); + break; + + case CHIPBUSY: + Serial.println("Chip is busy."); + Serial.println("Make sure all pins have been connected properly"); + break; + + case OUTOFBOUNDS: + Serial.println("Page overflow has been disabled and the address called exceeds the memory"); + break; + + case CANTENWRITE: + Serial.println("Unable to Enable Writing to chip."); + Serial.println("Please make sure the HOLD & WRITEPROTECT pins are pulled up to VCC"); + break; + + case PREVWRITTEN: + Serial.println("This sector already contains data."); + Serial.println("Please make sure the sectors being written to are erased."); + break; + + case LOWRAM: + Serial.println("You are running low on SRAM. Please optimise your program for better RAM usage"); + /*#if defined (ARDUINO_ARCH_SAM) + Serial.print("Current Free SRAM: "); + Serial.println(freeRAM()); + #endif*/ + break; + + case SYSSUSPEND: + Serial.println("Unable to suspend/resume operation."); + break; + + case UNSUPPORTED: + Serial.println("This function is not supported by the current flash IC."); + break; + + case ERRORCHKFAIL: + Serial.println("Write Function has failed errorcheck."); + break; + + default: + Serial.println("Unknown error"); + break; + } + if (_code != SUCCESS) { + _printSupportLink(); + } #endif - break; - } - } - #endif + } +} +#else //If compiled for ATTiny85 based platform - empty function to prevent compile errors +void troubleshoot(uint8_t _code, bool printoverride) {} +#endif //End of ATTiny85 code limitation From f5dfd52bbe0ab8c870d344b444434e057580b252 Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Mon, 29 May 2017 23:19:57 +1000 Subject: [PATCH 06/34] Library now works with Microchip flash memory. (Further optimizations required) --- examples/readWriteString/readWriteString.ino | 32 ++++++++------------ extras/Changes.log | 1 + 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/examples/readWriteString/readWriteString.ino b/examples/readWriteString/readWriteString.ino index 0d16942..cf57a7c 100644 --- a/examples/readWriteString/readWriteString.ino +++ b/examples/readWriteString/readWriteString.ino @@ -2,10 +2,10 @@ |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | readWriteString.ino | | SPIFlash library | - | v 2.5.0 | + | v 3.0.0 | |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | Marzogh | - | 16.11.2016 | + | 29.05.2017 | |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | | | This program shows the method of reading a string from the console and saving it to flash memory | @@ -14,8 +14,7 @@ */ #include -int strPage, strSize; -byte strOffset; +uint32_t strAddr; #if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) // Required for Serial on Zero based boards @@ -49,30 +48,25 @@ void setup() { #else randomSeed(analogRead(RANDPIN)); #endif - strPage = random(0, 4095); - strOffset = random(0, 255); + strAddr = random(0, flash.getCapacity()); String inputString = "This is a test String"; - flash.writeStr(strPage, strOffset, inputString); + flash.writeStr(strAddr, inputString); #ifndef __AVR_ATtiny85__ Serial.print(F("Written string: ")); - Serial.print(inputString); - Serial.print(F(" to page ")); - Serial.print(strPage); - Serial.print(F(", at offset ")); - Serial.println(strOffset); + Serial.println(inputString); + Serial.print(F("To address: ")); + Serial.println(strAddr); #endif String outputString = ""; - if (flash.readStr(strPage, strOffset, outputString)) { + if (flash.readStr(strAddr, outputString)) { #ifndef __AVR_ATtiny85__ Serial.print(F("Read string: ")); - Serial.print(outputString); - Serial.print(F(" from page ")); - Serial.print(strPage); - Serial.print(F(", at offset ")); - Serial.println(strOffset); + Serial.println(outputString); + Serial.print(F("From address: ")); + Serial.println(strAddr); #endif } - while (!flash.eraseSector(strPage, 0)); + while (!flash.eraseSector(strAddr)); } void loop() { diff --git a/extras/Changes.log b/extras/Changes.log index 2b17212..4cd596c 100644 --- a/extras/Changes.log +++ b/extras/Changes.log @@ -20,6 +20,7 @@ New Boards supported: --> Enhancements: +--> Library now works with Microchip flash memory. (Further optimizations required) --> Library faster than before (Refer to Library speed comparison in the extras folder for timing details): Improvements in speed in v3.0.0 when compared to v2.7.0 (values in percentage of time v3.0.0 is faster than v2.7.0) From ac1a256576d9261e6ea7302728724bec819b5110 Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Wed, 31 May 2017 08:52:19 +1000 Subject: [PATCH 07/34] All examples now work with the latest code --- examples/Struct_writer/Struct_writer.ino | 2 +- examples/TestFlash/TestFlash.ino | 215 ++++++++----------- examples/tinyFlashTester/tinyFlashTester.ino | 2 +- extras/Changes.log | 2 +- 4 files changed, 89 insertions(+), 132 deletions(-) diff --git a/examples/Struct_writer/Struct_writer.ino b/examples/Struct_writer/Struct_writer.ino index f7d0698..68f39b7 100644 --- a/examples/Struct_writer/Struct_writer.ino +++ b/examples/Struct_writer/Struct_writer.ino @@ -133,7 +133,7 @@ void setup() { Serial.println(); Serial.println(); flash.readAnything(_addr, configuration); - flash.eraseSector(_addr, 0); + flash.eraseSector(_addr); Serial.println("After reading"); Serial.println(configuration.lux); diff --git a/examples/TestFlash/TestFlash.ino b/examples/TestFlash/TestFlash.ino index 813233e..ffcca56 100644 --- a/examples/TestFlash/TestFlash.ino +++ b/examples/TestFlash/TestFlash.ino @@ -16,46 +16,46 @@ | 1. getID | | '1' gets the JEDEC ID of the chip | | | - | 2. writeByte [page] [offset] [byte] | - | '2' followed by '100' and then by '20' and then by '224' writes the byte 224 to page 100 position 20 | + | 2. writeByte [address] [byte] | + | '2' followed by '2435' and then by '224' writes the byte 224 to address 2435 | | | - | 3. readByte [page] [offset] | - | '3' followed by '100' and then by '20' returns the byte from page 100 position 20 | + | 3. readByte [address] | + | '3' followed by '2435' returns the byte from address '2435' | | | - | 4. writeWord [page] [offset] | - | '4' followed by '55' and then by '35' and then by '633' writes the int 633 to page 5 position 35 | + | 4. writeWord [address] [word] | + | '4' followed by '5948' and then by '633' writes the int 633 to address 5948 | | | - | 5. readWord [page] [offset] | - | '5' followed by '200' and then by '30' returns the int from page 200 position 30 | + | 5. readWord [address] | + | '5' followed by '5948' returns the int from address 5948 | | | - | 6. writeStr [page] [offset] [inputString] | - | '6' followed by '345' and then by '65' and then by 'Test String 1!' writes the String 'Test String 1! to page 345 position 65 | + | 6. writeStr [address] [inputString] | + | '6' followed by '345736' and then by 'Test String 1!' writes the String 'Test String 1! to address 345736 | | | - | 7. readStr [page] [offset] [outputString] | - | '7' followed by '2050' and then by '73' reds the String from page 2050 position 73 into the outputString | + | 7. readStr [address] [outputString] | + | '7' followed by '345736' reads the String from address 345736 into the outputString | | | | 8. writePage [page] | - | '8' followed by '33' writes bytes from 0 to 255 sequentially to fill page 33 | + | '8' followed by '33' writes bytes from 0 to 255 sequentially to fill a page (256 bytes) starting with address 33 | | | | 9. printPage [page] | - | '9' followed by 33 reads & prints page 33. To just read a page to a data buffer, refer | + | '9' followed by 33 reads & prints a page (256 bytes) starting with address 33. To just read a page to a data buffer, refer | | to 'ReadMe.md' in the library folder. | | | - | 10. printAllPages | - | '10' reads all 4096 pages and outputs them to the serial console | + | 10. printAllData | + | '10' reads the entire chip and outputs the data as a byte array to the serial console | | This function is to extract data from a flash chip onto a computer as a text file. | | Refer to 'Read me.md' in the library for details. | | | | 11. Erase 4KB sector | - | '11' followed by 2 erases a 4KB sector containing the page to be erased | + | '11' followed by 2 erases a 4KB sector containing the address be erased | | Page 0-15 --> Sector 0; Page 16-31 --> Sector 1;......Page 4080-4095 --> Sector 255 | | | | 12. Erase 32KB block | - | '12' followed by 2 erases a 32KB block containing the page to be erased | + | '12' followed by 2 erases a 32KB block containing the address to be erased | | Page 0-15 --> Sector 0; Page 16-31 --> Sector 1;......Page 4080-4095 --> Sector 255 | | | | 13. Erase 64KB block | - | '13' followed by 2 erases a 64KB block containing the page to be erased | + | '13' followed by 2 erases a 64KB block containing the address to be erased | | Page 0-15 --> Sector 0; Page 16-31 --> Sector 1;......Page 4080-4095 --> Sector 255 | | | | 14. Erase Chip | @@ -70,8 +70,8 @@ uint8_t pageBuffer[256]; String serialCommand; char printBuffer[128]; -uint16_t page; -uint8_t offset, dataByte; +uint32_t addr; +uint8_t dataByte; uint16_t dataInt; String inputString, outputString; @@ -141,24 +141,15 @@ void loop() { Serial.println(F(" Function 2 : Write Byte ")); printSplash(); printLine(); - Serial.print(F("Please enter the number of the page you wish to modify: ")); - while (!Serial.available()) { - } - page = Serial.parseInt(); - Serial.println(page); - Serial.print(F("Please enter the position on the page (0-255) you wish to modify: ")); - while (!Serial.available()) { - } - offset = Serial.parseInt(); - Serial.println(offset); + inputAddress(); Serial.print(F("Please enter the value of the byte (0-255) you wish to save: ")); while (!Serial.available()) { } dataByte = Serial.parseInt(); Serial.println(dataByte); - if (flash.writeByte(page, offset, dataByte)) { + if (flash.writeByte(addr, dataByte)) { clearprintBuffer(); - sprintf(printBuffer, "%d has been written to position %d on page %d", dataByte, offset, page); + sprintf(printBuffer, "%d has been written to address %d", dataByte, addr); Serial.println(printBuffer); } else { @@ -172,20 +163,11 @@ void loop() { Serial.println(F(" Function 3 : Read Byte ")); printSplash(); printLine(); - Serial.print(F("Please enter the number of the page the byte you wish to read is on: ")); - while (!Serial.available()) { - } - page = Serial.parseInt(); - Serial.println(page); - Serial.print(F("Please enter the position of the byte on the page (0-255) you wish to read: ")); - while (!Serial.available()) { - } - offset = Serial.parseInt(); - Serial.println(offset); + inputAddress(); clearprintBuffer(); - sprintf(printBuffer, "The byte at position %d on page %d is: ", offset, page); + sprintf(printBuffer, "The byte at address %d is: ", addr); Serial.print(printBuffer); - Serial.println(flash.readByte(page, offset)); + Serial.println(flash.readByte(addr)); printLine(); printNextCMD(); } @@ -194,24 +176,15 @@ void loop() { Serial.println(F(" Function 4 : Write Word ")); printSplash(); printLine(); - Serial.print(F("Please enter the number of the page you wish to modify: ")); - while (!Serial.available()) { - } - page = Serial.parseInt(); - Serial.println(page); - Serial.print(F("Please enter the position on the page (0-255) you wish to modify: ")); - while (!Serial.available()) { - } - offset = Serial.parseInt(); - Serial.println(offset); + inputAddress(); Serial.print(F("Please enter the value of the word (>255) you wish to save: ")); while (!Serial.available()) { } dataInt = Serial.parseInt(); Serial.println(dataInt); - if (flash.writeWord(page, offset, dataInt)) { + if (flash.writeWord(addr, dataInt)) { clearprintBuffer(); - sprintf(printBuffer, "%d has been written to position %d on page %d", dataInt, offset, page); + sprintf(printBuffer, "%d has been written to address %d", dataInt, addr); Serial.println(printBuffer); } else { @@ -225,20 +198,11 @@ void loop() { Serial.println(F(" Function 5 : Read Word ")); printSplash(); printLine(); - Serial.print(F("Please enter the number of the page the byte you wish to read is on: ")); - while (!Serial.available()) { - } - page = Serial.parseInt(); - Serial.println(page); - Serial.print(F("Please enter the position of the word on the page (0-255) you wish to read: ")); - while (!Serial.available()) { - } - offset = Serial.parseInt(); - Serial.println(offset); + inputAddress(); clearprintBuffer(); - sprintf(printBuffer, "The unsigned int at position %d on page %d is: ", offset, page); + sprintf(printBuffer, "The unsigned int at address %d is: ", addr); Serial.print(printBuffer); - Serial.println(flash.readWord(page, offset)); + Serial.println(flash.readWord(addr)); printLine(); printNextCMD(); } @@ -248,25 +212,16 @@ void loop() { printSplash(); printLine(); Serial.println(F("This function will write a String of your choice to the page selected.")); - Serial.print(F("Please enter the number of the page you wish to write to: ")); - while (!Serial.available()) { - } - page = Serial.parseInt(); - Serial.println(page); - Serial.print(F("Please enter the position on the page (0-255) you wish to write to: ")); - while (!Serial.available()) { - } - offset = Serial.parseInt(); - Serial.println(offset); + inputAddress(); Serial.println(F("Please enter the String you wish to save: ")); while (!Serial.available()) { } readSerialStr(inputString); - if (flash.writeStr(page, offset, inputString)) { + if (flash.writeStr(addr, inputString)) { clearprintBuffer(); Serial.print(F("String '")); Serial.print(inputString); - sprintf(printBuffer, "' has been written to position %d on page %d", offset, page); + sprintf(printBuffer, "' has been written to address %d", addr); Serial.println(printBuffer); } else { @@ -280,20 +235,12 @@ void loop() { Serial.println(F(" Function 7 : Read String ")); printSplash(); printLine(); - Serial.print(F("Please enter the number of the page the String you wish to read is on: ")); - while (!Serial.available()) { - } - page = Serial.parseInt(); - Serial.println(page); - Serial.print(F("Please enter the position of the String on the page (0-255) you wish to read: ")); - while (!Serial.available()) { - } - offset = Serial.parseInt(); - Serial.println(offset); + Serial.print(F("This function will read a string from your address of choice: ")); + inputAddress(); clearprintBuffer(); - sprintf(printBuffer, "The String at position %d on page %d is: ", offset, page); + sprintf(printBuffer, "The String at address %d is: ", addr); Serial.print(printBuffer); - flash.readStr(page, offset, outputString); + flash.readStr(addr, outputString); Serial.println(outputString); printLine(); printNextCMD(); @@ -303,18 +250,18 @@ void loop() { Serial.println(F(" Function 8 : Write Page ")); printSplash(); printLine(); - Serial.println(F("This function will write a sequence of bytes (0-255) to the page selected.")); - Serial.print(F("Please enter the number of the page you wish to write to: ")); + Serial.println(F("This function will write a sequence of bytes (0-255) starting from your address of choice")); + Serial.print(F("Please enter the address you wish to write to: ")); while (!Serial.available()) { } - page = Serial.parseInt(); - Serial.println(page); + addr = Serial.parseInt(); + Serial.println(addr); for (uint16_t i = 0; i < PAGESIZE; ++i) { pageBuffer[i] = i; } - if (flash.writeByteArray(page, 0, &pageBuffer[0], PAGESIZE)) { + if (flash.writeByteArray(addr, &pageBuffer[0], PAGESIZE)) { clearprintBuffer(); - sprintf(printBuffer, "Values from 0 to 255 have been written to the page %d", page); + sprintf(printBuffer, "Values from 0 to 255 have been written starting from the address %d", addr); Serial.println(printBuffer); printReadChoice(); while (!Serial.available()) { @@ -327,7 +274,7 @@ void loop() { } uint8_t outputType = Serial.parseInt(); Serial.println(outputType); - printPage(page, outputType); + printPage(addr, outputType); } } else { @@ -341,18 +288,18 @@ void loop() { Serial.println(F(" Function 9 : Read Page ")); printSplash(); printLine(); - Serial.println(F("This function will read the entire page selected.")); - Serial.print(F("Please enter the number of the page you wish to read: ")); + Serial.println(F("This function will read 256 bytes from the address selected.")); + Serial.print(F("Please enter the address you wish to read: ")); while (!Serial.available()) { } - page = Serial.parseInt(); - Serial.println(page); + addr = Serial.parseInt(); + Serial.println(addr); printOutputChoice(); while (!Serial.available()) { } uint8_t outputType = Serial.parseInt(); Serial.println(outputType); - printPage(page, outputType); + printPage(addr, outputType); printLine(); printNextCMD(); } @@ -384,14 +331,14 @@ void loop() { printSplash(); printLine(); Serial.println(F("This function will erase a 4KB sector.")); - Serial.print(F("Please enter the number of the page you wish to erase: ")); + Serial.print(F("Please enter the address you wish to erase: ")); while (!Serial.available()) { } - page = Serial.parseInt(); - Serial.println(page); - flash.eraseSector(page, 0); + addr = Serial.parseInt(); + Serial.println(addr); + flash.eraseSector(addr); clearprintBuffer(); - sprintf(printBuffer, "A 4KB sector containing page %d has been erased", page); + sprintf(printBuffer, "A 4KB sector containing address %d has been erased", addr); Serial.println(printBuffer); printReadChoice(); while (!Serial.available()) { @@ -404,7 +351,7 @@ void loop() { } uint8_t outputType = Serial.parseInt(); Serial.println(outputType); - printPage(page, outputType); + printPage(addr, outputType); } printLine(); printNextCMD(); @@ -415,14 +362,14 @@ void loop() { printSplash(); printLine(); Serial.println(F("This function will erase a 32KB block.")); - Serial.print(F("Please enter the number of the page you wish to erase: ")); + Serial.print(F("Please enter the address you wish to erase: ")); while (!Serial.available()) { } - page = Serial.parseInt(); - Serial.println(page); - flash.eraseBlock32K(page, 0); + addr = Serial.parseInt(); + Serial.println(addr); + flash.eraseBlock32K(addr); clearprintBuffer(); - sprintf(printBuffer, "A 32KB block containing page %d has been erased", page); + sprintf(printBuffer, "A 32KB block containing address %d has been erased", addr); Serial.println(printBuffer); printReadChoice(); while (!Serial.available()) { @@ -435,7 +382,7 @@ void loop() { } uint8_t outputType = Serial.parseInt(); Serial.println(outputType); - printPage(page, outputType); + printPage(addr, outputType); } printLine(); printNextCMD(); @@ -446,14 +393,14 @@ void loop() { printSplash(); printLine(); Serial.println(F("This function will erase a 64KB block.")); - Serial.print(F("Please enter the number of the page you wish to erase: ")); + Serial.print(F("Please enter the address you wish to erase: ")); while (!Serial.available()) { } - page = Serial.parseInt(); - Serial.println(page); - flash.eraseBlock64K(page, 0); + addr = Serial.parseInt(); + Serial.println(addr); + flash.eraseBlock64K(addr); clearprintBuffer(); - sprintf(printBuffer, "A 64KB block containing page %d has been erased", page); + sprintf(printBuffer, "A 64KB block containing address %d has been erased", addr); Serial.println(printBuffer); printReadChoice(); while (!Serial.available()) { @@ -466,7 +413,7 @@ void loop() { } uint8_t outputType = Serial.parseInt(); Serial.println(outputType); - printPage(page, outputType); + printPage(addr, outputType); } printLine(); printNextCMD(); @@ -536,16 +483,16 @@ void _printPageBytes(uint8_t *data_buffer, uint8_t outputType) { } //Reads a page of data and prints it to Serial stream. Make sure the sizeOf(uint8_t data_buffer[]) == 256. -void printPage(uint16_t page_number, uint8_t outputType) { +void printPage(uint32_t _address, uint8_t outputType) { if (!Serial) Serial.begin(115200); char buffer[24]; - sprintf(buffer, "Reading page (%04x)", page_number); + sprintf(buffer, "Reading address (%04x)", _address); Serial.println(buffer); uint8_t data_buffer[PAGESIZE]; - flash.readByteArray(page_number, 0, &data_buffer[0], PAGESIZE); + flash.readByteArray(_address, &data_buffer[0], PAGESIZE); _printPageBytes(data_buffer, outputType); } @@ -558,10 +505,11 @@ void printAllPages(uint8_t outputType) { Serial.println("Reading all pages"); uint8_t data_buffer[256]; - uint32_t maxPage = flash.getMaxPage(); - for (int a = 0; a < maxPage; a++) { - flash.readByteArray(a, 0, &data_buffer[0], 256); + uint32_t maxAddr = flash.getCapacity(); + for (int a = 0; a < maxAddr; a++) { + flash.readByteArray(a, &data_buffer[0], 256); _printPageBytes(data_buffer, outputType); + delay(100); } } @@ -601,3 +549,12 @@ void writeFail() { Serial.println("Data write failed"); } + +void inputAddress(void) { + Serial.print(F("Please enter the address (0 - CAPACITY) you wish to access: ")); + while (!Serial.available()) { + } + addr = Serial.parseInt(); + Serial.println(addr); +} + diff --git a/examples/tinyFlashTester/tinyFlashTester.ino b/examples/tinyFlashTester/tinyFlashTester.ino index 173c20e..5d65444 100644 --- a/examples/tinyFlashTester/tinyFlashTester.ino +++ b/examples/tinyFlashTester/tinyFlashTester.ino @@ -54,7 +54,7 @@ void setup() { configuration.light = 0; configuration.adc = 0; flash.readAnything(_addr, configuration); - flash.eraseSector(_addr, 0); + flash.eraseSector(_addr); Serial.println("After reading"); Serial.println(configuration.lux); Serial.println(configuration.vOut); diff --git a/extras/Changes.log b/extras/Changes.log index 4cd596c..6573375 100644 --- a/extras/Changes.log +++ b/extras/Changes.log @@ -10,7 +10,7 @@ Bugs Squashed: --> Deprecations: ---> flash.begin() no longer takes any variable as an argument. To define a custom CHIPSIZE to use the library with an unsupported chip - refer to 'Enhancements -> 5' +--> flash.begin() no longer takes any variable as an argument. To define a custom CHIPSIZE to use the library with an unsupported chip - refer to 'Enhancements -> 6' --> The library no longer supports using the page number + offset combination instead of addresses. If your code requires you to use a page number + offset combination, use the following code to help address = (pagenumber << 8) + offset. _____________________________________ From a6f14b37da5c2b4d438464243a68cbaf311cde17 Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Wed, 31 May 2017 09:20:22 +1000 Subject: [PATCH 08/34] Fixed issues with writeCharArray throwing compilation errors --- library.properties | 2 +- src/SPIFlash.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index bd79732..77df4c6 100644 --- a/library.properties +++ b/library.properties @@ -6,5 +6,5 @@ sentence=Winbond SPI flash library for Arduino. paragraph=This library enables read, write, erase and power functions on the following Winbond NOR Flash chips - W25X05CL, W25X10BV, W25X20BV, W25X40BV, W25Q80BV, W25Q16BV, W25Q32BV, W25Q64BV & W25Q128BV. All other Winbond flash chips can also be used with this library from v2.6.0 onwards. Refer to change log for further information about this release. category=Data Storage url=https://github.com/Marzogh/SPIFlash -architectures=avr,sam,samd,esp8266,esp32,simblee,rtl8195a +architectures=avr,sam,samd,esp8266,esp32,Simblee,rtl8195a includes=SPIFlash.h diff --git a/src/SPIFlash.cpp b/src/SPIFlash.cpp index df561bc..88fedb7 100644 --- a/src/SPIFlash.cpp +++ b/src/SPIFlash.cpp @@ -480,7 +480,7 @@ bool SPIFlash::writeCharArray(uint32_t _addr, char *data_buffer, uint16_t buffer CHIP_SELECT _nextByte(PAGEPROG); _transferAddress(); - _nextBuf(PAGEPROG, &data_buffer[0], bufferSize); + _nextBuf(PAGEPROG, (uint8_t*) &data_buffer[0], bufferSize); CHIP_DESELECT } else { From 7c9f7025750e8f10b5224e9b120b6cfd6badbfaa Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Fri, 16 Jun 2017 11:28:47 +1000 Subject: [PATCH 09/34] Turning of Trinket testing with Travis-CI till local testing of the branch's code is complete --- examples/tinyFlashDiagnostics/.trinket.test.skip | 0 examples/tinyFlashTester/.trinket.test.skip | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 examples/tinyFlashDiagnostics/.trinket.test.skip create mode 100644 examples/tinyFlashTester/.trinket.test.skip diff --git a/examples/tinyFlashDiagnostics/.trinket.test.skip b/examples/tinyFlashDiagnostics/.trinket.test.skip new file mode 100644 index 0000000..e69de29 diff --git a/examples/tinyFlashTester/.trinket.test.skip b/examples/tinyFlashTester/.trinket.test.skip new file mode 100644 index 0000000..e69de29 From 7113f105d27090a793420cb065801f8ee9fcf84c Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Wed, 9 Aug 2017 11:10:04 +1000 Subject: [PATCH 10/34] Removed all official support for ATTiny85 to enable ease of development with ARM platforms --- .travis.yml | 2 +- README.md | 3 +- examples/FlashDiagnostics/.trinket.test.skip | 1 - .../FlashDiagnostics/FlashDiagnostics.ino | 2 - examples/Struct_writer/.trinket.test.skip | 1 - examples/TestFlash/.trinket.test.skip | 1 - examples/getAddressEx/.trinket.test.skip | 1 - examples/readWriteString/.trinket.test.skip | 1 - examples/readWriteString/readWriteString.ino | 12 - .../tinyFlashDiagnostics/.trinket.test.skip | 0 .../tinyFlashDiagnostics/Attiny_functions.ino | 279 ----------- .../NonAttiny_functions.ino | 463 ------------------ examples/tinyFlashDiagnostics/Notes.cpp | 46 -- .../tinyFlashDiagnostics.ino | 80 --- examples/tinyFlashDiagnostics/vars.h | 96 ---- examples/tinyFlashTester/.trinket.test.skip | 0 examples/tinyFlashTester/tinyFlashTester.ino | 69 --- extras/Changes.log | 3 + src/FLASHIO.cpp | 18 +- src/SPIFlash.cpp | 3 - src/SPIFlash.h | 41 +- src/defines.h | 2 - src/tinySPI.cpp | 53 -- src/troubleshoot.cpp | 5 - 24 files changed, 20 insertions(+), 1162 deletions(-) delete mode 100644 examples/FlashDiagnostics/.trinket.test.skip delete mode 100644 examples/Struct_writer/.trinket.test.skip delete mode 100644 examples/TestFlash/.trinket.test.skip delete mode 100644 examples/getAddressEx/.trinket.test.skip delete mode 100644 examples/readWriteString/.trinket.test.skip delete mode 100644 examples/tinyFlashDiagnostics/.trinket.test.skip delete mode 100644 examples/tinyFlashDiagnostics/Attiny_functions.ino delete mode 100644 examples/tinyFlashDiagnostics/NonAttiny_functions.ino delete mode 100644 examples/tinyFlashDiagnostics/Notes.cpp delete mode 100644 examples/tinyFlashDiagnostics/tinyFlashDiagnostics.ino delete mode 100644 examples/tinyFlashDiagnostics/vars.h delete mode 100644 examples/tinyFlashTester/.trinket.test.skip delete mode 100644 examples/tinyFlashTester/tinyFlashTester.ino delete mode 100644 src/tinySPI.cpp diff --git a/.travis.yml b/.travis.yml index 261a945..71b4eaf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ before_install: - source <(curl -SLs https://raw.githubusercontent.com/Marzogh/Travis-CI/master/install.sh) script: - build_main_platforms - - build_platform trinket - build_platform rtl8195a #- build_platform uno #- build_platform due @@ -16,6 +15,7 @@ script: #- build_platform mega #- build_platform fio #- build_platform micro + #- build_platform trinket notifications: email: on_success: change diff --git a/README.md b/README.md index 296807b..82112b4 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ This Arduino library is for use with Winbond serial flash memory chips. In its c - IDE v1.5.x - IDE v1.6.0-v1.6.5 - IDE v1.6.9-v1.6.12 -- IDE v1.8.2 +- IDE v1.8.1-v1.8.3 ##### Boards @@ -28,7 +28,6 @@ This Arduino library is for use with Winbond serial flash memory chips. In its c - Arduino Mega - Arduino Micro - Arduino Fio -- Attiny85 Boards ###### In BETA - ESP32 Boards (Tested on the Adafruit Esp32 Feather) The library is known to work with the ESP32 core as of the current commit 9618eec on 02.08.2017. ```ESP32 support will remain in beta till the ESP32 core can be installed via the Arduino boards manager.``` diff --git a/examples/FlashDiagnostics/.trinket.test.skip b/examples/FlashDiagnostics/.trinket.test.skip deleted file mode 100644 index 8b13789..0000000 --- a/examples/FlashDiagnostics/.trinket.test.skip +++ /dev/null @@ -1 +0,0 @@ - diff --git a/examples/FlashDiagnostics/FlashDiagnostics.ino b/examples/FlashDiagnostics/FlashDiagnostics.ino index d6e076f..edcb595 100644 --- a/examples/FlashDiagnostics/FlashDiagnostics.ino +++ b/examples/FlashDiagnostics/FlashDiagnostics.ino @@ -17,9 +17,7 @@ #include -#if !defined (__AVR_ATtiny85__) #define RUNDIAGNOSTIC //Outputs detailed diagnostic on error codes generated by library to Serial -#endif //Define the make of the chip being tested #define WINBONDFLASH diff --git a/examples/Struct_writer/.trinket.test.skip b/examples/Struct_writer/.trinket.test.skip deleted file mode 100644 index 8b13789..0000000 --- a/examples/Struct_writer/.trinket.test.skip +++ /dev/null @@ -1 +0,0 @@ - diff --git a/examples/TestFlash/.trinket.test.skip b/examples/TestFlash/.trinket.test.skip deleted file mode 100644 index 8b13789..0000000 --- a/examples/TestFlash/.trinket.test.skip +++ /dev/null @@ -1 +0,0 @@ - diff --git a/examples/getAddressEx/.trinket.test.skip b/examples/getAddressEx/.trinket.test.skip deleted file mode 100644 index 8b13789..0000000 --- a/examples/getAddressEx/.trinket.test.skip +++ /dev/null @@ -1 +0,0 @@ - diff --git a/examples/readWriteString/.trinket.test.skip b/examples/readWriteString/.trinket.test.skip deleted file mode 100644 index 8b13789..0000000 --- a/examples/readWriteString/.trinket.test.skip +++ /dev/null @@ -1 +0,0 @@ - diff --git a/examples/readWriteString/readWriteString.ino b/examples/readWriteString/readWriteString.ino index c19a698..3d10643 100644 --- a/examples/readWriteString/readWriteString.ino +++ b/examples/readWriteString/readWriteString.ino @@ -34,37 +34,27 @@ SPIFlash flash; bool readSerialStr(String &inputStr); void setup() { -#ifndef __AVR_ATtiny85__ Serial.begin(BAUD_RATE); -#endif #if defined (ARDUINO_SAMD_ZERO) || (__AVR_ATmega32U4__) while (!Serial) ; // Wait for Serial monitor to open #endif flash.begin(); -#if defined __AVR_ATtiny85__ - randomSeed(65535537); -#else randomSeed(analogRead(RANDPIN)); -#endif strAddr = random(0, flash.getCapacity()); String inputString = "This is a test String"; flash.writeStr(strAddr, inputString); -#ifndef __AVR_ATtiny85__ Serial.print(F("Written string: ")); Serial.println(inputString); Serial.print(F("To address: ")); Serial.println(strAddr); -#endif String outputString = ""; if (flash.readStr(strAddr, outputString)) { -#ifndef __AVR_ATtiny85__ Serial.print(F("Read string: ")); Serial.println(outputString); Serial.print(F("From address: ")); Serial.println(strAddr); -#endif } while (!flash.eraseSector(strAddr)); } @@ -73,7 +63,6 @@ void loop() { } -#ifndef __AVR_ATtiny85__ //Reads a string from Serial bool readSerialStr(String &inputStr) { if (!Serial) @@ -85,4 +74,3 @@ bool readSerialStr(String &inputStr) { } return false; } -#endif diff --git a/examples/tinyFlashDiagnostics/.trinket.test.skip b/examples/tinyFlashDiagnostics/.trinket.test.skip deleted file mode 100644 index e69de29..0000000 diff --git a/examples/tinyFlashDiagnostics/Attiny_functions.ino b/examples/tinyFlashDiagnostics/Attiny_functions.ino deleted file mode 100644 index 1091824..0000000 --- a/examples/tinyFlashDiagnostics/Attiny_functions.ino +++ /dev/null @@ -1,279 +0,0 @@ -/* - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | Attiny_functions.ino | - | SPIFlash library | - | v 2.7.0 | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | Marzogh | - | 26.04.2017 | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | | - | For a full diagnostics rundown - with error codes and details of the errors | - | uncomment #define RUNDIAGNOSTIC in SPIFlash.cpp in the library before compiling | - | and loading this application onto your Arduino. | - | | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| -*/ - -#if defined (__AVR_ATtiny85__) - -void startup(void) { -#if defined (CHIPSIZE) - flash.begin(CHIPSIZE); //use flash.begin(CHIPSIZE) if using non-Winbond flash -#else - flash.begin(); -#endif -} - -void setWrittenStatus(void) { - dataPacket.writeStatus |= PASS; - dataPacket.writeStatus |= ATTINY85; -} - -void saveResults() { - flash.writeAnything(addr, dataPacket); -} - -void setTest(uint8_t _t) { - dataPacket.test |= _t; -} - -void intDiag(uint32_t _addr) { - //Set variables - word _data, _d; - _data = 4520; - setTest(INT); - - //Test & time Write function - if (flash.writeWord(_addr, _data)) { - dataPacket.Status |= iW; - } - else - { - dataPacket.Status &= !iW; - } - - - //Test & time Read function - _d = flash.readWord(_addr); - if (_d == _data) { - dataPacket.Status |= iR; - } - else - { - dataPacket.Status &= !iR; - } - - //Erase the sector previously written to - flash.eraseSector(_addr); -} - -void floatDiag(uint32_t _addr) { - //Set variables - float _data, _d; - _data = 3.1412; - setTest(FLOAT); - - //Test & time Write function - if (flash.writeFloat(_addr, _data)) { - dataPacket.Status |= fW; - } - else - { - dataPacket.Status &= !fW; - } - - - //Test & time Read function - _d = flash.readFloat(_addr); - if (_d == _data) { - dataPacket.Status |= fR; - } - else - { - dataPacket.Status &= !fR; - } - - //Erase the sector previously written to - flash.eraseSector(_addr); -} - -void structDiag(uint32_t _addr) { - //Set variables - struct Configuration { // Voltage ouput fR;om potential divider to Analog input - float RLDR; // Resistance calculation of potential divider with LDR - bool light; - uint8_t adc; - }; - Configuration _data, _d; - _data.RLDR = 89.32; - _data.light = true; - _data.adc = 5; - setTest(STRUCT); - - //Test & time Write function - if (flash.writeAnything(_addr, _data)) { - dataPacket.Status |= scW; - } - else - { - dataPacket.Status &= !scW; - } - - //Test & time Read function - if (flash.readAnything(_addr, _d)) { - if (_d.RLDR == _data.RLDR && _d.light == _data.light && _d.adc == _data.adc) { - dataPacket.Status |= scR; - } - else - { - dataPacket.Status &= !scR; - } - } - else { - dataPacket.Status &= !scR; - } - - //Erase the sector previously written to - flash.eraseSector(_addr); -} - -void stringDiag(uint32_t _addr) { - //Set variables - String _d = ""; - String _data = "1Ab# D"; - setTest(STRING); - - //Test & time Write function - if (flash.writeStr(_addr, _data)) { - dataPacket.Status |= sgW; - } - else - { - dataPacket.Status &= !sgW; - } - - - //Test & time Read function - if (flash.readStr(_addr, _d)) { - if (_d == _data) { - dataPacket.Status |= sgR; - } - else - { - dataPacket.Status &= !sgR; - } - //Erase the sector previously written to - flash.eraseSector(_addr); - } -} - -void arrayDiag(uint32_t _addr) { - //Set variables - uint8_t _data[20], _d[20]; - setTest(ARRAY); - - for (uint8_t i = 0; i < 21; i++) { - _data[i] = i; - } - - //Test & time Write function - if (flash.writeByteArray(_addr, _data, 20)) { - dataPacket.Status |= aW; - } - else - { - dataPacket.Status &= !aW; - } - - - //Test & time Read function - if (flash.readByteArray(_addr, _d, 20)) { - for (uint8_t i = 0; i < 21; i++) - if (_d[i] != _data[i]) { - dataPacket.Status &= aR; - break; - } - dataPacket.Status |= aR; - } - //Erase the sector previously written to - flash.eraseSector(_addr); -} - -void eraseDiag(uint32_t _addr) { - setTest(ERASE); - - //Test & time eraseBlock32K function - if (flash.eraseBlock32K(_addr)) { - dataPacket.Status |= eB; - } - else - { - dataPacket.Status &= !eB; - } - - //Test & time eraseChip function - if (flash.eraseChip()) { - dataPacket.Status |= eC; - } - else - { - dataPacket.Status &= !eC; - } -} - -void powerDiag(void) { - setTest(ERASE); - - //Test & time powerDown function - if (flash.powerDown()) { - dataPacket.Status |= pOFF; - } - else - { - dataPacket.Status &= !pOFF; - } - - //Test & time powerUp function - if (flash.powerUp()) { - dataPacket.Status |= pON; - } - else - { - dataPacket.Status &= !pON; - } -} - -void diagnose(void) { - do { - flash.eraseChip(); - } while (prevWritten()); - - setWrittenStatus(); - - uint32_t testaddr = random(STARTADDR, 0xFFFFF); -#if defined INTTEST - intDiag(testaddr); -#endif -#if defined FLOATTEST - floatDiag(testaddr); -#endif -#if defined STRUCTTEST - structDiag(testaddr); -#endif -#if defined STRINGTEST - stringDiag(testaddr); -#endif -#if defined ARRAYTEST - arrayDiag(testaddr); -#endif -#if defined ERASETEST - eraseDiag(testaddr); -#endif -#if defined POWERTEST - powerDiag(); -#endif - saveResults(); -} - -#endif diff --git a/examples/tinyFlashDiagnostics/NonAttiny_functions.ino b/examples/tinyFlashDiagnostics/NonAttiny_functions.ino deleted file mode 100644 index 7b364cc..0000000 --- a/examples/tinyFlashDiagnostics/NonAttiny_functions.ino +++ /dev/null @@ -1,463 +0,0 @@ -/* - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | NonAttiny_functions.ino | - | SPIFlash library | - | v 2.7.0 | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | Marzogh | - | 26.04.2017 | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | | - | For a full diagnostics rundown - with error codes and details of the errors | - | uncomment #define RUNDIAGNOSTIC in SPIFlash.cpp in the library before compiling | - | and loading this application onto your Arduino. | - | | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| -*/ - -#if !defined (__AVR_ATtiny85__) -void startup(void) { - Serial.begin(BAUD_RATE); -#if defined (ARDUINO_ARCH_SAMD) || (__AVR_ATmega32U4__) - while (!Serial) ; // Wait for Serial monitor to open -#endif - Serial.print(F("Initialising Flash memory")); - for (int i = 0; i < 10; ++i) - { - Serial.print(F(".")); - } - Serial.println(); -#if defined (CHIPSIZE) - flash.begin(CHIPSIZE); //use flash.begin(CHIPSIZE) if using non-Winbond flash (Refer to '#define CHIPSIZE' above) -#else - flash.begin(); -#endif - Serial.println(); - Serial.println(); - -#if defined (ARDUINO_ARCH_ESP32) - randomSeed(65535537); -#else - randomSeed(analogRead(RANDPIN)); -#endif -} - -void clearprintBuffer(char *bufPtr) -{ - for (uint8_t i = 0; i < 128; i++) { - //printBuffer[i] = 0; - *bufPtr++ = 0; - } -} - -void printLine() { - for (uint8_t i = 0; i < 230; i++) { - Serial.print(F("-")); - } - Serial.println(); -} - -void printPass() { - Serial.print(F("Pass")); -} - -void printFail() { - Serial.print(F("Fail")); -} - -void printTab(uint8_t a, uint8_t b) { - for (uint8_t i = 0; i < a; i++) { - Serial.print(F("\t")); - } - if (b > 0) { - Serial.print("||"); - for (uint8_t i = 0; i < b; i++) { - Serial.print(F("\t")); - } - } -} - -void printTime(uint32_t _wTime, uint32_t _rTime) { - printTab(2, 1); - printTimer(_wTime); - printTab(2, 1); - printTimer(_rTime); -} - -void printTimer(uint32_t _us) { - - if (_us > 1000000) { - float _s = _us / (float)1000000; - Serial.print(_s, 4); - Serial.print(" s"); - } - else if (_us > 10000) { - float _ms = _us / (float)1000; - Serial.print(_ms, 4); - Serial.print(" ms"); - } - else { - Serial.print(_us); - Serial.print(F(" us")); - } -} - -void getID() { - char printBuffer[128]; - printLine(); - for (uint8_t i = 0; i < 68; i++) { - Serial.print(F(" ")); - } - Serial.print(F("SPIFlash Library version")); -#ifdef LIBVER - uint8_t _ver, _subver, _bugfix; - flash.libver(&_ver, &_subver, &_bugfix); - clearprintBuffer(&printBuffer[1]); - sprintf(printBuffer, ": %d.%d.%d", _ver, _subver, _bugfix); - Serial.println(printBuffer); -#else - Serial.println(F("< 2.5.0")); -#endif - printLine(); - - for (uint8_t i = 0; i < 80; i++) { - Serial.print(F(" ")); - } - Serial.println(F("Get ID")); - printLine(); - uint8_t b1, b2; - uint16_t b3; - uint32_t JEDEC = flash.getJEDECID(); - uint32_t maxPage = flash.getMaxPage(); - uint32_t capacity = flash.getCapacity(); - b1 = (JEDEC >> 16); - b2 = (JEDEC >> 8); - b3 = (JEDEC >> 0); - - - printLine(); - //---------------------------------------------------------------------------------------------// - - clearprintBuffer(&printBuffer[1]); - sprintf(printBuffer, "\t\t\tJEDEC ID: %04lxh", JEDEC); - Serial.println(printBuffer); - clearprintBuffer(&printBuffer[1]); - sprintf(printBuffer, "\t\t\tManufacturer ID: %02xh\n\t\t\tMemory Type: %02xh\n\t\t\tCapacity: %lu bytes\n\t\t\tMaximum pages: %lu", b1, b2, capacity, maxPage); - Serial.println(printBuffer); -} - -bool checkPage(uint8_t *data_buffer) { - for (int i = 0; i < 256; i++) { - if (data_buffer[i] != i) - return false; - } - return true; -} - -void printHeader(uint8_t _t) { - if (_t == DATA_FUNCTION && data_header == false) { - printLine(); - - for (uint8_t i = 0; i < 79; i++) { - Serial.print(F(" ")); - } - Serial.println(F("Data Check")); - printLine(); - - Serial.println(F("\tData Type\t||\tWrite Check\t||\tRead Check\t")); - printLine(); - - data_header = true; - } - if (_t == OTHER_FUNCTION && power_header == false) { - printLine(); - - for (uint8_t i = 0; i < 74; i++) { - Serial.print(F(" ")); - } - Serial.println(F("Other Function Check")); - printLine(); - - Serial.println(F("\tTest Type\t||\tStatus")); - printLine(); - - power_header = true; - } -} -void diagnose() { - getID(); - - uint16_t _stat; - if (prevWritten) { - if (dataPacket.test & INT) { - printHeader(DATA_FUNCTION); - intDiag(); - } - if (dataPacket.test & FLOAT) { - printHeader(DATA_FUNCTION); - floatDiag(); - } - if (dataPacket.test & STRING) { - printHeader(DATA_FUNCTION); - stringDiag(); - } - if (dataPacket.test & STRUCT) { - printHeader(DATA_FUNCTION); - structDiag(); - } - if (dataPacket.test & ARRAY) { - printHeader(DATA_FUNCTION); - arrayDiag(); - } - if (dataPacket.test & ERASE) { - printHeader(OTHER_FUNCTION); - eraseDiag(); - } - if (dataPacket.test & POWER) { - printHeader(OTHER_FUNCTION); - powerDiag(); - } - } - else { - Serial.println(F("No data found on chip. Please run this sketch on a an ATTiny85 connected to this flash chip first")); - } -} - -void intDiag(void) { - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Integer // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(1, 0); - Serial.print(F("Integer")); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(2, 1); - if (dataPacket.Status & iW) { - printPass(); - } - else { - printFail(); - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Read // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(2, 1); - if (dataPacket.Status & iR) { - printPass(); - } - else { - printFail(); - } - Serial.println(); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //-----------------------------------------------------------------------------------------------------------------------------------------------------// -} - -void floatDiag(void) { - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Float // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(1, 0); - Serial.print(F("Float")); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(2, 1); - if (dataPacket.Status & fW) { - printPass(); - } - else { - printFail(); - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Read // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(2, 1); - if (dataPacket.Status & fR) { - printPass(); - } - else { - printFail(); - } - Serial.println(); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //-----------------------------------------------------------------------------------------------------------------------------------------------------// -} - -void stringDiag(void) { - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Integer // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(1, 0); - Serial.print(F("String")); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(2, 1); - if (dataPacket.Status & sgW) { - printPass(); - } - else { - printFail(); - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Read // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(2, 1); - if (dataPacket.Status & sgR) { - printPass(); - } - else { - printFail(); - } - Serial.println(); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //-----------------------------------------------------------------------------------------------------------------------------------------------------// -} - -void structDiag(void) { - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Integer // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(1, 0); - Serial.print(F("Integer")); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(2, 1); - if (dataPacket.Status & scW) { - printPass(); - } - else { - printFail(); - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Read // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(2, 1); - if (dataPacket.Status & scR) { - printPass(); - } - else { - printFail(); - } - Serial.println(); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //-----------------------------------------------------------------------------------------------------------------------------------------------------// -} - -void arrayDiag(void) { - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Integer // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(1, 0); - Serial.print(F("Array")); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(2, 1); - if (dataPacket.Status & aW) { - printPass(); - } - else { - printFail(); - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Read // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(2, 1); - if (dataPacket.Status & aR) { - printPass(); - } - else { - printFail(); - } - Serial.println(); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //-----------------------------------------------------------------------------------------------------------------------------------------------------// -} - -void eraseDiag(void) { - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Erase Block // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(1, 0); - Serial.print(F("Erase Block")); - printTab(2, 1); - if (dataPacket.Status & eB) { - printPass(); - } - else { - printFail(); - } - Serial.println(); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Erase Chip // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(1, 0); - Serial.print(F("Erase Chip")); - printTab(2, 1); - if (dataPacket.Status & eC) { - printPass(); - } - else { - printFail(); - } - Serial.println(); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //-----------------------------------------------------------------------------------------------------------------------------------------------------// -} - -void powerDiag(void) { - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Power on // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(1, 0); - Serial.print(F("Power off")); - printTab(2, 1); - if (dataPacket.Status & pOFF) { - printPass(); - } - else { - printFail(); - } - Serial.println(); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Power off // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(1, 0); - Serial.print(F("Power on")); - printTab(2, 1); - if (dataPacket.Status & pON) { - printPass(); - } - else { - printFail(); - } - Serial.println(); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //-----------------------------------------------------------------------------------------------------------------------------------------------------// -} -#endif diff --git a/examples/tinyFlashDiagnostics/Notes.cpp b/examples/tinyFlashDiagnostics/Notes.cpp deleted file mode 100644 index 1abbda2..0000000 --- a/examples/tinyFlashDiagnostics/Notes.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | Notes.cpp | - | SPIFlash library | - | v 2.7.0 | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | Marzogh | - | 26.04.2017 | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | | - | For a full diagnostics rundown - with error codes and details of the errors | - | uncomment #define RUNDIAGNOSTIC in SPIFlash.cpp in the library before compiling | - | and loading this application onto your Arduino. | - | | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| -*/ - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -// // -// Structure of the status integer // -// _____________________________________________________________________________________ // -// | Bit number | // -// |_____________________________________________________________________________________| // -// | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | // -// |-------------------------------------------------------------------------------------| // -// | RES | RES | pOFF | pON | eC | eB | aR | aW | // -// |_____________________________________________________________________________________| // -// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | // -// |-------------------------------------------------------------------------------------| // -// | scR | scW | sgR | sgW | fR | fW | iR | iW | // -// |_____________________________________________________________________________________| // -// // -// // -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -// // -// Structure of the test byte // -// _____________________________________________________________________________________ // -// | Bit number | // -// |_____________________________________________________________________________________| // -// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | // -// |-------------------------------------------------------------------------------------| // -// | RES | POWER | ERASE | ARRAY | STRUCT | STRING | FLOAT | INT | // -// |_____________________________________________________________________________________| // -// // -// // -//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!// diff --git a/examples/tinyFlashDiagnostics/tinyFlashDiagnostics.ino b/examples/tinyFlashDiagnostics/tinyFlashDiagnostics.ino deleted file mode 100644 index 4eb58c7..0000000 --- a/examples/tinyFlashDiagnostics/tinyFlashDiagnostics.ino +++ /dev/null @@ -1,80 +0,0 @@ -/* - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | tinyFlashDiagnostics.ino | - | SPIFlash library | - | v 2.6.0 | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | Marzogh | - | 16.04.2017 | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | | - | For a full diagnostics rundown - with error codes and details of the errors | - | uncomment #define RUNDIAGNOSTIC in SPIFlash.cpp in the library before compiling | - | and loading this application onto your Arduino. | - | | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| -*/ - -#include "vars.h" - -#include - -//Define a flash memory size (if using non-Winbond memory) according to the list in defines.h -//#define CHIPSIZE MB64 - - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!// - // // - // ___ _____ _____ _ _____ _____ // - // / _ \_ _|_ _(_) | _ || ___| // - // / /_\ \| | | | _ _ __ _ _ \ V / |___ \ // - // | _ || | | | | | '_ \| | | |/ _ \ \ \ // - // | | | || | | | | | | | | |_| | |_| |/\__/ / // - // \_| |_/\_/ \_/ |_|_| |_|\__, \_____/\____/ // - // __/ | // - // |___/ // - // // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Uncomment any of the tests below as required. // - // Remember, the ATTiny has a limited amount of SRAM, so only a limited number // - // of tests can be run concurrently. // - // // - //|------------------------------------------//----------------------------------------------|// - //| List of tests // _status bits |// - //|------------------------------------------//----------------------------------------------|// - #define INTTEST // iW, iR |// - #define FLOATTEST // fW, fR |// - //#define STRINGTEST // sgW, sgR |// - #define STRUCTTEST // scW, scR |// - //#define ARRAYTEST // aW, aR |// - #define ERASETEST // eB, eC |// - #define POWERTEST // pON, pOFF |// - //|------------------------------------------//----------------------------------------------|// - -SPIFlash flash; - -void setup() { - startup(); - diagnose(); -} - -void loop() { - -} - -//************************************************************************************************// -// // -// Non-board specific code // -// // -//************************************************************************************************// - -bool prevWritten() { - addr = flash.getAddress(sizeof(dataPacket)); - flash.readAnything(addr, dataPacket); - if (dataPacket.writeStatus != 0xFF) { - return true; - } - else { - return false; - } -} -//************************************************************************************************// diff --git a/examples/tinyFlashDiagnostics/vars.h b/examples/tinyFlashDiagnostics/vars.h deleted file mode 100644 index 378a8ab..0000000 --- a/examples/tinyFlashDiagnostics/vars.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | vars.h | - | SPIFlash library | - | v 2.7.0 | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | Marzogh | - | 26.04.2017 | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | | - | For a full diagnostics rundown - with error codes and details of the errors | - | uncomment #define RUNDIAGNOSTIC in SPIFlash.cpp in the library before compiling | - | and loading this application onto your Arduino. | - | | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| -*/ -//************************************************************************************************// -// // -// Non-board specific code // -// // -//************************************************************************************************// -#define PASS 0x01 -#define FAIL 0x00 -#define ATTINY85 0x02 - -#define INT 0x01 -#define FLOAT 0x02 -#define STRING 0x04 -#define STRUCT 0x08 -#define ARRAY 0x10 -#define ERASE 0x20 -#define POWER 0x40 - - -#define iW 0x0001 -#define iR 0x0002 -#define fW 0x0004 -#define fR 0x0008 -#define sgW 0x0010 -#define sgR 0x0020 -#define scW 0x0040 -#define scR 0x0080 -#define aW 0x0100 -#define aR 0x0200 -#define eB 0x0400 -#define eC 0x0800 -#define pON 0x1000 -#define pOFF 0x2000 - -struct _dataPacket { - uint8_t writeStatus; - uint8_t test; - uint16_t Status; -}; -_dataPacket dataPacket; -uint32_t addr; - -//************************************************************************************************// -// // -// If using an ATTiny85 board // -// // -//************************************************************************************************// - -#if defined (__AVR_ATtiny85__) - -#define STARTADDR ((sizeof(dataPacket))*2) - -#endif - -//************************************************************************************************// -// // -// If using a non ATTiny85 board // -// // -//************************************************************************************************// -#if !defined (__AVR_ATtiny85__) - -#if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) -// Required for Serial on Zero based boards -#define Serial SERIAL_PORT_USBVIRTUAL -#endif - -#if defined (SIMBLEE) -#define BAUD_RATE 250000 -#define RANDPIN 1 -#else -#define BAUD_RATE 115200 -#define RANDPIN A0 -#endif - -#define DATA_FUNCTION 0x03 -#define OTHER_FUNCTION 0x04 - -bool data_header, power_header = false; - -#endif - diff --git a/examples/tinyFlashTester/.trinket.test.skip b/examples/tinyFlashTester/.trinket.test.skip deleted file mode 100644 index e69de29..0000000 diff --git a/examples/tinyFlashTester/tinyFlashTester.ino b/examples/tinyFlashTester/tinyFlashTester.ino deleted file mode 100644 index 5d65444..0000000 --- a/examples/tinyFlashTester/tinyFlashTester.ino +++ /dev/null @@ -1,69 +0,0 @@ -/* - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | Struct_writer.ino | - | SPIFlash library | - | v 2.7.0 | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | Marzogh | - | 19.04.2017 | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | | - | This program writes a struct to a random location on your flash memory chip and reads it back. | - | This particular program is designed to test the library with an ATTiny85 chip. Follow the steps below to make sure the test runs as it should | - | 1. Compile and run this program on an ATTiny85 board to which an SPIFlash memory has been wired in. | - | 2. Swap Flash chip over to another supported board (with Serial IO) and compile and run this program again | - | 3. Check serial output to see if data has been written/read properly. | - | | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| -*/ - -#include - -SPIFlash flash; - -struct Configuration { - float lux; - float vOut; // Voltage ouput from potential divider to Analog input - float RLDR; // Resistance calculation of potential divider with LDR - bool light; - uint8_t adc; -}; -Configuration configuration; - -void setup() { - flash.begin(); - uint32_t _addr = 34235; - -#if defined (__AVR_ATtiny85__) - configuration.lux = 98.43; - configuration.vOut = 4.84; - configuration.RLDR = 889.32; - configuration.light = true; - configuration.adc = 5; - flash.writeAnything(_addr, configuration); -#else - Serial.println("Data Written to flash was: "); - Serial.println(configuration.lux); - Serial.println(configuration.vOut); - Serial.println(configuration.RLDR); - Serial.println(configuration.light); - Serial.println(configuration.adc); - configuration.lux = 0; - configuration.vOut = 0; - configuration.RLDR = 0; - configuration.light = 0; - configuration.adc = 0; - flash.readAnything(_addr, configuration); - flash.eraseSector(_addr); - Serial.println("After reading"); - Serial.println(configuration.lux); - Serial.println(configuration.vOut); - Serial.println(configuration.RLDR); - Serial.println(configuration.light); - Serial.println(configuration.adc); -#endif - -} - -void loop() { -} diff --git a/extras/Changes.log b/extras/Changes.log index 261e9d2..6207893 100644 --- a/extras/Changes.log +++ b/extras/Changes.log @@ -6,10 +6,13 @@ // Author: Prajwal Bhattaram // // 11.05.2017 // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +To check: +--> Check _nextBuf function and optimize Bugs Squashed: --> Deprecations: +--> Going forward the ATTiny85 is no longer officially supported. --> flash.begin() no longer takes any variable as an argument. To define a custom CHIPSIZE to use the library with an unsupported chip - refer to 'Enhancements -> 6' --> The library no longer supports using the page number + offset combination instead of addresses. If your code requires you to use a page number + offset combination, use the following code to help address = (pagenumber << 8) + offset. diff --git a/src/FLASHIO.cpp b/src/FLASHIO.cpp index 30afc37..42e9f92 100644 --- a/src/FLASHIO.cpp +++ b/src/FLASHIO.cpp @@ -71,7 +71,6 @@ bool SPIFlash::_transferAddress(void) { } bool SPIFlash::_startSPIBus(void) { -#ifndef __AVR_ATtiny85__ #ifndef SPI_HAS_TRANSACTION noInterrupts(); #endif @@ -92,9 +91,6 @@ bool SPIFlash::_startSPIBus(void) { SPI.setBitOrder(MSBFIRST); #endif #endif -#else - -#endif SPIBusState = true; return true; } @@ -152,15 +148,7 @@ uint8_t SPIFlash::_nextByte(uint8_t data) { //Reads/Writes next int. Call 'n' times to read/write 'n' number of bytes. Should be called after _beginSPI() uint16_t SPIFlash::_nextInt(uint16_t data) { - #ifndef __AVR_ATtiny85__ return SPI.transfer16(data); - #else - uint16_t _data; - _data = xfer(data >> 0); - data = (_data << 8); - _data += xfer(data >> 8); - return _data; - #endif } //Reads/Writes next data buffer. Call 'n' times to read/write 'n' number of bytes. Should be called after _beginSPI() @@ -170,7 +158,7 @@ void SPIFlash::_nextBuf(uint8_t opcode, uint8_t *data_buffer, uint32_t size) { case READDATA: #if defined (ARDUINO_ARCH_SAM) _dueSPIRecByte(&(*data_buffer), size); - #elif defined (ARDUINO_ARCH_AVR) && !defined (__AVR_ATtiny85__) + #elif defined (ARDUINO_ARCH_AVR) SPI.transfer(&data_buffer[0], size); #else for (uint16_t i = 0; i < size; i++) { @@ -183,7 +171,7 @@ void SPIFlash::_nextBuf(uint8_t opcode, uint8_t *data_buffer, uint32_t size) { case PAGEPROG: #if defined (ARDUINO_ARCH_SAM) _dueSPISendByte(&(*data_buffer), size); - #elif defined (ARDUINO_ARCH_AVR) && !defined (__AVR_ATtiny85__) + #elif defined (ARDUINO_ARCH_AVR) SPI.transfer(&(*data_buffer), size); #else for (uint16_t i = 0; i < size; i++) { @@ -204,7 +192,7 @@ void SPIFlash::_endSPI(void) { interrupts(); #endif - #if defined (ARDUINO_ARCH_AVR) && !defined (__AVR_ATtiny85__) + #if defined (ARDUINO_ARCH_AVR) SPCR = _SPCR; SPSR = _SPSR; #endif diff --git a/src/SPIFlash.cpp b/src/SPIFlash.cpp index edc571c..3d59f6b 100644 --- a/src/SPIFlash.cpp +++ b/src/SPIFlash.cpp @@ -31,9 +31,6 @@ #if defined (ARDUINO_ARCH_AVR) SPIFlash::SPIFlash(uint8_t cs, bool overflow) { csPin = cs; -#ifndef __AVR_ATtiny85__ - cs_port = portOutputRegister(digitalPinToPort(csPin)); -#endif cs_mask = digitalPinToBitMask(csPin); pageOverflow = overflow; pinMode(csPin, OUTPUT); diff --git a/src/SPIFlash.h b/src/SPIFlash.h index 2bc81dd..8858064 100644 --- a/src/SPIFlash.h +++ b/src/SPIFlash.h @@ -53,9 +53,7 @@ #include #endif -#ifndef __AVR_ATtiny85__ #include -#endif #if defined (ARDUINO_ARCH_SAM) || defined (ARDUINO_ARCH_SAMD) || defined (ARDUINO_ARCH_ESP8266) || defined (SIMBLEE) || defined (ARDUINO_ARCH_ESP32) || defined (BOARD_RTL8195A) // RTL8195A included - @boseji 02.03.17 @@ -79,31 +77,21 @@ extern "C" { #endif #ifdef ARDUINO_ARCH_AVR - #ifdef __AVR_ATtiny85__ - #define CHIP_SELECT PORTB &= ~cs_mask; - #define CHIP_DESELECT PORTB |= cs_mask; - #define SPIBIT \ - USICR = ((1< 02.03.17 #elif defined (BOARD_RTL8195A) - #define CHIP_SELECT gpio_write(&csPin, 0); - #define CHIP_DESELECT gpio_write(&csPin, 1); - #define xfer(n) SPI.transfer(n) - #define BEGIN_SPI SPI.begin(); + #define CHIP_SELECT gpio_write(&csPin, 0); + #define CHIP_DESELECT gpio_write(&csPin, 1); + #define xfer(n) SPI.transfer(n) + #define BEGIN_SPI SPI.begin(); #else //#elif defined (ARDUINO_ARCH_ESP8266) || defined (ARDUINO_ARCH_SAMD) #define CHIP_SELECT digitalWrite(csPin, LOW); #define CHIP_DESELECT digitalWrite(csPin, HIGH); @@ -216,11 +204,6 @@ class SPIFlash { void _dueSPISendByte(const uint8_t* buf, size_t len); void _dueSPISendChar(char b); void _dueSPISendChar(const char* buf, size_t len); -#endif -//-------------------------------------Private ATTiny85 Functions-------------------------------------// -#if defined (__AVR_ATtiny85__) - static uint8_t _tinySPItransfer(uint8_t _data); - void _tinySPIbegin(); #endif //----------------------------------------Private functions----------------------------------------// void _troubleshoot(uint8_t _code, bool printoverride = false); diff --git a/src/defines.h b/src/defines.h index 83f41ff..3861537 100644 --- a/src/defines.h +++ b/src/defines.h @@ -138,8 +138,6 @@ #define CS 15 #elif defined (ARDUINO_ARCH_SAMD) #define CS 10 -#elif defined __AVR_ATtiny85__ -#define CS 5 /********************************************************************************************* // Declaration of the Default Chip select pin name for RTL8195A // Note: This has been shifted due to a bug identified in the HAL layer SPI driver diff --git a/src/tinySPI.cpp b/src/tinySPI.cpp deleted file mode 100644 index 78e1303..0000000 --- a/src/tinySPI.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* Arduino SPIFlash Library v.2.7.0 - * Copyright (C) 2017 by Prajwal Bhattaram - * Created by Prajwal Bhattaram - 19/04/2017 - * Modified by Prajwal Bhattaram - 19/04/2017 - * Original code from @manitou48 - * - * 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 - * . - */ - #include "SPIFlash.h" - -#if defined (__AVR_ATtiny85__) -void SPIFlash::_tinySPIbegin() { - PORTB &= ~(_BV(PORTB0) | _BV(PORTB1) | _BV(PORTB2) | cs_mask); - DDRB &= ~_BV(PORTB0); // DI (NOT MISO) - DDRB |= _BV(PORTB1) // DO (NOT MOSI) - | _BV(PORTB2) // SCK - | cs_mask; // CS -} - -static uint8_t SPIFlash::_tinySPItransfer(uint8_t _data) { - USIDR = _data; - for (uint8_t i = 0; i < 8; i++) { - SPIBIT - } - /*SPIBIT - SPIBIT - SPIBIT - SPIBIT - SPIBIT - SPIBIT - SPIBIT - SPIBIT*/ - return USIDR; -} -#endif diff --git a/src/troubleshoot.cpp b/src/troubleshoot.cpp index 32673f6..5b1fa5e 100644 --- a/src/troubleshoot.cpp +++ b/src/troubleshoot.cpp @@ -27,8 +27,6 @@ #include "SPIFlash.h" -//ATTiny85 does not have enough pins to support Serial. So, the basic troubleshooting functions of this library are not applicable. It is up to the end user to come up with a diagnostic routine for the ATTiny85. -#if !defined (__AVR_ATtiny85__) //Subfunctions for troubleshooting function void SPIFlash::_printErrorCode(void) { Serial.print("Error code: 0x"); @@ -129,6 +127,3 @@ void SPIFlash::_troubleshoot(uint8_t _code, bool printoverride) { #endif } } -#else //If compiled for ATTiny85 based platform - empty function to prevent compile errors -void troubleshoot(uint8_t _code, bool printoverride) {} -#endif //End of ATTiny85 code limitation From b7d30061afd8ef05c7776383b5ed0569bb7a3243 Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Wed, 9 Aug 2017 15:40:37 +1000 Subject: [PATCH 11/34] Constructor changed to enable user to choose one of multiple SPI ports - if available. Look at wiki for further info --- .../FlashDiagnostics/FlashDiagnostics.ino | 2 +- extras/Changes.log | 5 +- src/FLASHIO.cpp | 71 +++++++++---------- src/SPIFlash.cpp | 33 ++++----- src/SPIFlash.h | 22 +++--- src/defines.h | 66 ++++++++--------- 6 files changed, 101 insertions(+), 98 deletions(-) diff --git a/examples/FlashDiagnostics/FlashDiagnostics.ino b/examples/FlashDiagnostics/FlashDiagnostics.ino index edcb595..14fe0bf 100644 --- a/examples/FlashDiagnostics/FlashDiagnostics.ino +++ b/examples/FlashDiagnostics/FlashDiagnostics.ino @@ -38,7 +38,7 @@ #define RANDPIN A0 #endif -SPIFlash flash; +SPIFlash flash(SS1); void setup() { Serial.begin(BAUD_RATE); diff --git a/extras/Changes.log b/extras/Changes.log index 6207893..4636156 100644 --- a/extras/Changes.log +++ b/extras/Changes.log @@ -4,7 +4,7 @@ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Version 3.0.0 // // Author: Prajwal Bhattaram // -// 11.05.2017 // +// 09.08.2017 // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// To check: --> Check _nextBuf function and optimize @@ -18,7 +18,7 @@ Deprecations: address = (pagenumber << 8) + offset. _____________________________________ (32 bit) | (16 bit) | (8 bit) - +--> The constructor no longer takes the pageOverflow variable as an argument. Page overflow is globally enabled by default and can be disabled by including a "#define DISABLEOVERFLOW" at the beginning of the user code. New Boards supported: --> @@ -45,6 +45,7 @@ Enhancements: --> Restructured the internal _troubleshoot() function to be better human readable and easier to compile. --> Users can define RUNDIAGNOSTIC or HIGHSPEED in their code to access the library's special modes. No requirement to modify the library any more. --> No need to include CHIPSIZE in flash.begin() any more. Just defining CHIPSIZE in user code as one of the standard sizes as in defines.h will be enough. (Refer to 'Deprecations -> 1' above) +--> Constructor changed to enable user to choose one of multiple SPI ports - if available. Look at wiki for further info //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Version 2.7.0 // // Author: Prajwal Bhattaram // diff --git a/src/FLASHIO.cpp b/src/FLASHIO.cpp index 42e9f92..9d7b7de 100644 --- a/src/FLASHIO.cpp +++ b/src/FLASHIO.cpp @@ -84,11 +84,11 @@ bool SPIFlash::_startSPIBus(void) { _SPSR = SPSR; #endif #ifdef SPI_HAS_TRANSACTION - SPI.beginTransaction(_settings); + _spi->beginTransaction(_settings); #else - SPI.setClockDivider(SPI_CLOCK_DIV_4) - SPI.setDataMode(SPI_MODE0); - SPI.setBitOrder(MSBFIRST); + _spi->setClockDivider(SPI_CLOCK_DIV_4) + _spi->setDataMode(SPI_MODE0); + _spi->setBitOrder(MSBFIRST); #endif #endif SPIBusState = true; @@ -148,7 +148,7 @@ uint8_t SPIFlash::_nextByte(uint8_t data) { //Reads/Writes next int. Call 'n' times to read/write 'n' number of bytes. Should be called after _beginSPI() uint16_t SPIFlash::_nextInt(uint16_t data) { - return SPI.transfer16(data); + return _spi->transfer16(data); } //Reads/Writes next data buffer. Call 'n' times to read/write 'n' number of bytes. Should be called after _beginSPI() @@ -159,7 +159,7 @@ void SPIFlash::_nextBuf(uint8_t opcode, uint8_t *data_buffer, uint32_t size) { #if defined (ARDUINO_ARCH_SAM) _dueSPIRecByte(&(*data_buffer), size); #elif defined (ARDUINO_ARCH_AVR) - SPI.transfer(&data_buffer[0], size); + _spi->transfer(&data_buffer[0], size); #else for (uint16_t i = 0; i < size; i++) { *_dataAddr = xfer(NULLBYTE); @@ -172,7 +172,7 @@ void SPIFlash::_nextBuf(uint8_t opcode, uint8_t *data_buffer, uint32_t size) { #if defined (ARDUINO_ARCH_SAM) _dueSPISendByte(&(*data_buffer), size); #elif defined (ARDUINO_ARCH_AVR) - SPI.transfer(&(*data_buffer), size); + _spi->transfer(&(*data_buffer), size); #else for (uint16_t i = 0; i < size; i++) { xfer(*_dataAddr); @@ -187,7 +187,7 @@ void SPIFlash::_nextBuf(uint8_t opcode, uint8_t *data_buffer, uint32_t size) { void SPIFlash::_endSPI(void) { CHIP_DESELECT #ifdef SPI_HAS_TRANSACTION - SPI.endTransaction(); + _spi->endTransaction(); #else interrupts(); #endif @@ -354,35 +354,33 @@ bool SPIFlash::_chipID(void) { } // If no capacity is defined in user code - if (!_chip.capacity) { - _chip.supported = _chip.manufacturerID; - if (_chip.supported == WINBOND_MANID || _chip.supported == MICROCHIP_MANID) { - //Identify capacity - for (uint8_t i = 0; i < sizeof(_capID); i++) - { - if (_chip.capacityID == _capID[i]) { - _chip.capacity = (_memSize[i]); - _chip.eraseTime = _eraseTime[i]; - } +#if !defined (CAPACITY) + _chip.supported = _chip.manufacturerID; + if (_chip.supported == WINBOND_MANID || _chip.supported == MICROCHIP_MANID) { + //Identify capacity + for (uint8_t i = 0; i < sizeof(_capID); i++) { + if (_chip.capacityID == _capID[i]) { + _chip.capacity = (_memSize[i]); + _chip.eraseTime = _eraseTime[i]; } - return true; - } - else { - _troubleshoot(UNKNOWNCAP); //Error code for unidentified capacity - return false; } + return true; } else { - // If a custom chip size is defined - _chip.eraseTime = _chip.capacity/KB8; - _chip.supported = false;// This chip is not officially supported - _troubleshoot(UNKNOWNCHIP); //Error code for unidentified chip - //while(1); //Enable this if usercode is not meant to be run on unsupported chips + _troubleshoot(UNKNOWNCAP); //Error code for unidentified capacity + return false; } +#else + // If a custom chip size is defined + _chip.eraseTime = _chip.capacity/KB8; + _chip.supported = false;// This chip is not officially supported + _troubleshoot(UNKNOWNCHIP); //Error code for unidentified chip + //while(1); //Enable this if usercode is not meant to be run on unsupported chips return true; +#endif } -//Checks to see if pageOverflow is permitted and assists with determining next address to read/write. +//Checks to see if page overflow is permitted and assists with determining next address to read/write. //Sets the global address variable bool SPIFlash::_addressCheck(uint32_t _addr, uint32_t size) { if (errorcode == UNKNOWNCAP || errorcode == NORESPONSE) { @@ -395,14 +393,13 @@ bool SPIFlash::_addressCheck(uint32_t _addr, uint32_t size) { //for (uint32_t i = 0; i < size; i++) { if (_addr + size >= _chip.capacity) { - if (!pageOverflow) { - _troubleshoot(OUTOFBOUNDS); - return false; // At end of memory - (!pageOverflow) - } - else { - _currentAddress = 0x00; - return true; // At end of memory - (pageOverflow) - } + #ifdef DISABLEOVERFLOW + _troubleshoot(OUTOFBOUNDS); + return false; // At end of memory - (!pageOverflow) + #else + _currentAddress = 0x00; + return true; // At end of memory - (pageOverflow) + #endif } //} _currentAddress = _addr; diff --git a/src/SPIFlash.cpp b/src/SPIFlash.cpp index 3d59f6b..8c00c12 100644 --- a/src/SPIFlash.cpp +++ b/src/SPIFlash.cpp @@ -2,7 +2,7 @@ * Copyright (C) 2017 by Prajwal Bhattaram * Created by Prajwal Bhattaram - 19/05/2015 * Modified by @boseji - 02/03/2017 - * Modified by Prajwal Bhattaram - 02/08/2017 + * Modified by Prajwal Bhattaram - 09/08/2017 * * 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 @@ -28,39 +28,40 @@ #include "SPIFlash.h" // Constructor -#if defined (ARDUINO_ARCH_AVR) -SPIFlash::SPIFlash(uint8_t cs, bool overflow) { +//If board has multiple SPI interfaces, this constructor lets the user choose between them +// Adding Low level HAL API to initialize the Chip select pinMode on RTL8195A - @boseji 2nd March 2017 +#if !defined (BOARD_RTL8195A) +SPIFlash::SPIFlash(uint8_t cs, SPIClass *spiinterface) { + _spi = spiinterface; //Sets SPI interface - if no user selection is made, this defaults to SPI csPin = cs; +#if defined (ARDUINO_ARCH_AVR) cs_mask = digitalPinToBitMask(csPin); - pageOverflow = overflow; +#endif pinMode(csPin, OUTPUT); } -// Adding Low level HAL API to initialize the Chip select pinMode on RTL8195A - @boseji 2nd March 2017 -#elif defined (BOARD_RTL8195A) -SPIFlash::SPIFlash(PinName cs, bool overflow) { +#else +SPIFlash::SPIFlash(PinName cs, SPIClass *spiinterface) { + _spi = spiinterface; //Sets SPI interface - if no user selection is made, this defaults to SPI gpio_init(&csPin, cs); gpio_dir(&csPin, PIN_OUTPUT); gpio_mode(&csPin, PullNone); gpio_write(&csPin, 1); - pageOverflow = overflow; -} -#else -SPIFlash::SPIFlash(uint8_t cs, bool overflow) { - csPin = cs; - pageOverflow = overflow; - pinMode(csPin, OUTPUT); } #endif + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Public functions used for read, write and erase operations // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// //Identifies chip and establishes parameters bool SPIFlash::begin(void) { -#ifdef CHIPSIZE - _chip.capacity = CHIPSIZE/8; +#if defined (CHIPSIZE) + _chip.capacity = CHIPSIZE; #endif + +Serial.print("CHIPSIZE: "); +Serial.println(_chip.capacity); BEGIN_SPI #ifdef SPI_HAS_TRANSACTION //Define the settings to be used by the SPI bus diff --git a/src/SPIFlash.h b/src/SPIFlash.h index 8858064..d4097c0 100644 --- a/src/SPIFlash.h +++ b/src/SPIFlash.h @@ -2,7 +2,7 @@ * Copyright (C) 2017 by Prajwal Bhattaram * Created by Prajwal Bhattaram - 19/05/2015 * Modified by @boseji - 02/03/2017 - * Modified by Prajwal Bhattaram - 02/08/2017 + * Modified by Prajwal Bhattaram - 09/08/2017 * * 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 @@ -33,7 +33,7 @@ // // // Error codes will be generated and returned on functions // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -//#define RUNDIAGNOSTIC // +#define RUNDIAGNOSTIC // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -79,8 +79,8 @@ extern "C" { #ifdef ARDUINO_ARCH_AVR #define CHIP_SELECT *cs_port &= ~cs_mask; #define CHIP_DESELECT *cs_port |= cs_mask; - #define xfer(n) SPI.transfer(n) - #define BEGIN_SPI SPI.begin(); + #define xfer(n) _spi->transfer(n) + #define BEGIN_SPI _spi->begin(); #elif defined (ARDUINO_ARCH_SAM) #define CHIP_SELECT digitalWrite(csPin, LOW); #define CHIP_DESELECT digitalWrite(csPin, HIGH); @@ -90,13 +90,13 @@ extern "C" { #elif defined (BOARD_RTL8195A) #define CHIP_SELECT gpio_write(&csPin, 0); #define CHIP_DESELECT gpio_write(&csPin, 1); - #define xfer(n) SPI.transfer(n) - #define BEGIN_SPI SPI.begin(); + #define xfer(n) _spi->transfer(n) + #define BEGIN_SPI _spi->begin(); #else //#elif defined (ARDUINO_ARCH_ESP8266) || defined (ARDUINO_ARCH_SAMD) #define CHIP_SELECT digitalWrite(csPin, LOW); #define CHIP_DESELECT digitalWrite(csPin, HIGH); - #define xfer(n) SPI.transfer(n) - #define BEGIN_SPI SPI.begin(); + #define xfer(n) _spi->transfer(n) + #define BEGIN_SPI _spi->begin(); #endif #define LIBVER 3 @@ -115,9 +115,9 @@ class SPIFlash { //----------------------------------------------Constructor----------------------------------------------- //New Constructor to Accept the PinNames as a Chip select Parameter - @boseji 02.03.17 #if !defined (BOARD_RTL8195A) - SPIFlash(uint8_t cs = CS, bool overflow = true); + SPIFlash(uint8_t cs = CS, SPIClass *spiinterface=&SPI); #else - SPIFlash(PinName cs = CS, bool overflow = true); + SPIFlash(PinName cs = CS, SPIClass *spiinterface=&SPI); #endif //----------------------------------------Initial / Chip Functions----------------------------------------// bool begin(void); @@ -235,6 +235,8 @@ class SPIFlash { #ifdef SPI_HAS_TRANSACTION SPISettings _settings; #endif + //If multiple SPI ports are available this variable is used to choose between them (SPI, SPI1, SPI2 etc.) + SPIClass *_spi; #if !defined (BOARD_RTL8195A) uint8_t csPin; #else diff --git a/src/defines.h b/src/defines.h index 3861537..279817b 100644 --- a/src/defines.h +++ b/src/defines.h @@ -52,39 +52,39 @@ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // General size definitions // -// B = Bytes; KB = Kilo bits; MB = Mega bits // +// B = Bytes; KB = Kilo Bytes; MB = Mega Bytes // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -#define B1 1L -#define B2 2L -#define B4 4L -#define B8 8L -#define B16 16L -#define B32 32L -#define B64 64L -#define B80 80L -#define B128 128L -#define B256 256L -#define B512 512L -#define KB1 B1 * K -#define KB2 B2 * K -#define KB4 B4 * K -#define KB8 B8 * K -#define KB16 B16 * K -#define KB32 B32 * K -#define KB64 B64 * K -#define KB128 B128 * K -#define KB256 B256 * K -#define KB512 B512 * K -#define MB1 B1 * M -#define MB2 B2 * M -#define MB4 B4 * M -#define MB8 B8 * M -#define MB16 B16 * M -#define MB32 B32 * M -#define MB64 B64 * M -#define MB128 B128 * M -#define MB256 B256 * M -#define MB512 B512 * M +#define B1 1L * B +#define B2 2L * B +#define B4 4L * B +#define B8 8L * B +#define B16 16L * B +#define B32 32L * B +#define B64 64L * B +#define B80 80L * B +#define B128 128L * B +#define B256 256L * B +#define B512 512L * B +#define KB1 1L * K +#define KB2 2L * K +#define KB4 4L * K +#define KB8 8L * K +#define KB16 16L * K +#define KB32 32L * K +#define KB64 64L * K +#define KB128 128L * K +#define KB256 256L * K +#define KB512 512L * K +#define MB1 1L * M +#define MB2 2L * M +#define MB4 4L * M +#define MB8 8L * M +#define MB16 16L * M +#define MB32 32L * M +#define MB64 64L * M +#define MB128 128L * M +#define MB256 256L * M +#define MB512 512L * M //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Chip specific instructions // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -94,6 +94,7 @@ #define PAGESIZE 0x100 #define WINBOND_WRITE_DELAY 0x02 #define WINBOND_WREN_TIMEOUT 10L + #define CHIPSIZE MB2 //~~~~~~~~~~~~~~~~~~~~~~~~ Microchip ~~~~~~~~~~~~~~~~~~~~~~~~// #define MICROCHIP_MANID 0xBF @@ -130,6 +131,7 @@ #endif #define arrayLen(x) (sizeof(x) / sizeof(*x)) #define lengthOf(x) (sizeof(x))/sizeof(byte) +#define B 1L #define K 1024L #define M K * K #define S 1000L From dde88d3db2bcfada398f5b2c2ec43bbe2ab3f5d2 Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Thu, 10 Aug 2017 03:38:00 +1000 Subject: [PATCH 12/34] Now works with other SPI ports - tested with Adafruit M0 Express' onboard memory Also works with Feather M0 with flash connected to HW SPI and SS Currently throwing errors on running on ATmega328 - to fix. --- .../FlashDiagnostic_functions.ino | 174 +++--- .../FlashDiagnostics/FlashDiagnostics.ino | 7 +- .../New_Diagnostics/Diagnostics_functions.ino | 508 ++++++++++++++++++ examples/New_Diagnostics/New_Diagnostics.ino | 68 +++ examples/Struct_writer/Struct_writer.ino | 2 +- examples/readWriteString/readWriteString.ino | 2 +- src/FLASHIO.cpp | 75 ++- src/SPIFlash.cpp | 33 +- src/SPIFlash.h | 23 +- src/defines.h | 15 +- 10 files changed, 770 insertions(+), 137 deletions(-) create mode 100644 examples/New_Diagnostics/Diagnostics_functions.ino create mode 100644 examples/New_Diagnostics/New_Diagnostics.ino diff --git a/examples/FlashDiagnostics/FlashDiagnostic_functions.ino b/examples/FlashDiagnostics/FlashDiagnostic_functions.ino index 399a231..9239734 100644 --- a/examples/FlashDiagnostics/FlashDiagnostic_functions.ino +++ b/examples/FlashDiagnostics/FlashDiagnostic_functions.ino @@ -39,13 +39,13 @@ void getID() { Serial.println(F("Get ID")); printLine(); uint8_t b1, b2; - uint16_t b3; + //uint16_t b3; uint32_t JEDEC = flash.getJEDECID(); uint32_t maxPage = flash.getMaxPage(); uint32_t capacity = flash.getCapacity(); b1 = (JEDEC >> 16); b2 = (JEDEC >> 8); - b3 = (JEDEC >> 0); + //b3 = (JEDEC >> 0); printLine(); @@ -80,17 +80,26 @@ void diagnose() { Serial.println(F("\t(No Error Chk)\t||")); printLine(); byteDiag(); + delay(1000); charDiag(); + delay(1000); wordDiag(); + delay(1000); shortDiag(); + delay(1000); uLongDiag(); + delay(1000); longDiag(); + delay(1000); floatDiag(); + delay(1000); stringDiag(); + delay(1000); structDiag(); + delay(1000); pageDiag(); + delay(1000); powerFuncDiag(); - } void byteDiag(void) { @@ -101,15 +110,16 @@ void byteDiag(void) { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// uint8_t _byte = 35; uint8_t _b; - float startTime; - uint32_t addr, wTime, rTime; + uint32_t addr, wTime, rTime, startTime; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Write // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// addr = random(0, 0xFFFFF); + wTime = 0; startTime = micros(); - flash.writeByte(addr, _byte); - wTime = micros() - startTime; + if (flash.writeByte(addr, _byte)) { + wTime = micros() - startTime; + } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Read // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -135,8 +145,9 @@ void byteDiag(void) { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// addr = random(0, 0xFFFFF); startTime = micros(); - flash.writeByte(addr, _byte, false); - wTime = micros() - startTime; + if (flash.writeByte(addr, _byte, false)) { + wTime = micros() - startTime; + } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Fast Read // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -162,15 +173,16 @@ void charDiag(void) { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// int8_t _char = -110; int8_t _c; - float startTime; - uint32_t addr, wTime, rTime; + uint32_t addr, wTime, rTime, startTime; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Write // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// addr = random(0, 0xFFFFF); + wTime = 0; startTime = micros(); - flash.writeChar(addr, _char); - wTime = micros() - startTime; + if (flash.writeChar(addr, _char)) { + wTime = micros() - startTime; + } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Read // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -195,8 +207,9 @@ void charDiag(void) { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// addr = random(0, 0xFFFFF); startTime = micros(); - flash.writeChar(addr, _char, false); - wTime = micros() - startTime; + if (flash.writeChar(addr, _char, false)) { + wTime = micros() - startTime; + } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Fast Read // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -222,15 +235,16 @@ void wordDiag(void) { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// uint16_t _word = 4520; uint16_t _w; - float startTime; - uint32_t addr, wTime, rTime; + uint32_t addr, wTime, rTime, startTime; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Write // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// addr = random(0, 0xFFFFF); + wTime = 0; startTime = micros(); - flash.writeWord(addr, _word); - wTime = micros() - startTime; + if (flash.writeWord(addr, _word)) { + wTime = micros() - startTime; + } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Read // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -255,8 +269,9 @@ void wordDiag(void) { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// addr = random(0, 0xFFFFF); startTime = micros(); - flash.writeWord(addr, _word, false); - wTime = micros() - startTime; + if (flash.writeWord(addr, _word, false)) { + wTime = micros() - startTime; + } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Fast Read // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -282,15 +297,16 @@ void shortDiag(void) { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// int16_t _short = -1250; int16_t _s; - float startTime; - uint32_t addr, wTime, rTime; + uint32_t addr, wTime, rTime, startTime; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Write // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// addr = random(0, 0xFFFFF); + wTime = 0; startTime = micros(); - flash.writeShort(addr, _short); - wTime = micros() - startTime; + if (flash.writeShort(addr, _short)) { + wTime = micros() - startTime; + } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Read // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -315,8 +331,9 @@ void shortDiag(void) { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// addr = random(0, 0xFFFFF); startTime = micros(); - flash.writeShort(addr, _short, false); - wTime = micros() - startTime; + if (flash.writeShort(addr, _short, false)) { + wTime = micros() - startTime; + } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Fast Read // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -342,15 +359,16 @@ void uLongDiag(void) { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// uint32_t _uLong = 876532; uint32_t _uL; - float startTime; - uint32_t addr, wTime, rTime; + uint32_t addr, wTime, rTime, startTime; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Write // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// addr = random(0, 0xFFFFF); + wTime = 0; startTime = micros(); - flash.writeULong(addr, _uLong); - wTime = micros() - startTime; + if (flash.writeULong(addr, _uLong)) { + wTime = micros() - startTime; + } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Read // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -375,8 +393,9 @@ void uLongDiag(void) { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// addr = random(0, 0xFFFFF); startTime = micros(); - flash.writeULong(addr, _uLong, false); - wTime = micros() - startTime; + if (flash.writeULong(addr, _uLong, false)) { + wTime = micros() - startTime; + } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Fast Read // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -402,15 +421,16 @@ void longDiag(void) { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// int32_t _long = -10959; int32_t _l; - float startTime; - uint32_t addr, wTime, rTime; + uint32_t addr, wTime, rTime, startTime; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Write // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// addr = random(0, 0xFFFFF); + wTime = 0; startTime = micros(); - flash.writeLong(addr, _long); - wTime = micros() - startTime; + if (flash.writeLong(addr, _long)) { + wTime = micros() - startTime; + } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Read // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -435,8 +455,9 @@ void longDiag(void) { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// addr = random(0, 0xFFFFF); startTime = micros(); - flash.writeLong(addr, _long, false); - wTime = micros() - startTime; + if (flash.writeLong(addr, _long, false)) { + wTime = micros() - startTime; + } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Fast Read // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -462,12 +483,12 @@ void floatDiag(void) { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// float _float = 3.1415; float _f; - float startTime; - uint32_t addr, wTime, rTime; + uint32_t addr, wTime, rTime, startTime; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Write // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// addr = random(0, 0xFFFFF); + wTime = 0; startTime = micros(); if (flash.writeFloat(addr, _float)) { wTime = micros() - startTime; @@ -524,12 +545,12 @@ void stringDiag(void) { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// String _string = "123 Test !@#"; String _str = ""; - float startTime; - uint32_t addr, wTime, rTime; + uint32_t addr, wTime, rTime, startTime; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Write // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// addr = random(0, 0xFFFFF); + wTime = 0; startTime = micros(); if (flash.writeStr(addr, _string)) { wTime = micros() - startTime; @@ -537,6 +558,7 @@ void stringDiag(void) { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Read // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + rTime = 0; startTime = micros(); if (flash.readStr(addr, _str)) { rTime = micros() - startTime; @@ -602,15 +624,16 @@ void structDiag(void) { inputStruct.s4 = true; inputStruct.s5 = 5; - float startTime; - uint32_t addr, wTime, rTime; + uint32_t addr, wTime, rTime, startTime; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Write // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// addr = random(0, 0xFFFFF); + wTime = 0; startTime = micros(); - flash.writeAnything(addr, inputStruct); - wTime = micros() - startTime; + if (flash.writeAnything(addr, inputStruct)) { + wTime = micros() - startTime; + } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Read // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -635,8 +658,9 @@ void structDiag(void) { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// addr = random(0, 0xFFFFF); startTime = micros(); - flash.writeAnything(addr, inputStruct, false); - wTime = micros() - startTime; + if (flash.writeAnything(addr, inputStruct, false)) { + wTime = micros() - startTime; + } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Fast Read // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -661,7 +685,7 @@ void pageDiag(void) { // Page // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// float startTime; - uint32_t addr, wTime, rTime; + uint32_t addr, wTime, rTime;//, startTime; uint8_t pageBuffer[PAGESIZE]; for (int i = 0; i < PAGESIZE; ++i) { @@ -763,15 +787,15 @@ void powerFuncDiag(void) { Serial.print(F("powerDown")); printTab(2, 2); //if (flash.writeStr(stringAddress1, _string)) { - wTime = micros(); - if (flash.powerDown()) { - wTime = micros() - wTime; - printPass(); - } - else { - wTime = micros() - wTime; - printFail(); - } + wTime = micros(); + if (flash.powerDown()) { + wTime = micros() - wTime; + printPass(); + } + else { + wTime = micros() - wTime; + printFail(); + } //} printTab(3, 2); printTimer(wTime); @@ -784,11 +808,11 @@ void powerFuncDiag(void) { if (flash.powerUp()) { wTime = micros() - wTime; //if (flash.writeStr(stringAddress3, _string)) { - printPass(); - } - else { - printFail(); - } + printPass(); + } + else { + printFail(); + } //} printTab(3, 2); printTimer(wTime); @@ -842,22 +866,22 @@ void powerFuncDiag(void) { printTimer(wTime); Serial.println(); - printTab(5, 0); - Serial.print(F("eraseChip")); - printTab(2, 2); - wTime = micros(); - if (flash.eraseChip()) { + /*printTab(5, 0); + Serial.print(F("eraseChip")); + printTab(2, 2); + wTime = micros(); + if (flash.eraseChip()) { wTime = micros() - wTime; printPass(); - } - else { + } + else { printFail(); - } + } - printTab(3, 2); - printTimer(wTime); - Serial.println(); + printTab(3, 2); + printTimer(wTime); + Serial.println();*/ printLine(); } diff --git a/examples/FlashDiagnostics/FlashDiagnostics.ino b/examples/FlashDiagnostics/FlashDiagnostics.ino index 14fe0bf..68ba49c 100644 --- a/examples/FlashDiagnostics/FlashDiagnostics.ino +++ b/examples/FlashDiagnostics/FlashDiagnostics.ino @@ -20,10 +20,10 @@ #define RUNDIAGNOSTIC //Outputs detailed diagnostic on error codes generated by library to Serial //Define the make of the chip being tested -#define WINBONDFLASH +//#define WINBONDFLASH //#define MICROCHIPFLASH //Define a flash memory size (if using non-Winbond memory) according to the list in defines.h -#define CHIPSIZE MB64 +//#define CHIPSIZE MB64 #if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) // Required for Serial on Zero based boards @@ -38,7 +38,8 @@ #define RANDPIN A0 #endif -SPIFlash flash(SS1); +SPIFlash flash(SS1, &SPI1); +//SPIFlash flash; void setup() { Serial.begin(BAUD_RATE); diff --git a/examples/New_Diagnostics/Diagnostics_functions.ino b/examples/New_Diagnostics/Diagnostics_functions.ino new file mode 100644 index 0000000..97ad439 --- /dev/null +++ b/examples/New_Diagnostics/Diagnostics_functions.ino @@ -0,0 +1,508 @@ +/* + |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| + | FlashDiagnostic_functions.ino | + | SPIFlash library | + | v 3.0.0 | + |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| + | Marzogh | + | 10.08.2017 | + |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| + | | + | For a full diagnostics rundown - with error codes and details of the errors | + | uncomment #define RUNDIAGNOSTIC in SPIFlash.cpp in the library before compiling | + | and loading this application onto your Arduino. | + | | + |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| +*/ +void printLine() { + for (uint8_t i = 0; i < 230; i++) { + Serial.print(F("-")); + } + Serial.println(); +} + +void clearprintBuffer(char *bufPtr) { + for (uint8_t i = 0; i < 128; i++) { + //printBuffer[i] = 0; + *bufPtr++ = 0; + } +} + +void printTime(uint32_t _wTime, uint32_t _rTime) { + if (_rTime != 0) { + Serial.print(F("\t\tWrite Time: \t")); + printTimer(_wTime); + Serial.print(F(", Read Time: ")); + printTimer(_rTime); + Serial.println(); + } + else { + Serial.print(F("\t\tTime: ")); + printTimer(_wTime); + Serial.println(); + } +} + +void printTimer(uint32_t _us) { + + if (_us > 1000000) { + float _s = _us / (float)1000000; + Serial.print(_s, 4); + Serial.print(" s"); + } + else if (_us > 10000) { + float _ms = _us / (float)1000; + Serial.print(_ms, 4); + Serial.print(" ms"); + } + else { + Serial.print(_us); + Serial.print(F(" us")); + } + delay(20); +} + +void pass(bool _status) { + Serial.print(F("\tData I/O test ")); + if (_status) { + Serial.print(F("PASS\t")); + } + else { + Serial.print(F("FAIL\t")); + } +} + +void getID() { + char printBuffer[128]; + printLine(); + for (uint8_t i = 0; i < 68; i++) { + Serial.print(F(" ")); + } + Serial.print(F("SPIFlash Library version")); +#ifdef LIBVER + uint8_t _ver, _subver, _bugfix; + flash.libver(&_ver, &_subver, &_bugfix); + clearprintBuffer(&printBuffer[1]); + sprintf(printBuffer, ": %d.%d.%d", _ver, _subver, _bugfix); + Serial.println(printBuffer); +#else + Serial.println(F("< 2.5.0")); +#endif + printLine(); + + for (uint8_t i = 0; i < 80; i++) { + Serial.print(F(" ")); + } + Serial.println(F("Get ID")); + printLine(); + uint8_t b1, b2; + //uint16_t b3; + uint32_t JEDEC = flash.getJEDECID(); + uint32_t maxPage = flash.getMaxPage(); + uint32_t capacity = flash.getCapacity(); + b1 = (JEDEC >> 16); + b2 = (JEDEC >> 8); + //b3 = (JEDEC >> 0); + + + printLine(); + //---------------------------------------------------------------------------------------------// + + clearprintBuffer(&printBuffer[1]); + sprintf(printBuffer, "\t\t\tJEDEC ID: %04lxh", JEDEC); + Serial.println(printBuffer); + clearprintBuffer(&printBuffer[1]); + sprintf(printBuffer, "\t\t\tManufacturer ID: %02xh\n\t\t\tMemory Type: %02xh\n\t\t\tCapacity: %lu bytes\n\t\t\tMaximum pages: %lu", b1, b2, capacity, maxPage); + Serial.println(printBuffer); + printLine(); + Serial.println(); +} + +void byteTest() { + uint32_t wTime, rTime, addr; + uint8_t _data, _d; + _d = 35; + + addr = random(0, 0xFFFFF); + wTime = micros(); + if (flash.writeByte(addr, _d)) { + wTime = micros() - wTime; + } + + rTime = micros(); + _data = flash.readByte(addr); + rTime = micros() - rTime; + + + Serial.print ("\t\t\tByte: \t\t"); + if (_data == _d) { + pass(TRUE); + } + else { + pass(FALSE); + } + printTime(wTime, rTime); +} + +void charTest() { + uint32_t wTime, rTime, addr; + int8_t _data, _d; + _d = -110; + + addr = random(0, 0xFFFFF); + wTime = micros(); + if (flash.writeChar(addr, _d)) { + wTime = micros() - wTime; + } + + rTime = micros(); + _data = flash.readChar(addr); + rTime = micros() - rTime; + + + Serial.print ("\t\t\tChar: \t\t"); + if (_data == _d) { + pass(TRUE); + } + else { + pass(FALSE); + } + printTime(wTime, rTime); +} + +void wordTest() { + uint32_t wTime, rTime, addr; + uint16_t _data, _d; + _d = 4520; + + addr = random(0, 0xFFFFF); + wTime = micros(); + if (flash.writeWord(addr, _d)) { + wTime = micros() - wTime; + } + + rTime = micros(); + _data = flash.readWord(addr); + rTime = micros() - rTime; + + + Serial.print ("\t\t\tWord: \t\t"); + if (_data == _d) { + pass(TRUE); + } + else { + pass(FALSE); + } + printTime(wTime, rTime); +} + +void shortTest() { + uint32_t wTime, rTime, addr; + int16_t _data, _d; + _d = -1250; + + addr = random(0, 0xFFFFF); + wTime = micros(); + if (flash.writeShort(addr, _d)) { + wTime = micros() - wTime; + } + + rTime = micros(); + _data = flash.readShort(addr); + rTime = micros() - rTime; + + + Serial.print ("\t\t\tShort: \t\t"); + if (_data == _d) { + pass(TRUE); + } + else { + pass(FALSE); + } + printTime(wTime, rTime); +} + +void uLongTest() { + uint32_t wTime, rTime, addr; + uint32_t _data, _d; + _d = 876532; + + addr = random(0, 0xFFFFF); + wTime = micros(); + if (flash.writeULong(addr, _d)) { + wTime = micros() - wTime; + } + + rTime = micros(); + _data = flash.readULong(addr); + rTime = micros() - rTime; + + + Serial.print ("\t\t\tULong: \t\t"); + if (_data == _d) { + pass(TRUE); + } + else { + pass(FALSE); + } + printTime(wTime, rTime); +} + +void longTest() { + uint32_t wTime, rTime, addr; + int32_t _data, _d; + _d = -10959; + + addr = random(0, 0xFFFFF); + wTime = micros(); + if (flash.writeLong(addr, _d)) { + wTime = micros() - wTime; + } + + rTime = micros(); + _data = flash.readLong(addr); + rTime = micros() - rTime; + + + Serial.print ("\t\t\tLong: \t\t"); + if (_data == _d) { + pass(TRUE); + } + else { + pass(FALSE); + } + printTime(wTime, rTime); +} + +void floatTest() { + uint32_t wTime, rTime, addr; + float _data, _d; + _d = 3.14; + + addr = random(0, 0xFFFFF); + wTime = micros(); + if (flash.writeFloat(addr, _d)) { + wTime = micros() - wTime; + } + + rTime = micros(); + _data = flash.readFloat(addr); + rTime = micros() - rTime; + + + Serial.print ("\t\t\tFloat: \t\t"); + if (_data == _d) { + pass(TRUE); + } + else { + pass(FALSE); + } + printTime(wTime, rTime); +} + +void stringTest() { + uint32_t wTime, rTime, addr; + String _data, _d; + _d = "This is a test String 123!@#"; + + addr = random(0, 0xFFFFF); + wTime = micros(); + if (flash.writeStr(addr, _d)) { + wTime = micros() - wTime; + } + + rTime = micros(); + flash.readStr(addr, _data); + rTime = micros() - rTime; + + + Serial.print ("\t\t\tString: \t"); + if (_data == _d) { + pass(TRUE); + } + else { + pass(FALSE); + } + printTime(wTime, rTime); +} + +void structTest() { + struct Test { + word s1; + float s2; + long s3; + bool s4; + byte s5; + }; + Test _d; + Test _data; + + _d.s1 = 31325; + _d.s2 = 4.84; + _d.s3 = 880932; + _d.s4 = true; + _d.s5 = 5; + + uint32_t addr, wTime, rTime; + + addr = random(0, 0xFFFFF); + wTime = micros(); + if (flash.writeAnything(addr, _d)) { + wTime = micros() - wTime; + } + + rTime = micros(); + flash.readAnything(addr, _data); + rTime = micros() - rTime; + + + Serial.print ("\t\t\tStruct: \t"); + if (_d.s1 == _data.s1 && _d.s2 == _data.s2 && _d.s3 == _data.s3 && _d.s4 == _data.s4 && _d.s5 == _data.s5) { + pass(TRUE); + } + else { + pass(FALSE); + } + printTime(wTime, rTime); +} + +void arrayTest() { + uint32_t wTime, rTime, addr; + uint8_t _d[256], _data[256]; + + for (uint16_t i = 0; i < 256; i++) { + _d[i] = i; + } + + addr = random(0, 0xFFFFF); + wTime = micros(); + if (flash.writeByteArray(addr, _d, 256)) { + wTime = micros() - wTime; + } + + rTime = micros(); + flash.readByteArray(addr, _data, 256); + rTime = micros() - rTime; + + + Serial.print ("\t\t\tByte Array: \t"); + for (uint16_t i = 0; i < 256; i++) { + if (_data[i] != i) { + pass(FALSE); + } + } + pass(TRUE); + printTime(wTime, rTime); + Serial.println(); +} + +void powerDownTest() { + uint32_t _time; + Serial.print(F("\t\t\tPower Down: \t")); + _time = micros(); + if (flash.powerDown()) { + _time = micros() - _time; + pass(TRUE); + printTime(_time, 0); + } + else { + pass(FALSE); + } +} + +void powerUpTest() { + uint32_t _time; + Serial.print(F("\t\t\tPower Up: \t")); + _time = micros(); + if (flash.powerUp()) { + _time = micros() - _time; + pass(TRUE); + printTime(_time, 0); + } + else { + pass(FALSE); + } +} + +void eraseSectorTest() { + uint32_t _time, _addr; + _addr = random(0, 0xFFFFF); + Serial.print(F("\t\t\tErase 4KB Sector: ")); + _time = micros(); + if (flash.eraseSector(_addr)) { + _time = micros() - _time; + pass(TRUE); + printTime(_time, 0); + } + else { + pass(FALSE); + } + Serial.println(); +} + +void eraseBlock32KTest() { + uint32_t _time, _addr; + _addr = random(0, 0xFFFFF); + Serial.print(F("\t\t\tErase 32KB Block: ")); + _time = micros(); + if (flash.eraseBlock32K(_addr)) { + _time = micros() - _time; + pass(TRUE); + printTime(_time, 0); + } + else { + pass(FALSE); + } +} + +void eraseBlock64KTest() { + uint32_t _time, _addr; + _addr = random(0, 0xFFFFF); + Serial.print(F("\t\t\tErase 64KB Block: ")); + _time = micros(); + if (flash.eraseBlock64K(_addr)) { + _time = micros() - _time; + pass(TRUE); + printTime(_time, 0); + } + else { + pass(FALSE); + } +} + +void eraseChipTest() { + uint32_t _time; + Serial.print(F("\t\t\tErase Chip: \t")); + _time = micros(); + if (flash.eraseChip()) { + _time = micros() - _time; + pass(TRUE); + printTime(_time, 0); + } + else { + pass(FALSE); + } +} + +void diagnose() { + eraseChipTest(); + eraseBlock64KTest(); + eraseBlock32KTest(); + eraseSectorTest(); + + byteTest(); + charTest(); + wordTest(); + shortTest(); + uLongTest(); + longTest(); + floatTest(); + stringTest(); + structTest(); + arrayTest(); + + + powerDownTest(); + powerUpTest(); +} + diff --git a/examples/New_Diagnostics/New_Diagnostics.ino b/examples/New_Diagnostics/New_Diagnostics.ino new file mode 100644 index 0000000..f0d3eb2 --- /dev/null +++ b/examples/New_Diagnostics/New_Diagnostics.ino @@ -0,0 +1,68 @@ +/* + |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| + | FlashDiagnostics.ino | + | SPIFlash library | + | v 3.0.0 | + |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| + | Marzogh | + | 10.08.2017 | + |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| + | | + | For a full diagnostics rundown - with error codes and details of the errors | + | uncomment #define RUNDIAGNOSTIC in SPIFlash.cpp in the library before compiling | + | and loading this application onto your Arduino. | + | | + |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| +*/ + +#include + +#define RUNDIAGNOSTIC //Outputs detailed diagnostic on error codes generated by library to Serial + +//Define the make of the chip being tested +//#define WINBONDFLASH +//#define MICROCHIPFLASH +//Define a flash memory size (if using non-Winbond memory) according to the list in defines.h +//#define CHIPSIZE MB64 + +#if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) +// Required for Serial on Zero based boards +#define Serial SERIAL_PORT_USBVIRTUAL +#endif + +#if defined (SIMBLEE) +#define BAUD_RATE 250000 +#define RANDPIN 1 +#else +#define BAUD_RATE 115200 +#define RANDPIN A0 +#endif + +#define TRUE 1 +#define FALSE 0 + +//SPIFlash flash(SS1, &SPI1); +SPIFlash flash(10); + +void setup() { + Serial.begin(BAUD_RATE); +#if defined (ARDUINO_ARCH_SAMD) || (__AVR_ATmega32U4__) + while (!Serial) ; // Wait for Serial monitor to open +#endif + Serial.print(F("Initialising Flash memory")); + for (int i = 0; i < 10; ++i) + { + Serial.print(F(".")); + } + Serial.println(); + flash.begin(); + Serial.println(); + Serial.println(); + randomSeed(analogRead(RANDPIN)); + getID(); + diagnose(); +} + +void loop() { + +} diff --git a/examples/Struct_writer/Struct_writer.ino b/examples/Struct_writer/Struct_writer.ino index 005a330..4bb10f8 100644 --- a/examples/Struct_writer/Struct_writer.ino +++ b/examples/Struct_writer/Struct_writer.ino @@ -45,7 +45,7 @@ -SPIFlash flash; +SPIFlash flash(SS1, &SPI1); struct Configuration { diff --git a/examples/readWriteString/readWriteString.ino b/examples/readWriteString/readWriteString.ino index 3d10643..c5f30d6 100644 --- a/examples/readWriteString/readWriteString.ino +++ b/examples/readWriteString/readWriteString.ino @@ -29,7 +29,7 @@ uint32_t strAddr; #define RANDPIN A0 #endif -SPIFlash flash; +SPIFlash flash(SS1, &SPI1); bool readSerialStr(String &inputStr); diff --git a/src/FLASHIO.cpp b/src/FLASHIO.cpp index 9d7b7de..57c44ef 100644 --- a/src/FLASHIO.cpp +++ b/src/FLASHIO.cpp @@ -1,4 +1,4 @@ -/* Arduino SPIFlash Library v.2.7.0 +/* Arduino SPIFlash Library v.3.0.0 * Copyright (C) 2017 by Prajwal Bhattaram * Created by Prajwal Bhattaram - 02/05/2017 * @@ -68,6 +68,7 @@ bool SPIFlash::_transferAddress(void) { _nextByte(_currentAddress >> 16); _nextByte(_currentAddress >> 8); _nextByte(_currentAddress); + return true; } bool SPIFlash::_startSPIBus(void) { @@ -77,19 +78,27 @@ bool SPIFlash::_startSPIBus(void) { #if defined (ARDUINO_ARCH_SAM) _dueSPIInit(DUE_SPI_CLK); - #else - #if defined (ARDUINO_ARCH_AVR) - //save current SPI settings - _SPCR = SPCR; - _SPSR = SPSR; - #endif + #elif defined (ARDUINO_ARCH_SAMD) #ifdef SPI_HAS_TRANSACTION _spi->beginTransaction(_settings); #else _spi->setClockDivider(SPI_CLOCK_DIV_4) _spi->setDataMode(SPI_MODE0); _spi->setBitOrder(MSBFIRST); - #endif + #endif + #else + #if defined (ARDUINO_ARCH_AVR) + //save current SPI settings + _SPCR = SPCR; + _SPSR = SPSR; + #endif + #ifdef SPI_HAS_TRANSACTION + SPI.beginTransaction(_settings); + #else + SPI.setClockDivider(SPI_CLOCK_DIV_4) + SPI.setDataMode(SPI_MODE0); + SPI.setBitOrder(MSBFIRST); + #endif #endif SPIBusState = true; return true; @@ -148,7 +157,11 @@ uint8_t SPIFlash::_nextByte(uint8_t data) { //Reads/Writes next int. Call 'n' times to read/write 'n' number of bytes. Should be called after _beginSPI() uint16_t SPIFlash::_nextInt(uint16_t data) { - return _spi->transfer16(data); +#if defined (ARDUINO_ARCH_SAMD) + return _spi->transfer16(data); +#else + return SPI.transfer16(data); +#endif } //Reads/Writes next data buffer. Call 'n' times to read/write 'n' number of bytes. Should be called after _beginSPI() @@ -158,26 +171,27 @@ void SPIFlash::_nextBuf(uint8_t opcode, uint8_t *data_buffer, uint32_t size) { case READDATA: #if defined (ARDUINO_ARCH_SAM) _dueSPIRecByte(&(*data_buffer), size); - #elif defined (ARDUINO_ARCH_AVR) + #elif defined (ARDUINO_ARCH_SAMD) _spi->transfer(&data_buffer[0], size); #else for (uint16_t i = 0; i < size; i++) { *_dataAddr = xfer(NULLBYTE); _dataAddr++; } - #endif + #endif break; case PAGEPROG: #if defined (ARDUINO_ARCH_SAM) _dueSPISendByte(&(*data_buffer), size); - #elif defined (ARDUINO_ARCH_AVR) + #elif defined (ARDUINO_ARCH_SAMD) _spi->transfer(&(*data_buffer), size); #else - for (uint16_t i = 0; i < size; i++) { + SPI.transfer(&(*data_buffer), size); + /*for (uint16_t i = 0; i < size; i++) { xfer(*_dataAddr); _dataAddr++; - } + }*/ #endif break; } @@ -186,16 +200,19 @@ void SPIFlash::_nextBuf(uint8_t opcode, uint8_t *data_buffer, uint32_t size) { //Stops all operations. Should be called after all the required data is read/written from repeated _nextByte() calls void SPIFlash::_endSPI(void) { CHIP_DESELECT - #ifdef SPI_HAS_TRANSACTION - _spi->endTransaction(); +#ifdef SPI_HAS_TRANSACTION + #if defined (ARDUINO_ARCH_SAMD) + _spi->endTransaction(); #else - interrupts(); + SPI.endTransaction(); #endif - - #if defined (ARDUINO_ARCH_AVR) +#else + interrupts(); +#endif +#if defined (ARDUINO_ARCH_AVR) SPCR = _SPCR; SPSR = _SPSR; - #endif +#endif SPIBusState = false; } @@ -325,7 +342,7 @@ bool SPIFlash::_getSFDP(void) { _chip.sfdp += (_nextByte() << (8*i)); } CHIP_DESELECT - if (_chip.sfdp = 0x50444653) { + if (_chip.sfdp == 0x50444653) { //Serial.print("_chip.sfdp: "); //Serial.println(_chip.sfdp, HEX); return true; @@ -354,9 +371,8 @@ bool SPIFlash::_chipID(void) { } // If no capacity is defined in user code -#if !defined (CAPACITY) - _chip.supported = _chip.manufacturerID; - if (_chip.supported == WINBOND_MANID || _chip.supported == MICROCHIP_MANID) { +#if !defined (CHIPSIZE) + if (_chip.manufacturerID == WINBOND_MANID || _chip.manufacturerID == MICROCHIP_MANID || _chip.manufacturerID == CYPRESS_MANID) { //Identify capacity for (uint8_t i = 0; i < sizeof(_capID); i++) { if (_chip.capacityID == _capID[i]) { @@ -364,6 +380,7 @@ bool SPIFlash::_chipID(void) { _chip.eraseTime = _eraseTime[i]; } } + _chip.supported = true; return true; } else { @@ -372,10 +389,12 @@ bool SPIFlash::_chipID(void) { } #else // If a custom chip size is defined - _chip.eraseTime = _chip.capacity/KB8; - _chip.supported = false;// This chip is not officially supported - _troubleshoot(UNKNOWNCHIP); //Error code for unidentified chip - //while(1); //Enable this if usercode is not meant to be run on unsupported chips + _chip.eraseTime = (400L *S); + if (_chip.manufacturerID!= WINBOND_MANID && _chip.manufacturerID != MICROCHIP_MANID && _chip.manufacturerID != CYPRESS_MANID) { + _chip.supported = false;// This chip is not officially supported + _troubleshoot(UNKNOWNCHIP); //Error code for unidentified chip + //while(1); //Enable this if usercode is not meant to be run on unsupported chips + } return true; #endif } diff --git a/src/SPIFlash.cpp b/src/SPIFlash.cpp index 8c00c12..ac3ad76 100644 --- a/src/SPIFlash.cpp +++ b/src/SPIFlash.cpp @@ -30,23 +30,25 @@ // Constructor //If board has multiple SPI interfaces, this constructor lets the user choose between them // Adding Low level HAL API to initialize the Chip select pinMode on RTL8195A - @boseji 2nd March 2017 -#if !defined (BOARD_RTL8195A) +#if defined (ARDUINO_ARCH_SAMD) SPIFlash::SPIFlash(uint8_t cs, SPIClass *spiinterface) { _spi = spiinterface; //Sets SPI interface - if no user selection is made, this defaults to SPI csPin = cs; -#if defined (ARDUINO_ARCH_AVR) - cs_mask = digitalPinToBitMask(csPin); -#endif pinMode(csPin, OUTPUT); } -#else -SPIFlash::SPIFlash(PinName cs, SPIClass *spiinterface) { - _spi = spiinterface; //Sets SPI interface - if no user selection is made, this defaults to SPI +#elif defined (BOARD_RTL8195A) +SPIFlash::SPIFlash(PinName cs) { gpio_init(&csPin, cs); gpio_dir(&csPin, PIN_OUTPUT); gpio_mode(&csPin, PullNone); gpio_write(&csPin, 1); } +#else +SPIFlash::SPIFlash(uint8_t cs) { + csPin = cs; + cs_mask = digitalPinToBitMask(csPin); + pinMode(csPin, OUTPUT); +} #endif @@ -59,9 +61,6 @@ bool SPIFlash::begin(void) { #if defined (CHIPSIZE) _chip.capacity = CHIPSIZE; #endif - -Serial.print("CHIPSIZE: "); -Serial.println(_chip.capacity); BEGIN_SPI #ifdef SPI_HAS_TRANSACTION //Define the settings to be used by the SPI bus @@ -725,20 +724,22 @@ bool SPIFlash::eraseBlock64K(uint32_t _addr) { //Erases whole chip. Think twice before using. bool SPIFlash::eraseChip(void) { - if(!_notBusy()||!_writeEnable()) - return false; + if(!_notBusy() || !_writeEnable()) { + return false; + } _beginSPI(CHIPERASE); - _endSPI(); - if(!_notBusy(_chip.eraseTime)) { - return false; //Datasheet says erasing chip takes 6s max + _endSPI(); + + while(_readStat1() & BUSY) { + _delay_us(30000L); } //_writeDisable(); //_writeDisable() is not required because the Write Enable Latch (WEL) flag is cleared to 0 // i.e. to write disable state upon the following conditions: // Power-up, Write Disable, Page Program, Quad Page Program, Sector Erase, Block Erase, ``Chip Erase``, Write Status Register, // Erase Security Register and Program Security register - + _endSPI(); return true; } diff --git a/src/SPIFlash.h b/src/SPIFlash.h index d4097c0..3feae66 100644 --- a/src/SPIFlash.h +++ b/src/SPIFlash.h @@ -79,8 +79,8 @@ extern "C" { #ifdef ARDUINO_ARCH_AVR #define CHIP_SELECT *cs_port &= ~cs_mask; #define CHIP_DESELECT *cs_port |= cs_mask; - #define xfer(n) _spi->transfer(n) - #define BEGIN_SPI _spi->begin(); + #define xfer(n) SPI.transfer(n) + #define BEGIN_SPI SPI.begin(); #elif defined (ARDUINO_ARCH_SAM) #define CHIP_SELECT digitalWrite(csPin, LOW); #define CHIP_DESELECT digitalWrite(csPin, HIGH); @@ -90,13 +90,18 @@ extern "C" { #elif defined (BOARD_RTL8195A) #define CHIP_SELECT gpio_write(&csPin, 0); #define CHIP_DESELECT gpio_write(&csPin, 1); - #define xfer(n) _spi->transfer(n) - #define BEGIN_SPI _spi->begin(); -#else //#elif defined (ARDUINO_ARCH_ESP8266) || defined (ARDUINO_ARCH_SAMD) + #define xfer(n) SPI.transfer(n) + #define BEGIN_SPI SPI.begin(); +#elif defined (ARDUINO_ARCH_SAMD) #define CHIP_SELECT digitalWrite(csPin, LOW); #define CHIP_DESELECT digitalWrite(csPin, HIGH); #define xfer(n) _spi->transfer(n) #define BEGIN_SPI _spi->begin(); +#else + #define CHIP_SELECT digitalWrite(csPin, LOW); + #define CHIP_DESELECT digitalWrite(csPin, HIGH); + #define xfer(n) SPI.transfer(n) + #define BEGIN_SPI SPI.begin(); #endif #define LIBVER 3 @@ -114,10 +119,12 @@ class SPIFlash { public: //----------------------------------------------Constructor----------------------------------------------- //New Constructor to Accept the PinNames as a Chip select Parameter - @boseji 02.03.17 - #if !defined (BOARD_RTL8195A) + #if defined (ARDUINO_ARCH_SAMD) SPIFlash(uint8_t cs = CS, SPIClass *spiinterface=&SPI); + #elif defined (BOARD_RTL8195A) + SPIFlash(PinName cs = CS); #else - SPIFlash(PinName cs = CS, SPIClass *spiinterface=&SPI); + SPIFlash(uint8_t cs = CS); #endif //----------------------------------------Initial / Chip Functions----------------------------------------// bool begin(void); @@ -247,10 +254,10 @@ class SPIFlash { bool pageOverflow, SPIBusState; uint8_t cs_mask, errorcode, state, _SPCR, _SPSR, _a0, _a1, _a2; struct chipID { + bool supported; uint8_t manufacturerID; uint8_t memoryTypeID; uint8_t capacityID; - uint16_t supported; uint32_t sfdp; uint32_t capacity; uint32_t eraseTime; diff --git a/src/defines.h b/src/defines.h index 279817b..20d08d1 100644 --- a/src/defines.h +++ b/src/defines.h @@ -40,7 +40,7 @@ #define WRITEENABLE 0x06 #define SECTORERASE 0x20 #define BLOCK32ERASE 0x52 -#define CHIPERASE 0xC7 +#define CHIPERASE 0x60 #define SUSPEND 0x75 #define ID 0x90 #define RESUME 0x7A @@ -54,7 +54,7 @@ // General size definitions // // B = Bytes; KB = Kilo Bytes; MB = Mega Bytes // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -#define B1 1L * B +/*#define B1 1L * B #define B2 2L * B #define B4 4L * B #define B8 8L * B @@ -84,7 +84,7 @@ #define MB64 64L * M #define MB128 128L * M #define MB256 256L * M -#define MB512 512L * M +#define MB512 512L * M*/ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Chip specific instructions // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -94,10 +94,13 @@ #define PAGESIZE 0x100 #define WINBOND_WRITE_DELAY 0x02 #define WINBOND_WREN_TIMEOUT 10L - #define CHIPSIZE MB2 + //#define CHIPSIZE 1*M //~~~~~~~~~~~~~~~~~~~~~~~~ Microchip ~~~~~~~~~~~~~~~~~~~~~~~~// #define MICROCHIP_MANID 0xBF + + //~~~~~~~~~~~~~~~~~~~~~~~~ Cypress ~~~~~~~~~~~~~~~~~~~~~~~~// + #define CYPRESS_MANID 0x1 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Definitions // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -105,6 +108,8 @@ #define BUSY 0x01 #if defined (ARDUINO_ARCH_ESP32) #define SPI_CLK 20000000 +/*#elif defined (ARDUINO_ARCH_SAMD) +#define SPI_CLK 8000000*/ #else #define SPI_CLK 104000000 //Hex equivalent of 104MHz //#define SPI_CLK 4000000 //Hex equivalent of 104MHz @@ -127,7 +132,7 @@ #if defined (SIMBLEE) #define BUSY_TIMEOUT 100L #else -#define BUSY_TIMEOUT 10L +#define BUSY_TIMEOUT 1000L #endif #define arrayLen(x) (sizeof(x) / sizeof(*x)) #define lengthOf(x) (sizeof(x))/sizeof(byte) From cc9817ca5dc0751a17a8ae3e00a01d12f62e2289 Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Thu, 10 Aug 2017 15:18:26 +1000 Subject: [PATCH 13/34] Multiple SPI interface support now baked in. Problems with comms with AVR Arch boards fixed --- examples/New_Diagnostics/New_Diagnostics.ino | 2 +- src/FLASHIO.cpp | 9 ++++--- src/SPIFlash.cpp | 8 +++++- src/SPIFlash.h | 27 ++++++++++---------- src/defines.h | 13 +++++++++- 5 files changed, 39 insertions(+), 20 deletions(-) diff --git a/examples/New_Diagnostics/New_Diagnostics.ino b/examples/New_Diagnostics/New_Diagnostics.ino index f0d3eb2..d8b91a0 100644 --- a/examples/New_Diagnostics/New_Diagnostics.ino +++ b/examples/New_Diagnostics/New_Diagnostics.ino @@ -42,7 +42,7 @@ #define FALSE 0 //SPIFlash flash(SS1, &SPI1); -SPIFlash flash(10); +SPIFlash flash; void setup() { Serial.begin(BAUD_RATE); diff --git a/src/FLASHIO.cpp b/src/FLASHIO.cpp index 57c44ef..3f78d8a 100644 --- a/src/FLASHIO.cpp +++ b/src/FLASHIO.cpp @@ -35,7 +35,7 @@ bool SPIFlash::_prep(uint8_t opcode, uint32_t _addr, uint32_t size) { switch (opcode) { case PAGEPROG: #ifndef HIGHSPEED - if(!_addressCheck(_addr, size) || !_notBusy() || !_writeEnable() || !_notPrevWritten(_addr, size)) { + if(!_addressCheck(_addr, size) || !_notPrevWritten(_addr, size) || !_notBusy() || !_writeEnable()) { return false; } #else @@ -65,9 +65,12 @@ bool SPIFlash::_prep(uint8_t opcode, uint32_t _addr, uint32_t size) { // Transfer Address. bool SPIFlash::_transferAddress(void) { - _nextByte(_currentAddress >> 16); + /*_nextByte(_currentAddress >> 16); _nextByte(_currentAddress >> 8); - _nextByte(_currentAddress); + _nextByte(_currentAddress);*/ + _nextByte(Higher(_currentAddress)); + _nextByte(Hi(_currentAddress)); + _nextByte(Lo(_currentAddress)); return true; } diff --git a/src/SPIFlash.cpp b/src/SPIFlash.cpp index ac3ad76..a0b700d 100644 --- a/src/SPIFlash.cpp +++ b/src/SPIFlash.cpp @@ -30,7 +30,13 @@ // Constructor //If board has multiple SPI interfaces, this constructor lets the user choose between them // Adding Low level HAL API to initialize the Chip select pinMode on RTL8195A - @boseji 2nd March 2017 -#if defined (ARDUINO_ARCH_SAMD) +#if defined (ARDUINO_ARCH_AVR) +SPIFlash::SPIFlash(uint8_t cs) { + csPin = cs; + cs_mask = digitalPinToBitMask(csPin); + pinMode(csPin, OUTPUT); +} +#elif defined (ARDUINO_ARCH_SAMD) SPIFlash::SPIFlash(uint8_t cs, SPIClass *spiinterface) { _spi = spiinterface; //Sets SPI interface - if no user selection is made, this defaults to SPI csPin = cs; diff --git a/src/SPIFlash.h b/src/SPIFlash.h index 3feae66..3fa609b 100644 --- a/src/SPIFlash.h +++ b/src/SPIFlash.h @@ -74,24 +74,23 @@ extern "C" { } #endif -#endif - #ifdef ARDUINO_ARCH_AVR - #define CHIP_SELECT *cs_port &= ~cs_mask; - #define CHIP_DESELECT *cs_port |= cs_mask; - #define xfer(n) SPI.transfer(n) - #define BEGIN_SPI SPI.begin(); + #define CHIP_SELECT *cs_port &= ~cs_mask; + #define CHIP_DESELECT *cs_port |= cs_mask; + #define xfer(n) SPI.transfer(n) + #define BEGIN_SPI SPI.begin(); + #endif #elif defined (ARDUINO_ARCH_SAM) - #define CHIP_SELECT digitalWrite(csPin, LOW); - #define CHIP_DESELECT digitalWrite(csPin, HIGH); - #define xfer _dueSPITransfer - #define BEGIN_SPI _dueSPIBegin(); + #define CHIP_SELECT digitalWrite(csPin, LOW); + #define CHIP_DESELECT digitalWrite(csPin, HIGH); + #define xfer _dueSPITransfer + #define BEGIN_SPI _dueSPIBegin(); // Specific access configuration for Chip select pin - @boseji 02.03.17 #elif defined (BOARD_RTL8195A) - #define CHIP_SELECT gpio_write(&csPin, 0); - #define CHIP_DESELECT gpio_write(&csPin, 1); - #define xfer(n) SPI.transfer(n) - #define BEGIN_SPI SPI.begin(); + #define CHIP_SELECT gpio_write(&csPin, 0); + #define CHIP_DESELECT gpio_write(&csPin, 1); + #define xfer(n) SPI.transfer(n) + #define BEGIN_SPI SPI.begin(); #elif defined (ARDUINO_ARCH_SAMD) #define CHIP_SELECT digitalWrite(csPin, LOW); #define CHIP_DESELECT digitalWrite(csPin, HIGH); diff --git a/src/defines.h b/src/defines.h index 20d08d1..46ee372 100644 --- a/src/defines.h +++ b/src/defines.h @@ -199,4 +199,15 @@ #define NORESPONSE 0x0C #define UNKNOWNERROR 0xFE - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +// Bit shift macros // +// Thanks to @VitorBoss // +// https://github.com/Marzogh/SPIFlash/issues/76 // +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +#define Lo(param) ((char *)¶m)[0] //0x000y +#define Hi(param) ((char *)¶m)[1] //0x00y0 +#define Higher(param) ((char *)¶m)[2] //0x0y00 +#define Highest(param) ((char *)¶m)[3] //0xy000 +#define Low(param) ((int *)¶m)[0] //0x00yy +#define Top(param) ((int *)¶m)[1] //0xyy00 +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// From 1c63fbd9c5f5d044b87a87501380f2fa81575b81 Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Thu, 10 Aug 2017 16:13:27 +1000 Subject: [PATCH 14/34] Fixed issues with test code that were causing Travis to throw errors --- .../Diagnostics_functions.ino | 6 +- .../FlashDiagnostic_functions.ino | 887 ------------------ .../FlashDiagnostics/FlashDiagnostics.ino | 72 +- examples/New_Diagnostics/New_Diagnostics.ino | 68 -- examples/Struct_writer/Struct_writer.ino | 3 +- examples/TestFlash/TestFlash.ino | 1 + examples/getAddressEx/getAddressEx.ino | 1 + examples/readWriteString/readWriteString.ino | 3 +- extras/~$Library speed comparisons.xlsx | Bin 0 -> 171 bytes src/SPIFlash.cpp | 2 +- 10 files changed, 16 insertions(+), 1027 deletions(-) rename examples/{New_Diagnostics => FlashDiagnostics}/Diagnostics_functions.ino (99%) delete mode 100644 examples/FlashDiagnostics/FlashDiagnostic_functions.ino delete mode 100644 examples/New_Diagnostics/New_Diagnostics.ino create mode 100644 extras/~$Library speed comparisons.xlsx diff --git a/examples/New_Diagnostics/Diagnostics_functions.ino b/examples/FlashDiagnostics/Diagnostics_functions.ino similarity index 99% rename from examples/New_Diagnostics/Diagnostics_functions.ino rename to examples/FlashDiagnostics/Diagnostics_functions.ino index 97ad439..99cffb2 100644 --- a/examples/New_Diagnostics/Diagnostics_functions.ino +++ b/examples/FlashDiagnostics/Diagnostics_functions.ino @@ -47,12 +47,12 @@ void printTimer(uint32_t _us) { if (_us > 1000000) { float _s = _us / (float)1000000; - Serial.print(_s, 4); + Serial.print(_s, 3); Serial.print(" s"); } - else if (_us > 10000) { + else if (_us > 1000) { float _ms = _us / (float)1000; - Serial.print(_ms, 4); + Serial.print(_ms, 3); Serial.print(" ms"); } else { diff --git a/examples/FlashDiagnostics/FlashDiagnostic_functions.ino b/examples/FlashDiagnostics/FlashDiagnostic_functions.ino deleted file mode 100644 index 9239734..0000000 --- a/examples/FlashDiagnostics/FlashDiagnostic_functions.ino +++ /dev/null @@ -1,887 +0,0 @@ -/* - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | FlashDiagnostic_functions.ino | - | SPIFlash library | - | v 2.6.0 | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | Marzogh | - | 13.11.2016 | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | | - | For a full diagnostics rundown - with error codes and details of the errors | - | uncomment #define RUNDIAGNOSTIC in SPIFlash.cpp in the library before compiling | - | and loading this application onto your Arduino. | - | | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| -*/ - -void getID() { - char printBuffer[128]; - printLine(); - for (uint8_t i = 0; i < 68; i++) { - Serial.print(F(" ")); - } - Serial.print(F("SPIFlash Library version")); -#ifdef LIBVER - uint8_t _ver, _subver, _bugfix; - flash.libver(&_ver, &_subver, &_bugfix); - clearprintBuffer(&printBuffer[1]); - sprintf(printBuffer, ": %d.%d.%d", _ver, _subver, _bugfix); - Serial.println(printBuffer); -#else - Serial.println(F("< 2.5.0")); -#endif - printLine(); - - for (uint8_t i = 0; i < 80; i++) { - Serial.print(F(" ")); - } - Serial.println(F("Get ID")); - printLine(); - uint8_t b1, b2; - //uint16_t b3; - uint32_t JEDEC = flash.getJEDECID(); - uint32_t maxPage = flash.getMaxPage(); - uint32_t capacity = flash.getCapacity(); - b1 = (JEDEC >> 16); - b2 = (JEDEC >> 8); - //b3 = (JEDEC >> 0); - - - printLine(); - //---------------------------------------------------------------------------------------------// - - clearprintBuffer(&printBuffer[1]); - sprintf(printBuffer, "\t\t\tJEDEC ID: %04lxh", JEDEC); - Serial.println(printBuffer); - clearprintBuffer(&printBuffer[1]); - sprintf(printBuffer, "\t\t\tManufacturer ID: %02xh\n\t\t\tMemory Type: %02xh\n\t\t\tCapacity: %lu bytes\n\t\t\tMaximum pages: %lu", b1, b2, capacity, maxPage); - Serial.println(printBuffer); -} - -bool checkPage(uint8_t *data_buffer) { - for (int i = 0; i < 256; i++) { - if (data_buffer[i] != i) - return false; - } - return true; -} - -void diagnose() { - printLine(); - for (uint8_t i = 0; i < 79; i++) { - Serial.print(F(" ")); - } - Serial.println(F("Data Check")); - printLine(); - - Serial.println(F("\tData Written\t||\tData Read\t||\tResult\t\t||\tWrite Time\t||\tRead Time\t||\tWrite Time\t||\tFast Read Time")); - Serial.print(F("\t\t\t||\t\t\t||\t\t\t||\t\t\t||\t\t\t||")); - Serial.println(F("\t(No Error Chk)\t||")); - printLine(); - byteDiag(); - delay(1000); - charDiag(); - delay(1000); - wordDiag(); - delay(1000); - shortDiag(); - delay(1000); - uLongDiag(); - delay(1000); - longDiag(); - delay(1000); - floatDiag(); - delay(1000); - stringDiag(); - delay(1000); - structDiag(); - delay(1000); - pageDiag(); - delay(1000); - powerFuncDiag(); -} - -void byteDiag(void) { - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Byte // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - uint8_t _byte = 35; - uint8_t _b; - uint32_t addr, wTime, rTime, startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - addr = random(0, 0xFFFFF); - wTime = 0; - startTime = micros(); - if (flash.writeByte(addr, _byte)) { - wTime = micros() - startTime; - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Read // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - startTime = micros(); - _b = flash.readByte(addr); - rTime = micros() - startTime; - //Print result - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Print Result // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(1, 0); - Serial.print(_byte); - printTab(2, 1); - Serial.print(_b); - printTab(2, 1); - if (_byte == _b) - printPass(); - else - printFail(); - printTime(wTime, rTime); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write (No Error) // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - addr = random(0, 0xFFFFF); - startTime = micros(); - if (flash.writeByte(addr, _byte, false)) { - wTime = micros() - startTime; - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Fast Read // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - startTime = micros(); - _b = flash.readByte(addr, true); - rTime = micros() - startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Print Result // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTime(wTime, rTime); - Serial.println(); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //-----------------------------------------------------------------------------------------------------------------------------------------------------// -} - -void charDiag(void) { - //-----------------------------------------------------------------------------------------------------------------------------------------------------// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Char // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - int8_t _char = -110; - int8_t _c; - uint32_t addr, wTime, rTime, startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - addr = random(0, 0xFFFFF); - wTime = 0; - startTime = micros(); - if (flash.writeChar(addr, _char)) { - wTime = micros() - startTime; - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Read // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - startTime = micros(); - _c = flash.readChar(addr); - rTime = micros() - startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Print Result // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(1, 0); - Serial.print(_char); - printTab(2, 1); - Serial.print(_c); - printTab(2, 1); - if (_char == _c) - printPass(); - else - printFail(); - printTime(wTime, rTime); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write (No Error) // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - addr = random(0, 0xFFFFF); - startTime = micros(); - if (flash.writeChar(addr, _char, false)) { - wTime = micros() - startTime; - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Fast Read // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - startTime = micros(); - _c = flash.readChar(addr, true); - rTime = micros() - startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Print Result // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTime(wTime, rTime); - Serial.println(); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //-----------------------------------------------------------------------------------------------------------------------------------------------------// -} - -void wordDiag(void) { - //-----------------------------------------------------------------------------------------------------------------------------------------------------// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Word // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - uint16_t _word = 4520; - uint16_t _w; - uint32_t addr, wTime, rTime, startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - addr = random(0, 0xFFFFF); - wTime = 0; - startTime = micros(); - if (flash.writeWord(addr, _word)) { - wTime = micros() - startTime; - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Read // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - startTime = micros(); - _w = flash.readWord(addr); - rTime = micros() - startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Print Result // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(1, 0); - Serial.print(_word); - printTab(2, 1); - Serial.print(_w); - printTab(2, 1); - if (_word == _w) - printPass(); - else - printFail(); - printTime(wTime, rTime); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write (No Error) // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - addr = random(0, 0xFFFFF); - startTime = micros(); - if (flash.writeWord(addr, _word, false)) { - wTime = micros() - startTime; - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Fast Read // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - startTime = micros(); - _w = flash.readWord(addr, true); - rTime = micros() - startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Print Result // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTime(wTime, rTime); - Serial.println(); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //-----------------------------------------------------------------------------------------------------------------------------------------------------// -} - -void shortDiag(void) { - //-----------------------------------------------------------------------------------------------------------------------------------------------------// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Short // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - int16_t _short = -1250; - int16_t _s; - uint32_t addr, wTime, rTime, startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - addr = random(0, 0xFFFFF); - wTime = 0; - startTime = micros(); - if (flash.writeShort(addr, _short)) { - wTime = micros() - startTime; - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Read // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - startTime = micros(); - _s = flash.readShort(addr); - rTime = micros() - startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Print Result // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(1, 0); - Serial.print(_short); - printTab(2, 1); - Serial.print(_s); - printTab(2, 1); - if (_short == _s) - printPass(); - else - printFail(); - printTime(wTime, rTime); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write (No Error) // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - addr = random(0, 0xFFFFF); - startTime = micros(); - if (flash.writeShort(addr, _short, false)) { - wTime = micros() - startTime; - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Fast Read // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - startTime = micros(); - _s = flash.readShort(addr, true); - rTime = micros() - startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Print Result // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTime(wTime, rTime); - Serial.println(); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //-----------------------------------------------------------------------------------------------------------------------------------------------------// -} - -void uLongDiag(void) { - //-----------------------------------------------------------------------------------------------------------------------------------------------------// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Ulong // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - uint32_t _uLong = 876532; - uint32_t _uL; - uint32_t addr, wTime, rTime, startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - addr = random(0, 0xFFFFF); - wTime = 0; - startTime = micros(); - if (flash.writeULong(addr, _uLong)) { - wTime = micros() - startTime; - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Read // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - startTime = micros(); - _uL = flash.readULong(addr); - rTime = micros() - startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Print Result // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(1, 0); - Serial.print(_uLong); - printTab(2, 1); - Serial.print(_uL); - printTab(2, 1); - if (_uLong == _uL) - printPass(); - else - printFail(); - printTime(wTime, rTime); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write (No Error) // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - addr = random(0, 0xFFFFF); - startTime = micros(); - if (flash.writeULong(addr, _uLong, false)) { - wTime = micros() - startTime; - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Fast Read // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - startTime = micros(); - _uL = flash.readULong(addr, true); - rTime = micros() - startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Print Result // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTime(wTime, rTime); - Serial.println(); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //-----------------------------------------------------------------------------------------------------------------------------------------------------// -} - -void longDiag(void) { - //-----------------------------------------------------------------------------------------------------------------------------------------------------// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Long // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - int32_t _long = -10959; - int32_t _l; - uint32_t addr, wTime, rTime, startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - addr = random(0, 0xFFFFF); - wTime = 0; - startTime = micros(); - if (flash.writeLong(addr, _long)) { - wTime = micros() - startTime; - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Read // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - startTime = micros(); - _l = flash.readLong(addr); - rTime = micros() - startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Print Result // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(1, 0); - Serial.print(_long); - printTab(2, 1); - Serial.print(_l); - printTab(2, 1); - if (_long == _l) - printPass(); - else - printFail(); - printTime(wTime, rTime); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write (No Error) // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - addr = random(0, 0xFFFFF); - startTime = micros(); - if (flash.writeLong(addr, _long, false)) { - wTime = micros() - startTime; - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Fast Read // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - startTime = micros(); - _l = flash.readLong(addr, true); - rTime = micros() - startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Print Result // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTime(wTime, rTime); - Serial.println(); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //-----------------------------------------------------------------------------------------------------------------------------------------------------// -} - -void floatDiag(void) { - //-----------------------------------------------------------------------------------------------------------------------------------------------------// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Float // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - float _float = 3.1415; - float _f; - uint32_t addr, wTime, rTime, startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - addr = random(0, 0xFFFFF); - wTime = 0; - startTime = micros(); - if (flash.writeFloat(addr, _float)) { - wTime = micros() - startTime; - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Read // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - startTime = micros(); - _f = flash.readFloat(addr); - rTime = micros() - startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Print Result // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(1, 0); - Serial.print(_float); - printTab(2, 1); - Serial.print(_f); - printTab(2, 1); - if (_float == _f) - printPass(); - else - printFail(); - printTime(wTime, rTime); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write (No Error) // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - addr = random(0, 0xFFFFF); - startTime = micros(); - if (flash.writeFloat(addr, _float, false)) { - wTime = micros() - startTime; - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Fast Read // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - startTime = micros(); - _f = flash.readFloat(addr, true); - rTime = micros() - startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Print Result // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTime(wTime, rTime); - Serial.println(); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //-----------------------------------------------------------------------------------------------------------------------------------------------------// -} - -void stringDiag(void) { - //-----------------------------------------------------------------------------------------------------------------------------------------------------// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // String // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - String _string = "123 Test !@#"; - String _str = ""; - uint32_t addr, wTime, rTime, startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - addr = random(0, 0xFFFFF); - wTime = 0; - startTime = micros(); - if (flash.writeStr(addr, _string)) { - wTime = micros() - startTime; - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Read // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - rTime = 0; - startTime = micros(); - if (flash.readStr(addr, _str)) { - rTime = micros() - startTime; - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Print Result // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(1, 0); - Serial.print(_string); - printTab(1, 1); - Serial.print(_str); - printTab(1, 1); - if (_string == _str) - printPass(); - else - printFail(); - printTime(wTime, rTime); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write (No Error) // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - addr = random(0, 0xFFFFF); - startTime = micros(); - if (flash.writeStr(addr, _string, false)) { - wTime = micros() - startTime; - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Fast Read // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - startTime = micros(); - if (flash.readStr(addr, _str, true)) { - rTime = micros() - startTime; - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Print Result // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTime(wTime, rTime); - Serial.println(); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //-----------------------------------------------------------------------------------------------------------------------------------------------------// -} - -void structDiag(void) { - //-----------------------------------------------------------------------------------------------------------------------------------------------------// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Struct // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - struct Test { - word s1; - float s2; - long s3; - bool s4; - byte s5; - }; - Test inputStruct; - Test outputStruct; - - inputStruct.s1 = 31325; - inputStruct.s2 = 4.84; - inputStruct.s3 = 880932; - inputStruct.s4 = true; - inputStruct.s5 = 5; - - uint32_t addr, wTime, rTime, startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - addr = random(0, 0xFFFFF); - wTime = 0; - startTime = micros(); - if (flash.writeAnything(addr, inputStruct)) { - wTime = micros() - startTime; - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Read // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - startTime = micros(); - flash.readAnything(addr, outputStruct); - rTime = micros() - startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Print Result // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTab(1, 0); - Serial.print(F("inputStruct")); - printTab(1, 1); - Serial.print(F("outputStruct")); - printTab(1, 1); - if (inputStruct.s1 == outputStruct.s1 && inputStruct.s2 == outputStruct.s2 && inputStruct.s3 == outputStruct.s3 && inputStruct.s4 == outputStruct.s4 && inputStruct.s5 == outputStruct.s5) - printPass(); - else - printFail(); - printTime(wTime, rTime); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write (No Error) // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - addr = random(0, 0xFFFFF); - startTime = micros(); - if (flash.writeAnything(addr, inputStruct, false)) { - wTime = micros() - startTime; - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Fast Read // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - startTime = micros(); - flash.readAnything(addr, outputStruct, true); - rTime = micros() - startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Print Result // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - printTime(wTime, rTime); - Serial.println(); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //-----------------------------------------------------------------------------------------------------------------------------------------------------// -} - -void pageDiag(void) { - //-----------------------------------------------------------------------------------------------------------------------------------------------------// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Page // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - float startTime; - uint32_t addr, wTime, rTime;//, startTime; - uint8_t pageBuffer[PAGESIZE]; - - for (int i = 0; i < PAGESIZE; ++i) { - pageBuffer[i] = i; - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - addr = random(0, flash.getMaxPage()); - startTime = micros(); - while (!flash.writeByteArray(addr, pageBuffer, PAGESIZE)); - wTime = micros() - startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Read & Print Result // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - for (int i = 0; i < PAGESIZE; ++i) { - pageBuffer[i] = 0; - } - startTime = micros(); - printTab(1, 0); - Serial.print(F("0 - ")); - Serial.print(PAGESIZE - 1); - printTab(2, 1); - startTime = micros(); - - flash.readByteArray(addr, pageBuffer, PAGESIZE); - rTime = micros() - startTime; - bool _pass; - for (uint16_t i = 0; i < 256; i++) { - if (pageBuffer [i] != i) { - _pass = false; - break; - } - else { - _pass = true; - } - } - - if (_pass) { - Serial.print(F("0 - ")); - Serial.print(PAGESIZE - 1); - printTab(2, 1); - printPass(); - } - else { - Serial.print(F("Unknown")); - printTab(2, 1); - printFail(); - } - printTime(wTime, rTime); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Write (No Error) // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - for (int i = 0; i < 256; ++i) { - pageBuffer[i] = i; - } - addr = random(0, flash.getMaxPage()); - startTime = micros(); - flash.writeByteArray(addr, pageBuffer, PAGESIZE, false); - wTime = micros() - startTime; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - // Fast Read & Print Result // - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - for (int i = 0; i < 256; ++i) { - pageBuffer[i] = 0; - } - startTime = micros(); - flash.readByteArray(addr, pageBuffer, PAGESIZE, true); - rTime = micros() - startTime; - printTime(wTime, rTime); - Serial.println(); - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - //-----------------------------------------------------------------------------------------------------------------------------------------------------// -} - -void powerFuncDiag(void) { - String _string = "123 Test !@#"; - float wTime; - - printLine(); - for (uint8_t i = 0; i < 72; i++) { - Serial.print(" "); - } - Serial.println(F("Check Other Functions")); - printLine(); - Serial.println(F("\t\t\t\t\tFunction\t\t||\t\tResult\t\t\t||\t\tTime")); - printLine(); - Serial.flush(); - - uint32_t capacity = flash.getCapacity(); - if (!Serial) - Serial.begin(115200); - uint32_t stringAddress1 = random(0, capacity); - uint32_t stringAddress2 = random(0, capacity); - uint32_t stringAddress3 = random(0, capacity); - - printTab(5, 0); - Serial.print(F("powerDown")); - printTab(2, 2); - //if (flash.writeStr(stringAddress1, _string)) { - wTime = micros(); - if (flash.powerDown()) { - wTime = micros() - wTime; - printPass(); - } - else { - wTime = micros() - wTime; - printFail(); - } - //} - printTab(3, 2); - printTimer(wTime); - Serial.println(); - - printTab(5, 0); - Serial.print(F("powerUp")); - printTab(3, 2); - wTime = micros(); - if (flash.powerUp()) { - wTime = micros() - wTime; - //if (flash.writeStr(stringAddress3, _string)) { - printPass(); - } - else { - printFail(); - } - //} - printTab(3, 2); - printTimer(wTime); - Serial.println(); - - printTab(5, 0); - Serial.print(F("eraseSector")); - wTime = micros(); - printTab(2, 2); - if (flash.eraseSector(stringAddress1)) { - wTime = micros() - wTime; - printPass(); - } - else { - printFail(); - } - wTime = wTime / 3; - printTab(3, 2); - printTimer(wTime); - Serial.println(); - - printTab(5, 0); - Serial.print(F("eraseBlock32K")); - wTime = micros(); - printTab(2, 2); - if (flash.eraseBlock32K(stringAddress2)) { - wTime = micros() - wTime; - printPass(); - } - else { - printFail(); - } - wTime = wTime / 3; - printTab(3, 2); - printTimer(wTime); - Serial.println(); - - printTab(5, 0); - Serial.print(F("eraseBlock64K")); - wTime = micros(); - printTab(2, 2); - if (flash.eraseBlock64K(stringAddress3)) { - wTime = micros() - wTime; - printPass(); - } - else { - printFail(); - } - wTime = wTime / 3; - printTab(3, 2); - printTimer(wTime); - Serial.println(); - - /*printTab(5, 0); - Serial.print(F("eraseChip")); - printTab(2, 2); - wTime = micros(); - if (flash.eraseChip()) { - wTime = micros() - wTime; - printPass(); - } - else { - printFail(); - } - - - printTab(3, 2); - printTimer(wTime); - Serial.println();*/ - - printLine(); -} diff --git a/examples/FlashDiagnostics/FlashDiagnostics.ino b/examples/FlashDiagnostics/FlashDiagnostics.ino index 68ba49c..eb45115 100644 --- a/examples/FlashDiagnostics/FlashDiagnostics.ino +++ b/examples/FlashDiagnostics/FlashDiagnostics.ino @@ -5,7 +5,7 @@ | v 3.0.0 | |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | Marzogh | - | 16.04.2017 | + | 10.08.2017 | |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | | | For a full diagnostics rundown - with error codes and details of the errors | @@ -38,8 +38,11 @@ #define RANDPIN A0 #endif -SPIFlash flash(SS1, &SPI1); -//SPIFlash flash; +#define TRUE 1 +#define FALSE 0 + +//SPIFlash flash(SS1, &SPI1); //Use this constructor if using an SPI bus other than the default SPI. Only works with chips with more than one hardware SPI bus +SPIFlash flash; void setup() { Serial.begin(BAUD_RATE); @@ -63,66 +66,3 @@ void setup() { void loop() { } - - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Serial Print Functions~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - -void clearprintBuffer(char *bufPtr) -{ - for (uint8_t i = 0; i < 128; i++) { - //printBuffer[i] = 0; - *bufPtr++ = 0; - } -} - -void printLine() { - for (uint8_t i = 0; i < 230; i++) { - Serial.print(F("-")); - } - Serial.println(); -} - -void printPass() { - Serial.print(F("Pass")); -} - -void printFail() { - Serial.print(F("Fail")); -} - -void printTab(uint8_t a, uint8_t b) { - for (uint8_t i = 0; i < a; i++) { - Serial.print(F("\t")); - } - if (b > 0) { - Serial.print("||"); - for (uint8_t i = 0; i < b; i++) { - Serial.print(F("\t")); - } - } -} - -void printTime(uint32_t _wTime, uint32_t _rTime) { - printTab(2, 1); - printTimer(_wTime); - printTab(2, 1); - printTimer(_rTime); -} - -void printTimer(uint32_t _us) { - - if (_us > 1000000) { - float _s = _us / (float)1000000; - Serial.print(_s, 4); - Serial.print(" s"); - } - else if (_us > 10000) { - float _ms = _us / (float)1000; - Serial.print(_ms, 4); - Serial.print(" ms"); - } - else { - Serial.print(_us); - Serial.print(F(" us")); - } -} diff --git a/examples/New_Diagnostics/New_Diagnostics.ino b/examples/New_Diagnostics/New_Diagnostics.ino deleted file mode 100644 index d8b91a0..0000000 --- a/examples/New_Diagnostics/New_Diagnostics.ino +++ /dev/null @@ -1,68 +0,0 @@ -/* - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | FlashDiagnostics.ino | - | SPIFlash library | - | v 3.0.0 | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | Marzogh | - | 10.08.2017 | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| - | | - | For a full diagnostics rundown - with error codes and details of the errors | - | uncomment #define RUNDIAGNOSTIC in SPIFlash.cpp in the library before compiling | - | and loading this application onto your Arduino. | - | | - |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| -*/ - -#include - -#define RUNDIAGNOSTIC //Outputs detailed diagnostic on error codes generated by library to Serial - -//Define the make of the chip being tested -//#define WINBONDFLASH -//#define MICROCHIPFLASH -//Define a flash memory size (if using non-Winbond memory) according to the list in defines.h -//#define CHIPSIZE MB64 - -#if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) -// Required for Serial on Zero based boards -#define Serial SERIAL_PORT_USBVIRTUAL -#endif - -#if defined (SIMBLEE) -#define BAUD_RATE 250000 -#define RANDPIN 1 -#else -#define BAUD_RATE 115200 -#define RANDPIN A0 -#endif - -#define TRUE 1 -#define FALSE 0 - -//SPIFlash flash(SS1, &SPI1); -SPIFlash flash; - -void setup() { - Serial.begin(BAUD_RATE); -#if defined (ARDUINO_ARCH_SAMD) || (__AVR_ATmega32U4__) - while (!Serial) ; // Wait for Serial monitor to open -#endif - Serial.print(F("Initialising Flash memory")); - for (int i = 0; i < 10; ++i) - { - Serial.print(F(".")); - } - Serial.println(); - flash.begin(); - Serial.println(); - Serial.println(); - randomSeed(analogRead(RANDPIN)); - getID(); - diagnose(); -} - -void loop() { - -} diff --git a/examples/Struct_writer/Struct_writer.ino b/examples/Struct_writer/Struct_writer.ino index 4bb10f8..660cb7c 100644 --- a/examples/Struct_writer/Struct_writer.ino +++ b/examples/Struct_writer/Struct_writer.ino @@ -45,7 +45,8 @@ -SPIFlash flash(SS1, &SPI1); +//SPIFlash flash(SS1, &SPI1); //Use this constructor if using an SPI bus other than the default SPI. Only works with chips with more than one hardware SPI bus +SPIFlash flash; struct Configuration { diff --git a/examples/TestFlash/TestFlash.ino b/examples/TestFlash/TestFlash.ino index ffcca56..182d0f5 100644 --- a/examples/TestFlash/TestFlash.ino +++ b/examples/TestFlash/TestFlash.ino @@ -89,6 +89,7 @@ String inputString, outputString; #define BAUD_RATE 115200 #endif +//SPIFlash flash(SS1, &SPI1); //Use this constructor if using an SPI bus other than the default SPI. Only works with chips with more than one hardware SPI bus SPIFlash flash; void setup() { diff --git a/examples/getAddressEx/getAddressEx.ino b/examples/getAddressEx/getAddressEx.ino index d391801..6a84572 100644 --- a/examples/getAddressEx/getAddressEx.ino +++ b/examples/getAddressEx/getAddressEx.ino @@ -41,6 +41,7 @@ byte testByte[] = { 3, 245, 84, 100 }; +//SPIFlash flash(SS1, &SPI1); //Use this constructor if using an SPI bus other than the default SPI. Only works with chips with more than one hardware SPI bus SPIFlash flash; void getAddresses(); diff --git a/examples/readWriteString/readWriteString.ino b/examples/readWriteString/readWriteString.ino index c5f30d6..64c6572 100644 --- a/examples/readWriteString/readWriteString.ino +++ b/examples/readWriteString/readWriteString.ino @@ -29,7 +29,8 @@ uint32_t strAddr; #define RANDPIN A0 #endif -SPIFlash flash(SS1, &SPI1); +//SPIFlash flash(SS1, &SPI1); //Use this constructor if using an SPI bus other than the default SPI. Only works with chips with more than one hardware SPI bus +SPIFlash flash; bool readSerialStr(String &inputStr); diff --git a/extras/~$Library speed comparisons.xlsx b/extras/~$Library speed comparisons.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..4004bc258fd68511d9669d1ed3a7e08bce9a3fc7 GIT binary patch literal 171 zcmWd(C`!yKPs~wp%1A6JNi0gtRUifkG6XObF(fi%F_Z(z90mmjCx#3ls{{xW!7{l( OF>1jT3EN~RegFXXD;dcE literal 0 HcmV?d00001 diff --git a/src/SPIFlash.cpp b/src/SPIFlash.cpp index a0b700d..46c4677 100644 --- a/src/SPIFlash.cpp +++ b/src/SPIFlash.cpp @@ -730,7 +730,7 @@ bool SPIFlash::eraseBlock64K(uint32_t _addr) { //Erases whole chip. Think twice before using. bool SPIFlash::eraseChip(void) { - if(!_notBusy() || !_writeEnable()) { + if (!_prep(ERASEFUNC, NULLBYTE)) { return false; } From e36184e7db8e029ea52a1ad670f397c750a1a352 Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Thu, 10 Aug 2017 16:16:35 +1000 Subject: [PATCH 15/34] Added chagelog entry about Completely re-written FlashDiagnostics - uses fewer resources, compatible with more chips and boards. --- extras/Changes.log | 1 + extras/~$Library speed comparisons.xlsx | Bin 171 -> 0 bytes 2 files changed, 1 insertion(+) delete mode 100644 extras/~$Library speed comparisons.xlsx diff --git a/extras/Changes.log b/extras/Changes.log index 4636156..dc256b0 100644 --- a/extras/Changes.log +++ b/extras/Changes.log @@ -23,6 +23,7 @@ New Boards supported: --> Enhancements: +--> Completely re-written FlashDiagnostics - uses fewer resources, compatible with more chips and boards --> Library now works with Microchip flash memory. (Further optimizations required) --> Library faster than before (Refer to Library speed comparison in the extras folder for timing details): diff --git a/extras/~$Library speed comparisons.xlsx b/extras/~$Library speed comparisons.xlsx deleted file mode 100644 index 4004bc258fd68511d9669d1ed3a7e08bce9a3fc7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 171 zcmWd(C`!yKPs~wp%1A6JNi0gtRUifkG6XObF(fi%F_Z(z90mmjCx#3ls{{xW!7{l( OF>1jT3EN~RegFXXD;dcE From a43a465ba9e22216683367264088f20db2017c06 Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Thu, 10 Aug 2017 16:24:32 +1000 Subject: [PATCH 16/34] Fixed error in code that caused the library to not compile with the simblee, esp8266, esp32 etc --- src/SPIFlash.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/SPIFlash.cpp b/src/SPIFlash.cpp index 46c4677..f3a27fc 100644 --- a/src/SPIFlash.cpp +++ b/src/SPIFlash.cpp @@ -52,7 +52,6 @@ SPIFlash::SPIFlash(PinName cs) { #else SPIFlash::SPIFlash(uint8_t cs) { csPin = cs; - cs_mask = digitalPinToBitMask(csPin); pinMode(csPin, OUTPUT); } #endif From a8bff341b37ca51551091d7144a95a50350b5e96 Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Thu, 10 Aug 2017 17:35:35 +1000 Subject: [PATCH 17/34] Minor formatting changes --- examples/FlashDiagnostics/FlashDiagnostics.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/FlashDiagnostics/FlashDiagnostics.ino b/examples/FlashDiagnostics/FlashDiagnostics.ino index eb45115..69ec813 100644 --- a/examples/FlashDiagnostics/FlashDiagnostics.ino +++ b/examples/FlashDiagnostics/FlashDiagnostics.ino @@ -59,8 +59,8 @@ void setup() { Serial.println(); Serial.println(); randomSeed(analogRead(RANDPIN)); - getID(); - diagnose(); + //getID(); + //diagnose(); } void loop() { From d94f41f102fa5ff529a3fc607097c59d258d9879 Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Thu, 10 Aug 2017 17:36:14 +1000 Subject: [PATCH 18/34] Code not compiling on atmega328 again. To fix. --- src/FLASHIO.cpp | 11 +++++--- src/SPIFlash.cpp | 3 ++- src/SPIFlash.h | 68 +++++++++++++++++++++++++----------------------- 3 files changed, 44 insertions(+), 38 deletions(-) diff --git a/src/FLASHIO.cpp b/src/FLASHIO.cpp index 3f78d8a..149bf4c 100644 --- a/src/FLASHIO.cpp +++ b/src/FLASHIO.cpp @@ -154,10 +154,12 @@ uint8_t SPIFlash::_nextByte(uint8_t data) { //#if defined (ARDUINO_ARCH_SAM) // return _dueSPITransfer(data); //#else + Serial.println(data, HEX); return xfer(data); //#endif } + //Reads/Writes next int. Call 'n' times to read/write 'n' number of bytes. Should be called after _beginSPI() uint16_t SPIFlash::_nextInt(uint16_t data) { #if defined (ARDUINO_ARCH_SAMD) @@ -189,12 +191,13 @@ void SPIFlash::_nextBuf(uint8_t opcode, uint8_t *data_buffer, uint32_t size) { _dueSPISendByte(&(*data_buffer), size); #elif defined (ARDUINO_ARCH_SAMD) _spi->transfer(&(*data_buffer), size); - #else - SPI.transfer(&(*data_buffer), size); - /*for (uint16_t i = 0; i < size; i++) { + #elif defined (ARDUINO_ARCH_ESP8266) || defined (ARDUINO_ARCH_ESP32) + for (uint16_t i = 0; i < size; i++) { xfer(*_dataAddr); _dataAddr++; - }*/ + } + #else + SPI.transfer(&(*data_buffer), size); #endif break; } diff --git a/src/SPIFlash.cpp b/src/SPIFlash.cpp index f3a27fc..8e93c3e 100644 --- a/src/SPIFlash.cpp +++ b/src/SPIFlash.cpp @@ -729,7 +729,8 @@ bool SPIFlash::eraseBlock64K(uint32_t _addr) { //Erases whole chip. Think twice before using. bool SPIFlash::eraseChip(void) { - if (!_prep(ERASEFUNC, NULLBYTE)) { + //if (!_prep(ERASEFUNC, NULLBYTE)) { + if(!_notBusy()||!_writeEnable()) { return false; } diff --git a/src/SPIFlash.h b/src/SPIFlash.h index 3fa609b..7a19910 100644 --- a/src/SPIFlash.h +++ b/src/SPIFlash.h @@ -26,14 +26,14 @@ */ #ifndef SPIFLASH_H -#define SPIFLASH_H + #define SPIFLASH_H //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Uncomment the code below to run a diagnostic if your flash // // does not respond // // // // Error codes will be generated and returned on functions // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -#define RUNDIAGNOSTIC // + #define RUNDIAGNOSTIC // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -57,21 +57,22 @@ #if defined (ARDUINO_ARCH_SAM) || defined (ARDUINO_ARCH_SAMD) || defined (ARDUINO_ARCH_ESP8266) || defined (SIMBLEE) || defined (ARDUINO_ARCH_ESP32) || defined (BOARD_RTL8195A) // RTL8195A included - @boseji 02.03.17 - #define _delay_us(us) delayMicroseconds(us) + #define _delay_us(us) delayMicroseconds(us) #else - #include + #include #endif // Includes specific to RTL8195A to access GPIO HAL - @boseji 02.03.17 #if defined (BOARD_RTL8195A) -#ifdef __cplusplus -extern "C" { -#endif + #ifdef __cplusplus + extern "C" { + #endif -#include "gpio_api.h" -#include "PinNames.h" + #include "gpio_api.h" + #include "PinNames.h" -#ifdef __cplusplus -} + #ifdef __cplusplus + } + #endif #endif #ifdef ARDUINO_ARCH_AVR @@ -79,24 +80,31 @@ extern "C" { #define CHIP_DESELECT *cs_port |= cs_mask; #define xfer(n) SPI.transfer(n) #define BEGIN_SPI SPI.begin(); - #endif + #elif defined (ARDUINO_ARCH_SAM) #define CHIP_SELECT digitalWrite(csPin, LOW); #define CHIP_DESELECT digitalWrite(csPin, HIGH); #define xfer _dueSPITransfer #define BEGIN_SPI _dueSPIBegin(); + extern char _end; + extern "C" char *sbrk(int i); + //char *ramstart=(char *)0x20070000; + //char *ramend=(char *)0x20088000; + +#elif defined (ARDUINO_ARCH_SAMD) + #define CHIP_SELECT digitalWrite(csPin, LOW); + #define CHIP_DESELECT digitalWrite(csPin, HIGH); + #define xfer(n) _spi->transfer(n) + #define BEGIN_SPI _spi->begin(); + // Specific access configuration for Chip select pin - @boseji 02.03.17 #elif defined (BOARD_RTL8195A) #define CHIP_SELECT gpio_write(&csPin, 0); #define CHIP_DESELECT gpio_write(&csPin, 1); #define xfer(n) SPI.transfer(n) #define BEGIN_SPI SPI.begin(); -#elif defined (ARDUINO_ARCH_SAMD) - #define CHIP_SELECT digitalWrite(csPin, LOW); - #define CHIP_DESELECT digitalWrite(csPin, HIGH); - #define xfer(n) _spi->transfer(n) - #define BEGIN_SPI _spi->begin(); -#else + +#elif !defined (ARDUINO_ARCH_AVR) || !defined (ARDUINO_ARCH_SAM) || !defined (ARDUINO_ARCH_SAMD) || !defined (BOARD_RTL8195A) #define CHIP_SELECT digitalWrite(csPin, LOW); #define CHIP_DESELECT digitalWrite(csPin, HIGH); #define xfer(n) SPI.transfer(n) @@ -107,24 +115,18 @@ extern "C" { #define LIBSUBVER 0 #define BUGFIXVER 0 -#if defined (ARDUINO_ARCH_SAM) - extern char _end; - extern "C" char *sbrk(int i); - //char *ramstart=(char *)0x20070000; - //char *ramend=(char *)0x20088000; -#endif class SPIFlash { public: //----------------------------------------------Constructor----------------------------------------------- //New Constructor to Accept the PinNames as a Chip select Parameter - @boseji 02.03.17 - #if defined (ARDUINO_ARCH_SAMD) +#if defined (ARDUINO_ARCH_SAMD) SPIFlash(uint8_t cs = CS, SPIClass *spiinterface=&SPI); - #elif defined (BOARD_RTL8195A) +#elif defined (BOARD_RTL8195A) SPIFlash(PinName cs = CS); - #else +#else SPIFlash(uint8_t cs = CS); - #endif +#endif //----------------------------------------Initial / Chip Functions----------------------------------------// bool begin(void); void setClock(uint32_t clockSpeed); @@ -238,17 +240,17 @@ class SPIFlash { template bool _writeErrorCheck(uint32_t _addr, const T& value); template bool _writeErrorCheck(uint32_t _addr, const T& value, uint8_t _sz); //-------------------------------------------Private variables------------------------------------------// - #ifdef SPI_HAS_TRANSACTION +#ifdef SPI_HAS_TRANSACTION SPISettings _settings; - #endif +#endif //If multiple SPI ports are available this variable is used to choose between them (SPI, SPI1, SPI2 etc.) SPIClass *_spi; - #if !defined (BOARD_RTL8195A) +#if !defined (BOARD_RTL8195A) uint8_t csPin; - #else +#else // Object declaration for the GPIO HAL type for csPin - @boseji 02.03.17 gpio_t csPin; - #endif +#endif volatile uint8_t *cs_port; bool pageOverflow, SPIBusState; uint8_t cs_mask, errorcode, state, _SPCR, _SPSR, _a0, _a1, _a2; From 52c1c173278069683c55b1cd87a074efbe968c33 Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Fri, 11 Aug 2017 12:33:38 +1000 Subject: [PATCH 19/34] Now compiles fine with all supported boards. --- .../Diagnostics_functions.ino | 31 ++----- .../FlashDiagnostics/FlashDiagnostics.ino | 22 ++++- extras/Changes.log | 1 + src/DMASPI.cpp | 0 src/FLASHIO.cpp | 67 ++++++++------- src/SPIFlash.cpp | 11 +-- src/SPIFlash.h | 86 +++++++++---------- src/defines.h | 0 src/troubleshoot.cpp | 0 9 files changed, 109 insertions(+), 109 deletions(-) mode change 100644 => 100755 src/DMASPI.cpp mode change 100644 => 100755 src/FLASHIO.cpp mode change 100644 => 100755 src/SPIFlash.cpp mode change 100644 => 100755 src/SPIFlash.h mode change 100644 => 100755 src/defines.h mode change 100644 => 100755 src/troubleshoot.cpp diff --git a/examples/FlashDiagnostics/Diagnostics_functions.ino b/examples/FlashDiagnostics/Diagnostics_functions.ino index 99cffb2..21f41da 100644 --- a/examples/FlashDiagnostics/Diagnostics_functions.ino +++ b/examples/FlashDiagnostics/Diagnostics_functions.ino @@ -30,9 +30,9 @@ void clearprintBuffer(char *bufPtr) { void printTime(uint32_t _wTime, uint32_t _rTime) { if (_rTime != 0) { - Serial.print(F("\t\tWrite Time: \t")); + Serial.print(F("\t\tWrite Time: ")); printTimer(_wTime); - Serial.print(F(", Read Time: ")); + Serial.print(F(",\tRead Time: ")); printTimer(_rTime); Serial.println(); } @@ -109,8 +109,11 @@ void getID() { //---------------------------------------------------------------------------------------------// clearprintBuffer(&printBuffer[1]); - sprintf(printBuffer, "\t\t\tJEDEC ID: %04lxh", JEDEC); + sprintf(printBuffer, "\t\t\tJEDEC ID: %04xh", JEDEC); Serial.println(printBuffer); + //Serial.print(F("\t\t\tJEDEC ID: ")); + //Serial.print(JEDEC, HEX); + //Serial.println(F("xh")); clearprintBuffer(&printBuffer[1]); sprintf(printBuffer, "\t\t\tManufacturer ID: %02xh\n\t\t\tMemory Type: %02xh\n\t\t\tCapacity: %lu bytes\n\t\t\tMaximum pages: %lu", b1, b2, capacity, maxPage); Serial.println(printBuffer); @@ -484,25 +487,3 @@ void eraseChipTest() { } } -void diagnose() { - eraseChipTest(); - eraseBlock64KTest(); - eraseBlock32KTest(); - eraseSectorTest(); - - byteTest(); - charTest(); - wordTest(); - shortTest(); - uLongTest(); - longTest(); - floatTest(); - stringTest(); - structTest(); - arrayTest(); - - - powerDownTest(); - powerUpTest(); -} - diff --git a/examples/FlashDiagnostics/FlashDiagnostics.ino b/examples/FlashDiagnostics/FlashDiagnostics.ino index 69ec813..5473ab1 100644 --- a/examples/FlashDiagnostics/FlashDiagnostics.ino +++ b/examples/FlashDiagnostics/FlashDiagnostics.ino @@ -59,8 +59,26 @@ void setup() { Serial.println(); Serial.println(); randomSeed(analogRead(RANDPIN)); - //getID(); - //diagnose(); + getID(); + eraseChipTest(); + eraseBlock64KTest(); + eraseBlock32KTest(); + eraseSectorTest(); + + byteTest(); + charTest(); + wordTest(); + shortTest(); + uLongTest(); + longTest(); + floatTest(); + stringTest(); + structTest(); + arrayTest(); + + powerDownTest(); + powerUpTest(); + printLine(); } void loop() { diff --git a/extras/Changes.log b/extras/Changes.log index dc256b0..5d08459 100644 --- a/extras/Changes.log +++ b/extras/Changes.log @@ -23,6 +23,7 @@ New Boards supported: --> Enhancements: +--> _notBusy() is faster --> Completely re-written FlashDiagnostics - uses fewer resources, compatible with more chips and boards --> Library now works with Microchip flash memory. (Further optimizations required) --> Library faster than before (Refer to Library speed comparison in the extras folder for timing details): diff --git a/src/DMASPI.cpp b/src/DMASPI.cpp old mode 100644 new mode 100755 diff --git a/src/FLASHIO.cpp b/src/FLASHIO.cpp old mode 100644 new mode 100755 index 149bf4c..f107744 --- a/src/FLASHIO.cpp +++ b/src/FLASHIO.cpp @@ -154,12 +154,10 @@ uint8_t SPIFlash::_nextByte(uint8_t data) { //#if defined (ARDUINO_ARCH_SAM) // return _dueSPITransfer(data); //#else - Serial.println(data, HEX); return xfer(data); //#endif } - //Reads/Writes next int. Call 'n' times to read/write 'n' number of bytes. Should be called after _beginSPI() uint16_t SPIFlash::_nextInt(uint16_t data) { #if defined (ARDUINO_ARCH_SAMD) @@ -178,6 +176,8 @@ void SPIFlash::_nextBuf(uint8_t opcode, uint8_t *data_buffer, uint32_t size) { _dueSPIRecByte(&(*data_buffer), size); #elif defined (ARDUINO_ARCH_SAMD) _spi->transfer(&data_buffer[0], size); + #elif defined (ARDUINO_ARCH_AVR) + SPI.transfer(&(*data_buffer), size); #else for (uint16_t i = 0; i < size; i++) { *_dataAddr = xfer(NULLBYTE); @@ -191,13 +191,13 @@ void SPIFlash::_nextBuf(uint8_t opcode, uint8_t *data_buffer, uint32_t size) { _dueSPISendByte(&(*data_buffer), size); #elif defined (ARDUINO_ARCH_SAMD) _spi->transfer(&(*data_buffer), size); - #elif defined (ARDUINO_ARCH_ESP8266) || defined (ARDUINO_ARCH_ESP32) + #elif defined (ARDUINO_ARCH_AVR) + SPI.transfer(&(*data_buffer), size); + #else for (uint16_t i = 0; i < size; i++) { xfer(*_dataAddr); _dataAddr++; } - #else - SPI.transfer(&(*data_buffer), size); #endif break; } @@ -224,10 +224,10 @@ void SPIFlash::_endSPI(void) { // Checks if status register 1 can be accessed - used to check chip status, during powerdown and power up and for debugging uint8_t SPIFlash::_readStat1(void) { - _beginSPI(READSTAT1); - uint8_t stat1 = _nextByte(); + _beginSPI(READSTAT1); + stat1 = _nextByte(); CHIP_DESELECT - return stat1; + return stat1; } // Checks if status register 2 can be accessed, if yes, reads and returns it @@ -251,44 +251,51 @@ bool SPIFlash::_noSuspend(void) { break; case MICROCHIP_MANID: - if(_readStat1() & WSE || _readStat1() & WSP) { + _readStat1(); + if(stat1 & WSE || stat1 & WSP) { _troubleshoot(SYSSUSPEND); return false; } - return true; } - + return true; } // Polls the status register 1 until busy flag is cleared or timeout bool SPIFlash::_notBusy(uint32_t timeout) { _delay_us(WINBOND_WRITE_DELAY); - uint32_t startTime = millis(); - - do { - state = _readStat1(); - if((millis()-startTime) > timeout){ - _troubleshoot(CHIPBUSY); - return false; - } - } while(state & BUSY); - return true; + uint32_t _time = 0; + + while (_time < timeout) { + _readStat1(); + if (!(stat1 & BUSY)) + { + return true; + } + _time++; + } + if (_time == timeout) { + return false; + } + return true; } //Enables writing to chip by setting the WRITEENABLE bit -bool SPIFlash::_writeEnable(uint32_t timeout) { - uint32_t startTime = millis(); - //if (!(state & WRTEN)) { +bool SPIFlash::_writeEnable(void) { + /*uint32_t startTime = millis(); do { _beginSPI(WRITEENABLE); CHIP_DESELECT - state = _readStat1(); + _readStat1(); if((millis()-startTime) > timeout) { _troubleshoot(CANTENWRITE); return false; } - } while (!(state & WRTEN)) ; - //} + } while (!(stat1 & WRTEN)) ;*/ + _beginSPI(WRITEENABLE); + CHIP_DESELECT + if (!(_readStat1() & WRTEN)) { + _troubleshoot(CANTENWRITE); + } return true; } @@ -367,12 +374,12 @@ bool SPIFlash::_chipID(void) { } if (_chip.manufacturerID == MICROCHIP_MANID) { - uint8_t _stat1 = _readStat1(); - _stat1 &= 0xC3; + _readStat1(); + stat1 &= 0xC3; _beginSPI(WRITESTATEN); CHIP_DESELECT _beginSPI(WRITESTAT); - _nextByte(_stat1); + _nextByte(stat1); CHIP_DESELECT } diff --git a/src/SPIFlash.cpp b/src/SPIFlash.cpp old mode 100644 new mode 100755 index 8e93c3e..a5bde96 --- a/src/SPIFlash.cpp +++ b/src/SPIFlash.cpp @@ -35,12 +35,14 @@ SPIFlash::SPIFlash(uint8_t cs) { csPin = cs; cs_mask = digitalPinToBitMask(csPin); pinMode(csPin, OUTPUT); + CHIP_DESELECT } #elif defined (ARDUINO_ARCH_SAMD) SPIFlash::SPIFlash(uint8_t cs, SPIClass *spiinterface) { _spi = spiinterface; //Sets SPI interface - if no user selection is made, this defaults to SPI csPin = cs; pinMode(csPin, OUTPUT); + CHIP_DESELECT } #elif defined (BOARD_RTL8195A) SPIFlash::SPIFlash(PinName cs) { @@ -48,11 +50,14 @@ SPIFlash::SPIFlash(PinName cs) { gpio_dir(&csPin, PIN_OUTPUT); gpio_mode(&csPin, PullNone); gpio_write(&csPin, 1); + CHIP_DESELECT } #else SPIFlash::SPIFlash(uint8_t cs) { csPin = cs; + cs_mask = digitalPinToBitMask(csPin); pinMode(csPin, OUTPUT); + CHIP_DESELECT } #endif @@ -63,9 +68,6 @@ SPIFlash::SPIFlash(uint8_t cs) { //Identifies chip and establishes parameters bool SPIFlash::begin(void) { -#if defined (CHIPSIZE) - _chip.capacity = CHIPSIZE; -#endif BEGIN_SPI #ifdef SPI_HAS_TRANSACTION //Define the settings to be used by the SPI bus @@ -729,8 +731,7 @@ bool SPIFlash::eraseBlock64K(uint32_t _addr) { //Erases whole chip. Think twice before using. bool SPIFlash::eraseChip(void) { - //if (!_prep(ERASEFUNC, NULLBYTE)) { - if(!_notBusy()||!_writeEnable()) { + if(!_notBusy() || !_writeEnable()) { return false; } diff --git a/src/SPIFlash.h b/src/SPIFlash.h old mode 100644 new mode 100755 index 7a19910..bacc135 --- a/src/SPIFlash.h +++ b/src/SPIFlash.h @@ -26,14 +26,14 @@ */ #ifndef SPIFLASH_H - #define SPIFLASH_H +#define SPIFLASH_H //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Uncomment the code below to run a diagnostic if your flash // // does not respond // // // // Error codes will be generated and returned on functions // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - #define RUNDIAGNOSTIC // +#define RUNDIAGNOSTIC // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -57,22 +57,21 @@ #if defined (ARDUINO_ARCH_SAM) || defined (ARDUINO_ARCH_SAMD) || defined (ARDUINO_ARCH_ESP8266) || defined (SIMBLEE) || defined (ARDUINO_ARCH_ESP32) || defined (BOARD_RTL8195A) // RTL8195A included - @boseji 02.03.17 - #define _delay_us(us) delayMicroseconds(us) + #define _delay_us(us) delayMicroseconds(us) #else - #include + #include #endif // Includes specific to RTL8195A to access GPIO HAL - @boseji 02.03.17 #if defined (BOARD_RTL8195A) - #ifdef __cplusplus - extern "C" { - #endif +#ifdef __cplusplus +extern "C" { +#endif - #include "gpio_api.h" - #include "PinNames.h" +#include "gpio_api.h" +#include "PinNames.h" - #ifdef __cplusplus - } - #endif +#ifdef __cplusplus +} #endif #ifdef ARDUINO_ARCH_AVR @@ -80,31 +79,24 @@ #define CHIP_DESELECT *cs_port |= cs_mask; #define xfer(n) SPI.transfer(n) #define BEGIN_SPI SPI.begin(); - + #endif #elif defined (ARDUINO_ARCH_SAM) #define CHIP_SELECT digitalWrite(csPin, LOW); #define CHIP_DESELECT digitalWrite(csPin, HIGH); #define xfer _dueSPITransfer #define BEGIN_SPI _dueSPIBegin(); - extern char _end; - extern "C" char *sbrk(int i); - //char *ramstart=(char *)0x20070000; - //char *ramend=(char *)0x20088000; - -#elif defined (ARDUINO_ARCH_SAMD) - #define CHIP_SELECT digitalWrite(csPin, LOW); - #define CHIP_DESELECT digitalWrite(csPin, HIGH); - #define xfer(n) _spi->transfer(n) - #define BEGIN_SPI _spi->begin(); - // Specific access configuration for Chip select pin - @boseji 02.03.17 #elif defined (BOARD_RTL8195A) #define CHIP_SELECT gpio_write(&csPin, 0); #define CHIP_DESELECT gpio_write(&csPin, 1); #define xfer(n) SPI.transfer(n) #define BEGIN_SPI SPI.begin(); - -#elif !defined (ARDUINO_ARCH_AVR) || !defined (ARDUINO_ARCH_SAM) || !defined (ARDUINO_ARCH_SAMD) || !defined (BOARD_RTL8195A) +#elif defined (ARDUINO_ARCH_SAMD) + #define CHIP_SELECT digitalWrite(csPin, LOW); + #define CHIP_DESELECT digitalWrite(csPin, HIGH); + #define xfer(n) _spi->transfer(n) + #define BEGIN_SPI _spi->begin(); +#else #define CHIP_SELECT digitalWrite(csPin, LOW); #define CHIP_DESELECT digitalWrite(csPin, HIGH); #define xfer(n) SPI.transfer(n) @@ -115,18 +107,24 @@ #define LIBSUBVER 0 #define BUGFIXVER 0 +#if defined (ARDUINO_ARCH_SAM) + extern char _end; + extern "C" char *sbrk(int i); + //char *ramstart=(char *)0x20070000; + //char *ramend=(char *)0x20088000; +#endif class SPIFlash { public: //----------------------------------------------Constructor----------------------------------------------- //New Constructor to Accept the PinNames as a Chip select Parameter - @boseji 02.03.17 -#if defined (ARDUINO_ARCH_SAMD) + #if defined (ARDUINO_ARCH_SAMD) SPIFlash(uint8_t cs = CS, SPIClass *spiinterface=&SPI); -#elif defined (BOARD_RTL8195A) + #elif defined (BOARD_RTL8195A) SPIFlash(PinName cs = CS); -#else + #else SPIFlash(uint8_t cs = CS); -#endif + #endif //----------------------------------------Initial / Chip Functions----------------------------------------// bool begin(void); void setClock(uint32_t clockSpeed); @@ -224,7 +222,7 @@ class SPIFlash { bool _noSuspend(void); bool _notBusy(uint32_t timeout = BUSY_TIMEOUT); bool _notPrevWritten(uint32_t _addr, uint32_t size = 1); - bool _writeEnable(uint32_t timeout = 10L); + bool _writeEnable(void); bool _writeDisable(void); bool _getJedecId(void); bool _getManId(uint8_t *b1, uint8_t *b2); @@ -240,20 +238,20 @@ class SPIFlash { template bool _writeErrorCheck(uint32_t _addr, const T& value); template bool _writeErrorCheck(uint32_t _addr, const T& value, uint8_t _sz); //-------------------------------------------Private variables------------------------------------------// -#ifdef SPI_HAS_TRANSACTION + #ifdef SPI_HAS_TRANSACTION SPISettings _settings; -#endif + #endif //If multiple SPI ports are available this variable is used to choose between them (SPI, SPI1, SPI2 etc.) SPIClass *_spi; -#if !defined (BOARD_RTL8195A) + #if !defined (BOARD_RTL8195A) uint8_t csPin; -#else + #else // Object declaration for the GPIO HAL type for csPin - @boseji 02.03.17 gpio_t csPin; -#endif + #endif volatile uint8_t *cs_port; bool pageOverflow, SPIBusState; - uint8_t cs_mask, errorcode, state, _SPCR, _SPSR, _a0, _a1, _a2; + uint8_t cs_mask, errorcode, stat1, _SPCR, _SPSR, _a0, _a1, _a2; struct chipID { bool supported; uint8_t manufacturerID; @@ -399,17 +397,11 @@ template bool SPIFlash::_read(uint32_t _addr, T& value, uint8_t _sz, b if (_prep(READDATA, _addr, _sz)) { uint8_t* p = (uint8_t*)(void*)&value; CHIP_SELECT - switch (fastRead) { - case false: - _nextByte(READDATA); - break; - - case true: + if (fastRead) { _nextByte(FASTREAD); - break; - - default: - break; + } + else { + _nextByte(READDATA); } _transferAddress(); for (uint16_t i = 0; i < _sz; i++) { diff --git a/src/defines.h b/src/defines.h old mode 100644 new mode 100755 diff --git a/src/troubleshoot.cpp b/src/troubleshoot.cpp old mode 100644 new mode 100755 From 27e6f6ad4e6f582462eaae793baf35bf4cd8589b Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Fri, 18 Aug 2017 21:37:22 +1000 Subject: [PATCH 20/34] Almost have DMA working for the Zero. Splitting code off into a separate branch (zero-dma-w.i.p) to work on later. --- .../FlashDiagnostics/Diagnostics_functions.ino | 1 - examples/FlashDiagnostics/FlashDiagnostics.ino | 14 ++++++++++++-- extras/SPI pinouts.md | 11 +++++++++++ src/{DMASPI.cpp => SAM_DMASPI.cpp} | 0 4 files changed, 23 insertions(+), 3 deletions(-) rename src/{DMASPI.cpp => SAM_DMASPI.cpp} (100%) diff --git a/examples/FlashDiagnostics/Diagnostics_functions.ino b/examples/FlashDiagnostics/Diagnostics_functions.ino index 21f41da..b469676 100644 --- a/examples/FlashDiagnostics/Diagnostics_functions.ino +++ b/examples/FlashDiagnostics/Diagnostics_functions.ino @@ -136,7 +136,6 @@ void byteTest() { _data = flash.readByte(addr); rTime = micros() - rTime; - Serial.print ("\t\t\tByte: \t\t"); if (_data == _d) { pass(TRUE); diff --git a/examples/FlashDiagnostics/FlashDiagnostics.ino b/examples/FlashDiagnostics/FlashDiagnostics.ino index 5473ab1..d137fa5 100644 --- a/examples/FlashDiagnostics/FlashDiagnostics.ino +++ b/examples/FlashDiagnostics/FlashDiagnostics.ino @@ -54,11 +54,12 @@ void setup() { { Serial.print(F(".")); } - Serial.println(); + Serial.println();randomSeed(analogRead(RANDPIN)); + //longBlink(); flash.begin(); Serial.println(); Serial.println(); - randomSeed(analogRead(RANDPIN)); + getID(); eraseChipTest(); eraseBlock64KTest(); @@ -84,3 +85,12 @@ void setup() { void loop() { } + +void longBlink() { + pinMode(13, OUTPUT); + digitalWrite(13, HIGH); + delay(3000); + digitalWrite(13, LOW); + delay(2000); +} + diff --git a/extras/SPI pinouts.md b/extras/SPI pinouts.md index 0b185f4..e952a72 100644 --- a/extras/SPI pinouts.md +++ b/extras/SPI pinouts.md @@ -21,4 +21,15 @@ * |____________|________________| * * +* Simblee (Sparkfun breakout) SPI pinout is as follows: +* _____________________________ +* | GPIO # | HSPI Function | +* |------------|----------------| +* | Pin 3 | MISO (DIN) | +* | Pin 5 | MOSI (DOUT) | +* | Pin 4 | CLOCK | +* | Pin 6 | CS / SS | +* |____________|________________| +* +* */ diff --git a/src/DMASPI.cpp b/src/SAM_DMASPI.cpp similarity index 100% rename from src/DMASPI.cpp rename to src/SAM_DMASPI.cpp From e11ea2fe189d2606dc49277b370aba01af87e87d Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Sat, 19 Aug 2017 00:15:25 +1000 Subject: [PATCH 21/34] Bugs Squashed: --> The writeByteArray() & writeCharArray() bug that occurred when writing arrays that spanned page boundaries (squashed in v2.5.0), stayed around to haunt the other functions. Writing any data larger than a single byte that spanned page boundaries would cause the data to wrap around to the beginning of the page. The likelihood of this occurring was slim - no one has reported it to date. However, just in case, this has now been squashed in this release. Enhancements: --> When RUNDIAGNOSTIC is uncommented in SPIFlash.h, users now have access to a new function called flash.functionRunTime() which can be called after any library I/O function is run. flash.functionRunTime() returns the time taken by the previous function to run, in microseconds (as a float). An example use case can be found when the FlashDiagnostics sketch is run with RUNDIAGNOSTIC uncommented. --- .../Diagnostics_functions.ino | 98 +++--- .../FlashDiagnostics/FlashDiagnostics.ino | 7 +- extras/Changes.log | 5 +- src/DMASAMD.h | 139 ++++++++ src/FLASHIO.cpp | 124 ++++--- src/SAM_DMASPI.cpp | 0 src/SPIFlash.cpp | 315 +++++++++++++----- src/SPIFlash.h | 206 +++++++----- src/defines.h | 9 +- src/troubleshoot.cpp | 0 10 files changed, 626 insertions(+), 277 deletions(-) create mode 100644 src/DMASAMD.h mode change 100755 => 100644 src/FLASHIO.cpp mode change 100755 => 100644 src/SAM_DMASPI.cpp mode change 100755 => 100644 src/SPIFlash.cpp mode change 100755 => 100644 src/SPIFlash.h mode change 100755 => 100644 src/defines.h mode change 100755 => 100644 src/troubleshoot.cpp diff --git a/examples/FlashDiagnostics/Diagnostics_functions.ino b/examples/FlashDiagnostics/Diagnostics_functions.ino index b469676..a58d601 100644 --- a/examples/FlashDiagnostics/Diagnostics_functions.ino +++ b/examples/FlashDiagnostics/Diagnostics_functions.ino @@ -127,14 +127,14 @@ void byteTest() { _d = 35; addr = random(0, 0xFFFFF); - wTime = micros(); + if (flash.writeByte(addr, _d)) { - wTime = micros() - wTime; + wTime = flash.functionRunTime(); } - rTime = micros(); + _data = flash.readByte(addr); - rTime = micros() - rTime; + rTime = flash.functionRunTime(); Serial.print ("\t\t\tByte: \t\t"); if (_data == _d) { @@ -152,14 +152,14 @@ void charTest() { _d = -110; addr = random(0, 0xFFFFF); - wTime = micros(); + if (flash.writeChar(addr, _d)) { - wTime = micros() - wTime; + wTime = flash.functionRunTime(); } - rTime = micros(); + _data = flash.readChar(addr); - rTime = micros() - rTime; + rTime = flash.functionRunTime(); Serial.print ("\t\t\tChar: \t\t"); @@ -178,14 +178,14 @@ void wordTest() { _d = 4520; addr = random(0, 0xFFFFF); - wTime = micros(); + if (flash.writeWord(addr, _d)) { - wTime = micros() - wTime; + wTime = flash.functionRunTime(); } - rTime = micros(); + _data = flash.readWord(addr); - rTime = micros() - rTime; + rTime = flash.functionRunTime(); Serial.print ("\t\t\tWord: \t\t"); @@ -204,14 +204,14 @@ void shortTest() { _d = -1250; addr = random(0, 0xFFFFF); - wTime = micros(); + if (flash.writeShort(addr, _d)) { - wTime = micros() - wTime; + wTime = flash.functionRunTime(); } - rTime = micros(); + _data = flash.readShort(addr); - rTime = micros() - rTime; + rTime = flash.functionRunTime(); Serial.print ("\t\t\tShort: \t\t"); @@ -230,14 +230,14 @@ void uLongTest() { _d = 876532; addr = random(0, 0xFFFFF); - wTime = micros(); + if (flash.writeULong(addr, _d)) { - wTime = micros() - wTime; + wTime = flash.functionRunTime(); } - rTime = micros(); + _data = flash.readULong(addr); - rTime = micros() - rTime; + rTime = flash.functionRunTime(); Serial.print ("\t\t\tULong: \t\t"); @@ -256,14 +256,14 @@ void longTest() { _d = -10959; addr = random(0, 0xFFFFF); - wTime = micros(); + if (flash.writeLong(addr, _d)) { - wTime = micros() - wTime; + wTime = flash.functionRunTime(); } - rTime = micros(); + _data = flash.readLong(addr); - rTime = micros() - rTime; + rTime = flash.functionRunTime(); Serial.print ("\t\t\tLong: \t\t"); @@ -282,14 +282,14 @@ void floatTest() { _d = 3.14; addr = random(0, 0xFFFFF); - wTime = micros(); + if (flash.writeFloat(addr, _d)) { - wTime = micros() - wTime; + wTime = flash.functionRunTime(); } - rTime = micros(); + _data = flash.readFloat(addr); - rTime = micros() - rTime; + rTime = flash.functionRunTime(); Serial.print ("\t\t\tFloat: \t\t"); @@ -308,14 +308,14 @@ void stringTest() { _d = "This is a test String 123!@#"; addr = random(0, 0xFFFFF); - wTime = micros(); + if (flash.writeStr(addr, _d)) { - wTime = micros() - wTime; + wTime = flash.functionRunTime(); } - rTime = micros(); + flash.readStr(addr, _data); - rTime = micros() - rTime; + rTime = flash.functionRunTime(); Serial.print ("\t\t\tString: \t"); @@ -348,14 +348,14 @@ void structTest() { uint32_t addr, wTime, rTime; addr = random(0, 0xFFFFF); - wTime = micros(); + if (flash.writeAnything(addr, _d)) { - wTime = micros() - wTime; + wTime = flash.functionRunTime(); } - rTime = micros(); + flash.readAnything(addr, _data); - rTime = micros() - rTime; + rTime = flash.functionRunTime(); Serial.print ("\t\t\tStruct: \t"); @@ -377,14 +377,14 @@ void arrayTest() { } addr = random(0, 0xFFFFF); - wTime = micros(); + if (flash.writeByteArray(addr, _d, 256)) { - wTime = micros() - wTime; + wTime = flash.functionRunTime(); } - rTime = micros(); + flash.readByteArray(addr, _data, 256); - rTime = micros() - rTime; + rTime = flash.functionRunTime(); Serial.print ("\t\t\tByte Array: \t"); @@ -401,9 +401,8 @@ void arrayTest() { void powerDownTest() { uint32_t _time; Serial.print(F("\t\t\tPower Down: \t")); - _time = micros(); if (flash.powerDown()) { - _time = micros() - _time; + _time = flash.functionRunTime(); pass(TRUE); printTime(_time, 0); } @@ -415,9 +414,8 @@ void powerDownTest() { void powerUpTest() { uint32_t _time; Serial.print(F("\t\t\tPower Up: \t")); - _time = micros(); if (flash.powerUp()) { - _time = micros() - _time; + _time = flash.functionRunTime(); pass(TRUE); printTime(_time, 0); } @@ -430,9 +428,8 @@ void eraseSectorTest() { uint32_t _time, _addr; _addr = random(0, 0xFFFFF); Serial.print(F("\t\t\tErase 4KB Sector: ")); - _time = micros(); if (flash.eraseSector(_addr)) { - _time = micros() - _time; + _time = flash.functionRunTime(); pass(TRUE); printTime(_time, 0); } @@ -446,9 +443,8 @@ void eraseBlock32KTest() { uint32_t _time, _addr; _addr = random(0, 0xFFFFF); Serial.print(F("\t\t\tErase 32KB Block: ")); - _time = micros(); if (flash.eraseBlock32K(_addr)) { - _time = micros() - _time; + _time = flash.functionRunTime(); pass(TRUE); printTime(_time, 0); } @@ -461,9 +457,8 @@ void eraseBlock64KTest() { uint32_t _time, _addr; _addr = random(0, 0xFFFFF); Serial.print(F("\t\t\tErase 64KB Block: ")); - _time = micros(); if (flash.eraseBlock64K(_addr)) { - _time = micros() - _time; + _time = flash.functionRunTime(); pass(TRUE); printTime(_time, 0); } @@ -475,9 +470,8 @@ void eraseBlock64KTest() { void eraseChipTest() { uint32_t _time; Serial.print(F("\t\t\tErase Chip: \t")); - _time = micros(); if (flash.eraseChip()) { - _time = micros() - _time; + _time = flash.functionRunTime(); pass(TRUE); printTime(_time, 0); } diff --git a/examples/FlashDiagnostics/FlashDiagnostics.ino b/examples/FlashDiagnostics/FlashDiagnostics.ino index d137fa5..7693940 100644 --- a/examples/FlashDiagnostics/FlashDiagnostics.ino +++ b/examples/FlashDiagnostics/FlashDiagnostics.ino @@ -54,8 +54,8 @@ void setup() { { Serial.print(F(".")); } - Serial.println();randomSeed(analogRead(RANDPIN)); - //longBlink(); + Serial.println(); + randomSeed(analogRead(RANDPIN)); flash.begin(); Serial.println(); Serial.println(); @@ -80,6 +80,9 @@ void setup() { powerDownTest(); powerUpTest(); printLine(); + if (!flash.functionRunTime()) { + Serial.println(F("Please uncomment RUNDIAGNOSTIC in SPIFlash.h to see the time taken by each function to run.")); + } } void loop() { diff --git a/extras/Changes.log b/extras/Changes.log index 5d08459..8dba31d 100644 --- a/extras/Changes.log +++ b/extras/Changes.log @@ -9,7 +9,7 @@ To check: --> Check _nextBuf function and optimize Bugs Squashed: ---> +--> The writeByteArray() & writeCharArray() bug that occurred when writing arrays that spanned page boundaries (squashed in v2.5.0), stayed around to haunt the other functions. Writing any data larger than a single byte that spanned page boundaries would cause the data to wrap around to the beginning of the page. The likelihood of this occurring was slim - no one has reported it to date. However, just in case, this has now been squashed in this release. Deprecations: --> Going forward the ATTiny85 is no longer officially supported. @@ -23,12 +23,13 @@ New Boards supported: --> Enhancements: +--> When RUNDIAGNOSTIC is uncommented in SPIFlash.h, users now have access to a new function called flash.functionRunTime() which can be called after any library I/O function is run. flash.functionRunTime() returns the time taken by the previous function to run, in microseconds (as a float). An example use case can be found when the FlashDiagnostics sketch is run with RUNDIAGNOSTIC uncommented. --> _notBusy() is faster --> Completely re-written FlashDiagnostics - uses fewer resources, compatible with more chips and boards --> Library now works with Microchip flash memory. (Further optimizations required) --> Library faster than before (Refer to Library speed comparison in the extras folder for timing details): - Improvements in speed in v3.0.0 when compared to v2.7.0 (values in percentage of time v3.0.0 is faster than v2.7.0) + Improvements in speed in v3.0.0 when compared to v2.6.0 (values in percentage of time v3.0.0 is faster than v2.6.0) (+) writeByte -> +3% (+) writeChar -> +6% (+) writeWord -> +3% diff --git a/src/DMASAMD.h b/src/DMASAMD.h new file mode 100644 index 0000000..b0d6997 --- /dev/null +++ b/src/DMASAMD.h @@ -0,0 +1,139 @@ +// DMA memory to memory ZERO +// ch 18 beat burst block +// xdk sam0/drivers/dma/dma.c +// packages/arduino/tools/CMSIS/4.0.0-atmel/Device/ATMEL/samd21/include/component/dmac.h +// http://asf.atmel.com/docs/3.16.0/samd21/html/asfdoc_sam0_sercom_spi_dma_use_case.html +// assume normal SPI setup, then we take over with DMA + +#include + +#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX) + + +#define BYTES 1024 +char txbuf[BYTES], rxbuf[BYTES]; + +/*void prmbs(char *lbl,unsigned long us,int bits) { + float mbs = (float)bits/us; + Serial.print(mbs,2); Serial.print(" mbs "); + Serial.print(us); Serial.print(" us "); + Serial.println(lbl); +}*/ + +// DMA 12 channels +typedef struct { + uint16_t btctrl; + uint16_t btcnt; + uint32_t srcaddr; + uint32_t dstaddr; + uint32_t descaddr; +} dmacdescriptor ; +volatile dmacdescriptor wrb[12] __attribute__ ((aligned (16))); +dmacdescriptor descriptor_section[12] __attribute__ ((aligned (16))); +dmacdescriptor descriptor __attribute__ ((aligned (16))); + +static uint32_t chnltx = 0, chnlrx = 1; // DMA channels +enum XfrType { DoTX, DoRX, DoTXRX}; +static XfrType xtype; +static uint8_t rxsink[1], txsrc[1] = {0xFF}; +volatile uint32_t dmadone; + +void DMAC_Handler() { + // interrupts DMAC_CHINTENCLR_TERR DMAC_CHINTENCLR_TCMPL DMAC_CHINTENCLR_SUSP + uint8_t active_channel; + + // disable irqs ? + __disable_irq(); + active_channel = DMAC->INTPEND.reg & DMAC_INTPEND_ID_Msk; // get channel number + DMAC->CHID.reg = DMAC_CHID_ID(active_channel); + dmadone = DMAC->CHINTFLAG.reg; + DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_TCMPL; // clear + DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_TERR; + DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_SUSP; + __enable_irq(); +} + +void dma_init() { + // probably on by default + PM->AHBMASK.reg |= PM_AHBMASK_DMAC ; + PM->APBBMASK.reg |= PM_APBBMASK_DMAC ; + NVIC_EnableIRQ( DMAC_IRQn ) ; + + DMAC->BASEADDR.reg = (uint32_t)descriptor_section; + DMAC->WRBADDR.reg = (uint32_t)wrb; + DMAC->CTRL.reg = DMAC_CTRL_DMAENABLE | DMAC_CTRL_LVLEN(0xf); +} + + +Sercom *sercom = (Sercom *)SERCOM4; // SPI SERCOM + +void spi_xfr(void *txdata, void *rxdata, size_t n) { + uint32_t temp_CHCTRLB_reg; + + // set up transmit channel + DMAC->CHID.reg = DMAC_CHID_ID(chnltx); + DMAC->CHCTRLA.reg &= ~DMAC_CHCTRLA_ENABLE; + DMAC->CHCTRLA.reg = DMAC_CHCTRLA_SWRST; + DMAC->SWTRIGCTRL.reg &= (uint32_t)(~(1 << chnltx)); + temp_CHCTRLB_reg = DMAC_CHCTRLB_LVL(0) | + DMAC_CHCTRLB_TRIGSRC(SERCOM4_DMAC_ID_TX) | DMAC_CHCTRLB_TRIGACT_BEAT; + DMAC->CHCTRLB.reg = temp_CHCTRLB_reg; + DMAC->CHINTENSET.reg = DMAC_CHINTENSET_MASK ; // enable all 3 interrupts + descriptor.descaddr = 0; + descriptor.dstaddr = (uint32_t) &sercom->SPI.DATA.reg; + descriptor.btcnt = n; + descriptor.srcaddr = (uint32_t)txdata; + descriptor.btctrl = DMAC_BTCTRL_VALID; + if (xtype != DoRX) { + descriptor.srcaddr += n; + descriptor.btctrl |= DMAC_BTCTRL_SRCINC; + } + memcpy(&descriptor_section[chnltx],&descriptor, sizeof(dmacdescriptor)); + + // rx channel enable interrupts + DMAC->CHID.reg = DMAC_CHID_ID(chnlrx); + DMAC->CHCTRLA.reg &= ~DMAC_CHCTRLA_ENABLE; + DMAC->CHCTRLA.reg = DMAC_CHCTRLA_SWRST; + DMAC->SWTRIGCTRL.reg &= (uint32_t)(~(1 << chnlrx)); + temp_CHCTRLB_reg = DMAC_CHCTRLB_LVL(0) | + DMAC_CHCTRLB_TRIGSRC(SERCOM4_DMAC_ID_RX) | DMAC_CHCTRLB_TRIGACT_BEAT; + DMAC->CHCTRLB.reg = temp_CHCTRLB_reg; + DMAC->CHINTENSET.reg = DMAC_CHINTENSET_MASK ; // enable all 3 interrupts + dmadone = 0; + descriptor.descaddr = 0; + descriptor.srcaddr = (uint32_t) &sercom->SPI.DATA.reg; + descriptor.btcnt = n; + descriptor.dstaddr = (uint32_t)rxdata; + descriptor.btctrl = DMAC_BTCTRL_VALID; + if (xtype != DoTX) { + descriptor.dstaddr += n; + descriptor.btctrl |= DMAC_BTCTRL_DSTINC; + } + memcpy(&descriptor_section[chnlrx],&descriptor, sizeof(dmacdescriptor)); + + // start both channels ? order matter ? + DMAC->CHID.reg = DMAC_CHID_ID(chnltx); + DMAC->CHCTRLA.reg |= DMAC_CHCTRLA_ENABLE; + DMAC->CHID.reg = DMAC_CHID_ID(chnlrx); + DMAC->CHCTRLA.reg |= DMAC_CHCTRLA_ENABLE; + + while(!dmadone); // await DMA done isr + + DMAC->CHID.reg = DMAC_CHID_ID(chnltx); //disable DMA to allow lib SPI + DMAC->CHCTRLA.reg &= ~DMAC_CHCTRLA_ENABLE; + DMAC->CHID.reg = DMAC_CHID_ID(chnlrx); + DMAC->CHCTRLA.reg &= ~DMAC_CHCTRLA_ENABLE; +} + +void spi_write(void *data, size_t n) { + xtype = DoTX; + spi_xfr(data,rxsink,n); +} +void spi_read(void *data, size_t n) { + xtype = DoRX; + spi_xfr(txsrc,data,n); +} +void spi_transfer(void *txdata, void *rxdata, size_t n) { + xtype = DoTXRX; + spi_xfr(txdata,rxdata,n); +} diff --git a/src/FLASHIO.cpp b/src/FLASHIO.cpp old mode 100755 new mode 100644 index f107744..24b699b --- a/src/FLASHIO.cpp +++ b/src/FLASHIO.cpp @@ -25,6 +25,7 @@ #include "SPIFlash.h" +#include "DMASAMD.h" //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Private functions used by read, write and erase operations // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -35,13 +36,13 @@ bool SPIFlash::_prep(uint8_t opcode, uint32_t _addr, uint32_t size) { switch (opcode) { case PAGEPROG: #ifndef HIGHSPEED - if(!_addressCheck(_addr, size) || !_notPrevWritten(_addr, size) || !_notBusy() || !_writeEnable()) { - return false; - } + if(!_addressCheck(_addr, size) || !_notPrevWritten(_addr, size) || !_notBusy() || !_writeEnable()) { + return false; + } #else - if (!_addressCheck(_addr, size) || !_notBusy() || !_writeEnable()) { - return false; - } + if (!_addressCheck(_addr, size) || !_notBusy() || !_writeEnable()) { + return false; + } #endif return true; break; @@ -55,9 +56,12 @@ bool SPIFlash::_prep(uint8_t opcode, uint32_t _addr, uint32_t size) { break; default: - if (!_addressCheck(_addr, size) || !_notBusy()){ - return false; - } + if (!_addressCheck(_addr, size) || !_notBusy()) { + return false; + } + #ifdef ENABLEZERODMA + _delay_us(3500L); + #endif return true; break; } @@ -68,9 +72,9 @@ bool SPIFlash::_transferAddress(void) { /*_nextByte(_currentAddress >> 16); _nextByte(_currentAddress >> 8); _nextByte(_currentAddress);*/ - _nextByte(Higher(_currentAddress)); - _nextByte(Hi(_currentAddress)); - _nextByte(Lo(_currentAddress)); + _nextByte(WRITE, Higher(_currentAddress)); + _nextByte(WRITE, Hi(_currentAddress)); + _nextByte(WRITE, Lo(_currentAddress)); return true; } @@ -89,6 +93,9 @@ bool SPIFlash::_startSPIBus(void) { _spi->setDataMode(SPI_MODE0); _spi->setBitOrder(MSBFIRST); #endif + #if defined ENABLEZERODMA + dma_init(); + #endif #else #if defined (ARDUINO_ARCH_AVR) //save current SPI settings @@ -115,34 +122,34 @@ bool SPIFlash::_beginSPI(uint8_t opcode) { CHIP_SELECT switch (opcode) { case READDATA: - _nextByte(opcode); + _nextByte(WRITE, opcode); _transferAddress(); break; case PAGEPROG: - _nextByte(opcode); + _nextByte(WRITE, opcode); _transferAddress(); break; case FASTREAD: - _nextByte(opcode); - _nextByte(DUMMYBYTE); + _nextByte(WRITE, opcode); + _nextByte(WRITE, DUMMYBYTE); _transferAddress(); case SECTORERASE: - _nextByte(opcode); + _nextByte(WRITE, opcode); _transferAddress(); case BLOCK32ERASE: - _nextByte(opcode); + _nextByte(WRITE, opcode); _transferAddress(); case BLOCK64ERASE: - _nextByte(opcode); + _nextByte(WRITE, opcode); _transferAddress(); default: - _nextByte(opcode); + _nextByte(WRITE, opcode); break; } return true; @@ -150,12 +157,22 @@ bool SPIFlash::_beginSPI(uint8_t opcode) { //SPI data lines are left open until _endSPI() is called //Reads/Writes next byte. Call 'n' times to read/write 'n' number of bytes. Should be called after _beginSPI() -uint8_t SPIFlash::_nextByte(uint8_t data) { -//#if defined (ARDUINO_ARCH_SAM) -// return _dueSPITransfer(data); -//#else +uint8_t SPIFlash::_nextByte(char IOType, uint8_t data) { +#if defined (ARDUINO_ARCH_SAMD) + #ifdef ENABLEZERODMA + union { + uint8_t dataBuf[1]; + uint8_t val; + } rxData, txData; + txData.val = data; + spi_transfer(txData.dataBuf, rxData.dataBuf, 1); + return rxData.val; + #else + return xfer(data); + #endif +#else return xfer(data); -//#endif +#endif } //Reads/Writes next int. Call 'n' times to read/write 'n' number of bytes. Should be called after _beginSPI() @@ -175,7 +192,11 @@ void SPIFlash::_nextBuf(uint8_t opcode, uint8_t *data_buffer, uint32_t size) { #if defined (ARDUINO_ARCH_SAM) _dueSPIRecByte(&(*data_buffer), size); #elif defined (ARDUINO_ARCH_SAMD) - _spi->transfer(&data_buffer[0], size); + #ifdef ENABLEZERODMA + spi_read(&(*data_buffer), size); + #else + _spi->transfer(&data_buffer[0], size); + #endif #elif defined (ARDUINO_ARCH_AVR) SPI.transfer(&(*data_buffer), size); #else @@ -190,7 +211,11 @@ void SPIFlash::_nextBuf(uint8_t opcode, uint8_t *data_buffer, uint32_t size) { #if defined (ARDUINO_ARCH_SAM) _dueSPISendByte(&(*data_buffer), size); #elif defined (ARDUINO_ARCH_SAMD) - _spi->transfer(&(*data_buffer), size); + #ifdef ENABLEZERODMA + spi_write(&(*data_buffer), size); + #else + _spi->transfer(&(*data_buffer), size); + #endif #elif defined (ARDUINO_ARCH_AVR) SPI.transfer(&(*data_buffer), size); #else @@ -225,7 +250,7 @@ void SPIFlash::_endSPI(void) { // Checks if status register 1 can be accessed - used to check chip status, during powerdown and power up and for debugging uint8_t SPIFlash::_readStat1(void) { _beginSPI(READSTAT1); - stat1 = _nextByte(); + stat1 = _nextByte(READ); CHIP_DESELECT return stat1; } @@ -233,8 +258,8 @@ uint8_t SPIFlash::_readStat1(void) { // Checks if status register 2 can be accessed, if yes, reads and returns it uint8_t SPIFlash::_readStat2(void) { _beginSPI(READSTAT2); - uint8_t stat2 = _nextByte(); - stat2 = _nextByte(); + uint8_t stat2 = _nextByte(READ); + stat2 = _nextByte(READ); CHIP_DESELECT return stat2; } @@ -263,24 +288,24 @@ bool SPIFlash::_noSuspend(void) { // Polls the status register 1 until busy flag is cleared or timeout bool SPIFlash::_notBusy(uint32_t timeout) { _delay_us(WINBOND_WRITE_DELAY); - uint32_t _time = 0; + uint32_t _time = micros(); - while (_time < timeout) { + do { _readStat1(); if (!(stat1 & BUSY)) { return true; } _time++; - } - if (_time == timeout) { + } while ((micros() - _time) < timeout); + if ((micros() - _time) == timeout) { return false; } return true; } //Enables writing to chip by setting the WRITEENABLE bit -bool SPIFlash::_writeEnable(void) { +bool SPIFlash::_writeEnable(bool _troubleshootEnable) { /*uint32_t startTime = millis(); do { _beginSPI(WRITEENABLE); @@ -294,7 +319,10 @@ bool SPIFlash::_writeEnable(void) { _beginSPI(WRITEENABLE); CHIP_DESELECT if (!(_readStat1() & WRTEN)) { - _troubleshoot(CANTENWRITE); + if (_troubleshootEnable) { + _troubleshoot(CANTENWRITE); + } + return false; } return true; } @@ -315,11 +343,11 @@ bool SPIFlash::_getManId(uint8_t *b1, uint8_t *b2) { if(!_notBusy()) return false; _beginSPI(MANID); - _nextByte(); - _nextByte(); - _nextByte(); - *b1 = _nextByte(); - *b2 = _nextByte(); + _nextByte(READ); + _nextByte(READ); + _nextByte(READ); + *b1 = _nextByte(READ); + *b2 = _nextByte(READ); CHIP_DESELECT return true; } @@ -330,9 +358,9 @@ bool SPIFlash::_getJedecId(void) { return false; } _beginSPI(JEDECID); - _chip.manufacturerID = _nextByte(NULLBYTE); // manufacturer id - _chip.memoryTypeID = _nextByte(NULLBYTE); // memory type - _chip.capacityID = _nextByte(NULLBYTE); // capacity + _chip.manufacturerID = _nextByte(READ); // manufacturer id + _chip.memoryTypeID = _nextByte(READ); // memory type + _chip.capacityID = _nextByte(READ); // capacity CHIP_DESELECT if (!_chip.manufacturerID || !_chip.memoryTypeID || !_chip.capacityID) { _troubleshoot(NORESPONSE); @@ -350,9 +378,9 @@ bool SPIFlash::_getSFDP(void) { _currentAddress = 0x00; _beginSPI(READSFDP); _transferAddress(); - _nextByte(DUMMYBYTE); + _nextByte(WRITE, DUMMYBYTE); for (uint8_t i = 0; i < 4; i++) { - _chip.sfdp += (_nextByte() << (8*i)); + _chip.sfdp += (_nextByte(READ) << (8*i)); } CHIP_DESELECT if (_chip.sfdp == 0x50444653) { @@ -379,7 +407,7 @@ bool SPIFlash::_chipID(void) { _beginSPI(WRITESTATEN); CHIP_DESELECT _beginSPI(WRITESTAT); - _nextByte(stat1); + _nextByte(WRITE, stat1); CHIP_DESELECT } @@ -441,7 +469,7 @@ bool SPIFlash::_addressCheck(uint32_t _addr, uint32_t size) { bool SPIFlash::_notPrevWritten(uint32_t _addr, uint32_t size) { _beginSPI(READDATA); for (uint32_t i = 0; i < size; i++) { - if (_nextByte() != 0xFF) { + if (_nextByte(READ) != 0xFF) { CHIP_DESELECT; return false; } diff --git a/src/SAM_DMASPI.cpp b/src/SAM_DMASPI.cpp old mode 100755 new mode 100644 diff --git a/src/SPIFlash.cpp b/src/SPIFlash.cpp old mode 100755 new mode 100644 index a5bde96..dc9883e --- a/src/SPIFlash.cpp +++ b/src/SPIFlash.cpp @@ -68,6 +68,9 @@ SPIFlash::SPIFlash(uint8_t cs) { //Identifies chip and establishes parameters bool SPIFlash::begin(void) { +#ifdef RUNDIAGNOSTIC + Serial.println("Full Diagnostics Workup initiated!"); +#endif BEGIN_SPI #ifdef SPI_HAS_TRANSACTION //Define the settings to be used by the SPI bus @@ -104,6 +107,11 @@ uint32_t SPIFlash::getMaxPage(void) { return (_chip.capacity / PAGESIZE); } +//Returns the time taken to run a function. Must be called immediately after a function is run as the variable returned is overwritten eachtime a function from this library is called. Primarily used in the diagnostics sketch included in the library to track function time. +float SPIFlash::functionRunTime(void) { + return _spifuncruntime; +} + //Returns the library version as a string bool SPIFlash::libver(uint8_t *b1, uint8_t *b2, uint8_t *b3) { *b1 = LIBVER; @@ -166,9 +174,14 @@ uint16_t SPIFlash::sizeofStr(String &inputStr) { // 3. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A uint8_t SPIFlash::readByte(uint32_t _addr, bool fastRead) { + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + #endif uint8_t data; - uint8_t _sizeofdata = sizeof(data); - _read(_addr, data, _sizeofdata, fastRead); + _read(_addr, data, sizeof(data), fastRead); + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros() - _spifuncruntime; + #endif return data; } @@ -183,9 +196,14 @@ uint8_t SPIFlash::readByte(uint32_t _addr, bool fastRead) { // 3. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A int8_t SPIFlash::readChar(uint32_t _addr, bool fastRead) { + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + #endif int8_t data; - uint8_t _sizeofdata = sizeof(data); - _read(_addr, data, _sizeofdata, fastRead); + _read(_addr, data, sizeof(data), fastRead); + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros() - _spifuncruntime; + #endif return data; } @@ -201,9 +219,12 @@ int8_t SPIFlash::readChar(uint32_t _addr, bool fastRead) { // 4. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A bool SPIFlash::readByteArray(uint32_t _addr, uint8_t *data_buffer, uint16_t bufferSize, bool fastRead) { - if (!_prep(READDATA, _addr, bufferSize)) { + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + #endif + if (!_prep(READDATA, _addr, bufferSize)) { return false; - } + } if(fastRead) { _beginSPI(FASTREAD); } @@ -212,6 +233,9 @@ bool SPIFlash::readByteArray(uint32_t _addr, uint8_t *data_buffer, uint16_t buf } _nextBuf(READDATA, &(*data_buffer), bufferSize); _endSPI(); + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros() - _spifuncruntime; + #endif return true; } @@ -227,6 +251,9 @@ bool SPIFlash::readByteArray(uint32_t _addr, uint8_t *data_buffer, uint16_t buf // 4. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A bool SPIFlash::readCharArray(uint32_t _addr, char *data_buffer, uint16_t bufferSize, bool fastRead) { + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + #endif if (!_prep(READDATA, _addr, bufferSize)) { return false; } @@ -238,6 +265,9 @@ bool SPIFlash::readCharArray(uint32_t _addr, char *data_buffer, uint16_t buffer } _nextBuf(READDATA, (uint8_t*) &(*data_buffer), bufferSize); _endSPI(); + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros() - _spifuncruntime; + #endif return true; } @@ -252,9 +282,14 @@ bool SPIFlash::readCharArray(uint32_t _addr, char *data_buffer, uint16_t buffer // 3. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A uint16_t SPIFlash::readWord(uint32_t _addr, bool fastRead) { + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + #endif uint16_t data; - uint8_t _sizeofdata = sizeof(data); - _read(_addr, data, _sizeofdata, fastRead); + _read(_addr, data, sizeof(data), fastRead); + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros() - _spifuncruntime; + #endif return data; } @@ -269,9 +304,14 @@ uint16_t SPIFlash::readWord(uint32_t _addr, bool fastRead) { // 3. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A int16_t SPIFlash::readShort(uint32_t _addr, bool fastRead) { + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + #endif int16_t data; - uint8_t _sizeofdata = sizeof(data); - _read(_addr, data, _sizeofdata, fastRead); + _read(_addr, data, sizeof(data), fastRead); + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros() - _spifuncruntime; + #endif return data; } @@ -286,9 +326,14 @@ int16_t SPIFlash::readShort(uint32_t _addr, bool fastRead) { // 3. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A uint32_t SPIFlash::readULong(uint32_t _addr, bool fastRead) { + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + #endif uint32_t data; - uint8_t _sizeofdata = sizeof(data); - _read(_addr, data, _sizeofdata, fastRead); + _read(_addr, data, sizeof(data), fastRead); + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros() - _spifuncruntime; + #endif return data; } @@ -303,9 +348,14 @@ uint32_t SPIFlash::readULong(uint32_t _addr, bool fastRead) { // 3. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A int32_t SPIFlash::readLong(uint32_t _addr, bool fastRead) { + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + #endif int32_t data; - uint8_t _sizeofdata = sizeof(data); - _read(_addr, data, _sizeofdata, fastRead); + _read(_addr, data, sizeof(data), fastRead); + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros() - _spifuncruntime; + #endif return data; } @@ -320,9 +370,14 @@ int32_t SPIFlash::readLong(uint32_t _addr, bool fastRead) { // 3. fastRead --> defaults to false - executes _beginFastRead() if set to true // Variant A float SPIFlash::readFloat(uint32_t _addr, bool fastRead) { + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + #endif float data; - uint8_t _sizeofdata = sizeof(data); - _read(_addr, data, _sizeofdata, fastRead); + _read(_addr, data, sizeof(data), fastRead); + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros() - _spifuncruntime; + #endif return data; } @@ -340,9 +395,15 @@ float SPIFlash::readFloat(uint32_t _addr, bool fastRead) { // This function first reads a short from the address to figure out the size of the String object stored and // then reads the String object data // Variant A -bool SPIFlash::readStr(uint32_t _addr, String &outStr, bool fastRead) { - uint8_t _sizeofdata = sizeof(outStr); - return _read(_addr, outStr, _sizeofdata, fastRead); +bool SPIFlash::readStr(uint32_t _addr, String &data, bool fastRead) { + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + bool _retVal = _read(_addr, data, sizeof(data), fastRead); + _spifuncruntime = micros() - _spifuncruntime; + return _retVal; + #else + return _read(_addr, data, sizeof(data), fastRead); + #endif } // Writes a byte of data to a specific location in a page. @@ -360,8 +421,14 @@ bool SPIFlash::readStr(uint32_t _addr, String &outStr, bool fastRead) { // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) // Variant A bool SPIFlash::writeByte(uint32_t _addr, uint8_t data, bool errorCheck) { - uint8_t _sizeofdata = sizeof(data); - return _write(_addr, data, _sizeofdata, errorCheck); + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + bool _retVal = _write(_addr, data, sizeof(data), errorCheck); + _spifuncruntime = micros() - _spifuncruntime; + return _retVal; + #else + return _write(_addr, data, sizeof(data), errorCheck); + #endif } // Writes a char of data to a specific location in a page. @@ -379,8 +446,14 @@ bool SPIFlash::writeByte(uint32_t _addr, uint8_t data, bool errorCheck) { // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) // Variant A bool SPIFlash::writeChar(uint32_t _addr, int8_t data, bool errorCheck) { - uint8_t _sizeofdata = sizeof(data); - return _write(_addr, data, _sizeofdata, errorCheck); + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + bool _retVal = _write(_addr, data, sizeof(data), errorCheck); + _spifuncruntime = micros() - _spifuncruntime; + return _retVal; + #else + return _write(_addr, data, sizeof(data), errorCheck); + #endif } // Writes an array of bytes starting from a specific location in a page. @@ -398,6 +471,9 @@ bool SPIFlash::writeChar(uint32_t _addr, int8_t data, bool errorCheck) { // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) // Variant A bool SPIFlash::writeByteArray(uint32_t _addr, uint8_t *data_buffer, uint16_t bufferSize, bool errorCheck) { + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + #endif if (!_prep(PAGEPROG, _addr, bufferSize)) { return false; } @@ -405,7 +481,7 @@ bool SPIFlash::writeByteArray(uint32_t _addr, uint8_t *data_buffer, uint16_t buf if (bufferSize <= maxBytes) { CHIP_SELECT - _nextByte(PAGEPROG); + _nextByte(WRITE, PAGEPROG); _transferAddress(); _nextBuf(PAGEPROG, &data_buffer[0], bufferSize); CHIP_DESELECT @@ -419,10 +495,10 @@ bool SPIFlash::writeByteArray(uint32_t _addr, uint8_t *data_buffer, uint16_t buf writeBufSz = (length<=maxBytes) ? length : maxBytes; CHIP_SELECT - _nextByte(PAGEPROG); + _nextByte(WRITE, PAGEPROG); _transferAddress(); for (uint16_t i = 0; i < writeBufSz; ++i) { - _nextByte(data_buffer[data_offset + i]); + _nextByte(WRITE, data_buffer[data_offset + i]); } CHIP_DESELECT @@ -440,6 +516,9 @@ bool SPIFlash::writeByteArray(uint32_t _addr, uint8_t *data_buffer, uint16_t buf if (!errorCheck) { _endSPI(); + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros() - _spifuncruntime; + #endif return true; } else { @@ -448,14 +527,17 @@ bool SPIFlash::writeByteArray(uint32_t _addr, uint8_t *data_buffer, uint16_t buf } _currentAddress = _addr; CHIP_SELECT - _nextByte(READDATA); + _nextByte(WRITE, READDATA); _transferAddress(); for (uint16_t j = 0; j < bufferSize; j++) { - if (_nextByte() != data_buffer[j]) { + if (_nextByte(READ) != data_buffer[j]) { return false; } } _endSPI(); + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros() - _spifuncruntime; + #endif return true; } } @@ -475,6 +557,9 @@ bool SPIFlash::writeByteArray(uint32_t _addr, uint8_t *data_buffer, uint16_t buf // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) // Variant A bool SPIFlash::writeCharArray(uint32_t _addr, char *data_buffer, uint16_t bufferSize, bool errorCheck) { + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + #endif if (!_prep(PAGEPROG, _addr, bufferSize)) { return false; } @@ -482,7 +567,7 @@ bool SPIFlash::writeCharArray(uint32_t _addr, char *data_buffer, uint16_t buffer if (bufferSize <= maxBytes) { CHIP_SELECT - _nextByte(PAGEPROG); + _nextByte(WRITE, PAGEPROG); _transferAddress(); _nextBuf(PAGEPROG, (uint8_t*) &data_buffer[0], bufferSize); CHIP_DESELECT @@ -496,10 +581,10 @@ bool SPIFlash::writeCharArray(uint32_t _addr, char *data_buffer, uint16_t buffer writeBufSz = (length<=maxBytes) ? length : maxBytes; CHIP_SELECT - _nextByte(PAGEPROG); + _nextByte(WRITE, PAGEPROG); _transferAddress(); for (uint16_t i = 0; i < writeBufSz; ++i) { - _nextByte(data_buffer[data_offset + i]); + _nextByte(WRITE, data_buffer[data_offset + i]); } CHIP_DESELECT @@ -517,6 +602,9 @@ bool SPIFlash::writeCharArray(uint32_t _addr, char *data_buffer, uint16_t buffer if (!errorCheck) { _endSPI(); + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros() - _spifuncruntime; + #endif return true; } else { @@ -525,14 +613,17 @@ bool SPIFlash::writeCharArray(uint32_t _addr, char *data_buffer, uint16_t buffer } _currentAddress = _addr; CHIP_SELECT - _nextByte(READDATA); + _nextByte(WRITE, READDATA); _transferAddress(); for (uint16_t j = 0; j < bufferSize; j++) { - if (_nextByte() != data_buffer[j]) { + if (_nextByte(READ) != data_buffer[j]) { return false; } } _endSPI(); + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros() - _spifuncruntime; + #endif return true; } } @@ -552,8 +643,14 @@ bool SPIFlash::writeCharArray(uint32_t _addr, char *data_buffer, uint16_t buffer // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) // Variant A bool SPIFlash::writeWord(uint32_t _addr, uint16_t data, bool errorCheck) { - uint8_t _sizeofdata = sizeof(data); - return _write(_addr, data, _sizeofdata, errorCheck); + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + bool _retVal = _write(_addr, data, sizeof(data), errorCheck); + _spifuncruntime = micros() - _spifuncruntime; + return _retVal; + #else + return _write(_addr, data, sizeof(data), errorCheck); + #endif } // Writes a signed int as two bytes starting from a specific location in a page. @@ -571,8 +668,14 @@ bool SPIFlash::writeWord(uint32_t _addr, uint16_t data, bool errorCheck) { // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) // Variant A bool SPIFlash::writeShort(uint32_t _addr, int16_t data, bool errorCheck) { - uint8_t _sizeofdata = sizeof(data); - return _write(_addr, data, _sizeofdata, errorCheck); + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + bool _retVal = _write(_addr, data, sizeof(data), errorCheck); + _spifuncruntime = micros() - _spifuncruntime; + return _retVal; + #else + return _write(_addr, data, sizeof(data), errorCheck); + #endif } // Writes an unsigned long as four bytes starting from a specific location in a page. @@ -590,8 +693,14 @@ bool SPIFlash::writeShort(uint32_t _addr, int16_t data, bool errorCheck) { // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) // Variant A bool SPIFlash::writeULong(uint32_t _addr, uint32_t data, bool errorCheck) { - uint8_t _sizeofdata = sizeof(data); - return _write(_addr, data, _sizeofdata, errorCheck); + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + bool _retVal = _write(_addr, data, sizeof(data), errorCheck); + _spifuncruntime = micros() - _spifuncruntime; + return _retVal; + #else + return _write(_addr, data, sizeof(data), errorCheck); + #endif } // Writes a signed long as four bytes starting from a specific location in a page. @@ -609,8 +718,14 @@ bool SPIFlash::writeULong(uint32_t _addr, uint32_t data, bool errorCheck) { // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) // Variant A bool SPIFlash::writeLong(uint32_t _addr, int32_t data, bool errorCheck) { - uint8_t _sizeofdata = sizeof(data); - return _write(_addr, data, _sizeofdata, errorCheck); + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + bool _retVal = _write(_addr, data, sizeof(data), errorCheck); + _spifuncruntime = micros() - _spifuncruntime; + return _retVal; + #else + return _write(_addr, data, sizeof(data), errorCheck); + #endif } // Writes a float as four bytes starting from a specific location in a page. @@ -628,8 +743,14 @@ bool SPIFlash::writeLong(uint32_t _addr, int32_t data, bool errorCheck) { // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) // Variant A bool SPIFlash::writeFloat(uint32_t _addr, float data, bool errorCheck) { - uint8_t _sizeofdata = sizeof(data); - return _write(_addr, data, _sizeofdata, errorCheck); + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + bool _retVal = _write(_addr, data, sizeof(data), errorCheck); + _spifuncruntime = micros() - _spifuncruntime; + return _retVal; + #else + return _write(_addr, data, sizeof(data), errorCheck); + #endif } // Reads a string from a specific location on a page. @@ -648,9 +769,15 @@ bool SPIFlash::writeFloat(uint32_t _addr, float data, bool errorCheck) { // This function first writes the size of the string as an unsigned int to the address to figure out the size of the String object stored and // then writes the String object data. Therefore it takes up two bytes more than the size of the String itself. // Variant A -bool SPIFlash::writeStr(uint32_t _addr, String &inputStr, bool errorCheck) { - uint8_t _sizeofdata = sizeof(inputStr); - return _write(_addr, inputStr, _sizeofdata, errorCheck); +bool SPIFlash::writeStr(uint32_t _addr, String &data, bool errorCheck) { + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + bool _retVal = _write(_addr, data, sizeof(data), errorCheck); + _spifuncruntime = micros() - _spifuncruntime; + return _retVal; + #else + return _write(_addr, data, sizeof(data), errorCheck); + #endif } //Erases one 4k sector. Has two variants: @@ -660,6 +787,9 @@ bool SPIFlash::writeStr(uint32_t _addr, String &inputStr, bool errorCheck) { // Page 0-15 --> Sector 0; Page 16-31 --> Sector 1;......Page 4080-4095 --> Sector 255 // Variant A bool SPIFlash::eraseSector(uint32_t _addr) { + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + #endif if (!_prep(ERASEFUNC, _addr)) { return false; } @@ -669,6 +799,9 @@ bool SPIFlash::eraseSector(uint32_t _addr) { if(!_notBusy(500L)) { return false; //Datasheet says erasing a sector takes 400ms max } + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros() - _spifuncruntime; + #endif //_writeDisable(); //_writeDisable() is not required because the Write Enable Latch (WEL) flag is cleared to 0 // i.e. to write disable state upon the following conditions: @@ -685,6 +818,9 @@ bool SPIFlash::eraseSector(uint32_t _addr) { // Page 0-127 --> Block 0; Page 128-255 --> Block 1;......Page 3968-4095 --> Block 31 // Variant A bool SPIFlash::eraseBlock32K(uint32_t _addr) { + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + #endif if (!_prep(ERASEFUNC, _addr)) { return false; } @@ -699,6 +835,9 @@ bool SPIFlash::eraseBlock32K(uint32_t _addr) { // i.e. to write disable state upon the following conditions: // Power-up, Write Disable, Page Program, Quad Page Program, Sector Erase, ``Block Erase``, Chip Erase, Write Status Register, // Erase Security Register and Program Security register + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros() - _spifuncruntime; + #endif return true; } @@ -710,6 +849,9 @@ bool SPIFlash::eraseBlock32K(uint32_t _addr) { // Page 0-255 --> Block 0; Page 256-511 --> Block 1;......Page 3840-4095 --> Block 15 // Variant A bool SPIFlash::eraseBlock64K(uint32_t _addr) { + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + #endif if (!_prep(ERASEFUNC, _addr)) { return false; } @@ -725,12 +867,17 @@ bool SPIFlash::eraseBlock64K(uint32_t _addr) { // i.e. to write disable state upon the following conditions: // Power-up, Write Disable, Page Program, Quad Page Program, Sector Erase, ``Block Erase``, Chip Erase, Write Status Register, // Erase Security Register and Program Security register - + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros() - _spifuncruntime; + #endif return true; } //Erases whole chip. Think twice before using. bool SPIFlash::eraseChip(void) { + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + #endif if(!_notBusy() || !_writeEnable()) { return false; } @@ -747,6 +894,9 @@ bool SPIFlash::eraseChip(void) { // Power-up, Write Disable, Page Program, Quad Page Program, Sector Erase, Block Erase, ``Chip Erase``, Write Status Register, // Erase Security Register and Program Security register _endSPI(); + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros() - _spifuncruntime; + #endif return true; } @@ -756,27 +906,37 @@ bool SPIFlash::eraseChip(void) { //Erase suspend is only allowed during Block/Sector erase. //Program suspend is only allowed during Page/Quad Page Program bool SPIFlash::suspendProg(void) { + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + #endif if(_notBusy()) { return false; } if(!_noSuspend()) { + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros() - _spifuncruntime; + #endif return true; } - else { - _beginSPI(SUSPEND); - _endSPI(); - _delay_us(20); - if(!_notBusy(50) || _noSuspend()) { //Max suspend Enable time according to datasheet - return false; - } - return true; + _beginSPI(SUSPEND); + _endSPI(); + _delay_us(20); + if(!_notBusy(50) || _noSuspend()) { //Max suspend Enable time according to datasheet + return false; } + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros() - _spifuncruntime; + #endif + return true; } //Resumes previously suspended Block Erase/Sector Erase/Page Program. bool SPIFlash::resumeProg(void) { + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + #endif if(!_notBusy() || _noSuspend()) { return false; } @@ -789,7 +949,10 @@ bool SPIFlash::resumeProg(void) { if(_notBusy(10) || !_noSuspend()) { return false; } - return true; + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros() - _spifuncruntime; + #endif + return true; } @@ -797,6 +960,9 @@ bool SPIFlash::resumeProg(void) { //Typical current consumption during power-down is 1mA with a maximum of 5mA. (Datasheet 7.4) //In powerDown() the chip will only respond to powerUp() bool SPIFlash::powerDown(void) { + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + #endif if(!_notBusy(20)) return false; @@ -805,32 +971,29 @@ bool SPIFlash::powerDown(void) { _delay_us(5); - _beginSPI(WRITEENABLE); - CHIP_DESELECT - if (_readStat1() & WRTEN) { - _endSPI(); - return false; - } - else { - - return true; - } + #ifdef RUNDIAGNOSTIC + bool _retVal = !_writeEnable(false); + _spifuncruntime = micros() - _spifuncruntime; + return _retVal; + #else + return !_writeEnable(false); + #endif } //Wakes chip from low power state. bool SPIFlash::powerUp(void) { + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + #endif _beginSPI(RELEASE); _endSPI(); _delay_us(3); //Max release enable time according to the Datasheet - _beginSPI(WRITEENABLE); - CHIP_DESELECT - if (_readStat1() & WRTEN) { - _endSPI(); - return true; - } - else { - - return false; - } + #ifdef RUNDIAGNOSTIC + bool _retVal = _writeEnable(false); + _spifuncruntime = micros() - _spifuncruntime; + return _retVal; + #else + return _writeEnable(false); + #endif } diff --git a/src/SPIFlash.h b/src/SPIFlash.h old mode 100755 new mode 100644 index bacc135..79beed6 --- a/src/SPIFlash.h +++ b/src/SPIFlash.h @@ -33,7 +33,7 @@ // // // Error codes will be generated and returned on functions // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -#define RUNDIAGNOSTIC // + #define RUNDIAGNOSTIC // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -44,8 +44,19 @@ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// //#define HIGHSPEED // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -#include -#include "defines.h" + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +// Comment out the code below to disable DMA mode on SAMD based // +// platforms // +// // +// Change the ZERO_SPISERCOM define below to use other SPI ports // +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +//#define ENABLEZERODMA // +//#define ZERO_SPISERCOM SERCOM4 // +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + #include + #include "defines.h" + #include #if defined (ARDUINO_ARCH_SAM) #include @@ -53,44 +64,55 @@ #include #endif - #include +#if defined (BOARD_RTL8195A) + #ifdef __cplusplus + extern "C" { + #endif + + #include "gpio_api.h" + #include "PinNames.h" + + #ifdef __cplusplus + } + #endif +#endif #if defined (ARDUINO_ARCH_SAM) || defined (ARDUINO_ARCH_SAMD) || defined (ARDUINO_ARCH_ESP8266) || defined (SIMBLEE) || defined (ARDUINO_ARCH_ESP32) || defined (BOARD_RTL8195A) // RTL8195A included - @boseji 02.03.17 - #define _delay_us(us) delayMicroseconds(us) + #define _delay_us(us) delayMicroseconds(us) #else - #include -#endif -// Includes specific to RTL8195A to access GPIO HAL - @boseji 02.03.17 -#if defined (BOARD_RTL8195A) -#ifdef __cplusplus -extern "C" { + #include #endif -#include "gpio_api.h" -#include "PinNames.h" +// Defines and variables specific to SAM architecture +#if defined (ARDUINO_ARCH_SAM) + #define CHIP_SELECT digitalWrite(csPin, LOW); + #define CHIP_DESELECT digitalWrite(csPin, HIGH); + #define xfer _dueSPITransfer + #define BEGIN_SPI _dueSPIBegin(); + extern char _end; + extern "C" char *sbrk(int i); + //char *ramstart=(char *)0x20070000; + //char *ramend=(char *)0x20088000; -#ifdef __cplusplus -} -#endif +// Specific access configuration for Chip select pin. Includes specific to RTL8195A to access GPIO HAL - @boseji 02.03.17 +#elif defined (BOARD_RTL8195A) + #ifdef __cplusplus + extern "C" { + #endif + + #include "gpio_api.h" + #include "PinNames.h" -#ifdef ARDUINO_ARCH_AVR - #define CHIP_SELECT *cs_port &= ~cs_mask; - #define CHIP_DESELECT *cs_port |= cs_mask; - #define xfer(n) SPI.transfer(n) - #define BEGIN_SPI SPI.begin(); + #ifdef __cplusplus + } #endif -#elif defined (ARDUINO_ARCH_SAM) - #define CHIP_SELECT digitalWrite(csPin, LOW); - #define CHIP_DESELECT digitalWrite(csPin, HIGH); - #define xfer _dueSPITransfer - #define BEGIN_SPI _dueSPIBegin(); -// Specific access configuration for Chip select pin - @boseji 02.03.17 -#elif defined (BOARD_RTL8195A) - #define CHIP_SELECT gpio_write(&csPin, 0); - #define CHIP_DESELECT gpio_write(&csPin, 1); - #define xfer(n) SPI.transfer(n) - #define BEGIN_SPI SPI.begin(); + #define CHIP_SELECT gpio_write(&csPin, 0); + #define CHIP_DESELECT gpio_write(&csPin, 1); + #define xfer(n) SPI.transfer(n) + #define BEGIN_SPI SPI.begin(); + +// Defines and variables specific to SAMD architecture #elif defined (ARDUINO_ARCH_SAMD) #define CHIP_SELECT digitalWrite(csPin, LOW); #define CHIP_DESELECT digitalWrite(csPin, HIGH); @@ -107,16 +129,9 @@ extern "C" { #define LIBSUBVER 0 #define BUGFIXVER 0 -#if defined (ARDUINO_ARCH_SAM) - extern char _end; - extern "C" char *sbrk(int i); - //char *ramstart=(char *)0x20070000; - //char *ramend=(char *)0x20088000; -#endif - class SPIFlash { public: - //----------------------------------------------Constructor----------------------------------------------- + //------------------------------------ Constructor ------------------------------------// //New Constructor to Accept the PinNames as a Chip select Parameter - @boseji 02.03.17 #if defined (ARDUINO_ARCH_SAMD) SPIFlash(uint8_t cs = CS, SPIClass *spiinterface=&SPI); @@ -125,7 +140,7 @@ class SPIFlash { #else SPIFlash(uint8_t cs = CS); #endif - //----------------------------------------Initial / Chip Functions----------------------------------------// + //----------------------------- Initial / Chip Functions ------------------------------// bool begin(void); void setClock(uint32_t clockSpeed); bool libver(uint8_t *b1, uint8_t *b2, uint8_t *b3); @@ -136,60 +151,60 @@ class SPIFlash { uint16_t sizeofStr(String &inputStr); uint32_t getCapacity(void); uint32_t getMaxPage(void); - //-------------------------------------------Write / Read Bytes-------------------------------------------// + float functionRunTime(void); + //-------------------------------- Write / Read Bytes ---------------------------------// bool writeByte(uint32_t _addr, uint8_t data, bool errorCheck = true); uint8_t readByte(uint32_t _addr, bool fastRead = false); - //----------------------------------------Write / Read Byte Arrays----------------------------------------// + //----------------------------- Write / Read Byte Arrays ------------------------------// bool writeByteArray(uint32_t _addr, uint8_t *data_buffer, uint16_t bufferSize, bool errorCheck = true); bool readByteArray(uint32_t _addr, uint8_t *data_buffer, uint16_t bufferSize, bool fastRead = false); - //-------------------------------------------Write / Read Chars-------------------------------------------// + //-------------------------------- Write / Read Chars ---------------------------------// bool writeChar(uint32_t _addr, int8_t data, bool errorCheck = true); int8_t readChar(uint32_t _addr, bool fastRead = false); - //----------------------------------------Write / Read Char Arrays----------------------------------------// + //------------------------------ Write / Read Char Arrays -----------------------------// bool writeCharArray(uint32_t _addr, char *data_buffer, uint16_t bufferSize, bool errorCheck = true); bool readCharArray(uint32_t _addr, char *data_buffer, uint16_t buffer_size, bool fastRead = false); - //------------------------------------------Write / Read Shorts------------------------------------------// + //-------------------------------- Write / Read Shorts --------------------------------// bool writeShort(uint32_t _addr, int16_t data, bool errorCheck = true); int16_t readShort(uint32_t _addr, bool fastRead = false); - //-------------------------------------------Write / Read Words-------------------------------------------// + //-------------------------------- Write / Read Words ---------------------------------// bool writeWord(uint32_t _addr, uint16_t data, bool errorCheck = true); uint16_t readWord(uint32_t _addr, bool fastRead = false); - //-------------------------------------------Write / Read Longs-------------------------------------------// + //-------------------------------- Write / Read Longs ---------------------------------// bool writeLong(uint32_t _addr, int32_t data, bool errorCheck = true); int32_t readLong(uint32_t _addr, bool fastRead = false); - //--------------------------------------Write / Read Unsigned Longs---------------------------------------// + //--------------------------- Write / Read Unsigned Longs -----------------------------// bool writeULong(uint32_t _addr, uint32_t data, bool errorCheck = true); uint32_t readULong(uint32_t _addr, bool fastRead = false); - //-------------------------------------------Write / Read Floats------------------------------------------// + //-------------------------------- Write / Read Floats --------------------------------// bool writeFloat(uint32_t _addr, float data, bool errorCheck = true); float readFloat(uint32_t _addr, bool fastRead = false); - //------------------------------------------Write / Read Strings------------------------------------------// - bool writeStr(uint32_t _addr, String &inputStr, bool errorCheck = true); - bool readStr(uint32_t _addr, String &outStr, bool fastRead = false); - //------------------------------------------Write / Read Anything-----------------------------------------// - template bool _write(uint32_t _addr, const T& value, uint8_t _sz, bool errorCheck); - template bool writeAnything(uint32_t _addr, const T& value, bool errorCheck = true); - template bool _read(uint32_t _addr, T& value, uint8_t _sz, bool fastRead = false); - template bool readAnything(uint32_t _addr, T& value, bool fastRead = false); - //--------------------------------------------Erase functions---------------------------------------------// + //-------------------------------- Write / Read Strings -------------------------------// + bool writeStr(uint32_t _addr, String &data, bool errorCheck = true); + bool readStr(uint32_t _addr, String &data, bool fastRead = false); + //------------------------------- Write / Read Anything -------------------------------// + + template bool writeAnything(uint32_t _addr, const T& data, bool errorCheck = true); + template bool readAnything(uint32_t _addr, T& data, bool fastRead = false); + //-------------------------------- Erase functions ------------------------------------// bool eraseSector(uint32_t _addr); bool eraseBlock32K(uint32_t _addr); bool eraseBlock64K(uint32_t _addr); bool eraseChip(void); - //---------------------------------------------Power functions--------------------------------------------// + //-------------------------------- Power functions ------------------------------------// bool suspendProg(void); bool resumeProg(void); bool powerDown(void); bool powerUp(void); - //-------------------------------------Public Arduino Due Functions-------------------------------------// + //-------------------------- Public Arduino Due Functions -----------------------------// //#if defined (ARDUINO_ARCH_SAM) //uint32_t freeRAM(void); //#endif - //-------------------------------------------Public variables-------------------------------------// + //------------------------------- Public variables ------------------------------------// private: #if defined (ARDUINO_ARCH_SAM) - //-------------------------------------Private Arduino Due Functions--------------------------------------// + //-------------------------- Private Arduino Due Functions ----------------------------// void _dmac_disable(void); void _dmac_enable(void); void _dmac_channel_disable(uint32_t ul_num); @@ -211,7 +226,7 @@ class SPIFlash { void _dueSPISendChar(char b); void _dueSPISendChar(const char* buf, size_t len); #endif - //----------------------------------------Private functions----------------------------------------// + //------------------------------- Private functions -----------------------------------// void _troubleshoot(uint8_t _code, bool printoverride = false); void _printErrorCode(void); void _printSupportLink(void); @@ -222,7 +237,7 @@ class SPIFlash { bool _noSuspend(void); bool _notBusy(uint32_t timeout = BUSY_TIMEOUT); bool _notPrevWritten(uint32_t _addr, uint32_t size = 1); - bool _writeEnable(void); + bool _writeEnable(bool _troubleshootEnable = true); bool _writeDisable(void); bool _getJedecId(void); bool _getManId(uint8_t *b1, uint8_t *b2); @@ -230,14 +245,16 @@ class SPIFlash { bool _chipID(void); bool _transferAddress(void); bool _addressCheck(uint32_t _addr, uint32_t size = 1); - uint8_t _nextByte(uint8_t data = NULLBYTE); + uint8_t _nextByte(char IOType, uint8_t data = NULLBYTE); uint16_t _nextInt(uint16_t = NULLINT); void _nextBuf(uint8_t opcode, uint8_t *data_buffer, uint32_t size); uint8_t _readStat1(void); uint8_t _readStat2(void); + template bool _write(uint32_t _addr, const T& value, size_t _sz, bool errorCheck); + template bool _read(uint32_t _addr, T& value, size_t _sz, bool fastRead = false); template bool _writeErrorCheck(uint32_t _addr, const T& value); - template bool _writeErrorCheck(uint32_t _addr, const T& value, uint8_t _sz); - //-------------------------------------------Private variables------------------------------------------// + template bool _writeErrorCheck(uint32_t _addr, const T& value, size_t _sz); + //-------------------------------- Private variables ----------------------------------// #ifdef SPI_HAS_TRANSACTION SPISettings _settings; #endif @@ -252,6 +269,9 @@ class SPIFlash { volatile uint8_t *cs_port; bool pageOverflow, SPIBusState; uint8_t cs_mask, errorcode, stat1, _SPCR, _SPSR, _a0, _a1, _a2; + char READ = 'R'; + char WRITE = 'W'; + float _spifuncruntime = 0; struct chipID { bool supported; uint8_t manufacturerID; @@ -263,13 +283,17 @@ class SPIFlash { }; chipID _chip; uint32_t currentAddress, _currentAddress = 0; - const uint8_t _capID[12] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x43, 0x4B}; - const uint32_t _memSize[12] = {64L * K, 128L * K, 256L * K, 512L * K, 1L * M, 2L * M, 4L * M, 8L * M, - 16L * M, 32L * M, 8L * M, 8L * M}; - const uint32_t _eraseTime[12] = {1L * S, 2L * S, 2L * S, 4L * S, 6L * S, 10L * S, 15L * S, 100L * S, 200L * S, 400L * S, 50L * S, 50L * S}; //Erase time in milliseconds + const uint8_t _capID[12] = + {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x43, 0x4B}; + + const uint32_t _memSize[12] = + {64L * K, 128L * K, 256L * K, 512L * K, 1L * M, 2L * M, 4L * M, 8L * M, 6L * M, 32L * M, 8L * M, 8L * M}; + + const uint32_t _eraseTime[12] = + {1L * S, 2L * S, 2L * S, 4L * S, 6L * S, 10L * S, 15L * S, 100L * S, 200L * S, 400L * S, 50L * S, 50L * S}; //Erase time in milliseconds }; -//----------------------------------------Public Templates----------------------------------------// +//--------------------------------- Public Templates ------------------------------------// // Writes any type of data to a specific location in the flash memory. // Takes three arguments - @@ -278,9 +302,8 @@ class SPIFlash { // 3. 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) -template bool SPIFlash::writeAnything(uint32_t _addr, const T& value, bool errorCheck) { - uint8_t _sizeofvalue = sizeof(value); - return _write(_addr, value, _sizeofvalue, errorCheck); +template bool SPIFlash::writeAnything(uint32_t _addr, const T& data, bool errorCheck) { + return _write(_addr, data, sizeof(data), errorCheck); } // Reads any type of data from a specific location in the flash memory. @@ -288,12 +311,11 @@ template bool SPIFlash::writeAnything(uint32_t _addr, const T& value, // 1. _addr --> Any address from 0 to maxAddress // 2. T& value --> Variable to return data into // 3. fastRead --> defaults to false - executes _beginFastRead() if set to true -template bool SPIFlash::readAnything(uint32_t _addr, T& value, bool fastRead) { - uint8_t _sizeofvalue = sizeof(value); - return _read(_addr, value, _sizeofvalue, fastRead); +template bool SPIFlash::readAnything(uint32_t _addr, T& data, bool fastRead) { + return _read(_addr, data, sizeof(data), fastRead); } -//----------------------------------------Private Templates---------------------------------------// +//---------------------------------- Private Templates ----------------------------------// // Checks for errors in writing data to flash memory. // Takes three arguments - @@ -301,17 +323,17 @@ template bool SPIFlash::readAnything(uint32_t _addr, T& value, bool fa // 2. const T& value --> Variable with the data to be error checked // 3. _sz --> Size of the data variable to be error checked, in bytes (1 byte = 8 bits) // Private template to check for errors in writing to flash memory -template bool SPIFlash::_writeErrorCheck(uint32_t _addr, const T& value, uint8_t _sz) { +template bool SPIFlash::_writeErrorCheck(uint32_t _addr, const T& value, size_t _sz) { if (!_notBusy()) { return false; } _currentAddress = _addr; const uint8_t* p = (const uint8_t*)(const void*)&value; CHIP_SELECT - _nextByte(READDATA); + _nextByte(WRITE, READDATA); _transferAddress(); for (uint16_t i = 0; i < _sz; i++) { - if (*p++ != _nextByte()) { + if (*p++ != _nextByte(READ)) { _troubleshoot(ERRORCHKFAIL); _endSPI(); return false; @@ -330,7 +352,7 @@ template bool SPIFlash::_writeErrorCheck(uint32_t _addr, const T& valu // WARNING: You can only write to previously erased memory locations (see datasheet). // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) -template bool SPIFlash::_write(uint32_t _addr, const T& value, uint8_t _sz, bool errorCheck) { +template bool SPIFlash::_write(uint32_t _addr, const T& value, size_t _sz, bool errorCheck) { if (!_prep(PAGEPROG, _addr, _sz)) { return false; } @@ -340,11 +362,11 @@ template bool SPIFlash::_write(uint32_t _addr, const T& value, uint8_t _startSPIBus(); } CHIP_SELECT - _nextByte(PAGEPROG); + _nextByte(WRITE, PAGEPROG); _transferAddress(); //If data is only one byte (8 bits) long if (_sz == 0x01) { - _nextByte(*p); + _nextByte(WRITE, *p); CHIP_DESELECT } else { //If data is longer than one byte (8 bits) @@ -353,7 +375,7 @@ template bool SPIFlash::_write(uint32_t _addr, const T& value, uint8_t if (maxBytes > length) { for (uint16_t i = 0; i < length; ++i) { - _nextByte(*p++); + _nextByte(WRITE, *p++); } CHIP_DESELECT } @@ -365,7 +387,7 @@ template bool SPIFlash::_write(uint32_t _addr, const T& value, uint8_t writeBufSz = (length<=maxBytes) ? length : maxBytes; for (uint16_t i = 0; i < writeBufSz; ++i) { - _nextByte(*p++); + _nextByte(WRITE, *p++); } CHIP_DESELECT _currentAddress += writeBufSz; @@ -393,19 +415,19 @@ template bool SPIFlash::_write(uint32_t _addr, const T& value, uint8_t // 2. T& value --> Variable to return data into // 3. _sz --> Size of the variable in bytes (1 byte = 8 bits) // 4. fastRead --> defaults to false - executes _beginFastRead() if set to true -template bool SPIFlash::_read(uint32_t _addr, T& value, uint8_t _sz, bool fastRead) { +template bool SPIFlash::_read(uint32_t _addr, T& value, size_t _sz, bool fastRead) { if (_prep(READDATA, _addr, _sz)) { uint8_t* p = (uint8_t*)(void*)&value; CHIP_SELECT if (fastRead) { - _nextByte(FASTREAD); + _nextByte(WRITE, FASTREAD); } else { - _nextByte(READDATA); + _nextByte(WRITE, READDATA); } _transferAddress(); for (uint16_t i = 0; i < _sz; i++) { - *p++ =_nextByte(); + *p++ =_nextByte(READ); } _endSPI(); return true; diff --git a/src/defines.h b/src/defines.h old mode 100755 new mode 100644 index 46ee372..2bdec94 --- a/src/defines.h +++ b/src/defines.h @@ -107,12 +107,9 @@ #define BUSY 0x01 #if defined (ARDUINO_ARCH_ESP32) -#define SPI_CLK 20000000 -/*#elif defined (ARDUINO_ARCH_SAMD) -#define SPI_CLK 8000000*/ +#define SPI_CLK 20000000 //Hz equivalent of 20MHz #else -#define SPI_CLK 104000000 //Hex equivalent of 104MHz -//#define SPI_CLK 4000000 //Hex equivalent of 104MHz +#define SPI_CLK 104000000 //Hz equivalent of 104MHz #endif #define WRTEN 0x02 #define SUS 0x80 @@ -131,6 +128,8 @@ #define ERASEFUNC 0xEF #if defined (SIMBLEE) #define BUSY_TIMEOUT 100L +#elif defined ENABLEZERODMA +#define BUSY_TIMEOUT 3500L #else #define BUSY_TIMEOUT 1000L #endif diff --git a/src/troubleshoot.cpp b/src/troubleshoot.cpp old mode 100755 new mode 100644 From 51fb74b20d72578cad8ae5f9bb639c6453f256bc Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Sat, 19 Aug 2017 00:44:07 +1000 Subject: [PATCH 22/34] Fixed formatting and code comments for IO functions. Fixed issue with DMASAMD.h to only let the code show itself to the compiler when running on the SAMD platform. Fixed a constructor bug that prevented compilation on the Simblee --- library.properties | 2 +- src/DMASAMD.h | 3 +- src/FLASHIO.cpp | 3 - src/SPIFlash.cpp | 379 +++++++++++++-------------------------------- src/SPIFlash.h | 11 +- 5 files changed, 117 insertions(+), 281 deletions(-) diff --git a/library.properties b/library.properties index dcf86fc..d3ad686 100644 --- a/library.properties +++ b/library.properties @@ -6,5 +6,5 @@ sentence=Winbond SPI flash library for Arduino. paragraph=This library enables read, write, erase and power functions on the following Winbond NOR Flash chips - W25X05CL, W25X10BV, W25X20BV, W25X40BV, W25Q80BV, W25Q16BV, W25Q32BV, W25Q64BV & W25Q128BV. All other Winbond flash chips can also be used with this library from v2.6.0 onwards. Refer to change log for further information about this release. category=Data Storage url=https://github.com/Marzogh/SPIFlash -architectures=avr,sam,samd,esp8266,esp32,simblee,ameba +architectures=avr,sam,samd,esp8266,esp32,Simblee,ameba includes=SPIFlash.h diff --git a/src/DMASAMD.h b/src/DMASAMD.h index b0d6997..a319555 100644 --- a/src/DMASAMD.h +++ b/src/DMASAMD.h @@ -4,7 +4,7 @@ // packages/arduino/tools/CMSIS/4.0.0-atmel/Device/ATMEL/samd21/include/component/dmac.h // http://asf.atmel.com/docs/3.16.0/samd21/html/asfdoc_sam0_sercom_spi_dma_use_case.html // assume normal SPI setup, then we take over with DMA - +#ifdef ARDUINO_ARCH_SAMD #include #define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX) @@ -137,3 +137,4 @@ void spi_transfer(void *txdata, void *rxdata, size_t n) { xtype = DoTXRX; spi_xfr(txdata,rxdata,n); } +#endif diff --git a/src/FLASHIO.cpp b/src/FLASHIO.cpp index 24b699b..211ef9e 100644 --- a/src/FLASHIO.cpp +++ b/src/FLASHIO.cpp @@ -69,9 +69,6 @@ bool SPIFlash::_prep(uint8_t opcode, uint32_t _addr, uint32_t size) { // Transfer Address. bool SPIFlash::_transferAddress(void) { - /*_nextByte(_currentAddress >> 16); - _nextByte(_currentAddress >> 8); - _nextByte(_currentAddress);*/ _nextByte(WRITE, Higher(_currentAddress)); _nextByte(WRITE, Hi(_currentAddress)); _nextByte(WRITE, Lo(_currentAddress)); diff --git a/src/SPIFlash.cpp b/src/SPIFlash.cpp index dc9883e..33391cb 100644 --- a/src/SPIFlash.cpp +++ b/src/SPIFlash.cpp @@ -55,7 +55,6 @@ SPIFlash::SPIFlash(PinName cs) { #else SPIFlash::SPIFlash(uint8_t cs) { csPin = cs; - cs_mask = digitalPinToBitMask(csPin); pinMode(csPin, OUTPUT); CHIP_DESELECT } @@ -164,15 +163,9 @@ uint16_t SPIFlash::sizeofStr(String &inputStr) { } // Reads a byte of data from a specific location in a page. -// Has two variants: -// A. Takes two arguments - -// 1. _addr --> Any address from 0 to capacity -// 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. fastRead --> defaults to false - executes _beginFastRead() if set to true -// Variant A +// Takes two arguments - +// 1. _addr --> Any address from 0 to capacity +// 2. fastRead --> defaults to false - executes _beginFastRead() if set to true uint8_t SPIFlash::readByte(uint32_t _addr, bool fastRead) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); @@ -186,15 +179,9 @@ uint8_t SPIFlash::readByte(uint32_t _addr, bool fastRead) { } // Reads a char of data from a specific location in a page. -// Has two variants: -// A. Takes two arguments - -// 1. _addr --> Any address from 0 to capacity -// 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. fastRead --> defaults to false - executes _beginFastRead() if set to true -// Variant A +// Takes two arguments - +// 1. _addr --> Any address from 0 to capacity +// 2. fastRead --> defaults to false - executes _beginFastRead() if set to true int8_t SPIFlash::readChar(uint32_t _addr, bool fastRead) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); @@ -207,18 +194,14 @@ int8_t SPIFlash::readChar(uint32_t _addr, bool fastRead) { return data; } -// Reads an array of bytes starting from a specific location in a page.// Has two variants: -// A. Takes three arguments -// 1. _addr --> Any address from 0 to capacity -// 2. data_buffer --> The array of bytes to be read from the flash memory - starting at the address indicated -// 3. fastRead --> defaults to false - executes _beginFastRead() if set to true -// B. Takes four arguments -// 1. page --> Any page number from 0 to maxPage -// 2. offset --> Any offset within the page - from 0 to 255 -// 3. data_buffer --> The array of bytes to be read from the flash memory - starting at the offset on the page indicated -// 4. fastRead --> defaults to false - executes _beginFastRead() if set to true -// Variant A -bool SPIFlash::readByteArray(uint32_t _addr, uint8_t *data_buffer, uint16_t bufferSize, bool fastRead) { +// Reads an array of bytes starting from a specific location in a page. +// Takes four arguments +// 1. _addr --> Any address from 0 to capacity +// 2. data_buffer --> The array of bytes to be read from the flash memory - starting at the address indicated +// 3. bufferSize --> The size of the buffer - in number of bytes. +// 4. fastRead --> defaults to false - executes _beginFastRead() if set to true + +bool SPIFlash::readByteArray(uint32_t _addr, uint8_t *data_buffer, size_t bufferSize, bool fastRead) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); #endif @@ -239,18 +222,13 @@ bool SPIFlash::readByteArray(uint32_t _addr, uint8_t *data_buffer, uint16_t buf return true; } -// Reads an array of chars starting from a specific location in a page.// Has two variants: -// A. Takes three arguments -// 1. _addr --> Any address from 0 to capacity -// 2. data_buffer --> The array of bytes to be read from the flash memory - starting at the address indicated -// 3. fastRead --> defaults to false - executes _beginFastRead() if set to true -// B. Takes four arguments -// 1. page --> Any page number from 0 to maxPage -// 2. offset --> Any offset within the page - from 0 to 255 -// 3. data_buffer --> The array of bytes to be read from the flash memory - starting at the offset on the page indicated -// 4. fastRead --> defaults to false - executes _beginFastRead() if set to true -// Variant A -bool SPIFlash::readCharArray(uint32_t _addr, char *data_buffer, uint16_t bufferSize, bool fastRead) { +// Reads an array of chars starting from a specific location in a page.. +// Takes four arguments +// 1. _addr --> Any address from 0 to capacity +// 2. data_buffer --> The array of bytes to be read from the flash memory - starting at the address indicated +// 3. bufferSize --> The size of the buffer - in number of bytes. +// 4. fastRead --> defaults to false - executes _beginFastRead() if set to true +bool SPIFlash::readCharArray(uint32_t _addr, char *data_buffer, size_t bufferSize, bool fastRead) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); #endif @@ -272,15 +250,9 @@ bool SPIFlash::readCharArray(uint32_t _addr, char *data_buffer, uint16_t buffer } // Reads an unsigned int of data from a specific location in a page. -// Has two variants: -// A. Takes two arguments - -// 1. _addr --> Any address from 0 to capacity -// 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. fastRead --> defaults to false - executes _beginFastRead() if set to true -// Variant A +// Takes two arguments - +// 1. _addr --> Any address from 0 to capacity +// 2. fastRead --> defaults to false - executes _beginFastRead() if set to true uint16_t SPIFlash::readWord(uint32_t _addr, bool fastRead) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); @@ -294,15 +266,9 @@ uint16_t SPIFlash::readWord(uint32_t _addr, bool fastRead) { } // Reads a signed int of data from a specific location in a page. -// Has two variants: -// A. Takes two arguments - -// 1. _addr --> Any address from 0 to capacity -// 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. fastRead --> defaults to false - executes _beginFastRead() if set to true -// Variant A +// Takes two arguments - +// 1. _addr --> Any address from 0 to capacity +// 2. fastRead --> defaults to false - executes _beginFastRead() if set to true int16_t SPIFlash::readShort(uint32_t _addr, bool fastRead) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); @@ -316,15 +282,9 @@ int16_t SPIFlash::readShort(uint32_t _addr, bool fastRead) { } // Reads an unsigned long of data from a specific location in a page. -// Has two variants: -// A. Takes two arguments - -// 1. _addr --> Any _addr from 0 to capacity -// 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. fastRead --> defaults to false - executes _beginFastRead() if set to true -// Variant A +// Takes two arguments - +// 1. _addr --> Any address from 0 to capacity +// 2. fastRead --> defaults to false - executes _beginFastRead() if set to true uint32_t SPIFlash::readULong(uint32_t _addr, bool fastRead) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); @@ -338,15 +298,9 @@ uint32_t SPIFlash::readULong(uint32_t _addr, bool fastRead) { } // Reads a signed long of data from a specific location in a page. -// Has two variants: -// A. Takes two arguments - -// 1. _addr --> Any _addr from 0 to capacity -// 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. fastRead --> defaults to false - executes _beginFastRead() if set to true -// Variant A +// Takes two arguments - +// 1. _addr --> Any address from 0 to capacity +// 2. fastRead --> defaults to false - executes _beginFastRead() if set to true int32_t SPIFlash::readLong(uint32_t _addr, bool fastRead) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); @@ -359,16 +313,10 @@ int32_t SPIFlash::readLong(uint32_t _addr, bool fastRead) { return data; } -// Reads a signed long of data from a specific location in a page. -// Has two variants: -// A. Takes two arguments - -// 1. _addr --> Any address from 0 to capacity -// 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. fastRead --> defaults to false - executes _beginFastRead() if set to true -// Variant A +// Reads a float of data from a specific location in a page. +// Takes two arguments - +// 1. _addr --> Any address from 0 to capacity +// 2. fastRead --> defaults to false - executes _beginFastRead() if set to true float SPIFlash::readFloat(uint32_t _addr, bool fastRead) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); @@ -382,19 +330,10 @@ float SPIFlash::readFloat(uint32_t _addr, bool fastRead) { } // Reads a string from a specific location on a page. -// Has two variants: -// A. Takes three arguments -// 1. _addr --> Any address from 0 to capacity -// 2. outputString --> String variable to write the output to -// 3. fastRead --> defaults to false - executes _beginFastRead() if set to true -// B. Takes four arguments -// 1. page --> Any page number from 0 to maxPage -// 2. offset --> Any offset within the page - from 0 to 255 -// 3. outputString --> String variable to write the output to -// 4. fastRead --> defaults to false - executes _beginFastRead() if set to true -// This function first reads a short from the address to figure out the size of the String object stored and -// then reads the String object data -// Variant A +// Takes three arguments +// 1. _addr --> Any address from 0 to capacity +// 2. outputString --> String variable to write the output to +// 3. fastRead --> defaults to false - executes _beginFastRead() if set to true bool SPIFlash::readStr(uint32_t _addr, String &data, bool fastRead) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); @@ -407,19 +346,12 @@ bool SPIFlash::readStr(uint32_t _addr, String &data, bool fastRead) { } // Writes a byte of data to a specific location in a page. -// Has two variants: -// A. Takes three arguments - -// 1. _addr --> Any address - from 0 to capacity -// 2. data --> One byte of data to be written to a particular location on a page -// 3. errorCheck --> Turned on by default. Checks for writing errors -// B. Takes four arguments - -// 1. page --> Any page number from 0 to maxPage -// 2. offset --> Any offset within the page - from 0 to 255 -// 3. data --> One byte of data to be written to a particular location on a page -// 4. errorCheck --> Turned on by default. Checks for writing errors +// Takes three arguments - +// 1. _addr --> Any address - from 0 to capacity +// 2. data --> One byte to be written to a particular location on a page +// 3. 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 +// Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) bool SPIFlash::writeByte(uint32_t _addr, uint8_t data, bool errorCheck) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); @@ -432,19 +364,12 @@ bool SPIFlash::writeByte(uint32_t _addr, uint8_t data, bool errorCheck) { } // Writes a char of data to a specific location in a page. -// Has two variants: -// A. Takes three arguments - -// 1. _addr --> Any address - from 0 to capacity -// 2. data --> One char of data to be written to a particular location on a page -// 3. errorCheck --> Turned on by default. Checks for writing errors -// B. Takes four arguments - -// 1. page --> Any page number from 0 to maxPage -// 2. offset --> Any offset within the page - from 0 to 255 -// 3. data --> One char of data to be written to a particular location on a page -// 4. errorCheck --> Turned on by default. Checks for writing errors +// Takes three arguments - +// 1. _addr --> Any address - from 0 to capacity +// 2. data --> One char to be written to a particular location on a page +// 3. 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 +// Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) bool SPIFlash::writeChar(uint32_t _addr, int8_t data, bool errorCheck) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); @@ -457,20 +382,14 @@ bool SPIFlash::writeChar(uint32_t _addr, int8_t data, bool errorCheck) { } // Writes an array of bytes starting from a specific location in a page. -// Has two variants: -// A. Takes three arguments - -// 1. _addr --> Any address - from 0 to capacity -// 2. data --> An array of bytes to be written to a particular location on a page -// 3. errorCheck --> Turned on by default. Checks for writing errors -// B. Takes four arguments - -// 1. page --> Any page number from 0 to maxPage -// 2. offset --> Any offset within the page - from 0 to 255 -// 3. data --> An array of bytes to be written to a particular location on a page -// 4. errorCheck --> Turned on by default. Checks for writing errors +// Takes four arguments - +// 1. _addr --> Any address - from 0 to capacity +// 2. data_buffer --> The pointer to the array of bytes be written to a particular location on a page +// 3. bufferSize --> Size of the array of bytes - in number of bytes +// 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 -bool SPIFlash::writeByteArray(uint32_t _addr, uint8_t *data_buffer, uint16_t bufferSize, bool errorCheck) { +// Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) +bool SPIFlash::writeByteArray(uint32_t _addr, uint8_t *data_buffer, size_t bufferSize, bool errorCheck) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); #endif @@ -543,20 +462,14 @@ bool SPIFlash::writeByteArray(uint32_t _addr, uint8_t *data_buffer, uint16_t buf } // Writes an array of bytes starting from a specific location in a page. -// Has two variants: -// A. Takes three arguments - -// 1. _addr --> Any address - from 0 to capacity -// 2. data --> An array of chars to be written to a particular location on a page -// 3. errorCheck --> Turned on by default. Checks for writing errors -// B. Takes four arguments - -// 1. page --> Any page number from 0 to maxPage -// 2. offset --> Any offset within the page - from 0 to 255 -// 3. data --> An array of chars to be written to a particular location on a page -// 4. errorCheck --> Turned on by default. Checks for writing errors +// Takes four arguments - +// 1. _addr --> Any address - from 0 to capacity +// 2. data_buffer --> The pointer to the array of chars be written to a particular location on a page +// 3. bufferSize --> Size of the array of chars - in number of bytes +// 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 -bool SPIFlash::writeCharArray(uint32_t _addr, char *data_buffer, uint16_t bufferSize, bool errorCheck) { +// Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) +bool SPIFlash::writeCharArray(uint32_t _addr, char *data_buffer, size_t bufferSize, bool errorCheck) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); #endif @@ -629,19 +542,12 @@ bool SPIFlash::writeCharArray(uint32_t _addr, char *data_buffer, uint16_t buffer } // Writes an unsigned int as two bytes starting from a specific location in a page. -// Has two variants: -// A. Takes three arguments - -// 1. _addr --> Any address - from 0 to capacity -// 2. data --> One unsigned int of data to be written to a particular location on a page -// 3. errorCheck --> Turned on by default. Checks for writing errors -// B. Takes four arguments - -// 1. page --> Any page number from 0 to maxPage -// 2. offset --> Any offset within the page - from 0 to 255 -// 3. data --> One unsigned int of data to be written to a particular location on a page -// 4. errorCheck --> Turned on by default. Checks for writing errors +// Takes three arguments - +// 1. _addr --> Any address - from 0 to capacity +// 2. data --> One word to be written to a particular location on a page +// 3. 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 +// Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) bool SPIFlash::writeWord(uint32_t _addr, uint16_t data, bool errorCheck) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); @@ -653,20 +559,13 @@ bool SPIFlash::writeWord(uint32_t _addr, uint16_t data, bool errorCheck) { #endif } -// Writes a signed int as two bytes starting from a specific location in a page. -// Has two variants: -// A. Takes three arguments - -// 1. _addr --> Any address - from 0 to capacity -// 2. data --> One signed int of data to be written to a particular location on a page -// 3. errorCheck --> Turned on by default. Checks for writing errors -// B. Takes four arguments - -// 1. page --> Any page number from 0 to maxPage -// 2. offset --> Any offset within the page - from 0 to 255 -// 3. data --> One signed int of data to be written to a particular location on a page -// 4. errorCheck --> Turned on by default. Checks for writing errors +// Writes a signed int as two bytes starting from a specific location in a page +// Takes three arguments - +// 1. _addr --> Any address - from 0 to capacity +// 2. data --> One short to be written to a particular location on a page +// 3. 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 +// Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) bool SPIFlash::writeShort(uint32_t _addr, int16_t data, bool errorCheck) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); @@ -679,19 +578,12 @@ bool SPIFlash::writeShort(uint32_t _addr, int16_t data, bool errorCheck) { } // Writes an unsigned long as four bytes starting from a specific location in a page. -// Has two variants: -// A. Takes three arguments - -// 1. _addr --> Any address - from 0 to capacity -// 2. data --> One unsigned long of data to be written to a particular location on a page -// 3. errorCheck --> Turned on by default. Checks for writing errors -// B. Takes four arguments - -// 1. page --> Any page number from 0 to maxPage -// 2. offset --> Any offset within the page - from 0 to 255 -// 3. data --> One unsigned long of data to be written to a particular location on a page -// 4. errorCheck --> Turned on by default. Checks for writing errors +// Takes three arguments - +// 1. _addr --> Any address - from 0 to capacity +// 2. data --> One unsigned long to be written to a particular location on a page +// 3. 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 +// Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) bool SPIFlash::writeULong(uint32_t _addr, uint32_t data, bool errorCheck) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); @@ -703,20 +595,13 @@ bool SPIFlash::writeULong(uint32_t _addr, uint32_t data, bool errorCheck) { #endif } -// Writes a signed long as four bytes starting from a specific location in a page. -// Has two variants: -// A. Takes three arguments - -// 1. _addr --> Any address - from 0 to capacity -// 2. data --> One signed long of data to be written to a particular location on a page -// 3. errorCheck --> Turned on by default. Checks for writing errors -// B. Takes four arguments - -// 1. page --> Any page number from 0 to maxPage -// 2. offset --> Any offset within the page - from 0 to 255 -// 3. data --> One signed long of data to be written to a particular location on a page -// 4. errorCheck --> Turned on by default. Checks for writing errors +// Writes a signed long as four bytes starting from a specific location in a page +// Takes three arguments - +// 1. _addr --> Any address - from 0 to capacity +// 2. data --> One signed long to be written to a particular location on a page +// 3. 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 +// Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) bool SPIFlash::writeLong(uint32_t _addr, int32_t data, bool errorCheck) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); @@ -728,20 +613,13 @@ bool SPIFlash::writeLong(uint32_t _addr, int32_t data, bool errorCheck) { #endif } -// Writes a float as four bytes starting from a specific location in a page. -// Has two variants: -// A. Takes three arguments - -// 1. _addr --> Any address - from 0 to capacity -// 2. data --> One float of data to be written to a particular location on a page -// 3. errorCheck --> Turned on by default. Checks for writing errors -// B. Takes four arguments - -// 1. page --> Any page number from 0 to maxPage -// 2. offset --> Any offset within the page - from 0 to 255 -// 3. data --> One float of data to be written to a particular location on a page -// 4. errorCheck --> Turned on by default. Checks for writing errors +// Writes a float as four bytes starting from a specific location in a page +// Takes three arguments - +// 1. _addr --> Any address - from 0 to capacity +// 2. data --> One float to be written to a particular location on a page +// 3. 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 +// Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) bool SPIFlash::writeFloat(uint32_t _addr, float data, bool errorCheck) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); @@ -753,22 +631,13 @@ bool SPIFlash::writeFloat(uint32_t _addr, float data, bool errorCheck) { #endif } -// Reads a string from a specific location on a page. -// Has two variants: -// A. Takes two arguments - -// 1. _addr --> Any address from 0 to capacity -// 2. inputString --> String variable to write the data from -// 3. errorCheck --> Turned on by default. Checks for writing errors -// B. Takes four arguments - -// 1. page --> Any page number from 0 to maxPage -// 2. offset --> Any offset within the page - from 0 to 255 -// 3. inputString --> String variable to write the data from -// 4. errorCheck --> Turned on by default. Checks for writing errors +// Writes a string to a specific location on a page +// Takes three arguments - +// 1. _addr --> Any address - from 0 to capacity +// 2. data --> One String to be written to a particular location on a page +// 3. 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) -// This function first writes the size of the string as an unsigned int to the address to figure out the size of the String object stored and -// then writes the String object data. Therefore it takes up two bytes more than the size of the String itself. -// Variant A +// Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) bool SPIFlash::writeStr(uint32_t _addr, String &data, bool errorCheck) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); @@ -780,12 +649,8 @@ bool SPIFlash::writeStr(uint32_t _addr, String &data, bool errorCheck) { #endif } -//Erases one 4k sector. Has two variants: -// A. Takes the address as the argument and erases the sector containing the address. -// B. Takes page to be erased as the argument and erases the sector containing the page. -// The sectors are numbered 0 - 255 containing 16 pages each. -// Page 0-15 --> Sector 0; Page 16-31 --> Sector 1;......Page 4080-4095 --> Sector 255 -// Variant A +// Erases one 4k sector. +// Takes an address as the argument and erases the block containing the address. bool SPIFlash::eraseSector(uint32_t _addr) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); @@ -803,20 +668,11 @@ bool SPIFlash::eraseSector(uint32_t _addr) { _spifuncruntime = micros() - _spifuncruntime; #endif - //_writeDisable(); //_writeDisable() is not required because the Write Enable Latch (WEL) flag is cleared to 0 - // i.e. to write disable state upon the following conditions: - // Power-up, Write Disable, Page Program, Quad Page Program, ``Sector Erase``, Block Erase, Chip Erase, Write Status Register, - // Erase Security Register and Program Security register - return true; } -//Erases one 32k block. Has two variants: -// A. Takes the address as the argument and erases the block containing the address. -// B. Takes page to be erased as the argument and erases the block containing the page. -// The blocks are numbered 0 - 31 containing 128 pages each. -// Page 0-127 --> Block 0; Page 128-255 --> Block 1;......Page 3968-4095 --> Block 31 -// Variant A +// Erases one 32k block. +// Takes an address as the argument and erases the block containing the address. bool SPIFlash::eraseBlock32K(uint32_t _addr) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); @@ -830,11 +686,6 @@ bool SPIFlash::eraseBlock32K(uint32_t _addr) { if(!_notBusy(1*S)) { return false; //Datasheet says erasing a sector takes 400ms max } - - //_writeDisable(); //_writeDisable() is not required because the Write Enable Latch (WEL) flag is cleared to 0 - // i.e. to write disable state upon the following conditions: - // Power-up, Write Disable, Page Program, Quad Page Program, Sector Erase, ``Block Erase``, Chip Erase, Write Status Register, - // Erase Security Register and Program Security register #ifdef RUNDIAGNOSTIC _spifuncruntime = micros() - _spifuncruntime; #endif @@ -842,12 +693,8 @@ bool SPIFlash::eraseBlock32K(uint32_t _addr) { return true; } -//Erases one 64k block. Has two variants: -// A. Takes the address as the argument and erases the block containing the address. -// B. Takes page to be erased as the argument and erases the block containing the page. -// The blocks are numbered 0 - 15 containing 256 pages each. -// Page 0-255 --> Block 0; Page 256-511 --> Block 1;......Page 3840-4095 --> Block 15 -// Variant A +// Erases one 64k block. +// Takes an address as the argument and erases the block containing the address. bool SPIFlash::eraseBlock64K(uint32_t _addr) { #ifdef RUNDIAGNOSTIC _spifuncruntime = micros(); @@ -862,11 +709,6 @@ bool SPIFlash::eraseBlock64K(uint32_t _addr) { if(!_notBusy(1200L)) { return false; //Datasheet says erasing a sector takes 400ms max } - - //_writeDisable(); //_writeDisable() is not required because the Write Enable Latch (WEL) flag is cleared to 0 - // i.e. to write disable state upon the following conditions: - // Power-up, Write Disable, Page Program, Quad Page Program, Sector Erase, ``Block Erase``, Chip Erase, Write Status Register, - // Erase Security Register and Program Security register #ifdef RUNDIAGNOSTIC _spifuncruntime = micros() - _spifuncruntime; #endif @@ -888,11 +730,6 @@ bool SPIFlash::eraseChip(void) { while(_readStat1() & BUSY) { _delay_us(30000L); } - - //_writeDisable(); //_writeDisable() is not required because the Write Enable Latch (WEL) flag is cleared to 0 - // i.e. to write disable state upon the following conditions: - // Power-up, Write Disable, Page Program, Quad Page Program, Sector Erase, Block Erase, ``Chip Erase``, Write Status Register, - // Erase Security Register and Program Security register _endSPI(); #ifdef RUNDIAGNOSTIC _spifuncruntime = micros() - _spifuncruntime; @@ -923,7 +760,7 @@ bool SPIFlash::suspendProg(void) { _beginSPI(SUSPEND); _endSPI(); _delay_us(20); - if(!_notBusy(50) || _noSuspend()) { //Max suspend Enable time according to datasheet + if(!_notBusy(50) || _noSuspend()) { return false; } #ifdef RUNDIAGNOSTIC @@ -957,7 +794,6 @@ bool SPIFlash::resumeProg(void) { } //Puts device in low power state. Good for battery powered operations. -//Typical current consumption during power-down is 1mA with a maximum of 5mA. (Datasheet 7.4) //In powerDown() the chip will only respond to powerUp() bool SPIFlash::powerDown(void) { #ifdef RUNDIAGNOSTIC @@ -997,3 +833,6 @@ bool SPIFlash::powerUp(void) { return _writeEnable(false); #endif } + +/* Note: _writeDisable() is not required at the end of any function that writes to the Flash memory because the Write Enable Latch (WEL) flag is cleared to 0 i.e. to write disable state upon the following conditions being completed: +Power-up, Write Disable, Page Program, Quad Page Program, Sector Erase, Block Erase, Chip Erase, Write Status Register, Erase Security Register and Program Security register */ diff --git a/src/SPIFlash.h b/src/SPIFlash.h index 79beed6..74bf521 100644 --- a/src/SPIFlash.h +++ b/src/SPIFlash.h @@ -156,14 +156,14 @@ class SPIFlash { bool writeByte(uint32_t _addr, uint8_t data, bool errorCheck = true); uint8_t readByte(uint32_t _addr, bool fastRead = false); //----------------------------- Write / Read Byte Arrays ------------------------------// - bool writeByteArray(uint32_t _addr, uint8_t *data_buffer, uint16_t bufferSize, bool errorCheck = true); - bool readByteArray(uint32_t _addr, uint8_t *data_buffer, uint16_t bufferSize, bool fastRead = false); + bool writeByteArray(uint32_t _addr, uint8_t *data_buffer, size_t bufferSize, bool errorCheck = true); + bool readByteArray(uint32_t _addr, uint8_t *data_buffer, size_t bufferSize, bool fastRead = false); //-------------------------------- Write / Read Chars ---------------------------------// bool writeChar(uint32_t _addr, int8_t data, bool errorCheck = true); int8_t readChar(uint32_t _addr, bool fastRead = false); //------------------------------ Write / Read Char Arrays -----------------------------// - bool writeCharArray(uint32_t _addr, char *data_buffer, uint16_t bufferSize, bool errorCheck = true); - bool readCharArray(uint32_t _addr, char *data_buffer, uint16_t buffer_size, bool fastRead = false); + bool writeCharArray(uint32_t _addr, char *data_buffer, size_t bufferSize, bool errorCheck = true); + bool readCharArray(uint32_t _addr, char *data_buffer, size_t buffer_size, bool fastRead = false); //-------------------------------- Write / Read Shorts --------------------------------// bool writeShort(uint32_t _addr, int16_t data, bool errorCheck = true); int16_t readShort(uint32_t _addr, bool fastRead = false); @@ -317,12 +317,11 @@ template bool SPIFlash::readAnything(uint32_t _addr, T& data, bool fas //---------------------------------- Private Templates ----------------------------------// -// Checks for errors in writing data to flash memory. +// Private template to check for errors in writing to flash memory // Takes three arguments - // 1. _addr --> Any address from 0 to maxAddress // 2. const T& value --> Variable with the data to be error checked // 3. _sz --> Size of the data variable to be error checked, in bytes (1 byte = 8 bits) -// Private template to check for errors in writing to flash memory template bool SPIFlash::_writeErrorCheck(uint32_t _addr, const T& value, size_t _sz) { if (!_notBusy()) { return false; From b00aed758bae2bda074d6ddf6d775d03fb41ac69 Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Sat, 19 Aug 2017 03:07:54 +1000 Subject: [PATCH 23/34] Confirmed to work with SPANSION/CYPRESS & MICROCHIP (Both SST25 & SST26 series). --- .../Diagnostics_functions.ino | 29 ++++-- .../FlashDiagnostics/FlashDiagnostics.ino | 12 +-- extras/Changes.log | 4 +- src/FLASHIO.cpp | 95 ++++++++++--------- src/SPIFlash.cpp | 54 +++++++---- src/SPIFlash.h | 6 +- src/defines.h | 46 +++++---- src/troubleshoot.cpp | 5 + 8 files changed, 149 insertions(+), 102 deletions(-) diff --git a/examples/FlashDiagnostics/Diagnostics_functions.ino b/examples/FlashDiagnostics/Diagnostics_functions.ino index a58d601..f8439f7 100644 --- a/examples/FlashDiagnostics/Diagnostics_functions.ino +++ b/examples/FlashDiagnostics/Diagnostics_functions.ino @@ -15,6 +15,7 @@ |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| */ void printLine() { + Serial.println(); for (uint8_t i = 0; i < 230; i++) { Serial.print(F("-")); } @@ -34,12 +35,10 @@ void printTime(uint32_t _wTime, uint32_t _rTime) { printTimer(_wTime); Serial.print(F(",\tRead Time: ")); printTimer(_rTime); - Serial.println(); } else { Serial.print(F("\t\tTime: ")); printTimer(_wTime); - Serial.println(); } } @@ -84,16 +83,16 @@ void getID() { flash.libver(&_ver, &_subver, &_bugfix); clearprintBuffer(&printBuffer[1]); sprintf(printBuffer, ": %d.%d.%d", _ver, _subver, _bugfix); - Serial.println(printBuffer); + Serial.print(printBuffer); #else - Serial.println(F("< 2.5.0")); + Serial.print(F("< 2.5.0")); #endif printLine(); for (uint8_t i = 0; i < 80; i++) { Serial.print(F(" ")); } - Serial.println(F("Get ID")); + Serial.print(F("Get ID")); printLine(); uint8_t b1, b2; //uint16_t b3; @@ -116,12 +115,12 @@ void getID() { //Serial.println(F("xh")); clearprintBuffer(&printBuffer[1]); sprintf(printBuffer, "\t\t\tManufacturer ID: %02xh\n\t\t\tMemory Type: %02xh\n\t\t\tCapacity: %lu bytes\n\t\t\tMaximum pages: %lu", b1, b2, capacity, maxPage); - Serial.println(printBuffer); + Serial.print(printBuffer); printLine(); - Serial.println(); } void byteTest() { + Serial.println(); uint32_t wTime, rTime, addr; uint8_t _data, _d; _d = 35; @@ -147,6 +146,7 @@ void byteTest() { } void charTest() { + Serial.println(); uint32_t wTime, rTime, addr; int8_t _data, _d; _d = -110; @@ -173,6 +173,7 @@ void charTest() { } void wordTest() { + Serial.println(); uint32_t wTime, rTime, addr; uint16_t _data, _d; _d = 4520; @@ -199,6 +200,7 @@ void wordTest() { } void shortTest() { + Serial.println(); uint32_t wTime, rTime, addr; int16_t _data, _d; _d = -1250; @@ -225,6 +227,7 @@ void shortTest() { } void uLongTest() { + Serial.println(); uint32_t wTime, rTime, addr; uint32_t _data, _d; _d = 876532; @@ -251,6 +254,7 @@ void uLongTest() { } void longTest() { + Serial.println(); uint32_t wTime, rTime, addr; int32_t _data, _d; _d = -10959; @@ -277,6 +281,7 @@ void longTest() { } void floatTest() { + Serial.println(); uint32_t wTime, rTime, addr; float _data, _d; _d = 3.14; @@ -303,6 +308,7 @@ void floatTest() { } void stringTest() { + Serial.println(); uint32_t wTime, rTime, addr; String _data, _d; _d = "This is a test String 123!@#"; @@ -329,6 +335,7 @@ void stringTest() { } void structTest() { + Serial.println(); struct Test { word s1; float s2; @@ -369,6 +376,7 @@ void structTest() { } void arrayTest() { + Serial.println(); uint32_t wTime, rTime, addr; uint8_t _d[256], _data[256]; @@ -399,6 +407,7 @@ void arrayTest() { } void powerDownTest() { + Serial.println(); uint32_t _time; Serial.print(F("\t\t\tPower Down: \t")); if (flash.powerDown()) { @@ -408,10 +417,12 @@ void powerDownTest() { } else { pass(FALSE); + Serial.print(F("\t\tNot all chips support power down. Please check your datasheet.")); } } void powerUpTest() { + Serial.println(); uint32_t _time; Serial.print(F("\t\t\tPower Up: \t")); if (flash.powerUp()) { @@ -425,6 +436,7 @@ void powerUpTest() { } void eraseSectorTest() { + Serial.println(); uint32_t _time, _addr; _addr = random(0, 0xFFFFF); Serial.print(F("\t\t\tErase 4KB Sector: ")); @@ -440,6 +452,7 @@ void eraseSectorTest() { } void eraseBlock32KTest() { + Serial.println(); uint32_t _time, _addr; _addr = random(0, 0xFFFFF); Serial.print(F("\t\t\tErase 32KB Block: ")); @@ -454,6 +467,7 @@ void eraseBlock32KTest() { } void eraseBlock64KTest() { + Serial.println(); uint32_t _time, _addr; _addr = random(0, 0xFFFFF); Serial.print(F("\t\t\tErase 64KB Block: ")); @@ -468,6 +482,7 @@ void eraseBlock64KTest() { } void eraseChipTest() { + Serial.println(); uint32_t _time; Serial.print(F("\t\t\tErase Chip: \t")); if (flash.eraseChip()) { diff --git a/examples/FlashDiagnostics/FlashDiagnostics.ino b/examples/FlashDiagnostics/FlashDiagnostics.ino index 7693940..470e9f6 100644 --- a/examples/FlashDiagnostics/FlashDiagnostics.ino +++ b/examples/FlashDiagnostics/FlashDiagnostics.ino @@ -19,12 +19,6 @@ #define RUNDIAGNOSTIC //Outputs detailed diagnostic on error codes generated by library to Serial -//Define the make of the chip being tested -//#define WINBONDFLASH -//#define MICROCHIPFLASH -//Define a flash memory size (if using non-Winbond memory) according to the list in defines.h -//#define CHIPSIZE MB64 - #if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) // Required for Serial on Zero based boards #define Serial SERIAL_PORT_USBVIRTUAL @@ -57,15 +51,17 @@ void setup() { Serial.println(); randomSeed(analogRead(RANDPIN)); flash.begin(); + //To use a custom flash memory size (if using memory from manufacturers not officially supported by the library) - declare a size variable according to the list in defines.h + //flash.begin(MB1); Serial.println(); Serial.println(); - + getID(); eraseChipTest(); eraseBlock64KTest(); eraseBlock32KTest(); eraseSectorTest(); - + byteTest(); charTest(); wordTest(); diff --git a/extras/Changes.log b/extras/Changes.log index 8dba31d..c9a7aa2 100644 --- a/extras/Changes.log +++ b/extras/Changes.log @@ -23,6 +23,7 @@ New Boards supported: --> Enhancements: +--> Confirmed to work with SPANSION/CYPRESS & MICROCHIP (Both SST25 & SST26 series). --> When RUNDIAGNOSTIC is uncommented in SPIFlash.h, users now have access to a new function called flash.functionRunTime() which can be called after any library I/O function is run. flash.functionRunTime() returns the time taken by the previous function to run, in microseconds (as a float). An example use case can be found when the FlashDiagnostics sketch is run with RUNDIAGNOSTIC uncommented. --> _notBusy() is faster --> Completely re-written FlashDiagnostics - uses fewer resources, compatible with more chips and boards @@ -46,9 +47,8 @@ Enhancements: (+) eraseChip -> +12% --> All functions except the Byte/Char Array Read/Write functions now call an internal _write/_read function. --> Restructured the internal _troubleshoot() function to be better human readable and easier to compile. ---> Users can define RUNDIAGNOSTIC or HIGHSPEED in their code to access the library's special modes. No requirement to modify the library any more. --> No need to include CHIPSIZE in flash.begin() any more. Just defining CHIPSIZE in user code as one of the standard sizes as in defines.h will be enough. (Refer to 'Deprecations -> 1' above) ---> Constructor changed to enable user to choose one of multiple SPI ports - if available. Look at wiki for further info +--> Constructor changed to enable user to choose one of multiple SPI ports - if available. Look at wiki for further info. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Version 2.7.0 // // Author: Prajwal Bhattaram // diff --git a/src/FLASHIO.cpp b/src/FLASHIO.cpp index 211ef9e..ebb839f 100644 --- a/src/FLASHIO.cpp +++ b/src/FLASHIO.cpp @@ -303,16 +303,6 @@ bool SPIFlash::_notBusy(uint32_t timeout) { //Enables writing to chip by setting the WRITEENABLE bit bool SPIFlash::_writeEnable(bool _troubleshootEnable) { - /*uint32_t startTime = millis(); - do { - _beginSPI(WRITEENABLE); - CHIP_DESELECT - _readStat1(); - if((millis()-startTime) > timeout) { - _troubleshoot(CANTENWRITE); - return false; - } - } while (!(stat1 & WRTEN)) ;*/ _beginSPI(WRITEENABLE); CHIP_DESELECT if (!(_readStat1() & WRTEN)) { @@ -376,9 +366,16 @@ bool SPIFlash::_getSFDP(void) { _beginSPI(READSFDP); _transferAddress(); _nextByte(WRITE, DUMMYBYTE); - for (uint8_t i = 0; i < 4; i++) { + /*for (uint8_t i = 0; i < 4; i++) { _chip.sfdp += (_nextByte(READ) << (8*i)); - } + }*/ + // Modification suggested by @VitorBoss on 13.08.2017. + // Ref issue 76 on Github here --> + // https://github.com/Marzogh/SPIFlash/issues/76 + Lo(_chip.sfdp) = _nextByte(READ); + Hi(_chip.sfdp) = _nextByte(READ); + Higher(_chip.sfdp) = _nextByte(READ); + Highest(_chip.sfdp) = _nextByte(READ); CHIP_DESELECT if (_chip.sfdp == 0x50444653) { //Serial.print("_chip.sfdp: "); @@ -390,6 +387,29 @@ bool SPIFlash::_getSFDP(void) { } } +bool SPIFlash::_disableGlobalBlockProtect(void) { + if (_chip.memoryTypeID == SST25) { + _readStat1(); + stat1 &= 0xC3; + _beginSPI(WRITESTATEN); + CHIP_DESELECT + _beginSPI(WRITESTAT); + _nextByte(WRITE, stat1); + CHIP_DESELECT + } + else if (_chip.memoryTypeID == SST26) { + if(!_notBusy()) { + return false; + } + _writeEnable(); + _delay_us(10); + _beginSPI(ULBPR); + CHIP_DESELECT + _delay_us(50); + _writeDisable(); + } +} + //Identifies the chip bool SPIFlash::_chipID(void) { //Get Manfucturer/Device ID so the library can identify the chip @@ -399,51 +419,40 @@ bool SPIFlash::_chipID(void) { } if (_chip.manufacturerID == MICROCHIP_MANID) { - _readStat1(); - stat1 &= 0xC3; - _beginSPI(WRITESTATEN); - CHIP_DESELECT - _beginSPI(WRITESTAT); - _nextByte(WRITE, stat1); - CHIP_DESELECT + _disableGlobalBlockProtect(); } - // If no capacity is defined in user code -#if !defined (CHIPSIZE) - if (_chip.manufacturerID == WINBOND_MANID || _chip.manufacturerID == MICROCHIP_MANID || _chip.manufacturerID == CYPRESS_MANID) { - //Identify capacity - for (uint8_t i = 0; i < sizeof(_capID); i++) { - if (_chip.capacityID == _capID[i]) { - _chip.capacity = (_memSize[i]); - _chip.eraseTime = _eraseTime[i]; + if (!_chip.capacity) { + if (_chip.manufacturerID == WINBOND_MANID || _chip.manufacturerID == MICROCHIP_MANID || _chip.manufacturerID == CYPRESS_MANID) { + //Identify capacity + for (uint8_t i = 0; i < sizeof(_capID); i++) { + if (_chip.capacityID == _capID[i]) { + _chip.capacity = (_memSize[i]); + _chip.supported = true; + return true; + } + } + if (!_chip.capacity) { + _troubleshoot(UNKNOWNCAP); + return false; } } - _chip.supported = true; - return true; - } - else { - _troubleshoot(UNKNOWNCAP); //Error code for unidentified capacity - return false; - } -#else - // If a custom chip size is defined - _chip.eraseTime = (400L *S); - if (_chip.manufacturerID!= WINBOND_MANID && _chip.manufacturerID != MICROCHIP_MANID && _chip.manufacturerID != CYPRESS_MANID) { - _chip.supported = false;// This chip is not officially supported - _troubleshoot(UNKNOWNCHIP); //Error code for unidentified chip - //while(1); //Enable this if usercode is not meant to be run on unsupported chips + else { + _troubleshoot(UNKNOWNCHIP); //Error code for unidentified capacity + return false; + } } return true; -#endif } + //Checks to see if page overflow is permitted and assists with determining next address to read/write. //Sets the global address variable bool SPIFlash::_addressCheck(uint32_t _addr, uint32_t size) { if (errorcode == UNKNOWNCAP || errorcode == NORESPONSE) { return false; } - if (!_chip.eraseTime) { + if (!_chip.capacity) { _troubleshoot(CALLBEGIN); return false; } diff --git a/src/SPIFlash.cpp b/src/SPIFlash.cpp index 33391cb..c2b7d5f 100644 --- a/src/SPIFlash.cpp +++ b/src/SPIFlash.cpp @@ -66,16 +66,30 @@ SPIFlash::SPIFlash(uint8_t cs) { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// //Identifies chip and establishes parameters -bool SPIFlash::begin(void) { +bool SPIFlash::begin(size_t flashChipSize) { #ifdef RUNDIAGNOSTIC Serial.println("Full Diagnostics Workup initiated!"); + Serial.println(); #endif BEGIN_SPI #ifdef SPI_HAS_TRANSACTION //Define the settings to be used by the SPI bus _settings = SPISettings(SPI_CLK, MSBFIRST, SPI_MODE0); #endif - return _chipID(); +// If no capacity is defined in user code + if (!flashChipSize) { + return _chipID(); + } + else { + _getJedecId(); + // If a custom chip size is defined + #ifdef RUNDIAGNOSTIC + Serial.println("Custom Chipsize defined"); + #endif + _chip.capacity = flashChipSize; + _chip.supported = false; + } + return true; } //Allows the setting of a custom clock speed for the SPI bus to communicate with the chip. @@ -796,24 +810,30 @@ bool SPIFlash::resumeProg(void) { //Puts device in low power state. Good for battery powered operations. //In powerDown() the chip will only respond to powerUp() bool SPIFlash::powerDown(void) { - #ifdef RUNDIAGNOSTIC - _spifuncruntime = micros(); - #endif - if(!_notBusy(20)) - return false; + if (_chip.manufacturerID != MICROCHIP_MANID) { + #ifdef RUNDIAGNOSTIC + _spifuncruntime = micros(); + #endif + if(!_notBusy(20)) + return false; - _beginSPI(POWERDOWN); - _endSPI(); + _beginSPI(POWERDOWN); + _endSPI(); - _delay_us(5); + _delay_us(5); - #ifdef RUNDIAGNOSTIC - bool _retVal = !_writeEnable(false); - _spifuncruntime = micros() - _spifuncruntime; - return _retVal; - #else - return !_writeEnable(false); - #endif + #ifdef RUNDIAGNOSTIC + bool _retVal = !_writeEnable(false); + _spifuncruntime = micros() - _spifuncruntime; + return _retVal; + #else + return !_writeEnable(false); + #endif + } + else { + _troubleshoot(UNSUPPORTEDFUNCTION); + return false; + } } //Wakes chip from low power state. diff --git a/src/SPIFlash.h b/src/SPIFlash.h index 74bf521..3ca9f8d 100644 --- a/src/SPIFlash.h +++ b/src/SPIFlash.h @@ -141,7 +141,7 @@ class SPIFlash { SPIFlash(uint8_t cs = CS); #endif //----------------------------- Initial / Chip Functions ------------------------------// - bool begin(void); + bool begin(size_t flashChipSize = 0); void setClock(uint32_t clockSpeed); bool libver(uint8_t *b1, uint8_t *b2, uint8_t *b3); uint8_t error(bool verbosity = false); @@ -231,6 +231,7 @@ class SPIFlash { void _printErrorCode(void); void _printSupportLink(void); void _endSPI(void); + bool _disableGlobalBlockProtect(void); bool _prep(uint8_t opcode, uint32_t _addr, uint32_t size = 0); bool _startSPIBus(void); bool _beginSPI(uint8_t opcode); @@ -288,9 +289,6 @@ class SPIFlash { const uint32_t _memSize[12] = {64L * K, 128L * K, 256L * K, 512L * K, 1L * M, 2L * M, 4L * M, 8L * M, 6L * M, 32L * M, 8L * M, 8L * M}; - - const uint32_t _eraseTime[12] = - {1L * S, 2L * S, 2L * S, 4L * S, 6L * S, 10L * S, 15L * S, 100L * S, 200L * S, 400L * S, 50L * S, 50L * S}; //Erase time in milliseconds }; //--------------------------------- Public Templates ------------------------------------// diff --git a/src/defines.h b/src/defines.h index 2bdec94..6a5d896 100644 --- a/src/defines.h +++ b/src/defines.h @@ -54,7 +54,7 @@ // General size definitions // // B = Bytes; KB = Kilo Bytes; MB = Mega Bytes // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -/*#define B1 1L * B +#define B1 1L * B #define B2 2L * B #define B4 4L * B #define B8 8L * B @@ -84,23 +84,26 @@ #define MB64 64L * M #define MB128 128L * M #define MB256 256L * M -#define MB512 512L * M*/ +#define MB512 512L * M //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Chip specific instructions // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// //~~~~~~~~~~~~~~~~~~~~~~~~~ Winbond ~~~~~~~~~~~~~~~~~~~~~~~~~// - #define WINBOND_MANID 0xEF - #define PAGESIZE 0x100 - #define WINBOND_WRITE_DELAY 0x02 + #define WINBOND_MANID 0xEF + #define PAGESIZE 0x100 + #define WINBOND_WRITE_DELAY 0x02 #define WINBOND_WREN_TIMEOUT 10L //#define CHIPSIZE 1*M //~~~~~~~~~~~~~~~~~~~~~~~~ Microchip ~~~~~~~~~~~~~~~~~~~~~~~~// - #define MICROCHIP_MANID 0xBF + #define MICROCHIP_MANID 0xBF + #define SST25 0x25 + #define SST26 0x26 + #define ULBPR 0x98 //Global Block Protection Unlock (Ref sections 4.1.1 & 5.37 of datasheet) //~~~~~~~~~~~~~~~~~~~~~~~~ Cypress ~~~~~~~~~~~~~~~~~~~~~~~~// - #define CYPRESS_MANID 0x1 + #define CYPRESS_MANID 0x01 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Definitions // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -183,20 +186,21 @@ // List of Error codes // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - #define SUCCESS 0x00 - #define CALLBEGIN 0x01 - #define UNKNOWNCHIP 0x02 - #define UNKNOWNCAP 0x03 - #define CHIPBUSY 0x04 - #define OUTOFBOUNDS 0x05 - #define CANTENWRITE 0x06 - #define PREVWRITTEN 0x07 - #define LOWRAM 0x08 - #define SYSSUSPEND 0x09 - #define UNSUPPORTED 0x0A - #define ERRORCHKFAIL 0x0B - #define NORESPONSE 0x0C - #define UNKNOWNERROR 0xFE + #define SUCCESS 0x00 + #define CALLBEGIN 0x01 + #define UNKNOWNCHIP 0x02 + #define UNKNOWNCAP 0x03 + #define CHIPBUSY 0x04 + #define OUTOFBOUNDS 0x05 + #define CANTENWRITE 0x06 + #define PREVWRITTEN 0x07 + #define LOWRAM 0x08 + #define SYSSUSPEND 0x09 + #define UNSUPPORTED 0x0A + #define ERRORCHKFAIL 0x0B + #define NORESPONSE 0x0C + #define UNSUPPORTEDFUNCTION 0x0D + #define UNKNOWNERROR 0xFE //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Bit shift macros // diff --git a/src/troubleshoot.cpp b/src/troubleshoot.cpp index 5b1fa5e..18e0588 100644 --- a/src/troubleshoot.cpp +++ b/src/troubleshoot.cpp @@ -53,6 +53,7 @@ void SPIFlash::_troubleshoot(uint8_t _code, bool printoverride) { #if defined (ARDUINO_ARCH_AVR) _printErrorCode(); #else + Serial.println(); switch (_code) { case SUCCESS: Serial.println("Action completed successfully"); @@ -105,6 +106,10 @@ void SPIFlash::_troubleshoot(uint8_t _code, bool printoverride) { #endif*/ break; + case UNSUPPORTEDFUNCTION: + Serial.println("This function is not supported by the flash memory hardware."); + break; + case SYSSUSPEND: Serial.println("Unable to suspend/resume operation."); break; From 7f81f41c6bf247365f0bc8aad97c5fb14b7b194f Mon Sep 17 00:00:00 2001 From: Marzogh Date: Sat, 19 Aug 2017 08:55:26 +1000 Subject: [PATCH 24/34] Added an _endSPI() to the end of the begin function. This will enable users to concurrently use multiple flash chips more easily. This fixes issue #72. --- src/SPIFlash.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/SPIFlash.cpp b/src/SPIFlash.cpp index c2b7d5f..ca5424a 100644 --- a/src/SPIFlash.cpp +++ b/src/SPIFlash.cpp @@ -78,7 +78,9 @@ bool SPIFlash::begin(size_t flashChipSize) { #endif // If no capacity is defined in user code if (!flashChipSize) { - return _chipID(); + bool retVal = _chipID; + _endSPI(); + return retVal; } else { _getJedecId(); @@ -89,6 +91,7 @@ bool SPIFlash::begin(size_t flashChipSize) { _chip.capacity = flashChipSize; _chip.supported = false; } + _endSPI(); return true; } From e5e980ef61cd7b7b61fc4a157901098b4b6f1c35 Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Sat, 19 Aug 2017 09:21:26 +1000 Subject: [PATCH 25/34] Fixed type in flash.begin(); --- src/SPIFlash.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPIFlash.cpp b/src/SPIFlash.cpp index ca5424a..65156c4 100644 --- a/src/SPIFlash.cpp +++ b/src/SPIFlash.cpp @@ -78,7 +78,7 @@ bool SPIFlash::begin(size_t flashChipSize) { #endif // If no capacity is defined in user code if (!flashChipSize) { - bool retVal = _chipID; + bool retVal = _chipID(); _endSPI(); return retVal; } From 75afe8b917762f1e8464aa85cc40338029cd23de Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Thu, 31 Aug 2017 22:05:14 +1000 Subject: [PATCH 26/34] STM32 support confirmed working with Nucleo-F091RC --- .../Diagnostics_functions.ino | 6 ++-- .../FlashDiagnostics/FlashDiagnostics.ino | 4 +-- examples/Struct_writer/Struct_writer.ino | 4 ++- src/FLASHIO.cpp | 13 ++++++--- src/SPIFlash.cpp | 17 ++++++++--- src/SPIFlash.h | 29 +++++++++++-------- src/defines.h | 17 +++++++---- 7 files changed, 58 insertions(+), 32 deletions(-) diff --git a/examples/FlashDiagnostics/Diagnostics_functions.ino b/examples/FlashDiagnostics/Diagnostics_functions.ino index f8439f7..d50ebd9 100644 --- a/examples/FlashDiagnostics/Diagnostics_functions.ino +++ b/examples/FlashDiagnostics/Diagnostics_functions.ino @@ -337,11 +337,11 @@ void stringTest() { void structTest() { Serial.println(); struct Test { - word s1; + uint16_t s1; float s2; - long s3; + int32_t s3; bool s4; - byte s5; + uint8_t s5; }; Test _d; Test _data; diff --git a/examples/FlashDiagnostics/FlashDiagnostics.ino b/examples/FlashDiagnostics/FlashDiagnostics.ino index 470e9f6..30e3e31 100644 --- a/examples/FlashDiagnostics/FlashDiagnostics.ino +++ b/examples/FlashDiagnostics/FlashDiagnostics.ino @@ -61,7 +61,7 @@ void setup() { eraseBlock64KTest(); eraseBlock32KTest(); eraseSectorTest(); - + byteTest(); charTest(); wordTest(); @@ -72,7 +72,7 @@ void setup() { stringTest(); structTest(); arrayTest(); - + powerDownTest(); powerUpTest(); printLine(); diff --git a/examples/Struct_writer/Struct_writer.ino b/examples/Struct_writer/Struct_writer.ino index 660cb7c..23fd488 100644 --- a/examples/Struct_writer/Struct_writer.ino +++ b/examples/Struct_writer/Struct_writer.ino @@ -91,7 +91,9 @@ void setup() { #ifdef SENSOR readLDR(); #endif - + if (flash.eraseChip()) { + Serial.println("Chip has been erased"); + } if (flash.writeAnything(_addr, configuration)) Serial.println ("Data write successful"); else diff --git a/src/FLASHIO.cpp b/src/FLASHIO.cpp index ebb839f..3bba149 100644 --- a/src/FLASHIO.cpp +++ b/src/FLASHIO.cpp @@ -35,6 +35,8 @@ bool SPIFlash::_prep(uint8_t opcode, uint32_t _addr, uint32_t size) { switch (opcode) { case PAGEPROG: + //Serial.print(F("Address being prepped: ")); + //Serial.println(_addr); #ifndef HIGHSPEED if(!_addressCheck(_addr, size) || !_notPrevWritten(_addr, size) || !_notBusy() || !_writeEnable()) { return false; @@ -72,6 +74,9 @@ bool SPIFlash::_transferAddress(void) { _nextByte(WRITE, Higher(_currentAddress)); _nextByte(WRITE, Hi(_currentAddress)); _nextByte(WRITE, Lo(_currentAddress)); + /*_nextByte(_currentAddress >> 16); + _nextByte(_currentAddress >> 8); + _nextByte(_currentAddress);*/ return true; } @@ -86,7 +91,7 @@ bool SPIFlash::_startSPIBus(void) { #ifdef SPI_HAS_TRANSACTION _spi->beginTransaction(_settings); #else - _spi->setClockDivider(SPI_CLOCK_DIV_4) + _spi->setClockDivider(SPI_CLOCK_DIV_4); _spi->setDataMode(SPI_MODE0); _spi->setBitOrder(MSBFIRST); #endif @@ -102,7 +107,7 @@ bool SPIFlash::_startSPIBus(void) { #ifdef SPI_HAS_TRANSACTION SPI.beginTransaction(_settings); #else - SPI.setClockDivider(SPI_CLOCK_DIV_4) + SPI.setClockDivider(SPI_CLOCK_DIV4); SPI.setDataMode(SPI_MODE0); SPI.setBitOrder(MSBFIRST); #endif @@ -349,7 +354,7 @@ bool SPIFlash::_getJedecId(void) { _chip.memoryTypeID = _nextByte(READ); // memory type _chip.capacityID = _nextByte(READ); // capacity CHIP_DESELECT - if (!_chip.manufacturerID || !_chip.memoryTypeID || !_chip.capacityID) { + if (!_chip.manufacturerID) { _troubleshoot(NORESPONSE); return false; } @@ -423,7 +428,7 @@ bool SPIFlash::_chipID(void) { } if (!_chip.capacity) { - if (_chip.manufacturerID == WINBOND_MANID || _chip.manufacturerID == MICROCHIP_MANID || _chip.manufacturerID == CYPRESS_MANID) { + if (_chip.manufacturerID == WINBOND_MANID || _chip.manufacturerID == MICROCHIP_MANID || _chip.manufacturerID == CYPRESS_MANID || _chip.manufacturerID == ADESTO_MANID || _chip.manufacturerID == MICRON_MANID) { //Identify capacity for (uint8_t i = 0; i < sizeof(_capID); i++) { if (_chip.capacityID == _capID[i]) { diff --git a/src/SPIFlash.cpp b/src/SPIFlash.cpp index 65156c4..6fca002 100644 --- a/src/SPIFlash.cpp +++ b/src/SPIFlash.cpp @@ -681,6 +681,7 @@ bool SPIFlash::eraseSector(uint32_t _addr) { if(!_notBusy(500L)) { return false; //Datasheet says erasing a sector takes 400ms max } + //_writeDisable(); #ifdef RUNDIAGNOSTIC _spifuncruntime = micros() - _spifuncruntime; #endif @@ -703,6 +704,7 @@ bool SPIFlash::eraseBlock32K(uint32_t _addr) { if(!_notBusy(1*S)) { return false; //Datasheet says erasing a sector takes 400ms max } + _writeDisable(); #ifdef RUNDIAGNOSTIC _spifuncruntime = micros() - _spifuncruntime; #endif @@ -849,11 +851,18 @@ bool SPIFlash::powerUp(void) { _delay_us(3); //Max release enable time according to the Datasheet #ifdef RUNDIAGNOSTIC - bool _retVal = _writeEnable(false); - _spifuncruntime = micros() - _spifuncruntime; - return _retVal; + if (_writeEnable(false)) { + _writeDisable(); + _spifuncruntime = micros() - _spifuncruntime; + return true; + } + return false; #else - return _writeEnable(false); + if (_writeEnable(false)) { + _writeDisable(); + return true; + } + return false; #endif } diff --git a/src/SPIFlash.h b/src/SPIFlash.h index 3ca9f8d..5015cca 100644 --- a/src/SPIFlash.h +++ b/src/SPIFlash.h @@ -77,7 +77,7 @@ #endif #endif -#if defined (ARDUINO_ARCH_SAM) || defined (ARDUINO_ARCH_SAMD) || defined (ARDUINO_ARCH_ESP8266) || defined (SIMBLEE) || defined (ARDUINO_ARCH_ESP32) || defined (BOARD_RTL8195A) +#if defined (ARDUINO_ARCH_SAM) || defined (ARDUINO_ARCH_SAMD) || defined (ARDUINO_ARCH_ESP8266) || defined (SIMBLEE) || defined (ARDUINO_ARCH_ESP32) || defined (BOARD_RTL8195A) || defined(__STM32F1__) || defined(STM32F0xx) // RTL8195A included - @boseji 02.03.17 #define _delay_us(us) delayMicroseconds(us) #else @@ -251,10 +251,10 @@ class SPIFlash { void _nextBuf(uint8_t opcode, uint8_t *data_buffer, uint32_t size); uint8_t _readStat1(void); uint8_t _readStat2(void); - template bool _write(uint32_t _addr, const T& value, size_t _sz, bool errorCheck); - template bool _read(uint32_t _addr, T& value, size_t _sz, bool fastRead = false); + template bool _write(uint32_t _addr, const T& value, uint32_t _sz, bool errorCheck); + template bool _read(uint32_t _addr, T& value, uint32_t _sz, bool fastRead = false); template bool _writeErrorCheck(uint32_t _addr, const T& value); - template bool _writeErrorCheck(uint32_t _addr, const T& value, size_t _sz); + template bool _writeErrorCheck(uint32_t _addr, const T& value, uint32_t _sz); //-------------------------------- Private variables ----------------------------------// #ifdef SPI_HAS_TRANSACTION SPISettings _settings; @@ -284,11 +284,11 @@ class SPIFlash { }; chipID _chip; uint32_t currentAddress, _currentAddress = 0; - const uint8_t _capID[12] = - {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x43, 0x4B}; + const uint8_t _capID[14] = + {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x43, 0x4B, 0x00, 0x01}; - const uint32_t _memSize[12] = - {64L * K, 128L * K, 256L * K, 512L * K, 1L * M, 2L * M, 4L * M, 8L * M, 6L * M, 32L * M, 8L * M, 8L * M}; + const uint32_t _memSize[14] = + {64L * K, 128L * K, 256L * K, 512L * K, 1L * M, 2L * M, 4L * M, 8L * M, 6L * M, 32L * M, 8L * M, 8L * M, 256L * K, 512L * K}; }; //--------------------------------- Public Templates ------------------------------------// @@ -320,10 +320,12 @@ template bool SPIFlash::readAnything(uint32_t _addr, T& data, bool fas // 1. _addr --> Any address from 0 to maxAddress // 2. const T& value --> Variable with the data to be error checked // 3. _sz --> Size of the data variable to be error checked, in bytes (1 byte = 8 bits) -template bool SPIFlash::_writeErrorCheck(uint32_t _addr, const T& value, size_t _sz) { +template bool SPIFlash::_writeErrorCheck(uint32_t _addr, const T& value, uint32_t _sz) { if (!_notBusy()) { return false; } + //Serial.print(F("Address being error checked: ")); + //Serial.println(_addr); _currentAddress = _addr; const uint8_t* p = (const uint8_t*)(const void*)&value; CHIP_SELECT @@ -349,12 +351,13 @@ template bool SPIFlash::_writeErrorCheck(uint32_t _addr, const T& valu // WARNING: You can only write to previously erased memory locations (see datasheet). // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs) -template bool SPIFlash::_write(uint32_t _addr, const T& value, size_t _sz, bool errorCheck) { +template bool SPIFlash::_write(uint32_t _addr, const T& value, uint32_t _sz, bool errorCheck) { if (!_prep(PAGEPROG, _addr, _sz)) { return false; } const uint8_t* p = ((const uint8_t*)(const void*)&value); - +//Serial.print(F("Address being written to: ")); +//Serial.println(_addr); if (!SPIBusState) { _startSPIBus(); } @@ -402,6 +405,8 @@ template bool SPIFlash::_write(uint32_t _addr, const T& value, size_t return true; } else { + //Serial.print(F("Address sent to error check: ")); + //Serial.println(_addr); return _writeErrorCheck(_addr, value, _sz); } } @@ -412,7 +417,7 @@ template bool SPIFlash::_write(uint32_t _addr, const T& value, size_t // 2. T& value --> Variable to return data into // 3. _sz --> Size of the variable in bytes (1 byte = 8 bits) // 4. fastRead --> defaults to false - executes _beginFastRead() if set to true -template bool SPIFlash::_read(uint32_t _addr, T& value, size_t _sz, bool fastRead) { +template bool SPIFlash::_read(uint32_t _addr, T& value, uint32_t _sz, bool fastRead) { if (_prep(READDATA, _addr, _sz)) { uint8_t* p = (uint8_t*)(void*)&value; CHIP_SELECT diff --git a/src/defines.h b/src/defines.h index 6a5d896..fb65b19 100644 --- a/src/defines.h +++ b/src/defines.h @@ -40,14 +40,14 @@ #define WRITEENABLE 0x06 #define SECTORERASE 0x20 #define BLOCK32ERASE 0x52 +#define BLOCK64ERASE 0xD8 #define CHIPERASE 0x60 #define SUSPEND 0x75 #define ID 0x90 #define RESUME 0x7A #define JEDECID 0x9F -#define RELEASE 0xAB #define POWERDOWN 0xB9 -#define BLOCK64ERASE 0xD8 +#define RELEASE 0xAB #define READSFDP 0x5A //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -89,21 +89,26 @@ // Chip specific instructions // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - //~~~~~~~~~~~~~~~~~~~~~~~~~ Winbond ~~~~~~~~~~~~~~~~~~~~~~~~~// +//~~~~~~~~~~~~~~~~~~~~~~~~~ Winbond ~~~~~~~~~~~~~~~~~~~~~~~~~// #define WINBOND_MANID 0xEF #define PAGESIZE 0x100 #define WINBOND_WRITE_DELAY 0x02 #define WINBOND_WREN_TIMEOUT 10L - //#define CHIPSIZE 1*M - //~~~~~~~~~~~~~~~~~~~~~~~~ Microchip ~~~~~~~~~~~~~~~~~~~~~~~~// +//~~~~~~~~~~~~~~~~~~~~~~~~ Microchip ~~~~~~~~~~~~~~~~~~~~~~~~// #define MICROCHIP_MANID 0xBF #define SST25 0x25 #define SST26 0x26 #define ULBPR 0x98 //Global Block Protection Unlock (Ref sections 4.1.1 & 5.37 of datasheet) - //~~~~~~~~~~~~~~~~~~~~~~~~ Cypress ~~~~~~~~~~~~~~~~~~~~~~~~// +//~~~~~~~~~~~~~~~~~~~~~~~~ Cypress ~~~~~~~~~~~~~~~~~~~~~~~~// #define CYPRESS_MANID 0x01 + +//~~~~~~~~~~~~~~~~~~~~~~~~ Adesto ~~~~~~~~~~~~~~~~~~~~~~~~// + #define ADESTO_MANID 0x1F + +//~~~~~~~~~~~~~~~~~~~~~~~~ Micron ~~~~~~~~~~~~~~~~~~~~~~~~// + #define MICRON_MANID 0x20 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Definitions // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// From 571ca852eed6415dc125f2234e9ee6d5672b59ad Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Thu, 31 Aug 2017 22:39:18 +1000 Subject: [PATCH 27/34] Added more badges to ReadMe.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 82112b4..e3abdaf 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,9 @@ # SPIFlash [![Build Status](https://travis-ci.org/Marzogh/SPIFlash.svg?branch=dev)](https://travis-ci.org/Marzogh/SPIFlash) [![DOI](https://zenodo.org/badge/18908/Marzogh/SPIFlash.svg)](https://zenodo.org/badge/latestdoi/18908/Marzogh/SPIFlash) +[![GitHub release](https://img.shields.io/github/release/Marzogh/SPIFlash.svg)](https://github.com/Marzogh/SPIFlash) +[![GitHub commits](https://img.shields.io/github/commits-since/Marzogh/SPIFlash/v2.7.0.svg)](https://github.com/Marzogh/SPIFlash) +[![GitHub issues](https://img.shields.io/github/issues/Marzogh/SPIFlash.svg)](https://github.com/Marzogh/SPIFlash) +[![GitHub pull requests](https://img.shields.io/github/issues-pr/Marzogh/SPIFlash.svg)](https://github.com/Marzogh/SPIFlash) +[![license](https://img.shields.io/github/license/Marzogh/SPIFlash.svg)](https://github.com/Marzogh/SPIFlash) ### Arduino library for Winbond Flash Memory Chips Download the latest stable release (v2.6.0) from here. Please report any bugs in issues. From b19c8f0d4afd2669d7e0ce85f7f7204ee6f9cc3b Mon Sep 17 00:00:00 2001 From: Marzogh Date: Thu, 31 Aug 2017 22:52:04 +1000 Subject: [PATCH 28/34] Update README.md Fix for commit count badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e3abdaf..312e006 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # SPIFlash [![Build Status](https://travis-ci.org/Marzogh/SPIFlash.svg?branch=dev)](https://travis-ci.org/Marzogh/SPIFlash) [![DOI](https://zenodo.org/badge/18908/Marzogh/SPIFlash.svg)](https://zenodo.org/badge/latestdoi/18908/Marzogh/SPIFlash) [![GitHub release](https://img.shields.io/github/release/Marzogh/SPIFlash.svg)](https://github.com/Marzogh/SPIFlash) -[![GitHub commits](https://img.shields.io/github/commits-since/Marzogh/SPIFlash/v2.7.0.svg)](https://github.com/Marzogh/SPIFlash) +[![GitHub commits](https://img.shields.io/github/commits-since/Marzogh/SPIFlash/v2.7.0.svg)](https://github.com/Marzogh/SPIFlash/compare/v2.7.0...development) [![GitHub issues](https://img.shields.io/github/issues/Marzogh/SPIFlash.svg)](https://github.com/Marzogh/SPIFlash) [![GitHub pull requests](https://img.shields.io/github/issues-pr/Marzogh/SPIFlash.svg)](https://github.com/Marzogh/SPIFlash) [![license](https://img.shields.io/github/license/Marzogh/SPIFlash.svg)](https://github.com/Marzogh/SPIFlash) From e6d993420c7b44fa859198d1539d6ff7b616c95a Mon Sep 17 00:00:00 2001 From: VitorBoss Date: Thu, 31 Aug 2017 17:09:00 -0300 Subject: [PATCH 29/34] Update STM32 definitions and code --- .../Diagnostics_functions.ino | 2 +- .../FlashDiagnostics/FlashDiagnostics.ino | 29 +++++--- src/SPIFlash.cpp | 8 +- src/SPIFlash.h | 17 +++-- src/defines.h | 74 ++++++++++--------- 5 files changed, 71 insertions(+), 59 deletions(-) diff --git a/examples/FlashDiagnostics/Diagnostics_functions.ino b/examples/FlashDiagnostics/Diagnostics_functions.ino index d50ebd9..6120b39 100644 --- a/examples/FlashDiagnostics/Diagnostics_functions.ino +++ b/examples/FlashDiagnostics/Diagnostics_functions.ino @@ -366,7 +366,7 @@ void structTest() { Serial.print ("\t\t\tStruct: \t"); - if (_d.s1 == _data.s1 && _d.s2 == _data.s2 && _d.s3 == _data.s3 && _d.s4 == _data.s4 && _d.s5 == _data.s5) { + if ((_d.s1 == _data.s1) && (_d.s2 == _data.s2) && (_d.s3 == _data.s3) && (_d.s4 == _data.s4) && (_d.s5 == _data.s5)) { pass(TRUE); } else { diff --git a/examples/FlashDiagnostics/FlashDiagnostics.ino b/examples/FlashDiagnostics/FlashDiagnostics.ino index 30e3e31..1aa0803 100644 --- a/examples/FlashDiagnostics/FlashDiagnostics.ino +++ b/examples/FlashDiagnostics/FlashDiagnostics.ino @@ -25,26 +25,31 @@ #endif #if defined (SIMBLEE) -#define BAUD_RATE 250000 -#define RANDPIN 1 + #define BAUD_RATE 250000 + #define RANDPIN 1 #else -#define BAUD_RATE 115200 -#define RANDPIN A0 + #define BAUD_RATE 115200 + #if defined(ARCH_STM32) + #define RANDPIN PA0 + #else + #define RANDPIN A0 + #endif #endif #define TRUE 1 #define FALSE 0 -//SPIFlash flash(SS1, &SPI1); //Use this constructor if using an SPI bus other than the default SPI. Only works with chips with more than one hardware SPI bus +//SPIFlash flash(SS1, &SPI2); //Use this constructor if using an SPI bus other than the default SPI. Only works with chips with more than one hardware SPI bus SPIFlash flash; void setup() { Serial.begin(BAUD_RATE); -#if defined (ARDUINO_ARCH_SAMD) || (__AVR_ATmega32U4__) - while (!Serial) ; // Wait for Serial monitor to open -#endif + #if defined (ARDUINO_ARCH_SAMD) || (__AVR_ATmega32U4__) || defined(ARCH_STM32) + while (!Serial) ; // Wait for Serial monitor to open + #endif + delay(50); //Time to terminal get connected Serial.print(F("Initialising Flash memory")); - for (int i = 0; i < 10; ++i) + for (uint8_t i = 0; i < 10; ++i) { Serial.print(F(".")); } @@ -86,10 +91,10 @@ void loop() { } void longBlink() { - pinMode(13, OUTPUT); - digitalWrite(13, HIGH); + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, HIGH); delay(3000); - digitalWrite(13, LOW); + digitalWrite(LED_BUILTIN, LOW); delay(2000); } diff --git a/src/SPIFlash.cpp b/src/SPIFlash.cpp index 6fca002..ee5ea87 100644 --- a/src/SPIFlash.cpp +++ b/src/SPIFlash.cpp @@ -37,7 +37,7 @@ SPIFlash::SPIFlash(uint8_t cs) { pinMode(csPin, OUTPUT); CHIP_DESELECT } -#elif defined (ARDUINO_ARCH_SAMD) +#elif defined (ARDUINO_ARCH_SAMD) || defined(ARCH_STM32) SPIFlash::SPIFlash(uint8_t cs, SPIClass *spiinterface) { _spi = spiinterface; //Sets SPI interface - if no user selection is made, this defaults to SPI csPin = cs; @@ -120,7 +120,7 @@ uint32_t SPIFlash::getCapacity(void) { //Returns maximum number of pages uint32_t SPIFlash::getMaxPage(void) { - return (_chip.capacity / PAGESIZE); + return (_chip.capacity / SPI_PAGESIZE); } //Returns the time taken to run a function. Must be called immediately after a function is run as the variable returned is overwritten eachtime a function from this library is called. Primarily used in the diagnostics sketch included in the library to track function time. @@ -413,7 +413,7 @@ bool SPIFlash::writeByteArray(uint32_t _addr, uint8_t *data_buffer, size_t buffe if (!_prep(PAGEPROG, _addr, bufferSize)) { return false; } - uint16_t maxBytes = PAGESIZE-(_addr % PAGESIZE); // Force the first set of bytes to stay within the first page + uint16_t maxBytes = SPI_PAGESIZE-(_addr % SPI_PAGESIZE); // Force the first set of bytes to stay within the first page if (bufferSize <= maxBytes) { CHIP_SELECT @@ -493,7 +493,7 @@ bool SPIFlash::writeCharArray(uint32_t _addr, char *data_buffer, size_t bufferSi if (!_prep(PAGEPROG, _addr, bufferSize)) { return false; } - uint16_t maxBytes = PAGESIZE-(_addr % PAGESIZE); // Force the first set of bytes to stay within the first page + uint16_t maxBytes = SPI_PAGESIZE-(_addr % SPI_PAGESIZE); // Force the first set of bytes to stay within the first page if (bufferSize <= maxBytes) { CHIP_SELECT diff --git a/src/SPIFlash.h b/src/SPIFlash.h index 5015cca..b393411 100644 --- a/src/SPIFlash.h +++ b/src/SPIFlash.h @@ -77,7 +77,12 @@ #endif #endif -#if defined (ARDUINO_ARCH_SAM) || defined (ARDUINO_ARCH_SAMD) || defined (ARDUINO_ARCH_ESP8266) || defined (SIMBLEE) || defined (ARDUINO_ARCH_ESP32) || defined (BOARD_RTL8195A) || defined(__STM32F1__) || defined(STM32F0xx) +#ifndef ARCH_STM32 + #if defined(ARDUINO_ARCH_STM32) || defined(__STM32F1__) || defined(STM32F1) || defined(STM32F3) || defined(STM32F4) || defined(STM32F0xx) + #define ARCH_STM32 + #endif +#endif +#if defined (ARDUINO_ARCH_SAM) || defined (ARDUINO_ARCH_SAMD) || defined (ARDUINO_ARCH_ESP8266) || defined (SIMBLEE) || defined (ARDUINO_ARCH_ESP32) || defined (BOARD_RTL8195A) || defined(ARCH_STM32) // RTL8195A included - @boseji 02.03.17 #define _delay_us(us) delayMicroseconds(us) #else @@ -112,8 +117,8 @@ #define xfer(n) SPI.transfer(n) #define BEGIN_SPI SPI.begin(); -// Defines and variables specific to SAMD architecture -#elif defined (ARDUINO_ARCH_SAMD) +// Defines and variables specific to ARM architecture +#elif defined (ARDUINO_ARCH_SAMD) || defined(ARCH_STM32) #define CHIP_SELECT digitalWrite(csPin, LOW); #define CHIP_DESELECT digitalWrite(csPin, HIGH); #define xfer(n) _spi->transfer(n) @@ -133,7 +138,7 @@ class SPIFlash { public: //------------------------------------ Constructor ------------------------------------// //New Constructor to Accept the PinNames as a Chip select Parameter - @boseji 02.03.17 - #if defined (ARDUINO_ARCH_SAMD) + #if defined (ARDUINO_ARCH_SAMD) || defined(ARCH_STM32) SPIFlash(uint8_t cs = CS, SPIClass *spiinterface=&SPI); #elif defined (BOARD_RTL8195A) SPIFlash(PinName cs = CS); @@ -288,7 +293,7 @@ class SPIFlash { {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x43, 0x4B, 0x00, 0x01}; const uint32_t _memSize[14] = - {64L * K, 128L * K, 256L * K, 512L * K, 1L * M, 2L * M, 4L * M, 8L * M, 6L * M, 32L * M, 8L * M, 8L * M, 256L * K, 512L * K}; + {64L * KiB, 128L * KiB, 256L * KiB, 512L * KiB, 1L * MiB, 2L * MiB, 4L * MiB, 8L * MiB, 6L * MiB, 32L * MiB, 8L * MiB, 8L * MiB, 256L * KiB, 512L * KiB}; }; //--------------------------------- Public Templates ------------------------------------// @@ -371,7 +376,7 @@ template bool SPIFlash::_write(uint32_t _addr, const T& value, uint32_ } else { //If data is longer than one byte (8 bits) uint32_t length = _sz; - uint16_t maxBytes = PAGESIZE-(_addr % PAGESIZE); // Force the first set of bytes to stay within the first page + uint16_t maxBytes = SPI_PAGESIZE-(_addr % SPI_PAGESIZE); // Force the first set of bytes to stay within the first page if (maxBytes > length) { for (uint16_t i = 0; i < length; ++i) { diff --git a/src/defines.h b/src/defines.h index fb65b19..201df25 100644 --- a/src/defines.h +++ b/src/defines.h @@ -52,46 +52,48 @@ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // General size definitions // -// B = Bytes; KB = Kilo Bytes; MB = Mega Bytes // +// B = Bytes; KiB = Kilo Bytes; MiB = Mega Bytes // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -#define B1 1L * B -#define B2 2L * B -#define B4 4L * B -#define B8 8L * B -#define B16 16L * B -#define B32 32L * B -#define B64 64L * B -#define B80 80L * B -#define B128 128L * B -#define B256 256L * B -#define B512 512L * B -#define KB1 1L * K -#define KB2 2L * K -#define KB4 4L * K -#define KB8 8L * K -#define KB16 16L * K -#define KB32 32L * K -#define KB64 64L * K -#define KB128 128L * K -#define KB256 256L * K -#define KB512 512L * K -#define MB1 1L * M -#define MB2 2L * M -#define MB4 4L * M -#define MB8 8L * M -#define MB16 16L * M -#define MB32 32L * M -#define MB64 64L * M -#define MB128 128L * M -#define MB256 256L * M -#define MB512 512L * M +#ifndef B1 + #define B1 1L * Bit +#endif +#define B2 2L * Bit +#define B4 4L * Bit +#define B8 8L * Bit +#define B16 16L * Bit +#define B32 32L * Bit +#define B64 64L * Bit +#define B80 80L * Bit +#define B128 128L * Bit +#define B256 256L * Bit +#define B512 512L * Bit +#define KB1 1L * KiB +#define KB2 2L * KiB +#define KB4 4L * KiB +#define KB8 8L * KiB +#define KB16 16L * KiB +#define KB32 32L * KiB +#define KB64 64L * KiB +#define KB128 128L * KiB +#define KB256 256L * KiB +#define KB512 512L * KiB +#define MB1 1L * MiB +#define MB2 2L * MiB +#define MB4 4L * MiB +#define MB8 8L * MiB +#define MB16 16L * MiB +#define MB32 32L * MiB +#define MB64 64L * MiB +#define MB128 128L * MiB +#define MB256 256L * MiB +#define MB512 512L * MiB //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Chip specific instructions // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// //~~~~~~~~~~~~~~~~~~~~~~~~~ Winbond ~~~~~~~~~~~~~~~~~~~~~~~~~// #define WINBOND_MANID 0xEF - #define PAGESIZE 0x100 + #define SPI_PAGESIZE 0x100 #define WINBOND_WRITE_DELAY 0x02 #define WINBOND_WREN_TIMEOUT 10L @@ -143,9 +145,9 @@ #endif #define arrayLen(x) (sizeof(x) / sizeof(*x)) #define lengthOf(x) (sizeof(x))/sizeof(byte) -#define B 1L -#define K 1024L -#define M K * K +#define Bit 1L +#define KiB 1024L +#define MiB KiB * KiB #define S 1000L #if defined (ARDUINO_ARCH_ESP8266) From 8216dca9ae5bf41210350b671e6ddf3a3523e101 Mon Sep 17 00:00:00 2001 From: VitorBoss Date: Thu, 31 Aug 2017 17:22:48 -0300 Subject: [PATCH 30/34] Fix SPI_PAGESIZE --- examples/TestFlash/TestFlash.ino | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/TestFlash/TestFlash.ino b/examples/TestFlash/TestFlash.ino index 182d0f5..1cc0977 100644 --- a/examples/TestFlash/TestFlash.ino +++ b/examples/TestFlash/TestFlash.ino @@ -257,10 +257,10 @@ void loop() { } addr = Serial.parseInt(); Serial.println(addr); - for (uint16_t i = 0; i < PAGESIZE; ++i) { + for (uint16_t i = 0; i < SPI_PAGESIZE; ++i) { pageBuffer[i] = i; } - if (flash.writeByteArray(addr, &pageBuffer[0], PAGESIZE)) { + if (flash.writeByteArray(addr, &pageBuffer[0], SPI_PAGESIZE)) { clearprintBuffer(); sprintf(printBuffer, "Values from 0 to 255 have been written starting from the address %d", addr); Serial.println(printBuffer); @@ -492,8 +492,8 @@ void printPage(uint32_t _address, uint8_t outputType) { sprintf(buffer, "Reading address (%04x)", _address); Serial.println(buffer); - uint8_t data_buffer[PAGESIZE]; - flash.readByteArray(_address, &data_buffer[0], PAGESIZE); + uint8_t data_buffer[SPI_PAGESIZE]; + flash.readByteArray(_address, &data_buffer[0], SPI_PAGESIZE); _printPageBytes(data_buffer, outputType); } From 77eeff2fc672fb9a4eba89b77cd99d8c3d430e88 Mon Sep 17 00:00:00 2001 From: VitorBoss Date: Thu, 31 Aug 2017 17:32:56 -0300 Subject: [PATCH 31/34] Fix LED_BUILTIN on boards wich don't have it --- src/defines.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/defines.h b/src/defines.h index 201df25..3abe011 100644 --- a/src/defines.h +++ b/src/defines.h @@ -221,3 +221,7 @@ #define Low(param) ((int *)¶m)[0] //0x00yy #define Top(param) ((int *)¶m)[1] //0xyy00 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + +#ifndef LED_BUILTIN //fix for boards without that definition + #define LED_BUILTIN 13 +#endif From 980cd64aca3faf5fe427688bc5453a4ba3adc6e3 Mon Sep 17 00:00:00 2001 From: per1234 Date: Sat, 2 Sep 2017 08:38:41 -0700 Subject: [PATCH 32/34] Use correct separator in keywords.txt The Arduino IDE requires the use of a tab separator between the name and identifier. Without this tab the keyword is not highlighted. Reference: https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5:-Library-specification#keywords --- keywords.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/keywords.txt b/keywords.txt index 92b31c3..13d9504 100644 --- a/keywords.txt +++ b/keywords.txt @@ -12,9 +12,9 @@ SPIFlash KEYWORD1 # Methods and Functions (KEYWORD2) ####################################### begin KEYWORD2 -setClock KEYWORD2 -error KEYWORD2 -libver KEYWORD2 +setClock KEYWORD2 +error KEYWORD2 +libver KEYWORD2 getJEDECID KEYWORD2 getManID KEYWORD2 getAddress KEYWORD2 From 5bd8902df5b7c50fde66b85b8c2c528295833cef Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Sat, 4 Nov 2017 18:33:49 +1000 Subject: [PATCH 33/34] v3.0.0 code tested and good to go. ReadMe.md and wiki need to be updated before release. Code is ready to be moved to Stable branch. --- .../Diagnostics_functions.ino | 50 ++++-- .../FlashDiagnostics/FlashDiagnostics.ino | 28 +++- extras/Changes.log | 34 ++-- extras/DMASAMD.cpp | 158 ++++++++++++++++++ extras/Library speed comparisons.xlsx | Bin extras/SPI pinouts.md | 11 -- ...nbond Flash Instructions - Comparison.xlsx | Bin src/FLASHIO.cpp | 3 +- src/SPIFlash.cpp | 19 ++- src/SPIFlash.h | 4 +- src/defines.h | 40 +---- src/troubleshoot.cpp | 2 +- 12 files changed, 262 insertions(+), 87 deletions(-) mode change 100644 => 100755 extras/Changes.log create mode 100644 extras/DMASAMD.cpp mode change 100644 => 100755 extras/Library speed comparisons.xlsx mode change 100644 => 100755 extras/SPI pinouts.md mode change 100644 => 100755 extras/Winbond Flash Instructions - Comparison.xlsx diff --git a/examples/FlashDiagnostics/Diagnostics_functions.ino b/examples/FlashDiagnostics/Diagnostics_functions.ino index 6120b39..a566420 100644 --- a/examples/FlashDiagnostics/Diagnostics_functions.ino +++ b/examples/FlashDiagnostics/Diagnostics_functions.ino @@ -5,7 +5,7 @@ | v 3.0.0 | |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | Marzogh | - | 10.08.2017 | + | 04.11.2017 | |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | | | For a full diagnostics rundown - with error codes and details of the errors | @@ -108,20 +108,29 @@ void getID() { //---------------------------------------------------------------------------------------------// clearprintBuffer(&printBuffer[1]); + #if defined (ARDUINO_ARCH_ESP32) sprintf(printBuffer, "\t\t\tJEDEC ID: %04xh", JEDEC); + #else + sprintf(printBuffer, "\t\t\tJEDEC ID: %04lxh", JEDEC); + #endif Serial.println(printBuffer); //Serial.print(F("\t\t\tJEDEC ID: ")); //Serial.print(JEDEC, HEX); //Serial.println(F("xh")); clearprintBuffer(&printBuffer[1]); + #if defined (ARDUINO_ARCH_ESP32) + sprintf(printBuffer, "\t\t\tManufacturer ID: %02xh\n\t\t\tMemory Type: %02xh\n\t\t\tCapacity: %u bytes\n\t\t\tMaximum pages: %u", b1, b2, capacity, maxPage); + #else sprintf(printBuffer, "\t\t\tManufacturer ID: %02xh\n\t\t\tMemory Type: %02xh\n\t\t\tCapacity: %lu bytes\n\t\t\tMaximum pages: %lu", b1, b2, capacity, maxPage); + #endif Serial.print(printBuffer); printLine(); } void byteTest() { Serial.println(); - uint32_t wTime, rTime, addr; + uint32_t wTime = 0; + uint32_t rTime, addr; uint8_t _data, _d; _d = 35; @@ -147,7 +156,8 @@ void byteTest() { void charTest() { Serial.println(); - uint32_t wTime, rTime, addr; + uint32_t wTime = 0; + uint32_t rTime, addr; int8_t _data, _d; _d = -110; @@ -174,7 +184,8 @@ void charTest() { void wordTest() { Serial.println(); - uint32_t wTime, rTime, addr; + uint32_t wTime = 0; + uint32_t rTime, addr; uint16_t _data, _d; _d = 4520; @@ -201,7 +212,8 @@ void wordTest() { void shortTest() { Serial.println(); - uint32_t wTime, rTime, addr; + uint32_t wTime = 0; + uint32_t rTime, addr; int16_t _data, _d; _d = -1250; @@ -228,7 +240,8 @@ void shortTest() { void uLongTest() { Serial.println(); - uint32_t wTime, rTime, addr; + uint32_t wTime = 0; + uint32_t rTime, addr; uint32_t _data, _d; _d = 876532; @@ -255,7 +268,8 @@ void uLongTest() { void longTest() { Serial.println(); - uint32_t wTime, rTime, addr; + uint32_t wTime = 0; + uint32_t rTime, addr; int32_t _data, _d; _d = -10959; @@ -282,7 +296,8 @@ void longTest() { void floatTest() { Serial.println(); - uint32_t wTime, rTime, addr; + uint32_t wTime = 0; + uint32_t rTime, addr; float _data, _d; _d = 3.14; @@ -308,8 +323,8 @@ void floatTest() { } void stringTest() { - Serial.println(); - uint32_t wTime, rTime, addr; + uint32_t wTime = 0; + uint32_t rTime, addr; String _data, _d; _d = "This is a test String 123!@#"; @@ -318,7 +333,6 @@ void stringTest() { if (flash.writeStr(addr, _d)) { wTime = flash.functionRunTime(); } - flash.readStr(addr, _data); rTime = flash.functionRunTime(); @@ -332,6 +346,14 @@ void stringTest() { pass(FALSE); } printTime(wTime, rTime); + +#if defined (ARDUINO_ARCH_SAM) || defined (ARDUINO_ARCH_ESP8266) + Serial.println(); + printLine(); + if (!flash.functionRunTime()) { + Serial.println(F("Please uncomment RUNDIAGNOSTIC in SPIFlash.h to see the time taken by each function to run.")); + } +#endif } void structTest() { @@ -352,7 +374,8 @@ void structTest() { _d.s4 = true; _d.s5 = 5; - uint32_t addr, wTime, rTime; + uint32_t wTime = 0; + uint32_t addr, rTime; addr = random(0, 0xFFFFF); @@ -377,7 +400,8 @@ void structTest() { void arrayTest() { Serial.println(); - uint32_t wTime, rTime, addr; + uint32_t wTime = 0; + uint32_t rTime, addr; uint8_t _d[256], _data[256]; for (uint16_t i = 0; i < 256; i++) { diff --git a/examples/FlashDiagnostics/FlashDiagnostics.ino b/examples/FlashDiagnostics/FlashDiagnostics.ino index 1aa0803..9459215 100644 --- a/examples/FlashDiagnostics/FlashDiagnostics.ino +++ b/examples/FlashDiagnostics/FlashDiagnostics.ino @@ -5,7 +5,7 @@ | v 3.0.0 | |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | Marzogh | - | 10.08.2017 | + | 04.11.2017 | |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | | | For a full diagnostics rundown - with error codes and details of the errors | @@ -17,8 +17,6 @@ #include -#define RUNDIAGNOSTIC //Outputs detailed diagnostic on error codes generated by library to Serial - #if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) // Required for Serial on Zero based boards #define Serial SERIAL_PORT_USBVIRTUAL @@ -39,8 +37,8 @@ #define TRUE 1 #define FALSE 0 -//SPIFlash flash(SS1, &SPI2); //Use this constructor if using an SPI bus other than the default SPI. Only works with chips with more than one hardware SPI bus -SPIFlash flash; +//SPIFlash flash(SS1, &SPI1); //Use this constructor if using an SPI bus other than the default SPI. Only works with chips with more than one hardware SPI bus +SPIFlash flash(15); void setup() { Serial.begin(BAUD_RATE); @@ -57,7 +55,7 @@ void setup() { randomSeed(analogRead(RANDPIN)); flash.begin(); //To use a custom flash memory size (if using memory from manufacturers not officially supported by the library) - declare a size variable according to the list in defines.h - //flash.begin(MB1); + //flash.begin(MB(1)); Serial.println(); Serial.println(); @@ -66,20 +64,32 @@ void setup() { eraseBlock64KTest(); eraseBlock32KTest(); eraseSectorTest(); - + +#if defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_ESP8266) + delay(10); + powerDownTest(); + powerUpTest(); + Serial.println(); +#endif + byteTest(); charTest(); wordTest(); shortTest(); uLongTest(); +#if defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_ESP8266) + delay(10); +#endif longTest(); floatTest(); - stringTest(); structTest(); arrayTest(); - + stringTest(); + +#if !defined(ARDUINO_ARCH_SAM) || !defined(ARDUINO_ARCH_ESP8266) powerDownTest(); powerUpTest(); +#endif printLine(); if (!flash.functionRunTime()) { Serial.println(F("Please uncomment RUNDIAGNOSTIC in SPIFlash.h to see the time taken by each function to run.")); diff --git a/extras/Changes.log b/extras/Changes.log old mode 100644 new mode 100755 index c9a7aa2..73291d9 --- a/extras/Changes.log +++ b/extras/Changes.log @@ -7,30 +7,37 @@ // 09.08.2017 // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// To check: ---> Check _nextBuf function and optimize Bugs Squashed: --> The writeByteArray() & writeCharArray() bug that occurred when writing arrays that spanned page boundaries (squashed in v2.5.0), stayed around to haunt the other functions. Writing any data larger than a single byte that spanned page boundaries would cause the data to wrap around to the beginning of the page. The likelihood of this occurring was slim - no one has reported it to date. However, just in case, this has now been squashed in this release. Deprecations: --> Going forward the ATTiny85 is no longer officially supported. ---> flash.begin() no longer takes any variable as an argument. To define a custom CHIPSIZE to use the library with an unsupported chip - refer to 'Enhancements -> 6' --> The library no longer supports using the page number + offset combination instead of addresses. If your code requires you to use a page number + offset combination, use the following code to help address = (pagenumber << 8) + offset. _____________________________________ (32 bit) | (16 bit) | (8 bit) --> The constructor no longer takes the pageOverflow variable as an argument. Page overflow is globally enabled by default and can be disabled by including a "#define DISABLEOVERFLOW" at the beginning of the user code. + New Boards supported: ---> +--> Nucleo-F091RC +--> Adafruit Feather M0 + +New Flash manufacturers supported: +--> Microchip (SST25 & SST26 series) +--> Cypress +--> Spansion Enhancements: --> Confirmed to work with SPANSION/CYPRESS & MICROCHIP (Both SST25 & SST26 series). ---> When RUNDIAGNOSTIC is uncommented in SPIFlash.h, users now have access to a new function called flash.functionRunTime() which can be called after any library I/O function is run. flash.functionRunTime() returns the time taken by the previous function to run, in microseconds (as a float). An example use case can be found when the FlashDiagnostics sketch is run with RUNDIAGNOSTIC uncommented. ---> _notBusy() is faster ---> Completely re-written FlashDiagnostics - uses fewer resources, compatible with more chips and boards ---> Library now works with Microchip flash memory. (Further optimizations required) +--> If not using an officially supported chip, use the following variation of flash.begin() : + flash.begin(flashChipSize); + + where flashChipSize is indicated in Bytes, Kilobytes or Megabytes. (Refer to the next two items in this change log) +--> Including 'flashChipSize' in flash.begin() compiles more efficiently than in prvious versions. +--> The way memory size is indicated by the users in flash.begin(flashChipSize) has changed - please refer to defines.h or the wiki for further information. The new method enables users to define any custom size unlike the previous version where only a limited number of predetermined sizes were available to use. --> Library faster than before (Refer to Library speed comparison in the extras folder for timing details): - Improvements in speed in v3.0.0 when compared to v2.6.0 (values in percentage of time v3.0.0 is faster than v2.6.0) + Improvements in speed in v3.0.0 when compared to v2.7.0 (values in percentage of time v3.0.0 is faster than v2.7.0) (+) writeByte -> +3% (+) writeChar -> +6% (+) writeWord -> +3% @@ -45,10 +52,13 @@ Enhancements: (+) eraseBlock32K -> +99.4% (+) eraseBlock64K -> +99.5% (+) eraseChip -> +12% ---> All functions except the Byte/Char Array Read/Write functions now call an internal _write/_read function. ---> Restructured the internal _troubleshoot() function to be better human readable and easier to compile. ---> No need to include CHIPSIZE in flash.begin() any more. Just defining CHIPSIZE in user code as one of the standard sizes as in defines.h will be enough. (Refer to 'Deprecations -> 1' above) ---> Constructor changed to enable user to choose one of multiple SPI ports - if available. Look at wiki for further info. + +--> Constructor changed to enable user to choose one of multiple SPI ports - if available. Look at wiki for further info +--> When RUNDIAGNOSTIC is uncommented in SPIFlash.h, users now have access to a new function called flash.functionRunTime() which can be called after any library I/O function is run. flash.functionRunTime() returns the time taken by the previous function to run, in microseconds (as a float). An example use case can be found when the FlashDiagnostics sketch is run with RUNDIAGNOSTIC uncommented. +--> _notBusy() is faster +--> Completely re-written FlashDiagnostics - uses fewer resources, compatible with more chips and boards +--> All functions except the Byte/Char Array Read/Write functions now call an internal _write/_read function for increased ease of compilation, execution and troubleshooting +--> Restructured the internal _troubleshoot() function to be better human readable and faster to compile. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Version 2.7.0 // // Author: Prajwal Bhattaram // diff --git a/extras/DMASAMD.cpp b/extras/DMASAMD.cpp new file mode 100644 index 0000000..678627b --- /dev/null +++ b/extras/DMASAMD.cpp @@ -0,0 +1,158 @@ +/* Arduino SPIFlash Library v.2.6.0 + * Copyright (C) 2017 by Prajwal Bhattaram + * Created by Prajwal Bhattaram - 30/09/2016 + * Modified by Prajwal Bhattaram - 14/04/2017 + * Original code from @manitou48 + * + * 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 + * . + */ + +#include "SPIFlash.h" + +//--------------------------- Private Arduino Zero Variables ----------------------------// + Sercom *sercom = (Sercom *)ZERO_SPISERCOM; //Set SPI SERCOM + // DMA 12 channels + typedef struct { + uint16_t btctrl; + uint16_t btcnt; + uint32_t srcaddr; + uint32_t dstaddr; + uint32_t descaddr; + } dmacdescriptor ; + volatile dmacdescriptor wrb[12] __attribute__ ((aligned (16))); + dmacdescriptor descriptor_section[12] __attribute__ ((aligned (16))); + dmacdescriptor descriptor __attribute__ ((aligned (16))); + + static uint32_t chnltx = 0, chnlrx = 1; // DMA channels + enum XfrType { DoTX, DoRX, DoTXRX}; + static XfrType xtype; + static uint8_t rxsink[1], txsrc[1] = {0xff}; + volatile uint32_t dmadone; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +// Private functions used by Arduino Zero DMA operations // +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + +void SPIFlash::_zeroDMAC_Handler(void) { + // interrupts DMAC_CHINTENCLR_TERR DMAC_CHINTENCLR_TCMPL DMAC_CHINTENCLR_SUSP + uint8_t active_channel; + + // disable irqs ? + __disable_irq(); + active_channel = DMAC->INTPEND.reg & DMAC_INTPEND_ID_Msk; // get channel number + DMAC->CHID.reg = DMAC_CHID_ID(active_channel); + dmadone = DMAC->CHINTFLAG.reg; + DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_TCMPL; // clear + DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_TERR; + DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_SUSP; + __enable_irq(); +} + +void SPIFlash::_zeroDma_init() { + // probably on by default + PM->AHBMASK.reg |= PM_AHBMASK_DMAC ; + PM->APBBMASK.reg |= PM_APBBMASK_DMAC ; + NVIC_EnableIRQ( DMAC_IRQn ) ; + + DMAC->BASEADDR.reg = (uint32_t)descriptor_section; + DMAC->WRBADDR.reg = (uint32_t)wrb; + DMAC->CTRL.reg = DMAC_CTRL_DMAENABLE | DMAC_CTRL_LVLEN(0xf); +} + +void SPIFlash::_zeroSpi_xfr(void *txdata, void *rxdata, size_t n) { + uint32_t temp_CHCTRLB_reg; + + // set up transmit channel + DMAC->CHID.reg = DMAC_CHID_ID(chnltx); + DMAC->CHCTRLA.reg &= ~DMAC_CHCTRLA_ENABLE; + DMAC->CHCTRLA.reg = DMAC_CHCTRLA_SWRST; + DMAC->SWTRIGCTRL.reg &= (uint32_t)(~(1 << chnltx)); + temp_CHCTRLB_reg = DMAC_CHCTRLB_LVL(0) | + DMAC_CHCTRLB_TRIGSRC(SERCOM4_DMAC_ID_TX) | DMAC_CHCTRLB_TRIGACT_BEAT; + DMAC->CHCTRLB.reg = temp_CHCTRLB_reg; + DMAC->CHINTENSET.reg = DMAC_CHINTENSET_MASK ; // enable all 3 interrupts + descriptor.descaddr = 0; + descriptor.dstaddr = (uint32_t) &sercom->SPI.DATA.reg; + descriptor.btcnt = n; + descriptor.srcaddr = (uint32_t)txdata; + descriptor.btctrl = DMAC_BTCTRL_VALID; + if (xtype != DoRX) { + descriptor.srcaddr += n; + descriptor.btctrl |= DMAC_BTCTRL_SRCINC; + } + memcpy(&descriptor_section[chnltx],&descriptor, sizeof(dmacdescriptor)); + + // rx channel enable interrupts + DMAC->CHID.reg = DMAC_CHID_ID(chnlrx); + DMAC->CHCTRLA.reg &= ~DMAC_CHCTRLA_ENABLE; + DMAC->CHCTRLA.reg = DMAC_CHCTRLA_SWRST; + DMAC->SWTRIGCTRL.reg &= (uint32_t)(~(1 << chnlrx)); + temp_CHCTRLB_reg = DMAC_CHCTRLB_LVL(0) | + DMAC_CHCTRLB_TRIGSRC(SERCOM4_DMAC_ID_RX) | DMAC_CHCTRLB_TRIGACT_BEAT; + DMAC->CHCTRLB.reg = temp_CHCTRLB_reg; + DMAC->CHINTENSET.reg = DMAC_CHINTENSET_MASK ; // enable all 3 interrupts + dmadone = 0; + descriptor.descaddr = 0; + descriptor.srcaddr = (uint32_t) &sercom->SPI.DATA.reg; + descriptor.btcnt = n; + descriptor.dstaddr = (uint32_t)rxdata; + descriptor.btctrl = DMAC_BTCTRL_VALID; + if (xtype != DoTX) { + descriptor.dstaddr += n; + descriptor.btctrl |= DMAC_BTCTRL_DSTINC; + } + memcpy(&descriptor_section[chnlrx],&descriptor, sizeof(dmacdescriptor)); + + // start both channels ? order matter ? + DMAC->CHID.reg = DMAC_CHID_ID(chnltx); + Serial.println("A"); + DMAC->CHCTRLA.reg |= DMAC_CHCTRLA_ENABLE; + system_interrupt_leave_critical_section(); + Serial.println("B"); + DMAC->CHID.reg = DMAC_CHID_ID(chnlrx); + Serial.println("C"); + DMAC->CHCTRLA.reg |= DMAC_CHCTRLA_ENABLE; + Serial.println("D"); + + while(!dmadone); // await DMA done isr + + DMAC->CHID.reg = DMAC_CHID_ID(chnltx); //disable DMA to allow lib SPI + DMAC->CHCTRLA.reg &= ~DMAC_CHCTRLA_ENABLE; + DMAC->CHID.reg = DMAC_CHID_ID(chnlrx); + DMAC->CHCTRLA.reg &= ~DMAC_CHCTRLA_ENABLE; +} + +void SPIFlash::_zeroSpi_write(void *data, size_t n) { + xtype = DoTX; + Serial.println("SPI_write started"); + _zeroSpi_xfr(data,rxsink,n); + Serial.println("WRITE DONE"); +} +void SPIFlash::_zeroSpi_read(void *data, size_t n) { + xtype = DoRX; + _zeroSpi_xfr(txsrc,data,n); + Serial.println("READ DONE"); +} +void SPIFlash::_zeroSpi_transfer(void *txdata, void *rxdata, size_t n) { + xtype = DoTXRX; + _zeroSpi_xfr(txdata,rxdata,n); + Serial.println("transfer done"); +} diff --git a/extras/Library speed comparisons.xlsx b/extras/Library speed comparisons.xlsx old mode 100644 new mode 100755 diff --git a/extras/SPI pinouts.md b/extras/SPI pinouts.md old mode 100644 new mode 100755 index e952a72..0b185f4 --- a/extras/SPI pinouts.md +++ b/extras/SPI pinouts.md @@ -21,15 +21,4 @@ * |____________|________________| * * -* Simblee (Sparkfun breakout) SPI pinout is as follows: -* _____________________________ -* | GPIO # | HSPI Function | -* |------------|----------------| -* | Pin 3 | MISO (DIN) | -* | Pin 5 | MOSI (DOUT) | -* | Pin 4 | CLOCK | -* | Pin 6 | CS / SS | -* |____________|________________| -* -* */ diff --git a/extras/Winbond Flash Instructions - Comparison.xlsx b/extras/Winbond Flash Instructions - Comparison.xlsx old mode 100644 new mode 100755 diff --git a/src/FLASHIO.cpp b/src/FLASHIO.cpp index 3bba149..d3f97af 100644 --- a/src/FLASHIO.cpp +++ b/src/FLASHIO.cpp @@ -1,6 +1,6 @@ /* Arduino SPIFlash Library v.3.0.0 * Copyright (C) 2017 by Prajwal Bhattaram - * Created by Prajwal Bhattaram - 02/05/2017 + * Created by Prajwal Bhattaram - 04/11/2017 * * 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 @@ -413,6 +413,7 @@ bool SPIFlash::_disableGlobalBlockProtect(void) { _delay_us(50); _writeDisable(); } + return true; } //Identifies the chip diff --git a/src/SPIFlash.cpp b/src/SPIFlash.cpp index ee5ea87..d62b5d5 100644 --- a/src/SPIFlash.cpp +++ b/src/SPIFlash.cpp @@ -2,7 +2,7 @@ * Copyright (C) 2017 by Prajwal Bhattaram * Created by Prajwal Bhattaram - 19/05/2015 * Modified by @boseji - 02/03/2017 - * Modified by Prajwal Bhattaram - 09/08/2017 + * Modified by Prajwal Bhattaram - 04/11/2017 * * 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 @@ -68,7 +68,11 @@ SPIFlash::SPIFlash(uint8_t cs) { //Identifies chip and establishes parameters bool SPIFlash::begin(size_t flashChipSize) { #ifdef RUNDIAGNOSTIC - Serial.println("Full Diagnostics Workup initiated!"); + Serial.println("Chip Diagnostics initiated."); + Serial.println(); +#endif +#ifdef HIGHSPEED + Serial.println("Highspeed mode initiated."); Serial.println(); #endif BEGIN_SPI @@ -78,6 +82,9 @@ bool SPIFlash::begin(size_t flashChipSize) { #endif // If no capacity is defined in user code if (!flashChipSize) { + #ifdef RUNDIAGNOSTIC + Serial.println("No Chip size defined by user"); + #endif bool retVal = _chipID(); _endSPI(); return retVal; @@ -92,6 +99,11 @@ bool SPIFlash::begin(size_t flashChipSize) { _chip.supported = false; } _endSPI(); + + if (_chip.manufacturerID == CYPRESS_MANID) { + setClock(SPI_CLK/4); + } + return true; } @@ -747,9 +759,10 @@ bool SPIFlash::eraseChip(void) { _endSPI(); while(_readStat1() & BUSY) { - _delay_us(30000L); + //_delay_us(30000L); } _endSPI(); + #ifdef RUNDIAGNOSTIC _spifuncruntime = micros() - _spifuncruntime; #endif diff --git a/src/SPIFlash.h b/src/SPIFlash.h index b393411..2a20d2e 100644 --- a/src/SPIFlash.h +++ b/src/SPIFlash.h @@ -2,7 +2,7 @@ * Copyright (C) 2017 by Prajwal Bhattaram * Created by Prajwal Bhattaram - 19/05/2015 * Modified by @boseji - 02/03/2017 - * Modified by Prajwal Bhattaram - 09/08/2017 + * Modified by Prajwal Bhattaram - 04/11/2017 * * 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 @@ -33,7 +33,7 @@ // // // Error codes will be generated and returned on functions // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - #define RUNDIAGNOSTIC // +#define RUNDIAGNOSTIC // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// diff --git a/src/defines.h b/src/defines.h index 3abe011..02fcacf 100644 --- a/src/defines.h +++ b/src/defines.h @@ -1,7 +1,7 @@ /* Arduino SPIFlash Library v.3.0.0 * Copyright (C) 2017 by Prajwal Bhattaram * Created by Prajwal Bhattaram - 19/05/2015 - * Modified by Prajwal Bhattaram - 02/08/2017 + * Modified by Prajwal Bhattaram - 04/11/2017 * * 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 @@ -54,39 +54,9 @@ // General size definitions // // B = Bytes; KiB = Kilo Bytes; MiB = Mega Bytes // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -#ifndef B1 - #define B1 1L * Bit -#endif -#define B2 2L * Bit -#define B4 4L * Bit -#define B8 8L * Bit -#define B16 16L * Bit -#define B32 32L * Bit -#define B64 64L * Bit -#define B80 80L * Bit -#define B128 128L * Bit -#define B256 256L * Bit -#define B512 512L * Bit -#define KB1 1L * KiB -#define KB2 2L * KiB -#define KB4 4L * KiB -#define KB8 8L * KiB -#define KB16 16L * KiB -#define KB32 32L * KiB -#define KB64 64L * KiB -#define KB128 128L * KiB -#define KB256 256L * KiB -#define KB512 512L * KiB -#define MB1 1L * MiB -#define MB2 2L * MiB -#define MB4 4L * MiB -#define MB8 8L * MiB -#define MB16 16L * MiB -#define MB32 32L * MiB -#define MB64 64L * MiB -#define MB128 128L * MiB -#define MB256 256L * MiB -#define MB512 512L * MiB +#define B(x) size_t(x*BYTE) +#define KB(x) size_t(x*KiB) +#define MB(x) size_t(x*MiB) //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Chip specific instructions // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -145,7 +115,7 @@ #endif #define arrayLen(x) (sizeof(x) / sizeof(*x)) #define lengthOf(x) (sizeof(x))/sizeof(byte) -#define Bit 1L +#define BYTE 1L #define KiB 1024L #define MiB KiB * KiB #define S 1000L diff --git a/src/troubleshoot.cpp b/src/troubleshoot.cpp index 18e0588..ce71a9f 100644 --- a/src/troubleshoot.cpp +++ b/src/troubleshoot.cpp @@ -56,7 +56,7 @@ void SPIFlash::_troubleshoot(uint8_t _code, bool printoverride) { Serial.println(); switch (_code) { case SUCCESS: - Serial.println("Action completed successfully"); + Serial.println("Function executed successfully"); break; case NORESPONSE: From d3fb527426d1cc72337fdc95b2db7e5112d7b71d Mon Sep 17 00:00:00 2001 From: Prajwal Bhattaram Date: Sat, 4 Nov 2017 21:17:13 +1000 Subject: [PATCH 34/34] Added a function which returns the unique ID of the flash memory chip as a 64-bit integer. --- .../Diagnostics_functions.ino | 12 +++++++ .../FlashDiagnostics/FlashDiagnostics.ino | 2 +- extras/Changes.log | 1 + keywords.txt | 31 ++++++++++++++----- src/SPIFlash.cpp | 23 ++++++++++++++ src/SPIFlash.h | 2 ++ src/defines.h | 1 + 7 files changed, 63 insertions(+), 9 deletions(-) mode change 100644 => 100755 keywords.txt diff --git a/examples/FlashDiagnostics/Diagnostics_functions.ino b/examples/FlashDiagnostics/Diagnostics_functions.ino index a566420..b5d8e1a 100644 --- a/examples/FlashDiagnostics/Diagnostics_functions.ino +++ b/examples/FlashDiagnostics/Diagnostics_functions.ino @@ -71,6 +71,16 @@ void pass(bool _status) { } } +void printUniqueID(void) { + Serial.print("Unique ID: "); + long long _uniqueID = flash.getUniqueID(); + Serial.print(uint32_t(_uniqueID/1000000L)); + Serial.print(uint32_t(_uniqueID%1000000L)); + Serial.print(", "); + Serial.print(uint32_t(_uniqueID >> 32), HEX); + Serial.print(uint32_t(_uniqueID), HEX); +} + void getID() { char printBuffer[128]; printLine(); @@ -124,6 +134,8 @@ void getID() { sprintf(printBuffer, "\t\t\tManufacturer ID: %02xh\n\t\t\tMemory Type: %02xh\n\t\t\tCapacity: %lu bytes\n\t\t\tMaximum pages: %lu", b1, b2, capacity, maxPage); #endif Serial.print(printBuffer); + Serial.print("\n\t\t\t"); + printUniqueID(); printLine(); } diff --git a/examples/FlashDiagnostics/FlashDiagnostics.ino b/examples/FlashDiagnostics/FlashDiagnostics.ino index 9459215..f153eab 100644 --- a/examples/FlashDiagnostics/FlashDiagnostics.ino +++ b/examples/FlashDiagnostics/FlashDiagnostics.ino @@ -38,7 +38,7 @@ #define FALSE 0 //SPIFlash flash(SS1, &SPI1); //Use this constructor if using an SPI bus other than the default SPI. Only works with chips with more than one hardware SPI bus -SPIFlash flash(15); +SPIFlash flash; void setup() { Serial.begin(BAUD_RATE); diff --git a/extras/Changes.log b/extras/Changes.log index 73291d9..8d070c1 100755 --- a/extras/Changes.log +++ b/extras/Changes.log @@ -59,6 +59,7 @@ Enhancements: --> Completely re-written FlashDiagnostics - uses fewer resources, compatible with more chips and boards --> All functions except the Byte/Char Array Read/Write functions now call an internal _write/_read function for increased ease of compilation, execution and troubleshooting --> Restructured the internal _troubleshoot() function to be better human readable and faster to compile. +--> Added a function `getUniqueID()` which returns the unique ID of the flash memory chip as a 64-bit integer. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Version 2.7.0 // // Author: Prajwal Bhattaram // diff --git a/keywords.txt b/keywords.txt old mode 100644 new mode 100755 index 13d9504..f10adaa --- a/keywords.txt +++ b/keywords.txt @@ -1,9 +1,9 @@ ####################################### -# Syntax Coloring Map SPI +# Syntax Coloring Map SPIFlash ####################################### ####################################### -# Datatypes (KEYWORD1) +# Class (KEYWORD1) ####################################### SPIFlash KEYWORD1 @@ -12,15 +12,17 @@ SPIFlash KEYWORD1 # Methods and Functions (KEYWORD2) ####################################### begin KEYWORD2 -setClock KEYWORD2 -error KEYWORD2 -libver KEYWORD2 -getJEDECID KEYWORD2 +setClock KEYWORD2 +libver KEYWORD2 +error KEYWORD2 getManID KEYWORD2 +getJEDECID KEYWORD2 +getUniqueID KEYWORD2 getAddress KEYWORD2 +sizeofStr KEYWORD2 getCapacity KEYWORD2 getMaxPage KEYWORD2 -sizeofStr KEYWORD2 +functionRunTime KEYWORD2 readByte KEYWORD2 readByteArray KEYWORD2 readChar KEYWORD2 @@ -52,7 +54,20 @@ resumeProg KEYWORD2 powerUp KEYWORD2 powerDown KEYWORD2 - ####################################### # Constants (LITERAL1) ####################################### +WINBOND_MANID LITERAL1 +MICROCHIP_MANID LITERAL1 +CYPRESS_MANID LITERAL1 +ADESTO_MANID LITERAL1 +MICRON_MANID LITERAL1 +NULLBYTE LITERAL1 +NULLINT LITERAL1 +BYTE LITERAL1 +KiB LITERAL1 +MiB LITERAL1 + +####################################### +# Built-in variables (LITERAL2) +####################################### diff --git a/src/SPIFlash.cpp b/src/SPIFlash.cpp index d62b5d5..df805c8 100644 --- a/src/SPIFlash.cpp +++ b/src/SPIFlash.cpp @@ -165,6 +165,29 @@ uint32_t SPIFlash::getJEDECID(void) { return id; } +// Returns a 64-bit Unique ID that is unique to each flash memory chip +uint64_t SPIFlash::getUniqueID(void) { + if(!_notBusy()) { + return false; + } + _beginSPI(UNIQUEID); + for (uint8_t i = 0; i < 4; i++) { + _nextByte(DUMMYBYTE); + } + + for (uint8_t i = 0; i < 8; i++) { + _uniqueID[i] = _nextByte(READ); + } + CHIP_DESELECT + + long long _uid; + for (uint8_t i = 0; i < 8; i++) { + _uid += _uniqueID[i]; + _uid = _uid << 8; + } + return _uid; +} + //Gets the next available address for use. Has two variants: // A. Takes the size of the data as an argument and returns a 32-bit address // B. Takes a three variables, the size of the data and two other variables to return a page number value & an offset into. diff --git a/src/SPIFlash.h b/src/SPIFlash.h index 2a20d2e..49705e9 100644 --- a/src/SPIFlash.h +++ b/src/SPIFlash.h @@ -152,6 +152,7 @@ class SPIFlash { uint8_t error(bool verbosity = false); uint16_t getManID(void); uint32_t getJEDECID(void); + uint64_t getUniqueID(void); uint32_t getAddress(uint16_t size); uint16_t sizeofStr(String &inputStr); uint32_t getCapacity(void); @@ -289,6 +290,7 @@ class SPIFlash { }; chipID _chip; uint32_t currentAddress, _currentAddress = 0; + uint8_t _uniqueID[8]; const uint8_t _capID[14] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x43, 0x4B, 0x00, 0x01}; diff --git a/src/defines.h b/src/defines.h index 02fcacf..ff02333 100644 --- a/src/defines.h +++ b/src/defines.h @@ -49,6 +49,7 @@ #define POWERDOWN 0xB9 #define RELEASE 0xAB #define READSFDP 0x5A +#define UNIQUEID 0x4B //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // General size definitions //