SNSへはこちら

AVR32マイコンやってみよう(10) - UART


続いて、各種デバッグメッセージを出す上で役に立つであろう、UART の設定をします。

USARTペリフェラル

32bit マイコンに積んであるこのペリフェラルも、ご多分に漏れず様々なモードに対応するように設計してあります。
ですので設定項目が非常に多いのですが、とりあえず簡単に設定項目のみを列挙していきます。いかに面倒くさいか見たい方はぜひデータシートをダウンロードの上見てみてください。

設定項目

列挙していきます。

動作モード

UART, USART, SPI, マンチェスターなんとか等々あります。ですが使うのはあくまでも UART なので、レジスタでは ノーマルモードとして設定してしまえばそれ以外のことは気にしなくて良くなります。良かったですね。
なお、その他モード専用のレジスタも多数あって、4つほど存在します。面倒くさそう。

そして、通常の USB - シリアル変換モジュールで行う通信として 1ストップビット、パリティなしを選択したいと思います。

ボーレートの計算

ボーレートはお得意の 115200 で行きます。このための計算式はデータシートに載っていますが、具体的にやっていきましょう。

まずですが、このマイコンは通信のためのクロック生成において、細かく値を設定できます。他のマイコンでは整数によって入力クロックを分周していますが、小数点以下を利用して割り算ができます。小数点以下を用いた際の計算式はこちら。

これを CD + 8 / FP について解きます。これはボーレート生成のためのレジスタ値となります。

$$CD + \frac{FP}{8} = \frac{SelectedClock}{BaudRate} \frac{1}{8(2-OVER)}$$

ここで、CD は整数、FP は小数部分(<1)と思ってください。とりあえず OVER == 0 とします。さらに入力クロックは 60MHz ですから、諸値を代入すると

$$ CD + \frac{FP}{8} = \frac{60e6}{115200} \frac{1}{16} = 32.552...$$

となりますね。よって CD == 32, FP/8 == 0.552 とすればいいでしょう。

コード全景

ちょっと説明が雑ですが、後は該当するレジスタのビットを操作すればいいだけなので、多分そこまで難しいことはないと思います(多分)。

また、ペリフェラルのピンマッピング表を見て、「あ、GPIO18 と GPIO19 を使えばいいかな〜」と思うのはやめてください。そこはクリスタルが接続されています。僕は気づかずに「あれ〜?」と時間を潰しまくったので、ぜひ気をつけたほうが良いと思います。そう考えると、マイコンによってクロック入力は専用のピンになっているものがありますけど、あれってこういう意味で結構良心的なんですね。

void usart_init(void) {
    // RXD: GPIO42(#57)
    // TXD: GPIO43(#58)
    const int MASK_FOR_PORT1 = (1 << (42 % 32)) | (1 << (43 % 32));
    AVR32_GPIO.port[1].gperc = MASK_FOR_PORT1;
    AVR32_GPIO.port[1].pmr0c = MASK_FOR_PORT1;
    AVR32_GPIO.port[1].pmr1s = MASK_FOR_PORT1;
    AVR32_GPIO.port[1].puers = MASK_FOR_PORT1;

    AVR32_PM.pbamask |= 1 << 7;

    AVR32_USART0.MR.mode = AVR32_USART_MR_MODE_NORMAL;
    AVR32_USART0.MR.sync = 0; // asynchronous mode
    AVR32_USART0.MR.nbstop = AVR32_USART_MR_NBSTOP_1;
    AVR32_USART0.MR.par = AVR32_USART_MR_PAR_NONE;
    AVR32_USART0.MR.mode9 = 0;
    AVR32_USART0.MR.chrl = AVR32_USART_MR_CHRL_8;
    AVR32_USART0.MR.msbf = 0; // LSB first
    AVR32_USART0.MR.chmode = AVR32_USART_MR_CHMODE_NORMAL;
    // 115200 & 60MHz ==> 32.552
    AVR32_USART0.MR.usclks = AVR32_USART_MR_USCLKS_MCK;
    AVR32_USART0.BRGR.cd = 32;
    AVR32_USART0.BRGR.fp = 0.552 * 8;

    AVR32_USART0.CR.txen = 1;
    AVR32_USART0.CR.rxen = 1;
}

char usart_read(void) {
    while( !AVR32_USART0.CSR.rxrdy );
    return AVR32_USART0.RHR.rxchr;
}

void usart_send(char ch) {
    while( !AVR32_USART0.CSR.txrdy );
    AVR32_USART0.THR.txchr = ch;
}

番外 - ローカルループバックモード

このペリフェラルでちょっと面白いところとして、テストモードが存在します。中でもローカルループバックモードでは、ピンに入出力を割り当てずに、ペリフェラル内部で TXD と RXD をショート結線するといったモードです。
「何の役に立つんだ」と思われるかも知れませんが、これは今回のようなペリフェラル設定をしている時に役に立ちます。

例えば設定して動作させようと思った時、フラグが立たないとします。オシロで波形を見たりすればいいでしょうが、入力端子(RXD) とかはオシロで見たところで何もわかりませんね。
また、オシロがない環境とかでは若干詰んでしまいます。そこでこのローカルループバックモードを使えば、これで送受信の完了を見られるというわけです。
実際に本当にデータは行っているのか?と言うことを知るには、例えば次のコードを書けば良いのです。

uart_send('A');
if( uart_read() == 'A' ) {
  ....
}

開発者の気持ちを少し考えてくれてるな〜という機能の紹介でした。