Need help with fast SD card SPI rountines.
Kye
Posts: 2,200
I need some help trying to get some SPI rountines for any SD card to work.
Basically, I made a general purpose SPI function that can run at any speed from 1 to about 3 Mhz. The code for that is below.
... CTRA is set to NCO mode (%00100) and its output is the clock pin.
... The SPITiming is either:
· fastTiming := ((constant(2_968_750 << 9) / clkfreq) << 23)
· slowTiming := ((constant(234_375 << 13) / clkfreq) << 19)
The nice thing about the above piece of code is that I can run the clock at many different speeds and still read the data correctly. However, I need to increase the preformance of my driver and thus I need the above code to go faster.
So after looking through the new FSRW block driver I came up with this below:
... CTRA is set to·Duty mode (%00110) and its output is the clock pin.
... The SPITiming is either:
· fastTiming := ((constant(2_968_750 << 9) / clkfreq) << 23)
· slowTiming := ((constant(234_375 << 13) / clkfreq) << 19)
And with this above code I should be able to go faster than 3Mhz but I still should be able to slow the clock down when I want to at will.
However, the above code does not work with the SD card and refuses to work at all. I do not know what I am doing wrong.
...
I've attached the source code and all the files need to run the demo I'm working on. The file with the SPI rountines is the SD2.0_FATEngine.spin
Thank you for any help,
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Nyamekye,
Basically, I made a general purpose SPI function that can run at any speed from 1 to about 3 Mhz. The code for that is below.
... CTRA is set to NCO mode (%00100) and its output is the clock pin.
... The SPITiming is either:
· fastTiming := ((constant(2_968_750 << 9) / clkfreq) << 23)
· slowTiming := ((constant(234_375 << 13) / clkfreq) << 19)
' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ' Read SPI ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// readSPI mov SPICounter, #8 ' Setup counter to read in 1 - 32 bits. mov SPIDataIn, #0 wc ' mov phsa, #0 ' Start clock low. mov frqa, SPITiming ' readSPILoop waitpne clockPin, clockPin ' Get bit. rcl SPIDataIn, #1 ' waitpeq clockPin, clockPin ' test dataOutPin, ina wc ' djnz SPICounter, #readSPILoop ' Loop. mov frqa, #0 ' Stop clock high. rcl SPIDataIn, #1 ' readSPI_ret ret ' Return. ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ' Write SPI ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// writeSPI mov SPICounter, #8 ' Setup counter to write out 1 - 32 bits. ror SPIDataOut, SPICounter ' mov phsa, #0 ' Start clock low. mov frqa, SPITiming ' writeSPILoop shl SPIDataOut, #1 wc ' Set bit. waitpne clockPin, clockPin ' muxc outa, dataInPin ' waitpeq clockPin, clockPin ' djnz SPICounter, #writeSPILoop ' Loop. mov frqa, #0 ' Stop clock high. or outa, dataInPin ' writeSPI_ret ret ' Return.
The nice thing about the above piece of code is that I can run the clock at many different speeds and still read the data correctly. However, I need to increase the preformance of my driver and thus I need the above code to go faster.
So after looking through the new FSRW block driver I came up with this below:
... CTRA is set to·Duty mode (%00110) and its output is the clock pin.
... The SPITiming is either:
· fastTiming := ((constant(2_968_750 << 9) / clkfreq) << 23)
· slowTiming := ((constant(234_375 << 13) / clkfreq) << 19)
' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ' Read SPI ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// readSPI mov SPICounter, #8 ' Setup counter to read in 1 - 32 bits. mov SPIDataIn, #0 ' mov frqa, SPITiming readSPILoop waitpeq clockPin, clockPin test dataOutPin, ina wc rcl SPIDataIn, #1 djnz SPICounter, #readSPILoop mov frqa, #0 readSPI_ret ret ' Return. ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ' Write SPI ' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// writeSPI mov SPICounter, #8 ' Setup counter to write out 1 - 32 bits. ror SPIDataOut, SPICounter ' mov frqa, SPITiming writeSPILoop shl SPIDataOut, #1 wc muxc outa, dataInPin waitpeq clockPin, clockPin djnz SPICounter, #writeSPILoop mov frqa, #0 or outa, dataInPin writeSPI_ret ret ' Return.
And with this above code I should be able to go faster than 3Mhz but I still should be able to slow the clock down when I want to at will.
However, the above code does not work with the SD card and refuses to work at all. I do not know what I am doing wrong.
...
I've attached the source code and all the files need to run the demo I'm working on. The file with the SPI rountines is the SD2.0_FATEngine.spin
Thank you for any help,
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Nyamekye,
Comments
A quick look at the code tells me that perhaps you're running through the loop multiple times while the waitpeq is true?
The original loop waits until the condition isn't met any longer.
I think you can only try to read (or write) like you try when the clock is running parallel to the loop, i.e. exact same timing, and you use the waitpeq just to synchronize on the falling or rising edge!? In that case you could even put it in front of the loop and just clock the bits in or out.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Pullmoll's Propeller Projects
I'm very sure the code does not lock up, but it also garbles the information.
I will probably need lonesock's or Kuneko help on this as I got the idea from their code.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Nyamekye,
- have a look at this thread as to why 25% DUTY mode is used
- forget about latching onto a single cycle pulse (from a DUTY counter) with a waitpxx in general, I can make it fail reliably (e.g. pin 0 and cog 4, 5MHz/PLL16)a
- if you want higher speeds you have to rely on instruction timings at some point, just make sure you're sync'd to the clock, then transfer the data blind
a most likely the rising edge is delayed slightly longer then the falling one which makes the pulse invisible to the waitpxx logicb, having said that there are cases when the pin/cog combination does work, sometimes too well (double count)b which is odd because it does work with 5MHz/PLL8 so I assume clock jitter may play a role as well
Post Edited (kuroneko) : 5/31/2010 11:01:35 AM GMT
I don't think that such an asymetrical clock matches the specs of an SD card. There will be a minimal high time for the clock greater than 12.5 ns.
Mostly a clock at the higher limit needs to have a duty of near to 50%.
If you not use a counter for the clock, but set and clear the clockpin with assembly instructions you are faster (5 instructions = 4 MHz clock @ 80MHz). The counter is only needed if you want 2 or 1 instruction loops (=10Mhz or 20MHz clock) but then you need also a second counter as multiplexer and shiftregister.
Why do you want to slow down the clock? With 4 or 5 Mhz every SD card should work.
Andy
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Nyamekye,