SCIの使い方(その2)
SCI割り込み関連レジスタ
・SCSCR(シリアルコントロールレジスタ)
SCIには次の4つの割り込みがある。
TXI : 送信データエンプティ割り込み(次の送信データを書き込み可能になった時に発生)
TEI : 送信終了割り込み(送信データの最終ビットを送り出したときに、次のデータがないときに発生)
RXI : 受信データフル割り込み(受信が完了し、受信データを読み出し可能になった時に発生)
ERI : 受信エラー割り込み(受信エラーを検出した時に発生)
SCSCRの各ビットで割り込みの発生を禁止/許可することができる。
・IPRL(インタラプトプライオリティレジスタL)
SCI割り込みの優先順位(レベル0~15)は、チャネルごとに1つだけ設定できる(例えば”SCI1はレベル8″のように)。チャネル内の優先順位は固定であり、ERI>RXI>TXI>TEIの順になっている(ERIが優先順位が高く、TEIが低い)
他の割り込みと同様に、レベル0の時は割り込みは発生しなくなる。
SCI割り込みとリングバッファ
ここでは、通信の処理でよく使われるリングバッファについて解説する。
リングバッファと呼ばれる仕組みがある。リングバッファはFIFO(First In First Out)と考えることもできる。
これを実現するには必要な容量の配列とリードポインタ、ライトポインタを用意する。
バッファに書き込むときは、ライトポインタの指す位置にデータを格納し、ライトポインタを一つ進める。
バッファから読み出すときは、リードポインタの指す位置のデータを読み出し、リードポインタを一つ進める。
リードポインタ、ライトポインタともに、配列の終端に達した場合は先頭に戻す。
このような仕組みを使うことにより、配列の容量を超えない限り、終わりのないバッファとして使うことができる。
1: char buf[64]; 2: int wptr, rptr; 3: 4: void write_buf(char data) 5: { 6: buf[wptr++] = data; 7: if (wptr >= 64) 8: wptr = 0; 9: } 10: 11: char read_buf() 12: { 13: char ret; 14: ret = buf[rptr++]; 15: if (rptr >= 64) 16: rptr = 0; 17: return (ret); 18: }
通信関係のプログラムで割り込みを使う場合は、このようなリングバッファを使うことが多い。
例えばsci_put_str()関数では送信用リングバッファにデータを転送し、送信を開始するようにSCIのレジスタを操作する。
1文字送信完了するたびに割り込みが発生するので、割り込み関数の中で送信用リングバッファから次の1文字を読み出して送信データレジスタに書き込む。
またsci_get_ch()関数では受信用リングバッファにデータがあれば、それを読み出すだけとする。
実際の受信処理は割り込み関数の中で、受信データレジスタを読み出して受信用リングバッファに格納するようにする。
このように、割り込み関数で行う処理と、一般関数で行う処理とをリングバッファを介して分離して、割り込みを意識させないようにする。
割り込みによるSCI通信の実現
ここでは、SCIの送受信割り込みと、リングバッファを組み合わせた、SCIによる調歩同期式通信の実現のための4つの関数について解説する。
受信動作は、データの取得とリングバッファへの格納を行うための受信割り込み関数と、リングバッファから受信データを取り出す(割り込み関数でない)一般関数、の二つで構成する。
・受信割り込み関数
受信割り込み関数のフローチャートを次に示す
SCIのSCRDRから受信データを読み出し、リングバッファに格納している。
・受信データ読み出し関数
リングバッファ内の受信データを読み出す関数である。これは割り込みではなく、通常処理の中で使う関数である。フローチャートを次に示す。
未読み出しデータの有無は、リードポインタとライトポインタを比較することにより判断することができる。リードポインタ = ライトポインタであれば、未読み出しデータは存在しない。
データ送信については、次の点に考慮して設計を行っている。
SCIの送信関連の割り込みは、TXI(次の送信データを書き込むことができる)とTEI(最後のデータ送出を完了した)の2種類があり、次の送信データを書き込むための割り込みとして使用することができる(データを連続送信する場合の2バイト目以降は、割り込み関数で送信データを書き込むことができる)。
しかし、最初の1バイトは送信割り込みで送ることはできない(何かを送信し終わらないと、割り込みは発生しない)。
これを解決するために、送信データ書き込み関数と、送信割り込み関数において、TDREビットと割り込み許可/禁止を使い、次のような処理を行う。
① 送信データ書き込み関数において、送信データを書き込める状態の時(TDRE = 1のとき)は直接SCIにデータを書き込み、送信割り込みを許可する(最初の1文字の送信)。TDRE=0の時は送信リングバッファにデータを書き込む(連続送信するときの2文字目以降)。
② 送信割り込み関数では、次の送信データがあるとき(送信リングバッファにデータがある)には、次の送信データをSCTDRに書き込み、TDREビットをクリアする。そうでないときは割り込みを禁止する(このときTDREビットはクリアしない。クリアしてしまうと、最初の1文字目を書き込めなくなる)
ここでは、送信割り込みとしてTXI(次の送信データを受け付け可能になると割り込み発生)を使用する。TEI(送信が完了してから割り込みが発生)では、送信データ間に隙間が空いてしまうため、厳密には連続送信にならないし、通常のアプリケーションでもTXIを主に使用するためである。
・送信データ書き込み関数
送信データをリングバッファに格納し、送信を開始する関数である。フローチャートを次に示す。
最初の1バイト目の場合は、この関数内でSCTDRにデータを書き込み、送信を開始する。
2バイト目以降は、送信割り込み内でSCTDRにデータを書き込むので、この関数はリングバッファに格納するだけである。
この関数の先頭でTXI割り込みを禁止しているが、禁止しない場合には誤動作する可能性がある。例えば、TDRE==0と判断をした直後で送信リングバッファにデータを格納する前に、TDRE=1になりTXI割り込みが発生した場合、TXI割り込み処理内で未送信データなしと判断して送信を終了してしまうことが考えられる。
・送信割り込み関数
送信割り込み関数のフローチャートを次に示す。
リングバッファ内にデータがある場合は、連続して送信データを書き込む。
リングバッファ内にデータがなくなった時は、TXI割り込みの発行を禁止する。送信の再開は送信データ書き込み関数で行っている。
演習
次のワークスペースをダウンロードし、展開する。
SCI2.zip
・演習1
SCI2_1.cの、関数INT_SCI1_TXI1()とsci1_putch()は未完成である。上のフローチャートを参考にして、これらの関数を完成せよ。
正常動作すると、Htermに’1’と表示される。
・演習2
SCI2_1.cの、関数sci1_putstr()は未完成である。この関数を完成せよ。
正常動作すると、Htermに”234567890″と表示される。
・演習3
SCI2_1.cの、関数INT_SCI1_RXI1()とsci1_getch()は未完成である。上のフローチャートを参考にして、これらの関数を完成せよ。
正常動作すると、Htermから送信した文字が、MEMEsのLCDに表示される。