⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mmc.asm

📁 AVR ATMega library for using MMC /SD cart.
💻 ASM
字号:
/* ***********************************************************************
**
**  Copyright (C) 2002  Jesper Hansen <jesperh@telia.com> and 
**			Romuald Bialy (MIS) <romek_b@o2.pl>.
**
**
**  Yampp-7/USB   - low level support library
**  File: mmc.asm - MultiMedia Card Support 
**
*************************************************************************
**
**   This file is part of the yampp system.
**
**  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.
**
*************************************************************************
**
**  Revision History
**
**  when         what  who	why
**
**  2003-01-22   1.0   MIS      initial public release
**  2003-07-14   1.1   MIS      added watchdog resets to USB<->CARD functions
**  2003-09-13   1.2   MIS      fixed card busy checking - speed up write about 60%
**
*********************************************************************** */

#define __ASSEMBLER__ 1
#define __SFR_OFFSET 0
#include <avr/io.h>

#define MMC_ASM
#include "mmc.h"

#define __tmp_reg__	r0
#define __zero_reg__	r1


#define USB_PORT	PORTD
#define USB_TXRDY	PD3
#define USB_RXRDY	PD2
#define USB_ADDR	0x8000

.section	.text

.extern vs1001_init_io
.extern usb_writeblock
 
;******************************************************************************* 
;*                          MMC Interface stuff				       *
;******************************************************************************* 



; 512 byte sector buffer in internal RAM

.global mmc_sbuf
	.comm	mmc_sbuf,512
	.comm	lba,3

.global mmc_response
	.comm	mmc_response,10


get_spi_byte:
		ser	r24
spi_tx_rx:
		out 	SPDR, r24			; send over SPI
vspi1:		sbis 	SPSR,SPIF			; while flag is clear
 		rjmp 	vspi1				; wait for SPI
 		in 	r24, SPDR			; and get input data
		ret					; done

;-------------------------------------------------------------------------------

IncLBA:							; LBA[0..24]++;
		lds	r22,(lba+0)
		lds	r23,(lba+1)
		lds	r24,(lba+2)
		sec
		adc	r22,__zero_reg__
		adc	r23,__zero_reg__
		adc	r24,__zero_reg__
		ret

;-------------------------------------------------------------------------------

StoreLBA:
		sts	(lba+0),r22
		sts	(lba+1),r23
		sts	(lba+2),r24
		ret
;-------------------------------------------------------------------------------

SendMmcCmd_0:					; r20 - cmd
		clr	r25			; all parameters = 0
		clr	r23
		clr	r22
		rjmp	SendMmcCmd

;-------------------------------------------------------------------------------
DecodeLBA:						; LBA[0..24] << 9
		lds	r22,(lba+0)
		lds	r23,(lba+1)
		lds	r24,(lba+2)
		lsl	r22
		rol	r23
		rol	r24
		mov	r25,r24
SendMmcCmd:					; r22,r23,r25 - param, r20 - cmd
		cbi	MMC_PORT,MMC_CS		; activate chip select

		mov	r24,r20
		ori	r24,0x40		; mmc comand
		rcall	spi_tx_rx
		mov	r24,r25			; arg [24..31]
		rcall	spi_tx_rx
		mov	r24,r23			; arg [16..23]
		rcall	spi_tx_rx
		mov	r24,r22			; arg [8..15]
		rcall	spi_tx_rx
		ldi	r24,0			; arg [0..7]
		rcall	spi_tx_rx
		ldi	r24,0x95		; good checksum for cmd 64 0 0 0 0 
		rcall	spi_tx_rx		; for others it's ignored

		ldi	r25,10

get_resp:
		rcall	get_spi_byte		; read card response

		sbrs	r24,7
		rjmp	cmdok

		dec	r25
		brne	get_resp

		ser	r24
		
cmdok:		ret

;-------------------------------------------------------------------------------
;
; clear MMC cycle 
;

FlushMMC_END:	rcall	FlushMMC
		rjmp	mmcFinish
	
FlushMMC:	push	r24			; count in r20
FlushMMCloop:	rcall	get_spi_byte		; read byte from MMC
		dec	r20
		brne	FlushMMCloop
		pop	r24
		ret

;-------------------------------------------------------------------------------
;
; wait for MMC 0xFE data token or error token
;

; ogranicznie do 255 bajtow
; bylo za male 
; karta Kingston 128MB potrzebowala ok 270 bajtow i dopiero odpowiadala


Read_Tag:	push	r26

		ldi	r26, 64		;; by ao
		ldi	r25, 0		;; by ao

readTag1:	dec	r25
		brne	skip

		dec	r26		;; by ao
		breq	rt1		;; by ao

skip:
		rcall	get_spi_byte			; read byte from MMC
		cpi	r24,0xFE			; check for data token
		breq	rt1
		andi	r24,0xf1			; check for data error token
		cpi	r24,0x01
		brne	readTag1	;; by ao

		;;brne	Read_Tag			; wait for data or error

rt1:		
		pop	r26
		ret

;-------------------------------------------------------------------------------

;u08 MMC_Reset(void);
	.global MMC_Reset
MMC_Reset:
		sbi	MMC_PORT, MMC_CS		; set CS high
		sbi	MMC_PORT-1, MMC_CS		; set CS as output

;;		call	vs1001_init_io

		ldi	r20,10
		rcall	FlushMMC			; 80 empty spi clocks

		ldi	r20,MMC_GO_IDLE_STATE
		rcall	SendMmcCmd_0			; set card in idle state
		rcall	mmcFinish
		andi	r24,0x85
		cpi	r24,1
		breq	rstchk
RST_Error:	clr	r25
		clr	r24				; return with NO CARD status
		ret

rstchk:		ldi	r20,MMC_SEND_OP_COND
		rcall	SendMmcCmd_0			; initialize operating conditions
		rcall	mmcFinish
		tst	r24
		brne	rstchk

		ldi	r20,MMC_SET_BLOCKLEN		; Set MMC block len
		ldi	r22,2				; to 512 bytes
		;;ldi	r23,255
		clr	r23
		clr	r25
		;;ldi	r25,16
		rcall	SendMmcCmd			; execute command
		rcall	mmcFinish
		tst	r24
		brne	RST_Error
		ser	r24				; Reset OK
		clr	r25
		ret

;-------------------------------------------------------------------------------
;void MMC_Off(void);
	.global MMC_Off
MMC_Off:
		ldi	r20,MMC_GO_IDLE_STATE
		rcall	SendMmcCmd_0			; set card in idle state
		rjmp	mmcFinish

;-------------------------------------------------------------------------------


	.global MMC_Read
;	      r25..r22
;u08 MMC_Read(u32 lba) 

MMC_Read:
		rcall	StoreLBA
		ldi	r20,MMC_READ_SINGLE_BLOCK
		rcall	DecodeLBA			; decode LBA and execute command
		tst	r24
		brne	mmcFinish

		rcall	Read_Tag
  		ldi 	r31,hi8(mmc_sbuf)
 		ldi 	r30,lo8(mmc_sbuf)
		clr	r20
read_loop:
		rcall	get_spi_byte			; read byte from MMC
		st	Z+,r24
		rcall	get_spi_byte			; read byte from MMC
		st	Z+,r24
		dec	r20
		brne	read_loop		

		clr	r24
		ldi	r20,2				;  drop CRC
		rjmp	FlushMMC_END

;-------------------------------------------------------------------------------

mmcFinish:					; deactivates MMC
		push	r24
		sbi	MMC_PORT,MMC_CS		; release chip select 
	  	rcall 	get_spi_byte		; one empty SPI cycle
		pop	r24
		ret


;-------------------------------------------------------------------------------

	.global MMC_Write
;	      r25..r22
;u08 MMC_Write(u32 lba) 

MMC_Write:
		rcall	StoreLBA
MMC_Write1:
		ldi	r20,MMC_WRITE_BLOCK
		rcall	DecodeLBA			; decode LBA and execute command
		tst	r24
		brne	mmcFinish

		rcall	get_spi_byte			; one empty cycle
		ldi	r24,0xFE			; send tag
		rcall	spi_tx_rx

  		ldi 	r31,hi8(mmc_sbuf)
 		ldi 	r30,lo8(mmc_sbuf)
		clr	r20
write_loop:
		ld	r24,Z+
		rcall	spi_tx_rx			; write byte to MMC
		ld	r24,Z+
		rcall	spi_tx_rx			; write byte to MMC
		dec	r20
		brne	write_loop		
USB_WR_HLP:
		clr	r24
		rcall	spi_tx_rx			; write CRC
		clr	r24
		rcall	spi_tx_rx			; write CRC
write_reply:	rcall	get_spi_byte
		andi	r24,0x1F
		cpi	r24,0x05
		brne	write_reply
wbusy:		rcall	delay100
		rcall	delay100		; delay 200us
		rcall	get_spi_byte		; check for busy
		inc	r24
		brne	wbusy			; card is busy
		clr	r24
		rjmp	mmcFinish

;-------------------------------------------------------------------------------
; This procedure is maximally optimized for best speed, but is little longer.
; Sorry, speed is needed.
;
;		    r25..r22 		r20     	
;u08 MMC_Write_USB( u32 lba,  u08 numsectors);
;	
	.global MMC_Write_USB

MMC_Write_USB:
		mov	r21,r20				; save numsectors
.UBW0:
		rcall	StoreLBA
		wdr
		ldi	r20,MMC_WRITE_BLOCK
		rcall	DecodeLBA			; decode LBA and execute command
		tst	r24
		brne	mmcFinish			; return with error

		rcall	get_spi_byte			; one empty cycle
		ldi	r24,0xFE			; tag
		out 	SPDR, r24

		ldi	r31,hi8(USB_ADDR)
		ldi	r30,lo8(USB_ADDR)		; Z points to USB
		clr	r20				; loop count = 256 words

.getusb0:	sbic 	USB_PORT-2,USB_RXRDY		; while flag is set
 		rjmp 	.getusb0			; wait for bit to be cleared
		ld	r24,Z				; get byte from USB
.waitspi0:	sbis 	SPSR,SPIF			; while flag is clear
		rjmp 	.waitspi0			; wait for SPI
;		in	r0,SPDR				; clear SPIF flag
		out 	SPDR, r24			; send over SPI

.getusb1:	sbic 	USB_PORT-2,USB_RXRDY		; while flag is set
 		rjmp 	.getusb1			; wait for bit to be cleared
		ld	r24,Z				; get byte from USB
.waitspi1:	sbis 	SPSR,SPIF			; while flag is clear
		rjmp 	.waitspi1			; wait for SPI
;		in	r0,SPDR				; clear SPIF flag
		out 	SPDR, r24			; send over SPI

		dec	r20
		brne	.getusb0

.waitspi2:	sbis 	SPSR,SPIF			; while flag is clear
		rjmp 	.waitspi2			; wait for SPI
;		in	r0,SPDR				; clear SPIF flag

		rcall	USB_WR_HLP			; write CRC and read ACK

		dec	r21				; dec sector counter
		breq	.RTU1

		rcall	IncLBA
		rjmp	.UBW0

;-------------------------------------------------------------------------------

	.global MMC_Read_USB
;		   r25..r22 		r20     	
;u08 MMC_Read_USB( u32 lba,  u08 numsectors);
;	
MMC_Read_USB:
		mov	r21,r20				; save numsectors
.RTU0:
		wdr
		rcall	MMC_Read			; read from MMC to RAM

		ldi	r25,hi8(mmc_sbuf)
		ldi	r24,lo8(mmc_sbuf)		; Z points to buffer
		ldi	r23,2				; 512 bytes length
		clr	r22

;;		call	usb_writeblock			; send buffer to USB

		dec	r21				; dec sector counter
		breq	.RTU1

		rcall	IncLBA
		rjmp	.RTU0

.RTU1:		clr	r24				; TODO! Return error values
		clr	r25
.RTU2:		ret


;-------------------------------------------------------------------------------

	.global MMC_Name
MMC_Name:
		ldi	r20,MMC_SEND_CID
		rcall	SendMmcCmd_0
		rcall	Read_Tag			; wait for data token
		ldi	r20,3				; skip first 3 bytes of CID
		rcall	FlushMMC

		ldi	r31,hi8(mmc_sbuf)
		ldi	r30,lo8(mmc_sbuf)		; Z points to buffer
		ldi	r20,7				; 7 bytes of name
.IN3:
		rcall	get_spi_byte
		st	Z+,r24
		dec	r20
		brne	.IN3

		clr	r24
		ldi	r20,8				; flush last 6 bytes of CID
		rjmp	FlushMMC_END			; + 2 byte of CRC

;-------------------------------------------------------------------------------

;
;u32 MMC_Capacity(void)
	.global MMC_Capacity
MMC_Capacity:
		ldi	r20,MMC_SEND_CSD
		rcall	SendMmcCmd_0
		rcall	Read_Tag			; wait for data token
		ldi	r20,6
		rcall	FlushMMC			; skip first 6 bytes of CSD

	; get size into reg 
	;
	; xxxx xxxx    xxxx xxxx    xxxx xxxx
	;        ^^    ^^^^ ^^^^    ^^ 

		rcall	get_spi_byte
		andi	r24,0x03
		mov	r23,r24				; save two highest bits
		rcall	get_spi_byte
		mov	r22,r24				; save middle bits
		rcall	get_spi_byte			; get lowest two bits
		lsl	r24
		rol	r22
		rol	r23
		lsl	r24
		rol	r22
		rol	r23				; shift the result by two bits left
							; now size is in r23:r22

	; get multiplier
	;
	; xxxx xxxx    xxxx xxxx
	;        ^^    ^

		rcall	get_spi_byte			; get byte
		andi	r24,0x03
		mov	r20,r24				; save it
		rcall	get_spi_byte			; get byte
		lsl	r24
		rol	r20				; multiplier in r20
		
		clr	r24
		sec
		adc	r22,__zero_reg__		; sectors = (size+1)<<(multiplier+2)
		adc	r23,__zero_reg__
		adc	r24,__zero_reg__
		clr	r25
		inc	r20
		inc	r20				; multiplier+2
sh_loop:
		lsl	r22
		rol	r23
		rol	r24
		rol	r25
		dec	r20
		brne	sh_loop
							; size in r25..r22

		ldi	r20,7				; flush last 5 bytes of CSD
		rjmp	FlushMMC_END			; + 2 byte of CRC

;-------------------------------------------------------------------------------


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -