cancel
Showing results for 
Search instead for 
Did you mean: 

L152 ADC DMA using LL libraries - working example sought

JU
Associate III

The short version is I'm trying to get a very basic setup working;

STM32L152 using Cube IDE, I want to sample ALL 22 ADC channels continuously into an array using DMA.

I've copied and pasted the 'ADC_MultiChannelSingleConversion' case into my pretty bare-bones project from:

STM32Cube_FW_L1_V1.10.3\Projects\NUCLEO-L152RE\Examples_LL\ADC\ADC_MultiChannelSingleConversion

But although a couple of interrupts fire (AdcDmaTransferComplete_Callback and AdcGrpRegularSequenceConvComplete_Callback get hit) no actual data appears to get transferred by DMA to the data buffer.

I have put the DMA Initialisation before the ADC due to that known bug, other than that my project is basically a copy-paste of the LL example.

The forum won't allow me to paste my code - I'll try in a comment I've pasted the important / relevant bits of the code below - at the moment there's nothing other than SysTick going on anyway.

1 REPLY 1
JU
Associate III

OK let's try to paste the relevant parts of the code...

void Real_MX_DMA_Init(void)
{
 
	/* Init with LL driver */
	/* DMA controller clock enable */
	LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
 
	/* DMA interrupt init */
	/* DMA1_Channel1_IRQn interrupt configuration */
	NVIC_SetPriority(DMA1_Channel1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),6, 0));  /* DMA IRQ lower priority than ADC IRQ */
	NVIC_EnableIRQ(DMA1_Channel1_IRQn);
 
}
 
void Configure_DMA(void)
{
	/* Configure the DMA transfer */
	LL_DMA_ConfigTransfer(DMA1,
			      LL_DMA_CHANNEL_1,
			      LL_DMA_DIRECTION_PERIPH_TO_MEMORY |
			      LL_DMA_MODE_CIRCULAR              |
			      LL_DMA_PERIPH_NOINCREMENT         |
			      LL_DMA_MEMORY_INCREMENT           |
			      LL_DMA_PDATAALIGN_HALFWORD        |
			      LL_DMA_MDATAALIGN_HALFWORD        |
			      LL_DMA_PRIORITY_HIGH               );
 
	/* Set DMA transfer addresses of source and destination */
	LL_DMA_ConfigAddresses(DMA1,
			       LL_DMA_CHANNEL_1,
			       LL_ADC_DMA_GetRegAddr(ADC1, LL_ADC_DMA_REG_REGULAR_DATA),
			       (uint32_t)&aADCxConvertedData[0],
			       LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
 
	/* Set DMA transfer size */
	LL_DMA_SetDataLength(DMA1,
			     LL_DMA_CHANNEL_1,
			     ADC_CONVERTED_DATA_BUFFER_SIZE);
 
	/* Enable DMA transfer interruption: transfer complete */
	LL_DMA_EnableIT_TC(DMA1,
			   LL_DMA_CHANNEL_1);
 
	/* Enable DMA transfer interruption: half transfer */
	/*
	LL_DMA_EnableIT_HT(DMA1,
			     LL_DMA_CHANNEL_1);
	 */
	/* Enable DMA transfer interruption: transfer error */
	LL_DMA_EnableIT_TE(DMA1,
			   LL_DMA_CHANNEL_1);
 
	/*## Activation of DMA #####################################################*/
	/* Enable the DMA transfer */
	LL_DMA_EnableChannel(DMA1,
			     LL_DMA_CHANNEL_1);
}
 
void MX_ADC_Init(void)
{
 
	/* USER CODE BEGIN ADC_Init 0 */
 
	/* USER CODE END ADC_Init 0 */
 
	LL_ADC_CommonInitTypeDef ADC_CommonInitStruct = {0};
	LL_ADC_InitTypeDef ADC_InitStruct = {0};
	LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
 
	LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
 
	/* Peripheral clock enable */
	LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC1);
 
	LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOC);
	LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
	LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOB);
	/**ADC GPIO Configuration
	  PC0   ------> ADC_IN10
	  PC1   ------> ADC_IN11
	  PC2   ------> ADC_IN12
	  PC3   ------> ADC_IN13
	  PA0-WKUP1   ------> ADC_IN0
	  PA1   ------> ADC_IN1
	  PA2   ------> ADC_IN2
	  PA3   ------> ADC_IN3
	  PA4   ------> ADC_IN4
	  PA5   ------> ADC_IN5
	  PA6   ------> ADC_IN6
	  PA7   ------> ADC_IN7
	  PC4   ------> ADC_IN14
	  PC5   ------> ADC_IN15
	  PB0   ------> ADC_IN8
	  PB1   ------> ADC_IN9
	  PB12   ------> ADC_IN18
	  PB13   ------> ADC_IN19
	  PB14   ------> ADC_IN20
	  PB15   ------> ADC_IN21
	 */
	GPIO_InitStruct.Pin = CUR4_Pin;
	GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
	GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
	LL_GPIO_Init(CUR4_GPIO_Port, &GPIO_InitStruct);
/** 
Trimmed for size - other 20 channels in here...
*/
	GPIO_InitStruct.Pin = SENS0_Pin;
	GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
	GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
	LL_GPIO_Init(SENS0_GPIO_Port, &GPIO_InitStruct);
 
	/* ADC DMA Init */
 
	/* ADC Init */
	LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
 
	LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PRIORITY_LOW);
 
	LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MODE_NORMAL);
 
	LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PERIPH_NOINCREMENT);
 
	LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MEMORY_INCREMENT);
 
	LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PDATAALIGN_HALFWORD);
 
	LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MDATAALIGN_HALFWORD);
 
	/* ADC interrupt Init */
	NVIC_SetPriority(ADC1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0));
	NVIC_EnableIRQ(ADC1_IRQn);
 
	/* USER CODE BEGIN ADC_Init 1 */
 
 
	/* USER CODE END ADC_Init 1 */
	/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
	 */
	ADC_CommonInitStruct.CommonClock = LL_ADC_CLOCK_ASYNC_DIV1;
	LL_ADC_CommonInit(__LL_ADC_COMMON_INSTANCE(ADC1), &ADC_CommonInitStruct);
	ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B;
	ADC_InitStruct.DataAlignment = LL_ADC_DATA_ALIGN_RIGHT;
	ADC_InitStruct.LowPowerMode = LL_ADC_LP_AUTOWAIT_NONE|LL_ADC_LP_AUTOPOWEROFF_NONE;
	ADC_InitStruct.SequencersScanMode = LL_ADC_SEQ_SCAN_ENABLE;
	LL_ADC_Init(ADC1, &ADC_InitStruct);
	ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_SOFTWARE;
	ADC_REG_InitStruct.SequencerLength = 22;
	ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
	ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_CONTINUOUS;//LL_ADC_REG_CONV_SINGLE; // LL_ADC_REG_CONV_CONTINUOUS
	ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_UNLIMITED;
	LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
	LL_ADC_REG_SetFlagEndOfConversion(ADC1, LL_ADC_REG_FLAG_EOC_UNITARY_CONV/*LL_ADC_REG_FLAG_EOC_SEQUENCE_CONV*/); // End of sequence
 
	/** Configure Regular Channel
	 */
	LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_0);
	LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_0, LL_ADC_SAMPLINGTIME_48CYCLES);
	
 
/** 
Trimmed for size - other 20 channels in here...
*/
	
	/** Configure Regular Channel
	 */
	LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_21, LL_ADC_CHANNEL_TEMPSENSOR);
	LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_TEMPSENSOR, LL_ADC_SAMPLINGTIME_48CYCLES);
	LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(ADC1), LL_ADC_PATH_INTERNAL_TEMPSENSOR);
	/** Configure Regular Channel
	 */
	LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_22, LL_ADC_CHANNEL_VREFINT);
	LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_VREFINT, LL_ADC_SAMPLINGTIME_48CYCLES);
	LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(ADC1), LL_ADC_PATH_INTERNAL_VREFINT);
	/* USER CODE BEGIN ADC_Init 2 */
 
	/* USER CODE END ADC_Init 2 */
 
}
 
void Configure_ADC(void)
{
 
	if (LL_ADC_IsEnabled(ADC1) == 0)
	{
		/* Enable ADC */
		LL_ADC_Enable(ADC1);
	}
 
	//LL_ADC_EnableIT_EOCS(ADC1);
 
	/* Enable interruption ADC group regular overrun */
	LL_ADC_EnableIT_OVR(ADC1);
 
}
 
/*
* This triggers ADC conversion and hence subsequent DMA transfer
*/
void service_ADC(void)
{
	static uint8_t flag = 0;
 
	/* Wait for ADC conversion and DMA transfer completion to process data */
	if(ubDmaTransferStatus != flag)
	{
		if(flag == 0)
		{
			ubDmaTransferStatus = 0;
			LL_ADC_REG_StartConversionSWStart(ADC1);
			flag = 1; // Conversion started
		}
		return;
	}
 
}
 
void DMA1_Channel1_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Channel1_IRQn 0 */
 
  /* USER CODE END DMA1_Channel1_IRQn 0 */
 
  /* USER CODE BEGIN DMA1_Channel1_IRQn 1 */
	/* Check whether DMA transfer complete caused the DMA interruption */
	if(LL_DMA_IsActiveFlag_TC1(DMA1) == 1)
	{
		/* Clear flag DMA transfer complete */
		LL_DMA_ClearFlag_TC1(DMA1);
 
		/* Call interruption treatment function */
		AdcDmaTransferComplete_Callback();
	}
 
	/* Check whether DMA half transfer caused the DMA interruption */
	if(LL_DMA_IsActiveFlag_HT1(DMA1) == 1)
	{
		/* Clear flag DMA half transfer */
		LL_DMA_ClearFlag_HT1(DMA1);
 
		/* Call interruption treatment function */
		AdcDmaTransferHalf_Callback();
	}
 
 
	/* Check whether DMA transfer error caused the DMA interruption */
	if(LL_DMA_IsActiveFlag_TE1(DMA1) == 1)
	{
		/* Clear flag DMA transfer error */
		LL_DMA_ClearFlag_TE1(DMA1);
 
		/* Call interruption treatment function */
		AdcDmaTransferError_Callback();
	}
  /* USER CODE END DMA1_Channel1_IRQn 1 */
}
 
void ADC1_IRQHandler(void)
{
  /* USER CODE BEGIN ADC1_IRQn 0 */
 
  /* USER CODE END ADC1_IRQn 0 */
  /* USER CODE BEGIN ADC1_IRQn 1 */
	/* Check whether ADC group regular overrun caused the ADC interruption */
	if(LL_ADC_IsActiveFlag_OVR(ADC1) != 0)
	{
		/* Clear flag ADC group regular overrun */
		LL_ADC_ClearFlag_OVR(ADC1);
 
		/* Call interruption treatment function */
		AdcGrpRegularOverrunError_Callback();
	}
 
	else
	{
		/* Clear flag ADC group regular end of sequence conversions */
		LL_ADC_ClearFlag_EOCS(ADC1);
 
		/* Call interruption treatment function */
		AdcGrpRegularSequenceConvComplete_Callback();
	}
  /* USER CODE END ADC1_IRQn 1 */
}
 
 
void AdcDmaTransferComplete_Callback(void)
{
	/* Update status variable of DMA transfer */
	ubDmaTransferStatus = 1;
 
	/* For this example purpose, check that DMA transfer status is matching     */
	/* ADC group regular sequence status:                                       */
	if (ubAdcGrpRegularSequenceConvStatus != 1)
	{
		AdcDmaTransferError_Callback();
	}
 
	/* Reset status variable of ADC group regular sequence */
	ubAdcGrpRegularSequenceConvStatus = 0;
}
 
void AdcDmaTransferError_Callback(void)
{
	while(1);
}
 
void AdcGrpRegularSequenceConvComplete_Callback(void)
{
	/* Update status variable of ADC group regular sequence */
	ubAdcGrpRegularSequenceConvStatus = 1;
	ubAdcGrpRegularSequenceConvCount++;
 
	if(ubAdcGrpRegularSequenceConvCount == ADC_CONVERTED_DATA_BUFFER_SIZE)
	{
		LL_ADC_DisableIT_EOCS(ADC1);
	}
}
 
 
void AdcGrpRegularOverrunError_Callback(void)
{
	LL_ADC_DisableIT_OVR(ADC1);
}