Entry

AT90S2313 で UART してみる

2004年06月13日

せっかく 2313 をいぢっているので,UART のシリアル通信をやってみました。

Atmel のアプリケーションノートによると,1200 みたいに UART を持っていない MCU でも非同期半二重通信を実装する方法が紹介されていますけど(参照:「AVR305: Half Duplex Compact Software UART」[PDF]),2313 の割り込みによる方法は,それよりももっと使いやすくできています。当たり前ですけど。

2313 のデータシートから UART の紹介部分を丸写ししてみると,

  • 各種ボーレートを生成できるボーレートジェネレータ
  • 周波数の低いクリスタルでも高いボーレートを作れる
  • 8bit と 9bit の両方を扱えます
  • ノイズフィルタあります
  • オーバーランを検知できます
  • フレーミングエラーも検知できます
  • スタートビットのエラーも見つけちゃいます
  • 送信完了,受信完了等々のそれぞれで割り込みが独立しています

といったところ……。豪華ですね。普通に PC 等々と連携させるだけなら十分過ぎる機能じゃないでしょうか。

ここでは単純に,「PC から送られた ASCII キャラクタをエコーバックする」といったことをやってみます。ただ,単純にエコーバックするだけじゃただのマグロ回路なので,もう少し反応するように,「受け取った小文字の ASCII キャラクタを大文字に変換してエコーバックする」くらいのことはさせてみることにします。

ちなみに,2313 のシリアル通信は全二重で通信できるけれど,ここでは半二重的に使うことにします。全二重だったら受信データをバッファリングすることもできそうな感じですけど,いかんせんあたしがよく分かってないもんで……。

UART する方法

2313 で UART を扱うには,大きく分けて2通りあります。つまり,

  • UART のデータレジスタ(UDR)を監視する方法
  • 割り込みを使う方法

です。それぞれ長短はあるようですけど,個人的な感覚からすると割り込みを使う方が手軽なような気がします。割り込みというと 1200 のようなスタックの少ない MCU だと,サブルーチンの階層を気にしないといけないけど,2313 では(あまり)気にする必要はありません。

ここでは,割り込みを使ってやってみます。

UART なレジスタたち

中身をいぢる前に,UART で使うレジスタを紹介しておきます(詳しくはデータシートを参照してください)。

UDR(UART Data Register)

UDR は送受信に使うデータの中身です。このレジスタにデータを書くと,そのデータが送信されるし,受信したときにこのレジスタの値を読むと,受信データを受け取ったことになるわけです。TxD も RxD も同じレジスタを使うってのは不思議な感じですけど,送信用レジスタと受信用レジスタは物理的に分離しているそうです。

単純ですけど,一応レジスタの構成をば……。

Bit76543210
Namedata7data6data5data4data3data2data1data0
I/OR/WR/WR/WR/WR/WR/WR/WR/W

USR(UART Status Register)

UART の状態を調べるのに使います。

Bit76543210
NameRXCTXCUDREFEOR---------
I/ORR/WRRRRRR

割り込みを使わないときは,RXC あたりを監視することになるんでしょうか。今回はいぢってないので深く触れません(触れられません)。

UCR(UART Control Register)

UART の挙動を設定するのに使うレジスタです。ビットフラグになってるので,必要なところをを立てて使います。

Bit76543210
NameRXIETXIEUDRIERXENTXENCHR9RXB9TXB9
I/OR/WR/WR/WR/WR/WR/WRW

上位ビットから順番に,「割り込み許可」(RXIE,TXIE,UDRIE),「送受信の許可」(RXEN,TXEN),「9bit モードのときに使うモノ」(CHR9,RXB9,TXB9)といったところです。後で説明しますけど,割り込みの許可・不許可はここで設定するだけじゃ不十分で,全体的な割り込み許可を出しておく必要があります。

UBRR(UART Baud Rate Register)

UART のボーレート(baud rate)を設定するのに使うレジスタです。8bit の値を入れるとボーレートを設定できます。

Bit76543210
Namedata7data6data5data4data3data2data1data0
I/OR/WR/WR/WR/WR/WR/WR/WR/W

どんな値を入れるかは,BAUD = f_CK / 16(UBRR+1) という方程式から求まります。ただ,いちいち計算するのは面倒臭いので,実際はデータシートにある表を見て適切な値を入れることになっています。参考までに 4MHz のクリスタルを使う場合の表を抜き出してみると……

Baud Rate4MHz%Error
2400UBRR=1030.2
4800UBRR=510.2
9600UBRR=250.2
14400UBRR=162.1
19200UBRR=120.2
28800UBRR=83.7
38400UBRR=67.5
57600UBRR=37.8
76800UBRR=27.8
115200UBRR=17.8

ってな感じです。よくまとまっていて便利ですね。

回路を作るぞっ

能書きたれたれなので,いい加減にモノを作ることにします。回路図はこんな感じ。

UART のテスト回路

シリアル通信お馴染みの MAX232 ファミリーでつなげただけです。これで EIA-232 レベルの電圧を TTL レベルに変換するわけです。2313 には RD0(RxD)と RD1(TxD)に線をつなげましょう。単純ですね。

結局,できたもんがこれ。

UART のテスト回路

あれれ……,奥の方に 74HC393 が見えますね……。今回の回路は別に作ってるモノの一部なので,ゴニョゴニョいろいろ付いてます。他にも変なモノがいろいろ見えますけど,回路図にない部品は無視してください。そのうち全部について紹介できるかもしれません……。

ファームウェアを書くぞっ

さて,やっとこさプログラミングです。ここでやりたいことは,「うけとったデータ(ASCII データ)を大文字に変換してエコーバックする」というものですから,具体的には,

  1. UART の設定をする
  2. 割り込みがくるまで待っている
  3. 受信完了の割り込みが入ったら,受信データを大文字に変換して送信
  4. また割り込みが入るまで待つ(2に戻る)

といった手順にすればよさそうです。プログラムにするとこんな感じ……。

;;; 
;;; UART TEST
;;;

.include "2313def.inc"

.equ    br      = 12            ; set 19200bps @4MHz XTAL
.def    temp    = r16
.def    dt      = r17           ; UART data
.def    status  = r23           ; SREG preservation

.cseg
.org 0
        rjmp    reset           ; reset
        reti                    ; external interrupt 0
        reti                    ; external interrupt 1
        reti                    ; timer/counter1 capture event
        reti                    ; timer/counter1 compare match
        reti                    ; timer/counter1 overflow
        reti                    ; timer/counter0 overflow
        rjmp    rx_cmp          ; UART RX complete
        reti                    ; UART data register empty
        reti                    ; UART TX complete
        reti                    ; analog comparator

reset:
        cli                     ; disable global interruption
        ;; Stack init
        ldi     temp, low(RAMEND)
        out     SPL, temp
        ;; PORT init (these value will be chaged at following UART init ..)
        ldi     temp, $ff
        out     DDRB, temp
        out     DDRD, temp
        ldi     temp, 0b00000000
        out     PORTB, temp
        ldi     temp, 0b00000000
        out     PORTD, temp
        ;; UART init
        ldi     temp, br        ; set baud rate
        out     UBRR, temp
        ldi     temp, 0b11111000; UCR set
        out     UCR, temp
        sei                     ; enable global interruption
main:                           ; waiting for RX complete interruption
        rjmp    main

;; UART
rx_cmp:
        in      status, SREG
        in      dt, UDR         ; receive data
        subi    dt, $20         ; translate ASCII char into upper case
        out     UDR, dt         ; transmit data
        out     SREG, status
        reti

AVR の場合,割り込みはベクタで管理しているので,該当する場所にルーチンを書いておきます。ここでは,受信完了の(RX complete)の割り込みを有効にして rx_comp ルーチンに飛ぶようにしておきました。

rx_comp ルーチンでは,データ受信後,大文字に加工してから送信しています(ASCII 配列では小文字の値から $20 引くと大文字の値になる)。UDR を読み書きするだけなんで簡単ですね。特に難しいことはしていません。

ちょっと話が前後してますけど,次に UART の設定です。ここでは,UBRR でボーレートを設定して,UCR で UART の挙動を設定しています。

ボーレートは UBRR に定数を書き込みます。ここでは,19200bps で通信したいので,"12" を書き込んでおきます。UBRR の項でも書いたとおり,この定数はデータシートを参照して決定します。クリスタルの周波数が高いほど,エラーレートが小さくなるようですけど,待ち時間のルーチンを作る場合なんかは低い周波数の方が扱いやすいので,両者の兼ね合いが悩みどころかもしれませんね。データシートによると 4MHz のクリスタルでは,19200bps が実用の限度みたいです。

UCR の書き込みでは割込み等々を有効にしています(USR ← 0b11111000)。どんなことを設定しているかは,上記 UCR の項を参照してください。

最後に,全体の割り込みを有効にするために,

        sei

しておきます。データシートにさりげなく書いてあるけれど,これをしておかないと UCR をいぢっても割り込みが起きません。忘れずに SREG の割り込み許可フラグを立てておきます。

通信してみる

シリアル通信というと,Windows よりも FreeBSD の方が得意なので,母艦は FreeBSD BOX にします。FreeBSD には cu というコマンドがあるので,これで通信してみましょう。

% cu -l /dev/cuaa0 -s 19200
connected

と表示されたら,適当に入力してみます。小文字のアスキー文字しかまともに受け付けられない「仕様」なので,小文字だけを使ってください。例えば,「abcd」と入力するのに対して,

ABCD

と表示されたら成功です。ええ,これだけです。苦労した割には地味ですね。

今回は,UART の基本的な部分でしたから地味なのも仕方ありません。受信ルーチンをもう少し工夫すれば,もう少し複雑な処理でも PC から操作できるようになるはずです。実は,AVR910 もこんな感じで制御コードをやりとりしてたりしますしね(「バージョン番号返せ」の命令なら「V」を送信するみたいに)。

余裕があれば,「ログインシェルみたいなものを実装する」とか,「データを受け取ったら LED を決まったパターンで光らせる」とかいったことをしてみても面白いかもしれません。

Trackback
Trackback URL:
Ads
About
Search This Site
Ads
Categories
Recent Entries
Log Archive
Syndicate This Site
Info.
クリエイティブ・コモンズ・ライセンス
Movable Type 3.36
Valid XHTML 1.1!
Valid CSS!
ブログタイムズ

© 2003-2012 AIAN