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
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
|
/*
* c't-Bot
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your
* option) any later version.
* This program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307, USA.
*
*/
#ifdef MCU
; Hinweis:
; Sollte der Build-Prozess an dieser Datei scheitern, bitte auch die
; Datei ".settings/org.eclipse.core.runtime.prefs" aus dem CVS laden, oder
; selbst veranlassen, dass .S-Dateien ebenfalls vom gcc verarbeitet werden
; (und nicht direkt vom Assembler).
/*!
* @file mmc-low.s
* @brief Low-Level-Routinen zum Lesen/Schreiben einer MMC / SD-Card
* @author Timo Sandmann (mail@timosandmann.de)
* @date 14.11.2006
*/
#include "mmc-low.h"
#include "ct-Bot.h"
#include "ena.h"
#ifdef MMC_AVAILABLE
#include <avr/io.h>
; Portkonfiguration umrechnen
.equ PORT_OUT, _SFR_IO_ADDR(MMC_PORT_OUT)
.equ PORT_IN, _SFR_IO_ADDR(MMC_PORT_IN)
.equ DDR, _SFR_IO_ADDR(MMC_DDR)
.equ SPI_CLK_MASK, _BV(SPI_CLK) ; 1<<SPI_CLK
/*!
* Schreibt ein Byte an die Karte
* @param data Das zu sendende Byte
* @author Timo Sandmann (mail@timosandmann.de)
* @date 14.11.2006
*/
.global mmc_write_byte
.type mmc_write_byte, @function
mmc_write_byte:
in r25, PORT_OUT ; MMC_PORT_OUT einlesen
cbr r25, SPI_CLK_MASK ; CLK auf low
bst r24, 7 ; Bit 7 der Daten
bld r25, SPI_DO ; Daten nach DO
out PORT_OUT, r25 ; Daten senden
sbi PORT_OUT, SPI_CLK ; CLK auf high
bst r24, 6 ; Bit 6 der Daten
bld r25, SPI_DO
out PORT_OUT, r25
sbi PORT_OUT, SPI_CLK
bst r24, 5 ; Bit 5 der Daten
bld r25, SPI_DO
out PORT_OUT, r25
sbi PORT_OUT, SPI_CLK
bst r24, 4 ; Bit 4 der Daten
bld r25, SPI_DO
out PORT_OUT, r25
sbi PORT_OUT, SPI_CLK
bst r24, 3 ; Bit 3 der Daten
bld r25, SPI_DO
out PORT_OUT, r25
sbi PORT_OUT, SPI_CLK
bst r24, 2 ; Bit 2 der Daten
bld r25, SPI_DO
out PORT_OUT, r25
sbi PORT_OUT, SPI_CLK
bst r24, 1 ; Bit 1 der Daten
bld r25, SPI_DO
out PORT_OUT, r25
sbi PORT_OUT, SPI_CLK
bst r24, 0 ; Bit 0 der Daten
bld r25, SPI_DO
out PORT_OUT, r25
sbi PORT_OUT, SPI_CLK
sbi PORT_OUT, SPI_DO ; DO auf high
ret
/*!
* Liest ein Byte von der Karte
* @return Das gelesene Byte
* @author Timo Sandmann (mail@timosandmann.de)
* @date 14.11.2006
*/
.global mmc_read_byte
.type mmc_read_byte, @function
mmc_read_byte:
in r19, PORT_OUT ; MMC_PORT_OUT einlesen
cbr r19, SPI_CLK_MASK ; CLK low
out PORT_OUT, r19 ; CLK auf low
mov r18, r19 ; CLK high
sbr r18, SPI_CLK_MASK
in r25, PORT_IN ; Bit 7 lesen
out PORT_OUT, r18 ; CLK Flanke
out PORT_OUT, r19
bst r25, SPI_DI ; Bit 7 speichern
bld r24, 7
in r25, PORT_IN ; Bit 6
out PORT_OUT, r18
out PORT_OUT, r19
bst r25, SPI_DI
bld r24, 6
in r25, PORT_IN ; Bit 5
out PORT_OUT, r18
out PORT_OUT, r19
bst r25, SPI_DI
bld r24, 5
in r25, PORT_IN ; Bit 4
out PORT_OUT, r18
out PORT_OUT, r19
bst r25, SPI_DI
bld r24, 4
in r25, PORT_IN ; Bit 3
out PORT_OUT, r18
out PORT_OUT, r19
bst r25, SPI_DI
bld r24, 3
in r25, PORT_IN ; Bit 2
out PORT_OUT, r18
out PORT_OUT, r19
bst r25, SPI_DI
bld r24, 2
in r25, PORT_IN ; Bit 1
out PORT_OUT, r18
out PORT_OUT, r19
bst r25, SPI_DI
bld r24, 1
in r25, PORT_IN ; Bit 0
out PORT_OUT, r18
bst r25, SPI_DI
bld r24, 0
clr r25 ; return ist in 8 Bit und wir sind ordentlich ;)
ret
/*!
* Schaltet die Karte aktiv und checkt dabei die Initialisierung
* @return 0 wenn alles ok ist, 1 wenn Init nicht moeglich
* @author Timo Sandmann (mail@timosandmann.de)
* @date 09.12.2006
*/
.global mmc_enable
.type mmc_enable, @function
mmc_enable:
lds r24, mmc_init_state ; Initialisierung der Karte checken
tst r24
breq 1f
call mmc_init ; neu initialisieren
tst r24
breq 1f
ret ; kein Init moeglich => Fehler
1:
ldi r24, lo8(ENA_MMC) ; Karte aktiv schalten
call ENA_on
ldi r24, lo8(ENA_MMC) ; Karte inaktiv schalten
call ENA_off
cbi DDR, SPI_DI ; DI auf input
sbi DDR, SPI_DO ; DO auf output
ldi r24, lo8(-1)
call mmc_write_byte ; sendet 8 CLK-Flanken
ldi r24, lo8(ENA_MMC) ; Karte aktiv schalten
call ENA_on
ldi r24, 0
ret ; alles ok
/*!
* Schreibt einen 512-Byte Sektor auf die Karte
* @param addr Nummer des 512-Byte Blocks
* @param Buffer Zeiger auf den Puffer
* @param async 0: synchroner, 1: asynchroner Aufruf, siehe MMC_ASYNC_WRITE in mmc-low.h
* @return 0 wenn alles ok ist, 1 wenn Init nicht moeglich oder Timeout vor / nach Kommando 24, 2 wenn Timeout bei busy
* @author Timo Sandmann (mail@timosandmann.de)
* @date 16.11.2006
*/
.global mmc_write_sector
.type mmc_write_sector, @function
mmc_write_sector:
push r13 ; allgemeine Register retten
push r14
push r15
push r16
push r28
push r29
movw r14, r22 ; Byte 1 und 2 von Parameter addr sichern
mov r16, r24 ; Byte 3 von Parameter addr sichern
movw r28, r20 ; Parameter Buffer sichern
mov r13, r18 ; Parameter async sichern
call mmc_enable ; Karte aktiv schalten
tst r24
breq 1f
rjmp 4f ; Karte kann nicht initialisiert werden => Fehler
1:
lsl r14 ; Block in Bytes umrechnen
rol r15
rol r16
#if MMC_ASYNC_WRITE == 1
clr r27 ; r27 = 0
1:
clr r26 ; r26 = 0
2:
call mmc_read_byte ; warten, ob Karte noch busy
cpi r24, lo8(-1)
breq 3f ; == 0xff?
dec r26 ; r26--
brne 2b ; r26 == 0?
dec r27 ; r27--
brne 1b ; r27 == 0?
rjmp 4f ; Timeout :(
3:
#endif
ldi r24, 88 ; Kommando 24 zum Schreiben eines Blocks senden, Byte 0
call mmc_write_byte
mov r24, r16 ; Byte 1
call mmc_write_byte
mov r24, r15 ; Byte 2
call mmc_write_byte
mov r24, r14 ; Byte 3
call mmc_write_byte
ldi r24, 0 ; Byte 4
call mmc_write_byte
ldi r24, lo8(-1) ; Byte 5 (CRC)
call mmc_write_byte
ldi r26, lo8(-1) ; Timeout nach 256 Versuchen
1:
call mmc_read_byte
cpi r24, lo8(-1) ; !0xff = Antwort
brne 3f
dec r26 ; r26--
brne 1b
3:
tst r24 ; Fehler oder Abbruch durch Timeout?
breq 1f
rjmp 4f ; Return-Code 1
1:
ldi r24, lo8(-2) ; Start-Byte an Karte senden
call mmc_write_byte
in r26, PORT_OUT ; MMC_PORT_OUT einlesen
cbr r26, SPI_CLK_MASK ; CLK auf low
ldi r18, 2 ; r18 = 2
clr r27 ; r27 = 0
1:
ld r25, Y+ ; Byte aus SRAM lesen
bst r25, 7 ; Bit 7
bld r26, SPI_DO
out PORT_OUT, r26 ; Daten senden
sbi PORT_OUT, SPI_CLK ; CLK auf high
bst r25, 6 ; Bit 6
bld r26, SPI_DO
out PORT_OUT, r26
sbi PORT_OUT, SPI_CLK
bst r25, 5 ; Bit 5
bld r26, SPI_DO
out PORT_OUT, r26
sbi PORT_OUT, SPI_CLK
bst r25, 4 ; Bit 4
bld r26, SPI_DO
out PORT_OUT, r26
sbi PORT_OUT, SPI_CLK
bst r25, 3 ; Bit 3
bld r26, SPI_DO
out PORT_OUT, r26
sbi PORT_OUT, SPI_CLK
bst r25, 2 ; Bit 2
bld r26, SPI_DO
out PORT_OUT, r26
sbi PORT_OUT, SPI_CLK
bst r25, 1 ; Bit 1
bld r26, SPI_DO
out PORT_OUT, r26
sbi PORT_OUT, SPI_CLK
bst r25, 0 ; Bit 0
bld r26, SPI_DO
out PORT_OUT, r26
sbi PORT_OUT, SPI_CLK
inc r27 ; r27++
breq 2f ; r27 == 0?
rjmp 1b
2:
dec r18 ; r18--
breq 3f ; r18 == 0?
rjmp 1b
3:
sbi PORT_OUT, SPI_DO ; DO auf high
call mmc_write_byte ; crc-Dummy schreiben
call mmc_write_byte
#if MMC_ASYNC_WRITE == 1
tst r13 ; wollten wir asynchron schreiben?
brne 3f ; wenn ja, nicht auf busy warten
#endif
1:
clr r28 ; r28 = 0
2:
call mmc_read_byte ; warten, ob Karte noch busy
cpi r24, lo8(-1)
breq 3f ; == 0xff?
dec r28 ; r28--
brne 2b ; r28 == 0?
dec r27 ; r27--
brne 1b ; r27 == 0?
rjmp 5f ; Timeout :(
3:
ldi r16, 0 ; Alles ok, also Return-Code 0 laden :)
rjmp 6f
4:
ldi r16, 1 ; Fehler, Return-Code 1 laden
sts mmc_init_state, r16 ; Initstatus auf Fehler setzen
rjmp 6f
5:
ldi r16, 2 ; Fehler, Return-Code 2 laden
sts mmc_init_state, r16 ; Initstatus auf Fehler setzen
6:
ldi r24, lo8(ENA_MMC) ; Karte inaktiv schalten
call ENA_off
mov r24, r16 ; Return-Code laden
ldi r25, 0
pop r29 ; allgemeine Register wiederherstellen
pop r28
pop r16
pop r15
pop r14
pop r13
ret
/*!
* Liest einen Block von der Karte
* @param addr Nummer des 512-Byte Blocks
* @param Buffer Puffer von mindestens 512 Byte
* @return 0 wenn alles ok ist, 1 wenn Init nicht moeglich oder Timeout vor / nach Kommando 17
* @author Timo Sandmann (mail@timosandmann.de)
* @date 17.11.2006
*/
.global mmc_read_sector
.type mmc_read_sector, @function
mmc_read_sector:
push r14 ; allgemeine Register retten
push r15
push r16
push r28
push r29
movw r14, r22 ; Byte 1 und 2 von Parameter addr sichern
mov r16, r24 ; Byte 3 von Parameter addr sichern
movw r28, r20 ; Parameter Buffer sichern
call mmc_enable ; Karte aktiv schalten
tst r24
breq 1f
rjmp 5f ; Karte kann nicht initialisiert werden => Fehler
1:
lsl r14 ; Block in Bytes umrechnen
rol r15
rol r16
#if MMC_ASYNC_WRITE == 1
clr r27 ; r27 = 0
1:
clr r26 ; r26 = 0
2:
call mmc_read_byte ; warten, ob Karte noch busy
cpi r24, lo8(-1)
breq 3f ; == 0xff?
dec r26 ; r26--
brne 2b ; r26 == 0?
dec r27 ; r27--
brne 1b ; r27 == 0?
rjmp 5f ; Timeout :(
3:
#endif
ldi r24, 81 ; Kommando 17 zum Lesen eines Blocks senden, Byte 0
call mmc_write_byte
mov r24, r16 ; Byte 1
call mmc_write_byte
mov r24, r15 ; Byte 2
call mmc_write_byte
mov r24, r14 ; Byte 3
call mmc_write_byte
ldi r24, 0 ; Byte 4
call mmc_write_byte
ldi r24,lo8(-1) ; Byte 5 (CRC)
call mmc_write_byte
ldi r16, lo8(-1) ; Timeout bei 256
1:
call mmc_read_byte
cpi r24, lo8(-2) ; 0xfe = Startbyte
breq 2f
call mmc_read_byte ; Noch ein Versuch
cpi r24, lo8(-2)
breq 2f
dec r16
brne 1b
rjmp 4f ; Timeout, also abbrechen :(
2:
in r20, PORT_OUT ; MMC_PORT_OUT einlesen
cbr r20, SPI_CLK_MASK ; CLK low
out PORT_OUT, r20 ; CLK auf low
mov r19, r20 ; CLK high
sbr r19, SPI_CLK_MASK
ldi r18, 2 ; Schleifenzaehler laden
clr r24
1:
in r26, PORT_IN ; Bit 7 lesen
out PORT_OUT, r19 ; CLK Flanke
out PORT_OUT, r20
bst r26, SPI_DI ; Bit 7 speichern
bld r25, 7
in r26, PORT_IN ; Bit 6
out PORT_OUT, r19
out PORT_OUT, r20
bst r26, SPI_DI
bld r25, 6
in r26, PORT_IN ; Bit 5
out PORT_OUT, r19
out PORT_OUT ,r20
bst r26, SPI_DI
bld r25, 5
in r26, PORT_IN ; Bit 4
out PORT_OUT, r19
out PORT_OUT, r20
bst r26, SPI_DI
bld r25, 4
in r26, PORT_IN ; Bit 3
out PORT_OUT, r19
out PORT_OUT, r20
bst r26, SPI_DI
bld r25, 3
in r26, PORT_IN ; Bit 2
out PORT_OUT, r19
out PORT_OUT, r20
bst r26, SPI_DI
bld r25, 2
in r26, PORT_IN ; Bit 1
out PORT_OUT, r19
out PORT_OUT, r20
bst r26, SPI_DI
bld r25, 1
in r26, PORT_IN ; Bit 0
out PORT_OUT, r19
out PORT_OUT, r20
bst r26, SPI_DI
bld r25, 0
st Y+, r25 ; Byte ins SRAM kopieren
inc r24 ; r24++
breq 2f ; r24 == 0?
rjmp 1b
2:
dec r18 ; r18--
breq 3f ; r18 == 0?
rjmp 1b
3:
out PORT_OUT, r19 ; CLK auf high
call mmc_read_byte ; crc-Dummy lesen
call mmc_read_byte
4:
tst r16 ; Abbruch durch Timeout?
breq 5f ; r27 == 0?
ldi r16, 0 ; Alles ok, also Return-Code 0 laden :)
rjmp 6f
5:
ldi r16, 1 ; Fehler, also Return-Code 1 laden
sts mmc_init_state, r16 ; Initstatus auf Fehler setzen
6:
ldi r24, lo8(ENA_MMC) ; Karte inaktiv schalten
call ENA_off
mov r24, r16 ; Return-Code laden
ldi r25, 0
pop r29 ; allgemeine Register wiederherstellen
pop r28
pop r16
pop r15
pop r14
ret
#endif // MMC_AVAILABLE
#endif // MCU
|