Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // SD.c
- #include "diskio.h"
- #include "SPI.h"
- #include "SD.h"
- #include "Microseconds.h"
- #include <REG51F380.H> // registres C8051F38C
- // data streaming
- #define FORWARD(d) {}
- #define _USE_WRITE 1
- // for vscode
- //typedef sbit sbit;
- sbit SD_CS = P1^4;
- static uint8_t CardType; /* b0:MMC, b1:SDv1, b2:SDv2, b3:Block addressing */
- // main source: http://www.rjhcoding.com/avrc-sd-interface-1.php
- // https://electronics.stackexchange.com/questions/602105/hoVw-can-i-initialize-use-sd-cards-with-spi
- // http://elm-chan.org/docs/mmc/mmc_e.html
- /*-----------------------------------------------------------------------*/
- /* Initialize Disk Drive */
- /*-----------------------------------------------------------------------*/
- DSTATUS disk_initialize(void);
- /*-----------------------------------------------------------------------*/
- /* Read partial sector */
- /*-----------------------------------------------------------------------*/
- DRESULT disk_readp (
- uint8_t *buff, /* Pointer to the read buffer (NULL:Read bytes are forwarded to the stream) */
- uint32_t sector, /* Sector number (LBA) */
- uint16_t offset, /* Byte offset to read from (0..511) */
- uint16_t count /* Number of bytes to read (ofs + cnt mus be <= 512) */
- ) compact;
- /*-----------------------------------------------------------------------*/
- /* Write partial sector */
- /*-----------------------------------------------------------------------*/
- DRESULT disk_writep (
- const uint8_t *buff, /* Pointer to the bytes to be written (NULL:Initiate/Finalize sector write) */
- uint32_t sc /* Number of bytes to send, Sector number (LBA) or zero */
- );
- /*
- void SD_Powerup()
- {
- uint8_t i;
- // make sure card is deselected
- SD_CS = SPI_CS_DISABLE;
- // give SD card time to power up
- MicrosecondsWait1000();
- MicrosecondsWait1000();
- // send 80 clock cycles to synchronize
- for(i = 0; i < 10; i++)
- SPIWrite8(0xFF);
- // deselect SD card
- SD_CS = SPI_CS_DISABLE;
- SPIWrite8(0xFF);
- }*/
- uint8_t SPI_Transfer(uint8_t SPI_data)
- {
- SPIWrite8(SPI_data);
- // added wait and delay to prevent write/read colision
- while(!TXBMT) {};
- // very slight improvement only
- MicrosecondsWait1();
- return SPIReadDirect();
- }
- // for init
- uint8_t SPI_TransferSlow(uint8_t SPI_data)
- {
- SPIWrite8(SPI_data);
- // added wait and delay to prevent write/read colision
- while(!TXBMT) {};
- MicrosecondsWait1();
- MicrosecondsWait1();
- MicrosecondsWait1();
- MicrosecondsWait1();
- return SPIReadDirect();
- }
- uint8_t SD_SendCommand(uint8_t cmd, uint32_t arg)
- {
- idata uint8_t crc = 0xFF;
- data uint8_t n, res;
- // transmit command to sd card
- SPIWrite8(cmd|0x40);
- // transmit argument
- SPIWrite8((uint8_t)(arg >> 24));
- SPIWrite8((uint8_t)(arg >> 16));
- SPIWrite8((uint8_t)(arg >> 8));
- SPIWrite8((uint8_t)(arg));
- // https://github.com/arduino-libraries/SD/blob/master/src/utility/Sd2Card.cpp#L132
- if (cmd == CMD0) {
- crc = 0X95; // correct crc for CMD0 with arg 0
- }
- if (cmd == CMD8) {
- crc = 0X87; // correct crc for CMD8 w
- }
- // transmit crc
- SPIWrite8(crc);
- /* Receive a command response */
- n = 10; /* Wait for a valid response in timeout of 10 attempts */
- do {
- res = SPI_Transfer(0xFF);
- } while ((res & 0x80) && --n);
- return res; /* Return with the response value */
- }
- // for init
- uint8_t SD_SendCommandSlow(uint8_t cmd, uint32_t arg)
- {
- uint8_t crc = 0xFF;
- uint8_t n, res;
- // transmit command to sd card
- SPIWrite8(cmd|0x40);
- // transmit argument
- SPIWrite8((uint8_t)(arg >> 24));
- SPIWrite8((uint8_t)(arg >> 16));
- SPIWrite8((uint8_t)(arg >> 8));
- SPIWrite8((uint8_t)(arg));
- // https://github.com/arduino-libraries/SD/blob/master/src/utility/Sd2Card.cpp#L132
- if (cmd == CMD0) {
- crc = 0X95; // correct crc for CMD0 with arg 0
- }
- if (cmd == CMD8) {
- crc = 0X87; // correct crc for CMD8 w
- }
- // transmit crc
- SPIWrite8(crc);
- /* Receive a command response */
- n = 10; /* Wait for a valid response in timeout of 10 attempts */
- do {
- res = SPI_TransferSlow(0xFF);
- } while ((res & 0x80) && --n);
- return res; /* Return with the response value */
- }
- /*--------------------------------------------------------------------------
- Public Functions
- ---------------------------------------------------------------------------*/
- /*-----------------------------------------------------------------------*/
- /* Initialize Disk Drive */
- /*-----------------------------------------------------------------------*/
- DSTATUS disk_initialize (void)
- {
- xdata uint8_t n, cmd, ty, buf[4];
- xdata uint16_t tmr;
- xdata uint8_t i;
- xdata uint8_t oldSpiFrequency;
- // hardware and pinout specific
- //P0MDOUT = 0x29;
- //P0SKIP = 0x07;
- //XBR0 = 0x02;
- // try keeping CKPOL at 0 for SD
- SPI0CFG = 0x40;//| 0x10; // MSTEN | CKPOL
- SPI0CN = 0x01; // SPIEN
- oldSpiFrequency = SPI0CKR;
- SPI0CKR = SPI0CKR_SPEED_INIT;
- SPI0CFG &= ~(0x20 | 0x10); // have both CKPOL and CKPHA to 0
- // assert chip select
- SPIWrite8(0xFF);
- SD_CS = SPI_CS_ENABLE;
- SPIWrite8(0xFF);
- /* Dummy clocks */
- for(i = 0; i < 10; i++) SPIWrite8(0xFF);
- ty = 0;
- if (SD_SendCommandSlow(CMD0, 0) == 1) { /* Enter Idle state */
- if (SD_SendCommandSlow(CMD8, 0x1AA) == 1) { /* SDv2 */
- for (n = 0; n < 4; n++) buf[n] = SPI_TransferSlow(0xFF); /* 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 (SD_SendCommandSlow(ACMD41, 1UL << 30) == 0) break;
- MicrosecondsWait1000();
- }
- if (tmr && SD_SendCommandSlow(CMD58, 0) == 0) { /* Check CCS bit in the OCR */
- for (n = 0; n < 4; n++) buf[n] = SPI_TransferSlow(0xFF);
- ty = (buf[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 (HC or SC) */
- }
- }
- } else { /* SDv1 or MMCv3 */
- if (SD_SendCommandSlow(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 (SD_SendCommandSlow(cmd, 0) == 0) break;
- MicrosecondsWait1000();
- }
- if (!tmr || SD_SendCommandSlow(CMD16, 512) != 0) /* Set R/W block length to 512 */
- ty = 0;
- }
- }
- CardType = ty;
- // deassert chip select
- SPIWrite8(0xFF);
- SD_CS = SPI_CS_DISABLE;
- SPIWrite8(0xFF);
- SPI0CKR = oldSpiFrequency;
- return ty ? 0 : STA_NOINIT;
- }
- /*-----------------------------------------------------------------------*/
- /* Read partial sector */
- /*-----------------------------------------------------------------------*/
- DRESULT disk_readp (
- uint8_t *buff, /* Pointer to the read buffer (NULL:Read bytes are forwarded to the stream) */
- uint32_t sector, /* Sector number (LBA) */
- uint16_t offset, /* Byte offset to read from (0..511) */
- uint16_t count /* Number of bytes to read (ofs + cnt mus be <= 512) */
- ) compact
- {
- idata DRESULT res;
- data uint8_t d;
- idata uint16_t bc, tmr;
- idata uint8_t oldSpiFrequency;
- oldSpiFrequency = SPI0CKR;
- SPI0CKR = SPI0CKR_SPEED_NORMAL;
- // assert chip select
- SPIWrite8(0xFF);
- SD_CS = SPI_CS_ENABLE;
- SPIWrite8(0xFF);
- if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */
- res = RES_ERROR;
- if (SD_SendCommand(CMD17, sector) == 0) { /* READ_SINGLE_BLOCK */
- tmr = 1000;
- do { /* Wait for data packet in timeout of 100ms */
- MicrosecondsWait100();
- d = SPI_Transfer(0xFF);
- } while (d == 0xFF && --tmr);
- if (d == 0xFE) { /* A data packet arrived */
- bc = 514 - offset - count;
- /* Skip leading bytes */
- while(offset--) SPIWrite8(0xFF);
- /* Receive a part of the sector */
- if (buff) { /* Store data to the memory */
- do
- *buff++ = SPI_Transfer(0xFF);
- while (--count);
- } else { /* Forward data to the outgoing stream */
- do {
- d = SPI_Transfer(0xFF);
- FORWARD(d);
- } while (--count);
- }
- /* Skip trailing bytes and CRC */
- while(bc--) SPIWrite8(0xFF);
- res = RES_OK;
- }
- }
- // deassert chip select
- SPIWrite8(0xFF);
- SD_CS = SPI_CS_DISABLE;
- SPIWrite8(0xFF);
- SPI0CKR = oldSpiFrequency;
- return res;
- }
- /*-----------------------------------------------------------------------*/
- /* Write partial sector */
- /*-----------------------------------------------------------------------*/
- #if _USE_WRITE
- DRESULT disk_writep (
- const uint8_t *buff, /* Pointer to the bytes to be written (NULL:Initiate/Finalize sector write) */
- uint32_t sc /* Number of bytes to send, Sector number (LBA) or zero */
- )
- {
- idata DRESULT res;
- idata uint16_t bc, tmr;
- static data uint16_t wc;
- idata uint8_t oldSpiFrequency;
- oldSpiFrequency = SPI0CKR;
- SPI0CKR = SPI0CKR_SPEED_NORMAL;
- // assert chip select
- SPIWrite8(0xFF);
- SD_CS = SPI_CS_ENABLE;
- SPIWrite8(0xFF);
- res = RES_ERROR;
- if (buff) { /* Send data bytes */
- bc = (UINT)sc;
- while (bc && wc) { /* Send data bytes to the card */
- SPIWrite8(*buff++);
- wc--; bc--;
- }
- res = RES_OK;
- } else {
- if (sc) { /* Initiate sector write transaction */
- if (!(CardType & CT_BLOCK)) sc *= 512; /* Convert to byte address if needed */
- if (SD_SendCommand(CMD24, sc) == 0) { /* WRITE_SINGLE_BLOCK */
- SPIWrite8(0xFF); SPIWrite8(0xFE); /* Data block header */
- wc = 512; /* Set byte counter */
- res = RES_OK;
- }
- } else { /* Finalize sector write transaction */
- bc = wc + 2;
- while (bc--) SPIWrite8(0); /* Fill left bytes and CRC with zeros */
- if ((SPI_Transfer(0xFF) & 0x1F) == 0x05) { /* Receive data resp and wait for end of write process in timeout of 300ms */
- for (tmr = 10000; SPI_Transfer(0xFF) != 0xFF && tmr; tmr--) /* Wait for ready (max 1000ms) */
- MicrosecondsWait100();
- if (tmr) res = RES_OK;
- }
- // deassert chip select
- SPIWrite8(0xFF);
- SD_CS = SPI_CS_DISABLE;
- SPIWrite8(0xFF);
- SPI0CKR = oldSpiFrequency;
- }
- }
- return res;
- }
- #endif
- // SD.h
- #ifndef __SD_H__
- #define __SD_H__
- #include <REG51F380.H>
- #include "types.h"
- // 100-400KHz during init
- #define SPI0CKR_SPEED_INIT (14*2*4)
- // max speed 20MHz+ is OK
- #define SPI0CKR_SPEED_NORMAL (0+3-1)
- #define CMD0_ARG 0x00000000
- #define CMD8_ARG 0x0000001AA
- #define ACMD41_ARG 0x40000000
- #define CMD0 0X00
- /** SEND_IF_COND - verify SD Memory Card interface operating condition.*/
- #define CMD8 0X08
- /** SEND_CSD - read the Card Specific Data (CSD register) */
- #define CMD9 0X09
- /** SEND_CID - read the card identification information (CID register) */
- #define CMD10 0X0A
- /** SEND_STATUS - read the card status register */
- #define CMD13 0X0D
- /** READ_BLOCK - read a single data block from the card */
- #define CMD17 0X11
- /** WRITE_BLOCK - write a single data block to the card */
- #define CMD24 0X18
- /** WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION */
- #define CMD25 0X19
- /** ERASE_WR_BLK_START - sets the address of the first block to be erased */
- #define CMD32 0X20
- /** ERASE_WR_BLK_END - sets the address of the last block of the continuous
- range to be erased*/
- #define CMD33 0X21
- /** ERASE - erase all previously selected blocks */
- #define CMD38 0X26
- /** APP_CMD - escape for application specific command */
- #define CMD55 0X37
- /** READ_OCR - read the OCR register of a card */
- #define CMD58 0X3A
- /** SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be
- pre-erased before writing */
- #define ACMD23 0X17
- /** SD_SEND_OP_COMD - Sends host capacity support information and
- activates the card's initialization process */
- #define ACMD41 0X29
- #define PARAM_ERROR(X) X & 0b01000000
- #define ADDR_ERROR(X) X & 0b00100000
- #define ERASE_SEQ_ERROR(X) X & 0b00010000
- #define CRC_ERROR(X) X & 0b00001000
- #define ILLEGAL_CMD(X) X & 0b00000100
- #define ERASE_RESET(X) X & 0b00000010
- #define IN_IDLE(X) X & 0b00000001
- /*struct SD_Error_Struct {
- unsigned IN_WHILE:1;
- unsigned ERASE_RESET:1;
- unsigned ILLEGAL_CMD:1;
- unsigned CRC_ERROR:1;
- unsigned ERASE_SEQ_ERROR:1;
- unsigned ADDR_ERROR:1;
- unsigned PARAM_ERROR:1;
- unsigned padding:1;
- } SD_Error_t;*/
- #define CMD_VER(X) ((X >> 4) & 0xF0)
- #define VOL_ACC(X) (X & 0x1F)
- #define VOLTAGE_ACC_27_33 0b00000001
- #define VOLTAGE_ACC_LOW 0b00000010
- #define VOLTAGE_ACC_RES1 0b00000100
- #define VOLTAGE_ACC_RES2 0b00001000
- #define SD_IN_IDLE_STATE 0x01
- #define SD_READY 0x00
- #define SD_R1_NO_ERROR(X) X < 0x02
- #define R3_BYTES 4
- #define R7_BYTES 4
- #define CMD0_MAX_ATTEMPTS 255
- #define CMD55_MAX_ATTEMPTS 255
- #define SD_ERROR 1
- #define SD_SUCCESS 0
- #define SD_MAX_READ_ATTEMPTS 1563
- #define SD_MAX_WRITE_ATTEMPTS 3907
- #define SD_READ_START_TOKEN 0xFE
- #define SD_INIT_CYCLES 80
- #define SD_START_TOKEN 0xFE
- #define SD_ERROR_TOKEN 0x00
- #define SD_DATA_ACCEPTED 0x05
- #define SD_DATA_REJECTED_CRC 0x0B
- #define SD_DATA_REJECTED_WRITE 0x0D
- #define SD_BLOCK_LEN 512
- /*--------------------------------------------------------------------------
- Module Private Functions
- ---------------------------------------------------------------------------*/
- /* 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 CMD16 (0x40+16) /* SET_BLOCKLEN */
- //#define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */
- //#define CMD24 (0x40+24) /* WRITE_BLOCK */
- //#define CMD55 (0x40+55) /* APP_CMD */
- //#define CMD58 (0x40+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 */
- //void SD_Powerup();
- uint8_t SPI_Transfer(uint8_t SPI_data);
- uint8_t SPI_TransferSlow(uint8_t SPI_data);
- uint8_t SD_SendCommand(uint8_t cmd, uint32_t arg);
- uint8_t SD_SendCommandSlow(uint8_t cmd, uint32_t arg);
- /*
- // R1 seams to be a header for other commands
- uint8_t SD_readResponseR1();
- uint8_t SD_GoIdle();
- void SD_readResponseR7R3(uint8_t *res);
- uint8_t SD_Init();
- void SD_SendInterfaceCondition(uint8_t *res);
- void SD_ReadOCR(uint8_t *res);
- uint8_t SD_sendAppSpecificCMDStatus();
- uint8_t SD_sendOperationConditions();
- uint8_t SD_ReadSingleBlock(uint32_t addr, uint8_t *buf, uint8_t *token);
- //uint8_t SD_WriteSingleBlock(uint32_t addr, uint8_t *buf, uint8_t *token);
- */
- #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement