I'm looking to implement ADC and DMA with HAL on a F767. I want the ADC to be always converting and storing to memory via DMA until it reaches the buffer limit of 320 and then I want to go to a conversion complete callback function. ADC seems to be enabled fine and it converts values up to the buffer limit and then it goes to the conversion callback routine. The problem I'm having is when I check the ADC buffer in the conversion complete callback function is that the first half of the ADC buffer (exactly the first half, 0 to 160) is full of these values when the ADC input is ground: enter image description here

I'd expect values anywhere from 0 to about 15 at the worst, so it is partially consistent.

When I connect the ADC to 3V I would expect close to 4096 but instead I get:

enter image description here

As the values ARE lower when the ADC is connected to ground and higher when the ADC is connected to 3V they're not completely garbage values, it's not just random values stored in memory. Also, after the first half of the buffer, everything is just zeroes so I'm thinking that maybe I've configured the ADC wrong or reading it wrong. I'm assuming that because the DMA stores the values in the array I just need to check the array during the conversion callback function but this doesn't work. The buffer size and DMA call

//this code before main #define ADC_BUFFER_LENGTH 340 //5000khz signal / 1.67 Msps = 334 samples


//this code after main but before while loop

And the ADC initialisation:

static void MX_ADC1_Init(void)

  /* USER CODE BEGIN ADC1_Init 0 */
//ADC operating @ 1.6MHz - 100MHz/4 = 25MHz
//25MHz/(12+3) = 1.67Msps
  /* USER CODE END ADC1_Init 0 */

  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC1_Init 1 */

  /* USER CODE END ADC1_Init 1 */
  /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.ScanConvMode = ADC_SCAN_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 = DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)

and my conversion callback function:

    void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
    //chop out sample window 1 and 2
    //sample window 1
    //Pulse Tx is 50 uS wide, there is a settling delay of 20us = 70us
    //with a sampling rate of 1.67Msps 70*1.67 = 119 samples
    uint32_t ADC_SW1_Temp[ADC_SW1_LENGTH] = {0};
    //30us sampled window @ 1.67Msps = 50 samples
    for(int i = 0 ; i < ADC_SW1_LENGTH; i++)
        ADC_SW1_Temp[i] = ADC_Val[(ADC_SW1_START + i)];
    ADC_SW_1 = 0;

Is there anything here that is obviously incorrect? If not, what is the best way to approach debugging of the DMA and the ADC?


It isn't a 32-bit ADC yet you are interpreting its outputs as UINT32.

Looking at your idle codes for example, 131073 = 2 ( * 2**16) + 1, or 2 and 1 if they were packed UINT16,

So those values all look fine to me.

I could do the same for the "3V" values but I'll let you do that.

  • 1
    \$\begingroup\$ riiiiight, and this explains why exactly the second half of the buffer is empty too. I mistakenly thought that the ADC used a 32 bit data register and it does - just not for a regular single channel mode that I'm using. Only half is used and the other half is reserved. Thanks \$\endgroup\$ – Christopher Dyer Apr 16 '20 at 11:08
  • \$\begingroup\$ I don't follow. Why would a presumably 12-bit ADC result in values larger than 12-bit just because the data is stored in a 32-bit array? Is that a function of the DMA? \$\endgroup\$ – Carl Gilbert Apr 16 '20 at 12:55
  • 1
    \$\begingroup\$ Packing 12 bits into 32 gets ugly. Padding to 16 bits is far more rational and allows compatibility between different ADCs. It's most probably a function of the ADC peripheral rather than the ADC : read the device datasheet for full details. \$\endgroup\$ – Brian Drummond Apr 16 '20 at 13:02

You need to enable DMA Continuous Requests!

hadc1.Init.DMAContinuousRequests = ENABLE;

And make sure that the DMA_INIT() function is called before the ADC1_Init()


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.