2012-03-13 01:30 AM
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-sdio2012-03-13 01:36 PM
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. Tsuneo2012-03-14 01:56 AM
thanks,
I
will
test
the
“PingPong�?buffer
once again
, then
come back
.
2012-04-04 06:51 PM
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?2012-04-06 01:21 AM
The most important
question of the s
end
double buffering
ishow 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
.
2012-04-06 05:13 AM
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.2012-04-08 07:18 PM
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.
2012-04-22 10:18 PM
UP.
2012-07-11 08:46 AM
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.cuint32_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 Abdul2012-07-11 09:54 AM
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