BayEOSArduino Library
SPIFlash.h
1 /* Arduino SPIMemory Library v.3.4.0
2  * Copyright (C) 2019 by Prajwal Bhattaram
3  * Created by Prajwal Bhattaram - 19/05/2015
4  * Modified by @boseji <salearj@hotmail.com> - 02/03/2017
5  * Modified by Prajwal Bhattaram - 03/06/2019
6  *
7  * This file is part of the Arduino SPIMemory Library. This library is for
8  * Flash and FRAM memory modules. In its current form it enables reading,
9  * writing and erasing data from and to various locations;
10  * suspending and resuming programming/erase and powering down for low power operation.
11  *
12  * This Library is free software: you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation, either version 3 of the License, or
15  * (at your option) any later version.
16  *
17  * This Library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License v3.0
23  * along with the Arduino SPIMemory Library. If not, see
24  * <http://www.gnu.org/licenses/>.
25  */
26 
27 #ifndef SPIFLASH_H
28 #define SPIFLASH_H
29 
30 #include "SPIMemory.h"
31 
32 class SPIFlash {
33 public:
34  //------------------------------------ Constructor ------------------------------------//
35  //New Constructor to Accept the PinNames as a Chip select Parameter - @boseji <salearj@hotmail.com> 02.03.17
36  #if defined (ARDUINO_ARCH_SAMD) || defined(ARCH_STM32) || defined(ARDUINO_ARCH_ESP32)
37  SPIFlash(uint8_t cs = CS, SPIClass *spiinterface=&SPI);
38  #elif defined (BOARD_RTL8195A)
39  SPIFlash(PinName cs = CS);
40  #else
41  SPIFlash(uint8_t cs = CS);
42  SPIFlash(int8_t *SPIPinsArray);
43  #endif
44  //----------------------------- Initial / Chip Functions ------------------------------//
45  bool begin(uint32_t flashChipSize = 0);
46  #ifdef SPI_HAS_TRANSACTION
47  void setClock(uint32_t clockSpeed);
48  #else
49  void setClock(uint8_t clockdiv);
50  #endif
51  bool libver(uint8_t *b1, uint8_t *b2, uint8_t *b3);
52  bool sfdpPresent(void);
53  uint8_t error(bool verbosity = false);
54  uint16_t getManID(void);
55  uint32_t getJEDECID(void);
56  uint64_t getUniqueID(void);
57  uint32_t getAddress(uint16_t size);
58  uint16_t sizeofStr(String &inputStr);
59  uint32_t getCapacity(void);
60  uint32_t getMaxPage(void);
61  float functionRunTime(void);
62  //-------------------------------- Write / Read Bytes ---------------------------------//
63  bool writeByte(uint32_t _addr, uint8_t data, bool errorCheck = true);
64  uint8_t readByte(uint32_t _addr, bool fastRead = false);
65  //----------------------------- Write / Read Byte Arrays ------------------------------//
66  bool writeByteArray(uint32_t _addr, uint8_t *data_buffer, size_t bufferSize, bool errorCheck = true);
67  bool readByteArray(uint32_t _addr, uint8_t *data_buffer, size_t bufferSize, bool fastRead = false);
68  //-------------------------------- Write / Read Chars ---------------------------------//
69  bool writeChar(uint32_t _addr, int8_t data, bool errorCheck = true);
70  int8_t readChar(uint32_t _addr, bool fastRead = false);
71  //------------------------------ Write / Read Char Arrays -----------------------------//
72  bool writeCharArray(uint32_t _addr, char *data_buffer, size_t bufferSize, bool errorCheck = true);
73  bool readCharArray(uint32_t _addr, char *data_buffer, size_t buffer_size, bool fastRead = false);
74  //-------------------------------- Write / Read Shorts --------------------------------//
75  bool writeShort(uint32_t _addr, int16_t data, bool errorCheck = true);
76  int16_t readShort(uint32_t _addr, bool fastRead = false);
77  //-------------------------------- Write / Read Words ---------------------------------//
78  bool writeWord(uint32_t _addr, uint16_t data, bool errorCheck = true);
79  uint16_t readWord(uint32_t _addr, bool fastRead = false);
80  //-------------------------------- Write / Read Longs ---------------------------------//
81  bool writeLong(uint32_t _addr, int32_t data, bool errorCheck = true);
82  int32_t readLong(uint32_t _addr, bool fastRead = false);
83  //--------------------------- Write / Read Unsigned Longs -----------------------------//
84  bool writeULong(uint32_t _addr, uint32_t data, bool errorCheck = true);
85  uint32_t readULong(uint32_t _addr, bool fastRead = false);
86  //-------------------------------- Write / Read Floats --------------------------------//
87  bool writeFloat(uint32_t _addr, float data, bool errorCheck = true);
88  float readFloat(uint32_t _addr, bool fastRead = false);
89  //-------------------------------- Write / Read Strings -------------------------------//
90  bool writeStr(uint32_t _addr, String &data, bool errorCheck = true);
91  bool readStr(uint32_t _addr, String &data, bool fastRead = false);
92  //------------------------------- Write / Read Anything -------------------------------//
93 
94  template <class T> bool writeAnything(uint32_t _addr, const T& data, bool errorCheck = true);
95  template <class T> bool readAnything(uint32_t _addr, T& data, bool fastRead = false);
96  //-------------------------------- Erase functions ------------------------------------//
97  bool eraseSection(uint32_t _addr, uint32_t _sz);
98  bool eraseSector(uint32_t _addr);
99  bool eraseBlock32K(uint32_t _addr);
100  bool eraseBlock64K(uint32_t _addr);
101  bool eraseChip(void);
102  //-------------------------------- Power functions ------------------------------------//
103  bool suspendProg(void);
104  bool resumeProg(void);
105  bool powerDown(void);
106  bool powerUp(void);
107  //-------------------------- Public Arduino Due Functions -----------------------------//
108 //#if defined (ARDUINO_ARCH_SAM)
109  //uint32_t freeRAM(void);
110 //#endif
111  //------------------------------- Public variables ------------------------------------//
112 
113 private:
114  //------------------------------- Private functions -----------------------------------//
115  unsigned _createMask(unsigned a, unsigned b);
116  void _troubleshoot(uint8_t _code, bool printoverride = false);
117  void _endSPI(void);
118  bool _disableGlobalBlockProtect(void);
119  bool _isChipPoweredDown(void);
120  bool _prep(uint8_t opcode, uint32_t _addr, uint32_t size = 0);
121  bool _startSPIBus(void);
122  bool _beginSPI(uint8_t opcode);
123  bool _noSuspend(void);
124  bool _notBusy(uint32_t timeout = BUSY_TIMEOUT);
125  bool _notPrevWritten(uint32_t _addr, uint32_t size = 1);
126  bool _writeEnable(bool _troubleshootEnable = true);
127  bool _writeDisable(void);
128  bool _getJedecId(void);
129  bool _getManId(uint8_t *b1, uint8_t *b2);
130  bool _chipID(uint32_t flashChipSize = 0);
131  bool _transferAddress(void);
132  bool _addressCheck(uint32_t _addr, uint32_t size = 1);
133  bool _enable4ByteAddressing(void);
134  bool _disable4ByteAddressing(void);
135  uint8_t _nextByte(char IOType, uint8_t data = NULLBYTE);
136  uint16_t _nextInt(uint16_t = NULLINT);
137  void _nextBuf(uint8_t opcode, uint8_t *data_buffer, uint32_t size);
138  uint8_t _readStat1(void);
139  uint8_t _readStat2(void);
140  uint8_t _readStat3(void);
141  bool _getSFDPTable(uint32_t _tableAddress, uint8_t *data_buffer, uint8_t numberOfDWords);
142  bool _getSFDPData(uint32_t _address, uint8_t *data_buffer, uint8_t numberOfBytes);
143  uint32_t _getSFDPdword(uint32_t _tableAddress, uint8_t dWordNumber);
144  uint16_t _getSFDPint(uint32_t _tableAddress, uint8_t dWordNumber, uint8_t startByte);
145  uint8_t _getSFDPbyte(uint32_t _tableAddress, uint8_t dWordNumber, uint8_t byteNumber);
146  bool _getSFDPbit(uint32_t _tableAddress, uint8_t dWordNumber, uint8_t bitNumber);
147  uint32_t _getSFDPTableAddr(uint32_t paramHeaderNum);
148  uint32_t _calcSFDPEraseTimeUnits(uint8_t _unitBits);
149  bool _checkForSFDP(void);
150  void _getSFDPEraseParam(void);
151  void _getSFDPProgramTimeParam(void);
152  bool _getSFDPFlashParam(void);
153  template <class T> bool _write(uint32_t _addr, const T& value, uint32_t _sz, bool errorCheck, uint8_t _dataType);
154  template <class T> bool _read(uint32_t _addr, T& value, uint32_t _sz, bool fastRead = false, uint8_t _dataType = 0x00);
155  //template <class T> bool _writeErrorCheck(uint32_t _addr, const T& value);
156  template <class T> bool _writeErrorCheck(uint32_t _addr, const T& value, uint32_t _sz, uint8_t _dataType = 0x00);
157  //-------------------------------- Private variables ----------------------------------//
158  #ifdef SPI_HAS_TRANSACTION
159  SPISettings _settings;
160  bool _SPISettingsSet = false;
161  #else
162  uint8_t _clockdiv;
163  #endif
164 
165  //If multiple SPI ports are available this variable is used to choose between them (SPI, SPI1, SPI2 etc.)
166  SPIClass *_spi;
167 
168  #if !defined (BOARD_RTL8195A)
169  uint8_t csPin;
170  #else
171  // Object declaration for the GPIO HAL type for csPin - @boseji <salearj@hotmail.com> 02.03.17
172  gpio_t csPin;
173  #endif
174 
175  // Variables specific to using non-standard SPI (currently only tested with ESP32)
176  struct _SPIPins {
177  int8_t sck = -1;
178  int8_t miso = -1;
179  int8_t mosi = -1;
180  int8_t ss = -1;
181  };
182  _SPIPins _nonStdSPI;
183  //_SPIPins _stdSPI;
184  uint8_t _SPIInUse;
185 
186  volatile uint8_t *cs_port;
187  bool pageOverflow;
188  bool SPIBusState = false;
189  bool chipPoweredDown = false;
190  bool address4ByteEnabled = false;
191  bool _loopedOver = false;
192  uint8_t cs_mask, errorcode, stat1, stat2, stat3, _SPCR, _SPSR, _a0, _a1, _a2;
193  char READ = 'R';
194  char WRITE = 'W';
195  float _spifuncruntime = 0;
196  struct chipID {
197  bool supported;
198  bool supportedMan;
199  bool sfdpAvailable;
200  uint8_t manufacturerID;
201  uint8_t memoryTypeID;
202  uint8_t capacityID;
203  uint32_t capacity;
204  uint32_t eraseTime;
205  };
206  chipID _chip;
207  struct eraseParam{
208  bool supported;
209  uint8_t opcode;
210  uint32_t time;
211  } kb4Erase, kb32Erase, kb64Erase, kb256Erase, chipErase;
212  uint8_t _noOfParamHeaders, _noOfBasicParamDwords;
213  uint16_t _eraseTimeMultiplier, _prgmTimeMultiplier, _pageSize;
214  uint32_t currentAddress, _currentAddress = 0;
215  uint32_t _addressOverflow = false;
216  uint32_t _BasicParamTableAddr, _SectorMapParamTableAddr, _byteFirstPrgmTime, _byteAddnlPrgmTime, _pagePrgmTime;
217  uint8_t _uniqueID[8];
218  const uint8_t _capID[18] =
219  {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x41, 0x42, 0x43, 0x4B, 0x00, 0x01, 0x13, 0x37};
220 
221  const uint32_t _memSize[18] =
222  {KB(64), KB(128), KB(256), KB(512), MB(1), MB(2), MB(4), MB(8), MB(16), MB(32), MB(2), MB(4), MB(8), MB(8), KB(256), KB(512), MB(4), KB(512)};
223  // To understand the _memSize definitions check defines.h
224 
225  const uint8_t _supportedManID[9] = {WINBOND_MANID, MICROCHIP_MANID, CYPRESS_MANID, ADESTO_MANID, MICRON_MANID, ON_MANID, GIGA_MANID, AMIC_MANID, MACRONIX_MANID};
226 
227  const uint8_t _altChipEraseReq[3] = {A25L512, M25P40, SST26};
228 };
229 
230 //--------------------------------- Public Templates ------------------------------------//
231 
232 // Writes any type of data to a specific location in the flash memory.
233 // Takes three arguments -
234 // 1. _addr --> Any address from 0 to maxAddress
235 // 2. T& value --> Variable to write
236 // 3. errorCheck --> Turned on by default. Checks for writing errors
237 // WARNING: You can only write to previously erased memory locations (see datasheet).
238 // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs)
239 template <class T> bool SPIFlash::writeAnything(uint32_t _addr, const T& data, bool errorCheck) {
240  return _write(_addr, data, sizeof(data), errorCheck, _STRUCT_);
241 }
242 
243 // Reads any type of data from a specific location in the flash memory.
244 // Takes three arguments -
245 // 1. _addr --> Any address from 0 to maxAddress
246 // 2. T& value --> Variable to return data into
247 // 3. fastRead --> defaults to false - executes _beginFastRead() if set to true
248 template <class T> bool SPIFlash::readAnything(uint32_t _addr, T& data, bool fastRead) {
249  return _read(_addr, data, sizeof(data), fastRead);
250 }
251 
252 //---------------------------------- Private Templates ----------------------------------//
253 
254 template <class T> bool SPIFlash::_writeErrorCheck(uint32_t _addr, const T& value, uint32_t _sz, uint8_t _dataType) {
255  if (_isChipPoweredDown() || !_addressCheck(_addr, _sz) || !_notBusy()) {
256  return false;
257  }
258  const uint8_t* p = (const uint8_t*)(const void*)&value;
259  /*if (_dataType == _STRUCT_) {
260  uint8_t _inByte[_sz];
261  _beginSPI(READDATA);
262  _nextBuf(READDATA, &(*_inByte), _sz);
263  _endSPI();
264  for (uint16_t i = 0; i < _sz; i++) {
265  if (*p++ != _inByte[i]) {
266  _troubleshoot(0x0A); //0x0A is ERRORCHKFAIL
267  return false;
268  }
269  else {
270  return true;
271  }
272  }
273  }
274  else {*/
275  CHIP_SELECT
276  _nextByte(WRITE, READDATA);
277  _transferAddress();
278  for (uint16_t i = 0; i < _sz; i++) {
279  if (*p++ != _nextByte(READ)) {
280  _troubleshoot(0x0A); //0x0A is ERRORCHKFAIL
281  _endSPI();
282  return false;
283  }
284  }
285  _endSPI();
286  //}
287  return true;
288 }
289 
290 // Writes any type of data to a specific location in the flash memory.
291 // Takes four arguments -
292 // 1. _addr --> Any address from 0 to maxAddress
293 // 2. T& value --> Variable to write
294 // 3. _sz --> Size of variable in bytes (1 byte = 8 bits)
295 // 4. errorCheck --> Turned on by default. Checks for writing errors
296 // WARNING: You can only write to previously erased memory locations (see datasheet).
297 // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs)
298 
299 template <class T> bool SPIFlash::_write(uint32_t _addr, const T& value, uint32_t _sz, bool errorCheck, uint8_t _dataType) {
300  bool _retVal;
301 #ifdef RUNDIAGNOSTIC
302  _spifuncruntime = micros();
303 #endif
304 
305  uint32_t _addrIn = _addr;
306  if (!_prep(PAGEPROG, _addrIn, _sz)) {
307  return false;
308  }
309  _addrIn = _currentAddress;
310  //Serial.print(F("_addrIn: "));
311  //Serial.println(_addrIn, HEX);
312  const uint8_t* p = ((const uint8_t*)(const void*)&value);
313  //Serial.print(F("Address being written to: "));
314  //Serial.println(_addr);
315  uint32_t length = _sz;
316  uint16_t maxBytes = SPI_PAGESIZE-(_addrIn % SPI_PAGESIZE); // Force the first set of bytes to stay within the first page
317 
318  if (!SPIBusState) {
319  _startSPIBus();
320  }
321  CHIP_SELECT
322  _nextByte(WRITE, PAGEPROG);
323  _transferAddress();
324 
325  if (maxBytes > length) {
326  for (uint16_t i = 0; i < length; ++i) {
327  _nextByte(WRITE, *p++);
328  }
329  CHIP_DESELECT
330  }
331  else {
332  uint32_t writeBufSz;
333  uint16_t data_offset = 0;
334 
335  do {
336  writeBufSz = (length<=maxBytes) ? length : maxBytes;
337  if(_currentAddress % SPI_PAGESIZE==0){
338  CHIP_SELECT
339  _nextByte(WRITE, PAGEPROG);
340  _transferAddress();
341  }
342  for (uint16_t i = 0; i < writeBufSz; ++i) {
343  _nextByte(WRITE, *p++);
344  }
345  CHIP_DESELECT
346  if (!_addressOverflow) {
347  _currentAddress += writeBufSz;
348  }
349  else {
350  if (data_offset >= _addressOverflow) {
351  _currentAddress = 0x00;
352  _addressOverflow = false;
353  }
354  }
355  data_offset += writeBufSz;
356  length -= writeBufSz;
357  maxBytes = SPI_PAGESIZE; // Now we can do up to 256 bytes per loop
358  if(!_notBusy() || !_writeEnable()) {
359  return false;
360  }
361  } while (length > 0);
362  }
363 
364  if (!errorCheck) {
365  _endSPI();
366  #ifdef RUNDIAGNOSTIC
367  _spifuncruntime = micros() - _spifuncruntime;
368  #endif
369  return true;
370  }
371  else {
372  //Serial.print(F("Address sent to error check: "));
373  //Serial.println(_addr);
374  _retVal = _writeErrorCheck(_addr, value, _sz, _dataType);
375  }
376 #ifdef RUNDIAGNOSTIC
377  _spifuncruntime = micros() - _spifuncruntime;
378 #endif
379  return _retVal;
380 }
381 
382 // Reads any type of data from a specific location in the flash memory.
383 // Takes four arguments -
384 // 1. _addr --> Any address from 0 to maxAddress
385 // 2. T& value --> Variable to return data into
386 // 3. _sz --> Size of the variable in bytes (1 byte = 8 bits)
387 // 4. fastRead --> defaults to false - executes _beginFastRead() if set to true
388 template <class T> bool SPIFlash::_read(uint32_t _addr, T& value, uint32_t _sz, bool fastRead, uint8_t _dataType) {
389  #ifdef RUNDIAGNOSTIC
390  _spifuncruntime = micros();
391  #endif
392  if (!_prep(READDATA, _addr, _sz)) {
393  return false;
394  }
395  else {
396  uint8_t* p = (uint8_t*)(void*)&value;
397 
398  if (_dataType == _STRING_) {
399  _sz++;
400  char _inChar[_sz];
401  _beginSPI(READDATA);
402  _nextBuf(READDATA, (uint8_t*) &(*_inChar), _sz);
403  _endSPI();
404  for (uint16_t i = 0; i < _sz; i++) {
405  *p++ = _inChar[i];
406  }
407  }
408  else {
409  CHIP_SELECT
410  if (fastRead) {
411  _beginSPI(FASTREAD);
412  }
413  else {
414  _beginSPI(READDATA);
415  }
416  for (uint16_t i = 0; i < _sz; i++) {
417  *p++ =_nextByte(READ);
418  }
419  _endSPI();
420  }
421  }
422  #ifdef RUNDIAGNOSTIC
423  _spifuncruntime = micros() - _spifuncruntime;
424  #endif
425  return true;
426 }
427 
428 #endif // _SPIFLASH_H_
Definition: SPIFlash.h:32