cancel
Showing results for 
Search instead for 
Did you mean: 

How to properly configure DMA for TIM2 timer?

esukh
Associate III

TIM2 Timer initialization:

static void my_TIM2_initInputCaptureTimer(void) {
  
  // enable clock source for timer
  RCC->APB1LENR |= (0x1 << 0);
  // set prescaler to 1
  TIM2->PSC = 200 - 1;
 
  // choose TIM2_CH1 input
  TIM2->TISEL |= (0x0 << 0);
  // set channel 1 as input mapped on TI1
  TIM2->CCMR1 |= (0x1 << 0);
  // digital filter length (0)
  TIM2->CCMR1 |= (0x0 << 4);
  // rising edge
  TIM2->CCER |= (0x1 << 1);
  TIM2->CCER |= (0x1 << 3);
  // prescaler to (0)
  TIM2->CCMR1 |= (0x0 << 2);
  // enable DMA interrupt
  TIM2->DIER |= (0x1 << 9) | (0x1 << 1);
  // enable timer
  TIM2->CCER |= (0x1 << 0);
  // reset registers WARNING: need for preloading PSC  
  TIM2->EGR |= (0x1 << 0);
  
  // enable TIM3 timer
  TIM2->CR1 |= TIM_CR1_CEN;
  // enable interrupt request
  NVIC_EnableIRQ(TIM2_IRQn);
  // set priority
  NVIC_SetPriority(TIM2_IRQn, 1);
 
}

DMA with DMAMUX initialization:

static void my_DMA_init(void) {
  // enable DMA1 clocking
  RCC->AHB1ENR |= (0x1 << 0);
  // clear EN bit to 0
  DMA1_Stream0->CR &= ~(0x1 << 0);
  // safeguard EN bit reset
  while (DMA1_Stream0->CR & 0x1);
  // check LISR HISR registers
  if ((DMA1->HISR == 0) && (DMA1->LISR == 0))
    printf("status registers is clear\r\n");
  else
    printf("status register is not clear -- DMA wont start\r\n");
  // set peripheral addres
  DMA1_Stream0->PAR = TIM2_CCR1_Address;
  // set memory addres
  DMA1_Stream0->M0AR = (unsigned int)buffer;
  // set total number of data items
  DMA1_Stream0->NDTR = DMA_BUFFER_SIZE;
  
  // NOTE: configurate TIM2_CH1 interrupt route
  // set DMAMUX to route request (TIM2_CH1)
  DMAMUX1_Channel0->CCR |= 18U;
  
  // set DMA priority (very high)
  DMA1_Stream0->CR |= (0x3 << 16);
  // set memory data size (32)
  DMA1_Stream0->CR |= (0x2 << 13);
  // set peripheral data size (32)
  DMA1_Stream0->CR |= (0x2 << 11);
  // set memory addres increment  (enable)
  DMA1_Stream0->CR |= (0x1 << 10);
  // set peripheral addres increment (disable)
  DMA1_Stream0->CR |= (0x0 << 9);
  // set circular buffer mode (enable)
  DMA1_Stream0->CR |= (0x1 << 8);
  // set data transfer direction (peripheral to memory)
  DMA1_Stream0->CR |= (0x0 << 6);
  // set transfer complete interrupt
  DMA1_Stream0->CR |= (0x1 << 4);
  // enable DMA1
  DMA1_Stream0->CR |= (0x1 << 0);
  // enable IRQ
  NVIC_EnableIRQ(DMA1_Stream0_IRQn);
  printf("DMA1_Stream0 %u \r\n", (DMA1_Stream0->CR & 0x1));
}

DMA interrupt routine (code never reach this part even once)

void DMA1_Stream0_IRQHandler(void) {
 
  flag = 2;
  printf("within\r\n");
  // clear interrupt flag
  //DMA1->IFCR |= (0x1 << 0);
  
}

My bet is wrong DMAMUX configuration, but I have no idea what else I got to configure to make this work. In case you interested in full project: (stm32h743zi-nucleo -- gcc-arm\make -- .bin .hex files attached)

https://drive.google.com/open?id=1fwns5fKexGWJl64UDeYfDyFmSFA9BURZ

expected behavior (when you press user button (the blue one) ->PG0 pin get SET (1) state -> so input capture pin (PA5, they should be connected via jumper) get low-high transition and capture first value and send it in COM port, when you unpress button, input capture pin get high-low transition and capture another value and sent it via COM port, but none of this events do not kickstart DMA request.

Data will be outputted via com port with 115200 speed.

Thanks in advance

4 REPLIES 4

The number of people wanting to wade through register level H7 code is pretty limited. You'll need to use the debugger, and probing into the Peripheral View windows and inspect the registers, and status/error bit that might be flagging.

The IRQ Handler won't enter if the transactions aren't occurring, and this should be apparent from the address/count not advancing.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

I don't 'H7, but can't this be the problem?

0690X0000060S0aQAE.png

// NOTE: configurate TIM2_CH1 interrupt route

// set DMAMUX to route request (TIM2_CH1)

DMAMUX1_Channel0->CCR |= 18U;

I also am not fan of using magic values; instead, I recommend using the symbols from the CMSIS-mandated device header.

JW

esukh
Associate III

0690X000006Br6rQAC.png

(RM0433 Reference manual STM32H743/753 advanced ARM ® -based 32-bit MCUs) 4th Revision (but it's looks like your document is different from mine, i should look into it too)

I'm totally agree about magic numbers but this is some kind of testing\fluent code I just poke into registers and trying to understand documentation.

The most interesting thing that there are few another question about dmamux configuration (one from stackoverflow, another from local resource) and none of them were answered.

Indeed. I have an old copy of the RM.

I don't know then.

0690X000006BrBwQAK.png