cancel
Showing results for 
Search instead for 
Did you mean: 

How to retrigger an externally triggered timer without changing the output channel state

antfarmer
Associate III

I have a timer (TIM15) setup in trigger slave mode which uses CH1 for edge detect, and output compare on CH2. I have it working nicely to have the output low during the initial delay until the CNT reaches autoreload ARR. Then the output goes high as the output compare is 'Active level on match'. I then keep the oc in this state for some period of time (much longer than the resolution of timer can allow). At the end of this long period, I would like to be able to use the same delay triggered by an edge from CH1. I can get the final delay using 'inactive on match', but it doesn't wait for an edge on CH1, it just starts immediately. My main question is how can you reset the timer back into a state where it is waiting for an edge on CH1, without affecting the output on CH2? I want to hold the output high throughout the long delay and the also during the delay once the final edge is detected, until the output compare matches. If there are better strategies for timer setup, I'd like to hear them. I'm working on a STM32G070RB, but I would consider using a more advanced micro as long as the price is reasonable. I don't need a fast cpu, just a very flexible set of timers.

 

A second question is there a way to control the polarity of the edge on CH1? From the documentation I could not find any setting to control rising/falling edge.

 

Thanks.

1 ACCEPTED SOLUTION

Accepted Solutions

> virtual timer in memory to handle setting the output to inactive

So, that's some piece of software which executes some code (presumably interrupt-related) when the long time expires, correct? So, that piece of software can also change the timer registers, correct? See then (*) below.

Trigger mode in Slave-Mode Controller (i.e. TIMx_SMCR.SMS=0b110) works so that when trigger arrives, TIMx_CR1.CEN is set in hardware. That means, that timer's counter has not to run (TIMx_CR1.CEN = 0) before trigger arrives, and then the trigger simply starts it running.

If you have given output channel set to Set Active on Match (i.e. TIMx_CCMRx.OCxM=0b001), then once the output is set due to TIMx_CNT=TIMx_CCRx match, it does not matter that the timer keeps running and the match keeps happening, it will remain active.

So, in (*),

- stop timer's counter (TIMx_CR1.CEN = 0) and reset its counter (TIMx_CNT = 0).

- set the output channel to Set Inactive on Match (i.e. TIMx_CCMRx.OCxM=0b010), so that the next active edge on the triggering input starts the timer again, and then again after a delay given by TIMx_CCRx match happens and that changes output to Inactive.

There may be other, maybe more appropriate ways to do this, too.

---

 

There's no drawback in enabling input capture on the channel you are using to trigger, if that's what Cube wants.However, TI1F_ED is the "any edge" i.e. it will react to both edges. If you want only one edge, use the TI1FP1 setting (TIMx_SMCR.TS=0b101).

Generally, if you want to do anything out of "usual" (as judged by Cube/CubeMX authors), you're better off not using Cube/CubeMX at all, as it then tends to get into way.

JW

View solution in original post

7 REPLIES 7
TDK
Guru

A little hard to decipher the behavior you want here. Perhaps a diagram would help.

You want CH2 to go high a set period of time after CH1 goes high? And then an indeterminate amount of time later, you want CH2 to go low after the same period of time as before after CH1 goes low?

 

IC polarity is selectable in CubeMX.

TDK_0-1707880426774.png

 

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

Yes, it's hard to explain, so I found a diagram tool and came up with this:

retriggerable_timer.png

  • The external int starts the sequence, but I am using the slave trigger mode to synchronize the actual start of the timer with the edge at TI1F_ED. This is Tsync which is variable
  • Then output compare at CH2 sets the OUT active. This gives the fixed Tdelay in us
  • Due to the large difference in time, I'm just implementing a virtual timer in memory to handle setting the output to inactive
  • This is where I need to re-trigger the timer so it only starts once the edge is detected at TI1F_ED and the Tsync, Tdelay sub-sequence can be restarted
  • Right now, it simply runs for Tdelay without waiting for re-synchronization with the TI1F_ED
  • the CNT_EN represents how the timer enable is set. Obviously this is just an implementation detail that could be changed

 

On the other issue, since I'm not using input compare, just slave mode with trigger, there is no control over the edge polarity in cube mx, at least that I could find. I'm not sure if there would be a better configuration for this process, as I've mostly use timers for very simple delays, etc.

> virtual timer in memory to handle setting the output to inactive

So, that's some piece of software which executes some code (presumably interrupt-related) when the long time expires, correct? So, that piece of software can also change the timer registers, correct? See then (*) below.

Trigger mode in Slave-Mode Controller (i.e. TIMx_SMCR.SMS=0b110) works so that when trigger arrives, TIMx_CR1.CEN is set in hardware. That means, that timer's counter has not to run (TIMx_CR1.CEN = 0) before trigger arrives, and then the trigger simply starts it running.

If you have given output channel set to Set Active on Match (i.e. TIMx_CCMRx.OCxM=0b001), then once the output is set due to TIMx_CNT=TIMx_CCRx match, it does not matter that the timer keeps running and the match keeps happening, it will remain active.

So, in (*),

- stop timer's counter (TIMx_CR1.CEN = 0) and reset its counter (TIMx_CNT = 0).

- set the output channel to Set Inactive on Match (i.e. TIMx_CCMRx.OCxM=0b010), so that the next active edge on the triggering input starts the timer again, and then again after a delay given by TIMx_CCRx match happens and that changes output to Inactive.

There may be other, maybe more appropriate ways to do this, too.

---

 

There's no drawback in enabling input capture on the channel you are using to trigger, if that's what Cube wants.However, TI1F_ED is the "any edge" i.e. it will react to both edges. If you want only one edge, use the TI1FP1 setting (TIMx_SMCR.TS=0b101).

Generally, if you want to do anything out of "usual" (as judged by Cube/CubeMX authors), you're better off not using Cube/CubeMX at all, as it then tends to get into way.

JW


@waclawek.jan wrote:

So, that's some piece of software which executes some code (presumably interrupt-related) when the long time expires, correct?


Yes, I'm using a count updated by the RTC wakeup timer at 1Hz for that. I would have liked to use a second timer to provide the long delay, but apparently this MCU is limited in routing the RTC clock to timers. I did consider using the RTC LSCO routed to the clock input pin for another timer, but that just seems hacky, as I know there are some timers that can clock internally off of the LSE. I just couldn't find how to route it on this MCU.

 

Thanks for the advice on how to reset the trigger. I will try that next. I just started testing another strategy, by switching between PWM Mode 2 and and Mode 1 in one pulse mode. The slave mode is trigger and reset. The synchronization and delay are working at both start and stop, but the trouble is the 60Hz clock is causing the CH2 output to flip when I want to remain high. I will try with regular output compare mode with TI1FP1. Hopefully that will allow control of the edge polarity and I will be able to ignore the trigger except for the initial and final synchronization.

I would use the same procedure. But may be there is another way (if Ton is some integer multiple of 60Hz period signal).
Use one counter (call it for example TIMA) as "delayer". In one-shot mode it can generate pulses (for internal use) delayed by Tdelay from each rising edge of 60Hz signal. Route update event to its TRGO. Then use another counter (TIMB) to count these delayed events and to generate "PWM" output (also in one-shot mode).
If i am not wrong, then this combination should generate rising edge (on TIMB output) delayed by TIMA.ARR and falling edge on TIMB output delayed by TIMB.ARR*60Hz_signal_period + TIMA.ARR (which can be different from previous value).


So I was able to get this working finally using regular slave trigger mode. I freeze the OC CH2 output after the initial delay, then after long, delay flip the oc mode to inactive on match and the rest works as it should. I'm not sure but in my testing I must have had a bug where the wrong interrupt wasn't cleared after the long delay, and also I now explicitly reset CNT to 0, just to be sure.

The TI1FP1 edge detection works perfectly, even provides a little noise immunity too. CubeMX doesn't allow input compare on CH1 as it is locked out in trigger mode.

Thanks for the help.

Everything seems to look good, except I should no figure out how to handle the long delay. If a timer can clock from LSE while being triggered on update from another timer, what should I look for in the docs? The ITR values for TIM1, 3, 4 don't seem to have anything other than other timers. Has anyone run LSCO out to an external clock pin? It seems strange to me that timers can only be run off the system clock.

antfarmer
Associate III

In case anyone is looking for clocking a timer with the LSE, I found how to route the LSE clock internally. It's just on the next step up MCU: STM32G071 using TIM2, which not available on the G070. Looks like that will simplify the software a bit.