portd.f1=0; // CS = 0
spi_write(0xff); // used in some examples but not required
spi_write(64); //cmd0
spi_write(0); //argument
spi_write(0); //argument
spi_write(0); //argument
spi_write(0); //argument
spi_write(149); //crc valid only for mmc_go_idle_state
for (i=0;i<=8;i++) // 8 (NCR) + 1 (result read)
{
result=spi_read(0xff);
if (result != 0xff) break;
}
portd.f1=1; // CS = 1
thx for your great guidance, I had a hard ware problem too, you know, my SD adapter was corrupted ! so I was confusing for two weeksCode:portd.f1=0; // CS = 0 spi_write(0xff); // used in some examples but not required spi_write(64); //cmd0 spi_write(0); //argument spi_write(0); //argument spi_write(0); //argument spi_write(0); //argument spi_write(149); //crc valid only for mmc_go_idle_state for (i=0;i<=8;i++) // 8 (NCR) + 1 (result read) { result=spi_read(0xff); if (result != 0xff) break; } portd.f1=1; // CS = 1
// */ ******CMD0 and CMD1****************
char r2=1;
char r1=0;
char bit=0;
char flag1=0;
char debounce = 30;
char count1=0;
unsigned count=0;
char i=0;
char result;
char result1;
char result58;
char i1=0;
//////////////////////////////////////////6
void mmccommand(){
delay_ms(1);
portd.f1=1;
r1=1;
while(r1<10){
spi_write(255);
r1++;
}
portd.f1=0;
spi_write(64);
spi_write(0);
spi_write(0);
spi_write(0);
spi_write(0);
spi_write(149); //crc valid only for mmc_go_idle_state
//
for (i=0;i<=8;i++)
{
result=spi_read(0xff);
if (result != 255) break;
}
portd.f1=1;
}
/////////////////////////////////////////////
void mmccommand1(){
char retry=1;
portd.f1=0;
spi_write(65);
spi_write(0);
spi_write(0);
spi_write(0);
spi_write(0);
spi_write(149); //crc valid only for mmc_go_idle_state
for (i=0;i<=8;i++) // 8 (NCR) + 1 (result read)
{
result1=spi_read(0xff);
if (result1 !=255) break;
}
portd.f1=1;
}
/////////////////////////////////////////////
void main() {
Spi_Init_Advanced(MASTER_OSC_DIV64, DATA_SAMPLE_MIDDLE, CLK_IDLE_LOW, LOW_2_HIGH);
trisd.f1 =0; //CS
portd.f1=1;
result=0;
result1=1;
while(1){
while (result != 1) {
mmccommand();
result1=1;
}
i1=0;
if (result==1){
while(result1!=0) {
i1++;
mmccommand1();
if(i1>125){
result=0;
break;
}
}
}
result=0;
}
}
The initializations sequences I know don't send CMD1 as second command. As previously mentioned by others, newer implementations are proceeding with CMD8 to detect SDHC cards.
The purpose of CMD8 has been mentioned multiple times in the discussion. I'm getting tired of repeating the stuff.according the data sheet, CMD8 is reserved. so that is meaning I can't use it.
Thx, cmd8 is using for both micro SD with the capacity of 2G and 8G ? because I am using both of them. could you please give me your datasheet? because It seems that your datasheet is fuller than mine. During this days I have tried several method for bring the SD from Idle state to active state for example while I couldn't reply from cmd1, I sent cmd55 and after that acmd41 but the SD returned illegal responses, I hope with your guidance can develop this step too. waiting for your reply...The purpose of CMD8 has been mentioned multiple times in the discussion. I'm getting tired of repeating the stuff.
The datasheet is a "pre SHDC" one. CMD8 is required if your code wants to handle SDHC cards.
/*-----------------------------------------------------------------------*/
/* MMCv3/SDv1/SDv2 (in SPI mode) control module (C)ChaN, 2009 */
/*-----------------------------------------------------------------------*/
/* Only rcvr_spi(), xmit_spi(), disk_timerproc() and some macros */
/* are platform dependent. */
/*-----------------------------------------------------------------------*/
#include <p24FJ64GA002.h>
#include "diskio.h"
/* Definitions for MMC/SDC command */
#define CMD0 (0x40+0) /* GO_IDLE_STATE */
#define CMD1 (0x40+1) /* SEND_OP_COND (MMC) */
#define ACMD41 (0xC0+41) /* SEND_OP_COND (SDC) */
#define CMD8 (0x40+8) /* SEND_IF_COND */
#define CMD9 (0x40+9) /* SEND_CSD */
#define CMD10 (0x40+10) /* SEND_CID */
#define CMD12 (0x40+12) /* STOP_TRANSMISSION */
#define ACMD13 (0xC0+13) /* SD_STATUS (SDC) */
#define CMD16 (0x40+16) /* SET_BLOCKLEN */
#define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */
#define CMD18 (0x40+18) /* READ_MULTIPLE_BLOCK */
#define CMD23 (0x40+23) /* SET_BLOCK_COUNT (MMC) */
#define ACMD23 (0xC0+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
#define CMD24 (0x40+24) /* WRITE_BLOCK */
#define CMD25 (0x40+25) /* WRITE_MULTIPLE_BLOCK */
#define CMD55 (0x40+55) /* APP_CMD */
#define CMD58 (0x40+58) /* READ_OCR */
/* Port Controls (Platform dependent) */
#define SELECT() _LATB15 = 0 /* MMC CS = L */
#define DESELECT() _LATB15 = 1 /* MMC CS = H */
#define SOCKPORT PORTB /* Socket contact port */
#define SOCKWP (1<<10) /* Write protect switch (RB10) */
#define SOCKINS (1<<11) /* Card detect switch (RB11) */
#define FCLK_SLOW() /* Set slow clock (100k-400k) */
#define FCLK_FAST() /* Set fast clock (depends on the CSD) */
/*--------------------------------------------------------------------------
Module Private Functions
---------------------------------------------------------------------------*/
static volatile
DSTATUS Stat = STA_NOINIT; /* Disk status */
static volatile
UINT Timer1, Timer2; /* 1000Hz decrement timer */
static
UINT CardType;
/*-----------------------------------------------------------------------*/
/* Exchange a byte between PIC and MMC via SPI (Platform dependent) */
/*-----------------------------------------------------------------------*/
#define xmit_spi(dat) xchg_spi(dat)
#define rcvr_spi() xchg_spi(0xFF)
#define rcvr_spi_m(p) SPI1BUF = 0xFF; while (!_SPIRBF); *(p) = (BYTE)SPI1BUF;
static
BYTE xchg_spi (BYTE dat)
{
SPI1BUF = dat;
while (!_SPIRBF);
return (BYTE)SPI1BUF;
}
/*-----------------------------------------------------------------------*/
/* Wait for card ready */
/*-----------------------------------------------------------------------*/
static
BYTE wait_ready (void)
{
BYTE res;
Timer2 = 500; /* Wait for ready in timeout of 500ms */
rcvr_spi();
do
res = rcvr_spi();
while ((res != 0xFF) && Timer2);
return res;
}
/*-----------------------------------------------------------------------*/
/* Deselect the card and release SPI bus */
/*-----------------------------------------------------------------------*/
static
void release_spi (void)
{
DESELECT();
rcvr_spi();
}
/*-----------------------------------------------------------------------*/
/* Power Control (Platform dependent) */
/*-----------------------------------------------------------------------*/
/* When the target system does not support socket power control, there */
/* is nothing to do in these functions and chk_power always returns 1. */
static
void power_on (void)
{
/* Enable SPI1 */
SPI1CON1 = 0x013B;
SPI1CON2 = 0x0000;
_SPIEN = 1;
}
static
void power_off (void)
{
SELECT(); /* Wait for card ready */
wait_ready();
release_spi();
_SPIEN = 0; /* Disable SPI1 */
Stat |= STA_NOINIT; /* Set STA_NOINIT */
}
/*-----------------------------------------------------------------------*/
/* Receive a data packet from MMC */
/*-----------------------------------------------------------------------*/
static
BOOL rcvr_datablock (
BYTE *buff, /* Data buffer to store received data */
UINT btr /* Byte count (must be multiple of 4) */
)
{
BYTE token;
Timer1 = 100;
do { /* Wait for data packet in timeout of 100ms */
token = rcvr_spi();
} while ((token == 0xFF) && Timer1);
if(token != 0xFE) return FALSE; /* If not valid data token, retutn with error */
do { /* Receive the data block into buffer */
rcvr_spi_m(buff++);
rcvr_spi_m(buff++);
rcvr_spi_m(buff++);
rcvr_spi_m(buff++);
} while (btr -= 4);
rcvr_spi(); /* Discard CRC */
rcvr_spi();
return TRUE; /* Return with success */
}
/*-----------------------------------------------------------------------*/
/* Send a data packet to MMC */
/*-----------------------------------------------------------------------*/
#if _READONLY == 0
static
BOOL xmit_datablock (
const BYTE *buff, /* 512 byte data block to be transmitted */
BYTE token /* Data/Stop token */
)
{
BYTE resp;
UINT bc = 512;
if (wait_ready() != 0xFF) return FALSE;
xmit_spi(token); /* Xmit data token */
if (token != 0xFD) { /* Is data token */
do { /* Xmit the 512 byte data block to MMC */
xmit_spi(*buff++);
xmit_spi(*buff++);
} while (bc -= 2);
xmit_spi(0xFF); /* CRC (Dummy) */
xmit_spi(0xFF);
resp = rcvr_spi(); /* Receive data response */
if ((resp & 0x1F) != 0x05) /* If not accepted, return with error */
return FALSE;
}
return TRUE;
}
#endif /* _READONLY */
/*-----------------------------------------------------------------------*/
/* Send a command packet to MMC */
/*-----------------------------------------------------------------------*/
static
BYTE send_cmd (
BYTE cmd, /* Command byte */
DWORD arg /* Argument */
)
{
BYTE n, res;
if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
cmd &= 0x7F;
res = send_cmd(CMD55, 0);
if (res > 1) return res;
}
/* Select the card and wait for ready */
DESELECT();
SELECT();
if (wait_ready() != 0xFF) return 0xFF;
/* Send command packet */
xmit_spi(cmd); /* Start + Command index */
xmit_spi((BYTE)(arg >> 24)); /* Argument[31..24] */
xmit_spi((BYTE)(arg >> 16)); /* Argument[23..16] */
xmit_spi((BYTE)(arg >> 8)); /* Argument[15..8] */
xmit_spi((BYTE)arg); /* Argument[7..0] */
n = 0x01; /* Dummy CRC + Stop */
if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */
if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */
xmit_spi(n);
/* Receive command response */
if (cmd == CMD12) rcvr_spi(); /* Skip a stuff byte when stop reading */
n = 10; /* Wait for a valid response in timeout of 10 attempts */
do
res = rcvr_spi();
while ((res & 0x80) && --n);
return res; /* Return with the response value */
}
/*--------------------------------------------------------------------------
Public Functions
---------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------*/
/* Initialize Disk Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE drv /* Physical drive nmuber (0) */
)
{
BYTE n, cmd, ty, ocr[4];
if (drv) return STA_NOINIT; /* Supports only single drive */
if (Stat & STA_NODISK) return Stat; /* No card in the socket */
power_on(); /* Force socket power on */
FCLK_SLOW();
for (n = 10; n; n--) rcvr_spi(); /* 80 dummy clocks */
ty = 0;
if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */
Timer1 = 1000; /* Initialization timeout of 1000 msec */
if (send_cmd(CMD8, 0x1AA) == 1) { /* SDHC */
for (n = 0; n < 4; n++) ocr[n] = rcvr_spi(); /* Get trailing return value of R7 resp */
if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
while (Timer1 && send_cmd(ACMD41, 1UL << 30)); /* Wait for leaving idle state (ACMD41 with HCS bit) */
if (Timer1 && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */
for (n = 0; n < 4; n++) ocr[n] = rcvr_spi();
ty = (ocr[0] & 0x40) ? CT_SD2|CT_BLOCK : CT_SD2;
}
}
} else { /* SDSC or MMC */
if (send_cmd(ACMD41, 0) <= 1) {
ty = CT_SD1; cmd = ACMD41; /* SDSC */
} else {
ty = CT_MMC; cmd = CMD1; /* MMC */
}
while (Timer1 && send_cmd(cmd, 0)); /* Wait for leaving idle state */
if (!Timer1 || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */
ty = 0;
}
}
CardType = ty;
release_spi();
if (ty) { /* Initialization succeded */
Stat &= ~STA_NOINIT; /* Clear STA_NOINIT */
FCLK_FAST();
} else { /* Initialization failed */
power_off();
}
return Stat;
}
/*-----------------------------------------------------------------------*/
/* Get Disk Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE drv /* Physical drive nmuber (0) */
)
{
if (drv) return STA_NOINIT; /* Supports only single drive */
return Stat;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE drv, /* Physical drive nmuber (0) */
BYTE *buff, /* Pointer to the data buffer to store read data */
DWORD sector, /* Start sector number (LBA) */
BYTE count /* Sector count (1..255) */
)
{
if (drv || !count) return RES_PARERR;
if (Stat & STA_NOINIT) return RES_NOTRDY;
if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */
if (count == 1) { /* Single block read */
if ((send_cmd(CMD17, sector) == 0) /* READ_SINGLE_BLOCK */
&& rcvr_datablock(buff, 512))
count = 0;
}
else { /* Multiple block read */
if (send_cmd(CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */
do {
if (!rcvr_datablock(buff, 512)) break;
buff += 512;
} while (--count);
send_cmd(CMD12, 0); /* STOP_TRANSMISSION */
}
}
release_spi();
return count ? RES_ERROR : RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
#if _READONLY == 0
DRESULT disk_write (
BYTE drv, /* Physical drive nmuber (0) */
const BYTE *buff, /* Pointer to the data to be written */
DWORD sector, /* Start sector number (LBA) */
BYTE count /* Sector count (1..255) */
)
{
if (drv || !count) return RES_PARERR;
if (Stat & STA_NOINIT) return RES_NOTRDY;
if (Stat & STA_PROTECT) return RES_WRPRT;
if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */
if (count == 1) { /* Single block write */
if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */
&& xmit_datablock(buff, 0xFE))
count = 0;
}
else { /* Multiple block write */
if (CardType & CT_SDC) send_cmd(ACMD23, count);
if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */
do {
if (!xmit_datablock(buff, 0xFC)) break;
buff += 512;
} while (--count);
if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */
count = 1;
}
}
release_spi();
return count ? RES_ERROR : RES_OK;
}
#endif /* _READONLY */
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl (
BYTE drv, /* Physical drive nmuber (0) */
BYTE ctrl, /* Control code */
void *buff /* Buffer to send/receive data block */
)
{
DRESULT res;
BYTE n, csd[16], *ptr = buff;
DWORD csize;
if (drv) return RES_PARERR;
if (Stat & STA_NOINIT) return RES_NOTRDY;
res = RES_ERROR;
switch (ctrl) {
case CTRL_SYNC : /* Flush dirty buffer if present */
SELECT();
if (wait_ready() == 0xFF)
res = RES_OK;
break;
case GET_SECTOR_COUNT : /* Get number of sectors on the disk (WORD) */
if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
csize = csd[9] + ((WORD)csd[8] << 8) + 1;
*(DWORD*)buff = (DWORD)csize << 10;
} else { /* MMC or SDC ver 1.XX */
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
*(DWORD*)buff = (DWORD)csize << (n - 9);
}
res = RES_OK;
}
break;
case GET_SECTOR_SIZE : /* Get sectors on the disk (WORD) */
*(WORD*)buff = 512;
res = RES_OK;
break;
case GET_BLOCK_SIZE : /* Get erase block size in unit of sectors (DWORD) */
if (CardType & CT_SD2) { /* SDC ver 2.00 */
if (send_cmd(ACMD13, 0) == 0) { /* Read SD status */
rcvr_spi();
if (rcvr_datablock(csd, 16)) { /* Read partial block */
for (n = 64 - 16; n; n--) rcvr_spi(); /* Purge trailing data */
*(DWORD*)buff = 16UL << (csd[10] >> 4);
res = RES_OK;
}
}
} else { /* SDC ver 1.XX or MMC */
if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */
if (CardType & CT_SD1) { /* SDC ver 1.XX */
*(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1);
} else { /* MMC */
*(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1);
}
res = RES_OK;
}
}
break;
case MMC_GET_TYPE : /* Get card type flags (1 byte) */
*ptr = CardType;
res = RES_OK;
break;
case MMC_GET_CSD : /* Receive CSD as a data block (16 bytes) */
if ((send_cmd(CMD9, 0) == 0) /* READ_CSD */
&& rcvr_datablock(buff, 16))
res = RES_OK;
break;
case MMC_GET_CID : /* Receive CID as a data block (16 bytes) */
if ((send_cmd(CMD10, 0) == 0) /* READ_CID */
&& rcvr_datablock(buff, 16))
res = RES_OK;
break;
case MMC_GET_OCR : /* Receive OCR as an R3 resp (4 bytes) */
if (send_cmd(CMD58, 0) == 0) { /* READ_OCR */
for (n = 0; n < 4; n++)
*((BYTE*)buff+n) = rcvr_spi();
res = RES_OK;
}
break;
case MMC_GET_SDSTAT : /* Receive SD statsu as a data block (64 bytes) */
if (send_cmd(ACMD13, 0) == 0) { /* SD_STATUS */
rcvr_spi();
if (rcvr_datablock(buff, 64))
res = RES_OK;
}
break;
default:
res = RES_PARERR;
}
release_spi();
return res;
}
/*-----------------------------------------------------------------------*/
/* Device Timer Interrupt Procedure (Platform dependent) */
/*-----------------------------------------------------------------------*/
/* This function must be called in period of 1ms */
void disk_timerproc (void)
{
static WORD pv;
WORD p;
BYTE s;
UINT n;
n = Timer1; /* 1000Hz decrement timer */
if (n) Timer1 = --n;
n = Timer2;
if (n) Timer2 = --n;
p = pv;
pv = SOCKPORT & (SOCKWP | SOCKINS); /* Sample socket switch */
if (p == pv) { /* Have contacts stabled? */
s = Stat;
if (p & SOCKWP) /* WP is H (write protected) */
s |= STA_PROTECT;
else /* WP is L (write enabled) */
s &= ~STA_PROTECT;
if (p & SOCKINS) /* INS = H (Socket empty) */
s |= (STA_NODISK | STA_NOINIT);
else /* INS = L (Card inserted) */
s &= ~STA_NODISK;
Stat = s;
}
}
so how should use cmd8 ? because as you know I should send 4 bytes as a argument and one byte as crc and after that, what SD return as response ?Unfortunately, I don't have a SD-Card V2 specification including CMD8 and SDHC handling. I learned about it from existing libraries, e.g. the said Microchip application library.
thx, for your codes but in frankly speaking I don't have enough knowledge for changing your codes to the acceptable codes for mikroc compiler, and if you have followed the topics you will understand my problem, yes finally I want to read and write into SD but at first I decided to run this project step by step so at first I sent cmd0, and the SD replied me 0x01 as a response and that was correct according the datasheet and after that I should send cmd1 for bring SD from idle sate to active state but the responses were illegal so as you know, others said: use cmd8, but in my datasheet is mentioned that cmd8 is reserved !!! so now I ask you if you can please correct my previous codes or give me codes just bring the SD from ideal state to active state, and ready for writing and reading. If you have a full datasheet of micro SD and SDHC please put the link here.unfortunately in all of my datasheet cmd8 is reserved!!!! meanwhile I have two memory one of them is 2G and one of them is 8G are both of them SDHC ?Check out this code:
Code:/*-----------------------------------------------------------------------*/ /* MMCv3/SDv1/SDv2 (in SPI mode) control module (C)ChaN, 2009 */ /*-----------------------------------------------------------------------*/ /* Only rcvr_spi(), xmit_spi(), disk_timerproc() and some macros */ /* are platform dependent. */ /*-----------------------------------------------------------------------*/
Thx, I have visited the above website several time but I didn't found any useful part that can help me except the hardware wiring and assembly. if you think I have missed a special part of this website don't hesitate, and just tell me.That is not my code...;-) It is from http://elm-chan.org/fsw/ff/00index_e.html
Any way, I didn't initialized an SD card, I did only MMC. After doing MMC based stuff, I simply tried for SD by some modification in my MMC code, but doesn't worked.. Then I didn't played on it since I don't have enough time...
Also I am not an expert in this topic, but what I tried to provide you is a part of the source code of elm-chan.... If you have enough time to read it, then you may be able to correct your code, I hope so...
This short guide tell what to do:
The free "simplified" offcial SD card specification has all necessary information with more details.
I think, I already mentioned earlier that I'm not presently involved in writing low level SD codes because I'm satisfied with the available libraries, e.g. from Microchip. But I try to stay informed to be able to debug the codes.
All recent SD libraries are performing CMD8 after CMD0 to detect SDHC cards. The detection sequence is described in detail in my latest links.
Thx, that was good point I just put "spi_write(255) between CMD0 and CMD1 and my problem solved and after that I used cmd59 and SD return "0" that is right. and after that I sent cmd24 and the SD return "0" that is right response and after that I sent "254" to understand the SD, that I want to write 512 byte as a sector, and after that I wrote 512bytes, and the SD return "229" that means data is accepted. after that I sent cmd17 for reading this sector and SD returned "0" as response as you know that is right. and after that I expected to receive 254 but I received "255" and "0" do you have any idea ?if you want I can put my codes hereDid you notice the possible delay for getting a ready state with CMD1?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?