第13回 EEPROM(1)〜EEPROMとは〜

今回から、EEPROMを使ったプログラムを作成します。

目次

現在のタイマー機能の問題点

前回までの記事で作成したプログラムでは、タイマー時間を設定する機能を追加しました。

でも、まだちょっと機能が足りませんよね。

すでにお気づきかもしれませんが、タイマー時間を変更しても、電源をOFFにすると変更した値は消されてしまい、次に電源を入れた時には元のデフォルトのタイマー時間に戻ってしまいます

タイマー時間を変更した場合、その設定時間は電源を切っても記憶しておいてほしいですよね。


PICマイコンに限らず、他のマイコンでも、この課題を解決する方法が用意されています。

それは「EEPROM」と呼ばれる、電源をOFFにしても記憶内容を保持するメモリが搭載されています

そこで、タイマー時間を変更したらその設定時間を「EEPROM」に保存しておき、電源をOFFにしてもその設定時間を保持しておく、というプログラムを作成していきます。

メモリの種類

データを保持しておく「メモリ」には様々な種類があります

これらのメモリは、記憶保持の観点から大きく2種類に分かれます

一つは電源がないと記憶した内容が消えてしまう「揮発性メモリ」、もう一つは電源をOFFにしても記憶内容が消えない「不揮発性メモリ」です。

単に「消えるメモリ」「消えないメモリ」と呼べばいいような気もしますが、「揮発性」という言葉を使用しています。

なんとなく意識高い系な気がしますが、学問の分野は基本的に意識高い系の用語を使うことになっていますので、まずはこの言葉を覚えましょう。


「揮発」という言葉ですが、一般に使われている意味とほぼ同じです。

例えば消毒用アルコールってすぐに蒸発してしまいますよね。これをちょっと難しくいうと「アルコールは揮発性が高い」と言ったりします。すぐに蒸発して消えてしまう液体を「揮発性がある」「揮発性が高い」と言うことがあります。

「揮発性メモリ」とは、電源をOFFにすると記憶した内容が蒸発して消えてしまうことからこのように呼ばれています。(日常生活で物忘れが多くなった場合には「最近、記憶の揮発性が高まった気がするんだよね」って言った方が前向きな気分になりますので使ってみてください)

EEPROMは電源をOFFにしても記憶内容が消えないので、「不揮発性メモリ」と呼ばれています。

「EEPROM」とは

EEPROMは不揮発性メモリであることがわかりましたが、次にこの言葉の意味を見ていきましょう。

EEPROMは次の英語の頭文字をとった用語です。

EEPROM = Electrically Erasable Programmable Read-Only Memory

日本に訳すと「電気的に消去、書き込み可能な、読み出し専用メモリ」です。

ふーん、という気もしますが、よく考えるとちょっと意味がおかしいような気がします。

「電気的に消去したり書き込み可能な」と言ってる割に「読み出し専用メモリ」ってなんか矛盾してるような気がします。「読み出し専用メモリ」でしたら消去とか書き込みができないような気もします…

さらにこの用語は「不揮発性」の意味が表現されていないような気もします…

気になってしまう方のためにこの疑問点を補足しておきますが、この部分は読まなくても問題ありません。先を急ぐ方は次のセクションに進んでいただいて大丈夫です。


昔、コンピュータのメモリは「RAM(Random Access Memory)」と呼ばれる「読み書き可能・電源がないと記憶内容が消えるメモリ」と、「ROM(Read-Only Memory)」と呼ばれる「読み出しのみ可能(書き込み不可)・電源がなくても記憶内容が消えないメモリ」の2種類がありました。

このROMですが、書き込みができないというのはいいですが、データはいつ書き込むのかちょっと不思議ですよね。

実はROMは一度だけデータを書き込むことができるようになっいるんです。

ROMにデータを書き込むときは「ROMライター(ROMデータ書き込み機)」と呼ばれる、ROMにデータを書き込む機器を使用します。

何もデータが書き込まれていない新品のROMに対して、このROMライターを使って、ROM内部接続回路を焼き切ってデータを書き込むようになっています。

イメージとしては、ROMの中にたくさんヒューズが並んでいて、ヒューズがあるところが1、ヒューズが焼き切ってあるところが0、というように、記憶するデータに合わせてヒューズを焼き切っていきます。

このタイプのROM、ROMライタは今でも販売されています。

ROMの例
ROMライタの例

このようにデータを書き込んだROMは、ヒューズを焼き切ってしまっていますので、当然ながらデータ内容を変更できません。その代わり、電源がなくてもデータが保持できるわけです。

このようなROMの仕組みでは、内容を変更したい場合はそのROMは捨てて新しいROMにデータを書き込むしかありません。

でも今回のように「設定時間を電源OFFでも記憶しておきたい」というように、あとからデータ内容を変更できる、電源をOFFにしても記憶内容が消えないメモリが欲しいですよね。

そこで、このような「あとから記憶内容を消去したり書き込んだりできるROM」が開発されたわけです(このメモリは、先ほどのヒューズを焼き切るタイプのROMの構造・原理とは違います)。

「あとから記憶内容を消去したり書き込んだりできる」という機能は、電気的に内部記憶状態を変更することにより実現しています。(内部回路に電荷があるかないかで0と1を記憶しているので、その電荷の状態を電気的に変更しています)

つまり「電気的にあとから記憶内容を消去したり書き込んだりできるROM」というわけです。


歴史的な経緯をなぞってきましたが、気づくと「電気的に記憶内容を消去したり書き込んだりできる、ROM(読み出し専用メモリ)」という用語になってしまいました。

PIC12F1822のEEPROM

それでは、PIC12F1822のEEPROMについて確認してみましょう。

EEPROMのサイズ

最初にどれぐらいの記憶容量があるか確認します。以下はPIC12F1822のデータシートです。

(Microchip Technology社「PIC12F1822データシート」より引用)

枠で囲んだ部分がEEPROMの容量の仕様です。

データシートから「256バイト」であることがわかります。「メガバイト」とか「ギガバイト」ではなく「バイト」です!

PCの世界では、メモリやSSDはギガバイト単位が普通ですよね。

PIC12F1822のEEPROMが256バイトとはずいぶん少なくて心もとない気もしますが、マイコンでしたらこのぐらいの容量で十分なケースが多いです。

今回のタイマー時間の保持も1バイトのみ使用しますので、256バイトはうまく使えばかなり有効活用できます。


このEEPROMですが、マイコン内部では独立したモジュールになっています。

(Microchip Technology社「PIC12F1822データシート」より引用)

EEPROMのデータ読み書き

これからこのEEPROMに対してデータを読み書きしていくわけですが、256バイトあるEEPROMのどこに書いたり、どこから読むか、場所を指定する必要があります。

この「場所」は、「アドレス」または「番地」と呼ばれています。

例えばPIC12F1822では、EEPROMの256バイトに対して次のようにアドレス(番地)が割り当てられています。

Pic app 13 eeprom address

プログラムでEEPROMを扱う場合、「どのアドレスにデータを書くか」あるいは「どのアドレスからデータを読むか」という指定を行います。

それでは次に、EEPROMの具体的な使い方をみてみましょう。

PICマイコンのEEPROMの使い方

EEPROMからデータ読み出す

最初はEEPROMからのデータの読み出し方法です。

例えばアドレス0から読み出した値を、変数read_dataに格納したい場合、次のように書きます。

uint8_t read_data = eeprom_read(0); // EEPROMのアドレス0の値を変数に読み出す

EEPROMのそれぞれのアドレスのデータサイズは1バイトですので、このように1バイトの変数に代入します。(uint8_t型、またはunsigned char型になります)

EEPROMにデータ書き込む

次にEEPROMへのデータの書き込みです。

例えば write_dataの値をアドレス0に書き込みたい場合、次のように書きます。

eeprom_write(0, write_data); // EEPROMのアドレス0に変数の値を書き込む

ここで使用する変数1バイトですので、変数型はuint8_t型、またはunsigned char型になります。

まとめると、次のようになります。

eeprom_read( アドレス );         // EEPROMから指定したアドレスの1バイトデータを読み出す
eeprom_write( アドレス, データ ); // EEPROMの指定したアドレスに1バイトデータを書き込む

これらの関数を使って、プログラムの動作を次のようにしたいと思います。

  • PICマイコンが動作を開始したら、最初にEEPROMから設定時間データを読み出す
  • スイッチが押されてタイマー時間が変更されたら、変更後の設定時間をEEPROMの書き込む

ところで、1番目の「PICマイコンが動作を開始したら、最初にEEPROMから設定時間データを読み出す」という動作ですが、プログラムを書き込んだあと、初回の動作はどうしたらよいでしょうか?

というのは、プログラムを書き込んで、初めてプログラムが動作するとき、最初に「EEPROMから設定時間データを読み出す」という処理をしますが、読み出すデータはまだ何も書き込まれていません。

ということは、EEPROMに対してデータを読み書きする以外にも、プログラムを書き込むときに、初期データを書き込んでおく必要がある、ということになります。

例えば、プログラム書き込み時に、EEPROMにデフォルトの「3」(分)というデータを書き込んでおき、プログラム動作開始時にその値を読み出してタイマー動作を開始する、という具合です。

このあとは、タイマー時間の変更があればEEPROMに書き込む、という動作をすれば問題なさそうです。

ということで、EEPROMの初期データの書き込みも必要ですので、その方法を確認してきおましょう。

EEPROMの初期データ書き込み

EEPROMの初期データはプログラム処理で行うことはできません。

例えば、main関数の最初に次のようなプログラムを書いたとします。

eeprom_write(0, 5);

このようにプログラムを書くと、電源を投入するたびにmain関数が呼ばれますので、毎回アドレス0が5になってしまいます。


そこで、PICマイコンのプログラムでは、EEPROMの初期データを設定したい場合、関数の外に次のフォーマットで書いておきます。(横に長くならないように改行を入れていますが、改行は必須ではありません)

__EEPROM_DATA (アドレス0のデータ,
               アドレス1のデータ,
               アドレス2のデータ,
               アドレス3のデータ,
               アドレス4のデータ,
               アドレス5のデータ,
               アドレス6のデータ,
               アドレス7のデータ);

EEPROMの前はアンダースコア2個、EEPROMDATAの間はアンダースコア1個です。

このように書いておくと、PICkitでプログラムを書き込むとき、一緒にEEPROMにこのデータも書き込んでくれます。


この書き方には注意点があり、必ず8バイト単位で書くことになっています。

例えば次の書き方は4バイト分のデータしか書いていませんので正しくありません。

__EEPROM (0x00, 0x01, 0x02, 0x03);

このように、8バイトに満たないデータ場合は、残りのバイトは例えば0xFFで埋めて無理やり8バイトにします。(埋めるデータは0xFFでなくても構いません)

例えば、アドレス0に0x1Fを書き込んでおきたい場合は、次のようにしておきます。

__EEPROM_DATA (0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);

また、8バイトを超える場合は、この行を複数行書きます。


以上がEEPROMの概要とプログラム方法です。

次回は、設定したタイマー値をEEPROMに保存、読み出しを行うプログラムを追加したいと思います。

更新履歴

日付内容
2017.7.30新規投稿
2018.12.2誤記訂正
2021.8.22誤記訂正
2025.5.19わかりづらい部分の説明補足(余計わかりづらくなった可能性あり)
通知の設定
通知タイミング
guest
2 コメント
新しい準
古い順 一番投票が多い
本文中にフィードバック
全てのコメントを見る
sasa
sasa
3 年 前

また誤記と思われる箇所がありましたので、お知らせします。
第13回(この回)ーpicマイコンのEEPROMの使い方ー〜またEEPROMへのデータの書き込みは eepprom_write(アドレス,データ); (pが1つ多い?)
・この回で「学問の分野は基本的に意識高い系の用語を使うという暗黙のルールがある」というのはおもしろいなと思いました。(いつも学ばせていただき、ありがとうございます)

Seren
Seren
6 年 前

こんにちは。読ませていただきました。
以前PWMの記事でもお世話になりました。
dsPIC30F4013を使用しているのですが,
eeprom_read();とeeprom_write();の関数を使用すると
undefined reference to `_eeprom_write’
というエラーが表示されてしまい,使用することができません。
dsPIC用のPeripheral Libraryもインストールしましたが,使えないようです。
データシート上ではdsPICのEEPROMは1024bitあるようなので,私のやり方が悪いように思うのですが,何卒アドバイスをよろしくお願いいたします。

Takahiro Ichiyama
Takahiro Ichiyama
6 年 前

PIC18F67J94のPICになりますが、もしお分かりでしたら教えてください。
EEPROMに設定値を書き込んで電源を起動してその設定を読み込むというプログラムを作りたいのですが、うまくいきません。。
現在書込みについては下記のような形で、
void eep_write(unsigned int edate)
{

INTCONbits.GIE = 0; // 全割込み禁止
TBLPTR = 0;//書き込みアドレスのセット
TBLPTRL = edate;
EECON1 = 0;//制御レジスタ1初期化
EECON1bits.WREN = 1;//書き込み許可
EECON2 = 0x55;
EECON2 = 0xAA;
EECON1bits.WR = 1;//書き込み開始
while(EECON1bits.WR == 1){}//書き込み終了待ち
INTCONbits.GIE = 1; // 全割込み許可

}
読み込みについてはどう読み込んでよいのかわからず
void eep_reed(void)
{
short o = 0;
o = TABLAT;
}
上記のような状態です。。
MPLABにてEEPROMに書き込めたか確認しようとしても、このピックにはEEPROMの読み出し項目がなくできていません。

Takahiro Ichiyama
Takahiro Ichiyama
6 年 前

PIC18F67J94のEEPROMについてご質問です。
簡単な設定値を保存し、電源再起動時に読み込めるようにしたいのですが、うまくいきません。。
現在書込みはこんな感じで
void eep_write(unsigned int edate)
{

INTCONbits.GIE = 0; // 全割込み禁止
TBLPTR = 0;//書き込みアドレスのセット
TBLPTRL = edate;
EECON1 = 0;//制御レジスタ1初期化
EECON1bits.WREN = 1;//書き込み許可
EECON2 = 0x55;
EECON2 = 0xAA;
EECON1bits.WR = 1;//書き込み開始
while(EECON1bits.WR == 1){}//書き込み終了待ち
INTCONbits.GIE = 1; // 全割込み許可

}
読み込みはあまりよくわからず
void eep_reed(void)
{
short o = 0;
o = TABLAT;
}
このような感じです。いろいろと探してみてもc言語でのサンプルコードが見つかりませんでした。もしお分かりでしたら教えていただけないでしょうか。

管理者
管理者
返信  Takahiro Ichiyama
6 年 前

ずいぶん難しいPICマイコンを使われているようですが、何を製作されているのでしょうか。ちょっと興味があります。

実機を持っていないのでデータシートからの推定になります点、ご了承ください。

なお、PIC18F67J94はEEPROMを持っていません。EEPROMの代わりにプログラムメモリを使用します。(フログラムをPICKitで書き込む際、プログラムはPICマイコン内のプログラムメモリに書き込まれます。このエリアは電源をOFFにしても消えないので、ここを使用してEEPROMの代わりにしています)

[読み出し方法]
 TBLPTRに読み出しアドレスを指定し、アセンブラの TBLRD (Table Read)命令を発行すると読み出したデータがTABLATレジスタに格納されます。

[読み出しプログラム]

 動作確認はできませんが、おそらく以下のようなプログラムで読み出すことができると思います。

// 指定アドレスから1バイト読む関数
// flashAddrに読み出しアドレスを指定すると、読み出した値が返ってくる

uint8_t FLASH_ReadByte(uint32_t flashAddr)
{

TBLPTRU = (uint8_t)((flashAddr & 0x00FF0000) >> 16);
TBLPTRH = (uint8_t)((flashAddr & 0x0000FF00)>> 8);
TBLPTRL = (uint8_t)(flashAddr & 0x000000FF);

asm(“TBLRD”);

return (TABLAT);

}

[書き込み方法]
 書き込みはちょっと厄介です。書き込みは512バイト単位で行いますので、書き込みたいアドレスを含む512バイトのエリアをまとめて書き込みします。

 そのため書き込み手順は以下のようになります。(データシートサンプルプログラムを参考にしました)

 1) 書き込みたいアドレスを含む512バイトのデータを読み出す。なお、512バイト単位でアドレスが区切られていますので、読み出し開始アドレスは0, 512, 1024…となります。

   例えば、アドレス0x3100に書き込みしたい場合、0x3000〜0x3200のブロックですので、0x3000から512バイトを読み出します。

 2) 書き込みたいアドレスのデータを書き換えます。0x3000から512バイト読み出しましたので、書き換えるデータは配列要素0x100のデータとなります。

   (buffer[512]に読み出した場合、buffer[0x100]のデータを書き換える

 3) 書き換えたデータを書き込むエリアの512バイトを消去します

 4) 512バイトのデータを書き込みます

[書き込みプログラム]
以下の番号は上の書き込み方法の番号に対応しています。

(1)まずデータを退避するための512バイト読み出し関数です。1バイト読み出しは TBLRD 命令ですが、連続して読み出す場合はアドレスを1ずつ進める必要があるため、TBLRDPOSTINC 命令を使用します。

// 指定アドレスから512バイト読み出す関数
// bufferは呼び出す側で uint8_t buffer[512]; で確保する
// 書き込みは512バイトブロック単位なので、アドレスは512単位で指定 (0, 512, 1024…)
void FLASH_Read512Bytes(uint32_t flashAddr, uint8_t *buffer)
{
TBLPTRU = (uint8_t)((flashAddr & 0x00FF0000) >> 16);
TBLPTRH = (uint8_t)((flashAddr & 0x0000FF00)>> 8);
TBLPTRL = (uint8_t)(flashAddr & 0x000000FF);

for( uint16_t i = 0; i < 512; i++ ) { // 読み出し命令 // アドレスはポストインクリメント // ただし最後の読み出しはインクリメントなしの TBLRD にする必要があるかも asm("TBLRDPOSTINC"); // 読み出したデータはTABLATに入っている buffer[i] = TABLAT; } } (2) データを読み出し後、書き換えたいアドレスのデータを書き換えます。 buffer[該当の場所] = 書き込みデータ; (3) 書き込む前に512バイト領域を消去する必要がありますので、512バイト消去関数を作っておきます。(4)の書き込み関数から呼び出します。 // 指定アドレスから512バイト消去 void FLASH_EraseBlock(uint32_t baseAddr) { TBLPTRU = (uint8_t)((baseAddr & 0x00FF0000) >> 16);
TBLPTRH = (uint8_t)((baseAddr & 0x0000FF00)>> 8);
TBLPTRL = (uint8_t)(baseAddr & 0x000000FF);

EECON1bits.WREN = 1; // メモリ書き込み許可
EECON1bits.FREE = 1; // 処理をメモリ消去に指定
INTCONbits.GIE = 0; // 割り込み禁止
EECON2 = 0x55;
EECON2 = 0xAA;
EECON1bits.WR = 1; // 消去
INTCONbits.GIE = 1; // 割り込み許可

}

(4) 512バイト書き込み
512バイトの書き込みですが、1回の書き込みは64バイトになりますので、8回繰り返します。

// 512バイト書き込み
// 書き込むデータをbuffer[512]にセットする
// 書き込みアドレスは512バイト単位 (0, 512, 1024…)
void FLASH_WriteBlock(uint32_t writeAddr, uint8_t *buffer)
{
// 書き込む前にメモリ消去
FLASH_EraseBlock(writeAddr);

// アドレス指定
TBLPTRU = (uint8_t)((writeAddr & 0x00FF0000) >> 16);
TBLPTRH = (uint8_t)((writeAddr & 0x0000FF00)>> 8);
TBLPTRL = (uint8_t)(writeAddr & 0x000000FF);

// 512バイトのデータ書き込み
// 64バイト書き込みを8回繰り返す

for ( uint8_t i=0; i<8; i++) {
for ( uint8_t j=0; J<64; J++) {
// データをセット
TABLAT = buffer[i*64 + j];
}

// 64バイト書き込み
EECON1bits.WREN = 1; // メモリ書き込み許可
EECON1bits.WWPROG = 0; // 64バイト書き込み指定
EECON1bits.FREE = 0; // 処理を書き込みに指定
INTCONbits.GIE = 0; // 割り込み禁止
EECON2 = 0x55;
EECON2 = 0xAA;
EECON1bits.WR = 1; // 書き込み
INTCONbits.GIE = 1; // 割り込み許可

}

}

すみません、データシートで判断するしかありませんのでこの程度の回答になります。

なお、フラッシュメモリに書き込みますので、アドレスには注意いただければと思います。

アドレスの最初の方と最後の方はシステムが使用しますので、空いているところを使用します。

(データシートp.117〜118にメモリマップがあります)

Takahiro Ichiyama
Takahiro Ichiyama
6 年 前

今回もとても丁寧な回答いただき本当にありがとうございます!!
ただ、ためしてみましたが、まだ動いていません。
おそらく原因と思われるのは下記の2点です。
1_アドレスの設定が正しくない?データシートをみてもどこが空いているのかわかりませんでした。MPLABで吸い出してみながら空いてそうなアドレスに設定しています。
2_下記こみのところに、asm(“TBLWTPOSTINC”);//こういったコマンドは必要ないでしょうか?
また検証してわかったことがあったらご報告させていただきますね。
*何を作っているかですが、ごめんなさい。言えないんです。。

Takahiro Ichiyama
Takahiro Ichiyama
返信  Takahiro Ichiyama
6 年 前

下記に現在のコードを載せますので、もしおかしなところがあれば教えていただけないでしょうか。

型については自分の環境用に変更しています。
//————————————————————————————–

//
char buffer[512];

//—————————————————–
//EEPROM_1Byte_読み込み
//—————————————————–
unsigned char FLASH_ReadByte(unsigned long flashAddr)
{
unsigned char FlashRead = 0;

TBLPTRU = (char)((flashAddr & 0x00FF0000) >> 16);
TBLPTRH = (char)((flashAddr & 0x0000FF00)>> 8);
TBLPTRL = (char)(flashAddr & 0x000000FF);

asm(“TBLRD”);

FlashRead = TABLAT;

return FlashRead;
}
//—————————————————–
//EEPROM_512Byte_読み込み //60000=1D4BE ~ 60511=1D8BC
//—————————————————–
// 指定アドレスから512バイト読み出す関数
// bufferは呼び出す側で uint8_t buffer[512]; で確保する
// 書き込みは512バイトブロック単位なので、アドレスは512単位で指定 (0, 512, 1024…)
void FLASH_Read512Bytes(unsigned long flashAddr, unsigned char *buffer)
{
TBLPTRU = (char)((flashAddr & 0x00FF0000) >> 16);
TBLPTRH = (char)((flashAddr & 0x0000FF00) >> 8);
TBLPTRL = (char)(flashAddr & 0x000000FF);

for( short i = 0; i < 512; i++ ) { // 読み出し命令 // アドレスはポストインクリメント // ただし最後の読み出しはインクリメントなしの TBLRD にする必要があるかも if(i == 511){ asm("TBLRD"); }else{ asm("TBLRDPOSTINC"); } // 読み出したデータはTABLATに入っている buffer[i] = TABLAT; } } //----------------------------------------------------- //EEPROM_消去 //----------------------------------------------------- // 指定アドレスから512バイト消去 void FLASH_EraseBlock(unsigned long baseAddr) { TBLPTRU = (char)((baseAddr & 0x00FF0000) >> 16);
TBLPTRH = (char)((baseAddr & 0x0000FF00)>> 8);
TBLPTRL = (char)(baseAddr & 0x000000FF);

EECON1bits.WREN = 1; // メモリ書き込み許可
EECON1bits.FREE = 1; // 処理をメモリ消去に指定
INTCONbits.GIE = 0; // 割り込み禁止
EECON2 = 0x55;
EECON2 = 0xAA;
EECON1bits.WR = 1; // 消去
while(EECON1bits.WR == 1){}//処理終了待ち
EECON1bits.WREN = 0; // メモリ書き込み許可無効
INTCONbits.GIE = 1; // 割り込み許可

}
//—————————————————–
//EEPROM_512Byte_書き込み
//—————————————————–
// 512バイト書き込み
// 書き込むデータをbuffer[512]にセットする
// 書き込みアドレスは512バイトf単位 (0, 512, 1024…)

void FLASH_WriteBlock(unsigned long writeAddr, unsigned char *buffer)
{
// 書き込む前にメモリ消去
FLASH_EraseBlock(writeAddr);

// アドレス指定
TBLPTRU = (char)((writeAddr & 0x00FF0000) >> 16);
TBLPTRH = (char)((writeAddr & 0x0000FF00)>> 8);
TBLPTRL = (char)(writeAddr & 0x000000FF);

// 512バイトのデータ書き込み
// 64バイト書き込みを8回繰り返す

for (char i=0; i<8; i++) {
for (char j=0; j<64; j++) {
// データをセット
TABLAT = buffer[i*64 + j];
//asm("TBLWTPOSTINC");//こういったコマンドは必要ないでしょうか?
}

// 64バイト書き込み
EECON1bits.WREN = 1; // メモリ書き込み許可
EECON1bits.WWPROG = 0; // 64バイト書き込み指定
EECON1bits.FREE = 0; // 処理を書き込みに指定
INTCONbits.GIE = 0; // 割り込み禁止
EECON2 = 0x55;
EECON2 = 0xAA;
EECON1bits.WR = 1; // 書き込み
while(EECON1bits.WR == 1){}//処理終了待ち
EECON1bits.WREN = 0; // メモリ書き込み許可無効
INTCONbits.GIE = 1; // 割り込み許可

}

}

//-----------------------------------------
*メインでの呼び出し

FLASH_Read512Bytes(0x3000,&buffer[0]);
buffer[100] = 5;
FLASH_WriteBlock(0x3000,&buffer[0]);
short aaa = (short)FLASH_ReadByte(0x3100);//<==ここが何を書いても255になります。

管理者
管理者
返信  Takahiro Ichiyama
6 年 前

回答が遅くなりすみませんでした。

すみません。TBLWTPOSTINCは必要そうです。ただ、PIC18F67J94のデータシート以外に、アプリケーションノートを探してみたところ、AN1095がありました。以下のPDFファイルです。

http://ww1.microchip.com/downloads/en/AppNotes/01095D.pdf

これによると、どうもユーティリティコードがリリースされているようで、これを使用すると簡単にEEPROMライクな使い方ができるようです。

以下がライブラリとサンプルコードになります。8ビット版のコードで問題ないと思いますが、すみません、実機確認できませんので情報のみとなります。

http://ww1.microchip.com/downloads/en/AppNotes/DEE%20Emulation%208-bit%20v1.0.0.zip

Takahiro Ichiyama
Takahiro Ichiyama
返信  管理者
6 年 前

情報ご提供いただき本当にありがとうございます。
最初に教えていただいたコードで1バイトのみの記録になりますが成功しました!本当に本当にありがとうございます。書き込みの際のコードを載せておきますね。

void FLASH_WriteBlock(unsigned long writeAddr, unsigned char *buffer)
{
// 書き込む前にメモリ消去
FLASH_EraseBlock(writeAddr);
// アドレス指定
TBLPTRU = (char)((writeAddr & 0x00FF0000) >> 16);
TBLPTRH = (char)((writeAddr & 0x0000FF00)>> 8);
TBLPTRL = (char)(writeAddr & 0x000000FF);

// 1バイト書き込み
TABLAT = buffer[0];// データをセット
asm(“TBLWT”);// データを書き込み

// 1バイト書き込み
EECON1bits.WREN = 1; // メモリ書き込み許可
EECON1bits.WWPROG = 1; // 2バイト書き込み指定
EECON1bits.FREE = 0; // 処理を書き込みに指定
INTCONbits.GIE = 0; // 割り込み禁止
EECON2 = 0x55;
EECON2 = 0xAA;
EECON1bits.WR = 1; // 書き込み
while(EECON1bits.WR == 1){}//処理終了待ち
EECON1bits.WREN = 0; // メモリ書き込み許可無効
INTCONbits.GIE = 1; // 割り込み許可
}

管理者
管理者
返信  Takahiro Ichiyama
6 年 前

情報共有いただきどうもありがとうございました!

ネットを調べてもフラッシュメモリをEEPROMとして使用する例はあまり見つからないので、貴重な情報です。動作確認済みということで私の方でもかなり参考になります。

こちらこそどうもありがとうございました。勉強になりました。

目次