123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524 |
- #include "sdcard.h"
- #include "stm32f4xx.h"
- #include <stm32f4xx_gpio.h>
- static uint32_t SD_Command(uint32_t cmd, uint32_t resp, uint32_t arg);
- static uint32_t SD_Response(uint32_t *response, uint32_t type);
- static void SD_Panic(uint32_t code, char *message);
- static void SD_StartBlockTransfer(uint8_t *buf, uint32_t cnt, uint32_t dir);
- static uint32_t SDType;
- static uint32_t RCA;
- static volatile uint32_t SDIOTxRx=0;
- //Private Write buffers
- static uint8_t DatBuf[512*2]; //2 blocks (One will be in transit while other is being filled)
- static uint8_t *pDatBuf=DatBuf;
- static uint32_t BufCnt=0;
- #define DATATIMEOUT (0xFFFFFF) //I simply made this up. A method for computing a realistic values from CSD is described in the specs.
- //SDIO Commands Index
- #define CMD0 ((uint8_t)0)
- #define CMD8 ((uint8_t)8)
- #define CMD55 ((uint8_t)55)
- #define ACMD41 ((uint8_t)41)
- #define CMD2 ((uint8_t)2)
- #define CMD3 ((uint8_t)3)
- #define CMD9 ((uint8_t)9)
- #define CMD7 ((uint8_t)7)
- #define ACMD6 ((uint8_t)6)
- #define CMD24 ((uint8_t)24)
- #define CMD25 ((uint8_t)25)
- #define CMD12 ((uint8_t)12)
- #define CMD13 ((uint8_t)13)
- #define CMD17 ((uint8_t)17)
- #define CMD18 ((uint8_t)18)
- //Auxilary defines
- #define NORESP (0x00)
- #define SHRESP (0x40)
- #define LNRESP (0xC0)
- #define R3RESP (0xF40) //Note this is totaly out of standard. However, becouse of the masking in SD_Command it will be processed as SHRESP
- //R3 does not contain a valid CRC. Therefore, CCRCFAIL is set and CMDREND is never set for R3.
- //To properly process R3, exit the loop CCRCFAIL condition and don't check CMDREND
- #define RESP_R1 (0x01)
- #define RESP_R1b (0x02)
- #define RESP_R2 (0x03)
- #define RESP_R3 (0x04)
- #define RESP_R6 (0x05)
- #define RESP_R7 (0x06)
- #define UM2SD (0x00) //Transfer Direction
- #define SD2UM (0x02)
- void SD_LowLevel_Init(void) {
- uint32_t tempreg;
-
- GPIO_InitTypeDef GPIO_InitStructure;
-
- // GPIOC and GPIOD Periph clock enable
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD, ENABLE);
- //Initialize the pins
- GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_SDIO);
- GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_SDIO);
- GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_SDIO);
- GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_SDIO);
- GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_SDIO);
- GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_SDIO);
- // Configure PC.08, PC.09, PC.10, PC.11 pins: D0, D1, D2, D3 pins
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
- GPIO_Init(GPIOC, &GPIO_InitStructure);
- // Configure PD.02 CMD line
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
- GPIO_Init(GPIOD, &GPIO_InitStructure);
- // Configure PC.12 pin: CLK pin
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
- GPIO_Init(GPIOC, &GPIO_InitStructure);
-
- //Enable the SDIO APB2 Clock
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_SDIO, ENABLE);
- // Enable the DMA2 Clock
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
-
- //Initialize the SDIO (with initial <400Khz Clock)
- tempreg=0; //Reset value
- tempreg|=SDIO_CLKCR_CLKEN; //Clock is enabled
- tempreg|= (uint32_t)0xFF;//(uint32_t)0x76; //Clock Divider. Clock=48000/(118+2)=400Khz
- //Keep the rest at 0 => HW_Flow Disabled, Rising Clock Edge, Disable CLK ByPass, Bus Width=0, Power save Disable
- SDIO->CLKCR=tempreg;
- //Power up the SDIO
- SDIO->POWER = 0x03;
-
- }
- void SD_Init(void){
- //uint32_t data;
- uint32_t response;
- uint32_t TimeOut=0xFFFF;
- uint32_t tempreg;
-
- //CMD0: GO_IDLE_STATE (No Response)
- SD_Command(CMD0, NORESP, 0);
-
- //CMD8: SEND_IF_COND //Response to CMD8 is R7. But I will ignore that response
- SD_Command(CMD8, SHRESP, 0x000001AA); //Non v2.0 compliant sd's will cause panic here due to the timeout
- SD_Response(&response, RESP_R7); //AA is the check pattern. If response does not match with it, execution will be blocked in panic
-
-
- while (1) {
- ////Send ACMD41
- //CMD55
- SD_Command(CMD55, SHRESP, 0); //Note that argument should be RCA. But at this point RCA of SD is 0. (It will be changed after cmd3)
- SD_Response(&response, RESP_R1);
-
- //ACMD41 (Response is R3 which does not contain any CRC)
- //Second argument in the argument indicates that host supports SDHC. We will check acmd41 response if the SD is SC or HC
- SD_Command(ACMD41, R3RESP, (uint32_t) 0x80100000 | (uint32_t) 0x40000000);
- SD_Response(&response, RESP_R3);
-
- //Check the ready status in the response (R3)
- if ((response >> 31) == 1) { //When card is busy this bit will be 0
- //Card is now initialized. Check to see if SD is SC or HC
- SDType=(response & 0x40000000) >> 30; //1=HC, 0=SC
- break;
- } else {
- TimeOut--;
- if (!TimeOut) {
- SD_Panic(ACMD41, "SDIO:ACMD41 Timeout\n");
- }
- }
- }
-
- //Now we are in the Ready State. Ask for CID using CMD2
- //Response is R2. RESP1234 are filled with CID. I will ignore them
- SD_Command(CMD2, LNRESP, 0);
-
- //Now the card is in the identification mode. Request for the RCA number with cmd3
- SD_Command(CMD3, SHRESP, 0);
- SD_Response(&response, RESP_R6);
- //Read the RCA
- RCA=response>>16;
-
- //Now the card is in stand-by mode. From this point on I can change frequency as I wish (max24MHz)
-
-
- //Use cmd9 to read the card specific information
- //Response is R2 with CSI. I will ignore the response
- SD_Command(CMD9, LNRESP, (RCA << 16));
-
-
- //Put the Card in the tranfer mode using cmd7. (I will change the clock spped later together with bus width)
- //Bus width can only be changed in transfer mode
- SD_Command(CMD7, SHRESP, (RCA << 16));
- SD_Response(&response, RESP_R1);
-
- //Change the bus-width with cmd6
- //CMD55
- SD_Command(CMD55, SHRESP, (RCA << 16)); //Note the real RCA in the argument
- SD_Response(&response, RESP_R1);
- //ACMD6
- SD_Command(ACMD6, SHRESP, 0x02);
- SD_Response(&response, RESP_R1);
-
- //Configure SDIO->CLKCr for wide-bus width and new clock
- tempreg=0; //Reset value
- //tempreg|=(0x01)<<11; //4 bit Bus Width
-
- //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- // ÎÑÒÀÂËßÅÌ ÏÎ ÓÌÎË×ÀÍÈÞ 1áèò øèíû
- // áèòû 11-12 = 00
-
- tempreg|=SDIO_CLKCR_CLKEN; //Clock is enabled
- //Keep the rest at 0=> HW_Flow:Disabled, Rising Edge, Disable bypass, Power save Disable, Clock Division=0
- //As the clock divider=0 => New clock=48/(Div+2)=48/2=24
- SDIO->CLKCR=tempreg;
-
- //Now we can start issuing read/write commands
- }
- void SD_WriteSingleBlock(uint8_t *buf, uint32_t blk) {
- uint32_t WriteAddr;
- uint32_t response;
-
- //uint32_t response;
- if (SDType==1) { //High Capacity
- WriteAddr=blk;
- } else if (SDType==0) {//Standard Capacity
- WriteAddr=blk*512;
- }
- //CMD24:WRITE_SINGLE_BLOCK
- SD_Command(CMD24, SHRESP, WriteAddr);
- SD_Response(&response, RESP_R1);
-
- //Card is now waiting some data from the Data lines. Start actual data transmission
- SD_StartBlockTransfer(buf, 512, UM2SD);
-
- //Wait for transmission to end
- SD_WaitTransmissionEnd();
- }
- void SD_ReadSingleBlock(uint8_t *buf, uint32_t blk) {
- uint32_t ReadAddr;
- uint32_t response;
-
- //uint32_t response;
- if (SDType==1) { //High Capacity
- ReadAddr=blk;
- } else if (SDType==0) {//Standard Capacity
- ReadAddr=blk*512;
- }
-
- //Send CMD17:READ_SINGLE_BLOCK
- SD_Command(CMD17, SHRESP, ReadAddr);
- SD_Response(&response, RESP_R1);
-
- //Card is now ready to send some data from the Data lines. Start actual data transmission
- SD_StartBlockTransfer(buf, 512, SD2UM);
-
- //Wait for transmission to end
- SD_WaitTransmissionEnd();
- }
- void SD_StartMultipleBlockWrite(uint32_t blk) {
- uint32_t WriteAddr;
- uint32_t response;
-
- //uint32_t response;
- if (SDType==1) { //High Capacity
- WriteAddr=blk;
- } else if (SDType==0) {//Standard Capacity
- WriteAddr=blk*512;
- }
-
- //CMD25:WRITE_MULT_BLOCK with argument data address
- SD_Command(CMD25, SHRESP, WriteAddr);
- SD_Response(&response, RESP_R1);
-
- //Clear any flags
- SDIO->ICR=(uint32_t) 0xA003FF;
- return;
- }
- void SD_StopMultipleBlockWrite(void) {
- uint32_t response;
-
- //If there is previously programmed communication, wait for it to end first
- SD_WaitTransmissionEnd();
-
- //CMD12:STOP_TRANSMISSION
- SD_Command(CMD12, SHRESP, 0);
- SD_Response(&response, RESP_R1b);
- //Discard the untransferred buffer
- pDatBuf=DatBuf;
- BufCnt=0;
-
- while (((response & 0x100)>>8)==0) {
- //After CMD12, SD Card puts itself to the prg mode, by pulling D0 to low.
- //DPSM is not aware of this. (I hope it is aware of this during multiblock communication. I need to verify this.
- //If it is not, then I have to repeat the same procedure after each block during multiblock write which will cause too much overhead)
- //Check Card status with CMD13 till, we get READY_FOR_DATA response
- //CMD13:Send Status
- SD_Command(CMD13, SHRESP, RCA << 16);
- SD_Response(&response, RESP_R1b);
- }
- }
- void SD_WriteData(uint8_t *buf, uint32_t cnt) {
- while (cnt>0) {
- //Copy the data to internal buffer
- *pDatBuf=*buf;
- pDatBuf++;
- buf++;
- cnt--;
- BufCnt++;
-
- if (BufCnt==512) {//Half Buffer is full.
- //Write Buffer to the SD
- SD_WaitTransmissionEnd(); //Wait for any previous transmission
- //Wait for busy.
- //With SPI we can check this by reading the dataline. SD stops holding the data line when it is not busy.
- //However in SDIO, the only way seems to use CMD13.
- //I am going to skip this part assuming that DPSM handles this properly.
- SD_StartBlockTransfer(pDatBuf-512, 512, UM2SD);
-
-
- //Switch to other half (if necessary)
- if (pDatBuf==(DatBuf+(512*2))) {pDatBuf=DatBuf;}
-
- //Reset Buffer counter
- BufCnt=0;
- }
- }
- }
- static uint32_t SD_Command(uint32_t cmd, uint32_t resp, uint32_t arg) {
- //Response must be:
- //0,2:No response (expect cmdsent) ->NORESP
- //1:Short Response (expect cmdrend and ccrcfail) ->SHRESP
- //3:Long Response (expect cmdrend and ccrcfail) ->LNRESP
-
- //Clear the Command Flags
- SDIO->ICR=(SDIO_STA_CCRCFAIL | SDIO_STA_CTIMEOUT | SDIO_STA_CMDREND | SDIO_STA_CMDSENT);
-
- SDIO->ARG=arg; //First adjust the argument (because I will immediately enable CPSM next)
- SDIO->CMD=(uint32_t)(cmd & SDIO_CMD_CMDINDEX) | (resp & SDIO_CMD_WAITRESP) | (0x0400); //The last argument is to enable CSPM
- //Block till we get a response
- if (resp==NORESP) {
- //We should wait for CMDSENT
- while (!(SDIO->STA & (SDIO_STA_CTIMEOUT | SDIO_STA_CMDSENT))) {};
- }
- else {//SHRESP or LNRESP or R3RESP
- //We should wait for CMDREND or CCRCFAIL
- while (!(SDIO->STA & (SDIO_STA_CTIMEOUT | SDIO_STA_CMDREND | SDIO_FLAG_CCRCFAIL))) {};
- }
-
- //Check to see if the response is valid
- //We consider all R3 responses without a timeout as a valid response
- //It seems CMDSENT and CMDREND are mutually exlusive. (though I am not sure. Check this later)
- if (SDIO->STA & SDIO_STA_CTIMEOUT) {
- SD_Panic(cmd, "SDIO: Command Timeout Error\n");
- } else if ((SDIO->STA & SDIO_FLAG_CCRCFAIL) && (resp!=R3RESP)) {
- SD_Panic(cmd, "SDIO: Command CRC Error\n");
- }
- return SDIO->STA;
- }
- static void SD_Panic(uint32_t code, char *message) {
- uint32_t i=0;
-
- printf("%s\r\n", message);
-
- //Block the execution with blinky leds
- while (1) {
- GPIO_SetBits(GPIOD, GPIO_Pin_13 | GPIO_Pin_12);
- GPIO_ResetBits(GPIOD, GPIO_Pin_15 | GPIO_Pin_14);
- i=168000000 / 4;
- while(i--){}
- GPIO_ResetBits(GPIOD, GPIO_Pin_13 | GPIO_Pin_12);
- GPIO_SetBits(GPIOD, GPIO_Pin_15 | GPIO_Pin_14);
- i=168000000 / 4;
- while(i--){}
- }
- }
- static uint32_t SD_Response(uint32_t *response, uint32_t type) {
- //I mainly use this to block the execution in case an unexpected response is received.
- //Actually I don't need this at all. However, just for the sake of extra information I keep this. All I reall need is for this function to return SDIO->RESP1
- //In the main code, I don't use the retun values at all. Perhaps I ought to have used void.
-
- //R1 Responses
- if ((type==RESP_R1) || (type==RESP_R1b)) {
- *response=SDIO->RESP1;
- if (SDIO->RESP1 & (uint32_t)0xFDFFE008) { //All error bits must be zero
- SD_Panic(SDIO->RESPCMD, "SDIO:Response Error\n");
- }
- return (*response & 0x1F00)>>8; //Return the card status
- }
- else if (type==RESP_R2) { //CSD or CSI register. 128 bit
- *response++=SDIO->RESP1;
- *response++=SDIO->RESP2;
- *response++=SDIO->RESP3;
- *response=SDIO->RESP4;
-
- return 0;
- }
- else if (type==RESP_R3) { //OCR
- if (SDIO->RESPCMD != 0x3F) {SD_Panic(SDIO->RESPCMD,"SDIO:Unexpected command index\n");} //CMD index for R3 must be 0x3F
- *response=SDIO->RESP1; //Equals to OCR
- return 0;
- }
- else if (type==RESP_R6) { //RCA Response
- if (SDIO->RESPCMD != 0x03) {SD_Panic(SDIO->RESPCMD,"SDIO:Unexpected command index\n");} //Only cmd3 generates R6 response
- *response=SDIO->RESP1; //Equals to OCR
-
- return (*response)>>16; //Return is equal to RCA. (The first 16 bit is equal to status)
- }
- else { //RESP_R7:Card Interface condition. Obtained after CMD8
- if (SDIO->RESPCMD != 0x08) {SD_Panic(SDIO->RESPCMD,"SDIO:Unexpected command index\n");} //Only cmd8 generates R7 response
- *response=SDIO->RESP1;
- if ((*response & 0xFF)!=0xAA) {SD_Panic(CMD8, "SDIO:Pattern did not match\n");} //Only cmd8 generates R7 response
- return ((*response) & 0xFF00)>>8; //Echo back value
- }
- }
- static void SD_StartBlockTransfer(uint8_t *buf, uint32_t cnt, uint32_t dir){
- //cnt must be integer multiple of 512!!! I will enforce this inside this function
- //Starts the actual data tranfer using the DMA.
- //Prior to calling this command. The SDCard must have been adjusted using commands
- uint32_t tempreg;
- //Make cnt an integer multiple of 512
- //Then mask it with the maximum value allowed (2^24)
- cnt=0x01FFFFFF & ((cnt>>8) << 8);
-
-
- /////PART I::::Adjust the DMA
- //Reset the control register (0x00 is the default value. this also disables the dma. When EN=0, it stops any ongoing DMA transfer)
- DMA2_Stream3->CR=0;
-
- //Clear all the flags
- DMA2->LIFCR=DMA_LIFCR_CTCIF3 | DMA_LIFCR_CTEIF3 | DMA_LIFCR_CDMEIF3 | DMA_LIFCR_CFEIF3 | DMA_LIFCR_CHTIF3;
-
- //Set the DMA Addresses
- DMA2_Stream3->PAR=((uint32_t) 0x40012C80); //SDIO FIFO Address (=SDIO Base+0x80)
- DMA2_Stream3->M0AR=(uint32_t) buf; //Memory address
-
- //Set the number of data to transfer
- DMA2_Stream3->NDTR=0; //Peripheral controls, therefore we don't need to indicate a size
-
- //Set the DMA CR
- tempreg=0;
- tempreg|=(0x04<<25) & DMA_SxCR_CHSEL; //Select Channel 4
- tempreg|=(0x01<<23) & DMA_SxCR_MBURST; //4 beat memory burst (memory is 32word. Therefore, each time dma access memory, it reads 4*32 bits) (FIFO size must be integer multiple of memory burst)(FIFO is 4byte. Therefore we can only use 4 beat in this case)
- //Note: Ref manual (p173 (the node at the end of 8.3.11) says that burst mode is not allowed when Pinc=0. However, it appears that this is not true at all. Furthermore. when I set pBurst=0, the SDIO's dma control does not work at all.)
- tempreg|=(0x01<<21) & DMA_SxCR_PBURST; //4 beat memory burst Mode ([Burst Size*Psize] must be equal to [FIFO size] to prevent FIFO underrun and overrun errors) (burst also does not work in direct mode).
- tempreg|=(0x00<<18) & DMA_SxCR_DBM; //Disable double buffer mode (when this is set, circluar mode is also automatically set. (the actual value is don't care)
- tempreg|=(0x03<<16) & DMA_SxCR_PL; //Priority is very_high
- tempreg|=(0x00<<15) & DMA_SxCR_PINCOS; //Peripheral increment offset (if this is 1 and Pinc=1, then Peripheral will be incremented by 4 regardless of Psize)
- tempreg|=(0x02<<13) & DMA_SxCR_MSIZE; //Memory data size is 32bit (word)
- tempreg|=(0x02<<11) & DMA_SxCR_PSIZE; //Peripheral data size is 32bit (word)
- tempreg|=(0x01<<10) & DMA_SxCR_MINC; //Enable Memory Increment
- tempreg|=(0x00<<9) & DMA_SxCR_MINC; //Disable Peripheral Increment
- tempreg|=(0x00<<8) & DMA_SxCR_CIRC; //Disable Circular mode
- //tempreg|=(0x00<<6) & DMA_SxCR_DIR; //Direction 0:P2M, 1:M2P
- tempreg|=(0x01<<5) & DMA_SxCR_PFCTRL; //Peripheral controls the flow control. (The DMA tranfer ends when the data issues end of transfer signal regardless of ndtr value)
- //Bit [4..1] is for interupt mask. I don't use interrupts here
- //Bit 0 is EN. I will set it after I set the FIFO CR. (FIFO CR cannot be modified when EN=1)
- DMA2_Stream3->CR=tempreg;
-
- //Set the FIFO CR
- tempreg=0x21; //Reset value
- tempreg|=(0<<7); //FEIE is disabled
- tempreg|=(1<<2); //Fifo is enabled (Direct mode is disabled);
- tempreg|=3; //Full fifo (Fifo threshold selection)
- DMA2_Stream3->FCR=tempreg;
-
- //Set the Direction of transfer
- if (dir==UM2SD) {
- DMA2_Stream3->CR|=(0x01<<6) & DMA_SxCR_DIR;
- } else if (dir==SD2UM) {
- DMA2_Stream3->CR|=(0x00<<6) & DMA_SxCR_DIR;
- }
-
- //Enable the DMA (When it is enabled, it starts to respond dma requests)
- DMA2_Stream3->CR|=DMA_SxCR_EN;
- //END of PART I
-
-
- ////PART II::::Adjust and enable SDIO Peripheral
- //Clear the Data status flags
- SDIO->ICR=(SDIO_STA_DCRCFAIL | SDIO_STA_DTIMEOUT | SDIO_STA_TXUNDERR | SDIO_STA_RXOVERR | SDIO_STA_DATAEND | SDIO_STA_STBITERR | SDIO_STA_DBCKEND);
-
- //First adjust the Dtimer and Data length
- SDIO->DTIMER=(uint32_t) DATATIMEOUT;
- SDIO->DLEN=cnt;
-
- //Now adjust DCTRL (and enable it at the same time)
- tempreg=0; //Reset value
- tempreg|=(uint32_t) 9 << 4; //Block size is 512 Compute log2(BlockSize) and shift 4bit
- tempreg|= 1<<3; //Enable the DMA
- tempreg|= 0<<2; //DTMode=Block Transfer (Actualy this is the reset value. Just a remainder)
- tempreg|=(dir & SDIO_DCTRL_DTDIR); //Direction. 0=Controller to card, 1=Card to Controller
- tempreg|=1; //DPSM is enabled
- //Keep the rest at 0 => OTher SDIO functions is disabled(we don't need them)
- SDIO->DCTRL=tempreg;
- //End of PART II
-
- //Warn everyone that there may be a transfer in progress
- SDIOTxRx=1;
- }
- void SD_WaitTransmissionEnd(void) {
- //This function first checks if there is an ogoing tranmission and block till it ends.
- //It then checks the data flags to see if there is an error. In case of an error it blocks
- //Before the start of data transmission the data flags are all cleared. Therefore, calling this fucntion after a real transmission works as expected.
- ////Check if there is an ongoing transmission
- //Check if the DMA is disabled (SDIO disables the DMA after it is done with it)
- while (DMA2_Stream3->CR & DMA_SxCR_EN) {};
- //Wait for the DMA Interrupt flags if there exist a previous SDIO transfer.
- if (SDIOTxRx) {
- if (DMA2->LISR & (DMA_LISR_TCIF3 | DMA_LISR_TEIF3 | DMA_LISR_DMEIF3 | DMA_LISR_FEIF3)) {
- if (!(DMA2->LISR & DMA_LISR_TCIF3)) {//A DMA error has occured. Panic!
- SD_Panic(DMA2->LISR, "SDIO:DMA Error");
- }
- }
- }
-
- //Wait till SDIO is not active
- while (SDIO->STA & (SDIO_STA_RXACT | SDIO_STA_TXACT)) {};
-
- //if there exist a previous transmission, check if the transmission has been completed without error
- if (SDIOTxRx) {
- //I will block here till I get a data response
- while (!(SDIO->STA & (SDIO_STA_DCRCFAIL | SDIO_STA_DTIMEOUT | SDIO_STA_DBCKEND | SDIO_IT_STBITERR))) {};
- if (!(SDIO->STA & SDIO_STA_DBCKEND)) { //An Error has occured.
- SD_Panic(SDIO->STA, "SDIO:Data Transmission Error\n");
- }
- }
-
- //If we are here, we can be sure that there is no ongoing transmission any more
- SDIOTxRx=0;
- }
|