みつきんのメモ

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

PlatformIO AE-ATmegaを動かす

はじめに

秋月のATmega168/328マイコンボードキットをPlatformIOでLチカしてみる。

かなり昔に購入したので、使用するMCUATmega168P

プログラムの書き込みにはAVRISP mkIIを使用する。最近では純正品は入手が難しいっぽい。

PlatformIOの設定方法はここを参照。

プロジェクトの作成

作業用ディレクトリを次のように作成する。

$ mkdir -p ~/pio/ae-atmega168p
$ cd ~/pio/ae-atmega168p

このボードはPlatformIOでサポートするボードのうちdiecimilaatmega168に該当する。

$ pio init -b diecimilaatmega168

プログラムの作成

platformio.ini

純粋なArduino DiecimilaではMCUATmega168だが、今回使用するボードではATmega168Pであるため、設定を変更する必要がある。

またプログラムを書き込むためのプログラマAVRISP mkIIに設定する。

[env:diecimilaatmega168]
platform = atmelavr
board = diecimilaatmega168
framework = arduino

; change microcontroller
board_build.mcu = atmega168p

; change programmer to AVRISP mkII
upload_protocol = stk500v2
; each flag in a new line
upload_flags =
    -Pusb

main.cpp

src/main.cppを次の内容で作成する。

#include <Arduino.h>

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{
  digitalWrite(LED_BUILTIN, HIGH);
  delay(1000);
  digitalWrite(LED_BUILTIN, LOW);
  delay(1000);
}

一般的なArduinoのLチカのコード。

AVRISP mkIIとボード、PCを接続

PCとAVRISP mkIIをUSBケーブルで接続する。

AVRISP mkIIの6ピンケーブルを、ボード上のICSPのシルクがある3x2のピンヘッダに接続する。 ケーブルの赤いほうが1ピン。

ボードは別途給電が必要なので、USBか電源を接続する。

ビルドと書き込み

次のコマンドでファームウェアをビルドする。

$ pio run

次のコマンドで書き込む。外部のプログラマを使用するのでtargetの指定がuploadでは無いことに注意。

$ pio run -t program
Processing diecimilaatmega168 (platform: atmelavr; board: diecimilaatmega168; framework: arduino)
--------------------------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option

...(snip)...

avrdude: verifying ...
avrdude: 928 bytes of flash verified

avrdude: safemode: Fuses OK (E:F8, H:DD, L:FF)

avrdude done.  Thank you.

========================= [SUCCESS] Took 1.34 seconds =========================

書き込みが成功し、LEDがチカチカする。

まとめ

今回はATmega168Pを使用したが、新しいロットではATmega328Pが付属しているらしいので 適宜、MCU変更する必要がある。

また、最近ではAVRISP mkIIは純正品の入手が困難みたいなので、互換品(クローン製品など含む)を使用する場合、 別途何か手順が必要かもしれない。

ともあれ、PlatformIOでも問題なく動作させられることがわかった。

STM32F4Discovery向けのNuttXをClangでビルドする

はじめに

NuttXは次のボードについてClangでのビルドに対応している。

  • nucleo-f446re
  • nucleo-f4x1re
  • stm32f746g-disco

筆者的によく使用するSTM32F4DiscoveryもClangでビルドできないか試してみる。

今回はclang-9を使用している。

clangの設定方法はここを参照。

NuttXのビルドやSTMへの書き込みに必要なパッケージの設定はここを参照。

Nuttxのビルド環境の作成

ソースの取得

$ mkdir ~/nuttx
$ cd ~/nuttx
$ git clone https://bitbucket.org/nuttx/nuttx.git
$ git clone https://bitbucket.org/nuttx/apps.git
$ cd nuttx

Clang対応

Make.defsの修正

./boards/arm/stm32/stm32f4discovery/scripts/Make.defsを修正し、Clangでのビルドに対応する。

この修正はすでにClangのビルドに対応してある環境のものを参考にする。

diff --git a/boards/arm/stm32/stm32f4discovery/scripts/Make.defs b/boards/arm/stm32/stm32f4discovery/scripts/Make.defs
index 48179cb2a5..189670ae2d 100644
--- a/boards/arm/stm32/stm32f4discovery/scripts/Make.defs
+++ b/boards/arm/stm32/stm32f4discovery/scripts/Make.defs
@@ -55,9 +55,6 @@ else
   ARCHSCRIPT = -T$(TOPDIR)/boards/$(CONFIG_ARCH)/$(CONFIG_ARCH_CHIP)/$(CONFIG_ARCH_BOARD)/scripts/$(LDSCRIPT)
 endif
 
-CC = $(CROSSDEV)gcc
-CXX = $(CROSSDEV)g++
-CPP = $(CROSSDEV)gcc -E
 LD = $(CROSSDEV)ld
 STRIP = $(CROSSDEV)strip --strip-unneeded
 AR = $(ARCROSSDEV)ar rcs
@@ -65,7 +62,6 @@ NM = $(ARCROSSDEV)nm
 OBJCOPY = $(CROSSDEV)objcopy
 OBJDUMP = $(CROSSDEV)objdump
 
-ARCHCCVERSION = ${shell $(CC) -v 2>&1 | sed -n '/^gcc version/p' | sed -e 's/^gcc version \([0-9\.]\)/\1/g' -e 's/[-\ ].*//g' -e '1q'}
 ARCHCCMAJOR = ${shell echo $(ARCHCCVERSION) | cut -d'.' -f1}
 
 ifeq ($(CONFIG_DEBUG_SYMBOLS),y)
@@ -73,19 +69,41 @@ ifeq ($(CONFIG_DEBUG_SYMBOLS),y)
 endif
 
 ifneq ($(CONFIG_DEBUG_NOOPT),y)
-  ARCHOPTIMIZATION += $(MAXOPTIMIZATION) -fno-strict-aliasing -fno-strength-reduce -fomit-frame-pointer
+  ARCHOPTIMIZATION += $(MAXOPTIMIZATION) -fno-strict-aliasing -fomit-frame-pointer
 endif
 
 ARCHCFLAGS = -fno-builtin
-ARCHCXXFLAGS = -fno-builtin -fno-exceptions -fcheck-new -fno-rtti
+ARCHCXXFLAGS = -fno-builtin -fno-exceptions -fcheck-new
 ARCHWARNINGS = -Wall -Wstrict-prototypes -Wshadow -Wundef
 ARCHWARNINGSXX = -Wall -Wshadow -Wundef
 ARCHDEFINES =
 ARCHPICFLAGS = -fpic -msingle-pic-base -mpic-register=r10
 
-CFLAGS = $(ARCHCFLAGS) $(ARCHWARNINGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRADEFINES) -pipe -funwind-tables
+ifeq ($(CONFIG_ARMV7M_TOOLCHAIN_CLANGL),y)
+  ARCHCCVERSION = {shell $(CC) -v 2>&1 | sed -n '/clang version/p' | sed -e 's/.* clang version \([0-9\.]\)/\1/g' -e 's/[-\ ].*//g'}
+  HOSTCC = clang
+  CC = clang
+  CXX = clang++
+  CPP = clang -E
+  ARCHCFLAGS += -nostdlib -ffreestanding -target arm-none-eabi -march=armv7-m -mcpu=cortex-m4
+  ARCHCXXFLAGS += -nostdlib -ffreestanding -target arm-none-eabi -march=armv7-m -mcpu=cortex-m4 -DCONFIG_WCHAR_BUILTIN
+else
+  ARCHCCVERSION = ${shell $(CC) -v 2>&1 | sed -n '/^gcc version/p' | sed -e 's/^gcc version \([0-9\.]\)/\1/g' -e 's/[-\ ].*//g' -e '1q'}
+  HOSTCC = gcc
+  CC = $(CROSSDEV)gcc
+  CXX = $(CROSSDEV)g++
+  CPP = $(CROSSDEV)gcc -E
+  ARCHCFLAGS += -funwind-tables
+  ARCHCXXFLAGS += -fno-rtti -funwind-tables
+  ifneq ($(CONFIG_DEBUG_NOOPT),y)
+    ARCHOPTIMIZATION += -fno-strength-reduce
+  endif
+
+endif
+
+CFLAGS = $(ARCHCFLAGS) $(ARCHWARNINGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRADEFINES) -pipe
 CPICFLAGS = $(ARCHPICFLAGS) $(CFLAGS)
-CXXFLAGS = $(ARCHCXXFLAGS) $(ARCHWARNINGSXX) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHXXINCLUDES) $(ARCHDEFINES) $(EXTRADEFINES) -pipe -funwind-tables
+CXXFLAGS = $(ARCHCXXFLAGS) $(ARCHWARNINGSXX) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHXXINCLUDES) $(ARCHDEFINES) $(EXTRADEFINES) -pipe
 CXXPICFLAGS = $(ARCHPICFLAGS) $(CXXFLAGS)
 CPPFLAGS = $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRADEFINES)
 AFLAGS = $(CFLAGS) -D__ASSEMBLY__
@@ -131,7 +149,6 @@ ifeq ($(CONFIG_DEBUG_SYMBOLS),y)
 endif
 
 
-HOSTCC = gcc
 HOSTINCLUDES = -I.
 HOSTCFLAGS = -Wall -Wstrict-prototypes -Wshadow -Wundef -g -pipe
 HOSTLDFLAGS =

コンフィグレーション

次のコマンドを実行し、STM32F4Discovery向けに設定する。

$ tools/configure.sh -l stm32f4discovery:nsh

make menuconfigでメニューを表示する。

$ make menuconfig

/キーで検索画面を表示しclangを検索する。検索結果の画面で1を押すとメニューにジャンプできる。

f:id:mickey_happygolucky:20200109102202p:plain
clangの検索結果

Toolchain SelectionのメニューからGeneric Clang toolchain under Linuxを選択する。

f:id:mickey_happygolucky:20200109102254p:plain
ツールチェインの選択

変更を保存し、メニューを終了する。

ビルド

下記のコマンドでビルド。

$ make -j $(nproc)

ビルドにclangが使用されているか確認したい場合は次のようにする。

$ make SHELL='sh -x' -j $(nproc)

nuttx.binが生成されればOK。

書き込み

次のコマンドで書き込む

$ st-flash write nuttx.bin 0x8000000

接続

USB-TTL変換ケーブルで、次の3つの信号を接続する。

ケーブル側 STM32F4Discovery
GND GND
TXD PA3(USART2_RX)
RXD PA2(USART2_TX)

実行

minicomなどでコンソールを開き、ターゲットをリセットする。

NuttShell (NSH) NuttX-8.2
nsh> help
help usage:  help [-v] [<cmd>]

  [         cp        exec      kill      mount     rmdir     true
  ?         cmp       exit      ls        mv        set       uname
  basename  dirname   false     mb        mw        sh        umount
  break     dd        free      mkdir     ps        sleep     unset
  cat       df        help      mkrd      pwd       test      usleep
  cd        echo      hexdump   mh        rm        time      xd

Builtin Apps:
  hello  nsh
nsh>

nshが使用できればOK。

まとめ

すでにNuttX側にClangのサポートが取り込まれているため、少しの修正でSTM32F4Discovery向けの環境でもClangでビルドできた。

PlatformIO nRF52840-DKをmbedで動かす

はじめに

nRF52840-DK(pca10056)をPlatoformIOで動かそうとしたところ、 デフォルトのframework(arduino)ではGPIOのピン割り当てが思ったようにならなかった。

そこで、frameworkをmbedに設定して試してみた。

プロジェクト作成

まずはプロジェクトを作成する。

$ pio init -b nrf52840_dk

platformio.iniを次の内容に修正する。

[env:nrf52840_dk]
platform = nordicnrf52
board = nrf52840_dk
framework = mbed

このように一度platformio.iniを出力してからframeworkを書き換える方法もあるが、下記のようにオプションを与えることで出力時点でframeworkを設定することもできる。

$ pio init -b nrf52840_dk -O "framework=mbed" 

objects_cryptocell.hでエラー

nRF52840-DKのmbed環境では、デフォルトの設定だと、ビルド時に次のようなエラーが発生する。

/home/mickey/.platformio/packages/framework-mbed/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/objects.h:58:10: fatal error: objects_cryptocell.h: No such file or directory

****************************************************************************
* Looking for objects_cryptocell.h dependency? Check our library registry!
*
* CLI  > platformio lib search "header:objects_cryptocell.h"
* Web  > https://platformio.org/lib/search?query=header:objects_cryptocell.h
*
****************************************************************************

 #include "objects_cryptocell.h"
          ^~~~~~~~~~~~~~~~~~~~~~
compilation terminated.

platform-nordicnrf52のissue(Missing objects_cryptocell.h)によるとbuild_flags = -DPIO_FRAMEWORK_MBED_RTOS_PRESENTによって回避できるとのこと。

次のようにすることで、プロジェクト作成時に設定することができる。

$ pio init -b nrf52840_dk -O "framework=mbed" -O"build_flags = -DPIO_FRAMEWORK_MBED_RTOS_PRESENT"

Lチカ

src/main.cppを次の内容で作成する。

#include "mbed.h"
 
DigitalOut myled(LED1);
 
int main() {
    while(1) {
        myled = 1;
        wait(0.25);
        myled = 0;
        wait(0.25);
    }
}

次のコマンドでビルドし、ボードへ書き込む。

$ pio run -t upload

LEDがチカチカした。

まとめ

nRF52840-DKのmbed環境ではbuild_flags = -DPIO_FRAMEWORK_MBED_RTOS_PRESENTが必要。

Ubuntu 18.04にaptでLLVM-9をインストール

はじめに

LLVM 9環境をUbuntu 18.04で構築する。

google先生に聞いても手動で設定する方法ばかり見つかったので、aptでインストールする方法を調べた。

2020/1/8 修正

リポジトリの設定

$ sudo apt-add-repository "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main"

パッケージのインストール

$ sudo apt install clang-9 clang-tools-9 clang-tidy-9 clang-format-9 lldb-9 lld-9 

シンボリックリンクの作成

Ubuntuでは複数のバージョンがインストールされている場合に、どのバージョンをアクティブにするかを管理するためのalternativesパッケージが存在する。

追加リポジトリでインストールしたclang-9はalternativesには対応していないようで、 /usr/bin/clangの実行時にclang-9を使用したい場合、シンボリックリンクを手動で切り替える必要がある。

$ sudo ln -s -f /usr/bin/clang-9 /usr/bin/clang
$ sudo ln -s -f /usr/bin/clang++-9 /usr/bin/clang++

素敵なスクリプトがあったので、これを使用する。

これを保存し、実行権限をつけて実行する。

$ wget https://gist.githubusercontent.com/junkdog/70231d6953592cd6f27def59fe19e50d/raw/92f0e73d2558402b7316021c1ab408b30e534de6/update-alternatives-clang.sh
$ chmod +x update-alternatives-clang.sh
$ sudo ./update-alternatives-clang.sh 9 50

その後、update-alternativesclangllvm-configを設定する。

clang

$ update-alternatives --config clang
alternative clang (/usr/bin/clang を提供) には 2 個の選択肢があります。

  選択肢    パス            優先度  状態
------------------------------------------------------------
  0            /usr/bin/clang-9   50        自動モード
  1            /usr/bin/clang-8   50        手動モード
* 2            /usr/bin/clang-9   50        手動モード

現在の選択 [*] を保持するには <Enter>、さもなければ選択肢の番号のキーを押してください: 2

llvm-config

$ update-alternatives --config llvm-config
alternative llvm-config (/usr/bin/llvm-config を提供) には 2 個の選択肢があります。

  選択肢    パス                  優先度  状態
------------------------------------------------------------
  0            /usr/bin/llvm-config-8   200       自動モード
  1            /usr/bin/llvm-config-8   200       手動モード
* 2            /usr/bin/llvm-config-9   50        手動モード

現在の選択 [*] を保持するには <Enter>、さもなければ選択肢の番号のキーを押してください: 2

まとめ

http://apt.llvm.org/bionicにはllvm-toolchain-bionic-9が存在するので、 リポジトリの追加とaptコマンドでインストール可能。

alterntivesの自動設定はされないので、必要に応じてシンボリックリンクリンクを貼り替える必要がある。 素敵なスクリプトのお世話になる。

NuttXをnRF52840-DKで動かす

はじめに

NuttXがnRF52840-DKに対応したっぽいので動かしてみる。

ARMのツールチェインの設定方法についてはここを参照。

J-Linkツールの設定方法についてはここを参照。

NuttXの作成

ソースの取得

$ git clone https://bitbucket.org/nuttx/nuttx.git
$ git clone https://bitbucket.org/nuttx/apps.git

コンフィグレーション

USB経由でシェルを使用する場合は次のようにする。

$ cd nuttx
$ tools/configure.sh -l nrf52840-dk:nsh

ビルド

次のコマンドでビルドする。

$ make -j $(nproc)

書き込み

upload.jlink

nuttxディレクトリ直下にupload.jlinkを次の内容で作成する。

h
loadbin nuttx.bin,0x0
r
q

書き込み

$ JLinkExe -device nRF52840_xxAA -speed 4000 -if swd -autoconnect 1 -CommanderScript upload.jlink 

実行

nRF52840-DKはボードとPCをUSBケーブルで接続すると、Linux上でシリアルコンソールが/dev/ttyACM0として見えるようになる。 これをminicomなどで開くことでnshというシェルが使用できる。

$ minicom -D /dev/ttyACM0
NuttShell (NSH) NuttX-8.2
nsh>

helpコマンドを実行すると、実行可能なコマンドを表示することができる。

nsh> help
help usage:  help [-v] [<cmd>]

  [         cd        echo      hexdump   mkfatfs   mw        sh        uname
  ?         cp        exec      kill      mkrd      pwd       sleep     umount
  basename  cmp       exit      ls        mh        rm        test      unset
  break     dirname   false     mb        mount     rmdir     time      usleep
  cat       dd        help      mkdir     mv        set       true      xd
nsh>

Hello worldサンプルの有効化

nRF52840-DKのNuttXのコンフィグレーションは最低限の設定しか有効化されていないので、 Hello worldのサンプルを有効化してみる。

コンフィグレーションを変更するには下記のコマンドを実行し、メニュー画面でコンフィグレーションを設定する。

$ make menuconfig

Hello worldのサンプルを有効化するには下記のコンフィグレーションを有効化する必要がある。

  • CONFIG_BUILTIN
  • CONFIG_EXAMPLES_HELLO
  • CONFIG_NSH_BUILTIN_APPS

メニュー画面で「/」を押すことでコンフィグレーション項目を検索することができる。 また、検索結果の左側にある「(1)」のような番号の数字を入力すると、そのメニューへジャンプできる。

コンフィグレーションを変更したら、リビルドしてイメージを書き込んで再度nshを開く。

nsh> help
help usage:  help [-v] [<cmd>]

  [         cd        echo      hexdump   mkfatfs   mw        sh        uname
  ?         cp        exec      kill      mkrd      pwd       sleep     umount
  basename  cmp       exit      ls        mh        rm        test      unset
  break     dirname   false     mb        mount     rmdir     time      usleep
  cat       dd        help      mkdir     mv        set       true      xd

Builtin Apps:
  hello  nsh

helpコマンドの結果にBuiltin Apps:としてhelloが追加されていればOK。

nsh> hello
Hello, World!!

世界に向かってご挨拶。

まとめ

しばらく見なかった間にtools/configure/shのコンフィグ指定が変わっていた。(nrf52840-dk/nsh -> nrf52840-dk:nshなど)

NuttXのビルド自体は問題なくできたが、ビルトインアプリケーションとしてHello worldのサンプルをイメージに組み込む際、CONFIG_BUILTINCONFIG_NSH_BUILTIN_APPSを一緒に有効化する必要があることがわからず、 しばらくハマった。

以前使用した時のターゲットであるSTM32F4Discovery向けの設定では、デフォルトでここらへんが有効になっていたので気づかなかった。

Linux経験者がこの手のボードで何か作りたい場合は、NuttXは使いやすいと思う。

使用したターゲットはSTM32F4Discoveryだけど、以前にこんなのも書いたので、NuttXに興味が出た方は是非!!(宣伝が露骨)

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

Longan nanoをUbuntu 18.04のPlatformIOでLチカ

はじめに

安価なRISC-Vボードとして国内でも比較的入手が簡単なLongan nanoを入手した。 開発環境としては当ブログでもおなじみのPlatformIOに対応している。

国内で入手が容易なせいか日本語の情報も多いが、Windows環境での動作報告記事が多いので、ここではUbuntu 18.04上でPlatformIOで動かした事例を紹介する。

PlatformIO

PlatformIOはpipコマンドでインストールするが、環境を汚さないためにuserインストールする。

$ pip install platformio --user

環境変数を通すために~/.bashrcに下記を追加する。

PATH="${HOME}/.local/bin:${PATH}"

端末を開き直すか次のコマンドを実行し、環境変数を読み直す。

$ source ~/.bashrc

whichコマンドで次のようになればOK。

~$ which platformio
/home/xxxxx/.local/bin/platformio

プロジェクトの作成

とりあえず作業用ディレクトリを次のように作成する。

$ mkdir -p ~/pio/longan
$ cd ~/pio/longan

PlatformIOでLongan nanoのボード名を確認する。

$ pio boards | grep longan
sipeed-longan-nano  GD32VF103CBT6  108MHz       128KB    32KB   Sipeed Longan Nano

次にlongan向けのプロジェクトを作成する。

$ pio init -b sipeed-longan-nano
$ ls
include  lib  platformio.ini  src  test

これでプロジェクトの作成は完了

プログラムの作成

main.cpp

src/main.cppを次の内容で作成する。

#include <Arduino.h>

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{
  digitalWrite(LED_BUILTIN, HIGH);
  delay(1000);
  digitalWrite(LED_BUILTIN, LOW);
  delay(1000);
}

一般的なArduinoのLチカのコード。

platformio.ini

Arduinoのライブラリを使用する場合、frameworkをarduinoに設定する必要がある。

また、ファームウェアの書き込みにdfuを使用するので、platformio.iniを次の内容に編集する。

[env:sipeed-longan-nano]
platform = gd32v
board = sipeed-longan-nano
framework = arduino
upload_protocol = dfu

udevルールの編集

DFUを使用してファームウェアを書き込むには、Longan nanoをDFUモードで接続する必要がある。

Ubuntu 18.04というか、LinuxマシンにLongan nanoをDFUモードで接続するためにはまずudevルールを追加する。

/etc/udev/rules.d/99-platformio-udev.rulesに次の内容を追加する。

# Longan Nano
ATTRS{idVendor}=="28e9", ATTRS{idProduct}=="0189", MODE="0666" 

次のコマンドでudevルールを読み込ませる。

$ sudo udevadm trigger

Longan nanoをDFUで接続

Longan nanoをDFUモードで接続するには、BOOT0ボタンを押しながらUSBケーブルを接続する。

基板をケースに入れていない場合はシルクで確認できるが、基板のType-Cコネクタを左にした時に下側にあるボタンがBOOT0ボタンとなる。 反対側のボタンはリセット。

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

DFUモードで接続できた場合、基板のBOOT0側の赤いLEDだけが光っている状態になるのでおそらくわかるが、確実に確認したい場合はdmesgコマンドを使用し、次のメッセージが表示されていることを確認する。

[26877.865188] usb 1-2: new full-speed USB device number 8 using xhci_hcd
[26878.201184] usb 1-2: device descriptor read/64, error -71
[26878.459003] usb 1-2: New USB device found, idVendor=28e9, idProduct=0189, bcdDevice=10.00
[26878.459008] usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[26878.459012] usb 1-2: Product: GD32 0x418 DFU Bootloade
[26878.459015] usb 1-2: Manufacturer: GDMicroelectronics
[26878.459017] usb 1-2: SerialNumber: 䌳䩂

これでファームウェアの書き込みが可能となる。

ビルドと書き込み

次のコマンドでファームウェアをビルドする。

$ pio run

次のコマンドで書き込む。

$ pio run -t upload

次のように「dfu-util: dfuse_download: libusb_control_transfer returned -1」というエラーが表示される。

Opening DFU capable USB device...
ID 28e9:0189
Run-time device DFU version 011a
Claiming USB DFU Interface...
Setting Alternate Setting #0 ...
Determining device status: state = dfuERROR, status = 10
dfuERROR, clearing status
Determining device status: state = dfuIDLE, status = 0
dfuIDLE, continuing
DFU mode device DFU version 011a
Device returned transfer size 2048
GD32 flash memory access detected
Device model: GD32VF103CB
Memory segment (0x08000000 - 0801ffff)(rew)
Erase size 1024, page count 128
Downloading to address = 0x08000000, size = 8268

Download    [                         ]   0%            0 bytes
Download    [                         ]   0%            0 bytes
Download    [======                   ]  24%         2048 bytes
Download    [============             ]  49%         4096 bytes
Download    [==================       ]  74%         6144 bytes
Download    [======================== ]  99%         8192 bytes
Download    [=========================] 100%         8268 bytes
Download done.
File downloaded successfully
dfu-util: dfuse_download: libusb_control_transfer returned -1
*** [upload] Error 74
================== [FAILED] Took 2.52 seconds ==================

ここによれば、

That message is unrelated. I recall reading that this was a failure (or perhaps a permissions problem) for a post-transfer operation, I think related to a post-transfer reset, but I forget where I read it. It doesn’t affect the actual flashing of the firmware, so far as I can tell.

とのことで書き込み結果には関係ないらしい。

まとめ

Longan nanoの開発環境をUbuntu 18.04上に構築し、無事に動かすことができた。

PlatformIOなので基本的にはWindowsmacOSでもほぼ変わらない手順で動くとは思うが、デバイスを認識させる手順などがおそらく異なる。

面白そうな基板なのでもう少し遊びたい。