Skip to main content
Jwork.1
Associate II
February 13, 2020
Question

Why does the DMA gets out of sync when doing a sequence of regular AD conversions on stm32f103C8TX? This only happens with DMA_NORMAL.

  • February 13, 2020
  • 5 replies
  • 3084 views

It works with DMA_CIRCULAR (but I do not want or need continuous DMA transfers.)

You see by the terminal output below that reading 2 analog inputs works OK. However, after a while (< 1 minute) the 2 analog values are exchanged now. Apparently the DMA gets confused, but how and why I cannot understand.

Here is the code, all initialization was generated by STM32CubeMX, v5.5.0. (Had to omit part due to website restrictions on size of message.) NUM_AN_INPUTS=2

 ********** console output (about 30 seconds after swi upload / reset) ************

1959 0

1956 0

1957 0

1954 0

1955 0

1957 0

1955 0

1955 0

1954 0

1957 0

1959 0

0 1952

0 1953

3 1952

0 1952

0 1952

0 1953

0 1952

0 1953

 ********** usage of ADC in my code ************

volatile bool    adc_done = false;       

volatile uint16_t adc_buf[NUM_AN_INPUTS];   

while(1) {

adc_done = false;

     HAL_ADC_Start_DMA(&hadc1, (uint32_t*) adc_buf, NUM_AN_INPUTS);

while(!adc_done) {HAL_Delay(1);}   

 sprintf(message, "%d %d\n", adc_buf[0], adc_buf[1]);

 serial.USBwrite(message);

 HAL_Delay(100);

}

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *) {

 adc_done=true;

}

 STMCubeMX Generated code and ADC calibration:

 ************ main.c: **************

 /* USER CODE END 1 */

 /* MCU Configuration--------------------------------------------------------*/

 /* Reset of all peripherals, Initializes the Flash interface and the Systick. */

 HAL_Init();

 SystemClock_Config();

 MX_GPIO_Init();

 MX_DMA_Init();

 MX_ADC1_Init();

 MX_USB_DEVICE_Init();

 MX_USART3_UART_Init();

 MX_USART1_UART_Init();

 /* USER CODE BEGIN 2 */

  /* Run the ADC calibration */ 

 if (HAL_ADCEx_Calibration_Start(&hadc1) != HAL_OK)

 {

   /* Calibration Error */

   Error_Handler();

 }

 Init functions generated by STM32CubeMX

/**

 * @brief ADC1 Initialization Function

 * @param None

 * @retval None

 */

static void MX_ADC1_Init(void)

{

 /* USER CODE BEGIN ADC1_Init 0 */

 /* USER CODE END ADC1_Init 0 */

 ADC_ChannelConfTypeDef sConfig = {0};

 /* USER CODE BEGIN ADC1_Init 1 */

 /* USER CODE END ADC1_Init 1 */

 /** Common config

 */

 hadc1.Instance = ADC1;

 hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;

 hadc1.Init.ContinuousConvMode = DISABLE;

 hadc1.Init.DiscontinuousConvMode = DISABLE;

 hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;

 hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;

 hadc1.Init.NbrOfConversion = 2;

 if (HAL_ADC_Init(&hadc1) != HAL_OK)

 {

   Error_Handler();

 }

 /** Configure Regular Channel

 */

 sConfig.Channel = ADC_CHANNEL_8;

 sConfig.Rank = ADC_REGULAR_RANK_1;

 sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES_5;

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

 {

   Error_Handler();

 }

 /** Configure Regular Channel

 */

 sConfig.Channel = ADC_CHANNEL_9;

 sConfig.Rank = ADC_REGULAR_RANK_2;

 sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES_5;

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

 {

   Error_Handler();

 }

 /* USER CODE BEGIN ADC1_Init 2 */

 /* USER CODE END ADC1_Init 2 */

}

/**

 * Enable DMA controller clock

 */

static void MX_DMA_Init(void)

{

 /* DMA controller clock enable */

 __HAL_RCC_DMA1_CLK_ENABLE();

 /* DMA interrupt init */

 /* DMA1_Channel1_IRQn interrupt configuration */

 HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);

 HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);

}

 STMCubeMX Generated code:

 ************ main.c: **************

 void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)

{

 GPIO_InitTypeDef GPIO_InitStruct = {0};

 if(hadc->Instance==ADC1)

 {

 /* USER CODE BEGIN ADC1_MspInit 0 */

 /* USER CODE END ADC1_MspInit 0 */

   /* Peripheral clock enable */

   __HAL_RCC_ADC1_CLK_ENABLE();

   __HAL_RCC_GPIOB_CLK_ENABLE();

   /**ADC1 GPIO Configuration   

   PB0    ------> ADC1_IN8

   PB1    ------> ADC1_IN9

   */

   GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;

   GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;

   HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

   /* ADC1 DMA Init */

   /* ADC1 Init */

   hdma_adc1.Instance = DMA1_Channel1;

   hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;

   hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;

   hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;

   hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;

   hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;

   hdma_adc1.Init.Mode = DMA_NORMAL;

   hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;

   if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)

   {

     Error_Handler();

   }

   __HAL_LINKDMA(hadc,DMA_Handle,hdma_adc1);

   /* ADC1 interrupt Init */

   HAL_NVIC_SetPriority(ADC1_2_IRQn, 0, 0);

   HAL_NVIC_EnableIRQ(ADC1_2_IRQn);

 /* USER CODE BEGIN ADC1_MspInit 1 */

 /* USER CODE END ADC1_MspInit 1 */

 }

}

 STMCubeMX Generated code:

 ************ stm32f1xx_hal_msp.c: **************

void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)

{

 GPIO_InitTypeDef GPIO_InitStruct = {0};

 if(hadc->Instance==ADC1)

 {

 /* USER CODE BEGIN ADC1_MspInit 0 */

 /* USER CODE END ADC1_MspInit 0 */

   /* Peripheral clock enable */

   __HAL_RCC_ADC1_CLK_ENABLE();

   __HAL_RCC_GPIOB_CLK_ENABLE();

   /**ADC1 GPIO Configuration   

   PB0    ------> ADC1_IN8

   PB1    ------> ADC1_IN9

   */

   GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;

   GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;

   HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

   /* ADC1 DMA Init */

   /* ADC1 Init */

   hdma_adc1.Instance = DMA1_Channel1;

   hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;

   hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;

   hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;

   hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;

   hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;

   hdma_adc1.Init.Mode = DMA_NORMAL;

   hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;

   if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)

   {

     Error_Handler();

   }

   __HAL_LINKDMA(hadc,DMA_Handle,hdma_adc1);

   /* ADC1 interrupt Init */

   HAL_NVIC_SetPriority(ADC1_2_IRQn, 0, 0);

   HAL_NVIC_EnableIRQ(ADC1_2_IRQn);

 /* USER CODE BEGIN ADC1_MspInit 1 */

 /* USER CODE END ADC1_MspInit 1 */

 }

}

This topic has been closed for replies.

5 replies

waclawek.jan
Super User
February 13, 2020

Do you look at the ADC registers in debugger? If yes, then don't.

JW

Jwork.1
Jwork.1Author
Associate II
February 13, 2020

Hello Jan,

Thanks for the advice. I do not use a debugger but just write a string to USB:

// write string of chars to USB. Must be terminated by \0.

void_serial:: USBwrite( char*data) {

CDC_Transmit_FS((uint8_t*) data, strlen(data));

Like this, all the code runs in "normal" mode =)

I tried just now an experiment where I put the ADC in continuous

conversion mode, and changed nothing else.

hadc1.Init.ContinuousConvMode= ENABLE;

Then each two/three samples the channels are reversed, showing again (I

think) a lack of synchronization between ADC and DMA controller.

John

On 2020-02-13 21:32, ST Community wrote:

waclawek.jan
Super User
February 13, 2020

John,

if you stop-start the DMA while conversions are started automatically, conversion results are inevitably lost while DMA is not running.

In the original case, what happens if you read out the ADC data register manually before each subsequent HAL_ADC_Start_DMA() call?

I don't Cube.

JW

Jwork.1
Jwork.1Author
Associate II
February 13, 2020
I read the DAC register just before the next call to HAL_ADC_Start_DMA() and list the result with prefix "manual".
See below, it keeps reading the second measurement.
This is what I expect, since that is the last conversion done before the start of the new sequence.
The interesting bit for me is that the manual ADC register read keeps correctly reading the second measurement.
While the result of the DMA read is reverted after a while.
I guess this shows the ADC is working as expected and indeed the DMA is out of sync?
1975 2
manual 2
1977 0
manual 0
1979 0
manual 0
1975 0
manual 0
1975 0
manual 0
1977 0
manual 0
1977 0
manual 0
1976 0
manual 0
1975 0
manual 0
1977 0
manual 0
1973 0
manual 0
1974 3
manual 3
1976 0
manual 0
1974 3
manual 0
0 1976
manual 0
0 1976
manual 0
0 1976
manual 0
On 2020-02-13 22:27, ST Community wrote:
waclawek.jan
Super User
February 14, 2020

Print out CNDTR of respective DMA channel and also the ADC status register.

JW

Jwork.1
Jwork.1Author
Associate II
February 14, 2020
Again logging around the point where the "sync is lost". Code:
sprintf(message, "%d %d\n", adc_buf[0], adc_buf[1]);
serial.USBwrite(message);
HAL_Delay(100);
sprintf(message, "ADC1->DR=%lu, ADC1->SR=%08X, DMA1->CNDTR=%08X\n", ADC1->DR, ADC1->SR, hdma_adc1.Instance->CNDTR);
serial.USBwrite(message);
1978 3
ADC1->DR=3, ADC1->SR=00000010, DMA1->CNDTR=00000000
1971 0
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
1975 0
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
1979 0
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
1977 0
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
1979 0
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
1977 0
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
1975 0
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
1978 0
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
1976 0
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
1979 0
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
1975 0
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1976
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1976
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1976
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1974
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1974
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1975
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1974
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1974
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1974
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1976
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1976
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1976
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1976
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1975
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1975
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1973
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1975
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1976
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1975
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1974
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1972
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1988
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1976
ADC1->DR=1, ADC1->SR=00000010, DMA1->CNDTR=00000000
1 1979
ADC1->DR=0, ADC1->SR=00000010, DMA1->CNDTR=00000000
0 1962
On 2020-02-14 03:11, ST Community wrote:
waclawek.jan
Super User
February 16, 2020

John,

Can you please do it again, this time printing ADC1->SR *before* reading ADC1->DR?

My theory is, that DMA misses one transfer, but I don't quite understand, why. What are the AHB and APB clocks, and what is the ADC clock?

JW

Jwork.1
Jwork.1Author
Associate II
February 16, 2020
Not sure if the picture of the clock configuration will get scrubbed, so:
AHB clock =  Is that the same as HCLOCK? I know that Hclock= Sysclock/1
= 72Mhz
APB1 (peripheral) clock = 36 Mhz, APB1 timer clock = 72Mhz
APB2 (peripheral) clock = 72 Mhz, APB2 timer clock = 72Mhz
ADC clock = 12 MHz
This time the ADC1 SR register is different after "ADC and DMA out of sync"
2696 0
ADC1: SR=00000010, DR=00000000. DMA1: CNDTR=00000000, CPAR=4001244C,
CMAR=20001994
2703 0
ADC1: SR=00000010, DR=00000000. DMA1: CNDTR=00000000, CPAR=4001244C,
CMAR=20001994
2694 0
ADC1: SR=00000010, DR=00000000. DMA1: CNDTR=00000000, CPAR=4001244C,
CMAR=20001994
2700 0
ADC1: SR=00000010, DR=00000000. DMA1: CNDTR=00000000, CPAR=4001244C,
CMAR=20001994
2695 0
ADC1: SR=00000010, DR=00000000. DMA1: CNDTR=00000000, CPAR=4001244C,
CMAR=20001994
2693 0
ADC1: SR=00000010, DR=00000000. DMA1: CNDTR=00000000, CPAR=4001244C,
CMAR=20001994
2697 0
ADC1: SR=00000010, DR=00000000. DMA1: CNDTR=00000000, CPAR=4001244C,
CMAR=20001994
2698 9
ADC1: SR=00000010, DR=00000009. DMA1: CNDTR=00000000, CPAR=4001244C,
CMAR=20001994
2696 0
ADC1: SR=00000010, DR=00000000. DMA1: CNDTR=00000000, CPAR=4001244C,
CMAR=20001994
2693 0
ADC1: SR=00000010, DR=00000000. DMA1: CNDTR=00000000, CPAR=4001244C,
CMAR=20001994
2697 0
ADC1: SR=00000010, DR=00000000. DMA1: CNDTR=00000000, CPAR=4001244C,
CMAR=20001994
2697 0
ADC1: SR=00000010, DR=00000000. DMA1: CNDTR=00000000, CPAR=4001244C,
CMAR=20001994
2696 10
ADC1: SR=00000010, DR=0000000A. DMA1: CNDTR=00000000, CPAR=4001244C,
CMAR=20001994
2695 1
ADC1: SR=00000012, DR=00000000. DMA1: CNDTR=00000000, CPAR=4001244C,
CMAR=20001994
0 2694
ADC1: SR=00000012, DR=00000000. DMA1: CNDTR=00000000, CPAR=4001244C,
CMAR=20001994
0 2692
ADC1: SR=00000012, DR=00000000. DMA1: CNDTR=00000000, CPAR=4001244C,
CMAR=20001994
0 2693
ADC1: SR=00000012, DR=00000000. DMA1: CNDTR=00000000, CPAR=4001244C,
CMAR=20001994
0 2693
ADC1: SR=00000012, DR=00000000. DMA1: CNDTR=00000000, CPAR=4001244C,
CMAR=20001994
0 2692
ADC1: SR=00000012, DR=00000000. DMA1: CNDTR=00000000, CPAR=4001244C,
CMAR=20001994
0 2694
On 2020-02-16 14:40, ST Community wrote:
Jwork.1
Jwork.1Author
Associate II
February 16, 2020

This is the complete clock configuration