Funzione GetTime()

Forum relativo alle schede FLEX, ERIKA Enterprise, RT-Druid, ScicosLab, ...

Moderator: paolo.gai

Locked
gianpaolo

Funzione GetTime()

Post by gianpaolo »

Salve,
sto cercando di creare una funzione che restituisca il ritardo di avvio di un task, usando una scheda FLEX full. Pensavo di farlo usando GetTime() però non so i valori restituiti a cosa corrispondono. Ho visto che esiste un topic simile sul forum inglese però il link non è più valido.
Grazie anticipatamente per l'aiuto.

Gianpaolo
paolo.gai
Administrator
Posts: 877
Joined: Thu Dec 07, 2006 12:11 pm

Re: Funzione GetTime()

Post by paolo.gai »

Cosa intendi per "ritardo di avvio" di un task?

GetTime è disponibile se non sbaglio solo con EDF. Il valore di ritorno è il valore del contatore del free running timer utilizzato per implementare EDF.

La cosa + semplice da fare credo sia programmare uno dei timer liberi e leggere direttamente il registro timer per avere informazioni sui cicli di clock passati a partire da un certo evento. Usa poi lo stesso timer per lanciare un interrupt ed attivare il task. In questo modo sai il valore del timer al momento dell'attivazione, lo leggi alla partenza del task e fai la differenza...

PJ
gianpaolo

Re: Funzione GetTime()

Post by gianpaolo »

Salve,
grazie per il suggerimento, ho letto il valore che è nel TMR1, dovrebbe rappresentare il tempo intercorso ad ogni reset del Timer1 misurato in cicli di clock. Quindi volevo chiedere qual'è la frequenza di clock, poichè su tutti i datasheet non l'ho trovata.

Grazie

Gianpaolo
paolo.gai
Administrator
Posts: 877
Joined: Thu Dec 07, 2006 12:11 pm

Re: Funzione GetTime()

Post by paolo.gai »

La frequenza di clock dipende da come programmi i PLL . Alcuni esempi di ERIKA mettono il codice del PLL all'inizio del main(). Quegli esempi vanno a 40MHz. gli altri non so... verifica le impostazionid al datasheet del micro!

PJ
steo82fi

Re: Funzione GetTime()

Post by steo82fi »

Anche io sono interessato a registrare i tempi di accesso e di uscita a dei thread.
Nel mio codice io uso il Timer1 con le impostazioni degli esempi di erika

Code: Select all

// Primary (XT, HS, EC) Oscillator with PLL
_FOSCSEL(FNOSC_PRIPLL);
// OSC2 Pin Function: OSC2 is Clock Output - Primary Oscillator Mode: XT Crystanl
_FOSC(OSCIOFNC_ON & POSCMD_XT);
// Watchdog Timer Enabled/disabled by user software
_FWDT(FWDTEN_OFF);
// Disable Code Protection
_FGS(GCP_OFF);

/* Program the Timer1 peripheral to raise interrupts */
void T1_program(void)
{
	T1CON = 0;		/* Stops the Timer1 and reset control reg	*/
	TMR1  = 0;		/* Clear contents of the timer register	*/
	PR1   = 0x9c40;		/* Load the Period register with the value 0x9c40 (1ms @ 40MIPS)	*/
	IPC0bits.T1IP = 5;	/* Set Timer1 priority to 1		*/
	IFS0bits.T1IF = 0;	/* Clear the Timer1 interrupt status flag	*/
	IEC0bits.T1IE = 1;	/* Enable Timer1 interrupts		*/
	T1CONbits.TON = 1;	/* Start Timer1 with prescaler settings at 1:1
				* and clock source set to the internal
				* instruction cycle			*/
}

/* Clear the Timer1 interrupt status flag */
void T1_clear(void)
{
	IFS0bits.T1IF = 0;
}

/* This is an ISR Type 2 which is attached to the Timer 1 peripheral IRQ pin
 * The ISR simply calls CounterTick to implement the timing reference
 */
ISR2(_T1Interrupt)	/* Clock setup */
{
	/* clear the interrupt source */
	T1_clear();
 
	/* count the interrupts, waking up expired alarms */
	CounterTick(myCounter);
}
e nel main il codice per l'oscillatore

Code: Select all

	/* Clock setup */
	CLKDIVbits.DOZEN   = 0;
	CLKDIVbits.PLLPRE  = 0;
	CLKDIVbits.PLLPOST = 0;
	PLLFBDbits.PLLDIV  = 78;

	/* Wait for PLL to lock */
	while(OSCCONbits.LOCK!=1);
Con questa configurazione essendo il periodo del timer 9c40 che in decimale è 40000 se moltiplicato per la frequenza del clock ,che è data da Fcy = Fosc/2 e quindi di 25ns, ottengo che il mio interrupt avviene ogni 0.001 secondi. Quindi se io prendo il registro TMR1 dovrei moltiplicare il suo contenuto per 25ns per ottenere il tempo trascorso giusto?.
Ora se io volessi interrupt in microsecondi dovrei cambiare il periodo del timer a 40 (decimale) e a 28 in esadecimale giusto?
Perchè se faccio cosi non funziona. Devo modificare altro?
Grazie
dibbe

Re: Funzione GetTime()

Post by dibbe »

Così stai generando un'interruzione ogni microsecondo! Il micro ha solo 40 cicli di clock per gestirla, il che è impossibile. Il risultato è che il tuo programma passa il 100% del suo tempo dentro l'ISR2.

Se ti interessa misurare il tempo trascorso tra due generici eventi, il modo più semplice è programmare uno dei timer HW del micro a funzionare in maniera continua e senza generare interruzioni (per i dettagli dei flag di scrivere nei registri fai riferimento ai datasheet; non so se c'è un esempio fatto e finito su questo). Per esempio, per un timer a 16 bit imposti il periodo a 0xffff. Quando il timer è programmato per non fermarsi mai, una volta che il suo valore ha raggiunto 0xffff riparte da 0 e riprende a salire. Poi usi del codice tipo questo (nota bene, il codice assume che il timer sia a 16 bit):

Code: Select all

EE_UINT16 beg, end;
EE_UINT16 time_us;
beg = read_timer_value();
...
/* Codice di cui vuoi misurare la durata */
...
end = read_timer_value();
time_us = (EE_UINT16)(end - beg) / (EE_UINT16)TICKS_PER_MICROSECOND;
Dove read_timer_value() sia una funzione che ti restituisca il valore del timer HW (es., il valore TMR1 se usi il timer 1), e TICKS_PER_MICROSECOND sia il numero di colpi di clock in un microsecondo (nel caso che hai descritto tu, sarebbe 40). La variabile time_us contiene il tempo passato tra le due misure, espresso in microsecondi. Attenzione che la massima misura di tempo che puoi fare così è di 0xffff / 40 us = 1.6 ms

Bernardo
steo82fi

Re: Funzione GetTime()

Post by steo82fi »

Ciao Bernardo grazie per la risposta.
Tenendo conto che la mia applicazione ha bisogno del timer1 per far ripartire ogni 2millisecondi i task che la compongono sto provando a utilizzare il timer2 nella configurazione che mi hai proposto:

Code: Select all

void T2_program(void)
{
T2CONbits.TON = 0; // Stop any 16/32-bit Timer3 operation
T2CONbits.TCS = 0; // Select internal instruction cycle clock
T2CONbits.TGATE = 0; // Disable Gated Timer mode
T2CONbits.TCKPS = 0b00; // Select 1:1 Prescaler
TMR2 = 0x00; // Clear 16-bit Timer
PR2 = 0xffff; // Load 16-bit period value
IPC1bits.T2IP = 0x01; // Set Timer2 Interrupt Priority Level
IFS0bits.T2IF = 0; // Clear Timer2 Interrupt Flag
IEC0bits.T2IE = 1; // Enable Timer2 interrupt
T2CONbits.TON = 1; // Start 16-bit Timer
}
In questo modo non appena nel main richiamo T2_program dovrebbe partire il timer. Se poi ho capito bene questo timer si riavvia ogni 1.6millisecondi giusto? Per aumentare il tempo massimo del timer come posso fare?
Dato che la mia applicazione dura circa 60secondi posso configurare il timer2 per contare fino a sessanta secondi?
Nel registro TMR2 come viene salvato il numero di colpi di clock?come riesco a ricavare un valore utile per il conteggio del tempo passato?
Grazie

Edit
Credo che per avere un timer più lungo potrei usare la combinazione dei due timer a 16 bit come segue:

Code: Select all

		
                T3CONbits.TON = 0; // Stop any 16-bit Timer3 operation
		T2CONbits.TON = 0; // Stop any 16/32-bit Timer3 operation
		T2CONbits.T32 = 1; // Enable 32-bit Timer mode
		T2CONbits.TCS = 0; // Select internal instruction cycle clock
		T2CONbits.TGATE = 0; // Disable Gated Timer mode
		T2CONbits.TCKPS = 0b00; // Select 1:1 Prescaler
		TMR3 = 0x00; // Clear 32-bit Timer (msw)
		TMR2 = 0x00; // Clear 32-bit Timer (lsw)
		PR3 = 0x0002; // Load 32-bit period value (msw)
		PR2 = 0x0000; // Load 32-bit period value (lsw)
		IPC2bits.T3IP = 0x01; // Set Timer3 Interrupt Priority Level
		IFS0bits.T3IF = 0; // Clear Timer3 Interrupt Flag
		IEC0bits.T3IE = 1; // Enable Timer3 interrupt
		T2CONbits.TON = 1; // Start 32-bit Timer
In questo caso se setto PR3 e PR2 a FFFF dovrei avere un timer di circa 107 secondi giusto?
Mi rimane il dubbio di come poter leggere i registri di counter.
Grazie
dibbe

Re: Funzione GetTime()

Post by dibbe »

TMR2 per te è contatore che viene incrementato a ogni ciclo di clock (non so se la funzione che hai scritto programma il timer esattamente in questo modo, perché non ho sottomano i datasheet). Per misurare un intervallo di tempo, basta che fai la differenza fra due letture (v. il mio esempio sopra).

Se vuoi misurare tempi più lunghi, o usi il prescaler del timer, o usi un timer a 32 bit (non mi ricordo se il micro lo permette), o usi un approccio software. L'approccio software consiste nell'avere un timer che genera un'interruzione periodica, e su questa tu vai ad incrementare una variabile globale (un contatore). Questa variabile globale la useresti come valore ritornato da read_timer_value() nel mio esempio sopra. In questo modo puoi far in modo per esempio di avere un'interruzione ogni 1 ms, per cui puoi misurare tempi fino 65.535 s; se usi una variabile a 32 bit, anche tempi di qualche giorno. Ovviamente perdi in precisione, ma forse se vuoi misurare tempi nell'ordine del minuto non ti importa di avere il microsecondo.

In ogni caso, fai attenzioni agli overflow numerici; i cast che ho messo nell'esempio servono per evitare che diano problemi.

Bernardo
steo82fi

Re: Funzione GetTime()

Post by steo82fi »

Ok perfetto, l'approccio software che dici tu l'avevo già provato (anche se usavo un double invece di un EE_UINT16)

Code: Select all

/* Program the Timer1 peripheral to raise interrupts */
void T1_program(void)
{
	T1CON = 0;		/* Stops the Timer1 and reset control reg	*/
	TMR1  = 0;		/* Clear contents of the timer register	*/
	PR1   = 0x9c40;		/* Load the Period register with the value 0x9c40 (1ms @ 40MIPS)	*/
	IPC0bits.T1IP = 1;	/* Set Timer1 priority to 1		*/
	IFS0bits.T1IF = 0;	/* Clear the Timer1 interrupt status flag	*/
	IEC0bits.T1IE = 1;	/* Enable Timer1 interrupts		*/
	T1CONbits.TON = 1;	/* Start Timer1 with prescaler settings at 1:1
				* and clock source set to the internal
				* instruction cycle			*/
}

/* Clear the Timer1 interrupt status flag */
void T1_clear(void)
{
	IFS0bits.T1IF = 0;
}
EE_UINT16 temp_ref;
/* This is an ISR Type 2 which is attached to the Timer 1 peripheral IRQ pin
 * The ISR simply calls CounterTick to implement the timing reference
 */
ISR2(_T1Interrupt)
{
	/* clear the interrupt source */
	T1_clear();
    temp_ref ++;
	/* count the interrupts, waking up expired alarms */
	CounterTick(myCounter);

}

E infatti ogni millisecondo lui mi aggiornava temp_ref. Poi io avevo il mio task

Code: Select all

TASK(t_rett){
	tx_vector[0] = temp_ref * 0.001;
	UDP_send();
	/*blocco della traiettoria rettilinea Inizio */
	if(myinit2 == 0){
		dot_x_trai = 0.0;
	}else{

			if (t<=ta)
				dot_x_trai = (Ap*t);
			else if ((t>ta) & (t<=(tf))){
				dot_x_trai = Vp;

			}
			else if ( (t>tf) & (t<=tend)){
				dot_x_trai = (Vp)-((Ap)*(t-tf));

			}
			else{
				dot_x_trai = 0.0;
				EE_pwm_close(1);
				EE_pwm_close(2);

			}
	}
	if(myinit == 0){

		x_trai = tRett_buff1 + tRett_buff2;

	}else{

		x_trai = Int_disc(dot_x_trai, &tRett_buff1, &tRett_buff2);

	}
	t += Tcalc;
	myinit2++;
	tx_vector[0] = temp_ref * 0.001;
	UDP_send();


}
Io quindi mi salvo il temp_ref nell'array e poi mando il valore tramite udp sia all'inizio che alla fine del thread. Poi mi sono fatto uno schema scicos con un blocco udp reciver e un blocco write to output file che prende e salva l'array dell'udp su un file di testo. Il problema è che ricevo sempre lo stesso valore sia a inizio che fine. E' per questo che volevo andare un ordine di misura sotto e provare con i microsecondi.
dibbe

Re: Funzione GetTime()

Post by dibbe »

Quando una variabile viene acceduta da task e/o ISR diversi, va dichiarata volatile. Già questo potrebbe anche essere sufficiente a spiegare il comportamento che osservi.

Bernardo
gianpaolo

Re: Funzione GetTime()

Post by gianpaolo »

Salve,
quando uso un timer a 32 bit è giusto questo codice per leggere il numero dei cicli:

Code: Select all

if(cont!=0) start_T3();
else cont++;
EE_UINT32 am=(TMR3HLD*65536)+TMR2-(del_cic*PR1);
dove uso cont per vedere se è la prima volta che attivo il mio task e del_cic è il periodo di richiamata del task.

Grazie
Gianpaolo
paolo.gai
Administrator
Posts: 877
Joined: Thu Dec 07, 2006 12:11 pm

Re: Funzione GetTime()

Post by paolo.gai »

Ciao,

dai uno sguardo al codice della MCU di ERIKA per dsPIC...

http://svn.tuxfamily.org/viewvc.cgi/eri ... iew=markup

PJ
Locked