??? 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 |
Topic | Author | Date |
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 |