Funzione GetTime()
Moderator: paolo.gai
Funzione GetTime()
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
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
Re: Funzione GetTime()
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
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
Re: Funzione GetTime()
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
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
Re: Funzione GetTime()
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
PJ
Re: Funzione GetTime()
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
e nel main il codice per l'oscillatore
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
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);
}
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);
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
Re: Funzione GetTime()
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):
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
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;
Bernardo
Re: Funzione GetTime()
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:
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:
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
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
}
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
Mi rimane il dubbio di come poter leggere i registri di counter.
Grazie
Re: Funzione GetTime()
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
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
Re: Funzione GetTime()
Ok perfetto, l'approccio software che dici tu l'avevo già provato (anche se usavo un double invece di un EE_UINT16)
E infatti ogni millisecondo lui mi aggiornava temp_ref. Poi io avevo il mio task
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.
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);
}
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();
}
Re: Funzione GetTime()
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
Bernardo
Re: Funzione GetTime()
Salve,
quando uso un timer a 32 bit è giusto questo codice per leggere il numero dei cicli:
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
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);
Grazie
Gianpaolo
Re: Funzione GetTime()
Ciao,
dai uno sguardo al codice della MCU di ERIKA per dsPIC...
http://svn.tuxfamily.org/viewvc.cgi/eri ... iew=markup
PJ
dai uno sguardo al codice della MCU di ERIKA per dsPIC...
http://svn.tuxfamily.org/viewvc.cgi/eri ... iew=markup
PJ