This repository has been archived on 2025-03-02. You can view files and clone it, but cannot push or open issues or pull requests.
rc2007-soccer/source/ct-Bot/mcu/mmc-low.S
2007-02-11 18:32:03 +00:00

482 lines
12 KiB
ArmAsm

/*
* 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