cancel
Showing results for 
Search instead for 
Did you mean: 

using cdc vcp with adc in dma Mode

Jamal Panah
Associate II
Posted on December 17, 2017 at 20:58

Hello,

i am trying to send data from the adc over the usb otg fs as virtual com port to my pc where i receive the data with a terminal program(HTerm).

Using the ADC in 8bit Mode works perfectly. The settings are the following:

For the ADC:

  hadc1.Instance = ADC1;

  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;

  hadc1.Init.Resolution = ADC_RESOLUTION_8B;

  hadc1.Init.ScanConvMode = DISABLE;

  hadc1.Init.ContinuousConvMode = ENABLE;

  hadc1.Init.DiscontinuousConvMode = DISABLE;

  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;

  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;

  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;

  hadc1.Init.NbrOfConversion = 1;

  hadc1.Init.DMAContinuousRequests = ENABLE;

  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

  if (HAL_ADC_Init(&hadc1) != HAL_OK)

  {

    _Error_Handler(__FILE__, __LINE__);

  }

For the DMA:

    hdma_adc1.Instance = DMA2_Stream0;

    hdma_adc1.Init.Channel = DMA_CHANNEL_0;

    hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;

    hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;

    hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;

    hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

    hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;

    hdma_adc1.Init.Mode = DMA_CIRCULAR;

    hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;

    hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;

    if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)

    {

      _Error_Handler(__FILE__, __LINE__);

    }

But now i want to use the ADC in 12bit Mode. Therefor i have to change:

For the ADC:

  hadc1.Init.Resolution = ADC_RESOLUTION_12B;

For the DMA:

    hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;

    hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;

But now the vcp is recognized as unknown device. I also found out that specially changing the DMA_PDATAALIGN_BYTE and DMA_MDATAALIGN_BYTE to DMA_PDATAALIGN_HALFWORD and DMA_MDATAALIGN_HALFWORD leads to the problem. Does someone know what i did wrong? because i can't see any connection betweeen the usb otg and the adc.

Thank You!

#usb #adc #otg #dma
1 ACCEPTED SOLUTION

Accepted Solutions
Posted on December 20, 2017 at 10:19

Can someone explaine why the 'define dereective works but not len=sizeof(adc_array) ??

Check the semantics of

sizeof

.

It returns the size in 'chars' (equal to bytes here) and NOT in elements (uint16_t).

View solution in original post

3 REPLIES 3
Jamal Panah
Associate II
Posted on December 20, 2017 at 10:08

I found the mistake. First the adc converts the value and stores it in the 16-bit long ADC_DR register. The real adc value is 12bits and the remaining 4 bits are trash. We have to set the DMA source peripherie data size to 16bit and also the destination DMA memory data size to 16bit.

  1.     hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;  

  2.     hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; 

Now we have to define an Array where we store the adc values. Since you chosed the DMA destination memory size as HALFWORD, the datatype of the Array needs to be uint16_t. Next you have to set the length of the Array therefor use the #define derective. I don't know why but if you use something like:

  1.     uint16_t    len=sizeof(adc_array);

and put this into:

  1.     HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_array, len)

it won't work.

Instead do it with the define derective:

  1.     #define ARRAYSIZE100

  1. HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_array, ARRAYSIZE);

For the transfer you can use something like:

  1.     (void)CDC_Transmit_FS((uint8_t*)adc_array, (2*ARRAYSIZE));

Because the CDC Transmit function only works with uint8_t we have to tell the function that the adc_array is uint8_t but twice the size of ARRAYSIZE.

Can someone explaine why the 'define dereective works but not len=sizeof(adc_array) ??

Posted on December 20, 2017 at 10:19

Can someone explaine why the 'define dereective works but not len=sizeof(adc_array) ??

Check the semantics of

sizeof

.

It returns the size in 'chars' (equal to bytes here) and NOT in elements (uint16_t).

leonsk
Associate II

Hi,

I'm working on similar project, I want to transfer 4000 string values from ADC buffer to PC, but I have two problem.

First problem is that the data were lost during transfer. Sometimes I receive almost every data (4000 string), sometimes I lost nearly 500 string data.

The second problem is that transfer doesn't reach speed of 12Mbps.

Do you have any idea what can be wrong? How do you transfer data from MCU to PC?