目次
前
次
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 );
}
定義した関数を利用して、端末ソフトで
動作を確認しました。
時刻の値が変化していることがわかります。
目次
前
次