SSブログ

SilentCが使っていないモジュールを探せ(9) [ColdFire V2]このエントリーを含むはてなブックマーク#

1990557

モジュール探訪の旅。 今日は、Universal Asynchronous Receiver / Transmitter (UART) を走ります。

最初は、レジスタのダンプから

UARTは、いわゆる非同期シリアル・インターフェースの事で、8ビットマイコンでは、 Serial Communication Interface (SCI) という名前で呼ばれたりします。 いずれも、信号レベルを変換して RS-232C という規格に使用されます。

MCF52233の三つのUARTのうち、UART0はSilentCのコンソールとして使用されていることが分かっていますので、適切にレジスタが設定されているはずです。 さっそく、レジスタを調べてみましょう。

40000200  07 00 00 00 0c 00 00 00  ........
40000208  00 00 00 00 00 00 00 00  ........
40000210  1e 00 00 00 05 00 00 00  ........
40000218  00 00 00 00 08 00 00 00  ........
40000220  00 00 00 00 00 00 00 00  ........
40000228  00 00 00 00 00 00 00 00  ........
40000230  0f 00 00 00 fe 00 00 00  ........
40000238  00 00 00 00 00 00 00 00  ........

これは、UART0のレジスタです。 UART1/UART2のレジスタは、初期設定のままでしたので、今回は割愛します。

UARTのレジスタは、32ビット境界に8ビットずつ配置されています。 16ビットのボーレートレジスタでさえ、8ビットずつ配置されているので、簡単に16ビットの値を設定することはできません。 加えて、UMR10/UMR20レジスタのように同じアドレスに別のレジスタが配置されて、モードによって書き込み先レジスタが切り替わるような仕組みも入っています。 これは、またDMAのお世話にならなきゃいけませんね。 ダンプリストをとっただけでは、隠れたレジスタの値は確認できないので、DMAの力を借りて引っ張り出してみました。

char *uart0 =0x40000200;
main(){
  char *pacr2 =0x40000026;
  char *umr=MemoryAlloc(4);
  char usr,uipcr,uisr,uip;
  usr=uart0[0x04];uipcr=uart0[0x10];
  uisr=uart0[0x14];uip=uart0[0x34];
  *pacr2 = 0x40 | (*pacr2 & 0x0F); // Enable DMA for UART
  readUMR(uart0,umr);
  PrStr("\r\nUMR10 =");PrHexByte(umr[0]);
  PrStr("\r\nUMR20 =");PrHexByte(umr[1]);
  PrStr("\r\nUSR0  =");PrHexByte(usr);
  PrStr("\r\nUIPCR0=");PrHexByte(uipcr);
  PrStr("\r\nUISR0 =");PrHexByte(uisr);
  PrStr("\r\nUIP0  =");PrHexByte(uip);
  PrStr("\r\n");
  MemoryFree(umr);
}
readUMR(char *uart, char *buf){
  long *sar1  =0x40000110;
  long *dar1  =0x40000114;
  long *bcr1  =0x40000118;
  long *dcr1  =0x4000011c;
  *bcr1 = 0x01000000; // clear DONE
  uart[8] = 0x10; // UCR:Reset UMR pointer
  *sar1 = uart+0; // source=UMRx
  *dar1 = buf; // destination
  *bcr1 = 2; // byte count
  *dcr1 = 0x001B0000; // Simple byte transfer
}

こうなりゃ、意地でもSilentCを使ってやる。 実行結果は、こんな風になりました。

UMR10 =13
UMR20 =07
USR0  =0c
UIPCR0=0e
UISR0 =05
UIP0  =fe

今まで見えてこなかった、UMR10が出てきました。 ステータス・レジスタ以外の設定レジスタを表にしてみました。

UART0のレジスタ設定
レジスタ備考
UMR10 [RXRTS]0 (no effect) 受信機能では、URTS0出力(request to send)をネゲートすることで通信相手に受信できないことを知らせ、バッファあふれを防止することができます。 ここでは、使用していません。
UMR10 [RXIRQ/FFULL]0 (RXIRQ) 1キャラクタが受信機に到着するたびに割り込みまたはDMAを発生します。 ここで、1 (FFULL)を指定すると、3キャラクタ分のFIFOがいっぱいになるまで割り込みまたはDMAを発生させません。
UMR10 [ERR]0 (character mode) FIFOの先頭のキャラクタを受信したときのエラー情報をステータスレジスタUSRのRB/FE/PEビットに示します。 ここで、1 (block mode)を指定すると、エラー・リセット・コマンドを送るまでエラー情報を蓄積し続けます。
UMR10 [PM]10 (no parity) パリティ無しプロトコルを指定します。
UMR10 [PT]0 (N/A) パリティの極性を示しますが、PMビットが、10 (no parity)の場合には、無効です。
UMR10 [B/C]11 (8bits) キャラクタあたりのビット長を指定します。
UMR20 [CM]00 (normal) ループ・バックや自動エコー・バックの機能を指定します。 ここでは、ループ・バックもエコー・バックも使用しません。
UMR20 [TXRTS]0 (no effect) 送信機能では、URTS0出力(ready to send)をアサートして送信するキャラクタがあることを通信相手に知らせることができます。 ここでは、使用していません。
UMR20 [TXCTS]0 (no effect) 送信機能では、通信相手から送られてきたUCTS0入力(clear to send)信号がアサートされるまで通信を止めることができます。 この機能によって、通信相手の受信バッファあふれを防ぐことができます。 ここでは、使用していません。
UMR20 [SB]0111 (1 bit) 1キャラクタの通信の最後にあるストップ・ビットの幅を指定します。 1ビット幅のストップ・ビットが使用されます。

と、各レジスタビットを並べてみましたが、UARTモジュールの設定レジスタは、多くが書き込み専用(write-only)になっているので、レジスタを読み取るだけでは本当の設定がわかりません。 例えば、ボーレートレジスタUBG10/UBG20も書き込み専用なので、ボーレートの設定も確認できない状態です。 これは、セキュリティなのか?

Interface誌の「マイコン基板とRS-232Cボードの接続図」では、UCTS0端子がGNDに接続されて「いつでも受信できます」状態になっています。 ところが、レジスタ設定だけを見ると、UCTS0入力で送信を抑止する機能(TXCTS)は使用されていないことがわかります。 ソフトウェアで処理しているのかな?

SilentCからUART1を使う

UART0は、SilentCによって使用されているので、ここではUART1を使用します。

最初にボーレートの計算を行っておきます。 今回は、SilentCと同じく 57600baud;8bit;no-parity;1-stopbit プロトコルを使用します。

divider=(60MHz)÷(32×57600Hz)=32.55

ということで、UBG11=0x00;UBG21=0x21;としてみます。 誤差が1.7%と大き目ですが、まあ大丈夫でしょう。

処理する内容ですが、「HELLO WORLD!」を延々と送信し続けるプログラムを作成してみました。

main(){
  char *pubpar=0x40100072;
  char *pacr2 =0x40000026;
  char *uart1 =0x40000240;
  char *ucr1  = uart1+0x08;
  char *msg   ="HELLO WORLD!\r\n";
  char *s;
  *pacr2 = 0x04 | (*pacr2 & 0xF0); // Enable DMA for UART1
  *pubpar= 0x05; // select URXD1/UTXD1
  *ucr1  = 0x0A; // disable RX/TX
  setUMR(uart1, 0x13, 0x07); // Set UMR
  setUBG(uart1, 0x0021); // Set UBG
  *ucr1  = 0x04; // enable TX
  s = msg;
  #stop 0;
  for (;;){
    if (Getc(0)=='q') break;
    while (!isTXRDY(uart1)) SystemSleep();
    writeUTB(uart1, *s++);
    if (*s == 0) s = msg;
  }
}
readUMR(char *uart, char *buf){
  long *sar1  =0x40000110;
  long *dar1  =0x40000114;
  long *bcr1  =0x40000118;
  long *dcr1  =0x4000011c;
  *bcr1 = 0x01000000; // clear DONE
  uart[8] = 0x10; // UCR:Reset UMR pointer
  *sar1 = uart+0; // source=UMRx
  *dar1 = buf; // destination
  *bcr1 = 2; // byte count
  *dcr1 = 0x001B0000; // Simple byte transfer
}
setUMR(char *uart, char umr1, char umr2){
  long *sar1  =0x40000110;
  long *dar1  =0x40000114;
  long *bcr1  =0x40000118;
  long *dcr1  =0x4000011c;
  char *buf = MemoryAlloc(4);
  buf[0] = umr1;
  buf[1] = umr2;
  *bcr1 = 0x01000000; // clear DONE
  uart[8] = 0x10; // UCR:Reset UMR pointer
  *sar1 = buf; // source
  *dar1 = uart+0; // destination=UMR
  *bcr1 = 2; // byte count
  *dcr1 = 0x00530000; // Simple byte transfer
  MemoryFree(buf);
}
setUBG(char *uart, int baud){
  writeByte(uart+0x18, (baud>>8)&0xff);
  writeByte(uart+0x1c, (baud   )&0xff);
}
isTXRDY(char *uart){
  return uart[0x04]&0x04;
}
isRXRDY(char *uart){
  return uart[0x04]&0x01;
}
writeUTB(char *uart, char c){
  writeByte(uart+0x0c, c);
}
readURB(char *uart){
  return uart[0x0c];
}
writeByte(char *addr, char data){
  long *sar1  =0x40000110;
  long *dar1  =0x40000114;
  long *bcr1  =0x40000118;
  long *dcr1  =0x4000011c;
  char *buf = MemoryAlloc(4);
  buf[0] = data;
  *bcr1 = 0x01000000; // clear DONE
  *sar1 = buf; // source
  *dar1 = addr; // destination=UTB
  *bcr1 = 1; // byte count
  *dcr1 = 0x00530000; // Simple byte transfer
  MemoryFree(buf);
}

実行速度は、毎秒3行ほどでした。 換算すると、500bpsほどにしかなりません。 やはり、このあたりがインタプリタの限界でしょうか。

UARTモジュールには、読み出し・書き込みを厳密に制御しなくてはならないところがたくさんあります。 リファレンス・マニュアルには、「UBGレジスタから値を読み出すと、良く分からないことが起きて、送受信がうまくいかなくなるよ。」などと脅し文句が書いてあります。 また、URB/UTBレジスタは、同じアドレスに配置されているので、送信データを書き込む時に読み出しアクセスが発生すると、せっかく受信したデータが消えてしまいます。 こういった、クリティカルな箇所は、すべてDMAによる転送処理を使用しました。 え~と、これは、何のプログラムだっけ。

参考文献

Interface (インターフェース) 2008年 09月号 [雑誌]

Interface (インターフェース) 2008年 09月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/07/25
  • メディア: 雑誌

nice!(0)  コメント(0)  トラックバック(0)  このエントリーを含むはてなブックマーク#

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

トラックバックの受付は締め切りました

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。