|
| 1 | +/********************************************************************* |
| 2 | + Adafruit invests time and resources providing this open source code, |
| 3 | + please support Adafruit and open-source hardware by purchasing |
| 4 | + products from Adafruit! |
| 5 | +
|
| 6 | + MIT license, check LICENSE for more information |
| 7 | + Copyright (c) 2019 Ha Thach for Adafruit Industries |
| 8 | + All text above, and the splash screen below must be included in |
| 9 | + any redistribution |
| 10 | +*********************************************************************/ |
| 11 | + |
| 12 | +#include "SPI.h" |
| 13 | +#include "SdFat.h" |
| 14 | +#include "Adafruit_InternalFlash.h" |
| 15 | +#include "Adafruit_TinyUSB.h" |
| 16 | + |
| 17 | +// Start address and size should matches value in the CircuitPython (INTERNAL_FLASH_FILESYSTEM = 1) |
| 18 | +// to make it easier to switch between Arduino and CircuitPython |
| 19 | +#define INTERNAL_FLASH_FILESYSTEM_START_ADDR (0x00040000 - 256 - 0 - INTERNAL_FLASH_FILESYSTEM_SIZE) |
| 20 | +#define INTERNAL_FLASH_FILESYSTEM_SIZE (64*1024) |
| 21 | + |
| 22 | +// Internal Flash object |
| 23 | +Adafruit_InternalFlash flash(INTERNAL_FLASH_FILESYSTEM_START_ADDR, INTERNAL_FLASH_FILESYSTEM_SIZE); |
| 24 | + |
| 25 | +// file system object from SdFat |
| 26 | +FatFileSystem fatfs; |
| 27 | + |
| 28 | +FatFile root; |
| 29 | +FatFile file; |
| 30 | + |
| 31 | +// USB MSC object |
| 32 | +Adafruit_USBD_MSC usb_msc; |
| 33 | + |
| 34 | +// Set to true when PC write to flash |
| 35 | +bool fs_changed; |
| 36 | + |
| 37 | +// the setup function runs once when you press reset or power the board |
| 38 | +void setup() |
| 39 | +{ |
| 40 | + // Initialize internal flash |
| 41 | + flash.begin(); |
| 42 | + |
| 43 | + // Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively |
| 44 | + usb_msc.setID("Adafruit", "Internal Flash", "1.0"); |
| 45 | + |
| 46 | + // Set callback |
| 47 | + usb_msc.setReadWriteCallback(msc_read_callback, msc_write_callback, msc_flush_callback); |
| 48 | + usb_msc.setWritableCallback(msc_writable_callback); |
| 49 | + |
| 50 | + // Set disk size, block size should be 512 regardless of flash page size |
| 51 | + usb_msc.setCapacity(flash.size()/512, 512); |
| 52 | + |
| 53 | + // Set Lun ready |
| 54 | + usb_msc.setUnitReady(true); |
| 55 | + |
| 56 | + usb_msc.begin(); |
| 57 | + |
| 58 | + // Init file system on the flash |
| 59 | + fatfs.begin(&flash); |
| 60 | + |
| 61 | + Serial.begin(115200); |
| 62 | + //while ( !Serial ) delay(10); // wait for native usb |
| 63 | + |
| 64 | + fs_changed = true; // to print contents initially |
| 65 | +} |
| 66 | + |
| 67 | +void loop() |
| 68 | +{ |
| 69 | + if ( fs_changed ) |
| 70 | + { |
| 71 | + fs_changed = false; |
| 72 | + |
| 73 | + if ( !root.open("/") ) |
| 74 | + { |
| 75 | + Serial.println("open root failed"); |
| 76 | + return; |
| 77 | + } |
| 78 | + |
| 79 | + Serial.println("Flash contents:"); |
| 80 | + |
| 81 | + // Open next file in root. |
| 82 | + // Warning, openNext starts at the current directory position |
| 83 | + // so a rewind of the directory may be required. |
| 84 | + while ( file.openNext(&root, O_RDONLY) ) |
| 85 | + { |
| 86 | + file.printFileSize(&Serial); |
| 87 | + Serial.write(' '); |
| 88 | + file.printName(&Serial); |
| 89 | + if ( file.isDir() ) |
| 90 | + { |
| 91 | + // Indicate a directory. |
| 92 | + Serial.write('/'); |
| 93 | + } |
| 94 | + Serial.println(); |
| 95 | + file.close(); |
| 96 | + } |
| 97 | + |
| 98 | + root.close(); |
| 99 | + |
| 100 | + Serial.println(); |
| 101 | + delay(1000); // refresh every 1 second |
| 102 | + } |
| 103 | +} |
| 104 | + |
| 105 | +// Callback invoked when received READ10 command. |
| 106 | +// Copy disk's data to buffer (up to bufsize) and |
| 107 | +// return number of copied bytes (must be multiple of block size) |
| 108 | +int32_t msc_read_callback (uint32_t lba, void* buffer, uint32_t bufsize) |
| 109 | +{ |
| 110 | + // Note: InternalFlash Block API: readBlocks/writeBlocks/syncBlocks |
| 111 | + // already include sector caching (if needed). We don't need to cache it, yahhhh!! |
| 112 | + return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1; |
| 113 | +} |
| 114 | + |
| 115 | +// Callback invoked when received WRITE10 command. |
| 116 | +// Process data in buffer to disk's storage and |
| 117 | +// return number of written bytes (must be multiple of block size) |
| 118 | +int32_t msc_write_callback (uint32_t lba, uint8_t* buffer, uint32_t bufsize) |
| 119 | +{ |
| 120 | + // Note: InternalFlash Block API: readBlocks/writeBlocks/syncBlocks |
| 121 | + // already include sector caching (if needed). We don't need to cache it, yahhhh!! |
| 122 | + return flash.writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1; |
| 123 | +} |
| 124 | + |
| 125 | +// Callback invoked when WRITE10 command is completed (status received and accepted by host). |
| 126 | +// used to flush any pending cache. |
| 127 | +void msc_flush_callback (void) |
| 128 | +{ |
| 129 | + // sync with flash |
| 130 | + flash.syncBlocks(); |
| 131 | + |
| 132 | + // clear file system's cache to force refresh |
| 133 | + fatfs.cacheClear(); |
| 134 | + |
| 135 | + fs_changed = true; |
| 136 | +} |
| 137 | + |
| 138 | +// Invoked to check if device is writable as part of SCSI WRITE10 |
| 139 | +// Default mode is writable |
| 140 | +bool msc_writable_callback(void) |
| 141 | +{ |
| 142 | + // true for writable, false for read-only |
| 143 | + return true; |
| 144 | +} |
0 commit comments