cancel
Showing results for 
Search instead for 
Did you mean: 

DMA firing 1 time with TIM9 on L152 nucleo

SwagWalker77
Associate II

Hi all, I'm trying to have the ADC sampling rate controlled by a timer (TIM9 in this case) and when 8 samples are acquired, DMA will fire a transfer complete interrupt. So far I'm able to get the ISR to fire one time but never again. In main I set up a simple delay loop to periodically start a conversion simulating a periodic task/button press. I searched some of the forums and elsewhere and a bit in the datasheet on what bits need to be cleared in the ISR, but I'm still having issues. Any help is appreciated.

void MX_TIM9_Init(void)
{
 
  /* USER CODE BEGIN TIM9_Init 0 */
 
  /* USER CODE END TIM9_Init 0 */
 
  LL_TIM_InitTypeDef TIM_InitStruct = {0};
 
  /* Peripheral clock enable */
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM9);
 
  /* TIM9 interrupt Init */
  //NVIC_SetPriority(TIM9_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
  //NVIC_EnableIRQ(TIM9_IRQn);
 
  /* USER CODE BEGIN TIM9_Init 1 */
 
  /* USER CODE END TIM9_Init 1 */
  TIM_InitStruct.Prescaler = 7;
  TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
  TIM_InitStruct.Autoreload = 59999;
  TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
  LL_TIM_Init(TIM9, &TIM_InitStruct);
  LL_TIM_DisableARRPreload(TIM9);
  LL_TIM_SetClockSource(TIM9, LL_TIM_CLOCKSOURCE_INTERNAL);
  LL_TIM_SetTriggerOutput(TIM9, LL_TIM_TRGO_UPDATE);
  LL_TIM_DisableMasterSlaveMode(TIM9);
  /* USER CODE BEGIN TIM9_Init 2 */
  LL_TIM_EnableCounter(TIM9); //PB14 ADC_In 20,
 
  /* USER CODE END TIM9_Init 2 */
 
}
//Sets up the ADC to use timer 9 and DMA
void ADC_Setup(ADC_Setup_t ADC_choice)
    {
 
	  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};
 
    /* Configure NVIC to enable ADC1 interruptions */
    NVIC_SetPriority(ADC1_IRQn, 1); /* ADC IRQ greater priority than DMA IRQ */
	NVIC_EnableIRQ(ADC1_IRQn);
 
	/* Peripheral clock enable */
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC1);
 
    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOB);
 
	GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
	GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
	GPIO_InitStruct.Pin = LL_GPIO_PIN_14;
	LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
	// 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_DISABLE;
	LL_ADC_Init(ADC1, &ADC_InitStruct);
 
	ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_EXT_TIM9_TRGO;
	ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_DISABLE;
	ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
	ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_SINGLE;
	ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_LIMITED;
	LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
 
	LL_ADC_SetChannelsBank(ADC1, LL_ADC_CHANNELS_BANK_A);// Nucleo only IC
 
	  /** Configure Regular Channel*/
	LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_20);
	LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_20, LL_ADC_SAMPLINGTIME_24CYCLES);
}
void DMA_Init(ADC_Setup_t ADC_choice)
{
	LL_DMA_InitTypeDef DMA_InitStructure;
 
	// DMA controller clock enable
	LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
 
	// DMA1_Channel1_IRQn interrupt configuration
	NVIC_SetPriority(DMA1_Channel1_IRQn, 2);
	NVIC_EnableIRQ(DMA1_Channel1_IRQn);
 
	// DMA1 Channel1 Config
	LL_DMA_DeInit(DMA1, LL_DMA_CHANNEL_1);
	DMA_InitStructure.PeriphOrM2MSrcAddress = (uint32_t) &(ADC1->DR);
 
	DMA_InitStructure.MemoryOrM2MDstAddress = (uint32_t) ADC_buffer;
	DMA_InitStructure.NbData = ADCdataLengthBattery;
 
	DMA_InitStructure.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
	DMA_InitStructure.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
	DMA_InitStructure.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
	DMA_InitStructure.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_HALFWORD;
	DMA_InitStructure.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD;
	DMA_InitStructure.Mode = LL_DMA_MODE_NORMAL;
	DMA_InitStructure.Priority = LL_DMA_PRIORITY_MEDIUM;
	LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &DMA_InitStructure);
 
	// Enable DMA transfer interruption: transfer complete
	LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1);
 
	// Enable the DMA transfer
	LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
}
void DMA1_Channel1_IRQHandler(void)
{
	//LL_TIM_DisableCounter(TIM9);
	LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); //disable so we can make changes
 
	//Clear DMA1 Channel1 Half Transfer, Transfer Complete, interrupt pending bits
	LL_DMA_ClearFlag_HT1(DMA1);
	LL_DMA_ClearFlag_GI1(DMA1);
 
	ADC1->SR &= ~(1<<4); //reset to allow when we want to start conversion again
 
	LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, 8); //Reload the DMA register
	LL_DMA_SetPeriphAddress(DMA1,LL_DMA_CHANNEL_1,(uint32_t) &(ADC1->DR));
	LL_DMA_SetMemoryAddress(DMA1,LL_DMA_CHANNEL_1,(uint32_t)ADC_buffer);
 
	LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
	//LL_TIM_EnableCounter(TIM9);
}
int main(void)
{
	/* USER CODE BEGIN 1 */
	static int count = 0;
	/* USER CODE END 1 */
 
	/* MCU Configuration--------------------------------------------------------*/
 
	/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
	LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_COMP);
	LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG);
	LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
 
	/* System interrupt init*/
	NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
 
	/* SysTick_IRQn interrupt configuration */
	NVIC_SetPriority(SysTick_IRQn,
	NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0));
 
	/* USER CODE BEGIN Init */
 
	/* USER CODE END Init */
 
	/* Configure the system clock */
	SystemClock_Config();
 
	/* USER CODE BEGIN SysInit */
 
	/* USER CODE END SysInit */
 
	/* Initialize all configured peripherals */
	MX_GPIO_Init();
 
	/* USER CODE BEGIN 2 */
	DMA_Init(ADC_Voltage);
	ADC_Setup(ADC_Voltage);
	Activate_ADC();
	MX_TIM9_Init();
 
	LL_ADC_REG_StartConversionExtTrig(ADC1, LL_ADC_REG_TRIG_EXT_RISING);
 
	/* USER CODE END 2 */
 
	/* Infinite loop */
	/* USER CODE BEGIN WHILE */
	while (1)
	{
		/* USER CODE END WHILE */
		LL_mDelay(20);
		count++;
 
		if (count == 32)
		{
			count = 0;
			LL_ADC_REG_StartConversionExtTrig(ADC1, LL_ADC_REG_TRIG_EXT_RISING);
		}
	}
 
	/* USER CODE BEGIN 3 */
/* USER CODE END 3 */
}

1 REPLY 1
FBL
ST Employee

Hello @SwagWalker77​ ,

Here are a few things to check:

  1. Well, you should first check how do you handle DMA interruption request.
  2. You may check registers, DMA_TCIF1 which should be cleared after each transfer detailed DMA_SxNDTR

You may get inspired with the examples provided.

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.