Top Page [◀◀]  2   3   4   5   6   7   8   9   ... [▶▶Last Page

C言語開発で,IOレジスタ直叩きの際,書き込み完了待機をするには

こんにちは

初めてこのフォーラムを利用させていただきます.

 RXマイコン(RX621)とマトリクス接続されたスイッチ(秋月)を接続し,キー入力を取得しようとしているのですが,
おそらくIOレジスタの読み込みが早すぎて出力の変更が反映される前にポート読みされていないようなのです.
ハードウェアマニュアルP131にはIOレジスタ書き込み時の注意事項があるので,これが原因ではないかと思っているのですが,対処方法がわかっていません.

>>引用
このような場合には、I/O レジスタの書き込みを行った後、以下の手順で書き込みの完了を待ってから、後
続の命令を実行するようにしてください。
(a) I/Oレジスタの書き込み
(b) 書き込んだI/Oレジスタの値を汎用レジスタに読み出し
(c) 読み出し値を使って演算を実行
(d) 後続の命令を実行

 

秋月のキーマトリクスキット
http://akizukidenshi.com/catalog/g/gK-12229/
を使用しています.

PORTDの4~6bit目を出力モードにし,マトリクスのXYZへ入力,
PORTDの0~3bit目を入力モードにし,マトリクスのABCDへ接続

 

ソースのコメントアウトされたdelay_ms(1)を入れると正しく動作します.
最初,レジスタを読めばいいのかと思い,以下のようにwhileをdelay_msの代わりに挿入してみましたがこの方法ではうまくいきませんでした.

while(PORTD.DR.BYTE != 0xb0);


以下ソース

※KEY_XDなどはdefineで整数を割り振っています


int8_t GetMatrixInput(){
    int8_t ret = 0;
 
    uint8_t a;
    PORTD.DR.BYTE = 0xb0;   //1011
    //delay_ms(1);
 
    a = PORTD.PORT.BYTE & 0x0f;
    if(!(a & 1)){
        ret = KEY_XD;
    }else if(!(a & 2)){
        ret = KEY_XC;
    }else if(!(a & 4)){
        ret = KEY_XB;
    }else if(!(a & 8)){
        ret = KEY_XA;
    }
    if(ret)
    return ret;


    PORTD.DR.BYTE = 0xd0;   //1101
    //delay_ms(1);
 
    a = PORTD.PORT.BYTE & 0x0f;
    if(!(a & 1)){
        ret = KEY_YD;
    }else if(!(a & 2)){
        ret = KEY_YC;
    }else if(!(a & 4)){
        ret = KEY_YB;
    }else if(!(a & 8)){
        ret = KEY_YA;
    }
    if(ret)
    return ret;


    PORTD.DR.BYTE = 0xe0;   //1110 0000
    //delay_ms(1);
 
    a = PORTD.PORT.BYTE & 0x0f;
    //return a;
    if(!(a&1)){
        ret= KEY_ZD;
    }else if(!(a&2)){
        ret= KEY_ZC;
    }else if(!(a&4) ){
        ret= KEY_ZB;
    }else if(!(a&8)){
        ret = KEY_ZA;
    }

    return ret;
}
  • チョコです。
    RXは使ったことはありません。
    しかし、キー・マトリクスを制御する場合には、配線容量等の影響で遅延が発生します。
    そのため、制御信号(スキャン信号)を切り替えても直ぐにリターン信号は正しい状態にはなりません。特に、配線容量を抵抗でチャージする場合には、期待される信号になるまでには時定数に比例するような時間が必要です。
    このためには、読出しまでに時間をかける必要があります。このためのdelay_ms(1)だと考えられます。

    このためだけの遅延処理がいやならば、定周期割り込み等でリターン信号の読出しを行い、その後にスキャンラインを更新します。
    次の定周期割り込み等でリターン信号(前回の結果)の読出しを行い、その後にスキャンラインを更新します。これを繰り返すことで、必要なキースキャンが可能です。(定周期の割り込みで処理するのは、チャタリング対策のためでもあります。
  • こんにちは
    書いてから読むのではなく
    読んでから次回XYZを書くようにしたらいかがでしょうか?
  • In reply to チョコ:

    お返事ありがとうございます

    なるほど,確かに配線容量等の影響は考えていませんでした
    マトリクスまで基板のパターンとケーブル含めて50cmくらい引き回しているので十分影響は大きそうです

    すぐにご報告できないかもしれませんが,検証してみたいと思います

    ポートの書き込み完了待機についてはマトリクスを介さずに2つのポートを直結してみても良いのかもしれません.とりあえず試してみたいと思います.
  • In reply to 3wayrenesas:

    お返事ありがとうございます
    恥ずかしながらその発想はありませんでした

    今回のソースではGetMatrixInputの中で3回列を変えながらスキャンしているのでそのままでは適用できませんが,解決策として大変面白いと思いました
  • In reply to ぴょん:

    チョコです。
    キースキャンについては、Renesasの「FAQ(よくあるお問い合わせ) インフォメーション」というPDFファイルの293ページから解説があるので、参考にしてみてください。
    8bitの78K0のアセンブラでのプログラムですが、説明の部分だけでも役に立つと思います。
    3wayrenesasさんがコメントした方法は、296ページの「【ちょっと注意 2】 」にタイミングチャート付きで説明されています。

    このPDFは、RenesasのTopページで"FAQ"で検索し、「キーワード検索」のページのドキュメントには6件該当でそのうちの4件だけが表示されるので、「ドキュメントをもっと見る」をクリックすると見れるようになります。
    ちょっとサイズが大きいですが、一度ダウンロードされることをお勧めします。
  • In reply to チョコ:

    こんなPDFがあったんですね
    ノウハウの塊で大変参考になります


    実験結果のご報告ですが,試しに
    PORTBとPORTCを直結して,次のようなソースを試してみました.


    PORTB.DDR.BYTE = 0xff;
    PORTC.DDR.BYTE = 0x00;
    PORTC.ICR.BYTE = 0xff;
    delay_ms(10);

    PORTB.DR.BYTE = 0x55;
    uint8_t data = PORTC.PORT.BYTE;
    xprintf("data(1)=%X\n", data);
    delay_ms(1);
    data = PORTC.PORT.BYTE;
    xprintf("data(2)=%X\n", data);
    while(1);

    実行結果は,
    data(1)=55
    data(2)=55

    となり,ポートの書き込み完了を待機することをせずとも問題がないということがわかりました.
    まだオシロでのチェックはできていませんが,今回の件はマトリクスまでの容量チャージが追い付いていないことが原因と結論付けられそうです.
    となると教えていただいた手段含め,何らかの方法で容量チャージ分の時間を待たねばならないようです.

    Arduinoを使っていたころはそもそもdigitalWrite等が激遅だったので気にする必要がなかったのですね.大変勉強になりました.

Top Page [◀◀]  2   3   4   5   6   7   8   9   ... [▶▶Last Page