Newsgroup: it.hobby.elettronica.digitale
Titolo: Come gestire interrupt UART

Ciao,
mi scuso in anticipo se faccio una domanda banale...
Sto usando un LM3S1918 e devo inviare periodicamente una stringa seriale 
(in particolare si tratta di una pacchetto DMX). Scopo del gioco è 
riuscire a inviare continuamente la stringa minimizzando il tempo di 
permanenza al di fuori del loop principale del programma.
In un progetto simile con un AVR avevo risolto facilmente la cosa 
agganciando l'invio di ogni byte alla ISR di byte trasmesso. In pratica 
nella routine di interrupt inviavo il byte successivo e poi me ne 
tornavo buono buono al ciclo principale.
Nei Luminary però l'interrupt di trasmissione (e ricezione) da quanto ho 
capito può scattare solo quando il FIFO di trasmissione è pieno per 1/8, 
1/4 1/2 e altri valori maggiori. Insomma pare che non si possa avere un 
interrupt ogni byte.
Se questo fosse vero non potrei usare la strategia di cui sopra.
In questa situazione quale altra strada potrei seguire?
Per completezza aggiungo che la trasmissione seriale è a 250 kbps (8N2) 
con pacchetti di 512 byte.
Ciao e grazie
--
Marco / iw2nzm

 
usa una FIFO software in trasmissione, la riempi tu devi trasmettere, la 
svuota l'ISR della seriale secondo la sua disponibilita'
ti basta un buffer di dimensione adeguata ed i due "puntatori" 
all'inizio ed alla fine delle coda, usando come dimensione della coda 
una potenza di 2 la gestione e' alquanto semplificata ( leggi economica 
come codice )
se cerchi un po' in giro dovrersti trovare codice gia' pronto in C


 Se questo fosse vero non potrei usare la strategia di cui sopra.
E perché no? L'unica cosa che cambia č che nella ISR tu scrivi ogni volta
piů di un byte, fino a riempire la FIFO.
-- 
emboliaschizoide.splinder.com

 se cerchi un po' in giro dovrersti trovare codice gia' pronto in C
Non è un problema l'implementazione, ne ho fatte diverse per varie 
applicazioni. E' che mi sarebbe piaciuto renderla indipendente 
sfruttando gli interrupt. Non è possibile, quindi cambio strada :)
Marco / iw2nzm

 più di un byte, fino a riempire la FIFO.
Ok, ma a parte che ho bisogno inizialmente di trasmettere un byte a una 
velocità e successivamente altri byte ad altra velocità (ok, qui posso 
permettermi di aspettare in loco la trasmissione del primo).
Ma dal momento che la lunghezza del pacchetto da trasmettere è variabile 
potrei facilmente trovarmi (50% di probabilità) nella condizione in cui 
l'interrupt non viene generato alla fine della trasmissione ritrovandomi 
così ad aspettare invano. Oppure dovrei inserire dei controlli e 
by-passare l'attesa nel caso in cui bla bla...
Mi sembra più macchinoso che non gestire il tutto a polling direttamente 
dal main loop: meno elegante, meno riutilizzabile, ma forse più efficace.
Ciao!
Marco / iw2nzm

 gestisca a polling la FIFO hardware. 
Così ho fatto e funziona. In pratica ho disattivato la FIFO che rimane 
quindi lunga 1 solo byte (peccato che non permetta la generazione 
dell'interrupt quando la FIFO è vuota... otterrei il comportamento 
voluto inizialmente). Dal ciclo principale chiamo una funzione che 
aggiorna lo stato di una FSM che gestisce l'invio di tutto il pacchetto 
ritornando un valore che mi dice se la trasmissione è stata completata.
Riesco a mandare uno stream continuo di dati a 250k mentre eseguo un 
file audio a 44100 kHz da scheda SD più altre cosette. Mi accontento 
anche se è un po' grezza come soluzione.
Ciao!
Marco / iw2nzm

 così ad aspettare invano.
Quello che ti complica la vita è dover inviare un byte a una bit rate
diversa, e ciò ti obbliga a dover aspettare che l'ultimo byte sia stato
effettivamente spedito. Questo non è normalmente necessario, di solito puoi
andare avanti dopo aver riempito la FIFO per l'ultima volta; se anche ci
fosse bisogno di inviare subito un'altra stringa, dovresti semplicemente
aspettare il prossimo interrupt anziché spedire subito il primo pacchetto
di dati.
Nel tuo caso probabilmente fai prima a disabilitare la FIFO in
trasmissione. In questo modo ti ritroverai con un buffer di un solo
elemento e l'interrupt sarà spedito quando il buffer è vuoto, ossia appunto
alla spedizione di ogni carattere; vedi il paragrafo 13.2.5 del datasheet.
-- 
emboliaschizoide.splinder.com

 alla spedizione di ogni carattere; vedi il paragrafo 13.2.5 del datasheet.
Esatto, è quello che ho fatto.
Solo che - a meno di errori miei - disabilitando la FIFO non ho 
interrupt di byte trasmesso, quindi ho risolto gestendo a polling dal 
ciclo principale.
Ciao!
Marco / iw2nzm

 interrupt di byte trasmesso
Non ci posso credere. :-(
Ma che je dice la capoccia?
Hai provato a chiedere a loro?
Non ci sono altri interrupt relativi alla seriale?

 Non ci sono altri interrupt relativi alla seriale?
The UART can generate interrupts when the following conditions are observed:
Overrun Error
Break Error
Parity Error
Framing Error
Receive Timeout
Transmit (when condition defined in the TXIFLSEL bit in the UARTIFLS 
register is met)
Receive (when condition defined in the RXIFLSEL bit in the UARTIFLS 
register is met)
I bit TXIFLSEL e RXIFLSEL definiscono il livello di riempimento della 
FIFO al quale viene generato l'interrupt:
TXIFLSEL
UART Transmit Interrupt FIFO Level Select
The trigger points for the transmit interrupt are as follows:
TX FIFO ? 1/8 full		0x0
TX FIFO ? ¼ full		0x1
TX FIFO ? ½ full (default) 	0x2
TX FIFO ? ¾ full 		0x3
TX FIFO ? 7/8 full 		0x4
Non ho trovato nulla a riguardo nel caso in cui la FIFO sia 
disabilitata, ma a logica non dovrebbe scattare l'interrupt (e una prova 
al volo pare avere confermato questa cosa). Mi prometto di rifare un 
test più approfondito.
Un peccato, perché anche in ricezione mi sono sempre trovato benissimo a 
leggere un carattere per volta (leggere, non ricevere: la FIFO è sempra 
benvenuta per non perdere byte) e determinare così l'inizio e fine 
trasmissione.
Ciao!
Marco / iw2nzm

 sul NG.
Grazie!

 
seguendo l'evoluzione del thread effettivamente la soluzione che ti 
avevo proposto non va bene, avevo pensato che la trasmissione DMX 
avvenisse con cadenze piu' lunghe

 TX FIFO ? 1/8 full		0x0
Scusa, ma non è che questo è ciò che ti serve?
La FIFO non è indirizzabile (eh, no, che FIFO sarebbe?) ed è di lunghezza
fissa? A che servirebbe, in tal caso, un interrupt del genere?
E' un'operazione molto lunga spillare i 7 byte che non ti intreressano?

 E' un'operazione molto lunga spillare i 7 byte che non ti intreressano?
Perdonami ma non ho capito. Il punto č che se in trasmissione non riempi 
a sufficienza la FIFO l'interrupt non viene generato. E comunque questo 
č relativo al riempimento della FIFO e non dell'avvenuta trasmissione ( 
= svuotamento).
Ciao
--
Marco / iw2nzn

 a sufficienza la FIFO l'interrupt non viene generato.
1/8 di 16 č 2, in pratica hai un buffer di trasmissione.
Cioč, davvero, pensaci meglio. ;-)
Puň darsi che a me sia sfuggito qualcosa, ma, scusa se lo dico, penso sia
piů probabile che tu sbagli ad interpretare quanto scritto che i
progettisti della Luminary abbiano fatto un simile errore.

 progettisti della Luminary abbiano fatto un simile errore.
Lo spero anche io che mi sia sfuggito qualcosa. Comunque riporto alcune 
risposte avute dal forum Luminary (utenti, sto aspettando ancora la 
risposta ufficiale in email).
"AFAIK, there's know way to do exactly what you want, which I find very 
frustrating. It's a major oversight on the interface that you can't get 
an immediate interrupt on data transmission or data receipt."
"One way that may help, but not get you exactly where you want to be, is 
to use the TX FIFO level interrupt. If you're streaming data, you could 
configure the transmit FIFO to generate an interrupt at 1/8 full (or 
less) which is 2 bytes, [...] The downside is that if you don't have any 
outbound data for the transmit stream, the last two bytes are 
transmitted without interrupt. I picked the 1/8 FIFO level to minimize 
the missing interrupts."
"It would be nice if UART generated a tx complete interrupt. The trigger 
level interrupt is no good since UART baud rate can be so variable."
Buona domenica!
Marco / iw2nzm

 Lo spero anche io che mi sia sfuggito qualcosa. 
Da quanto hai pubblicato direi proprio di no. Figurati se quelli della
Luminary (il forum è mantenuto e supportato da loro, vero?) non avrebbero
risposto ad interventi del genere, avessero potuto. :-(

 TX FIFO = 7/8 full         	0x4
Non capisco come possa impostarlo a 0. Ora sono di corsa che sto 
uscendo, nel pomeriggio ci guardo meglio.
Ciao!
Marco / iw2nzm

 Non capisco come possa impostarlo a 0.
Semplice: mettendolo a 0. ;-)
Ti stanno in pratica suggerendo di mettere l'interrupt FIFO ad 1/8, ovvero
di usarla come seriale triple-buffered, come s'era detto.
In pratica credo proprio che dovrai, per iniziare la trasmissione, caricare
i primi tre byte nella FIFO. Dopodiché avrai un interrupt per ogni byte
trasmesso.
Questo a meno tu non confermi che, *anche* per la trasmissione,
"L'interrupt sulla FIFO scatta quando il livello *sale* sopra quello
impostato", cosa che però non avrebbe alcun senso.
Spero tu non confermi quanto sopra (mi raccomando, fai anche un
esperimento, l'errore potrebbe essere nel datasheet), altrimenti mi sa che
Luminary *non* sarà il fabbricante ARM che sceglierò: se hanno fatto due
smaroni simili, figuriamoci il resto...

 risposto ad interventi del genere, avessero potuto. :-(
A seguito di uno scambio di email con i tecnici Luminary ecco la 
conclusione:
"After speaking with our designers, you are correct.  The only way to 
get an interrupt after each transmit byte is to disable the FIFO (1). 
Otherwise the only time a transmit interrupt will assert is when the 
FIFO crosses the thresholds defined in the FIFO level register.  That 
would mean the smallest level in when the FIFO goes from having 3 bytes 
to 2 bytes (1/8th setting, 16 byte FIFO).
Our next generation devices have a new EOT (End Of Transfer) interrupt 
that will have the ability to assert after each byte.  The current 
transmit interrupt asserts after the data has left the FIFO, not after 
the transmission occurs on the bus.  The new EOT bit will assert once a 
byte has been completely transferred on the bus."
Purtroppo non ho fatto a tempo a fare la prova di cui al punto (1) che 
già si era detta perché ho dovuto finire alla svelta e consegnare il 
semi-prototipo. Se riesco nel weekend la farò sulla scheda di sviluppo.
Di sicuro ci toccherà aspettare sto benedetto EOT... ma dico io: a cosa 
pensavano quando l'hanno progettato? In ambito embedded mi sembra una 
funzionalità normalissima e utilissima...
Bah
Marco / iw2nzm

 funzionalitą normalissima e utilissima...
Devo essere sincero?
In trasmissione m'č capitato poco spesso, per usare un eufemismo.
Anche a te, se ben ricordo, serve l'interrupt solo dopo il primo carattere
per cambiare la velocitą dopo la trasmissione.
Dico per dire, ma forse, se č come ho detto sopra, potresti hardcodare la
trasmissione del primo, lento, carattere in software, e poi partire di
FIFO.

 FIFO.
Il primo byte è l'ultimo dei problemi :)
Posso permettermi il lusso anche di aspettare lì. Il discorso era 
riferito a sapere quando un byte (o più byte in caso di FIFO) è stato 
*effettivamente* trasmesso sul bus.
Cioè sapere che è in coda di trasmissione va bene, magari voglio 
riempire il buffer, ok. Ma non mi dice nulla sul fatto che la 
trasmissione sia davvero completata!
Un esempio tra i tanti: RS485 e enable. Se non ho l'interrupt a fine tx 
o mi metto ad aspettare in polling oppure come sta facendo un utente sul 
forum Luminary, dovrei agganciare un timer impostato in funzione della 
velocità di trasmissione, parità, stop bit ecc attivato dall'ultimo 
interrupt FIFO... Ma ovviamente non è comodo né sistematico...
Ciao!
Marco / iw2nzm

 *effettivamente* trasmesso sul bus.
Ah, ok, bastava dirlo... ;-)