我想以毫秒为单位获得 C 代码的执行时间,我使用msp430f16
.
任何帮助将不胜感激。
谢谢你。
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 汇编器非常易于使用,并且该处理器的 asm 也非常简单,良好的架构......
一些 MSP430 器件具有板载周期计数器,在使用调试器时可用。我发现在比较代码序列时这是非常准确的。
我不知道你的设备是否有一个。事实上,我还没有找到一个名为 MSP430f16 的,它们通常在“f”之后有三四位数字。
没有通用的方法可以做到这一点,您可以使用可用的硬件计时器资源并将其配置为提供适当的时基。我建议对于计时代码执行,毫秒计时器可能有点理所当然;微秒可能更合适。
没有开销或额外代码(甚至硬件)并且可能更准确的更简单的方法是在模拟器中执行和分析代码。我相信 Code Composer Studio 包括分析和模拟工具。其他工具链也可以包含它们。如果正在测试的代码具有硬件时序/延迟依赖性,则此方法可能不适合。
另一种简单的方法是在执行前后切换可用的 GPIO,并使用示波器或外部定时器/计数器监控引脚。这种方法将包括硬件延迟/抖动以及与在执行被测代码期间可能发生的中断相关的任何开销。也可以在没有可用的硬件定时器资源时实现。
如果您正在寻找快速而不更改现有软件的东西,但不是超级准确。您可以在要分析的代码之前和之后使用日志记录断点。
如果您使用的是 IAR,则此选项有点隐藏。您必须右键单击要添加断点的行并选择记录断点。
当然,触发日志会有一些延迟,这个延迟应该是恒定的。