プログラムEEPROMへのRead/Write方法

【概要】

PIC16F877に新たに追加された機能で、意外と知られていないのが、プログラム
でプログラム内容そのものを書き換えが出来るようになったということです。
つまり、これまでは、PIC16F84を始めとして、プログラム自身では、データメモリ
だけしか書き換えをすることが出来ませんでしたが、PIC16F8xxシリーズでは、
プログラムメモリがフラッシュメモリであり、かつプログラムで、このメモリに書き
こみが出来るようになっています。

これを使うと、これまで256バイトしかなかったデータEEPROMが、一挙に最大
8kワード(14ビット幅)まで拡大することになります。
(尤もプログラム自身があるのでこれより少なくはなりますが)

プログラムメモリへのRead/Write手順は、EEPROMデータメモリと類似の手順と
なっていますが、書き込み完了待ちの方法が大きく異なっています。
つまり、一旦書き込み指令を出すと、PIC自身がHALTモード、すなわち停止状態
となり、メモリへの書き込みが完了すると自動的に停止した次の命令からプログラ
ムの実行を再開します。

これに対し読み出し手順はEEPROMデータメモリと同じ手順となっています。
しかしアドレスもデータも1バイト以上の幅がありますから、そこのところが少し
異なっています。

【レジスタの詳細内容】

プログラムメモリのRead/Writeに関連するレジスタには下記があります。

  EECON1 :Read/Write制御レジスタ
  EECON2 :Read/Writeシーケンス制御レジスタ
  EEDATA :データ下位バイト
  EEDATH :データ上位バイト(データは14ビット幅)
  EEADR  :アドレス下位バイト
  EEADRH :アドレス上位バイト(アドレスは13ビット幅)

≪EECON1レジスタの詳細≫
 制御用レジスタではEECON1が重要な働きをしています。その中身は
下図のようになっていて、EEPGDビットがEEPROMのデータメモリとプログラム
メモリの区別を行うビットとなっています。




【Read/Writte手順詳細】

実際にプログラムメモリにRead/Writeする手順は下記のフロー図のように
します。
読出しは高速で1命令の実行時間内で読出し動作を完了するので、待ち合わせ
などをする必要は全くありません。
しかし書込みの方は、
4〜10msec程度の時間を必要とし、この待ち合わせの間
は、PICは停止状態となりますので、使い方に注意が必要です。
特に高速処理で、一定時間内の実行を必要とするような処理中で書込みを行う
のは危険です。




【C言語プログラム例】

実際にCCS社のC言語によるプログラムでプログラムメモリにRead/Writeする
には下記関数を使用します。

組込み関数書式

機能内容

long data = READ_PROGRAM_EEPROM(long adrs) プログラムメモリのadrs番地の内容を読出しdataに代入する。
adrs、dataはいずれもlongかlong intで定義されていること。
WRITE_PROGRAM_EEPROM (long adrs, long data) プログラムメモリのadrs番地にdataというデータを書き込む。
adrsとdataはいずれもlongかlong intで定義されていること。

≪プログラム例≫
 下記リストは実際のプログラム例で、0x1E00番地から順にアドレスと同じデータ
 を256バイト書きこみ、その後それを読み出して液晶表示器に表示するという 
 動作をします。
 この例の回路は下図のようになっていて、液晶表示器は専用のライブラリと
 なっています。



////////////////////////////////////////////////////////////
// This program is program memory read/write test program.
// This test executed on PIC16F877 that is flash memory.
///////////////////////////////////////////////////////////
#include  <16f877.h>
#use delay(CLOCK=10000000)       //10MHz

//////// Port define and link LCD library
#include <lcd_lib3.c>

////////////// main routine
main() {
  long  adrs,data;
  lcd_init();               //initialize LCD
  ////main process
  printf(lcd_data,"Start EEPROM test");
  for (adrs=0x1E00;adrs<0x1F00;adrs++) {
    data=adrs;
    write_program_eeprom(adrs,data);
  }
  lcd_clear();
  for(adrs=0x1E00;adrs<0x1F00;adrs++) {
    data=read_program_eeprom(adrs);
    lcd_cmd(2);             //cursor at home
    printf(lcd_data,"%4LX %4LX",adrs,data);
    delay_ms(500);
  }
}



【アセンブラプログラム例】

上記のC言語の例と同じ機能をアセンブラ言語で作成した例です。
液晶表示器のサブルーチンは専用となっています。
この液晶表示器をポートDで使うときに注意が必要なのは、ポートE
にポートDの使い方を設定する必要があるのを忘れないようにする
ことです。

全体のリストは下記でダウンロードすることが出来ます。

  
★ プログラムEEPROM Read/writeテストプログラムリスト

この中で、EEPROMのRead/Writeをするサブルーチンの部分は下記
リストのようになっていて、上記のフローチャートの通りの手順と
なっています。
(注)下記リストには漢字スペースが混じっていますのでそのままでは使えません。

(1) 変数定義部
  並べる順序はこの通りでなければなりません。

ADRH EQU 020H  ;EEPROM address upper
ADRS EQU 021H  ;EEPROM address lower
DATH EQU 022H  ;EEPROM data upper
DATL EQU 023H  ;EEPROM data lower


(2) Readサブルーチン
  サブルーチン内で何度もバンクの切替をしますので、変数指定
  は間接アドレスとして取り出しています。従って変数の並び順
  は(1)の通りになっていなければなりません。


;*****************************************
; program memory read subroutine
; address set in ADRH,ADRS
; return with set data in DATH,DATL
;*****************************************
READ_EEMEM
  BCF  STATUS,IRP  ;bank0 for indirect address
  MOVLW ADRH     ;start from 0CH
  MOVWF FSR      ;set indirect pointer
  BSF  STATUS,RP1
  BCF  STATUS,RP0  ;bank2
  MOVF  INDF,W    ;get address upper
  MOVWF EEADRH    ;set EEPROM address upper
  INCF  FSR,F     ;next
  MOVF  INDF,W
  MOVWF EEADR     ;set EEPROM address lower
  INCF  FSR,F
  BSF  STATUS,RP0  ;bank3
  BSF  EECON1,EEPGD ;set program memory
  BSF  EECON1,RD   ;start read
  NOP         ;HALT dumy
  NOP
  BCF  STATUS,RP0  ;bank2
  MOVF  EEDATH,W   ;get upper data
  MOVWF INDF     ;save to DATH
  INCF  FSR,F     ;next
  MOVF  EEDATA,W   ;get lower data
  MOVWF INDF
  BCF  STATUS,RP1  ;bank0
  RETURN


(3) Writeサブルーチン
  書きこみサブルーチンでは、途中のNOP命令の所で数msecの間
  HALT(停止)モードとなりますので実行時間では注意が必要
  です。

;********************************************
; program memory write subroutine
; address set in ADRH,ADRS
; data set in DATH,DATL
;********************************************
WRITE_EEMEM
  BCF  STATUS,IRP  ;set bank0 for indirect
  MOVLW ADRH
  MOVWF FSR      ;set indirect
  BSF  STATUS,RP1  ;bank2
  BCF  STATUS,RP0
  MOVF  INDF,W    ;get upper address
  MOVWF EEADRH    ;set upper address
  INCF  FSR,F     ;next
  MOVF  INDF,W    ;get lower address
  MOVWF EEADR     ;set lower address
  INCF  FSR,F     ;next
  MOVF  INDF,W    ;get upper data
  MOVWF EEDATH    ;set upper data
  INCF  FSR,F     ;next
  MOVF  INDF,W    ;get lower data
  MOVWF EEDATA    ;set lower data

  BSF  STATUS,RP0  ;bank3
  BSF  EECON1,EEPGD ;program memory
  BSF  EECON1,WREN  ;write enable
  MOVLW 0x55     ;write sequence
  MOVWF EECON2
  MOVLW 0xAA
  MOVWF EECON2
  BSF  EECON1,WR   ;write start
  NOP         ;HALT NOP
  NOP
  BCF  EECON1,WREN  ;write disable
  BCF  STATUS,RP0
  BCF  STATUS,RP1  ;bank0
  RETURN



  目次ページに戻る