Skip to main content
FDrab.1
Associate
July 3, 2020
Solved

ADC with DMA in discontinuous mode samples first rank twice (STM32F103)

  • July 3, 2020
  • 10 replies
  • 8886 views

Hi,

I want to use an ADC with DMA in a STM32F103. I configured it in Cube as you can see in the following picures.

When I start the conversion with

HAL_ADC_Start_DMA(&hadc1,(uint32_t*)AdcData,5);

HAL_ADC_ConvCpltCallback() is called and I see that the AdcData values all changed.

Unfortunately the first rank is sampled twice and the last rank is lost.

I tried to extend the DMA length to 6 but then I do not receive the callback.

I tried to extend the DMA length to 4 but then the last AdcData is unchanged.

Has anybody an idea why this happens and how I can get rid of this?

0693W000001s5D7QAI.jpg0693W000001s595QAA.jpg0693W000001s590QAA.jpg

This topic has been closed for replies.
Best answer by FDrab.1

Now I found out that the false ADC conversion is triggered by setting the DMA bit when it is already set. Somehow the HAL does not clear this bit at the end of conversion.

I added

hadc1.Instance->CR2 &= ~ADC_CR2_DMA;

to my code after the conversion finished and now it works as expected.

But this is not a good solution.

EDIT:

I now searched for the ADC_CR2_DMA bi in the HAL source file and found

CLEAR_BIT(hadc->Instance->CR2, ADC_CR2_DMA);

only in HAL_ADC_Stop_DMA();

So I have to call HAL_ADC_Stop_DMA() before I can call HAL_ADC_Start_DMA() again?

EDIT:

Nope, calling HAL_ADC_Stop_DMA() causes a DMA_ERROR since the transfer finished already regularly.

Calling HAL_ADC_Init() does not solve this problem either. It does not clear the DMA flag.

So, STM, please review this issue for purpose..

10 replies

waclawek.jan
Super User
July 3, 2020

Read out and check/post the ADC registers content.

JW

FDrab.1
FDrab.1Author
Associate
July 4, 2020

Find attached the ADC and DMA registers.

Please note: I use the generated code only. No modifications..

FDrab.1
FDrab.1Author
Associate
July 4, 2020

I just found out, that the first sequence is correct (no double data). The second and following sequences are wrong...

waclawek.jan
Super User
July 4, 2020

Discontinuous mode is intended to convert a subgroup of the sequence defined in ADC_SQRx. But you set DISCNUM to the same value as ADC_SQR1.L. That doesn't make sense, so just simply don't set DISCEN.

JW

FDrab.1
FDrab.1Author
Associate
July 4, 2020

Hello JW. Thanx for your answer.

Though your answer sounds feasible it doesn't solve my problem.

I set discontinuous mode to "disabled" and regenerated the code.

What I now see is that in the second scan cycle the DMA waits endlessly for data.

I debugged into the HAL and saw, that setting the DMA bit in ADC_CR2 causes the ADC to execute a conversion! This is later the unwanted data..

     /* Enable ADC DMA mode */

     SET_BIT(hadc->Instance->CR2, ADC_CR2_DMA); // line 1643 of \STM32CubeMX\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_adc.c

Stupid question: What functions should I call to use this ADC in a SW triggered sequence mode?

I do:

  • MX_ADC1_Init()
  • HAL_ADCEx_Calibration_Start()
  • HAL_ADC_Start_DMA()
  • HAL_ADC_Start_DMA()
  • HAL_ADC_Start_DMA()
  • ...

Do I need to reinilialize the ADC between HAL_ADC_Start_DMA()?

FDrab.1
FDrab.1AuthorBest answer
Associate
July 4, 2020

Now I found out that the false ADC conversion is triggered by setting the DMA bit when it is already set. Somehow the HAL does not clear this bit at the end of conversion.

I added

hadc1.Instance->CR2 &= ~ADC_CR2_DMA;

to my code after the conversion finished and now it works as expected.

But this is not a good solution.

EDIT:

I now searched for the ADC_CR2_DMA bi in the HAL source file and found

CLEAR_BIT(hadc->Instance->CR2, ADC_CR2_DMA);

only in HAL_ADC_Stop_DMA();

So I have to call HAL_ADC_Stop_DMA() before I can call HAL_ADC_Start_DMA() again?

EDIT:

Nope, calling HAL_ADC_Stop_DMA() causes a DMA_ERROR since the transfer finished already regularly.

Calling HAL_ADC_Init() does not solve this problem either. It does not clear the DMA flag.

So, STM, please review this issue for purpose..

waclawek.jan
Super User
July 5, 2020

> I debugged into the HAL and saw, that setting the DMA bit in ADC_CR2 causes the ADC to execute a conversion!

I don't think so. Why do you think it does?

What's exactly the value written into ADC_CR2?

Does the ADC_SR register indicate a conversion (EOC being set after being 0)?

I don't Cube/HAL, and I personally would write this thing using register access, avoiding confusion stemming from Cube/HAL.

JW

FDrab.1
FDrab.1Author
Associate
July 6, 2020

Hi JW,

why I think setting the DMA bit causes a conversion?

I set a breakpoint to the line where the ADC_CR2_DMA bit is set. Then I reset all registers of the ADC and DMA to the values they had at the first cycle at exactly this location. When I now steped over the code which sets the DMA bit

  • the ADC data register content changes,
  • the EOC flag goes from 0 to 1
  • and the DMA transaction counter decreases..

So I'm quite sure that an ADC conversion is executed when the DMA bit is written by 1 when it already was 1 before.

I will ask a STM supporter to review this..

waclawek.jan
Super User
July 8, 2020

Breakpoint stops the processor but not the peripherals, they continue to work. Whether changes in register values during this time are reflected in the displayed values, depend on the toolchain.

>Then I reset all registers of the ADC and DMA to the values they had at the first cycle at exactly this location. 

What exactly do you do? Doesn't this start an ADC conversion?

JW

FDrab.1
FDrab.1Author
Associate
July 9, 2020

I use the Segger tool chain, which is quite reliable.

>>Then I reset all registers of the ADC and DMA to the values they had at the first cycle at exactly this location. 

 >What exactly do you do? Doesn't this start an ADC conversion?

I set the register values via the register editor in the debugger back to thier earlier values.

So in the second cylce just before the ADC_CR2_DMA bit is set I have the following system state:

  • ADC enabled waiting for SW-trigger or DMA request
  • ADC_CR2_DMA = 1 ; still set from first ADC sequence cycle (wrong, in my optinition, HAL should disable it when all transactions finished)
  • DMA is still enabled (wrong in my optinion; HAL should disable it when all transactions finished)
  • DMA_CNDTR0 = 0

Since DMA_CNDTR0 = 0 i assume that there is no DMA request pending. (if it were the ADC would keep konverting).

If I now set the ADC_CR2_DMA bit again the ADC conversion starts.

I just found the follwing note:

ADC_CR2:

Bit 0 ADON: A/D converter ON / OFF ..

1: Enable ADC and to start conversion

Note: If any other bit in this register apart from ADON is changed at the same time, then

conversion is not triggered. This is to prevent triggering an erroneous conversion.

Since the ADC_CR2.ADON bit is in the same register as the DMA bit this rule applies for setting the DMA bit. If the DMA bit was 1 before and is rewritten with 1 again, this might be counted as "DMA bit did not change" which might cause the (also set (correct)) ADON bit to trigger the ADC conversion.

waclawek.jan
Super User
July 9, 2020

That sounds as a plausible explanation.

JW