QTimer problem?
-
Hi all,
I have a problem in which my Qt program seems to be the bottleneck of my USB transfer.
I have a PollUSB() function that checks if the usb is connected, has something to send and then read the port. However, I am only getting 4.4KB/s speed.
A Qtimer calls the PollUSB() function, periodically, but it seems it is not fast enough. The weirdest thing is that I get the same transfert rate if I set timer->start(0) or timer->start(1000);
What is happening to the timer?
-
the value for "start":http://qt-project.org/doc/qt-5.1/qtcore/qtimer.html#start is in milliseconds. This confuses sometimes people. AFAIK a value of '0' will make make a direct timeout, but you may want to try with '1', I doubt that you will see a difference.
The transfer rate may be dependent on debug and release mode compilations. -
Hi, Did you place your USB connection in a different thread? Otherwise the GUI will slow down your transfer rate. Maybe place the USB in the different thread and using signals/slots port data or error from/to the main thread.
Then checks every couple of msecs is possible.
When a ask/receive game is played, this will speed up the process.
If it's a bulk transfer you might want to read out all data in one timer event?
So, if that doesn't solve it:- What type of USB connection do you use? What protocol?
- What does your USB receive code look like?
Greetz
-
Ok. I have found that start(value) is only for the first call.
After that, the delay is always 0 which means ASAP. I checked with remainingTime() fucntion and it is indeed always 0.
So the problem is not there, it is taking too much time between function calls.
-
Hi Jeroentje,
your idea is not bad at all, but before I do that I will setup a QDateTime to measure how much time there is between function calls.
-
wow... it is taking 130ms between each function calls and that was the fastest call of all.
I will try putting that into a Thread. If it is not working, I will have to do dual driver USB (right now it is HID... so limited to 64B every 1ms).
-
Hi,
Your HID device is also capable of Bulk transfers. Only the 'normal' HID sequencial messages needs to be transmitted as described in your USD descriptor. In that descriptor you are also capable of adding a port that will be used for bulk transfer. Ok, you don't get error checking that much, so maybe if that's real important, try a data transfer port. You do not need the HID device sequential messages to do that.
Placing communication protocols in a different tread is always a good idea btw. So your GUI and communication timing do not interfere.
Greetz -
Thanks jeroentje... I will begin with a new thread (need to clean up code before I do that)... and then if it is not enough, I will add a bulk transfer endpoint.
-
OK.. I put the PollUSB function in a different thread.
I verify using : @qDebug()<<"Worker:: get called from?: "<<QThread::currentThreadId();@ that I am actually in another thread.
I get more consistent results, but it is always exactly 150ms in fact:
0.0150001049041748 seconds
Then I disconnected the device and got 1ms delay! So it is really the device that gets me 150ms delay.
-
What type of device is it? You made it?
If using Microchip controllers? USe interrupts ;-) -
I am using Microchip uC and I am also using interrupts. :)
I used a USB analyser this morning... and got interesting results.
I have about 1 to 2 ms between each successive read of the USB port.
So the real problem would be that the software skips frames??
If I recapitulate:
- Without usb connection, the software complete the loop in 1ms
- With usb connection the software takes 150ms to complete the loop
- With software and connection, the USB analyser tells me I have 1 frame each 1 to 2 ms.
-
Hmm, I think the bigger question is, what data do you need to transfer?
For a 'standard' HID device only a couple of bytes every 5 msec is more then enough. This is setup in your usb_descriptor.c file and is sequential.
Next to this, if you want large chunks of data transferred, you could setup a second endpoint that handles e.b. Bulk transfers or other MSD type of transfers. Then no timing will be used, only the time for ask/answer mechanism, but Windows will do that for you.
From Microchip download the application libs (which you did already?) and check out a couple of examples.
Maybe post the pollUSB function in the thread so I could take a look at it.
Your transfer rate should be much higher then 4 kb/s! I could flash a PIC24F256 in less then 3 seconds transferring the entire buffer and letting the chip program itself in bootloader mode ;-) So 256kB in 3 secs is about 800kB/s for estimated transfer rate ;-)
So, keep on trying, it could go much faster!
Post the code, we take a look at that. -
Yes... I know I could add another endpoint to transfert large chunk of data, but there is definitely an underlying problem that I don,t want to leave there.
Here is the pollUSB function;
@void HID_PnP::run()
{
timer = new QTimer();
connect(timer, SIGNAL(timeout()), this, SLOT(PollUSB()));
timer->start(1); //start in 1ms, will repeat ASAP (remainingTime=0;)
qDebug()<<"Worker:: get called from?: "<<QThread::currentThreadId();exec();
}void HID_PnP::PollUSB()
{if (isConnected == false) { device = hid_open(myVID, myPID, NULL); if (device) { isConnected = true; hid_set_nonblocking(device, true); timer->start(15); } } else { unsigned char *TxPtr; TxPtr = &TxBuff.Data[0]; //Calculate delay since last time we sent usb. We need at least 1ms for messages to process correctly double temps = QDateTime::currentDateTime().toMSecsSinceEpoch()/1000.0; static double lastTimeWeSentUSB=temps; double delay=temps-lastTimeWeSentUSB; lastTimeWeSentUSB=temps; // qDebug()<<"Worker:: get called from?: "<<QThread::currentThreadId(); if (TxBuff.Len>=MAX_STR&&delay>0.001) { // Send the packet with 65 bytes everytime (USB endpoint size is always 65 bytes to send) sendToUsb(TxPtr); if (TxBuff.Len >= MAX_STR) { // Send pending bytes in next loop. TxBuff.Len -=MAX_STR; // Point to next 64bytes. TxPtr += MAX_STR; } else { // No more bytes. TxBuff.Len=0; } } ////////////Read from device///////////////// if(isConnected){ if(hid_read(device, inBuf, sizeof(inBuf)) == -1) { closeDevice(); return; } receivedCommand(inBuf[0], inBuf, delay ); //qDebug()<<"Worker:: get called from?: "<<QThread::currentThreadId(); } inBuf[0]=0; } //Calculate delay since last time we sent usb. We need at least 1ms for messages to process correctly double temps2 = QDateTime::currentDateTime().toMSecsSinceEpoch()/1000.0; static double lastTimeWeReceiveUSB=temps2; static double lastTime=temps2; double delay=temps2-lastTimeWeReceiveUSB; static double numberOfbytes=0; if((temps2-lastTime)>10){ numberOfbytes+=64; double F_P_S=numberOfbytes/(temps2-lastTime); lastTime=temps2; numberOfbytes=0; //qDebug()<<"Worker:: get called from?: "<<QThread::currentThreadId(); }else{ numberOfbytes+=64; } lastTimeWeReceiveUSB=temps2;
}@
-
Ok... the problem is really is with my software.
Using USBlyser, I can reach up to 60KB/s, but the Qt software is missing frame. Using a break point at line 81 of the above code, I calculate delay=15ms every time even if USBlyser tells me 1.2ms.
I am using microchip hid.c file.
Thanks for your help.
-
I made some more tests. If I prevent the PollUSB function from sending or receiving commands and only measure how much time it takes between 2 successive PollUSB function it is 15ms if the device is connected and it is 1.6ms if the device is connected.
So I don't think this function is problematic.
-
OMG... found it!!
check out line 22.. it is a beautiful 15ms before start.. and it seems that was setting up a 15ms delay!
-
Now the hardest part comes in... plotting all that data in real time like an oscilloscope.