March 20, 2025

Black Pill boards - F411 USB -- USB classes - VCP

The software we are working with has a directory "vcp" that holds both the CDC and VCP specific class suport files.

The current question is, "what is the class interface?". How hard will it be to swap another class in place of this? How clean is the interface?

The first thing to do is to omit the files in this directory from the link and see what things come up missing. These are things that are referenced from elsewhere (hopefully only in library).

rm-none-eabi-ld.bfd: main.o: in function `xfer_test':
main.c:(.text+0x214): undefined reference to `usb_hookup'

arm-none-eabi-ld.bfd: usbf4.o: in function `usb_init':
(.text+0x84): undefined reference to `USR_desc'

arm-none-eabi-ld.bfd: usbf4.o: in function `usb_puts':
(.text+0xe4): undefined reference to `VCP_DataTx'

arm-none-eabi-ld.bfd: usbf4.o: in function `usb_write':
(.text+0xf4): undefined reference to `VCP_DataTx'

arm-none-eabi-ld.bfd: usbf4.o: in function `usb_test_send':
(.text+0x12e): undefined reference to `VCP_DataTx'

arm-none-eabi-ld.bfd: usbf4.o: in function `usb_read':
(.text+0x13c): undefined reference to `VCPGetBytes'

arm-none-eabi-ld.bfd: usbf4.o: in function `usbd_cdc_EP0_RxReady':
usbd_cdc_core.c:(.text+0x14bc): undefined reference to `VCP_fops'
arm-none-eabi-ld.bfd: usbf4.o: in function `usbd_cdc_DataOut':
usbd_cdc_core.c:(.text+0x161c): undefined reference to `VCP_fops'
arm-none-eabi-ld.bfd: usbf4.o: in function `usbd_cdc_Setup':
usbd_cdc_core.c:(.text+0x16d0): undefined reference to `VCP_fops'
arm-none-eabi-ld.bfd: usbf4.o: in function `usbd_cdc_DeInit':
usbd_cdc_core.c:(.text+0x1708): undefined reference to `VCP_fops'
arm-none-eabi-ld.bfd: usbf4.o: in function `usbd_cdc_Init':
usbd_cdc_core.c:(.text+0x1754): undefined reference to `USBD_DeviceDesc'
arm-none-eabi-ld.bfd: usbd_cdc_core.c:(.text+0x1758): undefined reference to `VCP_fops'
This actually turns out more nicely than I thought it would. We have a variety of "direct calls" to VCP routines for things like usb_puts, usb_hookup, and such. These should be abstracted into generic routines that each class provides.

We have the reference during initialization to USR_desc. We should reengineer this so it is handled much like fops.

The rest of the calls are then via VCP_fops, which is a callback structure, just as things should be.

What about include files? We can just use grep to investigate.
We see these references from files in the "library" directory:

usbd_core.h:// #include 
usbd_def.h:// #include 
usbd_req.h:// #include  
I comment out these references one by one and it turns out that none of them are required. The code compiles just fine with all of them commented out.

Next I rename the "vcp" directory to "vvvvcp" to expose any dependencies on it that I had not yet discovered. And I find several:

usb.c:20:10: fatal error: vcp/usbd_cdc_core.h: No such file or directory
#include 
#include 
This file has two includes, as shown above. These supply the following:
usb.c:101:14: error: 'USR_desc' undeclared (first use in this function)
  101 |             &USR_desc,
usb.c:102:14: error: 'USBD_CDC_cb' undeclared (first use in this function)
  102 |             &USBD_CDC_cb,
Indeed, these are supplied, one each, by the include files mentioned:
usbd_desc.h:extern  USBD_DEVICE USR_desc;
usbd_cdc_core.h:extern USBD_Class_cb_TypeDef  USBD_CDC_cb;

Links for when the day comes

Conclusion

The class interface is much cleaner than I suspected.
The device interface on the other hand is woven through everything.
Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org