Finished SD initialization, implemented iotcl, ready to implement block transfers

This commit is contained in:
Mario Hüttel 2017-04-03 18:56:02 +02:00
parent b935f93ae1
commit df1d3eba77
4 changed files with 120 additions and 92 deletions

View File

@ -25,8 +25,8 @@
#define OCS_CCS (1<<30) #define OCS_CCS (1<<30)
#define OCS_BUSY (1<<31) #define OCS_BUSY (1<<31)
typedef enum {ACMD41_RESP_INIT, ACMD41_RESP_ERR, ACMD41_RESP_SDSC, ACMD41_RESP_SDXC} ACMD41_RESP_t; typedef enum {ACMD41_RESP_INIT = 0, ACMD41_RESP_ERR, ACMD41_RESP_SDSC, ACMD41_RESP_SDXC} ACMD41_RESP_t;
typedef enum {CMD8_RESP_TIMEOUT, CMD8_VOLTAGE_ACCEPTED, CMD8_VOLTAGE_DENIED} CMD8_RESP_t; typedef enum {CMD8_RESP_TIMEOUT = 0, CMD8_VOLTAGE_ACCEPTED, CMD8_VOLTAGE_DENIED} CMD8_RESP_t;
typedef uint8_t CID_t; typedef uint8_t CID_t;
void SDIO_init_hw(); void SDIO_init_hw();
@ -44,12 +44,16 @@ int SDIO_send_go_idle_CMD0();
CMD8_RESP_t SDIO_send_iface_condition_CMD8(); CMD8_RESP_t SDIO_send_iface_condition_CMD8();
int SDIO_send_block_length_CMD16(uint32_t blocklen); int SDIO_send_block_length_CMD16(uint32_t blocklen);
int SDIO_send_bus_width_ACMD6(uint8_t bus_width); int SDIO_send_bus_width_ACMD6(uint8_t bus_width);
int SDIO_send_csd_CMD9(uint16_t rca, uint32_t *responsebuffer);
int SDIO_send_select_card_CMD7(uint16_t rca);
int SDIO_check_status_register_CMD13(uint16_t rca, uint32_t *status);
void SDIO_init_detect_pins(); void SDIO_init_detect_pins();
int checkNotInserted(); // Returns 0 if inserted! int checkNotInserted(); // Returns 0 if inserted!
int checkWriteProtection(); // returns 0 if write protected int checkWriteProtection(); // returns 0 if write protected
void switchPrescaler(uint8_t clkdiv); void switchPrescaler(uint8_t clkdiv);
int SDIO_get_sector_count(uint16_t rca, uint32_t *sector_count);
//BYTE rxtxbuffer[1<<BLOCKSIZE]; //Data RX and TX Buffer not needed anymore. thanks to DMA //BYTE rxtxbuffer[1<<BLOCKSIZE]; //Data RX and TX Buffer not needed anymore. thanks to DMA
SDInfo_t card_info; // = {.type = CARD_NONE}; SDInfo_t card_info; // = {.type = CARD_NONE};
@ -67,9 +71,8 @@ DSTATUS SDIO_status(){
return returnval; return returnval;
} }
DSTATUS SDIO_initialize(){ DSTATUS SDIO_initialize(){
int timeout = 200; int timeout = 0x2000;
CMD8_RESP_t res8; CMD8_RESP_t res8;
ACMD41_RESP_t resa41; ACMD41_RESP_t resa41;
uint8_t hcs_flag = 0; uint8_t hcs_flag = 0;
@ -104,7 +107,6 @@ DSTATUS SDIO_initialize(){
do { do {
resa41 = SDIO_init_card_ACMD41(hcs_flag); resa41 = SDIO_init_card_ACMD41(hcs_flag);
} while((resa41 == ACMD41_RESP_INIT) && (--timeout > 0)); } while((resa41 == ACMD41_RESP_INIT) && (--timeout > 0));
switch (resa41) { switch (resa41) {
case ACMD41_RESP_SDSC: case ACMD41_RESP_SDSC:
detected_card = (hcs_flag ? SD_V2_SC : SD_V1); detected_card = (hcs_flag ? SD_V2_SC : SD_V1);
@ -119,18 +121,24 @@ DSTATUS SDIO_initialize(){
if (SDIO_send_all_send_cid_CMD2()) if (SDIO_send_all_send_cid_CMD2())
return STA_NOINIT; return STA_NOINIT;
if (SDIO_send_relative_address_CMD3(&card_info.rca)) if (SDIO_send_relative_address_CMD3(&card_info.rca))
return STA_NOINIT; 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<<BLOCKSIZE))) if (SDIO_send_block_length_CMD16((uint32_t)(1<<BLOCKSIZE)))
return STA_NOINIT; return STA_NOINIT;
if (SDIO_send_bus_width_ACMD6(BUSWIDTH)) if (SDIO_send_bus_width_ACMD6(BUSWIDTH))
return STA_NOINIT; return STA_NOINIT;
switchPrescaler(WORKCLK); switchPrescaler(WORKCLK);
card_info.type = detected_card; card_info.type = detected_card;
if (checkWriteProtection()) { if (checkWriteProtection()) {
return STA_PROTECT; return STA_PROTECT;
} else } else
@ -152,8 +160,11 @@ DRESULT SDIO_disk_ioctl(BYTE cmd, void* buff){
*((WORD*)buff) = (WORD)(1<<BLOCKSIZE); *((WORD*)buff) = (WORD)(1<<BLOCKSIZE);
break; break;
case GET_SECTOR_COUNT: case GET_SECTOR_COUNT:
if (card_info.type != CARD_NONE) {
*((DWORD*)buff) = (DWORD)card_info.sector_count;
} else {
res = RES_ERROR; res = RES_ERROR;
//TODO: Implement }
break; break;
case CTRL_SYNC: case CTRL_SYNC:
res = RES_OK; res = RES_OK;
@ -251,12 +262,9 @@ int SDIO_send_cmd(uint8_t CMD, uint32_t arg, uint8_t expectedAns){
SDIO->CMD = (CMD & SDIO_CMD_CMDINDEX) | SDIO_CMD_CPSMEN | /*SDIO_CMD_WAITPEND |*/ ((expectedAns << 6) & SDIO_CMD_WAITRESP); SDIO->CMD = (CMD & SDIO_CMD_CMDINDEX) | SDIO_CMD_CPSMEN | /*SDIO_CMD_WAITPEND |*/ ((expectedAns << 6) & SDIO_CMD_WAITRESP);
return 0; return 0;
} }
unsigned int debug;
void SDIO_wait_cmd_sent() { void SDIO_wait_cmd_sent() {
while (!(SDIO->STA & SDIO_STA_CMDSENT)) while (!(SDIO->STA & SDIO_STA_CMDSENT));
{
debug = SDIO->STA;
}
SDIO->ICR |= SDIO_ICR_CMDSENTC; SDIO->ICR |= SDIO_ICR_CMDSENTC;
} }
@ -270,9 +278,10 @@ int SDIO_get_response(uint8_t expectedCMD, uint8_t typeOfAns, uint32_t *response
if ((SDIO->STA & SDIO_STA_CCRCFAIL)) { if ((SDIO->STA & SDIO_STA_CCRCFAIL)) {
if(expectedCMD == 0xff) { // TODO: This seems odd.. if(expectedCMD == 0xff) { // TODO: This seems odd..
break; break;
} else } else {
return -CCRCFAIL; return -CCRCFAIL;
} }
}
if (SDIO->STA & SDIO_STA_CTIMEOUT) if (SDIO->STA & SDIO_STA_CTIMEOUT)
@ -300,7 +309,7 @@ int SDIO_switch_appmode_CMD55(){
uint32_t response; uint32_t response;
do { do {
//Execute Command and check for valid response //Execute Command and check for valid response
SDIO_send_cmd(55, card_info.rca, SHORT_ANS); SDIO_send_cmd(55, (card_info.rca<<16)&0xFFFF0000, SHORT_ANS);
if (!SDIO_get_response(55, SHORT_ANS, &response)) if (!SDIO_get_response(55, SHORT_ANS, &response))
{ {
@ -314,14 +323,14 @@ int SDIO_switch_appmode_CMD55(){
return -1; return -1;
} }
ACMD41_RESP_t SDIO_init_card_ACMD41(uint8_t HCS){ ACMD41_RESP_t SDIO_init_card_ACMD41(uint8_t HCS){
uint32_t response; uint32_t response;
int retry = 0x20; int retry = 0x20;
if (SDIO_switch_appmode_CMD55()) return -1; if (SDIO_switch_appmode_CMD55()) return ACMD41_RESP_ERR;
do { do {
SDIO_send_cmd(41, (HCS ? (1<<30) : 0) | (1<<28) | (1<<20) |(1<<21), SHORT_ANS);
SDIO_send_cmd(41, (HCS ? (1<<30) : 0) | (1<<28), SHORT_ANS);
if (!SDIO_get_response(0xFF, SHORT_ANS, &response)) { 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_BUSY) { // Card is ready... Who knows why this bit is called busy...
if (response & OCS_CCS) { if (response & OCS_CCS) {
@ -332,10 +341,7 @@ ACMD41_RESP_t SDIO_init_card_ACMD41(uint8_t HCS){
} else { } else {
return ACMD41_RESP_INIT; return ACMD41_RESP_INIT;
} }
} }
}while(--retry > 0); }while(--retry > 0);
return ACMD41_RESP_ERR; return ACMD41_RESP_ERR;
@ -408,7 +414,7 @@ void SDIO_init_detect_pins() {
*/ */
int checkNotInserted() { int checkNotInserted() {
#if SDIO_ENABLE_INS #if SDIO_ENABLE_INS
return ((INS_PORT->IDR & INS_PIN) == INS_ACTIVE_LEVEL ? 0 : 1); return ((INS_PORT->IDR & INS_PIN) == (INS_ACTIVE_LEVEL<<INS_PIN) ? 0 : 1);
#else #else
return 0; // Assume Card is inserted return 0; // Assume Card is inserted
#endif #endif
@ -420,9 +426,85 @@ int SDIO_send_block_length_CMD16(uint32_t blocklen) {
uint32_t response; uint32_t response;
do { do {
SDIO_send_cmd(16, (0x1<<BLOCKSIZE), SHORT_ANS); SDIO_send_cmd(16, blocklen, SHORT_ANS);
if (!(res = SDIO_get_response(16, SHORT_ANS, &response))) if (!(res = SDIO_get_response(16, SHORT_ANS, &response))) {
return 0; return 0;
}
}while(--timeout > 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); } while(--timeout > 0);
return res; return res;
@ -434,7 +516,7 @@ int SDIO_send_block_length_CMD16(uint32_t blocklen) {
*/ */
int checkWriteProtection() { int checkWriteProtection() {
#if SDIO_ENABLE_WRITEPROT #if SDIO_ENABLE_WRITEPROT
return ((WRITEPROT_PORT->IDR & WRITEPROT_PIN) == WRITEPROT_ACTIVE_LEVEL ? 1 : 0); return ((WRITEPROT_PORT->IDR & WRITEPROT_PIN) == (WRITEPROT_ACTIVE_LEVEL<<WRITEPROT_PIN) ? 1 : 0);
#else #else
return 0; // Assume Card is not write protected return 0; // Assume Card is not write protected
#endif #endif

View File

@ -68,6 +68,7 @@ typedef enum {CARD_NONE = 0, MMC, SD_V1, SD_V2_SC, SD_V2_HC} card_type_t;
typedef struct _SDInfo { typedef struct _SDInfo {
uint16_t rca; uint16_t rca;
card_type_t type; card_type_t type;
uint32_t sector_count;
}SDInfo_t; }SDInfo_t;
typedef union _StatusConv { typedef union _StatusConv {
@ -75,58 +76,4 @@ typedef union _StatusConv {
uint32_t value; uint32_t value;
}StatusConv_t; }StatusConv_t;
//General Definitions
//Blocksize: 512 = 2^9 => 9
#define BLOCKSIZE 9 //9
//Hardware Flow: Prevents over- and underruns.
#define HW_FLOW 0 //0
//1 bit: !=4
//4 bit: 4
#define BUSWIDTH 4 //4
//Initial Transfer CLK (ca. 400kHz)
#define INITCLK 120 //120
//Working CLK (Maximum)
#define WORKCLK 0 //0
//Data Timeout in CLK Cycles
#define DTIMEOUT 150 //150
//DMA Stream used for TX and RX DMA2 Stream 3 or 6 possible
#define DMASTREAM DMA2_Stream3
//Port Definitions
#define PORTCLKMASK (RCC_AHB1ENR_GPIODEN | RCC_AHB1ENR_GPIOCEN)
#define ALTFUNC 12
#define CLKPORT GPIOC
#define D0PORT GPIOC
#define D1PORT GPIOC
#define D2PORT GPIOC
#define D3PORT GPIOC
#define CMDPORT GPIOD
#define CLKPIN 12
#define D0PIN 8
#define D1PIN 9
#define D2PIN 10
#define D3PIN 11
#define CMDPIN 2
// Write Protection
#define SDIO_ENABLE_WRITEPROT 0
#define WRITEPROT_PORT GPIOD // Add this port to port clock mask!
#define WRITEPROT_PIN 0
#define WRITEPROT_PULLUP 0
#define WRITEPROT_ACTIVE_LEVEL 0
// Card inserted pin
#define SDIO_ENABLE_INS 0
#define INS_PORT GPIOD // Add this port to port clock mask!
#define INS_PIN 0
#define INS_PULLUP 0
#define INS_ACTIVE_LEVEL 0
#endif /* FATFS_SHIMATTA_SDIO_DRIVER_SHIMATTA_SDIO_DRIVER_H_ */ #endif /* FATFS_SHIMATTA_SDIO_DRIVER_SHIMATTA_SDIO_DRIVER_H_ */

View File

@ -14,7 +14,7 @@
//Initial Transfer CLK (ca. 400kHz) //Initial Transfer CLK (ca. 400kHz)
#define INITCLK 120 //120 #define INITCLK 120 //120
//Working CLK (Maximum) //Working CLK (Maximum)
#define WORKCLK 0 //0 #define WORKCLK 50 //0
//Data Timeout in CLK Cycles //Data Timeout in CLK Cycles
#define DTIMEOUT 150 //150 #define DTIMEOUT 150 //150
//DMA Stream used for TX and RX DMA2 Stream 3 or 6 possible //DMA Stream used for TX and RX DMA2 Stream 3 or 6 possible

17
main.c
View File

@ -7,28 +7,27 @@
#include <stm32f4xx.h> #include <stm32f4xx.h>
#include <cmsis/arm_math.h> #include <cmsis/arm_math.h>
#include <fatfs/ff.h> #include <fatfs/ff.h>
#include <fatfs/diskio.h>
#define OUTPUT(pin) (0b01 << (pin * 2)) #define OUTPUT(pin) (0b01 << (pin * 2))
FATFS SDfs; FATFS SDfs;
FIL file; FIL file;
volatile int w; volatile int w;
void SDIO_wait_cmd_sent(); DSTATUS SDIO_initialize();
int SDIO_switch_appmode_CMD55();
int SDIO_send_all_send_cid_CMD2();
int SDIO_send_relative_address_CMD3(uint16_t* rca);
int SDIO_send_go_idle_CMD0();
int SDIO_send_block_length_CMD16(uint32_t blocklen); int initreq = 0xFF;
int SDIO_send_bus_width_ACMD6(uint8_t bus_width);
int main() { int main() {
RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
__DSB(); __DSB();
GPIOD->MODER |= OUTPUT(12); GPIOD->MODER |= OUTPUT(12) | OUTPUT(13);
SysTick_Config(8*1680000); SysTick_Config(8*1680000);
// f_mount(&SDfs, "0:/", 1); // f_mount(&SDfs, "0:/", 1);
//SDIO_init_hw();
w = 0;
while(w<10);
initreq = SDIO_initialize();
while(1); while(1);
} }