PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SPIFlash.cpp 10KB

3 vuotta sitten
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. // Copyright (c) 2013-2015 by Felix Rusu, LowPowerLab.com
  2. // SPI Flash memory library for arduino/moteino.
  3. // This works with 256byte/page SPI flash memory
  4. // For instance a 4MBit (512Kbyte) flash chip will have 2048 pages: 256*2048 = 524288 bytes (512Kbytes)
  5. // Minimal modifications should allow chips that have different page size but modifications
  6. // DEPENDS ON: Arduino SPI library
  7. // > Updated Jan. 5, 2015, TomWS1, modified writeBytes to allow blocks > 256 bytes and handle page misalignment.
  8. // > Updated Feb. 26, 2015 TomWS1, added support for SPI Transactions (Arduino 1.5.8 and above)
  9. // > Selective merge by Felix after testing in IDE 1.0.6, 1.6.4
  10. // **********************************************************************************
  11. // License
  12. // **********************************************************************************
  13. // This program is free software; you can redistribute it
  14. // and/or modify it under the terms of the GNU General
  15. // Public License as published by the Free Software
  16. // Foundation; either version 3 of the License, or
  17. // (at your option) any later version.
  18. //
  19. // This program is distributed in the hope that it will
  20. // be useful, but WITHOUT ANY WARRANTY; without even the
  21. // implied warranty of MERCHANTABILITY or FITNESS FOR A
  22. // PARTICULAR PURPOSE. See the GNU General Public
  23. // License for more details.
  24. //
  25. // You should have received a copy of the GNU General
  26. // Public License along with this program.
  27. // If not, see <http://www.gnu.org/licenses/>.
  28. //
  29. // Licence can be viewed at
  30. // http://www.gnu.org/licenses/gpl-3.0.txt
  31. //
  32. // Please maintain this license information along with authorship
  33. // and copyright notices in any redistribution of this code
  34. #include <SPIFlash.h>
  35. uint8_t SPIFlash::UNIQUEID[8];
  36. /// IMPORTANT: NAND FLASH memory requires erase before write, because
  37. /// it can only transition from 1s to 0s and only the erase command can reset all 0s to 1s
  38. /// See http://en.wikipedia.org/wiki/Flash_memory
  39. /// The smallest range that can be erased is a sector (4K, 32K, 64K); there is also a chip erase command
  40. /// Constructor. JedecID is optional but recommended, since this will ensure that the device is present and has a valid response
  41. /// get this from the datasheet of your flash chip
  42. /// Example for Atmel-Adesto 4Mbit AT25DF041A: 0x1F44 (page 27: http://www.adestotech.com/sites/default/files/datasheets/doc3668.pdf)
  43. /// Example for Winbond 4Mbit W25X40CL: 0xEF30 (page 14: http://www.winbond.com/NR/rdonlyres/6E25084C-0BFE-4B25-903D-AE10221A0929/0/W25X40CL.pdf)
  44. SPIFlash::SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID) {
  45. _slaveSelectPin = slaveSelectPin;
  46. _jedecID = jedecID;
  47. }
  48. /// Select the flash chip
  49. void SPIFlash::select() {
  50. //save current SPI settings
  51. #ifndef SPI_HAS_TRANSACTION
  52. noInterrupts();
  53. #endif
  54. _SPCR = SPCR;
  55. _SPSR = SPSR;
  56. #ifdef SPI_HAS_TRANSACTION
  57. SPI.beginTransaction(_settings);
  58. #else
  59. // set FLASH SPI settings
  60. SPI.setDataMode(SPI_MODE0);
  61. SPI.setBitOrder(MSBFIRST);
  62. SPI.setClockDivider(SPI_CLOCK_DIV4); //decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present
  63. SPI.begin();
  64. #endif
  65. digitalWrite(_slaveSelectPin, LOW);
  66. }
  67. /// UNselect the flash chip
  68. void SPIFlash::unselect() {
  69. digitalWrite(_slaveSelectPin, HIGH);
  70. //restore SPI settings to what they were before talking to the FLASH chip
  71. #ifdef SPI_HAS_TRANSACTION
  72. SPI.endTransaction();
  73. #else
  74. interrupts();
  75. #endif
  76. SPCR = _SPCR;
  77. SPSR = _SPSR;
  78. }
  79. /// setup SPI, read device ID etc...
  80. boolean SPIFlash::initialize()
  81. {
  82. _SPCR = SPCR;
  83. _SPSR = SPSR;
  84. pinMode(_slaveSelectPin, OUTPUT);
  85. #ifdef SPI_HAS_TRANSACTION
  86. _settings = SPISettings(4000000, MSBFIRST, SPI_MODE0);
  87. #endif
  88. unselect();
  89. wakeup();
  90. if (_jedecID == 0 || readDeviceId() == _jedecID) {
  91. command(SPIFLASH_STATUSWRITE, true); // Write Status Register
  92. SPI.transfer(0); // Global Unprotect
  93. unselect();
  94. return true;
  95. }
  96. return false;
  97. }
  98. /// Get the manufacturer and device ID bytes (as a short word)
  99. uint16_t SPIFlash::readDeviceId()
  100. {
  101. #if defined(__AVR_ATmega32U4__) // Arduino Leonardo, MoteinoLeo
  102. command(SPIFLASH_IDREAD); // Read JEDEC ID
  103. #else
  104. select();
  105. SPI.transfer(SPIFLASH_IDREAD);
  106. #endif
  107. uint16_t jedecid = SPI.transfer(0) << 8;
  108. jedecid |= SPI.transfer(0);
  109. unselect();
  110. return jedecid;
  111. }
  112. /// Get the 64 bit unique identifier, stores it in UNIQUEID[8]. Only needs to be called once, ie after initialize
  113. /// Returns the byte pointer to the UNIQUEID byte array
  114. /// Read UNIQUEID like this:
  115. /// flash.readUniqueId(); for (uint8_t i=0;i<8;i++) { Serial.print(flash.UNIQUEID[i], HEX); Serial.print(' '); }
  116. /// or like this:
  117. /// flash.readUniqueId(); uint8_t* MAC = flash.readUniqueId(); for (uint8_t i=0;i<8;i++) { Serial.print(MAC[i], HEX); Serial.print(' '); }
  118. uint8_t* SPIFlash::readUniqueId()
  119. {
  120. command(SPIFLASH_MACREAD);
  121. SPI.transfer(0);
  122. SPI.transfer(0);
  123. SPI.transfer(0);
  124. SPI.transfer(0);
  125. for (uint8_t i=0;i<8;i++)
  126. UNIQUEID[i] = SPI.transfer(0);
  127. unselect();
  128. return UNIQUEID;
  129. }
  130. /// read 1 byte from flash memory
  131. uint8_t SPIFlash::readByte(uint32_t addr) {
  132. command(SPIFLASH_ARRAYREADLOWFREQ);
  133. SPI.transfer(addr >> 16);
  134. SPI.transfer(addr >> 8);
  135. SPI.transfer(addr);
  136. uint8_t result = SPI.transfer(0);
  137. unselect();
  138. return result;
  139. }
  140. /// read unlimited # of bytes
  141. void SPIFlash::readBytes(uint32_t addr, void* buf, uint16_t len) {
  142. command(SPIFLASH_ARRAYREAD);
  143. SPI.transfer(addr >> 16);
  144. SPI.transfer(addr >> 8);
  145. SPI.transfer(addr);
  146. SPI.transfer(0); //"dont care"
  147. for (uint16_t i = 0; i < len; ++i)
  148. ((uint8_t*) buf)[i] = SPI.transfer(0);
  149. unselect();
  150. }
  151. /// Send a command to the flash chip, pass TRUE for isWrite when its a write command
  152. void SPIFlash::command(uint8_t cmd, boolean isWrite){
  153. #if defined(__AVR_ATmega32U4__) // Arduino Leonardo, MoteinoLeo
  154. DDRB |= B00000001; // Make sure the SS pin (PB0 - used by RFM12B on MoteinoLeo R1) is set as output HIGH!
  155. PORTB |= B00000001;
  156. #endif
  157. if (isWrite)
  158. {
  159. command(SPIFLASH_WRITEENABLE); // Write Enable
  160. unselect();
  161. }
  162. //wait for any write/erase to complete
  163. // a time limit cannot really be added here without it being a very large safe limit
  164. // that is because some chips can take several seconds to carry out a chip erase or other similar multi block or entire-chip operations
  165. // a recommended alternative to such situations where chip can be or not be present is to add a 10k or similar weak pulldown on the
  166. // open drain MISO input which can read noise/static and hence return a non 0 status byte, causing the while() to hang when a flash chip is not present
  167. if (cmd != SPIFLASH_WAKE) while(busy());
  168. select();
  169. SPI.transfer(cmd);
  170. }
  171. /// check if the chip is busy erasing/writing
  172. boolean SPIFlash::busy()
  173. {
  174. /*
  175. select();
  176. SPI.transfer(SPIFLASH_STATUSREAD);
  177. uint8_t status = SPI.transfer(0);
  178. unselect();
  179. return status & 1;
  180. */
  181. return readStatus() & 1;
  182. }
  183. /// return the STATUS register
  184. uint8_t SPIFlash::readStatus()
  185. {
  186. select();
  187. SPI.transfer(SPIFLASH_STATUSREAD);
  188. uint8_t status = SPI.transfer(0);
  189. unselect();
  190. return status;
  191. }
  192. /// Write 1 byte to flash memory
  193. /// WARNING: you can only write to previously erased memory locations (see datasheet)
  194. /// use the block erase commands to first clear memory (write 0xFFs)
  195. void SPIFlash::writeByte(uint32_t addr, uint8_t byt) {
  196. command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program
  197. SPI.transfer(addr >> 16);
  198. SPI.transfer(addr >> 8);
  199. SPI.transfer(addr);
  200. SPI.transfer(byt);
  201. unselect();
  202. }
  203. /// write multiple bytes to flash memory (up to 64K)
  204. /// WARNING: you can only write to previously erased memory locations (see datasheet)
  205. /// use the block erase commands to first clear memory (write 0xFFs)
  206. /// This version handles both page alignment and data blocks larger than 256 bytes.
  207. ///
  208. void SPIFlash::writeBytes(uint32_t addr, const void* buf, uint16_t len) {
  209. uint16_t n;
  210. uint16_t maxBytes = 256-(addr%256); // force the first set of bytes to stay within the first page
  211. uint16_t offset = 0;
  212. while (len>0)
  213. {
  214. n = (len<=maxBytes) ? len : maxBytes;
  215. command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program
  216. SPI.transfer(addr >> 16);
  217. SPI.transfer(addr >> 8);
  218. SPI.transfer(addr);
  219. for (uint16_t i = 0; i < n; i++)
  220. SPI.transfer(((uint8_t*) buf)[offset + i]);
  221. unselect();
  222. addr+=n; // adjust the addresses and remaining bytes by what we've just transferred.
  223. offset +=n;
  224. len -= n;
  225. maxBytes = 256; // now we can do up to 256 bytes per loop
  226. }
  227. }
  228. /// erase entire flash memory array
  229. /// may take several seconds depending on size, but is non blocking
  230. /// so you may wait for this to complete using busy() or continue doing
  231. /// other things and later check if the chip is done with busy()
  232. /// note that any command will first wait for chip to become available using busy()
  233. /// so no need to do that twice
  234. void SPIFlash::chipErase() {
  235. command(SPIFLASH_CHIPERASE, true);
  236. unselect();
  237. }
  238. /// erase a 4Kbyte block
  239. void SPIFlash::blockErase4K(uint32_t addr) {
  240. command(SPIFLASH_BLOCKERASE_4K, true); // Block Erase
  241. SPI.transfer(addr >> 16);
  242. SPI.transfer(addr >> 8);
  243. SPI.transfer(addr);
  244. unselect();
  245. }
  246. /// erase a 32Kbyte block
  247. void SPIFlash::blockErase32K(uint32_t addr) {
  248. command(SPIFLASH_BLOCKERASE_32K, true); // Block Erase
  249. SPI.transfer(addr >> 16);
  250. SPI.transfer(addr >> 8);
  251. SPI.transfer(addr);
  252. unselect();
  253. }
  254. /// erase a 64Kbyte block
  255. void SPIFlash::blockErase64K(uint32_t addr) {
  256. command(SPIFLASH_BLOCKERASE_64K, true); // Block Erase
  257. SPI.transfer(addr >> 16);
  258. SPI.transfer(addr >> 8);
  259. SPI.transfer(addr);
  260. unselect();
  261. }
  262. void SPIFlash::sleep() {
  263. command(SPIFLASH_SLEEP);
  264. unselect();
  265. }
  266. void SPIFlash::wakeup() {
  267. command(SPIFLASH_WAKE);
  268. unselect();
  269. }
  270. /// cleanup
  271. void SPIFlash::end() {
  272. SPI.end();
  273. }