cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F407 Problem With Input Capture on Four Channels

mvaras101
Associate II
Posted on October 22, 2016 at 04:24

I’m having some trouble with four channel timers on the STM32F4 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. 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:

// 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

// 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
} 
}

4 REPLIES 4
mark239955_stm1
Associate II
Posted on October 22, 2016 at 06:08

Have you verified in a debugger that the MikroC output is configuring the TIM2 registers in the way that you expect?

mvaras101
Associate II
Posted on October 24, 2016 at 18:19

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. 

The image manager isn't working for me, so here is a link to a capture of the relevant registers from the debugger. 

http://i.imgur.com/OGjcWwX.png

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. 

Posted on October 24, 2016 at 18:31

The link you gave redirects me to http://i.imgur.com/removed.png

Check the relevant GPIO registers/post their content. Check that there *are* expected ''events'' on those pins - measure directly on the pins by an oscilloscope.

// 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

You probably meant CC4P/CC4NP, although they are at their reset values so it's the error won't demonstrate itself. And don't worry about PA0 sharing TIM2_CH1 and TIM2_ETR - as long as you don't use ETR (by enabling external clock mode 1) it's irrelevant. JW
Posted on October 24, 2016 at 19:06

You'd want to cross check the GPIO pin configuration and AF settings..

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..