Electrical – How to dynamically adjust a timer with STM32

interruptsmicrocontrollerregisterstm32f4timer

I've got this timer (TIM4) that's in PWM mode. I'm outputting one PWM channel and i want to wait a bit, and then grab the latest ADC samples from a DMA conversion.

TIM4 -> ARR is 4096
TIM4 -> CCR1 is dynamic, but it starts around 200

I want to start at the rising edge of the TIM4 pulse, wait half the of the Pulses on-time, and then grab the latest and greatest DMA samples…Here's a snippet of what I've got going on:

Where things seems to come unglued is the line: TIM5->ARR = TIM4->CCR1/2;.
What is strange, is that if I put a constant in there, like TIM5->ARR = 20;, it works fine…It doesn't fire in the middle of the on-pulse of TIM4, but it does fire at the 20/FCLK you would expect.

I read DM00236305.pdf, but I couldn't make sense of what they were talking about with Shadow registers, which is what I think my problem is. I also tried to follow what was said here, but that was also rather vauge, and I wasn't sure if it applied, since he was talking about output compares rather than auto-reload registers.

How do I adjust TIM5->ARR to track to one-half of what is in TIM4->CCR1?

void TIM5_IRQHandler(void)
{
  /* USER CODE BEGIN TIM5_IRQn 0 */

    HAL_GPIO_WritePin(GPIOA, TX_Pin, SET);
    HAL_TIM_Base_Stop(&htim5);
    while(!(DMA2->LISR & DMA_LISR_TCIF0));
    motorDummy_FOC.curr_a_sense = ADCValue[0];
    motorDummy_FOC.curr_b_sense = ADCValue[1];
    update_PWM(&motorDummy_FOC);
    HAL_GPIO_WritePin(GPIOA, TX_Pin, RESET);
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
  if (htim == &htim4){
    HAL_GPIO_WritePin(GPIOA, RX_Pin, SET);
    GPIOC->ODR = 0b0000000000000110;
    //TIM4->CR1 &= ~(1<<0);
    MX_TIM5_Init();
    TIM5->ARR = (TIM4->CCR1/2);
    HAL_TIM_Base_Start_IT(&htim5);
    HAL_TIM_Base_Start(&htim5);
  }

}
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim){

  if (htim == &htim4){
    GPIOC->ODR = 0b0000000000000100;
    HAL_GPIO_WritePin(GPIOA, RX_Pin, RESET);

  }
}

void update_PWM(motorFOC *c){
  if(c->curr_b_sense < c->curr_b_commanded)
  {c->i_feedback++;}
  else if(c->curr_b_sense > c->curr_b_commanded)
  {c->i_feedback--;}
  TIM4->CCR1 = c->i_feedback;
}

Best Answer

I think the mistake that you are doing is you are stopping the timer base clock in IRQHandler() and want to update it in PeriodElapsedCallback(), which will be executed inside the IRQHandler().

The thing you are looking for is __HAL_TIM_SET_AUTORELOAD macro.

There are individual macros defined in *_hal_tim.h files to update the ARR, CCR etc. values. The only thing you need to do is grab the CCR value dynamically and update the macro, you do not need to stop and start the timer..! The same problem is addressed here.