这是一个MSP430与MMC/SD卡接口设计,提供纯源代码。真正DIY设计! 由Rolf Freitag先生提供。
原文:A self documenting project (C source code) for reading/writing on MMC/SD cards in spi mode and with a hello world LED as output. The code works with many MMC/SD cards but not all; it is beta. The reasons are that some waiting times are not limited in the standard and that the cards are a little outside the standard specifications.
For a release version, which does not cost much and which has a mapping layer for reading/writing 1..512 Bytes starting at any address, you can contact me.
In 2003 TI planned to release an application note to this code but it seems that plan died.
I published the code under a beerware license: main.c mmc.c mmc.h led.c led.h
Program for Communikation of an MSP430F149 and an MMC via SPI in unprotected Mode.
Sytem quartz: 8 MHz, layout: see mmc.h.
Version 0.02 from 11. May 2003
Status: Everything works, but approx. 2 % of all MMC/SDCs do need some longer waiting cycles,
because some times are not limitated in the standards and every card is not strictly standard
conforming; they all do need more waiting cycles as specified in the standards.
*********************************************************/
/* * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 43): * Rolf Freitag (webmaster at true-random.com) wrote this file. * As long as you retain this notice you can do whatever * the LGPL (Lesser GNU public License) allows with this stuff. * If you think this stuff is worth it, you can send me money via * paypal or if we met some day you can buy me a beer in return. * ---------------------------------------------------------------------------- */
#include <msp430x14x.h>
#include <string.h>
#include "mmc.h"
#include "led.h"
extern char card_state;
extern char mmc_buffer[512];
char card_state = 0; // card state: 0: not found, 1 found (init successfull)
unsigned long loop;
void main (void)
{ volatile unsigned char dco_cnt = 255;
BCSCTL1 &= ~XT2OFF; // XT2on do // wait for MCLK from quartz { IFG1 &= ~OFIFG; // Clear OSCFault flag for (dco_cnt = 0xff; dco_cnt > 0; dco_cnt--); // Time for flag to set } while ((IFG1 & OFIFG) != 0); // OSCFault flag still set?
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
BCSCTL1 = 0x07; // LFXT1: XT2on: LF quartz for MCLK
// Port 4 Function Dir On/Off // 4.0-Led red Out 0 - off 1 - On // 4.1-Led green Out 0 - off 1 - On // 4.5-CardDetected ? 0 - ? 1 - ? // 4.6-WriteProtected ? 0 - ? 1 - ? // D 7 6 5 4 3 2 1 0 P4SEL = 0x00; // 0 0 0 0 0 0 0 0 P4DIR = 0x03; // 0 0 0 0 0 0 1 1 P4OUT = 0x00;
// Port 5 Function Dir On/Off // 5.1-Dout Out 0 - off 1 - On // 5.2-Din Inp 0 - off 1 - On // 5.3-Clk Out - // 5.4-mmcCS Out 0 - Active 1 - none Active
P5SEL = 0x00; P5DIR = 0xff; P5OUT = 0xfe;
P6SEL = 0x00; P6OUT = 0x00; P6DIR = 0xff;
ADC12IE = 0; ADC12IFG = 0;
initLED(); for (;;) { // switch on red led to indicate -> insert card
// #ifdef DeBuG0 RED_LED_ON(); GREEN_LED_OFF(); // Card insert? while(P4IN&0x20); //switch off both led's GREEN_LED_OFF(); RED_LED_OFF(); //init mmc card if (initMMC() == MMC_SUCCESS) // card found { card_state |= 1; GREEN_LED_ON(); // Read Out Card Type and print it or trace memory memset(&mmc_buffer,0,512); mmcReadRegister (10, 16); mmc_buffer[7]=0; // PLease mofify based on your Compiler sim io function // debug_printf("Multi Media Card Name: %s",&mmc_buffer[3]);
// Fill first Block (0) with 'A' memset(&mmc_buffer,'A',512); //set breakpoint and trace mmc_buffer contents mmcWriteBlock(0x00); // Fill second Block (1)-AbsAddr 512 with 'B' memset(&mmc_buffer,'B',512); mmcWriteBlock(512);
// Read first Block back to buffer memset(&mmc_buffer,0x00,512); mmcReadBlock(0x00,512); memset(&mmc_buffer,0x00,512); //set breakpoint and trace mmc_buffer contents mmcReadBlock(512,512); memset(&mmc_buffer,0x00,512); //set breakpoint and trace mmc_buffer contents }
else { //Error card not detected or rejected during writing // switch red led on card_state = 0; // no card RED_LED_ON(); }
// #endif
} // return;
}
[COLOR=red]mmc.h[/COLOR]
/* mmc.h: Dekcarations for Communikation with the MMC (see mmc.c) in unprotected spi mode.
Revisions Date Author Revision 11. May 2003 Rolf Freitag 0.02
(2004: corrected MC pin numbers (switched only 45, 46))
*/
/* * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 44): * Rolf Freitag (webmaster at true-random.com) wrote this file. * As long as you retain this notice you can do whatever * the LGPL (Lesser GNU public License) allows with this stuff. * If you think this stuff is worth it, you can send me money via * paypal or if we met some day you can buy me a beer in return. * ---------------------------------------------------------------------------- */
#ifndef _MMCLIB_H
#define _MMCLIB_H
#ifndef TXEPT // transmitter-empty flag
#define TEXPT 0x01
#endif
// macro defines
#define HIGH(a) ((a>>8)&0xFF) // high byte from word
#define LOW(a) (a&0xFF) // low byte from word
// Tokens (nessisary because at nop/idle (and CS active) only 0xff is on the data/command line)
#define MMC_START_DATA_BLOCK_TOKEN 0xfe // Data token start byte, Start Single Block Read
#define MMC_START_DATA_MULTIPLE_BLOCK_READ 0xfe // Data token start byte, Start Multiple Block Read
#define MMC_START_DATA_BLOCK_WRITE 0xfe // Data token start byte, Start Single Block Write
#define MMC_START_DATA_MULTIPLE_BLOCK_WRITE 0xfc // Data token start byte, Start Multiple Block Write
#define MMC_STOP_DATA_MULTIPLE_BLOCK_WRITE 0xfd // Data toke stop byte, Stop Multiple Block Write
// an affirmative R1 response (no errors)
#define MMC_R1_RESPONSE 0x00
// this variable will be used to track the current block length
// this allows the block length to be set only when needed
// unsigned long _BlockLength = 0;
/* * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 44): * Rolf Freitag (webmaster at true-random.com) wrote this file. * As long as you retain this notice you can do whatever * the LGPL (Lesser GNU public License) allows with this stuff. * If you think this stuff is worth it, you can send me money via * paypal or if we met some day you can buy me a beer in return. * ---------------------------------------------------------------------------- */
//raise SS and MOSI for 80 clock cycles //SendByte(0xff) 10 times with SS high //RAISE SS int i; char response=0x01;
// debug_printf("Start iniMMC......"); initSPI(); //initialization sequence on PowerUp CS_HIGH(); for(i=0;i<=9;i++) spiSendByte(0xff); CS_LOW(); //Send Command 0 to put MMC in SPI mode mmcSendCmd(0x00,0,0x95); //Now wait for READY RESPONSE if(mmcGetResponse()!=0x01); // debug_printf("no responce");
while(response==0x01) { // debug_printf("Sending Command 1"); CS_HIGH(); spiSendByte(0xff); CS_LOW(); mmcSendCmd(0x01,0x00,0xff); response=mmcGetResponse(); } CS_HIGH(); spiSendByte(0xff); // debug_printf("MMC INITIALIZED AND SET TO SPI MODE PROPERLY."); return MMC_SUCCESS;
}
// Ti added mmc Get Responce
char mmcGetResponse(void)
{ //Response comes 1-8bytes after command //the first bit will be a 0 //followed by an error code //data will be 0xff until response int i=0;
char mmcGetXXResponse(const char resp)
{ //Response comes 1-8bytes after command //the first bit will be a 0 //followed by an error code //data will be 0xff until response int i=0;
char mmcCheckBusy(void)
{ //Response comes 1-8bytes after command //the first bit will be a 0 //followed by an error code //data will be 0xff until response int i=0;
char response; char rvalue; while(i<=64) { response=spiSendByte(0xff); response &= 0x1f; switch(response) { case 0x05: rvalue=MMC_SUCCESS;break; case 0x0b: return(MMC_CRC_ERROR); case 0x0d: return(MMC_WRITE_ERROR); default: rvalue = MMC_OTHER_ERROR; break; } if(rvalue==MMC_SUCCESS)break; i++; } i=0; do { response=spiSendByte(0xff); i++; }while(response==0); return response;
}
// The card will respond with a standard response token followed by a data
// block suffixed with a 16 bit CRC.
// Ti Modification: long int -> long ; int -> long
char mmcReadBlock(const unsigned long address, const unsigned long count)
{ unsigned long i = 0; char rvalue = MMC_RESPONSE_ERROR;
// Set the block length to read if (mmcSetBlockLength (count) == MMC_SUCCESS) // block length could be set { // SS = LOW (on) CS_LOW (); // send read command MMC_READ_SINGLE_BLOCK=CMD17 mmcSendCmd (17,address, 0xFF); // Send 8 Clock pulses of delay, check if the MMC acknowledged the read block command // it will do this by sending an affirmative response // in the R1 format (0x00 is no errors) if (mmcGetResponse() == 0x00) { // now look for the data token to signify the start of // the data if (mmcGetXXResponse(MMC_START_DATA_BLOCK_TOKEN) == MMC_START_DATA_BLOCK_TOKEN) { // clock the actual data transfer and receive the bytes; spi_read automatically finds the Data Block for (i = 0; i < 512; i++) mmc_buffer = spiSendByte(0xff); // is executed with card inserted
// get CRC bytes (not really needed by us, but required by MMC) spiSendByte(0xff); spiSendByte(0xff); rvalue = MMC_SUCCESS; } else { // the data token was never received rvalue = MMC_DATA_TOKEN_ERROR; // 3 } } else { // the MMC never acknowledge the read command rvalue = MMC_RESPONSE_ERROR; // 2 } } else { rvalue = MMC_BLOCK_SET_ERROR; // 1 } CS_HIGH (); spiSendByte(0xff); return rvalue;
} // mmc_read_block
//---------------------------------------------------------------------
// Ti Modification: long int -> long
char mmcWriteBlock (const unsigned long address)
{ unsigned long i = 0; char rvalue = MMC_RESPONSE_ERROR; // MMC_SUCCESS; char c = 0x00;
// Set the block length to read if (mmcSetBlockLength (512) == MMC_SUCCESS) // block length could be set { // SS = LOW (on) CS_LOW (); // send write command mmcSendCmd (24,address, 0xFF);
// check if the MMC acknowledged the write block command // it will do this by sending an affirmative response // in the R1 format (0x00 is no errors) if (mmcGetXXResponse(MMC_R1_RESPONSE) == MMC_R1_RESPONSE) { spiSendByte(0xff); // send the data token to signify the start of the data spiSendByte(0xfe); // clock the actual data transfer and transmitt the bytes for (i = 0; i < 512; i++) spiSendByte(mmc_buffer); // mmc_buffer; Test: i & 0xff // put CRC bytes (not really needed by us, but required by MMC) spiSendByte(0xff); spiSendByte(0xff); // read the data response xxx0<status>1 : status 010: Data accected, status 101: Data // rejected due to a crc error, status 110: Data rejected due to a Write error. mmcCheckBusy(); } else { // the MMC never acknowledge the write command rvalue = MMC_RESPONSE_ERROR; // 2 } } else { rvalue = MMC_BLOCK_SET_ERROR; // 1 } // give the MMC the required clocks to finish up what ever it needs to do // for (i = 0; i < 9; ++i) // spiSendByte(0xff);
//--------------- set blocklength 2^n ------------------------------------------------------
// Ti Modification: long int-> long
char mmcSetBlockLength (const unsigned long blocklength)
{ char rValue = MMC_TIMEOUT_ERROR; char i = 0;
// SS = LOW (on) CS_LOW ();
// Set the block length to read //MMC_SET_BLOCKLEN =CMD16 mmcSendCmd(16, blocklength, 0xFF);
// get response from MMC - make sure that its 0x00 (R1 ok response format) if(mmcGetResponse()!=0x00);
CS_HIGH ();
// Send 8 Clock pulses of delay. spiSendByte(0xff);
return MMC_SUCCESS;
} // block_length
//TI added substitution routine for spi_read and spi_write
unsigned char spiSendByte(const unsigned char data)
{ while ((IFG2&UTXIFG1) ==0); // wait while not ready / for RX TXBUF1 = data; // write while ((IFG2 & URXIFG1)==0); // wait for RX buffer (full) return (RXBUF1);
}
// Reading the contents of the CSD and CID registers in SPI mode is a simple
// read-block transaction.
if (mmcSetBlockLength (length) == MMC_SUCCESS) { CS_LOW (); // CRC not used: 0xff as last byte mmcSendCmd(cmd_register, 0x000000, 0xff);
// wait for response // in the R1 format (0x00 is no errors) if (mmcGetResponse() == 0x00) { if (mmcGetXXResponse(0xfe)== 0xfe) for (uc = 0; uc < length; uc++) mmc_buffer[uc] = spiSendByte(0xff); // get CRC bytes (not really needed by us, but required by MMC) spiSendByte(0xff); spiSendByte(0xff); } else rvalue = MMC_RESPONSE_ERROR; // CS = HIGH (off) CS_HIGH ();
[COLOR=red]led.h[/COLOR]
/* * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 43): * Rolf Freitag (webmaster at true-random.com) wrote this file. * As long as you retain this notice you can do whatever * the LGPL (Lesser GNU public License) allows with this stuff. * If you think this stuff is worth it, you can send me money via * paypal or if we met some day you can buy me a beer in return. * ---------------------------------------------------------------------------- */
#ifndef _LED_H
#define _LED_H
#include <msp430x14x.h>
[COLOR=red]led.c[/COLOR]
/* * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 44): * Rolf Freitag (webmaster at true-random.com) wrote this file. * As long as you retain this notice you can do whatever * the LGPL (Lesser GNU public License) allows with this stuff. * If you think this stuff is worth it, you can send me money via * paypal or if we met some day you can buy me a beer in return. * ---------------------------------------------------------------------------- */
#include <msp430x14x.h>