Skip to main content
Explorer II
April 6, 2022
Question

L152 ADC DMA using LL libraries - working example sought

  • April 6, 2022
  • 1 reply
  • 3143 views

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.

    This topic has been closed for replies.

    1 reply

    JUAuthor
    Explorer II
    April 6, 2022

    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);
    }