cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F0 input capture interrupt quirk

alister
Lead

Bare-metal STM32F030C8.

Using input capture to receive encodes.

Encodes are delimited by idle.

I need to decode only the last 10 or so transitions of each encode.

I want to perform the decode during the idle.

So I’m using circular DMA and I want the timer interrupt to

  1. Fire on the first update following captures (on timer overflow), where I’ll signal the app do the decode and change the interrupt to capture, so it fires on the start of the next encode
  2. Fire on the first capture, where I’ll change the interrupt to update, i.e. two interrupts per received encode.

But what I’m observing in the interrupt is

  1. In the capture interrupt, I switch to interrupt to update successfully, i.e. I see only one capture interrupt.
  2. But I get two or three update interrupts in succession.

This is the instrumented IRQ handler.

EDIT replaced Cube TIM_FLAG macros with "CMSIS-mandated" TIM_SR macros.

void TIMx_IRQHandler(void)
{
  TIM_TypeDef *htimxInstance_p = _htimxInstance_p;
  uint16_t sr = htimxInstance_p->SR;
  // for testing
  uint16_t debugDier = htimxInstance_p->DIER;
 
  /* Clear the SR bits as early as possible.
   * Observe interrupts with SR = 0. So appears there’s latency from clearing SR to the
   * peripheral's clearing its interrupt. */
  htimxInstance_p->SR = 0;
 
  /* TIMx Capture event. */
  if (sr & TIM_SR_CC1IF)
  {
    /* Switch the interrupt to update.
     * The next interrupt will be after the encode has completed. */
    htimxInstance_p->DIER = TIM_DIER_CC1DE | TIM_DIER_UIE;
  }
 
  /* TIM Update event, i.e., the timer counter has overflowed. */
  else if (sr & TIM_SR_UIF)
  {
    /* This interrupt indicates the encode is completed.
     * Switch the interrupt to capture.
     * The next interrupt will be when the next encode has started.
     * Incrementing encodeCount signals the app to do the decode. */
    htimxInstance_p->DIER = TIM_DIER_CC1DE | TIM_DIER_CC1IE;
    encodeCount++;
  }
 
  // for testing
  debugSr[debugSrIdx].dier = debugDier;
  debugSr[debugSrIdx].sr = sr;
  if (++debugSrIdx >= ARRAY_SIZE(debugSr))
    debugSrIdx = 0;
}

Perhaps I might work-around it by adding state to the interrupt to signal to the app on the first update following capture.

But I’d like to fix it if possible. Any clues please?

1 ACCEPTED SOLUTION

Accepted Solutions

> I _do_ see a CC1IF

That's coincidental - you don't have DMA set to circular, or there are several edges on the input signal too close to each other, or something else I didn't consider.

Set CC2 to capture the *other* channel (i.e. that it captures the same signal on the same pin, TIM15_CCMR1.CC2S=0b10), and for interrupt use CC2 instead of CC1 (both in DIER and then in all handling within the ISR).

JW

View solution in original post

45 REPLIES 45

Humm.

Is this a free-running timer, or do you have any slave-mode reset imposed?

And what do you see in debugSr[]?

[stylistics]

> TIM_FLAG_UPDATE

I suspected where does this come from and went directly to the Cube/HAL TIM header.

IMHO you should get rid of the whole Cube burden once for all and stick to the CMSIS-mandated device header, or this might bite you in future when the cubers decide to change meaning/content of their haphazardly invented constants.

[/stylistics]

JW

> TIMx_IRQHandler()

How is this inserted to the vector table, btw?

JW

It's free-running.

I'm doing a slave-mode reset lifted from another of your posts on Community.

Half expected a comment about cube 🙂

Acknowledge that risk.

It's TIM15_IRQHandler on a board I'm using for prototyping.

#if PROTO_ON_MOX
#define _TIMx htim15
#define TIMx_IRQHandler TIM15_IRQHandler
#else
#define _TIMx htim1
#define TIMx_IRQHandler TIM1_CC_IRQHandler
#endif

There are about 30 transitions per encode.

From the instrumenting below, it cycles 6 capture to 1 update interrupt.

debugSr debugSr_t [24] 0x20000080

debugSr[0] debugSr_t {...}

dier uint16_t 0x202

sr uint16_t 0x45

debugSr[1] debugSr_t {...}

dier uint16_t 0x202

sr uint16_t 0x47

debugSr[2] debugSr_t {...}

dier uint16_t 0x201

sr uint16_t 0x45

debugSr[3] debugSr_t {...}

dier uint16_t 0x202

sr uint16_t 0x45

debugSr[4] debugSr_t {...}

dier uint16_t 0x202

sr uint16_t 0x45

debugSr[5] debugSr_t {...}

dier uint16_t 0x202

sr uint16_t 0x45

debugSr[6] debugSr_t {...}

dier uint16_t 0x202

sr uint16_t 0x45

debugSr[7] debugSr_t {...}

dier uint16_t 0x202

sr uint16_t 0x45

debugSr[8] debugSr_t {...}

dier uint16_t 0x202

sr uint16_t 0x47

debugSr[9] debugSr_t {...}

dier uint16_t 0x201

sr uint16_t 0x45

debugSr[10] debugSr_t {...}

dier uint16_t 0x202

sr uint16_t 0x45

debugSr[11] debugSr_t {...}

dier uint16_t 0x202

sr uint16_t 0x45

debugSr[12] debugSr_t {...}

dier uint16_t 0x202

sr uint16_t 0x45

debugSr[13] debugSr_t {...}

dier uint16_t 0x202

sr uint16_t 0x45

debugSr[14] debugSr_t {...}

dier uint16_t 0x202

sr uint16_t 0x45

debugSr[15] debugSr_t {...}

dier uint16_t 0x202

sr uint16_t 0x47

debugSr[16] debugSr_t {...}

dier uint16_t 0x201

sr uint16_t 0x45

debugSr[17] debugSr_t {...}

dier uint16_t 0x202

sr uint16_t 0x45

debugSr[18] debugSr_t {...}

dier uint16_t 0x202

sr uint16_t 0x45

debugSr[19] debugSr_t {...}

dier uint16_t 0x202

sr uint16_t 0x45

debugSr[20] debugSr_t {...}

dier uint16_t 0x202

sr uint16_t 0x45

debugSr[21] debugSr_t {...}

dier uint16_t 0x202

sr uint16_t 0x45

debugSr[22] debugSr_t {...}

dier uint16_t 0x202

sr uint16_t 0x47

debugSr[23] debugSr_t {...}

dier uint16_t 0x201

sr uint16_t 0x45

debugSrIdx int 0x1

> I'm doing a slave-mode reset

So, those Updates are probably caused by that slave-mode reset - from RM:

 Reset Mode - Rising edge of the selected trigger input (TRGI) reinitializes the counter

and generates an update of the registers.

You should perform an AND on the captured status register with the current DIER, before evaluating which was the source of interrupt.

> lifted from another of your posts on Community.

So, the blame is on me? 😉

> Half expected a comment about cube

Glad I did not disappoint :D

Jan

Thanks, yes, that evaluates the interrupt source correctly.

Neither blaming or disappointed.

But the slave-mode updates are interrupting almost every capture. Aside, the interrupt numbers are curious... for each 32 transition encode, by this corrected method there is 1 interrupt for CC1IF, 1 interrupt for UIF and between 22 and 26 interrupts for slave-mode update and some small number of these are spurious because SR = 0.

Do you or other readers know a less-cycles method to delineate the first update following a run of captures (i.e. the end of my encode)?

If not, I'll dispense with slave-mode reset.

Thanks!

It's still not OK that the interrupts happen, of course, as they are not enabled; and I don't have an explanation for that.

@berendi​ , could you please comment?

JW

The TIM15_CR1->URS... from the RM:

URS: Update request source

This bit is set and cleared by software to select the UEV event sources.

0: Any of the following events generate an update interrupt if enabled. These events can be:

– Counter overflow/underflow

– Setting the UG bit

– Update generation through the slave mode controller

1: Only counter overflow/underflow generates an update interrupt if enabled.