SD library in C
DavidZemon
Posts: 2,973
I am trying to write an SD library using my generic SPI library and it isn't going well. Most of the time, I get 0x01 from CMD0, but I have yet to get anything other than 0xff or 0x7f as the first byte from CMD8. I've tried referencing fsrw and safe_spi but, as far as I can tell, I'm doing the same thing.
What could cause me to receive 0x01 from CMD0 followed by an invalid response from CMD8?
Code can be found here and the relevant files are SD_Driver.*, sd.*, and maybe spi* but I believe the SPI library is working.
https://github.com/SwimDude0614/PropWare
Thanks,
David
What could cause me to receive 0x01 from CMD0 followed by an invalid response from CMD8?
Code can be found here and the relevant files are SD_Driver.*, sd.*, and maybe spi* but I believe the SPI library is working.
https://github.com/SwimDude0614/PropWare
Thanks,
David
Comments
Anyway, CMD9 is responding with 0x01 as the first byte... it's idle. Why? The only issue I'm noticing is that there's a weird hickup in MISO a little before the half-way point of the argument.
After I receive 0x01 as the first byte, an error is thrown and the program quits. I commented out that debug line once and only ever received 0xff following the idle response , making me think that the 0x01 response is not a fluke - it truly is in the idle state.
A snapshot of only CMD9 can be found here, and the complete file (type VCD) can be found here.
(Sorry chip select isn't there. I only have two probes at the moment and had to use a jumper wire just to get the third signal. Two more probes have been ordered...)
Also, I guess I forgot to update this thread - I changed the git repository completely and reorganized. The new link is here and in the first post.
I would be interested in the opinions of some other developers on a specific question though. One of the things I like about C/C++ is header files, and how perfect they are for documentation. I like having pre-processor definitions, function prototypes (and function docs) and various other things in the header because it creates a separation that allows for each searching/finding. However, I was recently introduced to the idea of "private" functions in C by placing the prototypes in the source file (as opposed to header) which imply that those functions are therefore inaccessible from other files. Seemed brilliant and I have used this method for PropWare so far. The bad news though, is that it has destroyed some of the readability and searchability of my code. For instance, the first executable line of sd.c is line 250+; past definitions, global variable declarations and function documentation/prototypes.
What would you suggest I do? Forget about having "private" functions? Accept the decrease in readability and leave it as is? Create a second header file for private information? Another option?
You might also want to use some naming convention for you public interfaces like prefixing all function names. for exaample:
int SDSD_mount(....):
Then we all know this function belongs to SwimDudes SD library and is less likely to conflict with other libraries we might use.
You will only need prototypes for some very few special cases:
a) Recursive functions
b) Functions calling each other (this is pretty rare)
So, for your 'top down' coding, start by implementing the 'top' function, then keep placing the more detailed functions above that one in the source file.
And obviously this will lead to 'main()' being at the bottom of the file, which is why you see that so often.
My files generally look as follows:
Include statements for system header files
Include statements for other, non-system header files (e.g. my other libraries)
Include statements for local header files (these will typically have prototypes for my non-static functions)
static variables, if any
static functions (i.e. private to this file), nicely sorted so that they self-prototype.
public functions, and prototypes for these are in one of the local header file(s) included above
(The reason I call it 'self-prototyping' is that the compiler will check the parameters just as if you had actual prototypes. Just like a Pascal compiler would, as Pascal programs are generally laid out the same way, with the callee function above the caller function).
-Tor
-Tor
But wait a minute, if you have all your functions defined in your C file before they are used (a good idea) why have any static function declarations in you header either?
It's a contradiction, the header file says "look I have these functions" and the "static" says "but you are not allowed to use them.
Things get a bit more complex if you library is big enough to warrant living in multiple C files. Then you might want a second header file declaring all the private functions that are shared between files and cannot be static.
The only items I put in header files are prototypes for public functions (and I slap an 'extern' on them too), and #defines for constants and macros.
And if I used global variables (which I don't) they would be declared as'extern int glob_var;' in a header file. If I used global variables.. which I don't.
-Tor
"For external declarations the default storage class specifier will be extern and for internal declarations it will be auto. The only exception to this rule is the declaration of functions, whose default storage class specifier is always extern." http://publications.gbdirect.co.uk/c_book/chapter8/declarations_and_definitions.html
"Internal" library functions (shared between functions in the library, but not with the user of the library) I obviously declare in header files, the difference between these header files and the "public" header files is that my 'make install' target won't copy those header files into the public
'include/ ' directory. So they stay in the directory/directories where the library source is, they'll never migrate to /usr/include/ or the equivalent place on whatever target it is.
Of course C has this slightly weak spot that these non-public, but non-static functions are still visible in the global namespace.. and could be accessed by someone using the library even though they are meant for library-internal use. The user would be without the prototypes and would have to figure out how to use the functions (and maybe writing their own protoptypes). And, seen from the library writer point of view, you should think about namespace pollution and not give function names that may collide with something else to your internal, but non-static functions. Don't call them sort() or compare(), for example.. better use e.g. tf_lib_internal_sort() or something.
-Tor
(sorry about a couple of spurious line shifts in the above, the forum software sometimes won't let me delete empty lines when I'm in the Android browser)
-Tor
I like the idea of static functions. It was not something I was previously aware of. Also, as I mentioned earlier, I like the idea of documentation for functions staying in the header file(s) and, for that, it makes sense to have prototypes in the headers. Results: I've done as Heater first suggested and moved definitions and prototypes to the header file, at the bottom, with functions be preceded by the static keyword. (Thankfully, I was already aware of the static keyword for variables.)
I also began the implementation of SPIShiftIn_fast and *Out_fast. I like how fsrw and SD_MMC_FATEngine use the counter module, so that's my end goal. For now, I've simply created routines that do not call another asm function to clock out, but rather call "xor" twice in a row.
Also, any way a moderator could change the thread title to "PropWare - Generic C library files"?
Unfortunately... it's extremely slow. With all debugging turned off and using my SPIShiftIn_fast routine, it took many minutes (I didn't time it, but I think ~5) to read an 8 MB mp3 file. When I have time, SPI speed will be the first thing I optimize. Specifically, an entire GAS routine that reads a block and writes it to HUB memory one long at a time.
I've also recorded the code size of the SD demo with various options enabled/disabled. Here are the results:
I'm not entirely happy with this. It wasn't but a couple days ago that, without any options enabled, CMM mode was around 5k. This also does not include write functionality, and I know that's going to add a significant chunk of code.
Now I have two big things I'd like to fix when I'm done with the necessary functions: 1) read/write speed, 2) code size.
This most recent update has added a few new functions: SDfputc, SDfputs, SDftellw, SDftellr, SDfseekw, and SDfseekr. The tell* and seek* are for the independent read and write pointers. I know that isn't quite POSIX standard, but until I'm done with senior design (it's more useful to me this way), that's how it's going to stay.
I also found a stupid mistake in my option definitions and the code size has been updated below to reflect it (namely, the shell is a lot smaller) :
I wasn't planning on doing this for my project but an overall simplification required that I be able to append to and create new files.
I'll update with code sizes later... it's grown quite a bit. Good news is, if you don't need to write to files, you can disable that option and the code size should remain very similar to the numbers listed in my previous post.
As always, code available here: https://github.com/SwimDude0614/PropWare
1) I'm starting the implementation of Doxygen for PropWare. Current progress (based on the master branch of the git repo) can be found here: http://david.zemon.name/professional/PropWare/docs/html/
2) I realized the stupidity of my ways and am now compiling PropWare into a static library. Progress on this has been moved to the development branch (https://github.com/SwimDude0614/PropWare/tree/development)
When I attempt to build the SPI demo, I get undefined reference errors. Does anyone know why? I'll post full output from the library compilation in a reply to this post.
Now the linker can't find my assembly (spi_as.S).
To get "__load_start_spi_as_cog" it seems that you need this: .section .spi_as_cog, "ax"
Add -Xlinker -MAP=map_file to your gcc line so you can see all symbols in map_file.
SimpleIDE has a "Show Map File" command that does this for us.
Symbols like __load_start_* are always at the end of the map file.
I'm not 100% sure what your suggestion was with the map file, but I added the arguments to the linker flags and here's the output now when I attempt to build SPI_Demo.elf. The output when building the library hasn't changed (because it's not running the linker)
(I've pushed the changes to common.mk and spi_as.S)
I'm guessing that's where I *should* see "__load_start_spi_as_cog"?
I've done some renaming and it didn't help any. Here's the new map: And yet, it still complains
To make it work, I had to do this:
Change all #include <PropWare.h> and other local includes to use non-default library syntax as #include "PropWare.h"
Add a main to your PropWare.c file.
Change your make file to look like this:
Also - the directory structure might look a little weird as I have it in the git repo. I'm a fan of Eclipse and Eclipse likes to do its builds in a "Debug" folder beneath the root directory. Henceforth why I defined PROPWARE_PATH as ".." in PropWare/Makefile
I've shown you how to successfully build using the tools provided. It's up to you to apply it however you like.
Am I missing something?
My end goal here is not to build SPI_Demo.elf. I want to create a large library full of functions that makes the Propeller as easy to use as Arduino. If I can get this working (and I know, I have a LOT of work left in a lot more areas than just expanding the number of modules), then this ought to make the Propeller more powerful than Arduino, with just as much versatility (module files like spi.c and hd44780.c), just as easy to use, with an IDE (Eclipse) that isn't complete garbage (Arduino)