AnsweredAssumed Answered

STM32F407 Problem With Input Capture on Four Channels

Question asked by Matthew on Oct 22, 2016
Latest reply on Oct 24, 2016 by Clive One

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

Outcomes