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.

CC253x: count cpu cycles

Other Parts Discussed in Thread: CC2530, TIMAC, Z-STACK

Hey there,

currently I'm working on a small project on a TI CC2530 and I also need to do some performance testing.

My idea to do this, was to use the timers from the cc2530 to count the cpu cylces a operation lasts.

So at first, would this be the right thing to solve my problem, or might there be a better way to do this?

The other question is, which timer should I use for this and is there somebody, who is able to show me a small example how to use the timers?

 

Kind regards and thanks in advance.

geuma

  • Yes, you can use a timer for this. I would recommend to use Timer 1, which has 16 bits. You can also use Timer 3 or Timer 4, but they have only 8 bits, or Timer 2, but that one is typically used for MAC timing in the radio (i.e. if you are using Z-stack or TIMAC).

    The exact use depends on the number of cycles you need to count. If it is less than 65536, I'd just do it like this:

    unsigned short num_cycles;

    T1CTL = 0x00; // Stop Timer 1
    T1CNTL = 0x00; // Clear Timer 1
    T1CTL = 0x01; // Start Timer 1 in free-running mode; no prescaler
    function_to_evaluate(); // Perform operations that you want to time
    T1CTL = 0x00; // Stop Timer 1
    ((unsigned char *)(&num_cycles))[0] = T1CNTL;
    ((unsigned char *)(&num_cycles))[1] = T1CNTH;
    // num_cycles will contain the number of cycles elapsed

    If you need to time more than 65535 cycles, you can either use an overflow interrupt of Timer 1 to update an overflow counter or use a prescaler (this will reduce your accuracy).

    It is also possible to read out the value of Timer 1 without stopping the timer first if you need to keep the timer running.

  • Hey, thanks for the response.

    I just verified your code and I think it is working.

    I tried to measure the cpu cycles a NOP() does take. The timer1 results an amount of 5 cycles, which could be right because of the context switches and so on. Is this correct?

    if the timer1 without a prescaler is able to handle 65.535 (because of the 16bit counter) cycles, he would be able to measure (on a 32Mhz MCU with a clock speed of 32.768kHz) nearly 2 seconds, right ??

    setting the prescaler to 128, the counter will be able to handle 65.535*128 = 8.388.480 cycles (with less accuracy), right ??? So this will result in nearly 256seconds on the same MCU?

    Are those assumption right? Did I understand the usage and math behind the timer?

    kind regards and thanks in advance!

  • geuma geuma said:
    I tried to measure the cpu cycles a NOP() does take. The timer1 results an amount of 5 cycles, which could be right because of the context switches and so on. Is this correct?

    This looks correct, as it will include the duration of the stop Timer 1 instruction as well as the NOP. The NOP takes 1 cycle, with a potential extra cycle for instruction fetching.

    geuma geuma said:
    if the timer1 without a prescaler is able to handle 65.535 (because of the 16bit counter) cycles, he would be able to measure (on a 32Mhz MCU with a clock speed of 32.768kHz) nearly 2 seconds, right ??

    No, Timer 1 runs on 32 MHz, not 32.768 kHz. So the maximum duration will be 2.048 ms. With a prescaler of 128, you get a maximum of 262 ms, but less accuracy. You can divide further by reducing TICKSPD (cf. Section 4.5 of the CC253x User Guide).

  • Thanks for the response again.

    hec said:
    No, Timer 1 runs on 32 MHz, not 32.768 kHz. So the maximum duration will be 2.048 ms. With a prescaler of 128, you get a maximum of 262 ms, but less accuracy. You can divide further by reducing TICKSPD (cf. Section 4.5 of the CC253x User Guide).

    By calculating the time, i forget 1k at the division of the clock speed. Is it true that the timer1 is running with 32.000kHz and the MCU itself is running with 32.768kHz???

    So, for my testing the 262ms will not be enough and I do need an acceptable accuracy of the counter - so increasing the prescaler to higher value than 128 is not an option for me, so I decided to do an overflow interrupt. The userguide says the following:

    When the terminal count value 0xFFFF is reached, both the IRCON.T1IF and T1STAT.OVFIF flags are set. An interrupt request is generated if the corresponding interrupt mask bit TIMIF.OVFIM is set together with IEN1.T1EN.

    But how do I catch this interrupt request, how do I tell the cc2530 to call a specific function on this?

    Currently my code looks like:

    unsigned short num_cycles;
    T1CTL = 0x00; // stop Timer1
    T1CNTL = 0x00; // clear Timer1
    //T1CTL |= 0x0C; // setting prescaler to 128

    T1CC0H = 0xFF; // set compare value for high bit
    T1CC0L = 0xFF; // set compare value for low bit
    T1CCTL0 = 0x44; // set compare mode

    // clear interrupt pending flag, disable interrupt
    T1CTL &= ~0x10; // T1CTL.OVFIF = 0
    T1STAT &= ~0x01; // T1STAT.CH1IF = 0
    IEN1 &= ~0x02; // IEN1.T1EN = 0

    T1CTL |= 0x01; // start Timer1 in free-running mode
    IEN1 |= 0x02; // enable interrupt

    do_something();
      
    T1CTL = 0x00; // stop Timer1
    ((unsigned char *)(&num_cycles))[0] = T1CNTL;
    ((unsigned char *)(&num_cycles))[1] = T1CNTH;
    sprintf(line2, "%u", num_cycles);

    Is the code correct for now? The counter overflows at a value of 65535 but I don't have any idea how to implement the counter for the overflow. It would assist me and I would totally appreciate the help.

    Thanks in advance and kind regards.

     

  • geuma geuma said:
    By calculating the time, i forget 1k at the division of the clock speed. Is it true that the timer1 is running with 32.000kHz and the MCU itself is running with 32.768kHz???

    No. The maximum CPU clock speed and the maximum Timer 1 tick speed are both 32 MHz (or 32000 kHz - but '.' means decimal point). There is also a 32.768 kHz (or 32768 Hz) crystal oscillator on the CC2530. This is only used for the sleep timer and watchdog timer.

    geuma geuma said:
    But how do I catch this interrupt request, how do I tell the cc2530 to call a specific function on this?

    You can do this in IAR as follows:

    volatile unsigned short t1ovf;

    #pragma vector=T1_VECTOR
    __interrupt void t1_isr(void)
    {
      // Clear all Timer 1 source interrupt flags
      T1STAT = 0x00;
      // Increment overflow counter
      t1ovf++;
    }

    In your main program, you need to enable time Timer 1 overflow interrupt and the global interrupt enable.  You also have some errors in the code and some unnecessary instructions. You could rewrite your program as follows:

    unsigned long num_cycles;
    T1CTL = 0x00; // stop Timer1
    T1CNTL = 0x00; // clear Timer1
    //T1CTL |= 0x0C; // setting prescaler to 128

    // disable interrupt, clear all interrupt pending flag
    T1IE = 0;      // Disable Timer 1 interrupt
    T1STAT = 0x00; // Clear all Timer 1 source interrupt flags
    T1IF = 0;      // Clear Timer 1 CPU interrupt flag

    t1ovf = 0;     // Clear overflow counter

    T1IE = 1;      // Enable Timer 1 interrupt
    EA = 1;        // Global interrupt enable

    T1CTL |= 0x01; // start Timer1 in free-running mode

    do_something();
     
    T1CTL = 0x00; // stop Timer1
    ((unsigned char *)(&num_cycles))[0] = T1CNTL; // Set byte 0 of num_cycles
    ((unsigned char *)(&num_cycles))[1] = T1CNTH;
    // Set byte 1 of num_cycles
    ((unsigned short *)(&num_cycles))[1] = t1ovf; // Set byte 2 and 3 of num_cycles

    sprintf(line2, "%lu", num_cycles);

     

  • thanks, works perfectly

  • Hi, I've been checking this post and it is pretty interesting. Could you please add information on the ratio of cycles that most of the instructions used?

    Thanks

  • I am not sure if I fully understand what you mean. Note that this is an old thread, and due to forum reorganization, it has ended up in the wrong forum (provided that your follow-up question is about CC2530).

    You can find a list of cycles needed for each assembly instruction in the user guide (http://www.ti.com/lit/pdf/SWRU191), Table 2-3. Note that these numbers do not include waitstates due to flash accesses.

    If you have follow-up questions, please ask them in the correct forum based on what chip you are using. For CC2530, the correct forum would be the ZigBee®, 6LoWPAN & 802.15.4 MAC Forum.