11/06/2018, 00:40
(Questo messaggio è stato modificato l'ultima volta il: 11/06/2018, 00:45 da ZeroUno.)
Ciao.
Sto sperimentando Raspberry e quindi ho preso un po' tutto quello ho e ce l'ho attaccato... contemporaneamente!!
Ovviamente sono esperimenti per ora, ma la problematica può sorgere anche in casi reali.
Molti di questi elementi per essere pilotato necessitano di eventi e relativi callback.
Come input ho 3 pulsanti, un rotatory encoder (e suo pulsante), un joystick (e relativo pulsante), un ir_receiver, ciascuno collegato ad un gpio event.
Poi ho inpostato un evento di tipo itimer ogni 250 millisecondi che ci faccio:
1) stampa di un orologio su display lcd 1602a (una volta al secondo)
2) leggi lo stato del joystick e salva qualche stato
3) pilota alcuni led in base allo stato salvato di joystick e altro.
la callback dell'ir_receiver stampa su lcd (in una zona diversa dell'orologio) il tasto premuto.
la callback del rotatory encoder stampa lo stato su lcd.
il tutto con lo stesso programma python
Ogni tanto l'lcd stampa roba un po' farlocca e stramba, e sono riuscito a ricostruire che probabilmente mentre mi sta stampando l'orologio scatta un evento quale il rotatory o l'ir_receiver che per quanto sono programmati per scrivere in zone diverse del display, usano lo stesso buffer.
Quindi può capitare che il display riceve una seconda scrittura mentre non è terminata la prima e quindi si incarta.
Ora sto citando l'lcd perchè è il dispositivo più lento che ho installato al momento, ma può succedere con qualunque cosa, e peggio sarà quando andrò a pilotare motorini.
Inizialmente ho pensato di inserire un lock per le chiamate a display in questo modo:
- setta LCD_LOCK=1 (una variabile globale)
- stampa su display
- setta LCD_LOCK=0
la prima di queste 3 sarebbe preceduta da if LCD_LOCK == 1: aspetta che LCD_LOCK diventi zero.
Ma poi mi sono reso conto che non ha senso perchè l'approccio di tipo ad eventi non è un approccio di tempo multitask. Quando scatta il secondo evento, il primo viene messo in pausa finchè il nuovo non viene gestito, quindi LCD_LOCK a zero non ci ridiventa e il secondo rimane in attesa perenne (o timeout se lo imposto, come era da idea). Diverso se invece il display era gestito da due programmi separati con lock su filesystem o semafori, in cui il multitasking avrebbe provveduto a mandare avanti il primo programma che avrebbe poi rilasciato il lock.
Allora l'altra idea che mi è venuta in mente è quella di fermare tutte le interrupt durante l'esecuzione di una di queste, ma così si rischia di perdersi alcuni eventi. A meno che non si riesca ad accodarli.
Un'altra ancora è quella di demandare (e per un aspetto l'ho già fatto) le scritture su lcd ad un sistema asincrono, così solo l'evento timer scrive lì sopra mentre gli altri eventi si limitano a scrivere le operazioni richieste in una variabile (magari in una struttura a coda). Di sicuro l'aggiornamento di queste variabili è più veloce della scrittura sul display.
Il problema di questo approccio è che così sembra che sto reinventando la ruota (il kernel è scritto esattamente per gestire tutto questo) e introduce molte latenze (ho visto che non ho possibilità di mettere un timer troppo frequente perchè si rischia l'esecuzione di un nuovo evento mentre non è terminata la esecuzione del precedente.
Altre idee prima che continuo a scervellarmi?
Grazie.
Sto sperimentando Raspberry e quindi ho preso un po' tutto quello ho e ce l'ho attaccato... contemporaneamente!!
Ovviamente sono esperimenti per ora, ma la problematica può sorgere anche in casi reali.
Molti di questi elementi per essere pilotato necessitano di eventi e relativi callback.
Come input ho 3 pulsanti, un rotatory encoder (e suo pulsante), un joystick (e relativo pulsante), un ir_receiver, ciascuno collegato ad un gpio event.
Poi ho inpostato un evento di tipo itimer ogni 250 millisecondi che ci faccio:
1) stampa di un orologio su display lcd 1602a (una volta al secondo)
2) leggi lo stato del joystick e salva qualche stato
3) pilota alcuni led in base allo stato salvato di joystick e altro.
la callback dell'ir_receiver stampa su lcd (in una zona diversa dell'orologio) il tasto premuto.
la callback del rotatory encoder stampa lo stato su lcd.
il tutto con lo stesso programma python
Ogni tanto l'lcd stampa roba un po' farlocca e stramba, e sono riuscito a ricostruire che probabilmente mentre mi sta stampando l'orologio scatta un evento quale il rotatory o l'ir_receiver che per quanto sono programmati per scrivere in zone diverse del display, usano lo stesso buffer.
Quindi può capitare che il display riceve una seconda scrittura mentre non è terminata la prima e quindi si incarta.
Ora sto citando l'lcd perchè è il dispositivo più lento che ho installato al momento, ma può succedere con qualunque cosa, e peggio sarà quando andrò a pilotare motorini.
Inizialmente ho pensato di inserire un lock per le chiamate a display in questo modo:
- setta LCD_LOCK=1 (una variabile globale)
- stampa su display
- setta LCD_LOCK=0
la prima di queste 3 sarebbe preceduta da if LCD_LOCK == 1: aspetta che LCD_LOCK diventi zero.
Ma poi mi sono reso conto che non ha senso perchè l'approccio di tipo ad eventi non è un approccio di tempo multitask. Quando scatta il secondo evento, il primo viene messo in pausa finchè il nuovo non viene gestito, quindi LCD_LOCK a zero non ci ridiventa e il secondo rimane in attesa perenne (o timeout se lo imposto, come era da idea). Diverso se invece il display era gestito da due programmi separati con lock su filesystem o semafori, in cui il multitasking avrebbe provveduto a mandare avanti il primo programma che avrebbe poi rilasciato il lock.
Allora l'altra idea che mi è venuta in mente è quella di fermare tutte le interrupt durante l'esecuzione di una di queste, ma così si rischia di perdersi alcuni eventi. A meno che non si riesca ad accodarli.
Un'altra ancora è quella di demandare (e per un aspetto l'ho già fatto) le scritture su lcd ad un sistema asincrono, così solo l'evento timer scrive lì sopra mentre gli altri eventi si limitano a scrivere le operazioni richieste in una variabile (magari in una struttura a coda). Di sicuro l'aggiornamento di queste variabili è più veloce della scrittura sul display.
Il problema di questo approccio è che così sembra che sto reinventando la ruota (il kernel è scritto esattamente per gestire tutto questo) e introduce molte latenze (ho visto che non ho possibilità di mettere un timer troppo frequente perchè si rischia l'esecuzione di un nuovo evento mentre non è terminata la esecuzione del precedente.
Altre idee prima che continuo a scervellarmi?
Grazie.