PICマイコンにはコンフィギュレーション・ビットあり、ハード初期設定を不揮発な記憶に残すもの。ありがたい機能ですが自分でやると設定がメンドイ。しかし、コンフィギュレーションツールMCCにお願すれば「よきに計らってくれる」っと。しかしソフトで設定値読み出そうとするとヤバイ?どうなっているの?
※『PIC三昧』PIC関係の記事総目次はこちら
※作業はMicroChip社の統合開発環境 MPLAB X IDEと、その上で走るコンフィギュレーションツールMCC Classic を使用して行っています。ターゲット・マイコンはPIC16F18855です。
※2023年12月11日追記:以下でCONFIGビットが読めないように見えたのは、MCCクラシックが提示するCONFIGの値が未実装Uビットを0と解釈しているためと判明。実機ではUビットは1に読めます。そう解釈しなおすと、以下で読んでいる値は期待どおりのCONFIGの値とな。MCCクラシックに騙された?
PIC16F18855のメモリ
今回は「メモリリード」してみるだけの回なのですが、ちょいと込み入ってます。なぜかと言えばPIC16F18855のメモリ「事情」がちょいと込み入っているためです。
-
- データメモリ(SRAM)は8ビット幅、Traditonalなバンクアクセスとリニアな間接アクセスが可能。PIC16F18855の場合1Kバイト、領域的には4KバイトMAX。なおバンクアクセス時のバンク内アドレスの下の方に「コア」レジスタとか「SFR」レジスタとか汎用SRAM以外のレジスタも見えている。
- 不揮発データメモリ(EEPROM)は8ビット幅、256バイトサイズ。
- プログラムメモリ(Flash)は、14ビット幅、PIC16F18855の場合8192ワード。アドレス空間的には32768ワードMAX
- 今回読み取りを試みるDEVICE IDやCONFIGといった情報は物理的にはFlashに置かれているように見えるが、通常のプログラムFlashメモリとは異なる領域で異なる扱いがされている
- なおアクセスしやすいようにか、SRAM、Flash、EEPROMに共通の線形なアドレス空間(ただしデータのビット幅は凸凹?)も定義されており、これを使ってアクセス可能。
今回はそれだけでも込み入っているデータメモリのTraditonalなバンクアクセスには深入りしませぬ。面白そうなのだけれども。
さて、FlashおよびEEPROMへアクセスするのに提供されている方法は以下の3種です。
-
- ICSP(In-Circuit Serial Programming)を使った外部アクセス
- NVMREG経由のアクセス
- FSR経由のアクセス
そのうち1は外部ツールを使ったホストからのアクセスであり、内部のプログラムで使用できるルートは2と3の2つであるようです。メモリアクセスのためにわざわざ2つもルートがあるのは、3ではFlashメモリとEEPROMはリードオンリのROMとしてアクセスするのに対して、2では読み書き可能な(一部アドレスはリードオンリの記載あり)アクセスできるためだと思います。
今回読み出しを試みるDEVICE IDやCONFIGxといったものは3のFSR経由のアクセスでは読み取り不可でした。データシートによると2のNVMREG経由であればConfiguration空間へもアクセス可であるように読み取れます。
MEMORYモジュール、その勝手改変
さて、EEPROM、FLASHへの書き込みを含むアクセスを許すためにMEMORYという名のモジュールが用意されています。今回はそれをリソースに加えてプロジェジェクトを生成しました。
これにより、FLASHメモリへの読み書きAPI、EEPROMへの読み書きAPIがプロジェクトに含まれるようになりました。どちらもアクセスに用いるアドレスは「線形な」16ビット幅です。ただしFLASHのデータ幅は形式16ビット(実際は14ビット)、EEPROMのデータ幅は8ビットです。
ここでFLASH読み出し用の関数にDEVICE IDやCONFIGxの「アドレス」を与えたら読めるんじゃね?と試みましたが
読めません
このMEMORYモジュールで生成されるAPI関数は、あくまでプログラムメモリ空間としての「表」のメモリにアクセスするためのものでそのままではDEVICE IDにもCONFIGxにもたどり着けませぬ。
APIのソースの内部をみると、Configuration空間への不埒なアクセスを防ぐために以下がありました。
NVMCON1bits.NVMREGS = 0; // Deselect Configuration space
ということは上記を1にしてやれば、アクセスできる? そのような勝手変更をした関数を以下プロトタイプで定義。これを main関数内で呼んだらどうよ?
uint16_t myFLASH_ReadWord(uint16_t flashAddr);
実験に使用したmain()関数とその動作結果
実験に使用したmain()関数が以下に。
void main(void) { // initialize the device SYSTEM_Initialize(); INTERRUPT_GlobalInterruptEnable(); INTERRUPT_PeripheralInterruptEnable(); while (1) { RA0 = 1; __delay_ms(2000); printf("via FLASH(0x%04x, DEVID ): 0x%04x\n", 0x8006, myFLASH_ReadWord(0x8006)); printf("via FLASH(0x%04x, CONFIG1): 0x%04x\n", 0x8007, myFLASH_ReadWord(0x8007)); printf("via FLASH(0x%04x, CONFIG2): 0x%04x\n", 0x8008, myFLASH_ReadWord(0x8008)); printf("via FLASH(0x%04x, CONFIG5): 0x%04x\n", 0x800B, myFLASH_ReadWord(0x800B)); RA0 = 0; __delay_ms(2000); } }
DEVICE IDについては、PIC16F18855のDEVICE IDである0x306Cが読み取れたのでOKに見えます。しかしCONFIGの値は「期待していた値」と全然違います。MCCで設定している値は以下のような感じ。
CONFIG部分については書き込みできないけれど読み取りできるような記載があるのだが。。。なぜ?要継続調査っす。