Dataflash_WaitWhileBusy() now always ensures that the dataflash is ready for the...
[pub/USBasp.git] / Demos / Device / ClassDriver / MassStorage / Lib / DataflashManager.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2009.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.fourwalledcubicle.com
7 */
8
9 /*
10 Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, and distribute this software
13 and its documentation for any purpose and without fee is hereby
14 granted, provided that the above copyright notice appear in all
15 copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaim all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29 */
30
31 /** \file
32 *
33 * Functions to manage the physical dataflash media, including reading and writing of
34 * blocks of data. These functions are called by the SCSI layer when data must be stored
35 * or retrieved to/from the physical storage media. If a different media is used (such
36 * as a SD card or EEPROM), functions similar to these will need to be generated.
37 */
38
39 #define INCLUDE_FROM_DATAFLASHMANAGER_C
40 #include "DataflashManager.h"
41
42 /** Writes blocks (OS blocks, not Dataflash pages) to the storage medium, the board dataflash IC(s), from
43 * the pre-selected data OUT endpoint. This routine reads in OS sized blocks from the endpoint and writes
44 * them to the dataflash in Dataflash page sized blocks.
45 *
46 * \param[in] BlockAddress Data block starting address for the write sequence
47 * \param[in] TotalBlocks Number of blocks of data to write
48 */
49 void DataflashManager_WriteBlocks(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, const uint32_t BlockAddress, uint16_t TotalBlocks)
50 {
51 uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
52 uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
53 uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
54 bool UsingSecondBuffer = false;
55
56 /* Copy selected dataflash's current page contents to the dataflash buffer */
57 Dataflash_SelectChipFromPage(CurrDFPage);
58 #if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
59 Dataflash_SendByte(DF_CMD_MAINMEMTOBUFF1);
60 Dataflash_SendAddressBytes(CurrDFPage, 0);
61 #endif
62 Dataflash_WaitWhileBusy();
63
64 /* Send the dataflash buffer write command */
65 Dataflash_ToggleSelectedChipCS();
66 Dataflash_SendByte(DF_CMD_BUFF1WRITE);
67 Dataflash_SendAddressBytes(0, CurrDFPageByte);
68
69 /* Wait until endpoint is ready before continuing */
70 while (!(Endpoint_IsReadWriteAllowed()));
71
72 while (TotalBlocks)
73 {
74 uint8_t BytesInBlockDiv16 = 0;
75
76 /* Write an endpoint packet sized data block to the dataflash */
77 while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
78 {
79 /* Check if the endpoint is currently empty */
80 if (!(Endpoint_IsReadWriteAllowed()))
81 {
82 /* Clear the current endpoint bank */
83 Endpoint_ClearOUT();
84
85 /* Wait until the host has sent another packet */
86 while (!(Endpoint_IsReadWriteAllowed()));
87 }
88
89 /* Check if end of dataflash page reached */
90 if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
91 {
92 /* Write the dataflash buffer contents back to the dataflash page */
93 Dataflash_WaitWhileBusy();
94 Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
95 Dataflash_SendAddressBytes(CurrDFPage, 0);
96
97 /* Reset the dataflash buffer counter, increment the page counter */
98 CurrDFPageByteDiv16 = 0;
99 CurrDFPage++;
100
101 /* Once all the dataflash ICs have had their first buffers filled, switch buffers to maintain throughput */
102 if (Dataflash_GetSelectedChip() == DATAFLASH_CHIP_MASK(DATAFLASH_TOTALCHIPS))
103 UsingSecondBuffer = !(UsingSecondBuffer);
104
105 /* Select the next dataflash chip based on the new dataflash page index */
106 Dataflash_SelectChipFromPage(CurrDFPage);
107
108 #if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
109 /* If less than one dataflash page remaining, copy over the existing page to preserve trailing data */
110 if ((TotalBlocks * (VIRTUAL_MEMORY_BLOCK_SIZE >> 4)) < (DATAFLASH_PAGE_SIZE >> 4))
111 {
112 /* Copy selected dataflash's current page contents to the dataflash buffer */
113 Dataflash_WaitWhileBusy();
114 Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_MAINMEMTOBUFF2 : DF_CMD_MAINMEMTOBUFF1);
115 Dataflash_SendAddressBytes(CurrDFPage, 0);
116 Dataflash_WaitWhileBusy();
117 }
118 #endif
119
120 /* Send the dataflash buffer write command */
121 Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2WRITE : DF_CMD_BUFF1WRITE);
122 Dataflash_SendAddressBytes(0, 0);
123 }
124
125 /* Write one 16-byte chunk of data to the dataflash */
126 Dataflash_SendByte(Endpoint_Read_Byte());
127 Dataflash_SendByte(Endpoint_Read_Byte());
128 Dataflash_SendByte(Endpoint_Read_Byte());
129 Dataflash_SendByte(Endpoint_Read_Byte());
130 Dataflash_SendByte(Endpoint_Read_Byte());
131 Dataflash_SendByte(Endpoint_Read_Byte());
132 Dataflash_SendByte(Endpoint_Read_Byte());
133 Dataflash_SendByte(Endpoint_Read_Byte());
134 Dataflash_SendByte(Endpoint_Read_Byte());
135 Dataflash_SendByte(Endpoint_Read_Byte());
136 Dataflash_SendByte(Endpoint_Read_Byte());
137 Dataflash_SendByte(Endpoint_Read_Byte());
138 Dataflash_SendByte(Endpoint_Read_Byte());
139 Dataflash_SendByte(Endpoint_Read_Byte());
140 Dataflash_SendByte(Endpoint_Read_Byte());
141 Dataflash_SendByte(Endpoint_Read_Byte());
142
143 /* Increment the dataflash page 16 byte block counter */
144 CurrDFPageByteDiv16++;
145
146 /* Increment the block 16 byte block counter */
147 BytesInBlockDiv16++;
148
149 /* Check if the current command is being aborted by the host */
150 if (MSInterfaceInfo->State.IsMassStoreReset)
151 return;
152 }
153
154 /* Decrement the blocks remaining counter and reset the sub block counter */
155 TotalBlocks--;
156 }
157
158 /* Write the dataflash buffer contents back to the dataflash page */
159 Dataflash_WaitWhileBusy();
160 Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
161 Dataflash_SendAddressBytes(CurrDFPage, 0x00);
162 Dataflash_WaitWhileBusy();
163
164 /* If the endpoint is empty, clear it ready for the next packet from the host */
165 if (!(Endpoint_IsReadWriteAllowed()))
166 Endpoint_ClearOUT();
167
168 /* Deselect all dataflash chips */
169 Dataflash_DeselectChip();
170 }
171
172 /** Reads blocks (OS blocks, not Dataflash pages) from the storage medium, the board dataflash IC(s), into
173 * the pre-selected data IN endpoint. This routine reads in Dataflash page sized blocks from the Dataflash
174 * and writes them in OS sized blocks to the endpoint.
175 *
176 * \param[in] BlockAddress Data block starting address for the read sequence
177 * \param[in] TotalBlocks Number of blocks of data to read
178 */
179 void DataflashManager_ReadBlocks(USB_ClassInfo_MS_Device_t* MSInterfaceInfo, const uint32_t BlockAddress, uint16_t TotalBlocks)
180 {
181 uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
182 uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
183 uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
184
185 /* Send the dataflash main memory page read command */
186 Dataflash_SelectChipFromPage(CurrDFPage);
187 Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
188 Dataflash_SendAddressBytes(CurrDFPage, CurrDFPageByte);
189 Dataflash_SendByte(0x00);
190 Dataflash_SendByte(0x00);
191 Dataflash_SendByte(0x00);
192 Dataflash_SendByte(0x00);
193
194 /* Wait until endpoint is ready before continuing */
195 while (!(Endpoint_IsReadWriteAllowed()));
196
197 while (TotalBlocks)
198 {
199 uint8_t BytesInBlockDiv16 = 0;
200
201 /* Write an endpoint packet sized data block to the dataflash */
202 while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
203 {
204 /* Check if the endpoint is currently full */
205 if (!(Endpoint_IsReadWriteAllowed()))
206 {
207 /* Clear the endpoint bank to send its contents to the host */
208 Endpoint_ClearIN();
209
210 /* Wait until the endpoint is ready for more data */
211 while (!(Endpoint_IsReadWriteAllowed()));
212 }
213
214 /* Check if end of dataflash page reached */
215 if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
216 {
217 /* Reset the dataflash buffer counter, increment the page counter */
218 CurrDFPageByteDiv16 = 0;
219 CurrDFPage++;
220
221 /* Select the next dataflash chip based on the new dataflash page index */
222 Dataflash_SelectChipFromPage(CurrDFPage);
223
224 /* Send the dataflash main memory page read command */
225 Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
226 Dataflash_SendAddressBytes(CurrDFPage, 0);
227 Dataflash_SendByte(0x00);
228 Dataflash_SendByte(0x00);
229 Dataflash_SendByte(0x00);
230 Dataflash_SendByte(0x00);
231 }
232
233 /* Read one 16-byte chunk of data from the dataflash */
234 Endpoint_Write_Byte(Dataflash_ReceiveByte());
235 Endpoint_Write_Byte(Dataflash_ReceiveByte());
236 Endpoint_Write_Byte(Dataflash_ReceiveByte());
237 Endpoint_Write_Byte(Dataflash_ReceiveByte());
238 Endpoint_Write_Byte(Dataflash_ReceiveByte());
239 Endpoint_Write_Byte(Dataflash_ReceiveByte());
240 Endpoint_Write_Byte(Dataflash_ReceiveByte());
241 Endpoint_Write_Byte(Dataflash_ReceiveByte());
242 Endpoint_Write_Byte(Dataflash_ReceiveByte());
243 Endpoint_Write_Byte(Dataflash_ReceiveByte());
244 Endpoint_Write_Byte(Dataflash_ReceiveByte());
245 Endpoint_Write_Byte(Dataflash_ReceiveByte());
246 Endpoint_Write_Byte(Dataflash_ReceiveByte());
247 Endpoint_Write_Byte(Dataflash_ReceiveByte());
248 Endpoint_Write_Byte(Dataflash_ReceiveByte());
249 Endpoint_Write_Byte(Dataflash_ReceiveByte());
250
251 /* Increment the dataflash page 16 byte block counter */
252 CurrDFPageByteDiv16++;
253
254 /* Increment the block 16 byte block counter */
255 BytesInBlockDiv16++;
256
257 /* Check if the current command is being aborted by the host */
258 if (MSInterfaceInfo->State.IsMassStoreReset)
259 return;
260 }
261
262 /* Decrement the blocks remaining counter */
263 TotalBlocks--;
264 }
265
266 /* If the endpoint is full, send its contents to the host */
267 if (!(Endpoint_IsReadWriteAllowed()))
268 Endpoint_ClearIN();
269
270 /* Deselect all dataflash chips */
271 Dataflash_DeselectChip();
272 }
273
274 /** Writes blocks (OS blocks, not Dataflash pages) to the storage medium, the board dataflash IC(s), from
275 * the a given RAM buffer. This routine reads in OS sized blocks from the buffer and writes them to the
276 * dataflash in Dataflash page sized blocks. This can be linked to FAT libraries to write files to the
277 * dataflash.
278 *
279 * \param[in] BlockAddress Data block starting address for the write sequence
280 * \param[in] TotalBlocks Number of blocks of data to write
281 * \param[in] BufferPtr Pointer to the data source RAM buffer
282 */
283 void DataflashManager_WriteBlocks_RAM(const uint32_t BlockAddress, uint16_t TotalBlocks, uint8_t* BufferPtr)
284 {
285 uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
286 uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
287 uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
288 bool UsingSecondBuffer = false;
289
290 /* Copy selected dataflash's current page contents to the dataflash buffer */
291 Dataflash_SelectChipFromPage(CurrDFPage);
292 #if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
293 Dataflash_SendByte(DF_CMD_MAINMEMTOBUFF1);
294 Dataflash_SendAddressBytes(CurrDFPage, 0);
295 #endif
296 Dataflash_WaitWhileBusy();
297
298 /* Send the dataflash buffer write command */
299 Dataflash_ToggleSelectedChipCS();
300 Dataflash_SendByte(DF_CMD_BUFF1WRITE);
301 Dataflash_SendAddressBytes(0, CurrDFPageByte);
302
303 while (TotalBlocks)
304 {
305 uint8_t BytesInBlockDiv16 = 0;
306
307 /* Write an endpoint packet sized data block to the dataflash */
308 while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
309 {
310 /* Check if end of dataflash page reached */
311 if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
312 {
313 /* Write the dataflash buffer contents back to the dataflash page */
314 Dataflash_WaitWhileBusy();
315 Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
316 Dataflash_SendAddressBytes(CurrDFPage, 0);
317
318 /* Reset the dataflash buffer counter, increment the page counter */
319 CurrDFPageByteDiv16 = 0;
320 CurrDFPage++;
321
322 /* Once all the dataflash ICs have had their first buffers filled, switch buffers to maintain throughput */
323 if (Dataflash_GetSelectedChip() == DATAFLASH_CHIP_MASK(DATAFLASH_TOTALCHIPS))
324 UsingSecondBuffer = !(UsingSecondBuffer);
325
326 /* Select the next dataflash chip based on the new dataflash page index */
327 Dataflash_SelectChipFromPage(CurrDFPage);
328
329 #if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
330 /* If less than one dataflash page remaining, copy over the existing page to preserve trailing data */
331 if ((TotalBlocks * (VIRTUAL_MEMORY_BLOCK_SIZE >> 4)) < (DATAFLASH_PAGE_SIZE >> 4))
332 {
333 /* Copy selected dataflash's current page contents to the dataflash buffer */
334 Dataflash_WaitWhileBusy();
335 Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_MAINMEMTOBUFF2 : DF_CMD_MAINMEMTOBUFF1);
336 Dataflash_SendAddressBytes(CurrDFPage, 0);
337 Dataflash_WaitWhileBusy();
338 }
339 #endif
340
341 /* Send the dataflash buffer write command */
342 Dataflash_ToggleSelectedChipCS();
343 Dataflash_SendByte(DF_CMD_BUFF1WRITE);
344 Dataflash_SendAddressBytes(0, 0);
345 }
346
347 /* Write one 16-byte chunk of data to the dataflash */
348 for (uint8_t ByteNum = 0; ByteNum < 16; ByteNum++)
349 Dataflash_SendByte(*(BufferPtr++));
350
351 /* Increment the dataflash page 16 byte block counter */
352 CurrDFPageByteDiv16++;
353
354 /* Increment the block 16 byte block counter */
355 BytesInBlockDiv16++;
356 }
357
358 /* Decrement the blocks remaining counter and reset the sub block counter */
359 TotalBlocks--;
360 }
361
362 /* Write the dataflash buffer contents back to the dataflash page */
363 Dataflash_WaitWhileBusy();
364 Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
365 Dataflash_SendAddressBytes(CurrDFPage, 0x00);
366 Dataflash_WaitWhileBusy();
367
368 /* Deselect all dataflash chips */
369 Dataflash_DeselectChip();
370 }
371
372 /** Reads blocks (OS blocks, not Dataflash pages) from the storage medium, the board dataflash IC(s), into
373 * the a preallocated RAM buffer. This routine reads in Dataflash page sized blocks from the Dataflash
374 * and writes them in OS sized blocks to the given buffer. This can be linked to FAT libraries to read
375 * the files stored on the dataflash.
376 *
377 * \param[in] BlockAddress Data block starting address for the read sequence
378 * \param[in] TotalBlocks Number of blocks of data to read
379 * \param[out] BufferPtr Pointer to the data destination RAM buffer
380 */
381 void DataflashManager_ReadBlocks_RAM(const uint32_t BlockAddress, uint16_t TotalBlocks, uint8_t* BufferPtr)
382 {
383 uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
384 uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
385 uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
386
387 /* Send the dataflash main memory page read command */
388 Dataflash_SelectChipFromPage(CurrDFPage);
389 Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
390 Dataflash_SendAddressBytes(CurrDFPage, CurrDFPageByte);
391 Dataflash_SendByte(0x00);
392 Dataflash_SendByte(0x00);
393 Dataflash_SendByte(0x00);
394 Dataflash_SendByte(0x00);
395
396 while (TotalBlocks)
397 {
398 uint8_t BytesInBlockDiv16 = 0;
399
400 /* Write an endpoint packet sized data block to the dataflash */
401 while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
402 {
403 /* Check if end of dataflash page reached */
404 if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
405 {
406 /* Reset the dataflash buffer counter, increment the page counter */
407 CurrDFPageByteDiv16 = 0;
408 CurrDFPage++;
409
410 /* Select the next dataflash chip based on the new dataflash page index */
411 Dataflash_SelectChipFromPage(CurrDFPage);
412
413 /* Send the dataflash main memory page read command */
414 Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
415 Dataflash_SendAddressBytes(CurrDFPage, 0);
416 Dataflash_SendByte(0x00);
417 Dataflash_SendByte(0x00);
418 Dataflash_SendByte(0x00);
419 Dataflash_SendByte(0x00);
420 }
421
422 /* Read one 16-byte chunk of data from the dataflash */
423 for (uint8_t ByteNum = 0; ByteNum < 16; ByteNum++)
424 *(BufferPtr++) = Dataflash_ReceiveByte();
425
426 /* Increment the dataflash page 16 byte block counter */
427 CurrDFPageByteDiv16++;
428
429 /* Increment the block 16 byte block counter */
430 BytesInBlockDiv16++;
431 }
432
433 /* Decrement the blocks remaining counter */
434 TotalBlocks--;
435 }
436
437 /* Deselect all dataflash chips */
438 Dataflash_DeselectChip();
439 }
440
441 /** Disables the dataflash memory write protection bits on the board Dataflash ICs, if enabled. */
442 void DataflashManager_ResetDataflashProtections(void)
443 {
444 /* Select first dataflash chip, send the read status register command */
445 Dataflash_SelectChip(DATAFLASH_CHIP1);
446 Dataflash_SendByte(DF_CMD_GETSTATUS);
447
448 /* Check if sector protection is enabled */
449 if (Dataflash_ReceiveByte() & DF_STATUS_SECTORPROTECTION_ON)
450 {
451 Dataflash_ToggleSelectedChipCS();
452
453 /* Send the commands to disable sector protection */
454 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[0]);
455 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[1]);
456 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[2]);
457 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[3]);
458 }
459
460 /* Select second dataflash chip (if present on selected board), send read status register command */
461 #if (DATAFLASH_TOTALCHIPS == 2)
462 Dataflash_SelectChip(DATAFLASH_CHIP2);
463 Dataflash_SendByte(DF_CMD_GETSTATUS);
464
465 /* Check if sector protection is enabled */
466 if (Dataflash_ReceiveByte() & DF_STATUS_SECTORPROTECTION_ON)
467 {
468 Dataflash_ToggleSelectedChipCS();
469
470 /* Send the commands to disable sector protection */
471 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[0]);
472 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[1]);
473 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[2]);
474 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[3]);
475 }
476 #endif
477
478 /* Deselect current dataflash chip */
479 Dataflash_DeselectChip();
480 }