 LIST P=16F687, R=DEC, ST=OFF, MM=OFF
 INCLUDE "p16F687.inc"

 __CONFIG _FCMEN_OFF & _IESO_OFF & _BOR_OFF & _CP_OFF & _CPD_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC 

#define BAUD 2400				; baud rate
#define XTAL 20					; crystal freq in MHz
#define X ((XTAL*1000000)/(BAUD*64))-1
#define CS PORTC,6

;  Data segment
 CBLOCK 0x20                  
 ind, msgNo, temp, cnt			; local variables
 cmd, crc						; MMC command and CRC7 check
 arg:4							; MMC command argument
 resp							; MMC response
 ENDC

; Code segment
 ORG 0
	goto	main

 ORG 4
	retfie

msg1
	movf	ind, w
	addwf	PCL, f
	dt 13, 10, 13, 10, "UART module is running", 13, 10, 0

msg2
	movf	ind, w
	addwf	PCL, f
	dt "MMC module is active", 13, 10, 0

msg3
	movf	ind, w
	addwf	PCL, f
	dt " CMD0 is through", 13, 10, 0

msg4
	movf	ind, w
	addwf	PCL, f
	dt " CMD1 is through", 13, 10, 0

msg5
	movf	ind, w
	addwf	PCL, f
	dt " MMC error", 13, 10, 0

msg6
	movf	ind, w
	addwf	PCL, f
	dt " reading block: ", 13, 10, 0	

msg7
	movf	ind, w
	addwf	PCL, f
	dt 13, 10, "end of code", 13, 10, 0	

msg8
	movf	ind, w
	addwf	PCL, f
	dt " writing block...", 13, 10, 0

msg9
	movf	ind, w
	addwf	PCL, f
	dt " block size is set", 13, 10, 0

getNextChar
	movf	msgNo, w
	addwf	PCL, f
	return
	goto	msg1
	goto	msg2
	goto	msg3
	goto	msg4
	goto	msg5
	goto	msg6
	goto	msg7
	goto	msg8
	goto	msg9

sendChar
	btfss	PIR1, TXIF			; TX buffer is full?
	 goto	$-1					; YES - wait
	movwf	TXREG				; send out byte
	return

sendString						; outputs string with number in WREG
	movwf	msgNo				; set message number
	clrf	ind					; start the message
	
	movf	ind, w				; next char index
	call	getNextChar			; get next char
	addlw	0					; set bit Z in STATUS
	btfsc	STATUS, Z			; end of string?
	 return						; YES - return
	
	btfss	PIR1, TXIF			; TX buffer is full?
	 goto	$-1					; YES - wait
	movwf	TXREG				; send out byte

	incf	ind, f				; get to the next char
	goto	sendString+2
	return 

spi_io							; send/receive byte via SPI
	movwf	SSPBUF				; put data to send in WREG into SSPBUF
	btfss	SSPCON, WCOL		; data sent?
	 goto	$+3					; YES - proceed
	bcf		SSPCON, WCOL		; NO - reset WCOL and try again
	goto	$-4					

	bsf		STATUS, RP0			; switch to BANK 1
	btfss	SSPSTAT ^ 0x80, BF	; buffer full?
	 goto	$-1					; NO - wait
	bcf		STATUS, RP0			; back to BANK 0

	movf	SSPBUF, w			; return the received data in WREG
	return

sendMMC							; send command to MMC
	movlw	0xFF
	call	spi_io
	movf	cmd, w				; send the command byte
	call	spi_io
	movf	arg+3, w			; send 4 argument bytes starting with
	call	spi_io
	movf	arg+2, w
	call	spi_io
	movf	arg+1, w
	call	spi_io
	movf	arg, w
	call	spi_io
	movf	crc, w				; send the CRC7 byte
	call	spi_io

wait_resp						; wait a response for at most 8 cycles
	movlw	0xFF				; waiting for MMC responce
	call	spi_io
	movwf	temp				; save response
	addlw	48					; ASCII conversion
	call	sendChar			; print response
	movf	temp, w				; restore response	
	subwf	resp, w				; expected responce?
	btfsc	STATUS, Z
	 retlw 	0					; YES - return
	decfsz	cnt, f				; waiting period is over?
	 goto	wait_resp			; NO - keep waiting
	retlw	1		

initMMC
	bsf		CS					; disable MMC
	movlw	10
	movwf	ind					; send 80 dummy clocks	

	movlw	0xFF
	call	spi_io
	decfsz	ind, f	
	 goto	$-3
	bcf		CS					; enable MMC

	movlw	0x40				; ************** send CMD0
	movwf	cmd
	clrf	arg
	clrf	arg+1
	clrf	arg+2
	clrf	arg+3
	movlw	0x95
	movwf	crc
	movlw	1					; expected response
	movwf	resp
	movlw	8					; maximum number of cycles
	movwf	cnt					; to wait for expected response
	call	sendMMC
	addlw	0					; set Z flag
	movlw	3					; message of success
	btfss	STATUS, Z
	 movlw	5					; report an error
	call	sendString

	movlw	0x41				; **************** send CMD1
	movwf	cmd
	clrf	arg
	clrf	arg+1
	clrf	arg+2
	clrf	arg+3
	movlw	0xFF
	movwf	crc
	clrf	resp				; expected response
	movlw	2
	movwf	cnt
	call	sendMMC
	addlw	0
	btfss	STATUS, Z
	 goto	$-14
	movlw	4					; message of success
	btfss	STATUS, Z
	 movlw	5
	call	sendString
	return

main
	bsf		CS					; disable MMC
	bsf		STATUS, RP1			; switch to BANK 2
	clrf	ANSEL ^ 0x100		; set all pins digital
	clrf	ANSELH ^ 0x100

	bcf		STATUS, RP1	
  	bsf    	STATUS, RP0			; switch to BANK 1

	movlw	b'111000'			; setup I/O ports
	movwf	TRISA ^ 0x80
	movlw	b'10110000'
	movwf	TRISB ^ 0x80
	clrf	TRISC ^ 0x80

	movlw 	X					; load the baud rate generator
	movwf	SPBRG ^ 0x80
	movlw	b'00100000'			; enable TX for 8 data bits
	movwf	TXSTA ^ 0x80

	bcf		SSPSTAT ^ 0x80, SMP	; input is ready at the middle of clock
	bcf		SSPSTAT ^ 0x80, CKE	; 

	bcf		STATUS, RP0			; switch to BANK 0
	movlw	b'10010000'			; enable USART for 8 data bits
	movwf	RCSTA				; this automatically configures TX and RX pins

	movlw	1					; display message1
	call	sendString			; if UART is working

	bsf		SSPCON, CKP			; idle state for clock is high
	bsf		SSPCON, SSPM1		; FOSC/64 speed
	bsf		SSPCON, SSPEN		; enable SPI master
	call	initMMC

;*******SET BLOCK SIZE 512 Bytes
	movlw	0x50				; ************** send CMD
	movwf	cmd
	clrf	arg					; arg = 512
	movlw	2
	movwf	arg+1
	clrf	arg+2
	clrf	arg+3
	movlw	0xFF
	movwf	crc
	clrf	resp
	movlw	8
	movwf	cnt
	call	sendMMC
	addlw	0
	movlw	9					; message of success
	btfss	STATUS, Z
	 movlw	5					; error message
	call	sendString

;*******WRITING IN 512-BYTE MODE
	movlw	0x58				; ************** send CMD
	movwf	cmd
	clrf	arg					; arg = 512
	movlw	2
	movwf	arg+1
	clrf	arg+2
	clrf	arg+3
	movlw	0xFF
	movwf	crc
	clrf	resp
	movlw	8
	movwf	cnt
	call	sendMMC
	addlw	0
	movlw	8					; message of success
	btfss	STATUS, Z
	 movlw	5					; error message
	call	sendString

	movlw	0xFF				; write prefix
	call	spi_io
	movlw	0xFF
	call	spi_io
	movlw	0xFE
	call	spi_io

	movlw	255					; output first 255 chars
	movwf	cnt
	movlw	65
	call	spi_io				; get data byte
	decfsz	cnt, f
	 goto	$-3				
	movlw	255					; output next 255 chars
	movwf	cnt
	movlw	66
	call	spi_io				; get data byte
	decfsz	cnt, f
	 goto	$-3	
	movlw	67
	call	spi_io				; get data byte
	movlw	68
	call	spi_io				; get data byte

	movlw	0xFF				; write 2 bytes CRC
	call	spi_io
	movlw	0xFF
	call	spi_io

	movlw	0xFF				; wait for 0xFF
	call	spi_io
	sublw	0xFF
	btfss	STATUS, Z
	 goto	$-4

;*****READING in 512-BYTE MODE
	movlw	0x51				; ************** send CMD
	movwf	cmd
	clrf	arg					; arg = 512
	movlw	2
	movwf	arg+1
	clrf	arg+2
	clrf	arg+3
	movlw	0xFF
	movwf	crc
	clrf	resp
	movlw	8
	movwf	cnt
	call	sendMMC
	addlw	0
	movlw	6					; message of success
	btfss	STATUS, Z
	 movlw	5					; error message
	call	sendString

	movlw	0xFF				; wait for 0xFE
	call	spi_io
	sublw	0xFE
	btfss	STATUS, Z
	 goto	$-4

	movlw	255					; output first 255 chars
	movwf	cnt
	movlw	0xFF
	call	spi_io				; get data byte
	call	sendChar			; send it to PC
	decfsz	cnt, f
	 goto	$-4				
	movlw	255					; output next 255 chars
	movwf	cnt
	movlw	0xFF
	call	spi_io				; get data byte
	call	sendChar			; send it to PC
	decfsz	cnt, f
	 goto	$-4	
	movlw	0xFF
	call	spi_io				; get data byte
	call	sendChar			; send it to PC
	movlw	0xFF
	call	spi_io				; get data byte
	call	sendChar			; send it to PC

	movlw	0xFF				; read 2 bytes CRC
	call	spi_io
	movlw	0xFF
	call	spi_io

L10
	bsf		CS

	movlw	7
	call	sendString
	goto	$

 END