The P2 ROM has callable routines to boot/access/load/run files from an SD Card formatted as FAT32. However, there are no write routines in the ROM, and only the root directory is supported directly.
For an example, see the Fun with the P2 ROM thread.
I've been working on a version of FSRW2.6 using inline asm. I plan to convert the SDSPI to P2asm but it's very slow going for me. Here's my latest verson (still needs a ton of work)
@Rayman I changed the pin config to match the P2 Eval board, however I just get "Mounting"
cs_pin=60
clk_pin=61
miso_pin=58
mosi_pin=59
Any thoughts about this?
Use the built-in TAQOZ to do a sanity check for you. Just reset and type the three keys [>] [space] [esc] and from TAQOZ type MOUNT. From there you can do a DIR.
If it doesn't work there then it won't work elsewhere.
It's because you're using PortB pins using the old OUTs and DIRs method. If you change the pin instructions to ones that span 64 pins OR sub 32 from pin numbers it should work.
@ke4pjw - yes, that looks like you should skip that ++ method and assign them using basepin as an offset.
You can also test your pin arrangement other than the default with TAQOZ by changing the sdpin constant with this expression:
&60.58.59.61 ' sdpins 2+ !
It's a bit more awkward than it usually is with the cramped ROM space because we are writing directly to the sdpins constant whereas normally we have a word to take care of it easily.
But the syntax is & for a decimal bytes notation (as in IP notation where every group of decimal digits represent a byte) in the sequence CS.MISO,MOSI.CLK and then the tick ' then a space and the name of the constant (sdpins) then 2+ to modify that address to point to the parameter field and then ! to store the new value into the sdpins constant. Just in case you want to double check your original setup.
BTW, the extended TAQOZ implementation of FAT32 includes all the FOPEN type commands, handling a file as virtual memory etc as well as the disk utilities and FORMAT.
I'm not sure if you've gone through my thread, but I wasn't able to get Ray's to work either. I think with the portB replacement macro you'd need to subtract 32 from the pin number to span 0-31.
pri read | r
'
' Read eight bits from the card.
'
r := 0
repeat 8
outa[clk] := 0
outa[clk] := 1
r += r + ina[do]
return r
becomes
pri read | r
'
' Read eight bits from the card.
'
r := 0
repeat 8
outB[clk] := 0
outB[clk] := 1
r += r + inB[do]
return r
Which won't work with pin numbers >31!!
Pretty sure he already fixed the Start_Explicit… at least I have it in mine if you need.
The thread I've got for what I was working on is here;
Right now I'm trying to learn how to start a cog the right way and pass everything, basic asm engine stuff. Once I have a handle on that I plan on using the smart pins. This is my SDSPI using inline asm. It should just replace fsrw2.6 sdspi, although I made some small tweaks to the fsrw file to make things return gracefully. When all the abort code was changed to return there were some edge cases that didn't seem quite right.
{{
SDSPI driver for P2-ES FastSpin/InlineASM RC2
Cheezus Slice (Joe Heinz) - Feb - 2019
Thanks to cluso, ersmith, David Betz, Rayman, Dave Hein
and all the other greats out there in fourm land!
Original spin version by Radical Eye Software Copyright 2008
}}
con
sectorsize = 512
sectorshift = 9
var
long di, do, clk, cs, starttime, sdhc, di_mask, do_mask, clk_mask, do_pin
pri send(outv) | c, i ' Send eight bits, then raise di.
i := di
c := clk
asm
rol outv, #24
rep #.end_send, #8
rol outv, #1 wc
drvl c
drvc i
drvh c
.end_send
drvh i
endasm
pri read : r | c, o ' Read eight bits from the card.
c := clk
o := do
asm
mov r, #0
rep #.end_read, #8
drvl c
waitx #14 '' !! 13 safe for up to 160 mhz, 14 for 320mhz
testp o wc
drvh c
rcl r, #1
.end_read
endasm
pri readresp | r
'' made return timeout to caller CHZ 2-2019
' Read eight bits, and loop until we
' get something other than $ff.
'
repeat
if (r := read) <> $ff
return r
if checktime == -41
return -41
pri busy | r ' Wait until card stops returning busy
'' made return timeout to caller CHZ 2-2019
'
repeat
if (r := read)
return r
if checktime == -41
return -41
pri checktime ' Did we go over our time limit yet?
{
if cnt - starttime > clkfreq
return -41'abort -41 ' Timeout during read
}
pri cmd(op, parm)
'
' Send a full command sequence, and get and
' return the response. We make sure cs is low,
' send the required eight clocks, then the
' command and parameter, and then the CRC for
' the only command that needs one (the first one).
' Finally we spin until we get a result.
DRVL_(cs)
read
send($40+op)
send(parm >> 24)
send(parm >> 16)
send(parm >> 8)
send(parm << 0)
if (op == 0)
send($95)
else
send($87)
return readresp
pri endcmd ' Deselect the card to terminate a command.
drvh_(cs) ' Deselect the card to terminate a command.
PUB stop ' RJA adding in some things
PUB release
pub start_explicit(iDO, iCLK, iDI, iCS)| t 'RJA adding in some things to make work
do := iDO
clk := iCLK
di := iDI
cs := iCS
t := clk
outh_(cs)
outh_(clk)
outh_(di)
dirh_(cs)
dirh_(clk)
dirh_(di)
asm
rep #.initclksout, #4800
drvnot t
.initclksout
getct t
endasm
starttime := t
cmd(0, 0)
drvh_(cs) ' Deselect the card to terminate a command.
cmd(8, $1aa)
read
read
read
read
drvh_(cs) ' Deselect the card to terminate a command.
repeat
cmd(55, 0)
t := cmd(41, $4000_0000)
drvh_(cs) ' Deselect the card to terminate a command.
if t <> 1
quit
if t
return -40'abort -40 ' could not initialize card
cmd(58, 0)
sdhc := (read >> 6) & 1
read
read
read
drvh_(cs) ' Deselect the card to terminate a command.
return sdhc +1 ' return card type
pub start(basepin)
result := start_explicit(basepin, basepin+1, basepin+2, basepin+3)
PUB doSDHC(n)
if sdhc == 0
return n <<= 9
else
return n
pub readblock(n, b)
'
' Read a single block. The "n" passed in is the
' block number (blocks are 512 bytes); the b passed
' in is the address of 512 blocks to fill with the
' data.
'
starttime := cnt
cmd(17, doSDHC(n))
readresp
repeat sectorsize
byte[b++] := read
read
read
return endcmd
{
pub getCSD(b)
'
' Read the CSD register. Passed in is a 16-byte
' buffer.
'
starttime := cnt
cmd(9, 0)
readresp
repeat 16
byte[b++] := read
read
read
return endcmd
}
pub writeblock(n, b)
'
' Write a single block. Mirrors the read above.
'
starttime := cnt
cmd(24, doSDHC(n))
send($fe)
repeat sectorsize
send(byte[b++])
read
read
if ((readresp & $1f) <> 5)
return -42'abort -42
busy
return endcmd
{{
' Permission is hereby granted, free of charge, to any person obtaining
' a copy of this software and associated documentation files
' (the "Software"), to deal in the Software without restriction,
' including without limitation the rights to use, copy, modify, merge,
' publish, distribute, sublicense, and/or sell copies of the Software,
' and to permit persons to whom the Software is furnished to do so,
' subject to the following conditions:
'
' The above copyright notice and this permission notice shall be included
' in all copies or substantial portions of the Software.
'
' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
' EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
' MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
' IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
' CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
' TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
' SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}}
No problem! I worked on my version for a while but it's far from perfect. I've looked at the output asm from fastspin and there's tons of room for improvement. The block read / write have not even been touched, other than to add sd / sdhc compatibility. I've tried to understand the best way to use the resources of the p2 and using the smartpins should be a huge boost, since the required turnaround from cog ->pin -> pin -> cog should disappear.
I think the idea is to set smartpin mode %00101 = transition output for the clock. Then use Sync serial tx and rx to push data around. It should end up with some really optimized code, as well as nice mhz.
Now that you have the dir and out macro, you'll still need to change the pin numbers by 32 right?
Ok, I see the issue is probably being on pins >31, right?
I'll look into this and see about fixing it.
I thought this stuff at the beginning would make it work, but maybe not
#ifdef __P2__
#define OUT OUTB
#define DIR DIRB
#else
#define OUT OUTA
#define DIR DIRA
#endif
Maybe changing OUTA to OUTB and DIRA to DIRB in sdspi.spin2 would fix it?
The RIGHT way to do it would be to use the DRVx instructions (and TESTP), since they can span all 64 pins. The one place to watch seems to be the READ mov ina. I have a rather large delay to make sure things work at 320mhz and that's using the TESTP instruction...
pri read : r | c, o ' Read eight bits from the card.
c := clk
o := do
asm
mov r, #0
rep #.end_read, #8
drvl c
waitx #14 '' !! 13 safe for up to 160 mhz, 14 for 320mhz
testp o wc
drvh c
rcl r, #1
.end_read
endasm
I'm pretty sure using the smart pins will make that delay go away. Cluso's way is to toggle the clock early and end up with an extra clock. I was going for the more brute force method, at least until I understand the chip better.
Rayman et al, I think I am doing something wrong. I can't get it to work. I updated fsrw.spin2 to point to sdspi2.spin2 for sdspi.
@Rayman, could you share your working version with all three .spin2 files in a zip? The one above only has sdspi2.spin2, but not the other spin2 files. I am sure I am doing something wrong and would like to compare with one that works.
No dice. I can mount the thing from TAQOZ and perform a DIR. I reformatted just to make sure something weird was hanging it up. All four LEDs light up solid when "Mounting" is sent through serial. P58-P61
Weird. Not sure what to do next. Maybe I should do a logic capture and compare with TAQOZ.
I see the problem now. CLK is idle high instead of low. This is a similar problem to what I had with the smartpin code I was doing for the 5-wire interface for the OLED display.
I think the pins just need to be initialized properly.
The card works just fine. This fsrw can't mount any card, for me. I have found that under some circumstances the pins will default "high" or "low" in an inconstant way. I think this may have something to do with the difference between how the pin is accessed by the COG vs smartpin or how it works when "floating".
Does not work for me either. I started looking at adapting safe_spi.spin from the fsrw26 version (using the slow_reaf/write functions). But it fails at the 1st command send (reset), same as with Rayman's code .
I lack a logic analyzer/scope, so I'm a bit stuck. Maybe start loking into ozpropdev's or cluso's prop2 based LA working.
Did you compile this with FastSpin? Or, PNut?
It might only work with FastSpin...
Ok, never mind PNut doesn't do Spin, dumb question...
I'm puzzled as to why it works for me and not you on the same hardware...
I was unable to get your version of FSRW working as well. I'm wondering how much of this has to do with PortB. I'm thinking once I attach a card to PortA pins things should work but I'll let you know when I figure it out.
BTW, I've been idling the clock high without an issue.
Comments
For an example, see the Fun with the P2 ROM thread.
Any thoughts about this?
Use the built-in TAQOZ to do a sanity check for you. Just reset and type the three keys [>] [space] [esc] and from TAQOZ type MOUNT. From there you can do a DIR.
If it doesn't work there then it won't work elsewhere.
Looking in sdspi.spin2, I think this may be the problem.
I don't think the pins are laid out the same.
You can also test your pin arrangement other than the default with TAQOZ by changing the sdpin constant with this expression: It's a bit more awkward than it usually is with the cramped ROM space because we are writing directly to the sdpins constant whereas normally we have a word to take care of it easily.
But the syntax is & for a decimal bytes notation (as in IP notation where every group of decimal digits represent a byte) in the sequence CS.MISO,MOSI.CLK and then the tick ' then a space and the name of the constant (sdpins) then 2+ to modify that address to point to the parameter field and then ! to store the new value into the sdpins constant. Just in case you want to double check your original setup.
BTW, the extended TAQOZ implementation of FAT32 includes all the FOPEN type commands, handling a file as virtual memory etc as well as the disk utilities and FORMAT.
becomes Which won't work with pin numbers >31!!
Pretty sure he already fixed the Start_Explicit… at least I have it in mine if you need.
The thread I've got for what I was working on is here;
https://forums.parallax.com/discussion/169786/working-on-fsrw/p1
Right now I'm trying to learn how to start a cog the right way and pass everything, basic asm engine stuff. Once I have a handle on that I plan on using the smart pins. This is my SDSPI using inline asm. It should just replace fsrw2.6 sdspi, although I made some small tweaks to the fsrw file to make things return gracefully. When all the abort code was changed to return there were some edge cases that didn't seem quite right.
So, I replaced dira and outa with DIR and OUT. I am going to look through simple serial and see how that works. I have pin 62 assigned.
I think the idea is to set smartpin mode %00101 = transition output for the clock. Then use Sync serial tx and rx to push data around. It should end up with some really optimized code, as well as nice mhz.
Now that you have the dir and out macro, you'll still need to change the pin numbers by 32 right?
I didn't try this on Eval board's uSD, used one on my own board...
I imagine those switches have to be in the right position for uSD access...
I'll look into this and see about fixing it.
I thought this stuff at the beginning would make it work, but maybe not
Maybe changing OUTA to OUTB and DIRA to DIRB in sdspi.spin2 would fix it?
fastspin provides P1 definitions for drvh_, drvl_, drvnot_, and waitx_. I should create a testp_ builtin as well, I think.
The RIGHT way to do it would be to use the DRVx instructions (and TESTP), since they can span all 64 pins. The one place to watch seems to be the READ mov ina. I have a rather large delay to make sure things work at 320mhz and that's using the TESTP instruction...
I'm pretty sure using the smart pins will make that delay go away. Cluso's way is to toggle the clock early and end up with an extra clock. I was going for the more brute force method, at least until I understand the chip better.
@Rayman, could you share your working version with all three .spin2 files in a zip? The one above only has sdspi2.spin2, but not the other spin2 files. I am sure I am doing something wrong and would like to compare with one that works.
Weird. Not sure what to do next. Maybe I should do a logic capture and compare with TAQOZ.
I think the pins just need to be initialized properly.
non-working mount with fsrw
Working mount in TAQOZ.
It might only work with FastSpin...
Ok, never mind PNut doesn't do Spin, dumb question...
I'm puzzled as to why it works for me and not you on the same hardware...
I lack a logic analyzer/scope, so I'm a bit stuck. Maybe start loking into ozpropdev's or cluso's prop2 based LA working.
I was unable to get your version of FSRW working as well. I'm wondering how much of this has to do with PortB. I'm thinking once I attach a card to PortA pins things should work but I'll let you know when I figure it out.
BTW, I've been idling the clock high without an issue.
If so, I'll upload my working binary. Can't imagine what's going on here...
You are running this as the top level file, right?:
sdrw_test_eval.spin2