目次

内蔵EEPROM利用

 多くのPICには、EEPROMが内蔵されています。

 非常勤講師をしていた大学校の学生から、内蔵EEPROMの
 アクセスに関して相談を受けたので、調べてみることに。

 利用PICはPIC16F688というので、ブレッドボードに
 簡単な回路を組んで貰いました。回路図は、以下。



 Personal Computerとシリアルケーブルで接続し
 端末ソフトを使い、PIC内に用意したコマンド
 インタプリタで、内蔵EEPROMをアクセスします。


 LEDは、PICが動作していることを示すため
 2秒周期で点滅させます。

 コマンドインタプリタのコマンドは、以下としました。

 コマンドインタプリタを次のように定義します。
 (MikroCを使うことにしてあります。)

    /* command interpreter */
    if ( RFLAG == ON ) {
      /* clear */
      RFLAG = OFF ;
      /* new line */
      crlf();
      /* get command */
      cmd = *(sbuf+0) ;
      /* help */
      if ( cmd == '?' ) { show_help() ; }
      /* set EEPROM data */
      if ( cmd == 'E' ) {
        /* get address */
        eadrx = get_hex( *(sbuf+1) ) ;
        eadrx <<= 4 ;
        eadrx |= get_hex( *(sbuf+2) ) ;
        /* get data */
        edatx = get_hex( *(sbuf+3) ) ;
        edatx <<= 4 ;
        edatx |= get_hex( *(sbuf+4) ) ;
        /* store */
        eeprom_byte_write(eadrx,edatx);
      }
      /* show EEPROM context */
      if ( cmd == 'e' ) {
        for ( loopx = 0 ; loopx < 256 ; loopx++ ) {
          /* set address */
          eadrx = (UBYTE)loopx ;
          /* get EEPROM data */
          edatx = eeprom_byte_read(eadrx);
          /* convert */
          *(msg+0) = get_asc( (edatx >> 4) & MASK0F );
          *(msg+1) = get_asc( edatx & MASK0F );
          /* show */
          rs_putchar(*(msg+0)) ;
          rs_putchar(*(msg+1)) ;
          rs_putchar(' ') ;
          /* judge new line */
          if ( (loopx & MASK0F) == 15 ) { crlf() ; }
        }
      }
      /* clear all EEPROM area */
      if ( cmd == 'C' ) {
        for ( loopx = 0 ; loopx < 256 ; loopx++ ) {
          eeprom_byte_write((UBYTE)loopx,0);
        }
      }
      /* set all EEPROM area */
      if ( cmd == 'S' ) {
        for ( loopx = 0 ; loopx < 256 ; loopx++ ) {
          eeprom_byte_write((UBYTE)loopx,0xff);
        }
      }
    }

 1文字で指定されるコマンドを判定し、対応する
 処理を実行します。

 コマンドインタプリタで利用できる、1バイトの
 リード、ライト関数を定義します。

 ライト関数
  アドレス、データを指定レジスタに転送後
  ライト処理を許可し、ライトシーケンスを
  起動します。

void  eeprom_byte_write(UBYTE xadr,UBYTE xdat)
{
  /* set address */
  EEADR  = xadr ;
  /* set data */
  EEDATA = xdat ;
  /* enable write */
  EECON1.EEPGD = OFF ;
  EECON1.WREN  = ON ;
  /* write sequence */
  EECON2 = 0x55 ;
  EECON2 = 0xaa ;
  EECON1.WR    = ON ;
  /* wait */
  while ( EECON1 & (1 << WR) ) ;
  /* disable */
  EECON1.WREN  = OFF ;
}

  ライトシーケンス開始をEECON2レジスタで
  制御するには、16進の値の書込み順を守ら
  なければなりません。

 リード関数
  アドレスを指定レジスタに転送後、リードを
  許可し、データがレジスタに転送されるのを
  待ちます。

UBYTE eeprom_byte_read(UBYTE xadr)
{
  /* set address */
  EEADR = xadr ;
  /* enable read */
  EECON1 = (1 << RD) ;
  /* wait */
  while ( EECON1 & (1 << RD) ) ;

  return EEDATA ;
}

 コマンドインタプリタを使うときは、受信バッファが
 必要なので、8バイトの配列と受信割込み発生時に
 配列のどこに格納するか、指定する変数が必要です。
 次のように確保しました。

volatile UBYTE sbuf[8] ;
volatile UBYTE sindex ;

 LEDの点滅には、タイマー0のオーバーフロー割込み
 シリアル受信には、受信割込みを使います。

 割込みが発生したことを、フラグで通知します。

 フラグは、1ビットで扱える論理フラグを使うことに。
 符号なし8ビットの変数で、8本のフラグを使えるよう
 共用体でビット定義しておきます。

typedef union {
  struct {
    unsigned B7:1;
    unsigned B6:1;
    unsigned B5:1;
    unsigned B4:1;
    unsigned B3:1;
    unsigned B2:1;
    unsigned B1:1;
    unsigned B0:1;
  } BIT ;
  unsigned char DR ;
} FLAGSP ;

volatile FLAGSP xflags ;

#define RFLAG xflags.BIT.B0
#define TFLAG xflags.BIT.B1

 割込みを扱う関数は、次のように定義。

void interrupt(void)
{
  UBYTE chx ;
  /* generate 1ms */
  if ( INTCON.TMR0IF == ON ) {
    /* clear flag */
    INTCON.TMR0IF = OFF ;
    /* initialize */
    TMR0 = 6 ;
    /* increment */
    timcnt++ ;
    /* judge */
    if ( (timcnt & 0x3ff) == 1000 ) { TFLAG = ON ; }
  }
  /* receive interrupt */
  if ( PIR1.RCIF == ON ) {
    /* clear flag */
    PIR1.RCIF = OFF ;
    /* get 1 charactor */
    chx = RCREG ;
    /* store */
    *(sbuf+sindex) = chx ;
    /* increment */
    sindex++ ;
    /* judge */
    if ( chx == '\r' ) {
      sindex = 0 ;
      RFLAG = ON ;
    }
  }
}

 タイマー0のオーバーフロー割込みは、1msの周期でフラグ
 通知しています。受信割込みは、1文字が入力されたなら
 受信バッファに保存し、ディリミタ'\r'を検出すると、上位
 関数にフラグ通知します。

 通信プロトコルは、以下とします。

  データ転送速度 9600bps
  データ長    8ビット
  ストップビット 1ビット
  パリティ    なし
  フロー制御   なし

 main関数の中では、フラグを受取ったなら
 クリアした後、対応処理を実行します。

 全ソースコードは以下。

/* redefine data type */
typedef unsigned char  UBYTE ;
typedef unsigned int   UWORD ;
typedef unsigned long  ULONG ;

#define OFF 0
#define ON  OFF+1

#define RX_BIT 5
#define TX_BIT 4

#define MASKFF 0xff
#define MASK0F 0x0f

typedef union {
  struct {
    unsigned B7:1;
    unsigned B6:1;
    unsigned B5:1;
    unsigned B4:1;
    unsigned B3:1;
    unsigned B2:1;
    unsigned B1:1;
    unsigned B0:1;
  } BIT ;
  unsigned char DR ;
} FLAGSP ;

volatile FLAGSP xflags ;

#define RFLAG xflags.BIT.B0
#define TFLAG xflags.BIT.B1

volatile ULONG timcnt ;
volatile UBYTE sbuf[8] ;
volatile UBYTE sindex ;
volatile UBYTE cmd ;
volatile UBYTE state ;
volatile UBYTE eadrx ;
volatile UBYTE edatx ;
volatile UWORD loopx ;
volatile UBYTE msg[2] ;

/* function prototype */
void  init_usr(void);
void  rs_putchar(UBYTE x);
void  rs_puts(UBYTE *ptr);
void  crlf(void);
void  show_help(void);
UBYTE get_hex(UBYTE x);
void  eeprom_byte_write(UBYTE xadr,UBYTE xdat);
UBYTE eeprom_byte_read(UBYTE xadr);
UBYTE get_asc(UBYTE x);

/* interrupt handler */
void interrupt(void)
{
  UBYTE chx ;
  /* generate 1ms */
  if ( INTCON.TMR0IF == ON ) {
    /* clear flag */
    INTCON.TMR0IF = OFF ;
    /* initialize */
    TMR0 = 6 ;
    /* increment */
    timcnt++ ;
    /* judge */
    if ( (timcnt & 0x3ff) == 1000 ) { TFLAG = ON ; }
  }
  /* receive interrupt */
  if ( PIR1.RCIF == ON ) {
    /* clear flag */
    PIR1.RCIF = OFF ;
    /* get 1 charactor */
    chx = RCREG ;
    /* store */
    *(sbuf+sindex) = chx ;
    /* increment */
    sindex++ ;
    /* judge */
    if ( chx == '\r' ) {
      sindex = 0 ;
      RFLAG = ON ;
    }
  }
}

void main(void)
{
  /* user initialize */
  init_usr();
  /* endless loop */
  while ( ON ) {
    /* command interpreter */
    if ( RFLAG == ON ) {
      /* clear */
      RFLAG = OFF ;
      /* new line */
      crlf();
      /* get command */
      cmd = *(sbuf+0) ;
      /* help */
      if ( cmd == '?' ) { show_help() ; }
      /* set EEPROM data */
      if ( cmd == 'E' ) {
        /* get address */
        eadrx = get_hex( *(sbuf+1) ) ;
        eadrx <<= 4 ;
        eadrx |= get_hex( *(sbuf+2) ) ;
        /* get data */
        edatx = get_hex( *(sbuf+3) ) ;
        edatx <<= 4 ;
        edatx |= get_hex( *(sbuf+4) ) ;
        /* store */
        eeprom_byte_write(eadrx,edatx);
      }
      /* show EEPROM context */
      if ( cmd == 'e' ) {
        for ( loopx = 0 ; loopx < 256 ; loopx++ ) {
          /* set address */
          eadrx = (UBYTE)loopx ;
          /* get EEPROM data */
          edatx = eeprom_byte_read(eadrx);
          /* convert */
          *(msg+0) = get_asc( (edatx >> 4) & MASK0F );
          *(msg+1) = get_asc( edatx & MASK0F );
          /* show */
          rs_putchar(*(msg+0)) ;
          rs_putchar(*(msg+1)) ;
          rs_putchar(' ') ;
          /* judge new line */
          if ( (loopx & MASK0F) == 15 ) { crlf() ; }
        }
      }
      /* clear all EEPROM area */
      if ( cmd == 'C' ) {
        for ( loopx = 0 ; loopx < 256 ; loopx++ ) {
          eeprom_byte_write((UBYTE)loopx,0);
        }
      }
      /* set all EEPROM area */
      if ( cmd == 'S' ) {
        for ( loopx = 0 ; loopx < 256 ; loopx++ ) {
          eeprom_byte_write((UBYTE)loopx,0xff);
        }
      }
    }
    /* 1second pass */
    if ( TFLAG == ON ) {
      /* clear flag */
      TFLAG = OFF ;
      /* update state */
      state++ ;
      /* impress */
      PORTC.B2 = (state & 1) ;
    }
  }
}

/* define function body */
void init_usr(void)
{
  /* disable A/D converter */
  ADCON1 = 0x07 ;
  /* disable Analog comparator */
  CMCON0 = 0x07 ;
  /* I/O initial state */
  PORTA = 0xff ;
  PORTC = (1 << RX_BIT);
  /* I/O direction */
  TRISA = 0 ;
  TRISC = (1 << RX_BIT) ;
  /* initialize serial interface */
  {
    sindex = 0 ;
    /* BAUD rate */
    BAUDCTL.BRG16 = ON ;
    SPBRG = 25 ; /* 9600bps */
    /* TxD */
    TXSTA.TXEN = ON ;
    TXSTA.SYNC = OFF ;
    TXSTA.BRGH = OFF ;
    /* RxD */
    RCSTA.SPEN = ON ;
    RCSTA.CREN = ON ;
    /* enable receive interrupt */
    PIE1.RCIE  = ON ;
  }
  /* initialize Timer 0 */
  {
    /*
       4MHz/4 = 1MHz -> 1MHz/4 = 250kHz prescaler = 1:4
       all inputs are pull-up .
    */
    OPTION_REG = 0x01 ;
    /* 256 - 250 = 6 */
    TMR0 = 6 ;
    /* enable timer0 overflow interrupt */
    INTCON.TMR0IE = ON ;
  }
  /* enable peripheral interrupt */
  INTCON.PEIE = ON ;
  /* enable general interrupt */
  INTCON.GIE = ON ;
  /* disable Flash ROM */
  EEADRH = 0 ;
  EEDATH = 0 ;
  /* clear flags */
  xflags.DR = 0 ;
  /* others */
  timcnt = 0 ;
  state = 0 ;
  eadrx = 0 ;
  edatx = 0 ;
}

void  rs_putchar(UBYTE x)
{
  /* judge */
  while ( !TXSTA.TRMT ) ;
  /* set data */
  TXREG = x ;
}

void  rs_puts(UBYTE *ptr)
{
  while ( *ptr ) {
    rs_putchar( *ptr );
    ptr++ ;
  }
  crlf();
}

void  crlf(void)
{
  rs_putchar('\r');
  rs_putchar('\n');
}

void  show_help(void)
{
  rs_puts("? help");
  rs_puts("E set EEPROM data");
  rs_puts("e show EEPROM data");
  rs_puts("C clear all EEPROM area");
  rs_puts("S set all EEPROM area");
}

UBYTE get_hex(UBYTE x)
{
  UBYTE result ;
  /* set default */
  result = 0 ;
  /* convert */
  if ( '0' <= x && x <= '9' ) { result = x - '0' ; }
  if ( 'A' <= x && x <= 'F' ) { result = x - 'A' + 10 ; }
  if ( 'a' <= x && x <= 'f' ) { result = x - 'a' + 10 ; }
  
  return result ;
}

void  eeprom_byte_write(UBYTE xadr,UBYTE xdat)
{
  /* set address */
  EEADR  = xadr ;
  /* set data */
  EEDATA = xdat ;
  /* enable write */
  EECON1.EEPGD = OFF ;
  EECON1.WREN  = ON ;
  /* write sequence */
  EECON2 = 0x55 ;
  EECON2 = 0xaa ;
  EECON1.WR    = ON ;
  /* wait */
  while ( EECON1 & (1 << WR) ) ;
  /* disable */
  EECON1.WREN  = OFF ;
}

UBYTE eeprom_byte_read(UBYTE xadr)
{
  /* set address */
  EEADR = xadr ;
  /* enable read */
  EECON1 = (1 << RD) ;
  /* wait */
  while ( EECON1 & (1 << RD) ) ;

  return EEDATA ;
}

UBYTE get_asc(UBYTE x)
{
  UBYTE result ;
  /* default */
  result = 0 ;
  /* range check */
  if ( x < 16 ) {
    result = x + '0' ;
    if ( x > 10 ) { result = x - 10 + 'A' ; }
  }

  return result ;
}

 実際に端末ソフトを利用してのEEPROM処理は
 次のようになります。

ヘルプ、EEPROM内容表示、バイト単位の設定



バイト単位設定の内容確認



クリアと内容確認



セットと内容確認



 動作チェックをしている状態です。




目次

inserted by FC2 system