C - Initializing an SD card in SPI mode, always reads back 0xFF -
i'm trying initialize 2 gb sandisk sd card on cypress psoc 5 using spi interface. i'm using sample bit banging code fatfs - generic fat file system module. i've analyzed interface on logic analyzer (see ). problem data out line sd card high, should getting 0x01 card init command. sd card reads fine on pc however. code using below, problem be?
i'm using sd socket http://ucontroller.com/documentation/sdcarddoc.html.
/*------------------------------------------------------------------------/ / bitbanging mmcv3/sdv1/sdv2 (in spi mode) control module /-------------------------------------------------------------------------/ / / copyright (c) 2010, chan, right reserved. / / * software free software , there no warranty. / * no restriction on use. can use, modify , redistribute / personal, non-profit or commercial products under responsibility. / * redistributions of source code must retain above copyright notice. / /--------------------------------------------------------------------------/ features , limitations: * easy port uses 4-6 bit of gpio port. no interrupt, no spi port used. * platform independent need modify few macros control gpio ports. * low speed data transfer rate several times slower hardware spi. * no media change detection application program must re-mount volume after media change or results hard error. /-------------------------------------------------------------------------*/ #include <device.h> #include "diskio.h" /* common include file fatfs , disk i/o layer */ /*-------------------------------------------------------------------------*/ /* platform dependent macros , functions needed modified */ /*-------------------------------------------------------------------------*/ #include <device.h> /* include device specific declareation file here */ #define init_port() /* initialize mmc control port (cs/clk/di:output, do/wp/ins:input) */ #define dly_us(n) cydelayus(n) /* delay n microseconds */ #define clk_delay() cydelayus(1) #define cs_h() cypins_setpin(ss_0) /* set mmc cs "high" */ #define cs_l() cypins_clearpin(ss_0) /* set mmc cs "low" */ #define ck_h() cypins_setpin(clk_0) /* set mmc sclk "high" */ #define ck_l() cypins_clearpin(clk_0) /* set mmc sclk "low" */ #define di_h() cypins_setpin(spiout_0) /* set mmc di "high" */ #define di_l() cypins_clearpin(spiout_0) /* set mmc di "low" */ #define cypins_readpin(spiin_0) /* mmc value (high:true, low:false) */ #define ins (1) /* card inserted (yes:true, no:false, default:true) */ #define wp (0) /* card write protected (yes:true, no:false, default:false) */ /*-------------------------------------------------------------------------- module private functions ---------------------------------------------------------------------------*/ /* mmc/sd command (spi mode) */ #define cmd0 (0) /* go_idle_state */ #define cmd1 (1) /* send_op_cond */ #define acmd41 (0x80+41) /* send_op_cond (sdc) */ #define cmd8 (8) /* send_if_cond */ #define cmd9 (9) /* send_csd */ #define cmd10 (10) /* send_cid */ #define cmd12 (12) /* stop_transmission */ #define acmd13 (0x80+13) /* sd_status (sdc) */ #define cmd16 (16) /* set_blocklen */ #define cmd17 (17) /* read_single_block */ #define cmd18 (18) /* read_multiple_block */ #define cmd23 (23) /* set_block_count */ #define acmd23 (0x80+23) /* set_wr_blk_erase_count (sdc) */ #define cmd24 (24) /* write_block */ #define cmd25 (25) /* write_multiple_block */ #define cmd41 (41) /* send_op_cond (acmd) */ #define cmd55 (55) /* app_cmd */ #define cmd58 (58) /* read_ocr */ /* card type flags (cardtype) */ #define ct_mmc 0x01 /* mmc ver 3 */ #define ct_sd1 0x02 /* sd ver 1 */ #define ct_sd2 0x04 /* sd ver 2 */ #define ct_sdc (ct_sd1|ct_sd2) /* sd */ #define ct_block 0x08 /* block addressing */ static dstatus stat = sta_noinit; /* disk status */ static byte cardtype; /* b0:mmc, b1:sdv1, b2:sdv2, b3:block addressing */ static char buf[80]; /*-----------------------------------------------------------------------*/ /* transmit bytes mmc (bitbanging) */ /*-----------------------------------------------------------------------*/ static void xmit_mmc ( const byte* buff, /* data sent */ uint bc /* number of bytes send */ ) { byte d; { d = *buff++; /* byte sent */ if (d & 0x80) di_h(); else di_l(); /* bit7 */ ck_h(); clk_delay(); ck_l(); clk_delay(); if (d & 0x40) di_h(); else di_l(); /* bit6 */ ck_h(); clk_delay(); ck_l(); clk_delay(); if (d & 0x20) di_h(); else di_l(); /* bit5 */ ck_h(); clk_delay(); ck_l(); clk_delay(); if (d & 0x10) di_h(); else di_l(); /* bit4 */ ck_h(); clk_delay(); ck_l(); clk_delay(); if (d & 0x08) di_h(); else di_l(); /* bit3 */ ck_h(); clk_delay(); ck_l(); clk_delay(); if (d & 0x04) di_h(); else di_l(); /* bit2 */ ck_h(); clk_delay(); ck_l(); clk_delay(); if (d & 0x02) di_h(); else di_l(); /* bit1 */ ck_h(); clk_delay(); ck_l(); clk_delay(); if (d & 0x01) di_h(); else di_l(); /* bit0 */ ck_h(); clk_delay(); ck_l(); clk_delay(); dly_us(10); //snprintf(buf, sizeof buf, "sent 0x%02x\r\n", d); //uart_1_putstring(buf); } while (--bc); } /*-----------------------------------------------------------------------*/ /* receive bytes mmc (bitbanging) */ /*-----------------------------------------------------------------------*/ static void rcvr_mmc ( byte *buff, /* pointer read buffer */ uint bc /* number of bytes receive */ ) { byte r; di_h(); /* send 0xff */ { r = 0; if (do) r++; /* bit7 */ ck_h(); clk_delay(); ck_l(); clk_delay(); r <<= 1; if (do) r++; /* bit6 */ ck_h(); clk_delay(); ck_l(); clk_delay(); r <<= 1; if (do) r++; /* bit5 */ ck_h(); clk_delay(); ck_l(); clk_delay(); r <<= 1; if (do) r++; /* bit4 */ ck_h(); clk_delay(); ck_l(); clk_delay(); r <<= 1; if (do) r++; /* bit3 */ ck_h(); clk_delay(); ck_l(); clk_delay(); r <<= 1; if (do) r++; /* bit2 */ ck_h(); clk_delay(); ck_l(); clk_delay(); r <<= 1; if (do) r++; /* bit1 */ ck_h(); clk_delay(); ck_l(); clk_delay(); r <<= 1; if (do) r++; /* bit0 */ ck_h(); clk_delay(); ck_l(); clk_delay(); *buff++ = r; /* store received byte */ dly_us(10); //snprintf(buf, sizeof buf, "received 0x%02x\r\n", r); //uart_1_putstring(buf); } while (--bc); } /*-----------------------------------------------------------------------*/ /* wait card ready */ /*-----------------------------------------------------------------------*/ static int wait_ready (void) /* 1:ok, 0:timeout */ { byte d; uint tmr; (tmr = 5000; tmr; tmr--) { /* wait ready in timeout of 500ms */ rcvr_mmc(&d, 1); if (d == 0xff) return 1; dly_us(100); } return 0; } /*-----------------------------------------------------------------------*/ /* deselect card , release spi bus */ /*-----------------------------------------------------------------------*/ static void deselect (void) { byte d; cs_h(); rcvr_mmc(&d, 1); } /*-----------------------------------------------------------------------*/ /* select card , wait ready */ /*-----------------------------------------------------------------------*/ static int select (void) /* 1:ok, 0:timeout */ { cs_l(); if (!wait_ready()) { deselect(); return 0; } return 1; } /*-----------------------------------------------------------------------*/ /* receive data packet mmc */ /*-----------------------------------------------------------------------*/ static int rcvr_datablock ( /* 1:ok, 0:failed */ byte *buff, /* data buffer store received data */ uint btr /* byte count */ ) { byte d[2]; uint tmr; (tmr = 1000; tmr; tmr--) { /* wait data packet in timeout of 100ms */ rcvr_mmc(d, 1); if (d[0] != 0xff) break; dly_us(100); } if (d[0] != 0xfe) return 0; /* if not valid data token, retutn error */ rcvr_mmc(buff, btr); /* receive data block buffer */ rcvr_mmc(d, 2); /* discard crc */ return 1; /* return success */ } /*-----------------------------------------------------------------------*/ /* send data packet mmc */ /*-----------------------------------------------------------------------*/ static int xmit_datablock ( /* 1:ok, 0:failed */ const byte *buff, /* 512 byte data block transmitted */ byte token /* data/stop token */ ) { byte d[2]; if (!wait_ready()) return 0; d[0] = token; xmit_mmc(d, 1); /* transmit token */ if (token != 0xfd) { /* data token? */ xmit_mmc(buff, 512); /* transmit 512 byte data block mmc */ rcvr_mmc(d, 2); /* dummy crc (ff,ff) */ rcvr_mmc(d, 1); /* receive data response */ if ((d[0] & 0x1f) != 0x05) /* if not accepted, return error */ return 0; } return 1; } /*-----------------------------------------------------------------------*/ /* send command packet mmc */ /*-----------------------------------------------------------------------*/ static byte send_cmd ( /* returns command response (bit7==1:send failed)*/ byte cmd, /* command byte */ dword arg /* argument */ ) { byte n, d, buf[6]; if (cmd & 0x80) { /* acmd<n> command sequense of cmd55-cmd<n> */ cmd &= 0x7f; n = send_cmd(cmd55, 0); if (n > 1) return n; } /* select card , wait ready */ deselect(); if (!select()) { return 0xff; } /* send command packet */ buf[0] = 0x40 | cmd; /* start + command index */ buf[1] = (byte)(arg >> 24); /* argument[31..24] */ buf[2] = (byte)(arg >> 16); /* argument[23..16] */ buf[3] = (byte)(arg >> 8); /* argument[15..8] */ buf[4] = (byte)arg; /* argument[7..0] */ n = 0x01; /* dummy crc + stop */ if (cmd == cmd0) n = 0x95; /* (valid crc cmd0(0)) */ if (cmd == cmd8) n = 0x87; /* (valid crc cmd8(0x1aa)) */ buf[5] = n; xmit_mmc(buf, 6); /* receive command response */ if (cmd == cmd12) rcvr_mmc(&d, 1); /* skip stuff byte when stop reading */ n = 10; /* wait valid response in timeout of 10 attempts */ rcvr_mmc(&d, 1); while ((d & 0x80) && --n); return d; /* return response value */ } /*-------------------------------------------------------------------------- public functions ---------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/ /* disk status */ /*-----------------------------------------------------------------------*/ dstatus disk_status ( byte drv /* drive number (0) */ ) { dstatus s = stat; if (drv || !ins) { s = sta_nodisk | sta_noinit; } else { s &= ~sta_nodisk; if (wp) s |= sta_protect; else s &= ~sta_protect; } stat = s; return s; } /*-----------------------------------------------------------------------*/ /* initialize disk drive */ /*-----------------------------------------------------------------------*/ dstatus disk_initialize ( byte drv /* physical drive nmuber (0) */ ) { byte n, ty, cmd, buf[4]; uint tmr; dstatus s; init_port(); /* initialize control port */ s = disk_status(drv); /* check if card in socket */ if (s & sta_nodisk) return s; cs_h(); (n = 10; n; n--) rcvr_mmc(buf, 1); /* 80 dummy clocks */ ty = 0; if (send_cmd(cmd0, 0) == 1) { /* enter idle state */ if (send_cmd(cmd8, 0x1aa) == 1) { /* sdv2? */ rcvr_mmc(buf, 4); /* trailing return value of r7 resp */ if (buf[2] == 0x01 && buf[3] == 0xaa) { /* card can work @ vdd range of 2.7-3.6v */ (tmr = 1000; tmr; tmr--) { /* wait leaving idle state (acmd41 hcs bit) */ if (send_cmd(acmd41, 1ul << 30) == 0) break; dly_us(1000); } if (tmr && send_cmd(cmd58, 0) == 0) { /* check ccs bit in ocr */ rcvr_mmc(buf, 4); ty = (buf[0] & 0x40) ? ct_sd2 | ct_block : ct_sd2; /* sdv2 */ } } } else { /* sdv1 or mmcv3 */ if (send_cmd(acmd41, 0) <= 1) { ty = ct_sd1; cmd = acmd41; /* sdv1 */ } else { ty = ct_mmc; cmd = cmd1; /* mmcv3 */ } (tmr = 1000; tmr; tmr--) { /* wait leaving idle state */ if (send_cmd(acmd41, 0) == 0) break; dly_us(1000); } if (!tmr || send_cmd(cmd16, 512) != 0) /* set r/w block length 512 */ ty = 0; } } else { uart_1_putstring("send cmd 0 failed"); } cardtype = ty; if (ty) /* initialization succeded */ s &= ~sta_noinit; else /* initialization failed */ s |= sta_noinit; stat = s; deselect(); return s; } /*-----------------------------------------------------------------------*/ /* read sector(s) */ /*-----------------------------------------------------------------------*/ dresult disk_read ( byte drv, /* physical drive nmuber (0) */ byte *buff, /* pointer data buffer store read data */ dword sector, /* start sector number (lba) */ byte count /* sector count (1..128) */ ) { dstatus s; s = disk_status(drv); if (s & sta_noinit) return res_notrdy; if (!count) return res_parerr; if (!(cardtype & ct_block)) sector *= 512; /* convert lba 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 */ { if (!rcvr_datablock(buff, 512)) break; buff += 512; } while (--count); send_cmd(cmd12, 0); /* stop_transmission */ } } deselect(); return count ? res_error : res_ok; } /*-----------------------------------------------------------------------*/ /* write sector(s) */ /*-----------------------------------------------------------------------*/ dresult disk_write ( byte drv, /* physical drive nmuber (0) */ const byte *buff, /* pointer data written */ dword sector, /* start sector number (lba) */ byte count /* sector count (1..128) */ ) { dstatus s; s = disk_status(drv); if (s & sta_noinit) return res_notrdy; if (s & sta_protect) return res_wrprt; if (!count) return res_parerr; if (!(cardtype & ct_block)) sector *= 512; /* convert lba 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 */ { if (!xmit_datablock(buff, 0xfc)) break; buff += 512; } while (--count); if (!xmit_datablock(0, 0xfd)) /* stop_tran token */ count = 1; } } deselect(); return count ? res_error : res_ok; } /*-----------------------------------------------------------------------*/ /* miscellaneous functions */ /*-----------------------------------------------------------------------*/ dresult disk_ioctl ( byte drv, /* physical drive nmuber (0) */ byte ctrl, /* control code */ void *buff /* buffer send/receive control data */ ) { dresult res; byte n, csd[16]; word cs; if (disk_status(drv) & sta_noinit) /* check if card in socket */ return res_notrdy; res = res_error; switch (ctrl) { case ctrl_sync : /* make sure no pending write process */ if (select()) { deselect(); res = res_ok; } break; case get_sector_count : /* number of sectors on disk (dword) */ if ((send_cmd(cmd9, 0) == 0) && rcvr_datablock(csd, 16)) { if ((csd[0] >> 6) == 1) { /* sdc ver 2.00 */ cs= csd[9] + ((word)csd[8] << 8) + 1; *(dword*)buff = (dword)cs << 10; } else { /* sdc ver 1.xx or mmc */ n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2; cs = (csd[8] >> 6) + ((word)csd[7] << 2) + ((word)(csd[6] & 3) << 10) + 1; *(dword*)buff = (dword)cs << (n - 9); } res = res_ok; } break; case get_block_size : /* erase block size in unit of sector (dword) */ *(dword*)buff = 128; res = res_ok; break; default: res = res_parerr; } deselect(); return res; }
normally, can put pull-up resistors when more 1 sd card connected same interface lines. in particular, signals di, do, , clk becomes floating when deselect , select card.
otherwise, can imagine has impact on length of track between host , slave, in case microsd card.
i see pullup resistors in many example circuits find on internet.
Comments
Post a Comment