Un vero fail-safe non inizia dal watchdog ma dal carico: devo progettare il circuito in modo che, se il microcontrollore si blocca, un pin resta alto, il firmware impazzisce oppure una parte dell'elettronica muore, l'energia venga comunque tolta. Un enable dinamico, protezioni indipendenti, limiti analogici, fusibili e ridondanza trasformano il guasto da evento incontrollabile ad uno stato previsto.
Il watchdog è utile, ma non è il mio ultimo giudice
Se avete progettato qualche scheda che comanda una resistenza, un motore, un'elettrovalvola oppure un relè saprete certamente che la domanda più fastidiosa non è "funziona?" ma "COSA SUCCEDE QUANDO NON FUNZIONA?". Quando progettavo più assiduamente di oggi questa cosa mi preoccupava parecchio, soprattutto davanti ai carichi che non potevo permettermi di lasciare inseriti senza controllo, ed avevo preso un'abitudine molto semplice: invece di pilotare il finale con un livello statico gli fornivo un segnale digitale che doveva continuare a cambiare stato, normalmente un'onda quadra, e poi ricavavo da quella attività una tensione continua con un piccolo circuito intermedio. Nella mia testa il ragionamento era molto terra terra: se sei vivo continua a battere, se sei morto puoi anche esserti fermato alto oppure basso, NON MI INTERESSA, il carico deve spegnersi.
Quell'idea appartiene alla stessa famiglia concettuale degli heartbeat hardware, degli enable dinamici e dei circuiti nei quali un treno di impulsi viene rivelato oppure trasformato attraverso un accoppiamento capacitivo, un raddrizzatore o una piccola charge pump. Non esiste un unico nome universale per ogni implementazione discreta di questo genere, quindi eviterei di appiccicare ad ogni schema la stessa etichetta, ma il principio è chiarissimo: uno stato statico non deve poter rappresentare indefinitamente la condizione di macchina sana. Per tenere acceso il finale bisogna continuare a DIMOSTRARE DI ESSERE VIVI.
Perché un livello logico fermo mi è sempre piaciuto poco
Prendiamo il caso più banale, un'uscita del microcontrollore che attraverso un transistor eccita la bobina di un relè. Se il livello alto significa relè attivo ed il processore entra in un loop, si blocca per un disturbo oppure finisce in una condizione nella quale quel GPIO rimane alto, dal punto di vista del relè non è successo niente: continua semplicemente a ricevere il comando di accensione. Se dietro al contatto ho una lampadina forse non importa molto, se ho una resistenza da qualche kilowatt, una pompa, un motore oppure una valvola che deve assolutamente richiudersi la stessa banalissima condizione prende tutto un altro significato.
Con un comando dinamico invece introduco un vincolo temporale. Il circuito a valle deve ricevere transizioni entro un certo intervallo e, se queste scompaiono, la sua energia di mantenimento decade. Un condensatore in serie può bloccare la componente continua, un raddrizzatore può ricavare dagli impulsi una tensione di enable ed una capacità può mantenerla per un tempo volutamente breve. Il micro può fermarsi alto, fermarsi basso oppure perdere completamente il clock e, salvo guasti del circuito di sicurezza stesso, l'uscita torna allo stato che ho deciso essere sicuro.
La parte bella è che questo meccanismo non deve per forza capire PERCHE' il controllore si sia bloccato. Non deve diagnosticare il bug, stabilire se c'è stato un disturbo EMC oppure riconoscere un latch-up. Deve soltanto constatare che il comportamento atteso non esiste più e togliere l'abilitazione.
Prima regola: decidere quale sia davvero lo stato sicuro
Qui c'è però un punto che viene prima di qualsiasi circuito. Fail-safe non significa automaticamente "tutto spento", significa portare il sistema nello STATO MENO PERICOLOSO plausibile dopo quel guasto. Per una resistenza di riscaldamento quasi sempre significa togliere energia, per una pompa di raffreddamento potrebbe non essere così semplice, per un freno elettromeccanico spesso si preferisce una struttura nella quale la mancanza di energia provochi la frenatura, mentre in altri sistemi fermare brutalmente un attuatore può creare un pericolo peggiore di quello che si voleva evitare.
Per i carichi che mi preoccupavano maggiormente io ragionavo quasi sempre secondo il principio "energia presente soltanto finché tutte le condizioni sono sane". Il relè o il contattore viene quindi eccitato per consentire il funzionamento e cade quando manca alimentazione, manca il comando dinamico oppure interviene una protezione. È il classico modo di progettare in cui il filo spezzato, l'alimentatore morto ed il transistor di pilotaggio aperto tendono tutti verso la stessa direzione, cioè DISABILITARE.
Ma non basta disegnare un contatto normalmente aperto e dichiararsi tranquilli, perché anche un contatto può saldarsi. Da qui nasce tutto il resto.
Il trucco dell'onda quadra, fatto con pochi componenti
Il circuito più semplice che avevo in mente era sostanzialmente un rilevatore di attività. Dal micro esce un'onda quadra, il segnale attraversa un condensatore e quindi la componente continua non può attraversarlo indefinitamente, gli impulsi vengono raddrizzati e caricano una capacità che mantiene polarizzato il transistor oppure l'enable del driver. Se gli impulsi continuano la tensione resta sopra soglia, se smettono la capacità si scarica attraverso una resistenza e dopo un tempo stabilito l'uscita cade.
Questa soluzione ha una proprietà che a me piace moltissimo: il pin bloccato ad 1 ed il pin bloccato a 0 producono alla fine LO STESSO RISULTATO. Dopo il transitorio iniziale non c'è più energia trasferita attraverso l'accoppiamento AC e l'enable scompare. È un modo estremamente economico per evitare il classico guasto singolo nel quale il processore è morto ma il suo ultimo livello logico continua a comandare un carico vivo.
Naturalmente bisogna progettarlo bene. La costante di tempo deve essere abbastanza lunga da non far cadere il carico per una normale variazione del firmware ma abbastanza corta da rispettare il tempo massimo nel quale quel carico può restare energizzato senza controllo. Bisogna inoltre considerare cosa succede all'accensione, allo spegnimento, durante i reset e quando il GPIO è ancora in alta impedenza. Ed io metterei SEMPRE una resistenza di pull-up oppure pull-down direttamente sul gate o sulla base del finale, scelta in modo che il componente resti spento mentre il microcontrollore non ha ancora preso possesso del pin.
Un monostabile retriggerabile è spesso ancora più pulito
Lo stesso concetto può essere realizzato senza raddrizzare artigianalmente un'onda quadra, usando un monostabile retriggerabile oppure un supervisore esterno. Ogni impulso valido ricarica, per così dire, il tempo concesso al sistema; se ne arriva un altro prima della scadenza l'uscita rimane abilitata, se il treno si ferma il tempo scade ed il finale viene disabilitato.
A volte questa soluzione è più leggibile dello schema a condensatori e diodi perché il timeout è definito chiaramente ed è meno dipendente da soglie analogiche sparse. Il principio però rimane identico: NON DEVO FIDARMI DI UNO STATO, devo fidarmi di un'attività che continua nel tempo.
Ed allora a cosa serve il watchdog
Il watchdog serve eccome, ed io lo userei. Ma gli affiderei il compito che sa fare bene, cioè accorgersi che l'esecuzione del software non procede nel modo previsto e tentare di riportare il microcontrollore in uno stato noto attraverso un reset. Un WWDT (Windowed Watchdog Timer) fa qualche cosa in più rispetto ad un watchdog elementare perché non controlla soltanto che il software lo rinfreschi prima che scada, controlla anche che non lo faccia TROPPO PRESTO, cosa utile per riconoscere alcuni loop nei quali il programma continua stupidamente ad eseguire soltanto il codice di refresh.
Il problema è che un reset del processore e la sicurezza del carico sono due cose diverse. Il watchdog ha inevitabilmente un tempo di intervento, può esserci un errore che non interrompe il codice incaricato di rinfrescarlo, può esserci corruzione dei dati senza perdita del flusso di esecuzione ed un watchdog interno condivide comunque parecchio silicio, alimentazione e condizioni ambientali con il micro che dovrebbe sorvegliare. Per questo, quando il carico conta davvero, preferisco che il watchdog sia UNA LINEA DI DIFESA e non l'unica.
Watchdog esterno: meglio ancora se sa togliere l'enable
Un supervisore esterno mi piace perché introduce un pezzo di hardware che non dipende dal core del microcontrollore e può avere il proprio riferimento temporale, il proprio monitor di alimentazione ed un'uscita separata. Esistono supervisori che chiedono periodicamente una transizione sul proprio ingresso watchdog e, quando non la ricevono, generano un reset oppure un'uscita di fault. Nei componenti destinati alla functional safety si arriva molto oltre, con watchdog a finestra, challenge-response, monitor dei clock, controllo delle alimentazioni ed uscite di safing capaci di disabilitare direttamente gli stadi di potenza.
Questa separazione secondo me è fondamentale: se il micro muore, NON VOGLIO CHE SIA IL MICRO A DECIDERE DI SPEGNERE IL CARICO. Voglio che qualcun altro si accorga che il micro non sta facendo ciò che deve ed abbia fisicamente la possibilità di togliergli l'autorità.
Il secondo trucco: la protezione non deve passare dal firmware
Immaginiamo una resistenza riscaldante controllata da un micro che legge un sensore di temperatura. La soluzione comoda è leggere il sensore, confrontare il valore con la soglia e spegnere il relè. Ma se micro, ADC, firmware oppure comunicazione con il sensore sono proprio ciò che è andato storto, la protezione dipende dalla stessa catena che dovrebbe controllare.
Io aggiungerei, quando il rischio lo giustifica, una seconda strada completamente indipendente. Può essere un termostato meccanico, un termostato elettronico autonomo, un comparatore analogico alimentato in maniera appropriata oppure un interruttore termico direttamente sul pezzo caldo. La sua uscita non deve dire al firmware "per favore spegni", deve poter INTERROMPERE L'ENABLE oppure l'alimentazione del finale.
Se la soglia normale di lavoro è 80 °C potrei avere il controllo software che regola attorno a quella temperatura ed una protezione hardware separata tarata più in alto, per esempio ad un valore compatibile con il processo ma ancora lontano dal danno. Il valore vero naturalmente dipende dal sistema e non si sceglie per abitudine. La cosa importante è che il secondo limite non sia semplicemente un altro if dentro lo stesso programma.
Il componente più intelligente può essere un fusibile termico che costa pochissimo
Quando il guasto peggiore è il surriscaldamento, un fusibile termico montato FISICAMENTE vicino all'elemento che può diventare pericoloso ha un pregio quasi imbarazzante: non conosce il firmware, non sa cosa sia un bus I2C, non ha un clock, non gli importa se il processore si è bloccato e non può essere convinto da una variabile corrotta che 180 °C siano in realtà 35 °C. Quando raggiunge la propria temperatura di intervento apre il circuito e basta.
Non è un dispositivo da usare come regolatore e normalmente è monouso, quindi se interviene va individuata la causa e va sostituito nel modo previsto dal progetto. Ma proprio per questo rappresenta una barriera ultima molto interessante per riscaldatori, trasformatori ed apparecchi nei quali una temperatura fuori controllo può provocare danni seri. Io lo considero l'esempio perfetto di quanto poco "smart" debba essere a volte l'ULTIMA PROTEZIONE.
Stessa filosofia per la corrente: il limite hardware deve arrivare prima del software
Se piloto un motore oppure un solenoide posso misurare la corrente con uno shunt e farla leggere al micro, ma ancora una volta quella è una misura utile al controllo, non necessariamente la mia ultima barriera. Un comparatore dedicato che osserva la caduta sullo shunt e disabilita direttamente il gate driver quando supera una soglia può intervenire senza aspettare una ISR, senza sperare che l'ADC sia configurato correttamente e senza passare attraverso mezzo firmware.
Oggi molti smart high-side switch e driver di potenza integrano già limitazione di corrente, protezione da corto circuito, shutdown termico e diagnostica. Non sono immortali e non eliminano la necessità di progettare correttamente fusibili, sezioni dei conduttori e dissipazione, ma sono molto più interessanti di un transistor nudo quando il carico è importante perché possono togliere energia anche se il micro continua ostinatamente a comandare ON.
Proteggere il controllore dai disturbi che lui stesso provoca
C'è poi una forma di fail-safe che comincia ancora prima del guasto, cioè evitare che il carico provochi il blocco del controllore. Relè, contattori, elettrovalvole, motori e trasformatori sono bravissimi a restituire al circuito disturbi proprio nel momento della commutazione, quindi diodo di flyback quando appropriato, TVS, snubber RC, varistori, corretta separazione delle masse, percorsi di ritorno studiati e disaccoppiamento serio non sono rifiniture da aggiungere quando la scheda funziona già.
Se la bobina del relè mi resetta il processore ogni cinquanta commutazioni non posso risolvere il problema dicendo "tanto c'è il watchdog". Il watchdog può aiutare a recuperare dopo l'evento, ma il mio primo lavoro è impedire che quell'evento entri nel dominio logico oppure che la sua energia finisca dove non deve.
La stessa cosa vale per il brown-out. Una tensione che scende lentamente oppure oscilla vicino al limite operativo può mettere un microcontrollore in condizioni decisamente meno pulite di un reset netto. Per questo uso volentieri BOR (Brown-Out Reset) e supervisori di tensione con soglie adatte, perché un sistema che non ha abbastanza alimentazione per funzionare correttamente deve RESTARE IN RESET, non tentare eroicamente di comandare un MOSFET mentre VCC collassa.
Occhio ad SCR e TRIAC, perché "ho tolto il gate" non significa sempre "è spento"
Quando nel finale compaiono SCR oppure TRIAC bisogna ricordarsi che non si comportano come un normale transistor comandato staticamente. Un SCR, una volta innescato, può rimanere in conduzione anche se il gate non riceve più comando e si spegne soltanto quando la corrente scende sotto la corrente di mantenimento; su una linea AC questo avviene normalmente al passaggio per lo zero, mentre in DC può significare che togliere il segnale di gate NON BASTA.
Quindi la filosofia dinamica resta valida per impedire nuovi inneschi, ma la scelta del dispositivo e del circuito deve garantire che esista realmente un meccanismo per togliere energia al carico nel tempo richiesto. È uno di quei casi nei quali il concetto corretto può diventare pericoloso se viene copiato senza guardare come funziona fisicamente il finale.
Un relè può restare incollato anche se tutta l'elettronica ha fatto il proprio dovere
Supponiamo che microcontrollore, watchdog esterno, charge pump ed alimentazione funzionino perfettamente e decidano tutti di spegnere. Se il contatto del relè si è saldato per un arco oppure per una sovracorrente, il carico può restare alimentato lo stesso. Questo è il motivo per cui nei sistemi di sicurezza veri si usano ridondanza, monitoraggio e relè con contatti a guida forzata quando l'applicazione lo richiede.
Un contatto a guida forzata non possiede poteri magici e non stacca da solo un contatto saldato. La sua utilità è permettere ad un altro circuito di RILEVARE in maniera affidabile che lo stato meccanico non è quello previsto. Per ottenere una funzione di sicurezza bisogna quindi inserirlo dentro un'architettura con ridondanza e controllo, per esempio due elementi di interruzione in serie ed una verifica che impedisca il riavvio se uno dei due non è realmente tornato nello stato previsto.
Questa è anche una buona lezione generale: fail-safe non significa scegliere un componente etichettato "safety". Significa progettare il PERCORSO DEL GUASTO.
Due interruttori in serie battono spesso un interruttore molto intelligente
Per alcuni carichi critici preferisco che ci siano due modi fisicamente distinti di interrompere la corrente. Posso avere il relè principale comandato dal processo ed un secondo contattore oppure MOSFET di safing comandato dalla catena di sicurezza, in serie al primeiro. Il firmware normale può chiedere di accendere e spegnere quanto vuole, ma se viene meno l'heartbeat oppure scatta il limite indipendente, il secondo percorso apre comunque.
Naturalmente bisogna stare attenti ai guasti comuni. Due transistor identici pilotati dallo stesso segnale, alimentati dallo stesso regolatore e posizionati nello stesso punto bollente non costituiscono automaticamente una grande ridondanza. Più le due catene condividono la stessa causa di guasto e meno quella ridondanza vale.
E-stop, finecorsa e interlock: se possono togliere energia da soli, meglio
Un altro trucco che ho sempre trovato sano è evitare che un consenso di sicurezza venga trasformato prima in un'informazione software e soltanto DOPO in un'azione. Se un finecorsa deve impedire fisicamente ad un attuatore di oltrepassare un punto pericoloso, quando possibile gli do anche una funzione hardware nella catena di enable. Il micro può leggerlo per sapere che cosa è successo, ma la sua capacità di fermare il movimento non dipende soltanto dal fatto che il firmware abbia letto correttamente quell'ingresso.
Lo stesso ragionamento vale per un arresto di emergenza in un sistema che lo richiede. Non mando semplicemente il pulsante ad un GPIO e poi aspetto che una funzione C decida di spegnere il motore. La catena destinata alla sicurezza deve essere progettata secondo il livello di rischio reale e, nei macchinari, secondo le norme applicabili, usando componenti ed architetture adatti. Il micro può conoscere lo stato dell'E-stop, ma non dovrebbe essere l'unico elemento che gli concede il diritto di funzionare.
Il fail-safe migliore parte già dal reset
Uno dei problemi più banali nasce nei primi millisecondi di vita della scheda. Durante il reset molti GPIO sono ingressi ad alta impedenza e, se il gate di un MOSFET oppure la base di un transistor viene lasciata fluttuante, il carico può fare esattamente ciò che non volevamo mentre il firmware non è ancora partito.
Per هذا considero quasi obbligatorio definire hardware lo stato di riposo di ogni finale importante. Una resistenza sul gate, sulla base oppure sull'enable deve imporre OFF quando il pin del micro non sta pilotando nulla. Il firmware successivamente deve guadagnarsi il diritto di abilitare l'uscita soltanto dopo inizializzazione, autodiagnostica e verifica dei consensi.
Io preferisco pensarlo così: ALL'ACCENSIONE IL SISTEMA NON È ANCORA SANO, deve dimostrare di esserlo.
Il firmware deve guadagnarsi anche il kick del watchdog
C'è poi un errore software che vanifica parecchi watchdog: mettere il refresh in un timer interrupt che continua a girare anche quando il programma principale è morto. In quel caso il processore può essere completamente inutile e continuare comunque a raccontare al watchdog che va tutto benissimo.
Il kick dovrebbe invece dipendere dall'avvenuto completamento delle attività realmente importanti. Posso far sì che più task dichiarino di avere completato il proprio ciclo e soltanto quando tutti i segnali sono coerenti venga aggiornato il watchdog. Con un window watchdog aggiungo anche il controllo temporale, evitando che un loop troppo rapido venga scambiato per salute. Ma rimane comunque una protezione software-hardware dentro la stessa macchina, quindi per i carichi pericolosi continuo a voler vedere un percorso di spegnimento esterno.
Una protezione deve poter essere provata
Questo è forse il trucco meno spettacolare e quello che vale di più. Se disegno una protezione che in teoria interviene quando il processore smette di generare l'onda quadra, devo poter togliere quell'onda e MISURARE quanto tempo impiega il finale a cadere. Se ho un limite di sovratemperatura indipendente devo poter simulare quella condizione. Se uso due relè devo poter verificare che il sistema rilevi il contatto incollato e rifiuti il riavvio.
Una funzione di sicurezza che non ho mai fatto scattare intenzionalmente è una promessa, non una verifica. Durante lo sviluppo provo quindi anche le cose brutte: pin fermo alto, pin fermo basso, micro in reset, clock assente, sensore scollegato, ADC fuori scala, alimentazione che scende, bobina staccata, driver in corto dove il test è realizzabile in sicurezza. Non serve distruggere la scheda per farlo, ma bisogna progettare i test fin dall'inizio.
Il mio modo di ragionare oggi non è molto diverso da allora
Riguardando quella vecchia abitudine di comandare i finali con un'onda quadra mi accorgo che non era tanto il circuito specifico ad essere importante, quanto il modo di pensare che c'era dietro: NON CONSIDERARE L'ELETTRONICA DI CONTROLLO INFALLIBILE. Se il microcontrollore è vivo deve continuare a dimostrarlo, se la temperatura supera un limite ci deve essere qualche cosa che possa intervenire senza chiedergli il permesso, se la corrente diventa assurda il driver deve potersi proteggere da solo ed infine, se tutto il resto fallisce, un fusibile oppure un dispositivo termico deve impedire che il guasto continui ad alimentarsi.
Il watchdog resta importantissimo, soprattutto se esterno ed a finestra, ma non lo considero il fail-safe per eccellenza perché il vero fail-safe è un'ARCHITETTURA. È scegliere lo stato sicuro, progettare il finale perché ci cada naturalmente, separare controllo e protezione, limitare energia e temperatura, prevedere il guasto del componente che dovrebbe spegnere ed infine provare davvero quelle condizioni, facendo in modo che pure un processore cotto non possa cuocere tutto.
Commenti
Nessun commento, per ora.
Per commentare serve un accesso. Qui siamo tutti tecnici e colleghi!
Accedi per commentare