2011-12-28 10 views

risposta

4

http://github.com/dwelch67/msp430_samples

i campioni mostrano periodi di rilevamento di tempo con il timer, il timer campione prima e dopo e sottrarre la differenza, cioè il tempo di esecuzione.

EDIT:

questo esempio utilizza i temporizzatori e divisori, invece di monitorare il ribaltamento bandiera leggere il registro contatore timer e supponendo che contano più del numero timer di zecche, sottrarre uno dall'altro a prendi il tempo Regola i divisori per evitare il ribaltamento e cerca anche la precisione che cerchi.

;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 

Questo esempio utilizza il timer per misurare un periodo di tempo per trasmettere i caratteri (RS232) di serie, come detto sopra regolare i divisori per assicurare voi non contano più di un ciclo del timer (il timer può rotolare, che va bene da 0xF000 a 0x3000 per esempio, non un problema, 0xF000, circa una volta a 0xF100 è un problema). Se possibile grossolanamente sopra la divisione in modo tale da non essere definitivamente in rotazione, la scala indietro i divisori fino a ottenere la migliore precisione.

Sì, è possibile utilizzare un interrupt per gestire il rollover, ma questo rovina la cosa che si sta tentando di misurare, non lo si vuole fare (a meno che il sovraccarico dell'interrupt o di qualsiasi meccanismo si usi per monitorare il rollover del timer) (non è necessario un interrupt per questo) è accettabile per la vostra misurazione). MSP430 backend

#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); 
    } 
} 
//------------------------------------------------------------------- 
//------------------------------------------------------------------- 

di LLVM è davvero sperimentale, leggi: rotto, Non fare affidamento su di esso più che solo per giocare con esso, il compilatore gcc non è banale, ma non eccessivamente doloroso per costruire uno. L'assemblatore naken430asm è molto facile da usare e l'asm per questo processore è abbastanza semplice, buona architettura ...

+0

Come da criteri di StackOverflow standard, è preferibile fornire una risposta reale, non solo un puntatore a una risposta (che può spostarsi o andare via in futuro). –

+0

allo stesso tempo, l'overflow dello stack perde improvvisazioni apportate al collegamento. Punto preso però, codice di esempio aggiunto nella risposta. –

+0

Vero, e sono d'accordo che anche l'aggiunta del collegamento sia utile. In ogni caso, la spiegazione che hai aggiunto con il codice è molto meglio di quello che ho trovato al link! Venerato con successo. –

1

Non c'è un modo generico per farlo, è possibile utilizzare una risorsa timer hardware disponibile e configurarla per fornire una base dei tempi appropriata. Suggerirei che per l'esecuzione del codice di temporizzazione, un timer millisecondo potrebbe essere in qualche modo corso; i microsecondi potrebbero essere più appropriati.

Un metodo più semplice senza overhead o codice aggiuntivo (o anche hardware), e probabilmente maggiore precisione, sarebbe quello di eseguire e profilare il codice nel simulatore. Credo che Code Composer Studio includa strumenti di profilazione e simulazione. Altre catene di strumenti sono anche inclini a includerle. Se il codice in prova ha dipendenze di timing/latenza hardware, questo approccio potrebbe non essere adatto.

Un altro semplice metodo consiste nel commutare un GPIO disponibile prima e dopo l'esecuzione e monitorare il pin con un oscilloscopio o un timer/contatore esterno. Questo approccio includerà latenze/jitter hardware e anche eventuali sovraccarichi associati agli interrupt che potrebbero verificarsi durante l'esecuzione del codice in prova. Può anche essere implementato quando non è disponibile una risorsa timer hardware.

+0

Per "In millisecondi", mi aspetto che il timing dell'oscilloscopio GPIO + sia piuttosto buono. – XTL

+0

@XTL: punto equo alla domanda specifica, ma per molte applicazioni "hard" in tempo reale i costi generali potrebbero essere critici. – Clifford

1

Alcuni dispositivi MSP430 dispongono di un contatore di cicli integrato, disponibile quando si utilizza un debugger. Ho trovato che questo è estremamente accurato quando si confrontano le sequenze di codice.

Non so se il tuo dispositivo ne ha uno però. In realtà, non ne ho trovato uno chiamato MSP430f16, in genere hanno tre o quattro cifre dopo la "f".

0

Se stai cercando qualcosa di veloce senza modificare il software esistente, ma non è molto preciso. È possibile utilizzare i punti di interruzione della registrazione prima e dopo il codice che si desidera profilare.

Se si utilizza IAR, questa opzione è un po 'nascosta. È necessario fare clic con il tasto destro sulla linea che si desidera aggiungere il punto di interruzione e selezionare il punto di interruzione della registrazione.

Naturalmente, ci sarà qualche ritardo per attivare il log, questo ritardo dovrebbe essere costante.

Problemi correlati