/* * shimatta_sdio-driver.c * * Created on: Apr 30, 2015 * Mario Hüttel */ #include #define SETAF(PORT,PIN,AF) PORT->AFR[(PIN < 8 ? 0 : 1)] |= AF << ((PIN < 8 ? PIN : (PIN - 8)) * 4) #define READCTRL ((BLOCKSIZE << 4) | SDIO_DCTRL_DMAEN) #define DMAP2M (DMA_SxCR_CHSEL_2 | DMA_SxCR_PBURST_0 | DMA_SxCR_MBURST_0 | DMA_SxCR_MSIZE_1 | DMA_SxCR_PSIZE_1 | DMA_SxCR_MINC | DMA_SxCR_PFCTRL) #define DMAM2P (DMA_SxCR_CHSEL_2 | DMA_SxCR_PBURST_0 | DMA_SxCR_MBURST_0 | DMA_SxCR_MSIZE_1 | DMA_SxCR_PSIZE_1 | DMA_SxCR_MINC | DMA_SxCR_PFCTRL | DMA_SxCR_DIR_0) #define SHORT_ANS 1 #define LONG_ANS 3 #define NO_ANS 0 #define CCRCFAIL -1 #define CTIMEOUT -2 void SDIO_DMA_Init(); void SDIO_InitModule(); int SDIO_sendCmd(uint8_t CMD, uint32_t arg, uint8_t expectedAns); int SDIO_getResp(uint8_t expectedCMD, uint8_t typeOfAns, uint32_t* responseBuffer); int SDIO_parseR1Ans(uint32_t resp, StatusConv_t converter); int SDIO_send_ACMD41(); int SDIO_send_CMD55(); //BYTE rxtxbuffer[1<AHB1ENR |= RCC_AHB1ENR_DMA2EN; DMASTREAM->CR = DMAM2P; //Address Conffiguration //Memory address is set by write and read block functions //DMASTREAM->M0AR = (uint32_t)&rxtxbuffer; //Has to be set in read/write func DMASTREAM->PAR = (uint32_t)&SDIO->FIFO; //Not sure if this works //DMASTREAM->CR |= DMA_SxCR_EN; } void SDIO_InitModule(){ //Init Clocks RCC->AHB1ENR |= PORTCLKMASK; 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<AFR[(CLKPIN < 8 ? 0 : 1)] |= ALTFUNC << ((CLKPIN < 8 ? CLKPIN : (CLKPIN - 8)) * 4); SETAF(CLKPORT, CLKPIN, ALTFUNC); SETAF(D0PORT, D0PIN, ALTFUNC); #if BUSWIDTH==1 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<<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; } //Send Command //Clear respone Flags //->CRC Fail, complete response, Timeout int SDIO_sendCmd(uint8_t CMD, uint32_t arg, uint8_t expectedAns){ //Clear Flags SDIO->ICR = SDIO_ICR_CCRCFAILC | SDIO_ICR_CMDRENDC | SDIO_ICR_CTIMEOUTC; //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_getResp(uint8_t expectedCMD, uint8_t typeOfAns, uint32_t *responseBuffer) { //Return with success because no data is needed if (typeOfAns == NO_ANS) return 0; //Wait for error or success while (1) { if (SDIO->STA & SDIO_STA_CMDREND) break; //Correct Respone Received //Exclude ACMD41 from valid CRC check if ((SDIO->STA & SDIO_STA_CCRCFAIL)) { if(expectedCMD == 41) { //This command does not have a CRC...Doushite.... break;//Hopefully the response is correct. Even without CRC.... } else return CCRCFAIL; } if (SDIO->STA & SDIO_STA_CTIMEOUT) return CTIMEOUT; } //Valid Respone Received if ((SDIO->RESPCMD & SDIO_RESPCMD_RESPCMD) != expectedCMD) return -1; //Not the expected respose //If case of a correct Response *(responseBuffer++) = SDIO->RESP1; //Long response. if (typeOfAns == LONG_ANS) { *(responseBuffer++) = SDIO->RESP2; *(responseBuffer++) = SDIO->RESP3; *(responseBuffer++) = SDIO->RESP4; } } int SDIO_send_CMD55(){ int retry = 0x20; StatusConv_t converter; uint32_t response; do { //Execute Command and check for valid response SDIO_sendCmd(55, cardInfo.rca, SHORT_ANS); if (!SDIO_getResp(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; } int SDIO_send_ACMD41(){ int retry = 0x20; if (SDIO_send_CMD55()) return -1; do { SDIO_sendCmd(41, 1<<30, SHORT_ANS); //TODO: Implement Response Check... }while(--retry > 0); }