cancel
Showing results for 
Search instead for 
Did you mean: 

stm32h747xi Cannot use DMA to continuously store ADC-converted data.

Runtu1996
Associate II

Hello.
I'm using a development board STM32H747I Disco. i'm using a DAC to output a Sinus signal and read it through the ADC. the DMA is able to store the data correctly in normal mode, but not in circular mode. If the DMA can fit exactly one or more cycles of data then the result is correct, otherwise the result is very confusing. 

My ADC code references the ADC_DMA_Transfer tutorial for the H7 platform to invalidate the cache at half and full DMA. And set the buffer alignment at the beginning.


/* Definition of ADCx conversions data table size */
#define ADC_CONVERTED_DATA_BUFFER_SIZE ((uint32_t) 256) /* Size of array aADCxConvertedData[] */
/* Variable containing ADC conversions data */
ALIGN_32BYTES (__IO uint16_t aADCxConvertedData[ADC_CONVERTED_DATA_BUFFER_SIZE]);


Can anyone help me please?

4 REPLIES 4
Stassen.C
ST Employee

Hello Runtu1996,

 

Could please share the complete sequence of your code or simply share your code here so that we can help?

 

Regards,
Stassen

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.

Hi, thanks for your reply.

The buffer is declared at the beginning of the file.
/* Definition of ADCx conversions data table size */
#define ADC_CONVERTED_DATA_BUFFER_SIZE ((uint32_t) 256) /* Size of array aADCxConvertedData[] */
/* Variable containing ADC conversions data */
ALIGN_32BYTES (__IO uint16_t aADCxConvertedData[ADC_CONVERTED_DATA_BUFFER_SIZE]);

 


In the main function:
/*adc calibration ############################################ */
if (HAL_ADCEx_Calibration_Start(&hadc1, ADC_CALIB_OFFSET , ADC_SINGLE_ENDED)!= HAL_OK)
{
Error_Handler();
}
/* DAC start############################################ */
HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_1, Sinus, 256, DAC_ALIGN_12B_R);
/* Start conversion in DMA mode ################################# */
if (HAL_ADC_Start_DMA(&hadc1,
(uint32_t *)aADCxConvertedData,
ADC_CONVERTED_DATA_BUFFER_SIZE
) != HAL_OK)
{
Error_Handler();
}

HAL_TIM_Base_Start(&htim2);
HAL_TIM_Base_Start(&htim3);


Two callback functions:

void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
{
/* Invalidate Data Cache to get the updated content of the SRAM on the first half of the ADC converted data buffer: 32 bytes */
SCB_InvalidateDCache_by_Addr((uint32_t *) &aADCxConvertedData[0], ADC_CONVERTED_DATA_BUFFER_SIZE);
}

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
/* Invalidate Data Cache to get the updated content of the SRAM on the second half of the ADC converted data buffer: 32 bytes */
SCB_InvalidateDCache_by_Addr((uint32_t *) &aADCxConvertedData[ADC_CONVERTED_DATA_BUFFER_SIZE/2], ADC_CONVERTED_DATA_BUFFER_SIZE);
}

Regarding the ADC setup section:
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_16B;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T3_TRGO;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;
hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
hadc1.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
hadc1.Init.OversamplingMode = DISABLE;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}

/** Configure the ADC multi-mode
*/
multimode.Mode = ADC_MODE_INDEPENDENT;
if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
{
Error_Handler();
}

/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_18;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
sConfig.OffsetSignedSaturation = DISABLE;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */

ADC_ConfigureBoostMode(&hadc1);

/* USER CODE END ADC1_Init 2 */

}

 


DMA setup:
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
if(hadc->Instance==ADC1)
{
/* USER CODE BEGIN ADC1_MspInit 0 */

/* USER CODE END ADC1_MspInit 0 */

/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInitStruct.PLL2.PLL2M = 4;
PeriphClkInitStruct.PLL2.PLL2N = 9;
PeriphClkInitStruct.PLL2.PLL2P = 10;
PeriphClkInitStruct.PLL2.PLL2Q = 2;
PeriphClkInitStruct.PLL2.PLL2R = 2;
PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_3;
PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOMEDIUM;
PeriphClkInitStruct.PLL2.PLL2FRACN = 3072;
PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLL2;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}

/* Peripheral clock enable */
__HAL_RCC_ADC12_CLK_ENABLE();

__HAL_RCC_GPIOA_CLK_ENABLE();
/**ADC1 GPIO Configuration
PA4 ------> ADC1_INP18
*/
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

/* ADC1 DMA Init */
/* ADC1 Init */
hdma_adc1.Instance = DMA1_Stream0;
hdma_adc1.Init.Request = DMA_REQUEST_ADC1;
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_CIRCULAR;
hdma_adc1.Init.Priority = DMA_PRIORITY_VERY_HIGH;
hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
{
Error_Handler();
}

__HAL_LINKDMA(hadc,DMA_Handle,hdma_adc1);

/* ADC1 interrupt Init */
HAL_NVIC_SetPriority(ADC_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(ADC_IRQn);
/* USER CODE BEGIN ADC1_MspInit 1 */

/* USER CODE END ADC1_MspInit 1 */
}

}

 

In addition to that I use D-cache and I-cache. i didn't put up the code for the Timer and DAC. the DAC I checked with an oscilloscope and it's fine.
Thanks for your help.

 

TDK
Guru

> If the DMA can fit exactly one or more cycles of data then the result is correct, otherwise the result is very confusing. 

What does this mean? From that statement, it sounds like you're converting multiple channels, but your code only shows one channel.

If you feel a post has answered your question, please click "Accept as Solution".

Hello, sorry for the confusion in my answer. For example if every 20 measurements are one sinus cycle, then the DMA size needs to be a multiple of 20, e.g. 200. But if the DMA size is 201 or so, then the data is all messed up.

I also used a signal generator to connect to the ADC and the results are still incorrect. But if the DMA is in normal mode and the data is measured only once, then the result is correct no matter how big the DMA is.