for testing/experimenting purposes i found it useful to include a
constant, 'xfrlen', which limits the number of bytes which will be read into or out of cpu memory by the card read/write routines
this value would normally be 200h for the default card block length size, but it can be reduced for testing purposes
re-instate the commented-out line beginning '( 200 xfrlen -'
in the definitions for 'mrd' & 'mwr'
if you wish to vary xfrlen:
- a full block of data must always be written to the card when using the card Block Write command, so if xfrlen is set to less than the current card block size then the write routine must supply 'fill' bytes to make up the correct length data transfer
- similarly, the read routine would need to issue sufficient dummy read byte calls to consume any remaining data sent by the card
(the MMC standard includes the ability to change the default block length used in card data read/write transfers - however, some card manufacturers use a fixed block size so i have not included the Set Block Length command in this
software)
i have included below an optional definition which issues an MMC
command to read the card specific data (including max. storage size of
card, default block length, etc) and also an alternative method for
defining the three Forth low-level code definitions, if a Forth
assembler is not available
if you have a Forth system running on your 1802 and you want to try out
the MMC / SD card interface described on this site, the source
code below can be cut-and-pasted from this HTML page into a text file to
customise the code and edit out the notes before producing the input
format required for your system
documentation is provided on the main MMC
card interface page
PLEASE NOTE:
since Forth is something of a 'write-only' language, ahead even of
'C' (but light-years behind 'APL'!) i have tried to keep the obscurity
to a minimum for general consumption - these listings are given as a guide only
feel free to improve the 'Forth factor' to your own satisfaction
hex
200 constant xfrlen
( card default block size )
0 variable cmd here 2- dp ! ( command buffer
)
40 c, 00 c, 00 c, 00 c, 00 c, 95 c,
code spi ( tx_byte -> rx_byte )
rb pop, (
pop top of stack into rb )
00 ldi rd phi rd plo
08 ldi rc plo
here
rb glo shl rb plo
here 04 + bdf req skp seq
rd glo shl
here 04 + b3 01 ori rd plo
s dec 03 out ( stack 's' is 'X' reg, set to r3
on HHC )
rc dec rc glo
bnz
rd push, ( push rd
onto top of stack )
next
end-code
code N6 ( -> )
s dec 6 out next
end-code
code N7 ( -> )
s dec 7 out next
end-code
: ccs0 ( -> )
N7 0FF spi drop ;
: ccs1 ( -> )
N6 0FF spi drop ;
: mmc ( command madr_lo madr_hi -> response )
cmd swap over 1+ ! swap over 3 + !
swap 40 or swap c! cmd 6 + cmd
do i c@ spi drop loop 8 0
do spi dup 0FF = not
if leave then
loop ;
: mini ( -> )
ccs1 0A 0 do 0FF spi drop loop
ccs0 0 0 0 mmc dup 01 =
if 8 0
do drop 1 0 0 mmc dup 00 =
if leave then
loop ?dup if ." mmc init err:" . abort then
else ." mmc reset err:" . abort
then ccs1 ;
: mrd ( madr_lo madr_hi adr -> ) ;
ccs0 rot rot 11 rot rot mmc dup
if ." mrd err:" . abort
else ( 0 ) 8 0
do 0FF spi 0FE =
if drop 1 leave then
loop
if xfrlen over + swap
do 0FF spi i c! loop
( 200 xfrlen - 0 do 0FF spi drop loop )
0FF spi drop 0FF spi drop
else ." mrd timeout" abort
then
then ccs1 ;
: mwr ( adr madr_lo madr_hi -> )
ccs0 18 rot rot mmc dup
if ." mwr err:" . abort
else drop 0FF spi drop 0FE spi drop
xfrlen over + swap
do i c@ spi drop loop
( 200 xfrlen - 0 do 0FF spi drop loop )
0FF spi drop 0FF spi drop
0 4 0
do 0FF spi 0F and 5 =
if drop 1 leave then
loop
if 80 0 do 0FF spi if leave then
loop
else ." mwr failed" abort
then
then ccs1 ;
: b>ad ( blk -> madr_lo madr_hi )
400 u* ;
: brd ( mblk bfr -> )
buffer >r b>ad
over over r@ mrd
200 0 d+ r> 200 + mrd ;
: bwr ( bfr mblk -> )
>r buffer dup 200 +
r@ b>ad 200 0 d+ mwr
r> b>ad mwr ;
\ ==========================================
\ optional command to read card specific data
\ - after initialising card using 'mini' above,
\ use 'cd csd' to read csd from card into buffer
\ variable cd 0e allot
\ (16 byte buffer for csd info from card)
\: csd ( bfr_adr -> )
\ ccs0 9 0 0 mmc dup
\ if ." csd err:" . abort
\ else ( 0 ) 8 0
\ do 0FF spi 0FE =
\ if drop 1 leave then
\ loop
\ if 10 over + swap
\ do 0FF spi i c! loop
\ 0FF spi drop 0FF spi drop
\ else ." csd timeout" abort
\ then
\ then ccs1 ;
\ ==========================================
\ if you don't have a Forth 1802 assembler,
\ you can customise the definitions below
\ you will need to check which registers
\ are free to use, swap in your preferred
\ parameter passing method and the code that
\ is required to return to the Forth
\ inner interpreter; then replace the
\ relevant bytes below with your
\ hand-compiled code values
\ variable spi here 2- dp ! ( reset dp to
PFA of spi )
\ 72 c, 0BB c, 72 c, 0AB c, ( rb pop, )
\ 0F8 c, 00 c, 0BD c, 0AD c, ( 00 ldi rd phi
rd plo )
\ 0F8 c, 08 c, 0AC
c, (
08 ldi rc plo )
\
here
( here )
\ 8B c, 0FE c, 0AB
c, ( rb glo
shl rb plo )
\ here 4 + 33 c,
c,
( here 04 + bdf )
\ 7A c, 38 c, 7B
c, ( req
skp seq )
\ 8D c, 0FE
c,
( rd glo shl )
\ here 4 + 36 c,
c,
( here 04 + b3 )
\ 0F9 c, 01 c, 0AD
c, ( 01 ori rd plo
)
\ 23 c, 63 c, 2c c, 8C
c, ( s dec 03 out rc dec
rc glo )
\ 3A c,
c,
( bnz )
\ 23 c, 8D c, 73 c, 9D c, 53 c, ( rd push, )
\ 0D8
c,
( next is 'sep r8' on HHC )
\ spi spi 2-
!
( point CFA of spi to code start )
\ variable N6 here 2- dp !
\ 23 c, 66 c, 0D8
c,
( s dec 6 out next )
\ N6 N6 2- !
\ variable N7 here 2- dp !
\ 23 c, 67 c, 0D8
c,
( s dec 7 out next )
\ N7 N7 2- !
|