Infact, I spend so long staring that I forgot to check that it actually, uh, works?
Which.. it doesn't.... (built with current flexspin master, no funny PRs - note how it just speeds through the file loading way too fast)
Sent a PR to fix the FS working at all when used from Spin.
Also, wrt. buffering, I took a look:
FatFS has sufficient internal bufffering
Parallax FS has sufficient internal buffering
LittleFS has no buffering (but can read/write partial blocks)
9P has no buffering
In either case the current buffer implementation that only sits on getc/putc needs to be removed and possibly replaced by something called into from the 9P/LFS VFS implementations (so it catches all v_write/v_read calls and doesn't need stupid flushing everywhere)
@Wuerfel_21 The internal buffering of FatFS is OK for reading (only about twice as slow as the stdio buffering; not great, but bearable). But for writing? It's very bad. Calling the FatFS write routine with 1 byte is about 1000 times slower than fputc(). And yes, doing 1 byte writes is a bad idea, but a lot of programs do it: fgetc/fputc are really widely used. Hence the need for buffering.
@ersmith said:
@Wuerfel_21 The internal buffering of FatFS is OK for reading (only about twice as slow as the stdio buffering; not great, but bearable). But for writing? It's very bad. Calling the FatFS write routine with 1 byte is about 1000 times slower than fputc(). And yes, doing 1 byte writes is a bad idea, but a lot of programs do it: fgetc/fputc are really widely used. Hence the need for buffering.
Are you sure you tested that correctly? (i.e. no unnecessary f_sync or such inbetween). There should be a fast-ish path through f_write when it's just appending to the buffer, just a few checks and a memcpy. 1000x slower sounds like buffer is being erroneously flushed on every call.
Also, if you're doing performance metrics, fun things to try:
@iseries said:
I'm confused about the cogstart function in C.
int cogstart(void (*func)(void *), void *arg, void *stack, size_tstacksize);
It shows the stack as size_tstacksize but what size is it. Is it in bytes or words?
int Stack[50];
cogstart(function, NULL, Stack, 50);
Maybe you could update the help docs as well.
Mike
In FlexC the stacksize parameter is ignored, the size of the array passed in for stack is used directly. In other compilers I believe the stacksize is in bytes.
One, I'm after some silence from the assembler. I can suppress the compiler warnings with the recommended -0 suffix, but not the subsequent assembler warnings.
Two, something is not right with the compiled example. The compiler seems to be producing additional MOV 0-0, instructions for no good reason. eg:
mov pa, 256
mov 0-0, pa
EDIT: Hmm, me now wonders if the two are related in that the extraneous instruction is the compiler's broken attempt to suppress assembler warnings.
(1) You can add -Wno-asm-usage to the command line to suppress warnings about assembly constructs. I guess this should always be set for the second pass of the assembler, I'll change that.
(2) What version of flexspin are you using? I don't see the mov 0-0, pa that you reported, just four mov pa, XXX where XXX are the various constants.
Maybe it's a debug issue. Compiled without debug looks fine. So I was really only fighting the warnings historically. The oddity with MOV 0-0,PA I've only just noticed.
@evanh : The inserted mov 0-0, pa instructions are indeed due to debugging. In general printing debug expressions requires copying the value to a register. In this particular case the value is already in a register so it isn't necessary, but the code that generates debug is not very smart and just always follows the same path. Basically debug() in inline assembly inside spin2 functions isn't very efficient (and also modifies the first few longs of COG memory, which is potentially a problem).
@ersmith said:
Basically debug() in inline assembly inside spin2 functions isn't very efficient (and also modifies the first few longs of COG memory, which is potentially a problem).
And I always looked at that and was like "wait that can't be right". It'd be better to make it grab the correct registers directly, but I guess that's hard.
@ersmith said:
Basically debug() in inline assembly inside spin2 functions isn't very efficient (and also modifies the first few longs of COG memory, which is potentially a problem).
And I always looked at that and was like "wait that can't be right". It'd be better to make it grab the correct registers directly, but I guess that's hard.
Yeah, for hardware registers it isn't too bad, but for local variables and such we don't know the addresses at compile time, they get computed later (during the second assembly pass). I guess what might make sense is to pass DEBUG() statements in inline assembler through to the .p2asm file, but that's also a lot of work.
Yay!! Successfully plugged into the new block device system. No longer need to duplicate all the sources in include/filesys/fatfs/*
Primarily, I've added a new set of entries to fatfs_vfs.c: Building _vfs_open_sdsdcard() and _sdsd_open() which was a case of duplicating and editing. And duplicated the related interfacing functions from sdmm.cc into my driver.
Also added the usual line to include/sys/vfs.h but I note it says that that is now legacy. Which I presume means there is a new method of mounting at the application level.
Card User Capacity = 122240 MiB
SD clock divider set to sysclock/3 (100.0 MHz)
CID decode: ManID=1B OEMID=SM Name=ED2S5
Ver=3.0 Serial=49C16906 Date=2023-2
Buffer = 2 kB, Written 2048 kB at 693 kB/s, Verified, Read 2048 kB at 5617 kB/s
Buffer = 2 kB, Written 2048 kB at 709 kB/s, Verified, Read 2048 kB at 6294 kB/s
Buffer = 2 kB, Written 2048 kB at 708 kB/s, Verified, Read 2048 kB at 6248 kB/s
Buffer = 2 kB, Written 2048 kB at 706 kB/s, Verified, Read 2048 kB at 6093 kB/s
Buffer = 4 kB, Written 2048 kB at 1479 kB/s, Verified, Read 2048 kB at 10349 kB/s
Buffer = 4 kB, Written 2048 kB at 1484 kB/s, Verified, Read 2048 kB at 10256 kB/s
Buffer = 4 kB, Written 2048 kB at 1485 kB/s, Verified, Read 2048 kB at 9975 kB/s
Buffer = 4 kB, Written 2048 kB at 1475 kB/s, Verified, Read 2048 kB at 10839 kB/s
Buffer = 8 kB, Written 4096 kB at 2771 kB/s, Verified, Read 4096 kB at 15766 kB/s
Buffer = 8 kB, Written 4096 kB at 2518 kB/s, Verified, Read 4096 kB at 13256 kB/s
Buffer = 8 kB, Written 4096 kB at 3079 kB/s, Verified, Read 4096 kB at 14922 kB/s
Buffer = 8 kB, Written 4096 kB at 2610 kB/s, Verified, Read 4096 kB at 15105 kB/s
Buffer = 16 kB, Written 4096 kB at 4725 kB/s, Verified, Read 4096 kB at 21335 kB/s
Buffer = 16 kB, Written 4096 kB at 4184 kB/s, Verified, Read 4096 kB at 18438 kB/s
Buffer = 16 kB, Written 4096 kB at 4317 kB/s, Verified, Read 4096 kB at 17385 kB/s
Buffer = 16 kB, Written 4096 kB at 4191 kB/s, Verified, Read 4096 kB at 21988 kB/s
Buffer = 32 kB, Written 8192 kB at 7168 kB/s, Verified, Read 8192 kB at 26483 kB/s
Buffer = 32 kB, Written 8192 kB at 6592 kB/s, Verified, Read 8192 kB at 29698 kB/s
Buffer = 32 kB, Written 8192 kB at 6726 kB/s, Verified, Read 8192 kB at 26936 kB/s
Buffer = 32 kB, Written 8192 kB at 6574 kB/s, Verified, Read 8192 kB at 24237 kB/s
Buffer = 64 kB, Written 8192 kB at 7097 kB/s, Verified, Read 8192 kB at 28950 kB/s
Buffer = 64 kB, Written 8192 kB at 6687 kB/s, Verified, Read 8192 kB at 25075 kB/s
Buffer = 64 kB, Written 8192 kB at 6677 kB/s, Verified, Read 8192 kB at 28660 kB/s
Buffer = 64 kB, Written 8192 kB at 6605 kB/s, Verified, Read 8192 kB at 25670 kB/s
Buffer = 128 kB, Written 16384 kB at 7552 kB/s, Verified, Read 16384 kB at 27048 kB/s
Buffer = 128 kB, Written 16384 kB at 6777 kB/s, Verified, Read 16384 kB at 27317 kB/s
Buffer = 128 kB, Written 16384 kB at 7063 kB/s, Verified, Read 16384 kB at 28143 kB/s
Buffer = 128 kB, Written 16384 kB at 6695 kB/s, Verified, Read 16384 kB at 29083 kB/s
Buffer = 256 kB, Written 16384 kB at 7048 kB/s, Verified, Read 16384 kB at 29500 kB/s
Buffer = 256 kB, Written 16384 kB at 6608 kB/s, Verified, Read 16384 kB at 29835 kB/s
Buffer = 256 kB, Written 16384 kB at 7186 kB/s, Verified, Read 16384 kB at 29532 kB/s
Buffer = 256 kB, Written 16384 kB at 6529 kB/s, Verified, Read 16384 kB at 29696 kB/s
EDIT2: But also a smidgin slower across the board at reads. Presumably due to more bloat layers. EDIT3: Err, the difference is from the clock speed. 100 MHz here vs 120 MHz in the earlier case.
With those warnings sorted, I've now eliminated the group of extern register allocation in cogRAM. And moved the preset parameters within Fcache range instead.
If you mean, the spin2 constants can't be used for some "constant-y" things like declaring array sizes, then yes, that's true. Unfortunately it's true even for C constants declared like const int x = 4. C doesn't trust consts to actually remain constants.
@evanh said:
Yay!! Successfully plugged into the new block device system. No longer need to duplicate all the sources in include/filesys/fatfs/*
... compared with a run under the old FAT FS it's three times faster on small buffer sizes - https://forums.parallax.com/discussion/comment/1562223/#Comment_1562223
Here's the new block write sequence for 2 x 128 kB buffer.
The big plus now is the filesystem layer no longer makes the single writes at the end of each write() function call. Having the buffer matching the cluster size is optimal.
Speed Class = C0 UHS Grade = U0 Video Class = V0 App Class = A0
Card User Capacity = 1962 MiB
SD clock divider set to sysclock/4 (80.0 MHz)
CID decode: ManID=1D OEMID=AD Name=SD
Ver=1.0 Serial=A15002BA Date=2007-5
Buffer = 2 kB, Written 2048 kB at 4652 kB/s, Verified, Read 2048 kB at 10364 kB/s
Buffer = 2 kB, Written 2048 kB at 4672 kB/s, Verified, Read 2048 kB at 10402 kB/s
Buffer = 2 kB, Written 2048 kB at 4685 kB/s, Verified, Read 2048 kB at 10422 kB/s
Buffer = 2 kB, Written 2048 kB at 4685 kB/s, Verified, Read 2048 kB at 10429 kB/s
Buffer = 4 kB, Written 2048 kB at 5338 kB/s, Verified, Read 2048 kB at 14250 kB/s
Buffer = 4 kB, Written 2048 kB at 5330 kB/s, Verified, Read 2048 kB at 14258 kB/s
Buffer = 4 kB, Written 2048 kB at 5362 kB/s, Verified, Read 2048 kB at 14271 kB/s
Buffer = 4 kB, Written 2048 kB at 5334 kB/s, Verified, Read 2048 kB at 14276 kB/s
Buffer = 8 kB, Written 4096 kB at 6021 kB/s, Verified, Read 4096 kB at 17551 kB/s
Buffer = 8 kB, Written 4096 kB at 5994 kB/s, Verified, Read 4096 kB at 17567 kB/s
Buffer = 8 kB, Written 4096 kB at 6004 kB/s, Verified, Read 4096 kB at 17575 kB/s
Buffer = 8 kB, Written 4096 kB at 6024 kB/s, Verified, Read 4096 kB at 17584 kB/s
Buffer = 16 kB, Written 4096 kB at 6414 kB/s, Verified, Read 4096 kB at 19450 kB/s
Buffer = 16 kB, Written 4096 kB at 6404 kB/s, Verified, Read 4096 kB at 19454 kB/s
Buffer = 16 kB, Written 4096 kB at 6439 kB/s, Verified, Read 4096 kB at 19459 kB/s
Buffer = 16 kB, Written 4096 kB at 6437 kB/s, Verified, Read 4096 kB at 19461 kB/s
Buffer = 32 kB, Written 8192 kB at 9044 kB/s, Verified, Read 8192 kB at 20588 kB/s
Buffer = 32 kB, Written 8192 kB at 9062 kB/s, Verified, Read 8192 kB at 20610 kB/s
Buffer = 32 kB, Written 8192 kB at 9068 kB/s, Verified, Read 8192 kB at 20616 kB/s
Buffer = 32 kB, Written 8192 kB at 9031 kB/s, Verified, Read 8192 kB at 20627 kB/s
Buffer = 64 kB, Written 8192 kB at 9060 kB/s, Verified, Read 8192 kB at 20625 kB/s
Buffer = 64 kB, Written 8192 kB at 9066 kB/s, Verified, Read 8192 kB at 20636 kB/s
Buffer = 64 kB, Written 8192 kB at 9084 kB/s, Verified, Read 8192 kB at 20646 kB/s
Buffer = 64 kB, Written 8192 kB at 9068 kB/s, Verified, Read 8192 kB at 20654 kB/s
Buffer = 128 kB, Written 16384 kB at 9062 kB/s, Verified, Read 16384 kB at 20670 kB/s
Buffer = 128 kB, Written 16384 kB at 9025 kB/s, Verified, Read 16384 kB at 20686 kB/s
Buffer = 128 kB, Written 16384 kB at 9020 kB/s, Verified, Read 16384 kB at 20701 kB/s
Buffer = 128 kB, Written 16384 kB at 9005 kB/s, Verified, Read 16384 kB at 20700 kB/s
Buffer = 256 kB, Written 16384 kB at 9916 kB/s, Verified, Read 16384 kB at 20712 kB/s
Buffer = 256 kB, Written 16384 kB at 9921 kB/s, Verified, Read 16384 kB at 20720 kB/s
Buffer = 256 kB, Written 16384 kB at 9936 kB/s, Verified, Read 16384 kB at 20732 kB/s
Buffer = 256 kB, Written 16384 kB at 9910 kB/s, Verified, Read 16384 kB at 20743 kB/s
PS: I mean I'm worried I've messed up and this isn't real. It feels too good to be true.
EDIT: I can't see anything wrong with the test. I revised it just now to ensure random data throughout every file written. No two files the same and no repetition in the files. Read back is after each file completely written, then 100% verified to contain the exact random data that was written, end to end, no skipped blocks.
PPS: The speed test normally repeats the buffer content over and over to the end of each file.
Eric,
Is there any examples of using ioctl() at the application level? Does it even function at that level in FlexC? I'm interested in making driver and SD card stats discoverable. Maybe move the clock divider away from being an init parameter. Do mode changes for changing use like loading with CRC enabled then later without.
PS: I've never written any such code anywhere, so am complete novice. Linux examples don't look all that applicable here.
@evanh said:
Eric,
Is there any examples of using ioctl() at the application level? Does it even function at that level in FlexC? I'm interested in making driver and SD card stats discoverable. Maybe move the clock divider away from being an init parameter. Do mode changes for changing use like loading with CRC enabled then later without.
PS: I've never written any such code anywhere, so am complete novice. Linux examples don't look all that applicable here.
There's not much to say about ioctl(): it's just called like:
r = ioctl(fd, cmd, buffer);
where fd is the file handle returned by open(), cmd is some arbitrary integer that the driver will recognize, and buffer is a pointer to the input and/or output data for the command. The library layers do nothing with any of this except to figure out which driver corresponds to the file and pass the arguments through to the vfs layer for that file. This is the same setup as Linux. The only ioctl used by the main C library is TTYIOCTLGETFLAGS used to determine if a file is a terminal or not. We also use ioctl internally in the littlefs file system driver, where the command BLKIOCTLERASE is issued to erase blocks; if that ioctl fails (returns -1) then we fall back to writing 0xff over the block instead.
fatfs has some ioctls internally for getting info about the disk. In the new setup these get passed through to the underlying file. I don't think anything except the SD card driver recognizes these ioctls, but I think they only matter if you're formatting the disk -- at least, the failure of ordinary files to respond to the SD card ioctls doesn't prevent FAT images from being mounted.
@ersmith said:
fatfs has some ioctls internally for getting info about the disk. In the new setup these get passed through to the underlying file. I don't think anything except the SD card driver recognizes these ioctls, but I think they only matter if you're formatting the disk -- at least, the failure of ordinary files to respond to the SD card ioctls doesn't prevent FAT images from being mounted.
Ah, I am getting something new now, I'd removed the file handle earlier and not noticed I left it that way. My old attempt always returned errno -1: Unknown error. Now I get 5: Bad file number. Oh, and a compiler warning of warning: mixing pointer and integer types in parameter passing: expected int but got pointer to _struct___dir So I guess I need to open a file rather than a directory? Is that an int type? I open the directory so as to kick the mounting process into gear because mount() doesn't do anything.
static void mountsd( void )
{
DIR *fh;
umount("/sd");
puts("Filesystem = fatfs, Driver = sdsdcard");
mount("/sd", _vfs_open_sdsdcard(CLK_DIV, PIN_CLK, PIN_CMD, PIN_DAT0, PIN_POW, PIN_LED));
errno = 0;
fh = opendir("/sd/."); // doesn't set errno on success ... which is standard!
perror("mount sd");
if( !fh )
exit(1); // requires #include <errno.h>
uint8_t *buff = __builtin_alloca(20); // auto-frees upon return
errno = 0;
ioctl(fh, 0, buff); // Attempting to trigger a CTRL_SYNC in the SD device driver
printf(" ioctl %d: %s\n", errno, strerror(errno));
closedir(fh);
}
I tried opening the device but that kept returning errno 4: No such file or directory, so I created a file instead and at least I got an okay from the file open, but still no help with the ioctl():
int fh = open("/sd/test.txt",O_CREAT,O_CREAT);
printf(" open file %d: %s\n", errno, strerror(errno));
uint8_t *buff = __builtin_alloca(20); // auto-frees upon return
errno = 0;
ioctl(fh, 0, buff); // Attempting to trigger a CTRL_SYNC in the SD device driver
printf(" ioctl %d: %s\n", errno, strerror(errno));
close(fh);
@evanh : Yeah, opendir, fopen, and open are all very different, at least in terms of what they return to the caller. For ioctl you need a file handle that comes back from open. I don't think you can open the SDMM device directly as we don't have a way to refer to it by name (we'd have to introduce a /dev type directory for devices, which might be nice but OTOH is kind of niche).
Looking at your code I think it should work, but you're checking errno rather than the returned value from ioctl. errno only has a sensible value if the call failed, which is true only if ioctl returns -1. Otherwise errno is left unchanged and has the last error, which may be pretty much anything. Can you put a debug printf into your version of sdmm.cc to see if the v_ioctl method is being called?
@ersmith said:
... Can you put a debug printf into your version of sdmm.cc to see if the v_ioctl method is being called?
Oops, doh, I thought that was there already. By attempting the same SYNC that appears in my detailed diagnostics for block access order. But that level of debug wasn't enabled ...
No, still the same:
RD0 762946 RD800 764290 RD801 765029 mount sd: OK
RD7f40 766582 RD7f41 767517 open file 0: OK
ioctl -1: Unknown error
Comments
Infact, I spend so long staring that I forgot to check that it actually, uh, works?
Which.. it doesn't.... (built with current flexspin master, no funny PRs - note how it just speeds through the file loading way too fast)
Sent a PR to fix the FS working at all when used from Spin.
Also, wrt. buffering, I took a look:
In either case the current buffer implementation that only sits on getc/putc needs to be removed and possibly replaced by something called into from the 9P/LFS VFS implementations (so it catches all v_write/v_read calls and doesn't need stupid flushing everywhere)
@Wuerfel_21 The internal buffering of FatFS is OK for reading (only about twice as slow as the stdio buffering; not great, but bearable). But for writing? It's very bad. Calling the FatFS write routine with 1 byte is about 1000 times slower than fputc(). And yes, doing 1 byte writes is a bad idea, but a lot of programs do it: fgetc/fputc are really widely used. Hence the need for buffering.
Are you sure you tested that correctly? (i.e. no unnecessary f_sync or such inbetween). There should be a fast-ish path through f_write when it's just appending to the buffer, just a few checks and a memcpy. 1000x slower sounds like buffer is being erroneously flushed on every call.
Also, if you're doing performance metrics, fun things to try:
I'm confused about the cogstart function in C.
int cogstart(void (*func)(void *), void *arg, void *stack, size_tstacksize);
It shows the stack as size_tstacksize but what size is it. Is it in bytes or words?
int Stack[50];
cogstart(function, NULL, Stack, 50);
Maybe you could update the help docs as well.
Mike
Neither, it just gets ignored:
There was some effort to harmonize the C API between compilers and I guess some need to know the stack size.
I think it's ostensibly supposed to be bytes.
@Wuerfel_21 if that was true then my code would not crash when it runs out of stack space and I make the number bigger and it works again.
Mike
@iseries the actual size of the stack can matter for sure. But, from the @Wuerfel_21 code above seems what you tell it is the size doesn’t matter.
Are you seeing that it does? That would be hard to explain…
In FlexC the
stacksize
parameter is ignored, the size of the array passed in forstack
is used directly. In other compilers I believe the stacksize is in bytes.Eric,
A couple of issues:
-0
suffix, but not the subsequent assembler warnings.EDIT: Hmm, me now wonders if the two are related in that the extraneous instruction is the compiler's broken attempt to suppress assembler warnings.
@evanh
(1) You can add
-Wno-asm-usage
to the command line to suppress warnings about assembly constructs. I guess this should always be set for the second pass of the assembler, I'll change that.(2) What version of flexspin are you using? I don't see the
mov 0-0, pa
that you reported, just fourmov pa, XXX
whereXXX
are the various constants.The warnings are gone now. The compiler build was a month old -
Version 7.0.0-beta-v6.9.7-67-g479049f9 Compiled on: Oct 14 2024
Latest build is
Version 7.0.0-beta2-v6.9.7-90-gcb2ee721 Compiled on: Nov 18 2024
EDIT: Oh, weirdly, the code oddity is still there though.
Maybe it's a debug issue. Compiled without debug looks fine. So I was really only fighting the warnings historically. The oddity with MOV 0-0,PA I've only just noticed.
@evanh : The inserted
mov 0-0, pa
instructions are indeed due to debugging. In general printing debug expressions requires copying the value to a register. In this particular case the value is already in a register so it isn't necessary, but the code that generates debug is not very smart and just always follows the same path. Basically debug() in inline assembly inside spin2 functions isn't very efficient (and also modifies the first few longs of COG memory, which is potentially a problem).I've fixed this particular case in github.
Thanks.
And I always looked at that and was like "wait that can't be right". It'd be better to make it grab the correct registers directly, but I guess that's hard.
Yeah, for hardware registers it isn't too bad, but for local variables and such we don't know the addresses at compile time, they get computed later (during the second assembly pass). I guess what might make sense is to pass DEBUG() statements in inline assembler through to the .p2asm file, but that's also a lot of work.
Yay!! Successfully plugged into the new block device system. No longer need to duplicate all the sources in include/filesys/fatfs/*
Primarily, I've added a new set of entries to fatfs_vfs.c: Building _vfs_open_sdsdcard() and _sdsd_open() which was a case of duplicating and editing. And duplicated the related interfacing functions from sdmm.cc into my driver.
Also added the usual line to include/sys/vfs.h but I note it says that that is now legacy. Which I presume means there is a new method of mounting at the application level.
EDIT: And getting improved write performance too ... compared with a run under the old FAT FS it's three times faster on small buffer sizes - https://forums.parallax.com/discussion/comment/1562223/#Comment_1562223
EDIT2: But also a smidgin slower across the board at reads. Presumably due to more bloat layers. EDIT3: Err, the difference is from the clock speed. 100 MHz here vs 120 MHz in the earlier case.
With those warnings sorted, I've now eliminated the group of
extern register
allocation in cogRAM. And moved the preset parameters within Fcache range instead.@ersmith Looks like if one's main code is C and include a Spin2 driver, that you can't read the constants in the driver. Is this right?
Do see one can override the constants in the driver though, maybe that's just as good.
It seems to work for me:
Prints 42.
If you mean, the spin2 constants can't be used for some "constant-y" things like declaring array sizes, then yes, that's true. Unfortunately it's true even for C constants declared like
const int x = 4
. C doesn't trust consts to actually remain constants.Ok thanks, yes was trying to declare array. I just move this to main C file with #define now..
Here's the new block write sequence for 2 x 128 kB buffer.
And subsequent double read back for verify then read speed:
The big plus now is the filesystem layer no longer makes the single writes at the end of each write() function call. Having the buffer matching the cluster size is optimal.
Oh, wow! That ancient 2GB SDSC camera card is a 100 times faster at small buffer writes now! Compare to https://forums.parallax.com/discussion/comment/1562889/#Comment_1562889
PS: I mean I'm worried I've messed up and this isn't real. It feels too good to be true.
EDIT: I can't see anything wrong with the test. I revised it just now to ensure random data throughout every file written. No two files the same and no repetition in the files. Read back is after each file completely written, then 100% verified to contain the exact random data that was written, end to end, no skipped blocks.
PPS: The speed test normally repeats the buffer content over and over to the end of each file.
Eric,
Is there any examples of using ioctl() at the application level? Does it even function at that level in FlexC? I'm interested in making driver and SD card stats discoverable. Maybe move the clock divider away from being an init parameter. Do mode changes for changing use like loading with CRC enabled then later without.
PS: I've never written any such code anywhere, so am complete novice. Linux examples don't look all that applicable here.
There's not much to say about ioctl(): it's just called like:
where
fd
is the file handle returned by open(),cmd
is some arbitrary integer that the driver will recognize, andbuffer
is a pointer to the input and/or output data for the command. The library layers do nothing with any of this except to figure out which driver corresponds to the file and pass the arguments through to the vfs layer for that file. This is the same setup as Linux. The only ioctl used by the main C library isTTYIOCTLGETFLAGS
used to determine if a file is a terminal or not. We also useioctl
internally in the littlefs file system driver, where the commandBLKIOCTLERASE
is issued to erase blocks; if that ioctl fails (returns -1) then we fall back to writing 0xff over the block instead.fatfs has some ioctls internally for getting info about the disk. In the new setup these get passed through to the underlying file. I don't think anything except the SD card driver recognizes these ioctls, but I think they only matter if you're formatting the disk -- at least, the failure of ordinary files to respond to the SD card ioctls doesn't prevent FAT images from being mounted.
Ah, I am getting something new now, I'd removed the file handle earlier and not noticed I left it that way. My old attempt always returned errno -1: Unknown error. Now I get 5: Bad file number. Oh, and a compiler warning of
warning: mixing pointer and integer types in parameter passing: expected int but got pointer to _struct___dir
So I guess I need to open a file rather than a directory? Is that an int type? I open the directory so as to kick the mounting process into gear because mount() doesn't do anything.Ooooo, open() is not fopen() ...
I tried opening the device but that kept returning
errno 4: No such file or directory
, so I created a file instead and at least I got an okay from the file open, but still no help with the ioctl():@evanh : Yeah,
opendir
,fopen
, andopen
are all very different, at least in terms of what they return to the caller. Forioctl
you need a file handle that comes back fromopen
. I don't think you can open the SDMM device directly as we don't have a way to refer to it by name (we'd have to introduce a/dev
type directory for devices, which might be nice but OTOH is kind of niche).Looking at your code I think it should work, but you're checking
errno
rather than the returned value fromioctl
.errno
only has a sensible value if the call failed, which is true only ifioctl
returns -1. Otherwiseerrno
is left unchanged and has the last error, which may be pretty much anything. Can you put a debug printf into your version of sdmm.cc to see if thev_ioctl
method is being called?Oops, doh, I thought that was there already. By attempting the same
SYNC
that appears in my detailed diagnostics for block access order. But that level of debug wasn't enabled ...No, still the same: