When I wrote code in usb.c to send data I did this:
(void) VCP_DataTx ( ubuf, len );This routine works with 3 global variables:
#define APP_TX_DATA_SIZE 512 volatile uint16_t APP_Tx_ptr_in = 0; volatile uint16_t APP_Tx_ptr_out = 0; uint8_t APP_Tx_Buffer [APP_TX_DATA_SIZE];The pointers are in library/usbd_cdc_core.c, the buffer is in library/usbd_cdc_core.c The buffer size is in vcp/usbd_conf.h. If we were working with the HS driver, the size would be 2048 Note that the buffer is NOT in the dedicated on-chip USB ram, that will come later.
What is going on here is that these pointers set up a software FIFO. Data gets loaded by calls to VCP_DataTx, then extracted and transmitted by routines in the driver in response to interrupts.
Two places in usbd_cdc_core.c deal with this buffer and these pointers. The first is in usbd_cdc_DataIn(). Remember that we are dealing with an IN endpoint to send data. This routine calculates how much data is in the buffer, and if the result is non-zero, it will call:
DCD_EP_Tx (pdev, CDC_IN_EP, (uint8_t*)&APP_Tx_Buffer[USB_Tx_ptr], USB_Tx_length);This is in driver/usb_dcd.c. It gets a pointer to an endpoint structure, sets up a bunch of information, and then (in our case where the endpoint is not 0) calls:
USB_OTG_EPStartXfer(pdev, ep );This routine is in driver/usb_core.c and talks to the USB hardware registers.
The second place in library/usbd_cdc_core.c that monitors these buffer pointers is the routine Handle_USBAsynchXfer(). Just like the case above, when this routine discovers there is a non-zero length waiting, it calls:
DCD_EP_Tx (pdev, CDC_IN_EP, (uint8_t*)&APP_Tx_Buffer[USB_Tx_ptr], USB_Tx_length);
This second case is handled as a result of a call to usbd_cdc_SOF() -- so in response to an SOF interrupt.
The first case is called by a "data in" event, which is a "well known thing" in the USB protocol. A callback "DataIn" is what calls us. And it is called by yet another callback "DataInStage"
This callback is called in driver/usb_dcd_int.c in the routine DCD_HandleInEP_ISR().
So, we are handling an endpoint interrupt and we see the "xfercompl" bit set. In other words, some previous transfer has completed, so the endpoint is now idle and available and we can put data on it, if we have data.
But, what if a transfer completes, we don't have data to send, so the endpoint just goes idle? That must be what the second case with the SOF interrupt takes care of. Maybe. As I understand it at this time.
Tom's Computer Info / tom@mmto.org