cancel
Showing results for 
Search instead for 
Did you mean: 

Using Timer Global Interrupt crashes board

Pepijn
Associate II

I have an Arduino Giga (STM32H7). I'm trying to generate an interrupt on the Catch/Compare even of TIM5_CH3. TIM5 is set to one pulse mode and triggered as a slave to TIM1, they generate some PWMs; everything is working absolutely fine there. Also, I've successfully used the CC interrupt of TIM1, and now I'm trying to do the same for TIM5, which only has a global interrupt handler. I've reduced my program to its simplest form for demonstration purposes:

 

 

TIM5->DIER = 0; //disable all interrups on TIM5
TIM5->SR = 0;   //set all flags down
TIM5->DIER |= TIM_DIER_CC3IE;    //enable interrupt from CH3

NVIC_EnableIRQ(TIM5_IRQn); //enable TIM5 ISR
	
// I don't set the priority here, doesn't seem to matter


extern "C" void TIM5_IRQHandler(void){
  TIM5->SR = 0; //set all flags to 0 again
}

 

 

For some reason, this makes the board unresponsive. I feel like I'm missing something obvious, even though this feels very safe. Only CH3 can generate an interrupt, which it does successfully (since it only crashes when the DIER_CC3IE is set). Then I just set its flag to 0 again (and all others, just for the sake of it).

Any help would be greatly appreciated! 

 

 

 

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
Pepijn
Associate II

Alright, I found the issue. TIM5 is used by the Arduino Giga for things such as writing to the serial port. It probably has other uses as well, but I noted that anytime Serial.println() was called for example, the counter TIM5 CR1 CEN would be enabled... And I'm sure the system interferes and somehow constantly triggers the ISR. So yeah, there seems to be no way to fix this, and it's rather unfortunate that there is no proper documentation from Arduino's side telling me that TIM5 is used for system tasks, but at least I know now... Thanks for the help anyways!

View solution in original post

11 REPLIES 11
TDK
Guru

Is that channel set up in input capture mode? Set a breakpoint in the interrupt and show the value of all TIM5 registers when it gets there.

Issue is no doubt that the interrupt gets called repeatedly, likely correctly.

If you feel a post has answered your question, please click "Accept as Solution".
Pepijn
Associate II

I set it as output capture, to generate a PWM (which works correctly), using

 

 

  TIM5->CCMR2   &= TIM_CCMR2_OC3M_Msk;              // for TIM5_CH3
  TIM5->CCMR2   |= (0x7UL << TIM_CCMR2_OC3M_Pos);

 

 

Okay, so you're getting an interrupt on every pulse of the PWM. What is your pulse frequency?

If you feel a post has answered your question, please click "Accept as Solution".
Pepijn
Associate II

With regards to the debugger, the Arduino IDE that I'm using doesn't support debugging the Giga board as far as I can find... 

The frequency is around 50Hz. Lowering it doesn't change behaviour. For completeness, here all all lines of code involving TIM1 and TIM5 in my code.

 

RCC->APB2ENR   |= RCC_APB2ENR_TIM1EN;     // for TIM1
RCC->APB1LENR  |= RCC_APB1LENR_TIM5EN;    // for TIM5

// Set Output Compare Mode for Timers_Channels.
  // 6:  PWM mode 1 - In upcounting, channel is active as long as TIMx_CNT<TIMx_CCR1, else inactive.
  // 7:  PWM mode 2 - Inversed... active = low.

  // Channels 1, 2 are in CCMR1. Channels 3,4 are in CCMR2, etc...

  TIM1->CCMR1   &= ~TIM_CCMR1_OC2M_Msk;             // for TIM1_CH2
  TIM1->CCMR1   |= (0x6UL << TIM_CCMR1_OC2M_Pos);

  TIM5->CCMR2   &= TIM_CCMR2_OC3M_Msk;              // for TIM5_CH3
  TIM5->CCMR2   |= (0x7UL << TIM_CCMR2_OC3M_Pos); 

  // Enable Capture/Compare output for Timers_Channels.
  TIM1->BDTR  |= TIM_BDTR_MOE;    // Enables Main Output. Only needed for some timers... (see Reference Manual)
  TIM1->CCER  |= TIM_CCER_CC2E;   // Enables output on TIM1_CH2
  TIM5->CCER  |= TIM_CCER_CC3E;   // Enables output on TIM5_CH3

// Set Master Timers.
  TIM1->CR2   &= ~TIM_CR2_MMS_Msk;
  TIM1->CR2   |= (0x2UL << TIM_CR2_MMS_Pos);  // Set the Update Event as Trigger Output (TRGO)

  // Set slaves to One Pulse Mode. This stops the counter on the next Update Event.
  TIM5->CR1   |= TIM_CR1_OPM;

// "Mode 6: Trigger Mode - The counter starts at a rising edge of the trigger TRGI
  // (but it is not reset). Only the start of the counter is controlled."
  // Note: We are in One Pulse Mode, so counter will be stopped at 0 (after reaching ARR) anyways...

  TIM5->SMCR  &= ~TIM_SMCR_SMS_Msk;
  TIM5->SMCR  |= (0x6UL << TIM_SMCR_SMS_Pos);

 // Set Trigger for Slave timers.
  TIM5->SMCR  &= ~TIM_SMCR_TS_Msk;            // Use Internal Trigger 0, corresponding to TIM1
  TIM5->SMCR  |= (0x0UL << TIM_SMCR_TS_Pos);

  // For safety. When using TIM5 an issue was encountered where it started beyond its ARR value...
  TIM1->CNT = 0;
  TIM5->CNT = 0;

// setting ports
  GPIOA->MODER  &= ~GPIO_MODER_MODE9_Msk;     // Clear bits at PA9
  GPIOA->MODER  |= GPIO_MODER_MODE9_1;        // Set PA9 to AF

  GPIOA->MODER  &= ~GPIO_MODER_MODE2_Msk;    
  GPIOA->MODER  |= GPIO_MODER_MODE2_1;       // Set PA2 to AF

  // Specify which Alternate Function to use. See Datasheet.
  // Ports 0 to 7 are set in low register [0].
  // Ports 8 to 15 are set in high register [1].

  GPIOA->AFR[1] &= ~GPIO_AFRH_AFSEL9_Msk;             
  GPIOA->AFR[1] |= (0x1UL << GPIO_AFRH_AFSEL9_Pos);   // AF1 for PA9  -> TIM1_CH2

  GPIOA->AFR[0] &= ~GPIO_AFRL_AFSEL2_Msk;            
  GPIOA->AFR[0] |= (0x2UL << GPIO_AFRL_AFSEL2_Pos);  // AF2 for PA2 -> TIM5_CH3


TIM1->PSC   = 240-1;        // Prescaler: Set so that 1 tick is 1 microsecond (at 240 MHz)
    TIM1->CCR2  = 1 + Laser1UpTime; // Capture/Compare: Output stays high while CNT<CCR
    TIM1->ARR   = 1 + VolRepTime;   // Auto-Reload: Timer starts over after reaching this value

TIM5->PSC   = 240-1;                              // Prescaler: Set so that 1 tick is 1 microseconds (at 240 MHz)
    TIM5->CCR3  = VolRepTime-GalvoMoveTime;           // Capture/Compare: Output stays low while CNT<CCR
    TIM5->ARR   = -1 + TIM5->CCR3 + Pulse;                    // Auto-Reload: Timer starts over after reaching this value

And then I trigger it all by enabling TIM1. Again, this implementation works absolutely fine, the PWMs are generated the way I want. It's simply the IRQ which doesn't work... Using the TIM1_CC_IRQHandler() for TIM1 works fine. 

Not really sure. You're hamstringing yourself by not using a system that facilitates debugging. You have a lot of variables without definitions in your code that don't allow me to see what TIM5->ARR actually is. Although in one pulse mode it should be stopping anyway. I'm sure we're missing something but can't see what it is at the moment.

If you feel a post has answered your question, please click "Accept as Solution".

Alright, I found at least part of the issue. I had noted before, without using the IRQ, that TIM5 started beyond its ARR value for some reason. So I set it to 0 as a somewhat crude solution that worked. However, when using the IRQ, it crashes the program, I think because TIM5 was turned on by default for some reason. 

 

  TIM5->CR1 &= ~TIM_CR1_CEN;
  TIM5->CNT = 0;
 
 

 

Pepijn
Associate II

Alright, I found the issue. TIM5 is used by the Arduino Giga for things such as writing to the serial port. It probably has other uses as well, but I noted that anytime Serial.println() was called for example, the counter TIM5 CR1 CEN would be enabled... And I'm sure the system interferes and somehow constantly triggers the ISR. So yeah, there seems to be no way to fix this, and it's rather unfortunate that there is no proper documentation from Arduino's side telling me that TIM5 is used for system tasks, but at least I know now... Thanks for the help anyways!

Where did you find proof that TIM5 was being used elsewhere?  We are trying to use if to count pulses from a hardware encoder.  When the pulses cause it to count down, we seem to loose our Ethernet/TCP communications and LinkStatus.  Counting up does not cause the crash.  If we don't configure TIM5 but just read the value, it appears to be set up as a microsecond counter.  Reprogramming TIM5 for our use does not seem to effect the system micros() or millis()  counters.  Only when it is counting down do we see the Ethernet issue.  It seems to be a waste of a good 32-bit timer to dedicate it to system use.  Is there any way around this?

Hi, it has been some time so my memory might be failing me somewhat. However, what I remember doing was trying to get TIM5 to work, but for some reason it wouldn't work properly. At some point I compared every single registry entry to another timer which I had set up in an identical manner. And then I remember finding what I wrote, basically that anytime I use the serial.print(), CR1 CEN would be enabled, even if I had disabled it prior. Maybe that's incorrect, but that was what I seemed to find back then... You can test it yourself I suppose 🙂

Also, on the other arduino's like the Mega some programmable timers are used for system functionality, so it's not out of the question. And to your point of wasting a timer, well, it has 10+ other timers you can use still I think...