Skip to main content
Visitor II
March 13, 2012
Question

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

  • March 13, 2012
  • 15 replies
  • 3244 views
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
    This topic has been closed for replies.

    15 replies

    Visitor II
    March 13, 2012
    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

    power3347Author
    Visitor II
    March 14, 2012
    Posted on March 14, 2012 at 09:56

    thanks,

    I

    will

    test

    the

     “PingPong�?buffer 

    once again

    , then

     come back

    .

    power3347Author
    Visitor II
    April 5, 2012
    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?

    power3347Author
    Visitor II
    April 6, 2012
    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

    .

    Graduate II
    April 6, 2012
    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.

    power3347Author
    Visitor II
    April 9, 2012
    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.

    power3347Author
    Visitor II
    April 23, 2012
    Posted on April 23, 2012 at 07:18

    UP.

    Visitor II
    July 11, 2012
    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
    Graduate II
    July 11, 2012
    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
    Visitor II
    July 12, 2012
    Posted on July 12, 2012 at 10:23

    Tanks you clive1, it's now clear,

    please one more questions according to your correction made on my code

    1/ I set in prop.c file in Mass_Storage_SetConfiguration following:

    void Mass_Storage_SetConfiguration(void)

    {

      if (pInformation->Current_Configuration != 0)

      {

        /* Device configured */

        bDeviceState = CONFIGURED;

       ClearDTOG_RX(ENDP2);

     

       ClearDTOG_TX(ENDP1);

     

       ToggleDTOG_TX(ENDP2); /* reset value of the data toggle bits for the endpoint out*/

     

        ClearDTOG_RX(ENDP1);

     

        ClearDTOG_TX(ENDP1); /* clear the data toggle bits for the endpoint IN*/

        Bot_State = BOT_IDLE; /* set the Bot state machine to the IDLE state */

      }

    }

    and in MASS_NoData_Setup function:

    RESULT MASS_NoData_Setup(uint8_t RequestNo)

    {

      if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))

          && (RequestNo == MASS_STORAGE_RESET) && (pInformation->USBwValue == 0)

          && (pInformation->USBwIndex == 0) && (pInformation->USBwLength == 0x00))

      {

            ClearDTOG_RX(ENDP2);

     

            ClearDTOG_TX(ENDP2);

     

           ToggleDTOG_TX(ENDP2); /* reset value of the data toggle bits for the endpoint out*/

     

           ClearDTOG_RX(ENDP1);

     

            ClearDTOG_TX(ENDP1); /* clear the data toggle bits for the endpoint IN*/    

        /*initialize the CBW signature to enable the clear feature*/

        CBW.dSignature = BOT_CBW_SIGNATURE;

        Bot_State = BOT_IDLE;

        return USB_SUCCESS;

      }

      return USB_UNSUPPORT;

    } is it correct ? because I still have code 10 error

    tanks

    Abdul