uint8_t mmc_init(void) { unsigned int i,retval; digitalWrite(SDSS,HIGH) ; for(i=0;i<10;i++) // send 80 clocks while card power stabilizes (void)spixfer(0xff); mmc_send_command(0,0,0); // send CMD0 - reset card retval=mmc_get(); if (retval != 1) // if no valid response code { printf("\nmmc init cmd 0 failed with code %d (should have been 1)\n"); mmc_clock_and_release(); return 1; // card cannot be detected } // // send CMD1 until we get a 0 back, indicating card is done initializing // i = 0xff; // max timeout while ((spixfer(0xff) != 0) && (--i)) // wait for it { mmc_send_command(1,0,0); // send CMD1 - activate card init } mmc_clock_and_release(); // clean up if (i == 0){ // if we timed out above printf("\nmmc cmd 1 failed\n"); return 2; // return failure code } return 0; }
/** Init MMC/SD card. Initialize I/O ports for the MMC/SD interface and send init commands to the MMC/SD card \return 0 on success, other values on error */ uint8_t mmc_init(void) { //Run configure_spi() to setup the SPI port before initializing MMC. int i; for(i=0;i<10;i++) // send 8 clocks while card power stabilizes spi_byte(0xff); mmc_send_command(0,0,0); // send CMD0 - reset card if (mmc_get() != 1) // if no valid response code { mmc_clock_and_release(); return 1; // card cannot be detected } // // send CMD1 until we get a 0 back, indicating card is done initializing // i = 0xffff; // max timeout while ((spi_byte(0xff) != 0) && (--i)) // wait for it { mmc_send_command(1,0,0); // send CMD1 - activate card init } mmc_clock_and_release(); // clean up if (i == 0) // if we timed out above return 2; // return failure code return 0; }
void mmc_playerStop(){ if(mmc_player_status==MMC_PLAYER_STARTED){ mmc_send_command(12,0,0); //stop transfers mmc_clock_and_release(); } mmc_player_status = MMC_PLAYER_STOPPED; }
static int mmc_get_card_status(uint32_t* result) { return mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SEND_STATUS) | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, MMC_CMD_SEND_STATUS_RCA(CEATA_MMC_RCA), result, CEATA_COMMAND_TIMEOUT); }
static int ceata_write_multiple_register(uint32_t addr, void* dest, uint32_t size) { uint32_t i; if (size > 0x10) RET_ERR(0); mmc_discard_irq(); SDCI_DMASIZE = size; SDCI_DMACOUNT = 0; SDCI_DCTRL = SDCI_DCTRL_TXFIFORST | SDCI_DCTRL_RXFIFORST; PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_CEATA_RW_MULTIPLE_REG) | SDCI_CMD_CMD_TYPE_ADTC | SDCI_CMD_CMD_RD_WR | SDCI_CMD_RES_BUSY | SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, MMC_CMD_CEATA_RW_MULTIPLE_REG_DIRECTION_WRITE | MMC_CMD_CEATA_RW_MULTIPLE_REG_ADDRESS(addr & 0xfc) | MMC_CMD_CEATA_RW_MULTIPLE_REG_COUNT(size & 0xfc), NULL, CEATA_COMMAND_TIMEOUT), 3, 1); SDCI_DCTRL = SDCI_DCTRL_TRCONT_TX; for (i = 0; i < size / 4; i++) SDCI_DATA = ((uint32_t*)dest)[i]; long startusec = USEC_TIMER; if (semaphore_wait(&mmc_wakeup, CEATA_COMMAND_TIMEOUT * HZ / 1000000) == OBJ_WAIT_TIMEDOUT) RET_ERR(2); while ((SDCI_STATE & SDCI_STATE_DAT_STATE_MASK) != SDCI_STATE_DAT_STATE_IDLE) { if (TIMEOUT_EXPIRED(startusec, CEATA_COMMAND_TIMEOUT)) RET_ERR(3); yield(); } PASS_RC(mmc_dsta_check_data_success(), 3, 4); return 0; }
/* write a single 512 byte sector to the SD card */ unsigned int mmc_writesector(uint32_t lba, uint8_t *buffer) { uint16_t i; uint8_t r; CS_ASSERT; // send command and sector mmc_send_command(WRITE_SINGLE_BLOCK, lba<<9); mmc_datatoken(); // get response spi_byte(0xfe); // send start block token for (i=0;i<512;i++) // write sector data spi_byte(*buffer++); spi_byte(0xff); // ignore checksum spi_byte(0xff); // ignore checksum r = spi_byte(0xff); // check for error if ((r & 0x1f) != 0x05) return r; // wait for SD card to complete writing and become idle i = 0xffff; while (!spi_byte(0xff) && --i) ; // wait for card to finish writing mmc_release(); // cleanup if (!i) return -1; // timeout error return 0; }
static int mmc_fastio_read(uint32_t addr, uint32_t* data) { return mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_FAST_IO) | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R4 | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, MMC_CMD_FAST_IO_RCA(CEATA_MMC_RCA) | MMC_CMD_FAST_IO_DIRECTION_READ | MMC_CMD_FAST_IO_ADDRESS(addr), data, CEATA_COMMAND_TIMEOUT); }
/* Initialize a mmc/sd card */ uint8_t mmc_init(void) { int i; // setup I/O ports PORTB &= ~((1 << MMC_SCK) | (1 << MMC_MOSI)); PORTB |= (1 << MMC_MISO); DDRB |= (1<<MMC_SCK) | (1<<MMC_MOSI); PORTB |= (1 << MMC_CS); DDRB |= (1 << MMC_CS); SPCR = (1<<MSTR)|(1<<SPE)|2; // enable SPI interface SPSR = 0; // set/disable double speed for(i=0;i<10;i++) // send 80 clocks spi_byte(0xff); mmc_send_command(GO_IDLE_STATE,0); // reset card if (mmc_get() != 1) // error if bad/no response code { mmc_release(); return 1; } // wait for initialization to finish (gets a 0 back) i = 0xffff; while ((spi_byte(0xff) != 0) && (--i)) { mmc_send_command(SEND_OP_COND,0); // init card } if (!i) return 2; // timed out above mmc_send_command(SET_BLOCK_LEN, 512); //set block size to 512 mmc_release(); // increase SPI clock to (Fosc/2) SPCR &= ~3; SPSR = 1; return 0; }
static int mmc_fastio_write(uint32_t addr, uint32_t data) { return mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_FAST_IO) | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R4 | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, MMC_CMD_FAST_IO_RCA(CEATA_MMC_RCA) | MMC_CMD_FAST_IO_DIRECTION_WRITE | MMC_CMD_FAST_IO_ADDRESS(addr) | MMC_CMD_FAST_IO_DATA(data), NULL, CEATA_COMMAND_TIMEOUT); }
static int mmc_init(void) { sleep(HZ / 10); PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_GO_IDLE_STATE) | SDCI_CMD_CMD_TYPE_BC | SDCI_CMD_RES_TYPE_NONE | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NID, 0, NULL, CEATA_COMMAND_TIMEOUT), 3, 0); long startusec = USEC_TIMER; uint32_t result; do { if (TIMEOUT_EXPIRED(startusec, CEATA_POWERUP_TIMEOUT)) RET_ERR(1); sleep(HZ / 100); PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SEND_OP_COND) | SDCI_CMD_CMD_TYPE_BCR | SDCI_CMD_RES_TYPE_R3 | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NID, MMC_CMD_SEND_OP_COND_OCR(MMC_OCR_270_360), NULL, CEATA_COMMAND_TIMEOUT), 3, 2); result = SDCI_RESP0; } while (!(result & MMC_OCR_POWER_UP_DONE)); PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_ALL_SEND_CID) | SDCI_CMD_CMD_TYPE_BCR | SDCI_CMD_RES_TYPE_R2 | SDCI_CMD_RES_SIZE_136 | SDCI_CMD_NCR_NID_NID, 0, NULL, CEATA_COMMAND_TIMEOUT), 3, 3); PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SET_RELATIVE_ADDR) | SDCI_CMD_CMD_TYPE_BCR | SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, MMC_CMD_SET_RELATIVE_ADDR_RCA(CEATA_MMC_RCA), NULL, CEATA_COMMAND_TIMEOUT), 3, 4); PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SELECT_CARD) | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, MMC_CMD_SELECT_CARD_RCA(CEATA_MMC_RCA), NULL, CEATA_COMMAND_TIMEOUT), 3, 5); PASS_RC(mmc_get_card_status(&result), 3, 6); if ((result & MMC_STATUS_CURRENT_STATE_MASK) != MMC_STATUS_CURRENT_STATE_TRAN) RET_ERR(7); return 0; }
static int ceata_cancel_command(void) { *((uint32_t volatile*)0x3cf00200) = 0x9000e; udelay(1); *((uint32_t volatile*)0x3cf00200) = 0x9000f; udelay(1); *((uint32_t volatile*)0x3cf00200) = 0x90003; udelay(1); PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_STOP_TRANSMISSION) | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_BUSY | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, 0, NULL, CEATA_COMMAND_TIMEOUT), 1, 0); PASS_RC(ceata_wait_idle(), 1, 1); return 0; }
static int ceata_init(int buswidth) { uint32_t result; PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SWITCH) | SDCI_CMD_RES_BUSY | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, MMC_CMD_SWITCH_ACCESS_WRITE_BYTE | MMC_CMD_SWITCH_INDEX(MMC_CMD_SWITCH_FIELD_HS_TIMING) | MMC_CMD_SWITCH_VALUE(MMC_CMD_SWITCH_FIELD_HS_TIMING_HIGH_SPEED), &result, CEATA_COMMAND_TIMEOUT), 3, 0); if (result & MMC_STATUS_SWITCH_ERROR) RET_ERR(1); if (buswidth > 1) { int setting; if (buswidth == 4) setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_4BIT; else if (buswidth == 8) setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_8BIT; else setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_1BIT; PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SWITCH) | SDCI_CMD_RES_BUSY | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, MMC_CMD_SWITCH_ACCESS_WRITE_BYTE | MMC_CMD_SWITCH_INDEX(MMC_CMD_SWITCH_FIELD_BUS_WIDTH) | MMC_CMD_SWITCH_VALUE(setting), &result, CEATA_COMMAND_TIMEOUT), 3, 2); if (result & MMC_STATUS_SWITCH_ERROR) RET_ERR(3); if (buswidth == 4) SDCI_CTRL = (SDCI_CTRL & ~SDCI_CTRL_BUS_WIDTH_MASK) | SDCI_CTRL_BUS_WIDTH_4BIT; else if (buswidth == 8) SDCI_CTRL = (SDCI_CTRL & ~SDCI_CTRL_BUS_WIDTH_MASK) | SDCI_CTRL_BUS_WIDTH_8BIT; } PASS_RC(ceata_soft_reset(), 3, 4); PASS_RC(ceata_read_multiple_register(0, ceata_taskfile, 0x10), 3, 5); if (ceata_taskfile[0xc] != 0xce || ceata_taskfile[0xd] != 0xaa) RET_ERR(6); PASS_RC(mmc_fastio_write(6, 0), 3, 7); return 0; }
//starts playing wav file pointed at by lba void mmc_playerStart(mmc_File file){ if(mmc_player_status==MMC_PLAYER_STARTED) { mmc_player_status = MMC_PLAYER_STOPPED; mmc_send_command(12,0,0); //stop current transfer mmc_clock_and_release(); } // send the multiple block read command and logical sector address mmc_player_sector=file.firstSector; mmc_send_command(18,(mmc_player_sector>>7) & 0xffff, (mmc_player_sector<<9) & 0xffff); playerRead=0; sectorRead=0; samplesToPlay.value=-1; mmc_player_status = MMC_PLAYER_STARTED; }
static int ceata_rw_multiple_block(bool write, void* buf, uint32_t count, long timeout) { mmc_discard_irq(); uint32_t responsetype; uint32_t cmdtype; uint32_t direction; if (write) { cmdtype = SDCI_CMD_CMD_TYPE_ADTC | SDCI_CMD_CMD_RD_WR; responsetype = SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_BUSY; direction = MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_DIRECTION_WRITE; } else { cmdtype = SDCI_CMD_CMD_TYPE_ADTC; responsetype = SDCI_CMD_RES_TYPE_R1; direction = MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_DIRECTION_READ; } SDCI_DMASIZE = 0x200; SDCI_DMAADDR = buf; SDCI_DMACOUNT = count; SDCI_DCTRL = SDCI_DCTRL_TXFIFORST | SDCI_DCTRL_RXFIFORST; commit_discard_dcache(); PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_CEATA_RW_MULTIPLE_BLOCK) | SDCI_CMD_CMD_TYPE_ADTC | cmdtype | responsetype | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, direction | MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_COUNT(count), NULL, CEATA_COMMAND_TIMEOUT), 4, 0); if (write) SDCI_DCTRL = SDCI_DCTRL_TRCONT_TX; if (semaphore_wait(&mmc_wakeup, timeout) == OBJ_WAIT_TIMEDOUT) { PASS_RC(ceata_cancel_command(), 4, 1); RET_ERR(2); } PASS_RC(mmc_dsta_check_data_success(), 4, 3); if (semaphore_wait(&mmc_comp_wakeup, timeout) == OBJ_WAIT_TIMEDOUT) { PASS_RC(ceata_cancel_command(), 4, 4); RET_ERR(4); } PASS_RC(ceata_check_error(), 4, 5); return 0; }
static int ceata_read_multiple_register(uint32_t addr, void* dest, uint32_t size) { if (size > 0x10) RET_ERR(0); mmc_discard_irq(); SDCI_DMASIZE = size; SDCI_DMACOUNT = 1; SDCI_DMAADDR = dest; SDCI_DCTRL = SDCI_DCTRL_TXFIFORST | SDCI_DCTRL_RXFIFORST; commit_discard_dcache(); PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_CEATA_RW_MULTIPLE_REG) | SDCI_CMD_CMD_TYPE_ADTC | SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR, MMC_CMD_CEATA_RW_MULTIPLE_REG_DIRECTION_READ | MMC_CMD_CEATA_RW_MULTIPLE_REG_ADDRESS(addr & 0xfc) | MMC_CMD_CEATA_RW_MULTIPLE_REG_COUNT(size & 0xfc), NULL, CEATA_COMMAND_TIMEOUT), 2, 1); if (semaphore_wait(&mmc_wakeup, CEATA_COMMAND_TIMEOUT * HZ / 1000000) == OBJ_WAIT_TIMEDOUT) RET_ERR(2); PASS_RC(mmc_dsta_check_data_success(), 2, 3); return 0; }
/* reads a single 512 bytes sector from the SD card */ int mmc_readsector(uint32_t lba, uint8_t *buffer) { uint16_t i; // send command and sector mmc_send_command(READ_SINGLE_BLOCK, lba<<9); if (mmc_datatoken() != 0xfe) // wait for start of block token { mmc_release(); // error return -1; } for (i=0;i<512;i++) *buffer++ = spi_byte(0xff); // read data spi_byte(0xff); // ignore checksum spi_byte(0xff); // ignore checksum mmc_release(); return 0; }