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.

CCS/MSP430FR2433: Result of timerA using SMCLK is not as expected.

Part Number: MSP430FR2433


Tool/software: Code Composer Studio

I'am trying to measure the operating time of the SPI slave device by timerA using SMCLK.

but result of timerA is weird.

It operates 400Hz. I measured it, but the accuracy was very high.

I need only 200 data, so it works only 0.5 second.


SMCLK (=MCLK) is 16MHz, input divider is 8, so..
The expected result is 1M.

16M / 8 / 2 = 1,000,000

but actual result is 930,000 ~ 950,000.

I didn't change LPM mode.
Interrupt and SPI communication are used while the SPI slave device is operating.
FLL is enabled. if disabled, result is around 770,000.

Why does this happen?

this code is my setting of timerA.

void init_timerA()
{

// starting the timer. user guide page 370
// TAIE - Timer_A interrupt enable. This bit enables the TAIFG interrupt request

// Timer_A clock source select 10b = SMCLK
// InputDivider. 0xC0 = /8
// ID. Input divider. 00b = /1, 11b = /8.
// ID_3 (3*0x40u) /* Timer A input divider: 3 - /8 */
// TASSEL1 = 10b = SMCLK\
// TASSEL0 = 01b = ACLK.

TA0CTL |= TASSEL1 + ID_3 + TAIE; // + 0xC0;

//CM0 = 0x4000 , 10b = Capture on falling edge
//CCIS_3 (3*0x1000u) /* Capture input select: 3 - Vcc */
//CAP (0x0100) /* Capture mode: 1 /Compare mode : 0 */
TA0CCTL0 = CM0 + CCIS_3; //

// 1. Write 1 to the TACLR bit (TACLR = 1) to clear TAxR, clock divider state, and the counter direction.
TA0CTL |= TACLR; // + TAIE; // Timer_A clear. Setting this bit resets TAxR, the timer clock divider logic (the divider setting remains unchanged), and the count direction.
// 2. If necessary, write initial counter value to TAxR.
TA0R = 0;
// 3. Initialize TAxCCRn.
TA0CCR0 = 50000;
// 16M / 8(div) / 400(Hz) = 5000.
// 4. Apply desired configuration to TAxIV, TAIDEX and TAxCCTLn.

// 5. Apply desired configuration to TAxCTL including to MC bits.
// Mode control
//00b = Stop mode: Timer is halted
//01b = MC0 = Up mode: Timer counts up to TAxCCR0
//10b = MC1 = Continuous mode: Timer counts up to 0FFFFh
//11b = Up/Down mode: Timer counts up to TAxCCR0 then down to 0000h

TA0CTL |= MC0;
}

  • I changed Main Clock to 4MHz and tried again.

    result is 205,000.

    It hasn't changed much.

    AND.

    I added this code before measure time.

    while(WDTcount < 10){
    WDTcount++;
    mcu_lpm_enter(4);
    }

     .. + init_timerA(); + measure time.

    the result is 291,400.

  • Why to CCIS_3? No set the CAP=1? 

    What is the SPI signal frequency? I.E. what period are you measuring using the SMCLK 2MHz? 

    Do you enable the interrupt to read out the timer count value? If not, how to guarantee immediately readout the timer data? Do you have captured many times and calculate the clock count with 2 adjacent capture timer values? 

    Thanks, 

    Lixin 

  • Hi Lixin,

    1. CCIS, CAP. there is no specific reason.
    Tried CCIS 0~2 and CAP but the results did not change.

    2. SPI signal frequency
    UCB0CTLW0 |= UCSSEL__SMCLK; // SMCLK
    UCB0BR0 = 0x10;

    3. what period are you measuring using the SMCLK 2MHz?
    I want to measure the time that a device operating at 400Hz operates 200 times.
    500ms is perfect, 497.5 ~ 502.5ms is safe. else shows that something went wrong and needs to be restarted.

    2MHz?
    I had to lower the clock to reduce power consumption for other reason.


    4. Do you enable the interrupt to read out the timer count value?

    I use interrupt like this.
    timer count reach 50000, it return 0 and raise overflow interrupt.

    #pragma vector=TIMER0_A1_VECTOR
    __interrupt void TIMER0_A1_ISR(void){
    int _ = TA0IV;
    TimerAcount++;
    }

    if TimerAcount = 5, ticksave = 40000,
    result is 290,000.

    5. Do you have captured many times and calculate the clock count with 2 adjacent capture timer values?

    capture just 2 time. before and after. this is my code.

        tickstart = TA0R;
        startOF = TimerAcount;
        while(savednum < 200){ // get 200 times. by interrupt. in 0.5 sec.
    
            if(readflag){   // interrupt of LIS
                readflag = false;
                lis_get_xyz_saveto(savednum);
    
                savednum++;
            }
        }
    
        end_timerA(); // TA0CTL = 0;
        ticksave = TA0R;
        endOF = TimerAcount;

    if disable FLL, result is around 206,000
    if enable FLL, reuslt is around 291,000.


    Thanks,

    KH

  • The FLL is what assures that your DCO (SMCLK) is running at the speed you think it is. It's not usually useful to turn it off. If you Must turn it off, at least wait for it to lock first; in theory that can take up to about 0.5 seconds.

    Unsolicited: Doing timing that way is susceptible to rollover glitches. Consider slowing the timer down even more using TA0EX0 (or maybe ACLK) such that it does not (normally) wrap during your timing.


  • Thanks for advice.

    I changed the settings and tried again.

    MCLK, SMCLK = 4MHz, input divider = 64, operating time = 0.5 second.
    expected ideal tick = 31,250 +- 156.25


    I saved the ticks for every transfer this time.

    [0] unsigned short 100 0x0024B0
    [1] unsigned short 230 0x0024B2
    [2] unsigned short 360 0x0024B4
    [3] unsigned short 490 0x0024B6
    [4] unsigned short 621 0x0024B8

    ...

    [98] unsigned short 15137 0x002574
    [99] unsigned short 15322 0x002576
    [100] unsigned short 15507 0x002578
    [101] unsigned short 15693 0x00257A

    The front Half were measured not badly.
    15693 * 64 = 1,004,352 .

    [155] unsigned short 26876 0x0025E6
    [156] unsigned short 27092 0x0025E8
    [157] unsigned short 27309 0x0025EA
    [158] unsigned short 27525 0x0025EC

    [197] unsigned short 35971 0x00263A
    [198] unsigned short 36188 0x00263C
    [199] unsigned short 36405 0x00263E

    But in the latter half, the rise increases and the result is completely wrong.

  • 1) Perhaps you can explain what we're looking at. Which numbers are "completely wrong", and how can you tell?

    2) How are you doing the measurements? Do you clear the timer each time, or capture start+stop and subtract? When I do this, I usually leave a Continuous mode timer running and capture start+stop, since that makes the arithmetic easy.

    3) What exactly are you timing? The fragment you posted earlier was dominated by a conditional (if()), so it seems that it might act differently under different conditions.

    4) Do you wait for the FLL to lock before starting the trials? You can do other things during that span, but you really want the FLL locked (consistent clock) when you start measuring.


  • Hi Bruce,

    1. Sorry, I mean. The results(36000) were not what I expected(31250).


    2. check 2 times. before and after.

    start timerA,
    check timer,
    what I want to know about the operating time,
    stop timer(maybe useless?),
    check timer.

    3. operating and capturing

    P1OUT &= !BIT5;
    tickstart = TA0R; startOF = TimerAcount; while(savednum < 200){ // get 200 times. by interrupt. in 0.5 sec. if(readflag){ // interrupt of LIS readflag = false; P1OUT |= BIT5; // toggle pin 1.5 lis_get_xyz_saveto(savednum); P1OUT &= !BIT5; // toggle pin 1.5 tickarr[savednum] = TA0R; savednum++; } } end_timerA(); ticksave = TA0R; endOF = TimerAcount;


    I tested with GPIO(with oscilloscope) and confirmed that the operation was working normally.

    4. I don't touch FLL now and I'm waiting 1.25 second.
    How long should I wait?

    this is flow of program.

    Init MSP430FR2433.
    change config for init MSP and other devices.
    init Watchdog timer.

    while(WDTcount < 5){
    WDTcount++;
    mcu_lpm_enter(4);
    }
    wait 1.25 second.

    init timerA.

    measure time.

    ...

    I tried moving init_timerA in front of waiting sequence, but the result was not different.

    thanks.

  • 1) OK, so that second number is the content of tickarr[], and it's monotonically increasing since you aren't clearing TA0R each time. (I don't necessarily recommend clearing the timer, I'm just describing.)

    So what's interesting is the delta between consecutive lines. That is indeed gradually increasing, from about 130 in the first group up to 217 in the final group.

    3) What you're measuring is dominated by that if(), which I suspect is checking a variable set in an ISR. Keep in mind that (a) the ISR rate is probably not coordinated with your code, so you're measuring the spinning between ISRs and (b) you're also measuring the cost of the ISR.

    For (a) in particular: If the ISR cycle is slightly longer than your code, it will drift forward, and your measurements will gradually increase due to extra spinning. I suggest you put the start/stop captures inside the if().

    4) Normally the FLL should lock in < 0.5 seconds (using the REFO, which I expect you are). Are you fairly certain that loop really waits for 1.25 seconds?

    If you want to be certain, you can insert:

    > while(CSCTL7 & (FLLUNLOCK0 | FLLUNLOCK1)); // Poll until FLL is locked

    [Lifted from Example msp430fr243x_CS_07.c, here:

    https://dev.ti.com/tirex/explore/node?node=AJXSKLubovap2pQl1MpHeA__IOGqZri__LATEST

    ]

    Unsolicited:

    P1OUT &= !BIT5; // toggle pin 1.5

    This is equivalent to "P1OUT = 0;". I suspect you wanted:

    P1OUT &= ~BIT5; // toggle pin 1.5

  • Hi Bruce,

    3. Can ISR be the cause of the problem? but. this program cannot run without interrupts..

    Receiving a ready signal from the device is interrupt and SPI transaction use interrupts.


    put the start/stop captures inside the if()?
    I can't understand.

    if(readflag){
    continue timerA
    P1OUT pin 1.5 = high
    do SPI things
    P1OUT pin 1.5 = low
    suspend timerA
    }

    This code can only measure the time when the pulse is high. Not the whole time.

    4. Maybe there is a big problem with FLL.

    void init_clocks()
    {
    // Configure one FRAM waitstate as required by the device datasheet for MCLK
    // operation beyond 8MHz _before_ configuring the clock system.
    FRCTL0 = FRCTLPW | NWAITS_1;
    
    __bis_SR_register(SCG0); // disable FLL
    
    CSCTL3 |= SELREF__REFOCLK; // Set REFO as FLL reference source
    CSCTL0 = 0; // clear DCO and MOD registers
    CSCTL1 &= ~(DCORSEL_7); // Clear DCO frequency select bits first
    
    // DCORSEL_3 = 0x011 -> 8MHz
    // DCORSEL_0 = 0x000 -> 1Mhz
    // DCORSEL_1 = 0x001 -> 2Mhz
    // DCORSEL_2 = 0x010 -> 4Mhz
    // DCORSEL_5 = 0x101 -> 16MHz. default.
    CSCTL1 |= DCORSEL_2; // Set DCO
    CSCTL2 = FLLD_0 + 487; // DCOCLKDIV = DCO
    __delay_cycles(3);
    __bic_SR_register(SCG0); // enable FLL
    
    while(CSCTL7 & (FLLUNLOCK0 | FLLUNLOCK1)); // Poll until FLL is locked
    
    CSCTL4 = SELMS__DCOCLKDIV; // set default REFO(~32768Hz) as ACLK source, ACLK = 32768Hz
    // default DCOCLKDIV as MCLK and SMCLK source
    CSCTL6 &= ~(XT1AUTOOFF);
    
    }

    in this code, debuging traped here. 'while(CSCTL7 & (FLLUNLOCK0 | FLLUNLOCK1));'.


    I comment out 

    CSCTL1 &= ~(DCORSEL_7); // Clear DCO frequency select bits first

    this line and tried changing CSCTL1 to

    CSCTL1 = DCOFTRIMEN | DCOFTRIM0 | DCOFTRIM1 | DCORSEL_0, 2, 3.;

    but still traped that while().


    Should I post a new question about this?


    Thanks a lot.

  • 3) If your goal is to capture the time of the ISR, then you should do that. But keep in mind that you're measuring the idle time between, which (these events being asynchronous) may vary.

    4) Short answer: Try DCORSEL=5. The reset value is =1. [Ref user guide (SLAU445I) Table 3-5 and data sheet (SLASE59D) Table 5-6]

    Slightly longer: That "487" specifies an absolute speed (487*32768Hz=~16MHz). If that speed isn't in the RSEL range, the FLL will push CSCTL0:DCO to one end of its range or the other and stick there (saturate), unable to lock.

    I expect the result in that case would be a constant (though incorrect) DCO speed, which in itself wouldn't explain a gradual timing drift.

    If you haven't already, you may want to look over example msp430fr243x_CS_03.c here:

    https://dev.ti.com/tirex/explore/node?node=AHMHa7q.qkFTrXXRnRPsug__IOGqZri__LATEST

    You can probably just copy/paste the relevant section. (That's what I usually do.)

  • Hi Bruce,

    when MCLK is 4MHz,
    CSCTL2 = FLLD_0 + 122;
    this code works well! thank you.


    I didn't understand FLLN before.


    With this nice FLLN, TimerA has become more accurate. but it doesn't seem to be perfect yet.

    I measured with 4 different boards.

    results :
    1. 31038, 31153, 31074, 31112, 31079
    2. 31737, 31745, 31772, 31748
    3. 31926, 31955, 31958, 31933
    4. 31248, 31252, 31243, 31246

    best result is 31250 +- 156.

    number 1 is little small and 2,3 is too big.


    Thanks.

**Attention** This is a public forum