cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 ADC Scan conversion is not working.

Patrick Morwald
Associate II
Posted on March 20, 2018 at 16:09

Hi,

i have an ADC where i want to read multiple channels sequentially and than use this data. I read them every second or so, so i want to start the reading manually each time. But when its started it should read all the assigned channels. 

Unfortunately, with the configuration below, it only seems to read the first channel and not going through the sequence of channels. This is my initialization code:

ADC_ChannelConfTypeDef sConfig;

/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)

*/

hadc2.Instance = ADC2;

hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;

hadc2.Init.Resolution = ADC_RESOLUTION_12B;

hadc2.Init.ScanConvMode = ENABLE;

hadc2.Init.ContinuousConvMode = DISABLE;

hadc2.Init.DiscontinuousConvMode = DISABLE;

hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;

hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;

hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;

hadc2.Init.NbrOfConversion = 2;

hadc2.Init.DMAContinuousRequests = DISABLE;

hadc2.Init.EOCSelection = ADC_EOC_SEQ_CONV;

if (HAL_ADC_Init(&hadc2) != HAL_OK)

{

_Error_Handler(__FILE__, __LINE__);

}

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

*/

sConfig.Channel = ADC_CHANNEL_12;

sConfig.Rank = 1;

sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;

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

{

_Error_Handler(__FILE__, __LINE__);

}

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

*/

sConfig.Channel = ADC_CHANNEL_13;

sConfig.Rank = 2;

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

{

_Error_Handler(__FILE__, __LINE__);

}

And this is my loop where i call a reading and the callback function:

while (1)

{

HAL_ADC_Start_IT(&hadc2);

HAL_Delay(4000);

}

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef * hadc){

if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOC))

{

// ADC_raw[0] = HAL_ADC_GetValue(hadc);

if (indexer < 2){

ADC_raw[indexer] = HAL_ADC_GetValue(hadc);

indexer++;

}

else {

vdd_a = ((float)ADC_raw[0] * 3.3) / 4095;

}

}

}

Please help.

#adc-scan-continuous #adc #stm32f4
8 REPLIES 8
Posted on March 20, 2018 at 16:47

Scan mode would typically use DMA into an array, I've posted clear and simple SPL examples of this, the HAL is a circuitous fuster cluck, but might be some workable examples under the code trees.

Normally you'd use a TIM to directly trigger the ADC at 1Hz, and review both samples in the DMA TC interrupt.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on March 20, 2018 at 17:13

Hi, thanks for the answer. I dont want to use a TC interrupt, since this 1s interval is just an example. In reality i have a high level software module that initiates the measurements.

I measure two channels at rather low frequency so i am not sure if DMA is necessary? If you say the scan function is not easily achievable with HAL (maybe HAL has missing features here..) what would be the easiest solution to do it (no polling though)

Regards,

Patrick

Posted on March 20, 2018 at 17:58

ST's multiple sample methodology is heavily predicated on the use of DMA, due to the potentially rapid rate of sample delivery, and the ability to get out of sequence in the overrun case. The module does not output any rank data, it just cycles. Many people have wasted a lot of time on the EOC approach. The DMA TC is the equivalent to EOC-on-ALL, if you can spin on ADC EOC you can spin on DMA TC. Or use the IRQ, or call-backs that they initiate.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Bill Dempsey
Senior
Posted on March 21, 2018 at 04:43

I do something very similar to what you are doing but I start off from a timer vs software (your method should be fine...)

After the sequence runs I get an interrupt and retrigger and go again from the main code.   Look at my conv complete routine -- that is where I flag the restart for the main code.  

Here are the only lines that appear different. 

hadc2.Init.DiscontinuousConvMode = ENABLE;

adc2.Init.NbrOfDiscConversion   = 1;

hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)

{

/* Get the converted value of regular channel */

adcStatus[loopct] = AdcHandle->Instance->SR;

if(adcStatus[loopct] & 0x20)

{

HAL_ADC_ErrorCallback(AdcHandle);

return;

}

adcCapture[loopct] = HAL_ADC_GetValue(AdcHandle);

loopct++; intCount++;

if(loopct >= ADC_NUM_CHAN)

{

loopct=0;

}

restartADC = true;

}

Posted on March 21, 2018 at 15:00

Can you point me to those examples? Thanks

Posted on March 21, 2018 at 15:09

The F4 DSP package and especially the F4 Discover firmware package used to contain several examples using ADC together with DMA.

However, mostly just one ADC channel, and often in continuous conversion mode.

I used these examples as starting point for my projects.

Posted on March 22, 2018 at 10:48

Hi,

i think i got it running now by doing this:

void CIP_EC_Init(ECManagerDataTypeDef * ec){

/** For this quick init code and using the scan mode, make sure

* that both ADC channels are on the same ADC block

*/

Q_REQUIRE(ec->adc_handle_ec == ec->adc_handle_thermo);

/** Initialize ADC component */

ADC_ChannelConfTypeDef sConfig;

/** Configure the global features of the ADC (Clock, Resolution,

* Data Alignment and number of conversion)

*/

hadc2.Instance = ADC2;

hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;

hadc2.Init.Resolution = ADC_RESOLUTION_12B;

hadc2.Init.ScanConvMode = ENABLE;

hadc2.Init.ContinuousConvMode = DISABLE;

hadc2.Init.DiscontinuousConvMode = DISABLE;

hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;

hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;

hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;

hadc2.Init.NbrOfConversion = 2;

hadc2.Init.DMAContinuousRequests = DISABLE;

hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

if (HAL_ADC_Init((ADC_HandleTypeDef *)ec->adc_handle_ec) != HAL_OK)

{

Q_ERROR();

}

/** Configure for the EC ADC regular channel its corresponding rank

* in the sequencer and its sample time.

*/

sConfig.Channel = ec->adc_channel_ec;

sConfig.Rank = 1;

/** Sampling takes T_conf = sampling_time + 12 cycles.

* At 480 cycles sampling time we need a total of 492 cycles

* At 186 MHz, this needs 2.93 micro seconds.

*/

sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;

if (HAL_ADC_ConfigChannel((ADC_HandleTypeDef *)ec->adc_handle_ec, &sConfig) != HAL_OK)

{

Q_ERROR();

}

/** Configure for the temperature ADC regular channel its corresponding rank

* in the sequencer and its sample time.

*/

sConfig.Channel = ec->adc_channel_thermo;

sConfig.Rank = 2;

if (HAL_ADC_ConfigChannel((ADC_HandleTypeDef *)ec->adc_handle_ec, &sConfig) != HAL_OK)

{

Q_ERROR();

}

static QEvt const setupDone = {EC_SETUP_DONE_SIG, 0, 0};

QACTIVE_POST(AO_ECManager, &setupDone, (void *)0);

}

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef * hadc){

/** Check if the interrupt flag is a EOC flag */

if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOC))

{

if (channel_position < EC_PROBE_CHANNEL_COUNT){

raw_results[channel_position] = HAL_ADC_GetValue(hadc);

channel_position++;

}

else {

/** Reset channel position to the first channel */

channel_position = 0;

//TODO: calculate the data

}

}

}

It reads two channels and transfers the raw results two a small array. Do you see any problems with this?

New.Fish
Associate III

The F4 examples only has one ADC channel, what will happen if has multiply channel.

In Scan Mode, for multiply channel, there is only one ADC_SR register, one ADC_DR register, if EOC interrupt occurs, how can read each channel's converted data?

HAL_ADC_GetValue(hadc) only return the channel with "sConfig.Rank = 1" ?