diff --git a/fatfs/diskio.c b/fatfs/diskio.c index d557503..21a33c5 100644 --- a/fatfs/diskio.c +++ b/fatfs/diskio.c @@ -33,7 +33,7 @@ DSTATUS disk_status ( switch (pdrv) { case DEV_SD: - return SDIO_status(); + return sdio_status(); } return STA_NOINIT; } @@ -53,7 +53,7 @@ DSTATUS disk_initialize ( switch (pdrv) { case DEV_SD: - return SDIO_initialize(); + return sdio_initialize(); } return STA_NOINIT; } @@ -76,7 +76,7 @@ DRESULT disk_read ( switch (pdrv) { case DEV_SD: - return SDIO_disk_read(buff, sector, count); + return sdio_disk_read(buff, sector, count); } return RES_PARERR; } @@ -125,7 +125,7 @@ DRESULT disk_ioctl ( switch (pdrv) { case DEV_SD: - return SDIO_disk_ioctl(cmd, buff); + return sdio_disk_ioctl(cmd, buff); } return RES_PARERR; diff --git a/fatfs/shimatta_sdio_driver/shimatta_sdio.c b/fatfs/shimatta_sdio_driver/shimatta_sdio.c index 763079e..979ee48 100644 --- a/fatfs/shimatta_sdio_driver/shimatta_sdio.c +++ b/fatfs/shimatta_sdio_driver/shimatta_sdio.c @@ -9,7 +9,8 @@ #include "shimatta_sdio_config.h" #include #include -extern void SDIO_wait_ms(unsigned int i); + +extern void sdio_wait_ms(unsigned int i); #define SETAF(PORT,PIN,AF) PORT->AFR[(PIN < 8 ? 0 : 1)] |= AF << ((PIN < 8 ? PIN : (PIN - 8)) * 4) @@ -20,7 +21,6 @@ extern void SDIO_wait_ms(unsigned int i); #define LONG_ANS 3 #define NO_ANS 0 - #define CCRCFAIL 1 #define CTIMEOUT 2 #define CNOTEXPETED 3 @@ -29,10 +29,11 @@ extern void SDIO_wait_ms(unsigned int i); #define OCS_CCS (1<<30) #define OCS_BUSY (1<<31) -typedef enum {ACMD41_RESP_INIT = 0, ACMD41_RESP_ERR, ACMD41_RESP_SDSC, ACMD41_RESP_SDXC} ACMD41_RESP_t; -typedef enum {CMD8_RESP_TIMEOUT = 0, CMD8_VOLTAGE_ACCEPTED, CMD8_VOLTAGE_DENIED} CMD8_RESP_t; +enum acmd41_ret {ACMD41_RESP_INIT = 0, ACMD41_RESP_ERR, ACMD41_RESP_SDSC, ACMD41_RESP_SDXC}; +enum cmd8_ret {CMD8_RESP_TIMEOUT = 0, CMD8_VOLTAGE_ACCEPTED, CMD8_VOLTAGE_DENIED}; typedef uint8_t CID_t; +/* void SDIO_init_hw(); int SDIO_send_cmd(uint8_t CMD, uint32_t arg, uint8_t expectedAns); @@ -58,28 +59,153 @@ void switchPrescaler(uint8_t clkdiv); int SDIO_send_write_block_CMD24(uint32_t addr); int SDIO_send_read_block_CMD17(uint32_t addr); int SDIO_get_sector_count(uint16_t rca, uint32_t *sector_count); +*/ //BYTE rxtxbuffer[1<IDR & INS_PIN) == (INS_ACTIVE_LEVEL<IDR & WRITEPROT_PIN) == (WRITEPROT_ACTIVE_LEVEL<STA & SDIO_STA_CMDSENT)); + SDIO->ICR |= SDIO_ICR_CMDSENTC; +} + +static int sdio_send_cmd(uint8_t CMD, uint32_t arg, uint8_t expectedAns){ + //Clear Flags + SDIO->ICR = SDIO_ICR_CCRCFAILC | SDIO_ICR_CMDRENDC | SDIO_ICR_CTIMEOUTC | SDIO_ICR_CMDSENTC; + //Send command + SDIO->ARG = arg; + SDIO->CMD = (CMD & SDIO_CMD_CMDINDEX) | SDIO_CMD_CPSMEN | /*SDIO_CMD_WAITPEND |*/ ((expectedAns << 6) & SDIO_CMD_WAITRESP); + return 0; +} + +static int sdio_get_response(uint8_t expected_command, uint8_t type_of_answer, uint32_t *response_buffer) { + uint32_t sdio_status; + + /* Wait until command isn't active anymore */ + while (SDIO->STA & SDIO_STA_CMDACT); + + /* Wait for error or success */ + while (1) { + sdio_status = SDIO->STA; + + /* Check if a valid response was received */ + if (sdio_status & SDIO_STA_CMDREND) + break; + + if ((sdio_status & SDIO_STA_CMDSENT) && (type_of_answer == NO_ANS)) + break; // No response required + + /* Exclude ACMD41 and CMD2 from valid CRC check */ + if ((sdio_status & SDIO_STA_CCRCFAIL)) { + if(expected_command == 0xff) { + break; + } else { + return -CCRCFAIL; + } + } + + if (sdio_status & SDIO_STA_CTIMEOUT) + return -CTIMEOUT; + } + //Valid Respone Received + if (((SDIO->RESPCMD & SDIO_RESPCMD_RESPCMD) != expected_command) && (expected_command != 0xff)) + return -CNOTEXPETED; //Not the expected respose + + /* If case of a correct Response */ + *(response_buffer++) = SDIO->RESP1; + /* Long response */ + if (type_of_answer == LONG_ANS) { + *(response_buffer++) = SDIO->RESP2; + *(response_buffer++) = SDIO->RESP3; + *(response_buffer++) = SDIO->RESP4; + } + + return 0; +} + +static int sdio_switch_appmode_cmd55() +{ + int retry = 0x20; + union sdio_status_conv converter; + uint32_t response; + do { + //Execute Command and check for valid response + sdio_send_cmd(55, (card_info.rca<<16)&0xFFFF0000, SHORT_ANS); + + if (!sdio_get_response(55, SHORT_ANS, &response)) + { + //Response valid. Check if Card has accepted switch to application command mode + converter.value = response; + if (converter.statusstruct.APP_CMD == 1) + return 0; + } + }while(--retry > 0); + + return -1; +} + +enum acmd41_ret sdio_init_card_acmd41(uint8_t HCS){ + uint32_t response; + int retry = 0x20; + if (sdio_switch_appmode_cmd55()) return ACMD41_RESP_ERR; + do { + sdio_send_cmd(41, (HCS ? (1<<30) : 0) | (1<<28) | (1<<20) |(1<<21)|(1<<22) |(1<<23)|(1<<19), SHORT_ANS); + if (!sdio_get_response(0xFF, SHORT_ANS, &response)) { + if (response & OCS_BUSY) { // Card is ready... Who knows why this bit is called busy... + if (response & OCS_CCS) { + return ACMD41_RESP_SDXC; + } else { + return ACMD41_RESP_SDSC; + } + } else { + return ACMD41_RESP_INIT; + } + } + }while(--retry > 0); + + return ACMD41_RESP_ERR; +} + +static int sdio_send_csd_cmd9(uint16_t rca, uint32_t *responsebuffer) { + int timeout = 0x20; + int res; + + do { + sdio_send_cmd(9, (rca<<16)&0xFFFF0000, LONG_ANS); + if (!(res = sdio_get_response(0xFF, LONG_ANS, responsebuffer))) { + break; + } + } while(--timeout > 0); + + return res; +} + +static void sdio_write_buffer(uint32_t dlen, uint32_t blklen, uint8_t *buff) { int count; int byte_count; @@ -118,123 +244,377 @@ sdio_write_buffer(uint32_t dlen, uint32_t blklen, uint8_t *buff) } -/* -uint8_t data1[512] = {(1<<1), 16, 0xC9, 0x9A, 0x20, 0x84, 0x3E, 0xD7, 0xD9, 0x0B, 0x68, 0x01, - 0xE4, 0x9F, 0x2B, 0xC8, 0x02, 0x77}; -sdio_unlock_card() +static int sdio_send_write_block_cmd24(uint32_t addr) { + return -1; +} - uint32_t resp[10]; +static int sdio_check_status_register_cmd13(uint16_t rca, uint32_t *status) +{ + int timeout = 0x20; + uint32_t response; + int res; + do { + sdio_send_cmd(13, (rca<<16)&0xFFFF0000, SHORT_ANS); + if (!(res = sdio_get_response(13, SHORT_ANS, &response))) { + *status = response; + break; + } + } while(--timeout > 0); - //SDIO_send_block_length_CMD16(18U); + return res; +} - SDIO_send_cmd(42, 0, SHORT_ANS); - SDIO_get_response(42, SHORT_ANS, resp); +static int sdio_send_bus_width_acmd6(uint8_t bus_width) +{ + uint32_t response; + int retry = 0x20; + union sdio_status_conv status; + int ret; + if (sdio_switch_appmode_cmd55()) return -1; + do { + sdio_send_cmd(0x6, (bus_width == 4 ? 0x2 : 0x0), SHORT_ANS); + if (!(ret = sdio_get_response(0x6, SHORT_ANS, &response))) { + status.value = response; + return 0; + } - sdio_write_buffer(512, 9, data1); + } while (--retry > 0); + + return ret; } -*/ -DSTATUS SDIO_initialize(){ - int timeout = 0x3000; - CMD8_RESP_t res8; - ACMD41_RESP_t resa41; - uint8_t hcs_flag = 0; - card_info.rca = 0; - card_info.type = CARD_NONE; - card_type_t detected_card = CARD_NONE; +static int sdio_get_sector_count(uint16_t rca, uint32_t *sector_count) +{ + uint32_t csd[4]; + int res; + uint32_t size, mult, read_len, csd_rev; - SDIO_init_hw(); - SDIO_wait_ms(2); - SDIO_init_detect_pins(); - if (checkNotInserted()) { - return STA_NOINIT | STA_NODISK; - } + if ((res = sdio_send_csd_cmd9(rca, csd))) { + return -1; + } - debug=0; - SDIO_send_go_idle_CMD0(); - SDIO_wait_ms(2); - res8 = SDIO_send_iface_condition_CMD8(); - switch (res8) { - case CMD8_VOLTAGE_ACCEPTED: // SDV2 Card - hcs_flag = 1; - break; - case CMD8_VOLTAGE_DENIED: // should not happen - return STA_NOINIT; - break; - case CMD8_RESP_TIMEOUT: // SDV1 Card - hcs_flag=0; - break; - default: - return STA_NOINIT; - break; - } - debug++; - debug_timeout=timeout; - do { - //SDIO_wait_ms(2); - resa41 = SDIO_init_card_ACMD41(hcs_flag); - } while((resa41 == ACMD41_RESP_INIT) && (--timeout > 0)); + csd_rev = ((csd[0] >> 30) & (0x3)); - debug++; - debug_acmd = resa41; - debug_timeout= timeout; - switch (resa41) { - case ACMD41_RESP_SDSC: - detected_card = (hcs_flag ? SD_V2_SC : SD_V1); - break; - case ACMD41_RESP_SDXC: - detected_card = SD_V2_HC; - break; - default: - return STA_NOINIT; - break; - } - debug++; - if (SDIO_send_all_send_cid_CMD2()) - return STA_NOINIT; + if (csd_rev == 0) { // SD v1 Card + size = ((csd[1] & 0x3FF) <<2) | (((csd[2]) & ((1<<31) | (1<<30)))>>30); + mult = ((csd[2] & ((1<<17)|(1<<16)|(1<<15)))>>15); + read_len = (1<<((csd[1] & ((1<<19)|(1<<18)|(1<<17)|(1<<16)))>>16)); + *sector_count = (((size +1)*(1<<(mult+2))*read_len) >> BLOCKSIZE); + } else if (csd_rev == 1) { // SD v2 Card + size = (((csd[1] & 0x3F)<<16) | ((csd[2] & 0xFFFF0000) >> 16)); + *sector_count = (size << (19-BLOCKSIZE)); + } - if (SDIO_send_relative_address_CMD3(&card_info.rca)) - return STA_NOINIT; - if (SDIO_get_sector_count(card_info.rca, &card_info.sector_count)) - return STA_NOINIT; - if (SDIO_send_select_card_CMD7(card_info.rca)) - return STA_NOINIT; - - if (SDIO_send_block_length_CMD16((uint32_t)(1<CLKCR; + /* Clear prescaler */ + reg &= ~SDIO_CLKCR_CLKDIV; + /* Set bits */ + reg |= (SDIO_CLKCR_CLKDIV & clkdiv); + SDIO->CLKCR = reg; +} -DRESULT SDIO_disk_read(BYTE *buff, DWORD sector, UINT count){ - uint32_t addr; - uint32_t sdio_status; - uint32_t fifo; - uint32_t counter; - debug_addr = sector; - debug_count = count; - addr = (card_info.type == SD_V2_HC ? (sector) : (sector*512)); - for (; count > 0; count--) { +/** + * @brief initDetectandProtectionPins + */ +static void sdio_init_detect_pins() +{ +#if SDIO_ENABLE_WRITEPROT==1 + WRITEPROT_PORT->PUPDR |= ((WRITEPROT_PULLUP ? 1 : 0)<PUPDR |= ((INS_PULLUP? 1 : 0)<AHB1ENR |= PORTCLKMASK | RCC_AHB1ENR_DMA2EN; + RCC->APB2ENR |= RCC_APB2ENR_SDIOEN; + //Init Alternate Functions + CLKPORT->MODER |= (2<MODER |= (2<PUPDR |= (1<MODER |= (2<PUPDR |= (1<MODER |= (2<PUPDR |= (1<MODER |= (2<PUPDR |= (1<MODER |= (2<PUPDR |= (1<AFR[(CLKPIN < 8 ? 0 : 1)] |= ALTFUNC << ((CLKPIN < 8 ? CLKPIN : (CLKPIN - 8)) * 4); + SETAF(CLKPORT, CLKPIN, ALTFUNC); + SETAF(CMDPORT, CMDPIN, ALTFUNC); + SETAF(D0PORT, D0PIN, ALTFUNC); +#if BUSWIDTH==4 + SETAF(D1PORT, D1PIN, ALTFUNC); + SETAF(D2PORT, D2PIN, ALTFUNC); + SETAF(D3PORT, D3PIN, ALTFUNC); +#endif + + + //Init Module + + //Set CLK Control Register + SDIO->CLKCR = (HW_FLOW<<14) | ((BUSWIDTH == 4 ? 1 : 0)<<11) | SDIO_CLKCR_CLKEN | + (INITCLK & SDIO_CLKCR_CLKDIV); + + //Set Data Timeout + SDIO->DTIMER = DTIMEOUT; + + //Set Data Parameters + //SDIO->DCTRL = (BLOCKSIZE << 4) | SDIO_DCTRL_DMAEN; + //Set Power Register: Power up Card CLK + SDIO->POWER = SDIO_POWER_PWRCTRL_0 | SDIO_POWER_PWRCTRL_1; + +} + +static int sdio_send_read_block_cmd17(uint32_t addr) +{ + uint32_t response; + + sdio_send_cmd(17, addr, SHORT_ANS); + return sdio_get_response(17, SHORT_ANS, &response); +} + +static int sdio_send_all_send_cid_cmd2() +{ + uint32_t response[4]; + int ret; + int retry = 0x20; + do { + sdio_send_cmd(2, 0, LONG_ANS); + if (!(ret = sdio_get_response(0xFF, LONG_ANS, response))) return 0; + }while(retry-- > 0); + return ret; +} + +static int sdio_send_relative_address_cmd3(uint16_t* rca) { + uint32_t response; + int retry = 0x20; + do { + sdio_send_cmd(3, 0, SHORT_ANS); + if (!sdio_get_response(3, SHORT_ANS, &response)) { + // TODO: Do some *optional* checking + *rca = ((response & 0xFFFF0000) >> 16); + return 0; + } + }while(retry-- > 0); + return -1; +} + +static int sdio_send_go_idle_cmd0() { + sdio_send_cmd(0, 0x0, NO_ANS); + sdio_wait_cmd_sent(); + return 0; +} + +static enum cmd8_ret sdio_send_iface_condition_cmd8() { + uint32_t response; + int res = 0; + int retry = 0x20; + do { + sdio_send_cmd(8, 0x1CC, SHORT_ANS); // 3.3V supply requesR + res = sdio_get_response(8, SHORT_ANS, &response); + if (res == 0) { + if (response & 0x100) + return CMD8_VOLTAGE_ACCEPTED; + else + return CMD8_VOLTAGE_DENIED; + } + }while(retry-- > 0); + + return CMD8_RESP_TIMEOUT; +} + +static int sdio_send_block_length_cmd16(uint32_t blocklen) { + int timeout = 0x20; + int res; + uint32_t response; + + do { + sdio_send_cmd(16, blocklen, SHORT_ANS); + if (!(res = sdio_get_response(16, SHORT_ANS, &response))) { + return 0; + } + }while(--timeout > 0); + + return res; +} + +static int sdio_send_select_card_cmd7(uint16_t rca) { + int timeout = 0x20; + uint32_t response; + union sdio_status_conv status; + int res; + + /* Send CMD7. Selects card */ + do { + sdio_send_cmd(7, (rca<<16)&0xFFFF0000, SHORT_ANS); + if (!(res = sdio_get_response(7, SHORT_ANS, &response))) { + break; + } + } while(--timeout > 0); + + /* Check, if card in in TRANS state */ + if (sdio_check_status_register_cmd13(rca, &(status.value))) + res = -1; + if (status.statusstruct.CURRENT_STATE != CURRENT_STATE_TRAN) + res = -2; + return res; +} + +DSTATUS sdio_status() +{ + DSTATUS returnval = 0; + + if (sdio_check_inserted()) { + returnval |= STA_NODISK; + } + if (card_info.type == CARD_NONE) { + returnval |= STA_NOINIT; + } + if (sdio_check_write_protection()) { + returnval |= STA_PROTECT; + } + return returnval; +} + +DRESULT sdio_disk_ioctl(BYTE cmd, void* buff){ + DRESULT res = RES_OK; + switch(cmd) { + case GET_BLOCK_SIZE: + *((DWORD*)buff) = (DWORD)0x01; + break; + case GET_SECTOR_SIZE: + *((WORD*)buff) = (WORD)(1< 0)); + + switch (resa41) { + case ACMD41_RESP_SDSC: + detected_card = (hcs_flag ? SD_V2_SC : SD_V1); + break; + case ACMD41_RESP_SDXC: + detected_card = SD_V2_HC; + break; + default: + return STA_NOINIT; + break; + } + + if (sdio_send_all_send_cid_cmd2()) + return STA_NOINIT; + + if (sdio_send_relative_address_cmd3(&card_info.rca)) + return STA_NOINIT; + if (sdio_get_sector_count(card_info.rca, &card_info.sector_count)) + return STA_NOINIT; + if (sdio_send_select_card_cmd7(card_info.rca)) + return STA_NOINIT; + + if (sdio_send_block_length_cmd16((uint32_t)(1< 0; count--) { + + /* configure read DMA */ // DMA2->LIFCR = 0xffffffff; // DMA2->HIFCR = 0xffffffff; // DMASTREAM->NDTR = 0; @@ -244,467 +624,79 @@ DRESULT SDIO_disk_read(BYTE *buff, DWORD sector, UINT count){ // DMASTREAM->CR = DMAP2M | DMA_SxCR_PL_1 | DMA_SxCR_PL_1; // DMASTREAM->CR |= DMA_SxCR_EN; - SDIO->DLEN = (1 << BLOCKSIZE); + SDIO->DLEN = (1 << BLOCKSIZE); + + SDIO->ICR = SDIO_ICR_CCRCFAILC | SDIO_ICR_DCRCFAILC | SDIO_ICR_CTIMEOUTC | SDIO_ICR_DTIMEOUTC | + SDIO_ICR_TXUNDERRC | SDIO_ICR_RXOVERRC | SDIO_ICR_CMDRENDC | SDIO_ICR_CMDSENTC | SDIO_ICR_DATAENDC | + SDIO_ICR_STBITERRC | SDIO_ICR_DBCKENDC | SDIO_ICR_SDIOITC | SDIO_ICR_CEATAENDC; + SDIO->DCTRL = (BLOCKSIZE<<4) | SDIO_DCTRL_DTDIR | /*SDIO_DCTRL_DMAEN |*/ SDIO_DCTRL_DTEN; + + /* Init Transfer */ + if (sdio_send_read_block_cmd17(addr)) { + return RES_ERROR; + } + + counter = 0; + while (counter < (1<<(BLOCKSIZE-2)) || !(SDIO->STA & (SDIO_STA_DBCKEND | SDIO_STA_DATAEND))) { // TODO: Handle errors + if (SDIO->STA & (SDIO_STA_DCRCFAIL | SDIO_STA_DTIMEOUT | SDIO_STA_STBITERR)) + { + return RES_ERROR; + } + + if (SDIO->STA & SDIO_STA_RXDAVL) { + counter++; + fifo = SDIO->FIFO; + *(buff++) = (BYTE)(fifo & 0xFF); + fifo >>= 8; + *(buff++) = (BYTE)(fifo & 0xFF); + fifo >>= 8; + *(buff++) = (BYTE)(fifo & 0xFF); + fifo >>= 8; + *(buff++) = (BYTE)(fifo & 0xFF); + } + + } + if (SDIO->STA & SDIO_STA_DCRCFAIL) return RES_ERROR; + + //while(DMASTREAM->CR & DMA_SxCR_EN); + while(1) { + __DSB(); + __DMB(); + sdio_status = SDIO->STA; + if (sdio_status & SDIO_STA_DCRCFAIL) { + return RES_ERROR; + } + if (sdio_status & SDIO_STA_DTIMEOUT) { + return RES_ERROR; + } + + if (sdio_status & SDIO_STA_DATAEND) { + + if (!(sdio_status & SDIO_STA_RXACT)) { + break; + } + } + } - SDIO->ICR = SDIO_ICR_CCRCFAILC | SDIO_ICR_DCRCFAILC | SDIO_ICR_CTIMEOUTC | SDIO_ICR_DTIMEOUTC | - SDIO_ICR_TXUNDERRC | SDIO_ICR_RXOVERRC | SDIO_ICR_CMDRENDC | SDIO_ICR_CMDSENTC | SDIO_ICR_DATAENDC | - SDIO_ICR_STBITERRC | SDIO_ICR_DBCKENDC | SDIO_ICR_SDIOITC | SDIO_ICR_CEATAENDC; - SDIO->DCTRL = (BLOCKSIZE<<4) | SDIO_DCTRL_DTDIR | /*SDIO_DCTRL_DMAEN |*/ SDIO_DCTRL_DTEN; - - - /* Init Transfer */ - if (SDIO_send_read_block_CMD17(addr)) { - SDIO->DCTRL = 0; - return RES_ERROR; - } - - debug=0; - counter = 0; - while (counter < (1<<(BLOCKSIZE-2)) || !(SDIO->STA & (SDIO_STA_DBCKEND | SDIO_STA_DATAEND))) { // TODO: Handle errors - if (SDIO->STA & (SDIO_STA_DCRCFAIL | SDIO_STA_DTIMEOUT | SDIO_STA_STBITERR)) - { - return RES_ERROR; - } - - if (SDIO->STA & SDIO_STA_RXDAVL) { - counter++; - fifo = SDIO->FIFO; - *(buff++) = (BYTE)(fifo & 0xFF); - fifo >>= 8; - *(buff++) = (BYTE)(fifo & 0xFF); - fifo >>= 8; - *(buff++) = (BYTE)(fifo & 0xFF); - fifo >>= 8; - *(buff++) = (BYTE)(fifo & 0xFF); - } - - } - if (SDIO->STA & SDIO_STA_DCRCFAIL) return RES_ERROR; - - //while(DMASTREAM->CR & DMA_SxCR_EN); - while(1) { - __DSB(); - __DMB(); - sdio_status = SDIO->STA; - if (sdio_status & SDIO_STA_DCRCFAIL) { - return RES_ERROR; - } - if (sdio_status & SDIO_STA_DTIMEOUT) { - return RES_ERROR; - } - - if (sdio_status & SDIO_STA_DATAEND) { - - if (!(sdio_status & SDIO_STA_RXACT)) { - break; - } - } - } - - - if (card_info.type == SD_V2_HC) { - addr++; - } else { - addr += (1<AHB1ENR |= PORTCLKMASK | RCC_AHB1ENR_DMA2EN; - RCC->APB2ENR |= RCC_APB2ENR_SDIOEN; - //Init Alternate Functions - CLKPORT->MODER |= (2<MODER |= (2<PUPDR |= (1<MODER |= (2<PUPDR |= (1<MODER |= (2<PUPDR |= (1<MODER |= (2<PUPDR |= (1<MODER |= (2<PUPDR |= (1<AFR[(CLKPIN < 8 ? 0 : 1)] |= ALTFUNC << ((CLKPIN < 8 ? CLKPIN : (CLKPIN - 8)) * 4); - SETAF(CLKPORT, CLKPIN, ALTFUNC); - SETAF(CMDPORT, CMDPIN, ALTFUNC); - SETAF(D0PORT, D0PIN, ALTFUNC); -#if BUSWIDTH==4 - SETAF(D1PORT, D1PIN, ALTFUNC); - SETAF(D2PORT, D2PIN, ALTFUNC); - SETAF(D3PORT, D3PIN, ALTFUNC); -#endif - - - //Init Module - - //Set CLK Control Register - SDIO->CLKCR = (HW_FLOW<<14) | ((BUSWIDTH == 4 ? 1 : 0)<<11) | SDIO_CLKCR_CLKEN | - (INITCLK & SDIO_CLKCR_CLKDIV); - - //Set Data Timeout - SDIO->DTIMER = DTIMEOUT; - - //Set Data Parameters - //SDIO->DCTRL = (BLOCKSIZE << 4) | SDIO_DCTRL_DMAEN; - //Set Power Register: Power up Card CLK - SDIO->POWER = SDIO_POWER_PWRCTRL_0 | SDIO_POWER_PWRCTRL_1; - -} - -void switchPrescaler(uint8_t clkdiv) { - uint32_t reg; - reg = SDIO->CLKCR; - reg &= ~SDIO_CLKCR_CLKDIV; // Clear prescaler - reg |= (SDIO_CLKCR_CLKDIV & clkdiv); // Set bits - SDIO->CLKCR = reg; -} - -int SDIO_send_bus_width_ACMD6(uint8_t bus_width) { - uint32_t response; - int retry = 0x20; - StatusConv_t status; - int ret; - if (SDIO_switch_appmode_CMD55()) return -1; - do { - SDIO_send_cmd(0x6, (bus_width == 4 ? 0x2 : 0x0), SHORT_ANS); - if (!(ret = SDIO_get_response(0x6, SHORT_ANS, &response))) { - status.value = response; - return 0; - } - - - } while(--retry > 0); - return ret; - -} - - -//Send Command -//Clear respone Flags -//->CRC Fail, complete response, Timeout -int SDIO_send_cmd(uint8_t CMD, uint32_t arg, uint8_t expectedAns){ - //Clear Flags - SDIO->ICR = SDIO_ICR_CCRCFAILC | SDIO_ICR_CMDRENDC | SDIO_ICR_CTIMEOUTC | SDIO_ICR_CMDSENTC; - //Send command - SDIO->ARG = arg; - SDIO->CMD = (CMD & SDIO_CMD_CMDINDEX) | SDIO_CMD_CPSMEN | /*SDIO_CMD_WAITPEND |*/ ((expectedAns << 6) & SDIO_CMD_WAITRESP); - return 0; -} - -int SDIO_send_write_block_CMD24(uint32_t addr) { - return -1; -} - -int SDIO_send_read_block_CMD17(uint32_t addr) { - uint32_t response; - - SDIO_send_cmd(17, addr, SHORT_ANS); - return SDIO_get_response(17, SHORT_ANS, &response); -} - -void SDIO_wait_cmd_sent() { - while (!(SDIO->STA & SDIO_STA_CMDSENT)); - SDIO->ICR |= SDIO_ICR_CMDSENTC; -} - -int SDIO_get_response(uint8_t expected_command, uint8_t type_of_answer, uint32_t *response_buffer) { - uint32_t sdio_status; - - /* Wait until command isn't active anymore */ - while (SDIO->STA & SDIO_STA_CMDACT); - - /* Wait for error or success */ - while (1) { - sdio_status = SDIO->STA; - - /* Check if a valid response was received */ - if (sdio_status & SDIO_STA_CMDREND) - break; - if ((sdio_status & SDIO_STA_CMDSENT) && (type_of_answer == NO_ANS)) break; // No response required - - //Exclude ACMD41 and CMD2 from valid CRC check - if ((sdio_status & SDIO_STA_CCRCFAIL)) { - if(expected_command == 0xff) { - break; - } else { - return -CCRCFAIL; - } - } - - - if (sdio_status & SDIO_STA_CTIMEOUT) - return -CTIMEOUT; - } - //Valid Respone Received - if (((SDIO->RESPCMD & SDIO_RESPCMD_RESPCMD) != expected_command) && (expected_command != 0xff)) - return -CNOTEXPETED; //Not the expected respose - - //If case of a correct Response - *(response_buffer++) = SDIO->RESP1; - //Long response. - if (type_of_answer == LONG_ANS) { - *(response_buffer++) = SDIO->RESP2; - *(response_buffer++) = SDIO->RESP3; - *(response_buffer++) = SDIO->RESP4; - } - return 0; - -} - -int SDIO_switch_appmode_CMD55(){ - int retry = 0x20; - StatusConv_t converter; - uint32_t response; - do { - //Execute Command and check for valid response - SDIO_send_cmd(55, (card_info.rca<<16)&0xFFFF0000, SHORT_ANS); - - if (!SDIO_get_response(55, SHORT_ANS, &response)) - { - //Response valid. Check if Card has accepted switch to application command mode - converter.value = response; - if (converter.statusstruct.APP_CMD == 1) - return 0; - } - }while(--retry > 0); - - return -1; -} - - -ACMD41_RESP_t SDIO_init_card_ACMD41(uint8_t HCS){ - uint32_t response; - int retry = 0x20; - if (SDIO_switch_appmode_CMD55()) return ACMD41_RESP_ERR; - do { - SDIO_send_cmd(41, (HCS ? (1<<30) : 0) | (1<<28) | (1<<20) |(1<<21)|(1<<22) |(1<<23)|(1<<19), SHORT_ANS); - if (!SDIO_get_response(0xFF, SHORT_ANS, &response)) { - if (response & OCS_BUSY) { // Card is ready... Who knows why this bit is called busy... - if (response & OCS_CCS) { - return ACMD41_RESP_SDXC; - } else { - return ACMD41_RESP_SDSC; - } - } else { - return ACMD41_RESP_INIT; - } - } - }while(--retry > 0); - - return ACMD41_RESP_ERR; -} - -int SDIO_send_all_send_cid_CMD2() { - uint32_t response[4]; - int ret; - int retry = 0x20; - do { - SDIO_send_cmd(2, 0, LONG_ANS); - if (!(ret = SDIO_get_response(0xFF, LONG_ANS, response))) return 0; - }while(retry-- > 0); - return ret; -} - -int SDIO_send_relative_address_CMD3(uint16_t* rca) { - uint32_t response; - int retry = 0x20; - do { - SDIO_send_cmd(3, 0, SHORT_ANS); - if (!SDIO_get_response(3, SHORT_ANS, &response)) { - // TODO: Do some *optional* checking - *rca = ((response & 0xFFFF0000) >> 16); - return 0; - } - }while(retry-- > 0); - return -1; -} - -int SDIO_send_go_idle_CMD0() { - SDIO_send_cmd(0, 0x0, NO_ANS); - SDIO_wait_cmd_sent(); - return 0; -} - -CMD8_RESP_t SDIO_send_iface_condition_CMD8() { - uint32_t response; - int res = 0; - int retry = 0x20; - do { - SDIO_send_cmd(8, 0x1CC, SHORT_ANS); // 3.3V supply requesR - res = SDIO_get_response(8, SHORT_ANS, &response); - if (res == 0) { - if (response & 0x100) - return CMD8_VOLTAGE_ACCEPTED; - else - return CMD8_VOLTAGE_DENIED; - } - }while(retry-- > 0); - return CMD8_RESP_TIMEOUT; + if (card_info.type == SD_V2_HC) { + addr++; + } else { + addr += (1<PUPDR |= ((WRITEPROT_PULLUP ? 1 : 0)<PUPDR |= ((INS_PULLUP? 1 : 0)<IDR & INS_PIN) == (INS_ACTIVE_LEVEL< 0); - - return res; -} - -int SDIO_send_select_card_CMD7(uint16_t rca) { - int timeout = 0x20; - uint32_t response; - StatusConv_t status; - int res; - - /* Send CMD7. Selects card */ - do { - SDIO_send_cmd(7, (rca<<16)&0xFFFF0000, SHORT_ANS); - if (!(res = SDIO_get_response(7, SHORT_ANS, &response))) { - break; - } - } while(--timeout > 0); - - /* Check, if card in in TRANS state */ - if (SDIO_check_status_register_CMD13(rca, &(status.value))) - res = -1; - if (status.statusstruct.CURRENT_STATE != CURRENT_STATE_TRAN) - res = -2; - return res; -} - -int SDIO_check_status_register_CMD13(uint16_t rca, uint32_t *status) { - int timeout = 0x20; - uint32_t response; - int res; - do { - SDIO_send_cmd(13, (rca<<16)&0xFFFF0000, SHORT_ANS); - if (!(res = SDIO_get_response(13, SHORT_ANS, &response))) { - *status = response; - break; - } - } while(--timeout > 0); - - return res; -} - -int SDIO_get_sector_count(uint16_t rca, uint32_t *sector_count) { - uint32_t csd[4]; - int res; - uint32_t size, mult, read_len, csd_rev; - - if ((res = SDIO_send_csd_CMD9(rca, csd))) { - return -1; - } - - csd_rev = ((csd[0] >> 30) & (0x3)); - - if (csd_rev == 0) { // SD v1 Card - size = ((csd[1] & 0x3FF) <<2) | (((csd[2]) & ((1<<31) | (1<<30)))>>30); - mult = ((csd[2] & ((1<<17)|(1<<16)|(1<<15)))>>15); - read_len = (1<<((csd[1] & ((1<<19)|(1<<18)|(1<<17)|(1<<16)))>>16)); - *sector_count = (((size +1)*(1<<(mult+2))*read_len) >> BLOCKSIZE); - } else if (csd_rev == 1) { // SD v2 Card - size = (((csd[1] & 0x3F)<<16) | ((csd[2] & 0xFFFF0000) >> 16)); - *sector_count = (size << (19-BLOCKSIZE)); - } - - return 0; -} - -int SDIO_send_csd_CMD9(uint16_t rca, uint32_t *responsebuffer) { - int timeout = 0x20; - int res; - - do { - SDIO_send_cmd(9, (rca<<16)&0xFFFF0000, LONG_ANS); - if (!(res = SDIO_get_response(0xFF, LONG_ANS, responsebuffer))) { - break; - } - } while(--timeout > 0); - - return res; -} - -/** - * @brief checkWriteProtection - * @return 0 if card is writable. - */ -int checkWriteProtection() { -#if SDIO_ENABLE_WRITEPROT - return ((WRITEPROT_PORT->IDR & WRITEPROT_PIN) == (WRITEPROT_ACTIVE_LEVEL< #include -DSTATUS SDIO_status(); -DSTATUS SDIO_initialize(); -DRESULT SDIO_disk_read(BYTE *buff, DWORD sector, UINT count); -DRESULT SDIO_disk_write(const BYTE *buff, DWORD sector, UINT count); -DRESULT SDIO_disk_ioctl(BYTE cmd, void* buff); -DWORD get_fattime(); +DSTATUS sdio_status(); +DSTATUS sdio_initialize(); + +DRESULT sdio_disk_read(BYTE *buff, DWORD sector, UINT count); +DRESULT sdio_disk_write(const BYTE *buff, DWORD sector, UINT count); +DRESULT sdio_disk_ioctl(BYTE cmd, void* buff); +DWORD get_fattime(); //Defines for Card Status in struct _CardStatus @@ -31,9 +32,7 @@ DWORD get_fattime(); #define CURRENT_STATE_PRG 7 #define CURRENT_STATE_DIS 8 - - -typedef struct _CardStatus { +struct sd_card_status { uint32_t reserved : 3; uint32_t AKE_SEQ_ERROR : 1; uint32_t reserved_2 : 1; @@ -60,21 +59,19 @@ typedef struct _CardStatus { uint32_t BLOCK_LEN_ERROR : 1; uint32_t ADDRESS_ERROR : 1; uint32_t OUT_OF_RANGE : 1; -}CardStatus_t; +}; - - -typedef enum {CARD_NONE = 0, MMC, SD_V1, SD_V2_SC, SD_V2_HC} card_type_t; +enum sdio_card_type {CARD_NONE = 0, MMC, SD_V1, SD_V2_SC, SD_V2_HC}; // MMC not supported -typedef struct _SDInfo { +struct sd_info { uint16_t rca; - card_type_t type; + enum sdio_card_type type; uint32_t sector_count; -}SDInfo_t; +}; -typedef union _StatusConv { - CardStatus_t statusstruct; +union sdio_status_conv { + struct sd_card_status statusstruct; uint32_t value; -}StatusConv_t; +}; #endif /* FATFS_SHIMATTA_SDIO_DRIVER_SHIMATTA_SDIO_DRIVER_H_ */ diff --git a/main.c b/main.c index a13053e..afc193a 100644 --- a/main.c +++ b/main.c @@ -92,7 +92,7 @@ void SysTick_Handler() sdio_wait++; } -void SDIO_wait_ms(unsigned int i) { +void sdio_wait_ms(unsigned int i) { sdio_wait = 0; while(sdio_wait