シリアル通信

Stellaris Wareでは、いくつかの方法でシリアル通信が可能です。今回は、ユーティリティライブラリのUART Standard IOモジュールを使ってみます。

UART Standard IOはutils/uartstdio.c、utils/uartstdio.hで提供されます。UART上で、C標準ライブラリのstdio.hライクな機能を提供するライブラリです。バッファモード、アンバッファモードの2つの動作モードが設けられていて、コンパイルスイッチUART_BUFFEREDで切り替え可能です。バッファモードでは、UART割り込みをモジュール側で使用します。

バッファモードとアンバッファモードでは、いくつかの関数の挙動が変わります。UARTgetsは、CR、LF、ESC、CR+LFのいずれかが入力されるまでブロックしますが、バッファモードでは、これら改行文字がすでに入力されているかををチェックするために、UARTPeekが使えます。バッファモード、アンバッファモードを比較するために、下のようなプログラムを書いてみました。
"echo xxxx"と入力された場合、"xxxx"をエコーバックする処理を繰り返すプログラムで、"\q"が入力されると終了します。UARTgetsのループ毎に"."を出力する処理を作り、アンバッファモードでは、UARTgetsが入力完了待ちでブロックするので"."出力は働きませんが、バッファモードでは、UARTPeekでのチェックにより、入力待ちの間も、1秒毎に"."が出力されるはずです。

#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "driverlib/gpio.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/interrupt.h"
#include "utils/uartstdio.h"
#include "utils/ustdlib.h"

#define MAX_CMD_LEN 255
char cmdbuff[MAX_CMD_LEN];

void main(void) {
    char *cmd;

    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC
        | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    UARTStdioInit(0);

    UARTprintf("start\n");
    UARTprintf(" Enter \\q to exit.\n");

    while(1) {
        // 1秒毎に . を出力
        UARTprintf(".");
        SysCtlDelay(SysCtlClockGet() / 3);
#ifdef UART_BUFFERED
        if (UARTPeek('\r') == -1)   // バッファモードでは改行文字がなければ
            continue;               // 次のループへ
#endif

        UARTgets(cmdbuff, MAX_CMD_LEN);
        cmd = cmdbuff;

        while (*cmd == ' ')
            cmd += 1;
        if (ustrnicmp(cmd, "\\q", 2) == 0)
            break;

        if (ustrnicmp(cmd, "echo", 4) == 0) {
            cmd = ustrstr(cmd, " ");
            if (cmd != 0)
                UARTprintf("%s\n", cmd+1);
        }
    }

    UARTprintf("exit\n");

    while(1) {}
}

実行結果はこのようになりました。期待通り、バッファモードでは、入力待ち状態でも"."の出力処理が実行されています。

# アンバッファモード
start
 Enter \q to exit.
.echo hogehoge
hogehoge
.echo fugafuga
fugafuga
.\q
exit

# バッファモード
start
 Enter \q to exit.
......e.cho ho.gehoge
hogehoge
.....e..cho .fugaf.uga
fugafuga
............\q
exit

バッファモードでは、リングバッファを使っているので、ハードFIFOへ転送される前にオーバフローした場合、上書きされてしまう問題もあり、これに対しても、バッファをフラッシュする関数が用意されていたりします。これについても今度見てみたいと思います。