Errori di lettura / scrittura EEPROM su dsPIC


8

Sto eseguendo un Microchip dsPIC30F6012a. Ho questo chip su diversi PCB, tutti con lo stesso software e osservo lo stesso problema su tutti. Ciò implica un problema sistemico, non un problema di produzione unico. Il problema è anche riproducibile, il che implica che dovrei essere in grado di ucciderlo se so dove cercare. Ma ho ancora difficoltà sorprendenti nel debug dell'applicazione.

La scheda sotto test accetta 24 V, che vengono ridotti a 5 V tramite un V7805. Il chip gira sul suo oscillatore interno, con un PLL 16x, offrendo una velocità operativa di ~ 29,5 MIPS. Il codice rilevante su questa scheda è essenzialmente molto semplice: sveglia, leggi i dati dalla EEPROM, quindi inserisci un ciclo infinito. Interrompere ogni millisecondo, osservare alcuni dati ambientali e scrivere un valore aggiornato su EEPROM. Ci sono altre cose in corso, ma il problema si verifica anche se il codice non correlato viene commentato, quindi posso essere ragionevolmente certo che non è rilevante per il problema in questione.

In generale, il 95% delle volte la scheda si sveglia con il valore corretto in memoria, e continua la sua attività. L'altro 5% delle volte, tuttavia, si sveglia con un valore errato. In particolare, si sveglia con una versione capovolta dei dati che dovrebbe avere. È un lungo senza segno a quattro byte che sto guardando, e la parola superiore o inferiore del lungo può essere capovolta. Ad esempio, 10 diventa 2 ^ 16-10, che in seguito diventa 2 ^ 32-10. Riesco a riprodurre il problema tecnico attivando manualmente la potenza diverse decine di volte, ma questo non è molto coerente e il mio dito interruttore si consuma.

Al fine di riprodurre il problema in modo controllato, ho creato una seconda scheda che guida l'alimentazione a 24 V sulla scheda in prova. (Un altro dsPIC che guida un fotoaccoppiatore darlington.) La scheda del tester spegne i 24 V per 1,5 secondi (abbastanza a lungo per far scendere la guida da 5 V essenzialmente a 0 e rimanere lì per un secondo), quindi attiva i 24 V per un periodo di tempo configurabile . Con un tempo di attività di circa 520 mS, posso riprodurre questo errore EEPROM entro cinque cicli di accensione, ogni volta.

La guida a 5 V si sta comportando in modo ragionevole. Si deposita a 5 V entro 1 mS dall'accensione, con forse .4 V di superamento, supponendo che mi possa fidare del mio ambito. Allo spegnimento decade a 0 V in modo esponenziale, raggiungendo 1 V entro 50 mS. Non ho avvisi di build che sembrano rilevanti, solo variabili inutilizzate e righe mancanti alla fine dei file.

Ho provato diverse cose:

  • Abilitazione / disabilitazione della MCLR
  • Abilitazione / disabilitazione di WDT
  • Abilitazione / disabilitazione della protezione del codice
  • Abilitare / disabilitare / modificare la tensione di rilevamento del brownout
  • Abilitazione / disabilitazione / modifica del timer di accensione
  • Diverse impostazioni PLL sull'oscillatore interno principale
  • Connessione / disconnessione del mio programmatore PICkit 3
  • Aggiunta di 470 uF di capacità alla guida 5V
  • Aggiunta / rimozione di .1 uF attraverso il pullup da 4,7k sul mio pin MCLR
  • Disabilitare tutti gli interrupt nel codice e non lasciare altro che aggiornamenti EEPROM nel loop principale
  • Aggiungendo un ritardo di 1,5 secondi alla mia routine di avvio prima di iniziare a leggere EEPROM

Ho anche scritto un codice di prova separato che non fa altro che scrivere continuamente valori su EEPROM e poi rileggerli, assicurandomi che il valore non sia cambiato. Decine di migliaia di iterazioni non hanno dato errori. Tutto quello che posso concludere è che qualcosa va storto con EEPROM in lettura o scrittura, in particolare all'accensione / spegnimento.

Uso le stesse librerie EEPROM dal 2007. Ho visto anomalie occasionali, ma nulla di riproducibile. Il codice pertinente è disponibile qui:
http://srange.net/code/eeprom.c
http://srange.net/code/readEEByte.s
http://srange.net/code/eraseEEWord.s
http: / /srange.net/code/writeEEWord.s

Ho già visto errori EEPROM in altre applicazioni, ma sempre come anomalie una tantum, niente di così riproducibile o coerente.

Qualcuno ha idea di cosa sta succedendo? Sto finendo le cose da provare.


Si prega di consultare qui per un aggiornamento sulla risoluzione di questo problema: electronics.stackexchange.com/questions/38083/…
Stephen Collings

Risposte:


3

Mi vengono in mente due cose:

Innanzitutto, secondo la scheda tecnica, un ciclo di cancellazione-scrittura richiede almeno 0,8 ms e fino a 2,6 ms. Dici di avere un interrupt ogni 1 ms, che può portare a un'operazione di scrittura. Ho visto nel codice che disabiliti gli interrupt per le parti della cancellazione e per le parti della funzione di scrittura. Ma potresti comunque ottenere un'interlacciatura divertente delle chiamate di funzione. Forse aiuta quando disabiliti gli interrupt per l'intera sequenza di cancellazione e scrittura?

Secondo: potresti voler scrivere mentre l'alimentazione si interrompe e la scrittura EEPROM avviene esattamente nel momento in cui la tensione di alimentazione scende al di sotto della tensione operativa. Puoi provare a monitorare la tensione di alimentazione e rifiutare una scrittura quando è sotto, diciamo, 4.5V. Ciò presuppone che rimanga abbastanza a lungo sopra i 2,7 V come minima tensione operativa e che il rilevamento del black out sia impostato per innescarsi solo al di sotto di quel punto.


Sei vicino! Il ciclo è cancella-> scrivi, quindi se lo spegnimento avviene tra cancella e scrivi, perdi i tuoi dati. La mia prima soluzione è stata quella di dividere la EEPROM in più copie ridondanti, che vengono automaticamente verificate incoerenze. Ma dal momento che ho mangiato 3/4 della mia EEPROM, lo sto sostituendo con un semplice buffer di scrittura. Il buffer sarà un blocco EEPROM speciale che contiene i dati da scrivere, l'indirizzo in cui scrivere e un flag che indica che la scrittura non è ancora completa. Questo dovrebbe affrontare il problema occupando molto meno spazio.
Stephen Collings,

Ora posso confermare che il mio approccio basato su buffer funziona e non subisce la perdita di dati a causa dello spegnimento asincrono tra cancellazione e scrittura.
Stephen Collings,

5

Hai esaminato molti possibili problemi hardware. Va bene, ma molto probabilmente è un bug del firmware.

Sfortunatamente, il tuo codice sorgente è scarsamente documentato ed è formattato per essere difficile da seguire visivamente. Il tuo primo file contiene in alto la dichiarazione delle routine esterne:

void readEEByte (unsigned int, unsigned int, void *);
void eraseEEWord (unsigned int, unsigned int);
void writeEEWord (unsigned int, unsigned int, void *);

Non solo è una cattiva idea mettere dichiarazioni come questa private nei moduli client, ma non c'è un solo commento in vista! Possiamo solo indovinare cosa intendi fare da queste routine dal loro nome e gli argomenti call non sono completamente documentati. Inoltre in quel file hai varie linee che iniziano con "//" e un'intera linea di segni uguali. Questi aggiungono disordine visivo che rende troppo difficile provare a seguire il codice.

Si può dire che nulla di tutto ciò è importante per il funzionamento del codice. Tuttavia, le cattive pratiche di programmazione come questa sono molto importanti. Esse causano una cattiva scrittura del codice e rendono difficile individuare i bug o persino ciò che il codice dovrebbe fare. Tutto ciò si traduce in agguato difficile da trovare problemi, come stai scoprendo. Hai anche detto di aver visto occasionalmente anomalie da questo codice dal 2007. Questo avrebbe dovuto essere un indizio forte di un bug, forse anche di un cattivo design complessivo.

Correggi il disordine, documenta correttamente tutte le interfacce e metti le dichiarazioni comuni nei file include che scrivi una volta, quindi fai riferimento quando necessario. Inoltre, la tua affermazione di non avere avvisi di costruzione che sembrano rilevanti è un'enorme bandiera rossa. Ancora una volta, risolvi il pasticcio. Durante il debug, segui sempre prima i problemi facilmente riproducibili e risolvibili. A volte quelli sono in realtà la causa dei problemi difficili, o a volte nel risolverli si scopre la causa di altri problemi. Il compilatore ti avverte della sciattezza su un piatto d'argento. Che cosa vuoi di più? Non dovresti avere variabili inutilizzate perché causano confusione a chiunque cerchi di dare un senso al tuo codice e non ci sono scuse per perdere nuove righe. Ancora una volta, risolvi gli ovvi problemi, soprattutto prima di chiedere a qualcun altro di guardare il tuo codice.

La pulizia e l'attenzione ai dettagli contano . Un sacco.

 


Hai ragione sul codice. Solo così siamo chiari, ho iniziato a usare questo codice cinque anni fa, ma qualcun altro lo ha scritto. Non scrivo cose che sembrano così. Dovrei ancora aggiustarlo, e non è un bene che non l'abbia fatto. Solo così non sembro QUITE così grande un goofball. :-)
Stephen Collings,

2
L'accesso alla EEPROM interna è semplice. Per cose così semplici, è più facile scrivere il proprio codice che cercare di capire come funziona il bugware di qualcun altro, quindi correggerlo fino a quando sembra funzionare. Leggi la scheda tecnica e scrivi il codice. Avresti finito tra un'ora.
Olin Lathrop,

Sono d'accordo con Olin qui che è molto probabilmente il firmware. La parte errata menziona nulla di sospetto con la EEPROM.
Adam Lawrence,

2
@Madmad - I fogli Errata potrebbero non dire che c'è qualcosa di sospetto nella parte, ma non diranno mai che non c'è niente di
sospetto

1
@stevenvh I miei rapporti con Microchip e le loro FAE sono stati per lo più positivi. Gli errata per le parti che ho usato sono stati accurati e sono intervenuti per aiutarci con i problemi, trovando spesso soluzioni alternative per noi.
Adam Lawrence,

0

Ho avuto un comportamento identico con 4 pezzi di dsPIC30F6014A (di circa 10 utilizzati negli ultimi mesi ..), l'unico modo per evitare la sporadica corruzione dei dati durante lo spegnimento è di azzerare l'MCLR appena prima dell'arresto.

Ovviamente questo non è fattibile in pratica, quindi ho optato per la sostituzione del "cattivo" dsPIC, se invece qualcuno ha un'altra soluzione ...


3
Perché non sarebbe fattibile? Il rilevamento delle interruzioni di corrente viene eseguito molto, anche per il salvataggio dei dati in EEPROM negli ultimi ms.
Stevenvh,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.