Newsgroup: it.comp.lang.c
Titolo: Gestione interrupt C

Ciao a tutti.
Devo imparare a programmare il MSP430 della TI ma ho problemi a capire
come fare per gestire gli interrupt.
So che un interrupt è un evento che interrompe il normale flusso di
funzionamento del programma caricato sul microcontrollore, ma non riesco
a capire come fare in C a far capire al micro che all'arrivo
dell'interrupt per esempio dovuto ad un overflow del conteggio di un
timer interno, lui deve far partire un ISR che faccia una certa cosa.
Vi faccio un esempio: voglio fare in modo che ogni 5 minuti un micro
acquisisca la temperatura da una sonda e tramite questa imposti il duty
cicle di un segnale PWM.
1) Blocco il watchdog timer, abilito l'interrupt di overflow sul timer
ed entro in low power mode;
2) Appena il contatore del timer va in overflow, una certa flag di
interrupt passa da 0 a 1 e a questo punto dovrebbe venire chiamata la
routine di interrupt durante la quale il micro campiona la temperatura,
la converte in digitale, con essa calcola il duty cicle opportuno, lo
imposta e va in low power mode;
3) Aspetta in low power mode altri 5 minuti prima di ripetere il tutto.
Io ho scritto il codice per fargli calcolare il duty cycle tramite la
temperatura acquisita e per farglielo settare ma non capisco come faccia
il programma principale a passare dal punto 1) al 2), poi dal 2) al 3) e
dal 3) di nuovo al 2) e così via.
Ho sempre sotto mano la user guide del MSP430 ma proprio non mi entra in
testa!!!
Spero di non aver fatto troppa confusione, di non aver scritto troppe
castronerie ma soprattutto che qualcuno mi aiuti, per favore!!!
Grazie mille!
-- 
---------------------
Ciao,
   Dave Evans
---------------------

Dave Evans wrote:
<cut/>
sei riuscito a collegare ad un qualsiasi interrupt come handler una tua 
funzione? Perchè a seconda dell'architettura, dovrai gestire 
appropriatamente lo stack ..
alcuni compilatori introducono delle keyword appropriate per far capire 
al compilatore di trattare lo stack correttamente ...
cod

 ed entro in low power mode;
Se il low-power mode significa che la CPU e' spenta, allora 
proababilmente all'arrivo dell'interrupt la CPU si riaccende e il tuo 
codice riprende a girare. Bastera' fargli controllare qual e' stata la 
causa del "risveglio" e fargli fare quello che vuoi.
E.

cod ha scritto:

??? scusa ma ho iniziato da una settimana a studiare come si programma 
un micro...
Ho trovato questo esempio (mi scuso per la lungaggine e per l'inglese):
The MSP430 C Compiler lets you write interrupt handlers
directly in C using the interrupt keyword. The interrupt we will
handle is the timer interrupt. This program sets up the timer to
interrupt once a second and outputs a succession of digits to the LCD.
The following is a listing of the interrupt code. The code is provided 
in the sample tutorials as tutor3.c.
/* This example demonstrates how to use the basic timer
Interrupt frequency 1 Hz */
/* enable use of extended keywords */
#pragma language=extended
/* include sfr definitions for I/O registers and
intrinsic functions (_EINT) */
#include "io310.h"
#include "in430.h"
volatile int clock; /* count number of basic timer
interrupts */
char digit[10] = {
0xB7, /* "0" LCD segments a+b+c+d+e+f */
0x12, /* "1" */
0x8F, /* "2" */
0x1F, /* "3" */
0x3A, /* "4" */
0x3D, /* "5" */
0xBD, /* "6" */
0x13, /* "7" */
0xBF, /* "8" */
0x3F /* "9" */
};
/* Basic Timer has vector address 0xFFE2, ie offset 2 in
INTVECT */
interrupt [0x02] void basic_timer(void)
{
if (++clock == 10)
clock = 0;
/* Display 1,2,3,...,9,0,1,2,... */
LCDMEM[0] = digit[clock];
}
void main(void)
{
/* Initialize LCD driver (4Mux mode) */
LCDCTL = 0xFF;
/* Initialize Basic Timer
Interrupt FQ is ACLK/256/128 = 1 Hz */
BTCTL = 0xF6;
ME2 |= 0x80; /* Set Basic Timer Module Enable */
BTCTL &=~0x40; /* Disable Basic Timer Reset */
IE2 |= 0x80; /* Set Basic Timer Interrupt Enable */
clock = 0;
/* Enable interrupts */
_EINT();
/* wait for interrupt */
while (1);
}
interrupt [0x02] void basic_timer(void)
{
if (++clock == 10)
clock = 0;
/* Display 1,2,3,...,9,0,1,2,... */
LCDMEM[0] = digit[clock];
}
The interrupt function itself is defined by the following lines:
interrupt [0x02] void basic_timer(void)
{
if (++clock == 10)
clock = 0;
/* Display 1,2,3,...,9,0,1,2,... */
LCDMEM[0] = digit[clock];
}
Ora: la funzione di interrupt la scrivo come se fosse una normale 
funzione che scrive su schermo "Hello, world!", giusto?
Ma dov'è il punto in cui il programma principale si sveglia ed esegue
la funzione di interrupt al ricevimento di una richiesta di interrupt? 
come discerne qual'è se ce n'è più d'una? forse dall'indirizzo [0x02]?
e una volta che ha finito di eseguire quello che c'è scritto dentro la 
funzione di interrupt come torna a dormire?


 funzione di interrupt come torna a dormire?
il tuo compilatore tratta la keyword interrupt e crea il codice 
necessario ha gestire quell'interrupt.
A questo punto a te non serve nulla di più da sapere.. se vuoi scendere 
nell'architettura e stabilire cosa avviene concretamente, dovresti farti 
generare l'assembly prodotto dal compilatore, e vedere come rigenera il 
codice dell'interrupt..
l'handler sarà eseguito in reazione di un evento hardware, e 
quell'istruzione sarà richiamata dal processore, senza che tu la debba 
esplicitamente richiamare.. secondo me comunque questo è argomento da 
discutere in tutt'altri ambienti.
cod


Bye
brix

 funzione di interrupt come torna a dormire?
Allora:
1) ti consiglio vivamente di leggerti il ref book del micro da cima a
fondo prima di iniziare a programmare (specialmente se non hai mai
programmato un micro).
2) gli interrupt sono funzioni a parte, non fanno parte (teoricamente)
del normale flusso principale del programma.
3) i micro hanno un interrupt vector (normalemente), che e' una parte
di memoria dove ci sono gli indirizzi delle funzioni di interrupt,
ogni tipo di interrupt ha una posizione diversa nell'interrupt vector
(ce ne e' una per l'interrupt dovuto all'overflow del timer, una per
end of scan dell'AD, ecc.), per vedere quali interrupt puo' gestire il
micro guarda il ref book. Nell'esempio di codice c'e' scritto che
l'interrupt del timer ha posizione 0xFFE2 nell'interrupt vector (che
inizia a 0xFFE0), quindi quando definisci un interrupt routine la devi
scrivere cosi:
interrupt [xxx] nome_fz(void) //gli interrupt NON passano argomenti,
dei usare le var. globali...
{
//codice
}
xxx e' l'offset dall'inizio del interrupt vector della posizione
associata a quell'interrupt (nel caso dell'interrupt del timer
l'offset e' 0x0002.
normalmente gli indirizzi del vettore di interrupt li trovi in una
qualche .h, insieme a delle macro mnemoniche per evitare di star li
ogni volta a farsi i calcoli per l'offset. cosi come ci saranno di
sicuro delle macro mnemoniche epr accedere ai vari registri delle
periferiche del micro.
Ciao Jack
PS: ho lavorato con un PIC (magari tutti i PIC sono cosi) che aveva
solo una interrupt service routine, e per vedere che interrupt la
invocava bisognava andare a leggere un registro, i cui bit
rappresentavano i vari interrupt generati.


penso sia ragionevole leggere la documentazione come dice Jack
e tutte le sue considerazioni aggiungo che, nella mia esperienza, la 
gestione di un "evento" *dovrebbe* essere veloce e rilasciare il 
controllo nel più breve tempo possibile, io normalmente imposto il 
"contaventi" e le informazioni per la gestione dello stesso il tutto 
condito di un "avviso" a chi "ascolta" l'evento, ed esco dalla routine 
di gestione dell'interrupt.
Luca