0
\$\begingroup\$

I am interfacing SD card (16Gb Class 10 Micro Sd HC) to STM32F407VET using SDIO protocol. I am using Chan FatFs version 13a for this project. I am able to open an existing file(with some content in it) and write new content for one cluster.

I have formatted SD card with unit size 8Kb so i am able to write till 8Kb which is one cluster. When i try to write data in new cluster, f_write function returns success but f_close function returns FR_DISK_ERR. If i create a new file, file is getting created but no data are written, though f_write gives FR_OK and Number of bytes written is correct but f_close throws FR_DISK_ERR. I went in deep and found that inside f_close, f_sync function is invoked. Here if the current sector number in FatFs and current sector number in File Pointer are different (This check happens inside move_window function which is invoked from f_sync) then disk_read function is invoked to fill sector window with new data. This is the place where i get error. Inside disk_read i send Cmd16 to set the block size and SD card returns Illegal Command as response.

This behaviour is found only when i try to create new file and write data or edit existing file with data and write till 8Kb. In both the case the current sector number in FatFs and current sector number in File Pointer are same so there is no problem in f_close. If new cluster is selected to write data then i end up with error.

I went through many forums and tried all possible solutions but nothing is working. I dont doubt RAM allocation because the controller has 192Kb RAM and i have allocated 0x4000 for Stack and 0x1000 for heap. I am supplying the SD card with 3.3V

I am not sure if my read logic has error because when i do f_open i invoke disk_read and at that time read happens properly without any issues. Read dosent happen only when i do f_close after writing data to new cluster. Any solutions to fix this issue is highly appreciated. If more information is required please comment i will update it.

Below is the code for Read_Block

Parameters passed for addr = sector << 9
Parameters passed for readbuff =(u32 *)(&buff[0])
Parameters passed for BlockSize = BlockSize = 512

    SD_Error SD_ReadBlock(uint32_t addr, uint32_t *readbuff, uint16_t BlockSize)
{
   SD_Error errorstatus = SD_OK;
  uint32_t count = 0, *tempbuff = readbuff;
  uint8_t power = 0/*, timeout = 0x3*/;

  if (NULL == readbuff)
  {
    errorstatus = SD_INVALID_PARAMETER;
    return(errorstatus);
  }

  TransferError = SD_OK;
  TransferEnd = 0;
  TotalNumberOfBytes = 0;

  /* Clear all DPSM configuration */
  SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
  SDIO_DataInitStructure.SDIO_DataLength = 0;
  SDIO_DataInitStructure.SDIO_DataBlockSize = SDIO_DataBlockSize_1b;
  SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToCard;
  SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;
  SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Disable;
  SDIO_DataConfig(&SDIO_DataInitStructure);
  SDIO_DMACmd(DISABLE);

  if (SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED)
  {
    errorstatus = SD_LOCK_UNLOCK_FAILED;
    return(errorstatus);
  }

  if (CardType == SDIO_HIGH_CAPACITY_SD_CARD)
  {
    BlockSize = 512;
    addr /= 512;
  }
  if ((BlockSize > 0) && (BlockSize <= 2048) && ((BlockSize & (BlockSize - 1)) == 0))
  {
    power = convert_from_bytes_to_power_of_two(BlockSize);

    /* Set Block Size for Card */
    SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) BlockSize;
    SDIO_CmdInitStructure.SDIO_CmdIndex = SDIO_SET_BLOCKLEN;
    SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
    SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
    SDIO_SendCommand(&SDIO_CmdInitStructure);

        //do
        //{
            errorstatus = CmdResp1Error(SDIO_SET_BLOCKLEN);
            printf("SD_ReadBlock CmdResp1Error for SDIO_SET_BLOCKLEN- Error Status = %d\n\r", errorstatus);
    //      timeout--;
    //  }while(errorstatus != SD_OK && timeout > 0);

    if (SD_OK != errorstatus)
    {
      return(errorstatus);
    }
  }
  else
  {
    errorstatus = SD_INVALID_PARAMETER;
    return(errorstatus);
  }

  SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
  SDIO_DataInitStructure.SDIO_DataLength = BlockSize;
  SDIO_DataInitStructure.SDIO_DataBlockSize = (uint32_t) power << 4;
  SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToSDIO;
  SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;
  SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Enable;
  SDIO_DataConfig(&SDIO_DataInitStructure);

  TotalNumberOfBytes = BlockSize;
  StopCondition = 0;
  DestBuffer = readbuff;

  /* Send CMD17 READ_SINGLE_BLOCK */
  SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)addr;
  SDIO_CmdInitStructure.SDIO_CmdIndex = SDIO_READ_SINGLE_BLOCK;
  SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
  SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
  //SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_Pend;
  SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
  SDIO_SendCommand(&SDIO_CmdInitStructure);

  errorstatus = CmdResp1Error(SDIO_READ_SINGLE_BLOCK);
    //printf("SD_ReadBlock CmdResp1Error for SDIO_READ_SINGLE_BLOCK- Error Status = %d\n\r", errorstatus);
  if (errorstatus != SD_OK)
  {
    return(errorstatus);
  }
  /* In case of single block transfer, no need of stop transfer at all.*/
  if (DeviceMode == SD_POLLING_MODE)
  {
    /* Polling mode */
    while (!(SDIO->STA &(SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND | SDIO_FLAG_STBITERR)))
    {
      if (SDIO_GetFlagStatus(SDIO_FLAG_RXFIFOHF) != RESET)
      {
        for (count = 0; count < 8; count++)
        {
          *(tempbuff + count) = SDIO_ReadData();
        }
        tempbuff += 8;
      }
    }

    if (SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)
    {
      SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT);
      errorstatus = SD_DATA_TIMEOUT;
      return(errorstatus);
    }
    else if (SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)
    {
      SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);
      errorstatus = SD_DATA_CRC_FAIL;
      return(errorstatus);
    }
    else if (SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET)
    {
      SDIO_ClearFlag(SDIO_FLAG_RXOVERR);
      errorstatus = SD_RX_OVERRUN;
      return(errorstatus);
    }
    else if (SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET)
    {
      SDIO_ClearFlag(SDIO_FLAG_STBITERR);
      errorstatus = SD_START_BIT_ERR;
      return(errorstatus);
    }
    while (SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL) != RESET)
    {
      *tempbuff = SDIO_ReadData();
      tempbuff++;
    }

    /* Clear all the static flags */
    SDIO_ClearFlag(SDIO_STATIC_FLAGS);
  }
  else if (DeviceMode == SD_INTERRUPT_MODE)
  {
    SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_IT_RXOVERR | SDIO_IT_RXFIFOHF | SDIO_IT_STBITERR, ENABLE);
    while ((TransferEnd == 0) && (TransferError == SD_OK))
    {}
    if (TransferError != SD_OK)
    {
      return(TransferError);
    }
  }
  else if (DeviceMode == SD_DMA_MODE)
  {
    SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_IT_RXOVERR | SDIO_IT_STBITERR, ENABLE);
    SDIO_DMACmd(ENABLE);
    DMA_RxConfiguration(readbuff, BlockSize);
    while (DMA_GetFlagStatus(DMA2_Stream3,DMA_FLAG_TCIF3) == RESET)
    {}
  }
  return(errorstatus);
}

Thank You

\$\endgroup\$
  • 3
    \$\begingroup\$ Can you try to clean up the formatting? \$\endgroup\$ – Tyler Feb 3 '18 at 14:13
  • \$\begingroup\$ This is all a bit confusing and probably too much information. You state that disk_read is throwing illegal command. I don't even see where you invoke a disk_read in you code snippet. What command are you trying to have disk_read perform? \$\endgroup\$ – Tyler Feb 3 '18 at 16:25
  • \$\begingroup\$ disk_read should only throw 4 errors, RES_OK (0), RES_ERROR, RES_PARERR, RES_NOTRDY so not sure where Illegal command comes from elm-chan.org/fsw/ff/doc/dread.html \$\endgroup\$ – Tyler Feb 3 '18 at 16:28
  • \$\begingroup\$ Actually inside disk_read we have to write our logic for reading data from storage using sdio protocol and i have implemented the logic which is there in the code snippet. Disk_read is not invoked from the code snippet instead SD_ReadBlock is invoked from disk_read. SD_ReadBlock is throwing error while setting block length and making the read_disk return error \$\endgroup\$ – Vijay Anand Chandrasekaran Feb 3 '18 at 18:18
  • \$\begingroup\$ If i add the code flow here then it will become too big. Download link for the chan FatFs is elm-chan.org/fsw/ff/00index_e.html In ff.c file inside f_close function f_sync will be invoked. From f_sync other function will be invoked finally invoking SD_ReadBlock. I just gave a overview in the question posted \$\endgroup\$ – Vijay Anand Chandrasekaran Feb 3 '18 at 18:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.