DSTATUS disk_initialize (void) { BYTE n, cmd, ty, ocr[4]; UINT tmr; #if _PF_USE_WRITE if (CardType && MMC_SEL) disk_writep(0, 0); /* Finalize write process if it is in progress */ #endif init_spi(); /* Initialize ports to control MMC */ DESELECT(); for (n = 100; n; n--) rcv_spi(); /* 80*10 dummy clocks with CS=H */ ty = 0; if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */ if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2 */ for (n = 0; n < 4; n++) ocr[n] = rcv_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 */ for (tmr = 10000; tmr && send_cmd(ACMD41, 1UL << 30); tmr--) dly_100us(); /* Wait for leaving idle state (ACMD41 with HCS bit) */ if (tmr && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */ for (n = 0; n < 4; n++) ocr[n] = rcv_spi(); ty = (ocr[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 = 10000; tmr && send_cmd(cmd, 0); tmr--) dly_100us(); /* Wait for leaving idle state */ if (!tmr || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */ ty = 0; } } CardType = ty; DESELECT(); rcv_spi(); //full speed SPI SPCR = (1<<MSTR)|(1<<SPE); SPSR = 0x01; /* SPI clk 2X */ return ty ? 0 : STA_NOINIT; }
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 rc; WORD bc; if (!(CardType & CT_BLOCK)) lba *= 512; /* Convert to byte address if needed */ res = RES_ERROR; if (send_cmd(CMD17, lba) == 0) { /* READ_SINGLE_BLOCK */ bc = 40000; do { /* Wait for data packet */ rc = rcv_spi(); } while (rc == 0xFF && --bc); if (rc == 0xFE) { /* A data packet arrived */ bc = 514 - ofs - cnt; /* Skip leading bytes */ if (ofs) { do rcv_spi(); while (--ofs); } /* Receive a part of the sector */ if (buff) { /* Store data to the memory */ do { *buff++ = rcv_spi(); } while (--cnt); } else { /* Forward data to the outgoing stream (depends on the project) */ do { //FORWARD(rcv_spi()); } while (--cnt); } /* Skip trailing bytes and CRC */ do rcv_spi(); while (--bc); res = RES_OK; } } DESELECT(); rcv_spi(); return res; }
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 rc; WORD bc; if ((PINB&_BV(SD_INS))!=0x00) return RES_ERROR; if (!(CardType & CT_BLOCK)) lba *= 512; // Convert to byte address if needed res = RES_ERROR; if (send_cmd(CMD17, lba) == 0) { // READ_SINGLE_BLOCK bc = 30000; do { // Wait for data packet in timeout of 100ms rc = rcv_spi(); } while (rc == 0xFF && --bc); if (rc == 0xFE) { // A data packet arrived bc = 514 - ofs - cnt; // Skip leading bytes if (ofs) { do rcv_spi(); while (--ofs); } // Receive a part of the sector if (buff) { // Store data to the memory do *buff++ = rcv_spi(); while (--cnt); } else { // Forward data to the outgoing stream (depends on the project) do ;//uart_transmit(rcv_spi()); // (Console output) while (--cnt); } // Skip trailing bytes and CRC do rcv_spi(); while (--bc); res = RES_OK; } } release_spi(); return res; }
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 */ ) { // BYTE buf; DRESULT res; WORD bc; static WORD wc; res = RES_ERROR; if (buff) { /* Send data bytes */ bc = (WORD)sa; while (bc && wc) { /* Send data bytes to the card */ xmit_spi(*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_spi(0xFF); xmit_spi(0xFE); /* Data block header */ wc = 512; /* Set byte counter */ res = RES_OK; } } else { /* Finalize sector write process */ bc = wc + 2; while (bc--) xmit_spi(0); /* Fill left bytes and CRC with zeros */ if ((rcv_spi() & 0x1F) == 0x05) { /* Receive data resp and wait for end of write process in timeout of 500ms */ // for (bc = 5000; buf!= 0xFF && bc; bc--){ // dly_100us(); /* Wait ready */ // buf=rcv_spi() ; // } for (bc = 5000; rcv_spi() != 0xFF && bc; bc--) dly_100us(); /* Wait ready */ if (bc) res = RES_OK; } DESELECT(); rcv_spi(); } } return res; }
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) */ ) { DRESULT res; BYTE rc; UINT bc; if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */ res = RES_ERROR; if (send_cmd(CMD17, sector) == 0) { /* READ_SINGLE_BLOCK */ bc = 40000; do { /* Wait for data packet */ rc = rcv_spi(); } while (rc == 0xFF && --bc); if (rc == 0xFE) { /* A data packet arrived */ bc = 514 - offset - count; /* Skip leading bytes */ if (offset) { do rcv_spi(); while (--offset); } /* Receive a part of the sector */ do { *buff++ = rcv_spi(); } while (--count); /* Skip trailing bytes and CRC */ do rcv_spi(); while (--bc); res = RES_OK; } } deselect(); return res; }
uint8_t nrf_read_reg(const uint8_t reg){ uint8_t val; CS_LOW(); xmit_spi(C_R_REGISTER | reg); rcv_spi(&val); CS_HIGH(); return val; };
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; static WORD wc; if ((PINB&_BV(SD_INS))!=0x00) return RES_ERROR; if ((PINB&_BV(SD_WP))!=0x00) return RES_ERROR; res = RES_ERROR; if (buff) { // Send data bytes bc = (WORD)sa; while (bc && wc) { // Send data bytes to the card xmit_spi(*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_spi(0xFF); xmit_spi(0xFE); // Data block header wc = 512; // Set byte counter res = RES_OK; } } else { // Finalize sector write process bc = wc + 2; while (bc--) xmit_spi(0); // Fill left bytes and CRC with zeros if ((rcv_spi() & 0x1F) == 0x05) { // Receive data resp and wait for end of write process in timeout of 300ms for (bc = 65000; rcv_spi() != 0xFF && bc; bc--) ; // Wait ready if (bc) res = RES_OK; } release_spi(); } } return res; }
//-------------------------------------------------------------------------- // Initialize Disk Drive //-------------------------------------------------------------------------- DSTATUS disk_initialize (void) { BYTE n, cmd, ty, ocr[4]; WORD tmr; INIT_SPI(); if ((PINB&_BV(SD_INS))!=0x00) return STA_NOINIT; #if _WRITE_FUNC if (MMC_SEL) disk_writep(0, 0); // Finalize write process if it is in progress #endif for (n = 100; n; n--) rcv_spi(); // 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++) ocr[n] = rcv_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 for (tmr = 12000; tmr && send_cmd(ACMD41, 1UL << 30); tmr--) ; // Wait for leaving idle state (ACMD41 with HCS bit) if (tmr && send_cmd(CMD58, 0) == 0) { // Check CCS bit in the OCR for (n = 0; n < 4; n++) ocr[n] = rcv_spi(); ty = (ocr[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 = 25000; tmr && send_cmd(cmd, 0); tmr--) ; // Wait for leaving idle state 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; }
static BYTE send_cmd ( BYTE cmd, /* 1st byte (Start + Index) */ DWORD arg /* Argument (32 bits) */ ) { 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 */ DESELECT(); rcv_spi(); SELECT(); rcv_spi(); /* Send a 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 a command response */ n = 10; /* Wait for a valid response in timeout of 10 attempts */ do { res = rcv_spi(); } while ((res & 0x80) && --n); return res; /* Return with the response value */ }
//----------------------------------------------------------------------- // 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 DESELECT(); rcv_spi(); SELECT(); rcv_spi(); // Send a 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 a command response n = 10; // Wait for a valid response in timeout of 10 attempts do { res = rcv_spi(); } while ((res & 0x80) && --n); return res; // Return with the response value }
DSTATUS disk_initialize (void) { BYTE n, cmd, ty, ocr[4]; UINT tmr; init_spi(); /* Initialize ports to control MMC */ for (n = 100; n; n--) dly_100us(); /* 10ms delay */ for (n = 10; n; n--) deselect(); /* 80 Dummy clocks with CS=H */ ty = 0; if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */ if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2 */ for (n = 0; n < 4; n++) ocr[n] = rcv_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 */ for (tmr = 10000; tmr && send_cmd(ACMD41, 1UL << 30); tmr--) dly_100us(); /* Wait for leaving idle state (ACMD41 with HCS bit) */ if (tmr && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */ for (n = 0; n < 4; n++) ocr[n] = rcv_spi(); ty = (ocr[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 = 10000; tmr && send_cmd(cmd, 0); tmr--) dly_100us(); /* Wait for leaving idle state */ if (!tmr || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */ ty = 0; } } CardType = ty; deselect(); return ty ? 0 : STA_NOINIT; }
DRESULT disk_readp ( BYTE *buff, /* Pointer to the read buffer (NULL:Forward 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) */ ) { DRESULT res; BYTE rc; UINT bc; if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */ res = RES_ERROR; if (send_cmd(CMD17, sector) == 0) { /* READ_SINGLE_BLOCK */ bc = 40000; /* Time counter */ do { /* Wait for data packet */ rc = rcv_spi(); } while (rc == 0xFF && --bc); if (rc == 0xFE) { /* A data packet arrived */ bc = 512 + 2 - offset - count; /* Number of trailing bytes to skip */ /* Skip leading bytes */ while (offset--) rcv_spi(); /* Receive a part of the sector */ if (buff) { /* Store data to the memory */ do { *buff++ = rcv_spi(); } while (--count); } else { /* Forward data to the outgoing stream */ do { FORWARD(rcv_spi()); } while (--count); } /* Skip trailing bytes and CRC */ do rcv_spi(); while (--bc); res = RES_OK; } } DESELECT(); rcv_spi(); return res; }
/* Select MMC (asmfunc.S) */ void deselect(void) { while(spi_busy); spi_cs = 1; rcv_spi(); }
//----------------------------------------------------------------------- // Deselect the card and release SPI bus //----------------------------------------------------------------------- static void release_spi (void) { rcv_spi(); }