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
14
34
15
35
#include < SPIFlash.h>
16
36
17
- byte SPIFlash::UNIQUEID[8 ];
37
+ uint8_t SPIFlash::UNIQUEID[8 ];
18
38
19
39
// / IMPORTANT: NAND FLASH memory requires erase before write, because
20
40
// / 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) {
32
52
33
53
// / Select the flash chip
34
54
void SPIFlash::select () {
35
- noInterrupts ();
36
55
// save current SPI settings
56
+ #ifndef SPI_HAS_TRANSACTION
57
+ noInterrupts ();
58
+ #endif
37
59
_SPCR = SPCR;
38
60
_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
40
66
SPI.setDataMode (SPI_MODE0);
41
67
SPI.setBitOrder (MSBFIRST);
42
68
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
43
69
SPI.begin ();
70
+ #endif
44
71
digitalWrite (_slaveSelectPin, LOW);
45
72
}
46
73
47
74
// / UNselect the flash chip
48
75
void SPIFlash::unselect () {
49
76
digitalWrite (_slaveSelectPin, HIGH);
50
77
// 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
51
83
SPCR = _SPCR;
52
84
SPSR = _SPSR;
53
- interrupts ();
54
85
}
55
86
56
87
// / setup SPI, read device ID etc...
57
88
boolean SPIFlash::initialize ()
58
89
{
59
- SPI.begin ();
60
90
_SPCR = SPCR;
61
91
_SPSR = SPSR;
62
92
pinMode (_slaveSelectPin, OUTPUT);
93
+ #ifdef SPI_HAS_TRANSACTION
94
+ _settings = SPISettings (4000000 , MSBFIRST, SPI_MODE0);
95
+ #endif
96
+
63
97
unselect ();
64
98
wakeup ();
65
99
@@ -73,15 +107,15 @@ boolean SPIFlash::initialize()
73
107
}
74
108
75
109
// / Get the manufacturer and device ID bytes (as a short word)
76
- word SPIFlash::readDeviceId ()
110
+ uint16_t SPIFlash::readDeviceId ()
77
111
{
78
112
#if defined(__AVR_ATmega32U4__) // Arduino Leonardo, MoteinoLeo
79
113
command (SPIFLASH_IDREAD); // Read JEDEC ID
80
114
#else
81
115
select ();
82
116
SPI.transfer (SPIFLASH_IDREAD);
83
117
#endif
84
- word jedecid = SPI.transfer (0 ) << 8 ;
118
+ uint16_t jedecid = SPI.transfer (0 ) << 8 ;
85
119
jedecid |= SPI.transfer (0 );
86
120
unselect ();
87
121
return jedecid;
@@ -90,47 +124,47 @@ word SPIFlash::readDeviceId()
90
124
// / Get the 64 bit unique identifier, stores it in UNIQUEID[8]. Only needs to be called once, ie after initialize
91
125
// / Returns the byte pointer to the UNIQUEID byte array
92
126
// / 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(' '); }
94
128
// / 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 ()
97
131
{
98
132
command (SPIFLASH_MACREAD);
99
133
SPI.transfer (0 );
100
134
SPI.transfer (0 );
101
135
SPI.transfer (0 );
102
136
SPI.transfer (0 );
103
- for (byte i=0 ;i<8 ;i++)
137
+ for (uint8_t i=0 ;i<8 ;i++)
104
138
UNIQUEID[i] = SPI.transfer (0 );
105
139
unselect ();
106
140
return UNIQUEID;
107
141
}
108
142
109
143
// / read 1 byte from flash memory
110
- byte SPIFlash::readByte (long addr) {
144
+ uint8_t SPIFlash::readByte (uint32_t addr) {
111
145
command (SPIFLASH_ARRAYREADLOWFREQ);
112
146
SPI.transfer (addr >> 16 );
113
147
SPI.transfer (addr >> 8 );
114
148
SPI.transfer (addr);
115
- byte result = SPI.transfer (0 );
149
+ uint8_t result = SPI.transfer (0 );
116
150
unselect ();
117
151
return result;
118
152
}
119
153
120
154
// / 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) {
122
156
command (SPIFLASH_ARRAYREAD);
123
157
SPI.transfer (addr >> 16 );
124
158
SPI.transfer (addr >> 8 );
125
159
SPI.transfer (addr);
126
160
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 );
129
163
unselect ();
130
164
}
131
165
132
166
// / 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){
134
168
#if defined(__AVR_ATmega32U4__) // Arduino Leonardo, MoteinoLeo
135
169
DDRB |= B00000001; // Make sure the SS pin (PB0 - used by RFM12B on MoteinoLeo R1) is set as output HIGH!
136
170
PORTB |= B00000001;
@@ -156,19 +190,19 @@ boolean SPIFlash::busy()
156
190
/*
157
191
select();
158
192
SPI.transfer(SPIFLASH_STATUSREAD);
159
- byte status = SPI.transfer(0);
193
+ uint8_t status = SPI.transfer(0);
160
194
unselect();
161
195
return status & 1;
162
196
*/
163
197
return readStatus () & 1 ;
164
198
}
165
199
166
200
// / return the STATUS register
167
- byte SPIFlash::readStatus ()
201
+ uint8_t SPIFlash::readStatus ()
168
202
{
169
203
select ();
170
204
SPI.transfer (SPIFLASH_STATUSREAD);
171
- byte status = SPI.transfer (0 );
205
+ uint8_t status = SPI.transfer (0 );
172
206
unselect ();
173
207
return status;
174
208
}
@@ -177,7 +211,7 @@ byte SPIFlash::readStatus()
177
211
// / Write 1 byte to flash memory
178
212
// / WARNING: you can only write to previously erased memory locations (see datasheet)
179
213
// / 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) {
181
215
command (SPIFLASH_BYTEPAGEPROGRAM, true ); // Byte/Page Program
182
216
SPI.transfer (addr >> 16 );
183
217
SPI.transfer (addr >> 8 );
@@ -186,20 +220,32 @@ void SPIFlash::writeByte(long addr, uint8_t byt) {
186
220
unselect ();
187
221
}
188
222
189
- // / write 1-256 bytes to flash memory
223
+ // / write multiple bytes to flash memory (up to 64K)
190
224
// / WARNING: you can only write to previously erased memory locations (see datasheet)
191
225
// / 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
+ }
203
249
}
204
250
205
251
// / erase entire flash memory array
@@ -214,7 +260,7 @@ void SPIFlash::chipErase() {
214
260
}
215
261
216
262
// / erase a 4Kbyte block
217
- void SPIFlash::blockErase4K (long addr) {
263
+ void SPIFlash::blockErase4K (uint32_t addr) {
218
264
command (SPIFLASH_BLOCKERASE_4K, true ); // Block Erase
219
265
SPI.transfer (addr >> 16 );
220
266
SPI.transfer (addr >> 8 );
@@ -223,7 +269,7 @@ void SPIFlash::blockErase4K(long addr) {
223
269
}
224
270
225
271
// / erase a 32Kbyte block
226
- void SPIFlash::blockErase32K (long addr) {
272
+ void SPIFlash::blockErase32K (uint32_t addr) {
227
273
command (SPIFLASH_BLOCKERASE_32K, true ); // Block Erase
228
274
SPI.transfer (addr >> 16 );
229
275
SPI.transfer (addr >> 8 );
0 commit comments