@@ -29,6 +29,7 @@ Adafruit_SPIFlash flash(FLASH_SS, &FLASH_SPI_PORT); // Use hardware SPI
2929
3030Adafruit_USBD_MSC usb_msc;
3131
32+
3233// the setup function runs once when you press reset or power the board
3334void setup ()
3435{
@@ -67,7 +68,8 @@ void loop()
6768int32_t msc_read_cb (uint32_t lba, void * buffer, uint32_t bufsize)
6869{
6970 const uint32_t addr = lba*512 ;
70- return flash.readBuffer (addr, (uint8_t *) buffer, bufsize);
71+ flash_cache_read ((uint8_t *) buffer, addr, bufsize);
72+ return bufsize;
7173}
7274
7375// Callback invoked when received WRITE10 command.
@@ -77,12 +79,116 @@ int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
7779{
7880 // need to erase & caching write back
7981 const uint32_t addr = lba*512 ;
80- return flash.writeBuffer (addr, buffer, bufsize);
82+ flash_cache_write (addr, buffer, bufsize);
83+ return bufsize;
8184}
8285
8386// Callback invoked when WRITE10 command is completed (status received and accepted by host).
8487// used to flush any pending cache.
8588void msc_flush_cb (void )
8689{
87- // nothing to do
90+ flash_cache_flush ();
91+ }
92+
93+ // --------------------------------------------------------------------+
94+ // Flash Caching
95+ // --------------------------------------------------------------------+
96+ #define FLASH_CACHE_SIZE 4096 // must be a erasable page size
97+ #define FLASH_CACHE_INVALID_ADDR 0xffffffff
98+
99+ uint32_t cache_addr = FLASH_CACHE_INVALID_ADDR;
100+ uint8_t cache_buf[FLASH_CACHE_SIZE];
101+
102+ static inline uint32_t page_addr_of (uint32_t addr)
103+ {
104+ return addr & ~(FLASH_CACHE_SIZE - 1 );
105+ }
106+
107+ static inline uint32_t page_offset_of (uint32_t addr)
108+ {
109+ return addr & (FLASH_CACHE_SIZE - 1 );
110+ }
111+
112+ void flash_cache_flush (void )
113+ {
114+ if ( cache_addr == FLASH_CACHE_INVALID_ADDR ) return ;
115+
116+ // indicator
117+ // ledOn(LED_BUILTIN);
118+
119+ flash.eraseSector (cache_addr/FLASH_CACHE_SIZE);
120+ flash.writeBuffer (cache_addr, cache_buf, FLASH_CACHE_SIZE);
121+
122+ // ledOff(LED_BUILTIN);
123+
124+ cache_addr = FLASH_CACHE_INVALID_ADDR;
125+ }
126+
127+ uint32_t flash_cache_write (uint32_t dst, void const * src, uint32_t len)
128+ {
129+ uint8_t const * src8 = (uint8_t const *) src;
130+ uint32_t remain = len;
131+
132+ // Program up to page boundary each loop
133+ while ( remain )
134+ {
135+ uint32_t const page_addr = page_addr_of (dst);
136+ uint32_t const offset = page_offset_of (dst);
137+
138+ uint32_t wr_bytes = FLASH_CACHE_SIZE - offset;
139+ wr_bytes = min (remain, wr_bytes);
140+
141+ // Page changes, flush old and update new cache
142+ if ( page_addr != cache_addr )
143+ {
144+ flash_cache_flush ();
145+ cache_addr = page_addr;
146+
147+ // read a whole page from flash
148+ flash.readBuffer (page_addr, cache_buf, FLASH_CACHE_SIZE);
149+ }
150+
151+ memcpy (cache_buf + offset, src8, wr_bytes);
152+
153+ // adjust for next run
154+ src8 += wr_bytes;
155+ remain -= wr_bytes;
156+ dst += wr_bytes;
157+ }
158+
159+ return len - remain;
160+ }
161+
162+ void flash_cache_read (uint8_t * dst, uint32_t addr, uint32_t count)
163+ {
164+ // overwrite with cache value if available
165+ if ( (cache_addr != FLASH_CACHE_INVALID_ADDR) &&
166+ !(addr < cache_addr && addr + count <= cache_addr) &&
167+ !(addr >= cache_addr + FLASH_CACHE_SIZE) )
168+ {
169+ int dst_off = cache_addr - addr;
170+ int src_off = 0 ;
171+
172+ if ( dst_off < 0 )
173+ {
174+ src_off = -dst_off;
175+ dst_off = 0 ;
176+ }
177+
178+ int cache_bytes = min (FLASH_CACHE_SIZE-src_off, count - dst_off);
179+
180+ // start to cached
181+ if ( dst_off ) flash.readBuffer (addr, dst, dst_off);
182+
183+ // cached
184+ memcpy (dst + dst_off, cache_buf + src_off, cache_bytes);
185+
186+ // cached to end
187+ int copied = dst_off + cache_bytes;
188+ if ( copied < count ) flash.readBuffer (addr + copied, dst + copied, count - copied);
189+ }
190+ else
191+ {
192+ flash.readBuffer (addr, dst, count);
193+ }
88194}
0 commit comments