cancel
Showing results for 
Search instead for 
Did you mean: 

TIM trigger is skipped while single-stepping with frozen TIM

SZano
Associate III

I'd like an opinion on this issue with timers; I have working code, but it took me a while to understand that the code was actually working (though not while debugging).

I'm using STM32F446RT.
I'm configuring two timers so that one timer is a master, and its enable signal (CR1.CEN) triggers the start of a slave timer (configured in TRIGGER mode).
I freeze the timers while debugging, so that I can better see their behavior. Actually, in the code below, only the slave is frozen, since that seems to be the source of the problem.
If I run the code below, it works.
If I don't freeze the slave timer, the problem disappears. Freezing the master timer seems to have no impact.
If I don't single-step through the code, the problem disappears.
If I run the code after single-stepping, the trigger doesn't work; i.e. the event is lost, it's not just somehow "paused".
Also, it seems that the problem also appears if I stop the MCU within a few (CPU) cycles from the trigger, with a breakpoint.
So, I suspect that I need to let the MCU run for a while after the trigger, maybe at least N (1, 2, … ?) APB cycles after it, so that the trigger signal can be consumed by the slave timer.
Otherwise, the signal is lost, and the timer never starts.
Also, I assume that the trigger signal is actually a 1CK (1 APB_CK) pulse (generated by the CEN signal rising edge, or by other sources, depending on the TIM TRGO configuration), which is not "frozen" like the rest of the peripheral is, hence it will be lost if not "consumed" immediately.
Actually, "freezing" does not completely freeze the peripheral; for timers, the reference manual says this about DBGMCU_APB1_FZ: "The clock of the involved Timer counter is stopped when the core is halted". So, the counter is stopped, but everything else (including trigger generation) is still working normally.

I'm not providing clock configuration code, as I don't think it's related to the problem.
The two timers (TIM3 and TIM9) are on APB1 and APB2, respectively.
I'm running at 180MHz, with APB1 and APB2 both at 45MHz (90MHz for the timers).

Finally, I'm assuming that something similar happened with other peripherals that can be triggered by TIM, like DAC and ADC.

Does anyone have a better understanding of this?
Anything else I should be aware of, to avoid stumbling upon these things in the future?
For instance: since the trigger source and the trigger destination can be on different APB buses, if I run the buses at different frequencies, could the trigger be skipped even while running normally? Or could get other quirky behavior due to this?

Code:

// Freeze slave TIM (while debugging)
DBGMCU->APB2FZ |= DBGMCU_APB2_FZ_DBG_TIM9_STOP;

// Reset both peripherals
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; (void)RCC->APB1ENR;
RCC->APB1RSTR |= RCC_APB1RSTR_TIM3RST;
RCC->APB1RSTR &= ~RCC_APB1RSTR_TIM3RST;

RCC->APB2ENR |= RCC_APB2ENR_TIM9EN; (void)RCC->APB2ENR;
RCC->APB2RSTR |= RCC_APB2RSTR_TIM9RST;
RCC->APB2RSTR &= ~RCC_APB2RSTR_TIM9RST;

// Everything can be at the default value, except that TIM3 generates
// a trigger on CEN, which is consumed by TIM9 (in TRIGGER mode: TIM9
// is started by the trigger)
TIM3->SMCR = TIM_SMCR_MSM; // master-slave mode: avoids delay between the master and slave timers
TIM3->CR2 = TIM_CR2_MMS_0; // TRGO is the signal CNT_EN
TIM9->SMCR = (1u << TIM_SMCR_TS_Pos) // TS=001: ITR1 (for TIM9, it means "triggered by TIM3")
	| (6u << TIM_SMCR_SMS_Pos) // SMS=110: Trigger mode (the trigger starts the slave)
	;
// TIM9 CR1_CEN is set (the timer is running) as a consequence of the
// following instruction, but only if not single-stepping the code.
// Actually, the first breakpoint must be later than the instruction marked with *,
// for the trigger to work.
TIM3->CR1 |= TIM_CR1_CEN;
__NOP();
__NOP();
__NOP();
__NOP();
__NOP();
__NOP();
__NOP();
__NOP();
__NOP(); // *
__NOP();
for(;;);
2 REPLIES 2
Sarra.S
ST Employee

Hello @SZano, thank you for the detailed description

I will try to address some points to think of -not necessarily providing the solution...-

The trigger signal generated by the master timer (TIM3) is a very short pulse (1 APB clock cycle). If the slave timer (TIM9) is frozen or if the MCU is halted immediately after the trigger, the slave timer might miss the trigger signal. When you single-step through the code, the timing of the trigger signal and the response of the slave timer can be disrupted, causing the trigger to be lost, and I highly suspect this is a timing and synchronization issue of the trigger signals between the master and slave timers

>>since the trigger source and the trigger destination can be on different APB buses, if I run the buses at different frequencies, could the trigger be skipped even while running normally?

if the master and slave timers are on different APB buses running at different frequencies, there could be additional synchronization delays. However, in your case, both APB1 and APB2 are running at the same frequency (45 MHz), so this should not be a significant issue.

You can use a loop with __NOP() instructions, as you have done, but ensure the delay is long enough.

 

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.

Thanks for the information.

However, I still have doubts.

From my tests, everything works (even when single-stepping) as long as I don't freeze TIM9. So, it seems the issue is not related to halting the CPU. Also, I would expect the CPU to be halted, but all the clocks to be running anyway (APBx, AHBx, and all the others).

But if the issue is only related to the freezing, then, why does it happen? "Freeze" is supposed to just inhibit the counter clock, not the whole peripheral. I'd expect everything else in the peripheral, including the master-slave unit which takes care of the triggers, to be fed by the APB clock, so I don't understand how it can miss an event.