1
+ #include " spi_flash.h"
2
+
3
+ namespace hal
4
+ {
5
+ constexpr size_t SPIFLASH_PAGESIZE = 256 ;
6
+
7
+ enum SPICommand
8
+ {
9
+ WRITEENABLE = 0x06 ,
10
+ WRITEDISABLE = 0x04 ,
11
+ BLOCKERASE_4K = 0x20 ,
12
+ BLOCKERASE_32K = 0x52 ,
13
+ BLOCKERASE_64K = 0xD8 ,
14
+ CHIPERASE = 0x60 ,
15
+ STATUSREAD = 0x05 ,
16
+ STATUSWRITE = 0x01 ,
17
+ ARRAYREAD = 0x0B ,
18
+ ARRAYREADLOWFREQ = 0x03 ,
19
+ SLEEP = 0xB9 ,
20
+ WAKE = 0xAB ,
21
+ BYTEPAGEPROGRAM = 0x02 ,
22
+ IDREAD = 0x9F ,
23
+ MACREAD = 0x4B
24
+ };
25
+
26
+ SPIFlash::SPIFlash (SPIClass &spi_instance, uint8_t cs_pin, uint16_t chip_id)
27
+ : m_spi(spi_instance)
28
+ , m_cs_pin(cs_pin)
29
+ , m_chip_id(chip_id)
30
+ {
31
+ }
32
+
33
+ void SPIFlash::select ()
34
+ {
35
+ m_spi.beginTransaction (m_settings);
36
+ digitalWrite (m_cs_pin, LOW);
37
+ }
38
+
39
+ void SPIFlash::unselect ()
40
+ {
41
+ digitalWrite (m_cs_pin, HIGH);
42
+ m_spi.endTransaction ();
43
+ }
44
+
45
+ boolean SPIFlash::begin ()
46
+ {
47
+ pinMode (m_cs_pin, OUTPUT);
48
+ m_spi.begin ();
49
+ m_settings = SPISettings (25000000 , MSBFIRST, SPI_MODE0);
50
+
51
+ unselect ();
52
+ wakeup ();
53
+
54
+ if (m_chip_id == 0 || read_chip_id () == m_chip_id)
55
+ {
56
+ command (SPICommand::STATUSWRITE, true );
57
+ m_spi.transfer (0 );
58
+ unselect ();
59
+ return true ;
60
+ }
61
+
62
+ return false ;
63
+ }
64
+
65
+ uint16_t SPIFlash::read_chip_id ()
66
+ {
67
+ command (SPICommand::IDREAD);
68
+ uint16_t chip_id = m_spi.transfer (0 ) << 8 ;
69
+ chip_id |= m_spi.transfer (0 );
70
+ unselect ();
71
+ return chip_id;
72
+ }
73
+
74
+ uint8_t SPIFlash::read (uint32_t addr)
75
+ {
76
+ command (SPICommand::ARRAYREADLOWFREQ);
77
+ m_spi.transfer (addr >> 16 );
78
+ m_spi.transfer (addr >> 8 );
79
+ m_spi.transfer (addr);
80
+ uint8_t result = m_spi.transfer (0 );
81
+ unselect ();
82
+ return result;
83
+ }
84
+
85
+ void SPIFlash::read_array (uint32_t addr, void * buf, uint16_t len)
86
+ {
87
+ command (SPICommand::ARRAYREAD);
88
+ m_spi.transfer (addr >> 16 );
89
+ m_spi.transfer (addr >> 8 );
90
+ m_spi.transfer (addr);
91
+ m_spi.transfer (0 ); // dummy 8 clocks
92
+
93
+ for (uint16_t i = 0 ; i < len; ++i)
94
+ {
95
+ ((uint8_t *)buf)[i] = m_spi.transfer (0 );
96
+ }
97
+
98
+ unselect ();
99
+ }
100
+
101
+ void SPIFlash::read_array_dma (uint32_t addr, void * buf, uint16_t len)
102
+ {
103
+ command (SPICommand::ARRAYREAD);
104
+ m_spi.transfer (addr >> 16 );
105
+ m_spi.transfer (addr >> 8 );
106
+ m_spi.transfer (addr);
107
+ m_spi.transfer (0 ); // dummy 8 clocks
108
+
109
+ m_spi.dmaTransfer (nullptr , buf, len);
110
+
111
+ for (uint16_t i = 0 ; i < len; ++i)
112
+ {
113
+ ((uint8_t *)buf)[i] = m_spi.transfer (0 );
114
+ }
115
+
116
+ unselect ();
117
+ }
118
+
119
+ void SPIFlash::command (uint8_t cmd, bool write)
120
+ {
121
+ if (cmd != SPICommand::WAKE)
122
+ {
123
+ while (busy ());
124
+ }
125
+
126
+ if (write )
127
+ {
128
+ select ();
129
+ m_spi.transfer (SPICommand::WRITEENABLE);
130
+ unselect ();
131
+ while (busy ());
132
+ }
133
+
134
+ select ();
135
+ m_spi.transfer (cmd);
136
+ }
137
+
138
+ boolean SPIFlash::busy ()
139
+ {
140
+ return read_status () & 1 ;
141
+ }
142
+
143
+ boolean SPIFlash::write_enable_latch ()
144
+ {
145
+ return read_status () & 2 ;
146
+ }
147
+
148
+ uint8_t SPIFlash::read_status ()
149
+ {
150
+ select ();
151
+ m_spi.transfer (SPICommand::STATUSREAD);
152
+ uint8_t status = m_spi.transfer (0 );
153
+ unselect ();
154
+ return status;
155
+ }
156
+
157
+ void SPIFlash::write (uint32_t addr, uint8_t bt)
158
+ {
159
+ command (SPICommand::BYTEPAGEPROGRAM, true );
160
+ m_spi.transfer (addr >> 16 );
161
+ m_spi.transfer (addr >> 8 );
162
+ m_spi.transfer (addr);
163
+ m_spi.transfer (bt);
164
+ unselect ();
165
+ }
166
+
167
+ void SPIFlash::write_array (uint32_t addr, const void * buf, uint16_t len)
168
+ {
169
+ uint16_t bytes_in_page = SPIFLASH_PAGESIZE - (addr % SPIFLASH_PAGESIZE);
170
+ uint16_t offset = 0 ;
171
+
172
+ while (len > 0 )
173
+ {
174
+ uint16_t batch_size = (len <= bytes_in_page) ? len : bytes_in_page;
175
+
176
+ command (SPICommand::BYTEPAGEPROGRAM, true );
177
+ m_spi.transfer (addr >> 16 );
178
+ m_spi.transfer (addr >> 8 );
179
+ m_spi.transfer (addr);
180
+
181
+ for (uint16_t i = 0 ; i < batch_size; i++)
182
+ {
183
+ m_spi.transfer (((uint8_t *)buf)[offset + i]);
184
+ }
185
+
186
+ unselect ();
187
+
188
+ // wait till it's programmed
189
+ while (write_enable_latch ());
190
+
191
+ addr += batch_size;
192
+ offset += batch_size;
193
+ len -= batch_size;
194
+ bytes_in_page = SPIFLASH_PAGESIZE;
195
+ }
196
+ }
197
+
198
+ void SPIFlash::write_array_dma (uint32_t addr, const void * buf, uint16_t len)
199
+ {
200
+ const uint8_t * byte_buf = (const uint8_t *)buf;
201
+ uint16_t bytes_in_page = SPIFLASH_PAGESIZE - (addr % SPIFLASH_PAGESIZE);
202
+
203
+ while (len > 0 )
204
+ {
205
+ uint16_t batch_size = (len <= bytes_in_page) ? len : bytes_in_page;
206
+
207
+ command (SPICommand::BYTEPAGEPROGRAM, true );
208
+ m_spi.transfer (addr >> 16 );
209
+ m_spi.transfer (addr >> 8 );
210
+ m_spi.transfer (addr);
211
+
212
+ m_spi.dmaSend (byte_buf, batch_size);
213
+
214
+ unselect ();
215
+
216
+ // wait till it's programmed
217
+ while (write_enable_latch ());
218
+
219
+ addr += batch_size;
220
+ byte_buf += batch_size;
221
+ len -= batch_size;
222
+ bytes_in_page = SPIFLASH_PAGESIZE;
223
+ }
224
+ }
225
+
226
+ void SPIFlash::erase_full_chip ()
227
+ {
228
+ command (SPICommand::CHIPERASE, true );
229
+ unselect ();
230
+ while (write_enable_latch ());
231
+ }
232
+
233
+ void SPIFlash::erase_4K (uint32_t addr)
234
+ {
235
+ command (SPICommand::BLOCKERASE_4K, true );
236
+ m_spi.transfer (addr >> 16 );
237
+ m_spi.transfer (addr >> 8 );
238
+ m_spi.transfer (addr);
239
+ unselect ();
240
+ while (write_enable_latch ());
241
+ }
242
+
243
+ void SPIFlash::erase_32K (uint32_t addr)
244
+ {
245
+ command (SPICommand::BLOCKERASE_32K, true );
246
+ m_spi.transfer (addr >> 16 );
247
+ m_spi.transfer (addr >> 8 );
248
+ m_spi.transfer (addr);
249
+ unselect ();
250
+ while (write_enable_latch ());
251
+ }
252
+
253
+ void SPIFlash::erase_64K (uint32_t addr)
254
+ {
255
+ command (SPICommand::BLOCKERASE_64K, true );
256
+ m_spi.transfer (addr >> 16 );
257
+ m_spi.transfer (addr >> 8 );
258
+ m_spi.transfer (addr);
259
+ unselect ();
260
+ while (write_enable_latch ());
261
+ }
262
+
263
+ void SPIFlash::sleep ()
264
+ {
265
+ command (SPICommand::SLEEP);
266
+ unselect ();
267
+ }
268
+
269
+ void SPIFlash::wakeup ()
270
+ {
271
+ command (SPICommand::WAKE);
272
+ unselect ();
273
+ }
274
+
275
+ void SPIFlash::end ()
276
+ {
277
+ m_spi.end ();
278
+ }
279
+ }
0 commit comments