Raspberry Pi PicoとCircuitPythonで和音楽器を作る

この記事ははJLCPCBの提供でお送りします。

JLCPCBとは

jlcpcb.jp (↑こちらは日本語版のログインページで、お得なクーポンも配布されています。)

JLCPCBとは、プリント基板製造などで有名な香港の企業です。

日本からでもWebページでポチポチするだけでKiCADなどで作成した基板データの製造を依頼できます。

値段もかなりお手頃で、ホビー電子工作ユーザーの間では広く利用されています。

この記事の作例はJLCPCBに基板を発注して作成した、以前の基板を更に活用した内容です。

inajob.hatenablog.jp

これは何?

私が作っているRakuChordは、もともとArduino UNOなどで用いられているATmega328をメインCPUとしたものでした。 しかし昨今半導体の高騰や新しい組み込み向けのCPUの登場により、ATmega328以外の選択肢も模索したいという気持ちが高まってきました。

ということでこの記事ではRaspberry Pi Picoに搭載されていることでおなじみのRP2040を使って和音楽器を作る方法について紹介します。

Raspberry Pi Picoでのプログラミング

今回利用するのはRP2040-Zeroという開発ボードで、厳密にはRaspberry Pi Picoとは異なります。 しかし回路の構成はほぼRaspberry Pi Picoと同じなので、Raspberry Pi Picoでもほぼ同じように和音楽器を作ることができるはずです。

Raspberry Pi Picoに搭載されているRP2040は、ATmega328などの8bit CPUと比べるとかなりパワフルなマイコンです。 C/C++での開発はもちろんできますがMicroPythonやCircuitPythonなどのインタプリタ言語も動作します。

今回は和音楽器の作成にあたり、CircuitPythonを使うことを選択しました。

C/C++と違い、インタプリタ型のCircuitPythonでの開発は、少し変更して実行してみるというトライ&エラーがやりやすく、高速に開発することができると感じました。 最終的にパフォーマンスの要件などでC/C++を使うとしても、プロトタイプとしてCircuitPythonを使って動作検証を行うのはかなりアリだと思います。

CircuitPythonで和音を鳴らす

CircuitPythonはインタプリタ方式のプログラミング言語で、C/C++と比べると明らかに実行速度が遅いです。 そのため、音の生成、特に和音の生成などをCircuitPythonの層で実装することは現実的ではありません。

しかしCircuitPythonには標準の組み込みのモジュールとしてsynthioという和音をサポートして音源ライブラリが搭載されており、これを利用することで、気軽なインタプリタ方式のプログラミング言語で、高速動作が要求される和音の生成を実現することができます。

synthio

RP2040で動作するPythonの実装としては有名なのはMicroPythonとCircuitPythonがあります。これらはそれぞれ微妙に違った特性を持っていますが、今回CircuitPythonを選択したのは、CircuitPythonには組み込みライブラリとしてsynthioがあったからです。

このライブラリは音を鳴らすためのもので、今回やりたい和音の生成もサポートしています。

docs.circuitpython.org

配線

synthioはDAC出力とPWM出力をサポートしています。今回は追加部品が不要なPWM出力を利用します。 このために出力ピンは適切なRCフィルタを構成のが定石のようですが、ちょっと試す分には、深く考えずスピーカやオーディオアンプを直接繋いでも動作を確認できます。 参考元の資料では1kΩの抵抗と100nFのコンデンサでRCフィルタを作成していました。

単音を鳴らしてみる

以下のようなシンプルなソースコードでファの音を0.5秒毎にON/OFFできます。

import board, time
import synthio

import audiopwmio
audio = audiopwmio.PWMAudioOut(board.GP10)

synth = synthio.Synthesizer(sample_rate=22050)
audio.play(synth)

while True:
    synth.press(65) # midi note 65 = F4
    time.sleep(0.5)
    synth.release(65)
    time.sleep(0.5)

from GitHub - todbot/circuitpython-synthio-tricks: tips, tricks, and examples of using CircuitPython synthio

和音を鳴らしてみる

和音を鳴らすのも単音と同じようにできます。

import board, time
import audiopwmio
import synthio

audio = audiopwmio.PWMAudioOut(board.GP10)
synth = synthio.Synthesizer(sample_rate=22050)
audio.play(synth)

while True:
  synth.press( (65,69,72) ) # midi notes 65,69,72  = F4, A4, C5
  time.sleep(0.5)
  synth.release( (65,69,72) )
  time.sleep(0.5)

from github.com

キー操作に対応して音を鳴らしてみる

ここまでの例は無限ループでsleepさせて音を鳴らしていましたが、ここをキーの入力判定に書き換えればキー操作に対応して音を鳴らすことが出来る、いわゆる「楽器」を作ることが出来ます

この例ではRaspberry Pi PicoのGPIO2番にタクトスイッチつながっており、スイッチを押下することでGNDとショートするような回路を想定しています。

import board, time
import audiopwmio
import synthio

audio = audiopwmio.PWMAudioOut(board.GP10)
synth = synthio.Synthesizer(sample_rate=22050)
audio.play(synth)

p1 = digitalio.DigitalInOut(board.GP2)
p1.direction = digitalio.Direction.INPUT
p1.pull = digitalio.Pull.UP
isPlaying= False

while True:
  if p1.value == False and isPlaying== False:
    synth.press( (65,69,72) ) # midi notes 65,69,72  = F4, A4, C5
    isPlaying= True
  else:
    if isPlaying== True:
      synth.release( (65,69,72) )
      isPlaying= False

和音を鳴らす以外の処理が複雑になると音が途切れてしまう問題の対処

さて、ここまでで電子楽器を作るための準備が整いました。 しかし、楽器を作りこんでいくにしたがって、音を鳴らす以外の処理が増えてきます。前述のキーの入力検出に始まり、画面の制御なども実装していくと、だんだん生成される音にノイズが混じるようになってきます。

これはsynthioの音波の生成がほかの処理により遅れてしまい、音の再生スピードに追い付かなくなることから発生するようです。

根本的には、音波の生成以外の処理を減らせば、この問題は起きませんが、もっと処理を詰め込むことは出来ないでしょうか?

こんな時に役立つのがsynthioのバッファリング機能です。

synthioでは、生成する音波をバッファにためておく機能があり、これを使うことで、少しほかの処理が複雑になっても、バッファにためておいたデータの分だけ時間に余裕が出来ます。

ただ、バッファを大きくすればするほど、音の生成にラグが生じるので、バッファの大きさには注意が必要です。楽器として使いやすくするうえではバッファをなるべく小さくして、キーを入力したらなるべく早く音が鳴ってくれる方がが扱いやすいので、ここは操作性とのトレードオフとなります。

import board, time
import audiopwmio
import audiomixer
import synthio

audio = audiopwmio.PWMAudioOut(board.GP10)

# ここからがバッファリングの処理
mixer = audiomixer.Mixer(sample_rate=22050, buffer_size=2048) # ここの2048を大きくするとバッファを大きくできる
synth = synthio.Synthesizer(sample_rate=22050)
mixer.voice[0].play(synth)
mixer.voice[0].level = 0.25 # 音量の調整もできる
# ここまでバッファリングの処理

p1 = digitalio.DigitalInOut(board.GP2)
p1.direction = digitalio.Direction.INPUT
p1.pull = digitalio.Pull.UP
isPlaying= False

while True:
  if p1.value == False and isPlaying== False:
    synth.press( (65,69,72) ) # midi notes 65,69,72  = F4, A4, C5
    isPlaying= True
  else:
    if isPlaying== True:
      synth.release( (65,69,72) )
      isPlaying= False

OLEDの制御

さて、ここまでで和音楽器として実用的なものが作れるようになりましたが、私の作ろうとしている楽器には128x64のI2C接続のOLEDが搭載されており、キーの入力に合わせてOLEDの表示も変更する必要がありました。

CircuitPythonは組み込みのライブラリではOLED制御をするためのものが含まれていないのでOLEDを制御するためのライブラリを導入します。

OLED制御のライブラリはCircuitPython Library Bundleという標準的なライブラリ集に含まれているので、これをダウンロードします。

Libraries

この中に含まれるファイルをRaspberry Pi Picoのファイルシステムにコピーします。 adafruit_framebuf.mpy, adafruit_ssd1306.mpylib以下に、font5x8.binをルートに配置します。

ここまで準備すれば、以下のようなプログラムでOLEDに文字を表示できます。

import board
import busio
import adafruit_ssd1306

i2c = busio.I2C(board.GP11, board.GP10)
oled = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c)
oled.text("Hello World!",20,5,1)
oled.show()

OLEDの表示と和音生成の両立

しかし上記の方法でOLEDを制御しつつ音を鳴らそうとすると、画面表示にCPU処理を使いすぎてしまい、かなり大きなバッファを設けないとノイズが発生してしまう問題が起きました。

しかし、バッファを大きくすると前述のようにラグが大きくなり、実用に耐えない楽器となってしまうという問題があります。

色々調べているうちに、OLEDの画面転送のオプションを変更し、1つの画面をいくつかに分割して更新することで、バッファを小さく保ったままノイズのない音を生成することが出来ました。

これは、OLEDの画面転送を分割することで、その隙間にsynthioの音波生成の処理を実行することが出来るようになるからだと考えています。

副作用として画面の更新が少し遅くなりますが、楽器を操作するうえで気になるほどではありませんでした。

import board
import busio
import adafruit_ssd1306

i2c = busio.I2C(board.GP11, board.GP10)

# page_addressing=True により画面更新を分割する
oled = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c, page_addressing=True)
# なぜか手元のOLEDだと表示位置がずれるので微調整
oled.page_column_start[1] = oled.page_column_start[1] -4
oled.text("Hello World!",20,5,1)

# page_addressingの設定を変更したのでこのshowの中身の動作が変わり、画面更新を分割して実行する
oled.show()

ATmega328用の基板を流用してRP2040の動作の確認をする

ここまでで、ソフトウェア的にRakuChord的なものをRP2040で実行できる目途が立ちました。

ここからは、ハードウェア的にRakuChord的な構成を作り、動作検証をしていきたいので、このために新たに基板を作る必要がありそうです、、、が、、

そういえば以前表面実装部品版RakuChordの改良版を作った - inajob's blogの記事で作成したRakuChordは、キー入力のためのピンを引き出して設計していたので、この基板を流用して、RP2040の開発ボードと無理やりくっつけることで、ハードウェア的な動作確認もできるのでは?と考えました。

その結果がこちら!

動画はこちら

www.youtube.com

21個のキーの入力を受け付けるために3*7のマトリクスで処理しているので、全部で10本の信号線と電源の線をつなげる必要があり、こんな風にモジャモジャになりました。アンプやスピーカーもつなげました。

これで、RP2040をコアとしたRakuChordの試作機が完成しました。

こんなこともあろうかと、キー入力のパッドを引き出しておいてよかったです。

で、実際にRakuChord的なソフトウェアをCircuitPythonで作って、触ってみたところ、、特に問題なく動作しそうでした。

さて、次はこの構成を踏まえてRP2040をコアとしたRakuChordの基板を発注するぞ!という気持ちです。(それはまた別の話と言うことで・・)

まとめ

今までATmega328を使っていたRakuChordのCPUをRP2040かつCircuitPythonに変更できるかを色々検証しました。

C/C++に比べるとパフォーマンスの低いCircuitPythonでも、工夫すれば音の生成とOLEDの描画が出来そうなことがわかりました。

CircuitPythonでの開発は非常に手軽なので、簡単な電子楽器を作ろうと考えている方にはとてもお勧めの手法です。

また、過去に作成したATmega328用のボードの「こんなこともあろうかと」用意しておいた拡張端子をうまく利用することで、新たに基板を設計する前に、動作確認することが出来ました。

参考

Synthioの活用法については以下のリポジトリが参考になりました

github.com

UARTで書き込みできるCH32V003開発ボードを作った

この記事ははJLCPCBの提供でお送りします。

JLCPCBとは

jlcpcb.jp (↑こちらは日本語版のログインページで、お得なクーポンも配布されています。)

JLCPCBとは、プリント基板製造などで有名な香港の企業です。

日本からでもWebページでポチポチするだけでKiCADなどで作成した基板データの製造を依頼できます。

値段もかなりお手頃で、ホビー電子工作ユーザーの間では広く利用されています。

この記事の作例もJLCPCBに基板を発注して実現しました。

これは何?

以前CH32V003を使った基板を作って遊びました。今回はその時の知見を活かして、UARTで書き込みできるCH32V003開発ボードを作成してみました。

inajob.hatenablog.jp inajob.hatenablog.jp

仕様

この基板は何か専用の機能を持つものではなく、汎用的な開発基板です。

  • CH32V003F4P6
  • USBコネクタ(フットプリントのテストのため3種)
  • USBシリアル変換IC CH340G
  • RSTスイッチ、BOOTスイッチ
  • 自動リセット回路(ESP32などの回路をまねたもの)
  • WCH-LinkE接続用端子

基板の設計

今回の基板は以前作ったCH32V003の基板とよく似たものですが、USBシリアル変換ICとRSTスイッチ、BOOTスイッチが搭載されているのが特徴です。 また、Arduinoではおなじみの自動リセットの仕組みを実現するための回路も搭載しています。

今回利用するファームウェアは、起動時にPC0の状態を読み取り、LOWであれば書き込みモードに入るという動作をするものです。 これを実現するためにBOOTスイッチを搭載しています。つまり、BOOTスイッチを押しながらRSTスイッチを押すことで書き込みモードに入るということです。

CH32V003のUART書き込みのサンプルは、PC0がHIGHであれば書き込みモードに入るような作りになっていますが、ここではESP32などで良く用いられる自動リセット回路をまねて作る関係でこの動作を変更してLOWであれば書き込みモードに入るという作りに変更しました。

さらにこの基板で特徴的なのは3つのUSBポートです。 これは何か3つに特別な機能がある、というわけではなく、手元にある3種類のUSBソケットの実装練習のためのものです。

3つのうち2つがUSB Type-Cのソケットなので、CC1、CC2ピンのための抵抗も配置します。(この抵抗が無いとType-C -> Type-Cケーブルを使った時に給電されないことが起きるようです)

JLCPCBに発注

今回も発注はJLCPCBです。基板は赤色にしました。また基板の厚さを1mmにしています。

jlcpcb.jp (↑こちらは日本語版のログインページで、お得なクーポンも配布されています。)

動作確認のための実装

CH340GはArduino Nanoのクローンなどでよく利用されているICで、自分もそのような基板を自作したことがあるので、難なく実装できました。 CH32V003F4P6も前回の挑戦ではんだ付けしたことがあったので、こちらも簡単。

MicroUSBコネクタはよく使うのですが、なかなか実装のコツがつかめず、よく接続不良を起こしてしてしまいます。ホットエアーガンを使い今回は(たまたま)一発で動作しました。

ということで、あっという間に実装できました。

自動書き込み回路や、あと2つのUSBコネクタの実装は後回しです。

ブートローダーの準備と、書き込みテスト

CH32V003でさらに遊んでみた - inajob's blogで紹介した74thさんのファームウェアを少し改造して利用しました。 74thさんのものは書き込みモードに入る際にPC0をHIGHにする必要がありましたが、今回はPC0がLOWのときに書き込みモードに変更したものを用意しました。

このファームウェアをWCH-LinkEを使いブートローダー領域に書き込めば準備は完了です。

基板上のMicro USB端子をパソコンとつなげ、BOOTスイッチを押しながら、RSTスイッチを押して書き込みモードにしたのちに、74thさん作のCLIツールを使い適当なプログラムを書き込み、最後にRSTスイッチを押して、実行モードにすれば、書き込んだプログラムが動き始めます。

USBソケットの実験

前述したようにこの基板には3つのUSBソケットのフットプリントがあります。

Micro USB

いつものソケットです。ここまでの実験ではこのソケットを使い接続しています。 このソケット、実装の難易度はそこそこ高く、個人的にははんだごてではうまく実装できず、ホットエアーで実装しています。

いつも使っているのですが、Micro USBということで、稀にコネクタが「もげ」るという事故が起きます。 ということで、そろそろ自分もUSB Type-Cのコネクタを試してみたいなと考えていました。

そこで出てきたのが次の2つのUSB Type-Cソケットです

USB Type-C(スルーホール)

スルーホール型のソケットです。後述の表面実装のものと比べると価格が高いのですが、実装しやすそうだなと思い、今回試してみることにしました。

スルーホール型ではあるのですが、足がそこまで長くないため、一般的な厚さ1.6mmの基板では足が下まで届かないので、はんだ付けが難しいようで、今回は厚さ1mmの基板としました。

スルーホールとはいえ、かなりピンが近くにあるので、はんだ付けは気を遣いましたが、何とかはんだごてで実装し、動作することを確認しました。

USB Type-C(表面実装)

よく見かけるソケットです。ピンの幅が狭く、実装の難易度が高そうに見えます。 はんだごてで実装するとすぐにブリッジ思想だったので、ホットエアーを使って実装しました。

フットプリントは以下の記事を参考にして、いくつかのパッドを長くすることで、はんだ付けしやすいようにしました。

inajob.github.io

心配しましたが、こちらも動作することを確認しました。

自動書き込み回路の動作確認

最後に、ESP32などの開発ボードでよくみられる、トランジスタを2つ使った、自動書き込み回路の動作を確認しました。 この回路は抵抗付きのトランジスタが2つ内蔵されたUMH3Nという部品により実現されます。(この部品は以前ESPboyというオープンソースの携帯ゲーム機を日本用に再設計してみた - inajob's blogで利用したことがありました)

ちょっと小さな部品ですが、これを実装します。

このトランジスタ2つをうまく組み合わせて、USBシリアル変換ICの~DTR, ~RTS信号を、CH32V003のリセット信号と、書き換えモード切替信号(PC0)への入力に変換します。

ESP32などでは書き込みツールがDTR、RTS信号をうまい具合に制御してくれるのですが、今回はそういうツールが無いので、Pythonスクリプトを用意して、書き込みモードへの切り替えの動作を実現しました。

具体的には以下のようなコードで書き込みモードに入ります

import serial
ser = serial.Serial()
ser.port = "COM14" # 利用するポートの番号
ser.baudrate = 115200

# Write mode
ser.setDTR(True)
ser.setRTS(False)
ser.open()
ser.close()

そして以下のようなコードで実行モードに入ります

import serial
ser = serial.Serial()
ser.port = "COM14" # 利用するポートの番号
ser.baudrate = 115200

# Run mode
ser.setDTR(False)
ser.setRTS(True)
ser.open()
ser.close()

これと74thさん作のCLIツールを組み合わせると、Arduino風の書き込み環境となります。

まとめ

ということで、一度ブートローダーを用意してしまえば、後は開発基板のみで書き換えができる基板が完成しました。

まぁ、CH32V003でやるならこの方法ですが、もう一つ上のスペックのCH32V203などではIC単体でUSB書き込み機能を備えているので、あえてCH32V003でここまでする意味はないかもしれませんが、構成例の一つとして、誰かの役に立てば幸いです。

また、自動リセット回路について、CH32V003でも期待通り動くことが確認できました。

おまけとして、3種類のUSBソケットの実装実験が出来ました。ホットエアーガンがあればどのソケットもそこまで難しくなく実装できることが確認できました。

参考

自動リセット回路の動作原理について詳しく説明されています days-of-programming.blogspot.com

前回記事に続き 74th.hateblo.jp

CH32V003でさらに遊んでみた

この記事ははJLCPCBの提供でお送りします。

JLCPCBとは

jlcpcb.com (↑こちらは日本語版のログインページで、お得なクーポンも配布されています。)

JLCPCBとは、プリント基板製造などで有名な上海の企業です。

日本からでもWebページでポチポチするだけでKiCADなどで作成した基板データの製造を依頼できます。

値段もかなりお手頃で、ホビー電子工作ユーザーの間では広く利用されています。

この記事の作例もJLCPCBに基板を発注して実現しました。

前回までのあらすじ

以前作った基板を流用して CH32V003 で遊んでみることにしました。

inajob.hatenablog.jp

CH32V003F4P6を自分ではんだ付けしてみる

前回の記事では、CH32V003の開発ボードを使ったため、CH32V003F4P6を直接はんだ付けすることはしませんでした。

しかし、この基板は開発ボードでも、ICを直接実装するでも、どちらでも動作するように作っていたので、今回は直接のはんだ付けを試してみました。

表面実装でピンの間は0.65mmでこれが10*2=20か所はんだ付けします。

うまくはんだ付けできるか心配でしたが、意外と簡単にはんだ付けできました。

過去の実績としてはATmega328が0.8㎜ピッチで32か所というのがありましたが、これと比べると今回のはんだ付けは簡単でした。

比較するとこんな感じ

というのも、ATmega328はICの4辺すべてに足が出ているQFPと呼ばれるパッケージで、今回の物は2辺に足が出ているTSSOPと呼ばれるパッケージだったというのが大きいです。

分析するに、QFPの方はICの向きが少しずれるとどこかの辺のピンがパッドからずれてしまうのに対し、TSSOPの方はピンのある辺に水平にずれる分には問題ないというのが原因だと感じました。

ピッチは今回のICの方が細かかったですが、その点はあまり気になりませんでした。

温調付きのはんだごてと、フラックスがあれば比較的簡単だと思いますので、挑戦する方はこれらの機材をそろえると良いと思います。

最低限動作に必要な部品

改めて回路を見直してみると、このICは周辺の部品は、ほぼ何もなくても動くことがわかりました。 開発ボードには水晶発振子が付いていましたが、ICの内部にも発振機能があるようで、精度が多少悪くなりますがこちらを使うようにすれば、水晶発振子は不要でした。

いわゆる「おまじないコンデンサ」と言ったりするパスコン(バイパスコンデンサ)を一応1つ取り付けました。

ここに写っている部品のみでOK

書き込み

書き込みは開発ボードを使った時と同様にWCH-LinkEという専用の書き込み機を使いました。 ソフトウェアは前回の記事で紹介したch32v003funを利用しました。

専用書き込み機を使わずに書き換える方法

WCH-LinkEを使わないと書き換えられないのが少し気になって、調べてみると、WCH社が公式のサンプルとしてUART経由でプログラムを書き換えることが出来るサンプルプログラムを公開していることを知りました。

github.com

UARTを使って書き換えるといえば、よく知られている例だとArduino UNOなどの方式です。

この方式は、素朴ですが、ボード上にUSBシリアル変換ICを搭載することで、そのボード単体で開発が完結するという点で魅力的です。 (もちろん一番初めにこのプログラムを書き込むためにWCH-LinkEが必要なのですが、一度書き込んでしまえば以降はUARTで書き換えることが出来ます。)

さらに、このWCH社が提供しているサンプルの細かい問題点を解消したものを74thさんが作っているのを発見したので、今回はこちらを利用しました。

github.com

WCH-LinkEにはUSBシリアル変換の機能も搭載されているので、この書き換えの仕組みもWCH-LinkEで動作確認できました。また念のため手元にあったCH340G搭載のUSBシリアル変換モジュールを使っても書き換えが出来ました。

書き込みのためにはPC側で動作する書き込みソフトが必要となります。WCH社公式のWindows専用ツール74thさん作のCLIツールの2つがありますがどちらでも書き込みできました。

RSTスイッチでリセットされない問題

74thさんが改良したプログラムでは以下の2つの変更が加わっていました

  • UART通信の精度を上げるため書き込み速度を115200に低下させる
  • 書き換えモードに入るためのピンをプルダウンし、ピンに何もつながっていないときは、実行モードとする

これで随分使いやすくなっていたのですが、74thさんのブログでも言及されているのですが、RSTスイッチの挙動が少し期待と異なるという問題が残っていました。

RSTスイッチは私の利用している開発ボードではタクトスイッチと接続されており、このスイッチを押すことでマイコンボードを「リセット」しプログラムをはじめから実行しなおすことができます。

UARTで書き込みを実現するプログラムは、起動時に特定のピンの状態を確認し、それがHIGHであれば書き込みモードに入り、LOWであれば実行モードに入るというロジックとなっています。

こういう書き込みロジックはESP32などでも採用されており、このようなボードにはBOOTスイッチとRESETスイッチが搭載されていることが一般的です。

BOOTスイッチを押しながらRESETスイッチを押すことで書き込みモードで起動し、BOOTスイッチを押さずにRESETスイッチを押すと、実行モードで起動するというのが期待する動作です。

もちろん手でスイッチを操作する以外にも、USBシリアル変換ICのDTRやRTSの信号をうまく使って、自動的に書き込みモードに入るというようなことも行われたりします。

さて、今回のUARTで書き込みを実現するプログラムを利用する際、このRSTスイッチはどのようにふるまうかというと・・

  • 書き込みモードで起動中
    • RSTスイッチを押すと、実行モードで起動する
    • 書き込みピンをHIGHにしてRSTスイッチを押すと、書き込みモードで起動する
  • 実行モードで起動中
    • RSTスイッチを押すと、再び実行モードで起動する
    • 書き込みピンをHIGHにしてRSTスイッチを押しても、再び実行モードで起動する(ここがおかしい!!)

実行モードで起動中に、書き込みピンをHIGHにしたときに、書き込みモードに移行せず、実行モードとなってしまうことが期待と違うと感じました。

この原因を調べるためにソースコードを見てみると、UARTで書き込みを実現するプログラムは以下のように実装されているようでした

  • UARTで書き込みを実現するロジックはFlashメモリのBOOT領域に書き込まれている
  • BOOT領域の処理の一番初めに書き込みピンの状態を確認するロジックがある
    • ここでLOWが検出されると、User領域から実行するフラグを立ててソフトウェアリセットをする
  • User領域を実行中にRSTスイッチによるリセットが起きても、User領域から再実行される

というような動きをしているようでした。(データシートで細かい裏付けをしているわけではなく、あくまで挙動から推測した動きです)

ということで、以下のような処理をUser領域に書くことで、User領域を実行中にRSTスイッチによりリセットされたときにBOOT領域の処理が実行されるようにしてみたところ、期待通りに実行モードで起動中にRSTスイッチを押した際に、書き込みモードで起動することが確認できました。

   if(RCC->RSTSCKR & RCC_PINRSTF){ // リセットボタンを押されて起動した場合に真となる
     FLASH->BOOT_MODEKEYR = FLASH_KEY1;
     FLASH->BOOT_MODEKEYR = FLASH_KEY2;
     FLASH->STATR |= (1<<14);
     NVIC_SystemReset();
   }

要は、UARTで書き込みする対象のプログラムに、おまじない的に、このロジックを入れておけば良いということです。

さて、今回はここまでの調査で打ち切りましたが、この先はUSBシリアル変換ICを搭載した基板を作ったり、RSTやDTRで自動プログラム機能を作りこんだ書き込み用のプログラムを作ったりすると、Arduinoっぽく書き込みできる仕組みが作れそうです。

そこまでしてUARTで書き込みしたい?

ここで調査を打ち切ったのは、CH32V003をどこまで頑張って使い倒すか?ということを考えたからです。

実はCH32VシリーズのCH32V203は、CH32V003よりは高いですが、その分スペックも良く、USB経由でのファームウェア書き込みもサポートしています。

ここまでCH32V003をArduino的に書き換える方法を探ってきましたが、そんなに頑張らなくともCH32V203を使えばよいのでは・・?という気がしてきました。

ということで、近いうちにCH32V203を購入して、その使い勝手を確かめてみることとします。

日本で買うなら RISC-V MCU CH32V203 ProMicro Like 開発ボードキット(¥1,500) [74th-034] - 74th Books & Gadgets - BOOTH、AliExpressでもいくつかの開発ボードを見つけることが出来ます。

まとめ

前回記事では、開発ボードを利用していましたが、ICを直接基板に実装する方法も試すことが出来ました。

これにより開発ボードに頼らずに、スタンドアローンなガジェットを作れるようになりました。

Arduino互換のSDKも整備されてきているようなので、次何か作る時の候補に入れておくことにします。

2023まとめ

今年もいろいろなことがありました。

毎年恒例ですがまとめていきます。

ピックアップニュース

ポッドキャストを始めた

5月ごろから#inajob の試しに録音してみた を始めました。なんだかんだでほぼ毎週配信できています。

open.spotify.com

ポッドキャスト仲間とのコミュニケーションが出来たり、音声編集のテクニックが身についたり得るものが多くありました。

また、ポッドキャストをよく聞くようにもなり、お気に入りのポッドキャストもたくさんできました。 副次的な効果として、日記をしっかり書くようになり、日々をより噛み締めて生活できるようになり、人生を濃くすることが出来ていると感じます。

ChatGPTを活用し始めた

このブログではあまり紹介していませんでしたが、自分の日記をChatGPTに分析させたり、omoikaneに参加して、ChatGPTを使ったSFプロトタイピングを体験したりしました。

このあたりの話は以下のポッドキャストのエピソードでも話しています。

open.spotify.com

PASMOがバズる

誤ってPASMOを洗濯機に投入してしまい、破片しか残らなかったエピソードがバズりいくつかのメディアで記事にしてもらいました。 平和な内容でバズるのはまぁインターネットと言う感じで面白かったです。

nlab.itmedia.co.jp

ステータス

  • 今の家に引っ越してから7年目
  • 会社に入ってから14年目
  • 結婚して7年ちょっと
  • 娘が生まれて3年目

子供がいる生活にもだんだんと慣れてきて、そういった環境でもできる新たな挑戦などにも取り組めていると思います。引き続きやっていこう!

今年学んだスキル

今年は技術的なところというよりは、家族周りのスキルアップも多かった年でした。 親の介護なんていう次なる課題も見えてきて、色々と考える機会となりました。

今年買ったもの

ハンドソープディスペンサー(娘の手洗いがずいぶん楽になりました)

ヘッドセット(ポッドキャストの録音はこれで行っています。リーズナブル!)

電気圧力鍋(料理で大活躍)

ロボットペット(親の方が欲しかった、クリスマスプレゼント)

レゴ(親も楽しい、誕生日プレゼント)

ScanSnap S1500(全然使える、中古で買った)

コンパクトなキーボード

感想

昨年から模索している非同期コミュニケーション手段の1つとしてScrapboxに加えてポッドキャストの配信を始めたというのが一番大きな変化です。

最新の技術であるChatGPTを触ることが出来ているのも良かったです。

朝ジョギングを始めるなど、健康維持についても行動できているので、継続していきたいです。

娘も3歳となり、一緒に技術展示のイベントに参加したり、宿泊を伴う旅行に連れて行けるようになったりと、行動の幅が広がったのも良かったです。引き続き、英才教育・・という名の親の趣味に付き合わせていきたいなと思っています。

月別生データ

1月

  • 親子2人で電車でお出かけ
  • 動画で子守するのを解禁
  • 凧揚げ
  • 内窓を設置
  • 前半は風邪、後半は胃腸炎

ひらがなおもちゃを作る

RakuChordのSMD版を作る inajob.hatenablog.jp

2月

  • 節分
  • 水族館にいく
  • 成田空港にいく

おしたくボード改

MakePython Audio Expansionレビュー inajob.github.io

HandiPiを作る inajob.hatenablog.jp

事前に議事録を作る方式について qiita.com

3月

なぜなぜ分析

おもちゃの分解

Web Assembly qiita.com

ChatGPTに英語記事の要約を頼む実験

OLEDの不良品を激安のロジックアナライザーで分析 scrapbox.io

オーディオコメンタリーメーカーを作る github.com

inajob.hatenablog.jp

3Dプリンタの寸法チェック用モデル

蛇口延長用アダプタ

ESPHomeを試す(が結局プログラミングすることに・・)

4月

レタスの発芽(失敗)

PASMOがバズる

電子メモパッドのレビュー inajob.github.io

小型のフルカラーLEDのテスト基板 inajob.hatenablog.jp

モノクロ液晶の試食

ESP32で動く日本語入力対応Wiki的なもの

5月

枝豆・トマトを植える

埼玉県近代美術館

電気圧力釜を買った

DIYこいのぼり

粘土に夢中

自動ハンドソープディスペンサー購入

トイレの最中

ケースづくり

ESP32搭載のDIY時計ガジェットキットレビュー inajob.github.io

ペン型マルチメーターレビュー inajob.github.io

乾電池駆動のArduino Nanoボード inajob.hatenablog.jp

Vision Five2試食

ダイソーで買ったおもちゃ

6月

  • 長靴を買った
  • 七五三の前撮り
  • KEY PALETTOを購入
  • omoikane参加
  • blueskyを始める

ノートパソコンのバッテリーが膨らむ

ジャガイモを収穫

スカイツリーを見に行く

Raspberry Pi Picoを使った携帯ゲーム機 inajob.hatenablog.jp

7月

  • 地域のソーメン流し参加
  • ブルーベリー狩り
  • 打ち上げ花火を見る
  • Threadsに参加
  • (今更)Twitter API V2を試す
  • ヘッドセット、ロジクールH111rを買った
  • SNSを同期する仕組みの作成

トマト、枝豆の収穫

絵を描いて教える

お金やさん

8月

Raspberry Pi Pico搭載のマクロパッド inajob.hatenablog.jp

バタフライピー

ビリヤニ

ポップコーン

市販キーボード用のマウンタ

ログ機能付きの電流計自作

フレキシブルHDMIケーブル

inajob.hatenablog.jp

9月

  • 写真データをGoogle Photosから自宅のNASに移行
  • synthioを試す
  • Raspberry Pi Picoで遊ぶ
  • MSX0で遊ぶ
  • NS8002オーディオアンプ実験
  • CH32V003で和音実験
  • 遊園地に行く

自作キーボード inajob.hatenablog.jp

10月

  • 上野動物園、ジャグリング鑑賞
  • 地元の秋祭り
  • 自転車が壊れる
  • コテンラジオを聞き始める
  • 安い骨伝導イヤホンを買った(いまいち)
  • LISTENトーク(仮)に参加
  • パパ友とバーベキュー会主催
  • 七五三撮影

RP2040実装練習

inajob.hatenablog.jp

11月

  • 幼稚園の入園面談
  • 国立科学博物館に行く
  • ChatGPT with Voiceで子守してみる
  • サーキュレーターを買った
  • 加湿器を買った
  • 喰い切りニッパーを買った
  • Milk-V Duo試食
  • CadQueryを学ぶ

娘を連れてNT東京2023を見に行った

不良品と思われるATmega328の調査

inajob.hatenablog.jp

12月

コストコ入会

クリスマスオーナメントを作る

クリスマスツリーを作る

Loona購入

inajob.hatenablog.jp

CH32V003を使った和音の鳴るピアノ基板

この記事ははJLCPCBの提供でお送りします。

JLCPCBとは

jlcpcb.com (↑こちらは日本語版のログインページで、お得なクーポンも配布されています。)

JLCPCBとは、プリント基板製造などで有名な香港の企業です。

日本からでもWebページでポチポチするだけでKiCADなどで作成した基板データの製造を依頼できます。

値段もかなりお手頃で、ホビー電子工作ユーザーの間では広く利用されています。

この記事の作例もJLCPCBに基板を発注して実現しました。

これは何?

CH32V003という最近流行りのRISC-Vの激安マイコンモジュールを使って楽器を作ってみました。

仕様

  • 128*64 モノクロOLED
  • CH32V003
  • NS8002オーディオアンプモジュール
  • 鍵盤を含む20個のタクトスイッチ
  • スピーカ
  • オーディオジャック
  • ボリューム

パーツ紹介-CH32V003F4P6

最近流行りのWCH社製のRISC-Vマイコンです。 CH32VのシリーズはほかにもありますがCH32V003はその中でも最も廉価なシリーズです。

秋月電子でも販売しており、記事執筆時点では1つ50円です

akizukidenshi.com

プログラムメモリ16KB, RAM 2KB、GPIO18個というシンプルなスペックですが、ちょっとした電子工作のロジックを作るには十分です。

パーツ紹介-CH32V003モジュール

今回のピアノ基板はCH32V003F4P6を基板に直接取り付けることもできますが、よくあるCH32V003を搭載した開発ボードを使うこともできます。

今回はまずはこのCH32V003モジュールを利用する方法で組み立てました。

CH32V003はUSBデバイスの機能を持っていないので当然ですが、このモジュールのUSB端子は電源用で、書き込みを行うことは出来ません。

書き込みのためには専用の書き込み装置であるWCH-Linkが必要となります。(セット販売しているものを買いました)

基板の設計

今まで私は、この手のちょっとした音が鳴るガジェットを作ったことは結構あるので、ここまでのブログ記事などでも紹介しているような「鉄板」の構成で設計しました。

20個のタクトスイッチは 4*5のマトリクス配線とし、同時押しをサポートするためにダイオードを実装しています。

オーディオ周りはいつものスイッチ付きのオーディオジャックや、NS8002オーディオアンプ、ボリューム、表面実装スピーカなどを採用しました。

JLCPCBに発注

今回も発注はJLCPCBです。基板の色は白にしました。

この基板も10cm×10cmに収まるように設計したので5枚だと $2 + 送料です。

jlcpcb.com (↑こちらは日本語版のログインページで、お得なクーポンも配布されています。)

実装

今回はそこまで複雑な回路ではないので、サクッと実装できました。

ソフトウェアの実装

今回のチャレンジはソフトウェアです。CH32V003は比較的新しいマイコンなので、参考となるソースコードが少ないのが現状です。

CH32V003公式の開発環境としてはMounRiver Studio IDEというGUIIDEと公式のSDKを使う手があるのですが、どうも大げさな開発環境で、肌になじまなかったので、シンプルなch32v003funを使うことにしました。

github.com

ch32v003funはシンプルな実装ですが、このくらいの規模のCH32V003の開発には必要十分で、サンプルも豊富です。 いくつかのサンプルを組み合わせることで目的のプログラムを作ることが出来ました。

  • blink
    • まずはLEDをチカチカします
    • これで最低限の雰囲気をつかみました
  • tim2_pwm
    • 音を鳴らすために利用するPWMの機能
    • LEDをフェードイン・フェードアウトするような使い方にも利用できます
  • systick_irq
    • 音源のオシレータを一定時間ごとに進めるためにタイマ割込みの機能
  • i2c_oled
    • I2C接続のOLEDの制御
    • ホビー電子工作でよく利用するSSD1306向けの描画ロジックが便利です

ch32v003funを使うにあたっては以下のブログ記事が非常に参考になりました。

74th.hateblo.jp

つぎはぎですがソースコードはこんな感じです (ch32v003funのi2c_oledのexampleを以下のように書き換えて、ビルドしました)

gist.github.com

まとめ

安価なRISC-VマイコンであるCH32V003を使って、和音の鳴るピアノ的な楽器を作ることが出来ました。

ch32v003funという軽量なライブラリを利用して、比較的簡単に楽器的なロジックを作れることがわかりました。

自分が今までよく利用していたArduino UNOのメインマイコンであるATmega328は半導体不足で価格が高騰し、今ではだいぶ落ち着きましたが、それでもまだ価格が高止まっています。また、ATmega328は昔からあるマイコンであることもあってテキトーに買うと偽物が混ざっているようなこともあり困っていました。

CH32V003は非常に安く、新しいマイコンであるため今のところ偽物の情報も聞きません。

ちょっとここらで、メインで使うマイコンをCH32シリーズに移行してみても良いかも・・と感じました。

グリッド楽器igetaを作った

この記事ははJLCPCBの提供でお送りします。

JLCPCBとは

jlcpcb.com (↑こちらは日本語版のログインページで、お得なクーポンも配布されています。)

JLCPCBとは、プリント基板製造などで有名な香港の企業です。

日本からでもWebページでポチポチするだけでKiCADなどで作成した基板データの製造を依頼できます。

値段もかなりお手頃で、ホビー電子工作ユーザーの間では広く利用されています。

この記事の作例もJLCPCBに基板を発注して実現しました。

グリッド楽器igetaとは

まぁ世の中によくあるグリッド型の電子楽器的なものを自分も作ってみようという試みです。

有名なところだとTENORI-ONとか Launch Padというものがあったりしますね。

igetaは8x8のスイッチと8x8のLEDを搭載した入力装置です。 音声出力する機能もあり、オーディオアンプやボリュームも搭載しています

仕様

  • Raspberry Pi Pico
  • 8x8=64個 タクトスイッチ
  • 8x8=64個 LED
  • NS8002オーディオアンプモジュール
  • ボリューム

今回はRaspberry Pi Picoの性能に全のっかりで行きます

パーツ紹介 - NS8002オーディオアンプモジュール

AliExpressで発見したモノラルのオーディオアンプモジュールです。 詳しいことはよく知らないですが、今まで使っていたLM386よりも3.3Vで大きな音が出る点が気に入っています。

その他のパーツたち

タクトスイッチはFusionPCBを使って(ほぼ)はんだ付けせずに自作ゲーム機を作った(PCBA) - inajob's blogで紹介した DTSM-62K-S-V-T/R(SN431)です。 楽器としてはカチカチ音が鳴る点が微妙かもしれませんが、軽いタッチ(100gF)で押せるのでなかなか気に入っています。

LEDは以前購入していた1206サイズの赤色LEDを使いました。別に何色でも良いので、次作る時は別の色にしようかなと思います。

ボリュームはオリジナルのマクロパッドを作ってみた - inajob's blogで紹介したB103です。薄型の部品で、側面にちょっとした隙間があれば実装できる点が気に入っています。

Raspberry Pi Picoは言わずと知れた有名なマイコンボードです。ちょっと前まではArduno Nanoをメインに使っていたのですが、最近の半導体不足の影響か価格が高騰しています。またArduino Nanoに搭載されているマイコンであるATmegaはどうも質の悪い偽物が出回っているようで、一見ちゃんと動いているようでも、細かい部分の動作がおかしい個体があるように見えます。

一方でRaspberry Pi Picoは安価で、性能が高く、コアとなるRP2040も新しいマイコンのためか、偽物の情報もあまり聞かないので、最近はこちらをメインに利用しています。

基板の設計

今回の基板のキモは大量のタクトスイッチとLEDの接続です。

タクトスイッチ64個とLED64個をどうやってRaspberry Pi Picoに接続するかという話です。 よくあるのはマトリクスで配線する方法ですが、これは64個の部品を制御するのに16個のGPIOが必要となります。

素朴にLEDとタクトスイッチのそれぞれをマトリクス配線するとなると16+16=32のGPIOが必要となります

Raspberry Pi PicoのGPIOは28個なので、このままではGPIOが足りません。

そこで今回は、Charlieplexingという手法を採用します。この手法により16個のGPIOでこれらの制御ができます。

しかしCharieplexingは配線が複雑で、回路図を描くのが難しいという課題があります。

これについても様々な解決策があるのですが、今回はikkeiplexingという手法を採用しました。

この手法は https://twitter.com/jh3kxmさんが考案されたもので、ikkeiplexing shieldのページのPDFが非常に参考になりました。

回路図を示すと以下のような感じとなりました

左下がタクトスイッチ(とダイオード)、右上がLEDで、左縦一列の16個のGPIOで制御できます。

LEDが抵抗なしでGPIOと接続されていますがRP2040はGPIOの電流制限の機能があるようなので、正しく設定して利用すれば問題ないと理解しています。(https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf のp239 2mA, 4mA, 8mA, 12mAの間で設定可能)

で、後は基板を設計するだけ!

だけ、と書きましたが、意外とこの基板配線が複雑で、配置を工夫する必要がありました。

配線は自動配線ツールのFreeroutingに丸投げなのですが、配置が悪いといくら待っても配線が完了しない感じになります。

Raspberry Pi Picoはスルーホール穴での実装はせずに、端面スルーホールを利用し表面実装することにしました。これで裏面が自由に使えるので配線の複雑さが緩和されます。

オーディオアンプNS8002は、出来合いのモジュールを使う方法と、直接基板に実装する方法の2パターンに対応しました。 (直接基板に実装するパターンは、手元に部品がなくまだ動作が確認できていないですが・・)

JLCPCBに発注

今回も発注はJLCPCBです。今回の基板の色は黒色です。

この基板も10cm×10cmに収まるように設計したので5枚だと $2 + 送料です。

jlcpcb.com (↑こちらは日本語版のログインページで、お得なクーポンも配布されています。)

実装

今回はとにかく、タクトスイッチ、ダイオード発光ダイオードの数が多いというのが大変なところでした。

ひたすらはんだ付けです・・

そんな中で、今回もいくつかのトラブルが起きました。

配線が足りてない!

今回のミスです。単純にCharieplexingの配線を間違えており、必要な部分が結線されていませんでした。 いくつかのパターンをカットし、8本の配線を後から追加で足すことで、正しい回路に修正しましたが、表面はもじゃもじゃのケーブルが這うことになりました。

USBケーブルが基板と干渉する

Raspberry Pi Picoを基板の端からやや内側に配置したことと、端面スルーホールを利用して表面実装したために、Raspberry Pi PicoのUSBポートが基板にかなり近くなってしまいました。

その影響で、USBケーブルを指そうとすると基板と干渉してしまいうまく接続できない問題が起きました。

これはどうしようもないか・・と思ったのですが、手元にあるちょっと変わった形のUSBケーブルを使うと、何とか干渉せずに接続することが出来ました。

とはいえ、一般的なUSBケーブルが刺さらないのは問題なので、次回は直したいところです。

完成

何とか動作するものが出来ました。

ソフトウェアの実装

今回はCircuitPythonで実装しました。

今回の回路設計に用いたCharieplexingという手法の難しい所は配線だけではなく、ソフトウェアの実装についてもです。 適切な順番でGPIOを制御しないと、意図しないLEDが光ったり、正しくキー入力を検知できない問題が起きます。

CircuiyPythonはプログラムを変更してから実行するまでのサイクルがC/C++と比べると早いので(特にコンパイルが不要というのが大きい)こういう試行錯誤には向いていると感じました。

一応「楽器」ということで、音を鳴らす機能も付けてみることにしました。CircuitPythonには音を鳴らすためのSynthioというライブラリがデフォルトで同梱されているのでこれを使うことにしました。

Synthioはとてもシンプルな制御で、和音も鳴らすことが出来るのでちょっとした音の鳴るおもちゃを作るのに非常に便利だと感じました。

ただCircuitPyhton自体がネイティブと比べると処理が遅いので、凝ったことをしようとすると音が途切れてしまったり、期待した速度で動かないことなどがあるので、そういう場合はおとなしくC/C++を使うのがよさそうです。

ということで、できました。

押したキーに対応するLEDが点灯し、かつそのキーに対応した音が鳴るプログラムです。 同時押しにも対応しており、同時押しすると和音を演奏できます。

"""
igeta-pico test

Copyright (c) 2023 inajob

This software is released under the MIT License.
http://opensource.org/licenses/mit-license.php
"""

import digitalio
from board import *
import time
import synthio
import audiopwmio
audio = audiopwmio.PWMAudioOut(GP18)

synth = synthio.Synthesizer(sample_rate=22050)
audio.play(synth)
#synth.press((65,69,72))

p1 = GP2
p2 = GP3
p3 = GP4
p4 = GP5
p5 = GP6
p6 = GP7
p7 = GP8
p8 = GP9

p9 = GP10
p10 = GP11
p11 = GP12
p12 = GP13
p13 = GP14
p14 = GP15
p15 = GP16
p16 = GP17

ports = [p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16]
pports = []
for p in ports:
    pports.append(digitalio.DigitalInOut(p))
    
sw = [
    [True, True, True, True, True, True, True, False],
    [True, True, True, True, True, True, True, True],
    [False, False, False, False, False, False, False, False],
    [False, False, False, False, False, False, False, False],
    [False, False, False, False, False, False, False, False],
    [False, False, False, False, False, False, False, False],
    [False, False, False, False, False, False, False, False],
    [False, False, False, False, False, False, False, False],
    ]

def scanKey(n):
    for i in range(8):
        pports[i].switch_to_input(digitalio.Pull.UP)
    pports[n + 8].switch_to_output(False) # active
    for i in range(8):
        if pports[i].value:
            if sw[i][n]:
                pass
            else:
                synth.release(i*8+n+64)
        else:
            if sw[i][n]:
                synth.press(i*8+n + 64)
            else:
                pass
        sw[i][n] = pports[i].value
    pports[n + 8].switch_to_input(None) # deactive
def scanLed(n):
    for i in range(8):
        if sw[n][i]:
            pports[i].switch_to_input(None)
        else:
            pports[i].switch_to_output(False)
    #time.sleep(0.1)
    pports[8 + n].switch_to_output(True)
    # flash
    time.sleep(0.001)
    pports[8 + n].switch_to_input(None) # Hi-Z

while True:
    # scan switch
    for i in range(8):
        scanKey(i)
    
    # LED
    for i in range(8):
        pports[i].switch_to_output(False)
        pports[i+8].switch_to_input(None)
    #time.sleep(1)
    for i in range(8):
        scanLed(i)

まとめ

グリッド楽器igetaを作ることが出来ました。

この過程で以下を学ぶことが出来ました

  • Charieplexingを使い多数のスイッチとLEDを制御
  • Raspberry Pi Pico + CircuitPythonを使ってCharieplexingを実現
  • Synthioを使った簡易的な楽器の作成

あとやりたいこととしては、筐体の作成、楽器としての機能の拡充、乾電池駆動でモバイル楽器化などを考えています。まぁボチボチやります。

おまけ 過去のigeta

実はこのグリッド楽器igetaは過去に別のアプローチで試作したことがありました。

その時は Arduino NanoとCH451を使った構成でした。

CH451というのが、この時のキモで、8×8入力、8×8出力を一気に扱えるインターフェースICです。

しかし、作ってから気づいたのですがこのCH451はキーの同時押しに対応しておらず、楽器として利用するには機能が足りないという点でお蔵入りとなりました。

また、この時は小型のスイッチと3Dプリンタで作成したスイッチのカバープレートを組み合わせて、スイッチ自体が光るような見た目にできないかと模索していました。

この試みは一定の成果があり、キーが光るような見た目の筐体を作ることはできたのですが、手元の3Dプリンタの精度ではどうしてもキーが引っかかったりとか、押し心地にムラが出る、という結果となりました。

ということで今回は素朴に6mm角のタクトスイッチをそのまま使う設計としました。

この過去のigetaでも音を鳴らすところまではプログラムを作り、それなりに遊んだりもしました。

こういう過去があっての今回のigetaの製作につながっています。

ってこれやってたの2021年5月とかですね、、意外と歴史があります。

表面実装部品版RakuChordの改良版を作った

この記事ははJLCPCBの提供でお送りします。

JLCPCBとは

jlcpcb.com (↑こちらは日本語版のログインページで、お得なクーポンも配布されています。)

JLCPCBとは、プリント基板製造などで有名な香港の企業です。

日本からでもWebページでポチポチするだけでKiCADなどで作成した基板データの製造を依頼できます。

値段もかなりお手頃で、ホビー電子工作ユーザーの間では広く利用されています。

この記事の作例もJLCPCBに基板を発注して実現しました。

表面実装版RakuChordとは?

RakuChordというのはinajobが開発している電子楽器です。

inajob.github.io

ワンタッチで和音を演奏できるボタンがあり、だれでも比較的簡単に演奏ができるという電子楽器で、少しずつバージョンアップをさせながら、電子工作キットとしての販売をしています。

以前RakuChordの表面実装版を作ったことがありましたが、今回はこれの更なる改良版です。

inajob.hatenablog.jp

今回の表面実装版RakuChordの設計

基本的な設計は前回の表面実装版RakuChordと同じです

前回は6mmのスイッチで、修飾キーは基板裏面に配置したのですが、どうにも使い勝手が悪かったので、今回の改良で12mmタクトスイッチを採用し、従来のRakuChordの操作性を再現することと、修飾キーを上側に並べることを試すことにしました。

  • タクトスイッチは12mmスルーホール
    • 表面実装版と謳っているいるが、家にこの部品がたくさんあるのでスルーホールを使うことにする
  • 昇圧回路は安価な昇圧モジュールも利用できるようにする
  • 7つの修飾キーは基板裏面ではなく、90度の角度が付いたものを上辺に並べる
  • 相変わらず10cm×10cmに収める(安いので)
  • 表面実装部品のサイズを0603に変更(以前は1206)

90度の角度が付いたタクトスイッチ

以前、AliExpressでタクトスイッチのアソートを買ったのですが、その中に90度の角度が付いたものがあり、これを使うことにしました。

タクトスイッチのアソートは100種類のタクトスイッチがそれぞれ5個ずつ入っているような商品で、スイッチ好きの人にはたまらないものとなっています。お勧めです。

商品リンク

基板の設計

今回は以前作ったデータを改良する形で設計を行いました。そのため比較的簡単に設計が完了しました。 (前回の作例を記事にしていたおかげで、修正が必要なバグが探しやすかったです)

実際論理回路図の変更部分は非常に少なく、フットプリントの付け替えや、拡張端子の引き出し程度でした。

実体配線図は、さすがに流用することが難しいので新たに作っています。 タクトスイッチが6mmのものから12mmのものに変更となったので、基板の横幅を少し広げました。

JLCPCBに発注

今回も発注はJLCPCBです。今回の基板の色は紫色です。

10cm×10cm以内で5枚だと $2 + 送料です。お安い・・

jlcpcb.com (↑こちらは日本語版のログインページで、お得なクーポンも配布されています。)

実装

さてさて、今回もいくつかのトラブルに見舞われました

我が家のICがやはりおかしい

今回もどうもATmega328の様子がおかしく、シリアル通信の速度を遅くしないと書き込みができませんでした。 以前の記事ではUSBシリアル変換ICであるCH340Nがおかしいかも、と書きましたが、色々実験をしているとATmega328の方がおかしいようでした。

我が家にストックしているATmega328が偽物という可能性が出てきています・・・どうしたものか・・

ともあれ、前回と同様にだましだまし書き込むことで一応期待した動作をしています。

格安の昇圧モジュールから電源を供給すると動作が不安定

今回は、HT7750を使った昇圧回路とは別に、格安の昇圧モジュール(名称不明)を使って乾電池2本から5Vへの昇圧が出来るように設計していました。 しかし、こちらの昇圧モジュールを使った場合、どうも動作が不安定になるという事象が発生しました。

おそらく、音を鳴らす際に多くの電流を取り出そうとするために、電圧低下を起こしてしまっているのだと思います。 おとなしく前回と同じHT7750を用いた昇圧回路の方を使うことにしました。

昇圧方法を両方用意しておいてよかったです。

この格安の昇圧モジュールについては Arduino Nanoを単4電池で動かすボードを作った - inajob's blog で紹介しました

ダイオードのフットプリントが1つだけ逆向き

この基板にはスイッチの同時押しを実現するために、多数のダイオードが存在しています。 ダイオードには極性があるため、実装時には注意が必要ですが、実装を簡単にするため、同じような位置に存在するダイオードの向きは揃えておいたつもりだったのですが・・・

1つだけ並んでいるなかで向きが逆のものが残ってしまっていました。 案の定実装するときに、ほかと同じ向きに実装してしまい、キーが認識されないという問題が発生しました。

基板上には正しい向きが指定されているので、バグではないのですが、実装ミスを誘う良くない設計だと感じました。

格安の昇圧モジュールの向きが逆

昇圧モジュールは単純に2.54mm間隔ピンが3つ出ているだけなので、専用のフットプリントを作らず、汎用的なコネクタ部品とを配置し、格安の昇圧モジュールの配置を示す四角形を基板上に描画していたのですが、この四角形の配置を間違えており、実際の格安の昇圧モジュールの配置と食い違っていました。

そのままでは乾電池ケースと干渉してしまい、格安の昇圧モジュールが実装できない、という感じだったのですが、想定していた基板の面とは逆の表面に実装することで対応しました。 (上に書いたようにこのモジュールはそもそも性能不足で利用できなかったのですが・・)

電源スイッチの配線が間違っている

電源スイッチ周りの配線は、格安の昇圧モジュールからくるもの、HT7750の昇圧モジュールからくるものの両方を考慮する必要があったのですが、格安の昇圧モジュールからくるものを見落としており、こちらは電源スイッチとは関係なく導通した状態になってしまっていました。

これは一部の回路のパターンを切断し、導線を使ってジャンパすることで、修正しました。

(これも上に書いたように、このモジュールの性能不足により、利用できないのですが・・・)

ダイオードが破損

これは実装が終わってしばらく遊んでいる最中に起きたことなのですが、1つのキーが反応しなくなりました。 原因がわからずいろいろ試していたところ、キーの同時押しを実現するためのダイオードの1つが壊れていることが判明しました。

ダイオードは通常片方向からのみ電気を通す素子ですが、なぜかどちらからも電気を通さない状態になっていました。

部品を交換することで、この問題を解消しました。 ダイオードって壊れやすいんですかね?

ケースの作成

演奏しやすいように3Dプリンタでケースを作るというのもやってみました。

利用したツールはOpenSCADとLibreCADです。

モデリングを簡単にするために、KiCADから基板データをdxf形式エクスポートしたものを積極的に利用するスタイルで設計しました。

まず基板外形を使いベースとなる形を整え、それをくりぬいていくという手法です。 くりぬく範囲もKiCADのUserレイヤーを使いGUIで作成しました。

くりぬきは貫通、micro USBコネクタの高さ、筐体側2mm残しの3段階とし、それぞれのレイヤーをdxfでエクスポートし、OpenSCADを使って切り抜きました。

(この画像で黄色、薄緑、灰の3色の塗りつぶしがくりぬきを表しています)

この手法は、OpenSCADのプログラミングによる手軽な設計の良さと、KiCADで部品を見ながらくりぬき範囲を描画できるGUIの良さを両立させる手法だと感じています。

指をひっかけるための突起は、LibreCADやOpenSCADで頑張って設計しています。(ここはもうちょっとどうにかしたい)

まとめ

以前とほぼ同じ構成ですが、表面実装RakuChordの改良版を作りました。

やはり新しく作った個所で問題が起こりやすいことがわかりました。前回の物より演奏しやすくなって満足です。

格安昇圧モジュールは試してみたものの、今回の用途では性能不足であることが分かったのも収穫で、かつそのような問題があってもHT7750を使った昇圧回路を利用できるようにした「こんなこともあろうかと」の設計が役立って良かったです。