cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 ADC dual regular simultaneous mode

AKhot.1
Senior

I need to use dual regular simultaneous mode as I am using ADC1 and ADC2 simultaneously. I have enabled DMA for the both ADCs.

When I am running below code in debug mode it is going into hard fault after halfconversioncplt function. It is not going into conversionCplt function. Can anyone tell what is wrong?

Please look at the code below:

#define ADC_BUF_LEN 4000

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

ADC_HandleTypeDef hadc1;

ADC_HandleTypeDef hadc2;

DMA_HandleTypeDef hdma_adc1;

DMA_HandleTypeDef hdma_adc2;

UART_HandleTypeDef huart2;

/* USER CODE BEGIN PV */

uint16_t adc_buf_1[ADC_BUF_LEN];

uint16_t adc_buf_2[ADC_BUF_LEN];

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

void SystemClock_Config(void);

void PeriphCommonClock_Config(void);

static void MX_GPIO_Init(void);

static void MX_USART2_UART_Init(void);

static void MX_DMA_Init(void);

static void MX_ADC2_Init(void);

static void MX_ADC1_Init(void);

int main(void)

{

 HAL_Init();

 /* Configure the system clock */

 SystemClock_Config();

/* Configure the peripherals common clocks */

 PeriphCommonClock_Config();

 /* Initialize all configured peripherals */

 MX_GPIO_Init();

 MX_USART2_UART_Init();

 MX_DMA_Init();

 MX_ADC2_Init();

 MX_ADC1_Init();

 /* USER CODE BEGIN 2 */

 HAL_ADC_Start(&hadc2);

 HAL_ADCEx_MultiModeStart_DMA(&hadc1,(uint32_t *)adc_buf_1, ADC_BUF_LEN);

static void MX_ADC1_Init(void)

{

 /* USER CODE BEGIN ADC1_Init 0 */

 /* USER CODE END ADC1_Init 0 */

 ADC_MultiModeTypeDef multimode = {0};

 ADC_ChannelConfTypeDef sConfig = {0};

 /* USER CODE BEGIN ADC1_Init 1 */

 /* USER CODE END ADC1_Init 1 */

 /** Common config

 */

 hadc1.Instance = ADC1;

 hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;

 hadc1.Init.Resolution = ADC_RESOLUTION_12B;

 hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;

 hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;

 hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

 hadc1.Init.LowPowerAutoWait = DISABLE;

 hadc1.Init.ContinuousConvMode = ENABLE;

 hadc1.Init.NbrOfConversion = 1;

 hadc1.Init.DiscontinuousConvMode = DISABLE;

 hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;

 hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;

 hadc1.Init.DMAContinuousRequests = ENABLE;

 hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;

 hadc1.Init.OversamplingMode = DISABLE;

 if (HAL_ADC_Init(&hadc1) != HAL_OK)

 {

  Error_Handler();

 }

 /** Configure the ADC multi-mode

 */

 multimode.Mode = ADC_DUALMODE_REGSIMULT;

 multimode.DMAAccessMode = ADC_DMAACCESSMODE_12_10_BITS;

 multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_1CYCLE;

 if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)

 {

  Error_Handler();

 }

 /** Configure Regular Channel

 */

 sConfig.Channel = ADC_CHANNEL_5;

 sConfig.Rank = ADC_REGULAR_RANK_1;

 sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;

 sConfig.SingleDiff = ADC_SINGLE_ENDED;

 sConfig.OffsetNumber = ADC_OFFSET_NONE;

 sConfig.Offset = 0;

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

 {

  Error_Handler();

 }

 /* USER CODE BEGIN ADC1_Init 2 */

 /* USER CODE END ADC1_Init 2 */

}

/**

 * @brief ADC2 Initialization Function

 * @param None

 * @retval None

 */

static void MX_ADC2_Init(void)

{

 /* USER CODE BEGIN ADC2_Init 0 */

 /* USER CODE END ADC2_Init 0 */

 ADC_ChannelConfTypeDef sConfig = {0};

 /* USER CODE BEGIN ADC2_Init 1 */

 /* USER CODE END ADC2_Init 1 */

 /** Common config

 */

 hadc2.Instance = ADC2;

 hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;

 hadc2.Init.Resolution = ADC_RESOLUTION_12B;

 hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;

 hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE;

 hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

 hadc2.Init.LowPowerAutoWait = DISABLE;

 hadc2.Init.ContinuousConvMode = ENABLE;

 hadc2.Init.NbrOfConversion = 1;

 hadc2.Init.DiscontinuousConvMode = DISABLE;

 hadc2.Init.DMAContinuousRequests = ENABLE;

 hadc2.Init.Overrun = ADC_OVR_DATA_PRESERVED;

 hadc2.Init.OversamplingMode = DISABLE;

 if (HAL_ADC_Init(&hadc2) != HAL_OK)

 {

  Error_Handler();

 }

 /** Configure Regular Channel

 */

 sConfig.Channel = ADC_CHANNEL_1;

 sConfig.Rank = ADC_REGULAR_RANK_1;

 sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;

 sConfig.SingleDiff = ADC_SINGLE_ENDED;

 sConfig.OffsetNumber = ADC_OFFSET_NONE;

 sConfig.Offset = 0;

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

 {

  Error_Handler();

 }

 /* USER CODE BEGIN ADC2_Init 2 */

 /* USER CODE END ADC2_Init 2 */

}

/**

 * @brief USART2 Initialization Function

 * @param None

 * @retval None

 */

static void MX_USART2_UART_Init(void)

{

 /* USER CODE BEGIN USART2_Init 0 */

 /* USER CODE END USART2_Init 0 */

 /* USER CODE BEGIN USART2_Init 1 */

 /* USER CODE END USART2_Init 1 */

 huart2.Instance = USART2;

 huart2.Init.BaudRate = 115200;

 huart2.Init.WordLength = UART_WORDLENGTH_8B;

 huart2.Init.StopBits = UART_STOPBITS_1;

 huart2.Init.Parity = UART_PARITY_NONE;

 huart2.Init.Mode = UART_MODE_TX_RX;

 huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;

 huart2.Init.OverSampling = UART_OVERSAMPLING_16;

 huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;

 huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;

 if (HAL_UART_Init(&huart2) != HAL_OK)

 {

  Error_Handler();

 }

 /* USER CODE BEGIN USART2_Init 2 */

 /* USER CODE END USART2_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);

 /* DMA1_Channel2_IRQn interrupt configuration */

 HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);

 HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);

}

/**

 * @brief GPIO Initialization Function

 * @param None

 * @retval None

 */

static void MX_GPIO_Init(void)

{

 GPIO_InitTypeDef GPIO_InitStruct = {0};

 /* GPIO Ports Clock Enable */

 __HAL_RCC_GPIOC_CLK_ENABLE();

 __HAL_RCC_GPIOH_CLK_ENABLE();

 __HAL_RCC_GPIOA_CLK_ENABLE();

 __HAL_RCC_GPIOB_CLK_ENABLE();

 /*Configure GPIO pin Output Level */

 HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);

 /*Configure GPIO pin : B1_Pin */

 GPIO_InitStruct.Pin = B1_Pin;

 GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;

 GPIO_InitStruct.Pull = GPIO_NOPULL;

 HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);

 /*Configure GPIO pin : LD2_Pin */

 GPIO_InitStruct.Pin = LD2_Pin;

 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

 GPIO_InitStruct.Pull = GPIO_NOPULL;

 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

 HAL_GPIO_Init(LD2_GPIO_Port, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc) {

HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);

}

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {

HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);

HAL_ADCEx_MultiModeStop_DMA(&hadc1);

}

7 REPLIES 7
RomainR.
ST Employee

Hello @AKhot.1 (Community Member) 

Can you indicate which STM32 product are you using?

It seems you are using a large amount of Data bss in SRAM.

Due to 

uint16_t adc_buf_1[4000] = {0};

uint16_t adc_buf_2[4000]= {0};

These array take 2x8000 Bytes in SRAM. 

Can you try to reduce the buffer size to check if Hardfault is caused by memory allocation?

Best regards,

Romain,

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

AKhot.1
Senior

I am using STM32L476RG. I tried to reduce it but still the issue is there. Are the ADC settings correct? And the multimode ADC settings correct?  

multimode.Mode = ADC_DUALMODE_REGSIMULT;

 multimode.DMAAccessMode = ADC_DMAACCESSMODE_12_10_BITS;

 multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_1CYCLE;

 if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)

 {

  Error_Handler();

 }

RomainR.
ST Employee

I will check your ADC1/ADC2 Dual mode configuration.

What are the SYSCLK, PCLK and AHB/APB clock frequency in your project?

And what is ADC1/ADC2 clock frequency?

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

AKhot.1
Senior

Everything is set to 80MHz

RomainR.
ST Employee

I created a new project on Nucleo-L476RG (see archive STM32CubeIDE attached)

ADC1 and ADC2 are configured in Dual regular conversion.

Some of fADC, channel and sampling time are the same than you.

Only one buffer aADCDualConvertedValues[4000] contains the results of ADC1 and ADC2 conversions:

ADC conversions results are transferred automatically by DMA, into variable array "aADCDualConvertedValues".

ADC master and ADC slave results are concatenated in a common 32-bit data register:

  • ADC1 master results in the 16 LSB [15:0] (with ADC resolution 12 bits, bits effectively used are [11:0])
  • ADC2 slave results in the 16 MSB [31:16] (with ADC resolution 12 bits, bits effectively used are [27:16])

It's important to configure DMA in 32 bit size for memory transfert and configure the NVIC priorities in order to do not create race conditions between ADCx and DMA.

This project is totally fonctionnal, place a breakpoint at line below in main()

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);

Can you try it and let me know if it helps you?

Best regards,

Romain,

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

AKhot.1
Senior

Thank you so much. I will try it and let you know.

rorengo
Associate

Hi RomainR,

Please, I would like to continue this post because it is really interesting. I would like to know if it is possible on this base to trigger the conversion via Timer1 TRGO and not perform continuous DMA then generate an IT DMA at the end of the conversion ?

Best regards,

Richard