aboutsummaryrefslogtreecommitdiff
path: root/amforth-6.5/avr8/lib/hardware/mmc.frt
blob: f213c9bedc9c12e75feef9ef43cd48889411054a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
\ MMC+SD card - Lubos Pekny, www.forth.cz
\ Library for amforth 3.0, mFC modification
\ Max. 4GB no SDHC, access thru buffer 512B or short block or direct

\ V.1.0, 16.07.2009, tested on atmega32, amforth30mFC12.zip
\ - used SPI (MOSI, MISO, SCK, SS)
\ mmc_init, mmc_CID, mmc_CSD, mmc_read, mmc_mread, mmc_write,
\ mmc_blk@, mmc_blk!, mmc_c@, mmc_c!, mmc_end?, mmc_end!

\ needs +/-spi for pin configuration
\ needs +/-mmc for slave select action

hex

variable mmc_#buf          \ position in buf
variable mmc_buf 1FE allot \ 512B RAM


  \ enable spi for mmc, set I/O
: mmc_+spi ( -- )
    +spi
    -spi2x
    SPCR_SPE SPCR_MSTR or 
    spi.f/128 or
    spi.mode0 or SPCR c! ;

  \ send dummy byte x-times
: mmc_dummy ( x -- )
    0 ?do $ff c!spi loop ;


\ convert 32b block to byte addr, double 9 lshift
: mmc_blk2addr ( L H -- L H )
    swap dup 9 lshift      \ -- H L L<<9
    swap 7 rshift          \ -- H L<<9 L>>7
    rot 9 lshift or ;      \ -- L<<9 H<<9


  \ waiting for cmd response
: mmc_cresp ( -- c|-1 )
    FF 0 do
      c@spi dup 80 and 0=   \ bit7=0?
      if unloop exit then  \ -- c, 0=ok
      drop                 \ --
    loop -1 ;              \ -- -1, timeout


  \ waiting for data response
: mmc_dresp ( -- c|-1 )
    FF 0 do
      c@spi dup 11 and 1 =  \ xxx0ccc1
      if
        0F and unloop exit \ -- c, 5=ok
      then
      drop                 \ --
    loop -1 ;              \ -- -1, timeout


  \ waiting for token
: mmc_token ( -- c|-1 )
    FF 0 do
      c@spi dup FF -        \ <>FF?
      if unloop exit then  \ -- c, FC,FE=ok
      drop                 \ --
    loop -1 ;              \ -- -1, timeout


  \ waiting while busy, after write
: mmc_busy ( -- 0|-1 )
    FF 0 do
      c@spi FF =              \ =FF?
      if 0 unloop exit then  \ -- 0, ok
    loop -1 ;                \ -- -1, timeout


  \ send command cmd, data xl, xh
: mmc_cmd ( xl xh cmd -- c|-1 )
    FF c!spi                \ flush spi register
    40 or c!spi             \ send command cmd
    dup >< c!spi c!spi       \ send xhh, xhl
    dup >< c!spi c!spi       \ send xlh, xll
    95 c!spi                \ no crc
    mmc_cresp ;            \ -- c|-1, c=0 no errors 


  \ set block length
: mmc_length ( n -- c|-1 )
    0 10 mmc_cmd ;         \ CMD16


  \ stop multiread
: mmc_rstop ( -- c|-1 )
    0 0 C mmc_cmd          \ CMD12
    mmc_busy or -mmc ;     \ -- c|-1, c=0 no errors


  \ stop multiwrite
: mmc_wstop ( -- c|-1 )
    FD c!spi                \ Stop tran for CMD25
    FF c!spi                \ 1B wait
    mmc_busy -mmc ;        \ -- c|-1, c=0 no errors


  \ reset card, idle
: mmc_reset ( -- c|-1 )
    -mmc 10 mmc_dummy      \ 74< clk to reset mmc
    +mmc
    0 0 0 mmc_cmd ;        \ CMD0, -- 1, reset ok


  \ detect sd card, 0=SD, -1=timeout
: mmc_sd? ( -- c|-1 )
    0 0 37 mmc_cmd drop    \ CMD55
    0 0 29 mmc_cmd         \ ACMD41, -- c
    dup 1+                 \ -- -1 0, timeout
    if 4 and then ;        \ SD(R1.2=0) / MMC(R1.2=1)


  \ wait for init MMC card
: mmc_waitmmc ( -- 0|-1 )
    FF                     \ -- cnt
    begin
      0 0 1 mmc_cmd 0=     \ CMD1, -- cnt f
      if drop 0 exit then  \ -- 0, ok
      1- dup 0=            \ -- cnt-1 f
    until 1- ;             \ -- -1, timeout


  \ wait for init SD card
: mmc_waitsd ( -- 0|-1 )
    FF                     \ -- cnt
    begin
      0 0 37 mmc_cmd drop  \ CMD55
      0 0 29 mmc_cmd 0=    \ ACMD41, -- cnt f
      if drop 0 exit then  \ -- 0, ok
      1- dup 0=            \ -- cnt-1 f
    until 1- ;             \ -- -1, timeout




  \ check end of sector, for mmc read
: mmc_end? ( -- flag )
    200 mmc_#buf @
    > 0= dup               \ -- c c, -1=end
    if                     \ size<=#buf then
      2 mmc_dummy          \ dummy crc
    then ;


\ check end of sector, wait for no busy, for mmc write 
: mmc_end! ( -- 0|-1 )
    mmc_end?               \ -- flag, crc dummy for end
    if
      mmc_dresp 5 <>       \ -- 0, 0=ok, response
      mmc_busy  or         \ -- c, 0=ok, writed
    else 0 then ;          \ -- c, 0=ok, -1=timeout


: mmc_buf> ( addr n -- 0|-1 )
    dup mmc_#buf +!        \ +n, update buf position
    0 ?do                  \ addr n -- send n bytes from addr
       dup c@ c!spi 1+       \ -- addr+1
    loop drop
    \ n!spi
    mmc_end! ;             \ -- c, 0=ok, -1=timeout


  \ copy spi to buf
: mmc_>buf ( addr n -- )
    dup mmc_#buf +!        \ +n, update buf position
    0 ?do                  \ write n bytes to addr
      c@spi over c! 1+      \ -- addr+1
    loop drop
\    n@spi
    mmc_end? drop ;        \ crc dummy for end
    

  \ wait for token, copy first n bytes to buf
: mmc_(read) ( n 0 -- c|-1 )
    0 mmc_#buf !           \ reset buf position
    dup 0=                 \ 0 -- , cmd ok
    if
      drop mmc_token dup   \ c -- c c
      FE =
      if 
        drop mmc_buf swap  \ -- addr n
        mmc_>buf 0         \ -- 0, ok
      else
        swap drop          \ n c -- c
      then
    else
      swap drop            \ n c -- c
    then ;                 \ 0=ok, -1=timeout 


  \ copy first n bytes to card, response, busy
: mmc_(write) ( n 0 -- c|-1 )
    0 mmc_#buf !           \ reset buf position
    dup 0=                 \ 0 -- , cmd ok
    if
      drop FF c!spi   \ wait 1B
      FE c!spi              \ send start byte
      mmc_buf swap         \ -- addr n
      mmc_buf>             \ -- c, 0=ok, -1=timeout
    else
      swap drop            \ n c -- c
    then ;                 \ 0=ok, -1=timeout 


  \ copy first n bytes to card, multiwrite, busy
: mmc_(mwrite) ( n 0 -- c|-1 )
    0 mmc_#buf !           \ reset buf position
    dup 0=                 \ 0 -- , cmd ok
    if
      drop FF c!spi   \ wait 1B
      FC c!spi              \ send start byte
      mmc_buf swap         \ -- addr n
      mmc_buf>             \ -- c, 0=ok, -1=timeout
    else
      swap drop            \ n c -- c
    then ;                 \ 0=ok, -1=timeout 


\ ----- final words -----

  \ initialize card MMC or SD v.1.x
: mmc_init (  -- x|-1 )
    0 mmc_#buf !
    mmc_+spi               \ init spi, I/O
    mmc_reset              \ -- c, 1=ok
    dup 1- 
    if -mmc 100 xor exit then  \ <>1 then exit
    drop                   \ --

    mmc_sd?                \ detect SD
    dup 0<                 \ -- 0, SD
    if -mmc 200 xor exit then \ -1 --, timeout
    if
      mmc_waitmmc          \ MMC init
    else
      mmc_waitsd           \ SD init
    then
    200 mmc_length         \ set sector length
    or -mmc ;              \ -- 0|-1, 0=ok, -1=timeout


  \ read CID register 16B
: mmc_CID ( -- c|-1 )
    +mmc 10                \ length 16B
    0 0 A mmc_cmd          \ CMD10,
    mmc_(read)             \ 10 c -- c, 0=ok, -1=timeout
    2 mmc_dummy            \ dummy CRC
    -mmc ;


  \ read CSD register 16B
: mmc_CSD ( -- c|-1 )
    +mmc 10                \ length 16B
    0 0 9 mmc_cmd          \ CMD9
    mmc_(read)             \ 10 c -- c, 0=ok, -1=timeout
    2 mmc_dummy            \ dummy CRC
    -mmc ;


  \ open sector for read, copy n bytes to buf
  \   200 ABCD 7F mmc_read     \ open,copy 512B from sector
  \   0   ABCD 7F mmc_read     \ only open sector 7FABCD
: mmc_read ( n xl xh -- c|-1 ) \ length, sector addr
    +mmc
    mmc_blk2addr           \ addr*512, block->byte
    11 mmc_cmd             \ addrL addrH 11 --, CMD17
    mmc_(read)             \ n c -- c, 0=ok, -1=timeout
    -mmc ;


  \ open sector for multi read, copy n bytes to buf
: mmc_mread ( n xl xh -- c|-1 ) \ length, sector addr
    +mmc
    mmc_blk2addr           \ addr*512, block->byte
    12 mmc_cmd             \ addrL addrH 12 --, CMD18
    mmc_(read)             \ n c -- c, 0=ok, -1=timeout
    -mmc ;


  \ open sector for write, copy n bytes from buf to card
: mmc_write ( n xl xh -- c|-1 )  \ length, sector addr
    +mmc
    mmc_blk2addr           \ addr*512, block->byte
    18 mmc_cmd             \ addrL addrH 18 --, CMD24
    mmc_(write)            \ n c -- c, 0=ok, -1=timeout
    -mmc ;


  \ open sector for multi write, copy n bytes from buf to card
: mmc_mwrite ( n xl xh -- c|-1 )  \ length, sector addr
    +mmc
    mmc_blk2addr           \ addr*512, block->byte
    19 mmc_cmd             \ addrL addrH 19 --, CMD25
    mmc_(mwrite)           \ n c -- c, 0=ok, -1=timeout
    -mmc ;


  \ read short block from opened sector to buf
  \ use mmc_read or mmc_(read) first
: mmc_blk@ ( addr n -- )   \ addr, length of blk
    +mmc 
    mmc_>buf               \ addr n -- ,copy spi to buf
    -mmc ;


  \ write short block to opened sector from buf
  \ use mmc_write or mmc_(write) first
: mmc_blk! ( addr n -- 0|-1 )   \ addr, length of blk
    +mmc 
    mmc_buf>               \ addr n -- 0|-1, from buf
    -mmc ;                 \ 0=ok, -1=timeout


  \ direct read byte from opened sector
  \ note: +mmc, if end of sector then dummy crc, -mmc
: mmc_c@ ( -- c )
    c@spi             \ read byte from card
    1 mmc_#buf +! ;        \ increment position


  \ direct write byte to opened sector
  \ note: +mmc, if end of sector then mmc_end!, -mmc
: mmc_c! ( c -- )
    c!spi             \ write byte to card
    1 mmc_#buf +! ;        \ increment position


  \ view n bytes from mmc_buf+offset
: mmc. ( n offset -- )
    mmc_buf + swap
    0 ?do                  \ addr n -- view n bytes from addr
      dup c@ . 1+          \ -- addr+1
    loop drop ;


\ sptx Stop transmit

: mmc_tstmread ( n -- )    \ read n x 1MB
    0 .
    200 0 0 mmc_mread .    \ open for multiread
    +mmc
    0 ?do
      800 1 do             \ 1MB
        200 0 mmc_(read)   \ 512B
        drop
      loop
      i .
    loop 0 .
    mmc_rstop drop ;


: mmc_tstread ( n -- )     \ read n x 1MB
    0 .
    200 0 0 mmc_read .
    0 ?do
      800 1 do             \ 1MB
        200 0 0 mmc_read   \ 512B
        drop
      loop
      i .
    loop 0 . ;


\ sptx Stop transmit