鳥なき里のマイコン屋(88) Longan nano、USARTでprintf

JosephHalfmoon

超お求め易い価格で多機能、そして何かと話題のRISC-V搭載のマイコン・ボード、Longan nanoにも大分慣れてきました。オンボードのLCD、LEDそしてDACという順番に動かしてきましたが、この辺でシリアルポートにprintfできるようにしておきたい。原始的とそしられても、あれば使ってしまうprintfデバッグであります。

※「鳥なき里のマイコン屋」投稿順Indexはこちら

まず、シリアルポートを使う前に正直に申告しておきます。LEDの点灯、消灯ルーチン、間違っていました。別にprintfデバッグの結果ではありません。

LCDにREDと表示出ているのに、LEDは赤く光ってないな~

という至極あたりまえな現象に気付いたからであります。LEDの色が変わっていくので、OKなどと思い込んでおりました。あっと思ってみてみたら、LOW出力で点灯なのに、HIGH出力で点灯のように関数を逆につかっていました。よって、赤のつもりが、青と緑の混合で水色になっていた。。。BUGをFIX。ちゃんと「観察」するのが一番のデバッグであります。

また、もひとつ前から気になっていたメモリ容量も確認しました。というのも私が購入させてもらった価格より、さらに「お求めやすい価格」になっているLongan nanoを発見、ただし、メモリ容量が小さくなっているようであったのです。手元のバージョンは本当にメモリが大きいのだよね、と。PlatformIOでのビルド時の出力をしげしげと眺めました。以下の通り。

Linking .pio\build\sipeed-longan-nano\firmware.elf
Building .pio\build\sipeed-longan-nano\firmware.hex
Building .pio\build\sipeed-longan-nano\firmware.bin
Checking size .pio\build\sipeed-longan-nano\firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM: [= ] 7.1% (used 2328 bytes from 32768 bytes)
Flash: [= ] 12.2% (used 15968 bytes from 131072 bytes)

よかった、フラッシュ128Kバイト、RAM32Kバイトでした。でも今回のような小さなプログラムであれば、よりお求めやすいフラッシュ64Kバイト、RAM20Kバイト版でも十分です。追加購入するときはそちらの版も仕入れようかしら。

ようやく本題です。USARTでprintf。複数チャネルのUSARTが搭載されていますが、少ない端子のやりくり厳しいなか、この目的に使いやすいのはUSART0に「決まって」います。ボードの端面に8ピンがかなり無理やり感のある立て方で接続されているのですが、ここに出ているのが以下だからです。

    • JTAG4ピン(RSTはなし)
    • USART0のRXとTX
    • GND
    • 3V3

3V3はJTAGデバッグ時のVREFに使え、ということだと思います。JTAG4ピンはボード裏面側から引き出されており、ボード表面にはRX,TX,GND,3V3がでています。JTAGデバッグならGND, 3V3, JTAGの6本、UARTシリアルであればRX,TX,GNDの3本を使えば接続できそうです。当然、RX, TXしか出ていないので、ハード的にはUSARTですが、UARTとしての使用で、かつ、他の制御信号なども使用しない方法となります。USARTを使ったprintfの実装は、例のExamplesの中にサンプルコードがあるので、それを参考にしながら、前回のプログラムに追加して行きます。

初期化はまず、USART0にもクロックを与えておかねばなりませぬ。

    rcu_periph_clock_enable(RCU_GPIOC);
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_DAC);
    rcu_periph_clock_enable(RCU_USART0);

GPIOAの9番がUSART0のTX, 10番がRXなので端子の初期化も追加します。

    gpio_init(GPIOC, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13); // LED_RED
    gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1 | GPIO_PIN_2); // LED_GREEN, LED_BLUE
    gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_4); //DAC0
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9); // USART0 TX
    gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10); // USART0 RX

そして、USART0自体の初期化。RX使ってシリアル入力をするとなると、割り込みとか、バッファリングとかいろいろ面倒ですが、ここでは、printfで垂れ流し出力のみなので、最小限の設定のみ。

void usart0_config(void) {
    usart_deinit(USART0);
    usart_baudrate_set(USART0, 115200U);
    usart_word_length_set(USART0, USART_WL_8BIT);
    usart_stop_bit_set(USART0, USART_STB_1BIT);
    usart_parity_config(USART0, USART_PM_NONE);
    usart_hardware_flow_rts_config(USART0, USART_RTS_DISABLE);
    usart_hardware_flow_cts_config(USART0, USART_CTS_DISABLE);
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
    usart_enable(USART0);
}

そして、最後に忘れてならないのは、printfが内部で呼び出しているらしい_put_char()関数のオーバライドでした。

int _put_char(int ch)
{
    usart_data_transmit(USART0, (uint8_t) ch );
    while ( usart_flag_get(USART0, USART_FLAG_TBE)== RESET){
    }
    return ch;
}

ここまで準備すると、普通にstdio.hをインクルードしてprintfすると、USART0から出力文字列が垂れ流されていきます。今回は、アイキャッチ画像のようにLongan nanoに取り付けたお手製「アダプタ」の先には、定番の

秋月電子 FT232RL USB-シリアル変換モジュール

を接続しております。PlatformIOのシリアルモニタは、仮想COMポートを適当に探してくれるみたい(複数あったらどれか指定しないといけないのだと思う)なので、platformio.iniのmonitor_portは設定せず、

monitor_speed = 115200

のみ記入。幾つかprintfをちりばめたプログラムを書き込み、動かしてみたところがこちら。

--- Miniterm on COM4  115200,8,N,1 ---
--- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
  DAC : 00ff
  DAC : 01ff
LOOP  : 1   
  DAC : 02ff
  DAC : 03ff
  DAC : 04ff
LOOP  : 2   
  DAC : 05ff
  DAC : 06ff
  DAC : 07ff
LOOP  : 3   
  DAC : 08ff
  DAC : 09ff
  DAC : 0aff

1ループ9秒設定(ハンディDMMで電圧を読み取れるようにゆるゆる)、その中で3秒毎DACの設定値を更新している様子が観察できました。

また、一歩前進したな、次は何?

鳥なき里のマイコン屋(87) Longan nano、DAC へ戻る

鳥なき里のマイコン屋(89) Longan nano、I2CでAQM1602 へ進む