2026年8月4日火曜日

FDK HY0020で遊んでみる(Raspberry Pi デバッグプローブで書き込み)

秋月で取り扱いの始まったFDK製 超小型BLEモジュール HY0020 にはAdafruit nRF52 ブートローダが書き込まれており、UART経由で容易にプログラムを書き込むことができます。

このブートローダを利用することで書き込みは容易になりますが、リアルタイムOS Zephyrを使うこともできません。

そのため、このブートローダを使用せずに書き込みを行ってみます。

HY0020に搭載されているNordic nRF52832はArmプロセッサが載っており、SWD(Serial Wire Debug)を使用することができます。

このSWDは規格化されたものですので、SWDに対応したデバッガであれば基本的にどのようなものでも使用できます。

今回は手元にあったRaspberry Pi Pico用のデバッガ Raspberry Pi デバッグプローブを使って書き込みできる環境を整えます。

デバッグプローブがなくとも、Raspberry Pi Picoがあればデバッグプローブ化することが可能です。

ハードウェアの接続 (SWD)

Pico Debug Probeの SWD端子(付属のブレッドボード用ジャンパ線)をHY0020モジュールに接続します。
SWDではSWDIO, SWCLKピンを使いますが、秋月のDIP化モジュールではSWCLK, SWDIOは基板真ん中に近いところに配置されていますので、他のピンと逆向きにピンヘッダをつけると、そのままデバックプローブを接続することができます。(この辺りの設計はさすがですね)



接続は以下のように行います。

Pico Debug Probe (SWD側)HY0020モジュール役割
SWCLK (1ピン / 橙)SWDCLK (P0.21)クロック信号
GND (2ピン / 黒)GND共通グランド
SWDIO (3ピン / 黄)SWDIO (P0.18)データ信号

こんな感じで接続してみました。わかりにくいですが、黒はGNDに接続しています。


VS Code での書き込み

今回はPlatformIOを使ったArduino環境を構築します。もしPlatformIOがインストールされていなければ拡張機能からインストールしておいてください。

1. VS Codeに 「Cortex-Debug」 拡張機能をインストールします。


2. PlatformIOで新規Projectを作成します。


3. Adafruit Bluefruit nRF52832 Featherを選択します。


完了すればプロジェクトが作成されます。

4. platformio.inoを以下のように記載します。
[env:adafruit_feather_nrf52832]
platform = nordicnrf52
board = adafruit_feather_nrf52832
framework = arduino

; ==== 書き込みとデバッグの設定 ====
; Pico Debug Probe (CMSIS-DAP) を指定
upload_protocol = cmsis-dap
debug_tool = cmsis-dap

; シリアルモニタの通信速度
monitor_speed = 115200 

今回はBLE_uartのサンプルを元にLEDをuartコマンドで制御するプログラムを作成してみました。
#include <Arduino.h>
#include <bluefruit.h>

// Lチカで使用したピン(P0.17)
const int ledPin = 12;

// BLE UARTサービスのインスタンスを作成
BLEUart bleuart;

// アドバタイズ設定用の関数
void startAdv(void){
  Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
  Bluefruit.Advertising.addTxPower();
  Bluefruit.Advertising.addService(bleuart);
  Bluefruit.ScanResponse.addName();
  Bluefruit.Advertising.restartOnDisconnect(true);
  Bluefruit.Advertising.setInterval(32, 244);
  Bluefruit.Advertising.setFastTimeout(30);
  Bluefruit.Advertising.start(0);
}

void setup(){
  Serial.begin(115200);

  // LEDピンの初期設定
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);

  // BLEの初期化
  Bluefruit.begin();
  Bluefruit.setTxPower(4);
  Bluefruit.setName("HY0020_LED");

  // UARTサービスの開始
  bleuart.begin();

  // アドバタイズの開始
  startAdv();

  Serial.println("BLE UART LED Control Ready.");
}

void loop(){
  if(bleuart.available()){
    // 1文字読む
    char c = (char)bleuart.read();

    // シリアルモニタに受信した文字を表示
    Serial.print("Received: ");
    Serial.println(c);

    // 受信した文字に応じた処理
    if(c == '1'){
      digitalWrite(ledPin, HIGH);
      Serial.println("-> LED Turned ON");
      bleuart.println("LED is ON");
    }
    else if (c == '0'){
      digitalWrite(ledPin, LOW);
      Serial.println("-> LED Turned OFF");
      bleuart.println("LED is OFF");
    }
  }
}

VSCodeの左下の✔️マークがビルド、→マークが書き込みです。



書き込みを行ってみます。

書き込みができれば下記のようにターミナルに表示されます。


動作確認してみます。

BLEの動作確認

スマートフォンに「Bluefruit Connect」というアプリをインストールします。
このアプリ経由でBLEの接続、通信を行います。

アプリを立ち上げるとBLEで接続可能な相手(ペリフェラル)の一覧が表示されます。
HY0020_LEDというペリフェラルに接続します。



接続に成功すると、機能が選択できますので、uartを選択します。
これでBLEを経由したUARTで通信ができます。


画面下にテキストボックスが現れますので、文字を送ります。
今回のプログラムでは、"1"を送るとP0.12ピンがHに(LED ON)、"0"を送るとP0.12ピンがLに(LED OFF)なります。


実際に送るとこんな感じになります。



これで書き込みができるようになりました!
ブートローダを間違って消してしまっても、復旧することが可能です。




2026年7月30日木曜日

FDK HY0020で遊んでみる(Arduino 環境構築編)

秋月電子で面白そうなモジュールの取り扱いが始まったので、早速買ってみました。

FDK製 BLEモジュール HY0020 ブートローダ書き込み済み

https://akizukidenshi.com/catalog/g/g131343/



DIP化キットもあります。

https://akizukidenshi.com/catalog/g/g131342

特徴

超小型のBLE(Bluetooth Low Energy)モジュールです。
外形は 3.5 x 10 x 1 mm と指先に乗る大きさです。
この大きさでBLE用のアンテナや通信用の回路、MPU(Nordic nRF52832) 動作させるための高効率DC-DCコンバータおよびLDO、発振器(32MHz/32.678kHz)まで搭載しています。
要はBLEモジュールなわけですが、必要な周辺部品がかなり少なく、ほぼ電源だけで動作させることができます。

超小型なBLE搭載マイコンボードといっても過言ではないでしょう。

こんな面白そうなもの、触ってみないわけにはいかないですよね!
秋月のマニュアルを参考に早速遊んでみます。

ハードウェア結線

秋月で扱っているものはAdafruit nRF52というブートローダが書き込まれているので、専用のデバッガがなくとも、シリアル通信経由で書き込むことが可能です。

配線は以下のようにします。DTRがない場合はGNDに接続できるようにしておきます。
(起動時にDFUをGNDに接続した状態で起動するとDFUモードに入り、書き込みができるようになります。)


USBシリアル変換側HY0020モジュール側備考
VCC (3.3V)VDD絶対に5Vを入力しないでください
GNDGND
TXD (送信)RXD (受信)クロス接続
RXD (受信)TXD (送信)クロス接続
DTRDFU 0.1µFのコンデンサを直列に挟んで接続する




DIP化モジュールのピン配置は上記の通り。わかりやすく配線されています。

開発環境の構築

今回は、Arduino環境でサンプルスケッチを動かすところまでやってみようと思います。

ボードマネージャURLの追加

Preferences / 環境設定
ファイル > 環境設定 (macOSの場合は Arduino IDE > Settings...)を開き、「追加のボードマネージャのURL」に以下を追加してOKを押します。
https://adafruit.github.io/arduino-board-index/package_adafruit_index.json



すでにURLが入っている場合は、「,」を入れてその後にURLを入れるようにしてください。

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

ボードマネージャ
ツール > ボード > ボードマネージャ を開き、検索窓に「nRF52」と入力します。
リストから Adafruit nRF52 by Adafruit を見つけてインストールする。



ターゲットボードとポートの選択

ベースモデルとしてFeatherを使用

ツール > ボード から Adafruit Feather nRF52832 を選択します。


続いて ツール > シリアルポート から、接続したUSBシリアル変換モジュールのポート (WindowsならCOM番号、Macなら /dev/cu.usbserial-xxxなど)を選択します。



プログラムのコンパイルと書き込み

適当なサンプルスケッチを書き込んで動作確認をしてみます。
今回は下記のLチカのプログラムを書き込んでみます。
ファイル > スケッチ例 > Adafruit Bruefruit nRF52 Libraries > Hardware > blinky



DFUピンをGNDに落とした状態で電源を投入します。
マイコンボードに書き込む(→ボタン)を押します。
自動的にシリアル経由で書き込みが行われます。


書き込み完了!

これで書き込みまでできましたので、次回はBluetoothを使ってみようと思います。

2023年5月18日木曜日

whisperを使って自動文字起こしシステムを作ってみた

 家族が録音したデータをいちいち聞いてまとめるのが大変で負担になっているということだったので、最近流行りのAIを使って文字起こしをするシステムを作ってみました。

文字起こしをしてくれるクラウドサービスなどもあるようでしたが、今回はオープンソースで使えるwhisperを使ってみました。

whisperはOpenAI社の作った自動文字起こしするためのAIで、日本語に対応した学習モデルも公開されています。

whisper + python で思ったよりもかなり簡単にできてしまったので驚いています。家族も大満足なので、おすすめです。


作ったシステムの概要

音声データをフォルダに入れておいて、定期的にサーバから音声ファイルを確認して、文字起こしがされていなければそのファイルを文字起こしして結果のテキストファイルを特定のフォルダに書き出す、というものです。

文字起こし自体はpythonで実現しました。
定期的な処理は自宅のサーバ(ubuntu)のcronで定期実行しています。
文字起こしにはそれなりに時間がかかるので、夜間に実行するようにしています。

必要なソフトウェアのインストール

以下のブログを参考にさせていただきました。

以下、前提としてpythonの環境構築はできているものとします。
今回はubuntu 20.04で実行しています。

whisperのインストール

githubに公開されているものをpipコマンドでインストールします。

$ pip install git+https://github.com/openai/whisper.git

ちょっと時間がかかります。
このインストールが完了した時点では学習モデルはダウンロードされていません。

ffmpegのインストール

今回、iphoneで録音したデータをNASに保存してもらい、その文字起こしを行いました。
iphoneの標準のアプリで録音されたデータはm4aという拡張子で、ubuntu標準ではコーデックがないようなので、ffmpegをインストールしておきます。

$ sudo apt-get install ffmpeg

Pythonスクリプト(文字起こし)

文字起こしスクリプトはpythonで実装しました。
文字起こしした結果のテキストファイルは指定のフォルダパスに、音声ファイルのファイル名の拡張子を.txtに変えたファイル名で保存するようにしています。

毎回すべての音声ファイルを文字起こしするといろいろと無駄なので、音声ファイルとテキストファイルの一覧を比較し、テキストファイル(文字起こしの結果ファイル)がないもののみ文字起こしするようにしています。

whisperの文字起こし結果は音声ファイルの時間なども含まれていますが、文字起こししたテキストのみ保存しています。

以下が最終的なファイルです。

# -*- encoding:utf-8 -*-
#----------------------------------------------------
# auto_whisper.py
#
# generate trascription file from audio data.
# ---------------------------------------------------
import glob
import os
import re
import whisper

# audio file types
audio_types = "(m4a|mp3|wav)"

# filepath
audio_folder_path = "音声ファイルのフォルダパス"
text_folder_path = "出力テキストファイルのフォルダパス"

# audio file list
audio_file_list = []
for audio_file in glob.glob(audio_folder_path+"/*"):
    if re.match('.+\.'+audio_types+'$', audio_file):
        audio_file_list.append(audio_file)

# text file list
text_file_list = []
for text_file in glob.glob(text_folder_path+"/*"):
    if re.match('.+\.txt$', text_file):
        text_file_list.append(os.path.splitext(os.path.basename(text_file))[0])

# pick up audio files that have not yet been transcripted.
transcript_file_list = []
for audio_file in audio_file_list:
    if os.path.splitext(os.path.basename(audio_file))[0] in text_file_list:
        print(audio_file, "ari")
    else:
        print(audio_file, "nashi")
        transcript_file_list.append(audio_file)

# transcript files
if bool(transcript_file_list):
    # load model
    model = whisper.load_model("small")

    print("transcripting...")

    # transcript files
    for transcript_file in transcript_file_list:
        print("trascripting: "+ transcript_file)
        # output file
        output_file_path = text_folder_path + "/" + os.path.splitext(os.path.basename(transcript_file))[0] + ".txt"
        f = open(output_file_path, 'w')

        result = model.transcribe(transcript_file, verbose=True, language='ja')

        f.write(result["text"])

        f.close()

# end


定期実行

定期実行はシンプルにcronを使っています。
処理時間がかかるので夜間に実行するようにしています。


2023年2月19日日曜日

Kicad 6 で部品がSTEPファイルに出力できない場合の対応策

 Kicad 6 でSTEPファイルに出力してFusion360でインポートをよく実施するのですが、

そのときに部品がSTEPファイルにエクスポートできていない時があります。

対策として、部品の3DモデルをSTEPファイルにする必要があります。


デフォルトのライブラリではwrl形式のファイルだったりするので、その場合には対応が必要です。


デフォルトの3DモデルのフォルダにSTEPファイルも入っているので、その場合には差し替えるだけでOKです。

2021年3月6日土曜日

今更ながらRaspberry Pi Picoを触ってみる(環境構築)

Raspberry Pi は前から触っていたのですが、Raspberry Pi Picoが出たというニュースを見た時も、どうせZeroみたいに小さくなっただけでしょと思い込んであまり興味がありませんでした。

よくよく調べてみると、これまでのRaspberry Piとは異なりベアメタルで使用することが前提ということが分かり、マイコン好きとしては断然興味が湧いてきました。



 ということでまずは開発環境の構築をしてみます。

2020年10月23日金曜日

宅内LAN配線してIPv6とIPv4を両立してVPNサーバを立ててみた

今年の秋についに一軒家を購入したので、家庭内のLANを構築しなおしました。
備忘録を兼ねてゼロからLANケーブルを壁内配線してネットワークを構築するまでをまとめます。

やっぱり高速なIPv6(IPoE)で有線LANを引き回したいし、VPNもつなぎたい

宅内でLANを引き回すからにはなるべく高速で快適な環境を作りたいですね。
インターネットの接続はPPPoE方式ではなくIPoE方式とします。
IPoE方式などはこちらが参考になりました。

IPoE方式についていろいろ調べてみると、サーバの公開やVPNサーバがそのままではできないことが分かり、先人たちが二重ルータにしたりいろいろ試行錯誤されていることも分かりました。
要はIPv4ネットワークとIPv6ネットワークを共存させれば何とかなりそうです。
今回はIPoEオプションが2020年1月から無料になったということでIIJのmioひかりを契約しました。

有線を宅内に配線する

インターネットへの接続方法が決まったところで、宅内に有線LANを張り巡らせる方法を考えます。
壁内に配線管(CB管)をあらかじめ用意しておき、そこにLANケーブルを通すのが理想的ですが、私が購入した家はそのような配線管はありません。
そうなるとLANケーブルを引き回すには部屋の中にモールを設置してそのモールの中をLANケーブルを通すか、どうにかして壁内を引き回す必要があります。
モールは簡単でよいのですが、見栄えが良くありません。
ということで、大変そうですが壁内にLANケーブルを通すことにしました。

住宅の構造がどうなっているのか調べてみた

今回LANケーブルを引き回す我が家はいわゆる在来工法(木造軸組構法)です。
在来工法は木で柱と梁で構造をつくり、そこに壁を張っていきます。
梁の両側に壁を張るため、壁と壁の間にスペースができます。そのままでは断熱効果が弱いので断熱材をこの壁の間に敷き詰める構造になっています。
上から見た断面図はこんな感じです。

今回、この壁と断熱材の間にLANケーブルを通していきます。

我が家はロフトのような屋根裏収納があり、そこから点検口を通じて屋根裏に入ることができます。
この屋根裏収納を簡易サーバルーム(夏は暑いのであまりよくないですが...)にするため、屋根裏と各部屋にLANケーブルを配線します。
LANケーブルはコンセントに接続口を設ける形にします。

屋根裏から壁の中へ通線ワイヤを通す

壁内を通すといっても、壁の中へ入ったりすることはできないので、何らかの方法で屋根裏からコンセントまでLANケーブルを通す必要があります。
今回は通線ワイヤを用意して作業することにしました。壁の中を通すためになるべくスリムなものをということで、ジェフコムのDENSAN BX4030Jを用意しました。
ケース付きでお買い得です。



作戦としては、屋根裏からコンセントにつながる電力線(VVFケーブル)を探し、その電力線伝いに通線ワイヤを壁の中に通していきます。
屋根裏はこんな感じでした。下に見えている白いものが断熱材です。断熱材の下は天井なので、体重をかけたら天井が抜けて下に落ちます。柱の上を通って電力線を辿っていきますが、柱と柱の間隔が空いているところがあるので、近所のホームセンターで2×10の木材を買ってきて足場にしました。


通線前にあらかじめコンセントのふた(?)を開けておきます。
天井裏から壁の中に通線ワイヤを通し、ワイヤの先が目的のコンセントまで到達したら、その先にLANケーブルを取り付けて屋根裏に引っ張り上げて作業完了です。
ワイヤの先が目的のコンセントにうまくいくかは運次第です。何度もワイヤを出し入れしてようやく目的のコンセントまで届きました。


ここまでくれば後は通線ワイヤの先にLANケーブルを括り付けて天井裏に引っ張り上げるだけです。
これを繰り返して必要な部屋にLANケーブルを配線しました。

コンセントのLANケーブルの接続口はぐっどすを使いました。
LANケーブルのコネクタは結構つけるのが大変なイメージがありましたが、工具もいらず楽ちんです。
こんな感じでLANケーブルの口を取り付けることができました。


CD管を通しているわけではないので、交換することはしばらくないだろうと思い贅沢にCAT6のケーブルを通しました。

外からVPNでつなげるようIPv4を共存させる

さて、物理的な接続ができたところで宅外からつなぐ用のIPv4とインターネットに高速に接続するためのIPv6を共存させる方法を考えます。
以前やっていたように、外部にVPNサーバを立てて家庭内のサーバからブリッジを張るという方法もあり、これでもうまくいきそうな気がしましたが、なんだか複雑になってしまいそうなので、なるべくシンプルにしたいところです。

いろいろ調べてみると、以下の記事が見つかりました。

これはいいなということで、こちらの記事を参考にネットワークを構築することにしました。

VPNがつながらない

ubuntuマシンにSoftether VPNサーバを立てて、ルータの設定をしてみました。
構成は以下のような感じです。



上記の記事にあるようにルータ側の設定でVPNサーバからの通信はIPoEではなくPPPoEで接続するように設定してあげます。
こうすることでVPNサーバからの通信はPPPoEによるIPv4接続、ほかのPCやスマートフォンからの接続はIPv6接続できるようです。

しかし、LAN内部から外部にIPv6で出ていくことはできるのですが、外部からVPNサーバへの接続ができません。
ためしにルータの接続方式をPPPoE(IPv4)に変えると外部からVPN接続できました。
どうやらVPNサーバ自体は正常に動いているようです。
ルータの設定を色々変えて試してみましたが、結局IPoEにして外部からVPNサーバへ接続することはできませんでした。
何日か悩んで結局うまくいかず諦めました。

二重ルータにしてみる

ルータを一台の構成は諦めて、ルータを2台使用する方法を試してみました。
構成はこんな感じです。


ルータ1はIPoEで接続するルータで、PPPoEパススルー(Baffuloはこういう設定名のようです。PPPoEブリッジとか呼ばれる場合もあるようです)設定しておきます。
もう一台のルータ2PPPoEで接続するルータです。
また、この2台のルータのLAN側を接続して同じLANセグメントとしておきます。
(この時、片方のDHCPサーバ機能はOFFにする必要があります)
ルータ1,2どちらをデフォルトゲートウェイに設定するかでIPv4ネットワークに繋ぐか、IPv6ネットワークに接続するかを選択できます。

この構成で試してみたところ、やはり外部からVPNで接続することができませんでした。
今回はIPv4の方は固定IPではないためDDNSを使用する方法にしていましたが、どうやらIPv4のDDNSサーバにアクセスができていないようでした。

IPv6用のルータ1の設定をPPPoE(IPv4)にすると正常に接続できるので、おそらくIPv4用のルータ2でに出て行くことができていないと思われます。

ONUからスイッチングハブでIPv4とIPv6用のルータで分けてみる

ルータを2台でPPPoEパススルーを使用する構成はうまくいかなかったため、ONUからの配線をスイッチングハブで2台のルータにそれぞれ分ける方法をとってみました。

構成は以下の感じです。

先ほどとの違いは、ルータ1はPPPoEパススルー機能が必要ないということです。
ルータ1,2のWAN側はスイッチングハブ(HUB)に、ルータ1,2のLAN側をそれぞれ接続して同じセグメントにしておきます。

この構成にしても、二重ルータにする方法と同じ結果で、デフォルトゲートウェイをIPv4側にしてもIPv6で接続しているようでした。
いろいろルータの設定をいじりながら悩みましたが、結果的にIPv6側のルータで送信元のIPがVPNサーバのものは全て無視するようにパケットフィルタリングの設定をしたところ、無事にVPN接続ができるようになりました。
おそらくVPNサーバからDDNSサーバにパケットを送るときにIPv6側のルータを通ってしまっていたためと思われます。(ルーティングの問題?)

VPNサーバ自体でPPPoE接続してみた

何とかルータ2台とスイッチングハブを使用して目的は達成できましたが、外からVPNサーバに接続するためだけにルータを一台用意するのはあまりスマートとは言えないですね。
どうにかもっとシンプルにできないかと考えていたところ、PPPoEで接続するためにルータを用意するのであれば、VPNサーバ自体がPPPoEで接続すれば良いのではと思いつきました。
調べてみるとRaspberry Pi 4で同じようなことをやっている方がいました。

こちらの記事を参考にさせていただきました。
(ほとんど丸ごとコピペです)

最終的な構成は以下のようになりました。結局、最終的に考えていた構成と同じでかなりシンプルです。



VPNサーバにpppoeとpppoeconfをインストールして、PPPoE接続している時のデフォルトルートを変更しておきます。忘れずにルータのPPPoEパススルーも有効にしておきます。
VPNサーバに直接グローバルIPが割り振られることになるのでファイヤーウォールの設定もしておく必要があります。今回はVPN接続に必要なポートと、SSH用のポートのみ開放としておきました。

おうちネットワークは楽しい

引越しを機に久しぶりにネットワークの構築を行ってみました。
LANケーブルの引き回しやIPv6についてなど、初めてのことが沢山ありますとても勉強になりました。何より自分で何かを作っていくのは楽しいですね。

2020年1月4日土曜日

M5Balaのサンプルプログラムを動かすまでの顛末

あけましておめでとうございます。

本業のほうがかなり忙しく、年末まで個人的な開発はほとんどできない状況でした。
今年の年末年始はM5Balaを買ったのでこれを題材に制御のお勉強をしたいと思います。
M5Stack自体は以前から触ってはいたのですが、今回は本格的に開発したいということでPlatformIOの開発環境を整えてM5Balaのサンプルプログラムを動かしてみます。
この過程でかなりはまった点があり、これについても記載します。