PDA

View Full Version : Need help with fast SD card SPI rountines.



Kye
05-30-2010, 11:41 PM
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)



' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
' 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,

pullmoll
05-31-2010, 12:41 AM
Kye said...
I need some help trying to get some SPI rountines for any SD card to work.


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 (http://pmbits.ath.cx/prop/)

Kye
05-31-2010, 09:43 AM
Mmm, that's not what's sopposed to happen. The duty cycle mode makes sure the clock is only high for one clock cycle and then it goes low for like 29 clock cycles after that.

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,

kuroneko
05-31-2010, 05:04 PM
Kye said...
I will probably need lonesock's or kuroneko help on this as I got the idea from their code.

I think you slightly misunderstood the code in the SPI driver, sorry. DUTY mode is not really suitable for arbitrary clock frequencies.
have a look at this thread (http://forums.parallax.com/showthread.php?p=818605) 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

Ariba
05-31-2010, 07:54 PM
Kye

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

Kye
05-31-2010, 11:15 PM
Its nice to be able to slow down the clock becuase then you can reuse the same code for the slow SPI initialization commands.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Nyamekye,