Pagina 1 di 1

ADC e TIMER che fanno a cazzotti

MessaggioInviato: 19 feb 2018, 18:09
da dadduni
salve a tutti,
vi faccio una domanda particolare perché non mi era mai capiutata una cosa simile.
Sto lavorando su un AtTiny 817, configuro l'ADC come freerun mode e con le inteurrupt ad ogni conversione:funziona.
Apro un nuovo programma per provare la configurazione del timer che genera un interrupt quando va in overflow: funziona.
Metto tutto in un programma solo... l'ADC non genera più l'interrupt! mi basta commentare l'inizializzazione del timer per far funzionare l'adc.

Secondo voi dove può stare il problema?
Davide

Re: ADC e TIMER che fanno a cazzotti

MessaggioInviato: 19 feb 2018, 22:07
da xyz
Impossibile dire nulla senza codice, non specifichi neanche quali timer usi e quale porta ADC e come viene programmato se direttamente in C o usi API particolari come quelle di Arduino o programmi direttamente in assembler o altro.

Re: ADC e TIMER che fanno a cazzotti

MessaggioInviato: 19 feb 2018, 23:20
da Fedhman
Forse il timer si impadronisce dei registri di interrupt usati dall'ADC. Leggi bene il datasheet, alla sezioni interrupt, timer e ADC - a volte per risovere problemi simili sugli interrupt serve pure leggere qualcos'altro*. Sii puntiglioso!

*qualcos'altro potrebbero essere i registri che vanno a configurare come sono abilitati gli interrupt. Talvolta non sono descritti nella sezione degli interrupt.

Re: ADC e TIMER che fanno a cazzotti

MessaggioInviato: 20 feb 2018, 9:48
da harpefalcata
Oppure, più semplicemente i timer sono programmati per avere un intervallo troppo ristretto e generano un proliferare di interrupt tale, che quelli dell'ADC, anche se presenti, vengono completamente ignorati.

Re: ADC e TIMER che fanno a cazzotti

MessaggioInviato: 20 feb 2018, 15:26
da dadduni
Codice: Seleziona tutto
int8_t TIMER_0_init()
{

   //TCA0.SINGLE.CMP0 = 0xffff; /* Compare Register 0: 0x0 */

   // TCA0.SINGLE.CMP1 = 0x0; /* Compare Register 1: 0x0 */

   // TCA0.SINGLE.CMP2 = 0x0; /* Compare Register 2: 0x0 */

   TCA0.SINGLE.CNT = 0x0000; /* Count: 0xff */

   TCA0.SINGLE.CTRLB = 0 << TCA_SINGLE_ALUPD_bp       /* Auto Lock Update: disabled */
                       | 0 << TCA_SINGLE_CMP0EN_bp    /* Compare 0 Enable: enabled */
                       | 0 << TCA_SINGLE_CMP1EN_bp    /* Compare 1 Enable: disabled */
                       | 0 << TCA_SINGLE_CMP2EN_bp    /* Compare 2 Enable: disabled */
                       | TCA_SINGLE_WGMODE_NORMAL_gc; /*  */

   // TCA0.SINGLE.CTRLC = 0 << TCA_SINGLE_CMP0OV_bp /* Compare 0 Waveform Output Value: disabled */
   //       | 0 << TCA_SINGLE_CMP1OV_bp /* Compare 1 Waveform Output Value: disabled */
   //       | 0 << TCA_SINGLE_CMP2OV_bp; /* Compare 2 Waveform Output Value: disabled */

   TCA0.SINGLE.DBGCTRL = 1 << TCA_SINGLE_DBGRUN_bp; /* Debug Run: enabled */

   // TCA0.SINGLE.EVCTRL = 0 << TCA_SINGLE_CNTEI_bp /* Count on Event Input: disabled */
   //       | TCA_SINGLE_EVACT_POSEDGE_gc; /* Count on positive edge event */

   TCA0.SINGLE.INTCTRL = 0 << TCA_SINGLE_CMP0_bp   /* Compare 0 Interrupt: enabled */
                         | 0 << TCA_SINGLE_CMP1_bp /* Compare 1 Interrupt: disabled */
                         | 0 << TCA_SINGLE_CMP2_bp /* Compare 2 Interrupt: disabled */
                         | 1 << TCA_SINGLE_OVF_bp; /* Overflow Interrupt: disabled */
   //TCA0.SINGLE.INTFLAGS |= 1<<0;
   TCA0.SINGLE.PER = 0x0f00; /* Period: 0xffff */

   TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1024_gc /* System Clock / 1024 */
                       | 1 << TCA_SINGLE_ENABLE_bp; /* Module Enable: enabled */

   return 0;
}

ho impostato così il timer A. Setto un valore in PER (period) che dovrebbe essere il massimo a cui arriva e poi si resetta generando un overflow interrupt.
Il codice di inizializzazione è generato da Atmel START che è una interfaccia grafica per impostare i parametri nei registri, sono comunque stati controllati e a me sembrano giusti.
Voi ci vedete qualcosa che non torna?

Re: ADC e TIMER che fanno a cazzotti

MessaggioInviato: 20 feb 2018, 17:04
da EcoTan
non è che hai abilitato anche l'interrupt di compare 0 mentre l'istruzione che imposta il registro compare 0 è commentata?

Re: ADC e TIMER che fanno a cazzotti

MessaggioInviato: 20 feb 2018, 17:32
da dadduni
mistero risolto!
ogni volta che viene generata un'interrupt, deve essere resettata a mano la flag. Pensavo che per l'overlow azzerandosi il timer si resettasse da solo ma a quanto pare no, nel capitolo dei timer non c'era scritto ma stava nel capitolo delle interrupt :twisted:
se tutto va come deve settimana prossima potrebbe uscire un articoletto :mrgreen:

Re: ADC e TIMER che fanno a cazzotti

MessaggioInviato: 20 feb 2018, 17:41
da Fedhman
dadduni ha scritto:[..] nel capitolo dei timer non c'era scritto ma stava nel capitolo delle interrupt :twisted:


Tipico! :lol:

Re: ADC e TIMER che fanno a cazzotti

MessaggioInviato: 22 feb 2018, 19:48
da dadduni
ho aggiornamenti e mi servirebbero chiarimenti se potete!
questa è la funzione handler dell'interrupt dell'ADC
Codice: Seleziona tutto
ISR(ADC0_RESRDY_vect)
{   rms_buffer[rms_buffer_pointer]= ADC0.RES;
   rms_buffer_pointer++;
   /* The interrupt flag has to be cleared manually */
   ADC0.INTFLAGS = ADC_RESRDY_bm;
   ADC0.COMMAND=1;
}

Scrivo in un buffer circolare, resetto la interrupt flag e faccio ripartire la nuova conversione. A voi sembra una routine troppo lunga? perché mi sono accorto che se la lascio così la interrupt del timer non viene proprio eseguita invece se tolgo i comandi che scrivono nel buffer il timer funziona perfettamente. Voi che ne pensate? pensavo di poter scrivere in un paio di registri in una interrupt!

PS non ha senso però che nella routine faccio alzare un bit che segnala la fine della conversione perché poi dovrei fare polling nel main a questo punto tanto vale la pena fare direttamente polling e questa interrupt non generarla nemmeno!

Re: ADC e TIMER che fanno a cazzotti

MessaggioInviato: 22 feb 2018, 21:21
da xyz
Quello non è un buffer circolare. Manca il controllo del limite massimo nell'indice e molto probabilmente hai un buffer overflow con conseguenze deleterie nel codice. Devi mettere un test sull'indice, se raggiunge il massimo azzerarlo.

Un trucco per evitare il test è creare il buffer con un numero di elementi uguale a una potenza di 2, quando incrementi l'indice fai un "and" binario (&) col numero numero di elementi meno 1. Ad esempio se il buffer ha 16 (2^4) elementi, quando incrementi l'indice fai:

Codice: Seleziona tutto
rms_buffer_pointer = (rms_buffer_pointer + 1) & 0x0F