みつきんのメモ

組み込みエンジニアです。Interface誌で「Yocto Projectではじめる 組み込みLinux開発入門」連載中

Longan nanoをUbuntu 18.04のPlatformIOでハロワ

はじめに

Lチカが動いたのでシリアルでHello worldしてみる。

このハロワは失業と関係ない

今時の人たちはHello worldを「ハロワ」と略すらしい。

当時在籍した会社が潰れてハローワークにお世話になった経験がある筆者は、このワードからは悲壮感しか無い。

プロジェクトの作成

戯言はともかく、プロジェクトを作成する。

$ mkdir -p ~/pio/longan_hello
$ cd ~/pio/longan_hello
$ pio init -b sipeed-longan-nano

USART0のピン

Longan nanoで一番簡単に使用できそうなシリアルポートはUSART0で、 これらは基板に引き出されている。

f:id:mickey_happygolucky:20191221065223p:plain
基板

Type-Cポートを左にした時に右側に見える「T0」と「R0」のシルクがあるピンがそれぞれ次のようになっている。

pin 機能
T0 PA9/USART0_TX
R0 PA10/USART0_RX

今回は出力だけなのでT0のみ使用する。

プログラムの作成

platformio.ini

Lチカではframeworkをarduinoとしたが、今回はデフォルトのgd32vf103-sdkを使用する。

ファームウェアの書き込みにDFUを使用するので、最終的には次のようになる。

[env:sipeed-longan-nano]
platform = gd32v
board = sipeed-longan-nano
framework = gd32vf103-sdk

upload_protocol = dfu

シリアル送信までの流れ

まず、Longan nanoのUSART0を使用できるようにする必要がある。

それには次のような処理が必要となる。

  1. GPIOAのクロック有効化
  2. USART0のクロック有効化
  3. PA9ピンのAlternative Function設定
  4. USART0の有効化

初期化処理は次のようにする。

    // 1. GPIOAのクロック有効化
    rcu_periph_clock_enable(RCU_GPIOA);

    // 2. USART0のクロック有効化
    rcu_periph_clock_enable(RCU_USART0);

    // 3. PA9の設定
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);

    // 4. USART0の有効化
    usart_enable(USART0);

その後USART0の設定を行い、送信シーケンスに入る。

USARTの送信シーケンス

マニュアルからUSARTの送信シーケンスを抜粋する。

f:id:mickey_happygolucky:20191223065413p:plain
送信シーケンス

送信関数として実装するのはこの7〜10まで。

要約すると、次のようになる。

  1. TBEを待つ
  2. USART_DATAレジスタに送信データを書く
  3. データ数分1と2を繰り返す
  4. TC=1を待つ

図にはTCはcleared by softwareとあるので、明示的にクリアする必要があるかもしれない。

それらを踏まえて次のようにする。

static void putc(unsigned char c) {
    // 1. TBEを待つ
    while (usart_flag_get(USART0, USART_FLAG_TBE) == RESET) 
        ;

    // 2. USART_DATAレジスタにデータを書く
    usart_data_transmit(USART0, c);
}

static void puts(const char* s)
{
    // 3. 送信データ数分1と2を繰り返す
    while (*s != '\0') {
        if (*s == '\n')
            putc('\r');
        putc(*s++);
    }

    // 4. TC=1を待つ
    while (usart_flag_get(USART0, USART_FLAG_TC) == RESET) 
        ;

    // おまけ TCをクリアする。
    usart_flag_clear(USART0, USART_FLAG_TC);
}

サンプルコードではTBE待ちとDATA書き込みが逆になっているが、とりあえずマニュアルにならった。

main.c

これらを踏まえて最終的なプログラムは次のようになる。

#include "gd32vf103.h"

static void putc(unsigned char c) {
    while (usart_flag_get(USART0, USART_FLAG_TBE) == RESET) 
        ;
    usart_data_transmit(USART0, c);
}

static void puts(const char* s)
{
    while (*s != '\0') {
        if (*s == '\n')
            putc('\r');
        putc(*s++);
    }
    while (usart_flag_get(USART0, USART_FLAG_TC) == RESET) 
        ;
    usart_flag_clear(USART0, USART_FLAG_TC);
}

int main(int argc, char* argv[])
{
    rcu_periph_clock_enable(RCU_USART0);
    rcu_periph_clock_enable(RCU_GPIOA);
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);

    usart_deinit(USART0);
    usart_enable(USART0);
    usart_baudrate_set(USART0, 115200);
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);

    puts("Hello ");
    puts("World\n");

    while (1);

    return 0;
}

ビルドと書き込み

Longan nanoをDFUモードでPCと接続し、次のコマンドでファームウェアを書き込む。

$ pio run -t upload

ビルドが必要な場合は、ビルドした後にファームウェアを書き込む。

dfu-util: dfuse_download: libusb_control_transfer returned -1
*** [upload] Error 74

前回同様このエラーは無視する。

実行

USB-シリアル変換ケーブルでLongan nanoとPCを接続し、minicomなど端末を開く。

Longan nanoのリセットボタンを押して、次のように表示されれば成功。

minicom へようこそ 2.7.1

オプション: I18n 
コンパイルされた日時は:  Aug 13 2017, 15:25:34.
ポート /dev/ttyUSB0, 21:32:17

CTRL-@ Z を押すと、説明画面になります。

Hello World

ただ、Longan nanoのピン電圧は3.3Vで、筆者が普段使っている変換ケーブルが5Vのみの対応だったので、 出力が確認できずしばらくハマった。

ロジアナで出力を確認したりオシロで電圧を測ってみたりで原因はわかったが、こういう作業も組み込みの楽しみだと思う。

まとめ

最近ではHello worldのことを「ハロワ」という。

USART0を使う間にGPIOAとUSART0のクロック有効化が必要だが、それを忘れていてしばらくハマった。

ピン設定からUSART0設定は特に癖はない。

USART0のピン電圧は3.3V。

ということで、無事にHello worldができた。

今回は、gd32vf103-sdkを使用したので、レジスタのアドレスなどは特に意識しなくてもプログラムできた。

参考

Longan_GD32VF_examplesのgdv32v_lcd