dmitrystu / libusb_stm32

Lightweight USB device Stack for STM32 microcontrollers
Apache License 2.0
707 stars 160 forks source link

Isochronous IN (TX) without double-buffer #59

Closed Seneral closed 4 years ago

Seneral commented 4 years ago

I am using the STMF103 to implement a 50 to 300 byte transfer every 10 to 25ms to a host PC. Currently, isochronous transfers have to be double-buffered - however since the PMA is limited to 512bytes on the STMF103, this means the isochronous packet size is in turn limited to less than 256bytes. For my case, together with control ep, I could only have one double-buffered isochronous ep with a packet size of 224bytes if my understanding is correct. While my design is flexible, I would prefer one large transfer over multiple smaller ones, mostly due to latency, so one larger buffer is preferrable to me. Since I'm only sending at max every 10ms I do not expect to need the second buffer. Would it be possible to change this behaviour or is this a hardware limitation? Currently I'm still in the phase where I don't need the bigger transfers, but I'd be interested to know for the future.

dmitrystu commented 4 years ago

AFAIK ISO EP double buffering for the F103 and similar USBFS can't be disabled due to hardware design. Anyway, let me check the docs.

dmitrystu commented 4 years ago

Yes. See RM008 Section 23.4.4 "Isochronous transfers"

Seneral commented 4 years ago

Thank you for pointing me in the right direction. Seems clear that it is not intended to be used using a single buffer, and any possible solution will be non-standard.

However, for future reference, I might try these two things:

  1. Set TX_0 and TX_1 to the same packet buffers, without any other additional action taken. Hardware toggle of DTOG should have no effect then, however behaviour might be undefined
  2. Set one adress field to a small separate buffer and then manually toggle DTOG when I'm ready to send again, unless I want it to it shouldn't have to do anything with the small buffer

Will comment when I did try, but probably won't do for at least a few months.

Seneral commented 4 years ago

I have a related followup, not sure if it is an issues per se though. The TX pma buffers are not cleared after an isochronous IN transfer has been completed, resulting in the same data being send 2 frames afterwards if you do not explicitly overwrite the PMA. I adressed this by a usbd_ep_write(usbd, ep, NULL, 0); call in the isochronous TX callback. Since all it needs to do is reset the PMA buffer count COUNTn_TX_x, this works as well:

if (!(*reg & USB_EP_DTOG_TX)) {
    tbl->tx1.cnt = 0;
} else {
    tbl->tx0.cnt = 0;
}

Since the TX callback is fired right when the DTOG is toggled (according to RM008), the usb driver user shouldn't have had the chance to write to the buffer yet, so I think this is a safe addition to the libusb_stm32 core (for isochronous transfers IN). This results in only the isochronous transfer immediately after a usbd_ep_write call to send the data, as expected.

On an unrelated note, I would think that a WCID example might be helpful. I recently implemented it and while it didn't take terribly long, it's simple copy-paste code that would be nice to have as an example, since I assume many people will be using WinUSB for windows. There are only two requests to cover and some custom data structures. If you want, I can create a simple example.