cancel
Showing results for 
Search instead for 
Did you mean: 

USB Mass storage + SDMMC read write too slow

Hau Lam
Associate II
Posted on May 08, 2018 at 13:11

i using STMF779I-EVAL board and try to  implement USB Mass Storage + SD Card . But the read/write speed i am getting when write/read from Window PC is too slow. 

Read : 1MB/s; Write : 200KB/s

Even I already used DMA mechanism to speed up the SDMMC driver .

This is my implementation for read/write

int8_t STORAGE_Write_HS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)

{

//printf('STORAGE_Write_HS \n');

HAL_SD_CardStateTypeDef sd_card_state_return;

HAL_SD_StateTypeDef state_return;

uint32_t timeout = 0;

if(HAL_OK != HAL_SD_WriteBlocks_DMA(&hsd1, buf, blk_addr, (uint32_t) blk_len))

{

printf('Error : STORAGE_Write_HS failed Err: %u, blk_addr : %u ; blk_len : %u\n', hsd1.ErrorCode, blk_addr, blk_len);

return USBD_FAIL;

}

// Callback 

HAL_SD_TxCpltCallback increare writestatus  to check writing status

while (writestatus == 0)

{

}

writestatus = 0;

/* Wait until SD card is ready to use for new operation */

while (HAL_SD_GetCardState(&hsd1) != HAL_SD_CARD_TRANSFER)

{

}

return (USBD_OK);

/* USER CODE END 14 */

}

void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)

{

//printf('HAL_SD_TxCpltCallback \n');

if(hsd->Instance == SDMMC1)

{

writestatus = 1;

}

}

I think that the HAL_SD_GetCardState(0 to long time to change state to HAL_SD_CARD_TRANSFER.

Could you let me know what is the root cause and is there any way to improve the speed ?

Thank you very much.

11 REPLIES 11
Hau Lam
Associate II
Posted on May 16, 2018 at 11:58

Could somebody help to take a look ? 

Posted on May 16, 2018 at 13:52

>> STMF779I-EVAL

Sorry not a board that I have.

Would check to see the maximum block requested for read/write operations, and check if descriptors/settings reported to PC limit block count or transfer size.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on May 17, 2018 at 04:56

Hi

Turvey.Clive

‌,

I checked block len in functionint8_t STORAGE_Write_HS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)

it always write 1 block /time, and block size is 512 bytes.

Is it the problem cause writing slow issue ? and how can i improve this ?

Posted on May 17, 2018 at 05:37

STM32Cube_FW_F7_V1.0\Projects\STM32756G_EVAL\Applications\USB_Device\MSC_Standalone\Inc\usbd_conf.h

/* MSC Class Config */

#define MSC_MEDIA_PACKET 512 // Increase as a binary multiple, ie (512 << 1)

You might need to make the heap large also

https://community.st.com/0D50X00009XkXa1SAF

>>Is it the problem cause writing slow issue ? and how can i improve this ?

Single block read/write is the worst case scenario for mass storage, high command penalty on each block, designed to stream 32-64KB

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on May 18, 2018 at 04:15

You'd want to make sure there isn't an issue with using or allocating that much memory. Where it falls in the memory space may also be problematic. Issues with caching, use of DMA, use of DTCMRAM, etc.

If the size is reported somewhere, there might be a 16-bit limit.

32KB should be sufficient, consider the speed the SDMMC is being clocked. Most microSD cards are supported to clock a 50 MHz on the bus (not 24 MHz the 48 MHz gets you).

Check the clock source selected in RCC->DCKCFGR2, you should be able to select the 200 MHz SYSCLK, not the ~48 MHz of the PLL_Q or PLLSAI_P. You'll need to change the SDMMC ClockDiv appropriately.

http://www.st.com/content/ccc/resource/technical/document/reference_manual/group0/96/8b/0d/ec/16/22/43/71/DM00224583/files/DM00224583.pdf/jcr:content/translations/en.DM00224583.pdf

 

void plldumpf7(void) //

mailto:sourcer32@gmail.com

{

  uint32_t vcoinput, vco;

  uint32_t oscsource;

  uint32_t dckcfgr2 = RCC->DCKCFGR2;

  uint32_t pllcfgr = RCC->PLLCFGR;

  uint32_t plli2scfgr = RCC->PLLI2SCFGR;

  uint32_t pllsaicfgr = RCC->PLLSAICFGR;

  uint32_t pllp, pllq, pllr;

  uint32_t p, q, r;

  uint32_t plli2s_p, plli2s_q, plli2s_r;

  uint32_t pllsai_p, pllsai_q, pllsai_r;

  /* Configure the PLLSAI division factor */

  /* PLLSAI_VCO Input  = PLL_SOURCE/PLLM */

  if((pllcfgr & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSI)

    oscsource = HSI_VALUE; /* In Case the PLL Source is HSI (Internal Clock) */

  else

    oscsource = HSE_VALUE; /* In Case the PLL Source is HSE (External Clock) */

  vcoinput = (oscsource / (uint32_t)(pllcfgr & RCC_PLLCFGR_PLLM));

  vco = (vcoinput * ((pllcfgr & RCC_PLLCFGR_PLLN) >> 6));

  pllp = (((pllcfgr & RCC_PLLCFGR_PLLP) >> 16) + 1) * 2; // SYSCLK

  p = vco / pllp;

  pllq = (pllcfgr & RCC_PLLCFGR_PLLQ) >> 24; // PLL48

  q = vco / pllq;

  pllr = (pllcfgr & 0x70000000) >> 28; // Not on F74xx RCC_PLLCFGR_PLLR

  r = vco / pllr;

  printf('PLL    P:%9d Q:%9d R:%9d\n', p, q, r);

  vco = (vcoinput * ((plli2scfgr & RCC_PLLI2SCFGR_PLLI2SN) >> 6));

  pllq = (((plli2scfgr & RCC_PLLI2SCFGR_PLLI2SP) >> 16) + 1) * 2;

  plli2s_p = vco / pllp;

  pllp = (plli2scfgr & RCC_PLLI2SCFGR_PLLI2SQ) >> 24;

  plli2s_q = vco / pllq;

  pllr = (plli2scfgr & RCC_PLLI2SCFGR_PLLI2SR) >> 28;

  plli2s_r = vco / pllr;

  printf('PLLI2S P:%9d Q:%9d R:%9d\n', plli2s_p, plli2s_q, plli2s_r);

  vco = (vcoinput * ((pllsaicfgr & RCC_PLLSAICFGR_PLLSAIN) >> 6));

  pllq = (((pllsaicfgr & RCC_PLLSAICFGR_PLLSAIP) >> 16) + 1) * 2;

  pllsai_p = vco / pllp;

  pllp = (pllsaicfgr & RCC_PLLSAICFGR_PLLSAIQ) >> 24; // 2..15

  pllsai_q = vco / pllq;

  pllr = (pllsaicfgr & RCC_PLLSAICFGR_PLLSAIR) >> 28; // 2..7

  pllsai_r = vco / pllr;

  printf('PLLSAI P:%9d Q:%9d R:%9d\n', pllsai_p, pllsai_q, pllsai_r);

  // DCKCFGR2 bit 27 PLL48CLK 0=PLLQ, 1=SAIP

  // DCKCFGR2 bit 28 SDMMCSEL 0=PLL48, 1=SYSCLK (bit 29 for SDMMC2)

  {

    uint32_t pll48clk = ((dckcfgr2 & (1<<27)) ? pllsai_p : q);

    uint32_t sdmmc_clkcr = SDMMC1->CLKCR;

    uint32_t sdclk = ((dckcfgr2 & (1<<28)) ? p : pll48clk) / ((sdmmc_clkcr & 0xFF) + 2);

    printf('PLL48CLK %9d, %6.2lf MHz\n', pll48clk, (double)pll48clk*1e-6);

    printf('SDCLK    %9d, %6.2lf MHz\n', sdclk, (double)sdclk*1e-6);

  }

  {

    uint32_t dckcfgr1 = RCC->DCKCFGR1;

    uint32_t divr = 2 << ((dckcfgr1 & RCC_DCKCFGR1_PLLSAIDIVR) >> 16); // 2,4,8,16

    uint32_t lcdclk = pllsai_r / divr;

    printf('LCDCLK   %9d, %6.2lf MHz\n', lcdclk, (double)lcdclk*1e-6);

  }

}

>>Could you help me on this issue ? 

Consider sponsoring my work/projects.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on May 18, 2018 at 03:41

Dear

Turvey.Clive.002

‌,

Many thanks for for your support , now i can improve the writing speed to 2.5 MB/s on STM32F779 eval board.

by change to#define MSC_MEDIA_PACKET 32768

But i want to improve more then i changeMSC_MEDIA_PACKET to 65536 but can not read/write SDCard any more.

I already check the USB descriptor it define the USB MAX packet size is 64

__ALIGN_BEGIN uint8_t USBD_HS_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END =

{

0x12, /*bLength */

USB_DESC_TYPE_DEVICE, /*bDescriptorType*/

#if (USBD_LPM_ENABLED == 1)

0x01, /*bcdUSB */ /* changed to USB version 2.01

in order to support LPM L1 suspend

resume test of USBCV3.0*/

#else

0x00, /*bcdUSB */

#endif /* (USBD_LPM_ENABLED == 1) */

0x02,

0x00, /*bDeviceClass*/

0x00, /*bDeviceSubClass*/

0x00, /*bDeviceProtocol*/

USB_MAX_EP0_SIZE, /*bMaxPacketSize*/ // This is 64

LOBYTE(USBD_VID), /*idVendor*/

HIBYTE(USBD_VID), /*idVendor*/

LOBYTE(USBD_PID_HS), /*idProduct*/

HIBYTE(USBD_PID_HS), /*idProduct*/

0x00, /*bcdDevice rel. 2.00*/

0x02,

USBD_IDX_MFC_STR, /*Index of manufacturer string*/

USBD_IDX_PRODUCT_STR, /*Index of product string*/

USBD_IDX_SERIAL_STR, /*Index of serial number string*/

USBD_MAX_NUM_CONFIGURATION /*bNumConfigurations*/

};

So I suspect whether the Window host PC doesn't support packet size 64or any issue from the USB storage driver from firmware side ?

Could you help me on this issue ?

Posted on May 18, 2018 at 05:00

Dear

Turvey.Clive.002

‌,

It actually the is a warning compiler when i set MSC_MEDIA_PACKET to 65536

Look intousbd_msc_scsi.c there is 1 functionSCSI_Read10() itset hmsc->bot_data_length = MSC_MEDIA_PACKET; but

bot_data_length is declared uint16_t only.

So can i say that the current ST USB stack only support 32KB ?

Consider sponsoring my work/projects.

What do you mean

Posted on May 18, 2018 at 17:36

I'm not paid by ST, if I've saved you man-hours or man-days of work, consider how you can help me.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
James Murray
Senior
Posted on May 19, 2018 at 00:22

On the STM32F769I-DISCO I had similar issues, the example code was very slow. Writes corrupted the card too.

I have fixed the write corruption (must check no longer busy before returning) and boosted read speed to over 7MB/sec.

My approach was to implement a simple read-cache and read in numerous blocks in one go.

i.e. instead of requesting as single 512 byte sectors, I read 32x 512 byte sectors, store the result to RAM and then return a pointer to the start of the sector. On the next read, if that sector is already in RAM, I just return a pointer and don't do an SDcard read. This makes a BIG difference. Any writes invalidate the cache valid flag.

I also found that the provided SD card read block code is issuing an initialisation command every time, that is not required and wastes time.

I'm afraid I'm not sharing the code, but hopefully these notes should give you a start.

James