TIM2 configuración de DMA para stm32h7

1

Mi problema: No puedo configurar DMA para que funcione correctamente en el evento Input Capture. Los datos no se transfieren y se produce un error.

static void my_TIM2_initInputCaptureTimer(void) {

  // enable clock source for timer
  RCC->APB1LENR |= (0x1 << 0);
  // set prescaler to 200
  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 & falling edge
  TIM2->CCER |= (0x1 << 1);
  TIM2->CCER |= (0x1 << 3);
  // prescaler to (0)
  TIM2->CCMR1 |= (0x0 << 2);
  // enable DMA interrupt & Capture/Compare interrupt
  TIM2->DIER |= (0x1 << 9) | (0x1 << 1);
  // capture enabled
  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);

}

configuración de DMA:

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 = 10;

  // 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);
  // set transfer error interrupt
  DMA1_Stream0->CR |= (0x1 << 2);
  // enable DMA1
  DMA1_Stream0->CR |= (0x1 << 0);
  // enable IRQ
  NVIC_EnableIRQ(DMA1_Stream0_IRQn);
  printf("DMA1_Stream0 %u \r\n", (DMA1_Stream0->CR & 0x1));
}

Rutinas de interrupción:

void TIM2_IRQHandler(void) {

  InCapTick = TIM2->CCR1;
  // reset interrupt flag
  TIM2->SR = 0;

  tick = systick_ms;
  flag++;
}

void DMA1_Stream0_IRQHandler(void) {

  printf("within\r\n");
  printf("LISR: %u \r\n", DMA1->LISR);
  // clear interrupt flag
  DMA1->LIFCR |= (0x1 << 3) | (0x1 << 5);

}

Proyecto compilado completo (gcc-arm \ make) para aquellos que estén interesados: enlace

(placa stm32h743zi-nucleo) comportamiento esperado: (cuando presiona el botón de usuario (el azul) - > PG0 pin obtener el estado SET (1) - > entonces ingrese el pin de captura (PA5, deben estar conectados mediante un jumper) obtenga la transición de alto a bajo y capture primero el valor (lo genera a través del puerto de comunicaciones) cuando libera el botón, el pin de captura de entrada obtiene una transición alto-bajo y captura otro valor (lo genera a través del puerto de comunicaciones), pero ninguno de estos eventos no inicia la solicitud DMA de inicio.

Los datos se enviarán a través del puerto COM a una velocidad de 115200.

    
pregunta stronk_kisik

1 respuesta

1

DMA se inicializó correctamente. El problema fue que la matriz de búfer no se inicializó en ninguna área de memoria SRAM, por lo que cuando DMA intenta alcanzar esa memoria a través de AHB (no es posible), DMA se bloquea con error y configura TEI_flag (interrupción de error de transferencia).

La forma más sencilla de hacer que esto funcione (y, obviamente, no es la forma correcta, pero para fines de conocimiento funciona)

#define Destination_Address ((unsigned int)0x30000000)
  DMA1_Stream0->M0AR = Destination_Address;

0x30000000 -> es el límite de la memoria SRAM1

y necesita habilitar primero SRAM1 \ 2 \ 3:

static void my_SRAM_init(void) {
  // activate SRAM1
  RCC->AHB2ENR |= (0x7 << 29);   
}

puedes llegar a esa área con:

  uint32_t *Ptr_Dest = (uint32_t *)Destination_Address;
  printf("buffer: %lu %lu \r\n", *Ptr_Dest, *(Ptr_Dest + 1));

Para aquellos, esto no funcionará o sucederá algo de UB (datos dañados, ubicación extraña) posibles motivos:

  1. El caché (el caché habilitado podría dañar los datos)
  2. Sus direcciones deben estar alineadas con PSIZE y MSIZE

Ejemplo: si su MSIZE y PSIZE es una dirección de 32 bits, debe terminar en 0x4

Espero que esto ayude a alguien, porque esto fue un gran dolor en mi culo durante 3 días seguidos, lo odio.

    
respondido por el stronk_kisik

Lea otras preguntas en las etiquetas