PIC24FJ64GA002 のプログラム領域ROMをデータROMとして使う

1.はじめに

PIC24Fはデータ記憶用のROMがなく、データの保存にはプログラム領域のROMを用いる必要があるらしい。

とあることから、300程度のINTデータを保存しておきたくなったのだが、インターネット上でざっと私が調べた範囲では、多くても1ページ(3Byte×64)を使うもので、ページをまたがってデータを保存する方法が簡単に書かれたものはなかった。使い方を理解するのに相当の時間を費やしたので、ここにまとめておく。

 

ただしまだ完全とは言えず、データROMに使う領域を変更すると、一部使えなくなることがある(詳細は後述)。つまり、ここに書いてあることは、まったくの間違いという可能性もある。このプログラムを使う際はトライアルを厳重にする等、十分注意をお願いします。


なお、本調査にあたっては、以下のブログを参考にさせていただいた。
あらためてお礼を申し上げるとともに、リンクフリーとのことなので、リンクを張らせていただく。まず、こちらを読んだほうが理解が深まると思う。
    ハム三昧さん
    http://jr4pdp.blog.enjoy.jp/myblog/2019/05/pic24f64ga004ee-d37e.html

 

2.前提条件
 ・利用したPICは、PIC24FJ64GA002
  その他のPIC24でも使えると思う(未確認)。その場合はメモリマップを参照の上、利用する領域を適宜変更のこと。
 ・INT(16Bit)データを読み書きする。
 ・データの消去単位である1536Byteを対象とするが、1/3は使いにくいので使わないこととし、1024Bit(=Intで512個)のデータを読み書きする。
 ・コンパイラは、X16 V1.24。古いがご勘弁を。

3.使い方

3-1.事前準備
(1) ヘッダーファイルの準備
    p24FJ64GA002.h
をインクルードする。私の環境では、
    C:\Program Files (x86)\Microchip\xc16\v1.24\support\PIC24F\h
にあった。


(2)データROM領域の定義
コンフィギュレーションビット設定の前に
const __attribute__*1 unsigned int _flash_datas[96*8];
を追記する。

上記は、0x9C00~0xA1FFをデータROMにする例である。
このスタートアドレス(0x9C00)は、0x600 ごとに設定できる(0x9000,0x9600,0x9C00,0xA200・・・)。
*なぜか0x9600、0xA200に設定した場合は、半分の256個までしか使えなかった。
 理由は不明。間違っているのかもしれない と書いたのはこれが理由。

 

3-2.書き込み
da_tmp にあるデータを書き込みたい場合は以下とする。
複数ページに書き込む場合、要はoffsetを128づつインクリメントしていけばよい。

void Flash_Write() {
    unsigned int i=0;
    unsigned int j=0;
    
    unsigned int page = __builtin_tblpage(&_flash_datas);
    unsigned int offset = __builtin_tbloffset(&_flash_datas);

    // ページ消去
    TBLPAG = page;
    __builtin_tblwtl(offset, 0x0000); // 
    NVMCON = 0x4042;
    asm volatile ("disi #5");
    __builtin_write_NVM();          //erase 8line = 64*8
    while(NVMCONbits.WR);
 
    
    // メモリー書き込み
    for(j=0;j<8;j++) {
    NVMCON = 0x4001;
    TBLPAG = page;
  
    for (i=0; i<64; i++) {
        __builtin_tblwtl(offset + i*2, da_tmp[i+j*64]);  // *2 偶数
        __builtin_tblwth(offset + i*2, 0xFF);
       }
    asm volatile ("disi #5");
    __builtin_write_NVM();
    while(NVMCONbits.WR);
    
    offset=offset+128;
    
    }
}


3-3. 読み込み
da にデータを読み込む場合は以下。
こちらも、offsetを128づつインクリメントする。

void Flash_Read() {
 unsigned int i=0;
 unsigned int j=0;

    unsigned int page = __builtin_tblpage(&_flash_datas);
    unsigned int offset = __builtin_tbloffset(&_flash_datas);
      // フラッシュメモリー読み込み
        TBLPAG=page;
        
    for(j=0;j<8;j++){
        for(i=0;i<64;i++){
        da[i+j*64] = __builtin_tblrdl(offset + i*2);
        }
        
        offset=offset+128;
    }
}

 

*1:section(".Data_Memory"), space (prog), address (0x9c00)