DSTATUS disk_initialize (void) { BYTE n, cmd, ty, buf[4]; UINT tmr; // INIT_PORT(); mmc_spi_InitSocket(); // CS_H(); mmc_spi_SetCardDeselect(); skip_mmc(10); /* Dummy clocks */ ty = 0; if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */ if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2 */ for (n = 0; n < 4; n++) buf[n] = rcvr_mmc(); /* Get trailing return value of R7 resp */ if (buf[2] == 0x01 && buf[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */ for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state (ACMD41 with HCS bit) */ if (send_cmd(ACMD41, 1UL << 30) == 0) break; // DLY_US(1000); mmc_spi_SetTimer(1); while( mmc_spi_CheckTimer() ) {} } if (tmr && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */ for (n = 0; n < 4; n++) buf[n] = rcvr_mmc(); ty = (buf[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 (HC or SC) */ } } } else { /* SDv1 or MMCv3 */ if (send_cmd(ACMD41, 0) <= 1) { ty = CT_SD1; cmd = ACMD41; /* SDv1 */ } else { ty = CT_MMC; cmd = CMD1; /* MMCv3 */ } for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state */ if (send_cmd(ACMD41, 0) == 0) break; // DLY_US(1000); mmc_spi_SetTimer(1); while( mmc_spi_CheckTimer() ) {} } if (!tmr || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */ ty = 0; } } CardType = ty; release_spi(); // return ty ? 0 : STA_NOINIT; if ( !ty ) return STA_NOINIT; mmc_spi_SetTransClock(); return 0; }
DRESULT disk_readp ( BYTE *buff, /* Pointer to the read buffer (NULL:Read bytes are forwarded to the stream) */ DWORD lba, /* Sector number (LBA) */ WORD ofs, /* Byte offset to read from (0..511) */ WORD cnt /* Number of bytes to read (ofs + cnt mus be <= 512) */ ) { DRESULT res; BYTE d; WORD bc, tmr; if (!(CardType & CT_BLOCK)) lba *= 512; /* Convert to byte address if needed */ res = RES_ERROR; if (send_cmd(CMD17, lba) == 0) { /* READ_SINGLE_BLOCK */ tmr = 1000; do { /* Wait for data packet in timeout of 100ms */ // DLY_US(100); mmc_spi_Wait100us(); d = rcvr_mmc(); } while (d == 0xFF && --tmr); if (d == 0xFE) { /* A data packet arrived */ bc = 514 - ofs - cnt; /* Skip leading bytes */ if (ofs) skip_mmc(ofs); /* Receive a part of the sector */ // if (buff) { /* Store data to the memory */ do *buff++ = rcvr_mmc(); while (--cnt); // } else { /* Forward data to the outgoing stream */ // do { // d = rcvr_mmc(); // FORWARD(d); // } while (--cnt); // } /* Skip trailing bytes and CRC */ skip_mmc(bc); res = RES_OK; } } release_spi(); return res; }
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; } #if AXI_SPI XStatus Status = XSpi_SetSlaveSelect(&Spi, 0); if(Status != XST_SUCCESS) { xil_printf("Failure Slave Select 0\r\n"); xil_printf("Status = %d\r\n", Status); } rcvr_mmc(); Status = XSpi_SetSlaveSelect(&Spi, 1); if(Status != XST_SUCCESS) { xil_printf("Failure Slave Select 1\r\n"); } rcvr_mmc(); #else /* Select the card */ CS_H(); rcvr_mmc(); CS_L(); rcvr_mmc(); #endif /* Send a command packet */ xmit_mmc(cmd); /* Start + Command index */ xmit_mmc((BYTE)(arg >> 24)); /* Argument[31..24] */ xmit_mmc((BYTE)(arg >> 16)); /* Argument[23..16] */ xmit_mmc((BYTE)(arg >> 8)); /* Argument[15..8] */ xmit_mmc((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_mmc(n); /* Receive a command response */ n = 10; /* Wait for a valid response in timeout of 10 attempts */ do { res = rcvr_mmc(); } while ((res & 0x80) && --n); return res; /* Return with the response value */ }
static void release_spi (void) { // CS_H(); mmc_spi_SetCardDeselect(); rcvr_mmc(); }
DRESULT disk_writep ( const BYTE *buff, /* Pointer to the bytes to be written (NULL:Initiate/Finalize sector write) */ DWORD sa /* Number of bytes to send, Sector number (LBA) or zero */ ) { DRESULT res; WORD bc, tmr; static WORD wc; res = RES_ERROR; if (buff) { /* Send data bytes */ bc = (WORD)sa; while (bc && wc) { /* Send data bytes to the card */ xmit_mmc(*buff++); wc--; bc--; } res = RES_OK; } else { if (sa) { /* Initiate sector write process */ if (!(CardType & CT_BLOCK)) sa *= 512; /* Convert to byte address if needed */ if (send_cmd(CMD24, sa) == 0) { /* WRITE_SINGLE_BLOCK */ xmit_mmc(0xFF); xmit_mmc(0xFE); /* Data block header */ wc = 512; /* Set byte counter */ res = RES_OK; } } else { /* Finalize sector write process */ bc = wc + 2; while (bc--) xmit_mmc(0); /* Fill left bytes and CRC with zeros */ if ((rcvr_mmc() & 0x1F) == 0x05) { /* Receive data resp and wait for end of write process in timeout of 300ms */ for (tmr = 10000; rcvr_mmc() != 0xFF && tmr; tmr--) /* Wait for ready (max 1000ms) */ // DLY_US(100); mmc_spi_Wait100us(); if (tmr) res = RES_OK; } release_spi(); } } return res; }
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> is the command sequense of CMD55-CMD<n> */ cmd &= 0x7F; n = send_cmd(CMD55, 0); if (n > 1) return n; } /* Select the card and wait for ready */ deselect(); if (!SPI_select()) return 0xFF; /* Send a 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 for CMD0(0)) */ if (cmd == CMD8) n = 0x87; /* (valid CRC for CMD8(0x1AA)) */ buf[5] = n; xmit_mmc(buf, 6); /* Receive command response */ if (cmd == CMD12) rcvr_mmc(&d, 1); /* Skip a stuff byte when stop reading */ n = 10; /* Wait for a valid response in timeout of 10 attempts */ do rcvr_mmc(&d, 1); while ((d & 0x80) && --n); return d; /* Return with the response value */ }
static int rcvr_datablock ( /* 1:OK, 0:Failed */ BYTE *buff, /* Data buffer to store received data */ UINT btr /* Byte count */ ) { BYTE d[2]; UINT tmr; for (tmr = 1000; tmr; tmr--) { /* Wait for 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, return with error */ rcvr_mmc(buff, btr); /* Receive the data block into buffer */ rcvr_mmc(d, 2); /* Discard CRC */ return 1; /* Return with success */ }
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 */ CS_H(); rcvr_mmc(); CS_L(); rcvr_mmc(); /* Send a command packet */ XMIT_MMC(cmd); /* Start + Command index */ XMIT_MMC((BYTE)(arg >> 24)); /* Argument[31..24] */ XMIT_MMC((BYTE)(arg >> 16)); /* Argument[23..16] */ XMIT_MMC((BYTE)(arg >> 8)); /* Argument[15..8] */ XMIT_MMC((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_MMC(n); /* Receive a command response */ n = 10; /* Wait for a valid response in timeout of 10 attempts */ do { res = rcvr_mmc(); } while ((res & 0x80) && --n); return res; /* Return with the response value */ }
static int xmit_datablock ( /* 1:OK, 0:Failed */ const BYTE *buff, /* 512 byte data block to be transmitted */ BYTE token /* Data/Stop token */ ) { BYTE d[2]; if (!wait_ready()) return 0; d[0] = token; xmit_mmc(d, 1); /* Xmit a token */ if (token != 0xFD) { /* Is it data token? */ xmit_mmc(buff, 512); /* Xmit the 512 byte data block to MMC */ rcvr_mmc(d, 2); /* Xmit dummy CRC (0xFF,0xFF) */ rcvr_mmc(d, 1); /* Receive data response */ if ((d[0] & 0x1F) != 0x05) /* If not accepted, return with error */ return 0; } return 1; }
static void release_spi (void) { #if AXI_SPI XStatus Status = XSpi_SetSlaveSelect(&Spi, 1); if(Status != XST_SUCCESS) { xil_printf("Failure Slave Select release_spi\r\n"); } //DLY_US(1); #else CS_H(); rcvr_mmc(); #endif }
static void skip_mmc ( WORD n /* Number of bytes to skip */ ) { do { rcvr_mmc(); } while (--n); // DI_H(); /* Send 0xFF */ // // do { // CK_H(); CK_L(); // CK_H(); CK_L(); // CK_H(); CK_L(); // CK_H(); CK_L(); // CK_H(); CK_L(); // CK_H(); CK_L(); // CK_H(); CK_L(); // CK_H(); CK_L(); // } while (--n); }
DRESULT disk_readp ( BYTE *buff, /* Pointer to the read buffer (NULL:Read bytes are forwarded to the stream) */ DWORD sector, /* Sector number (LBA) */ UINT offset, /* Byte offset to read from (0..511) */ UINT count /* Number of bytes to read (ofs + cnt mus be <= 512) */ ) { BYTE *buff_sec = buffer; DRESULT res; BYTE d; UINT bc, tmr; if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */ // check if sector is already in sector buffer if(buffer_sector == sector) { buff_sec += offset; // skip to requested bytes while(count--) *buff++ = *buff_sec++; return RES_OK; } res = RES_ERROR; if (send_cmd(CMD17, sector) == 0) { /* READ_SINGLE_BLOCK */ tmr = 1000; do { /* Wait for data packet in timeout of 100ms */ DLY_US(100); d = rcvr_mmc(); } while (d == 0xFF && --tmr); if (d == 0xFE) { /* A data packet arrived */ bc = 512 - offset - count; /* Skip leading bytes (store in buffer only) */ while(offset--) *buff_sec++ = rcvr_mmc(); /* Receive a part of the sector */ if (buff) { /* Store data to the memory */ do *buff_sec++ = *buff++ = rcvr_mmc(); while (--count); } else { /* Forward data to the outgoing stream */ do { *buff_sec++ = d = rcvr_mmc(); FORWARD(d); } while (--count); } /* Skip trailing bytes (store in buffer only) */ while(bc--) *buff_sec++ = rcvr_mmc(); /* and skip crc */ skip_mmc(2); buffer_sector = sector; res = RES_OK; } } release_spi(); return res; }
static void release_spi (void) { CS_H(); rcvr_mmc(); }
DRESULT disk_readp ( BYTE *buff, /* Pointer to the read buffer (NULL:Read bytes are forwarded to the stream) */ DWORD lba, /* Sector number (LBA) */ WORD ofs, /* Byte offset to read from (0..511) */ WORD cnt /* Number of bytes to read (ofs + cnt mus be <= 512) */ ) { #if 0 xil_printf("\n\n"); xil_printf("lba = %d\n", lba); xil_printf("ofs = %d\n", ofs); xil_printf("cnt = %d\n", cnt); #endif typedef struct LRUEntry { bool valid; DWORD lba_key; BYTE buffer[512]; struct LRUEntry* more_recently_used; struct LRUEntry* less_recently_used; } LRUEntry; #define NUM_LRU_ENTRIES 2 // At least 2 static LRUEntry* least_recently_used_entry = 0; static LRUEntry* most_recently_used_entry = 0; static LRUEntry read_buff_lru[NUM_LRU_ENTRIES]; static BYTE write_buff[512]; // Init once. if(!write_buff[0]){ memset(write_buff, 0xff, 512); // 0 is most recent and NUM_LRU_ENTRIES-1 is least recent. read_buff_lru[0].valid = false; read_buff_lru[0].more_recently_used = NULL; read_buff_lru[0].less_recently_used = &read_buff_lru[1]; most_recently_used_entry = &read_buff_lru[0]; for(int i = 1; i < NUM_LRU_ENTRIES-1; i++){ read_buff_lru[i].valid = false; read_buff_lru[i].more_recently_used = &read_buff_lru[i-1]; read_buff_lru[i].less_recently_used = &read_buff_lru[i+1]; } read_buff_lru[NUM_LRU_ENTRIES-1].valid = false; read_buff_lru[NUM_LRU_ENTRIES-1].more_recently_used = &read_buff_lru[NUM_LRU_ENTRIES-2]; read_buff_lru[NUM_LRU_ENTRIES-1].less_recently_used = NULL; least_recently_used_entry = &read_buff_lru[NUM_LRU_ENTRIES-1]; } // Search for entry... for(int i = 0; i < NUM_LRU_ENTRIES; i++){ if(read_buff_lru[i].valid && read_buff_lru[i].lba_key == lba){ if(buff){ memcpy(buff, read_buff_lru[i].buffer + ofs, cnt); } LRUEntry* curr_entry = &read_buff_lru[i]; // Update LRU list. if(curr_entry != most_recently_used_entry){ if(curr_entry == least_recently_used_entry){ least_recently_used_entry = curr_entry->more_recently_used; least_recently_used_entry->less_recently_used = NULL; } most_recently_used_entry->more_recently_used = curr_entry; curr_entry->less_recently_used = most_recently_used_entry; curr_entry->more_recently_used = NULL; most_recently_used_entry = curr_entry; } return RES_OK; } } // Took least recently used entry to read to it. // Update LRU list. LRUEntry* curr_entry = least_recently_used_entry; // Setting new least recently used. least_recently_used_entry = curr_entry->more_recently_used; least_recently_used_entry->less_recently_used = NULL; // Prepending new most recently used. most_recently_used_entry->more_recently_used = curr_entry; curr_entry->less_recently_used = most_recently_used_entry; curr_entry->more_recently_used = NULL; most_recently_used_entry = curr_entry; curr_entry->valid = true; curr_entry->lba_key = lba; BYTE* read_buff = curr_entry->buffer; if (!(CardType & CT_BLOCK)) lba *= 512; /* Convert to byte address if needed */ DRESULT res = RES_ERROR; if (send_cmd(CMD17, lba) == 0) { /* READ_SINGLE_BLOCK */ BYTE d; int tmr = 100000; do { /* Wait for data packet in timeout of 100ms */ DLY_US(1); d = rcvr_mmc(); } while (d == 0xFF && --tmr); if (d == 0xFE) { /* A data packet arrived */ XStatus Status = XSpi_Transfer(&Spi, write_buff, read_buff, 512); if(Status != XST_SUCCESS) { xil_printf("Error in read transfer\r\n"); return res; } if(buff){ memcpy(buff, read_buff + ofs, cnt); } res = RES_OK; } } release_spi(); return res; }
DSTATUS disk_initialize (void) { BYTE n, cmd, ty, buf[4]; UINT tmr; #if AXI_SPI /* * Initialize the SPI driver so that it's ready to use, * specify the device ID that is generated in xparameters.h. */ XStatus Status = XSpi_Initialize(&Spi, XPAR_SDCARD_SPI_DEVICE_ID); if(Status != XST_SUCCESS) {\ xil_printf("Failure INIT\r\n"); return XST_FAILURE; } /* * Set the SPI device as a master and in manual slave select mode such * that the slave select signal does not toggle for every byte of a * transfer, this must be done before the slave select is set. */ Status = XSpi_SetOptions(&Spi, XSP_MASTER_OPTION | XSP_MANUAL_SSELECT_OPTION); if(Status != XST_SUCCESS) { xil_printf("Failure Options\r\n"); return XST_FAILURE; } Status = XSpi_SetSlaveSelect(&Spi, 1); if(Status != XST_SUCCESS) { xil_printf("Failure Slave Select\r\n"); return XST_FAILURE; } XSpi_Start(&Spi); XSpi_IntrGlobalDisable(&Spi); DLY_US(1); #else INIT_PORT(); CS_H(); #endif skip_mmc(10); /* Dummy clocks */ ty = 0; if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */ if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2 */ for (n = 0; n < 4; n++) buf[n] = rcvr_mmc(); /* Get trailing return value of R7 resp */ if (buf[2] == 0x01 && buf[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */ for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state (ACMD41 with HCS bit) */ if (send_cmd(ACMD41, 1UL << 30) == 0) break; DLY_US(1000); } if (tmr && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */ for (n = 0; n < 4; n++) buf[n] = rcvr_mmc(); ty = (buf[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 (HC or SC) */ } } } else { /* SDv1 or MMCv3 */ if (send_cmd(ACMD41, 0) <= 1) { ty = CT_SD1; cmd = ACMD41; /* SDv1 */ } else { ty = CT_MMC; cmd = CMD1; /* MMCv3 */ } for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state */ if (send_cmd(cmd, 0) == 0) break; DLY_US(1000); } if (!tmr || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */ ty = 0; } } CardType = ty; release_spi(); return ty ? 0 : STA_NOINIT; }