Numero di serie PIC modificabile nel file HEX


8

Attualmente ho un numero seriale hardcoded nel mio firmware per un design con cui sto lavorando. Il firmware può leggere e riportare il numero seriale. Funziona bene per quello che mi serve. Il problema è che ogni nuovo numero seriale mi richiede di modificare il mio codice e ricompilare. Questo è ingombrante quando ci sono molte unità da costruire, ha forse il rischio di introdurre errori ed è una cattiva pratica a tutto tondo. I numeri di serie mi vengono forniti e il design dell'hardware è impostato su pietra, quindi non posso aggiungere alcuna funzionalità nell'hardware per serializzare le unità (EEPROM / Silicon ID Chip / Pull-Ups). Quello che vorrei fare è individuare il numero seriale a un indirizzo fisso, compilare il codice una volta, quindi modificare quell'indirizzo nel file HEX compilato per ogni nuovo numero seriale. Il numero viene referenziato in diversi punti, quindi idealmente, voglio definirlo e localizzarlo una volta, quindi fare riferimento a quella "variabile" in qualsiasi altra parte del mio codice. Qualcuno sa come individuare dati costanti in una specifica posizione di memoria indirizzabile di mia scelta, utilizzando il compilatore C18? C'è un modo migliore che qualcuno può suggerire?


1
Circa la metà dei PIC18 ha incorporato da 128 byte a 1K di EEPROM. Presumo dalla tua domanda che il tuo PIC18 sia uno del 50% che non ha EEPROM?
Tcrosley,

Risposte:


4

In particolare per risolvere la questione delle variabili vincolanti a indirizzi specifici nella memoria flash sul PIC18 con il compilatore C18, fare riferimento alla sezione "Pragmi" in hlpC18ug.chm nella directory doc in cui è installato il compilatore.

Per fare questo è necessario definire una nuova "sezione" in memoria e associarla a un indirizzo iniziale così

#pragma romdata serial_no_section=0x1700

Questo crea una nuova sezione chiamata "serial_no_section" che inizia all'indirizzo 0x1700 nella memoria flash (programma) (perché abbiamo definito "romdata" nel #pragma).

Direttamente dopo la riga #pragma, definisci le variabili in modo che:

#pragma romdata serial_no_section=0x1700
const rom int mySerialNumber = 0x1234;
#pragma romdata

Ora hai 0x12 all'indirizzo 0x1700 e 0x34 all'indirizzo 0x1701 in memoria (perché PIC18 utilizza il modello little-endian). La "const rom" assicura che il compilatore sappia che si tratta di un tipo di variabile const e che la variabile si trova nella memoria "rom" e pertanto è necessario accedervi tramite le istruzioni di lettura della tabella.

L' #pragma romdataistruzione finale garantisce che tutte le seguenti dichiarazioni di variabili siano collegate alle sezioni di memoria predefinite quando il linker ritiene opportuno anziché seguire nella sezione "serial_no_section".

Ora tutto il codice può semplicemente fare riferimento alla variabile "mySerialNumber" e sai esattamente a quale indirizzo è possibile trovare il numero seriale in memoria.

La modifica del codice HEX può essere un po 'impegnativa in quanto è necessario calcolare il checksum per ogni riga modificata. Sto lavorando su una classe C ++ per decodificare e codificare i file Intel HEX che dovrebbero renderlo più semplice, ma non è ancora finito. La decodifica dei file funziona, la codifica di nuovo non è ancora implementata. Il progetto (se sei interessato) è qui https://github.com/codinghead/Intel-HEX-Class

Spero che sia di aiuto


4

Ho fatto il numero seriale (abbreviato in s) in un modo simile a quello che Joel sta descrivendo. Stavo usando il compilatore PIC18F4620 e CCS. La posizione di s / n nella memoria Flash è stata forzata agli ultimi 4 byte. Dato che stavo usando solo l'80% di Flash, il mio compilatore e linker non scrivevano codice eseguibile negli ultimi 4 byte.

Poi ho avuto 2 modi alternativi per scrivere effettivamente s / n in singole unità:

  • Il debugger in-circuit CCS (ICD) aveva una funzione che permetteva di manipolare qualsiasi posizione all'interno di Flash. È stato un trucco utile. Nelle revisioni successive lo hanno rimosso, sfortunatamente.
  • PIC aveva un collegamento seriale a un PC. s / n è stato caricato tramite esso. Il firmware aveva una routine che riceveva l's / n e lo memorizzava in Flash.

Rispondi al commento di Joel

Non so di C18, ma il compilatore CCS viene fornito con funzioni di libreria write_program_eeprom(...)e read_program_eeprom(...). Ecco come si presentano in assemblea.

.................... write_program_eeprom (i_ADDR, iWord);
EF84: BSF FD0.6
EF86: CLRF FF8
EF88: MOVLW 7F
EF8A: MOVWF FF7
EF8C: MOVLW F0
EF8E: MOVWF FF6
EF90: MOVLB 0
EF92: BRA EF24
EF94: MOVLW F0
EF96: MOVWF FF6
EF98: MOVFF 490, FF5
EF9C: TBLWT * +
EF9E: MOVFF 491, FF5
EFA2: TBLWT *
EFA4: BCF FA6.6
EFA6: BSF FA6.4
EFA8: RCALL EF3C
EFAA: RCALL EF3C
EFAC: CLRF FF8
EFAE: CLRF FF8
.................... iWord = read_program_eeprom (i_ADDR); 
EF60: CLRF FF8
EF62: MOVLW 7F
EF64: MOVWF FF7
EF66: MOVLW F0
EF68: MOVWF FF6
EF6A: TBLRD * +
EF6C: MOVF FF5, W
EF6E: TBLRD *
EF70: MOVFF FF5,03
EF74: CLRF FF8
EF76: MOVLB 4
EF78: MOVWF x90
EF7A: MOVFF 03.491

1
Sì, questo è esattamente quello che sto chiedendo! Puoi descrivere quali attributi di codice hai usato per impacchettare il tuo codice S / N negli ultimi byte di flash?
Gioele B

"Il firmware aveva una routine che riceveva l's / n e lo memorizzava in Flash" write_program_eeprom(...)e read_program_eeprom(...). EEPROM e Flash sono due cose diverse!
m.,

@ m.Alin Ecco come venivano chiamate le funzioni "in scatola" fornite con il compilatore CCS. In realtà avrebbero scritto e letto Flash.
Nick Alexeev

2

L'ho fatto alcune volte. Di solito definisco un'area di informazioni sul firmware in una posizione fissa nella memoria del programma, quindi scrivo un programma che crea un file HEX serializzato dal file HEX del modello. Queste sono tutte cose facili da fare.

In produzione, si esegue il programma di serializzazione una volta che tutti i test sono stati superati. Crea il file HEX temporaneo con il numero seriale univoco, che viene programmato nel PIC, quindi il file HEX temporaneo viene eliminato.

Non vorrei lasciare che la posizione fosse trasferibile, quindi dovevo trovarla. Ciò può cambiare ogni build mentre il linker sposta le cose. L'ho fatto per PIC molto piccoli come la serie 10F in cui queste costanti fanno parte delle istruzioni MOVLW. In quei casi ho letto il file MAP al volo per determinare dove si trovano quelle posizioni. Ho un codice MPLINK MAP che analizza il codice in una libreria solo per quello scopo.

Per mettere qualcosa in una posizione fissa, definire un segmento a un indirizzo fisso. Il linker posizionerà prima tali segmenti assoluti, quindi quelli trasferibili attorno ad esso. Non dimenticare di utilizzare CODE_PACK anziché solo CODE su un PIC 18, altrimenti avrai a che fare con parole di istruzioni complete anziché singoli byte. Ad esempio (appena digitato, non correre oltre l'assemlber):

.fwinfo code_pack h'1000 '; area informazioni firmware ad indirizzo noto fisso
         db h'FFFFFFFF '; numero di serie, compilato dal programma di produzione
         db fwtype; ID tipo di questo firmware
         db fwver; numero di versione
         db fwseq; numero di sequenza build

2

Suggerirei di memorizzare il numero seriale in un indirizzo fisso. A seconda del compilatore / linker e della parte in questione, ci sono alcuni approcci che potresti adottare:

  1. Definisci una sezione trasferibile che conterrà il numero seriale, usa una direttiva #pragma nel tuo codice per forzare il numero seriale in quella sezione e forzare l'indirizzo di quella sezione all'interno delle specifiche del link.
  2. Per le parti in grado di leggere direttamente la memoria del codice, escludere un'area di memoria dall'area che il linker è autorizzato a utilizzare (ovvero indicare che la parte è ad esempio quattro byte più piccola di quanto non sia in realtà), quindi leggere il numero seriale nel codice usando qualcosa come `((unsigned long const *) 0x3FFC)`.
  3. Per le parti che non sono in grado di leggere direttamente la memoria del codice, potresti essere in grado di inserire le istruzioni "RETLW" su un indirizzo fisso e quindi convincere il linker che esistono funzioni richiamabili che restituiscono "byte" a quegli indirizzi. Quindi si direbbe ad esempio "out_hex (ser_byte0 ()); out_hex (ser_byte1 ()); out_hex (ser_byte2 ()); per generare i byte del numero seriale.

Tutti i PIC 18F possono leggere la memoria del programma tramite il meccanismo di lettura della tabella.
Olin Lathrop,

Questo è vero. Alcune parti di 14 bit sono in grado di leggere anche la memoria del programma. Anche su PIC in grado di leggere la memoria del programma, tuttavia, l' retlwapproccio è spesso molto più veloce (su PIC a 18 bit, da calla a retlwa impiegherà quattro cicli in totale; l'utilizzo clrf TBLPTRU/movlw xx/movwf TBLPTRH/movlw xx/movwf TBLPTRL/tblrd *+/movf TABLAT,wne richiederebbe otto).
supercat

1

Farei il contrario: compilare e collegare il codice, quindi scoprire dove è memorizzato il valore dal file linker. Potrebbe essere necessario individuare esplicitamente la variabile in un segmento mappato su Flash.

Non ho chiesto questo, ma il software per PC fornito per il mio programmatore Wisp648 ha la capacità di leggere un file .hex, modificare un percorso specifico e riscrivere il file .hex (nello stesso o in un altro file). Non è necessario che il mio programmatore sia presente. La fonte è disponibile (in Python), la licenza consente tutto l'uso: www.voti.nl/xwisp Potrebbe essere utile una volta risolto il problema principale.


Grazie @Wouter van Ooijen! Sto cercando di evitare l'approccio "scopri dove è memorizzato il valore", dal momento che molto probabilmente significherà che il valore viene trasferito su compilazioni successive e richiedo a me (o qualche tipo triste che viene dietro di me) di scoprire dove il valore si trova di nuovo, introducendo sicuramente problemi.
Gioele B
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.