Beh, guarda caso la soluzione che stavo per proporre è proprio la tua...
L'hardware dovrebbe essere qualcosa del genere:
Hai un bus di sincronizzazione che viene tenuto alto da un pull-up su ogni scheda.
Per tirarlo basso, ogni microcontroller ha un uscita open-drain collegata e un ingresso per campionarne lo stato (ci sono micro che offrono la stessa funzione usando un solo pin, non so se è il tuo caso).
I microcontroller lavorano alla loro frequenza nominale (24 MHz o qualcosa giú di lì).
Usa uno dei timer hardware per generare un clock lento che controllerà i LED. La frequenza di lavoro deve essere tale da permetterti di gestire lo skew massimo che ti sei preposto. Quindi, per 500 us, con un po' di oversampling, ci vogliono 20 kHz (piú o meno, non è un valore critico).
Questo clock lento governa un counter. Quando il counter raggiunge il valore prefissato (che devi calcolare in base al tempo tra due impulsi), il micro accende il led, resetta il counter e aspetta che sia passato il tempo durante il quale i led sono accesi, li spegne, e così via...
Con questo programma, ogni scheda funziona per conto suo e hai il problema che hai descritto.
Per implementare la sincronizzazione ci sono un paio di approcci diversi.
First-come, first-serveIl microcontroller accende il led quando il primo di questi due eventi si verifica:
- il counter raggiunge il valore prefissato (in questo caso, il micro è il piú veloce e deve segnalarlo agli altri abbassando la linea sense)
- la line sense viene portata a 0
Fin qui è facile: il micro piú veloce detta il momento dell'accensione. Se ci sono piú micro che in contemporanea arrivano a questo punto... chissenefrega: la linea sense è un wired-or.
Inserisci all'accensione un ritardo pari a 3-4 cicli, durante i quali il micro ignora il suo counter e ascolta solo la linea sync. In questo modo puoi "hotpluggare" una scheda.
Ora, quando spegnere il led?
Anche qui ci sono diverse possibilità:
- ogni micro lo spegne autonomamente usando il suo counter. È la soluzione piú semplice. Causa skew sullo spegnimento, ma la domanda è "quanto?". Se i clock hanno una tolleranza di 30 ppm (tipica per un buon quarzo) e l'impulso dura 500 ms avrai uno skew massimo di 15 us. Probabilmente piú che accettabile.
- dopo un breve periodo di tempo che permetta a tutti i micro di rilevare la linea di sense a 0 e accendere il led, i micro che l'hanno abbassata rilasciano il bus. Questo periodo di tempo deve essere ovviamente minore della durata dell'impulso, ma non dovrebbe essere un problema. Quando il counter del micro piú veloce raggiunge il momento di spegnere il led, la linea viene abbassata nuovamente e tutti gli altri seguono. Questa soluzione elimina lo skew in spegnimento ma introduce un potenziale problema: se una scheda viene collegata a sistema acceso, non sa se è nella fase on o off. Il problema si potrebbe presentare anche nel caso in cui un'interferenza elettromagnetica faccia "perdere un colpo" ad una scheda. Questo problema è però piú che altro teorico: allo scadere del counter, anche questa scheda spegnerebbe il led. Il problema vero si risolve con una specie di comunicazione digitale sulla linea sync iniziata dal micro che la abbassa: se dopo 2 ms il bus viene rilasciato per 1 ms e poi nuovamente abbassato, allora è una fase ON, altrimenti OFF (o qualcosa di simile).
Soft-PLLStesso discorso come sopra, ma gli "slave" non si limitano ad accendere e spegnere il led. Quando si accorgono che la linea sync è stata tirata bassa, memorizzano lo stato del loro counter e lo usano come valore a cui commutare per il prossimo ciclo. In sostanza calibrano la durata dei loro impulsi in base a quella imposta dal micro piú veloce.
Questa soluzione ha un paio di vantaggi:
- se il master viene allontanato dal sistema, questo continua a funzionare alla stessa velocità. Con la soluzione FCFS, la velocità cambierebbe per adeguarsi a quella del micro piú veloce.
- la correzione del tempo di accensione può essere usata per correggere anche il tempo di spegnimento (dato che derivano dallo stesso clock). In questo modo la linea sync viene usata solo per segnalare l'accensione, cosa che risolve tutti i problemi citati sopra e rende il sistema decisamente piú robusto.
Questa soluzione ha però anche uno svantaggio:
- la correzione che apporti al tempo di commutazione ha una risoluzione finita e può quindi succedere che il micro X corregga per adattarsi al micro Y (piú veloce). Dopo la correzione X commuta prima di Y. Ora sarà quest'ultimo a correggersi accelerando, e così via. Devi quindi introdurre una banda morta dentro la quale (quando sei sufficientemente vicino alla sincronia) i micro non apportano nessuna correzione ai loro tempi di commutazione.
Saluti Boiler