Skip to main content
Graduate II
February 13, 2024
Solved

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

  • February 13, 2024
  • 3 replies
  • 3763 views

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.

    This topic has been closed for replies.
    Best answer by waclawek.jan

    > 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

    3 replies

    Super User
    February 14, 2024

    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

     

    antfarmerAuthor
    Graduate II
    February 14, 2024

    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.

    Super User
    February 14, 2024

    > 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

    antfarmerAuthor
    Graduate II
    February 14, 2024

    @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.

    antfarmerAuthor
    Graduate II
    February 16, 2024

    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.