cancel
Showing results for 
Search instead for 
Did you mean: 

Strange behaviour when I overwrite a slave timer's registers after CubeMX

Claegtun
Associate III

Hello,

I was working on a project and came across a rather strange behaviour with a triggered slave timer. I have recreated the behaviour in a separate isolated CubeIDE project as not to distract you with the irrelevant parts. So, forgive the contrived scenario since it lacks the context of my project (which is communicating with an external ADC but that is besides the point). This isn't a big problem for me since it is a relatively minor bug that came about when I was playing around. However, I am really more curious as to why this happens, and I thought that I can at least document it here.

In this example, I am using a NUCLEO-H723ZG board, and I have two timers, TIM2 and TIM3, both with PWM outputs. The former is set up as a basic PWM generator, and the latter is set up in one-pulse-mode as a slave triggered by the former's update, i.e. TRGO. TIM3's source is thus ITR1 as according to Table-355 in the reference-manual (RM0468) The timing is such:

 TIM2TIM3
PSC00
ARR499399
CRR1250390

To be honest, the exact values do not matter too much, but I thought that I would give as much detail so that one of you can replicate it.

This is all created in CubeMX. Attached is the generated tim.c file and the .ioc file (never mind, can't attach it).

Here is the code in main():

 

 

/**
  * @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_TIM2_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
  //TIM3->CCR1 = 200;

  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
  HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	HAL_GPIO_TogglePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin);
	HAL_Delay(500);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

 

 

So, what happens is that TIM2_CH1 outputs a PWM signal with a duty of about 50%. Then, TIM3_CH1 goes high for 390 bus-clock-cycles and then low for the remaing 10 cycles and then high again. This is for each rising edge of TIM2_CH1. I know that this is an odd scenario, but bear with me; the point of this post is not the exact timing by what happens to the registers. So, the result is seen below; this is expected.

fig_1.png

However, if one wanted TIM3's pulse-length to be shorter, i.e. CRR1 = 200 instead of 390, and one changed it by overwriting the CCR1 register directly (i.e. uncomment the line above HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1)), then the result is somewhat expected as seen below (also attached). All other pulses are 200 bus-clock-cycles long as expected (I will admit that this is a bit hard to see in the screenshot). However, the first triggered pulse is still 390 cycles long as configured in CubeMX even though the CCR1 should be 200. It is almost as if the CCR1 has some kind of 'memory' of the original CubeMX value. Keep in mind that this is before both timers are started. The same thing happens when I put a breakpoint at the line where TIM3 is started and manually wait before resuming; so, it does not seem to be a race-condition.

fig_2.png

Here are both timers' registers after CCR1 is overwritten as 200. Clearly, the CCR1 is 200 before both timers are started.

fig_3.png

fig_4.png

A similar thing happens with TIM8's RCR. I had TIM8 outputting repeated short pulses triggered by TIM2 like before with TIM3. In CubeMX, I originally had the number of repetitions as 64 but changed it to 32 by directly writing to the RCR. The result is 64 pulses on the first rising edge and then intended 32 for the rest.

Of course, this is all simply fixed by sticking to making changes in CubeMX. But it is nevertheless startling and a bit disconcerting.

Am I missing something? I thought that after writing to a register, that's it. Its former content should not matter. Is there some kind of FIFO buffer before the register? Does it need some kind of event for the content to update?

Let me know if you need any more information. I would be interested if anyone had an explanation or could at least replicate it.

Thanks

1 ACCEPTED SOLUTION

Accepted Solutions
Sarra.S
ST Employee

Hello @Claegtun, welcome to ST Community, 

I would like to thank you for the quality of your explanation! 

I believe your question in tightly related to @Jan Waclawek gotcha.

I will try to replicate the use case and get back to you! 

 

 

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

View solution in original post

4 REPLIES 4
MasterT
Lead

TIM_AUTORELOAD_PRELOAD_ENABLE?

Sarra.S
ST Employee

Hello @Claegtun, welcome to ST Community, 

I would like to thank you for the quality of your explanation! 

I believe your question in tightly related to @Jan Waclawek gotcha.

I will try to replicate the use case and get back to you! 

 

 

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

This seems to be it. Silly me not researching enough. Thanks

Yeah, as Sarra.S said, it seems to be because the registers are preloaded. I will have to try that out to see if that is the case, but I am willing to accept this. Thanks