Bearbeitbare PIC-Seriennummer in der HEX-Datei


8

Derzeit habe ich eine in meiner Firmware fest codierte Seriennummer für ein Design, mit dem ich arbeite. Die Firmware kann die Seriennummer lesen und zurückmelden. Das funktioniert gut für das, was ich brauche. Das Problem ist, dass ich bei jeder neuen Seriennummer meinen Code ändern und neu kompilieren muss. Dies ist umständlich, wenn viele Einheiten gebaut werden müssen, möglicherweise Fehler auftreten und eine rundum schlechte Praxis ist. Die Seriennummern werden mir gegeben und das Hardware-Design ist in Stein gemeißelt, sodass ich keine Hardware-Funktionen zur Serialisierung der Einheiten hinzufügen kann (EEPROM / Silicon ID Chip / Pull-Ups). Ich möchte die Seriennummer an einer festen Adresse suchen, den Code einmal kompilieren und diese Adresse dann in der kompilierten HEX-Datei für jede neue Seriennummer bearbeiten. Die Nummer wird an mehreren Stellen referenziert, daher möchte ich sie im Idealfall einmal definieren und lokalisieren. Verweisen Sie dann überall in meinem Code auf diese "Variable". Weiß jemand, wie man mit dem C18-Compiler konstante Daten an einem bestimmten adressierbaren Speicherort meiner Wahl findet? Gibt es einen besseren Weg, den jemand vorschlagen kann?


1
In etwa die Hälfte der PIC18 sind 128 Byte bis 1 KB EEPROM integriert. Ich gehe von Ihrer Frage aus, dass Ihr PIC18 einer der 50% ist, die kein EEPROM haben?
Tcrosley

Antworten:


4

Um die Frage der Bindung von Variablen an bestimmte Adressen im Flash-Speicher des PIC18 mit dem C18-Compiler zu lösen, lesen Sie bitte den Abschnitt "Pragmas" in der Datei hlpC18ug.chm im Verzeichnis doc, in dem der Compiler installiert ist.

Dazu müssen Sie einen neuen "Abschnitt" im Speicher definieren und ihn an eine Startadresse binden

#pragma romdata serial_no_section=0x1700

Dadurch wird ein neuer Abschnitt mit dem Namen "serial_no_section" erstellt, der an der Adresse 0x1700 im Flash-Speicher (Programmspeicher) beginnt (da wir "romdata" im #pragma definiert haben).

Definieren Sie Ihre Variablen direkt nach der Zeile #pragma wie folgt:

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

Jetzt haben Sie 0x12 an der Adresse 0x1700 und 0x34 an der Adresse 0x1701 im Speicher (da PIC18 das Little-Endian-Modell verwendet). Das "const rom" stellt sicher, dass der Compiler weiß, dass dies ein const-Variablentyp ist und dass die Variable im "rom" -Speicher liegt und daher über Tabellenleseanweisungen zugegriffen werden muss.

Die letzte #pragma romdataAnweisung stellt sicher, dass alle folgenden Variablendeklarationen mit Standardspeicherabschnitten verknüpft sind, wie der Linker dies für richtig hält, anstatt im Abschnitt "serial_no_section" weiterzumachen.

Jetzt kann der gesamte Code einfach auf die Variable "mySerialNumber" verweisen, und Sie wissen genau, unter welcher Adresse sich die Seriennummer im Speicher befindet.

Das Bearbeiten des HEX-Codes kann etwas schwierig sein, da Sie die Prüfsumme für jede von Ihnen bearbeitete Zeile berechnen müssen. Ich arbeite an einer C ++ - Klasse, um Intel HEX-Dateien zu dekodieren und zu kodieren, was dies einfacher machen sollte, aber es ist noch nicht fertig. Das Dekodieren von Dateien funktioniert, das erneute Kodieren ist noch nicht implementiert. Das Projekt (wenn Sie interessiert sind) ist hier https://github.com/codinghead/Intel-HEX-Class

Hoffe das hilft


4

Ich habe die Seriennummer (kurz s / n) ähnlich wie Joel beschrieben. Ich habe PIC18F4620 und CCS Compiler verwendet. Die Position von s / n im Flash-Speicher wurde auf die letzten 4 Bytes erzwungen. Da ich nur 80% von Flash verwendet habe, haben mein Compiler und Linker in den letzten 4 Bytes keinen ausführbaren Code geschrieben.

Dann hatte ich zwei alternative Möglichkeiten, um S / N tatsächlich in einzelne Einheiten zu schreiben:

  • Der CCS-In-Circuit-Debugger (ICD) verfügte über eine Funktion, mit der jeder Ort in Flash manipuliert werden konnte. Es war ein nützlicher Hack. In späteren Revisionen haben sie es leider entfernt.
  • PIC hatte eine serielle Verbindung zu einem PC. s / n wurde dadurch hochgeladen. Die Firmware hatte eine Routine, die das S / N empfing und in Flash speicherte.

Antworte auf Joels Kommentar

Ich weiß nichts über C18, aber der CCS-Compiler verfügt über Bibliotheksfunktionen write_program_eeprom(...)und read_program_eeprom(...). So sehen sie in der Montage aus.

.................... 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
Ja, genau darum bitte ich! Können Sie beschreiben, mit welchen Codeattributen Sie Ihr S / N in die letzten Flash-Bytes gepackt haben?
Joel B

"Firmware hatte eine Routine, die das S / N empfangen und in Flash speichern würde" write_program_eeprom(...)und read_program_eeprom(...). Das EEPROM und Flash sind zwei verschiedene Dinge!
m.Alin

@ m.Alin So wurden die mit CCS ccompiler gelieferten "Dosen" -Funktionen aufgerufen. Sie würden tatsächlich Flash schreiben und lesen.
Nick Alexeev

2

Ich habe das ein paar Mal gemacht. Normalerweise definiere ich einen Firmware-Infobereich an einem festen Ort im Programmspeicher und schreibe dann ein Programm, das aus der HEX-Vorlagendatei eine serialisierte HEX-Datei erstellt. Dies sind alles einfache Dinge zu tun.

In der Produktion führen Sie das Serialisierungsprogramm einmal aus, nachdem alle Tests bestanden wurden. Es erstellt die temporäre HEX-Datei mit der eindeutigen Seriennummer, die in den PIC programmiert wird, und löscht dann die temporäre HEX-Datei.

Ich würde nicht zulassen, dass der Standort verlegt werden kann, und muss ihn dann finden. Das kann jeden Build ändern, wenn der Linker Dinge bewegt. Ich habe das für sehr kleine PICs wie die 10F-Serie gemacht, bei denen diese Konstanten Teil der MOVLW-Anweisungen sind. In diesen Fällen habe ich die MAP-Datei im laufenden Betrieb gelesen, um festzustellen, wo sich diese Speicherorte befinden. Ich habe MPLINK MAP-Datei-Parsing-Code in einer Bibliothek nur für diesen Zweck.

Um etwas an einem festen Ort zu platzieren, definieren Sie ein Segment an einer festen Adresse. Der Linker platziert zuerst solche absoluten Segmente und dann die verschiebbaren um ihn herum. Vergessen Sie nicht, CODE_PACK anstelle von CODE auf einem PIC 18 zu verwenden, da Sie sonst ganze Instruktionswörter anstelle einzelner Bytes verwenden. Zum Beispiel (nur eingegeben, nicht am Assembler vorbei):

.fwinfo code_pack h'1000 '; Firmware-Infobereich an fester bekannter Adresse
         db h'FFFFFFFF '; Seriennummer, vom Produktionsprogramm ausgefüllt
         db fwtype; Typ-ID dieser Firmware
         db fwver; Versionsnummer
         db fwseq; Sequenznummer erstellen

2

Ich würde vorschlagen, die Seriennummer in einer festen Adresse zu speichern. Abhängig von Ihrem Compiler / Linker und dem betreffenden Teil gibt es einige Ansätze, die Sie verfolgen können:

  1. Definieren Sie einen verschiebbaren Abschnitt, der die Seriennummer enthält, verwenden Sie eine # Pragma-Direktive in Ihrem Code, um die Seriennummer in diesen Abschnitt zu zwingen, und erzwingen Sie die Adresse dieses Abschnitts innerhalb der Linkspezifikation.
  2. Schließen Sie für Teile, die den Codespeicher direkt lesen können, einen Speicherbereich aus dem Bereich aus, den der Linker verwenden darf (dh sagen Sie, dass der Teil z. B. vier Byte kleiner ist als er tatsächlich ist), und lesen Sie dann die Seriennummer im Code mit etwas wie `((unsigned long const *) 0x3FFC)`.
  3. Für Teile, die den Codespeicher nicht direkt lesen können, können Sie möglicherweise "RETLW" -Anweisungen an einer festen Adresse ablegen und dann den Linker davon überzeugen, dass es aufrufbare Funktionen gibt, die an diesen Adressen "Byte" zurückgeben. Dann würde man zB "out_hex (ser_byte0 ()); out_hex (ser_byte1 ()); out_hex (ser_byte2 ()) sagen, um die Bytes der Seriennummer auszugeben.

Alle PIC 18F können ihren Programmspeicher über den Tabellenlesemechanismus lesen.
Olin Lathrop

Das ist wahr. Einige der 14-Bit-Teile können auch den Programmspeicher lesen. Selbst auf PICs, die Programmspeicher lesen können, ist der retlwAnsatz jedoch oft viel schneller (bei 18-Bit-PICs dauert a callbis a retlwinsgesamt vier Zyklen; die Verwendung clrf TBLPTRU/movlw xx/movwf TBLPTRH/movlw xx/movwf TBLPTRL/tblrd *+/movf TABLAT,wwürde acht dauern).
Supercat

1

Ich würde das Gegenteil tun: Kompilieren und verknüpfen Sie den Code und finden Sie dann heraus, wo der Wert in der Linker-Datei gespeichert ist. Möglicherweise müssen Sie die Variable explizit in einem Segment suchen, das dem Flash zugeordnet ist.

Ich habe nicht danach gefragt, aber die PC-Software, die ich für meinen Wisp648-Programmierer bereitstelle, kann eine .hex-Datei lesen, einen bestimmten Speicherort ändern und die .hex-Datei zurückschreiben (in dieselbe oder eine andere Datei). Mein Programmierer muss nicht anwesend sein. Quelle ist verfügbar (in Python), Lizenz erlaubt jede Nutzung: www.voti.nl/xwisp Könnte nützlich sein, wenn Sie Ihr primäres Problem gelöst haben.


Danke @Wouter van Ooijen! Ich versuche, den Ansatz "herauszufinden, wo der Wert gespeichert ist" zu vermeiden, da dies höchstwahrscheinlich bedeutet, dass der Wert auf aufeinanderfolgende Kompilierungen verlagert wird und ich (oder ein trauriger Kerl, der hinter mir steht) verlangen muss, herauszufinden, wo der Wert liegt ist wieder lokalisiert, was sicherlich zu Problemen führt.
Joel B
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.