BayEOSArduino Library
SPIFram.h
1 /* Arduino SPIMemory Library v.3.4.0
2  * Copyright (C) 2019 by Prajwal Bhattaram
3  * Created by Prajwal Bhattaram - 19/06/2018
4  *
5  * This file is part of the Arduino SPIMemory Library. This library is for
6  * Flash and FRAM memory modules. In its current form it enables reading,
7  * writing and erasing data from and to various locations;
8  * suspending and resuming programming/erase and powering down for low power operation.
9  *
10  * This Library is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This Library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License v3.0
21  * along with the Arduino SPIMemory Library. If not, see
22  * <http://www.gnu.org/licenses/>.
23  */
24 
25 #ifndef SPIFRAM_H
26 #define SPIFRAM_H
27 
28 #include "SPIMemory.h"
29 
30 //#define OVERWRITE
31 
32 class SPIFram {
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)
37  SPIFram(uint8_t cs = CS, SPIClass *spiinterface=&SPI);
38  #elif defined (BOARD_RTL8195A)
39  SPIFram(PinName cs = CS);
40  #else
41  SPIFram(uint8_t cs = CS);
42  #endif
43  //----------------------------- Initial / Chip Functions ------------------------------//
44  bool begin(uint32_t flashChipSize = 0);
45  void setClock(uint32_t clockSpeed);
46  bool libver(uint8_t *b1, uint8_t *b2, uint8_t *b3);
47  uint8_t error(bool verbosity = false);
48  uint16_t getManID(void);
49  uint32_t getJEDECID(void);
50  uint64_t getUniqueID(void);
51  uint32_t getAddress(uint16_t size);
52  uint16_t sizeofStr(String &inputStr);
53  uint32_t getCapacity(void);
54  float functionRunTime(void);
55  //-------------------------------- Write / Read Bytes ---------------------------------//
56  bool writeByte(uint32_t _addr, uint8_t data, bool errorCheck = true);
57  uint8_t readByte(uint32_t _addr, bool fastRead = false);
58  //----------------------------- Write / Read Byte Arrays ------------------------------//
59  bool writeByteArray(uint32_t _addr, uint8_t *data_buffer, size_t bufferSize, bool errorCheck = true);
60  bool readByteArray(uint32_t _addr, uint8_t *data_buffer, size_t bufferSize, bool fastRead = false);
61  //-------------------------------- Write / Read Chars ---------------------------------//
62  bool writeChar(uint32_t _addr, int8_t data, bool errorCheck = true);
63  int8_t readChar(uint32_t _addr, bool fastRead = false);
64  //------------------------------ Write / Read Char Arrays -----------------------------//
65  bool writeCharArray(uint32_t _addr, char *data_buffer, size_t bufferSize, bool errorCheck = true);
66  bool readCharArray(uint32_t _addr, char *data_buffer, size_t buffer_size, bool fastRead = false);
67  //-------------------------------- Write / Read Shorts --------------------------------//
68  bool writeShort(uint32_t _addr, int16_t data, bool errorCheck = true);
69  int16_t readShort(uint32_t _addr, bool fastRead = false);
70  //-------------------------------- Write / Read Words ---------------------------------//
71  bool writeWord(uint32_t _addr, uint16_t data, bool errorCheck = true);
72  uint16_t readWord(uint32_t _addr, bool fastRead = false);
73  //-------------------------------- Write / Read Longs ---------------------------------//
74  bool writeLong(uint32_t _addr, int32_t data, bool errorCheck = true);
75  int32_t readLong(uint32_t _addr, bool fastRead = false);
76  //--------------------------- Write / Read Unsigned Longs -----------------------------//
77  bool writeULong(uint32_t _addr, uint32_t data, bool errorCheck = true);
78  uint32_t readULong(uint32_t _addr, bool fastRead = false);
79  //-------------------------------- Write / Read Floats --------------------------------//
80  bool writeFloat(uint32_t _addr, float data, bool errorCheck = true);
81  float readFloat(uint32_t _addr, bool fastRead = false);
82  //-------------------------------- Write / Read Strings -------------------------------//
83  bool writeStr(uint32_t _addr, String &data, bool errorCheck = true);
84  bool readStr(uint32_t _addr, String &data, bool fastRead = false);
85  //------------------------------- Write / Read Anything -------------------------------//
86 
87  template <class T> bool writeAnything(uint32_t _addr, const T& data, bool errorCheck = true);
88  template <class T> bool readAnything(uint32_t _addr, T& data, bool fastRead = false);
89  //-------------------------------- Erase functions ------------------------------------//
90  bool eraseSection(uint32_t _addr, uint32_t _sz);
91  bool eraseChip(void);
92  //-------------------------------- Power functions ------------------------------------//
93  bool powerDown(void);
94  bool powerUp(void);
95  //-------------------------- Public Arduino Due Functions -----------------------------//
96 //#if defined (ARDUINO_ARCH_SAM)
97  //uint32_t freeRAM(void);
98 //#endif
99  //------------------------------- Public variables ------------------------------------//
100 
101 private:
102  //------------------------------- Private functions -----------------------------------//
103  unsigned _createMask(unsigned a, unsigned b);
104  void _troubleshoot(uint8_t _code, bool printoverride = false);
105  void _endSPI(void);
106  bool _disableGlobalBlockProtect(void);
107  bool _isChipPoweredDown(void);
108  bool _prep(uint32_t _addr, uint32_t size = 0);
109  bool _startSPIBus(void);
110  bool _beginSPI(uint8_t opcode);
111  bool _noSuspend(void);
112  bool _notPrevWritten(uint32_t _addr, uint32_t size = 1);
113  bool _writeEnable(bool _troubleshootEnable = true);
114  bool _writeDisable(void);
115  bool _getJedecId(void);
116  bool _chipID(uint32_t flashChipSize = 0);
117  bool _transferAddress(void);
118  bool _addressCheck(uint32_t _addr, uint32_t size = 1);
119  uint8_t _nextByte(char IOType, uint8_t data = NULLBYTE);
120  uint16_t _nextInt(uint16_t = NULLINT);
121  void _nextBuf(uint8_t opcode, uint8_t *data_buffer, uint32_t size);
122  uint8_t _readStat1(void);
123  template <class T> bool _write(uint32_t _addr, const T& value, uint32_t _sz, bool errorCheck, uint8_t _dataType);
124  template <class T> bool _read(uint32_t _addr, T& value, uint32_t _sz, bool fastRead = false, uint8_t _dataType = 0x00);
125  //template <class T> bool _writeErrorCheck(uint32_t _addr, const T& value);
126  template <class T> bool _writeErrorCheck(uint32_t _addr, const T& value, uint32_t _sz, uint8_t _dataType = 0x00);
127  //-------------------------------- Private variables ----------------------------------//
128  #ifdef SPI_HAS_TRANSACTION
129  SPISettings _settings;
130  #endif
131  //If multiple SPI ports are available this variable is used to choose between them (SPI, SPI1, SPI2 etc.)
132  SPIClass *_spi;
133  #if !defined (BOARD_RTL8195A)
134  uint8_t csPin;
135  #else
136  // Object declaration for the GPIO HAL type for csPin - @boseji <salearj@hotmail.com> 02.03.17
137  gpio_t csPin;
138  #endif
139  volatile uint8_t *cs_port;
140  bool pageOverflow;
141  bool chipPoweredDown = false;
142  bool SPIBusState = false;
143  bool _loopedOver = false;
144  uint8_t cs_mask, errorcode, stat1, stat2, stat3, _SPCR, _SPSR, _a0, _a1, _a2;
145  char READ = 'R';
146  char WRITE = 'W';
147  float _spifuncruntime = 0;
148  uint32_t _chipCapacity;
149  struct chipID {
150  bool supported;
151  bool supportedMan;
152  uint8_t manufacturerID;
153  uint8_t devID1;
154  uint8_t devID2;
155  uint32_t capacity;
156  };
157  chipID _chip;
158  uint32_t currentAddress, _currentAddress = 0;
159  uint32_t _addressOverflow = false;
160  uint8_t _uniqueID[8];
161 
162  const uint8_t _supportedManID[1] = {RAMTRON_FRAM_MANID};
163 };
164 
165 //--------------------------------- Public Templates ------------------------------------//
166 
167 // Writes any type of data to a specific location in the flash memory.
168 // Takes three arguments -
169 // 1. _addr --> Any address from 0 to maxAddress
170 // 2. T& value --> Variable to write
171 // 3. errorCheck --> Turned on by default. Checks for writing errors
172 // WARNING: You can only write to previously erased memory locations (see datasheet).
173 // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs)
174 template <class T> bool SPIFram::writeAnything(uint32_t _addr, const T& data, bool errorCheck) {
175  return _write(_addr, data, sizeof(data), errorCheck, _STRUCT_);
176 }
177 
178 // Reads any type of data from a specific location in the flash memory.
179 // Takes three arguments -
180 // 1. _addr --> Any address from 0 to maxAddress
181 // 2. T& value --> Variable to return data into
182 // 3. fastRead --> defaults to false - executes _beginFastRead() if set to true
183 template <class T> bool SPIFram::readAnything(uint32_t _addr, T& data, bool fastRead) {
184  return _read(_addr, data, sizeof(data), fastRead);
185 }
186 
187 //---------------------------------- Private Templates ----------------------------------//
188 
189 template <class T> bool SPIFram::_writeErrorCheck(uint32_t _addr, const T& value, uint32_t _sz, uint8_t _dataType) {
190  if (!_addressCheck(_addr, _sz)) {
191  return false;
192  }
193  const uint8_t* p = (const uint8_t*)(const void*)&value;
194  /*if (_dataType == _STRUCT_) {
195  uint8_t _inByte[_sz];
196  _beginSPI(READDATA);
197  _nextBuf(READDATA, &(*_inByte), _sz);
198  _endSPI();
199  for (uint16_t i = 0; i < _sz; i++) {
200  if (*p++ != _inByte[i]) {
201  _troubleshoot(0x0A); //0x0A is ERRORCHKFAIL
202  return false;
203  }
204  else {
205  return true;
206  }
207  }
208  }
209  else {*/
210  CHIP_SELECT
211  _nextByte(WRITE, READDATA);
212  _transferAddress();
213  for (uint16_t i = 0; i < _sz; i++) {
214  if (*p++ != _nextByte(READ)) {
215  _troubleshoot(0x0A); //0x0A is ERRORCHKFAIL
216  _endSPI();
217  return false;
218  }
219  }
220  _endSPI();
221  //}
222  return true;
223 }
224 
225 // Writes any type of data to a specific location in the flash memory.
226 // Takes four arguments -
227 // 1. _addr --> Any address from 0 to maxAddress
228 // 2. T& value --> Variable to write
229 // 3. _sz --> Size of variable in bytes (1 byte = 8 bits)
230 // 4. errorCheck --> Turned on by default. Checks for writing errors
231 // WARNING: You can only write to previously erased memory locations (see datasheet).
232 // Use the eraseSector()/eraseBlock32K/eraseBlock64K commands to first clear memory (write 0xFFs)
233 
234 template <class T> bool SPIFram::_write(uint32_t _addr, const T& value, uint32_t _sz, bool errorCheck, uint8_t _dataType) {
235  bool _retVal;
236 #ifdef RUNDIAGNOSTIC
237  _spifuncruntime = micros();
238 #endif
239 
240  uint32_t _addrIn = _addr;
241  if(_isChipPoweredDown() || !_addressCheck(_addrIn, _sz) || !_notPrevWritten(_addrIn, _sz) || !_writeEnable()) {
242  return false;
243  }
244  _addrIn = _currentAddress;
245  //Serial.print("_addrIn: ");
246  //Serial.println(_addrIn, HEX);
247  const uint8_t* p = ((const uint8_t*)(const void*)&value);
248  //Serial.print(F("Address being written to: "));
249  //Serial.println(_addr);
250  uint32_t length = _sz;
251  uint16_t maxBytes = SPI_PAGESIZE-(_addrIn % SPI_PAGESIZE); // Force the first set of bytes to stay within the first page
252 
253  if (!SPIBusState) {
254  _startSPIBus();
255  }
256  CHIP_SELECT
257  _nextByte(WRITE, PAGEPROG);
258  _transferAddress();
259 
260  if (maxBytes > length) {
261  for (uint16_t i = 0; i < length; ++i) {
262  _nextByte(WRITE, *p++);
263  }
264  CHIP_DESELECT
265  }
266  else {
267  uint32_t writeBufSz;
268  uint16_t data_offset = 0;
269 
270  do {
271  writeBufSz = (length<=maxBytes) ? length : maxBytes;
272 
273  for (uint16_t i = 0; i < writeBufSz; ++i) {
274  _nextByte(WRITE, *p++);
275  }
276  CHIP_DESELECT
277  if (!_addressOverflow) {
278  _currentAddress += writeBufSz;
279  }
280  else {
281  if (data_offset >= _addressOverflow) {
282  _currentAddress = 0x00;
283  _addressOverflow = false;
284  }
285  }
286  data_offset += writeBufSz;
287  length -= writeBufSz;
288  maxBytes = SPI_PAGESIZE; // Now we can do up to 256 bytes per loop
289  if(!_writeEnable()) {
290  return false;
291  }
292  } while (length > 0);
293  }
294 
295  if (!errorCheck) {
296  _endSPI();
297  return true;
298  }
299  else {
300  //Serial.print(F("Address sent to error check: "));
301  //Serial.println(_addr);
302  _retVal = _writeErrorCheck(_addr, value, _sz, _dataType);
303  }
304 #ifdef RUNDIAGNOSTIC
305  _spifuncruntime = micros() - _spifuncruntime;
306 #endif
307  return _retVal;
308 }
309 
310 // Reads any type of data from a specific location in the flash memory.
311 // Takes four arguments -
312 // 1. _addr --> Any address from 0 to maxAddress
313 // 2. T& value --> Variable to return data into
314 // 3. _sz --> Size of the variable in bytes (1 byte = 8 bits)
315 // 4. fastRead --> defaults to false - executes _beginFastRead() if set to true
316 template <class T> bool SPIFram::_read(uint32_t _addr, T& value, uint32_t _sz, bool fastRead, uint8_t _dataType) {
317  #ifdef RUNDIAGNOSTIC
318  _spifuncruntime = micros();
319  #endif
320 
321  if(_isChipPoweredDown() || !_addressCheck(_addr, _sz)) {
322  return false;
323  }
324  else {
325  uint8_t* p = (uint8_t*)(void*)&value;
326 
327  if (_dataType == _STRING_) {
328  char _inChar[_sz];
329  _beginSPI(READDATA);
330  _nextBuf(READDATA, (uint8_t*) &(*_inChar), _sz);
331  _endSPI();
332  for (uint16_t i = 0; i < _sz; i++) {
333  *p++ = _inChar[i];
334  }
335  }
336  else {
337  CHIP_SELECT
338  if (fastRead) {
339  _nextByte(WRITE, FASTREAD);
340  }
341  else {
342  _nextByte(WRITE, READDATA);
343  }
344  _transferAddress();
345  for (uint16_t i = 0; i < _sz; i++) {
346  *p++ =_nextByte(READ);
347  }
348  _endSPI();
349  }
350  }
351  #ifdef RUNDIAGNOSTIC
352  _spifuncruntime = micros() - _spifuncruntime;
353  #endif
354  return true;
355 }
356 
357 #endif // _SPIFRAM_H_
Definition: SPIFram.h:32