diff options
Diffstat (limited to 'source/ct-Bot/mcu/mmc-low.S')
-rw-r--r-- | source/ct-Bot/mcu/mmc-low.S | 482 |
1 files changed, 482 insertions, 0 deletions
diff --git a/source/ct-Bot/mcu/mmc-low.S b/source/ct-Bot/mcu/mmc-low.S new file mode 100644 index 0000000..b4ef6f5 --- /dev/null +++ b/source/ct-Bot/mcu/mmc-low.S @@ -0,0 +1,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 |