cancel
Showing results for 
Search instead for 
Did you mean: 

Inprove the speed of the ''Mass storage'' as u disk

power3347
Associate II
Posted on March 13, 2012 at 09:30

hello everybody,

  I was tested using the TF card as a U disk routines.The read speed is 500KB

-700KB / s, write speed of 100KB/ s. Too slow, I would like to increase its 

transmission speed.I will change the way of the USB to transfer data to double 

buffering, speed does not improve, I would like to speed transmission 

bottlenecks on the TF card flash, and do you have any good suggestions?(In 

this post I willcontinue to update content on the USB.)

    (The operation of the TF card SDIO,DMA, 4bit.)

#usb-sdio-tf-card #usb-tf-dma-sdio #usb-tf-card-sdio
15 REPLIES 15
tsuneo
Senior
Posted on March 13, 2012 at 21:36

a) USB transfer speed of MSC-BOT (Mass-Storage Class - Bulk-Only Transport)

MSC-BOT protocol has overhead to transfer data on both direction.

READ10/WRITE10 SCSI commands are carried by this BOT protocol.

CBW - Data transport (IN/OUT) - CSW

When Host runs OHCI or UHCI host controller (as usual on PCs), each transport stage takes one or more USB frame, because these host controllers delay interrupt of transfer completion until next SOF timing.

- CBW                       : 1 frame (1 ms)

- Data transport (4K Bytes) : 4 frames

- CSW                       : 1 frame

4K bytes / 6 ms = 667K Bytes/s

Therefore, your observation, 500KB-700KB/s, hits the practical max of full-speed MSC-BOT.

When the MSC device plugs in to a high-speed USB port (EHCI) over a USB2.0 hub, you may see a little better performance. On EHCI, each transport stage is assigned to micro-frame (125 us), instead of frame (1 ms).

b) Protocol overhead of SDIO

While host reads/writes file data on SD card, host accesses to it in the unit of 4K bytes cluster. To read/write this size of data form a SD card, multi-block read/write: READ_MULTIPLE_BLOCK (CMD18), WRITE_MULTIPLE_BLOCK (CMD25), have less protocol overhead than repeated single-block ones, though it requires a buffer of cluster size.

Put SET_WR_BLOCK_ERASE_COUNT (ACMD23: CMD55,CMD23) before WRITE_MULTIPLE_BLOCK, to speed up multi-block write.

c) Concurrent processes of SDIO and USB

To run SDIO and USB concurrently, double buffer is applied. That is, while a buffer is filled with SDIO, another buffer is sent over USB. When both processes finish, the buffers are swapped and next processes start. This scheme speeds up the throughput but it requires double-sized buffer.

To reduce the total buffer size, above double buffer is replaced with a cyclic buffer in the unit of wMaxPacketSize (64 bytes). Every time 64 bytes are read out, the firmware halts SDIO to check the buffer full. Next read of SDIO is delayed until USB makes any room on the buffer. SDIO halts while SD clock pauses, at any phase of multi-block read/write protocol. Similarly, USB waits while the buffer is empty.

In this way, even 128 bytes buffer works.

Tsuneo

power3347
Associate II
Posted on March 14, 2012 at 09:56

thanks,

I

will

test

the

 “PingPong�?buffer 

once again

, then

 come back

.

power3347
Associate II
Posted on April 05, 2012 at 03:51

I tested

the STM32

receive

double buffering

, like this:

//EndPoint2  AS the receive double buffer,init in the Usb_prop.c

  SetEPDoubleBuff(ENDP2);

  SetEPDblBuffAddr(ENDP2, ENDP2_RXADDR, ENDP2_RXADDR2);

  SetEPDblBuffCount(ENDP2, EP_DBUF_OUT, Device_Property.MaxPacketSize);

  ClearDTOG_RX(ENDP2);

  ClearDTOG_TX(ENDP2);

  ToggleDTOG_TX(ENDP2);

//********

  SetEPRxStatus(ENDP2, EP_RX_VALID);

  SetEPTxStatus(ENDP2, EP_TX_DIS);

//deal with the receive data in Usb_sil.c

if (GetENDPOINT(ENDP2) & EP_DTOG_TX)

{

DataLength = GetEPDblBuf0Count(ENDP2);

PMAToUserBufferCopy(pBufferPointer, ENDP2_RXADDR, DataLength);

}

else

{

// FreeUserBuffer(ENDP2, EP_DBUF_OUT);

DataLength = GetEPDblBuf1Count(ENDP2);

PMAToUserBufferCopy(pBufferPointer, ENDP2_RXADDR2, DataLength);

}

FreeUserBuffer(ENDP2, EP_DBUF_OUT);

OK ,it is very good,i can improve about 40KB/S.

but i can not set the send double buffer by the stm32's refer.

May someone help me?

power3347
Associate II
Posted on April 06, 2012 at 10:21

The most important

question  of the s

end

double buffering

 is

how to calculate

 the 

the file size which will be send.

For

example

,

the

PC

side 

began to

copy

the

data

,

select the file

and then

transfer

selected

files

,

so it is necessary

to dynamically

go

to

calculate

the

PC

selected files

,

this

is

 not easy

.

Posted on April 06, 2012 at 14:13

The file size is entirely irrelevant, it's the transfer size requested by the SCSI CDB that is critical.

The PC can read any part of the file in a non-linear fashion (random access), and a file may be scattered over many disconnected clusters (groups of sectors). A smart OS will attempt to consolidate maximal run lengths, but will often attempt to just read in the cached page size or cluster size, depending on the buffering scheme.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
power3347
Associate II
Posted on April 09, 2012 at 04:18

i write some codes in two files like receive double buffer'code like this:

//usb_prop.c'code

  /* Initialize Endpoint 1 */

  SetEPType(ENDP1, EP_BULK);

  SetEPDoubleBuff(ENDP1);

  SetEPDblBuffAddr(ENDP1, ENDP1_TXADDR, ENDP1_TXADDR2);

  SetEPDblBuffCount(ENDP1, EP_DBUF_IN, Device_Property.MaxPacketSize);

  ClearDTOG_RX(ENDP1);

  ClearDTOG_TX(ENDP1);

  ToggleDTOG_RX(ENDP1);

  SetEPTxStatus(ENDP1, EP_TX_NAK);

  SetEPRxStatus(ENDP1, EP_RX_DIS);

//usb_sil.c'code   if (GetENDPOINT(ENDP1) & EP_DTOG_RX)//

{

UserToPMABufferCopy(pBufferPointer,ENDP1_TXADDR , wBufferSize);

}

else

{

UserToPMABufferCopy(pBufferPointer,ENDP1_TXADDR2 , wBufferSize);

}

FreeUserBuffer(ENDP1, EP_DBUF_IN);

SetEPTxCount((bEpAddr & 0x7F), wBufferSize);

but it doesn't work,

i think i understand wrong of the double buffering mode.

power3347
Associate II
Posted on April 23, 2012 at 07:18

UP.

gafsos
Associate II
Posted on July 11, 2012 at 17:46

Hello,

I have the same problem (With Modified prop.c and sil.c files)

1/ prop.c:

  /*Set Endp1 as a sent double buffer*/

  SetEPType(ENDP1, EP_BULK);

  SetEPDoubleBuff(ENDP1);

  SetEPDblBuffAddr(ENDP1, ENDP1_BUFF0ADDR, ENDP1_BUFF1ADDR);

  ClearDTOG_RX(ENDP1);

  ToggleDTOG_RX(ENDP1);

  ClearDTOG_TX(ENDP1);

  SetEPTxStatus(ENDP1, EP_TX_VALID);

  SetEPRxStatus(ENDP1, EP_RX_DIS);

 

  /*Set Endp2 as a received double buffer*/

  SetEPType(ENDP2, EP_BULK);

  SetEPDoubleBuff(ENDP2);

  SetEPDblBuffAddr(ENDP2, ENDP2_BUFF0ADDR, ENDP2_BUFF1ADDR);

  SetEPDblBuffCount(ENDP2, EP_DBUF_OUT, BULK_MAX_PACKET_SIZE);

  ClearDTOG_RX(ENDP2);

  ClearDTOG_TX(ENDP2);

  ToggleDTOG_TX(ENDP2);

  SetEPRxStatus(ENDP2, EP_RX_VALID);

  SetEPTxStatus(ENDP2, EP_TX_DIS);

2/ sil.c

uint32_t USB_SIL_Write(uint8_t bEpAddr, uint8_t* pBufferPointer, uint32_t wBufferSize)

{

    /* Update the data length in the control register */

  SetEPTxCount((bEpAddr & 0x7F), wBufferSize);

  

  /*write to buffer 0*/

  if (GetENDPOINT(ENDP2) & EP_DTOG_TX)

  {

    wBufferSize = GetEPDblBuf0Count(ENDP2);

    UserToPMABufferCopy(pBufferPointer, ENDP2_BUFF0ADDR, wBufferSize);

  }

  else

  {

     /*write to buffer 1*/

    wBufferSize = GetEPDblBuf1Count(ENDP2);

    UserToPMABufferCopy(pBufferPointer, ENDP2_BUFF1ADDR, wBufferSize);

  }

FreeUserBuffer(ENDP2, EP_DBUF_OUT);

  return 0;

}

and :

uint32_t USB_SIL_Read(uint8_t bEpAddr, uint8_t* pBufferPointer)

{

  uint32_t DataLength = 0;

  /* Get the number of received data on the selected Endpoint */

  DataLength = GetEPRxCount(bEpAddr & 0x7F);

   /*read from buffer 0*/

  if (GetENDPOINT(ENDP2) & EP_DTOG_TX)

  {

    DataLength = GetEPDblBuf0Count(ENDP2);

    PMAToUserBufferCopy(pBufferPointer, ENDP2_BUFF0ADDR, DataLength);

  }

  else

  {

     /*read from buffer 1*/

    DataLength = GetEPDblBuf1Count(ENDP2);

    PMAToUserBufferCopy(pBufferPointer, ENDP2_BUFF1ADDR, DataLength);

  }

FreeUserBuffer(ENDP2, EP_DBUF_OUT);

/* Return the number of received data */

  return DataLength;

Could you please Help me

Abdul
Posted on July 11, 2012 at 18:54

Could you please Help me

Even with a cursory analysis you have internal inconsistencies between End Points and Rx and Tx. A far more considered implementation, although still rather hackish, would look a bit like :

/* Initialize Endpoint 1 (TX) (IN) (USB_SIL_WRITE) (EP1_IN)*/
SetEPType(ENDP1, EP_BULK);
SetEPDoubleBuff(ENDP1);
SetEPDblBuffAddr(ENDP1, ENDP1_BUF0ADDR, ENDP1_BUF1ADDR);
SetEPDblBuffCount(ENDP1, EP_DBUF_IN, Device_Property.MaxPacketSize); // 0x40
ClearDTOG_TX(ENDP1); // USB PERIPHERAL
ClearDTOG_RX(ENDP1); // SW_BUF for APPLICATION
ToggleDTOG_RX(ENDP1); // NOT TX ie SW_BUF
SetEPTxStatus(ENDP1, EP_TX_NAK);
SetEPRxStatus(ENDP1, EP_RX_DIS); // NOT TX DISABLE
/* Initialize Endpoint 2 (RX) (OUT) (USB_SIL_Read) (EP2_OUT)*/
SetEPType(ENDP2, EP_BULK);
SetEPDoubleBuff(ENDP2);
SetEPDblBuffAddr(ENDP2, ENDP2_BUF0ADDR, ENDP2_BUF1ADDR);
SetEPDblBuffCount(ENDP2, EP_DBUF_OUT, Device_Property.MaxPacketSize); // 0x40
ClearDTOG_RX(ENDP2); // USB PERIPHERAL
ClearDTOG_TX(ENDP2); // SW_BUF for APPLICATION
ToggleDTOG_TX(ENDP2); // NOT RX ie SW_BUF
SetEPRxStatus(ENDP2, EP_RX_VALID);
SetEPTxStatus(ENDP2, EP_TX_DIS); // NOT RX DISABLE
/*******************************************************************************
* Function Name : USB_SIL_Write
* Description : Write a buffer of data to a selected endpoint.
* Input : - bEpAddr: The address of the non control endpoint.
* - pBufferPointer: The pointer to the buffer of data to be written
* to the endpoint.
* - wBufferSize: Number of data to be written (in bytes).
* Output : None.
* Return : Status.
*******************************************************************************/
uint32_t USB_SIL_Write(uint8_t bEpAddr, uint8_t* pBufferPointer, uint32_t wBufferSize)
{
// Hard coded to simplify
// Assumes (bEpAddr & 0x7F) == ENDP1 or EP1_IN?
if (GetENDPOINT(ENDP1) & EP_DTOG_RX) // NOT TX ie SW_BUF
{
UserToPMABufferCopy(pBufferPointer, ENDP1_BUF0ADDR, wBufferSize);
SetEpDblBuf0Count(ENDP1, wBufferSize);
}
else
{
UserToPMABufferCopy(pBufferPointer, ENDP1_BUF1ADDR, wBufferSize);
SetEpDblBuf1Count(ENDP1, wBufferSize);
}
FreeUserBuffer(ENDP1, EP_DBUF_IN); // Toggles EP_DTOG_RX / SW_BUF
return 0;
}
/*******************************************************************************
* Function Name : USB_SIL_Read
* Description : Write a buffer of data to a selected endpoint.
* Input : - bEpAddr: The address of the non control endpoint.
* - pBufferPointer: The pointer to which will be saved the
* received data buffer.
* Output : None.
* Return : Number of received data (in Bytes).
*******************************************************************************/
uint32_t USB_SIL_Read(uint8_t bEpAddr, uint8_t* pBufferPointer)
{
uint32_t DataLength = 0;
// Hard coded to simplify
// Assumes (bEpAddr & 0x7F) == ENDP2 or EP2_OUT?
if (GetENDPOINT(ENDP2) & EP_DTOG_TX) // NOT RX ie SW_BUF
{
DataLength = GetEPDblBuf0Count(ENDP2);
PMAToUserBufferCopy(pBufferPointer, ENDP2_BUF0ADDR, DataLength);
}
else
{
DataLength = GetEPDblBuf1Count(ENDP2);
PMAToUserBufferCopy(pBufferPointer, ENDP2_BUF1ADDR, DataLength);
}
FreeUserBuffer(ENDP2, EP_DBUF_OUT); // Toggles EP_DTOG_TX / SW_BUF
/* Return the number of received data */
return DataLength;
}

I don't think this addresses STALL conditions
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..