LittleFS port to Teensy/SPIFlash

@PaulStoffregen - @defragster

Ran it on a T3.5 with
Code:
DMAMEM char buf[49000];;  // USE DMAMEM for more memory than ITCM allows - or remove

and my last posted test program and it seems to be working - no hangs!
Code:
LittleFS Test
TotalSize (Bytes): 48896
started
printDirectory
--------------

 0 dirs with 0 files of Size 0 Bytes

MAKE files
printDirectory
--------------
DIR	structureData1 / 

 0 dirs with 0 files of Size 0 Bytes

 1 dirs with 0 files of Size 0 Bytes

--------------
printDirectory
--------------
DIR	structureData1 / 
	FILE	temp_test.txt		19

 0 dirs with 1 files of Size 19 Bytes
FILE	temp_test1.txt		19
FILE	temp_test2.txt		19
FILE	temp_test3.txt		1024

 1 dirs with 3 files of Size 1062 Bytes

Disk Usuage:
Bytes Used: 2816, Bytes Total:48896
Test for SOME DATA TO TEST
 
I have an ADC sketch running on a T_4.0 and I rebuilt that to work.

Tested the ASCIITable to build and run on T_4

The LittleFS_Program sketch certainly should not use any of the _RAM code changed - but note p#848 that fails as well.

Also fails on T_MMod :(

I can build and upload that NVRAM test sketch to both : T_4.0 and T_MMod though ...
 
Opened IDE 1.8.13 with TD 1.54 b7 and it builds and runs with 1MB :: LittleFS_Program myfs;

I'll install 1.54 b9 over that IDE 1.8.13 and see ...
 
TD 1.54 Beta 9 installed over IDE 1.8.13 beta 7 {working in poist #852}:

Same sketch EPROM DISK of 1MB :: #define TEST_PROG with if (!myfs.begin(1024 * 1024 * 1)) {

FAILS to start the T_4.0 after upload w/TeensyLoader - USB device OFFLINE - removed from Ports:
Code:
17:45:46.375 (loader):  gauge old value = 91
17:45:46.375 (loader): flash, block=92, bs=1024, auto=1
17:45:46.375 (loader):  gauge old value = 92
17:45:46.380 (loader): sending reboot
17:45:46.380 (loader): begin wait_until_offline
17:45:46.392 (ports 5): WM_DEVICECHANGE DBT_DEVICEREMOVECOMPLETE
17:45:46.393 (ports 5): remove: loc=usb:0/140000/0/6/1/4
17:45:46.393 (ports 5): usb_remove: usb:0/140000/0/6/1/4
17:45:46.393 (ports 5): nothing new, skipping HID & Ports enum
17:45:46.448 (loader): offline, waited 1
17:45:46.448 (loader): end operation, total time = 0.903 seconds
17:45:46.450 (loader): set background IMG_REBOOT_OK
17:45:46.451 (loader): redraw timer set, image 14 to show for 1200 ms
17:45:46.498 (loader): HID/win32:  vid:046D pid:C52B ver:1211
17:45:46.498 (loader): HID/win32:  vid:046D pid:C52B ver:1211
17:45:46.498 (loader): HID/win32:  vid:046D pid:C52B ver:1211
17:45:46.498 (loader): HID/win32:  vid:046D pid:C52B ver:1211
17:45:46.498 (loader): HID/win32:  vid:046D pid:C52B ver:1211
17:45:46.498 (loader): HID/win32:  vid:046D pid:C52B ver:1211
17:45:46.498 (loader): HID/win32:  vid:046D pid:C52B ver:1211
17:45:46.498 (loader): HID/win32:  vid:046D pid:C52B ver:1211
17:45:46.591 (ports 5): WM_DEVICECHANGE DBT_DEVNODES_CHANGED
17:45:46.591 (ports 5): nothing new, skipping HID & Ports enum
17:45:47.676 (loader): redraw, image 9
17:45:48.008 (ports 5): purge, name=hid#vid_16c0&pid_0478 (Teensy 4.0) Bootloader, loc=usb:0/140000/0/6/1/4, age=1.615 sec
17:46:14.137 (loader): file changed
17:46:14.157 (loader): File "LFSintegrity.ino.hex". 95232 bytes, 5% used
17:46:14.200 (post_compile 7): Begin, version=1.54-beta9, high-res time
17:46:14.202 (loader): remote connection 1540 opened
17:46:14.202 (loader): remote cmd from 1540: "comment: Teensyduino 1.54-beta9 - WINDOWS (teensy_post_compile)"
17:46:14.202 (loader): remote cmd from 1540: "status"
17:46:14.203 (post_compile 7): Sending command: comment: Teensyduino 1.54-beta9 - WINDOWS (teensy_post_compile)
17:46:14.203 (loader): remote cmd from 1540: "dir:C:\Users\Tim\AppData\Local\Temp\arduino_build_8985\"
17:46:14.203 (loader): remote cmd from 1540: "file:LFSintegrity.ino.hex"
17:46:14.204 (post_compile 7): Status: 1, 1, 0, 2, 0, 0, C:\Users\Tim\AppData\Local\Temp\arduino_build_8985\, LFSintegrity.ino.hex
17:46:14.204 (post_compile 7): Sending command: dir:C:\Users\Tim\AppData\Local\Temp\arduino_build_8985\
17:46:14.204 (post_compile 7): Sending command: file:LFSintegrity.ino.hex
17:46:14.220 (loader): File "LFSintegrity.ino.hex". 95232 bytes, 5% used
17:46:14.227 (loader): remote cmd from 1540: "status"
17:46:14.228 (post_compile 7): Status: 1, 1, 0, 2, 0, 0, C:\Users\Tim\AppData\Local\Temp\arduino_build_8985\, LFSintegrity.ino.hex
17:46:14.228 (post_compile 7): Disconnect
17:46:14.249 (loader): remote connection 1540 closed
17:46:14.516 (loader): remote connection 1460 opened
17:46:14.516 (loader): remote cmd from 1460: "comment: Teensyduino 1.54-beta9 - WINDOWS (teensy_post_compile)"
17:46:14.516 (loader): remote cmd from 1460: "status"
17:46:14.516 (loader): remote cmd from 1460: "dir:C:\Users\Tim\AppData\Local\Temp\arduino_build_8985\"
17:46:14.516 (loader): remote cmd from 1460: "file:LFSintegrity.ino.hex"
17:46:14.520 (post_compile 8): Begin, version=1.54-beta9, high-res time
17:46:14.522 (post_compile 8): Sending command: comment: Teensyduino 1.54-beta9 - WINDOWS (teensy_post_compile)
17:46:14.523 (post_compile 8): Status: 1, 1, 0, 2, 0, 0, C:\Users\Tim\AppData\Local\Temp\arduino_build_8985\, LFSintegrity.ino.hex
17:46:14.523 (post_compile 8): Sending command: dir:C:\Users\Tim\AppData\Local\Temp\arduino_build_8985\
17:46:14.523 (post_compile 8): Sending command: file:LFSintegrity.ino.hex
17:46:14.532 (loader): File "LFSintegrity.ino.hex". 95232 bytes, 5% used
17:46:14.548 (loader): remote cmd from 1460: "status"
17:46:14.549 (post_compile 8): Status: 1, 1, 0, 2, 0, 0, C:\Users\Tim\AppData\Local\Temp\arduino_build_8985\, LFSintegrity.ino.hex
17:46:14.549 (post_compile 8): Disconnect
17:46:14.563 (loader): remote connection 1460 closed
17:46:14.563 (loader): remote connection 1460 opened
17:46:14.564 (post_compile 9): Running teensy_reboot: "T:\arduino-1.8.13_t54\hardware\teensy\..\tools\teensy_reboot.exe" teensy_reboot.exe "-board=TEENSY40" "-port=usb:0/140000/0/6/1/4" "-portlabel=(null)" "-portprotocol=(null)"
17:46:14.579 (loader): remote connection 1468 opened
17:46:14.579 (reboot 10): Begin, version=1.54-beta9, high-res time
17:46:14.579 (reboot 10): location = usb:0/140000/0/6/1/4
17:46:14.579 (reboot 10): portlabel = (null)
17:46:14.579 (reboot 10): portprotocol = (null)
17:46:14.579 (reboot 10): LoadLibrary cfgmgr32 ok
17:46:14.579 (reboot 10): LoadLibrary ntdll ok
17:46:14.582 (reboot 10): nothing new, skipping HID & Ports enum
17:46:14.584 (reboot 10): Disconnect
17:46:14.595 (loader): remote connection 1468 closed
17:46:14.595 (loader): remote connection 1460 closed
17:46:18.485 (ports 5): WM_DEVICECHANGE DBT_DEVICEARRIVAL
17:46:18.486 (ports 5): found_usb_device, id=\\?\usb#vid_16c0&pid_0478#00096263#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
17:46:18.486 (ports 5): found_usb_device, loc=usb:0/140000/0/6/1/4    Port_#0004.Hub_#0011
17:46:18.486 (ports 5): found_usb_device, hwid=USB\VID_16C0&PID_0478&REV_0105
17:46:18.486 (ports 5): found_usb_device, devinst=00000018
17:46:18.486 (ports 5): add: loc=usb:0/140000/0/6/1/4, class=HID, vid=16C0, pid=0478, ver=0105, serial=00096263, dev=\\?\usb#vid_16c0&pid_0478#00096263#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
17:46:18.486 (ports 5): hiddev_from_devinst_list: iface=0
17:46:18.487 (ports 5): found_usb_device complete
17:46:18.489 (ports 5): hid, found devinst=00000019
17:46:18.489 (ports 5): hid, path=\\?\hid#vid_16c0&pid_0478#8&36efacb3&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
17:46:18.489 (ports 5): hid,  opened handle
17:46:18.489 (ports 5):  devinst=00000019, location=usb:0/140000/0/6/1/4
17:46:18.489 (ports 5):  vid=16C0, pid=0478, ver=0105, usepage=FF9C, use=0024
17:46:18.489 (ports 5):  devpath=\\?\hid#vid_16c0&pid_0478#8&36efacb3&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
17:46:18.489 (ports 5): usb_add: usb:0/140000/0/6/1/4  hid#vid_16c0&pid_0478 (Teensy 4.0) Bootloader
17:46:18.501 (ports 5): WM_DEVICECHANGE DBT_DEVNODES_CHANGED
17:46:18.502 (ports 5): nothing new, skipping HID & Ports enum
17:46:18.673 (ports 5): WM_DEVICECHANGE DBT_DEVNODES_CHANGED
17:46:18.673 (ports 5): nothing new, skipping HID & Ports enum
17:46:18.679 (loader): Device came online, code_size = 2031616
17:46:18.679 (loader): Board is: Teensy 4.0 (IMXRT1062), version 1.05
17:46:18.694 (loader): File "LFSintegrity.ino.hex". 95232 bytes, 5% used
17:46:18.694 (loader): set background IMG_ONLINE
17:46:18.710 (loader): File "LFSintegrity.ino.hex". 95232 bytes, 5% used
17:46:18.710 (loader): elf appears to be for Teensy 4.0 (IMXRT1062) (2031616 bytes)
17:46:18.710 (loader): elf binary data matches hex file
17:46:18.710 (loader): elf file is for Teensy 4.0 (IMXRT1062)
17:46:18.710 (loader): begin operation
17:46:18.737 (loader): flash, block=0, bs=1024, auto=1
17:46:18.737 (loader):  gauge old value = 0
...
17:46:19.413 (loader): flash, block=91, bs=1024, auto=1
17:46:19.418 (loader):  gauge old value = 91
17:46:19.418 (loader): flash, block=92, bs=1024, auto=1
17:46:19.418 (loader):  gauge old value = 92
17:46:19.423 (loader): sending reboot
17:46:19.423 (loader): begin wait_until_offline
17:46:19.434 (ports 5): WM_DEVICECHANGE DBT_DEVICEREMOVECOMPLETE
17:46:19.435 (ports 5): remove: loc=usb:0/140000/0/6/1/4
17:46:19.435 (ports 5): usb_remove: usb:0/140000/0/6/1/4
17:46:19.435 (ports 5): nothing new, skipping HID & Ports enum
17:46:19.484 (loader): offline, waited 1
17:46:19.484 (loader): end operation, total time = 0.774 seconds
17:46:19.484 (loader): set background IMG_REBOOT_OK
17:46:19.484 (loader): redraw timer set, image 14 to show for 1200 ms
17:46:19.484 (loader): HID/win32:  vid:046D pid:C52B ver:1211
17:46:19.484 (loader): HID/win32:  vid:046D pid:C52B ver:1211
17:46:19.484 (loader): HID/win32:  vid:046D pid:C52B ver:1211
17:46:19.484 (loader): HID/win32:  vid:046D pid:C52B ver:1211
17:46:19.484 (loader): HID/win32:  vid:046D pid:C52B ver:1211
17:46:19.500 (loader): HID/win32:  vid:046D pid:C52B ver:1211
17:46:19.500 (loader): HID/win32:  vid:046D pid:C52B ver:1211
17:46:19.500 (loader): HID/win32:  vid:046D pid:C52B ver:1211
17:46:19.747 (ports 5): WM_DEVICECHANGE DBT_DEVNODES_CHANGED
17:46:19.747 (ports 5): nothing new, skipping HID & Ports enum
17:46:20.690 (loader): redraw, image 9
17:46:21.074 (ports 5): purge, name=hid#vid_16c0&pid_0478 (Teensy 4.0) Bootloader, loc=usb:0/140000/0/6/1/4, age=1.639 sec
17:46:32.925 (loader): Verbose Info event
 
Installed TD Beta 8 over Beta 9 on IDE 1.8.13 and LFSIntegrity.ino works on T_4.0:
Code:
[B]17:54:31.698 (loader): redraw, image 9[/B]
17:54:40.819 (serialmon 6): Begin, version=1.54-beta8, high-res time
17:54:40.819 (serialmon 6): listening for location: usb:0/140000/0/6/1/4
17:54:40.819 (serialmon 6): LoadLibrary cfgmgr32 ok
17:54:40.819 (serialmon 6): LoadLibrary ntdll ok
17:54:40.822 (serialmon 6): callback 0024
17:54:40.822 (serialmon 6): callback 0081
17:54:40.825 (serialmon 6): callback 0083
17:54:40.825 (serialmon 6): hWnd = 1316154
17:54:40.825 (serialmon 6): loop stdin, ready=262143
17:54:40.827 (serialmon 6): found_usb_device, id=\\?\usb#vid_16c0&pid_0483#6150110#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
17:54:40.827 (serialmon 6): found_usb_device, loc=usb:0/140000/0/6/1/4    Port_#0004.Hub_#0011
17:54:40.827 (serialmon 6): found_usb_device, hwid=USB\VID_16C0&PID_0483&REV_0279
17:54:40.827 (serialmon 6): found_usb_device, devinst=00000004
17:54:40.827 (serialmon 6): add: loc=usb:0/140000/0/6/1/4, class=USB, vid=16C0, pid=0483, ver=0279, serial=6150110, dev=\\?\usb#vid_16c0&pid_0483#6150110#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
17:54:40.827 (serialmon 6):   comport_from_devinst_list attempt
[B]17:54:40.827 (serialmon 6):   found Ports in classguid_list at index=1
17:54:40.827 (serialmon 6):   port COM19 found from devnode
[/B]17:54:40.827 (serialmon 6): found_usb_device complete
17:54:40.828 (serialmon 6): usb_add: usb:0/140000/0/6/1/4
[B]17:54:40.828 (serialmon 6): translate "COM19" -> "\\.\COM19"
[/B]17:54:40.879 (serialmon 6): GetDefaultCommConfig success
17:54:40.918 (serialmon 6): SetDefaultCommConfig success
17:54:40.918 (serialmon 6): Opened \\.\COM19 Serial
17:54:40.920 (ports 5): callback 001A
17:54:41.006 (loader): remote connection 1440 opened
17:55:32.031 (loader): Verbose Info event
 
Just tried Teensy Micromod with my test sketch:
1. Hangs with 1.54bet9 on 1.8.15
but
2. Works with 1.54beta8 with IDE1.8.14
3. T4.0 works as well with beta8
 
@PaulStoffregen - @defragster

Don't think its an issue with LittleFS believe its something that changed in the core between 1.54beta8 and beta9. Why do I say this - I went back to previous commits - back to feb 23, 2021 with the same results it hangs the Teensy 4.0. Think @defragster is implying the same thing in post #854
Installed TD Beta 8 over Beta 9 on IDE 1.8.13 and LFSIntegrity.ino works on T_4.0:

@KurtE mentioned that if the core changed memory alignment (don't remember if you reverted that one or not) it might be the delta between T4 and t4.1?
 
@PaulStoffregen - @defragster - @KurtE

Not sure you reverted the 1k boundaries completely from the core for the 1062. This is still in imxrt1052.ld
Code:
	.text.csf : {
		FILL(0xFF)
		. = ALIGN(1024);
 
@all - Sorry head in different ...

Mike and I have been chatting as part of Hexapod stuff...

I wondered about maybe core changes to align memory to some alignments in flash...
And wondered if maybe something along that line.

I assume some of the obvious things have been checked, like that it is properly getting the size of the Flash for the 3 boards (T4, 4.1 and MM)...

And the starting location is OK...
EEPROM?

Again sorry I know random stuff

Edit: Will try in the morning... Hands shot for today!
 
Rabbit holes ….

Late for me to start playing but want to hook up a spi flash and see if there is a further problem or just the use of dmamem. Tim forgot if you tested with program mem. Eyes are crossed now.
 
Which sketch? Does it have spi flash ram? Does the 4.1 have psram… which would turn into dammed usage without?
 
Which sketch? Does it have spi flash ram? Does the 4.1 have psram… which would turn into dammed usage without?

post #853 - lfsintegrity using RAM1 or RAM2 - DMAMEM ( dammed :) ) - or EEPROM Program memory : didn't see it work ...
 
Typed the text below before I checked that I am running 1.54b9 with *.LD's from 1.54b8!
>> I had that thought and copied from the IDE 1.5.13 reinstall ... but apparently left before I built from that setup ... and then didn't restore the LD's

------------------- ALL GOOD USING THE TD 1.54b8 : imxrt1062.ld with :: IDE 1.8.15 and TeensyDuino 1.54 Beta 9
Got out a Beta T_4.0 Ran a sketch from 6 Nov 2020 - that was already on it and then rebuilt and ran fine

Put the same sketch on another T_4.0 that failed earlier and now it works. It does both RAM and SPI FLASH- but without Flash connected to stopped there.

Then put an older local copy of LFSIntegrity on that worked RAM and PROG on the Beta T_4 - and then that sketch on the other T-4.0 also working now????

This is current system IDE 1.8.15 and TeensyDuino 1.54 Beta 9 - running as before from TSET CmdLine builds from SublimeText editor - using TyCommnader for upload and SerMon.


No Idea what changed - or how it was wrong and match what Paul and Mike found ... now is working fine?
 
Looks like the 1K memory align change in the linker script exposed a bug in the startup code where we need a memory barrier between configuring the stack pointer and calling the memory copy function.

Committed a fix on github
https://github.com/PaulStoffregen/cores/commit/b8478ad56714087692b5c38ba0b0d864b035c2ed

1K memory align is necessary for (future) support of encrypting flash memory.

Good morning all

Just gave the fix a quick try on the MM and the 4.0. The worked like a charm.

No hangs my little test sketch from post https://forum.pjrc.com/threads/6750...tek-LY68L6400S?p=281478&viewfull=1#post281478.

That looks like it got, ok have to go and make some coffee - just work up.
 
Glad you found it! I wonder if it was like the Uncanny eyes code that tried to estimate how much memory we used so walked from top of memory to stack pointer finding out where memory changed. And I think it was Frank who mentioned I needed to not get that close to top of memory.... But that was awhile ago before this change
 
I've got an issue when using LittleFS on a T4.1 with an external flash chip, while running under a separate thread. It hangs the thread randomly, where the code works just fine when compiled without threads. I also see that if I substantially increase the setMicroTimer the condition improves, but does not go away. This wasn't an issue when using the same (similar) code with an SD card.

Are there any known issues using LittleFS or external Flash with threading?
 
I've got an issue when using LittleFS on a T4.1 with an external flash chip, while running under a separate thread. It hangs the thread randomly, where the code works just fine when compiled without threads. I also see that if I substantially increase the setMicroTimer the condition improves, but does not go away. This wasn't an issue when using the same (similar) code with an SD card.

Are there any known issues using LittleFS or external Flash with threading?

Not sure any use with threading was tested. SD card I/o uses interrupts or DMA perhaps and can complete its process without being on an active thread.

LittleFS code is all direct action where it uses the user thread for completion. If the thread is parked that ongoing operation will be frozen and that will leave the operation incomplete and the Flash in an unknown state.
 
I've got an issue when using LittleFS on a T4.1 with an external flash chip, while running under a separate thread. It hangs the thread randomly, where the code works just fine when compiled without threads. I also see that if I substantially increase the setMicroTimer the condition improves, but does not go away. This wasn't an issue when using the same (similar) code with an SD card.

Are there any known issues using LittleFS or external Flash with threading?

As @defragster mentioned - LittleFS wasn't tested with Teensythreads. The SD card operates differently than a flash chip.

Can you post the code so we can either test or see if there is anything obvious. Without that I can run an example and it works but may not work in your situation.
 
Installed 1.54b10 and it works initially on T_4.0

Seeing odd DMAMEM char buf[490000]; behavior - doing 'R'estart to test static RAM and hanging on restart?
Saw it on beta 10 announce post ... but this diff now?
Installed td 1.54 b10 on Win 10 over IDE 1.8.15 - Install good and no problems w/LittleFS LFSIntegrity onto T_4.0.

Ramdisk note - Primary RAM / RAM1 is always zeroed on any restart to won't persist.
Does work with DMAMEM / RAM2 : using LFSIntegrity {DMAMEM char buf[490000];} found an anomaly filling half of disk with a 'B'igfile then 'R'estart and 'b'igfile delete does a forever delete. using 256 byte blocks for file of size 223232 leaves something about the long file chain file unwritten. Will add .flush to see if it triggers safe use. Other I/O after 'B' is safe so not a lfs problem. Will move to T_4.1 PSRAM and try similar.
>> .flush() didn't fix ?

Not sure if it is added .flush leaving the RAM in odd worse state than just bad 'B'igfile ... looking some more.
 
Took out .flush that was not there before - can't even write the Bigfile just now?

It hangs and keeps hanging on restart until power off ... like DMAMEM adjustment changed how it works ????

DMAMEM char buf[490000];
that leaves room in RAM2:
teensy_size: Memory Usage on Teensy 4.1:
teensy_size: FLASH: code:78264, data:9752, headers:8236 free for files:8030212
teensy_size: RAM1: variables:21184, code:72536, padding:25768 free for local variables:404800
teensy_size: RAM2: variables:502400 free for malloc/new:21888
 
Switched to PSRAM ramdrive - 'B'igfile won't complete there either? It hangs after some portion of the write.

Button and TyComm/Reset has it start and dies early in setup() - next line would be ramdisk .begin()

Note just Bigfile - dies on first file write in a single iteration too ... Then hangs on restart after disk mounted - with debug on ...
Code:
printDirectory RAM_DISK
--------------

 0 dirs with 0 files of Size 0 Bytes
 Total 0 files of Size 0 Bytes
Bytes Used: 4096, Bytes Total:8388608
[B]:: /B_file.txt [/B]  [B][COLOR="#FF0000"]dies here ... then restart follows[/COLOR][/B]
T:\arduino-1.8.15\hardware\teensy\avr\libraries\LittleFS\examples\LFSintegrity\LFSintegrity.ino Jun 18 2021 23:31:25
LittleFS Test : File Integrity
configure 
mounted atfer format

Mounts and returns to setup then dies doing:
>> filecount = printDirectoryFilecount( myfs.open("/") ); // Set base value of filecount for disk
 
Last edited:
Can you post the code so we can either test or see if there is anything obvious. Without that I can run an example and it works but may not work in your situation.

My code is too large/complex to post (thousands of lines, a dozen sensors, four thread loops, etc). I’m heading out of town, but I’ll try and isolate it on Monday and post.

That said, when I couldn’t get the littleFS flash to work in threads, I reverted that section of my code to my old SD card solution. To my surprise it had the same strange behavior and also hung the thread. So, I went back a few revs to my last known good sketch on a known good board and it also didn’t work. This was all on 1.54b9. So, I ditched the 1.54 beta and went back to the GA IDE and all my SD routines in a thread worked great again. So, I suspect there is something in the beta that is breaking both SD and LittleFS in threads (both work fine without threads), in my specific situation.

Again, I’ll work to isolate a subset/sample and post next Monday.

Thanks,
Mike
 
@TeensyDigital - TD 1.54 Beta 10 was released with a change in startup that Paul saw cause troubles.

Though something new and bad affecting the LittleFS sketch in use with Beta 10.

@Paul /@all - I cannot now get the LFSIntegrity to write a complete file and not hang. I reverted the _RAM code in listtleFS.h for static RAM - always Zeros and no _sync doing dcache_flush - and still it is failing the write without hang on PSRAM?

Using a T_4.1 with twin PSRAMS but only using 8MB - was seeing the same with DMAMEM RAM2 on T_4.1 and on T_4.0:

Odd it was doing better on first post in Beta 10 thread ...now a total fail. Before and after removing the just added RAM code.

DOING: 'B' - starts BIG write and does not complete
or
DOING '1' - a single loop write to one small file and it hangs.

Something is corrupting the FS on RAM? With the STATIC RAM reversion and always ZERO on start it will restart okay, if not reverted it hangs on starting as the image is broken.

past times for Zzzz's ...

Current edits to LFSIntegrity as installed are the top: ROOTONLY, _RAM select and sizing, and (optional for smaller DMAMEM) fewer subdirs of 16 are only changes to test:

Code:
//#include <LittleFS.h>
#include <LittleFS_NAND.h>

#define HALFCUT  // HALFCUT defined to fill half the disk
[B]#define ROOTONLY // NORMAL is NOT DEFINED![/B]
#define NUMDIRS 32  // When not ROOTONLY must be 1 or more
#define MYPSRAM 8	// compile time PSRAM size
#define MYBLKSIZE 2048 // 2048
//#define SHOW_YIELD_CNT  1 // uncommented shows calls to Yield per second

[B]#define TEST_RAM[/B]
//#define TEST_SPI
//#define TEST_QSPI
//#define TEST_SPI_NAND
//#define TEST_QSPI_NAND
//#define TEST_PROG
//#define TEST_MRAM

IntervalTimer clocked10ms;
uint32_t yCalls = 0;
uint32_t yCallsMax = 0;
uint32_t yCallsLast = 0;
uint32_t yCallsIdx = 0;
uint32_t yCallsSum = 0;
#ifdef SHOW_YIELD_CNT
void yield() {
	yCalls++;
}
#endif
void clock_isr() {
	yCallsIdx++;
	if ( yCallsIdx >= 100 ) {
		if (yCallsSum > 0 )
			Serial.printf( "\n yps=%lu [mx=%lu]\t", yCallsSum, yCallsMax * 100);
		yCallsIdx = 0;
		yCallsSum = 0;
		yCallsMax = 0;
	}
	yCallsSum += yCalls - yCallsLast;
	if ( yCalls - yCallsLast > yCallsMax ) yCallsMax = yCalls - yCallsLast;
	yCallsLast = yCalls;
}

// Set for SPI usage
//const int FlashChipSelect = 10; // AUDIO BOARD
const int FlashChipSelect = 4; // PJRC Mem board 64MB on #5, #6 : NAND 1Gb on #3, 2GB on #4
//const int FlashChipSelect = 5; // PJRC Mem board 64MB on #5, #6 : NAND 1Gb on #3, 2GB on #4
//const int FlashChipSelect = 6; // digital pin for flash chip CS pin


#ifdef TEST_RAM
LittleFS_RAM myfs;
// RUNTIME :: extern "C" uint8_t external_psram_size;
[B]EXTMEM char buf[MYPSRAM * 1024 * 1024];	// USE DMAMEM for more memory than ITCM allows - or remove[/B]
//DMAMEM char buf[490000];	// USE DMAMEM for more memory than ITCM allows - or remove
//char buf[390000];	// USE DMAMEM for more memory than ITCM allows - or remove
char szDiskMem[] = "RAM_DISK";
#elif defined(TEST_SPI)
//const int FlashChipSelect = 10; // Arduino 101 built-in SPI Flash
#define FORMATSPI
//#define FORMATSPI2
LittleFS_SPIFlash myfs;
char szDiskMem[] = "SPI_DISK";
#elif defined(TEST_MRAM)
//const int FlashChipSelect = 10; // Arduino 101 built-in SPI Flash
LittleFS_SPIFram myfs;
char szDiskMem[] = "FRAM_DISK";
#elif defined(TEST_PROG)
LittleFS_Program myfs;
char szDiskMem[] = "PRO_DISK";
#elif defined(TEST_QSPI_NAND)
char szDiskMem[] = "QSPI_NAND";
LittleFS_QPINAND myfs;
#elif defined(TEST_SPI_NAND)
char szDiskMem[] = "SPI_NAND";
LittleFS_SPINAND myfs;
#else // TEST_QSPI
LittleFS_QSPIFlash myfs;
char szDiskMem[] = "QSPI_DISK";

#endif

File file3;

uint32_t DELSTART = 3; // originally was 3 + higher bias more to writes and larger files - lower odd
#define SUBADD 512	// bytes added each pass (*times file number)
#define BIGADD 1024	// bytes added each pass - bigger will quickly consume more space
[B]#define MAXNUM 16	// ALPHA A-Z is 26, less for fewer files[/B]
#define MAXFILL 2048 // 66000	// ZERO to disable :: Prevent iterations from over filling - require this much free
#define DELDELAY 0 	// delay before DEL files : delayMicroseconds
#define ADDDELAY 0 	// delay on ADD FILE : delayMicroseconds

const uint32_t lowOffset = 'a' - 'A';
const uint32_t lowShift = 13;
uint32_t errsLFS = 0;
uint32_t warnLFS = 0;
uint32_t lCnt = 0;
uint32_t LoopCnt = 0;
uint64_t rdCnt = 0;
uint64_t wrCnt = 0;
int filecount = 0;

void setup() {
	while (!Serial) ; // wait
	Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
	Serial.println("LittleFS Test : File Integrity"); delay(5);

#ifdef TEST_RAM
	if (!myfs.begin(buf, sizeof(buf))) {
#elif defined(TEST_RAM2)
	if (!myfs.begin(buf, sizeof(buf), MYBLKSIZE )) {
#elif defined(TEST_SPI)
#ifdef FORMATSPI
	if (!myfs.begin( FlashChipSelect )) {
#elif defined(FORMATSPI2)
	pinMode(FlashChipSelect, OUTPUT);
	digitalWriteFast(FlashChipSelect, LOW);
	SPI2.setMOSI(50);
	SPI2.setMISO(54);
	SPI2.setSCK(49);
	SPI2.begin();
	if (!myfs.begin(51, SPI2)) {
#endif
#elif defined(TEST_MRAM)
	if (!myfs.begin( FlashChipSelect )) {
#elif defined(TEST_SPI_NAND)
	if (!myfs.begin( FlashChipSelect )) {
#elif defined(TEST_PROG)
	if (!myfs.begin(1024 * 1024 * 6)) {
#else
	if (!myfs.begin()) {
#endif
		Serial.printf("Error starting %s\n", szDiskMem);
		checkInput( 1 );
	}
	// parseCmd( 'F' ); // ENABLE this if disk won't allow startup
	filecount = printDirectoryFilecount( myfs.open("/") );  // Set base value of filecount for disk
	printDirectory();
	parseCmd( '?' );
#ifndef ROOTONLY // make subdirs if !ROOTONLY
	makeRootDirs();
#endif
	checkInput( 1 );
	filecount = printDirectoryFilecount( myfs.open("/") );  // Set base value of filecount for disk
	printDirectory();
#ifdef SHOW_YIELD_CNT
	clocked10ms.begin(clock_isr, 10000);
#endif
	while ( 1 ) {
		loopX(); // Avoid end of loop() yield so the clock_isr() isn't noisy when used.
#ifndef SHOW_YIELD_CNT
		yield(); // simulate normal exec
#endif
	}
}

void makeRootDirs() {
	char szDir[16];
	for ( uint32_t ii = 1; ii <= NUMDIRS; ii++ ) {
		sprintf( szDir, "/%lu_dir", ii );
		myfs.mkdir( szDir );
	}
}

int loopLimit = 0; // -1 continuous, otherwise # to count down to 0
bool pauseDir = false;  // Start Pause on each off
bool showDir =  false;  // false Start Dir on each off
bool bDirVerify =  false;  // false Start Dir on each off
bool bWriteVerify = true;  // Verify on Write Toggle
bool bAutoFormat =  false;  // false Auto formatUnused() off
bool bCheckFormat =  false;  // false CheckFormat
bool bCheckUsed =  false;  // false CheckUsed
uint32_t res = 0; // for formatUnused
void loop() { }
void loopX() {
	char szDir[16];
	LoopCnt++;
	uint32_t chStep;
	if ( loopLimit != 0 ) {
#ifdef ROOTONLY // ii=1-NUMDIRS are subdirs. #0 is Root
		for ( uint32_t ii = 0; ii < 1 && ( loopLimit != 0 ); ii++ )
#else
		for ( uint32_t ii = 0; ii < NUMDIRS && ( loopLimit != 0 ); ii++ )
#endif
		{
			if ( ii == 0 )
				sprintf( szDir, "/" );
			else
				sprintf( szDir, "/%lu_dir", ii );
			chStep = fileCycle(szDir);
			if ( bAutoFormat && !(lCnt % 5) ) res = loopAutoFormat( 20, res );
//			if ( bAutoFormat && !(lCnt % 20) ) res = loopAutoFormat( 6, res );
			while ( chStep != fileCycle(szDir) && ( loopLimit != 0 ) ) {
				if ( bAutoFormat && !(lCnt % 5) ) res = loopAutoFormat( 12, res ); // how often and how many depends on media and sizes
				//if ( bAutoFormat && !(lCnt % 20) ) res = loopAutoFormat( 6, res );
				checkInput( 0 ); // user input can 0 loopLimit
			}
		}
		checkInput( 0 );
		if ( loopLimit > 0 ) // -1 means continuous
			loopLimit--;
	}
	else
		checkInput( 1 );
}
uint32_t loopAutoFormat( uint32_t cnt, uint32_t myres ) {
	uint32_t retres;
	retres = myfs.formatUnused( cnt, myres );
	Serial.printf("\t fmtU @ %lu - %lu \n", myres, retres );
	return retres;

}

char szInputs[] = "0123456789RdwcghkFqvplmusSBbyYxfan+-?";
uint32_t lastTime;
void checkInput( int step ) { // prompt for input without user input with step != 0
	uint32_t nowTime = micros();

	char retVal = 0, temp;
	char *pTemp;
	if ( step != 0 ) {
		nowTime -= lastTime;
		Serial.printf( "[%6.2f M](%6.5f M elap) Awaiting input %s loops left %d >", millis() / 60000.0, nowTime / 60000000.0, szInputs, loopLimit );
	}
	else {
		if ( !Serial.available() ) return;
		nowTime -= lastTime;
		Serial.printf( "[%6.2f M](%6.2f elap) Awaiting input %s loops left %d >", millis() / 60000.0, nowTime / 60000000.0, szInputs, loopLimit );
		//Serial.printf( "[%6.2f] Awaiting input %s loops left %d >", millis() / 60000.0, szInputs, loopLimit );
		while ( Serial.available() ) {
			temp = Serial.read( );
			if ( (pTemp = strchr(szInputs, temp)) ) {
				retVal = pTemp[0];
				parseCmd( retVal );
			}
		}
	}
	while ( !Serial.available() );
	while ( Serial.available() ) {
		temp = Serial.read();
		if ( (pTemp = strchr(szInputs, temp)) ) {
			retVal = pTemp[0];
			parseCmd( retVal );
		}
	}
	Serial.print( '\n' );
	if ( '?' == retVal ) checkInput( 1 ); // recurse on '?' to allow command show and response
	return;
}
void parseCmd( char chIn ) { // pass chIn == '?' for help
	uint32_t timeMe;
		char szNone[]="";
	switch (chIn ) {
	case '?':
		Serial.printf( "%s\n", " 0, 1-9 '#' passes continue loop before Pause\n\
 'a' Auto formatUnused() during iterations - TOGGLE\n\
 'R' Restart Teensy\n\
 'd' Directory of LittleFS\n\
 'w' WIPE Directory of LittleFS\n\
 'b' big file delete\n\
 'B' BIG FILE MAKE\n\
 'S' FILE 2MB MAKE\n\
 's' FILE 2MB delete\n\
 'c' Continuous Loop\n\
 'g' run speedBench()\n\
 'h' Hundred loops\n\
 'k' Thousand loops\n\
 'F' LittleFS_ Low Level Format Disk \n\
 'f' LittleFS::formatUnused( ALL ) : DATA PRESERVED \n\
 'q' LittleFS_ Quick Format Disk \n\
 'v' Verbose All Dir Prints - TOGGLE\n\
 'p' Pause after all Dir prints - TOGGLE\n\
 'l' Show count of loop()'s, Bytes Read,Written\n\
 'm' Make ROOT dirs (needed after q/F format !ROOTONLY)\n\
 'u' Update Filecount\n\
 'x' Directory filecount verify - TOGGLE\n\
 'n' No verify on Write- TOGGLE\n\
 '+' more add to delete cycles\n\
 '-' fewer add to delete cycles\n\
 'y' reclaim 1 block :: myfs.formatUnused( 1 )\n\
 'Y' reclaim 15 blocks :: myfs.formatUnused( 15 )\n\
 '?' Help list" );
		break;
	case 'R':
		Serial.print(" RESTART Teensy ...");
		delay(100);
		SCB_AIRCR = 0x05FA0004;
		break;
	case '0':
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
		loopLimit = chIn - '0';
		if ( chIn != '0' )	// Preserve elapsed time on Error or STOP command
			lastTime = micros();
		break;
	case 'b':
		bigFile( 0 ); // delete
		chIn = 0;
		break;
	case 'B':
		lastTime = micros();
		bigFile( 1 ); // CREATE
		chIn = 0;
		break;
	case 's':
		bigFile2MB( 0 ); // CREATE
		chIn = 0;
		break;
	case 'S':
		lastTime = micros();
		bigFile2MB( 1 ); // CREATE
		chIn = 0;
		break;
	case 'c':
		loopLimit = -1;
		break;
	case 'g':
		lastTime = micros();
		speedBench();
		chIn = 0;
		break;
	case 'd':
		Serial.print( " d\n" );
		lastTime = micros();
		printDirectory();
		Serial.print( '\n' );
		parseCmd( 'l' );
		checkInput( 1 );
		chIn = 0;
		break;
	case 'w':
		Serial.println("\nWipe All Files and DIRS:");
		deleteAllDirectory(myfs.open("/"), szNone );
		errsLFS = 0; // No Errors on new Format
		warnLFS = 0; // No warning on new Format
		chIn = 0;
		parseCmd( 'u' );
		break;
	case 'h':
		loopLimit = 100;
		lastTime = micros();
		break;
	case 'k':
		loopLimit = 1000;
		lastTime = micros();
		break;
	case 'F': // Low Level format
		Serial.print( "\nFormatting Low Level:\n\t" );
		lastTime = micros();
		timeMe = micros();
		myfs.lowLevelFormat('.');
		timeMe = micros() - timeMe;
		Serial.printf( "\n Done Formatting Low Level in %lu us.\n", timeMe );
		errsLFS = 0; // No Errors on new Format
		warnLFS = 0; // No warning on new Format
		bCheckFormat  = false;
		parseCmd( 'u' );
		break;
	case 'q': // quick format
		lastTime = micros();
		myfs.quickFormat();
		errsLFS = 0; // No Errors on new Format
		parseCmd( 'u' );
		break;
	case 'v': // verbose dir
		showDir = !showDir;
		showDir ? Serial.print(" Verbose on: ") : Serial.print(" Verbose off: ");
		chIn = 0;
		break;
	case 'p': // pause on dirs
		pauseDir = !pauseDir;
		pauseDir ? Serial.print(" Pause on: ") : Serial.print(" Pause off: ");
		chIn = 0;
		break;
	case 'x': // dir filecount Verify
		bDirVerify = !bDirVerify;
		bDirVerify ? Serial.print(" FileCnt on: ") : Serial.print(" FileCnt off: ");
		lastTime = micros();
		dirVerify();
		chIn = 0;
		break;
	case 'n': // No Verify on write
		bWriteVerify = !bWriteVerify;
		bWriteVerify ? Serial.print(" Write Verify on: ") : Serial.print(" Write Verify off: ");
		chIn = 0;
		break;
	case 'a': // Auto myfs.formatUnused() during iterations
		bAutoFormat = !bAutoFormat;
		bAutoFormat ? Serial.print(" \nAuto formatUnused() On: ") : Serial.print(" \nAuto formatUnused() Off: ");
		chIn = 0;
		break;
	case 'y': // Reclaim 1 unused format
		lastTime = micros();
		Serial.printf( "\n myfs.formatUnused( 1 ) ...\n" );
		timeMe = micros();
		res = myfs.formatUnused( 1, res );
		timeMe = micros() - timeMe;
		Serial.printf( "\n\t formatUnused :: Done Formatting Low Level in %lu us (last %lu).\n", timeMe, res );
		chIn = 0;
		break;
	case 'Y': // Reclaim 15 unused format
		lastTime = micros();
		Serial.printf( "\n myfs.formatUnused( 15 ) ...\n" );
		timeMe = micros();
		res = myfs.formatUnused( 15, res );
		timeMe = micros() - timeMe;
		Serial.printf( "\n\t formatUnused :: Done Formatting Low Level in %lu us (last %lu).\n", timeMe, res );
		chIn = 0;
		break;
	case 'f': // Reclaim all unused format
		lastTime = micros();
		Serial.printf( "\n myfs.formatUnused( 0 ) ...\n" );
		timeMe = micros();
		myfs.formatUnused( 0, 0 );
		timeMe = micros() - timeMe;
		Serial.printf( "\n\t formatUnused :: Done Formatting Low Level in %lu us.\n", timeMe );
		chIn = 0;
		break;
	case 'l': // Show Loop Count
		Serial.printf("\n\t Loop Count: %u (#fileCycle=%u), Bytes read %llu, written %llu, #Files=%u\n", LoopCnt, lCnt, rdCnt, wrCnt, filecount );
		if ( 0 != errsLFS )
			Serial.printf("\t ERROR COUNT =%u\n", errsLFS );
		if ( 0 != warnLFS )
			Serial.printf("\t Free Space Warn COUNT =%u\n", warnLFS );
		dirVerify();
		chIn = 0;
		break;
	case 'm':
		Serial.printf("m \n\t Making Root Dirs\n" );
		makeRootDirs();
		parseCmd( 'd' );
		chIn = 0;
		break;
	case 'u': // Show Loop Count
		filecount = printDirectoryFilecount( myfs.open("/") );
		Serial.printf("u \n\t Updated filecount %u\n", filecount );
		chIn = 0;
		break;
	case '+': // increase add cycles
		DELSTART++;
		Serial.printf("+\n Deletes start after %u cycles ", DELSTART);
		chIn = 0;
		break;
	case '-': // decrease add cycles
		DELSTART--;
		if ( DELSTART < 1 ) DELSTART = 1;
		Serial.printf("-\n Deletes start after %u cycles ", DELSTART);
		chIn = 0;
		break;
	default:
		Serial.println( chIn ); // never see without unhandled char in szInputs[]
		break;
	}
	if ( 0 != chIn ) Serial.print( chIn );
}

uint32_t fTot, totSize;
void printDirectory() {
	fTot = 0, totSize = 0;
	Serial.printf("printDirectory %s\n--------------\n", szDiskMem);
	printDirectory(myfs.open("/"), 0);
	Serial.printf(" %Total %u files of Size %u Bytes\n", fTot, totSize);
	Serial.printf("Bytes Used: %llu, Bytes Total:%llu\n", myfs.usedSize(), myfs.totalSize());
}

void deleteAllDirectory(File dir, char *fullPath ) {
	char myPath[ 256 ] = "";
	while (true) {
		File entry =  dir.openNextFile();
		if (! entry) {
			// no more files
			break;
		}
		if (entry.isDirectory()) {
			strcpy( myPath, fullPath);
			strcat( myPath, entry.name());
			strcat( myPath, "/");
			deleteAllDirectory(entry, myPath);
			entry.close();
			if ( !myfs.remove( myPath ) )
				Serial.print( "  Fail remove DIR>\t");
			else
				Serial.print( "  Removed DIR>\t");
			Serial.println( myPath );

		} else {
			strcpy( myPath, fullPath);
			strcat( myPath, entry.name());
			entry.close();
			if ( !myfs.remove( myPath ) )
				Serial.print( "\tFail remove>\t");
			else
				Serial.print( "\tRemoved>\t");
			Serial.println( myPath );
		}
	}
}

int printDirectoryFilecount(File dir) {
	unsigned int filecnt = 0;
	while (true) {
		File entry =  dir.openNextFile();
		if (! entry) {
			// no more files
			break;
		}
		if (entry.isDirectory()) {
			filecnt += printDirectoryFilecount(entry);
		} else {
			filecnt++;
		}
		entry.close();
	}
	return filecnt;
}

void printDirectory(File dir, int numTabs) {
	//dir.whoami();
	uint32_t fSize = 0, dCnt = 0, fCnt = 0;
	if ( 0 == dir ) {
		Serial.printf( "\t>>>\t>>>>> No Dir\n" );
		return;
	}
	while (true) {
		File entry =  dir.openNextFile();
		if (! entry) {
			// no more files
			Serial.printf("\n %u dirs with %u files of Size %u Bytes\n", dCnt, fCnt, fSize);
			fTot += fCnt;
			totSize += fSize;
			break;
		}
		for (uint8_t i = 0; i < numTabs; i++) {
			Serial.print('\t');
		}

		if (entry.isDirectory()) {
			Serial.print("DIR\t");
			dCnt++;
		} else {
			Serial.print("FILE\t");
			fCnt++;
			fSize += entry.size();
		}
		Serial.print(entry.name());
		if (entry.isDirectory()) {
			Serial.println(" / ");
			printDirectory(entry, numTabs + 1);
		} else {
			// files have sizes, directories do not
			Serial.print("\t\t");
			Serial.println(entry.size(), DEC);
		}
		entry.close();
		//Serial.flush();
	}
}

uint32_t cCnt = 0;
uint32_t fileCycle(const char *dir) {
	static char szFile[] = "_file.txt";
	char szPath[150];
	int ii;
	lCnt++;
	byte nNum = lCnt % MAXNUM;
	char chNow = 'A' + lCnt % MAXNUM;
	lfs_ssize_t resW = 1;
	uint32_t timeMeAll = micros();

	if ( dir[1] == 0 )	// catch root
		sprintf( szPath, "/%c%s", chNow, szFile );
	else
		sprintf( szPath, "%s/%c%s", dir, chNow, szFile );
	if ( cCnt >= DELSTART && myfs.exists(szPath) ) { // DELETE ALL KNOWN FILES
		if ( nNum == 1 ) {
			Serial.print( "\n == == ==   DELETE PASS START  == == == = \n");
			if ( showDir ) {
				printDirectory();
				Serial.print( " == == ==   DELETE PASS START  == == == = \n");
			}
			delayMicroseconds(DELDELAY);
		}
	}
	Serial.printf( ":: %s ", szPath );
	if ( cCnt >= DELSTART && myfs.exists(szPath) ) { // DELETE ALL KNOWN FILES
		readVerify( szPath, chNow );
		myfs.remove(szPath);
		filecount--;
		Serial.printf(" %s ----DEL----", szDiskMem);
		Serial.printf(" -- %c", chNow);
		if ( showDir ) {
			Serial.print("\n");
			printDirectory(myfs.open(dir), 1);
		}
		if ( pauseDir ) checkInput( 1 );
		Serial.println();
	}
	else {
		if ( bWriteVerify && myfs.totalSize() - myfs.usedSize() < MAXFILL ) {
			warnLFS++;
			Serial.printf( "\tXXX\tXXX\tXXX\tXXX\tSIZE WARNING { MAXFILL } \n" );
			cCnt = DELSTART;
			return cCnt;	// EARLY EXIT
		}
		if ( nNum == 0 ) {
			nNum = 10;
			cCnt++;
			if ( cCnt >= DELSTART + 2 ) cCnt = 0;
		}
		file3 = myfs.open(szPath, FILE_WRITE);
		if ( 0 == file3 ) {
			Serial.printf( "\tXXX\tXXX\tXXX\tXXX\tFail File open {mkdir?}\n" );
			delayMicroseconds(300000);
			checkInput( 1 );	// PAUSE on CmdLine
		}
		else {
			delayMicroseconds(ADDDELAY);
			char mm = chNow + lowOffset;
			uint32_t jj = file3.size() + 1;
			uint32_t timeMe = micros();
			for ( ii = 0; ii < (nNum * SUBADD + BIGADD ) && resW > 0; ii++ ) {
				if ( 0 == ((ii + jj) / lowShift) % 2 )
					resW = file3.write( &mm , 1 );
				else
					resW = file3.write( &chNow , 1 );
				wrCnt++;
				// if ( lCnt%100 == 50 ) mm='x'; // GENERATE ERROR to detect on DELETE read verify
			}
			file3.close();
			timeMe = micros() - timeMe;
			timeMeAll = micros() - timeMeAll;
			Serial.printf(" %s +++ Add [sz %u add %u] @KB/sec %5.2f {%5.2f} ", szDiskMem, jj - 1, ii, ii / (timeMe / 1000.0), ii / (timeMeAll / 1000.0) );
			if (resW < 0) {
				Serial.printf( "\n\twrite fail ERR# %i 0x%X \n", resW, resW );
				parseCmd( '0' );
				errsLFS++;
				checkInput( 1 );	// PAUSE on CmdLine
			}
			else if ( jj == 1 ) filecount++; // File Added
			Serial.printf(" ++ %c ", chNow);
			if ( bWriteVerify )
				readVerify( szPath, chNow );
			else
				Serial.print('\n');
			if ( showDir ) {
				Serial.print('\n');
				printDirectory(myfs.open(dir), 1);
			}
		}
		if ( pauseDir ) checkInput( 1 );
		//Serial.print("\n");
		delayMicroseconds(ADDDELAY);
	}
	checkInput( 0 ); // user stop request?
	if ( bDirVerify ) dirVerify();
	return cCnt;
}

void dirVerify() {
	uint32_t timeMe = micros();
	Serial.printf("\tdirV...");
	if ( filecount != printDirectoryFilecount( myfs.open("/") ) ) {
		Serial.printf( "\tFilecount mismatch %u != %u\n", filecount, printDirectoryFilecount( myfs.open("/") ) );
		parseCmd( '0' );
		errsLFS++;
		checkInput( 1 );	// PAUSE on CmdLine
	}
	timeMe = micros() - timeMe;
	Serial.printf("%lu_us\t", timeMe);
}

void readVerify( char szPath[], char chNow ) {
	uint32_t timeMe = micros();
	file3 = myfs.open(szPath);
	if ( 0 == file3 ) {
		Serial.printf( "\tV\t Fail File open %s\n", szPath );
		parseCmd( '0' );
		errsLFS++;
		checkInput( 1 );
	}
	char mm;
	char chNow2 = chNow + lowOffset;
	uint32_t ii = 0;
	while ( file3.available() ) {
		file3.read( &mm , 1 );
		rdCnt++;
		//Serial.print( mm ); // show chars as read
		ii++;
		if ( 0 == (ii / lowShift) % 2 ) {
			if ( chNow2 != mm ) {
				Serial.printf( "<Bad Byte!  %c! = %c [0x%X] @%u\n", chNow2, mm, mm, ii );
				parseCmd( '0' );
				errsLFS++;
				checkInput( 1 );
				break;
			}
		}
		else {
			if ( chNow != mm ) {
				Serial.printf( "<Bad Byte!  %c! = %c [0x%X] @%u\n", chNow, mm, mm, ii );
				parseCmd( '0' );
				errsLFS++;
				checkInput( 1 );
				break;
			}
		}
	}
	Serial.printf( "  Verify %s %uB ", szPath, ii );
	if (ii != file3.size()) {
		Serial.printf( "\n\tRead Count fail! :: read %u != f.size %llu", ii, file3.size() );
		parseCmd( '0' );
		errsLFS++;
		checkInput( 1 );	// PAUSE on CmdLine
	}
	file3.close();
	timeMe = micros() - timeMe;
	Serial.printf( " @KB/sec %5.2f \n", ii / (timeMe / 1000.0) );
}

bool bigVerify( char szPath[], char chNow ) {
	uint32_t timeMe = micros();
	file3 = myfs.open(szPath);
	if ( 0 == file3 ) {
		return false;
	}
	char mm;
	uint32_t ii = 0;
	uint32_t kk = file3.size() / 50;
	Serial.printf( "\tVerify %s bytes %llu : ", szPath, file3.size() );
	while ( file3.available() ) {
		file3.read( &mm , 1 );
		rdCnt++;
		ii++;
		if ( !(ii % kk) ) Serial.print('.');
		if ( chNow != mm ) {
			Serial.printf( "<Bad Byte!  %c! = %c [0x%X] @%u\n", chNow, mm, mm, ii );
			parseCmd( '0' );
			errsLFS++;
			checkInput( 1 );
			break;
		}
	}
	if (ii != file3.size()) {
		Serial.printf( "\n\tRead Count fail! :: read %u != f.size %llu\n", ii, file3.size() );
		parseCmd( '0' );
		errsLFS++;
		checkInput( 1 );	// PAUSE on CmdLine
	}
	else
		Serial.printf( "\tGOOD! >>  bytes %lu", ii );
	file3.close();
	timeMe = micros() - timeMe;
	Serial.printf( "\n\tBig read&compare KBytes per second %5.2f \n", ii / (timeMe / 1000.0) );
	if ( 0 == ii ) return false;
	return true;
}


void bigFile( int doThis ) {
	char myFile[] = "/0_bigfile.txt";
	char fileID = '0' - 1;

	if ( 0 == doThis ) {	// delete File
		Serial.printf( "\nDelete with read verify all #bigfile's\n");
		do {
			fileID++;
			myFile[1] = fileID;
			if ( myfs.exists(myFile) && bigVerify( myFile, fileID) ) {
				filecount--;
				myfs.remove(myFile);
			}
			else break; // no more of these
		} while ( 1 );
	}
	else {	// FILL DISK
		lfs_ssize_t resW = 1;
		char someData[2048];
		uint32_t xx, toWrite;
		toWrite = (myfs.totalSize()) - myfs.usedSize();
		if ( toWrite < 65535 ) {
			Serial.print( "Disk too full! DO :: b or q or F");
			return;
		}
		toWrite -= 40960; // allow for slack space :: WORKS on FLASH?
#ifdef HALFCUT
		toWrite /= 2; // cutting to this works on LittleFS_RAM myfs - except reported file3.size()=2054847098 OR now 0
#endif
		xx = toWrite;
		Serial.printf( "\nStart Big write of %u Bytes", xx);
		uint32_t timeMe = micros();
		file3 = nullptr;
		do {
			if ( file3 ) file3.close();
			fileID++;
			myFile[1] = fileID;
			file3 = myfs.open(myFile, FILE_WRITE);
		} while ( fileID < '9' && file3.size() > 0);
		if ( fileID == '9' ) {
			Serial.print( "Disk has 9 halves 0-8! DO :: b or q or F");
			return;
		}
		memset( someData, fileID, 2048 );
		int hh = 0;
		while ( toWrite > 2048 && resW > 0 ) {
			resW = file3.write( someData , 2048 );
			hh++;
			if ( !(hh % 40) ) Serial.print('.');
			toWrite -= 2048;
		}
		xx -= toWrite;
		file3.close();
		timeMe = micros() - timeMe;
		file3 = myfs.open(myFile, FILE_WRITE);
		if ( file3.size() > 0 ) {
			filecount++;
			Serial.printf( "\nBig write %s took %5.2f Sec for %lu Bytes : file3.size()=%llu", myFile , timeMe / 1000000.0, xx, file3.size() );
		}
		if ( file3 != 0 ) file3.close();
		Serial.printf( "\n\tBig write KBytes per second %5.2f \n", xx / (timeMe / 1000.0) );
		Serial.printf("\nBytes Used: %llu, Bytes Total:%llu\n", myfs.usedSize(), myfs.totalSize());
		if ( resW < 0 ) {
			Serial.printf( "\nBig write ERR# %i 0x%X \n", resW, resW );
			errsLFS++;
			myfs.remove(myFile);
		}
	}
}

void bigFile2MB( int doThis ) {
	char myFile[] = "/0_2MBfile.txt";
	char fileID = '0' - 1;

	if ( 0 == doThis ) {	// delete File
		Serial.printf( "\nDelete with read verify all #bigfile's\n");
		do {
			fileID++;
			myFile[1] = fileID;
			if ( myfs.exists(myFile) && bigVerify( myFile, fileID) ) {
				filecount--;
				myfs.remove(myFile);
			}
			else break; // no more of these
		} while ( 1 );
	}
	else {	// FILL DISK
		lfs_ssize_t resW = 1;
		char someData[2048];
		uint32_t xx, toWrite;
		toWrite = 2048 * 1000;
		if ( toWrite > (65535 + (myfs.totalSize() - myfs.usedSize()) ) ) {
			Serial.print( "Disk too full! DO :: q or F");
			return;
		}
		xx = toWrite;
		Serial.printf( "\nStart Big write of %u Bytes", xx);
		uint32_t timeMe = micros();
		file3 = nullptr;
		do {
			if ( file3 ) file3.close();
			fileID++;
			myFile[1] = fileID;
			file3 = myfs.open(myFile, FILE_WRITE);
		} while ( fileID < '9' && file3.size() > 0);
		if ( fileID == '9' ) {
			Serial.print( "Disk has 9 files 0-8! DO :: b or q or F");
			return;
		}
		memset( someData, fileID, 2048 );
		int hh = 0;
		while ( toWrite >= 2048 && resW > 0 ) {
			resW = file3.write( someData , 2048 );
			hh++;
			if ( !(hh % 40) ) Serial.print('.');
			toWrite -= 2048;
		}
		xx -= toWrite;
		file3.close();
		timeMe = micros() - timeMe;
		file3 = myfs.open(myFile, FILE_WRITE);
		if ( file3.size() > 0 ) {
			filecount++;
			Serial.printf( "\nBig write %s took %5.2f Sec for %lu Bytes : file3.size()=%llu", myFile , timeMe / 1000000.0, xx, file3.size() );
		}
		if ( file3 != 0 ) file3.close();
		Serial.printf( "\n\tBig write KBytes per second %5.2f \n", xx / (timeMe / 1000.0) );
		Serial.printf("\nBytes Used: %llu, Bytes Total:%llu\n", myfs.usedSize(), myfs.totalSize());
		if ( resW < 0 ) {
			Serial.printf( "\nBig write ERR# %i 0x%X \n", resW, resW );
			errsLFS++;
			myfs.remove(myFile);
		}
	}
}

#include <sdios.h>
ArduinoOutStream cout(Serial);
File file;

// File size in bytes.
const uint32_t FILE_SIZE = 16 * 1024;

// Set SKIP_FIRST_LATENCY true if the first read/write to the SD can
// be avoid by writing a file header or reading the first record.
const bool SKIP_FIRST_LATENCY = true;

// Size of read/write.
const size_t BUF_SIZE = 2048;

// Write pass count.
const uint8_t WRITE_COUNT = 5;

// Read pass count.
const uint8_t READ_COUNT = 5;

//Block size for qspi
#define MYBLKSIZE 2048 // 2048

// Insure 4-byte alignment.
uint32_t buf32[(BUF_SIZE + 3) / 4];
uint8_t* bufA32 = (uint8_t*)buf32;

//Number of random reads
#define randomReads 1

void speedBench() {
	File file;
	float s;
	uint32_t t;
	uint32_t maxLatency;
	uint32_t minLatency;
	uint32_t totalLatency;
	bool skipLatency;

	myfs.remove("bench.dat");
	//for(uint8_t cnt=0; cnt < 10; cnt++) {

	// fill buf with known data
	if (BUF_SIZE > 1) {
		for (size_t i = 0; i < (BUF_SIZE - 2); i++) {
			bufA32[i] = 'A' + (i % 26);
		}
		bufA32[BUF_SIZE - 2] = '\r';
	}
	bufA32[BUF_SIZE - 1] = '\n';

	Serial.printf("%s Disk Stats:", szDiskMem );
	Serial.printf("Bytes Used: %llu, Bytes Total:%llu\n", myfs.usedSize(), myfs.totalSize());
	Serial.printf("%s Benchmark:\n", szDiskMem );
	cout << F("FILE_SIZE = ") << FILE_SIZE << endl;
	cout << F("BUF_SIZE = ") << BUF_SIZE << F(" bytes\n");
	cout << F("Starting write test, please wait.") << endl << endl;

	// do write test
	uint32_t n = FILE_SIZE / BUF_SIZE;
	cout << F("write speed and latency") << endl;
	cout << F("speed,max,min,avg") << endl;
	cout << F("KB/Sec,usec,usec,usec") << endl;

	// open or create file - truncate existing file.
	file = myfs.open("bench.dat", FILE_WRITE);

	for (uint8_t nTest = 0; nTest < WRITE_COUNT; nTest++) {
		file.seek(0);

		maxLatency = 0;
		minLatency = 9999999;
		totalLatency = 0;
		skipLatency = SKIP_FIRST_LATENCY;
		t = millis();

		for (uint32_t i = 0; i < n; i++) {
			uint32_t m = micros();
			if (file.write(bufA32, BUF_SIZE) != BUF_SIZE) {
				Serial.println("write failed");
			}
			m = micros() - m;
			totalLatency += m;
			if (skipLatency) {
				// Wait until first write to SD, not just a copy to the cache.
				skipLatency = file.position() < 512;
			} else {
				if (maxLatency < m) {
					maxLatency = m;
				}
				if (minLatency > m) {
					minLatency = m;
				}
			}
		}

		t = millis() - t;
		s = file.size();
		cout << s / t << ',' << maxLatency << ',' << minLatency;
		cout << ',' << totalLatency / n << endl;
	}
	cout << endl << F("Starting sequential read test, please wait.") << endl;
	cout << endl << F("read speed and latency") << endl;
	cout << F("speed,max,min,avg") << endl;
	cout << F("KB/Sec,usec,usec,usec") << endl;

	// do read test
	for (uint8_t nTest = 0; nTest < READ_COUNT; nTest++) {
		file.seek(0);
		maxLatency = 0;
		minLatency = 9999999;
		totalLatency = 0;
		skipLatency = SKIP_FIRST_LATENCY;
		t = micros();
		for (uint32_t i = 0; i < n; i++) {
			bufA32[BUF_SIZE - 1] = 0;
			uint32_t m = micros();
			int32_t nr = file.read(bufA32, BUF_SIZE);
			if (nr != BUF_SIZE) {
				Serial.println("read failed");
			}
			m = micros() - m;
			totalLatency += m;
			if (bufA32[BUF_SIZE - 1] != '\n') {
				Serial.println("data check error");
			}
			if (skipLatency) {
				skipLatency = false;
			} else {
				if (maxLatency < m) {
					maxLatency = m;
				}
				if (minLatency > m) {
					minLatency = m;
				}
			}
		}

		s = file.size();

		t = micros() - t;
		cout << s * 1000 / t << ',' << maxLatency << ',' << minLatency;
		cout << ',' << totalLatency / n << endl;
	}

	cout << endl << F("Done") << endl;

	cout << endl << F("Starting random read test, please wait.") << endl;

	Serial.printf("Number of random reads: %d\n", randomReads);
	Serial.printf("Number of blocks: %d\n", n);

	cout << endl << F("read speed and latency") << endl;
	cout << F("speed,max,min,avg") << endl;

	// do read test
	for (uint8_t nTest = 0; nTest < READ_COUNT; nTest++) {
		file.seek(0);
		maxLatency = 0;
		minLatency = 0;
		totalLatency = 0;
		skipLatency = SKIP_FIRST_LATENCY;
		t = micros();
		for (uint32_t i = 0; i < randomReads; i++) {
			bufA32[BUF_SIZE - 1] = 0;
			uint32_t m = micros();
			uint32_t block_pos = random(0, (n - 1));
			uint32_t random_pos = block_pos * MYBLKSIZE;
			cout << "Position (bytes), Block: " << random_pos << ", ";
			cout << block_pos << endl;
			uint32_t startCNT = ARM_DWT_CYCCNT;
			file.seek(random_pos);
			int32_t nr = file.read(bufA32, BUF_SIZE);
			uint32_t endCNT = ARM_DWT_CYCCNT;
			cout << F("Read Time (ARM Cycle Delta): ") << endCNT - startCNT << endl;
			if (nr != BUF_SIZE) {
				Serial.println("read failed");
			}
			m = micros() - m;
			totalLatency += m;
			if (bufA32[BUF_SIZE - 1] != '\n') {
				Serial.println("data check error");
			}
			if (skipLatency) {
				skipLatency = false;
			} else {
				if (maxLatency < m) {
					maxLatency = m;
				}
				if (minLatency > m) {
					minLatency = m;
				}
			}
		}

		s = file.size();


		t = micros() - t;
		cout << F("KB/Sec,usec,usec,usec") << endl;
		cout << s * 1000 / t << ',' << maxLatency << ',' << minLatency;
		cout << ',' << totalLatency / n << endl;
	}
	cout << endl << F("Done") << endl;


	file.close();
	myfs.remove("bench.dat");

}
 
@TeensyDigital - TD 1.54 Beta 10 was released with a change in startup that Paul saw cause troubles.

Though something new and bad affecting the LittleFS sketch in use with Beta 10.

@Paul /@all - I cannot now get the LFSIntegrity to write a complete file and not hang. I reverted the _RAM code in listtleFS.h for static RAM - always Zeros and no _sync doing dcache_flush - and still it is failing the write without hang on PSRAM?

Using a T_4.1 with twin PSRAMS but only using 8MB - was seeing the same with DMAMEM RAM2 on T_4.1 and on T_4.0:

Odd it was doing better on first post in Beta 10 thread ...now a total fail. Before and after removing the just added RAM code.

DOING: 'B' - starts BIG write and does not complete
or
DOING '1' - a single loop write to one small file and it hangs.

Something is corrupting the FS on RAM? With the STATIC RAM reversion and always ZERO on start it will restart okay, if not reverted it hangs on starting as the image is broken.

past times for Zzzz's ...

Current edits to LFSIntegrity as installed are the top: ROOTONLY, _RAM select and sizing, and (optional for smaller DMAMEM) fewer subdirs of 16 are only changes to test:

Code:
//#include <LittleFS.h>
#include <LittleFS_NAND.h>

#define HALFCUT  // HALFCUT defined to fill half the disk
[B]#define ROOTONLY // NORMAL is NOT DEFINED![/B]
#define NUMDIRS 32  // When not ROOTONLY must be 1 or more
#define MYPSRAM 8	// compile time PSRAM size
#define MYBLKSIZE 2048 // 2048
//#define SHOW_YIELD_CNT  1 // uncommented shows calls to Yield per second

[B]#define TEST_RAM[/B]
//#define TEST_SPI
//#define TEST_QSPI
//#define TEST_SPI_NAND
//#define TEST_QSPI_NAND
//#define TEST_PROG
//#define TEST_MRAM

IntervalTimer clocked10ms;
uint32_t yCalls = 0;
uint32_t yCallsMax = 0;
uint32_t yCallsLast = 0;
uint32_t yCallsIdx = 0;
uint32_t yCallsSum = 0;
#ifdef SHOW_YIELD_CNT
void yield() {
	yCalls++;
}
#endif
void clock_isr() {
	yCallsIdx++;
	if ( yCallsIdx >= 100 ) {
		if (yCallsSum > 0 )
			Serial.printf( "\n yps=%lu [mx=%lu]\t", yCallsSum, yCallsMax * 100);
		yCallsIdx = 0;
		yCallsSum = 0;
		yCallsMax = 0;
	}
	yCallsSum += yCalls - yCallsLast;
	if ( yCalls - yCallsLast > yCallsMax ) yCallsMax = yCalls - yCallsLast;
	yCallsLast = yCalls;
}

// Set for SPI usage
//const int FlashChipSelect = 10; // AUDIO BOARD
const int FlashChipSelect = 4; // PJRC Mem board 64MB on #5, #6 : NAND 1Gb on #3, 2GB on #4
//const int FlashChipSelect = 5; // PJRC Mem board 64MB on #5, #6 : NAND 1Gb on #3, 2GB on #4
//const int FlashChipSelect = 6; // digital pin for flash chip CS pin


#ifdef TEST_RAM
LittleFS_RAM myfs;
// RUNTIME :: extern "C" uint8_t external_psram_size;
[B]EXTMEM char buf[MYPSRAM * 1024 * 1024];	// USE DMAMEM for more memory than ITCM allows - or remove[/B]
//DMAMEM char buf[490000];	// USE DMAMEM for more memory than ITCM allows - or remove
//char buf[390000];	// USE DMAMEM for more memory than ITCM allows - or remove
char szDiskMem[] = "RAM_DISK";
#elif defined(TEST_SPI)
//const int FlashChipSelect = 10; // Arduino 101 built-in SPI Flash
#define FORMATSPI
//#define FORMATSPI2
LittleFS_SPIFlash myfs;
char szDiskMem[] = "SPI_DISK";
#elif defined(TEST_MRAM)
//const int FlashChipSelect = 10; // Arduino 101 built-in SPI Flash
LittleFS_SPIFram myfs;
char szDiskMem[] = "FRAM_DISK";
#elif defined(TEST_PROG)
LittleFS_Program myfs;
char szDiskMem[] = "PRO_DISK";
#elif defined(TEST_QSPI_NAND)
char szDiskMem[] = "QSPI_NAND";
LittleFS_QPINAND myfs;
#elif defined(TEST_SPI_NAND)
char szDiskMem[] = "SPI_NAND";
LittleFS_SPINAND myfs;
#else // TEST_QSPI
LittleFS_QSPIFlash myfs;
char szDiskMem[] = "QSPI_DISK";

#endif

File file3;

uint32_t DELSTART = 3; // originally was 3 + higher bias more to writes and larger files - lower odd
#define SUBADD 512	// bytes added each pass (*times file number)
#define BIGADD 1024	// bytes added each pass - bigger will quickly consume more space
[B]#define MAXNUM 16	// ALPHA A-Z is 26, less for fewer files[/B]
#define MAXFILL 2048 // 66000	// ZERO to disable :: Prevent iterations from over filling - require this much free
#define DELDELAY 0 	// delay before DEL files : delayMicroseconds
#define ADDDELAY 0 	// delay on ADD FILE : delayMicroseconds

const uint32_t lowOffset = 'a' - 'A';
const uint32_t lowShift = 13;
uint32_t errsLFS = 0;
uint32_t warnLFS = 0;
uint32_t lCnt = 0;
uint32_t LoopCnt = 0;
uint64_t rdCnt = 0;
uint64_t wrCnt = 0;
int filecount = 0;

void setup() {
	while (!Serial) ; // wait
	Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
	Serial.println("LittleFS Test : File Integrity"); delay(5);

#ifdef TEST_RAM
	if (!myfs.begin(buf, sizeof(buf))) {
#elif defined(TEST_RAM2)
	if (!myfs.begin(buf, sizeof(buf), MYBLKSIZE )) {
#elif defined(TEST_SPI)
#ifdef FORMATSPI
	if (!myfs.begin( FlashChipSelect )) {
#elif defined(FORMATSPI2)
	pinMode(FlashChipSelect, OUTPUT);
	digitalWriteFast(FlashChipSelect, LOW);
	SPI2.setMOSI(50);
	SPI2.setMISO(54);
	SPI2.setSCK(49);
	SPI2.begin();
	if (!myfs.begin(51, SPI2)) {
#endif
#elif defined(TEST_MRAM)
	if (!myfs.begin( FlashChipSelect )) {
#elif defined(TEST_SPI_NAND)
	if (!myfs.begin( FlashChipSelect )) {
#elif defined(TEST_PROG)
	if (!myfs.begin(1024 * 1024 * 6)) {
#else
	if (!myfs.begin()) {
#endif
		Serial.printf("Error starting %s\n", szDiskMem);
		checkInput( 1 );
	}
	// parseCmd( 'F' ); // ENABLE this if disk won't allow startup
	filecount = printDirectoryFilecount( myfs.open("/") );  // Set base value of filecount for disk
	printDirectory();
	parseCmd( '?' );
#ifndef ROOTONLY // make subdirs if !ROOTONLY
	makeRootDirs();
#endif
	checkInput( 1 );
	filecount = printDirectoryFilecount( myfs.open("/") );  // Set base value of filecount for disk
	printDirectory();
#ifdef SHOW_YIELD_CNT
	clocked10ms.begin(clock_isr, 10000);
#endif
	while ( 1 ) {
		loopX(); // Avoid end of loop() yield so the clock_isr() isn't noisy when used.
#ifndef SHOW_YIELD_CNT
		yield(); // simulate normal exec
#endif
	}
}

void makeRootDirs() {
	char szDir[16];
	for ( uint32_t ii = 1; ii <= NUMDIRS; ii++ ) {
		sprintf( szDir, "/%lu_dir", ii );
		myfs.mkdir( szDir );
	}
}

int loopLimit = 0; // -1 continuous, otherwise # to count down to 0
bool pauseDir = false;  // Start Pause on each off
bool showDir =  false;  // false Start Dir on each off
bool bDirVerify =  false;  // false Start Dir on each off
bool bWriteVerify = true;  // Verify on Write Toggle
bool bAutoFormat =  false;  // false Auto formatUnused() off
bool bCheckFormat =  false;  // false CheckFormat
bool bCheckUsed =  false;  // false CheckUsed
uint32_t res = 0; // for formatUnused
void loop() { }
void loopX() {
	char szDir[16];
	LoopCnt++;
	uint32_t chStep;
	if ( loopLimit != 0 ) {
#ifdef ROOTONLY // ii=1-NUMDIRS are subdirs. #0 is Root
		for ( uint32_t ii = 0; ii < 1 && ( loopLimit != 0 ); ii++ )
#else
		for ( uint32_t ii = 0; ii < NUMDIRS && ( loopLimit != 0 ); ii++ )
#endif
		{
			if ( ii == 0 )
				sprintf( szDir, "/" );
			else
				sprintf( szDir, "/%lu_dir", ii );
			chStep = fileCycle(szDir);
			if ( bAutoFormat && !(lCnt % 5) ) res = loopAutoFormat( 20, res );
//			if ( bAutoFormat && !(lCnt % 20) ) res = loopAutoFormat( 6, res );
			while ( chStep != fileCycle(szDir) && ( loopLimit != 0 ) ) {
				if ( bAutoFormat && !(lCnt % 5) ) res = loopAutoFormat( 12, res ); // how often and how many depends on media and sizes
				//if ( bAutoFormat && !(lCnt % 20) ) res = loopAutoFormat( 6, res );
				checkInput( 0 ); // user input can 0 loopLimit
			}
		}
		checkInput( 0 );
		if ( loopLimit > 0 ) // -1 means continuous
			loopLimit--;
	}
	else
		checkInput( 1 );
}
uint32_t loopAutoFormat( uint32_t cnt, uint32_t myres ) {
	uint32_t retres;
	retres = myfs.formatUnused( cnt, myres );
	Serial.printf("\t fmtU @ %lu - %lu \n", myres, retres );
	return retres;

}

char szInputs[] = "0123456789RdwcghkFqvplmusSBbyYxfan+-?";
uint32_t lastTime;
void checkInput( int step ) { // prompt for input without user input with step != 0
	uint32_t nowTime = micros();

	char retVal = 0, temp;
	char *pTemp;
	if ( step != 0 ) {
		nowTime -= lastTime;
		Serial.printf( "[%6.2f M](%6.5f M elap) Awaiting input %s loops left %d >", millis() / 60000.0, nowTime / 60000000.0, szInputs, loopLimit );
	}
	else {
		if ( !Serial.available() ) return;
		nowTime -= lastTime;
		Serial.printf( "[%6.2f M](%6.2f elap) Awaiting input %s loops left %d >", millis() / 60000.0, nowTime / 60000000.0, szInputs, loopLimit );
		//Serial.printf( "[%6.2f] Awaiting input %s loops left %d >", millis() / 60000.0, szInputs, loopLimit );
		while ( Serial.available() ) {
			temp = Serial.read( );
			if ( (pTemp = strchr(szInputs, temp)) ) {
				retVal = pTemp[0];
				parseCmd( retVal );
			}
		}
	}
	while ( !Serial.available() );
	while ( Serial.available() ) {
		temp = Serial.read();
		if ( (pTemp = strchr(szInputs, temp)) ) {
			retVal = pTemp[0];
			parseCmd( retVal );
		}
	}
	Serial.print( '\n' );
	if ( '?' == retVal ) checkInput( 1 ); // recurse on '?' to allow command show and response
	return;
}
void parseCmd( char chIn ) { // pass chIn == '?' for help
	uint32_t timeMe;
		char szNone[]="";
	switch (chIn ) {
	case '?':
		Serial.printf( "%s\n", " 0, 1-9 '#' passes continue loop before Pause\n\
 'a' Auto formatUnused() during iterations - TOGGLE\n\
 'R' Restart Teensy\n\
 'd' Directory of LittleFS\n\
 'w' WIPE Directory of LittleFS\n\
 'b' big file delete\n\
 'B' BIG FILE MAKE\n\
 'S' FILE 2MB MAKE\n\
 's' FILE 2MB delete\n\
 'c' Continuous Loop\n\
 'g' run speedBench()\n\
 'h' Hundred loops\n\
 'k' Thousand loops\n\
 'F' LittleFS_ Low Level Format Disk \n\
 'f' LittleFS::formatUnused( ALL ) : DATA PRESERVED \n\
 'q' LittleFS_ Quick Format Disk \n\
 'v' Verbose All Dir Prints - TOGGLE\n\
 'p' Pause after all Dir prints - TOGGLE\n\
 'l' Show count of loop()'s, Bytes Read,Written\n\
 'm' Make ROOT dirs (needed after q/F format !ROOTONLY)\n\
 'u' Update Filecount\n\
 'x' Directory filecount verify - TOGGLE\n\
 'n' No verify on Write- TOGGLE\n\
 '+' more add to delete cycles\n\
 '-' fewer add to delete cycles\n\
 'y' reclaim 1 block :: myfs.formatUnused( 1 )\n\
 'Y' reclaim 15 blocks :: myfs.formatUnused( 15 )\n\
 '?' Help list" );
		break;
	case 'R':
		Serial.print(" RESTART Teensy ...");
		delay(100);
		SCB_AIRCR = 0x05FA0004;
		break;
	case '0':
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
		loopLimit = chIn - '0';
		if ( chIn != '0' )	// Preserve elapsed time on Error or STOP command
			lastTime = micros();
		break;
	case 'b':
		bigFile( 0 ); // delete
		chIn = 0;
		break;
	case 'B':
		lastTime = micros();
		bigFile( 1 ); // CREATE
		chIn = 0;
		break;
	case 's':
		bigFile2MB( 0 ); // CREATE
		chIn = 0;
		break;
	case 'S':
		lastTime = micros();
		bigFile2MB( 1 ); // CREATE
		chIn = 0;
		break;
	case 'c':
		loopLimit = -1;
		break;
	case 'g':
		lastTime = micros();
		speedBench();
		chIn = 0;
		break;
	case 'd':
		Serial.print( " d\n" );
		lastTime = micros();
		printDirectory();
		Serial.print( '\n' );
		parseCmd( 'l' );
		checkInput( 1 );
		chIn = 0;
		break;
	case 'w':
		Serial.println("\nWipe All Files and DIRS:");
		deleteAllDirectory(myfs.open("/"), szNone );
		errsLFS = 0; // No Errors on new Format
		warnLFS = 0; // No warning on new Format
		chIn = 0;
		parseCmd( 'u' );
		break;
	case 'h':
		loopLimit = 100;
		lastTime = micros();
		break;
	case 'k':
		loopLimit = 1000;
		lastTime = micros();
		break;
	case 'F': // Low Level format
		Serial.print( "\nFormatting Low Level:\n\t" );
		lastTime = micros();
		timeMe = micros();
		myfs.lowLevelFormat('.');
		timeMe = micros() - timeMe;
		Serial.printf( "\n Done Formatting Low Level in %lu us.\n", timeMe );
		errsLFS = 0; // No Errors on new Format
		warnLFS = 0; // No warning on new Format
		bCheckFormat  = false;
		parseCmd( 'u' );
		break;
	case 'q': // quick format
		lastTime = micros();
		myfs.quickFormat();
		errsLFS = 0; // No Errors on new Format
		parseCmd( 'u' );
		break;
	case 'v': // verbose dir
		showDir = !showDir;
		showDir ? Serial.print(" Verbose on: ") : Serial.print(" Verbose off: ");
		chIn = 0;
		break;
	case 'p': // pause on dirs
		pauseDir = !pauseDir;
		pauseDir ? Serial.print(" Pause on: ") : Serial.print(" Pause off: ");
		chIn = 0;
		break;
	case 'x': // dir filecount Verify
		bDirVerify = !bDirVerify;
		bDirVerify ? Serial.print(" FileCnt on: ") : Serial.print(" FileCnt off: ");
		lastTime = micros();
		dirVerify();
		chIn = 0;
		break;
	case 'n': // No Verify on write
		bWriteVerify = !bWriteVerify;
		bWriteVerify ? Serial.print(" Write Verify on: ") : Serial.print(" Write Verify off: ");
		chIn = 0;
		break;
	case 'a': // Auto myfs.formatUnused() during iterations
		bAutoFormat = !bAutoFormat;
		bAutoFormat ? Serial.print(" \nAuto formatUnused() On: ") : Serial.print(" \nAuto formatUnused() Off: ");
		chIn = 0;
		break;
	case 'y': // Reclaim 1 unused format
		lastTime = micros();
		Serial.printf( "\n myfs.formatUnused( 1 ) ...\n" );
		timeMe = micros();
		res = myfs.formatUnused( 1, res );
		timeMe = micros() - timeMe;
		Serial.printf( "\n\t formatUnused :: Done Formatting Low Level in %lu us (last %lu).\n", timeMe, res );
		chIn = 0;
		break;
	case 'Y': // Reclaim 15 unused format
		lastTime = micros();
		Serial.printf( "\n myfs.formatUnused( 15 ) ...\n" );
		timeMe = micros();
		res = myfs.formatUnused( 15, res );
		timeMe = micros() - timeMe;
		Serial.printf( "\n\t formatUnused :: Done Formatting Low Level in %lu us (last %lu).\n", timeMe, res );
		chIn = 0;
		break;
	case 'f': // Reclaim all unused format
		lastTime = micros();
		Serial.printf( "\n myfs.formatUnused( 0 ) ...\n" );
		timeMe = micros();
		myfs.formatUnused( 0, 0 );
		timeMe = micros() - timeMe;
		Serial.printf( "\n\t formatUnused :: Done Formatting Low Level in %lu us.\n", timeMe );
		chIn = 0;
		break;
	case 'l': // Show Loop Count
		Serial.printf("\n\t Loop Count: %u (#fileCycle=%u), Bytes read %llu, written %llu, #Files=%u\n", LoopCnt, lCnt, rdCnt, wrCnt, filecount );
		if ( 0 != errsLFS )
			Serial.printf("\t ERROR COUNT =%u\n", errsLFS );
		if ( 0 != warnLFS )
			Serial.printf("\t Free Space Warn COUNT =%u\n", warnLFS );
		dirVerify();
		chIn = 0;
		break;
	case 'm':
		Serial.printf("m \n\t Making Root Dirs\n" );
		makeRootDirs();
		parseCmd( 'd' );
		chIn = 0;
		break;
	case 'u': // Show Loop Count
		filecount = printDirectoryFilecount( myfs.open("/") );
		Serial.printf("u \n\t Updated filecount %u\n", filecount );
		chIn = 0;
		break;
	case '+': // increase add cycles
		DELSTART++;
		Serial.printf("+\n Deletes start after %u cycles ", DELSTART);
		chIn = 0;
		break;
	case '-': // decrease add cycles
		DELSTART--;
		if ( DELSTART < 1 ) DELSTART = 1;
		Serial.printf("-\n Deletes start after %u cycles ", DELSTART);
		chIn = 0;
		break;
	default:
		Serial.println( chIn ); // never see without unhandled char in szInputs[]
		break;
	}
	if ( 0 != chIn ) Serial.print( chIn );
}

uint32_t fTot, totSize;
void printDirectory() {
	fTot = 0, totSize = 0;
	Serial.printf("printDirectory %s\n--------------\n", szDiskMem);
	printDirectory(myfs.open("/"), 0);
	Serial.printf(" %Total %u files of Size %u Bytes\n", fTot, totSize);
	Serial.printf("Bytes Used: %llu, Bytes Total:%llu\n", myfs.usedSize(), myfs.totalSize());
}

void deleteAllDirectory(File dir, char *fullPath ) {
	char myPath[ 256 ] = "";
	while (true) {
		File entry =  dir.openNextFile();
		if (! entry) {
			// no more files
			break;
		}
		if (entry.isDirectory()) {
			strcpy( myPath, fullPath);
			strcat( myPath, entry.name());
			strcat( myPath, "/");
			deleteAllDirectory(entry, myPath);
			entry.close();
			if ( !myfs.remove( myPath ) )
				Serial.print( "  Fail remove DIR>\t");
			else
				Serial.print( "  Removed DIR>\t");
			Serial.println( myPath );

		} else {
			strcpy( myPath, fullPath);
			strcat( myPath, entry.name());
			entry.close();
			if ( !myfs.remove( myPath ) )
				Serial.print( "\tFail remove>\t");
			else
				Serial.print( "\tRemoved>\t");
			Serial.println( myPath );
		}
	}
}

int printDirectoryFilecount(File dir) {
	unsigned int filecnt = 0;
	while (true) {
		File entry =  dir.openNextFile();
		if (! entry) {
			// no more files
			break;
		}
		if (entry.isDirectory()) {
			filecnt += printDirectoryFilecount(entry);
		} else {
			filecnt++;
		}
		entry.close();
	}
	return filecnt;
}

void printDirectory(File dir, int numTabs) {
	//dir.whoami();
	uint32_t fSize = 0, dCnt = 0, fCnt = 0;
	if ( 0 == dir ) {
		Serial.printf( "\t>>>\t>>>>> No Dir\n" );
		return;
	}
	while (true) {
		File entry =  dir.openNextFile();
		if (! entry) {
			// no more files
			Serial.printf("\n %u dirs with %u files of Size %u Bytes\n", dCnt, fCnt, fSize);
			fTot += fCnt;
			totSize += fSize;
			break;
		}
		for (uint8_t i = 0; i < numTabs; i++) {
			Serial.print('\t');
		}

		if (entry.isDirectory()) {
			Serial.print("DIR\t");
			dCnt++;
		} else {
			Serial.print("FILE\t");
			fCnt++;
			fSize += entry.size();
		}
		Serial.print(entry.name());
		if (entry.isDirectory()) {
			Serial.println(" / ");
			printDirectory(entry, numTabs + 1);
		} else {
			// files have sizes, directories do not
			Serial.print("\t\t");
			Serial.println(entry.size(), DEC);
		}
		entry.close();
		//Serial.flush();
	}
}

uint32_t cCnt = 0;
uint32_t fileCycle(const char *dir) {
	static char szFile[] = "_file.txt";
	char szPath[150];
	int ii;
	lCnt++;
	byte nNum = lCnt % MAXNUM;
	char chNow = 'A' + lCnt % MAXNUM;
	lfs_ssize_t resW = 1;
	uint32_t timeMeAll = micros();

	if ( dir[1] == 0 )	// catch root
		sprintf( szPath, "/%c%s", chNow, szFile );
	else
		sprintf( szPath, "%s/%c%s", dir, chNow, szFile );
	if ( cCnt >= DELSTART && myfs.exists(szPath) ) { // DELETE ALL KNOWN FILES
		if ( nNum == 1 ) {
			Serial.print( "\n == == ==   DELETE PASS START  == == == = \n");
			if ( showDir ) {
				printDirectory();
				Serial.print( " == == ==   DELETE PASS START  == == == = \n");
			}
			delayMicroseconds(DELDELAY);
		}
	}
	Serial.printf( ":: %s ", szPath );
	if ( cCnt >= DELSTART && myfs.exists(szPath) ) { // DELETE ALL KNOWN FILES
		readVerify( szPath, chNow );
		myfs.remove(szPath);
		filecount--;
		Serial.printf(" %s ----DEL----", szDiskMem);
		Serial.printf(" -- %c", chNow);
		if ( showDir ) {
			Serial.print("\n");
			printDirectory(myfs.open(dir), 1);
		}
		if ( pauseDir ) checkInput( 1 );
		Serial.println();
	}
	else {
		if ( bWriteVerify && myfs.totalSize() - myfs.usedSize() < MAXFILL ) {
			warnLFS++;
			Serial.printf( "\tXXX\tXXX\tXXX\tXXX\tSIZE WARNING { MAXFILL } \n" );
			cCnt = DELSTART;
			return cCnt;	// EARLY EXIT
		}
		if ( nNum == 0 ) {
			nNum = 10;
			cCnt++;
			if ( cCnt >= DELSTART + 2 ) cCnt = 0;
		}
		file3 = myfs.open(szPath, FILE_WRITE);
		if ( 0 == file3 ) {
			Serial.printf( "\tXXX\tXXX\tXXX\tXXX\tFail File open {mkdir?}\n" );
			delayMicroseconds(300000);
			checkInput( 1 );	// PAUSE on CmdLine
		}
		else {
			delayMicroseconds(ADDDELAY);
			char mm = chNow + lowOffset;
			uint32_t jj = file3.size() + 1;
			uint32_t timeMe = micros();
			for ( ii = 0; ii < (nNum * SUBADD + BIGADD ) && resW > 0; ii++ ) {
				if ( 0 == ((ii + jj) / lowShift) % 2 )
					resW = file3.write( &mm , 1 );
				else
					resW = file3.write( &chNow , 1 );
				wrCnt++;
				// if ( lCnt%100 == 50 ) mm='x'; // GENERATE ERROR to detect on DELETE read verify
			}
			file3.close();
			timeMe = micros() - timeMe;
			timeMeAll = micros() - timeMeAll;
			Serial.printf(" %s +++ Add [sz %u add %u] @KB/sec %5.2f {%5.2f} ", szDiskMem, jj - 1, ii, ii / (timeMe / 1000.0), ii / (timeMeAll / 1000.0) );
			if (resW < 0) {
				Serial.printf( "\n\twrite fail ERR# %i 0x%X \n", resW, resW );
				parseCmd( '0' );
				errsLFS++;
				checkInput( 1 );	// PAUSE on CmdLine
			}
			else if ( jj == 1 ) filecount++; // File Added
			Serial.printf(" ++ %c ", chNow);
			if ( bWriteVerify )
				readVerify( szPath, chNow );
			else
				Serial.print('\n');
			if ( showDir ) {
				Serial.print('\n');
				printDirectory(myfs.open(dir), 1);
			}
		}
		if ( pauseDir ) checkInput( 1 );
		//Serial.print("\n");
		delayMicroseconds(ADDDELAY);
	}
	checkInput( 0 ); // user stop request?
	if ( bDirVerify ) dirVerify();
	return cCnt;
}

void dirVerify() {
	uint32_t timeMe = micros();
	Serial.printf("\tdirV...");
	if ( filecount != printDirectoryFilecount( myfs.open("/") ) ) {
		Serial.printf( "\tFilecount mismatch %u != %u\n", filecount, printDirectoryFilecount( myfs.open("/") ) );
		parseCmd( '0' );
		errsLFS++;
		checkInput( 1 );	// PAUSE on CmdLine
	}
	timeMe = micros() - timeMe;
	Serial.printf("%lu_us\t", timeMe);
}

void readVerify( char szPath[], char chNow ) {
	uint32_t timeMe = micros();
	file3 = myfs.open(szPath);
	if ( 0 == file3 ) {
		Serial.printf( "\tV\t Fail File open %s\n", szPath );
		parseCmd( '0' );
		errsLFS++;
		checkInput( 1 );
	}
	char mm;
	char chNow2 = chNow + lowOffset;
	uint32_t ii = 0;
	while ( file3.available() ) {
		file3.read( &mm , 1 );
		rdCnt++;
		//Serial.print( mm ); // show chars as read
		ii++;
		if ( 0 == (ii / lowShift) % 2 ) {
			if ( chNow2 != mm ) {
				Serial.printf( "<Bad Byte!  %c! = %c [0x%X] @%u\n", chNow2, mm, mm, ii );
				parseCmd( '0' );
				errsLFS++;
				checkInput( 1 );
				break;
			}
		}
		else {
			if ( chNow != mm ) {
				Serial.printf( "<Bad Byte!  %c! = %c [0x%X] @%u\n", chNow, mm, mm, ii );
				parseCmd( '0' );
				errsLFS++;
				checkInput( 1 );
				break;
			}
		}
	}
	Serial.printf( "  Verify %s %uB ", szPath, ii );
	if (ii != file3.size()) {
		Serial.printf( "\n\tRead Count fail! :: read %u != f.size %llu", ii, file3.size() );
		parseCmd( '0' );
		errsLFS++;
		checkInput( 1 );	// PAUSE on CmdLine
	}
	file3.close();
	timeMe = micros() - timeMe;
	Serial.printf( " @KB/sec %5.2f \n", ii / (timeMe / 1000.0) );
}

bool bigVerify( char szPath[], char chNow ) {
	uint32_t timeMe = micros();
	file3 = myfs.open(szPath);
	if ( 0 == file3 ) {
		return false;
	}
	char mm;
	uint32_t ii = 0;
	uint32_t kk = file3.size() / 50;
	Serial.printf( "\tVerify %s bytes %llu : ", szPath, file3.size() );
	while ( file3.available() ) {
		file3.read( &mm , 1 );
		rdCnt++;
		ii++;
		if ( !(ii % kk) ) Serial.print('.');
		if ( chNow != mm ) {
			Serial.printf( "<Bad Byte!  %c! = %c [0x%X] @%u\n", chNow, mm, mm, ii );
			parseCmd( '0' );
			errsLFS++;
			checkInput( 1 );
			break;
		}
	}
	if (ii != file3.size()) {
		Serial.printf( "\n\tRead Count fail! :: read %u != f.size %llu\n", ii, file3.size() );
		parseCmd( '0' );
		errsLFS++;
		checkInput( 1 );	// PAUSE on CmdLine
	}
	else
		Serial.printf( "\tGOOD! >>  bytes %lu", ii );
	file3.close();
	timeMe = micros() - timeMe;
	Serial.printf( "\n\tBig read&compare KBytes per second %5.2f \n", ii / (timeMe / 1000.0) );
	if ( 0 == ii ) return false;
	return true;
}


void bigFile( int doThis ) {
	char myFile[] = "/0_bigfile.txt";
	char fileID = '0' - 1;

	if ( 0 == doThis ) {	// delete File
		Serial.printf( "\nDelete with read verify all #bigfile's\n");
		do {
			fileID++;
			myFile[1] = fileID;
			if ( myfs.exists(myFile) && bigVerify( myFile, fileID) ) {
				filecount--;
				myfs.remove(myFile);
			}
			else break; // no more of these
		} while ( 1 );
	}
	else {	// FILL DISK
		lfs_ssize_t resW = 1;
		char someData[2048];
		uint32_t xx, toWrite;
		toWrite = (myfs.totalSize()) - myfs.usedSize();
		if ( toWrite < 65535 ) {
			Serial.print( "Disk too full! DO :: b or q or F");
			return;
		}
		toWrite -= 40960; // allow for slack space :: WORKS on FLASH?
#ifdef HALFCUT
		toWrite /= 2; // cutting to this works on LittleFS_RAM myfs - except reported file3.size()=2054847098 OR now 0
#endif
		xx = toWrite;
		Serial.printf( "\nStart Big write of %u Bytes", xx);
		uint32_t timeMe = micros();
		file3 = nullptr;
		do {
			if ( file3 ) file3.close();
			fileID++;
			myFile[1] = fileID;
			file3 = myfs.open(myFile, FILE_WRITE);
		} while ( fileID < '9' && file3.size() > 0);
		if ( fileID == '9' ) {
			Serial.print( "Disk has 9 halves 0-8! DO :: b or q or F");
			return;
		}
		memset( someData, fileID, 2048 );
		int hh = 0;
		while ( toWrite > 2048 && resW > 0 ) {
			resW = file3.write( someData , 2048 );
			hh++;
			if ( !(hh % 40) ) Serial.print('.');
			toWrite -= 2048;
		}
		xx -= toWrite;
		file3.close();
		timeMe = micros() - timeMe;
		file3 = myfs.open(myFile, FILE_WRITE);
		if ( file3.size() > 0 ) {
			filecount++;
			Serial.printf( "\nBig write %s took %5.2f Sec for %lu Bytes : file3.size()=%llu", myFile , timeMe / 1000000.0, xx, file3.size() );
		}
		if ( file3 != 0 ) file3.close();
		Serial.printf( "\n\tBig write KBytes per second %5.2f \n", xx / (timeMe / 1000.0) );
		Serial.printf("\nBytes Used: %llu, Bytes Total:%llu\n", myfs.usedSize(), myfs.totalSize());
		if ( resW < 0 ) {
			Serial.printf( "\nBig write ERR# %i 0x%X \n", resW, resW );
			errsLFS++;
			myfs.remove(myFile);
		}
	}
}

void bigFile2MB( int doThis ) {
	char myFile[] = "/0_2MBfile.txt";
	char fileID = '0' - 1;

	if ( 0 == doThis ) {	// delete File
		Serial.printf( "\nDelete with read verify all #bigfile's\n");
		do {
			fileID++;
			myFile[1] = fileID;
			if ( myfs.exists(myFile) && bigVerify( myFile, fileID) ) {
				filecount--;
				myfs.remove(myFile);
			}
			else break; // no more of these
		} while ( 1 );
	}
	else {	// FILL DISK
		lfs_ssize_t resW = 1;
		char someData[2048];
		uint32_t xx, toWrite;
		toWrite = 2048 * 1000;
		if ( toWrite > (65535 + (myfs.totalSize() - myfs.usedSize()) ) ) {
			Serial.print( "Disk too full! DO :: q or F");
			return;
		}
		xx = toWrite;
		Serial.printf( "\nStart Big write of %u Bytes", xx);
		uint32_t timeMe = micros();
		file3 = nullptr;
		do {
			if ( file3 ) file3.close();
			fileID++;
			myFile[1] = fileID;
			file3 = myfs.open(myFile, FILE_WRITE);
		} while ( fileID < '9' && file3.size() > 0);
		if ( fileID == '9' ) {
			Serial.print( "Disk has 9 files 0-8! DO :: b or q or F");
			return;
		}
		memset( someData, fileID, 2048 );
		int hh = 0;
		while ( toWrite >= 2048 && resW > 0 ) {
			resW = file3.write( someData , 2048 );
			hh++;
			if ( !(hh % 40) ) Serial.print('.');
			toWrite -= 2048;
		}
		xx -= toWrite;
		file3.close();
		timeMe = micros() - timeMe;
		file3 = myfs.open(myFile, FILE_WRITE);
		if ( file3.size() > 0 ) {
			filecount++;
			Serial.printf( "\nBig write %s took %5.2f Sec for %lu Bytes : file3.size()=%llu", myFile , timeMe / 1000000.0, xx, file3.size() );
		}
		if ( file3 != 0 ) file3.close();
		Serial.printf( "\n\tBig write KBytes per second %5.2f \n", xx / (timeMe / 1000.0) );
		Serial.printf("\nBytes Used: %llu, Bytes Total:%llu\n", myfs.usedSize(), myfs.totalSize());
		if ( resW < 0 ) {
			Serial.printf( "\nBig write ERR# %i 0x%X \n", resW, resW );
			errsLFS++;
			myfs.remove(myFile);
		}
	}
}

#include <sdios.h>
ArduinoOutStream cout(Serial);
File file;

// File size in bytes.
const uint32_t FILE_SIZE = 16 * 1024;

// Set SKIP_FIRST_LATENCY true if the first read/write to the SD can
// be avoid by writing a file header or reading the first record.
const bool SKIP_FIRST_LATENCY = true;

// Size of read/write.
const size_t BUF_SIZE = 2048;

// Write pass count.
const uint8_t WRITE_COUNT = 5;

// Read pass count.
const uint8_t READ_COUNT = 5;

//Block size for qspi
#define MYBLKSIZE 2048 // 2048

// Insure 4-byte alignment.
uint32_t buf32[(BUF_SIZE + 3) / 4];
uint8_t* bufA32 = (uint8_t*)buf32;

//Number of random reads
#define randomReads 1

void speedBench() {
	File file;
	float s;
	uint32_t t;
	uint32_t maxLatency;
	uint32_t minLatency;
	uint32_t totalLatency;
	bool skipLatency;

	myfs.remove("bench.dat");
	//for(uint8_t cnt=0; cnt < 10; cnt++) {

	// fill buf with known data
	if (BUF_SIZE > 1) {
		for (size_t i = 0; i < (BUF_SIZE - 2); i++) {
			bufA32[i] = 'A' + (i % 26);
		}
		bufA32[BUF_SIZE - 2] = '\r';
	}
	bufA32[BUF_SIZE - 1] = '\n';

	Serial.printf("%s Disk Stats:", szDiskMem );
	Serial.printf("Bytes Used: %llu, Bytes Total:%llu\n", myfs.usedSize(), myfs.totalSize());
	Serial.printf("%s Benchmark:\n", szDiskMem );
	cout << F("FILE_SIZE = ") << FILE_SIZE << endl;
	cout << F("BUF_SIZE = ") << BUF_SIZE << F(" bytes\n");
	cout << F("Starting write test, please wait.") << endl << endl;

	// do write test
	uint32_t n = FILE_SIZE / BUF_SIZE;
	cout << F("write speed and latency") << endl;
	cout << F("speed,max,min,avg") << endl;
	cout << F("KB/Sec,usec,usec,usec") << endl;

	// open or create file - truncate existing file.
	file = myfs.open("bench.dat", FILE_WRITE);

	for (uint8_t nTest = 0; nTest < WRITE_COUNT; nTest++) {
		file.seek(0);

		maxLatency = 0;
		minLatency = 9999999;
		totalLatency = 0;
		skipLatency = SKIP_FIRST_LATENCY;
		t = millis();

		for (uint32_t i = 0; i < n; i++) {
			uint32_t m = micros();
			if (file.write(bufA32, BUF_SIZE) != BUF_SIZE) {
				Serial.println("write failed");
			}
			m = micros() - m;
			totalLatency += m;
			if (skipLatency) {
				// Wait until first write to SD, not just a copy to the cache.
				skipLatency = file.position() < 512;
			} else {
				if (maxLatency < m) {
					maxLatency = m;
				}
				if (minLatency > m) {
					minLatency = m;
				}
			}
		}

		t = millis() - t;
		s = file.size();
		cout << s / t << ',' << maxLatency << ',' << minLatency;
		cout << ',' << totalLatency / n << endl;
	}
	cout << endl << F("Starting sequential read test, please wait.") << endl;
	cout << endl << F("read speed and latency") << endl;
	cout << F("speed,max,min,avg") << endl;
	cout << F("KB/Sec,usec,usec,usec") << endl;

	// do read test
	for (uint8_t nTest = 0; nTest < READ_COUNT; nTest++) {
		file.seek(0);
		maxLatency = 0;
		minLatency = 9999999;
		totalLatency = 0;
		skipLatency = SKIP_FIRST_LATENCY;
		t = micros();
		for (uint32_t i = 0; i < n; i++) {
			bufA32[BUF_SIZE - 1] = 0;
			uint32_t m = micros();
			int32_t nr = file.read(bufA32, BUF_SIZE);
			if (nr != BUF_SIZE) {
				Serial.println("read failed");
			}
			m = micros() - m;
			totalLatency += m;
			if (bufA32[BUF_SIZE - 1] != '\n') {
				Serial.println("data check error");
			}
			if (skipLatency) {
				skipLatency = false;
			} else {
				if (maxLatency < m) {
					maxLatency = m;
				}
				if (minLatency > m) {
					minLatency = m;
				}
			}
		}

		s = file.size();

		t = micros() - t;
		cout << s * 1000 / t << ',' << maxLatency << ',' << minLatency;
		cout << ',' << totalLatency / n << endl;
	}

	cout << endl << F("Done") << endl;

	cout << endl << F("Starting random read test, please wait.") << endl;

	Serial.printf("Number of random reads: %d\n", randomReads);
	Serial.printf("Number of blocks: %d\n", n);

	cout << endl << F("read speed and latency") << endl;
	cout << F("speed,max,min,avg") << endl;

	// do read test
	for (uint8_t nTest = 0; nTest < READ_COUNT; nTest++) {
		file.seek(0);
		maxLatency = 0;
		minLatency = 0;
		totalLatency = 0;
		skipLatency = SKIP_FIRST_LATENCY;
		t = micros();
		for (uint32_t i = 0; i < randomReads; i++) {
			bufA32[BUF_SIZE - 1] = 0;
			uint32_t m = micros();
			uint32_t block_pos = random(0, (n - 1));
			uint32_t random_pos = block_pos * MYBLKSIZE;
			cout << "Position (bytes), Block: " << random_pos << ", ";
			cout << block_pos << endl;
			uint32_t startCNT = ARM_DWT_CYCCNT;
			file.seek(random_pos);
			int32_t nr = file.read(bufA32, BUF_SIZE);
			uint32_t endCNT = ARM_DWT_CYCCNT;
			cout << F("Read Time (ARM Cycle Delta): ") << endCNT - startCNT << endl;
			if (nr != BUF_SIZE) {
				Serial.println("read failed");
			}
			m = micros() - m;
			totalLatency += m;
			if (bufA32[BUF_SIZE - 1] != '\n') {
				Serial.println("data check error");
			}
			if (skipLatency) {
				skipLatency = false;
			} else {
				if (maxLatency < m) {
					maxLatency = m;
				}
				if (minLatency > m) {
					minLatency = m;
				}
			}
		}

		s = file.size();


		t = micros() - t;
		cout << F("KB/Sec,usec,usec,usec") << endl;
		cout << s * 1000 / t << ',' << maxLatency << ',' << minLatency;
		cout << ',' << totalLatency / n << endl;
	}
	cout << endl << F("Done") << endl;


	file.close();
	myfs.remove("bench.dat");

}

@defragster - @Paul - @all

Downloaded the beta10 and installed over 1.54beta9. Loaded up the LFSIntegrity sketch in previous post and ran it on both a T4.1 and Teensy MicroMod. Then for using:
DOING: 'B' - starts BIG write
or
DOING '1' - a single loop write to one small file

Tested EXTMEM, DMAMEM, RAM1 and in all cases did I see any hangs. I did it a few times between power recycling. Did "Restart" as well for all 3 regions and then used 1 and B again, no hangs.
 
Back
Top