HEXファイルの編集可能なPICシリアル番号


8

現在、使用しているデザインのシリアル番号がファームウェアにハードコードされています。ファームウェアはシリアル番号を読み取って報告できます。それは私が必要とするもののためにうまく働きます。問題は、新しいシリアル番号ごとにコードを変更して再コンパイルする必要があることです。これは、構築するユニットが多数ある場合に扱いにくく、エラーが発生する可能性があり、万能の悪い習慣です。シリアル番号が私に与えられ、ハードウェア設計がしっかりと決められているので、ハードウェアに機能を追加してユニットをシリアル化することはできません(EEPROM /シリコンIDチップ/プルアップ)。私がやりたいことは、シリアル番号を固定アドレスに配置し、コードを1回コンパイルしてから、コンパイルされたHEXファイルで新しいシリアル番号ごとにそのアドレスを編集することです。番号はいくつかの場所で参照されているので、理想的には、一度定義して特定したいのですが、次に、コード内の他の場所でその「変数」を参照します。C18コンパイラを使用して、選択した特定のアドレス指定可能なメモリ位置に定数データを配置する方法を知っている人はいますか?誰もが提案できるより良い方法はありますか?


1
PIC18の約半分には、128バイトから1KのEEPROMが組み込まれています。あなたの質問から、あなたのPIC18はEEPROMを持たない50%の1つだと思いますか?
tcrosley

回答:


4

特に、C18コンパイラを使用してPIC18のフラッシュメモリの特定のアドレスに変数をバインドする問題を解決するには、コンパイラがインストールされているdocディレクトリのhlpC18ug.chmにある「プラグマ」セクションを参照してください。

これを行うには、メモリに新しい「セクション」を定義し、それを開始アドレスにバインドする必要があります。

#pragma romdata serial_no_section=0x1700

これにより、フラッシュ(プログラム)メモリのアドレス0x1700から始まる「serial_no_section」という新しいセクションが作成されます(#pragmaで「romdata」を定義したため)。

#pragma行の直後に、変数を次のように定義します。

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

これで、メモリのアドレス0x1700に0x12、アドレス0x1701に0x34ができました(PIC18はリトルエンディアンモデルを使用しているため)。"const rom"は、これがconst変数型であること、および変数が "rom"メモリーにあるため、テーブル読み取り命令を介してアクセスする必要があることをコンパイラーに認識させます。

最後の#pragma romdataステートメントは、リンカが「serial_no_section」セクションをたどるのではなく、適切と見なすように、次の変数宣言がデフォルトのメモリセクションにリンクされるようにします。

これで、すべてのコードが変数「mySerialNumber」を参照するだけで、シリアル番号がメモリ内で見つかるアドレスが正確にわかります。

HEXコードの編集は、編集する各行のチェックサムを計算する必要があるため、少し難しい場合があります。私はこれをより簡単にするはずのIntel HEXファイルをデコードおよびエンコードするC ++クラスに取り組んでいますが、まだ完成していません。ファイルのデコードは機能しますが、エンコードはまだ実装されていません。プロジェクト(興味がある場合)はこちらhttps://github.com/codinghead/Intel-HEX-Class

お役に立てれば


4

Joelの説明と同様の方法でシリアル番号(略してs / n)を作成しました。PIC18F4620とCCSコンパイラを使用していました。フラッシュメモリ内のs / nの場所は、最後の4バイトに強制されました。フラッシュの80%しか使用していなかったので、コンパイラーとリンカーは最後の4バイトに実行可能コードを書きませんでした。

次に、実際にs / nを個々のユニットに書き込むための2つの代替方法がありました。

  • CCSインサーキットデバッガー(ICD)には、Flash内の任意の場所を操作できる機能がありました。それは便利なハックでした。後のリビジョンでは、残念ながらそれを削除しました。
  • PICにはPCへのシリアルリンクがありました。s / nはそれを通じてアップロードされました。ファームウェアには、s / nを受信して​​フラッシュに保存するルーチンがありました。

Joelさんのコメントに返信

C18については知りませんが、CCSコンパイラにはライブラリ関数write_program_eeprom(...)とが付属していますread_program_eeprom(...)。以下は、アセンブリでの外観です。

.................... 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 / Nをパックするために使用したコード属性を説明できますか?
ジョエルB

「ファームウェアには、s / nを受け取ってフラッシュに保存するルーチンがありました」write_program_eeprom(...)read_program_eeprom(...)。EEPROMとフラッシュは2つの異なるものです!
m.Alin

@ m.Alinこれが、CCS ccompilerに付属する「缶詰」関数が呼び出された方法です。彼らは実際にフラッシュを読み書きします。
Nick Alexeev

2

私はこれを数回行いました。通常、プログラムメモリの固定位置にファームウェア情報領域を定義し、テンプレートHEXファイルからシリアル化されたHEXファイルを作成するプログラムを記述します。これらはすべて簡単に行うことができます。

本番環境では、すべてのテストに合格した後、シリアル化プログラムを1回実行します。PICにプログラムされる一意のシリアル番号を持つ一時HEXファイルを作成し、一時HEXファイルを削除します。

その場所を再配置可能にしないで、それを見つける必要があります。リンカが物事を移動するので、それはすべてのビルドを変えることができます。私は、これらの定数がMOVLW命令の一部である10Fシリーズのような非常に小さなPICに対してそれを行いました。それらの場合、それらの場所がどこにあるかを決定するために、その場でMAPファイルを読み取らせます。そのために、ライブラリにMPLINK MAPファイル解析コードがあります。

固定位置に何かを配置するには、固定アドレスでセグメントを定義します。リンカは、そのような絶対セグメントを最初に配置し、次にその周りに再配置可能なセグメントを配置します。PIC 18でCODEの代わりにCODE_PACKを使用することを忘れないでください。そうしないと、個々のバイトの代わりに命令語全体を処理することになります。たとえば、次のように入力しただけです。

.fwinfo code_pack h'1000 ';既知の固定アドレスのファームウェア情報領域
         db h'FFFFFFFF ';製造番号によって入力されたシリアル番号
         db fwtype;このファームウェアのタイプID
         db fwver;バージョン番号
         db fwseq;ビルドシーケンス番号

2

シリアル番号を固定アドレスに保存することをお勧めします。コンパイラ/リンカーと問題の部分に応じて、いくつかのアプローチを取ることができます:

  1. シリアル番号を含む再配置可能セクションを定義し、コードで#pragmaディレクティブを使用してシリアル番号をそのセクションに強制し、リンク仕様内でそのセクションのアドレスを強制します。
  2. コードメモリを直接読み取ることができるパーツの場合、リンカが使用を許可されているエリアからメモリのエリアを除外し(つまり、パーツが実際よりも4バイト小さいなどと伝えて)、コードを使用してシリアル番号を読み取ります`((unsigned long const *)0x3FFC)`のように。
  3. コードメモリを直接読み取ることができないパーツの場合、固定アドレスに「RETLW」命令を配置して、それらのアドレスに「バイト」を返す呼び出し可能な関数があることをリンカに納得させることができます。次に、「out_hex(ser_byte0()); out_hex(ser_byte1()); out_hex(ser_byte2());と言って、シリアル番号のバイトを出力します。

すべてのPIC 18Fは、テーブル読み取りメカニズムを介してプログラムメモリを読み取ることができます。
Olin Lathrop、2012

それは本当です。14ビットパーツの一部は、プログラムメモリも読み取ることができます。ただし、プログラムメモリを読み取ることができるPICでも、retlwアプローチははるかに高速です(18ビットPICでは、a callからa retlwまでに合計4サイクルかかり、使用clrf TBLPTRU/movlw xx/movwf TBLPTRH/movlw xx/movwf TBLPTRL/tblrd *+/movf TABLAT,wすると8 サイクルかかります)。
supercat

1

私は反対のことをします。コードをコンパイルしてリンクし、値がリンカーファイルから格納されている場所を見つけます。フラッシュにマップされているセグメントで変数を明示的に配置する必要がある場合があります。

これを要求しませんでしたが、私のWisp648プログラマーに提供するPCソフトウェアには、.hexファイルを読み取り、特定の場所を変更し、.hexファイルを(同じまたは別のファイルに)書き戻す機能があります。プログラマーを同席させる必要はありません。ソースが利用可能(Pythonで)、ライセンスはすべての使用を許可します。


@Wouter van Ooijenに感謝します!「値が格納されている場所を見つける」アプローチを回避しようとしています。これは、値が連続したコンパイルで再配置され、私(または私の後ろにいる悲しい仲間)が値の場所を見つける必要があるためです。再び配置され、確実に問題が発生します。
Joel B
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.