Jump to content

    

Почему не запустить SD-карточку?

Вторую неделю безрезультатно пытаюсь запустить работу SD-карточки совместно с платой MSP430-CCRF от Olimex (http://olimex.com/dev/msp-ccrf.html).

Исходные данные:

Проц cc430f5137, IDE IAR 5.10.1.

Карточка 256 мб, рабочая (проверял на компе).

Работает от DCO 1 MHz.

Карту вешаю на USCI_B0, т.к. удобно разводить.

Подключения:

P1.2 (SOMI он же MISO) <- DO

P1.3 (SIMO он же MOSI) -> DI

P1.4 (CLK) -> CLK

P 2.6 -> Cable Select

Ну, про питание, понятно…

Осциллографом вижу импульсы тактирования, сам проц работает – main крутится.

В последнем варианте кода понизил частоту тактирования до порядка 200 кГц. Вижу импульсы, идущие на пин карточки DI. CS тоже работает исправно. А вот пин карточки DO постоянно подтянут к плюсу даже если отпаять подтягивающий к питанию резистор. В итоге при опросе карточки на response() получаю постоянно 0xFF. При вынутой карточке получаю 0x00. Значит, вход рабочий, но карта не откликается.

Пожалуйста, посмотрите исходник. Может, найдете глупый косяк или подскажете где искать причину.

 

Далее привожу листинги файлов

 

main.c

/****************************************************************************/
/*    Demo program for  						    */
/*	  Board: MSP430-CCRF                                                */
/*    Manufacture: OLIMEX                                                   */
/*	  COPYRIGHT © 2011                                                */
/*    Designed by:	Penko Todorov Bozhkov                               */
/*    Module Name:  main                                                    */
/*    File   Name:  main.c		                	            */
/*    Revision:		initial          	   		            */
/*    Date:  		07.06.2011		                            */
/*    Built with IAR Embedded Workbench C/C++ Compiler for MSP430 4.21.2    */
/****************************************************************************/
// Target : CC430F5137
#include <cc430x513x.h>
#include <intrinsics.h>
#include <string.h>
#include "usart.h"
#include "spi.h"
#include "mmc.h"
#include <stdio.h>


//Definitions
#define LED_On			P1OUT |=   BIT0;	P1DIR |= BIT0;
#define LED_Off		        P1OUT &= (~BIT0);	P1DIR |= BIT0;
#define LED_Togg		P1OUT ^= BIT0;		P1DIR |= BIT0;
#define LED_Chk		        (P1IN & BIT0)



#define timer1_A3_Stop_Mode     TA1CTL &= (~0x0030)
#define timer1_A3_Up_Mode       TA1CTL |= (0x0010)


extern char mmc_buffer[512];


/****************************************************************************/
/*  Function name: delay                                                    */
/*  	Parameters                                                          */
/*          Input   :  p	                                            */
/*          Output  :  No	                                            */
/*	Action: Simple delay                                                */
/****************************************************************************/
void delay(volatile unsigned long p){
while(p){p--;}
}


/****************************************************************************/
/*  Function name: ports_init                                               */
/*  	Parameters                                                          */
/*          Input   :  No	                                            */
/*          Output  :  No	                                            */
/*	Action: Initialize all Port's directions and states                 */
/****************************************************************************/
void ports_init(void){
 P1OUT = 0x00;
 P1DIR = (BIT0); // Led out

 P2OUT = 0x00;  
 P2DIR = (CS);  //CS OUTPUT ACTIVE = LOW

 P3OUT = 0x00;
 P3DIR = 0x00;
}


/****************************************************************************/
/*  Function name: RTC_Clock_init                                           */
/*  	Parameters                                                          */
/*          Input   :  No	                                            */
/*          Output  :  No	                                            */
/*	Action: Set up RTC clock operation                                  */
/****************************************************************************/
void RTC_Clock_init(void){
 P5OUT = 0x00;
 //P5DIR = 0x02;  // If this is uncommented RTC doesn't work!!!!!!!!!!!!!!!!!! P5DIR register must be set to 0x00!!!!!!
 P5SEL = 0x03; // Enabled alternative functions 

 _BIC_SR(OSCOFF);          // Enable the LFXT1 crystal oscillator
 UCSCTL6 &= (~XTS);        // Select Low-frequency mode. XCAP bits define the capacitance at the XIN and XOUT pins.
 UCSCTL6 |= (XCAP0);       // Set XCAP0
 UCSCTL6 |= (XCAP1);       // Set XCAP1
 // Then Qrystal Load Capacitance is:  
 //  (XCAP1=0),(XCAP0=0) -> 2pF     (XCAP1=0),(XCAP0=1) -> 5.5pF
 //  (XCAP1=1),(XCAP0=0) -> 8.5pF   (XCAP1=1),(XCAP0=1) -> 12pF
 UCSCTL6 &= (~XT1OFF);     // Turns on the XT1.


 // ---------------------------------------------------------------------
// Configure CPU clock for 12MHz
/*_BIS_SR(SCG0);                  // Disable the FLL control loop
UCSCTL0 = 0x0000;          // Set lowest possible DCOx, MODx
UCSCTL1 = DCORSEL_5;       // Select suitable range
UCSCTL2 = FLLD_1 + 0x16E;  // Set DCO Multiplier
_BIC_SR(SCG0);                  // Enable the FLL control loop*/

   // Worst-case settling time for the DCO when the DCO range bits have been
   // changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx
   // UG for optimization.
   // 32 x 32 x 8 MHz / 32,768 Hz = 250000 = MCLK cycles for DCO to settle
   __delay_cycles(250000);



 // Æäåì, ïîêà âíåøíèå êâàðöû íå ñòàáèëèçèðóþòñÿ. Â ýòî âðåìÿ ðàáîòàåì íà âòóòðåííåì ãåíåðàòîðå. Loop until XT1,XT2 & DCO stabilizes
 do {
   UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + XT1HFOFFG + DCOFFG); // Clear XT2,XT1,DCO fault flags
   SFRIFG1 &= ~OFIFG;                      // Clear fault flags
 }while (SFRIFG1&OFIFG);                   // Test oscillator fault flag

 UCSCTL4 = ((SELA__XT1CLK | SELS__DCOCLKDIV) | SELM__DCOCLKDIV);   // ACLK source: XT1CLK, SMCLK: DCOCLKDIV, MCLK: DCOCLKDIV
 SFRIFG1 &= (~OFIFG);      // Oscillator fault interrupt flag
 SFRIE1 |= (OFIE);         // Oscillator fault interrupt enable


}


/****************************************************************************/
/*  Function name: timer1_A3_init                                           */
/*  	Parameters                                                          */
/*          Input   :  No                                                   */
/*          Output  :  No	                                            */
/*	Action: Initialize Timer1_A3 operation                              */
/****************************************************************************/
//TIMER1 initialize - prescale:0 
// desired value:	2Hz, i.e. 32768/2 = 16384(0x4000)
void timer1_A3_init(void){
 TA1CTL    = 0x0004;   // Timer1_A3 clear.
 TA1CCTL0  = 0x0010; // Timer1_A3 Capture/compare 0 interrupt enable.
 TA1CCR0   = 0x4000;  // Set TACCR0 value
 TA1CTL    = 0x0110;   // Selected: ACLK, divider:0, Up mode.
}


/****************************************************************************/
/*  Function name: init_devices                                             */
/*  	Parameters                                                          */
/*          Input   :  No	                                            */
/*          Output  :  No	                                            */
/*	Action: Initialize all peripherals                                  */
/****************************************************************************/
void init_devices(void){
//1. Stop errant interrupts until set up
_BIC_SR(GIE); // Disable interrupts during initialization process
//2. Init System Clock
// By defaut the FLL stabilizes MCLK and SMCLK to 1.048576 MHz and fDCO = 2.097152 MHz.

//3. Init Peripherals
RTC_Clock_init();
ports_init();
timer1_A3_init();
USART_Init(9600);
spi_master_init(); //Èíèöèàëèçàöèÿ SPI
//USART_Send_Data((unsigned char)'S');
initMMC();


//P3DIR |= BIT7;                  // Show SMCLK to P3.7
//P3SEL |= BIT7;

_BIS_SR(GIE); // Global Interrupt enabled. Do this at the END of the initialization!!!!!!!!
//all peripherals are now initialized
}


int main(void){
 WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
 init_devices();

  /*   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);   */

 //USART_Send_ROM_Menu_Begin();
 while(1){ 
   asm("NOP");
    __delay_cycles(250000);
    LED_Togg;

 }

}


/****************************************************************************/
/*  Timer1_A3 CC0 interrupt service routine.                                */
/****************************************************************************/
#pragma vector=TIMER1_A0_VECTOR
__interrupt void TIMER1_A0_Capture_Compare_ISR(void){
 //LED_Togg;
 //USART_Send_Data((unsigned char)'L');
 //sendSPI((char)'C');

}

/****************************************************************************/
/*  user NMI(UNMI) Non-Maskable interrupt service routine.                  */
/****************************************************************************/
#pragma vector=UNMI_VECTOR
__interrupt void UNMI_ISR(void)
{
 if(UCSCTL7 & XT2OFFG){          //XT2 oscillator fault flag
   UCSCTL7 &= (~XT2OFFG);        //Clear flag XT2OFFG
 }
 if(UCSCTL7 & XT1HFOFFG){        //XT1 oscillator fault flag (HF mode).
   UCSCTL7 &= (~XT1HFOFFG);      //Clear flag XT1HFOFFG
 }
 if(UCSCTL7 & XT1LFOFFG){        //XT1 oscillator fault flag (LF mode)
   UCSCTL7 &= (~XT1LFOFFG);      //Clear flag XT1LFOFFG
 }
 if(UCSCTL7 & DCOFFG){           //DCO fault flag.
   UCSCTL7 &= (~DCOFFG);         //Clear flag DCOFFG
 }
 SFRIFG1 &= (~OFIFG);    // Oscillator fault interrupt flag
}


 

 

spi.h

#ifndef __SPI_H
#define __SPI_H

/***** 1.All functions prototypes *****/
void spi_master_init(void);
unsigned char spiSendByte(unsigned char FMST2SLV_Data);
unsigned char get_spi_rxbuff(void);


#define CS                      BIT6
#define CS_HIGH			P2OUT |= (BIT6);	P2DIR |= (BIT6);
#define CS_LOW		        P2OUT &= (~(BIT6));	P2DIR |= (BIT6);

#endif //__SPI_H

 

 

spi.c

//******************************************************************************
//   CC430F5137  - USCI_B0, SPI 3-Wire Master 
#include "spi.h"
#include "cc430f5137.h"

#define MISO  BIT2
#define MOSI  BIT3
#define CLK   BIT4

void spi_master_init(void){
 WDTCTL = WDTPW+WDTHOLD;                   // Stop watchdog timer

 //Ýòî ñòàðûé êîä. òàê è íå ïîíÿë çà ÷åì ýòî áûëî, íî áåç íåãî ðàáîòàåò òàê æå.
/* PMAPPWD = 0x02D52;                        // Get write-access to port mapping regs  
 // Allow reconfiguration during runtime:
 PMAPCTL = PMAPRECFG;
 P1MAP2 = PM_UCB0SOMI;                     // Map UCB0SOMI output to P1.2 
 P1MAP3 = PM_UCB0SIMO;                     // Map UCB0SIMO output to P1.3 
 P1MAP4 = PM_UCB0CLK;                      // Map UCB0CLK output to P1.4 
 PMAPPWD = 0;                              // Lock port mapping registers  */

 //CS óæå çàäàí â main ïðè îïðåäåëåíèèè ïîðòîâ.

 P1OUT |= MOSI + CLK;
 P1DIR |= MOSI + CLK;                                                       
 P1SEL |= MOSI + MISO + CLK;      


 //Âçÿòî èç ïðèìåðà TI

 UCB0CTL0 = UCMST+UCCKPL+UCMSB+UCSYNC;     // 3-pin, 8-bit SPI master
 UCB0CTL1 = UCSSEL_2+UCSWRST;              // SMCLK
 UCB0BR0 |= 0x05;                          // 
 UCB0BR1 = 0;
 //UCB0MCTL = 0;
 UCB0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**



 while (!(UCB0IFG&UCTXIFG));
}

unsigned char spiSendByte(const unsigned char Data){

 while ((UCB0IFG&UCTXIFG)==0);               // USCI_B0 TX buffer ready?
 UCB0TXBUF = Data;                // Transmit first character and reset interrupt  

 while ((UCB0IFG&UCRXIFG)==0);               // USCI_B0 RX buffer ready?

 return (UCB0RXBUF);                        // return respond

}


/*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);
}*/




/*#pragma vector=USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
{
 switch(__even_in_range(UCB0IV,4))
 {
   case 0: break;                          // Vector 0 - no interrupt
   case 2:                                 // Vector 2 - RXIFG
     while (!(UCB0IFG&UCTXIFG));           // USCI_B0 TX buffer ready?
     FSLV2MST_Data = UCB0RXBUF;            // Read RX Buffer and reset Interrup
     __delay_cycles(80);                   // Add time between transmissions to
                                           // make sure slave can process information
     break;
   case 4: break;                          // Vector 4 - TXIFG
   default: break;
 }
}*/

 

 

mmc.h

 

#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

//#define CS_LOW()  P5OUT &= ~0x10                  // Card Select
//#define CS_HIGH() P5OUT |= 0x10                   // Card Deselect
#define SPI_RXC (IFG2 & URXIFG1)
#define SPI_TXC (IFG2 & UTXIFG1)

#define SPI_RX_COMPLETE (IFG2 & URXIFG1)
#define SPI_TX_READY (IFG2 & UTXIFG1)

#define DUMMY 0xff

// 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;

// error/success codes
#define MMC_SUCCESS           0x00
#define MMC_BLOCK_SET_ERROR   0x01
#define MMC_RESPONSE_ERROR    0x02
#define MMC_DATA_TOKEN_ERROR  0x03
#define MMC_INIT_ERROR        0x04
#define MMC_CRC_ERROR         0x10
#define MMC_WRITE_ERROR       0x11
#define MMC_OTHER_ERROR       0x12
#define MMC_TIMEOUT_ERROR     0xFF

// commands: first bit 0 (start bit), second 1 (transmission bit); CMD-number + 0ffsett 0x40
#define MMC_GO_IDLE_STATE   0x40                  //CMD0
#define MMC_SEND_OP_COND  0x41                    //CMD1
#define MMC_READ_CSD    0x49                      //CMD9
#define MMC_SEND_CID    0x4a                      //CMD10
#define MMC_STOP_TRANSMISSION   0x4c              //CMD12
#define MMC_SEND_STATUS   0x4d                    //CMD13
#define MMC_SET_BLOCKLEN  0x50                    //CMD16 Set block length for next read/write
#define MMC_READ_SINGLE_BLOCK   0x51              //CMD17 Read block from memory
#define MMC_READ_MULTIPLE_BLOCK 0x52              //CMD18
#define MMC_CMD_WRITEBLOCK  0x54                  //CMD20 Write block to memory
#define MMC_WRITE_BLOCK   0x58                    //CMD25
#define MMC_WRITE_MULTIPLE_BLOCK 0x59             //CMD??
#define MMC_WRITE_CSD     0x5b                    //CMD27 PROGRAM_CSD
#define MMC_SET_WRITE_PROT  0x5c                  //CMD28
#define MMC_CLR_WRITE_PROT  0x5d                  //CMD29
#define MMC_SEND_WRITE_PROT   0x5e                //CMD30
#define MMC_TAG_SECTOR_START  0x60                //CMD32
#define MMC_TAG_SECTOR_END  0x61                  //CMD33
#define MMC_UNTAG_SECTOR  0x62                    //CMD34
#define MMC_TAG_EREASE_GROUP_START 0x63           //CMD35
#define MMC_TAG_EREASE_GROUP_END 0x64             //CMD36
#define MMC_UNTAG_EREASE_GROUP  0x65              //CMD37
#define MMC_EREASE    0x66                        //CMD38
#define MMC_READ_OCR    0x67                      //CMD39
#define MMC_CRC_ON_OFF    0x68                    //CMD40

//TI added sub function for top two spi_xxx

// mmc init
char initMMC (void);
// send command to MMC
void mmcSendCmd (const char cmd, unsigned long data, const char crc);
// set MMC block length of count=2^n Byte
char mmcSetBlockLength (const unsigned long);
// read a size Byte big block beginning at the address.
char mmcReadBlock(const unsigned long address, const unsigned long count);
// write a 512 Byte big block beginning at the (aligned) adress
char mmcWriteBlock (const unsigned long address);
// Register arg1 der Laenge arg2 auslesen (into the buffer)
char mmcReadRegister(const char, const unsigned char);
#endif                                            /* _MMCLIB_H */

 

 

 

mmc.c

 

// MMC Lib
#ifndef _MMCLIB_C
#define _MMCLIB_C
//---------------------------------------------------------------------
#include "mmc.h"

#include  "MSP430x14x.H"
#include  "math.h"
#include  "string.h"
#include  "spi.h"
#include  "usart.h"
#include  <stdio.h>

char mmcGetResponse(void);
char mmcGetXXResponse(const char resp);
char mmcCheckBusy(void);

char mmc_buffer[512] =                            // Buffer for mmc i/o for data and registers
{
 0
};



// Initialisieren
char initMMC (void){
 int i;
 char response=0x01;

 //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");

 if(mmcGetResponse()!=0x01){
   printf("SD INIT error\r", 1);
   return MMC_INIT_ERROR;
 }

 while(response==0x01){
   puts("RESPONCE?\r");
    // debug_printf("Sending Command 1");
   CS_HIGH;
   spiSendByte(0xff);
   CS_LOW;
  // mmcSendCmd(0x01,0x00,0xff);
    mmcSendCmd(MMC_SEND_OP_COND,0x00,0xff);
   response  = mmcGetResponse();
         printf("SD responce is %i\r", response);
 }
 CS_HIGH;

     printf("SD responce is %i\r", response);

 spiSendByte(0xff);

         puts("SD INIT FINISHED\r");
 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 response;

 while(i<=64)
 {
   response=spiSendByte(0xff);
   if(response==0x00)break;
   if(response==0x01)break;
   i++;
 }

 // printf("mmcGetResponse results %i\r", response);
 return response;
}


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 response;

 while(i<=500)
 {
   response=spiSendByte(0xff);
   if(response==resp)break;
   i++;
 }
 return response;
}


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[i] = 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[i]);               // mmc_buffer[i];       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);

 CS_HIGH;
 // Send 8 Clock pulses of delay.
 spiSendByte(0xff);
 return rvalue;
}                                                 // mmc_write_block


//---------------------------------------------------------------------
void mmcSendCmd (const char cmd, unsigned long data, const char crc){
 char frame[6];
 char temp;
 int i;

 frame[0]=(cmd|0x40);
 for(i=3;i>=0;i--)
 {
   temp=(char)(data>>(8*i));
   frame[4-i]=(temp);
 }
 frame[5]=(crc);
 for(i=0;i<6;i++)
   spiSendByte(frame[i]);
}


//--------------- set blocklength 2^n ------------------------------------------------------
// Ti Modification: long int-> long
char mmcSetBlockLength (const unsigned long blocklength){

 // 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.

char mmcReadRegister (const char cmd_register, const unsigned char length)
{
 char uc = 0;
 char rvalue = MMC_TIMEOUT_ERROR;
 //  char i = 0;

 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;

   // Send 8 Clock pulses of delay.
   spiSendByte(0xff);
 }
 CS_HIGH;
 return rvalue;
}                                                 // mmc_read_register


//---------------------------------------------------------------------
#endif                                            /* _MMCLIB_C */

 

Share this post


Link to post
Share on other sites
//Send Command 0 to put MMC in SPI mode

mmcSendCmd(0x00,0,0x95);

если принять правильным инит пинов и настройку интерфейса SPI, то мне вот эта строчка "не нравится"..

в свое время я прилаживал SD карточку к Atmega128 по SPI, вот кусок сорца (все разумеется работало):

 

// Функция команды SD
unsigned char command(char befF, uint16_t AdrH, uint16_t AdrL, char befH )
    {
    u08 temp;
    u08 retry = 0x00;
    spi(0xFF);
    spi(befF);
    spi((uint8_t)(AdrH >> 8));
    spi((uint8_t)AdrH);
    spi((uint8_t)(AdrL >> 8));
    spi((uint8_t)AdrL);
    spi(befH);
    spi(0xFF);
    while((temp = spi(0xFF)) == 0xFF)
        if(retry++ > 250)
            {
            uart_puts("SD: CMD timeout");
            cr();
            break;
            }
    return temp;    // return the last received character
    }

// Инит карточки
int sd_init(void)
    {
    char i;
    PORTB |= (1 << SPICSSD);            // disable MMC
                                        // start MMC in SPI mode
    for(i=0; i < 10; i++) spi(0xFF);    // send 10*8=80 clock pulses
    PORTB &= ~(1 << SPICSSD);            // enable MMC

    if (command(0x40,0,0,0x95) != 1) goto mmcerror; // reset MMC

st: // if there is no MMC, prg. loops here
    if (command(0x41,0,0,0xFF) !=0) goto st;
    PORTB |= (1 << SPICSSD);    // disable MMC
    sd_csd();                    // считали CSD
    sd_cid();                    // считали CID
    if(partition() != 1)                // считали Partition Table
        read_mbr();                    // считали MBR
    return 1;
mmcerror:
    PORTB |= (1 << SPICSSD);    // disable MMC
    return 0;
    }

 

большая часть кода не моя, я просто дописал и поправил под свое железо :D

Share this post


Link to post
Share on other sites

день добрый, портировался похоже этот код? - MMC/SDC driver for MSP430 (www.true-random.com)

 

вот пример посвежее - slaa281b ( ti.com )

рекомендую ознакомится с FATfs ( ChaN ) How to Use MMC/SDC - красиво и доступно.

 

для начала сделать программный SPI, медленно,.. зато удобно запускаться (утверждение спорно, но я делал именно программный со старта ).

 

Share this post


Link to post
Share on other sites

Отвечаю сам себе. Может, кому пригодится.

 

1. старые карточки на 16 мб Canon и 256 мб SanDisk не работают (да я тоже удивился!)

А вот карточки на 1 Гб (Transcend) и 2 Гб тоже Transcend заработали на ура

 

2. Строка UCB0BR0 |= 0x04; идет норм для инициализации.

3. В mmcSendCmd(...)

 

frame[0]=(cmd|0x40);

|0x40 надо оставить,

а в других местах убрать

 

MMC_GO_IDLE_STATE должно быть 0x40, а не 0x00, как и для других команд.

 

:smile3009:

Share this post


Link to post
Share on other sites

По поводу старых и новых карт. Первоначально использовал EFSL и не работала часть карт, например стабильно не работали карты Apacer, после ряда экспериментов выяснили, что дело было в просадках напряжения питания на карте, повесили тантал на 47мкф непосредственно вблизи ножек разъема, проблема решилась. Далее стали использовать либу Chan'а, появилась поддержка SD HC, но перестали работать ряд старых карт, все современные карты работают на ура. Думаю дело в начальной скорости работы. Порт лучше делать сразу аппаратный. Примеры на два поста выше - все кроме варианта от Chan'а криво работают с новыми картами.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this