Hi all,
I am using JM60 USB module. For bulk mode, the maximum bit rate that i can get is 200Kbit\sec.
my buffer size is 64 byte. This is not sufficient for my application.
Can any one give suggestion to improve the data rate
The bit rate on USB is fixed for each bus speed.
JM60 is a full-speed (FS) device. FS bus is driven at 12Mbps.
USB is a time-shared bus. Many endpoints of devices may share single bus.
A single endpoint occupies the bus for limited time of a transaction. Therefore, the transfer speed on USB is determined by the number of transactions per 1ms USB frame (for FS bus). In this reason, to measure transfer speed on USB, bps is not a good unit. Packets (transactions)/frame or bytes/sec are better unit.
For FS bulk transfer, 19 full-size packets (transactions) / frame is the theoretical max.
As a full-size packet carries 64 bytes, it means 19 x 64 bytes / 1 ms = 1,216,000 bytes/sec
But this max speed isn't always achieved.
For JM60, the process speed of firmware should be the bottleneck, when the firmware exchanges packets with the bulk endpoint of the USB engine. But 200Kbit/sec (25 KBytes/sec) sounds like too slow. Usually, it reaches to 200 - 300 KBytes/sec.
The principles are simple to get better transfer speed.
On the device side,
- Always exchange full-size (64 bytes) transactions
- Double (ping-pong) buffer increases the performance
On the PC applications,
- Request as large transfer size as possible for the device driver.
For the details, I wrote it in this post on ST Micro forum,
Testing STM32 FS USB Library Performance
https://my.st.com/public/STe2ecommunities/mcu/Lists/ARM%20CortexM3%20STM32/Flat.aspx?RootFolder=http...
Posted: 10/3/2010 2:37 PM by chinzei.tsuneo
Which example is your project based on?
It's better that we are talking of the same source code, to discuss on the real modification to get better transfer speed.
Tsuneo
Thanks for the reply,
I am using Endpoint 3 as OUT and Endpoint 4 as IN.
{sizeof(USB_EP_DSC), DSC_EP, _EP03_OUT, _BULK, (word)(UEP3_SIZE << 8), 0},
{sizeof(USB_EP_DSC), DSC_EP, _EP04_IN, _BULK, (word)(UEP4_SIZE << 8), 0}
The code I am using is based on the JM60 Evaluation code in the link below.
I see. The example device is equipped a vendor specific interface of interrupt IN/OUT and bulk IN/OUT endpoints. On the PC side, WinUSB drives the device.
Next, I ask you about your application.
1) Which type your application is, storage type or streaming type?
- A typical example of storage type is a ROM writer. The MCU can write transferred data to the external EEPROM at any time. Also, the MCU can read out from the EEPROM and send to the host at any time. No timing restriction is there.
- Streaming type has timing restriction. An ADC produces data periodically at given sampling rate. These sampled data have to be transferred to host without any data drop. A DAC consumes transferred data also at given sampling rate. Host must put data in time so that the DAC doesn't dry up.
2) What is the transfer direction, host --> device, or device --> host, or both?
Tsuneo
I am using a storage type and the communication is both ways.
Thanks again
Storage type is simple, because of no timing restriction. You can apply above principles directly.
For host --> device direction,
On the PC application, send as large data size as you want, using single SimpleUSB.WriteData() call.
For example, to send 1M bytes of data, the data buffer is passed to single WriteData() call, claiming 1M Bytes in Size parameter (transfer size). WinUSB and PC host controller splits this request into a sequence of 64 bytes packets.
On the device side,
- your firmware polls arrival of a packet using CheckEndPointOUT().
- If CheckEndPointOUT() returns 1, read out the packet by calling EndPoint_OUT(). The packet is read out into EP3_Buffer[], and its size is held in EP3_OUT_SIZE after EndPoint_OUT() call. The packet size is usually 64 bytes. The last packet of the transfer may have less than 64 bytes, when the transfer size is not a multiple of 64.
- The firmware processes data on EP3_Buffer[].
- When data process finishes, the firmware returns to polling of CheckEndPointOUT()
Thanking to USB hardware flow control (NAK flow control), PC host controller waits for your firmware until it consumes the last packet. So, you don't need to worry about any packet loss.
To make this scenario work, you have to modify USB_Transaction_Handler() a little, so that it doesn't call EndPoint_OUT() on the endpoint interrupt.
Usb_Ep0_Handler.c
void USB_Transaction_Handler(void)
{
unsigned char stat = STAT;
if((stat & 0xF0 ) == 0x00)
{
stat &= 0xF8;
if(stat == EP00_OUT)
{
if(Bdtmap.ep0Bo.Stat.RecPid.PID == SETUP_TOKEN)
USB_CtrlTrf_SetupStage_Processing();
else
USB_CtrlTrf_Out_Handler();
}
else
{
if(stat == EP00_IN)
USB_CtrlTrf_In_Handler();
}
}
else
{
if(stat & 0x08)
asm(nop);
else // OUT handler
// EndPoint_OUT((stat & 0xF0)>>4); // <------ comment this line
asm(nop); // <------ add this line
}
}
I have to move to another place, now
To be continued ..
Tsuneo
Hi Tsuneo,
In above post, I said to use CheckEndPointOUT() to poll the arrival of a packet.
Instead, use this routine.
UINT8 CheckEndPointOUT3( void )
{
return !EP3_Set.Stat.McuCtlBit.OWN; // check own bit on EP3 BDT directly
}
OK, the other direction.
For device --> host,
On the PC application, request as large data size as you expect, using single SimpleUSB.ReadBulkEndpoint call.
To receive 1K bytes of data, claim 1K Bytes in Size parameter (transfer size). WinUSB and PC host controller splits this request into a sequence of IN transactions. The packets from the device are aligned on the buffer by the host controller. When the transferred data reaches to the request size, ReadBulkEndpoint finishes.
On the device side,
1) The firmware fills EP4_Buffer[] with the first 64 bytes packet
2) The firmware polls finish of last transaction using CheckEndPointIN4() (see below)
3) Call EndPoint_IN()
4) Back to 1) for the next packet
UINT8 CheckEndPointIN4( void )
{
return !EP4_Set.Stat.McuCtlBit.OWN; // check own bit on EP4 BDT directly
}
Tsuneo
Thank you very much it works..
will a SimpleUSB.ReadBulkEndpoint handle a ping pong buffer?