Email: Password: Remember Me | Create Account (Free)

Back to Subject List

Old thread has been locked -- no new posts accepted in this thread
???
04/04/07 13:45
Read: times


 
Msg Score: +1
 +1 Good Answer/Helpful
#136588 - Reference software - MMC
Responding to: ???'s previous message


FInd the reference software for your development - Code is based on ATMEL AT89S52.


;notes:
;
; 1. after each 512 byte block is sent to the MMC the card must be given time
; to actually save the bytes to flash. this takes so long that the
; microcontroller misses one cycle. this must be taken into account in
; any program that manipulates the data. this happens the first time
; on the 86th data sample and every 85 samples thereafter.
; 2. to accurately read timer 2 it must be turned off, read, then turned back
; on. it loses a total of 4 machine cycles every data sample so the
; difference between successive reads of timer 2 is always short by 4.
; 4 must thus be added to the delta in any program that manipulates the
; data. to use the values from the timer exactly, 4 must be added to the
; first value read, 8 to the second, 12 to the third etc.
; 3. if any known error occurs when reading or writing the MMC, the code resets
; the system.

;constants not defined by assembler
.EQU SPCR,0D5H
.EQU SPSR,0AAH
.EQU SPDR,086H

;ram locations for some variables
.EQU ERRORNUM,120 ;error number
.EQU WC,121 ;write counter, 85 data points = 510 bytes
.EQU OUTL,122 ;low byte sent to MMC over MOSI
.EQU OUTH,123 ;high byte sent to MMC over MOSI

.EQU ADDR0,124 ;LSB of MMC memory address to write
.EQU ADDR1,125
.EQU ADDR2,126
.EQU ADDR3,127 ;MSB of MMC memory address to write

;reset interrupt service routine
.ORG 0000h
SJMP start

;external interrupt 0 service routine (unused)
.ORG 0003h
RETI

;timer 0 interrupt service routine (unused)
.ORG 000Bh
RETI

;external interrupt 1 service routine
.ORG 0013h
ACALL serviceint1
RETI

;timer 1 interrupt service routine (unused)
.ORG 001Bh
RETI

;serial interrupt service routine (unused)
.ORG 0023h
RETI

;timer 2 interrupt service routine (unused)
.ORG 002Bh
RETI

;-------------------------------------------------------------------------------
;main routine

.ORG 0033h
start:

SETB P1.4 ;SPI pins must be high before set SPI mode
SETB P1.5 ; they are after reset but let's be sure
SETB P1.6 ; as per the atmel manual
SETB P1.7

;----------------------------------Set up SPI communications
MOV SPCR,#01011100b ;no SPI interrupt
;enable SPI
;send and receive most significant bit 1st
;set up the microcontroller as the master
;send high on SCK when idle
;latch incoming data on rising edge
;use fastest possible SCK speed (2 bits)

;----------------------------------Set up timers (timer 2 uses defaults)
MOV TMOD,#10011001b ;timer 1 only counts when INT1* is high
;timer 1 used as a timer, not counter
;with TMOD.4, sets timer 1 as 16 bit
;with TMOD.5, sets timer 1 as 16 bit
;timer 0 only counts when INT1* is high
;timer 0 used as a timer, not counter
;with TMOD.0, sets timer 0 as 16 bit
;with TMOD.1, sets timer 0 as 16 bit

SETB TR2 ;start timers running
SETB TR1
SETB TR0

;----------------------------------Set up interrupts
CLR ES ;Disable serial port interrupts
CLR ET1 ;Disable timer 1 overflow interrupt
CLR EX1 ;Disable INT1* (X) ext. interrupt for now
CLR ET0 ;Disable timer 0 overflow interrupt
CLR EX0 ;Disable INT0* (Y) external interrupt
SETB EA ;Enable interrupts

;----------------------------------Initialize MultiMediaCard
MOV ADDR3,#0
MOV ADDR2,#0
MOV ADDR1,#0
MOV ADDR0,#0
ACALL initmmc

;----------------------------------If the erase button is down, erase the card
JB P1.0,noerase

CLR P3.7 ;light the red LED to signal erase going
ACALL erase ;erase all blocks

MOV R7,20
flash: SETB P3.7 ;flash the LED 20 times to give the user
MOV A,250 ;time to power off. this is about 10 sec
ACALL waitms
CLR P3.7
MOV A,250
ACALL waitms
DJNZ R7,flash
noerase: ;jump here if we don't want to erase

;----------------------------------Find where existing data ends in memory
MOV ADDR3,#0 ;start reading at first byte
MOV ADDR2,#0
MOV ADDR1,#0
MOV ADDR0,#0


MOV R6,#245 ;check all 15680 blocks in an 8MB MMC
bloop1: MOV R5,#64 ; until we find one that is all zero
CPL P2.0 ;blink the green LED while searching
bloop2: MOV R7,#0 ;start out assuming will find no data in blk
ACALL readstart ;open next block for reading
MOV R4,#4 ;these two loops run over the 512 bytes
bloop3: MOV R3,#128 ; in each block
bloop4: MOV A,#0FFH
ACALL spiout
CJNE R0,#0FFH,hasdata
SJMP hasnodata
hasdata: MOV R7,#1
hasnodata:
DJNZ R3,bloop4
DJNZ R4,bloop3
ACALL readend
CJNE R7,#1,emptyblock
ACALL incaddr ;increment address
DJNZ R5,bloop2
DJNZ R6,bloop1

MOV ERRORNUM,#4 ;if we got here, memory is full, light the
AJMP error ; just sit here

emptyblock: ;if we got here, the last block read was
; empty. fill it with zero to act as a
; separator between the old data and the
; new data we are about to save.

ACALL writestart
MOV R7,#4
loopc1: MOV R6,#128
loopc2: MOV A,#0
ACALL spiout
DJNZ R6,loopc2
DJNZ R7,loopc1
ACALL writeend

;----------------------------------Set up writing to first empty block
ACALL writestart ;open the first MMC block for output
MOV WC,#85 ;initialize write counter,
; 6 bytes/loop*85=510 bytes,
; other 2 bytes will be filled with junk

;----------------------------------Turn on the INT1* interrupt
JNB P3.3,* ;wait for X output hi so no immed. interrupt
SETB EX1 ;enable INT1* (X) ext. interrupt

;----------------------------------Infinite loop, work done by INT1* interrupt
CLR P2.0 ;light the green LED solid while running
do:
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
SJMP do

;-------------------------------------------------------------------------------
;-----------------------------SUBROUTINES---------------------------------------
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
;----------------------------------INT1* interrupt handler, you get the
; interrupt that vectors here whenever the
; X acceleration signal is low
serviceint1:
CLR TR2 ;stop timer 2
MOV OUTL,TL2 ;read low byte of timer (1MC)
MOV OUTH,TH2 ;read high byte of timer and put in tmp (2MC)
SETB TR2 ;start timer 2 again (1MC, lost 4 cnts total)
ACALL spiwc ;write the two bytes to the MMC

MOV OUTL,TL1 ;read and store timer 1 cnt (X acceleration)
MOV OUTH,TH1 ; don't have to wait for X low as do with Y
ACALL spiwc ; below since had to happen already for intr

JB P3.2,* ;wait until Y acceleration bit goes low
MOV OUTL,TL0 ;read and store timer 0 cnt (Y acceleration)
MOV OUTH,TH0
ACALL spiwc

DJNZ WC,waitint1hi ;if block not full, jump over next 4 lines

ACALL spiwc ;fill last 2 bytes of block with whatever
; junk is already in OUTL and OUTH
ACALL writeend ;Allow MMC to store block to flash
ACALL writestart ;Open the next MMC block for output
MOV WC,#85 ;reinitialize write counter

waitint1hi:
JNB P3.3,* ;wait here until X accel output goes high
; otherwise we will immediately interrupt
; again
RET ;RETI handled in interrupt block

;-------------------------------------------------------------------------------
;----------------------------------Initialize MultiMediaCard
initmmc:
SETB P1.4 ;Take CS* high
MOV A,0FFH
ACALL spiout
MOV A,0FFH
ACALL spiout
MOV A,0FFH
ACALL spiout
MOV A,0FFH
ACALL spiout
MOV A,0FFH
ACALL spiout
MOV A,0FFH
ACALL spiout
MOV A,0FFH
ACALL spiout
MOV A,0FFH
ACALL spiout

CLR P1.4 ;take CS* low to select card

MOV A,0FFH
ACALL spiout
MOV A,0FFH
ACALL spiout

MOV A,#0 ;send CMD0 to enable SPI mode on MMC
ACALL cmd
MOV A,#0FFH ;enable the MMC to finish
ACALL spiout

notready:
MOV A,#1
ACALL cmd

CJNE R0,#1,ready ;return if the MMC is ready
MOV A,#0FFH ;enable the MMC to finish
ACALL spiout
SJMP notready

ready:
MOV A,#0FFH ;enable the MMC to finish if we got here
ACALL spiout
RET

;-------------------------------------------------------------------------------
;----------------------------------Send a byte from ACC to MOSI, result=R0
spiout:
MOV SPDR,A
ACALL waitspi
MOV R0,SPDR

RET

;-------------------------------------------------------------------------------
;----------------------------------Writes two bytes of data to the MMC
spiwc:
MOV SPDR,OUTL ;Send the low byte out on MOSI
ACALL waitspi ;Wait for the byte to shift out
MOV SPDR,OUTH ;Send the high byte out on MOSI
ACALL waitspi ;Wait for the byte to shift out

RET

;-------------------------------------------------------------------------------
;----------------------------------Send a CMD to the MMC
cmd:
ORL A,#01000000b ;CMD's always have bit 7 set
ACALL spiout ;send command byte
MOV A,ADDR3 ;send 4 argument bytes
ACALL spiout
MOV A,ADDR2
ACALL spiout
MOV A,ADDR1
ACALL spiout
MOV A,ADDR0
ACALL spiout
MOV A,#95H ;checksum, 95H for CMD0, ignored for rest
ACALL spiout

MOV R1,#8 ;read up to 8 times for valid response
checkr:
MOV A,#0FFH
ACALL spiout
CJNE R0,#255,response
DJNZ R1,checkr

MOV ERRORNUM,#1 ;didn't get a valid response, stop
AJMP error

response: ;can't check to see if good: cmd0/1 not
RET

;-------------------------------------------------------------------------------
;----------------------------------Wait for the SPI data to shift out
waitspi:
MOV A,SPSR ;read the status register
ANL A,#10000000b ;upper bit=1 when data is gone
CJNE A,#10000000b,waitspi ;if only bit 7 set, the data is gone
RET

;-------------------------------------------------------------------------------
;----------------------------------Erases the entire MMC by filling with 0xffh
erase:
MOV ADDR3,#0 ;start at address zero
MOV ADDR2,#0
MOV ADDR1,#0
MOV ADDR0,#0

MOV OUTL,#255 ;will use "spiwc" to write 2 bytes at a time
MOV OUTH,#255

MOV R7,#64
eloop1: MOV R6,#245
CPL P2.0 ;flash green LED
eloop2: ACALL writestart
MOV R5,#128
eloop3: ACALL spiwc
ACALL spiwc
DJNZ R5,eloop3
ACALL writeend
DJNZ R6,eloop2
DJNZ R7,eloop1

SETB P2.0 ;turn the green LED off when done

RET

;-------------------------------------------------------------------------------
;----------------------------------Starts writing a block of data
writestart:
MOV A,#24 ;command 24 = "write block"
ACALL cmd
MOV A,#0FFH ;let MMC finish
ACALL spiout
MOV A,#0FEH ;send data start token
ACALL spiout
ACALL incaddr ;increment the address for next time

RET

;-------------------------------------------------------------------------------
;----------------------------------Finishes writing a block of data
writeend:
MOV A,#0FFH ;Send dummy data CRC to card
ACALL spiout

waitr: ;Loop waiting for response from card
MOV A,#0FFH
ACALL spiout
CJNE R0,#0FFH,gotr
SJMP waitr

gotr: ;Got a response
MOV A,R0
ANL A,#00011111b ;Mask off top three bits since undefined
CJNE A,#00000101b,badr ;reset if the response was bad
SJMP goodr ;skip the error stuff if response was good

badr: MOV ERRORNUM,#2 ;had an error, stop
AJMP error

goodr:
busy: ;wait for the card to finish programming
MOV A,#0FFH
ACALL spiout
CJNE R0,#00H,programmed
SJMP busy

programmed:
MOV A,#0FFH
ACALL spiout
; MOV A,#13
; ACALL cmd

; MOV A,#0FFH ;check 2nd status byte (1st done by "cmd")
; ACALL spiout
; MOV A,#0FFH ;let the card finish
; ACALL spiout
; CJNE R0,#00000000b,badstatus
; SJMP goodwrite

badstatus: ;had an error, restart the system
; AJMP start

goodwrite:
RET

;-------------------------------------------------------------------------------
;----------------------------------Opens a block for reading
readstart:
MOV A,#17 ;send cmd 17, "read block"
ACALL cmd

MOV R2,#255
wfe1: MOV R1,#255
wfe2: MOV A,#0FFH ;wait for start of data byte (FEH)
ACALL spiout
CJNE R0,#0FFH,gotfe
DJNZ R1,wfe2
DJNZ R2,wfe1

MOV ERRORNUM,#3 ;never received FEh, stop
AJMP error

gotfe: ;got either a data token or data error token
CJNE R0,#0FEH,badfe
SJMP goodfe

badfe: MOV ERRORNUM,#5
AJMP error

goodfe: ;got a valid data token
RET

;-------------------------------------------------------------------------------
;----------------------------------Read a byte of data from the MMC
spirc:
MOV SPDR,#0FFH ;shift out 0FFH to cause data to shift in
ACALL waitspi ;wait for the byte to finish shifting in
MOV R0,SPDR ;store the byte read in R0
RET

;-------------------------------------------------------------------------------
;----------------------------------Finish reading a block of data
readend:
MOV A,#0FFH ;"read" dummy 16bit data CRC
ACALL spiout
MOV A,#0FFH
ACALL spiout
MOV A,#0FFH ;make sure card is done
ACALL spiout
RET

;-------------------------------------------------------------------------------
;----------------------------------Increment the MMC memory address
incaddr:
MOV ADDR0,#0 ;ensure LSB of address always zero
MOV A,ADDR1
CLR C
ADDC A,#2 ;increment write address by 2 means jump
MOV ADDR1,A
JNC donea
MOV A,ADDR2
CLR C
ADDC A,#1 ;increment 3rd address byte if needed
MOV ADDR2,A
JNC donea
CLR C
INC ADDR3 ;increment 4th address byte if needed
donea:
RET

;-------------------------------------------------------------------------------
;----------------------------------Millisecond delay routine, waits ACC ms
waitms: DEC A ;Note, if A=1, may fail
MOV R1,A
loopm1: MOV R2,#4 ;1000 loops just over 1ms @ 24MHz
loopm2: MOV R3,#250
DJNZ R3,*
DJNZ R2,loopm2
DJNZ R1,loopm1
RET

;-------------------------------------------------------------------------------
;----------------------------------Error handler, num blinks each time=error #
error:
SETB P2.0
SETB P3.7
MOV R7,ERRORNUM ;blink red led number of times=error #
count: CLR P3.7 ;light the red LED
MOV A,#166 ;wait 0.166 secs
ACALL waitms
SETB P3.7 ;turn off the red LED
MOV A,#167 ;wait 0.167 secs
ACALL waitms
DJNZ R7,count
MOV A,#250 ;wait a second with red LED off
ACALL waitms
MOV A,#250
ACALL waitms
MOV A,#250
ACALL waitms
MOV A,#250
ACALL waitms
SJMP error ;repeat the error endlessly

;------------------------------------------------------------------------
.END



List of 10 messages in thread
TopicAuthorDate
AT89C51ED2 SD/MMC interface            01/01/70 00:00      
   I do not know about Atmel            01/01/70 00:00      
   Maybe...            01/01/70 00:00      
      Re: Maybe...            01/01/70 00:00      
         I do,            01/01/70 00:00      
            How about this?            01/01/70 00:00      
            Re: I do,            01/01/70 00:00      
               SILabs chipa ARE 8051 derivatives            01/01/70 00:00      
   Atmel SPI            01/01/70 00:00      
   Reference software - MMC            01/01/70 00:00      

Back to Subject List