USB - sync vs async vs semi-async

Update:

I wrote an asynchronous version of C, and it works as it should.

Turns out the speed issue is related to the Python GIL. There is a way to fine-tune its behavior. sys.setcheckinterval (interval)

The tuning interval to zero (the default is 100) fixes the problem at a slow speed. Now all that remains is to find out what causes another problem (not all pixels are full). It makes no sense. usbmon shows that all communications go through. Debugging libusb messages doesn't show anything unusual. I think I need to take usbmon output and compare sync vs async. The data shown on the usbmon display seems correct at first glance (the first byte should be 0x96 or 0x95).

As stated below in the original question, S. Lott, this is for the USB LCD controller. There are three different versions of drv_send, which are the outgoing final methods. I explained the differences below. Perhaps this will help if I describe asynchronous USB operations. Please note that synchronous operations with USB work the same way, just so that this happens synchronously.

We can consider asynchronous I / O as a five-step process:

  • Highlight: highlight libusb_transfer (this is self.transfer)
  • Filling: fill in the libusb_transfer instance with the transfer information you want to complete (libusb_fill_bulk_transfer)
  • View: ask libusb to transfer the transfer (libusb_submit_transfer)
  • Termination Handling: Check the transfer results in the libusb_transfer structure (libusb_handle_events and libusb_handle_events_timeout)
  • Exemption: resource cleanup (not shown below)

The original question:

I have three different versions. One is fully synchronous, one is semi-asynchronous and the last is completely asynchronous. The differences are that the synchronous one completely fills the liquid crystal display, which I control with the expected pixels, and it is very fast . The semi-asynchronous version fills only part of the display , but is still very fast . The asynchronous version is very slow and fills only part of the display. I am confused why the pixels are not full and why the asynchronous version is very slow. Any clues?

Here's a fully synchronous version:

def drv_send(self, data): if not self.Connected(): return self.drv_locked = True buffer = '' for c in data: buffer = buffer + chr(c) length = len(buffer) out_buffer = cast(buffer, POINTER(c_ubyte)) libusb_fill_bulk_transfer(self.transfer, self.handle, LIBUSB_ENDPOINT_OUT + 1, out_buffer, length, self.cb_send_transfer, None, 0) lib.libusb_submit_transfer(self.transfer) while self.drv_locked: r = lib.libusb_handle_events(None) if r < 0: if r == LIBUSB_ERROR_INTERRUPTED: continue lib.libusb_cancel_transfer(transfer) while self.drv_locked: if lib.libusb_handle_events(None) < 0: break self.count += 1 

Here's the semi-asynchronous version:

 def drv_send(self, data): if not self.Connected(): return def f(d): self.drv_locked = True buffer = '' for c in data: buffer = buffer + chr(c) length = len(buffer) out_buffer = cast(buffer, POINTER(c_ubyte)) libusb_fill_bulk_transfer(self.transfer, self.handle, LIBUSB_ENDPOINT_OUT + 1, out_buffer, length, self.cb_send_transfer, None, 0) lib.libusb_submit_transfer(self.transfer) while self.drv_locked: r = lib.libusb_handle_events(None) if r < 0: if r == LIBUSB_ERROR_INTERRUPTED: continue lib.libusb_cancel_transfer(transfer) while self.drv_locked: if lib.libusb_handle_events(None) < 0: break self.count += 1 self.command_queue.put(Command(f, data)) 

Here is a fully asynchronous version. device_poll is in the thread by itself.

 def device_poll(self): while self.Connected(): tv = TIMEVAL(1, 0) r = lib.libusb_handle_events_timeout(None, byref(tv)) if r < 0: break def drv_send(self, data): if not self.Connected(): return def f(d): self.drv_locked = True buffer = '' for c in data: buffer = buffer + chr(c) length = len(buffer) out_buffer = cast(buffer, POINTER(c_ubyte)) libusb_fill_bulk_transfer(self.transfer, self.handle, LIBUSB_ENDPOINT_OUT + 1, out_buffer, length, self.cb_send_transfer, None, 0) lib.libusb_submit_transfer(self.transfer) self.count += 1 self.command_queue.put(Command(f, data)) 

And here, where the line is empty. This is a callback for gobject timeout.

 def command_worker(self): if self.drv_locked: # or time.time() - self.command_time < self.command_rate: return True try: tmp = self.command_queue.get_nowait() except Queue.Empty: return True tmp.func(*tmp.args) self.command_time = time.time() return True 

Here's the transfer callback. It simply changes the lock state to false, indicating that the operation is complete.

 def cb_send_transfer(self, transfer): if transfer[0].status.value != LIBUSB_TRANSFER_COMPLETED: error("%s: transfer status %d" % (self.name, transfer.status)) print "cb_send_transfer", self.count self.drv_locked = False 
+4
source share
1 answer

Well, I don't know if I'm right. You have a device with an LCD display, you have firmware to handle USB requests. On the PC side, you are using PyUSB, which wraps libUsb.

A few suggestions, if you are experiencing speed problems, try to limit the data that you transfer. Do not transfer whole raw data, only changed pixels can.

Secondly, you measured the transfer speed using some software for the USB analyzer, if you do not have money for a hardvare usb analyzer, perhaps try the software version. I have never used such analyzers, but I think that the data provided by them is not very reliable.

Thirdly, see which device really works, perhaps this is a bottleneck in your data transfer.

I don’t have much time to accurately answer your question, so I will come back to this later.

I have been watching this topic for some time, and there is dead silence around, so I tried to save time and look deeper. Today there is still not so much, maybe today and today. Unfortunately, I am not a python expert, but I know something about C, C ++, Windows, and most of all USB. But I think that it could be a problem with the LCD device that you are using, because if the transfer is working fine and the data has been restored by the device, this indicates a device problem.

I looked at your code a bit, could you do some testing by sending only 1 byte, 8 bytes and the byte length of the endpoint length. And look how it looks on USB mon?

Endpoint size is the size of the Hardvare buffer used by the USB PICO LCD controller. I'm not sure if this is for you, but I assume that when you send a message about the size of ENDpoint, the next masage should be 0 bytes long. There may be a problem. As for the test, I assume that you saw the data that you programmed to send. The second thing may be that the data is overwritten or not received fast enough. Speaking of rewriting, I mean that the LCD cannot see the data at the end and mix one transmission with another.

I'm not sure what USB mon is capable of showing, but according to the USB standard, after a len endpoint length packet, 0 len packet data should be sent, indicating that this is the end of the transfer.

+1
source

All Articles