How to get execution time using msp430?

ouma talel picture ouma talel · Dec 28, 2011 · Viewed 7k times · Source

I would like to have the execution time of a C code in milliseconds and I use msp430f16.

Any help will be appreciated.

Thank you.

Answer

old_timer picture old_timer · Dec 28, 2011

http://github.com/dwelch67/msp430_samples

the samples show measuring periods of time using the timer, sample the timer before and after and subtract the difference, that is your execution time.

EDIT:

this sample uses the timers and divisors, instead of monitoring the roll over flag read the timer counter register and assuming you are counting more than the timer number of ticks, subtract one from the other to get the time. Adjust divisors to avoid the roll over and also try for the accuracy you are after.

    ;This version is written for naken430asm.
    ;http://www.mikekohn.net/micro/naken430asm_msp430_assembler.php
    ;naken430asm -o filename.hex filename.s
    ;mspdebug takes hex files as well as elfs.

WDTCTL equ 0x0120


CALBC1_1MHZ equ 0x10FF
CALDCO_1MHZ equ 0x10FE

DCOCTL  equ 0x56
BCSCTL1 equ 0x57
BCSCTL2 equ 0x58

TACTL   equ 0x0160
TAR     equ 0x0170
TACCR0  equ 0x0172
TACCTL0 equ 0x0162

P1OUT   equ 0x0021
P1DIR   equ 0x0022


    org 0xFC00

reset:
    mov #0x0280,r1

    mov #0x5A80,&WDTCTL ; 0x5A00|WDTHOLD

    ; use calibrated clock
    clr.b &DCOCTL
    mov.b &CALBC1_1MHZ,&BCSCTL1
    mov.b &CALDCO_1MHZ,&DCOCTL

    ; make p1.0 and p1.6 outputs
    bis.b #0x41,&P1DIR
    bic.b #0x41,&P1OUT
    bis.b #0x40,&P1OUT

    ; 1MHz is 1000000 clocks per second
    ; 1000000 = 0xF4240
    ; The timers are 16 bit
    ; Using a divide by 8 in BCSCTL2 gives
    ; 125000 (0x1E848) clocks in a second
    ; Using a divide by 8 in the timer gives
    ; 15625 (0x3D09) timer ticks per second.

    ; If both divisors are by 8, and we set
    ; TACCR0 to 0x3D08 and set for count up mode
    ; then, theory, we can measure seconds.

    bis.b #0x06,&BCSCTL2
    mov #0x02C4,&TACTL
    mov #0x3D08,&TACCR0
    mov #0x02D0,&TACTL
    ;mov #0x02D0,&TACTL ; use this instead to blink faster

loop:
    xor.b #0x41,&P1OUT
loop0:
    bit.w #0x0001,&TACCTL0
    jz loop0
    bic.w #0x0001,&TACCTL0

    jmp loop


hang:
    jmp hang

    org 0xFFE0
    dw hang
    dw hang
    dw hang
    dw hang
    dw hang
    dw hang
    dw hang
    dw hang
    dw hang
    dw hang
    dw hang
    dw hang
    dw hang
    dw hang
    dw hang
    dw reset

This sample uses the timer to measure a time period to transmit serial (rs232) characters, as mentioned above adjust the divisors to insure you dont count more than one cycle of the timer (the timer can roll over, that is fine 0xF000 to 0x3000 for example, not a problem, 0xF000, around once to 0xF100 that is a problem). If possible grossly over divide so that you are definitely not rolling over, the scale back the divisors until you get the best accuracy.

Yes you can use an interrupt to deal with the roll over but that messes up the thing you are trying to measure, you dont want to do that (unless the overhead of the interrupt or whatever mechanism you use to monitor timer rollover (you dont need an interrupt for this) is acceptable to your measurement).

#define WDTCTL     (*((volatile unsigned short *)0x0120))

#define CALBC1_1MHZ (*((volatile unsigned char *)0x10FF))
#define CALDCO_1MHZ (*((volatile unsigned char *)0x10FE))
#define CALBC1_8MHZ (*((volatile unsigned char *)0x10FD))
#define CALDCO_8MHZ (*((volatile unsigned char *)0x10FC))
#define CALBC1_12MHZ (*((volatile unsigned char *)0x10FB))
#define CALDCO_12MHZ (*((volatile unsigned char *)0x10FA))
#define CALBC1_16MHZ (*((volatile unsigned char *)0x10F9))
#define CALDCO_16MHZ (*((volatile unsigned char *)0x10F8))

#define DCOCTL  (*((volatile unsigned char *)0x56))
#define BCSCTL1 (*((volatile unsigned char *)0x57))
#define BCSCTL2 (*((volatile unsigned char *)0x58))

#define TACTL   (*((volatile unsigned short *)0x0160))
#define TAR     (*((volatile unsigned short *)0x0170))
#define TACCR0  (*((volatile unsigned short *)0x0172))
#define TACCTL0 (*((volatile unsigned short *)0x0162))


#define P1IN  (*((volatile unsigned char *)0x0020))
#define P1OUT (*((volatile unsigned char *)0x0021))
#define P1DIR (*((volatile unsigned char *)0x0022))

// 16MHz clock
// The timer is 16 bit
// set to divide by 1
// 16,000,000 / 155200 = 138.88889
#define TACCR0_VALUE 138

//-------------------------------------------------------------------
void uart_putc ( unsigned short c )
{
    unsigned short sa;
    unsigned short sb;
    unsigned short then,now;

    sa=c<<1;
    sa|=1<<9;
    sb=10;
    then=TAR;
    while(sb--)
    {
        if(sa&1) P1OUT|=1; else P1OUT&=(~1);
        sa>>=1;
        while(1)
        {
            now=TAR-then;
            if(now>TACCR0_VALUE) break;
        }
        then+=TACCR0_VALUE;
    }
}
//-------------------------------------------------------------------
void hexstring ( unsigned short d, unsigned short cr )
{
    //unsigned short ra;
    unsigned short rb;
    unsigned short rc;

    rb=16;
    while(1)
    {
        rb-=4;
        rc=(d>>rb)&0xF;
        if(rc>9) rc+=0x37; else rc+=0x30;
        uart_putc(rc);
        if(rb==0) break;
    }
    if(cr)
    {
        uart_putc(0x0D);
        uart_putc(0x0A);
    }
    else
    {
        uart_putc(0x20);
    }
}
//-------------------------------------------------------------------
void notmain ( void )
{
    unsigned short /*sa,*/sb;
    //unsigned short start;
    unsigned short then; //,now;
    unsigned short bitin;
    //unsigned short log[32];

    WDTCTL = 0x5A80;

    // use calibrated clock
    DCOCTL = 0x00;
    BCSCTL1 = CALBC1_16MHZ;
    DCOCTL = CALDCO_16MHZ;

    // make p1.0 an output
    P1DIR |= 0x01;
    P1OUT |= 0x01;

    P1DIR &= ~0x02;


    BCSCTL2&=~0x06;
    TACTL = 0x0204;
    TACTL = 0x0220;

    hexstring(0x1234,1);
    hexstring(0x5678,1);

    while(1)
    {
        //sa=0;
        bitin=0;
        while(1) if((P1IN&2)==0) break;
        then=TAR;
        while(1)
        {
            if((TAR-then)>=(TACCR0_VALUE>>1)) break;
        }
        if(P1IN&2)
        {
            bitin>>=1;
            bitin|=1<<9;
        }
        else
        {
            bitin>>=1;
        }
        then+=(TACCR0_VALUE>>1);
            for(sb=0;sb<9;sb++)
        {
            while(1)
            {
                if((TAR-then)>=TACCR0_VALUE) break;
            }
            if(P1IN&2)
            {
                bitin>>=1;
                bitin|=1<<9;
            }
            else
            {
                bitin>>=1;
            }
            then+=TACCR0_VALUE;
        }
        hexstring(bitin,0);  hexstring(bitin>>1,1);
    }
}
//-------------------------------------------------------------------
//-------------------------------------------------------------------

llvm's msp430 backend is truly experimental, read: broken, dont rely on it more than just to play with it, the gcc compiler is not trivial but not excessively painful to build either. The naken430asm assembler is very easy to use and the asm for this processor is quite simple as well, good architecture...