MicroPython的午睡(91) STM32F401RE、UART(USART)の続き

Joseph Halfmoon

前回、Nucleo-F401REボード用のMicroPythonでUARTを使ってみたのですが、釈然としない部分がありました。今回はその落穂ひろいです。前回疑問だったUART1が使えない理由は、MicroPythonのソースレベルで原因部分は判明。ソースを改変して再ビルドしたらば動くのかなあ?どうなんだろう。

※「MicroPython的午睡」投稿順 Indexはこちら

※ST Microelectronics社製Nucleo-F401REボード上で使用しているSTM32版MicroPythonについてはこちら

UART1が使えない直接原因

Nucleo-F401REボードのマイコン、STM32F401REには3本のUSART(同期、非同期両方に使えるのでUARTでなくUSARTです)「1」「2」「6」が存在します。そのうち「2」はSTLinkのハードを経由してホストのUSBの仮想シリアルに接続しているので、通常は使用不可です。よって「1」と「6」の2本が使える筈なのですが、前回MicroPython上で動作確認できたのは「6」だけでした。「1」はエラーになって動かせませぬ。

その件について、MicroPythonのソースコードを確認してみました。直接の問題個所は直ぐに判明。MicroPythonのソースインストールディレクトリ配下の

ports/stm32/NUCLEO_F401RE/mpconfigboard.h

の以下の部分です。STM32F401_UART_CONFIG

上記のようにUART2とUART6の TX, RXピンが定義されていますが、UART1のTX,RXピンのアサインがないのです。UARTポートの在、不在はMICROPY_HW_UARTx_TX および _RXが存在すれば在、存在しなければ不在と判断されるので、UART1を使おうとするとエラーになるのでした。なぜUART1の記述が無いのか、何か別な目的に使っているのか、は不明です。後でこの部分を勝手改変してUART1を使えるかどうか見てみようかしらん。メンドイけど。

なお、ついでにUART2はMicroPythonからでも「一応」使えるのね、という件についても確認。上記のようにUART2は定義されているのでエラーにはなりません。USBシリアル相手に通信もできます。しかし、Thonny IDEのようにUSBシリアルでREPLを動かしている場合、その制御を取り上げてしまうので、IDEが使えなくなってしまいます。

UARTからの「行入力待ち」

前回、UART6に接続した「端末」にプロンプトを出して入力待ちに入り、1行入力してRETURNキーを押したらば処理をするような操作を書こうとしたら、readlineのデフォルトのタイムアウトが短すぎるのか、うまく行きませんでした。そこで今回は、行入力待ちを自前で実装してみました。

from pyb import UART
import time

uart6 = UART(6, 9600)
uart6.init(9600, bits=8, parity=None, stop=1)

def readLineBlocking():
    inFlag = True
    buf = ""
    while inFlag:
        if uart6.any():
            rc = uart6.readchar()
            if (rc >= 0x20) and (rc < 0x80):
                uart6.write(chr(rc))
                buf += chr(rc)
            elif rc == 13:
                inFlag = False
        time.sleep_ms(10)
    return buf

def main():
    print("STM32F401RE UART6 readLine Test.") 
    i = 1
    while True:
        uart6.write(str(i))
        uart6.write('>')
        i+=1
        tmp = readLineBlocking()
        uart6.write(' = ')
        uart6.write(tmp)
        uart6.write('<\r\n')
        if tmp.startswith("."):
            break

if __name__ == "__main__":
    main()

上記の readLineBlocking()は、キャリッジリターン(0x0D)コードが入力されるまで待つルーチンです。アスキー可読文字+0x7Fについては入力された文字を即座に返すので、相手先はローカルエコーしなくても入力文字が「見えます」。

上のプログラムをCOM11上の仮想端末相手に動かしているところが以下に。blockingReadLine

今のところ、行編集は何もできませんが、おいおい追加しておきたいと思います。でもREPL用にそういう関数がどこかに定義されている筈だなあ、またソース内を探してみるか。

MicroPython的午睡(90) STM32F401RE、UART6はOK、UART1? へ戻る

MicroPython的午睡(92) STM32版、74HC595で7SEG LED2桁駆動 へ進む