cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with ADC Multi-channel DMA

fan zhang
Associate II
Posted on December 04, 2017 at 22:33

Hello,

I am using ADC multi-channel DMA on stm32f105rc to receive some data on 3 adc channels. Ideally I would see 3 values with not much variations on my PC display. However, values I retrieved from the DMA were changing all the time and I do not know what goes wrong. Here is what I have for the code, I basically use cubeMX to generate the code and make a few modification on it. The idea is to retrieve the adc data by using DMA and transmit to PC terminal by UART.

  

&sharpinclude 'main.h'

&sharpinclude 'stm32f1xx_hal.h'

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

&sharpdefine LED_1 GPIO_PIN_12

&sharpdefine SW_ENABLE_3V3 GPIO_PIN_1

/* Private variables ---------------------------------------------------------*/

ADC_HandleTypeDef hadc1;

DMA_HandleTypeDef hdma_adc1;

UART_HandleTypeDef huart1;

DMA_HandleTypeDef hdma_usart1_tx;

/* USER CODE BEGIN PV */

/* Private variables ---------------------------------------------------------*/

uint32_t buff_rx1[3];

uint32_t adc[3];

int len0, len1, i;

char header[100];

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/

void SystemClock_Config(void);

static void MX_GPIO_Init(void);

static void MX_DMA_Init(void);

static void MX_USART1_UART_Init(void);

static void MX_ADC1_Init(void);

int main(void)

{

HAL_Init();

SystemClock_Config();

MX_GPIO_Init();

MX_DMA_Init();

MX_USART1_UART_Init();

MX_ADC1_Init();

while (1)

{

HAL_GPIO_WritePin(GPIOB, SW_ENABLE_3V3, GPIO_PIN_RESET);

HAL_Delay(500);

HAL_ADC_Start_DMA(&hadc1, (uint32_t*)buff_rx1, 3);

HAL_ADC_Start_IT(&hadc1);

HAL_GPIO_WritePin(GPIOB, SW_ENABLE_3V3, GPIO_PIN_SET);

sprintf(header, '%lu %lu %lu data done\r\n', (unsigned long)buff_rx1[0], (unsigned long)buff_rx1[1], (unsigned long)buff_rx1[2]);

len0 = strlen(header);

HAL_UART_Transmit(&huart1, header, len0, 500);

HAL_Delay(1500);

HAL_GPIO_TogglePin(GPIOC,LED_1);

}

}

/************************************/

I set 3 adc channels with sampling time of 1.5 cycle. The output value looks like:

783 560 378 data done

783 755 2565 data done

775 644 2326 data done

776 2564 382 data done

2638 2633 462 data done

775 634 408 data done

783 2564 373 data done

776 732 2553 data done

2637 2569 410 data done

776 522 365 data done

776 2620 437 data done

2636 2563 402 data done

Thanks for your help.

#multichannel-adc #dma #stm32f1
4 REPLIES 4
Posted on December 04, 2017 at 22:52

So may be show the ADC initialization code?

Do you have a sufficient sample time? You're charging a capacitor so think how much current your sources can supply to change the state from the prior channel.

Consider not restarting the ADC/DMA in every loop iteration. It should be possible to put the DMA in a circular mode so you don't lose channel synchronization.

How do you know if the conversion completes?

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 04, 2017 at 23:14

Thanks for your reply.

The adc init looks like this:

static void MX_ADC1_Init(void)

{

ADC_ChannelConfTypeDef sConfig;

/**Common config

*/

hadc1.Instance = ADC1;

hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;

hadc1.Init.ContinuousConvMode = ENABLE;

hadc1.Init.DiscontinuousConvMode = DISABLE;

hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;

hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;

hadc1.Init.NbrOfConversion = 3;

if (HAL_ADC_Init(&hadc1) != HAL_OK)

{

_Error_Handler(__FILE__, __LINE__);

}

/**Configure Regular Channel

*/

sConfig.Channel = ADC_CHANNEL_10;

sConfig.Rank = 1;

sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;

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

{

_Error_Handler(__FILE__, __LINE__);

}

/**Configure Regular Channel

*/

sConfig.Channel = ADC_CHANNEL_12;

sConfig.Rank = 2;

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

{

_Error_Handler(__FILE__, __LINE__);

}

/**Configure Regular Channel

*/

sConfig.Channel = ADC_CHANNEL_13;

sConfig.Rank = 3;

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

{

_Error_Handler(__FILE__, __LINE__);

}

}

If I do not put the adc/dma into a loop, what would be the right way to read data continuously?  When talking about the conversion complete, I know it may requires an interrupt but I don't know what would be the appropriate way. I am still new to stm32 and embedded. 

Posted on December 05, 2017 at 08:31

You can configure DMA in circular mode and use HAL_ADC_ConvCpltCallback and HAL_ADC_ConvHalfCpltCallback to push data continuously from ADC to a buffer it is similar to that of doing ping pong. 

Posted on December 07, 2017 at 14:05

Thank you!