C & GAS SPI library
DavidZemon
Posts: 2,973
After some initial Googling, I was unable to find a SPI library written in C/GAS. So, I've begun writing my own. I used obex #433 (SPI Spin - Serial Peripheral Interface) for my inspiration and it is largely compatible with it (constants like MSB_FIRST are the same and, for the most part, parameters remain the same).
My goal with this library is to have a good compromise between fast and safe. I think I've done a good job with that by allowing the programmer to choose between fast and safe and it's made debugging the code much easier.
You can find the SPI code (spi.c, spi.h, and spi_as.S) in my git repository here. The driver program is an ongoing attempt to make an SD library and is not yet stable.
I am unsure of the robustness at this point, but I have been able to (sometimes) get the first R1 response from the SD card which makes me think the SPI library might be working correctly. My next step is to switch to inline assembly stored in FCACHE.
Thoughts and comments are welcome! I'd love to get some criticism on the code so I can make it even better!
David
My goal with this library is to have a good compromise between fast and safe. I think I've done a good job with that by allowing the programmer to choose between fast and safe and it's made debugging the code much easier.
You can find the SPI code (spi.c, spi.h, and spi_as.S) in my git repository here. The driver program is an ongoing attempt to make an SD library and is not yet stable.
I am unsure of the robustness at this point, but I have been able to (sometimes) get the first R1 response from the SD card which makes me think the SPI library might be working correctly. My next step is to switch to inline assembly stored in FCACHE.
Thoughts and comments are welcome! I'd love to get some criticism on the code so I can make it even better!
David
Comments
You may want to buy a simple SPI device to test it out with, and go from there. If you really do want to use the SD card, perhaps the easiest option would be to convert FSRW, and replace safe_spi with your version of the SPI. Then, you don't have to worry about the FAT stuff.
Also, the change suggested by kuroneko was implemented.
If I can get the first R1 response from an SD card, I'll call v1.0 complete.
Ah! I was looking for two instructions like rcr/rcl but apparently not hard enough. That'll do much nicer
I'm going through SPIShiftIn() now trying to get it to at least run without errors. I definitely should have done that before posting tonight lol
Also, I fixed the djnz instructions in READ. They all pointed back to msb_pre
The status of the MISO pin seems to have no affect on the value being read (always reads 0, even when shorted to Vcc). Not sure what that's about yet but I'll continue poking around tomorrow.
I'm glad you asked: I wrote a short tutorial on that here: https://sites.google.com/site/propellergcc/documentation/tutorials/inline-asm-basics
To get the best timing, you should put the SPI loop in FCACHE.
@SRLM: That's a very well written tutorial; thanks. I'm going to continue a bit more work on the SD side of things and then go back and make the changes you suggested with inline GAS and FCACHE.
https://github.com/SwimDude0614/PropGCC_SPI
For a long while, I was getting 0x7F as the first-byte response to CMD8. Not sure when exactly it it changed, but now I'm just getting a timeout during the first-byte read.
During the debugging I tried one specific suggestion: send CMD0 multiple times. This resulted in successful first read (same as always) but unsuccessful (timed out) second read every time.
@SRLM: fsrw was actually where I started with this whole thing. I wanted to do exactly what you suggested and just replace safe_spi. Unfortunately, for the life of me I can not figure out where fsrw does it's initialization. I've looked at both mount_explicit() and init() and neither seems to do anything with SPI. Without knowing where the SPI calls are, I can't replace them. Or even use it as a code reference (until I get past the initialization).
On the bright side, I hooked it up to a DAC and was able to (fix a bug and) confirm that SPIShiftOut() works correctly! I was able to create and measure a saw-tooth wave from the DAC so that's at least a small accomplishment there.
Still odd things with the SD card though. I have an ADC that would, seemingly, be easier to test SPIShiftIn() with but I haven't been able to get it working and I don't know if it's because I burnt the chip a year ago or if my library is incorrect
Git repository updated.
Hooked it up to an ARM board running in slave mode and I'm able to send/receive at 1.5 MHz with debugging turned on and 1.9 MHz without debugging. The test program was simply
As soon as I increased speed to 1.91 MHz, it had a hissy-fit. This is probably something I can fix later but for now, I'm off to continue down the road of the SD card as my senior project relies on it.
Thanks again for all the help debugging this thing! I would like opinions though - is this something worth submitting to the obex once I give it another once-over and finish up documentation?
David
Congrats!
Maybe we can put what you have into the propeller-gcc demos.
I certainly don't mind, but the project should be re-written before that happens. The spi* files are okay but the driver needs to be cleaned up.
I think, and I hope, it is all much better labeled and explained that previously.
https://github.com/SwimDude0614/PropWare
Interesting work so far. I like your documentation style. You only need a few changes for Doxygen to make html pages.
I noticed you mentioned private functions, but did not make them private by using the static keyword.
Looks good, but I did not make a detailed study of all functions.
Generally, I think the work is a very nice coding example.
I'm glad you like it - making readable code is something I've been working very hard on this past year, and not something we are taught in school. I picked up on the format by reading APIs like TI's StellarisWare (henceforth, "PropWare"). Didn't realize it was part of an official standard that could auto-generate html. I'll have to look up the rules later and tweak them to make it work.
Re: Private Functions
I also didn't realize there was an official way to make private functions without classes. I was just told at the beginning of this semester about the concept of "private" functions in C by placing the prototypes in the source file instead of header.