如何使用msp430获取程序的执行时间?

5
我想要以毫秒为单位测量C代码的执行时间,我使用 msp430f16

任何帮助将不胜感激。

谢谢。

4个回答

4

http://github.com/dwelch67/msp430_samples

这些示例展示了使用计时器测量时间周期,先采样计时器,然后再进行差值运算,得到的结果就是程序执行时间。 编辑: 这个示例使用定时器和除数,而不是监视滚动标志。读取计时器计数寄存器并假设你正在计数超过计时器的计数,从中减去一个来获取时间。调整除数以避免滚动,并尝试获得所需精度。
    ;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

这个示例使用定时器来测量传输串行(rs232)字符的时间周期,如上所述,请调整除数以确保您不会计算超过定时器的一个周期(定时器可以翻转,例如0xF000到0x3000是可以的,但是0xF000左右一次到0xF100就是一个问题)。如果可能的话,要粗略地进行分频,以确保您绝对不会翻转,然后再缩小除数,直到获得最佳准确性。

是的,您可以使用中断来处理翻转,但那会干扰您正在尝试测量的东西,您不想这样做(除非中断的开销或您用于监视定时器翻转的任何机制(您不需要中断)可接受您的测量)。

#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的msp430后端实在是太实验性了,也就是说:它有很多问题,不要过度依赖它,只可用于玩耍。GCC编译器并不算简单,但也不过分繁琐。Naken430asm汇编程序非常易于使用,而且这个处理器的汇编语言也相当简单,是一个很好的架构...


根据StackOverflow的标准政策,最好提供实际答案,而不仅仅是指向答案的指针(该指针可能在未来移动或消失)。 - Brooks Moses
同时,堆栈溢出失去了在链接中进行的改进。不过,我们接受了您的建议,在答案中添加了示例代码。 - old_timer
没错,我同意添加链接也很有用。无论如何,你加上的代码解释比我在链接中找到的要好得多!非常高兴给你点赞。 - Brooks Moses

1

没有通用的方法来做到这一点,您可以使用可用的硬件定时器资源并将其配置为提供适当的时间基准。我建议对于计时代码执行,毫秒定时器可能有些粗糙;微秒可能更合适。

另一种简单的方法是在模拟器中执行和分析代码,它没有额外的开销或代码(甚至硬件),并且可能具有更高的准确性。我相信Code Composer Studio包括分析和模拟工具。其他工具链也可能包括它们。如果被测试的代码具有硬件定时/延迟依赖关系,则此方法可能不适用。

另一种简单的方法是在执行前后切换可用的GPIO,并使用示波器或外部计时器/计数器监视引脚。该方法将包括硬件延迟/抖动以及在测试代码执行期间可能发生的任何中断相关的开销。当没有可用的硬件定时器资源时,也可以实现它。


对于“以毫秒为单位”,我期望GPIO +示波器的定时非常好。 - XTL
@XTL:考虑到具体问题,你说得很中肯。但对于许多“硬”实时应用程序来说,开销可能是至关重要的。 - Clifford

1
一些MSP430设备有一个内置的周期计数器,使用调试器时可以使用。我发现在比较代码序列时这非常准确。
但我不知道你的设备是否有一个。事实上,我没有找到一个名为MSP430f16的设备,它们通常在"f"后面有三到四个数字。

0

如果您想要快速地进行性能分析,而不改变现有的软件,但是不需要非常精确,您可以在所需代码前后使用日志断点。

如果您正在使用IAR,这个选项可能会有些难以找到。您需要右键单击要添加断点的行,并选择日志断点。

当然,触发日志的延迟会有一些时间,但这个延迟应该是恒定的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接