Smart-Home am Beispiel der Präsenzerkennung im Raum Projektarbeit Lennart Heimbs, Johannes Krug, Sebastian Dohle und Kevin Holzschuh bei Prof. Oliver Hofmann SS2019
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 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  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. // > Updated May 19, 2016 D-H-R, added support for SST25/Microchip Flash which does not support Page programming with OPCode 0x02,
  11. // > use define MY_SPIFLASH_SST25TYPE for SST25 Type Flash Memory
  12. // > Updated Sep 07, 2018 tekka, sync with https://github.com/LowPowerLab/SPIFlash
  13. // **********************************************************************************
  14. // License
  15. // **********************************************************************************
  16. // This program is free software; you can redistribute it
  17. // and/or modify it under the terms of the GNU General
  18. // Public License as published by the Free Software
  19. // Foundation; either version 3 of the License, or
  20. // (at your option) any later version.
  21. //
  22. // This program is distributed in the hope that it will
  23. // be useful, but WITHOUT ANY WARRANTY; without even the
  24. // implied warranty of MERCHANTABILITY or FITNESS FOR A
  25. // PARTICULAR PURPOSE. See the GNU General Public
  26. // License for more details.
  27. //
  28. // You should have received a copy of the GNU General
  29. // Public License along with this program.
  30. // If not, see <http://www.gnu.org/licenses/>.
  31. //
  32. // Licence can be viewed at
  33. // http://www.gnu.org/licenses/gpl-3.0.txt
  34. //
  35. // Please maintain this license information along with authorship
  36. // and copyright notices in any redistribution of this code
  37. #include "SPIFlash.h"
  38. uint8_t SPIFlash::UNIQUEID[8];
  39. /// IMPORTANT: NAND FLASH memory requires erase before write, because
  40. /// it can only transition from 1s to 0s and only the erase command can reset all 0s to 1s
  41. /// See http://en.wikipedia.org/wiki/Flash_memory
  42. /// The smallest range that can be erased is a sector (4K, 32K, 64K); there is also a chip erase command
  43. /// Constructor. JedecID is optional but recommended, since this will ensure that the device is present and has a valid response
  44. /// get this from the datasheet of your flash chip
  45. /// Example for Atmel-Adesto 4Mbit AT25DF041A: 0x1F44 (page 27: http://www.adestotech.com/sites/default/files/datasheets/doc3668.pdf)
  46. /// Example for Winbond 4Mbit W25X40CL: 0xEF30 (page 14: http://www.winbond.com/NR/rdonlyres/6E25084C-0BFE-4B25-903D-AE10221A0929/0/W25X40CL.pdf)
  47. // Suppress uninitialized member variable in constructor because some memory can be saved with
  48. // on-demand initialization of these members
  49. // cppcheck-suppress uninitMemberVar
  50. SPIFlash::SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID)
  51. {
  52. _slaveSelectPin = slaveSelectPin;
  53. _jedecID = jedecID;
  54. }
  55. /// Select the flash chip
  56. void SPIFlash::select()
  57. {
  58. //save current SPI settings
  59. #ifndef SPI_HAS_TRANSACTION
  60. noInterrupts();
  61. #endif
  62. #if defined(SPCR) && defined(SPSR)
  63. _SPCR = SPCR;
  64. _SPSR = SPSR;
  65. #endif
  66. #ifdef SPI_HAS_TRANSACTION
  67. SPI.beginTransaction(_settings);
  68. #else
  69. // set FLASH SPI settings
  70. SPI.setDataMode(SPI_MODE0);
  71. SPI.setBitOrder(MSBFIRST);
  72. SPI.setClockDivider(
  73. 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
  74. #endif
  75. hwDigitalWrite(_slaveSelectPin, LOW);
  76. }
  77. /// UNselect the flash chip
  78. void SPIFlash::unselect()
  79. {
  80. hwDigitalWrite(_slaveSelectPin, HIGH);
  81. //restore SPI settings to what they were before talking to the FLASH chip
  82. #ifdef SPI_HAS_TRANSACTION
  83. SPI.endTransaction();
  84. #else
  85. interrupts();
  86. #endif
  87. #if defined(SPCR) && defined(SPSR)
  88. SPCR = _SPCR;
  89. SPSR = _SPSR;
  90. #endif
  91. }
  92. /// setup SPI, read device ID etc...
  93. bool SPIFlash::initialize()
  94. {
  95. #if defined(SPCR) && defined(SPSR)
  96. _SPCR = SPCR;
  97. _SPSR = SPSR;
  98. #endif
  99. hwPinMode(_slaveSelectPin, OUTPUT);
  100. SPI.begin(); // see https://github.com/LowPowerLab/SPIFlash/issues/20
  101. #ifdef SPI_HAS_TRANSACTION
  102. _settings = SPISettings(4000000, MSBFIRST, SPI_MODE0);
  103. #endif
  104. unselect();
  105. wakeup();
  106. if (_jedecID == 0 || readDeviceId() == _jedecID) {
  107. command(SPIFLASH_STATUSWRITE, true); // Write Status Register
  108. SPI.transfer(0); // Global Unprotect
  109. unselect();
  110. return true;
  111. }
  112. return false;
  113. }
  114. /// Get the manufacturer and device ID bytes (as a short word)
  115. uint16_t SPIFlash::readDeviceId()
  116. {
  117. #if defined(__AVR_ATmega32U4__) // Arduino Leonardo, MoteinoLeo
  118. command(SPIFLASH_IDREAD); // Read JEDEC ID
  119. #else
  120. select();
  121. SPI.transfer(SPIFLASH_IDREAD);
  122. #endif
  123. uint16_t jedecid = SPI.transfer(0) << 8;
  124. jedecid |= SPI.transfer(0);
  125. unselect();
  126. return jedecid;
  127. }
  128. /// Get the 64 bit unique identifier, stores it in UNIQUEID[8]. Only needs to be called once, ie after initialize
  129. /// Returns the byte pointer to the UNIQUEID byte array
  130. /// Read UNIQUEID like this:
  131. /// flash.readUniqueId(); for (uint8_t i=0;i<8;i++) { Serial.print(flash.UNIQUEID[i], HEX); Serial.print(' '); }
  132. /// or like this:
  133. /// flash.readUniqueId(); uint8_t* MAC = flash.readUniqueId(); for (uint8_t i=0;i<8;i++) { Serial.print(MAC[i], HEX); Serial.print(' '); }
  134. uint8_t* SPIFlash::readUniqueId()
  135. {
  136. command(SPIFLASH_MACREAD);
  137. SPI.transfer(0);
  138. SPI.transfer(0);
  139. SPI.transfer(0);
  140. SPI.transfer(0);
  141. for (uint8_t i=0; i<8; i++) {
  142. UNIQUEID[i] = SPI.transfer(0);
  143. }
  144. unselect();
  145. return UNIQUEID;
  146. }
  147. /// read 1 byte from flash memory
  148. uint8_t SPIFlash::readByte(uint32_t addr)
  149. {
  150. command(SPIFLASH_ARRAYREADLOWFREQ);
  151. SPI.transfer(addr >> 16);
  152. SPI.transfer(addr >> 8);
  153. SPI.transfer(addr);
  154. uint8_t result = SPI.transfer(0);
  155. unselect();
  156. return result;
  157. }
  158. /// read unlimited # of bytes
  159. void SPIFlash::readBytes(uint32_t addr, void* buf, uint16_t len)
  160. {
  161. command(SPIFLASH_ARRAYREAD);
  162. SPI.transfer(addr >> 16);
  163. SPI.transfer(addr >> 8);
  164. SPI.transfer(addr);
  165. SPI.transfer(0); //"dont care"
  166. for (uint16_t i = 0; i < len; ++i) {
  167. ((uint8_t*) buf)[i] = SPI.transfer(0);
  168. }
  169. unselect();
  170. }
  171. /// Send a command to the flash chip, pass TRUE for isWrite when its a write command
  172. void SPIFlash::command(uint8_t cmd, bool isWrite)
  173. {
  174. #if defined(__AVR_ATmega32U4__) // Arduino Leonardo, MoteinoLeo
  175. DDRB |= B00000001; // Make sure the SS pin (PB0 - used by RFM12B on MoteinoLeo R1) is set as output HIGH!
  176. PORTB |= B00000001;
  177. #endif
  178. if (isWrite) {
  179. command(SPIFLASH_WRITEENABLE); // Write Enable
  180. unselect();
  181. }
  182. //wait for any write/erase to complete
  183. // a time limit cannot really be added here without it being a very large safe limit
  184. // that is because some chips can take several seconds to carry out a chip erase or other similar multi block or entire-chip operations
  185. // 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
  186. // 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
  187. while(busy());
  188. select();
  189. SPI.transfer(cmd);
  190. }
  191. /// check if the chip is busy erasing/writing
  192. bool SPIFlash::busy()
  193. {
  194. /*
  195. select();
  196. SPI.transfer(SPIFLASH_STATUSREAD);
  197. uint8_t status = SPI.transfer(0);
  198. unselect();
  199. return status & 1;
  200. */
  201. return readStatus() & 1;
  202. }
  203. /// return the STATUS register
  204. uint8_t SPIFlash::readStatus()
  205. {
  206. select();
  207. SPI.transfer(SPIFLASH_STATUSREAD);
  208. uint8_t status = SPI.transfer(0);
  209. unselect();
  210. return status;
  211. }
  212. /// Write 1 byte to flash memory
  213. /// WARNING: you can only write to previously erased memory locations (see datasheet)
  214. /// use the block erase commands to first clear memory (write 0xFFs)
  215. void SPIFlash::writeByte(uint32_t addr, uint8_t byt)
  216. {
  217. command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program
  218. SPI.transfer(addr >> 16);
  219. SPI.transfer(addr >> 8);
  220. SPI.transfer(addr);
  221. SPI.transfer(byt);
  222. unselect();
  223. }
  224. /// write multiple bytes to flash memory (up to 64K)
  225. /// WARNING: you can only write to previously erased memory locations (see datasheet)
  226. /// use the block erase commands to first clear memory (write 0xFFs)
  227. /// This version handles both page alignment and data blocks larger than 256 bytes.
  228. /// See documentation of #MY_SPIFLASH_SST25TYPE define for more information
  229. void SPIFlash::writeBytes(uint32_t addr, const void* buf, uint16_t len)
  230. {
  231. #ifdef MY_SPIFLASH_SST25TYPE
  232. //SST25 Type of Flash does not support Page Programming but AAI Word Programming
  233. uint16_t i=0;
  234. uint8_t oddAdr=0;
  235. command(SPIFLASH_AAIWORDPROGRAM, true); // Byte/Page Program
  236. SPI.transfer(addr >> 16);
  237. SPI.transfer(addr >> 8);
  238. SPI.transfer(addr);
  239. if (addr%2) {
  240. //start address is not even, i.e. first byte of word must be 0xff
  241. SPI.transfer(0xff);
  242. SPI.transfer(((uint8_t*) buf)[0]);
  243. unselect();
  244. oddAdr=1; //following addresses must all be shifted one off
  245. len--;
  246. if (len > 0) {
  247. command(SPIFLASH_AAIWORDPROGRAM); //If for loop will run issue Wordprogram command
  248. }
  249. }
  250. for (i=0; i<(len/2); i++) {
  251. //AAI command must be set before every new word
  252. if (i>0) {
  253. command(SPIFLASH_AAIWORDPROGRAM); //Wordprogram command for first write has been issued before
  254. }
  255. SPI.transfer(((uint8_t*) buf)[i*2+oddAdr]);
  256. SPI.transfer(((uint8_t*) buf)[i*2+1+oddAdr]);
  257. unselect();
  258. }
  259. if (len-i*2 == 1) {
  260. //There is one byte (i.e. half word) left. This happens if len was odd or (len was even and addr odd)
  261. if (i>0) {
  262. command(SPIFLASH_AAIWORDPROGRAM); //if for loop had not run wordprogram command from before is still valid
  263. }
  264. SPI.transfer(((uint8_t*) buf)[i*2+oddAdr]);
  265. SPI.transfer(0xff);
  266. unselect();
  267. }
  268. command(SPIFLASH_WRITEDISABLE); //end AAI programming
  269. unselect();
  270. #else
  271. uint16_t maxBytes = 256-(addr%256); // force the first set of bytes to stay within the first page
  272. uint16_t offset = 0;
  273. while (len>0) {
  274. uint16_t n = (len<=maxBytes) ? len : maxBytes;
  275. command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program
  276. SPI.transfer(addr >> 16);
  277. SPI.transfer(addr >> 8);
  278. SPI.transfer(addr);
  279. for (uint16_t i = 0; i < n; i++) {
  280. SPI.transfer(((uint8_t*) buf)[offset + i]);
  281. }
  282. unselect();
  283. addr+=n; // adjust the addresses and remaining bytes by what we've just transferred.
  284. offset +=n;
  285. len -= n;
  286. maxBytes = 256; // now we can do up to 256 bytes per loop
  287. }
  288. #endif
  289. }
  290. /// erase entire flash memory array
  291. /// may take several seconds depending on size, but is non blocking
  292. /// so you may wait for this to complete using busy() or continue doing
  293. /// other things and later check if the chip is done with busy()
  294. /// note that any command will first wait for chip to become available using busy()
  295. /// so no need to do that twice
  296. void SPIFlash::chipErase()
  297. {
  298. command(SPIFLASH_CHIPERASE, true);
  299. unselect();
  300. }
  301. /// erase a 4Kbyte block
  302. void SPIFlash::blockErase4K(uint32_t addr)
  303. {
  304. command(SPIFLASH_BLOCKERASE_4K, true); // Block Erase
  305. SPI.transfer(addr >> 16);
  306. SPI.transfer(addr >> 8);
  307. SPI.transfer(addr);
  308. unselect();
  309. }
  310. /// erase a 32Kbyte block
  311. void SPIFlash::blockErase32K(uint32_t addr)
  312. {
  313. command(SPIFLASH_BLOCKERASE_32K, true); // Block Erase
  314. SPI.transfer(addr >> 16);
  315. SPI.transfer(addr >> 8);
  316. SPI.transfer(addr);
  317. unselect();
  318. }
  319. /// erase a 64Kbyte block
  320. void SPIFlash::blockErase64K(uint32_t addr)
  321. {
  322. command(SPIFLASH_BLOCKERASE_64K, true); // Block Erase
  323. SPI.transfer(addr >> 16);
  324. SPI.transfer(addr >> 8);
  325. SPI.transfer(addr);
  326. unselect();
  327. }
  328. void SPIFlash::sleep()
  329. {
  330. command(SPIFLASH_SLEEP);
  331. unselect();
  332. }
  333. void SPIFlash::wakeup()
  334. {
  335. command(SPIFLASH_WAKE);
  336. unselect();
  337. }
  338. /// cleanup
  339. void SPIFlash::end()
  340. {
  341. SPI.end();
  342. }