STM32でNUTTXを使ってみる

UART通信


NuttxのUART通信はとても簡単です。
デバイスファイル(/dev/ttySx)をopenし、read/writeで通信することができます。
UARTのread/writeは全てバッファ経由で行われます。
read/writeともに256バイトのバッファを持っています。
writeしたデータは一旦カーネルバッファに格納され、カーネルが順次ポートに出力します。
アプリケーションはいつデータが全て出力されたかを知ることはできません。
ポートから入力したデータは、一旦カーネルがバッファに格納します。
アプリケーションはpoll関数を使ってカーネルバッファに受信したデータあるかどうかを確認することができます。
バッファにデータあるときはread関数を使ってカーネルバッファからアプリケーション領域にデータをコピーします。

多量のデータを送信するときは、カーネルバッファの空をチェックしながら、少しずつデータを送る必要が有ります。
多量のデータを受信するときは、USARTポートを使ってフロー制御を行う必要が有ります。

まず以下の手順でUARTを有効にします。






ここで厄介なのは、使えるUSART(UART)とアサインされるデバイスファイルがボードごとに違います。
また、一部のポートは、nshコンソールやsyslogの出力先としてアサインされています。
こちらで紹介しているUSBコンソールを有効にすると、さらに変わります。

F4 Discovery(usbnsh) F4 Discovery(nsh) F3 Discovery F103xx(Serial Console) F103xx(USB Console)
USART1 × × × /dev/ttyS0
concole
syslog
/dev/ttyS0
USART2 /dev/ttyS0
syslog
/dev/ttyS0
console
syslog
/dev/ttyS0
console
syslog
/dev/ttyS1 /dev/ttyS1
USATR3 /dev/ttyS1 /dev/ttyS1 × /dev/ttyS2 /dev/ttyS2
UART4 × × /dev/ttyS1 × ×
USART5 /dev/ttyS2 /dev/ttyS2 /dev/ttyS2 × ×
USART6 /dev/ttyS3 /dev/ttyS3 × × ×

使えるUSART(UART)の情報は(少しだけ)以下に記載されていますが、
最終的には実際にUSART(UART)を有効にしてどのデバイスが追加されるか、実機で確認するしかありません。
使えないUSART(UART)をメニューで有効にするとコンパイルエラーとなります。

F4 Discovery
$HOME/nuttxspace/nuttx/configs/stm32f4discovery/include/board.h

F3 Discovery
$HOME/nuttxspace/nuttx/configs/stm32f3discovery/include/board.h

F103xx
$HOME/nuttxspace/nuttx/configs/stm32f103-minimum/include/board.h
記載なし

ここまで設定したらひたすらExitで抜けます。
新しい[.config]を使ってファームウェアをビルドし、新しいファームウェアをマイコンに書き込みます。
nshに接続するとttyS0とttyS1が有効になっています。




UARTの動作を確認するためのサンプルアプリを公開しています。
こちらの手順でapps/examplesディレクトリに追加してくださ い。
以下の手順でサンプルアプリをファームに組み込みます。
$ make clean
$ make menuconfig

Application Configuration > Examples で以下のアプリを追加してください。


UART通信でpoll関数を使うためには、Device DriversメニューでDisable driver poll interfacesを無効にする必要が有ります。


ここまで設定したらひたすらExitで抜けます。
新しい[.config]を使ってファームウェアをビルドし、新しいファームウェアをマイコンに書き込みます。
nshに接続するとuart_testアプリが追加されています。




このアプリは/dev/ttyyS1が送信側、/dev/ttyS2が受信側ですが、ここでまた厄介なのは
デバイスファイルと実際のポートのアサインがボードごとに違います。
実際のポートの情報はこちらにに記載されています。

arch/arm/src/stm32/chip/stm32f30xxx_pinmap.h

UART4とUART5は以下のポートですが、それ以外は代替ピンまで記載されているので
実際にどのポートが使われるのか良くわかりません。

#define GPIO_UART4_RX       (GPIO_ALT|GPIO_PUSHPULL|GPIO_AF5|GPIO_PULLUP|GPIO_SPEED_50MHz|GPIO_PORTC|GPIO_PIN11)
#define GPIO_UART4_TX       (GPIO_ALT|GPIO_PUSHPULL|GPIO_AF5|GPIO_PULLUP|GPIO_SPEED_50MHz|GPIO_PORTC|GPIO_PIN10)

#define GPIO_UART5_RX       (GPIO_ALT|GPIO_PUSHPULL|GPIO_AF5|GPIO_PULLUP|GPIO_SPEED_50MHz|GPIO_PORTD|GPIO_PIN2)
#define GPIO_UART5_TX       (GPIO_ALT|GPIO_PUSHPULL|GPIO_AF5|GPIO_PULLUP|GPIO_SPEED_50MHz|GPIO_PORTC|GPIO_PIN12)

実機で調べた結果は以下の通りです。
めっちゃ複雑です。

F4 Discovery(usbnsh) F4 Discovery(nsh) F3 Discovery F103xx(Serial Console) F103xx(USB Console)
USART1
×
×
×
/dev/ttyS0
UARTで使えない
/dev/ttyS0
RX PA10/TX PA9
USART2
/dev/ttyS0
UARTで使えない(※1)
/dev/ttyS0
UARTで使えない
/dev/ttyS0
UARTで使えない
/dev/ttyS1
TX PA2/RX PA3
/dev/ttyS1
TX PA2/RX PA3
USATR3
/dev/ttyS1
TX PB10/RX PB11
/dev/ttyS1
TX PB10/RX PB11
×
/dev/ttyS2
TX PB10/RX PB11
/dev/ttyS2
TX PB10/RX PB11
UART4
×
×
/dev/ttyS1
TX PC10/RX PC11
×
×
USART5
/dev/ttyS2
TX PC12/RX PD2
/dev/ttyS2
TX PC12/RX PD2
/dev/ttyS2
TX PC12/RX PD2
×
×
USART6
/dev/ttyS3
TXPC6/RX PC7
/dev/ttyS3
TX PC6/RX PC7
×
×
×

(※1)
デフォルトではsyslogの出力先
syslogの出力先をRAMLOGに変更すれば使える
TX PA2/RX PA3



/dev/ttyS1と/dev/ttyS2をクロス結線します。
ttyS1(TX)-ttyS2(RX)
ttyS1(RX)-ttyS2(TX)
recvの引数で実行すると、受信タスクを起動します。
受信タスクは/dev/ttyS2を待ちます。
nsh> uart_test recv
receive from /dev/ttyS2
task_create name:recvTask priority:100
recvTask ready to receive from /dev/ttyS2
nsh>



recvに続いてsendの引数で実行すると、送信タスクを起動します。
送信タスクは/dev/ttyS1に送信します。
受信タスク側では受信した文字を表示します。
nsh> uart_test send
send to /dev/ttyS1
task_create name:sendTask priority:100
sendTask start PID:5 device=/dev/ttyS1 loop:10 wait:1 system_timer:5967
nsh> recvTask buffer=this is /dev/ttyS1 - 0
recvTask buffer=this is /dev/ttyS1 - 1
recvTask buffer=this is /dev/ttyS1 - 2
recvTask buffer=this is /dev/ttyS1 - 3
recvTask buffer=this is /dev/ttyS1 - 4
recvTask buffer=this is /dev/ttyS1 - 5
recvTask buffer=this is /dev/ttyS1 - 6
recvTask buffer=this is /dev/ttyS1 - 7
recvTask buffer=this is /dev/ttyS1 - 8
recvTask buffer=this is /dev/ttyS1 - 9
sendTask end PID:5 system_timer:6977



APIの使い方に間違いがあるかもしれません。
こ ちらのドキュメントで確認してください。

ファームの書き込み方法と、nshへの接続方法はこちらに紹介しています。
STM32F4 Discovery
STM32F3 Discovery
STM32F103RB Nucleo
STM32F103 BluePill/BlackPill
STM32F103 VEボード
STM32F407 VGボード

続く...