IOポートに関する補足

Copyright(C)12Nov2005
coskx

1.IOポートへの出力

IOポート(入出力ポート)は,メモリと同じアドレス空間にある。(メモリマップトIO)IOポートはメモリの一部のように見え,8ビットデータを書き込んだり読み出したりすることができる。
ある出力ポートに8ビットデータを書き込むと,そのポートにつながる端子から1と0のビットパターンが電圧のVccまたはGNDレベルとして出力される。
ある入力ポートから8ビットデータを読み出すと,そのポートにつながる端子に与えられた電圧のVccまたはGNDレベルを1と0として読み出すことができる。

2.出力ポート5のアドレスとCPUの外側

H8/3052のマザーボードでは,ポート5の第0ビットと第1ビットがそれぞれ2つのLEDにつながれているため,ポート5の第0ビットと第1ビットに1と0のビットパターンを出力することにより,LEDの点灯消灯を実現できる。(図1,2,3参照)

図1 マザーボード,CPUカード,CPUの接続
ポート5の第0ビットと第1ビットはCPUの53番ピン,54番ピンから外部に出ており,CPUカードのコネクタ3(CN3)の31,32ピンに接続されています。
マザーボード上ではCN3の31,32ピンから1.5kΩの抵抗を介してLEDにつながっています。
図2 CPUカード
実際のCPUカードのCN3の31,32ピン
右の図とは上下が逆なので注意
図3 マザーボード
マザーボード上でCN3の31,32ピンから引き出されているLED

 

3.ポート5の実体

AKI-H8/3052は,H8/300Hアドバンスモードのモード7で動作しているこの時のアドレスとメモリの関係は表1のようになっている。
特に,ポート5に関しては表2のようになっている。 メモリ空間は1Mバイトになる。

実際のプログラムでは,16Mバイトメモリ空間モードに対応できるような記述となるため,アドレスは16進6桁で記述している。
1Mバイトメモリ空間の場合,アドレスの上位4ビットは捨てられてコンパイルされるため,実用上は差し支えない。

                     表1 メモリマップ

メモリの種類 アドレス 備考
ROM 0x00000-0x07FFFF (512kbyte) 実際にはフラッシュメモリ,書き込みモードでのみ書き込むことが出来る。
電源が切れても,内容は保たれる。

割り込みベクタテーブル,プログラム,定数,変数の初期値の格納場所
RAM 0xFEF10-0xFFF0F ( 4kbyte) 電源が切れると内容は消滅する。

変数,スタック(オート変数,戻りアドレス,レジスタ退避)の格納場所
I/Oレジスタ 0xFFF1C-0xFFFFF (228byte) I/Oレジスタ

              表2 IOレジスタポート5

ポート5レジスタの役割 アドレス
DDR データディレクションレジスタ(8ビット幅)
DR(8ビット)の各ビットを入力用に使うか出力用に使うかを定義する
ビットごとに0なら入力,1なら出力の設定となる。
0xFFFC8
DR データレジスタ(8ビット幅)
IOレジスタ
0xFFFCA

よくある質問
Q:どうしてポート5の第0ビットと第1ビットにLEDがつながれているのですか。
A:マザーボードの設計者がLEDをつなぐ位置をポート5の第0ビットと第1ビットに決めています。
Q:他のポートの適当なビットにLEDをつなぐことができますか
A:出力に使えるポートのビットであり,他の用途に使われていないのならLEDをつなぐことができます。
 ただし,ソフトウェアを対応させないとLEDを点灯することができません。

勘どころ

ポート5レジスタのアドレスが0xFFFC8であることはCPUの設計者が決めたことなので,使用者は変更することができない。
ポート5のbit0とbit1の先にLEDをつけたのはマザーボードの設計者が決め,配線がされているため,
使用者はプログラムの書き換えでポートの変更をすることはできない。

 

4.ポート5の実体を意識したLED点灯消灯のプログラム

ポート5の下位2ビットからデータを出力するためには,次の手順となる
(1)ポート5は入出力兼用であるため,下位2ビットを出力に使うように設定する
(2)ポート5の下位2ビットに任意のデータを出力する。
   (2進法で00,01,10,11の4通りしかない)

具体的な手順は図4を参考に,次の通りとなる。
(1)ポート5データディレクションレジスタ(8ビット幅)
 メモリマップドIOレジスタ アドレス FFFFC8
 ビットごとに0なら入力,1なら出力の設定となる。
 ここでは下位2ビットを出力とし,他を入力の設定にするため3を書き込む
(2)ポート5データレジスタ(8ビット幅)
 メモリマップドIOレジスタ アドレス FFFFCA
 下位2ビットにデータを書き込む

図4 CPUがポート5を通してLEDをON−OFFさせる様子


動作させるプログラムの手順は上記のとおりだが,Cプログラムでどのように記述するかについてはいろいろ工夫がある。
実用上は「4.4 ヘッダ記載のstruct表現によるプログラム」が使われているが,「4.1」から「4.3」は説明のために表
記方法を工夫している例である。

 

4.1 ポインタと#defineを用いて,あるアドレス(ポートP5)に直接データを書き込むプログラム

リスト1
#define P5DDR *(unsigned char*)0xffffc8
#define P5DR  *(unsigned char*)0xffffca

void msecwait(int msec)
/*mesc間なにもしない時間稼ぎ関数*/
{
    int i,j;
    for (i=0;i<msec;i++) {
        for (j=0;j<1588;j++);    /*1588は実測によって求めた値*/
    }
}

main()
{
    /*P5の下位2ビットを出力に設定*/
    /* P5のDDRの下位2ビットに1を与えるとこの設定になる*/
    /*DDRとはDataDirectionRegister(データ方向設定レジスタ)*/
    P5DDR =  0x3;     /*0x3 = 00000011(二進数)*/
    while(1) {/*これは無限ループ*/
        /*LED0をONに,LED1をOFFにする
          P5のDRの第0ビットを1に,第1ビットを0にする*/
        /*DRとはDataRegister(データレジスタ)*/
        P5DR=1;
        msecwait(1000);/*1000msecの間なにもしない*/
        /*LED0をOFFに,LED1をONにする
          P5のDRの第0ビットを0に,第1ビットを1にする*/
        /*LED0をOFFにする  P5のDRの第0ビットを0にする*/
        P5DR=2;
        msecwait(1000);
    }
}

4.2 ポインタとstructを用いた表現によるプログラム

リスト2
struct port5 {
    unsigned char      DDR;
    char               dummy;  /*ここは使われない*/
    unsigned char      DR;
};

#define P5 (*(struct port5*)0xffffc8)

void msecwait(int msec)
/*mesc間なにもしない時間稼ぎ関数*/
{
    int i,j;
    for (i=0;i<msec;i++) {
        for (j=0;j<1588;j++);    /*1588は実測によって求めた値*/
    }
}

main()
{
    /* P5のDDRの下位2ビットに1を与える*/
    P5.DDR =  0x3;     /*0x3 = 00000011(二進数)*/
    while(1) {/*これは無限ループ*/
        /*LED0をONに,LED1をOFFにする
          P5のDRの第0ビットを1に,第1ビットを0にする*/
        P5.DR=1;
        msecwait(1000);/*1000msecの間なにもしない*/
        /*LED0をOFFに,LED1をONにする
          P5のDRの第0ビットを0に,第1ビットを1にする*/
        P5.DR=2;
        msecwait(1000);
    }
}

4.3 ビットフィールドと共用体を用いた表現によるプログラム

P5.DRをバイト単位で扱ったり,ビット単位で扱えるように工夫している

リスト3
struct port5 {
    unsigned char      DDR;
    char               dummy;  /*ここは使われない*/
    union {
        unsigned char  BYTE;
        struct {
            unsigned char dummy6 :6; /*6ビット ここは使われない*/
            unsigned char B1     :1; /*1ビット*/
            unsigned char B0     :1; /*1ビット*/
        } BIT;
    } DR;
};

#define P5 (*(struct port5*)0xffffc8)

void msecwait(int msec)
/*mesc間なにもしない時間稼ぎ関数*/
{
    int i,j;
    for (i=0;i<msec;i++) {
        for (j=0;j<1588;j++);    /*1588は実測によって求めた値*/
    }
}

main()
{
    /*P5の下位2ビットを出力に設定*/
    P5.DDR =  0x3;     /*0x3 = 00000011(二進数)*/
    while(1) {/*これは無限ループ*/
        /*LED0をONに,LED1をOFFにする
          P5のDRの第0ビットを1に,第1ビットを0にする*/
        P5.DR.BYTE=1;
        msecwait(1000);/*1000msecの間なにもしない*/
        /*LED0をOFFに,LED1をONにする
          P5のDRの第0ビットを0に,第1ビットを1にする*/
        P5.DR.BYTE=2;
        msecwait(1000);
        /*LED0をONに,LED1をOFFにする
          P5のDRの第0ビットを1に,第1ビットを0にする*/
        P5.DR.BIT.B0=1;
        P5.DR.BIT.B1=0;
        msecwait(250);/*250msecの間なにもしない*/
        /*LED0をOFFに,LED1をONにする
          P5のDRの第0ビットを0に,第1ビットを1にする*/
        P5.DR.BIT.B0=0;
        P5.DR.BIT.B1=1;
        msecwait(250);
    }
}

4.4 ヘッダ記載のstruct表現によるプログラム

リスト4
#include <3052f.h>

void msecwait(int msec)
/*mesc間なにもしない時間稼ぎ関数*/
{
    int i,j;
    for (i=0;i<msec;i++) {
        for (j=0;j<1588;j++);    /*1588は実測によって求めた値*/
    }
}

main()
{
    /*P5の下位2ビットを出力に設定*/
    P5.DDR =  0x3;     /*0x3 = 00000011(二進数)*/
    while(1) {/*これは無限ループ*/
        /*LED0をONに,LED1をOFFにする
          P5のDRの第0ビットを1に,第1ビットを0にする*/
        P5.DR.BYTE=1;
        msecwait(1000);/*1000msecの間なにもしない*/
        /*LED0をOFFに,LED1をONにする
          P5のDRの第0ビットを0に,第1ビットを1にする*/
        P5.DR.BYTE=2;
        msecwait(1000);
        /*LED0をONに,LED1をOFFにする
          P5のDRの第0ビットを1に,第1ビットを0にする*/
        P5.DR.BIT.B0=1;
        P5.DR.BIT.B1=0;
        msecwait(250);/*250msecの間なにもしない*/
        /*LED0をOFFに,LED1をONにする
          P5のDRの第0ビットを0に,第1ビットを1にする*/
        P5.DR.BIT.B0=0;
        P5.DR.BIT.B1=1;
        msecwait(250);
    }
}