C言語(SDCC)を使用して、STC8G1K08AでのI2Cアドレスサーチのプログラムを作成したいと思います。
回路図は、シリアル通信に使用している下記回路です。
SDAは8pin(P3.3)、SCLは7pin(P3.2)になります。図示はしていませんが、SDA及びSCLは2.2Kでプルアップしています。
まずは、I2C関連のレジスターを登録します。
#define CLKDIV (*(unsigned char volatile __xdata *)0xfe01)
#define I2CCFG (*(unsigned char volatile __xdata *)0xfe80)
#define I2CMSCR (*(unsigned char volatile __xdata *)0xfe81)
#define I2CMSST (*(unsigned char volatile __xdata *)0xfe82)
#define I2CSLCR (*(unsigned char volatile __xdata *)0xfe83)
#define I2CSLST (*(unsigned char volatile __xdata *)0xfe84)
#define I2CSLADR (*(unsigned char volatile __xdata *)0xfe85)
#define I2CTXD (*(unsigned char volatile __xdata *)0xfe86)
#define I2CRXD (*(unsigned char volatile __xdata *)0xfe87)
//BYTE 指定可能なレジスター
__sfr __at 0x8e AUXR ;
__sfr __at 0xba P_SW2 ;
__sfr __at 0xb2 P3M0 ;
__sfr __at 0xb1 P3M1 ;
__sfr __at 0xca P5M0 ;
__sfr __at 0xc9 P5M1 ;
__sbit __at 0xb3 SDA;
__sbit __at 0xb2 SCL;
今回は、I2C通信はマスターモードでポーリングしています。(割り込みは使用していません)。
P_SW2レジスターのbit4,5でI2Cを設定できます。STC8G1K08Aでは00でSCL(P3.2)、SDA(3.3)を設定できます。
また、以後XFR(拡張RAM領域特殊機能レジスタ)をアクセスすることなりますのでbit7は"1"に設定します(0x80)
I2CCFGの7bit目で1:enable、6bit目で1:Masterにしています(0xe0)
I2CMSSTをアイドル状態に設定(0x00)
P_SW2 = 0x80;
I2CCFG = 0xe0; //マスターモード
I2CMSST = 0x00;
I2Cのアドレスは、二重のFOR文で00~7Fまで作成し、そのアドレスをチェックしていきます。
実際のアドレスは addr=i*0x10+j となります。
I2Cアドレスのチェックはi2c_addr(addr)で戻り値として、”0”か”1”を返します。
switch文で”1”であればNACKであり、無応答なので”*”を表示します。
”0”であればACKであり応答したとみなし、そのアドレスを表示します。
printf_tiny("Addr 0 1 2 3 4 5 6 7 8 9 a b c d e f\r\n");
for (i = 0; i <= 0x7; i++) {
printf_tiny(" %x ", i*0x10);
for (j = 0; j <= 0xf; j++) {
addr = i * 0x10 + j;
switch(i2c_addr(addr)){
case 0x1: //addr+R >> NACK
printf_tiny("* ");
break;
case 0x0: //addr+R >> ACK
printf_tiny("%x",addr);
break;
default:
printf_tiny("er");
}
}
printf_tiny("\r\n");
関数i2c_addrでは、引数としてint addrを受け取ります。
I2CMSCRレジスタに0x01を設定することにより、I2C動作がスタートします。
I2CMSSTの6bit目(MSIF)は、I2CMSCRにコマンド(ここでは0x01)が入力されると、割り込み要求フラグが”1”になります。while文でこのフラグをチェックします(”while(!(I2CMSST & 0x40))”)、ここではポーリングしているので、割り込みは発生しません。MSIFビットは、ソフトでクリアする必要があります。(”I2CMSST &= ~0x40”)
次にI2CTXDにデータを送信します。ここではI2Cアドレス+Readモードを設定します。
I2CMSCRにデータ送信コマンド0x02を設定し、I2CTXDに設定したデータを送信します。
送信したデータの返答をreply()でACKまたは、NACKの確認をします。
I2CMSCRにACKコマンドの受信(0x03)を設定します。
I2CMSSTの2bit目(MSACK1)をチェックします。
ACKが返答されば”0”に、NACKが返答されば”1”になります。
最後にI2CMSCRにストップデータ0x06を設定します。
int i2c_addr(int addr) //I2Cアドレスサーチ
{
int i;
I2CMSCR = 0x01; //I2C スタート
while(!(I2CMSST & 0x40));
I2CMSST &= ~0x40;
I2CTXD = ((addr << 1) | 0x01); //I2C_ADDR + READ 送信
I2CMSCR = 0x02;
while(!(I2CMSST & 0x40));
I2CMSST &= ~0x40;
i=reply(); //ACK、NACK返答確認
I2CMSCR = 0x06; //I2C ストップ
while(!(I2CMSST & 0x40));
I2CMSST &= ~0x40;
return i;
}
int reply(void) //ACK、NACK返答確認
{
int i;
I2CMSCR = 0x03;
while(!(I2CMSST & 0x40));
i=I2CMSST & 0x02;
I2CMSST &= ~0x40;
return (i >> 1); //ACK =0,NACK=1
}
全体的なプログラムは下記のとおりです。
// STC8G1K08A I2C アドレスサーチ C言語版
//
// STC8G1K08A MPU
// Flash ROM 8Kbyte
// RAM 1Kbyte
//
// SDCC 4.0.0
//
// file name STC8G1K08A_I2C_search.c
// $ sdcc -mmcs51 --model-small --xram-size 0x400 --xram-loc 0x0000 --code-size 0x2000 STC8G1K08A_I2C_search.c
// $ packihx STC8G1K08A_I2C_search.ihx > STC8G1K08A_I2C_search.hex
// $ stcgal -P stc8g -t 22118.4 -p /dev/ttyUSB0 STC8G1K08A_I2C_search.hex
//
#include <8052.h>
#include <stdio.h>
//XFR(拡張RAM領域特殊機能レジスタ)
#define CLKDIV (*(unsigned char volatile __xdata *)0xfe01)
#define I2CCFG (*(unsigned char volatile __xdata *)0xfe80)
#define I2CMSCR (*(unsigned char volatile __xdata *)0xfe81)
#define I2CMSST (*(unsigned char volatile __xdata *)0xfe82)
#define I2CSLCR (*(unsigned char volatile __xdata *)0xfe83)
#define I2CSLST (*(unsigned char volatile __xdata *)0xfe84)
#define I2CSLADR (*(unsigned char volatile __xdata *)0xfe85)
#define I2CTXD (*(unsigned char volatile __xdata *)0xfe86)
#define I2CRXD (*(unsigned char volatile __xdata *)0xfe87)
//BYTE 指定可能なレジスター
__sfr __at 0x8e AUXR ;
__sfr __at 0xba P_SW2 ;
__sfr __at 0xb2 P3M0 ;
__sfr __at 0xb1 P3M1 ;
__sfr __at 0xca P5M0 ;
__sfr __at 0xc9 P5M1 ;
__sbit __at 0xb3 SDA;
__sbit __at 0xb2 SCL;
// uart 初期化
void uart_init(void) {
P_SW2 = 0x80;
CLKDIV = 0x02; //システムクロック分周値を 1/2にセット
P_SW2 = 0x00;
AUXR = 0xc0; //SYSCLK/1 timer0 or timer1 clock souce
SCON = 0x50; //UARTはモード1に設定、受信イネーブル
//SCON=01010000B
TMOD |= 0x20; //タイマー1を8ビット自動リロードモードに設定
//TMOD=00100000B
TH1 = 0xf7; //タイマーカウンターセット
TL1 = 0xf7;
TR1 = 1; // タイマー1スタート
}
// I2C 関連関数
int reply(void) //ACK、NACK返答確認
{
int i;
I2CMSCR = 0x03;
while(!(I2CMSST & 0x40));
i=I2CMSST & 0x02;
I2CMSST &= ~0x40;
return (i >> 1); //ACK =0,NACK=1
}
// 1文字シリアル出力
int putchar(int data) {
TI = 0; //SCONのTI(1bit目)をケリア
SBUF = data; //dataからSBUFバッファーに格納
while (!TI); //SCONのTI(1bit目)が"1"なるまでループ
return data;
}
// 1文字シリアル入力
int getchar(void) {
while (!RI); //SCONのRI(0bit目)が"1"なるまでループ
RI = 0; //SCONのRI(0bit目)をクリア
return SBUF; // 受信データ返却
}
int i2c_addr(int addr) //I2Cアドレスサーチ
{
int i;
I2CMSCR = 0x01; //I2C スタート
while(!(I2CMSST & 0x40));
I2CMSST &= ~0x40;
I2CTXD = ((addr << 1) | 0x01); //I2C_ADDR + READ 送信
I2CMSCR = 0x02;
while(!(I2CMSST & 0x40));
I2CMSST &= ~0x40;
i=reply(); //ACK、NACK返答確認
I2CMSCR = 0x06; //I2C ストップ
while(!(I2CMSST & 0x40));
I2CMSST &= ~0x40;
return i;
}
void main(void) //main関数
{
P3M0 = 0x00; //P3ポートを準双方向モードに
P3M1 = 0x00;
P5M0 = 0x00; //P5ポートを準双方向モードに
P5M1 = 0x00;
uart_init();
printf_tiny("STC8G1K08A I2C address search Test !\r\n");
int i, j, addr;
P_SW2 = 0x80;
I2CCFG = 0xe0; //マスターモード
I2CMSST = 0x00;
do{ printf_tiny("I2C Address Search (STC8G1K08A)\r\n");
printf_tiny("Addr 0 1 2 3 4 5 6 7 8 9 a b c d e f\r\n");
for (i = 0; i <= 0x7; i++) {
printf_tiny(" %x ", i*0x10);
for (j = 0; j <= 0xf; j++) {
addr = i * 0x10 + j;
switch(i2c_addr(addr)){
case 0x1: //addr+R >> NACK
printf_tiny("* ");
break;
case 0x0: //addr+R >> ACK
printf_tiny("%x",addr);
break;
default:
printf_tiny("er");
}
}
printf_tiny("\r\n");
};
printf_tiny("s key = research!\r\n");
}while(getchar() == 's');
}
コンパイルします。
$ sdcc -mmcs51 --model-small --xram-size 0x400 --xram-loc 0x0000 --code-size 0x2000 STC8G1K08A_I2C_search.c
ihxからインテルHEXコードhexに変換します。
$ packihx STC8G1K08A_I2C_search.ihx > STC8G1K08A_I2C_search.hex
packihx: read 46 lines, wrote 81: OK.
STC8G1K08Aに書き込みします。
$ stcgal -P stc8g -t 22118.4 -p /dev/ttyUSB0 STC8G1K08A_I2C_search.hex
Waiting for MCU, please cycle power: done
Target model:
Name: STC8G1K08A-8PIN
Magic: F794
Code flash: 8.0 KB
EEPROM flash: 4.0 KB
Target frequency: 22.094 MHz
Target BSL version: 7.3.13U
Target wakeup frequency: 36.800 KHz
Target ref. voltage: 1185 mV
Target mfg. date: 2024-07-01
Target options:
reset_pin_enabled=False
clock_gain=high
watchdog_por_enabled=False
watchdog_stop_idle=True
watchdog_prescale=64
low_voltage_reset=False
low_voltage_threshold=2
eeprom_erase_enabled=True
bsl_pindetect_enabled=False
por_reset_delay=long
rstout_por_state=high
uart1_remap=False
uart2_passthrough=True
uart2_pin_mode=push-pull
epwm_open_drain=True
program_eeprom_split=8192
Loading flash: 1172 bytes (Intel HEX)
Target frequency: Target 22.118 MHz
Adjusted frequency: 22.102 MHz(-0.076%)
Switching to 115200 baud: done
Erasing flash: done
Writing flash: 1600 Bytes [00:00, 6286.93 Bytes/s]
Finishing write: done
Setting options: done
Target UID: F794C4161F25D0
Disconnected!
ターミナルで確認します。
まずはI2Cデバイスを接続していないとき、続いてEEPROMである24FC1025を接続したとき(A0~A2はオープンのとき)次にA0だけをプルアップしたときのI2Cアドレスをサーチしてみました。
STC8G1K08A I2C address search Test !
I2C Address Search (STC8G1K08A)
Addr 0 1 2 3 4 5 6 7 8 9 a b c d e f
0 * * * * * * * * * * * * * * * *
10 * * * * * * * * * * * * * * * *
20 * * * * * * * * * * * * * * * *
30 * * * * * * * * * * * * * * * *
40 * * * * * * * * * * * * * * * *
50 * * * * * * * * * * * * * * * *
60 * * * * * * * * * * * * * * * *
70 * * * * * * * * * * * * * * * *
s key = research!
I2C Address Search (STC8G1K08A)
Addr 0 1 2 3 4 5 6 7 8 9 a b c d e f
0 * * * * * * * * * * * * * * * *
10 * * * * * * * * * * * * * * * *
20 * * * * * * * * * * * * * * * *
30 * * * * * * * * * * * * * * * *
40 * * * * * * * * * * * * * * * *
50 50* * * * * * * * * * * * * * *
60 * * * * * * * * * * * * * * * *
70 * * * * * * * * * * * * * * * *
s key = research!
I2C Address Search (STC8G1K08A)
Addr 0 1 2 3 4 5 6 7 8 9 a b c d e f
0 * * * * * * * * * * * * * * * *
10 * * * * * * * * * * * * * * * *
20 * * * * * * * * * * * * * * * *
30 * * * * * * * * * * * * * * * *
40 * * * * * * * * * * * * * * * *
50 * 51* * * * * * * * * * * * * *
60 * * * * * * * * * * * * * * * *
70 * * * * * * * * * * * * * * * *
s key = research!
次はI2Cデバイスを色々と接続してみたいですね。