We have seen that usb_printf() does the job for writing data. We should dig into it in detail eventually. But what about reading data? When we type a character into picocom, we see the following chatter on our console:
USBint - Rx level Endpoint 0, read packet 1 bytes from FIFO USBint - Rx level USBint = OUT Endpoint 1 xfer complete VCP_DataRx 1 - EP 1 StartXfer 64 bytesAll of these are debug messages, generated by printf statements that I sprinkled (back in 2021) through the source code.
The first -- USBint - Rx level -- comes from usbF4/driver/usb_dcd_int.c in the routine USBD_OTG_ISR_Handler(). We have seen a USB interrupt and the status register has "rxstsqlvl" set. This will be handled by a call to DCD_HandleRxStatusQueueLevel_ISR().
The next -- Endpoint 0, read packet 1 bytes from FIFO -- comes from usbF4/driver/usb_core.c in the routine USB_OTG_ReadPacket(). Are we sure this is on endpoint 0? I think this could be any endpoint and is almost surely endpoint 1 in this case.
The next -- USBint - Rx level -- is just like the first, another interrupt indicating data.
The next -- USBint = OUT Endpoint 1 xfer complete -- is from usbF4/driver/usb_dcd_int.c in the routine DCD_HandleOutEP_ISR()
Then we get: -- VCP_DataRx 1 -- from usbF4/vcp/usbd_cdc_vcp.c in the routine VCP_DataRx(). Our single byte of data has been passed up to the higher VCP layer to be handled. It goes into a receive buffer (unless a read_hook exists to claim it). If the buffer is full, reception on the endpoint will be disabled.
Last of all, we get: -- - EP 1 StartXfer 64 bytes -- from usbF4/driver/usb_core.c in the routine USB_OTG_EPStartXfer() This looks like it is preparing the endpoint to receive more data?
Now I don't understand why, but we get a second level interrupt.
Now we get yet another interrupt, but not a level interupt this time. This one is "outepintr" and gets handled by DCD_HandleOutEP_ISR(). The situation is "transfer complete" and the path to VCP_DataRx() is far from simple.
What about usb_read_hook? This is something I added so that Hydra can ask for an upcall when data is received. It can be set via "usb_hookup ( func )". I set a hook, and when I type an "x" I now see this:
- EP 1 StartXfer 64 bytes USBint - Rx level Endpoint ??, read packet 1 bytes from FIFO USBint - Rx level USBint - OUT Endpoint USBint = OUT Endpoint 1 xfer complete VCP_DataRx 1 Hydra USB got: 1 x
Note the message: "Endpoint ??, read packet 1 bytes from FIFO". I don't think this read is for any specific endpoint (and it must be for endpoint 1 in this case). I'll need to study the manual more, but I think there is only one Rx FIFO for all endpoints.
We can also use the stm32duino USB driver to learn things. However we need a more in depth understanding both of the F411 USB hardware and the structure of the stm32duino USB driver to get much out of this.
Tom's Computer Info / tom@mmto.org