目次

IIC処理

 IIC処理は、GPIOを利用しても実現できます。

 IICの動作をタイミングチャートでみてみます。





 SCL、SDAの2信号を利用して、スタートとストップ
 の状態を構成します。

 関数で定義すると、以下。

void  put_iic_start(void)
{
  /* both high level */
  GP0DAT |= ((1 << S_SCL) | (1 << S_SDA)) ; /* SCL = ON ; SDA = ON */
  /* 0 -> SDA */
  GP0DAT &= ~(1 << S_SDA) ; /* SCL = ON ; SDA = OFF */
  /* 0 -> SCL */
  GP0DAT &= ~(1 << S_SCL) ; /* SCL = OFF ; SDA = OFF */
}

void  put_iic_stop(void)
{
  /* both low level */
  GP0DAT &= 0xff3fffff ; /* SCL = OFF ; SDA = OFF */
  /* 1 -> SCL */
  GP0DAT |= (1 << S_SCL) ; /* SCL = ON ; SDA = OFF */
  /* both high level */
  GP0DAT |= (1 << S_SDA) ; /* SCL = ON ; SDA = ON */
}

 2つの関数では、GP0の上位2ビット(GP07,GP06)を
 SCL、SDAに割り当てて使っています。

 IICバス接続のEEPROMをアクセスする場面を
 考えてみます。

 ライト処理のタイミングチャートは、以下。



 ライト処理は、SDAを入力にも出力にも利用しています。
 EEPROMでは、デバイスID(ライト用)、アドレス上位
 アドレス下位、データの順で1バイトをライトしています。

 この処理を、関数で定義します。

typedef unsigned char  UBYTE ;
typedef unsigned short UWORD ;

#define MASK80 0x80
#define MASKFF 0xff

UBYTE put_eeprom_data(UWORD ax,UBYTE dx)
{
  UBYTE tmp ;
  UBYTE ack ;
  UBYTE i ;
  UBYTE j ;
  /* start condition */
  put_sccb_start() ;
  /* clear */
  ack = 0 ;
  /* transfer data */
  for ( j = 0 ; j < 4 ; j++ ) {
    /* set parameter */
    tmp = 0xa0 ;
    if ( j == 1 ) { tmp = (ax >> 8) & MASKFF ; }
    if ( j == 2 ) { tmp = ax & MASKFF ; }
    if ( j == 3 ) { tmp = dx ; }
    /* transfer */
    for ( i = 0 ; i < 8 ; i++ ) {
      /* send 1 bit */
      GP0DAT &= ~(1 << S_SDA) ;
      if ( tmp & MASK80 ) { GP0DAT |= (1 << S_SDA) ; }
      /* SCL : H */
      GP0DAT |= (1 << S_SCL) ;
      /* shift */
      tmp <<= 1 ;
      /* SCL : L */
      GP0DAT &= ~(1 << S_SCL) ;
    }
    /* ack or nak read */
    {
      /* change input */
      GP0DAT &= 0xbfffffff ;
      /* SCL : H */
      GP0DAT |= (1 << S_SCL) ;
      /* input */
      if ( GP0DAT & 0x40 ) { ack++ ; }
      /* SCL : L */
      GP0DAT &= ~(1 << S_SCL) ;
      /* change output */
      GP0DAT |= 0x40000000 ;
    }
  }
  /* stop condition */
  put_sccb_stop() ;

  return ack ;
}

 関数を動かして、0より大きい値が返ってきたら
 書き込み処理が失敗している可能性があるとして
 動作させています。

 リード処理のタイミングチャートは、以下。



 この処理を、関数で定義します。

UWORD get_eeprom_data(UWORD ax)
{
  UBYTE result ;
  UBYTE i ;
  UBYTE j ;
  UBYTE tmp ;
  UBYTE ack ;
  /* clear */
  ack = 0 ;
  /* start condition */
  put_sccb_start() ;
  /* send address */
  for ( j = 0 ; j < 3 ; j++ ) {
    /* set parameter */
    tmp = 0xa0 ;
    if ( j == 1 ) { tmp = (ax >> 8) & MASKFF ; }
    if ( j == 2 ) { tmp = ax & MASKFF ; }
    /* transfer */
    for ( i = 0 ; i < 8 ; i++ ) {
      /* send 1 bit */
      GP0DAT &= ~(1 << S_SDA) ;
      if ( tmp & MASK80 ) { GP0DAT |= (1 << S_SDA) ; }
      /* SCL : H */
      GP0DAT |= (1 << S_SCL) ;
      /* shift */
      tmp <<= 1 ;
      /* SCL : L */
      GP0DAT &= ~(1 << S_SCL) ;
    }
    /* get ack or nak read */
    {
      /* change input */
      GP0DAT &= 0xbfffffff ;
      /* SCL : H */
      GP0DAT |= (1 << S_SCL) ;
      /* input */
      if ( GP0DAT & 0x40 ) { ack++ ; }
      /* SCL : L */
      GP0DAT &= ~(1 << S_SCL) ;
      /* change output */
      GP0DAT |= 0x40000000 ;
    }
  }
  /* start condition */
  put_sccb_start() ;
  /* send code */
  {
    /* set parameter */
    tmp = 0xa1 ;
    /* transfer */
    for ( i = 0 ; i < 8 ; i++ ) {
      /* send 1 bit */
      GP0DAT &= ~(1 << S_SDA) ;
      if ( tmp & MASK80 ) { GP0DAT |= (1 << S_SDA) ; }
      /* SCL : H */
      GP0DAT |= (1 << S_SCL) ;
      /* shift */
      tmp <<= 1 ;
      /* SCL : L */
      GP0DAT &= ~(1 << S_SCL) ;
    }
    /* ack or nak */
    {
      /* change input */
      GP0DAT &= 0xbfffffff ;
      /* SCL : H */
      GP0DAT |= (1 << S_SCL) ;
      /* dummy input */
      if ( GP0DAT & 0x40 ) { ack++ ; }
      /* SCL : L */
      GP0DAT &= ~(1 << S_SCL) ;
      /* change output */
      GP0DAT |= 0x40000000 ;
    }
  }
  /* get data */
  {
    result = 0 ;
    /* change input */
    GP0DAT &= 0xbfffffff ;
    /* get */
    for ( i = 0 ; i < 8 ; i++ ) {
      /* shift */
      result <<= 1 ;
      /* SCL : H */
      GP0DAT |= (1 << S_SCL) ;
      /* data */
      if ( GP0DAT & 0x40 ) { result |= ON ; }
      /* SCL : L */
      GP0DAT &= ~(1 << S_SCL) ;
    }
    /* nak */
    {
      /* SCL : H */
      GP0DAT |= (1 << S_SCL) ;
      /* input */
      if ( !(GP0DAT & 0x40) ) { ack++ ; }
      /* SCL : L */
      GP0DAT &= ~(1 << S_SCL) ;
      /* change output */
      GP0DAT |= 0x40000000 ;
    }
  }
  /* stop condition */
  put_sccb_stop() ;

  return((ack << 8) | result) ;
}

 16ビットを返しておき、上位8ビットに正常終了したか
 どうかの情報を入れ、下位8ビットに1バイトデータを
 格納します。

 IICデバイスとしては、手元にRTC(RealTimeClock)があります。



 このRTCを扱う関数を、次のように定義しました。

#define RTC_ID_WR 0xa2
#define RTC_ID_RD 0xa3

#define RTC_SCL  21
#define RTC_SDA  20

void  put_rtc_start(void)
{
  /* both high level */
  GP3DAT |= ((1 << RTC_SCL) | (1 << RTC_SDA)) ; /* SCL = ON ; SDA = ON */
  /* 0 -> SDA */
  GP3DAT &= ~(1 << RTC_SDA) ; /* SCL = ON ; SDA = OFF */
  /* 0 -> SCL */
  GP3DAT &= ~(1 << RTC_SCL) ; /* SCL = OFF ; SDA = OFF */
}

void  put_rtc_stop(void)
{
  /* both low level */
  GP3DAT &= 0xffcfffff ; /* SCL = OFF ; SDA = OFF */
  /* 1 -> SCL */
  GP3DAT |= (1 << RTC_SCL) ; /* SCL = ON ; SDA = OFF */
  /* 1 -> SDA */
  GP3DAT |= (1 << RTC_SDA) ; /* SCL = ON ; SDA = ON */
}

void  put_rtc_data(UBYTE ax,UBYTE x)
{
  UBYTE tmp ;
  UBYTE i ;
  UBYTE j ;
  UBYTE k ;
  /* start condition */
  put_rtc_start() ;
  /* transfer data */
  for ( j = 0 ; j < 3 ; j++ ) {
    /* set parameter */
    tmp = RTC_ID_WR ;
    if ( j == 1 ) { tmp = ax ; }
    if ( j == 2 ) { tmp = x ; }
    /* transfer */
    for ( i = 0 ; i < 8 ; i++ ) {
      /* send 1 bit */
      GP3DAT &= ~(1 << RTC_SDA) ;
      if ( tmp & MASK80 ) { GP3DAT |= (1 << RTC_SDA) ; }
      /* delay */
      k++ ;
      /* SCL : H */
      GP3DAT |= (1 << RTC_SCL) ;
      /* shift */
      tmp <<= 1 ;
      /* SCL : L */
      GP3DAT &= ~(1 << RTC_SCL) ;
      /* delay */
      k++ ;
    }
    /* dummy read */
    {
      /* change input */
      GP3DAT &= 0xefffffff ;
      /* SCL : H */
      GP3DAT |= (1 << RTC_SCL) ;
      /* dummy input */
      tmp = GP3DAT & 0x10 ;
      /* SCL : L */
      GP3DAT &= ~(1 << RTC_SCL) ;
      /* change output */
      GP3DAT |= 0x10000000 ;
    }
  }
  /* stop condition */
  put_rtc_stop() ;
}

UBYTE  get_rtc_data(UBYTE ax)
{
  UBYTE result ;
  UBYTE i ;
  UBYTE j ;
  UBYTE k ;
  UBYTE tmp ;
  /* start condition */
  put_rtc_start() ;
  /* send address */
  for ( j = 0 ; j < 2 ; j++ ) {
    /* set parameter */
    tmp = RTC_ID_WR ;
    if ( j == 1 ) { tmp = ax ; }
    /* transfer */
    for ( i = 0 ; i < 8 ; i++ ) {
      /* send 1 bit */
      GP3DAT &= ~(1 << RTC_SDA) ;
      if ( tmp & MASK80 ) { GP3DAT |= (1 << RTC_SDA) ; }
      /* delay */
      k++ ;
      /* SCL : H */
      GP3DAT |= (1 << RTC_SCL) ;
      /* shift */
      tmp <<= 1 ;
      /* SCL : L */
      GP3DAT &= ~(1 << RTC_SCL) ;
      /* delay */
      k++ ;
    }
    /* dummy read */
    {
      /* change input */
      GP3DAT &= 0xefffffff ;
      /* SCL : H */
      GP3DAT |= (1 << RTC_SCL) ;
      /* dummy input */
      tmp = GP3DAT & 0x10 ;
      /* SCL : L */
      GP3DAT &= ~(1 << RTC_SCL) ;
      /* change output */
      GP3DAT |= 0x10000000 ;
    }
  }
  /* start condition */
  put_rtc_start() ;
  /* send code */
  {
    /* set parameter */
    tmp = RTC_ID_RD ;
    /* transfer */
    for ( i = 0 ; i < 8 ; i++ ) {
      /* send 1 bit */
      GP3DAT &= ~(1 << RTC_SDA) ;
      if ( tmp & MASK80 ) { GP3DAT |= (1 << RTC_SDA) ; }
      /* delay */
      k++ ;
      /* SCL : H */
      GP3DAT |= (1 << RTC_SCL) ;
      /* shift */
      tmp <<= 1 ;
      /* SCL : L */
      GP3DAT &= ~(1 << RTC_SCL) ;
      /* delay */
      k++ ;
    }
    /* dummy read */
    {
      /* change input */
      GP3DAT &= 0xefffffff ;
      /* SCL : H */
      GP3DAT |= (1 << RTC_SCL) ;
      /* dummy input */
      tmp = GP3DAT & 0x10 ;
      /* SCL : L */
      GP3DAT &= ~(1 << RTC_SCL) ;
      /* change output */
      GP3DAT |= 0x10000000 ;
    }
  }
  /* get data */
  {
    result = 0 ;
    /* change input */
    GP3DAT &= 0xefffffff ;
    /* get */
    for ( i = 0 ; i < 8 ; i++ ) {
      /* shift */
      result <<= 1 ;
      /* SCL : H */
      GP3DAT |= (1 << RTC_SCL) ;
      /* delay */
      k++ ;
      /* data */
      if ( GP3DAT & 0x10 ) { result |= ON ; }
      /* SCL : L */
      GP3DAT &= ~(1 << RTC_SCL) ;
      /* delay */
      k++ ;
    }
    /* ACK(1) send */
    {
      /* change output */
      GP3DAT |= 0x10000000 ;
      /* confirm data */
      GP3DAT |= (1 << RTC_SDA) ;
      /* SCL : H */
      GP3DAT |= (1 << RTC_SCL) ;
      /* delay */
      k++ ;
      /* SCL : L */
      GP3DAT &= ~(1 << RTC_SCL) ;
      /* delay */
      k++ ;
    }
  }
  /* stop condition */
  put_rtc_stop() ;

  return result ;
}

void  init_rtc(void)
{
  /* message */
  rs_puts("** initialize RTC ***"); crlf() ;
  /* control 1 do STOP motion */
  put_rtc_data(0x00,0x20) ;
  /* control 2 disable all interrupts */
  put_rtc_data(0x01,0x00) ;
  /* seconds (BCD) */
  put_rtc_data(0x02,0x56) ;
  /* minutes (BCD) */
  put_rtc_data(0x03,0x34) ;
  /* hours (BCD) */
  put_rtc_data(0x04,0x12) ;
  /* days (BCD) */
  put_rtc_data(0x05,0x24) ;
  /* weekdays */
  put_rtc_data(0x06,0x04) ;
  /* Months and century (BCD) */
  put_rtc_data(0x07,0x01) ;
  /* Years (BCD) */
  put_rtc_data(0x08,0x13) ;
  /* minute alarm */
  put_rtc_data(0x09,0x00) ;
  /* hour alarm */
  put_rtc_data(0x0a,0x00) ;
  /* day alarm */
  put_rtc_data(0x0b,0x00) ;
  /* weekdays alarm */
  put_rtc_data(0x0c,0x00) ;
  /* disabel CLKOUT 1 second pulse */
  put_rtc_data(0x0d,0x03) ;
  /* disable timer interrupt */
  put_rtc_data(0x0e,0x00) ;
  /* set timer counter */
  put_rtc_data(0x0f,0x00) ;
  /* start RTC */
  {
    /* enable RTC */
    put_rtc_data(0x00,0x00) ;
  }
  /* message */
  rs_puts("** complete ! ***"); crlf() ;
}

void  show_rtc(void)
{
  UBYTE tmp ;
  /* control 1 do STOP motion */
  tmp = get_rtc_data(0x00) & 0x20 ;
  show_value( tmp );
  rs_putchar(' ') ;
  /* control 2 disable all interrupts */
  tmp = get_rtc_data(0x01) & 0x1f ;
  show_value( tmp );
  rs_putchar(' ') ;
  /* hours (BCD) */
  tmp = get_rtc_data(0x04) & 0x3f ;
  show_value( tmp );
  /* minutes (BCD) */
  tmp = get_rtc_data(0x03) & 0x3f ;
  show_value( tmp );
  /* seconds (BCD) */
  tmp = get_rtc_data(0x02) & 0x7f ;
  show_value( tmp );
  rs_putchar(' ') ;
  /* Years (BCD) */
  tmp = get_rtc_data(0x08) ;
  show_value( tmp );
  /* Months and century (BCD) */
  tmp = get_rtc_data(0x07) & 0x9f ;
  show_value( tmp );
  /* days (BCD) */
  tmp = get_rtc_data(0x05) & 0x3f ;
  show_value( tmp );
  rs_putchar(' ') ;
  /* weekdays */
  tmp = get_rtc_data(0x06) & 0x07 ;
  show_value( tmp );
  crlf() ;
  /* minute alarm */
  tmp = get_rtc_data(0x09) & 0x7f;
  show_value( tmp );
  rs_putchar(' ') ;
  /* hour alarm */
  tmp = get_rtc_data(0x0a) & 0x3f;
  show_value( tmp );
  rs_putchar(' ') ;
  /* day alarm */
  tmp = get_rtc_data(0x0b) & 0x3f;
  show_value( tmp );
  rs_putchar(' ') ;
  /* weekdays alarm */
  tmp = get_rtc_data(0x0c) & 0x07;
  show_value( tmp );
  rs_putchar(' ') ;
  /* disabel CLKOUT 1 second pulse */
  tmp = get_rtc_data(0x0d) & 0x83;
  show_value( tmp );
  rs_putchar(' ') ;
  /* disable timer interrupt */
  tmp = get_rtc_data(0x0e) & 0x83;
  show_value( tmp );
  rs_putchar(' ') ;
  /* set timer counter */
  tmp = get_rtc_data(0x0f) ;
  show_value( tmp );
  crlf() ;
}

void  show_value(UBYTE x)
{
  UBYTE msg[3] ;
  /* separate */
  *(msg+0) = (x >> 4) & MASK0F ;
  *(msg+1) = (x & MASK0F) ;
  /* conversion */
  *(msg+0) = asc_hex[ *(msg+0) ] ;
  *(msg+1) = asc_hex[ *(msg+1) ] ;
  *(msg+2) = '\0' ;
  /* show */
  rs_puts( msg );
}

 定義した関数を利用して、端末ソフトで
 動作を確認しました。
 時刻の値が変化していることがわかります。




目次

inserted by FC2 system