cancel
Showing results for 
Search instead for 
Did you mean: 

which channel which data

Ehsan Behravan
Associate II
Posted on May 06, 2017 at 13:34

Hi there. i have a question about stm32f745 adc. When we use ADC in Scan mode,Continuous,Regular with Interrupt, how to detect which data is for which channel. eos flag bit is not considered in this chip. I have to use counter to know end of all conversions.it's true but i think it's not reliable. my Software and Configuration is:

Configuration:

static void MX_ADC1_Init(void)

{

ADC_ChannelConfTypeDef sConfig;

/**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 = ENABLE;

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 = 3;

hadc1.Init.DMAContinuousRequests = DISABLE;

hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

if (HAL_ADC_Init(&hadc1) != HAL_OK)

{

Error_Handler();

}

/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.

*/

sConfig.Channel = ADC_CHANNEL_4;

sConfig.Rank = 1;

sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;

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

{

Error_Handler();

}

/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.

*/

sConfig.Channel = ADC_CHANNEL_5;

sConfig.Rank = 2;

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

{

Error_Handler();

}

/**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.

*/

sConfig.Channel = ADC_CHANNEL_6;

sConfig.Rank = 3;

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

{

Error_Handler();

}

}

-------------------------------------------------------------------------------------------

Software:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)

{

ADCValue[i]=HAL_ADC_GetValue(hadc);

i++;

if (i==3)

{

i=0;

}

}

Note: this post was migrated and contained many threaded conversations, some content may be missing.
9 REPLIES 9
Posted on May 07, 2017 at 03:19

Well the idea is that you DMA into an array which is a multiple of the sample count, and then get an interrupt when that is full, or half full, and the array is all nicely aligned.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on May 07, 2017 at 07:17

Thanks for your reply.

I didn't use DMA. is there any way without DMA??

i have to use counter for detecting which adc channel generated this data.

is there any flag register that determine active adc channel or something like this??

thanks alot

Posted on May 07, 2017 at 08:24

If using ADC normal channels, all share a single DR per ADC. DMA is the right plumbing when continuous data flow is happening. 3 ADC for 3 DMA channels going to 3 memory buffers, if running independentlt.  Otherwise, there are some ADC flavors with injected channels which have one DR per input on some STM32.

Posted on May 07, 2017 at 09:27

Thanks for your help. I'm going to work with DMA.

Posted on November 28, 2017 at 11:50

Hi,

Sorry to dig into an old post.

I have configured ADC - 1 channel with DMA to retrieve data. It all works fine. 

Now, I am trying to use the same ADC (ADC1, DMA2_Stream0) to use 2 channels (channel 12 and 13). 

uint16_t ADC_Value[2] = {0,0}; //the user variable for retrieving ADC data from 2 channels

 DMA_InitStructure.DMA_Channel =DMA_Channel_0;

 DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t)&ADC1->DR;

 DMA_InitStructure.DMA_Memory0BaseAddr =(uint32_t)&ADC_Value;

 DMA_InitStructure.DMA_DIR =DMA_DIR_PeripheralToMemory;

 DMA_InitStructure.DMA_BufferSize =2; // increase the buffer size for multi-channels

 DMA_InitStructure.DMA_PeripheralInc =DMA_PeripheralInc_Disable;

 DMA_InitStructure.DMA_MemoryInc =DMA_MemoryInc_Enable; //Enabling the memory increment

 DMA_InitStructure.DMA_PeripheralDataSize =DMA_PeripheralDataSize_HalfWord;

 DMA_InitStructure.DMA_MemoryDataSize =DMA_MemoryDataSize_HalfWord;

 DMA_InitStructure.DMA_Mode =DMA_Mode_Circular;

 DMA_InitStructure.DMA_Priority =DMA_Priority_High;

 DMA_InitStructure.DMA_FIFOMode =DMA_FIFOMode_Disable;

 DMA_InitStructure.DMA_FIFOThreshold =DMA_FIFOThreshold_HalfFull;

 DMA_InitStructure.DMA_MemoryBurst =DMA_MemoryBurst_Single;

 DMA_InitStructure.DMA_PeripheralBurst =DMA_PeripheralBurst_Single;

 DMA_Init(DMA2_Stream0, &DMA_InitStructure);

 DMA_Cmd(DMA2_Stream0, ENABLE);

 /* ADC1 Init ****************************************************************/

 ADC_InitStructure.ADC_Resolution =ADC_Resolution_12b;

 ADC_InitStructure.ADC_ScanConvMode =ENABLE;  // Single channel or Multiple channels (ENABLE)

 ADC_InitStructure.ADC_ContinuousConvMode =ENABLE;

 ADC_InitStructure.ADC_ExternalTrigConvEdge =ADC_ExternalTrigConvEdge_None;

 ADC_InitStructure.ADC_ExternalTrigConv =ADC_ExternalTrigConv_T1_CC1;

 ADC_InitStructure.ADC_DataAlign =ADC_DataAlign_Right;

 ADC_InitStructure.ADC_NbrOfConversion =2; // INCREASE for multiple channels

 ADC_Init(ADC1, &ADC_InitStructure);

Firstly, I'd like to know if my settings are correct. And secondly, Can someone explain me how exactly the result variable (array) is filled with ADC data from the DR? 

Thanks a lot.

Posted on November 28, 2017 at 17:27

Filled one word at a time, in Rank order as configured.

I would NOT use two entries, better to use more, and allow the HT/TC DMA interrupts determine what half of the buffer was stable.

Variable should be volatile as changed outside of execution flow.

Prefer (uint32_t)&ADC_Value[0]

Sequencing might get muddled if ADC calibration attempted

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on November 28, 2017 at 17:49

'Filled one word at a time, in Rank order as configured.'  I Understand.

'I would NOT use two entries, better to use more, and allow the HT/TC DMA interrupts determine what half of the buffer was stable.

'

Ok, so  I will increase the DMA buffer as suggested.

'

Variable should be volatile as changed outside of execution flow.

'

Sorry, yes it should be volatile.

'

Sequencing might get muddled if ADC calibration attempted

'

Ok, so far, I have not tried to calibrate the ADC.

'

Prefer (uint32_t)&ADC_Value[0]

'

Sorry, but I don't understand here, Why should we update only the first index of the array?

Posted on November 28, 2017 at 18:02

>>Sorry, but I don't understand here, Why should we update only the first index of the array?

Because it is explicitly the address of the first entry in the array and the DMA steps forward from there.

ADC_Value would work, as does &ADC_Value[0], where as &ADC_Value can mean something else depending on context, ie if it is a pointer

Casting removes any kind of warning you might get.

I prefer it, it conveys intent.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on December 02, 2017 at 17:14

Hi Clive,

Thanks for enlightening me.

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1_DR;

DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_values[0];

when we declare our variable ADC_values as uint16_t, why do we typecast here?

From the RM,

'ADC1_DR is a 16 bit register, and the AHB slave port is used to program the DMA controller (it supports only 32-bit

accesses).'

Is my understanding correct?

Thanks.