Lo stato predefinito della memoria non utilizzata

4

In un dispositivo incorporato, durante l'inizializzazione delle posizioni di memoria, c'è qualche convenzione che viene praticata.

Voglio dire, ad esempio, impostare ogni byte su zero o 0xFF o qualsiasi altro valore.

    
posta Shamim Hafiz 01.03.2011 - 12:27
fonte

5 risposte

2

I moderni dispositivi embedded hanno spesso (almeno) 3 tipi di memoria. Se sei responsabile del codice di avvio, potresti prendere in considerazione di fare qualcosa del genere:

RAM: Al momento dell'avvio (all'accensione e anche in caso di timeout del watchdog), avvio tipico codice (" crt0 ") azzererà tutta la RAM, quindi copierà un blocco di dati (il segmento dati) dalla memoria del programma alla RAM, quindi chiamerà main() . Questo è il modo più semplice per conformarsi ai requisiti C per le variabili inizializzate (statiche e globali), il ".bss segment" e il ".data segment", senza sprecare memoria flash su variabili inizializzate su tutti zeri. I programmatori di linguaggio assembly spesso scrivono due loop nel loro codice per farlo all'inizio del programma; la maggior parte degli altri programmatori non scrive alcun codice specifico per fare ciò, invece dipende dal runtime " crt0 " che tipicamente fa questo per loro prima che la loro prima riga di codice venga eseguita.

Questo non significa che un valore non inizializzato (heap o stack) sarà zero. Se si assume che sia zero, può sembrare che funzioni la prima volta, ma dopo che il programma è stato eseguito per un po 'e riutilizzato l'heap e lo stack alcune volte, probabilmente non sarà più zero , che porta a errori intermittenti e difficili da correggere.

Come sottolineato dall'autocrazia, molti strumenti di debug impostano la RAM non inizializzata su qualche altro valore magico, per rilevare più rapidamente questo errore "erroneamente assunto che fosse zero" e altri bug.

Alcuni programmi bit-flip tolleranti al soft-error reinizializzano la RAM dalla ROM il più spesso possibile - non esiste un codice di "inizializzazione", tutte le cose di inizializzazione avvengono all'interno del ciclo principale. Il puntatore dello stack viene inizializzato nuovamente all'inizio della pila RAM all'inizio di ogni passaggio attraverso il ciclo principale, i registri della velocità di trasmissione vengono reimpostati per fornire 9600 bps per ciascun passaggio attraverso il ciclo principale, l'ora e il giorno completi viene letto dall'RTCC una volta al secondo anche se sei quasi sicuro che è ancora mercoledì, ecc.

Memoria dati Flash: Un programma che scrive nuovi dati in un blocco di memoria flash deve prima cancellare l'intero blocco. La cancellazione di un blocco richiede in genere ordini di grandezza più lunghi rispetto alla lettura di un blocco di dati dal flash. Immediatamente dopo la cancellazione, il valore di tali posizioni di memoria "vuote" è - per nessuna buona ragione di cui sono a conoscenza - il modello all-ones 0xFF. La convenzione comune è di lasciare blocchi non utilizzati come quel modello 0xFF, e per immediatamente "pre-cancellare" i blocchi di dati non appena sono più necessari per quel modello 0xFF, in modo che più tardi, quando abbiamo bisogno di memorizzare i dati in quel blocco, possiamo immediatamente scrivere i dati (o almeno abbiamo solo bisogno attendere il tempo rimanente per la cancellazione)

Memoria di programma (spesso in ROM o memoria flash): Al momento dell'avvio, la CPU avvierà l'esecuzione del codice di avvio (" crt0 ") nella memoria del programma. Quando si masterizza un nuovo programma nella memoria del programma, molti toolchain cancelleranno il vecchio programma e lasceranno la memoria non utilizzata dal nuovo programma nello stato 0xGR non programmato. Come sottolineato da JThompson, altre toolchain più tolleranti agli errori useranno le programmazione di immunità consapevole , riempiendo tutta la memoria di programma inutilizzata ( nel caso in cui il contatore del programma in qualche modo si corrompe e punti in quella memoria inutilizzata) con salti al vettore di reset o una slitta di nop che alla fine va al vettore di reset.

    
risposta data 03.03.2011 - 02:10
fonte
6

La risposta è: dipende.

Se si programma in C, la definizione del linguaggio afferma che le variabili solo statiche non inizializzate verranno impostate su 0 all'avvio del programma. Se si osserva il tipico sistema di runtime fornito dai produttori di compilatori incorporati, la maggior parte include o alcuni o tutti i codici sorgente, e si può vedere l'azzeramento esplicito della sezione utilizzata per le variabili non const.

Le variabili dichiarate const sono solitamente collocate in una sezione di memoria separata, frequentemente ROM o flash EPROM. E le variabili inizializzate hanno i valori iniziali raccolti in un blocco di ROM o Flash, e all'avvio del programma questo blocco viene copiato nella sezione ram per "variabili inizializzate".

Se si programma in altre lingue, il comportamento dipende dalla lingua e dal comportamento di avvio del tempo di esecuzione.

Se si considera un micro embedded con periferiche, ad esempio UART o blocchi Capture, questi avranno sempre una definizione di avvio fornita dal produttore di chip. Tuttavia la mia regola d'oro è di non fare mai affidamento su questo. Se si desidera inizializzare una periferica in uno stato particolare, quindi inizializzarla. Ogni bit di ogni registro, se pensi che sia necessario o meno. In questo modo hai sempre il controllo dello stato del dispositivo. [Sai come a volte un dispositivo PC si trasforma in schifo, ad esempio USB non funzionerà ... e dopo un riavvio non funzionerà ancora. Ma dopo un ciclo di alimentazione lo fa. Beh, indovina un po '. Qualcuno ha fatto un'ipotesi nel driver e non ha inizializzato ogni bit di ogni registro. Bad!]

In realtà, ho alcune regole d'oro per la programmazione dei dispositivi embedded. Ce ne sono altri, ma questi sono quelli sull'inizializzazione, l'avvio e l'esecuzione.

  1. Non assumere mai nulla. Inizializza tutte le tue periferiche (come sopra).

  2. In ogni unità di codice, dispone di funzioni "init" e "shutdown" esplicite esportate - ANCHE SE QUESTE SONO VUOTE. Puoi aggiungere cose senza modifiche altrove, nel caso avessi bisogno di più tardi.

  3. In ogni unità di codice, la funzione "init" inizializza TUTTE le variabili locali dell'unità (cioè le statiche dichiarate in quell'unità e non viste da alcuna altra unità), INCLUSA l'impostazione a 0 quelle che dovrebbero iniziare impostate su 0 Ciò significa che non ti affidi alle impostazioni di run-time su 0. Se lo vuoi 0, impostalo 0. [Una volta ho usato un compilatore non conforme che non inizializza ... il ragazzo era un'esperienza di apprendimento .]

  4. Separa i dispositivi e il comportamento del dispositivo il più lontano possibile nei livelli di astrazione hardware che scrivi (anche questi sono solo macro che usano qualcosa fornito dal venditore). Se è necessario modificare la piattaforma hardware in un secondo momento, ciò ridurrà il tempo di migrazione a circa il 20% di ciò che potrebbe essere altrimenti. Questo non è sempre possibile, ma vale la pena provarlo.

  5. Rendi il programma principale piccolo - dovrebbe semplicemente chiamare le funzioni init in OGNI unità di codice, e quindi eseguire il ciclo per sempre elaborando il "loop principale". Puoi quindi utilizzare flag o altre cose nascoste all'interno delle API per far sì che gli eventi si verifichino, e i timer e il comportamento a tempo diventano facili - se il ciclo principale viene eseguito da un timer maggiore (basato su interrupt) che scatta ad intervalli regolari (ad esempio, 2, 5 , 10, 12, 16, 20 millisecondi - sono tutti comuni) quindi gli eventi basati sul tempo sono facili e i ritardi sono solo contatori del conto alla rovescia che risolvono i multipli dell'intervallo dell'anello principale. Il tuo programma principale dovrebbe essere da qualche parte nella regione 50 - 200 linee di codice, massimo

Spero che questo aiuti. Dillo così se vuoi qualche pratica in più che renda i dispositivi embedded robusti.

    
risposta data 01.03.2011 - 13:47
fonte
2

Cosa fare con la memoria non utilizzata può anche dipendere dall'uso previsto. Per i software critici per la sicurezza, è comune riempire la memoria inutilizzata con comandi che costringono il sistema a uno stato sicuro. Come esempio rudimentale, il software che controlla un forno potrebbe avere tutte le posizioni di memoria inutilizzate piene di comandi di salto che salgono a una funzione di stato di sicurezza che garantirebbe che il forno sia spento. In questo modo, se il contatore del programma viene inavvertitamente danneggiato (danneggiando quelle fastidiose macchie solari!), Potresti almeno aumentare le possibilità di gestirlo in sicurezza.

    
risposta data 01.03.2011 - 23:23
fonte
0

Non farei ipotesi. Probabilmente dipende dall'hardware e dal sistema operativo.

    
risposta data 01.03.2011 - 13:18
fonte
0

link

Quindi, non tanto standardizzati ... Aspettiamo che potrebbe esserci QUALCHE COSA se non l'avessi impostato da solo.

    
risposta data 01.03.2011 - 18:18
fonte