Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

I2C più SPI, funzioni non bloccanti, Ardu-semafori, etc.

Progetti, interfacciamento, discussioni varie su questa piattaforma.

Moderatori: Foto UtenteWALTERmwp, Foto Utentexyz

0
voti

[1] I2C più SPI, funzioni non bloccanti, Ardu-semafori, etc.

Messaggioda Foto Utentelemure64 » 21 apr 2023, 0:03

Ciao Forum

Scusate il titolo strano ma riflette la confusione che ho in testa. Sempre a proposito del mio progettino, vorrei poter usare la seriale (nella sua declinazione SoftwareSerial) e anche I2C. Sui vari forum dicono che possono coesistere ma mi trovo in difficoltà nella concezione di alcune parti del progetto.

In sostanza ho tre sezioni principali, distribuite di conseguenza nei moduli sorgenti. Una si occupa dell'IO con SoftwareSerial, l'altra di IO con il protocollo I2C e la terza è lo schedulatore dei task, fatto con macchine a stati finiti, o meglio una loro implementazione.

Il modo di interagire dei primi due sistemi verso il programmatore è diverso. SoftwareSerial ha una funzione che permette di sapere se ci sono bytes in attesa e una per leggerli. Invece I2C con Wire chiede all'utente una funzione di callback che viene chiamata quando ci sono caratteri in attesa. La mia implementazione è la più semplice possibile: quando viene chiamata legge quello che c'è e lo copia in un buffer.

E' chiaro che la logica del programma dipende in parte da cosa fa l'hardware. Se fossi su un normale SO potrei ragionare in termini di threads e usare le relative tecniche. Ma non riesco a capire come funziona Arduino, quello che trovo in rete è troppo tecnico per me. Da un lato ho funzioni che sono chiaramente bloccanti, le mie. Dall'altro una delle due non sono io a chiamarla ma Arduino. Sono confuso sulle modalità con cui questo possa avvenire, ovvero se, come credo, quando viene chiamata l'esecuzione del mio programma viene sospesa fino a che non si esce dalla funzione di callback oppure Arduino ha una specie di multitasking via hardware e se è così non so come regolarmi per scrivere la mia libreria. La domanda è: la funzione di callback è eseguita contemporaneamente al flusso del programma dello sketch? O fino a che è in esecuzione viene eseguita solo quella?

Cerco di descrivere il problema. Su un arduino che chiamo R(ipetitore) possono arrivare in qualsiasi momento dei comandi da un H(ardware) connesso via I2C. Dovrei poterli leggere e comunicarli ai task in esecuzione su R, che sono assegnati dall'utente tramite funzioni di callback. Una volta elaborato il comando arrivato da H il risultato dovrebbe essere mandato via SofwareSerial a un altro arduino F(oglia), aspettare e ricevere da questo una risposta che R re-invia ad H via I2C. In pratica il tutto dovrebbe agire come uno strato intermedio per gestire la comunicazione tra un hardware H che nelle mie intenzioni è raspberry e degli arduini F fisicamente molto lontani connessi con RS485.

Gerarchicamente abbiamo:

*** H, per fissare le idee un raspberry che può mandare comandi quando gli pare e al limite mettersi in ascolto se si aspetta una risposta da R o F.

*** R, lo strato centrale che riceve i comandi da H e ne fa una prima elaborazione poi li trasmette a

*** F, che può ulteriormente elaborarli e trasmettere il risultato a R che nel frattempo si è messo in ascolto dopo aver trasmesso. Ovvio che R interrogherà sempre un F alla volta.

La logica di base che vorrei seguire è che il canale R-F segua la logica della connessione RS485 ovvero che lo slave F possa trasmettere solo se interrogato, in modo che sul bus SoftwareSerial ci sia sempre il segnale di un solo dispositivo. Riguardo invece al flusso dati H-R, acquisire sempre e comunque tutto quello che arriva da H ma utilizzare solo i pacchetti arrivati quando 1) R-F non stanno comunicando e 2) I task di R non stanno elaborando i comandi. Di fatto, catturare il comando da H solo quando tutti gli altri sistemi sono in idle. In questo modo R non potrebbe venire bloccato se il flusso dati da H diventa continuo o arrivano packet sbagliati.

Quello che pensavo di fare per impostare il codice di R è un flusso di questo tipo nel "loop" di Arduino:

1) Se R e F stanno comunicando, o prima ancora R sta elaborando, nella funzione di callback usata da I2C viene settato un flag che fa saltare la sezione di lettura; in pratica i caratteri vengono tolti dal buffer in uscita di H in ogni caso, ma non memorizzati nel buffer dei comandi arrivati ad R. Vengono invece presi in considerazione solo quando R e i vari F non fanno niente.

2) Controllo se in R è in corso l'elaborazione del comando da trasmettere a F.

3) Se è pronto, viene trasmesso a F e R aspetta la risposta di F. Come sopra, se stanno arrivando caratteri da H vengono ignorati.

4) Quando è arrivata a R la risposta di F, se ci sono caratteri dal buffer I2C anche stavolta vengono tolti dal buffer senza essere utilizzati. Se invece non ce ne sono si procede direttamente a trasmettere da R a H.

Ora per esempio per il punto 4, se mentre sto per trasmettere da R ad H, H trasmette? Non mi è chiaro come I2C gestisce questo tipo di comunicazione.

Come sarà evidente sono un po' confuso io. Non so se come impostazione potrebbe andare o se come temo ci sono problemi e funzionamenti dell'harware che renderebbero irrealizzabile questa soluzione. A favore di sicurezza potrei anche predisporre tutto in modo che possa parlare solo un dispositivo alla volta, nonostante a quanto pare I2C e seriali possono lavorare contemporaneamente. Ma non devo fare il software di un missile che deve prevedere tutti gli scenari. Penso che il tutto potrebbe funzionare permettendo la comunicazione H-R solo se il resto del sistema non sta facendo niente. Ci sarebbero race conditions in questo modo? O altri problemi e scenari che ora non vedo?

Ho paura che un progetto apparentemente banale possa diventare un osso duro quando si toccano i problemi di sospensione dei task in tanti scenari diveri. Magari le cose sono più semplici di come mi sembrano e spero sia così.

Grazie a tutti :)
Avatar utente
Foto Utentelemure64
689 3 6
Stabilizzato
Stabilizzato
 
Messaggi: 421
Iscritto il: 23 giu 2020, 12:26

1
voti

[2] Re: I2C più SPI, funzioni non bloccanti, Ardu-semafori, etc.

Messaggioda Foto UtenteWALTERmwp » 21 apr 2023, 0:47

Io non ho compreso quasi niente ...
Una prima domanda: ma di tutto quel che hai scritto, hai messo giù del codice?
Se si, potresti intanto inserirlo.
Poi, comunque, con calma, molta calma, cerchiamo di fare l'analisi del tuo post.

Saluti
W - U.H.F.
Avatar utente
Foto UtenteWALTERmwp
30,2k 4 8 13
G.Master EY
G.Master EY
 
Messaggi: 8986
Iscritto il: 17 lug 2010, 18:42
Località: le 4 del mattino

1
voti

[3] Re: I2C più SPI, funzioni non bloccanti, Ardu-semafori, etc.

Messaggioda Foto UtenteMarcoD » 21 apr 2023, 9:07

Foto Utentelemure64, complimenti per la ben scritta esposizione del problema.
Purtroppo, anche se avevo programmato con arduino anni fa, posso aiutarti poco. Anche io mi lamentavo della scarsa descrizione del funzionamento delle funzioni di arduino.
Avevo realizzato una singola connessione fra PC e arduino, ma solo unidirezionale da arduino a PC per trasmettere temperature.
Quindi non so se la esecuzione chiamata-risposta I2C può essere concomitante con quella seriale. Quale è il baudrate?

Ogni quanto tempo H interroga il master e ogni quanto tempo
il master interroga i vari foglie ? 10 ms ? 1 s?
E se gli interrogati non rispondono e si perde un ciclo il funzionamento è compromesso?

https://www.electroyou.it/marcod/wiki/a ... emperature
Avatar utente
Foto UtenteMarcoD
12,2k 5 9 13
Master EY
Master EY
 
Messaggi: 6696
Iscritto il: 9 lug 2015, 16:58
Località: Torino

0
voti

[4] Re: I2C più SPI, funzioni non bloccanti, Ardu-semafori, etc.

Messaggioda Foto Utentelemure64 » 21 apr 2023, 14:21

MarcoD ha scritto:Foto Utentelemure64, complimenti per la ben scritta esposizione del problema.
Purtroppo, anche se avevo programmato con arduino anni fa, posso aiutarti poco. Anche io mi lamentavo della scarsa descrizione del funzionamento delle funzioni di arduino.
Avevo realizzato una singola connessione fra PC e arduino, ma solo unidirezionale da arduino a PC per trasmettere temperature.
Quindi non so se la esecuzione chiamata-risposta I2C può essere concomitante con quella seriale. Quale è il baudrate?

Ogni quanto tempo H interroga il master e ogni quanto tempo
il master interroga i vari foglie ? 10 ms ? 1 s?
E se gli interrogati non rispondono e si perde un ciclo il funzionamento è compromesso?


Grazie intanto per la prima frase, ce l'ho messa tutta data la complessità del problema ma evidentemente ho qualche limite di comunicazione che qualche volta è avvertito e altre no "a seconda".

Riguardo il resto, come sempre dormendoci sopra al mattino si hanno le idee meno confuse rispetto al giorno prima. Ho deciso di procedere in questo modo: considero l'interfacciamento con I2C come non bloccante, quindi anche mentre il mio sketch sta girando, Wire può chiamare la funzione di callback. Invece ho ipotizzato di avere io il controllo completo di SoftwareSerial nel senso che tutte le interazioni sono all'interno di quello che scrivo io e quindi sia tutto bloccante.

Sui timing ho fatto qualche prova con l'analizzatore logico, usando baudrate 9600. Riesco a spedire 30 bytes ogni 400 ms circa sul Nano, che sto usando per le prove proprio perché è lento e mi metto nelle condizioni peggiori. 400 ms non sono tanti per l'uso che vorrei farne, ovvero una comunicazione robusta a lunga distanza. Ciascun messaggio di N bytes (appunto, al momento sto provando con 30) è preceduto e seguito da tre caratteri di controllo e questo pacchetto viene spedito M volte, al momento M==3. Alla prima ricezione il sistema setta un flag in modo da confrontare ciascuna sequenza successiva con la prima ricevuta. Dato che tra queste deve esserci una certa distanza temporale e considerato un margine sufficiente vedo che dai 250 ms minini dovrei poter contare sui 400 sicuri di cui sopra. Vedo un po' di scambio di bytes sul collegamento RS-485 quando non dovrebbero esserci quindi mi aspetto di non poter avere grandi velocità. Che peraltro non mi servono.

Naturalmente ci sono timers ovunque in modo che si possa considerare perso un pacchetto in ritardo e lo stesso anche tra la ricezione dei caratteri del pacchetto. Considerato che ci sono due canali attivi di cui uno lentissimo ho messo macchine a stati finiti dove possibile. Mi ha sempre affascinato (ma senza grande successo, quello che scrivo ha sempre dei bugs) il mondo del software ultra robusto e ultra sicuro che non si ferma mai; detesto programmare ma penso che la vita professionale di chi programma per le sonde su Marte sia parecchio interessante.

Se vuoi darci un'occhiata qui sotto c'è il link. Ma stupidamente stamattina ho iniziato a "smontarlo" e non ho conservato la copia precedente, come spesso mi accade. Da stamattina ho scritto oltre 20 k di codice e modificato tutto senza provare niente. Mi sento come un sarto a cui è stato affidato un vestito, l'ha scucito tutto e sta iniziando a raccapezzarsi per rimetterlo in piedi. Credo che chi un po' programma capisca bene la sensazione di sconforto. Oltretutto penso di essere a circa 1/3 del lavoro, qundi lo condivido solo per una specie di pudore di essere preso per un contaballe, non ho ancora incorporato la parte che funzionava e questo è solo lo scheletro. Ma lo sto facendo davvero questo lavoro! Tutto sta a vedere se lo finirò :)

https://drive.google.com/file/d/1hI92_Ug4vXc0iQOIQVpEyGkvxIjxciF6/view?usp=share_link

PS i nomi assurdi di files e variabili sono dovuti ad abitudini prese ai tempi dell'8088; una volta sostituii tutte le occorrenze di una variabile dimenticando l'opzione "parola intera". Non avevo ancora capito l'importanza del backup, stavo per buttare a mare tutto il lavoro della tesi e ho passato un mese di disperazione che ancora ricordo bene. Quindi se volessi utilizzare la stringa "buf" uso, che so, "bhuf" così so che quella stringa compare solo in quella variabile. Inoltre sono rimasto con un editor di quel periodo archeologico che ordina alfabeticamente i files del progetto. Dato che li vorrei in ordine logico ho potuto soltanto nominarli di conseguenza. Altre stranezze sono dovute al fatto che i compilatori di allora non avevano le sbalorditive ottimizzazioni di gcc di adesso e che tendo a usare il C/C++ come il Pascal. Ma essendo più abitudinario di Kant non ho modo di fare diversamente.

PPS @WALTER, non sapevo proprio che codice scrivere, l'implementazione è sparsa per metà dei files e mi sa che sarei stato bannato a vita se ci avessi provato :)
Avatar utente
Foto Utentelemure64
689 3 6
Stabilizzato
Stabilizzato
 
Messaggi: 421
Iscritto il: 23 giu 2020, 12:26


Torna a Arduino

Chi c’è in linea

Visitano il forum: Nessuno e 3 ospiti