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.
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...
There is no generic way to do this, you might use an available hardware timer resource and configure it to provide an appropriate timebase. I would suggest that for timing code execution, a millisecond timer might be somewhat course; microseconds might be more appropriate.
A simpler method with no overhead or additional code (or even hardware), and probably greater accuracy, would be to execute and profile the code in the simulator. I believe Code Composer Studio includes profiling and simulation tools. Other tool-chains are likley to include them too. If the code being tested has hardware timing/latency dependencies, this approach may not be suitable.
Another simple method is to toggle an available GPIO before and after execution and monitor the pin with an oscilloscope or external timer/counter. This approach will include hardware latencies/jitter and also any overhead associated with interrupts that may occur during execution of the code under test. It can also be implemented when there is no available hardware timer resource.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With