Pages: [1] 2   Go Down
Author Topic: Definizione Interrupt Service Routine  (Read 1261 times)
0 Members and 1 Guest are viewing this topic.
Torino
Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Carissimi, oggi mentre cercavo di digerire la colomba mi sono messo a cercare di capire come funziona la libreria SPI.h.
Pessima idea.  smiley-confuse

Con l'aiuto del datasheet del 328P in realtà credo di aver capito come si comporta, ma mi è venuto un grosso dubbio riguardo alle ISR.
Le funzioni attachInterrupt() e detachInterrupt() della libreria infatti, si limitano ad attivare o disattivare l'interrupt relativo all'SPI (se non vado errato).

La domanda che mi sorge spontanea è allora: come faccio a definire un'ISR?
Ho visto sul datasheet che il il vettore degli handler ha un apposito spazio che dovrebbe contenere (immagino) l'indirizzo della mia funzione:
VectorNoProgram AddressSourceInterrupt Definition
180x0022SPI, STCSPI Serial Transfer Complete
Come faccio però in pratica?

Ho pensato di risolvere il problema leggendo il codice della attachInterrupt() generica, quella relativa agli interrupt esterni, che tra gli altri argomenti prevede anche il passaggio della funzione che faccia da handler. Però qui arriva la seconda domanda: dove lo trovo il codice di questa funzione, così come quello di tutte le altre funzioni "di base", non appartenenti ad alcuna libreria?

Grazie e Buona Pasqua Buona Pasquetta (a questo punto  smiley )
Logged

BZ (I)
Offline Offline
Brattain Member
*****
Karma: 258
Posts: 21494
+39 349 2158303
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
oggi mentre cercavo di digerire la colomba
gran brutta cosa ... consiglio della Coca Cola, una bella passegiata o simile che risolve meglio il problema che studiare Arduino.

In certe funzioni deve disattivare eventuali interrupts perché quello che fa la funzione é molto criticca a livello di tempo. Se per esempio la libreria SPI deve mandare dei dati con una frequenza vicina a quella del Clock (8 o 4MHz) non possono esserci interuzini dati da un'interrupt.

C ha pochissime funzioni che non sono definiti in qualche libreria. Arduino include parecchie librerie in automatico.
Non so se ha senso che Tu Ti faccia questo lavoro (lascio esprimersi altre persone). Per l' uso medio - alto di Arduino non é necessario conoscere il funzionamento nei minimi particolari delle funzioni e librerie.

Ciao Uwe
« Last Edit: March 31, 2013, 03:25:45 pm by uwefed » Logged

Cagliari, Italy
Offline Offline
Tesla Member
***
Karma: 112
Posts: 7079
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

dove lo trovo il codice di questa funzione, così come quello di tutte le altre funzioni "di base", non appartenenti ad alcuna libreria?

In quello che viene chiamato CORE di Arduino, nelle sottocartelle dell'IDE.
 --> \\arduino-1.0.x\hardware\arduino\cores\arduino
Logged

Code fast. Code easy. Codebender --> http://codebender.cc/?referrer=PaoloP

Torino
Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

In quello che viene chiamato CORE di Arduino, nelle sottocartelle dell'IDE.
 --> \\arduino-1.0.x\hardware\arduino\cores\arduino
Grazie Paolo...domani, per digerire la grigliata, mi metto a leggere  smiley-razz

In certe funzioni deve disattivare eventuali interrupts perché quello che fa la funzione é molto criticca a livello di tempo. Se per esempio la libreria SPI deve mandare dei dati con una frequenza vicina a quella del Clock (8 o 4MHz) non possono esserci interuzini dati da un'interrupt.
Ok uwe, però, se ho capito bene quello che ho letto sul datasheet, l'SPI lavora "in parallelo" alle altre operazioni del micro, nel senso che una volta caricato il byte da trasmettere nell'apposito registro, la trasmissione avviene in automatico mentre altre operazioni continuano a essere eseguite. Sbaglio?
E dato che in ricezione, quando il secondo byte viene completamente ricevuto, il primo viene perso. Quindi senza l'utilizzo degli interrupt difficilmente riesco a "garantire" una latenza adeguata (soprattutto se lavoro a frequenze alte)..no?
Logged

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 327
Posts: 22651
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

La domanda che mi sorge spontanea è allora: come faccio a definire un'ISR?
Nel datasheet esiste una tabella dei vettori di interrupt.
Per creare una ISR devi:
1) verificare il vettore che vuoi usare (cap. 11.1)
2) creare il codice relativo. Ad esempio, per il vettore 18, una cosa tipo ISR(SPI_vect) {...}
3) attivare l'interrupt agendo sul registro. Siccome vuoi usare l'interrupt sul completamento del trasferimento dati SPI devi impostare ad 1 il bit SPIE del registro SPCR (cap. 18.5).
Logged


0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10465
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Le funzioni attachInterrupt() e detachInterrupt() della libreria infatti, si limitano ad attivare o disattivare l'interrupt relativo all'SPI (se non vado errato).

no, quelle funzioni agiscono sugli interrupt causati da un vettore a parte. Esistono vari meccanismi Hardware indipendenti per gestire i vari interrupt; nel remoto caso di una sovrapposizione, essi hanno una priorità.

Per esempio, ogni timer ha degli interrupt indipendeti, esistono 3 sistemi di interrupt di cui ognuno gestisce 8 pin, alcuni pin ne hanno aggiuntivi e dedicati che sono quelli usati dalla attachInterrupt (che quindi è un mondo mooooolto limitato di ciò che puoi avere), etc..


ps. la SPI è bloccate o usa dei buffer riempiti/svuotati da interrupt? esiste una gestione degli errori con timeout o simili?
Logged

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Torino
Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Il periferico SPI è non bloccante: ti basta caricare il byte da passare nel registro SPDR (SPI Data Register) e lui lo trasmette alla velocità impostata. Alla fine lancia un interrupt se abilitato e setta il bit SPIF (SPI Interrupt Flag).

Tuttavia, per come è implementato il trasferimento nella libreria SPI.h credo che se usi l'apposita funzione sia da considerare bloccante perchè aspetta che il trasferimento sia finito per ritornare. Il vantaggio è che non devi definire alcun ISR per gestire la comunicazione.
Code:
byte SPIClass::transfer(byte _data) {
  SPDR = _data;
  while (!(SPSR & _BV(SPIF)))
    ;
  return SPDR;
}
Per quanto riguarda i buffer in uscita non ne hai, hai solo il registro SPDR. In ingresso invece hai un "buffer" a due byte: mentre ricevi un byte hai tempo per copiare il precendente, ma appena anche il secondo viene ricevuto del tutto, il primo va perso.

Per quanto riguarda le funzioni attach e detachInterrupt() esistono sia quelle generiche del core (relative agli interrupt esterni) sia quelle della classe SPI che si "limitano" ad abilitare o disabilitare l'handler (che però non passi come argomento). Tutto questo inizia ad avere senso alla luce di quello che ha scritto leo, ma sto ancora cercando di capire bene come funziona  smiley-mr-green 

Dimenticavo: la gestione degli errori.
Hai un bit che ti segnala se scrivi nel registro SPDR mentre il trasfetimento corrente è ancora in atto, ma non hai niente relativo a timer o cose del genere. Del resto non credo che abbia senso/ che ce ne sia bisogno per come è fatto il protocollo: se vuoi implementare ack o altro devi agire a livello più alto.
« Last Edit: April 02, 2013, 12:42:58 pm by VanDerTull » Logged

0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10465
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

che il chip possa funzionare in modlità non bloccante lo immaginavo, ma la libreria è bloccante. in oltre come dicevo quel while non tiene conto degli errori: se per esempio qualcuno stacca il dispositivo SPI, o c'è un errore di trasmissione, ti si impalla tutto il codice...
Logged

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Torino
Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

In realtà non credo che il codice si blocchi, ma questa non è una mancanza della libreria quanto una debolezza intrinseca del protocollo: l'ATmega manderà comunque tutto il dato fuori e setterà la flag di interrupt alla fine sia che ci siano disturbi sulla linea sia che dall'altra parte venga disattivato lo slave. Io non apprezzo il fatto che durante la comnicazione il micro resti fermo ad aspettare, ma comunque prima o poi ritornerà a lavorare: se vuoi controlli sulla vitalità dello slave o controlli sulla correttezza dei dati trasmessi devi implementarli a livello più alto per forza di cose per come è pensato l'SPI.

Almeno questo è quello di cui sono convinto  smiley-roll-blue
Logged

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 327
Posts: 22651
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Posso fare una domanda? Ma hai un problema oppure questo thread è una specie di esternazione delle tue idee?  smiley-lol
Avevi iniziato la discussione facendo intendere che ti serviva capire come si scriveva una ISR e ti avevo dato alcune dritte, però adesso sembra che tu ne sappia più di quel lasciavi intendere e che stia ragionando fra te e te di come risolvere le cose  smiley-wink smiley-grin
Logged


Ivrea
Offline Offline
God Member
*****
Karma: 5
Posts: 680
"La teoria è quando si sa tutto ma non funziona niente. La pratica è quando funziona tutto ma non si sa il perché. In ogni caso si finisce sempre con il coniugare la teoria con la pratica: non funziona niente e non si sa il perché." Albert Einstein
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Secondo me c'è un motivo per cui per la seriale hanno previsto un buffer da elaborare ad interrupt e per la SPI no.

La seriale è mooooooooooooooooolto più lenta per processore (anche a 115200bps ci vogliono circa 1100 cicli di clock per trasmettere 8 bit) mentre la SPI, viaggiando a 4MHz (8MHz al limite) ci mette 32 (16 se a 8MHz) cicli di clock per trasmettere gli stessi 8 bit: in quel poco tempo il micro avrebbe appena il tempo (forse neppure quello) per tornare al codice principale per poi tornare a servire l'interrupt successivo.
Logged

Rome (Italy)
Offline Offline
Tesla Member
***
Karma: 124
Posts: 9329
"Il Vero Programmatore ha imparato il C sul K&R, qualunque altro testo è inutile e deviante."
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

che il chip possa funzionare in modlità non bloccante lo immaginavo, ma la libreria è bloccante.

Non si blocca nulla, la SPI, lato master, non ha alcun modo, hardware, per sapere se è andata a buon fine la trasmissione, semplicemente emette tutti i bit e poi setta il relativo flag, l'attesa serve solo se devi inviare più byte di seguito, fino a che non hai finito quello in corso non puoi inviarne.
Eventualmente si può prevedere un risposta di consenso (se possibile farlo), basta un singolo byte, da parte dello slave dopo che ha ricevuto un pacchetto dati, se questo byte non arriva, o arriva con un valore non atteso,  vuol dire che c'è stato un problema nella trasmissione del pacchetto dati.
Diverso è il discorso lato slave dove il device si aspetta di ricevere un certo numero di impulsi di clock, quanti dipende dalla dimensione della word SPI (può essere anche di 16-32 bit), se non arrivano tutti rimane in attesa, senza settare il flag di ricezione avvenuta, in eterno o, peggio, ne prende alcuni dalla trasmissione seguente con effetti disastrosi sul dato, in questo caso è necessario prevedere un time out.
Logged

Torino
Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Posso fare una domanda? Ma hai un problema oppure questo thread è una specie di esternazione delle tue idee?  smiley-lol
Avevi iniziato la discussione facendo intendere che ti serviva capire come si scriveva una ISR e ti avevo dato alcune dritte, però adesso sembra che tu ne sappia più di quel lasciavi intendere e che stia ragionando fra te e te di come risolvere le cose  smiley-wink smiley-grin

 smiley-yell
In realtà i problemi che avevo credo che tu e PaoloP li abbiate risolti. Tuttavia non ho ancora avuto tempo per mettermi al lavoro e verificare se effettivamente riesco a scrivere la ISR come mi hai indicato (anche se non vedo come potrebbe non funzionare).

Il resto del topic è nato dalla domanda di lesto e ho riletto varie volte il datasheet da quando ho postato a oggi^^

E intanto sto anche ragionando di come risolvermi le cose..ma questa è un'altra esternazione di quello che penso  smiley-razz
Logged

Torino
Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Alla fine sono riuscito a scrivere qualcosa: per quanto riguarda l'interrupt handler la sintassi è quella che ha detto leo, ISR(SPI_STC_vect){...}.

Ho provato a buttare giù una funzione che invii una sequenza di byte che sia non bloccante. Credo che funzioni ma per ora ho fatto un testing mooolto parziale. Per farlo ho semplicemente aggiunto nella libreria SPI questo:
Code:
volatile int SPI_len;
char *SPI_str;

void SPIClass::sendString(char* string, byte length)
{
//make sure that the SPI interrupt is enabled
SPI.attachInterrupt();
//save length and str pointer in global variable
SPI_len = length;
SPI_str = string;
//move first char in the SPDR register
SPDR = *string;
}

int SPIClass::isBusy(){
return(SPI_len);
}

ISR(SPI_STC_vect){
*SPI_str = SPDR;
SPI_str++;
if (--SPI_len) SPDR = *SPI_str;
}

La funzione SPI.isBusy() si può chiamare per evitare di scrivere mentre il precedente trasferimento è ancora in corso.

Grazie ancora a tutti per l'aiuto smiley
Ciao!
Logged

0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10465
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

cìè confusione con i puntatori.
In oltre devi assicurarti che mentre sei busy la sendString non funzioni... io farei che ritorna false, oppure un numero: 0 = tutto ok, altrimenti un numero che corrisponde all'errore riscontrato

edit: dimenticavo, manca anche la DISATTIVAZIONE dell'interrupt quando arrivi a 0


per i puntatori:

Code:
SPI_str = string;
brutta roba, se l'utente cambia la stringa passata come parametro, a te cambia la SPI_str, e la len può essere errata... fai una copia in un array locale.

la Serial ad esempio usa un array (buffer) di 64char "circolare": ovvero mette i dati nell'array, quando l'array è pieno (o la stringa da scrivere troppo grande) ti tiene bloccato nella Write, mette i pezzi di stringa che ci stanno nell'array buffer ficnhè non li ha messi tutti nel buffer. poi "ti lascia andare"
« Last Edit: April 04, 2013, 10:06:26 am by lesto » Logged

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Pages: [1] 2   Go Up
Jump to: