cancel
Showing results for 
Search instead for 
Did you mean: 

How to setup DMA from timer to memory

BTrem.1
Senior II

I'm very new to the STM32 and am trying to set up TIM2 to trigger a dma input capture to memory. I have been pouring over examples and the STM32F302R8 ref manual but am not there yet.

What is working is I am inputting 30Hz ref signal on both PA5 and PB10 (TIM2_Ch1 & TIM2_Ch3). These are being detected and I see the CCR1 and CCR3 registers reflecting the capture count.

What is not working is I don't seem to be generating (or servicing) a DMA request.

In my code I am using HAL_DMA_Start and __HAL_TIM_ENABLE_DMA for both DMA channels 1 & 3 on the TIM2. The respective memory buffers are buffer1 and buffer2 in SRAM. I initialize these to 0xdead at reset and see them get updated once after the DMA is enabled and the TIM2 capture/compare is enabled, but after that the buffer never gets updated again.

Also in the TIM2 SR register the CC10F and CC13F overflow flags are set, and my two DMA IRQ routines never get triggered.

Am I missing a critical enable somewhere?

I've seen in some discussion/examples the use of a Call_Back function. Am I missing a critical piece of code here>

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_DAC_Init();
  MX_TIM1_Init();
  MX_TIM2_Init();
  MX_USART2_UART_Init();
  MX_MotorControl_Init();
 
  /* Initialize interrupts */
  MX_NVIC_Init();
  /* USER CODE BEGIN 2 */
 
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  NVIC->STIR = EXTI15_10_IRQn;  /* what is this for? 5/6/20           */
	
	
	/* HAL_StatusTypeDef HAL_DMA_Start(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength) */
	HAL_DMA_Start(&hdma_tim2_ch1, (uint32_t) &TIM2->CCR1, (uint32_t) buffer1, 0x01);
	HAL_DMA_Start(&hdma_tim2_ch3, (uint32_t) &TIM2->CCR3, (uint32_t) buffer2, 0x01);
	
	/* enable DMA */
	__HAL_TIM_ENABLE_DMA(&htim2, TIM_DMA_CC1); 
	__HAL_TIM_ENABLE_DMA(&htim2, TIM_DMA_CC3);
	
	/* Start TIM2 then enable capture 									 */
	TIM2->CR1 |= TIM_CR1_CEN_Msk; //start the timer
	/* *** TIM2 captrure/compare enable register: CCER 	 */
	/* [15:12] - Don't care															 */
	/* [11]  CC3NP select polarity for capture operation */ 
	/* [10] - reserved																	 */
	/* [9]   CC3P																				 */
	/* [8]   CC3E enable																 */
	value |= 0x0100;
	/* [7:4] - don't care  															 */
	/* [3]   CC1NP select polarity for capture operation */
	/* [2] - reserved																		 */
	/* [1]   Set the CC1P bit to zero for active high.	 */
	/* [0]   CC1E enable																 */
	value |= 0x0001;
	/* Set the TIM2_CCER register:											 */
	TIM2->CCER = value;
 
  while (1)
  {

Thanks for any and all help,

1 ACCEPTED SOLUTION

Accepted Solutions

> TransferComplete interrupt routines are not executed

Are these interrupts enabled in the respective DMA stream control register?

Are they enabled in NVIC?

Do the DMA indeed run to completion? (counterexample would be a very slowly running timer and DMA set with very high NDTR)

Do you observe in the interrupt routines (ISR) themselves (i.e. no Cube callback)? Are these ISR properly inserted in the vector table (see vector table in disasm/memory watch in debugger and compare to address of given ISR, e.g. in mapfile)?

Even if you use Cube, you still can/should read out and check the peripherals' registers, for debugging purposes.

JW

View solution in original post

6 REPLIES 6

Review AN4666.

JW

Thanks , I'll do so this afternoon & report back 🙂

BTrem.1
Senior II

Here is an update from the poster ... not an answer more input ...

Because I am using the ST Motor Control Library I am sort of forced into using Cube to write this code. I did the setup of the DMA in Cube but was not aware there was more code I needed to add in the 'user' section. I added a function called DMA config to configure needed parameters.

I am still having issues in that the dma appears to be running; the two destinations buffers are getting updated.

But, I am not getting either TransferComplete interrupts. How can this be happen if the dma appears to be updating the buffers?

In the debugger if I toggle the TIM2->DIER register bits CC1DE or CC3DE I can start/stop the transfers but the TransferComplete interrupt routines are not executed at any time.

I used the Cube example code for STM32F302R8-Nucleo DMA to get this far.

Here is the use in main.c (line 39):

int main(void)
{
  /* USER CODE BEGIN 1 */
	uint16_t value = {0x0000} ;
 
  /* USER CODE END 1 */
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
	 /* Set to 1 if an transfer error is detected */
  transferErrorDetected = 0;
 
  /* 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();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_DAC_Init();
  MX_TIM1_Init();
  MX_TIM2_Init();
  MX_USART2_UART_Init();
  MX_MotorControl_Init();
 
  /* Initialize interrupts */
  MX_NVIC_Init();
  /* USER CODE BEGIN 2 */
	DMA_Config();
 
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  NVIC->STIR = EXTI15_10_IRQn;  /* what is this for? 5/6/20  */
	
	/* Start TIM2 then enable capture 									 */
	TIM2->CR1 |= TIM_CR1_CEN_Msk;     /* start the timer */
	/* *** TIM2 captrure/compare enable register: CCER 	 */
	value = 0x0100 | 0x0001;
	/* Set the TIM2_CCER register:											 */
	TIM2->CCER = value;
	/* enable TIM2 DMA interrupts */
	TIM2->DIER = 0x0A00;
 
  while (1)
  {

Here are the contents of DMA_Config for setting up dma channels 1 and 5:

static void DMA_Config(void)
{
  /*##-2- Select the DMA functional Parameters for chan1 & chan3 ######################*/
  hdma_tim2_ch1.Init.Direction = DMA_PERIPH_TO_MEMORY;          /* M2M transfer mode                */
  hdma_tim2_ch1.Init.PeriphInc = DMA_PINC_DISABLE;              /* Peripheral increment mode Enable */
  hdma_tim2_ch1.Init.MemInc = DMA_MINC_DISABLE;                 /* Memory increment mode Enable     */
  hdma_tim2_ch1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; /* Peripheral data alignment : Word */
  hdma_tim2_ch1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;    /* memory data alignment : Word     */
  hdma_tim2_ch1.Init.Mode = DMA_CIRCULAR;                       /* Circular DMA mode                */
  hdma_tim2_ch1.Init.Priority = DMA_PRIORITY_HIGH;              /* priority level : high            */
	
	hdma_tim2_ch3.Init.Direction = DMA_PERIPH_TO_MEMORY;          /* M2M transfer mode                */
  hdma_tim2_ch3.Init.PeriphInc = DMA_PINC_DISABLE;              /* Peripheral increment mode Enable */
  hdma_tim2_ch3.Init.MemInc = DMA_MINC_DISABLE;                 /* Memory increment mode Enable     */
  hdma_tim2_ch3.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; /* Peripheral data alignment : Word */
  hdma_tim2_ch3.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;    /* memory data alignment : Word     */
  hdma_tim2_ch3.Init.Mode = DMA_CIRCULAR;                       /* Normal DMA mode                  */
  hdma_tim2_ch3.Init.Priority = DMA_PRIORITY_HIGH;              /* priority level : high            */
 
  /* ##-3- Select the DMA instance to be used for the transfers # */
  hdma_tim2_ch1.Instance = DMA1_Channel5;
  hdma_tim2_ch3.Instance = DMA1_Channel1;
 
  /*##-4- Initialize the DMA channel ##########################################*/
  if (HAL_DMA_Init(&hdma_tim2_ch1) != HAL_OK)
  {
    /* Initialization Error */
    Error_Handler();
  }
	if (HAL_DMA_Init(&hdma_tim2_ch3) != HAL_OK)
  {
    /* Initialization Error */
    Error_Handler();
  }
  
  /*##-5- Select Callbacks functions called after Transfer complete and Transfer error */
  HAL_DMA_RegisterCallback(&hdma_tim2_ch1, HAL_DMA_XFER_CPLT_CB_ID, TransferComplete1);
	HAL_DMA_RegisterCallback(&hdma_tim2_ch3, HAL_DMA_XFER_CPLT_CB_ID, TransferComplete3);
	
  HAL_DMA_RegisterCallback(&hdma_tim2_ch1, HAL_DMA_XFER_ERROR_CB_ID, TransferError);
	HAL_DMA_RegisterCallback(&hdma_tim2_ch3, HAL_DMA_XFER_ERROR_CB_ID, TransferError);
	
	/*##-6- Configure NVIC for DMA transfer complete/error interrupts ##########*/
  /* Set Interrupt Group Priority */
  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
 
  HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
	
	/*##-7- Start the DMA transfers using the interrupt mode ####################*/
  /* Configure the source, destination and buffer size DMA fields and Start DMA transfer */
  /* Enable All the DMA interrupts */
  if (HAL_DMA_Start_IT(&hdma_tim2_ch1, (uint32_t)&TIM2->CCR1, (uint32_t)&buffer1, BUFFER_SIZE) != HAL_OK)
  {
    /* Transfer Error */
    Error_Handler();
  }
	if (HAL_DMA_Start_IT(&hdma_tim2_ch3, (uint32_t)&TIM2->CCR3, (uint32_t)&buffer2, BUFFER_SIZE) != HAL_OK)
  {
    /* Transfer Error */
    Error_Handler();
 
  }
}

I appreciate all advise, guidance, suggestions ... Thanks!!

#[STM32 MCUs]​  #DMA​  #STM32F3​ 

> TransferComplete interrupt routines are not executed

Are these interrupts enabled in the respective DMA stream control register?

Are they enabled in NVIC?

Do the DMA indeed run to completion? (counterexample would be a very slowly running timer and DMA set with very high NDTR)

Do you observe in the interrupt routines (ISR) themselves (i.e. no Cube callback)? Are these ISR properly inserted in the vector table (see vector table in disasm/memory watch in debugger and compare to address of given ISR, e.g. in mapfile)?

Even if you use Cube, you still can/should read out and check the peripherals' registers, for debugging purposes.

JW

PPott.1
Associate II

@BTrem.1​ what was your solution? I have the same problem on the stm32g030

BTrem.1
Senior II

Hi,

This was some time ago so I forget the solution I found. However, I did write a blog on the use of the DMA in a phase detector. This was the problem I was solving at the time. My blog link is here:

https://tremaineconsultinggroup.com/phase-detector-using-stm32f303re-dma/

It includes the code snippets that involve the DMA,

Hope this helps