ブログトップ 記事一覧 ログイン 無料ブログ開設

JF1DIR業務日誌 このページをアンテナに追加 RSSフィード

電子工作・オーディオクラフト・アマチュア無線・コンテスト・BCL
プロフィールはこちら

2017-11-17 Mbed OS 2をMbed OS 5 CLIで動かす

Mbed OS 2をMbed OS 5 CLIで動かす

| Mbed OS 2をMbed OS 5 CLIで動かすを含むブックマーク Mbed OS 2をMbed OS 5 CLIで動かすのブックマークコメント

前回の記事でMbed OS 5のCLIインストールし実際にARMを動かすのをお見せしました。Mbed OS 5に対応していないボードをtargetにすると、そのままでコンパイルできないのでイマイチ使い物にならないと思い込んでましたが、実は(まぁ当たり前ですが)そんなことはありませんでした。GitHubのMbed CLIのページを見るとMbed OS 2を動かせるとあります。引用すると、

$ mbed new mbed-classic-program --mbedlib
[mbed] Creating new program "mbed-classic-program" (git)
[mbed] Adding library "mbed" from "https://mbed.org/users/mbed_official/code/mbed/builds" at latest revision in the current branch
[mbed] Downloading mbed library build "f9eeca106725" (might take a minute)
[mbed] Unpacking mbed library build "f9eeca106725" in "D:\Work\examples\mbed-classic-program\mbed"
[mbed] Updating reference "mbed" -> "https://mbed.org/users/mbed_official/code/mbed/builds/f9eeca106725"
[mbed] Couldn't find build tools in your program. Downloading the mbed 2.0 SDK tools...

とこれはWidowsでの動作例ですが、--mbedlibオプションで昔のmbedライブラリまるごとごっそりとgitで引っ張ってくることができるようです。しかし、実際にやってみると、

$ mbed new mbed-classic-program --mbedlib
[mbed] Creating new program "classic-test" (git)
[mbed] Adding library "mbed" from "https://mbed.org/users/mbed_official/code/mbed/builds" at latest revision in the current branch
[mbed] Updating reference "mbed" -> "https://mbed.org/users/mbed_official/code/mbed/builds/tip"
[mbed] Couldn't find build tools in your program. Downloading the mbed 2.0 SDK tools...

となり、mbedライブラリダウンロードしません。mbed-classic-program/mbedディレクトリが空っぽです。

ならばマニュアルで強引にライブラリダウンロードしようと、ブラウザhttps://os.mbed.com/users/mbed_official/code/mbed/アクセスし、ダウンロードレポジトリzipファイルクリックしてダウンロードしてきました。unzipしてできたファイルを丸ごと、先のmbed-classic-program/mbedにコピーしてしまうと、一応、プロジェクト内のファイル構成がおなじになるはずです。

ターゲットをLPC11U35のQuickStart Board互換(秋月で売ってる互換ボード)として、Lチカのmain.cppを適当にこしらえ、コンパイルしてみます。

$ cat main.cpp
#include "mbed.h"
DigitalOut led(P0_8);
int main()
{
  led = 0;
  while(1) {
    led = !led;
    wait(0.5);
  }
}
$ mbed compile -m lpc11u35_401
Building project mbed-classic-program (LPC11U35_401, GCC_ARM)
Scan: .
Scan: env
Scan: mbed
Compile [100.0%]: main.cpp
Link: mbed-classic-program
Elf2Bin: mbed-classic-program
+--------------------------+-------+-------+------+
| Module                   | .text | .data | .bss |
+--------------------------+-------+-------+------+
| BUILD/lpc11u35_401       |   228 |     4 |   24 |
| [fill]                   |   281 |     0 |    6 |
| [lib]/c_nano.a           |  2391 |   100 |   12 |
| [lib]/gcc.a              |  1044 |     0 |    0 |
| [lib]/mbed.a             |  1368 |     0 |   30 |
| [lib]/misc               |   244 |     8 |   28 |
| mbed/TARGET_LPC11U35_401 |  2928 |     8 |   24 |
| Subtotals                |  8484 |   120 |  124 |
+--------------------------+-------+-------+------+
Total Static RAM memory (data + bss): 244 bytes
Total Flash memory (text + data): 8604 bytes

Image: ./BUILD/lpc11u35_401/GCC_ARM/mbed-classic-program.bin

はい。これでMbed OS 2のボードでも無事にMbed CLIビルドすることができました。やれやれ

f:id:WideR:20171117224637j:image

2017-11-10 爆安Black Pillをmbedで動かしてみた

爆安Black Pillをmbedで動かしてみた

| 爆安Black Pillをmbedで動かしてみたを含むブックマーク 爆安Black Pillをmbedで動かしてみたのブックマークコメント

またまたマイコンネタですが・・・・世の中にARMの石であるSTM32F103C8T6のボードがありまして、これをArduinoにするという「STM32duino」プロジェクトがあるそうです。ここを見るとこの石の評価ボードにはいろいろ亜流があるらしく、Blue PillやらBlack Pillといわれる中華コピー版が100円台と超格安で売られているとのことで、Aliexpressで10枚くらい購入しましまた。で、忘れた頃に届きました。Arduinoではなくもちろんmbedで動かしてみたのですが、実に簡単です。これがおそらく最安値のmbedハードでしょう。Cortex-M3がこんな安く手に入り手軽に使えるなんてさすがARMでありSTであります。

f:id:WideR:20171110204020j:image

ピンのはんだ付け

ピンとジャンパスイッチが付いていないので自分ではんだ付けします。変な油が基板にべっとり付いていたので、アセトンを浸した綿棒でよく拭ってからはんだ付けしましょう。ピン名のシルク印刷が非常に不鮮明、基板の切断位置がズレたりして、さすがは中華クオリティです。

基板上のジャンパスイッチは、ISPモードにするか動作モードにするかのスイッチらしく、ISPモード起動はB0+/B1-のようです。

f:id:WideR:20171110204043j:image

mbedコンパイル

STM32F103C8T6はmbedに非対応ですが、これに似ているNUCLEO F103RBmbedのプラットフォームにしてしまえば、出来上がったプログラムはバイナリ互換です。しかmbed OS 5対応。オンラインコンパイラもしくはmbed CLIでLチカプログラムをコンパイルします。

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

UARTでプログラムを転送

USB-シリアル変換のTXをボードのRX(A10)、RXをボードのTX(A9)に接続し(なおピン配置はBlue Pillの基板であるがココを参考にしました)、stm32flashというツールダウンロードして入手します。なおLinux版のファイルは"stm32flash-0.5.tar.gz"です。以下Linuxでの操作を示します。

$tar xvfz stm32flash-0.5.tar.gz
$cd stm32flash
$sudo make install

USB-シリアル変換のUSBPCに挿して、dmsegコマンドで、シリアルポートを確認。

$dmseg | grep 'USB Serial'
[850126.770536] usb 2-1.7: FTDI USB Serial Device converter now attached to ttyUSB0

ここでは/dev/ttyUSB0がシリアルポートでした。Fチカのプログラムをそのポート転送します。

$sudo stm32flash -w F103test.bin -v -g 0x0 /dev/ttyUSB0
stm32flash 0.5

http://stm32flash.sourceforge.net/

Using Parser : Raw BINARY
Interface serial_posix: 57600 8E1
Version      : 0x22
Option 1     : 0x00
Option 2     : 0x00
Device ID    : 0x0410 (STM32F10xxx Medium-density)
- RAM        : 20KiB  (512b reserved by bootloader)
- Flash      : 128KiB (size first sector: 4x1024)
- Option RAM : 16b
- System RAM : 2KiB
Write to memory
Erasing memory
Wrote and verified address 0x08004d84 (100.00%) Done.

Starting execution at address 0x08000000... done.

これで書き込みできました。プログラム起動するには、ジャンパをB0-/B1-にして電源を入れます。

f:id:WideR:20171110204115j:image

秋月のLPC11U35 QuickStart互換ボードも安いですが、Black Pillはmbed OS 5に対応しているSTM32F103なのでmbed CLIで開発するにはとてもFBで使いやすそうです。

【追記】Windows上でbinファイル転送

リクエストがありましたので、Windows上での方法を記してみます。ここにstm32flashのWindows版があるので、これをダウンロードして適当なフォルダに展開します。実行ファイルの"stm32flash.exe"はCLIプログラムなので、このフォルダパスを通すか、Windows PowerShellもしくはDOSプロンプトを実行しこのフォルダに移動します。さらにmbedコンパイラビルドしたBinファイルをこのフォルダへ移動しておきます。

次にデバイスマネージャーを開いて、「ポート(COMとLPT)」を開いてUSB Serial Portのポート番号を確認してます。例えば、COM9だとします。Black PillをISP起動モードにしてUSBをつなぎ直して、プロンプトから、

> .\stm32flash.exe  -w '.\F103test.bin' -v -g 0x0 COM9

とすると、Black Pillへ書き込まれます。エラーが出る場合は、ISP起動モードになっているか、COMポートが正しく指定されているか、Black Pillへの配線が正しいかUSBバスパワーが足りているか確認して下さい。

2017-11-09 mbed CLIをlinuxで構築してみた

mbed cliをlinuxで構築してみた

| mbed cliをlinuxで構築してみたを含むブックマーク mbed cliをlinuxで構築してみたのブックマークコメント

これまで書いてきたマイコン記事の通り、ふだんの工作に使っているマイコンARM mbedです。世の中で最も出回っているマイコンであり、安価で手に入りやすく、それでいてクラウドmbed環境はとても使いやすいからです。しかし日本ではPICAVR(Arduino)に負けるらしく、日本語で情報を入手できにくい感があります。

今回オフラインコンパイラであるmbed OS 5のmbed CLIコマンドラインインターフェイス)をLinux上に環境構築してみたので、備忘録代わりにブログに記してみます。ST安価mbedボードであるNUCLEOシリーズをCLIビルドする際、ハマってしまった点がいくつかあったのでその解決法も記してみます。

まずは、こちらのシステム環境です。

Ubuntu 16.04.3 LTS

Linux kernel 4.4.0-92-generic 64bit

GCC 5.4.0 20160609

Python 2.7.12

usbmountのインストール

USBマウントして実行権付きで読み書きするパッケージをインストールします。

$sudo apt-get install usbmount

mbedボードをUSBポートに差し込んでUSBストレージとして認識させ、dfコマンドで見ると、/media/usb0などが見えるはずです。しかしこのままではファイルのユーザーがrootなので多少使いにくいです。そこで/etc/usbmount/usbmount.confを編集してみます。

MOUNTOPTIONS="sync,nodev,noatime,nodiratime"
FS_MOUNTOPTIONS="-fstype=vfat,uid=yuji,gid=yuji"

この2箇所を書き換えると実行権が自分のものになるので使いやすくなります(あくまで個人環境で使う場合の設定です)。

Python 2.7を入れる

mbedpythonスクリプトを多用するので入ってなければPythonを入れておきます。デフォルトでpython3が動く環境だとエラーになるので注意して下さい。Pythonのモジュールインストーラーであるpipも使うので、

$sudo apt-get install python2.7 python-pip

としておきます。続いてmbed cliをpipでインストール

$sudo pip install mbed-cli

ARM GCC, mercurial, gitインストール

ツールチェーンであるARM GCCレポジトリ管理のMercuialと必要ならばGitも入れておきます。

$sudo apt-get install gcc-arm-none-eabi mercurial git

Lチカのプロジェクトを作ってコンパイル

定番テストプログラムである「Lチカ」を動かしてみましょう。オンラインmbed IDEと同様プロジェクトとしてディレクトリを用意しておきます。

$mkdir mbed-test
$cd mbed-test
$mbed new .

ここでmbed-osのすべてのライブラリgithubからダウンロードしてくるので結構時間がかかります。

次に、ここのフォルダUSBマウントされているmbedボードを認識させます。ここではSTのNucleo F411REをつなげてみた例です。

$mbed detect

[mbed] Detected NUCLEO_F411RE, port /dev/ttyACM0, mounted /media/usb0
[mbed] Supported toolchains for NUCLEO_F411RE
+---------------+-----------+-----------+-----------+-----------+-----------+-----------+
| Target        | mbed OS 2 | mbed OS 5 |    ARM    |  GCC_ARM  |    IAR    |   ARMC6   |
+---------------+-----------+-----------+-----------+-----------+-----------+-----------+
| NUCLEO_F411RE | Supported | Supported | Supported | Supported | Supported | Supported |
+---------------+-----------+-----------+-----------+-----------+-----------+-----------+
Supported targets: 1
Supported toolchains: 4

もしNucleo 4xxを使っていて正しく認識されないようならば、ST-LINKファームアップしてみて下さい。mbedのページあります。Windows機でST-LINKで接続し(場合によって最新のデバイスドライバが必要かも。場所は先のリンクにあります)、Windows上のファームアップソフトを立ち上げてファームアップできます。

また、この時点で、

[mbed] Auto-installing missing Python modules...

と表示されたら、足りないPythonモジュールがあるようなので、追加で入れておきます。

$sudo pip install -r mbed-os/requirements.txt

まだプロジェクトにプログラムの中身が無いので、Lチカのmain.cppを作っておきます。

#include <mbed.h>
DigitalOut led1(D13);
int main()
{
  led1 = 1;
  while(1) {
    led1 = !led1;
    wait(0.1);
  }
}

D13ピンにLEDのアノードを接続、GNDにカソードを接続しておきます。モジュールとツールチェインの設定を済ませて、ようやくビルドへ。

$mbed target NUCLEO_F411RE
$mbed toochain -G GCC_ARM
$mbed compile

設定とソースに誤りがなければ、

Building project mbed-test (NUCLEO_F411RE, GCC_ARM)
Scan: .
Scan: mbed
Scan: env
Compile [  5.8%]: TimerEvent.cpp
Compile [  6.1%]: Timeout.cpp
Compile [  6.4%]: Timer.cpp
・
・
・
Compile [ 99.7%]: stm_spi_api.c
Compile [100.0%]: test_env.cpp
Link: mbed-test
Elf2Bin: mbed-test
+------------------+-------+-------+------+
| Module           | .text | .data | .bss |
+------------------+-------+-------+------+
| [fill]           |   115 |     4 |   11 |
| [lib]/c.a        | 17219 |  2472 |   89 |
| [lib]/gcc.a      |  3120 |     0 |    0 |
| [lib]/misc       |   252 |    16 |   28 |
| main.o           |    80 |     4 |   28 |
| mbed-os/drivers  |   136 |     4 |  100 |
| mbed-os/hal      |   863 |     0 |   26 |
| mbed-os/platform |  1246 |     4 |  270 |
| mbed-os/rtos     |  8539 |   180 | 5988 |
| mbed-os/targets  |  6102 |     4 |  820 |
| Subtotals        | 37672 |  2688 | 7360 |
+------------------+-------+-------+------+
Total Static RAM memory (data + bss): 10048 bytes
Total Flash memory (text + data): 40360 bytes

Image: ./BUILD/NUCLEO_F411RE/GCC_ARM/mbed-test.bin

と表示されbinファイルが生成されます。このファイルmbedにコピーすれば完了。

$cp ./BUILD/NUCLEO_F411RE/GCC_ARM/mbed-test.bin /media/usb0

無事にLチカが動くはずです。

NUCLEO F746ZGでは最新のtoolchainが必要!

別のmbedボードにつなぎ直して動作するか確かめていたところ、mbed OS 5に対応のSTMのNucleo F746ZGでは、うまくコンパイルできませんでした。

$mbed target NUCLEO_F746ZG
$mbed compile
・
・
・
/usr/lib/gcc/arm-none-eabi/4.9.3/../../../arm-none-eabi/bin/ld: error: /usr/lib/gcc/arm-none-eabi/4.9.3/../../../arm-none-eabi/lib/libc.a(lib_a-setjmp.o): Conflicting CPU architectures 13/1
/usr/lib/gcc/arm-none-eabi/4.9.3/../../../arm-none-eabi/bin/ld: failed to merge target specific data of file /usr/lib/gcc/arm-none-eabi/4.9.3/../../../arm-none-eabi/lib/libc.a(lib_a-setjmp.o)
collect2: error: ld returned 1 exit status
[ERROR] /usr/lib/gcc/arm-none-eabi/4.9.3/../../../arm-none-eabi/bin/ld: error: /usr/lib/gcc/arm-none-eabi/4.9.3/../../../arm-none-eabi/lib/libc.a(lib_a-setjmp.o): Conflicting CPU architectures 13/1
/usr/lib/gcc/arm-none-eabi/4.9.3/../../../arm-none-eabi/bin/ld: failed to merge target specific data of file /usr/lib/gcc/arm-none-eabi/4.9.3/../../../arm-none-eabi/lib/libc.a(lib_a-setjmp.o)
collect2: error: ld returned 1 exit status

リンカの設定がおかしいの?pythonもモジュールがおかしいのか?いろいろ悩んだり調べてみた挙句、最新のGCC Toolchainを使えば治るっぽいことがわかりました。早速、GNU ARM Embedded Toolchainのページへ行ってLinux版のライブラリをダウンロードしてきました。

これをbunzip2+tarで展開し、展開場所が/usr/localだとすると、そこにパスを通しておくのを忘れずに。

$mbed config -G GCC_ARM_PATH="/usr/local/gcc-arm-none-eabi-6-2017-q2-update/bin"

とし、compileをかけると、

$mbed compile
・
・
・
Compile [100.0%]: test_env.cpp
Link: mbed-test
Elf2Bin: mbed-test
+------------------+-------+-------+-------+
| Module           | .text | .data |  .bss |
+------------------+-------+-------+-------+
| [fill]           |   104 |     4 |    19 |
| [lib]/c.a        | 17219 |  2472 |    89 |
| [lib]/gcc.a      |  3120 |     0 |     0 |
| [lib]/misc       |   252 |    16 |    28 |
| main.o           |    80 |     4 |    28 |
| mbed-os/drivers  |   136 |     4 |   100 |
| mbed-os/features |    44 |     0 | 12556 |
| mbed-os/hal      |   863 |     0 |    26 |
| mbed-os/platform |  1246 |     4 |   270 |
| mbed-os/rtos     |  8809 |   180 |  5988 |
| mbed-os/targets  |  9727 |     4 |  1084 |
| Subtotals        | 41600 |  2688 | 20188 |
+------------------+-------+-------+-------+
Total Static RAM memory (data + bss): 22876 bytes
Total Flash memory (text + data): 44288 bytes

Image: ./BUILD/NUCLEO_F746ZG/GCC_ARM/mbed-test.bin

と、無事にビルドが通りました。

f:id:WideR:20171109215131p:image

mbed CLIを使ってみて

mbed OS 5に対応していないとダメなのが残念ですが、使い慣れたLinux上のCエディタ(Emacs)でサクサクとコードが書けるのが快適です。mbed OS 5に対応しているNucleoのようなボードでソースのトライアンドエラーを済ませて、またオンラインコンパイラに戻って古いmbedボードを動かす、というのも悪くないと思っています。しかし、mbed-osを一々ダウンロードしてくるのには閉口しました・・・^^;まだまだ洗練度が足りない感じですね。

Windowsにもオフラインコンパイラがほしいですが、CLIではなくWindowsらしくEclipseで動かしてみたいと思います。

2017-10-09 ドットマトリックスLED LTP-305を動かしてみた

ドットマトリックスLED LTP-305を動かしてみた

| ドットマトリックスLED LTP-305を動かしてみたを含むブックマーク ドットマトリックスLED LTP-305を動かしてみたのブックマークコメント

部品箱を整理していると買い込んでみたものの買ったことすら忘れられている部品ってありますよね。この連休に整理していたら、ドットマトリックスタイプのLEDディスプレイ LTP-305HRが大量に出てきました(汗)。ちょうどmbedをいじっていたところなので光らせてみました。

LEDエレメントは5列7行のマトリクスでピン配置はこのとおり。

f:id:WideR:20171009214227j:image

列のアノードと行のカソードがつながるとその交点のLEDが光るという仕組みで、デコーダーのようなものは内蔵されていません。文字を表示させるには各列(または各行)をダイナミック点灯していく必要があります。多桁表示し接続ピン数を節約するためには、行を並列接続し、列をスキャンさせていくのが良さそうです。

どこか探せばライブラリが見つかりそうですが、とりあえず数字「0」〜「9」を光らせることくらいなら自力で作ってみました。各文字のドットパターンを決めて、各列のパターン(一次元)をビットデータに置き換えて(行は7つなので先頭ビットを0に固定)1バイト表現してみました。つまり、各文字を5バイトを割り当てました。例えば、「0」は、{0x3e, 0x45, 0x49, 0x51, 0x3e}となります。各列ごと各行ごとに、ビットシフトして光らせるデータを取り出し、高速に列をスキャンしていき、チラ付かない程度のウェイトでループさせてみました。

マイコンLPC11U35の互換ボードを使ってみました。GPIOがたくさんあるので、3桁くらい光らせることができそうです。実際に動かしてみた動画がこちらです。

D

少し明るいところでは視認性が悪く、各点の明るさにバラツキがあるのが気になりますね。ディスプレイの上に曇りガラスやスモークを乗せると少し見やすくなりますが・・・。

デモのプログラムはこちらです。後日、mbedレポジトリに登録したいと思います。

// Dot matrix led display LTP-305 demo using mbed LPC11U35
// copyright 2017 Oct, JF1DIR
// LTP-305 http://akizukidenshi.com/catalog/g/gI-07440/
//

#include "mbed.h"

Ticker sec_timer;
DigitalOut col[5]={P0_7, P0_8, P0_9, P0_10, P0_22}; // connected anodes
DigitalOut row[7]={P0_6, P0_21, P0_5, P0_4, P0_3, P0_2, P0_20}; // connected cathodes

unsigned char numdata[10][5] = {
                                {0x3e, 0x45, 0x49, 0x51, 0x3e}, // "0"
                                {0x00, 0x21, 0x7f, 0x01, 0x00}, // "1"
                                {0x21, 0x43, 0x45, 0x49, 0x31}, // "2"
                                {0x42, 0x41, 0x51, 0x69, 0x46}, // "3"
                                {0x0c, 0x14, 0x24, 0x7f, 0x04}, // "4"
                                {0x72, 0x51, 0x51, 0x51, 0x4e}, // "5"
                                {0x1e, 0x29, 0x49, 0x49, 0x06}, // "6"
                                {0x40, 0x47, 0x48, 0x50, 0x60}, // "7"
                                {0x36, 0x49, 0x49, 0x49, 0x36}, // "8"
                                {0x30, 0x49, 0x49, 0x4a, 0x3c}  // "9"
                                };
int sec = 0;

void countup()
{
    sec++;
    if (sec > 9) sec = 0;
}

int main() {
    unsigned char x;
    int k = 0; // number of col
   
    sec_timer.attach(&countup, 0.3);
    
    while(1) {
        for(int i = 0; i < 5; i++) col[i] = 0; // all segments turn off
        for(int i = 0; i < 7; i++) row[i] = 1; // all segments turn off
        x = numdata[sec][k];
        col[k] = 1;
        for(int i = 0; i < 7; i++) {
            if ((x & 0x40) == 0x40) row[i] = 0;
            x <<= 1;
        }
        k++;
        if (k > 5) k = 0;
        wait(0.002);
    }
}

※2017/10/10 追記

3桁バージョンも作ってみました。並列化の配線が大変だったのと、GPIOを22本も使ってしまったので利用価値が微妙です(苦笑)。waitを1ms以下にしないとちらつきが目立ちます。消費電流が大きいのでドライバを使うべきです。

f:id:WideR:20171010235700j:image

2017-09-23 mbedによるGPS同期時計の製作

mbedによるGPS同期時計の製作

| mbedによるGPS同期時計の製作を含むブックマーク mbedによるGPS同期時計の製作のブックマークコメント

久々のブログ更新・・・しかも、電子工作の記事が少ないぞ、と言われ続けようやくの工作ネタで更新になりました(汗)。

お空のcondxもイマイチだし無線運用も飽きてきたなと思い、チョット気分を変えるために、購入したけど手を付けられず放置されていた電子工作キット(いわゆる「積みキット」)を消化しておりました。その中にあった秋月電子から出ている時計のキット2種を作ってみました。なんだかんだ時計が一番実用的ですからね(汗)。

f:id:WideR:20170923222627j:image

下がNTP同期時計で上がGPS同期時計です。この通り、1秒以下できっちり同期しており時刻のズレなど心配せず使えるのですが、このLCD表示では字が小さくて見えないし(寝室に置きたいのでメガネがない状態でも読めないと困る)、バックライトが妙に明るいなど不満が多いものでした。一応シリアルの他桁7セグLEDに接続できる仕様となっているのですが、LEDが選べないのが不満(汗)。どちらも1万円近いお値段で、これならマイコン使って数千円程度で自分で作ってみようと考えました。太陽誘電製GPSモジュールGYSFDMAXB安価で部屋の中でも衛星が常に受信できるという高性能なので使いこなしたいとも思いました。

表示機はLCDよりは7セグLEDがFBです。しかも最近の眩しい高輝度タイプではなくぼんやりと光る古いタイプを使ってみたいと部品箱を漁ると、古い東芝のTLR324が多数出てきました。2桁の赤LEDでカソードコモンタイプのものです。これを3つ並べて6桁にすればOK。TLR324のピン配置はこちら。古い部品なのでデーターシートを見つけるのに苦労しました。ちなみにコレの緑も在庫があるので2台目は緑にしたいです。

f:id:WideR:20170923233132j:image

6桁のLEDをダイナミック点灯するので、信号線は8+6で14本。他にGPSモジュールから出ている1PPSの信号とLED点滅を同期させるために2本、合計16本のGPIOと1つのUSART(シリアル)が必要となります。設計当初はRaspberry Pi3でPythonを使って設計したのですが、たかが時計のためにRPiを組み込んでしまうのはもったいないので、普通のマイコンにすることにしました。mbed安価LPC1114を使ってみたいところだったのですが、ピン数がギリギリ足りないのでNG。手持ちのSTmicroから出ているNucleoが安価なのでこれを使うことにしました。ここ最近Pythonばかりだったので、C++はかなり抵抗があります・・・だけどだんだん慣れてきました(笑)。

ピン数が多くて組みやすいNucleo F746ZGを使ってで試作。ARM32-bitCortex-M7が搭載されておりEthernetもなんでもあり最大クロック216MHzというバケモノクラスのボードですね(汗)。GPSのNMEAパーサーとしてTinyGPSというライブラリを利用しました。

全体のプログラムはごく簡単で、mainループ内でtime(NULL)関数で現在時刻を得ながら、GPSからの受信を割り込みで時刻を取得し、一定時間間隔でset_time関数を使って現在時刻をGPSの時刻に設定(補正)していくだけのものです。GPSモジュールの1PPS出力を立ち下がり・立ち上がり割り込みでLEDを点滅させたりなどもしています。一つ注意点としては、LEDのダイナミック点灯の素早いループがmainで走っているのですが、waitを掛けないとLEDが完全に消灯しないうちに点灯するので、全桁「8」の字に見えてしまいます。これもTLR324のような古いLEDを使っているせいでしょうか、2〜5msくらいのwaitで塩梅よくLEDが点いてくれました。それと、ピンあたりの電流量が不足しがちなので、GPIOに直接LEDを繋げるのではなく、アノード側にソースドライバTD62783AP、カソード側にシンクドライバTD62083AFNPを使いました。これでアノード側もカソード側も正論理でスイッチすることができるので、ソースコードのロジックが気持ち悪くなくなります(苦笑)。

f:id:WideR:20170923222841j:image

ここまでは順調に行ったのですが、次に安価Nucleo F401REに載せ替えようとしたところ、急に動かなくなりました。mainループハングアップ。どうやらシリアル割り込みするとハングアップするようです。F401REには2つのUSARTポートがあり、USART2(tx:D1, rx:D0)であったところを(ちなみにD0, D1ピンは裏面のハンダブリッジをしないと使えないので注意。これもしばらくハマった)。USART1(tx:D10, rx:D2)にすると、mainが動き出しました。しかしLEDの表示がヘンです。そこで割り込みの優先度を上げるためのおまじないとして、"NVIC_SetPriority(USART1_IRQn, 0);"を記述したり、ダイナミック点灯のwaitを微調整しました。それでも安定しません。最後に、GPSからの受信割り込みのコードを一番最初に書くと、完璧に治りました。この正解にたどり着くまで2日費やしまった(大汗)。mbedでもボードを変えるといろいろ不具合が出るものなんですね。Nucleo F401REでの試作の様子がコレ。

f:id:WideR:20170923222936j:image

後はユニバ基板に取り付けケーシングし、視認性がよい安価なGPS同期時計が完成です。

以下にソースコードを示しますが、上記のようにmbedプラットフォームによってそのままでは動かないことがあるので注意して下さい。

/*    GPS同期時計 mbed版 by JF1DIR 2017
 *    Nucleo F401RE
 */

#include "mbed.h"
#include "TinyGPS.h"

DigitalOut led[8]={D1, D3, D4, D5, D6, D7, D8, D9}; // nucleo F401RE
DigitalOut digit[6]={D14, D15, D12, D13, D0, D11};
DigitalOut pps(PC_0);
InterruptIn pps_in(PC_1);
Ticker ticker_set_time;

int number[11][8]={
                    {1,1,1,1,1,1,0,0},          //zero
                    {0,1,1,0,0,0,0,0},          //one
                    {1,1,0,1,1,0,1,0},          //two
                    {1,1,1,1,0,0,1,0},          //three
                    {0,1,1,0,0,1,1,0},          //four
                    {1,0,1,1,0,1,1,0},          //five
                    {0,0,1,1,1,1,1,0},          //six
                    {1,1,1,0,0,0,0,0},          //seven
                    {1,1,1,1,1,1,1,0},          //eight
                    {1,1,1,1,0,1,1,0},          //nine
                    {0,0,0,0,0,0,0,1}          //dot
                  };

Serial serial_gps(D10, D2);  // UART1: tx, rx なぜかF401REのUART2では割り込み不能
TinyGPS gpsr;

int year;
byte month, day, hour, minute, second;

void led_off()
{
    pps = 0;
}

void led_on()
{
    pps = 1;
}

void setup()
{
    pps = 0;
    serial_gps.baud(9600);
    NVIC_SetPriority(USART1_IRQn, 0);
}

void getgps()
{
    if (serial_gps.readable()) {
        char c = serial_gps.getc();
        bool gps_avairable = gpsr.encode(c);
        if (gps_avairable) {
            (void)gpsr.crack_datetime(&year, &month, &day, &hour, &minute, &second);
        }
    }
}

void gps_to_nowtime()
{
    struct tm t;
    t.tm_sec = (int)second;
    t.tm_min = (int)minute;
    t.tm_hour = (int)((hour + 9) % 24);
    t.tm_mday = 1;
    t.tm_mon = 1;
    t.tm_year = 100;
    
    time_t sec2 = mktime(&t);
    set_time(sec2);
}

int main() {
    int h, m, s, v, j, k = 0;
    int x[6] = {0, 0, 0, 0, 0, 0};
    
    time_t seconds;
    struct tm *ts;

    setup();
    serial_gps.attach(getgps, Serial::RxIrq);
    ticker_set_time.attach(&gps_to_nowtime, 10.0);
    pps_in.fall(&led_on);
    pps_in.rise(&led_off);

    while (1) {
        seconds = time(NULL);
        ts = localtime(&seconds);
        h = ts->tm_hour;
        m = ts->tm_min;
        s = ts->tm_sec;
        
        x[0] = (int)(h / 10);
        x[1] = (int)(h - x[0] * 10);
        x[2] = (int)(m / 10);
        x[3] = (int)(m - x[2] * 10);
        x[4] = (int)(s / 10);
        x[5] = (int)(s - x[4] * 10);

        for (v = 0; v < 8; v++) { led[v] = 0; }
        for (v = 0; v < 6; v++) { digit[v] = 0; }
        
        digit[k] = 1;
        j = x[k];

        if ((k == 1) or (k == 3)) {
          for (v = 0; v < 7; v++) { led[v] = number[j][v]; }
          led[7] = 1;
        } else {
          for (v = 0; v < 8; v++) { led[v] = number[j][v]; }
        }
 
        wait(0.005);
        k++;
        if (k > 5) { k = 0; }
    }
}