TIM trigger is skipped while single-stepping with frozen TIM
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(;;);