
.include "m8def.inc"


.def temp1=r16
.def temp2=r17
.def temp3=r18



.equ	MMC_Write	=PORTB		;//Port an der die MMC/SD-Karte angeschlossen ist also des SPI 
.equ 	MMC_Read	=PINB
.equ	MMC_Dir		=DDRB	
	
.equ	SPI_DI		=4		;//Port Pin an dem Data Output der MMC/SD-Karte angeschlossen ist 
.equ	SPI_DO		=3		;//Port Pin an dem Data Input der MMC/SD-Karte angeschlossen ist
.equ	SPI_Clock	=5		;//Port Pin an dem die Clock der MMC/SD-Karte angeschlossen ist (clk)
.equ	MMC_Chip_Select	=2		;//Port Pin an dem Chip Select der MMC/SD-Karte angeschlossen ist



	   	   ldi temp1, LOW(RAMEND)      ; LOW-Byte der obersten RAM-Adresse
           out SPL, temp1
           ldi temp1, HIGH(RAMEND)     ; HIGH-Byte der obersten RAM-Adresse
           out SPH, temp1




start:
	rcall schwachsinn

	rcall spi_init
	rcall mmc_init
	rcall testbild
	rcall lcd_wait
	ldi temp1 , 0b01010000
	rcall lcd_data
	rcall lcd_wait
	rcall spi_init
	rcall mmc_init
	rcall testbild
	rcall lcd_wait
	rcall spi_init
	rcall mmc_init
	ldi temp1, 0x00
	sts addresse, temp1
	sts addresse+1, temp1
	ldi temp1, 0x14
	sts addresse+2, temp1
	ldi temp1, 0x00
	sts addresse+3, temp1
	rcall CID_read
	rcall testbild
	rcall lcd_wait
	rcall Read_Block_MMC
	rcall testbild
	rcall lcd_wait
		
	rcall lcd_wait
	rcall lcd_clear
	rjmp start


;________________________________
;hier geht das versuchsprog weiter
;---------------------------------

schwachsinn:

			ldi temp1, 0xFF    ;Port B = Ausgang
           out DDRB, temp1

           rcall lcd_init     ;Display initialisieren
           rcall lcd_clear    ;Display löschen

           ldi temp1, 'T'     ;Zeichen anzeigen
           rcall lcd_data

           ldi temp1, 'e'     ;Zeichen anzeigen
           rcall lcd_data
           
           ldi temp1, 's'     ;Zeichen anzeigen
           rcall lcd_data

           ldi temp1, 't'     ;Zeichen anzeigen
           rcall lcd_data
			rcall lcd_wait
ret


testbild:
		

		ldi	temp2,	0x00
		out	SPCR,	temp2
		ldi temp2,  0x00
		out	SPSR,	temp2

		ldi temp1, 0xFF
		out DDRB, temp1
		rcall lcd_init
		rcall lcd_clear
		lds temp1, response_ini+1
		ldi temp2, 0b00110000
		add temp1, temp2
		rcall lcd_data
		lds temp1, response_ini
		ldi temp2, 0b00110000
		add temp1, temp2
		rcall lcd_data
		lds temp1, response_read+1
		ldi temp2, 0b00110000
		add temp1, temp2
		rcall lcd_data
		lds temp1, response_read
		subi temp1, 0x01
		rcall lcd_data
		
		ret


;_____________________________
;INITIALISIERUNG SPI UND MMC
;----------------------------


spi_init:
		
		;//Konfiguration des Ports an der die MMC/SD-Karte angeschlossen wurde	
		cbi	MMC_Dir,	SPI_DI 			;//Setzen von Pin MMC_DI auf Input
		sbi	MMC_Dir,	SPI_Clock 		;//Setzen von Pin MMC_Clock auf Output
		sbi	MMC_Dir,	SPI_DO 			;//Setzen von Pin MMC_DO auf Output
		sbi	MMC_Dir,	MMC_Chip_Select 	;//Setzen von Pin MMC_Chip_Select auf Output	
		sbi	MMC_Write,	MMC_Chip_Select 



		;//Aktiviren des SPI - Bus, Clock = Idel High
		;ldi	work,	(1<<SPE)|(1<<MSTR)|(1<<SPR0)	;//Enable SPI, SPI in Master Mode
		ldi	temp1,	0x53
		out	SPCR,	temp1
		ldi temp1,  0x00
		out	SPSR,	temp1

		ret



mmc_init:

		;//Initialisiere MMC/SD-Karte in den SPI-Mode
		ldi	temp2,	15
lp1:	ldi	temp1,	0xFF
		rcall	Write_Byte_MMC				;//Sendet min 74+ Clocks an die MMC/SD-Karte
		dec	temp2
		brne	lp1

CMD_0:;//Sendet Commando CMD0 an MMC/SD-Karte
	ldi	temp1, 0x40
	sts CMD,   temp1
	ldi temp1, 0x00
	sts CMD+1, temp1	
	sts CMD+2, temp1
	sts CMD+3, temp1
	sts CMD+4, temp1
	ldi	temp1, 0x95
	sts CMD+5, temp1	;speichert denn CMD0 befehl in hex auf SRAM 40 00 00 00 00 95

	rcall	Write_Command_MMC
	
	rcall send_end
	
	lds temp1, response_save
	sts response_ini+1, temp1
	cpi temp1, 0x01
	breq CMD_1
	rjmp CMD_0



;//Sendet Commando CMD1 an MMC/SD-Karte
	
CMD_1:
	ldi	temp1,0x41		;//Commando 1
	sts CMD, temp1
	ldi temp1, 0x00
	sts CMD+1, temp1
	sts CMD+2, temp1
	sts CMD+3 ,temp1
	sts CMD+4, temp1
	ldi	temp1,0xFF
	sts CMD+5, temp1

	rcall	Write_Command_MMC

	rcall send_end

	lds temp1, response_save
	sts response_ini, temp1
	cpi temp1, 0x00
	breq fertig
	rjmp CMD_1

fertig:

	;schneller machen des spi taktes weil ini erfolgreich und unter 400khz von statten geht
	ldi	temp1,	0x50
	out	SPCR,	temp1
	ldi temp1,  0x00
	out	SPSR,	temp1       ;hier kann die geschwindigkeit au noch verdoppelt werden durch
							;schreiben von 0x01 in das register SPSR
	ret



;____________________
;BEFEHLE STEHEN HIER
;--------------------


;Routine zum beenden nach einer übertragung, z.b. nach einem kommando oder nach 
;dem die 512 byte empfangen wurden ...
send_end:	

	sbi MMC_Write,	MMC_Chip_Select
	ldi temp1, 0xFF
	rcall Write_Byte_MMC
	ret


;//Routine zum Senden eines Bytes zur MMC-Karte (SPI)
Write_Byte_MMC:	

		out	SPDR,	temp1 
lp7:	sbis	SPSR,	SPIF
	  	rjmp	lp7
		ret




;//Routine zun senden eines 6 byte Commandos
Write_Command_MMC:	
	
	;//sendet 8 Clock Impulse
	ldi	temp1,	0xFF
	rcall	Write_Byte_MMC

	;//sendet 6 Byte Commando
	cbi	MMC_Write,	MMC_Chip_Select		;//set MMC_Chip_Select to low (MMC/SD-Karte Aktiv)

	lds temp1, CMD				;//sendet 6 Byte Commando zur MMC/SD-Karte
	rcall Write_BYTE_MMC
	lds temp1, CMD+1
	rcall Write_Byte_MMC
	lds temp1, CMD+2
	rcall Write_Byte_MMC
	lds temp1, CMD+3
	rcall Write_Byte_MMC
	lds temp1, CMD+4
	rcall Write_Byte_MMC
	lds temp1, CMD+5
	rcall Write_Byte_MMC

response:

	ldi	temp1,	0xFF
	rcall	Write_Byte_MMC 		;//Wartet auf ein gültige Antwort von der MMC/SD-Karte
	in	temp1,	SPDR
	sts response_save, temp1		;sichern des der antwort(response) von der MMC
	cpi	temp1,	0xFF			; Antwort sollte 0x01 bei CMD0 und ...... sein
	brne	response2
	cpi temp1, 0xFF
	breq	response
	
response2:	
  	
	ret
  						;//Abbruch da die MMC/SD-Karte antwortet





;//Routine zum lesen eines Blocks(512Byte) von der MMC/SD-Karte
Read_Block_MMC:	;
	
	
	;//Commando 17 zum lesen eines Blocks
CMD_17:	
	ldi temp1, 0x51		;//Commando 17
	sts CMD,   temp1
	lds temp1, addresse
	sts CMD+1, temp1
	lds temp1, addresse+1
	sts CMD+2, temp1
	lds temp1, addresse+2
	sts CMD+3, temp1
	lds temp1, addresse+3
	sts CMD+4, temp1
	ldi temp1, 0xFF
	sts CMD+5, temp1

	rcall Write_Command_MMC

	lds temp1, response_save
	sts response_read+1, temp1
	cpi temp1, 0x00
	breq read
	rcall send_end 
	rjmp CMD_17

	
;Wartet auf Start Byte von der MMC/SD-Karte (FEh/Start Byte)
	
read:	

	ldi	temp1,	0xFF
	rcall	Write_Byte_MMC
	in	temp1,	SPDR
	sts 	response_read, temp1
	cpi	temp1,	0xFE			; Antwort sollte 0xFE für lesebstätigung
	breq	read2
	cpi temp1, 0xFE
	brne	read


read2:


	ldi ZL, LOW(cluster*2)               ; Adresse von clusterspeicher in den z pointer laden
        ldi ZH, HIGH(cluster*2)
	ldi temp2, 0xFF
	
read2_1:	
		ldi	temp1,	0xFF
		rcall	Write_Byte_MMC
		in	temp1,	SPDR
		st	Z+,	temp1
		dec temp2
		cpi temp2, 0x00
		breq read3
		rjmp read2_1

read3:	
	ldi temp2, 0xFF
read3_1:
		ldi	temp1,	0xFF
		rcall	Write_Byte_MMC
		in	temp1,	SPDR
		st	Z+,	temp1
		dec temp2
		cpi temp2, 0x00
		breq read_crc
		rjmp read3_1
	
read_crc:			 ;nicht wichtig darum auslesen und net speichern
	ldi	temp1,	0xFF
	rcall	Write_Byte_MMC
	ldi	temp1,	0xFF
	rcall	Write_Byte_MMC

	rcall send_end

	ret

	
	


CID_read:
	
		
CMD_10:	
	ldi temp1, 0x4A		;//Commando 10
	sts CMD,   temp1
	lds temp1, 0x00
	sts CMD+1, temp1
	sts CMD+2, temp1
	sts CMD+3, temp1
	sts CMD+4, temp1
	ldi temp1, 0xFF
	sts CMD+5, temp1

	rcall Write_Command_MMC

	lds temp1, response_save
	sts response_read+1, temp1
	cpi temp1, 0x00
	breq read_CID
	rcall send_end 
	rjmp CMD_10

	
;Wartet auf Start Byte von der MMC/SD-Karte (FEh/Start Byte)
	
read_CID:	

	ldi	temp1,	0xFF
	rcall	Write_Byte_MMC
	in	temp1,	SPDR
	sts 	response_read, temp1
	cpi	temp1,	0xFE			; Antwort sollte 0xFE für lesebstätigung
	breq	read_CID2
	cpi temp1, 0xFE
	brne	read_CID


read_CID2:


	ldi ZL, LOW(cluster*2)               ; Adresse von clusterspeicher in den z pointer laden
        ldi ZH, HIGH(cluster*2)
	ldi temp2, 0x10
	
read_CID2_1:	
		ldi	temp1,	0xFF
		rcall	Write_Byte_MMC
		in	temp1,	SPDR
		st	Z+,	temp1
		dec temp2
		cpi temp2, 0x00
		breq read_CID_crc
		rjmp read_CID2_1	
	
	
read_CID_crc:			 ;nicht wichtig darum auslesen und net speichern
	ldi	temp1,	0xFF
	rcall	Write_Byte_MMC
	ldi	temp1,	0xFF
	rcall	Write_Byte_MMC

	rcall send_end

	ret



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                 LCD-Routinen                ;;
;;                 ============                ;;
;;              (c)andreas-s@web.de            ;;
;;                                             ;;
;; 4bit-Interface                              ;;
;; DB4-DB7:       PB0-PB3                      ;;
;; RS:            PB4                          ;;
;; E:             PB5                          ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 
 
 ;sendet ein Datenbyte an das LCD
lcd_data:
           mov temp2, temp1             ;"Sicherungskopie" für
                                        ;die Übertragung des 2.Nibbles
           swap temp1                   ;Vertauschen
           andi temp1, 0b00001111       ;oberes Nibble auf Null setzen
           sbr temp1, 1<<4              ;entspricht 0b00010000
           out PORTB, temp1             ;ausgeben
           rcall lcd_enable             ;Enable-Routine aufrufen
                                        ;2. Nibble, kein swap da es schon
                                        ;an der richtigen stelle ist
           andi temp2, 0b00001111       ;obere Hälfte auf Null setzen 
           sbr temp2, 1<<4              ;entspricht 0b00010000
           out PORTB, temp2             ;ausgeben
           rcall lcd_enable             ;Enable-Routine aufrufen
           rcall delay50us              ;Delay-Routine aufrufen
           ret                          ;zurück zum Hauptprogramm    ;89 CLOCKS

 ;sendet einen Befehl an das LCD
lcd_command:                            ;wie lcd_data, nur ohne RS zu setzen
           mov temp2, temp1
           swap temp1
           andi temp1, 0b00001111
           out PORTB, temp1
           rcall lcd_enable
           andi temp2, 0b00001111
           out PORTB, temp2
           rcall lcd_enable
           rcall delay50us
           ret								;87 CLOCKS

 ;erzeugt den Enable-Puls
lcd_enable:
           sbi PORTB, 5                 ;Enable high
           ; ============================= 
;   Warteschleifen-Generator 
;     48 Zyklen:
; ----------------------------- 
; warte 48 Zyklen:
          ldi  temp1, $10
WGLOOP0:  dec  temp1
          brne WGLOOP0
; ============================= 
           cbi PORTB, 5                 ;Enable wieder low
           ret                          ;Und wieder zurück                     
delay50us:

 ;Pause nach jeder Übertragung
; ============================= 
;   Warteschleifen-Generator 
;     800 Zyklen:
; ----------------------------- 
; warte 798 Zyklen:
          ldi  temp1, $02
WGLOOP1:  ldi  temp2, $84
WGLOOP2:  dec  temp2
          brne WGLOOP2
          dec  temp1
          brne WGLOOP1
; ----------------------------- 
; warte 2 Zyklen:
          nop
          nop
; ============================= 

           ret                          ;wieder zurück

 ;Längere Pause für manche Befehle
delay5ms:                               ;5ms Pause
; ============================= 
;   Warteschleifen-Generator 
;     80000 Zyklen:
; ----------------------------- 
; warte 79998 Zyklen:
          ldi  temp1, $86
WGLOOP3:  ldi  temp2, $C6
WGLOOP4:  dec  temp2
          brne WGLOOP4
          dec  temp1
          brne WGLOOP3
; ----------------------------- 
; warte 2 Zyklen:
          nop
          nop
; ============================= 
           ret                          ;wieder zurück

 ;Initialisierung: muss ganz am Anfang des Programms aufgerufen werden
lcd_init:
           ldi	temp3,50
powerupwait:
           rcall	delay5ms
           dec	temp3
           brne	powerupwait
           ldi temp1, 0b00000011        ;muss 3mal hintereinander gesendet
           out PORTB, temp1             ;werden zur Initialisierung
           rcall lcd_enable             ;1
           rcall delay5ms
           rcall lcd_enable             ;2
           rcall delay5ms
           rcall lcd_enable             ;und 3!
           rcall delay5ms
           ldi temp1, 0b0010            ;4bit-Modus einstellen
           out PORTB, temp1
           rcall lcd_enable
           rcall delay5ms
           ldi temp1, 0b00101000        ;noch was einstellen...
           rcall lcd_command
           ldi temp1, 0b00001100        ;...nochwas...
           rcall lcd_command
           ldi temp1, 0b00000110        ;endlich fertig
           rcall lcd_command
		   rcall lcd_clear
           ret

 ;Sendet den Befehl zur Löschung des Displays
lcd_clear:
           ldi temp1, 0b00000001   ;Display löschen
           rcall lcd_command
           rcall delay5ms
           ret


lcd_wait:
	; ============================= 
; ============================= 
;   Warteschleifen-Generator 
;     96000000 Zyklen:
; ----------------------------- 
; warte 49939965 Zyklen:
          ldi  temp1, $FF
WGLOOP5:  ldi  temp2, $FF
WGLOOP6:  ldi  temp3, $FF
WGLOOP7:  dec  temp3
          brne WGLOOP7
          dec  temp2
          brne WGLOOP6
          dec  temp1
          brne WGLOOP5
; ----------------------------- 
; warte 46052235 Zyklen:
          ldi  temp1, $FF
WGLOOP8:  ldi  temp2, $ED
WGLOOP9:  ldi  temp3, $FD
WGLOOP10:  dec  temp3
          brne WGLOOP10
          dec  temp2
          brne WGLOOP9
          dec  temp1
          brne WGLOOP8
; ----------------------------- 
; warte 7797 Zyklen:
          ldi  temp1, $17
WGLOOP11:  ldi  temp2, $70
WGLOOP12:  dec  temp2
          brne WGLOOP12
          dec  temp1
          brne WGLOOP12
; ----------------------------- 
; warte 3 Zyklen:
          ldi  temp1, $01
WGLOOP13:  dec  temp1
          brne WGLOOP13
; ============================= 

ret







		





;_________________________
;HIER SIND SRAM EINTRÄGE
;------------------------

.dseg
CMD:  .byte 6

.dseg
response_save:  .byte 1

.dseg 
response_ini:  .byte 2

.dseg 
response_read:  .byte 2

.dseg 
addresse:   .byte 4

.dseg
cluster:   .byte 512
