cancel
Showing results for 
Search instead for 
Did you mean: 

SD card access through MSC

Marina Dioto
Associate II
Posted on November 24, 2017 at 22:21

Hello,

I am trying to make a MSC USB device to access SD card files.

The computer recognizes the mass storage device, but cannot open the folder. After a while, it says the device was unrecognized.

My code from usbd_storage_if.c is like this:

int8_t STORAGE_Init_FS (uint8_t lun)

{

/* USER CODE BEGIN 2 */

return (USBD_OK);

/* USER CODE END 2 */

}

/*******************************************************************************

* Function Name : STORAGE_GetCapacity_FS

* Description :

* Input : None.

* Output : None.

* Return : None.

*******************************************************************************/

int8_t STORAGE_GetCapacity_FS (uint8_t lun, uint32_t *block_num, uint16_t *block_size)

{

/* USER CODE BEGIN 3 */

HAL_SD_GetCardInfo(&hsd, &SDCardInfo);

*block_num = SDCardInfo.BlockNbr / BLOCK_SIZE;

*block_size = BLOCK_SIZE;

return (USBD_OK);

/* USER CODE END 3 */

}

/*******************************************************************************

* Function Name : STORAGE_IsReady_FS

* Description :

* Input : None.

* Output : None.

* Return : None.

*******************************************************************************/

int8_t STORAGE_IsReady_FS (uint8_t lun)

{

/* USER CODE BEGIN 4 */

return (USBD_OK);

/* USER CODE END 4 */

}

/*******************************************************************************

* Function Name : STORAGE_IsWriteProtected_FS

* Description :

* Input : None.

* Output : None.

* Return : None.

*******************************************************************************/

int8_t STORAGE_IsWriteProtected_FS (uint8_t lun)

{

/* USER CODE BEGIN 5 */

return (USBD_OK);

/* USER CODE END 5 */

}

/*******************************************************************************

* Function Name : STORAGE_Read_FS

* Description :

* Input : None.

* Output : None.

* Return : None.

*******************************************************************************/

int8_t STORAGE_Read_FS (uint8_t lun,

uint8_t *buf,

uint32_t blk_addr,

uint16_t blk_len)

{

/* USER CODE BEGIN 6 */

HAL_SD_ReadBlocks(&hsd, buf, (blk_addr * BLOCK_SIZE), BLOCK_SIZE, blk_len);

return (USBD_OK);

/* USER CODE END 6 */

}

/*******************************************************************************

* Function Name : STORAGE_Write_FS

* Description :

* Input : None.

* Output : None.

* Return : None.

*******************************************************************************/

int8_t STORAGE_Write_FS (uint8_t lun,

uint8_t *buf,

uint32_t blk_addr,

uint16_t blk_len)

{

/* USER CODE BEGIN 7 */

HAL_SD_WriteBlocks(&hsd, buf, (blk_addr * BLOCK_SIZE), BLOCK_SIZE, blk_len);

return (USBD_OK);

/* USER CODE END 7 */

}

Does someone could help me? Maybe I am missing a step..

Thank you!!

6 REPLIES 6
Posted on November 24, 2017 at 22:54

Isn't SDCardInfo.BlockNbr already in Blocks? Look to be a couple of instances where the math needs 64-bit casts in order not to fail.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
john doe
Lead
Posted on November 25, 2017 at 12:44

not sure if it helps, but there is an example for doing this in the F7 repository

STM32Cube_FW_F7_V1.8.0/Projects/STM32F769I-Discovery/Applications/USB_Device/MSC_Standalone

Posted on December 05, 2017 at 15:32

Do you mean that I don´t need to divide by BLOCK_SIZE?

Where do you think is missing the 64-bit casts?

I found out that the problem is on the HAL_ReadBlocks function. It gives a SDIO_FLAG_RXOVERR: Received FIFO overrun error

But I don`t know what is causing it and what should I change.. can you help me?
Posted on December 05, 2017 at 19:20

I mean you should check and validate your assumptions here. I'm not using this library, ST keeps changing it, so review in the context of what you're using.

STM32Cube_FW_F7_V1.8.0\Drivers\STM32F7xx_HAL_Driver\Inc\stm32f7xx_hal_sd.h

/**

  * @brief  SD Card Information Structure definition

  */

typedef struct

{

  uint32_t CardType;                     /*!< Specifies the card Type                         */

  uint32_t CardVersion;                  /*!< Specifies the card version                      */

  uint32_t Class;                        /*!< Specifies the class of the card class           */

  uint32_t RelCardAdd;                   /*!< Specifies the Relative Card Address             */

  uint32_t BlockNbr;                     /*!< Specifies the Card Capacity in blocks           */

  uint32_t BlockSize;                    /*!< Specifies one block size in bytes               */

  uint32_t LogBlockNbr;                  /*!< Specifies the Card logical Capacity in blocks   */

  uint32_t LogBlockSize;                 /*!< Specifies logical block size in bytes           */

}HAL_SD_CardInfoTypeDef;

A Block count would not need dividing down as it is already in units of blocks, not bytes.

I think this would be more robust, as the math done at 32-bit is apt to overflow. This should force a 64-bit multiplication.

HAL_SD_WriteBlocks(&hsd, buf, ((uint64_t)blk_addr * BLOCK_SIZE), BLOCK_SIZE, blk_len);

But if it already a block address you don't need the multiplication, but your parameters mismatch...

STM32Cube_FW_F7_V1.8.0\Drivers\STM32F7xx_HAL_Driver\Src\stm32f7xx_hal_sd.c

/**

  * @brief  Allows to write block(s) to a specified address in a card. The Data

  *         transfer is managed by polling mode.

  * @note   This API should be followed by a check on the card state through

  *         HAL_SD_GetCardState().

  * @param  hsd: Pointer to SD handle

  * @param  pData: pointer to the buffer that will contain the data to transmit

  * @param  BlockAdd: Block Address where data will be written

  * @param  NumberOfBlocks: Number of SD blocks to write

  * @param  Timeout: Specify timeout value

  * @retval HAL status

  */

HAL_StatusTypeDef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks, uint32_t Timeout)

{

  SDMMC_DataInitTypeDef config;

  uint32_t errorstate = HAL_SD_ERROR_NONE;

  uint32_t tickstart = HAL_GetTick();

  uint32_t count = 0;

  uint32_t *tempbuff = (uint32_t *)pData;

...

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on March 19, 2018 at 14:53

For me that example can read ok but writes do not work. It does look like the code is missing an important step. In the FATfs example code the calls to read or write block are always followed by calls to check that the card isn't busy any more and the code notes that is required. The MSC example omits those calls.

The MSC example is calling the readblocks function with single block reads only, I've been tweaking it to try to improve performance and once I try to read multiple blocks there I get intermittent overruns like the OP reports.

James

Posted on March 19, 2018 at 18:17

Replying with a solution.

As per the notes in the ST code, the MSC example is missing the following in STORAGE_Read() in usbd_storage:

        ret = BSP_SD_WriteBlocks((uint32_t *)buf, blk_addr, blk_len, STORAGE_TIMEOUT);

+        /* Wait until the write operation is finished */

+        while(BSP_SD_GetCardState()!= MSD_OK)

+        {

+            /* FIXME timeout!! */

+        }

That ensures that the write has completed and avoids a failure on the next sector write.

I've optimised this further by making this check happen on the next Write10 command by placing this check in STORAGE_IsReady instead.

The reported write speed goes from 550kB/s to 3.1M/s with the deferred check and some other improvements.

James