This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C129XNCZAD: Getting Tachometer Counts from Timer Pins on the Board

Part Number: TM4C129XNCZAD
Other Parts Discussed in Thread: EK-TM4C1294XL

Hello all, I have a custom board that can control some fans and record their RPM's. The fans are controlled via PWM signals and they have a tachometer that are connected to several CCP pins on the boards. I will use Fan 1 which is connected to T0CCP1 for this question since all the other fans should be the same with different pins configured for them. Here is the code and circuitry I have so far.

Pin connection to the tachometer:

Fan tachometer output information.

Code to setup timer:

static void InitializeTimer0( uint32_t ui32SysClock )
{

    //Enable timer 0 peripheral
    SysCtlPeripheralEnable( SYSCTL_PERIPH_TIMER0 );
    while(!SysCtlPeripheralReady( SYSCTL_PERIPH_TIMER0 )){

    }

    //Enable GPIO A peripheral since the CCP pins are on there.
    SysCtlPeripheralEnable( SYSCTL_PERIPH_GPIOA );
    while(!SysCtlPeripheralReady( SYSCTL_PERIPH_GPIOA )){

    }

    //Configure the GPIO pins used for CCP operation.
    GPIOPinConfigure( GPIO_PA1_T0CCP1 );

    //Set the pins as timer pins.
    GPIOPinTypeTimer(PA_FAN_TACHOMETER_PORT, PA1_TCU_FAN_1_TACHOMETER_PIN);

    //Initialize the timer so timer 0B counts the number of positive edges while timer 0A counts up.
    //When timer 0B reaches a preset value check the timer 0A value and get the number of pulses/time.
    TimerConfigure(TIMER0_BASE, ( TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC | TIMER_CFG_B_CAP_TIME ));

    //Set the timers so timerA counts to 0.1S, and timerB counts to 1000 positive edges.
    TimerLoadSet(TIMER0_BASE, TIMER_BOTH, ui32SysClock/10);

    TimerControlEvent(TIMER0_BASE, TIMER_B, TIMER_EVENT_POS_EDGE);

    //set the initial value of the counter to 0.
    TCUFan1TimerValue = 0;

    IntRegister(INT_TIMER0B, InterruptHandlerTimer0B);
    //Configure timerB interrupt to occur when the count is reached.
    TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
    IntEnable(INT_TIMER0A);

    TimerIntEnable(TIMER0_BASE, TIMER_CAPB_EVENT);
    IntEnable(INT_TIMER0B);

    // Enable the timers.
    TimerEnable(TIMER0_BASE, TIMER_A);
    TimerEnable(TIMER0_BASE, TIMER_B);

}

Interrupt handlers for the timer:

//Timer0B interrupt handler that calculates the RPM of TCU Fan 1.
void InterruptHandlerTimer0A( void ){

    //Clear the interrupt.
    TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    //read the fan rpm data.
    Laser.Miscellaneous.Monitor.TCUFan1RMP = TCUFan1TimerValue*300;
    TCUFan1TimerValue=0;

    //Reset the value in timer0B to 0
    HWREG(TIMER0_BASE  + TIMER_O_TBV) = 0;

}

//interrupt handler for timer0B.
void InterruptHandlerTimer0B( void ){
    TimerIntClear(TIMER0_BASE, TIMER_CAPB_EVENT);
    TCUFan1TimerValue++;
}

I get 0 for the variable called TCUFan1RPM that is set in the Timer0A interrupt handler. The logic is increment the global variable TCUFan1TimerValue on the pos-edge of the signal and see how big this variable is every time timer0A runs out. I also tried to do it so that I would just sample the posedge 1000 times and on the timeout event, see the value of Timer0A to see how long it takes to get 1000 posedges but this method didn't work because Timer0B did not want to be in Capture mode and also timeout. 

Any help would be appreciated, I would like to get the second logic working but if we can get the first version working I will be happy too.

  • Hi,

      First of all, I can't see your captures. Please upload if it shows useful information. 

      Your comment in the code says you want to count 1000 edges using timerB. Is the comment the correct description of what you want to achieve for your application? If that is the case then you need to use edge-count mode, not edge-time mode. You can use TIMER_CFG_B_CAP_COUNT_UP so the timerB will count edges of the input. You also need to set up the load register and match registers for the number of edges to count up to. When the match register is reached, it will then generate an interrupt. Please refer to the datasheet for description. I highlighted in red the below text if you are count up. You may possible do something like the code as follows. If edge-count mode is not what you are looking for then please clarify why you want to use edge-time mode. In edge-time mode, whenever an input edge is detected, the current timer count value is saved so you can determine the amount of elapsed time between the two edges. If this is what you are looking for then you can refer to the example in C:\ti\TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c1294xl\timer_edge_capture that does just that. In this mode, you also need to check your input on the scope if the edge really comes before your timer expires. In your code you only use 16-bit counter. You didn't use the prescaler to extend the timer to 24-bit.

        TimerControlEvent(TIMER4_BASE, TIMER_A, TIMER_EVENT_POS_EDGE);
        TimerLoadSet(TIMER0_BASE, TIMER_B,1000);
        TimerMatchSet(TIMER0_BASE, TIMER_B,1000);
        IntEnable(INT_TIMER0B);
        TimerIntEnable(TIMER0_BASE, TIMER_CAPB_MATCH);

    In Edge-Count mode, the timer is configured as a 24-bit up- or down-counter including the optional
    prescaler with the upper count value stored in the GPTM Timer n Prescale (GPTMTnPR) register
    and the lower bits in the GPTMTnR register. In this mode, the timer is capable of capturing three
    types of events: rising edge, falling edge, or both. To place the timer in Edge-Count mode, the
    TnCMR bit of the GPTMTnMR register must be cleared. The type of edge that the timer counts is
    determined by the TnEVENT fields of the GPTMCTL register. During initialization in down-count
    mode, the GPTMTnMATCHR and GPTMTnPMR registers are configured so that the difference
    between the value in the GPTMTnILR and GPTMTnPR registers and the GPTMTnMATCHR and
    GPTMTnPMR registers equals the number of edge events that must be counted. In up-count mode,
    the timer counts from 0x0 to the value in the GPTMTnMATCHR and GPTMTnPMR registers. Note
    that when executing an up-count, that the value of GPTMTnPR and GPTMTnILR must be greater
    than the value of GPTMTnPMR and GPTMTnMATCHR. Table 13-7 on page 963 shows the values
    that are loaded into the timer registers when the timer is enabled.

  • I noticed the error with edge-count vs edge-time after I posted this so sorry about that, using the code you sent I am able to do what I am intending however now that I think about it using the edge-time mode and seeing how long between edges then using this value as a representation of RPM may be better so I am thinking of giving that a shot.

  • Hi,

      Ok, in that case, I don't think you really need timerA. You just need timerB in edge-time mode. Please refer to the edge-time example I mentioned in my last reply. 

    C:\ti\TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c1294xl\timer_edge_capture

  • Thx for the help, appreciate it.