cancel
Showing results for 
Search instead for 
Did you mean: 

Is it possible to compare compare the output using STM32's timer interrupts

JTurn.2
Senior

I am currently learning to use timer interrupts using the HAL library on the STMF769I-DISCO. I am trying to get the interrupt to activate when it reaches a certain value. From my understanding, the interrupt activates when the counter period overflows. As I'll have different time periods to compare, I can't set the counter period to one of the values. Instead, I'd like to do something similar to Arduino's compare match timer interrupt method where you compare if the timer's value to see if it matches the time you want. Is this possible on STM32. If so, could someone kindly provide an example or explain how to do it? If not, would I have have to set the counter period to the period I want the timer interrupt to activate and re-initialise the timer every time I want to change the duration of the timer interrupt?

Edit 1:

I have managed to get the timer to work but I can't seem to manually reset the counter properly. When I use TIM5->CNT=0; or the HAL function shown below, the timer seems to reset but it then takes longer than 10 secs for the message to print out.

Edit 2:

I should add that both reset methods I have mentioned works but it just takes way too long to reset. For example, the timer resets after 30+ seconds when I set the timer to interrupt every 10 seconds.

#include "main.h"
 
TIM_HandleTypeDef htim5;
 
UART_HandleTypeDef huart1;
 
/* USER CODE BEGIN PV */
uint32_t uhCapture = 0; //Capture buffer/register
/* USER CODE END PV */
 
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_TIM5_Init(void);
/* USER CODE BEGIN PFP */
 
/* USER CODE END PFP */
 
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
int flag=0;
/* USER CODE END 0 */
 
/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
 
  /* USER CODE END 1 */
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* 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();
  MX_USART1_UART_Init();
  MX_TIM5_Init();
  /* USER CODE BEGIN 2 */
  //Note: SystemCoreClock=64MHz
  HAL_TIM_OC_Start_IT(&htim5, TIM_CHANNEL_1); 
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
    if (flag==1) // reset timer
	{
	  HAL_TIM_OC_Stop_IT(&htim5, TIM_CHANNEL_1); 
	  __HAL_TIM_SET_COUNTER(&htim5,0); //set counter to 0
	  HAL_TIM_OC_Start_IT(&htim5, TIM_CHANNEL_1); 
	}
  }
  /* USER CODE END 3 */
}
 
static void MX_TIM5_Init(void)
{
 
  /* USER CODE BEGIN TIM5_Init 0 */
 
  /* USER CODE END TIM5_Init 0 */
 
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};
 
  /* USER CODE BEGIN TIM5_Init 1 */
 
  /* USER CODE END TIM5_Init 1 */
  htim5.Instance = TIM5;
  htim5.Init.Prescaler = 640-1;  
  htim5.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim5.Init.Period = 4294967296-1;  
  htim5.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim5.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim5) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim5, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_OC_Init(&htim5) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim5, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_TIMING;
  sConfigOC.Pulse = 100000-1;  // The no. of desired ticks the timer should execute.
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_OC_ConfigChannel(&htim5, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM5_Init 2 */
 
  /* USER CODE END TIM5_Init 2 */
 
}
 
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef* htim)  
{
 
    if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1){
    	uhCapture = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);  
    	/* Set the Capture Compare Register value */
    	if (__HAL_TIM_SET_COMPARE(&htim5, TIM_CHANNEL_1, (uhCapture + 100000-1)))  
    	{
    		uint8_t testt[] = "alive"; //Data to send
    		HAL_UART_Transmit(&huart1,testt,strlen(testt),100);// Sending in normal mode
    	}
 
    }
}

7 REPLIES 7
LCE
Principal

That's what the CCRx (capture / compare) registers und interrupts are for.

I recommend using direct register settings to set this up, not HAL, and I don't think you will get there using CubeMX.

So check the ref manual about the CCRx registers, how to set these up with the CCMRx, CCER and DIER registers.

Use output compare mode, without actually triggereing any GPIOs (I think that's output compare mode "frozen", not sure though).

Basically you write a timer value in CCR1 -> interrupt on compare, next timer value in CCR2 -> interrupt on compare, etcpp...

Maybe someone else has some examples.

And there are many timer tutorials out there.

Hi, thank you for your advice. I have tried searching for some examples on how to directly set the registers but all of the tutorials I found use HAL. I have also tried reading the manuals and it's a little too overwhelming for me at the moment.

TIM5->CCR1 += 1000; // Advance trigger point by 1000 ticks

CC1 interrupt when TIM5->CNT == TIM5->CCR1

htim5.Instance->CCR1 = htim5.Instance->CNT + 1234;

STM32Cube_FW_F7_V1.16.0\Projects\STM32756G_EVAL\Examples\TIM\TIM_OCToggle\Src\main.c

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

> I have also tried reading the manuals and it's a little too overwhelming for me at the moment.

Write simple test programs (you can take the CubeMX output as basis, but omit any TIM setup, so that you can get your own feet wet), and play with the timer (and GPIO etc.) registers in debugger, observing both registers and pins (using oscilloscope).

And read the manual again.

JW

Hi, thank you for your help. I was able to set the output compare timer based on the example you provided. However, I think the example uses HAL instead of directly setting the registers if I'm not mistaken.

Also, I am having a bit of trouble manually resetting the timer interrupt. (I have updated my question above.) For example, if another condition is fulfilled, I call __HAL_TIM_SET_COUNTER(&htim5,0) to reset the counter to 0. But for some reason the timer will then take longer than usual to reach the set counter value. Am I doing it wrong is there another way of doing it?

Hi, thank you for your advice. I was able to set a timer but am having some trouble with manually resetting the timer as the timer then takes longer than 10 secs to print a message after manually setting the counter to 0. I have updated the code above. Do you provide me with some guidance?

I don't use Cube and don't understand what Cube functions do and not willing to look into them, sorry.

JW