Author Topic: STM32F407 Problem With Input Capture on Four Channels  (Read 7328 times)

0 Members and 1 Guest are viewing this topic.

Offline techy101Topic starter

  • Supporter
  • ****
  • Posts: 39
  • Country: us
    • My site
STM32F407 Problem With Input Capture on Four Channels
« on: October 22, 2016, 02:21:51 am »
I’m having some trouble with four channel timers on the STM32F407. I am trying to use all four channels of Timer 2 for input capture and am not quite able to get it to work. Channels 1 and 4 work just fine, but 2 and 3 don’t seem to be doing anything at all. Looking at the block diagram it seems that there’s an option of using an XOR for channels 2 and 3 muxed with channel 1 (Circled in red in block diagram below). I did find a bit related to this in the reference manual, TIM2_CR2.TI1S, but setting it either way does not change the behavior. The reference manual makes it seem like all four channels are available for input capture, and they are each mapped to TI1..TI4 respectively in the TIM2_CCMR1 and TIM2_CCMR2 registers.

I’ve attached code for both my initialization function and the interrupt handler. I’m using MikroC, so the syntax is a bit weird. The program is designed to use a structure to create six instances and pass the struct into functions, which makes the handler a bit messy. There is more going on in the handler than I’d like, but for now I don’t know a better way to deal with the delta calculations, and that’s another topic anyway.

Any help would be appreciated. It took a while to get these working and I simply don’t understand why 2 and 3 wouldn’t work when 1 and 4 do. My best guess is that it has something to do with the XOR and mux between channel 1, 2, and 3.




Initialization
Code: [Select]
// Initialize Input Capture on Timer 2 Channel 1
void init_input_capture() {

    // Configure timer 2
    RCC_APB1ENR.TIM2EN = 1;                                                 // Enable clock gating for timer module 2
    TIM2_CR1.CEN = 0;                                                       // Disable timer/counter
    TIM2_CR2.TI1S = 0;                                                      // TIM2_CH1 connected to TI1 Input (1 would be Ch1, 2, 3 XOR to TI1)
    TIM2_PSC = ENCODER_TIM_PSC;                                             // Set timer 2 prescaler
    TIM2_ARR = ENCODER_TIM_RELOAD;                                          // Set timer 2 Auto Reload value
    TIM2_CR1 |= 0x10;                                                       // Set counter direction as upcounting (DIR bit)
   
    // Configure motor 1 (Pin A0, Channel 1) input capture
    GPIO_Alternate_Function_Enable(&_GPIO_MODULE_TIM2_CH1_PA0);             // Configure alternate function for A0 as Timer 2 Channel 1
    TIM2_CCMR1_Input |= 0x01;                                               // Set capture channel 1 as input on TI1 (CC1S = 01)
    TIM2_CCER.CC1P = 0;                                                     // Set capture on rising edge event
    TIM2_CCER.CC1NP = 0;
    TIM2_CCER.CC1E = 1;                                                     // Enable capture on channel 1
    TIM2_DIER.CC1IE = 1;                                                    // Enable interrupt on capture channel 1

    // Configure motor 2 (Pin A1, Channel 2) input capture
    GPIO_Alternate_Function_Enable(&_GPIO_MODULE_TIM2_CH2_PA1);             // Configure alternate function for pin A1 as Timer 2 Channel 2
    TIM2_CCMR1_Input |= 0x100;                                              // Set capture channel 2 as input on TI2 (CC2S = 01)
    TIM2_CCER.CC2P = 0;                                                     // Set capture on rising edge event
    TIM2_CCER.CC2NP = 0;
    TIM2_CCER.CC2E = 1;                                                     // Enable capture on channel 2
    TIM2_DIER.CC2IE = 1;                                                    // Enable interrupt on capture channel 2
   
    // Configure motor 3 (Pin A2, Channel 3) input capture
    GPIO_Alternate_Function_Enable(&_GPIO_MODULE_TIM2_CH3_PA2);             // Configure alternate function for pin A2 as Timer 2 Channel 3
    TIM2_CCMR2_Input |= 0x01;                                               // Set capture channel 3 as input on TI3 (CC3S = 01)
    TIM2_CCER.CC3P = 0;                                                     // Set capture on rising edge event
    TIM2_CCER.CC3NP = 0;
    TIM2_CCER.CC3E = 1;                                                     // Enable capture on channel 2
    TIM2_DIER.CC3IE = 1;                                                    // Enable interrupt on capture channel 3
   
    // Configure motor 4 (Pin A3, Channel 4) input capture
    GPIO_Alternate_Function_Enable(&_GPIO_MODULE_TIM2_CH4_PA3);             // Configure alternate function for pin A3 as Timer 2 Channel 4
    TIM2_CCMR2_Input |= 0x100;                                              // Set capture channel 4 as input on TI4 (CC4S = 01)
    TIM2_CCER.CC3P = 0;                                                     // Set capture on rising edge event
    TIM2_CCER.CC3NP = 0;
    TIM2_CCER.CC4E = 1;                                                     // Enable capture on channel 2
    TIM2_DIER.CC4IE = 1;                                                    // Enable interrupt on capture channel 4

    // Configure timer interrupts
    TIM2_DIER.UIE = 1;                                                      // Enable overflow interrupt
    NVIC_IntEnable(IVT_INT_TIM2);                                           // Enable timer 2 interrupt
    TIM2_CR1.CEN = 1;                                                       // Enable timer/counter

    // Calculate period of TIM2_CLK in ms
    timer2_period_ms = (long double) 1000.0 / (MCU_FREQUENCY / (ENCODER_TIM_PSC + 1));
}




Interrupt handler
Code: [Select]
// Interrupt handler for Timer 2 (Overflows and Capture events)
void timer2_ISR() iv IVT_INT_TIM2 {                                                                                                                       

    // Timer 2 Overflow
    if(TIM2_SR.UIF == 1) {                                                     
        TIM2_SR.UIF = 0;                                                        // Clear timer 2 interrupt bit
        overflow_count++;                                                       // Increment overflow counter
    }

    // Channel 1 (Motor 1) input capture event
    if (TIM2_SR.CC1IF == 1) {   
        fngr_pointer.enc_start_time = fngr_pointer.enc_end_time;                // Store previous captured value for next calculation
        fngr_pointer.enc_end_time = TIM2_CCR1;                                  // Read stored input capture time
        fngr_pointer.enc_overflow_start = fngr_pointer.enc_overflow_end;        // Store previous overflow value for next calculation
        fngr_pointer.enc_overflow_end = overflow_count;                         // Store number of timer 2 overflows for this motor
        fngr_pointer.enc_chan_b = FNGR_POINTER_ENC_B;                           // Sample the second encoder channel state (For direction)
        fngr_pointer.position_temp++;                                           // Increment total input capture event counter
    }
       

    // Channel 2 (Motor 2) input capture event
    if (TIM2_SR.CC2IF == 1) {                                               
        fngr_middle.enc_start_time = fngr_middle.enc_end_time;                  // Store previous captured value for next calculation
        fngr_middle.enc_end_time = TIM2_CCR2;                                   // Read stored input capture time
        fngr_middle.enc_overflow_start = fngr_middle.enc_overflow_end;          // Store previous overflow value for next calculation
        fngr_middle.enc_overflow_end = overflow_count;                          // Store number of timer 2 overflows for this motor
        fngr_pointer.enc_chan_b = FNGR_MIDDLE_ENC_B;                            // Sample the second encoder channel state (For direction)
        fngr_middle.position_actual++;                                          // Increment total input capture event counter
    }       
       
    // Channel 3 (Motor 3) input capture event
    if (TIM2_SR.CC3IF == 1) {
        fngr_ring.enc_start_time = fngr_ring.enc_end_time;                      // Store previous captured value for next calculation
        fngr_ring.enc_end_time = TIM2_CCR3;                                     // Read stored input capture time
        fngr_ring.enc_overflow_start = fngr_ring.enc_overflow_end;              // Store previous overflow value for next calculation
        fngr_ring.enc_overflow_end = overflow_count;                            // Store number of timer 2 overflows for this motor
        fngr_pointer.enc_chan_b = FNGR_RING_ENC_B;                              // Sample the second encoder channel state (For direction)
        fngr_ring.position_actual++;                                            // Increment total input capture event counter
    }       
       
    // Channel 4 (Motor 4) input capture event
    if (TIM2_SR.CC4IF == 1) {                                               
        fngr_pinky.enc_start_time = fngr_pinky.enc_end_time;                    // Store previous captured value for next calculation
        fngr_pinky.enc_end_time = TIM2_CCR4;                                    // Read stored input capture time
        fngr_pinky.enc_overflow_start = fngr_pinky.enc_overflow_end;            // Store previous overflow value for next calculation
        fngr_pinky.enc_overflow_end = overflow_count;                           // Store number of timer 2 overflows for this motor
        fngr_pointer.enc_chan_b = FNGR_PINKY_ENC_B;                             // Sample the second encoder channel state (For direction)
        fngr_pinky.position_actual++;                                           // Increment total input capture event counter
    }       
}
« Last Edit: October 22, 2016, 02:24:13 am by techy101 »
 

Offline newbrain

  • Super Contributor
  • ***
  • Posts: 1847
  • Country: se
Re: STM32F407 Problem With Input Capture on Four Channels
« Reply #1 on: October 22, 2016, 12:24:33 pm »
Just some minor things:
  • You got the direction wrong. 0 is upcount and 1 is downcount. But this is immaterial, as this bit is ignored in this configuration.
  • You are relying on the fact that all the registers hold their reset value when you call the init function. This depends on the rest of your code, so it might be a safe assumption.
  • In setting up CCR4, you are setting again CC3P and CC3NP bits. But see the previous comment.
  • The setting of TI1S is correct.

But, apart from the above, I can't see anything obvious.
Have you tried some basic debugging such as breakpoint in the relevant ISR section, swapping the physical inputs, mapping CCR2 and 3 inputs respectively to TI1 and TI4?

Maybe your code is too well behaved to give you the middle finger... :-DD
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline techy101Topic starter

  • Supporter
  • ****
  • Posts: 39
  • Country: us
    • My site
Re: STM32F407 Problem With Input Capture on Four Channels
« Reply #2 on: October 23, 2016, 04:32:37 pm »
Thank you for catching the couple of silly errors  :-[

I've gone through with a debugger and verified that the registers I'm trying to set are in fact set correctly. I can also verify that the ISR's for channels 2 and 3 are not being entered as it's coded right now. However I was able to map CC2 to TI1 and it fired right up, so there's something going on with TI2 and TI3. Still stumped though  :-\

Oh, and that joke was absolutely terrible and amazing at the same time. It made my wife groan :)
 

Offline newbrain

  • Super Contributor
  • ***
  • Posts: 1847
  • Country: se
Re: STM32F407 Problem With Input Capture on Four Channels
« Reply #3 on: October 23, 2016, 06:49:00 pm »
Thank you for catching the couple of silly errors  :-[

I've gone through with a debugger and verified that the registers I'm trying to set are in fact set correctly. I can also verify that the ISR's for channels 2 and 3 are not being entered as it's coded right now. However I was able to map CC2 to TI1 and it fired right up, so there's something going on with TI2 and TI3. Still stumped though  :-\
Very strange.
I'd make sure of all the HW connections, but you've probably already done that.
Next step would be checking the code for those MikroC library calls (is that even available?), or, better yet, set up the GPIO pins yourself with registers.

Quote
Oh, and that joke was absolutely terrible and amazing at the same time. It made my wife groan :)
I'll take that as a compliment. My wife has lost all hopes since longtime. The offspring still complains, though...
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline techy101Topic starter

  • Supporter
  • ****
  • Posts: 39
  • Country: us
    • My site
Re: STM32F407 Problem With Input Capture on Four Channels
« Reply #4 on: October 24, 2016, 04:17:11 pm »
I've been able to verify the CCMR1, CCMR2, CCER, and DIER registers are configured as expected by looking at the register descriptions in the reference manual. I've also been able to verify that the TIM2_SR CC2IF and CC3IF bits aren't being set when an event happens.

Here is a capture of the relevant registers from the debugger.


As far as I can tell all channels are configured identically. The only thing that's giving me pause is the register map in the datasheet shows PA0 AF1 listed as "TIM2_CH1_ETR" not "TIM2_CH1" like the other channels. I don't really understand the external trigger in relation to an input capture, but I thought it wasn't used. I'm not sure if this plays any role or not.

Thank you for the help.
« Last Edit: October 24, 2016, 09:19:51 pm by techy101 »
 

Offline newbrain

  • Super Contributor
  • ***
  • Posts: 1847
  • Country: se
Re: STM32F407 Problem With Input Capture on Four Channels
« Reply #5 on: October 24, 2016, 07:31:28 pm »
I've been able to verify the CCMR1, CCMR2, CCER, and DIER registers are configured as expected by looking at the register descriptions in the reference manual. I've also been able to verify that the TIM2_SR CC2IF and CC3IF bits aren't being set when an event happens.

Here is a capture of the relevant registers from the debugger.


As far as I can tell all channels are configured identically. The only thing that's giving me pause is the register map in the datasheet shows PA0 AF1 listed as "TIM2_CH1_ETR" not "TIM2_CH1" like the other channels. I don't really understand the external trigger in relation to an input capture, but I thought it wasn't used. I'm not sure if this plays any role or not.

Thank you for the help.
The PA0 pin acts as both input capture and ETR for Timer 2, depending on the configuration (other timers have separate pins), so no, it does not matter.

Unfortunately, the image is not showing; did it include also GPIO registers?

Since the capture triggers when connected to TI1, it could be a GPIO misconfiguration, or an HW issue.

Can you use any of the other TI2 and TI3 pins, resp. PB3 and PB10, or check that the used pins are actually working (e.g. using an EXTI interrupt to capture the edge, though it might not be definitive proof - pins circuitry can also be "half-cooked")?

BTW: I also checked the errata for the F407, no mention of timer input capture problems.

Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline newbrain

  • Super Contributor
  • ***
  • Posts: 1847
  • Country: se
Re: STM32F407 Problem With Input Capture on Four Channels
« Reply #6 on: October 25, 2016, 10:32:37 pm »
So,
in the end I wrote some code to test all the Timer 2 input capture registers, with the relevant interrupt.

I jumpered PA0-PA3 to PD12-PD15 (the LEDs on the STM32F407 Discovery) and toggled them every 100ms, either in a Gray Code pattern to have at most a single IRQ pending/active, or downcounting 15-0 to have a nice 0000->1111 transition.

The code is attached below, just cobbled up together this evening (no style prize), one needs the F4 Cube (HAL+CMSIS) to compile it and "-std=c99".
I did not add UART or SWO output, lazy me, so I ended up using a debugger (eh, some say it's useless) :horse:.

The TimerInit() and the ISR (TIM2_IRQHandler) are strictly modeled on the ones included in the OP (but I used CMSIS register and bit names).

This 0000->1111 event is shown in the screenshot.

Again check your hardware, and whether the pins are OK!
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: STM32F407 Problem With Input Capture on Four Channels
« Reply #7 on: October 26, 2016, 11:28:26 am »
You nay want to check your pin remapping.

As to the code itself, I posted a piece of code that does direct register access on timer 1 (tested also on 2 through 5) for compare match on f1. Input capture should be similar.
================================
https://dannyelectronics.wordpress.com/
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf