Newsgroup: it.hobby.elettronica.digitale
Titolo: Concatenare dispositivi seriali TTL/Atmel/Arduino

Ciao.
Ci sto ragionando su da qualche giorno e non mi vengono in mente 
controindicazioni.
 
Dato un Arduino "master" (o simile, comunque un uC Atmel) voglio 
distribuire delle informazioni ad una serie di uC Atmel in maniera 
asincrona e *unidirezionale*. C'e' qualche controindicazione nell'usare 
la semplice seriale (UART TTL), fintanto che implemento nel codice un 
modo affinche' ogni slave sia in grado di capire se il messaggio e' 
indirizzato a lui o altrove?
 
Le distanze sono brevi. Le velocità di aggiornamento è molto bassa, meno 
di un update al secondo. I byte inviati sono 2 o 3 per pacchetto. Posso 
fare a meno di un ACK da parte degli slave, perchè i pin mi servono per 
altre funzioni...
 
In pratica implementerei una specie di i2c/twi unidirezionale usando la 
USART. Se il fan-out della porta del master e' sufficiente ... perche' no?!
 
Opinioni?
PaoloC

 Se il fan-out della porta del master e' sufficiente ... perche' no?!
 
Io l'ho fatto con la USART, cioè Sincrona con un CLK e un DATA e va a 2,5Mhz,
però con un buffer 74HC04 sulle uscite e uno Schmitt trigger 74HC14 in ingresso.
 
Il tutto dentro lo stesso contenitore, senza problemi particolari.
 
 
-- 
ciao
  Stefano

comunicazione, mentre la UART è asincrona e ne usa uno solo.
 
Preciso meglio, la UART ne usa uno per ogni direzione, quindi 2 TXD e RXD
 
La USART ne usa 3 DATA-OUT, DATA-IN e CLOCK
 
La usart negli AVR si può assimilare ad una SPI, con qualche differenza, che
però se usi la UART come USART da tutte le parti non da problemi.
 
 
-- 
ciao
  Stefano

Ciao Stefano.
Grazie per le dritte. Intendevo UART, seriale classica senza controllo 
di flusso. RXD e TXD, stop.
 
Nel mio caso distribuirei il segnale TXD "master" ai RXD di 4 o 6 slave. 
Son tutti nello stesso contenitore e magari in un'area di 10x15 cm o 
meno. Metti che sia un orologio che aggiorna le cifre del display, 
due-tre byte una volta al secondo. Il progetto attualmente non prevede 
visualizzazioni più rapide ma posso pensare ad altri effetti visivi a 
fronte di aggiornamenti dei dati più corposi. E' un gioco, destinato 
probabilmente al mio comodino ;-)
 
Proverò il tutto appena mi arrivano i tiny4313 per fare gli slave.
 
PaoloC
 

 indirizzato a lui o altrove?
 
Visto che i bytes sono pochi, puoi inviare semplici nibble di 4 bit + indirizzo destinatario.
Con 2 ottetti invii un byte al destinatario giusto: i uC non interessati semplicemente scartano il dato per via del campo indirizzo (4 bit) che non 'matcha'.
Con questa soluzione, però, devi assegnare un indirizzo ad ogni uC e può essere scomodo, magari in fase di programmazione che si traduce in ricompilazioni dello stesso codice con un parametro diverso o arzigoggoli per assegnare l'ID via software più o meno onerosi, fino al massimo spreco hardware che richiede l'uso di pin esterni.
Sennò, puoi implementare una soluzione posizionale in modo da compilare una sola volta il codice uguale per tutti.
Colleghi in catena i uC connettendo il Tx del primo (master) con l'Rx del secondo (primo slave) e così via.
Il master ha indirizzo nullo e gli slave in sequenza 'subiscono' indirizzi crescenti: il primo sarà lo '0', il secondo l'1', il terzo il '2' e così via fino a 15.
Ogni uC riceve dal precedente e rinvia (se necessario) al successivo.
Il pacchetto deve essere così formato:
 
primo byte:
   bit 7..4 = <indirizzo_destinatario>
   bit 3..0 = 0b000
 
secondo byte:
   <dato>
 
Il master indica l'indirizzo del destinatario nei bit 7..4 (puoi usare un codice anche per il broadcast) e pone i bit 3..0 a zero.
Il primo slave riceve il byte, confronta il nibble alto con quello basso e se non sono uguali ritrasmette il dato al prossimo slave incrementando i bit 3..0 di una unità.
Se sono uguali, utilizza il dato seguente e non ritrasmette nulla (il dato era per lui).
 
Così scrivi un solo codice e puoi metter in catena quanti slave ti pare (fino a 15 ma puoi facilmente estendere il principio).
 
Piccio.

 Così scrivi un solo codice e puoi metter in catena quanti slave ti pare (fino a 15 ma puoi facilmente estendere il principio).
 
Aggiungo:
è bene prevedere una sequenza di sincronizzazione tipo 2 byte consecutivi a 0x00 (quindi gli slave devono partire dall'indirizzo '1').
Se per qualsiasi motivo un byte di dato viene interpretato come indirizzo, nascono casini.
La sequenza 0x00 + 0x00 deve indicare una situazione di reset comunicazione e deve essere ritrasmessa tra tutti gli slave.
Sarebbe bene usare tale sequenza come header prima di ogni pacchetto.
 
Migliorando (in partenza dal master):
 
1° byte: 0x00
2° byte: 0x00
3° byte: bit(7..4) = <indirizzo_destinatario>
3° byte: bit(3..0) = 0b001 (contatore ad incremento)
4° byte: <dato>
5° byte: 0xFF
 
Pesantuccio ma semplice.
 
Piccio.
 

> Così scrivi un solo codice e puoi metter in catena quanti slave ti pare (fino a 15 ma puoi facilmente estendere il principio).
 
Mi sembra che con il sistema delle ritrasmissioni si aumenta solo la 
latenza e si moltiplica la possibilita` di errore (anche se in un 
insieme embedcontenuto si dovrebbero poter considerare prossimi allo zero).
 
Ogni slave *deve comunque* leggere tutto il pacchetto, e *deve comunque* 
riconoscere il proprio addr, a quel punto mi sembra meglio scartarlo 
velocemente piuttosto che ritrasmetterlo.
 
Il problema della sincronizzazione invece e` reale, e in casi semplici 
si puo` risolvere anche con un solo bit (il byte che ha D7=1 e` sempre 
il primo della sequenza):
 
.----+----+----+----+----+----+----+----.
|  1 | A3 | A2 | A1 | A0 | D7a| D7b| D7c|
'----+----+----+----+----+----+----+----'
 
.----+----+----+----+----+----+----+----.
|  0 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |   byte a
'----+----+----+----+----+----+----+----'
 
.----+----+----+----+----+----+----+----.
|  0 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |   byte b
'----+----+----+----+----+----+----+----'
 
.----+----+----+----+----+----+----+----.
|  0 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |   byte c
'----+----+----+----+----+----+----+----'
 
 

 il primo della sequenza):
 
Sui uC Fujitsu (tipo 89530) c'era la possibilità di impiegare un nono bit proprio per questa circostanza in modo da non dover tribolare a far scorrere dei bit per ricostruire il pacchetto.
In alternativa si potrebbe inserire la parità e correggerla alla bisogna ma si tribola un po', soprattutto in ricezione.
 
Sviluppando la mia idea precedente (magari neanche originale), si può chiudere il loop dei Tx-Rx con il master: Tx dell'ultimo slave con l'Rx del master.
In questo modo, assegnando al master l'address '0' ed inibendo l'incremento del contatore, gli slave possono anche rispondere; gli slave seguenti semplicemente ritrasmetteranno il pacchetto integralmente finché giungerà al master che lo impiegherà.
 
Risposta da uno slave:
 
1° byte: 0x00
2° byte: 0x00
3° byte: 0x01
4° byte: <dato>
5° byte: 0xFF
 
Sacrificando poi un bit nel 3° byte che si traduce nel poter indirizzare solo 6 slave + il master, si possono dividere i pacchetti in <dato> e <comando>.
 
Il 5° byte a 0xFF non è proprio indispensabile, nasce dalla considerazione che un <dato> potrebbe essere a '0' e si concatenerebbe con un nuovo header dando origine ad una sequenza di tre zeri che in ogni caso non sarebbe un problema.
La cosa importante è che il 3° byte non sia mai '0'.
 
Mi vien quasi voglia di implementarlo!  :)
Ho un sacco di schede di produzione (da mettere a posto) con gli ATmega48 pronte ed accessibili...
 
Piccio.

 Il 5° byte a 0xFF non è proprio indispensabile, nasce dalla
 
Utile. Anche se pensavo di provare ad usare il primo byte per 
trasportare la info sulla lunghezza della trasmissione:
 
1 byte: &B1AAAAALL   // A = address, L = lunghezza dati in byte
2 byte: &B0DDDDDDD   // D = data
3 byte: &B0DDDDDDD
...
L+1 byte: &B11111111  // da valutare se usarlo
 
Al momento la lunghezza dei dati può essere di 1 byte o di 5 byte quindi 
anche in caso di 15 slave non avrei uno start-byte di 0xFF: &B11111101 
(1 byte dati) o &B11111110 (5 byte dati). L'indirizzo 0 lo tengo come 
broadcast.
 
Chissà se oggi mi arrivano i tiny per fare gli slave definitivi...
PaoloC
 

 senza indirizzo diventi il 2". E così via.
...
 
Puoi anche tenere tutti i uC montati ma in reset con un jumper tranne uno per volta, sempre che non utilizzi anche quel pin come I/O.
 
Piccio.

 uno per volta, sempre che non utilizzi anche quel pin come I/O.
 
Vero. Il reset E' il reset. Una volta ho sbagliato a mettere i fuse ed 
ho dovuto costruire un HVP per recuperare un paio di chip.
 
Il /RESET per me è sacro. :-)
 
PaoloC

 Il /RESET per me è sacro. :-)
 
Anche per me ma sugli AVR funziona lo stesso e anche meglio se non lo disturba visto che ha innumerevoli fonti.
Per come la vedo io, monterei una rastrelliera per jumper da 3 file per tante colonne quante sono i uC.
Tutti i pin dela prima fila in alto dovrebbero essere collegati al reset proveniente dal programmatore AVR.
Tutti i pin della fila in basso a GND in modo da inibire i uC interessati.
La fila di mezzo dovrebbe far capo a ciascun pin di reset di ogni uC.
In questo modo puoi mettere in parallelo tutti i pin MISO, MOSI e CLK ed usare un solo pod di programmazione.
Questo vuol dire anche sprecare 3 pin per uC, però...
 
Piccio.