cancel
Showing results for 
Search instead for 
Did you mean: 

Purpose of dedicated DMA for USB and how does it work

matic
Associate III
Posted on December 06, 2016 at 20:42

Hi.

I started to work with STM32F7 series and USB HS (CDC class). I am able to send data to PC using CDC_Transmit_HS(uint8_t* Buf, uint16_t Len) function, but I am not aware what is going on behind it. If let say, I want to transmit a Buffer of 4096 bytes by CDC_Transmit_HS((uint8_t *)Buffer, 4096). Is CPU blocked while all 4096 bytes are not sent out?

Is this the case, where dedicated DMA for USB is helpful? Can someone please explain a little bit how to start transfer using DMA for USB?

Thanks a lot.

#usb #stm32f7 #usb-cdc #stm32-usb-dma
5 REPLIES 5
shingadaddy
Senior
Posted on December 06, 2016 at 22:31

I saw this in the UM1734 and it kind of caught me by surprise:

6.5.7 CDC known limitations

When using this driver with the OTG HS core, enabling DMA mode (define USB_OTG_HS_INTERNAL_DMA_ENABLED in

usb_conf.h

file) results in data being sent only by multiple of 4 bytes. This is due to the fact that USB DMA does not allow sending data from non word-aligned addresses. For this specific application, it is advised not to enable this option unless required.

And I've seen some unusual '-1' (minus one) index or count bumps in some of the code that ALSO got my attention. Maybe why you were having the 2048 trouble but no trouble with 2047 or 2049   maybe ? Sorry I can't help further.

Posted on December 06, 2016 at 22:33

Yes, the USB peripheral has its own DMA for exactly that reason.  You do not need to worry about what is going on beneath your CDC_Transmit call unless you want to re-invent what ST has provided for you.  When you call CDC_Transmit, it allocates your buffer as a source for the peripheral DMA controller to use and releases control back to your program almost immediately.  When the transmission completes, the hardware generates an interrupt which is again handled by the underlying code without any need for you to be concerned.  If you consider that the USB bus in HS mode can be running at around 400 Mbits/Sec, that's 50Mbytes per second -> 20nS per byte, or 80nS per 32 bit word.  At these rates you better use a DMA to manage the transfers with an interrupt on completion to clean things up for the next transfer.

So no, the call will not block until all 4096 bytes are sent.  It will return as soon as it sets up the DMA and the send process.  There is nothing you need to do to use the USB in DMA mode because that is the only way it works.

Posted on December 06, 2016 at 23:18

Thank you, this was helpful, but I still have a question...

If I understand you, you are saying that DMA is enabled by default and it is the only way how USB HS works.

But in the usbd_conf.c file there is a definition where it could be enabled/disabled:

USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev)

{

/* Init USB_IP */

if (pdev->id == DEVICE_HS) {

/* Link The driver to the stack */

hpcd_USB_OTG_HS.pData = pdev;

pdev->pData = &hpcd_USB_OTG_HS;

hpcd_USB_OTG_HS.Instance = USB_OTG_HS;

hpcd_USB_OTG_HS.Init.dev_endpoints = 9;

hpcd_USB_OTG_HS.Init.speed = PCD_SPEED_HIGH;

hpcd_USB_OTG_HS.Init.dma_enable = DISABLE;

hpcd_USB_OTG_HS.Init.ep0_mps = DEP0CTL_MPS_64;

hpcd_USB_OTG_HS.Init.phy_itface = USB_OTG_ULPI_PHY;

hpcd_USB_OTG_HS.Init.Sof_enable = DISABLE;

hpcd_USB_OTG_HS.Init.low_power_enable = DISABLE;

hpcd_USB_OTG_HS.Init.lpm_enable = DISABLE;

hpcd_USB_OTG_HS.Init.vbus_sensing_enable = DISABLE;

hpcd_USB_OTG_HS.Init.use_dedicated_ep1 = DISABLE;

hpcd_USB_OTG_HS.Init.use_external_vbus = DISABLE;

if (HAL_PCD_Init(&hpcd_USB_OTG_HS) != HAL_OK)

{

Error_Handler();

}

HAL_PCDEx_SetRxFiFo(&hpcd_USB_OTG_HS, 0x200);

HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_HS, 0, 0x80);

HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_HS, 1, 0x174);

}

return USBD_OK;

}

PS: Don't know how to paste it as a code.

Posted on December 06, 2016 at 23:27

So you see the 'LL' in the name of the module you are looking at?  That stands for Low Level.  If you really want to get into the weeds have fun, but I'm not interested.  If you don't believe that it is using DMA, try using a high speed hardware timer to measure the difference bewteen the start and return time when you call CDC_Transmit with a large buffer.  See if it comes back in a microsecond or two, or if it stalls for milliseconds.  You can prove to yourself what is actually going on without having to read the 5,000 lines of code in the multiple layers of the ST HAL and support middleware.

Posted on December 06, 2016 at 23:40

I am not opposing you... I came to that LL definition, because I first saw in CubeMX that there is an option under Configuration tab, to enable or disable DMA. See the attached photo... I will definitely try this with a timer...

0690X00000605lfQAA.png