cancel
Showing results for 
Search instead for 
Did you mean: 

TIM8 Input capture mode using firmware trigger?

BTrem.1
Senior II

I have a STM32G431 MCU board and TIM8 is triggered by an external input pin to perform a counter capture and initiate a DMA transfer for CH1. What I would like to also do on TIM8 is perform a counter capture based on a software trigger to CH3. Is this possible?

And yes I have read the Ref Manual ;) But I don't see any discussion of software triggers for the counters.

EDIT addition: Worst case I will externally connect a GPIO output to the TIM8_CH3 input and use a dma channel to capture & store the timer count value. In my high priority ISR I will write the GPIO to initiate the capture.

Thanks,

BT

1 ACCEPTED SOLUTION

Accepted Solutions

Setting TIM8_EGR.CCG3 alone will set the CC3 event (thus trigger related DMA if enabled etc.). Don't set TIM8_EGR.TG, that's an unrelated signal (although confusingly named "trigger").

JW

View solution in original post

6 REPLIES 6

Setting TIMx_EGR.CCxG didn't work?

JW

Thanks for pointing me at this register. I'm trying to using CubeMX to set this up and for TIM8_CH3 it will allow me to set Input Capture Direct mode, which uses the external pin, but the Input Capture by TRC is greyed out. The other options are Output Compare, PWM modes and Forced Output. I don't think these will do want I want, capture the count in the shadow register.

The greyed out TRC shows a msg says ITRx must be selected as a source so I selected ITR3 to be the source. [Q?] Will this interfere with my TIM8_CH1 being triggered on the input pin?

BT

Cube/CubeMX inevitably supports only a fraction of the all possible settings, a selection of the "most usual ones". Anything out of ordinary means that Cube/CubeMX gets into way.

Why would you want to select TRC at all? Use TIM8_CH3 as input ("direct"), but simply don't assign any pin to it in GPIO. But if you select TRC, make sure the source you've selected in SMCR.TS (tim4_trgo, if I see it correctly) does not change.

If CH1 is set to input captore from the input pin ("direct"), then setting SMCR.TS has no effect on it.

JW

I thought if I selected "direct" mode I had no other choice but to use the GPIO pin. I'll give your suggestion a try and use TIM8_CH3 in direct mode with TIM8_EGR.CCG3 set then use TIM8_EGR.TG to trigger CH3.

I'll let you know how it goes. ~Thanks

BT

Setting TIM8_EGR.CCG3 alone will set the CC3 event (thus trigger related DMA if enabled etc.). Don't set TIM8_EGR.TG, that's an unrelated signal (although confusingly named "trigger").

JW

Hi-

Following up, here is how I set up the TIM8 on a STM32G431C8x. This all seems to work. I am using the TIM8_CH3 as my second input but the trigger actually comes internally. I have a firmware signal for which I look for a zero crossing, and if it occurs I execute this line:

/* add 'limiting' function that gives square-wave */
    uint16_t limited;
    if(y0 > 0) limited = 3048;
    else limited = 1048;	
    /** capture counter & trigger DMA1_CH2 if positive crossing
        * this generates interrupt for phase detector to do processing.
        */
if( (limited == 3048) && (old_limit == 1048))
    TIM8->EGR |=  TIM_EGR_CC3G ;

Here is how I set up TIM8 and DMA:

	#define PHASE_DETECT
	#ifdef PHASE_DETECT
	{
		/* TIM8_CH1 is capture/compare from input pin and
		   TIM8_CH3 is capture/compare FW triggered by TIM8_EGR.CCG3  
		 */     		
	  /* enable TIM8 DMA interrupts */
	  TIM8->DIER |= (TIM_DIER_CC3DE | TIM_DIER_CC1DE) ;		
		/* enable TIM8 capture / compare */
		TIM8->CCER |= ( TIM_CCER_CC1E | TIM_CCER_CC3E ) ;
		/* enable TIM8 */
		TIM8->CR1 |= TIM_CR1_CEN; 
	}
/**
  * @brief TIM8 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM8_Init(void)
{
  /* USER CODE BEGIN TIM8_Init 0 */
  /* USER CODE END TIM8_Init 0 */
 
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_IC_InitTypeDef sConfigIC = {0};
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
 
  /* USER CODE BEGIN TIM8_Init 1 */
  /* USER CODE END TIM8_Init 1 */
  htim8.Instance = TIM8;
  htim8.Init.Prescaler = 32;
  htim8.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim8.Init.Period = 48000;
  htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim8.Init.RepetitionCounter = 0;
  htim8.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_IC_Init(&htim8) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
  sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
  sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
  sConfigIC.ICFilter = 0;
  if (HAL_TIM_IC_ConfigChannel(&htim8, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_IC_ConfigChannel(&htim8, &sConfigIC, TIM_CHANNEL_3) != HAL_OK)
  {
    Error_Handler();
  }
  sBreakDeadTimeConfig.BreakAFMode = TIM_BREAK_AFMODE_INPUT;
  sBreakDeadTimeConfig.Break2AFMode = TIM_BREAK_AFMODE_INPUT;
  if (HAL_TIMEx_ConfigBreakDeadTime(&htim8, &sBreakDeadTimeConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM8_Init 2 */
  /* USER CODE END TIM8_Init 2 */
}

and the DMA config:

static void DMA_Config(void)
{
  /*##-2a- Select the DMA functional Parameters for TIM8 chan1 ######################*/	
	hdma_tim8_ch1.Init.Direction = DMA_PERIPH_TO_MEMORY;          /* M2M transfer mode                */
  hdma_tim8_ch1.Init.PeriphInc = DMA_PINC_DISABLE;              /* Peripheral increment mode Enable */
  hdma_tim8_ch1.Init.MemInc = DMA_MINC_DISABLE;                 /* Memory increment mode Enable     */
  hdma_tim8_ch1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; /* Peripheral data alignment : Word */
  hdma_tim8_ch1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;    /* memory data alignment : Word     */
  hdma_tim8_ch1.Init.Mode = DMA_CIRCULAR;                       /* Normal DMA mode                  */
  hdma_tim8_ch1.Init.Priority = DMA_PRIORITY_HIGH;              /* priority level : high            */
	
	/*##-2b- Select the DMA functional Parameters for TIM8 chan3 ######################*/	
	hdma_tim8_ch3.Init.Direction = DMA_PERIPH_TO_MEMORY;          /* M2M transfer mode                */
  hdma_tim8_ch3.Init.PeriphInc = DMA_PINC_DISABLE;              /* Peripheral increment mode Enable */
  hdma_tim8_ch3.Init.MemInc = DMA_MINC_DISABLE;                 /* Memory increment mode Enable     */
  hdma_tim8_ch3.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; /* Peripheral data alignment : Word */
  hdma_tim8_ch3.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;    /* memory data alignment : Word     */
  hdma_tim8_ch3.Init.Mode = DMA_CIRCULAR;                       /* Normal DMA mode                  */
  hdma_tim8_ch3.Init.Priority = DMA_PRIORITY_HIGH;              /* priority level : high            */
 
  /* ##-3- Select the DMA instance to be used for the transfers # */
	/* TIM8 ch1 is DMA ch 1 */
  hdma_tim8_ch1.Instance = DMA1_Channel1;
	/* TIM8 ch3 is DMA ch 2 */
  hdma_tim8_ch3.Instance = DMA1_Channel2;
 
  /*##-4- Initialize the DMA channel ##########################################*/
  if (HAL_DMA_Init(&hdma_tim8_ch1) != HAL_OK)
  {
    /* Initialization Error */
    Error_Handler();
  }
  if (HAL_DMA_Init(&hdma_tim8_ch3) != HAL_OK)
  {
    /* Initialization Error */
    Error_Handler();
  }
	
  /*##-5- Select Callbacks functions called after Transfer complete and Transfer error */
	HAL_DMA_RegisterCallback(&hdma_tim8_ch1, HAL_DMA_XFER_CPLT_CB_ID, TransferCompleteRef);
	HAL_DMA_RegisterCallback(&hdma_tim8_ch3, HAL_DMA_XFER_CPLT_CB_ID, TransferCompleteFb);
	
	HAL_DMA_RegisterCallback(&hdma_tim8_ch1, HAL_DMA_XFER_ERROR_CB_ID, TransferErrorRef);
	HAL_DMA_RegisterCallback(&hdma_tim8_ch3, HAL_DMA_XFER_ERROR_CB_ID, TransferErrorFb);
		
 /*##-6- Configure NVIC for DMA transfer complete/error interrupts ##########*/
  /* Set Interrupt Group Priority */
  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 3, 2); /* sets intr # and priority */
  HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);         /* enables intr */
 
  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 3, 2); /* sets intr # and priority */
  HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);         /* enables intr */
	
	/*##-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_tim8_ch1, (uint32_t)&TIM8->CCR1, (uint32_t)&buffer1, BUFFER_SIZE) != HAL_OK)
  {
    /* Transfer Error */
    Error_Handler();
  }
	
if (HAL_DMA_Start_IT(&hdma_tim8_ch3, (uint32_t)&TIM8->CCR3, (uint32_t)&buffer2, BUFFER_SIZE) != HAL_OK)
  {
    /* Transfer Error */
    Error_Handler();
  }
}