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.

Timer_d Accuracy

Hi Everyone,

I am currently working on a project which requires measuring the frequency of a signal in the range of 40KHz-170KHz, with reasonably high accuracy. Any clock/timer with more than 48Mhz should provide sufficient accuracy. I have been experimenting with the MSP460F5171 as the timer_d module of this chip is capable of these speeds while still quite low power. However, I seem to be having an issue with accuracy which I believe is due to jitter and would like to know if this is a hardware limitation or if the module is configured incorrectly.

The setup:

Using timer_d in capture mode and free-running mode at 64MHz I am able to get the time between rising edges for a given number of rising edges, then observe the time taken to do so. For example I have been counting the total time taken for 23 rising edges from a 90KHz square wave signal from a function generator.

The Problem:

The time take for each cycle (23 rising edges) appears to variate by around 20 - 50 of the 64MHz clock cycles.  The input is quite stable, I have confirmed it is stable by measuring it on an oscilloscope and checked it on another (non TI) microcontroller which has successfully measured the same period with a maximum variation 2 (48 MHz) clock cycles. I require the variation to be less than 8 clock cycles out.

After measuring 5 cycles (of 23 rising edges) in a row, I got the following values: 14680, 14689, 14674, 14678, 14693 which shows a variation of 19 (14693 - 14674) 64MHz clock cycles. 19 clock cycles variation in such a small time is too much.

Is this some sort of jitter problem? Is the module not able to do the required accuracy since it is reliant on an oscillator internal to the timer_d module? Any ideas if its possible to fix this issue?

I have initialised the module with the following:

P3DIR &= ~BIT2; // TD0.0 input
P3SEL |= BIT2; // TD0.0 option select

TD0HCTL1 = CALTDH0CTL1_64; // Get the 64 Mhz TimerD TLV Data
TD0CTL0 = CNTL_0 // 16-bit timer
+ ID_0 // Divide by 1
+ MC_0; // Halt timer until init is complete

TD0CTL1 |= TDCLKM_1; // TD0 clock = Hi-res local clock

// FREE RUNNING MODE (TDHREGEN = 0)
TD0HCTL0 = TDHFW // Fast wake-up mode.
+ TDHD_0 // Set divider to 1
+ TDHM_0 // Multiply by 8
+ TDHEAEN // Enhance accuracy
+ TDHEN; // Enable Hi-Res

// Dual Capture mode.
TD0CTL2 |= TDCAPM0; 

TD0CCTL0 = CAP // Capture mode
+ CM_1 // Rising edge
+ CCIS_1
+ CCIE; // Enable local interrupt for Timer TD0.0


// Start the counter (continuous mode).
TD0CTL0 |= MC_2;

Any insights would be greatly appreciated.


Thanks,
Jake

  • Hi Jake, 

    Have you tried this experiment running the timer in regulated mode? In free-running mode an internal clock to the timer is used and may result in the observed issue. If you have an external crystal on the system, you can use regulated mode and multiply it by 8 or 16 (depending on the crystal frequency) and use it for your capture system. If you don't have an external crystal, you can still use regulated mode with SMCLK as the source clock which presents a 20% worst-case jitter according to the datasheet.  

    You may have seen this already, but just in case this app note has good information on Timer_D: http://www.ti.com/lit/an/slaa601/slaa601.pdf

    Damian

  • Hi Damian,

    Thanks for the reply. I have attempted using regulated mode with an external 16Mhz oscillator running the timer_d at 128Mhz; however, I still seem to have similar issues with the accuracy. Here are 6 sequential periods of 23 cycles of the 90Khz sine wave: 29235, 29272, 29269, 29297, 29285, 29246. This still results in a jitter of 62 (29297 - 29235) 128MHz clock cycles,  which is still out too inaccurate for the task. Can you think of anything else I may be able to do to enhance the accuracy? Or am I at the limits of the chip?

    My initialisation code is:

    PJSEL |= BIT4+BIT5; // Port select XT1
    UCSCTL6 &= ~(XT1OFF); // XT1 On
    UCSCTL6 |= XTS | XT1DRIVE_2;

    UCSCTL3 = 0; // FLL Reference Clock = XT1

    // Loop until XT1 & DCO stabilizes - In this case loop until XT1 and DCo settle
    do
    {
    UCSCTL7 &= ~(XT1LFOFFG + XT1HFOFFG + DCOFFG);
    // Clear XT1,DCO fault flags
    SFRIFG1 &= ~OFIFG; // Clear fault flags
    }while (SFRIFG1&OFIFG); // Test oscillator fault flag

    UCSCTL6 &= ~(XT1DRIVE_2); // Xtal is now stable, reduce drive strength

    UCSCTL4 &= ~(SELS_7); // Set SMCLK to the external oscillator.
    UCSCTL4 &= ~(SELM_7); // Set MCk to the external oscillator.

    __delay_cycles(375000);


    P3DIR &= ~BIT2; // TD0.0 input
    P3SEL |= BIT2; // TD0.0 option select

    TD0HCTL1 |= TDHCLKCR;
    TD0CTL0 = TDSSEL_2 // Use SMCLK – 16 MHz
    + CNTL_0 // 16-bit timer
    + ID_0 // Divide by 1
    + MC_0; // Halt timer until init is complete

    TD0CTL1 |= TDCLKM_1; // TD0 clock = Hi-res local clock

    TD0HCTL0 = TDHFW // Fast wake-up mode.
    + TDHD_0 // Set divider to 1
    + TDHM_0 // Multiply by 8. 8 MHz x 16 = 128 MHz
    + TDHREGEN // Regulated Mode
    + TDHEAEN // Enhance accuracy
    + TDHEN; // Enable Hi-Res


    // Dual Capture mode.
    TD0CTL2 |= TDCAPM0; // Channel 2 single capture mode

    TD0CCTL0 = CAP // Capture mode
    + CM_1 // Rising edge
    + CCIS_1
    + CCIE; // Enable local interrupt for Timer TD0.0

    // Start the counter (continuous mode).
    TD0CTL0 |= MC_2;

    Cheers,
    Jake

  • Jake, 

    How are you observing the captured values? Are you running this test with the debugger on? Also, do you have all other interrupts disabled? Can you please provide the code for your interrupt routine? I expect a more accurate reading with an external clock. Also, can you try using pin P1.7 instead of P3.2 for your input capture? 

    Thanks, 

    Damian 

  • Hi Damian,

    Sorry for the late reply, unfortunately this part of the project has been put on hold for the time being.

    I was observing the values using break points with the debugger and reading the variable values. However I did run a test by toggling pins based on the lower bits of the period values and reading them with a logic analyser. This confirmed my method of reading the values was unlikely to be the issue. No other interrupts have been enabled and I will try it using pin 1.7 when I get a chance to work on it again.

    My code in the interrupt routine is as follows:

    // Timer0_D0 Interrupt Vector
    #pragma vector=TIMER0_D0_VECTOR
    __interrupt void TIMER0_D0_ISR (void)
    {
    edge1[edgeCounter] = TD0CL0;
    edge2[edgeCounter] = TD0CCR0;

    edgeCounter++;


    if (edgeCounter > 23)
    {
    edgeCounter = 0;
    readyFlag = true;                                // Set the ready flag to true so the values can be processed in the main loop.
    __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
    }
    }

    Cheers,
    Jake

**Attention** This is a public forum