1- /*
2- * Copyright (c) 2013 by Felix Rusu <[email protected] > 3- * SPI Flash memory library for arduino/moteino.
4- * This works with 256byte/page SPI flash memory
5- * For instance a 4MBit (512Kbyte) flash chip will have 2048 pages: 256*2048 = 524288 bytes (512Kbytes)
6- * Minimal modifications should allow chips that have different page size but modifications
7- * DEPENDS ON: Arduino SPI library
8- *
9- * This file is free software; you can redistribute it and/or modify
10- * it under the terms of either the GNU General Public License version 2
11- * or the GNU Lesser General Public License version 2.1, both as
12- * published by the Free Software Foundation.
13- */
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
1434
1535#include < SPIFlash.h>
1636
17- byte SPIFlash::UNIQUEID[8 ];
37+ uint8_t SPIFlash::UNIQUEID[8 ];
1838
1939// / IMPORTANT: NAND FLASH memory requires erase before write, because
2040// / it can only transition from 1s to 0s and only the erase command can reset all 0s to 1s
@@ -32,34 +52,48 @@ SPIFlash::SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID) {
3252
3353// / Select the flash chip
3454void SPIFlash::select () {
35- noInterrupts ();
3655 // save current SPI settings
56+ #ifndef SPI_HAS_TRANSACTION
57+ noInterrupts ();
58+ #endif
3759 _SPCR = SPCR;
3860 _SPSR = SPSR;
39- // set FLASH chip SPI settings
61+
62+ #ifdef SPI_HAS_TRANSACTION
63+ SPI.beginTransaction (_settings);
64+ #else
65+ // set FLASH SPI settings
4066 SPI.setDataMode (SPI_MODE0);
4167 SPI.setBitOrder (MSBFIRST);
4268 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
4369 SPI.begin ();
70+ #endif
4471 digitalWrite (_slaveSelectPin, LOW);
4572}
4673
4774// / UNselect the flash chip
4875void SPIFlash::unselect () {
4976 digitalWrite (_slaveSelectPin, HIGH);
5077 // restore SPI settings to what they were before talking to the FLASH chip
78+ #ifdef SPI_HAS_TRANSACTION
79+ SPI.endTransaction ();
80+ #else
81+ interrupts ();
82+ #endif
5183 SPCR = _SPCR;
5284 SPSR = _SPSR;
53- interrupts ();
5485}
5586
5687// / setup SPI, read device ID etc...
5788boolean SPIFlash::initialize ()
5889{
59- SPI.begin ();
6090 _SPCR = SPCR;
6191 _SPSR = SPSR;
6292 pinMode (_slaveSelectPin, OUTPUT);
93+ #ifdef SPI_HAS_TRANSACTION
94+ _settings = SPISettings (4000000 , MSBFIRST, SPI_MODE0);
95+ #endif
96+
6397 unselect ();
6498 wakeup ();
6599
@@ -73,15 +107,15 @@ boolean SPIFlash::initialize()
73107}
74108
75109// / Get the manufacturer and device ID bytes (as a short word)
76- word SPIFlash::readDeviceId ()
110+ uint16_t SPIFlash::readDeviceId ()
77111{
78112#if defined(__AVR_ATmega32U4__) // Arduino Leonardo, MoteinoLeo
79113 command (SPIFLASH_IDREAD); // Read JEDEC ID
80114#else
81115 select ();
82116 SPI.transfer (SPIFLASH_IDREAD);
83117#endif
84- word jedecid = SPI.transfer (0 ) << 8 ;
118+ uint16_t jedecid = SPI.transfer (0 ) << 8 ;
85119 jedecid |= SPI.transfer (0 );
86120 unselect ();
87121 return jedecid;
@@ -90,47 +124,47 @@ word SPIFlash::readDeviceId()
90124// / Get the 64 bit unique identifier, stores it in UNIQUEID[8]. Only needs to be called once, ie after initialize
91125// / Returns the byte pointer to the UNIQUEID byte array
92126// / Read UNIQUEID like this:
93- // / flash.readUniqueId(); for (byte i=0;i<8;i++) { Serial.print(flash.UNIQUEID[i], HEX); Serial.print(' '); }
127+ // / flash.readUniqueId(); for (uint8_t i=0;i<8;i++) { Serial.print(flash.UNIQUEID[i], HEX); Serial.print(' '); }
94128// / or like this:
95- // / flash.readUniqueId(); byte * MAC = flash.readUniqueId(); for (byte i=0;i<8;i++) { Serial.print(MAC[i], HEX); Serial.print(' '); }
96- byte * SPIFlash::readUniqueId ()
129+ // / flash.readUniqueId(); uint8_t * MAC = flash.readUniqueId(); for (uint8_t i=0;i<8;i++) { Serial.print(MAC[i], HEX); Serial.print(' '); }
130+ uint8_t * SPIFlash::readUniqueId ()
97131{
98132 command (SPIFLASH_MACREAD);
99133 SPI.transfer (0 );
100134 SPI.transfer (0 );
101135 SPI.transfer (0 );
102136 SPI.transfer (0 );
103- for (byte i=0 ;i<8 ;i++)
137+ for (uint8_t i=0 ;i<8 ;i++)
104138 UNIQUEID[i] = SPI.transfer (0 );
105139 unselect ();
106140 return UNIQUEID;
107141}
108142
109143// / read 1 byte from flash memory
110- byte SPIFlash::readByte (long addr) {
144+ uint8_t SPIFlash::readByte (uint32_t addr) {
111145 command (SPIFLASH_ARRAYREADLOWFREQ);
112146 SPI.transfer (addr >> 16 );
113147 SPI.transfer (addr >> 8 );
114148 SPI.transfer (addr);
115- byte result = SPI.transfer (0 );
149+ uint8_t result = SPI.transfer (0 );
116150 unselect ();
117151 return result;
118152}
119153
120154// / read unlimited # of bytes
121- void SPIFlash::readBytes (long addr, void * buf, word len) {
155+ void SPIFlash::readBytes (uint32_t addr, void * buf, uint16_t len) {
122156 command (SPIFLASH_ARRAYREAD);
123157 SPI.transfer (addr >> 16 );
124158 SPI.transfer (addr >> 8 );
125159 SPI.transfer (addr);
126160 SPI.transfer (0 ); // "dont care"
127- for (word i = 0 ; i < len; ++i)
128- ((byte *) buf)[i] = SPI.transfer (0 );
161+ for (uint16_t i = 0 ; i < len; ++i)
162+ ((uint8_t *) buf)[i] = SPI.transfer (0 );
129163 unselect ();
130164}
131165
132166// / Send a command to the flash chip, pass TRUE for isWrite when its a write command
133- void SPIFlash::command (byte cmd, boolean isWrite){
167+ void SPIFlash::command (uint8_t cmd, boolean isWrite){
134168#if defined(__AVR_ATmega32U4__) // Arduino Leonardo, MoteinoLeo
135169 DDRB |= B00000001; // Make sure the SS pin (PB0 - used by RFM12B on MoteinoLeo R1) is set as output HIGH!
136170 PORTB |= B00000001;
@@ -156,19 +190,19 @@ boolean SPIFlash::busy()
156190 /*
157191 select();
158192 SPI.transfer(SPIFLASH_STATUSREAD);
159- byte status = SPI.transfer(0);
193+ uint8_t status = SPI.transfer(0);
160194 unselect();
161195 return status & 1;
162196 */
163197 return readStatus () & 1 ;
164198}
165199
166200// / return the STATUS register
167- byte SPIFlash::readStatus ()
201+ uint8_t SPIFlash::readStatus ()
168202{
169203 select ();
170204 SPI.transfer (SPIFLASH_STATUSREAD);
171- byte status = SPI.transfer (0 );
205+ uint8_t status = SPI.transfer (0 );
172206 unselect ();
173207 return status;
174208}
@@ -177,7 +211,7 @@ byte SPIFlash::readStatus()
177211// / Write 1 byte to flash memory
178212// / WARNING: you can only write to previously erased memory locations (see datasheet)
179213// / use the block erase commands to first clear memory (write 0xFFs)
180- void SPIFlash::writeByte (long addr, uint8_t byt) {
214+ void SPIFlash::writeByte (uint32_t addr, uint8_t byt) {
181215 command (SPIFLASH_BYTEPAGEPROGRAM, true ); // Byte/Page Program
182216 SPI.transfer (addr >> 16 );
183217 SPI.transfer (addr >> 8 );
@@ -186,20 +220,32 @@ void SPIFlash::writeByte(long addr, uint8_t byt) {
186220 unselect ();
187221}
188222
189- // / write 1-256 bytes to flash memory
223+ // / write multiple bytes to flash memory (up to 64K)
190224// / WARNING: you can only write to previously erased memory locations (see datasheet)
191225// / use the block erase commands to first clear memory (write 0xFFs)
192- // / WARNING: if you write beyond a page boundary (or more than 256bytes),
193- // / the bytes will wrap around and start overwriting at the beginning of that same page
194- // / see datasheet for more details
195- void SPIFlash::writeBytes (long addr, const void * buf, uint16_t len) {
196- command (SPIFLASH_BYTEPAGEPROGRAM, true ); // Byte/Page Program
197- SPI.transfer (addr >> 16 );
198- SPI.transfer (addr >> 8 );
199- SPI.transfer (addr);
200- for (uint16_t i = 0 ; i < len; i++)
201- SPI.transfer (((byte*) buf)[i]);
202- unselect ();
226+ // / This version handles both page alignment and data blocks larger than 256 bytes.
227+ // /
228+ void SPIFlash::writeBytes (uint32_t addr, const void * buf, uint16_t len) {
229+ uint16_t n;
230+ uint16_t maxBytes = 256 -(addr%256 ); // force the first set of bytes to stay within the first page
231+ uint16_t offset = 0 ;
232+ while (len>0 )
233+ {
234+ n = (len<=maxBytes) ? len : maxBytes;
235+ command (SPIFLASH_BYTEPAGEPROGRAM, true ); // Byte/Page Program
236+ SPI.transfer (addr >> 16 );
237+ SPI.transfer (addr >> 8 );
238+ SPI.transfer (addr);
239+
240+ for (uint16_t i = 0 ; i < n; i++)
241+ SPI.transfer (((uint8_t *) buf)[offset + i]);
242+ unselect ();
243+
244+ addr+=n; // adjust the addresses and remaining bytes by what we've just transferred.
245+ offset +=n;
246+ len -= n;
247+ maxBytes = 256 ; // now we can do up to 256 bytes per loop
248+ }
203249}
204250
205251// / erase entire flash memory array
@@ -214,7 +260,7 @@ void SPIFlash::chipErase() {
214260}
215261
216262// / erase a 4Kbyte block
217- void SPIFlash::blockErase4K (long addr) {
263+ void SPIFlash::blockErase4K (uint32_t addr) {
218264 command (SPIFLASH_BLOCKERASE_4K, true ); // Block Erase
219265 SPI.transfer (addr >> 16 );
220266 SPI.transfer (addr >> 8 );
@@ -223,7 +269,7 @@ void SPIFlash::blockErase4K(long addr) {
223269}
224270
225271// / erase a 32Kbyte block
226- void SPIFlash::blockErase32K (long addr) {
272+ void SPIFlash::blockErase32K (uint32_t addr) {
227273 command (SPIFLASH_BLOCKERASE_32K, true ); // Block Erase
228274 SPI.transfer (addr >> 16 );
229275 SPI.transfer (addr >> 8 );
0 commit comments