cancel
Showing results for 
Search instead for 
Did you mean: 

inconsistent behaviour in TIMER and CCxR interrupt

evank
Associate

Hi, I'm using an STM32L053R6Tx chip

I've implemented at TMR2_interrupt hander it gets triggered on ARR overflow and CC1F

I'm using the interrupt to trigger a GPIO output to work like a PWM the

- GPIO is high when CNT is less than CCR1

- GPIO is low when CNT is greater than CCR1

(I couldn't use the PWM hardware pin because its not wired to the correct pin on the circuit board hence i have to do it manually)

the Timer 2 frequency with ARR = 200 is approx. 22khz

The code works as expected i.e. when CCR1 value triggers before the interrupt is completed e.g. for CCR1 values between 1-5 i.e. same PWM size for any value between 1-5. I expect this case. PWM is capped at approx. 2% (due to time it takes to execute the interrupt)

For CCR1 value > 10 up to 200 the GPIO works normally as expected e.g. is

CCR1 = 50 the PWM is 25% 

CCR1 = 100 give 50% PWM

CCR1 = 200 give 100% PWM

 

The problem I have is when I set CCR1 values between 6-8 I get 100% PWM output.

Also note this only happens when I set the CCR1 value inside the interrupt. Alternatively if I set CCR1 = 6 only once and outside the interrupt then the PWM works fine.

Is there something that happens to the interrupts when you set CCR1 value inside the interrupt?

#NOTE Please consider answers carefully since interrupt code is more intricate that it seems.

 

Source code below

 

 

 

void TIM2_IRQHandler(void) {
	
	if (READ_BIT(TIM2->SR, TIM_SR_UIF)) {
		WRITE_REG(TIM2->CCR1, 3); //TODO: updating the register here to a value around 6 causes PWM to be full on
		CLEAR_BIT(TIM2->SR, TIM_SR_UIF);
		if (READ_REG(TIM2->CCR1) != 0) { //don't blip when zero
			LED_SET_RED();
		}
	}

	if (READ_BIT(TIM2->SR, TIM_SR_CC1IF)) {
		LED_CLEAR_RED();
		CLEAR_BIT(TIM2->SR, TIM_SR_CC1IF);
	}

}

/**
 * TIM2 CLK = 32MhZ
 * TIM2 PSC = 8 = 4Mhz
 * TIM2 ARR = 200 = 20khz
 */
void app_pwm_init() {
	HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
	HAL_NVIC_EnableIRQ(TIM2_IRQn);

	__HAL_TIM_ENABLE_IT(&htim2, TIM_IT_UPDATE);
	__HAL_TIM_ENABLE_IT(&htim2, TIM_IT_CC1);
	HAL_TIM_Base_Start(&htim2);
	WRITE_REG(TIM2->CCR1, 3);
}

 

 

 

 

 

 

static void MX_TIM2_Init(void)
{

  /* USER CODE BEGIN TIM2_Init 0 */

  /* USER CODE END TIM2_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  /* USER CODE BEGIN TIM2_Init 1 */

  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 8;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 200;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM2_Init 2 */

  /* USER CODE END TIM2_Init 2 */

}

 

 

 

1 ACCEPTED SOLUTION

Accepted Solutions

> CLEAR_BIT(TIM2->SR, TIM_SR_UIF);

Don't use RMW to clear TIMx_SR bits.

Btw. you should also switch on compiler optimizations when working on timing sensitive code.

JW

View solution in original post

1 REPLY 1

> CLEAR_BIT(TIM2->SR, TIM_SR_UIF);

Don't use RMW to clear TIMx_SR bits.

Btw. you should also switch on compiler optimizations when working on timing sensitive code.

JW