Skip to main content
MNapi
Senior II
February 23, 2019
Question

Any ideas why I get those 0 - 65500 values from adc ?

  • February 23, 2019
  • 6 replies
  • 1429 views

I have

uint16_t array[2000];

HAL_ADC_Start_DMA(&hadc1, (uint32_t*)array, 2000);

I get values from 0 up to 65535

but when I declare

uint8_t array[2000];

I get values 0-255

I shouldn't be bigger than 4095 since it is 12 bit resolution for ADC

I have STM32L416KBU6

I do not have the problem with STM32F446RE

This topic has been closed for replies.

6 replies

Tesla DeLorean
Guru
February 23, 2019

Depends on the 12-bit being left or right aligned, you can pick either. Left aligned would have the 12-bits in the high order bits of a 16-bit word, and thus up to 65500 ish.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
MNapi
MNapiAuthor
Senior II
February 23, 2019

I tried left and right the same no change

S.Ma
Principal
February 23, 2019

How the ADC is configured? It could be the DMA is wrongly configured, could be direction or wrong ADC number. Have you also aligned the 16 bit array to a even address number? (#pragma or align keyword, compiler dependent).

MNapi
MNapiAuthor
Senior II
February 23, 2019

I do not see anything wrong in ADC setting I use Cube MX

static void MX_ADC1_Init(void)

{

 /* USER CODE BEGIN ADC1_Init 0 */

 /* USER CODE END ADC1_Init 0 */

 ADC_MultiModeTypeDef multimode = {0};

 ADC_ChannelConfTypeDef sConfig = {0};

 /* USER CODE BEGIN ADC1_Init 1 */

 /* USER CODE END ADC1_Init 1 */

 /**Common config

 */

 hadc1.Instance = ADC1;

 hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;

 hadc1.Init.Resolution = ADC_RESOLUTION_12B;

 hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;

 hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;

 hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;

 hadc1.Init.LowPowerAutoWait = DISABLE;

 hadc1.Init.ContinuousConvMode = ENABLE;

 hadc1.Init.NbrOfConversion = 1;

 hadc1.Init.DiscontinuousConvMode = DISABLE;

 hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;

 hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;

 hadc1.Init.DMAContinuousRequests = ENABLE;

 hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;

 hadc1.Init.OversamplingMode = DISABLE;

 if (HAL_ADC_Init(&hadc1) != HAL_OK)

 {

   Error_Handler();

 }

 /**Configure the ADC multi-mode

 */

 multimode.Mode = ADC_MODE_INDEPENDENT;

 if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)

 {

   Error_Handler();

 }

 /**Configure Regular Channel

 */

 sConfig.Channel = ADC_CHANNEL_5;

 sConfig.Rank = ADC_REGULAR_RANK_1;

 sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5;

 sConfig.SingleDiff = ADC_SINGLE_ENDED;

 sConfig.OffsetNumber = ADC_OFFSET_NONE;

 sConfig.Offset = 0;

 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)

 {

   Error_Handler();

 }

 /* USER CODE BEGIN ADC1_Init 2 */

 /* USER CODE END ADC1_Init 2 */

}

S.Ma
Principal
February 24, 2019

Look at ADC + DMA examples for the closest Nucleo board and narrow down what's different.

Maybe the ADC or DMA IP is slightly different between both STM32 families and copy/paste requires code edits. This happened between STM32L496 and STM32L4R5 for DMAMUX and EXTI.

Nix Wayne
Associate III
February 25, 2019

I think you have problem with data alignment.

Have a look at my union declaration which I use to assign to DMA call and to extract proper data when conversion is done. This is example for 3 channels.

typedef union
{
 uint32_t data[2];
	
	struct 
	{
	 uint16_t channels[4];	
	} fields;
	
} adc_buffer_s;

So my DMA call looks like:

HAL_ADC_Start_DMA(&adc.hadc1, cnv_buffer.data, 3);

where

// buffer 
adc_buffer_s cnv_buffer;

And then I get data out of buffer by accessing fields in this way:

// first channel
cnv_buffer.fields.channels[0]
 
// second channel
cnv_buffer.fields.channels[1]
 
// third channel
cnv_buffer.fields.channels[2]

A short explanation:

We have 3 channels... each channel has 16 bit data and this results in 6 bytes (3x 2bytes)... but DMA demands pointer to 32bit buffer... so we have to reserve 2x 32 bits which is enough for 4 channels. So there will be one left empty.

Why I am using union in such way? Because data will be written and aligned into memory in a such way that accesing cnv_buffer.fields.channels[X] will already give me back properly aligned data and I can avoid any additional operations to compose data when not using union.

I hope this helps.