MENU

オープンソースなゲームダンパー CartReader V4を作ろう

このエントリーをはてなブックマークに追加


CartReaderはたくさんのゲームハードに対応しているオープンソースのゲームダンパーです。

2021年末にメジャーバージョンアップがあり、Cart Reader Version 4が公開されたので作ってみました。
今回はその製作過程を公開したいと思います。

せっかくのオープンソースプロジェクトです。
この記事を読んだら作れるように書いたつもりなので、皆さんにもこの記事を読んで自作にチャレンジしてほしいです。

Cart Readerについて

改めてCart Readerについて簡単に説明します。
Cart Readerはgithub上で運営されているオープンソースのゲームソフトROM吸出し機(ダンパー)です。

github.com

大きな特徴は次の二つです。

  • ハードウェアもソフトウェアもオープンソース化されており、だれでも自由に作ることができる。
  • 対応しているゲームハードはFC, SFC, メガドライブ, N64,,, と多岐にわたる。

プロジェクトは誰でも簡単に作れることを目指して運営されてるっぽいです。
Wikiが充実していますし、設計は買ってきたモジュール同士をつなぎ合わせることがメインなので、難しい作業がほとんどありません。
簡単なはんだ付けができれば十分です。

では、さっそく作っていきます。

必要な材料

必要な材料はざっくりと大別すると、

  • 基板類(MAIN基板と各種カートリッジ基板)
  • モジュール類
  • こまごました部品類

という感じでしょうか。

それぞれの説明と入手の仕方を書いていきます。

基板類

基板類はgithub上の基板設計データ(ガーバーデータ)から作ります。

といっても、JLCPCBなどの基板メーカーサイトにガーバーデータをアップロードして注文するだけの簡単な作業です。

私は今回PCBGOGOを使用しましたが、どこのメーカーでも手順はだいたい一緒です。
ガーバーデータのダウンロードから基板の注文までの手順を簡単に書いておきます。

① 基板のガーバーデータをダウンロードします。

基板のガーバーデータはリポジトリのhardwareフォルダの各ゲームハードのフォルダにzip形式でアップされています。
https://github.com/sanni/cartreader/tree/master/hardware

例えば、MAIN基板のガーバーデータはmain_pcbフォルダのmain_pcb_gerber.zipです。
私はファミコン、スーファミ、N64のゲームカートリッジの吸出しを行いたかったので、次の4つのガーバーデータを使いました。

  • cartreader/hardware/main_pcb/main_pcb_gerber.zip
  • cartreader/hardware/famicom_adapter/famicom_adapter_gerber.zip
  • cartreader/hardware/snes_adapter/snes_adapter_gerber.zip
  • cartreader/hardware/n64_adapter/n64_adapter_gerber.zip

githubのリポジトリごとダウンロードかクローンしておくのがおすすめです。あとでほかのファイルも使うので。

② 基板メーカーサイトにzipファイルをアップロードします。

ダウンロードしたzipファイルを基板メーカーサイトにアップロードします。
例えばJLCPCBだと、まずトップページの"Instant Quote"をクリックし、

"Add gerber file"をクリックし、ダウンロードしたzipファイルを選択すればアップロード完了です。

うまくアップできればこんな感じの表示になるかと思います。

③ 基板の製造条件を選択します。

アップロードが完了したら、あとは基板の製造条件を選択してカートに追加し、清算すれば基板を製造してもらえます。

製造条件は初期設定だと下記の感じかと思います。

基本的には、この初期設定からいじる必要はありません。
好みで、"PCB Color"と"Silkscreen"を変更してもよいかと思います。

設定が終わったらSave To Cartを押してカートに追加しておきましょう。

これでMAIN基板が製造準備OK状態になりました。

あとは残りの基板についても同様の作業をしていけばOKです。

これで基板の準備は完了です。
深圳から基板が来るのを待ちましょう。

モジュール類とこまごました部品類

必要なモジュール類と部品類はほぼほぼAliexpressでそろえることができます。
一覧は次の表のとおりです。

材料名 備考 商品リンク
arduino mega 2560互換マイコンモジュール Aliexpress
SDカードスロット付きLCDモジュール(MKS MINI12864 V3) Aliexpress
SI5351クロックジェネレータモジュール N64/スーファミ/NP/SVでのみ必要 Aliexpress
18650バッテリー取り付け用モジュール なくてもよい。一応買ったけど使ってない。 Aliexpress
18650バッテリー なくてもよい。変なとこから買うと危ないのでAliexpressで買わないこと。
2.54mmピッチ 40pin ソケット カットして使用する Aliexpress
2.54mmピッチ 40pin ピンヘッダー カットして使用する Aliexpress
オス-メスのジャンパーワイヤー リード線でもよい Aliexpress
スライドスイッチ 1,2個でいいのに50個も入ってる Aliexpress
SDカード FAT32かexFATでフォーマットしておくこと。ラズパイでも使えるようにmicroSDカードが良いかも(→リンクはMicroSD to SD変換付き) Amazon
100nFコンデンサ(2012サイズ) スーファミの一部カセットの吸出しに必要。→はサンプルブック Aliexpress
PIC12F629T-I/SN スーファミの一部カセットの吸出しに必要。 秋月電子
1kΩ抵抗 N64スロットに必要 秋月電子

今回はバッテリーは無しで組み立てました。
わざわざバッテリーを搭載するメリットをそんなに感じなかったので。
USBから電源供給なので、モバイルバッテリーを使ってもいいですしね。

ひとまずPIC12F629もなしで組んでます。
ただ、実際に使った感じ、吸い出せないスーファミカセットがあったのでやっぱり必要かも。

あと、カートリッジスロットの商品リンク一覧は下の通りです。
遊びたいゲーム機に合わせて選んでください。

今回は上三つを購入しました。

必要な工具

私が実際に組み立て時に使った工具を書いときます。
基本的にははんだごて一式とニッパーがあればなんとかなると思います。

工具名 型番 備考 商品リンク
はんだごて FX600-02 二本あると便利。二本目は安いのでOK Amazon
こて台 633-01 Amazon
はんだ FS402-02 Amazon
ニッパー 不明 今回はダイソーのやつを使用 -
ワイヤーストリッパー PA-14 ニッパーでも代用可能。(ダイソーのでは厳しいかも) Amazon
ピンセット P-880 Amazon
のこぎり 4907052107489 SFCスロットの加工に使用 Amazon


必要なものがそろったら早速組み立てていきましょう。

組み立て手順

材料を並べるとこんな感じです。

では、さっそく組み立てていきましょう。

Mega 2560 Proにプログラムを書き込む

まずは、Mega 2560 Proにプログラムを書き込みます。
プログラムの書き込みにはArduino IDEを使います。
持ってない方はこちらからインストールしておきましょう。

プログラムの準備

プログラム本体はリポジトリのcartreader/Cart_Reader/Cart_Reader.ino です。
まずはこのファイルをArduino IDEから開きましょう。
こんな感じで開くかと思います。

上にずらーっとタブが出てると思うので、option.hタブに移動して、次の修正をします。

  1. HW4をアンコメント、HW1,HW2,HW3をコメントアウト

  2. clockgen_installedをアンコメント

必要なライブラリのインストール

次のライブラリが必要です。

Arduino IDEのスケッチ→ライブラリをインクルード→ライブラリを管理 からライブラリマネージャを開き、

必要なライブラリを各リポジトリ名で検索してインストールしてください。

IDEの書き込み設定

IDEのツールメニューからボード:Arduino Mega or Mega 2560に設定、プロセッサ: ATmega2560(Mega 2560)に設定します。

プログラムの書き込み

Mega2560をPCとUSB接続し、IDEのツール→シリアルポート からMega2560が接続されているポートを選択した後、左上の矢印アイコンを押して書き込みます。

以上で、Mega 2560にCartReaderのプログラムが書き込みできました。

SDカードの準備

FAT32かexFATでフォーマットしたSDカードを用意します。
SDカードをPCに接続し、リポジトリのsdフォルダ配下のファイルをすべてSDカードにコピペしておきます。

モジュールの改造

Mega2560とLCDモジュールにちょっとだけ改造が必要です。

Mega 2560の改造

まずは下の写真の赤で囲んだ部品(Fuse)を

外します。

このときはんだごてを二本使って、部品をつまむようにしてあてると簡単に取れます。
はんだごてが一本しかない場合ははんだを大量に盛って、部品の両端子のはんだをうまく溶かしながら外しましょう。

次に、USBコネクタ側のランドにジャンパーワイヤーをはんだ付けします。
(ジャンパーワイヤーはあらかじめ半分に切って被覆を剥いておきます。)

これでMega2560の改造は完了です。

LCDモジュールの改造

R4(下の写真の赤丸)を

はんだでショートさせます。

LCDモジュールの改造はこれだけです。

ピンヘッダーとソケットのはんだ付け

ここからひたすらピンヘッダーとソケットのはんだ付けです。
大量にはんだ付けするので、換気はしっかりとおこないましょう。
では頑張ってください。

まずはMega2560に、付属していたピンヘッダーのはんだ付け。

続いて、クロックジェネレーターモジュールのはんだ付け。

次にMAIN基板へソケットとピンヘッダー、ジャンパーワイヤーのはんだ付け。

ピンヘッダーとソケットは1x40のものを使っている場合は、ニッパーで必要な長さに切って使いましょう。

上の写真の右下のピンヘッダーはLCDモジュールのコネクタ接続用ですが、2列あるのでずれに注意しながらつけましょう。
↓のようにあらかじめコネクタにピンヘッダーを挿した状態ではんだ付けするとずれないですよ。


あとは、モジュールとMAIN基板を接続していけば、CartReader本体の完成です。
まずは、ジャンパーワイヤーをモジュールと接続して、

(写真上部のモジュールはバッテリーモジュールです。最終的には使ってません。)

すべてのモジュールをがっしゃーん。

(真ん中のスロット部については次で説明します。)

バッテリーモジュールが取りつかない場合の接続は下の写真のようになります。

バッテリーモジュール用のジャンパーワイヤーと写真左上端のソケットの一番左に接続してあります。

これでCart Reader本体は完成です。
ひとまずお疲れ様です。
続いて、各スロット部を組み立てていきましょう。

スロット部の組み立て

ファミコン用とN64用についてはひたすらはんだ付けするだけです。
N64用1Kと書いてるとこに1kΩ抵抗をつけます。
完成品はそれぞれこんな感じ。

ファミコン用アダプタ

ニンテンドー64用アダプタ

SFC用については、スロット部品がそのままだと写真のように基板と干渉して取り付けられないので、加工が必要です。

まずは下の写真の赤線部をのこぎりなどで切り落とします。

あとはちょっと凸部が残るので、赤線のようにニッパーで切り落とします。

これで基板に取り付けられるようになります。

あとは、スライドスイッチとスロット部品、ピンヘッダーをはんだ付けすれば完成です。

これでスロット部の組み立ても終わりです。



お疲れさまでした!!
これでCartReaderの組み立てはすべて完了です。

使い方

今回はバッテリーなしなので、USBケーブルから直接電源を供給してあげます。

ここでは一例としてN64ソフト「ゼルダの伝説 ムジュラの仮面」をダンプしてみます。

N64スロットをCartReader本体に差し込み、カートリッジを上から挿し、USBケーブルを接続して電源を入れます。

メニューからNintendo 64→Game Cartridge →カートリッジの情報の表示画面 → Read Rom と選択することで、カートリッジのダンプができます。

このダンプしたファイルを使えば、PCやラズパイでゲームを遊べるようになります。

SFCカートリッジの吸出しについて

SFCのソフトには吸い出せるゲームと吸い出せないゲームがありました。
例えば、上の写真の星のカービィ 3は吸い出せなかったです。
おそらく、PIC12F629を実装して特殊チップ(SA1)に対応させることができれば吸い出せるのかな。

FCカートリッジの吸出しについて

カートリッジの情報(PRG, CHR, Mapper, RAM)をこういったサイト調べてから、それをもとにCartReaderを設定し、吸出しを行う必要があります。
詳しくは本家wiklを見ていただくのがいいかと思います。

スロットの交換について

ほかのゲーム機のカートリッジをダンプしたいときは、スロットを交換する必要があるのですが、抜くのがめちゃくちゃ固いです。
抜くときにはこのようにドライバーなどを差し込んで、テコの要領でちょっとずつ抜くようにしてください。

遊んでみる

さっそく吸い出したゲームで遊んでみたいと思います。
エミュレーターはRecalboxを使用します。

https://www.recalbox.com/diy/1-discover/

RecalboxはRaspberry PIで動作するエミュレーターです。
これについてはまた別の記事で紹介できたらいいなと思います。

遊ぶ方法は簡単です。
Recalboxのイメージが入ったSDカードのそれぞれのゲームハード用のフォルダに、先ほど吸い出したファイルをコピペするだけです。
例えばSFCのソフトだと、"SNES"っていうフォルダに吸い出したファイルを親フォルダごとコピペすればOKです。

すると、Recalboxのメニュー上で先ほど吸い出したゲームが選択できます。

これを選ぶと、ちゃんとゲームが遊べました。

写ってるコントローラーは純正のSFCコントローラーをUSB化したものです。
思い出のコントローラーで思い出のゲームを遊べるのは最高でした。

SFCコントローラーUSB化基板は以下で頒布されてます。

geekyfab.booth.pm

www.kadenken.com

裏面のねじを5本緩めて中の基板と取り換えるだけなんで、cartreaderを自作するような人には物足りないかも。
そんな人はこちらの自作キットをどうぞ。
www.switch-science.com

最後に

今回は、オープンソースなゲームダンパー CartReader Version 4を作ってみました。
製作難易度はそんなに高くなかったので、電子工作入門としてもいい題材かなと思います。
ただ、はんだ付けするピンの数がめちゃくちゃ多かったので、はんだ付け嫌いになるかもしれないなあ。  

オープンソースなだけあって、ネットで検索すると完成品を販売してる人や製作代行してる人なんかも見つかるかと思います。
とはいえ、繰り返しになりますが、せっかくのオープンソースプロジェクトです。
ぜひ皆さんにも一度、自作にチャレンジしてほしいところです。


今回はこれで終わります。

SFCコントローラーをUSBゲームパッド化する基板を作りました

今回はスーパーファミコン(SFC)のコントローラーをUSB Gamepad化する基板を作りました。

こちらの記事では、SFCコントローラー USBゲームパッド化基板の制作過程を順を追って紹介します。
設計データはgithubに公開していますので、自作にもぜひ挑戦してみてください。

お知らせ

こちらの記事で紹介している基板は製品化して、以下で頒布しています。
geekyfab.booth.pm

www.kadenken.com

また、自作キットはスイッチサイエンスで頒布しています。

www.switch-science.com

興味を持っていただいた方はご覧ください。


では本編です。

こんな感じの仕様で作ります。

SFCコントローラーの筐体にピッタリ収まるUSBゲームパッドの基板を作ります。
SFCコントローラーはボタン数が少ないので、今どきのゲームも遊べるように、Start, Selectボタンを長押しすることでボタンの割り当てを変更できるようにします。

回路図を描いてみます

全体回路図はこういう感じにしました。

SFCコントローラー USBゲームパッド化基板 回路図
基本的にはメインマイコンであるPIC16F1459のIOポートにボタン用のパッドを直つなぎしている回路になっています。
PIC16F1459はIOポートによっては内蔵プルアップ抵抗がついてたりついてなかったりのようなので、念のためすべてのボタン用のパッドにはプルアップ抵抗用のランドを設けてあります。

メインマイコン PIC16F1459

メインマイコンにはPICマイコンのPIC16F1459を使用しています。
このPICマイコンは俗にいうUSBマイコンで、USBデバイスとしてふるまうことができます。

IOポート数も多いところもよいところです。
キーマトリックスなどの回路を組まなくても、SFCコントローラーのボタン数をカバーすることができるので、回路が単純になります。

アートワークを描いてみます

今回のプロジェクトの肝です。
SFCコントローラーの筐体と基板から寸法を実測し、筐体にぴったりとはまり、ボタン位置も合うようにアートワークを設計します。
とはいえ、一発でSFCの筐体にピッタリはまる基板を作るのは難しくて、基板を製造して微調整してまた作って…みたいなことをしました。

そして、最終的に出来上がったアートワークがこちらになります。

SFCコントローラー USBゲームパッド化基板 表面

SFCコントローラー USBゲームパッド化基板 裏面

左下にちょろっとついてるのはL,Rボタン用の基板になります。

基板を製造します

基板製造はAllpcbに注文をしました。
基本的にはデフォルトのオプションになりますが、表面処理については金メッキ処理を選択する必要があります。
これは、ボタン用のパッドの酸化を避けるためです。
半田レベラーや銅箔むき出しではボタン用のパッドが酸化して反応しなくなってしまうので、金メッキ処理をして酸化を防ぎます。

そして、届いた基板がこちらです。

届いたSFCコントローラー USB Gamepad化基板 表面

届いたSFCコントローラー USB Gamepad化基板 裏面

金メッキでピカピカのきれいな基板です。
ロゴをレジスト抜きで作ってみましたが、なかなかかっこいいです。

金メッキのロゴ

部品を実装します

早速部品を実装していきます。
そして、実装後の基板がこちらです。

実装後はこんな感じです

配布するならもっときれいに作りますが、自分用なのでこんなもんでしょう。

プログラムを書いてみます

USB Gamepad化基板用のソースコード全文はGithubに公開していますので、この記事ではいくつかのポイントだけ紹介します。

github.com

このプログラムはMicrochip社が提供するMicrochip Libraries for Applications (MLA) をベースに書いています。

MLA内にはPICマイコンごとにプロジェクトファイルのサンプルが用意されています。
例えば、今回使用するPIC16F1459のUSB Joystickのサンプルプロジェクトは下記階層にあるはずです。

mla\v2018_11_26\apps\usb\device\hid_joystick\firmware\low_pin_count_usb_development_kit_pic16f1459.x

PICのポート設定とタイマ初期化

PICのポート設定とタイマ初期化はmain.cのmainの初めのほうで行っています。

    /* set all ports input*/
    TRISA = 0x30;
    TRISB = 0xf0;
    TRISC = 0xff;
    
    /* enabling internal pull up*/
    OPTION_REGbits.nWPUEN = 0;
    WPUA = 0x30;
    WPUB = 0xf0;
    
    /* all ports used as degital ports.*/
    ANSELA = 0x00;
    ANSELB = 0x00;
    ANSELC = 0x00;
    
    /* initializing timer0 and interruption*/
    
    OPTION_REGbits.PS = 0b111;        // clock divided by 256
    OPTION_REGbits.PSA = 0;         // enabling prescaler
    OPTION_REGbits.TMR0SE = 0;      // edge select (rise)
    OPTION_REGbits.TMR0CS = 0;      // clock source select (internal)
    OPTION_REGbits.INTEDG = 1;      // interrupt edge select (rise)
//    INTCONbits.TMR0IF = 0;          // reset timer0 interrupt flag
//    INTCONbits.TMR0IE = 1;          // enabling peripheral interrupts
    INTCONbits.GIE = 1;             // enabling interrupts
    
    // setting initial value of timer 0.
    // 1 clock = 256/16MHz = 16us 
    // the timer interrupt happens every 16us x 0xff(255) = 4080us .
    // 
    // set the timer0 value so that timer interruption happens every 4000us.
    // 80us / 16us = 5 clocks
    TMR0bits.TMR0 = (uint8_t)5;
    

コメントの通りです。
IOポートをすべて入力にして、内部プルアップがついてるポートはすべて有効にして、デフォルトのポート設定はアナログなのですべてデジタルに設定しています。
次に、タイマー0のパラメーターを設定しています。

USB通信に使うデータ型

USB通信で送るpacketのデータの型はapp_device_joystick.h内で次のように宣言しています。

typedef union _INTPUT_CONTROLS_TYPEDEF
{
    struct
    {
        struct
        {
            uint8_t y:1;
            uint8_t b:1;
            uint8_t a:1;
            uint8_t x:1;
            uint8_t L1:1;
            uint8_t R1:1;
            uint8_t L2:1;
            uint8_t R2:1;//            
            uint8_t select:1;
            uint8_t start:1;
            uint8_t left_stick:1;
            uint8_t right_stick:1;
            uint8_t home:1;
            uint8_t :3;    //filler            
        } buttons;
        struct
        {
            uint8_t hat_switch:4;
            uint8_t :4;//filler
        } hat_switch;        
        struct
        {
            uint8_t X;
            uint8_t Y;
            uint8_t Z;
            uint8_t Rz;            
        } analog_stick;
    } members;
    uint8_t val[7];
} INPUT_CONTROLS;

ボタンの押下に合わせて、これらの変数に値を格納することでUSB Gamepadを動作させることができます。
例えば、"Y"ボタンが押されたら、変数yの値を1にしてUSBでPCに送信します。
これにより、USB Gamepadで"Y"ボタンが押されたんだなということがわかります。

ボタン処理部

ボタン処理部はmy_app_device_gamepad.cに書いています。
ここのコードでは、

  • ボタンの状態の監視
  • start/select長押し時の処理とステートの管理

を行っています。

ボタン状態の監視は例えば下記のような簡単なコードをボタン分用意しているだけです。

gamepad_input->members.buttons.select = BUTTON_IsPressed(BUTTON_SELECT);

start/select長押し時の処理にはPICマイコンの初期化したタイマー0を使っています。
以下はstartの長押し処理のための関数です。

void ChangeSWMode_Button_Start(void){
    uint16_t cnt_timer =0;
    
    if (BUTTON_IsPressed(BUTTON_START)){
        INTCONbits.TMR0IF = 0;          // reset timer0 interrupt flag
        TMR0bits.TMR0 = (uint8_t)5;
        cnt_timer = 0;
        while(BUTTON_IsPressed(BUTTON_START)){
            if(INTCONbits.TMR0IF){          // INTCONbits.TMR0IF happens every 4ms
                cnt_timer++;
                if(cnt_timer >=500){        // 2s
                    flags.sw_flag = ~(flags.sw_flag);
                    cnt_timer =0;
                    while(BUTTON_IsPressed(BUTTON_START));
                }
                INTCONbits.TMR0IF = 0;
                TMR0bits.TMR0 = (uint8_t)5;
            }
        }
    }
        
    return;
}

USB HID report descriptors

USB HID report descriptorsは資料が公式のドキュメント以外あまりなく、仕様もわかりにくく、かなり厄介でした。
内容的にはusb_descriptors.cに書かれている下記部分になります。

const struct{uint8_t report[HID_RPT01_SIZE];}hid_rpt01={{
  0x05,0x01,        //USAGE_PAGE (Generic Desktop)
  0x09,0x05,        //USAGE (Game Pad)
  0xA1,0x01,        //COLLECTION (Application)
  0x15,0x00,        //  LOGICAL_MINIMUM(0)
  0x25,0x01,        //  LOGICAL_MAXIMUM(1)
  0x35,0x00,        //  PHYSICAL_MINIMUM(0)
  0x45,0x01,        //  PHYSICAL_MAXIMUM(1)
  0x75,0x01,        //  REPORT_SIZE(1)
  0x95,0x0D,        //  REPORT_COUNT(13)
  0x05,0x09,        //  USAGE_PAGE(Button)
  0x19,0x01,        //  USAGE_MINIMUM(Button 1)
  0x29,0x0D,        //  USAGE_MAXIMUM(Button 13)
  0x81,0x02,        //  INPUT(Data,Var,Abs)
  0x95,0x03,        //  REPORT_COUNT(3)
  0x81,0x01,        //  INPUT(Cnst,Ary,Abs)
  0x05,0x01,        //  USAGE_PAGE(Generic Desktop)
  0x25,0x07,        //  LOGICAL_MAXIMUM(7)
  0x46,0x3B,0x01,   //  PHYSICAL_MAXIMUM(315)
  0x75,0x04,        //  REPORT_SIZE(4)
  0x95,0x01,        //  REPORT_COUNT(1)
  0x65,0x14,        //  UNIT(Eng Rot:Angular Pos)
  0x09,0x39,        //  USAGE(Hat Switch)
  0x81,0x42,        //  INPUT(Data,Var,Abs,Null)
  0x65,0x00,        //  UNIT(None)
  0x95,0x01,        //  REPORT_COUNT(1)
  0x81,0x01,        //  INPUT(Cnst,Ary,Abs)
  0x26,0xFF,0x00,   //  LOGICAL_MAXIMUM(255)
  0x46,0xFF,0x00,   //  PHYSICAL_MAXIMUM(255)
  0x09,0x30,        //  USAGE(X)
  0x09,0x31,        //  USAGE(Y)
  0x09,0x32,        //  USAGE(Z)
  0x09,0x35,        //  USAGE(Rz)          
  0x75,0x08,        //  REPORT_SIZE(8)
  0x95,0x04,        //  REPORT_COUNT(4)
  0x81,0x02,        //  INPUT(Data,Var,Abs)
  0xC0              //END_COLLECTION
}
};

ここの書き方は需要があれば別の記事で書きたいと思います。

プログラムのライセンスについて

Microchipが提供するMLAのソースコードのほとんどはApache License 2.0で提供されています。
私が追加したソースコードについてもApache License 2.0で提供することにしましたので、個人利用・商用利用かかわらずご自由にお使いください。
ただし、USB プロダクトID(PID)についてはMicrochip社とのサブライセンス契約により提供されているものですので、商用利用不可となります。
ファイルとしてはmy_usb_pid.hが商用利用不可です。

SFCコントローラーを改造してみます

出来上がったプログラムをpickit3で基板に書き込めば、基板は完成です。

では早速、出来上がった基板を使ってSFCコントローラーをUSBゲームパッド化してみましょう。

これを、

こうして、

こうして、

こうじゃ。

あとはふたを戻して出来上がりです。

SFCコントローラー USBゲームパッドver.

早速動かしてみましょう。

動かしてみます

Windowsで動作確認

まずは動作確認です。
PCに挿してみると、コントロールパネルにちゃんと"SFC Gamepad"が認識されました。

"デバイスとプリンター"にSFC Gamepadが表示されました

では、上のアイコンを右クリック→ "ゲームコントローラーの設定"→"プロパティ"と移動し、ゲームパッドの動作確認画面を表示させます。
で、動かすとこんな感じです。

動作確認(Select長押し機能の確認中)

動作確認 (Start長押し機能の確認中)

しっかり動いてくれてますね。
初めて動いたときはかなりうれしかったです。

Raspberry PIで動作確認

Raspberry PIでの動作確認もしておきました。

ラズパイでGamepadを使うには"Joystick"パッケージを使用します。
また、動作確認には"jstest-gtk"が使いやすいです。
まずはterminalから次のコマンドを実行してこれらのパッケージをインストールします。

sudo apt install joystick jstest-gtk

続いて、terminalから次のコマンドを実行してjstest-gtkを立ち上げます。

jstest-gtk

あとは、windowsと同じ感じです。

最終的に動作確認したOSは次の通りです。

  • Raspberry PI 3
    • Raspberry Pi OS
    • Recalbox for RASPBERRY PI 3
    • RetroPie 4.7.1 for RASPBERRY PI 2/3
  • Raspberry PI 4
    • Raspberry Pi OS
    • Recalbox for RASPBERRY PI 4/400
    • RetroPie 4.7.1 for RASPBERRY PI 4/400

その他は確認してませんが、特殊なドライバーは使っておらず、標準ドライバーで動いてるのでおそらく行けるでしょう。

Steamで遊んでみる

USBゲームパッド化したSFCコントローラーで、Steamのゲームを遊んでみました。

まずは子供の頃スーファミでよく遊んでたボンバーマンのバトロワゲーム、"スーパーボンバーマン R オンライン"。

スーパーボンバーマン R オンライン
最新のボンバーマンがSFCコントローラーで遊べるなんて、感動です…

大好きなゲーム"UNDERTALE"を手掛けたToby Fox氏が贈る新作、"DELTARUNE"。

DELTARUNE
最近のゲームなのにSFCコントローラーでプレイすることに全く違和感がない。

今時な3Dパーティーゲーム"Fall Guys"

Fall Guys: Ultimate Knockout
さすがに無理かと思いましたが、全然遊べました!

テイストが1930年代のカートゥーンっぽい"Cuphead"

Cuphead
SFCコントローラーにめちゃくちゃあう。

EPIC Gamesで遊んでみる…?

EPIC Gamesでは対応コントローラーが限られているようで、遊べませんでした…
FORTNITEも遊びたかったなぁ…

<後日談>
x360ceを使用することでできました。
詳しくは↓
geekyfab.com

最後に

今回は、スーパーファミコンのコントローラーをUSBゲームパッド化する基板を作り、実際にスーファミのコントローラーを改造してゲームを遊んでみました。

スーファミのコントローラーってすごく好きなんで、最近のゲームもこれで遊びたいなぁと思ったのが制作のきっかけです。
結果、大満足な仕上がりになりました。

作った基板のガーバーデータとファームウェアのソースコードはGithub上で公開してるので、よろしければぜひ作ってみてください。

github.com

今回はこれで終わります。

High-Speed対応の小型USB切替器を作ってみた

f:id:moutakusan:20210825230907p:plain:w400



最近はテレワークでの仕事が多くなり、家のデスクトップ環境の隣に会社のノートPCを置いて仕事をしております。
そうなると、家のPCで使っているキーボードを会社のノートPCにもつないで使いたくなるわけですが、意外と面倒なのがUSBの差し替えです。
一回一回は大した作業ではないのですが、毎回となると結構なストレスなんですよね。
これを何とかしようということで、今回はUSB切替器を自作してみることにしました。

この記事ではUSB切替器の制作過程を順を追って紹介します。

お知らせ

こちらの記事で紹介している基板は製品化して、スイッチサイエンスで頒布しています。

www.switch-science.com

興味を持っていただいた方はご覧ください。


では本編です。

こんな感じの仕様で作ります

今回は2入力1出力のUSB切替器を作ろうと思います。
PCからの入力が2ポート、デバイス側への出力が1ポートついていて、スイッチでUSBデバイスの接続先PCを切り替えられるようなイメージです。

f:id:moutakusan:20210813161316p:plain
USB切替器イメージ

出力側はせっかくならUSBハブが使えると便利なので、USB2.0 High Speed(480Mbps)の信号を通せることを目指します。
USB2.0って中々に高速なので、適当なスイッチや配線じゃダメだったりするんですよね。なので、USB切替専用のICを使うことにしました。

あと何気に考える必要があるのは、デバイス側への電源供給をどうするかです。
PCを切り替えるたびに、電源供給元も切り替えた側のPCに一緒に切り替えるのが自然な動作だと思うので、そのようにします。
こういう動作をさせるときに怖いのは電流の逆流です。ちゃんと回路を組まないと、片方のPCからもう一方のPCに電流が逆流したりするので危険です。

市販の機器でも電流が逆流してくるものがごくたまにあるので、機器を選ぶ際は気をつけましょう。

回路図を描いてみます

USB切替器の全体回路図はこういう感じにしました。

f:id:moutakusan:20210825224426p:plain
USB切替器回路図
pdfもあります↓
https://drive.google.com/file/d/1PDiqCJw0ZSpBnHbXeTuMrltwRQDd_-Q_/view?usp=sharing

次からはブロックごとに説明していきます。

USB信号切替回路

回路図左上のUSB信号切替回路の説明です。

f:id:moutakusan:20210813164351p:plain
USB信号切替回路

左側のJ101,J102がPC側のUSBポート、右側のJ103がデバイス側USBポートで、IC103がUSB信号切り替え用のICです。

ここでは、IC103はUSB2.0に対応した専用IC(TS3USB30E)を使用しています。
下図はデータシートからの引用で、左上がICを通してないとき、右上がICの一方のパスを、下がICのもう一方のパスを通した時のUSBの信号波形です。
(どっちがどっちのパスかはよくわかりません…。それぞれNC=Normally Close, NO=Normally Openとは記載ありますが、NormallyがHighとLowのどっちを指してるのか不明なので。)

f:id:moutakusan:20210813170016p:plain
USBの信号波形

いずれのパスを通った時でも、USB信号がほとんど劣化してないことがわかると思います。
なので、このICを使ってうまく設計してやればUSB2.0対応は行けるはずです。

回路図の上のほうに書いてあるSEL_Nは、物理スイッチSW101につながっています。
ユーザーが物理スイッチを切り替えるとIC103が連動して信号の接続を切り替えてくれるようになっています。

3.3V出力のリニアレギュレーター回路

回路図右上は3.3V出力のリニアレギュレーター回路です。

f:id:moutakusan:20210813221234p:plain
3.3V出力リニアレギュレーター回路

PCから供給される5Vから、IC103(USBスイッチIC)の電源を作っています。
IC103が高速信号扱ってるし、一応きれいな電源いるのかなぁということで、リニアレギュレーターを使いました。

USB電源切り替え回路

回路図左下はUSB電源切り替え回路です。

f:id:moutakusan:20210813221438p:plain
USB電源切り替え回路

PCから供給される電源が物理スイッチSW101に連動して切り替わるようになっています。
物理スイッチにはトグルスイッチを使いました。かっこいいので。

ここの回路の動作の説明は長くなるので、別の記事で紹介できたらなと思います。
LTSpiceを用いたシミュレーションにて動作も確認したので、それも一緒に紹介できたらいいな。

ということで、ここでは簡単な説明だけ。
それぞれのPCからの供給電源に対してPch-MOSFETが二個ずつ入っており、物理スイッチを介してFETをLowに引っ張ることで供給元の電源ラインが出力側に導通します。
トグルスイッチの構造上、上側の二つのFETと下側の二つのFETが同時にLowに引っ張られることはなく、二つの電源ラインは排他動作をします。

ちなみに、1ライン当たりFETを1個じゃなくて2個使用してるのは逆流防止のためです。
Pch-MOSFETはドレイン→ソースの中に寄生ダイオードがあり、電流は流れてしまいます。
今回のように電源ラインを2つくっつけてスイッチングする場合は、一方の電源から他方の電源へドレイン→ソース間を通っての逆流を防ぐために、ソースを背中合わせにしてFETを2つ配置します。

f:id:moutakusan:20210813230525p:plain
逆流防止のためにFETは2個配置
さらにFETはLowに引っ張られてないときは常にHighで固定したいので、抵抗を介してソース側の電源ラインにプルアップします。
その抵抗を介して電源が逆流したら困るのでダイオードも配置してあります。
 

回路の説明は以上です。

アートワークを描いてみます

今回は専用基板を起こすためにアートワークを描きます。
で、描いたアートワークがこちらです。

f:id:moutakusan:20210816224305p:plain
USB切替器アートワーク (表面)

f:id:moutakusan:20210816224357p:plain
USB切替器アートワーク (裏面)

基板を3Dビューアで見るとこんな感じです。

f:id:moutakusan:20210816225449p:plain
3Dビュー (表面)

手前の灰色の箱二つがUSB Type-B (PC側)、奥の箱がUSB Type-A(デバイス側)、左側の箱がトグルスイッチです。
PC側のUSBポート二つとトグルスイッチの両サイドにはそれぞれシルクで名前が書いてあって、トグルスイッチで倒した方のUSBポートが有効になるような感じで描きました。

机の上において使うときに邪魔にならないように、サイズは5cm x 5cmと、かなり小型にしました。

裏面はこんな感じ。

f:id:moutakusan:20210816230042p:plain
3Dビュー (裏面)

USBコネクタの足からUSBスイッチIC(IC101)のラインが太くなっているとこはポイントの一つです。
ここはUSBの信号線(D+/D-)で、差動インピーダンスをUSBの規格値である90ohmに近づけるようにラインを引いています。
インピーダンスの計算はこちらのサイトを使いました。

インピーダンス計算 - 基板クイック試作 - PCBWay

基板の製作と部品実装、そして完成!

今回はFusionPCBで基板を製作しました。

www.fusionpcb.jp

FusionPCBへの基板の発注方法については、また別の記事で紹介できたらと思います。

発注してからおよそ二週間で基板が手元に届きました。
それがこちらです。

f:id:moutakusan:20210825225354p:plain
きれいな青色の基板が届きました

青色の基板にしました。
きれいな青色です。

今回は4枚に面付けしました。
割るとこんな感じです。

f:id:moutakusan:20210825225758p:plain
USB切替器の生基板

5cm x 5cmしかないので、実際に触ってみるとめちゃくちゃ小さいです。

早速、部品を基板に実装しました。

f:id:moutakusan:20210826213034p:plain
表面
f:id:moutakusan:20210826213112p:plain
裏面

全部手ではんだ付けしたんですが、部品が小さくて難易度が高く、全部つけるのに1時間くらいかかりました。
USB切り替え用のIC(TS3USB30E)のピンなんて0.5mmピッチでしたからね。
かなり大変でした。

[追記]その後の成長↓

最後に周辺の4つの穴にスペーサーをつけて完成です!

f:id:moutakusan:20210825230815p:plain

f:id:moutakusan:20210825230907p:plain

作業机に置くとこんな感じ。 f:id:moutakusan:20210825231013p:plain

いい感じです!

お次は肝心の動作確認です。

動作確認してみます

キーボードをつないで動作確認

まずは、キーボードをつないでデスクトップPCとノートPCを切り替えられるか確認しました。
その様子がこちらです。

f:id:moutakusan:20210825234740g:plain
USB切替器にキーボードを接続して動作確認

ちゃんとトグルスイッチを切り替えることで、キーボードの接続先のPCを変えることができました!

キータイプ時の遅延というのも一切感じないです。
USB切替用のICには、信号の切替のみを行うパッシブタイプと信号を一度受けて叩き直すリドライバタイプがありますが、今回使用しているICは前者のため、より遅延が少ないっていうのもあるかもしれないです。
というか、パッシブタイプの場合は切り替えのみなので遅延は0のはずです。

HDDをつないで動作確認

今回はUSB2.0 High-Speed信号を通せるUSB切替器の自作を目指しました。
USB2.0が達成できているかの確認のために、外付けUSB HDDをUSB切替器あり/なしでPCに接続したときの通信速度の変化を調査しました。
通信速度の測定にはCrystalDiskMarkを使用しました。

crystalmark.info

その結果がこちらです。
f:id:moutakusan:20210826221341p:plain USB切替器あり/なしともに通信速度は約40MB/s(=320Mbps)出ており、USB2.0High-Speedで通信を行っていそうです。
ということで、USB2.0 High Speedモードでの通信が達成できていました!

スイッチサイエンスマーケットプレイスに委託

スイッチサイエンスには同人ハードウェアを委託頒布してくれるマーケットプレイスという仕組みがあります。
今回作ったUSB切替器も委託頒布してもらうことにしました。
方法は簡単で、まずはこちらのページを参考にメールを送るだけでOKです。
あとは担当者とやり取りしながら進めていくと、こういう風に製品ページを作ってくれて委託頒布してもらえるようになりました。
www.switch-science.com
これで私も同人作家の仲間入りです。

おわりに

今回はUSB2.0 High Speed対応の小型USB切替器を作りました。
自分で回路から設計したものが、基板になって、さらに実際に動いてというのはすごく感動しますね。
今回作ったUSB切替器はかなり実用的で、まだ使い始めて数日ですが、すでに手放せない予感です。

長い記事を最後までお読みいただきありがとうございました。
読んでくれた人の参考になってくれればうれしいです。

今回はこれで終わります。



おしまい。

AliExpressで買ったRTCモジュール(DS1302)をArduinoで動作確認

f:id:moutakusan:20210627234919p:plain:w400

RTCモジュール(DS1302)をAliExpressで購入したので、Arduinoにつないで動作確認しました。

RTCモジュールについて

購入時の価格は1個当たり$0.62でした。とんでもない安さです。

ja.aliexpress.com

本編とは関係ないですが、並行輸入したやつはamazonとかでも売ってたりします。
割高になりますが、すぐ来るのがメリットです。
Aliexpressは2週間から2か月とかかかりますからね。

せっかくなんで数個買ったんですが、送られてきたものは一つずつ個包装になってました。

f:id:moutakusan:20210619160110p:plain
個包装されてた。お菓子みたい。

さっそく開封! f:id:moutakusan:20210619160304p:plain f:id:moutakusan:20210619161821p:plain

作りは問題なさそうですね。端子側の基板カットが攻めすぎている気もしますが、実害はないでしょう。

乗ってるRTC ICはちゃんとDS1302と書いてあります。Maxim純正品なワケありませんが。
Maxim純正品だとICだけで1個当たり$1.86以上しますからね。あくまでもお遊び品です。

ともかく動かしてみましょう。

プログラム

Arduino IDEの"ライブラリを管理"メニューから検索できる、"RTC by Makuna"ライブラリを使うことにします。

f:id:moutakusan:20210627075452p:plain
RTC by Makuna

すると、スケッチ例もいくつか取り込まれるので、今回はDS1302_Simpleっていうやつを使って動作確認することにします。名前からして一番単純なので。

回路

前記のスケッチ例の接続に合わせて、ArduinoとDS1302をつなぎます。
こんな感じ。 f:id:moutakusan:20210627220647p:plain  

で、実際につなぐとこんな感じ。
f:id:moutakusan:20210627234919p:plain

電池はCR2032を使用していますが、DS1302ではトリクルチャージ機能がついており、充電式のボタン電池LIR2032を使うこともできます。
トリクルチャージ機能はデフォルトではOFFになってますので、CR2032を使う場合は特に設定する必要はありません、というか、してはいけません。
ざっくりと書いとくと、下記の図の感じでAddress0x90に0b0101XXXXを書き込めばトリクルチャージ機能がONになります。

f:id:moutakusan:20210627230520p:plain
トリクルチャージ機能の概略図

詳しくはデータシートをご確認ください。
繰り返しになりますが、くれぐれもCR2032ではトリクルチャージ機能を使わないようにご注意ください。

あと、ここで使ってるArduinoは普通に売ってるArduino UNOとかではなくて、ATMEGA328PをArduino化したものです。
詳しくはこちらの記事をご覧ください。

geekyfab.com

動作確認

つないだら、さっそく動かしてみましょう。

シリアルモニターを開き、通信速度をコード上の値(57600bps)に合わせ、書き込み実行アイコンをクリックして書き込みます。
すると、こんな感じでシリアルモニター上に現在の時刻が流れ始めました。

f:id:moutakusan:20210627224746p:plain

ちゃんと動いてそうですね。

RTCということで、30分ほどUSBケーブルを抜いてArduinoの電源をOFFにし、その後再び電源を投入してちゃんと時計が動いているか確認してみます。 f:id:moutakusan:20210627232301p:plain うん、大丈夫そうですね。ちゃんと動いてそうです。

あとは精度がどの程度かは気になるところですが、しばらく時間をおいてみてみないとわからないので、おいおい確認しようと思います。

というわけで、1個当たり$0.62の激安RTCモジュールはそれなりに使えそうなことがわかりました。



今回はこれで終わります。




おしまい。

ESP32とLEDマトリクスでテトリス風アニメーション時計を作る

f:id:moutakusan:20210223235908p:plain:w400




64x32 LEDマトリクスとESP32でテトリス風時計を作ってみました。


この記事では、次のページを参考にしました。

GitHub - witnessmenow/WiFi-Tetris-Clock: A WiFi clock made of falling tetris blocks. For the ESP8266 or ESP32

材料、電源、配線について

材料、電源、配線については次の記事と同様になります。 geekyfab.com

詳しくは上記記事の"今回使った部品"から"LEDマトリックスとESP32を接続する"を参考にしてください。

コード

githubのコードをベースに修正していきます。

まず、無線LANのssidとpaswordの情報を記入します。

// Initialize Wifi connection to the router
char ssid[] = "SSID";     // your network SSID (name)
char password[] = "PASSWORD"; // your network key

次にタイムゾーンを日本に変更します。

//#define MYTIMEZONE "Europe/Dublin"
#define MYTIMEZONE "Asia/Tokyo"

次にOEピンの指定を使っているESP32ボードに合わせて修正します。

//#define P_OE 26 //TinyPICO
//#define P_OE 21 //Huzzah32
//#define P_OE 2 // Generic ESP32
#define P_OE 16 // ESP32-DevKitC

次に使用しているLEDマトリクスに合わせて、PxMATRIX display()を修正します。

// PxMATRIX display(32,16,P_LAT, P_OE,P_A,P_B,P_C);
PxMATRIX display(64,32,P_LAT, P_OE,P_A,P_B,P_C,P_D);
//PxMATRIX display(64, 32, P_LAT, P_OE, P_A, P_B, P_C, P_D, P_E);

また、前回同様にマルチプレクサにディレイをかける対策を追加します。

void setup(){
<中略>
    display.setMuxDelay(1,1,1,1,1)
<中略>
}

最後に使っているESP32ボードに合わせてdisplay.begin()を修正します。

//display.begin(16, SPI_BUS_CLK, 27, SPI_BUS_MISO, SPI_BUS_SS); // TinyPICO
display.begin(16); // Generic ESP32 including Huzzah

これでコードの修正は完了です。
修正後のコードは下記に置いています。

github.com

で、早速ESP32にコードを書き込んで動かしてみました。 f:id:moutakusan:20210223233120g:plain

テトリミノが降ってきて時間を表してくれました。カッコイイ!
今度、LEDマトリクスの周りを装飾して、置時計風にして部屋に飾ってみようと思います。



今回はこれで終わります。


おしまい。

64x32LEDマトリックスをESP32で動かしてみた

f:id:moutakusan:20210126231547p:plain:w400




Aliexpressで64x32LEDマトリックスが安く売っていたので、買ってみました。
P2.5,p3,p4,p5,p6,p8,p10,rgb,p4,64x32,フルカラー屋内ディスプレイ用のledウォールモジュール|full color led display|led displaycolor led display - AliExpress

Adafruitが出してる64x32 RGB LEDマトリックスの互換品だと思われます。
これをESP32とつないで動作させ、ドット絵とかちょっとした映像とかを映してみました。

今回はESP32で64x32LEDマトリックスを動作させるために必要な部材、接続方法、プログラムを紹介しています。
おまけでは「ひげのおじさん」と「うざい犬」のドット絵をLEDマトリックスで映したところを紹介しています。



この記事では以下のサイトを参考にさせていただきました。
GitHub - 2dom/PxMatrix: Adafruit GFX compatible graphics driver for LED matrix panels
RGB LED Matrix With an ESP8266 : 7 Steps (with Pictures) - Instructables

今回使った部品

今回使用した主要パーツは御覧の通りです。

パーツ 購入先
64x32 RGB LEDマトリックス Aliexpress
ESP32 DevKitC 秋月電子通商
5V 10A ACアダプタ (変換コネクタ付き ) Amazon(販売終了)

ACアダプタについて

ACアダプタの購入先は販売終了になっていました。同等性能のACアダプタは例えば、

とか使えるんじゃないかなと思います。安全規格も取ってるっぽいですし。
ただ、こちらは変換コネクタが付属してないっぽいので、別で購入必要かもしれません。
変換コネクタはどこでも売ってますが、例えばコレ(秋月電子リンク)とかコレ(Aliexpressリンク)とかですかね。

もし、電源の扱いに慣れてる方なら

とかでもいいと思います。

64x32 RGB LEDマトリックスについて

外観はこんな感じ。

f:id:moutakusan:20210126222818p:plain
64x32 LEDマトリックス 表面

f:id:moutakusan:20210126222622p:plain
64x32 LEDマトリックス 裏面

向かって左側が信号入力コネクタ、右側が信号出力コネクタ、真ん中が電源コネクタとなっています。
出力コネクタはLEDマトリックスを複数枚連結させるときに使います。

裏面の信号入出力コネクタ部にはピンアサインが記載されてなかったので一応ストアに聞いたところ、下記表をもらいました。

f:id:moutakusan:20201212224721p:plain

Adafruitのものと同じですね。
ピンの説明を加えた表を下に書いておきます。

No. ピン名 説明 No. ピン名 説明
1 DR1 赤データ1 2 DG1 緑データ1
3 DB1 青データ1 4 GND GND
5 DR2 赤データ2 6 DG2 緑データ2
7 DB2 青データ2 8 GND GND
9 A 光らせる行の選択用 10 B 光らせる行の選択用
11 C 光らせる行の選択用 12 D 光らせる行の選択用
13 CLK クロック 14 LAT シフトレジスタのラッチ用
15 OE シフトレジスタのEnable用 16 GND GND

GND以外の1~7ピンにRGBデータ信号を入れて、9~15ピンで制御することでLEDマトリックスに好きな映像を出力することができます。

LEDマトリックスとACアダプタを接続する

ACアダプタとLEDマトリックスの電源ハーネスとは、ACアダプタに変換をかませてこんな感じで接続します。
プラスが赤、マイナスが黒です。注意してください。

f:id:moutakusan:20210126230853p:plain
ACアダプタと電源ハーネスの接続
ハーネスの逆側は普通にLEDマトリックス裏面の真ん中のコネクタに接続です。

LEDマトリックスとESP32を接続する

今回はこちらのLEDマトリックスのライブラリを使用しようと思うので、readmeを参考にしながら下表のように接続していきます。

  • 入力コネクタ-出力コネクタ間接続

    入力コネクタ 出力コネクタ
    DR2 DR1
    DG1 DR2
    DG2 DG1
    DB1 DG2
    DB2 DB1
  • 入力コネクタ-ESP32間接続

    入力コネクタ ESP32 GPIO
    A 19
    B 23
    C 18
    D 5
    LAT 22
    OE 16
    CLK 14
    DR1 13
    GND GND

接続するとこんな感じです。

f:id:moutakusan:20210126234623p:plain
信号線配線

余談ですが、こちらのライブラリの面白いところは、入力コネクタと出力コネクタを接続することですべてのシフトレジスタを直列につなげてしまって、大きな一つのシフトレジスタとして扱ってしまっているところです。

f:id:moutakusan:20210126225547p:plain
つまりこういうこと
ですので、普通ならAdafruitのチュートリアルのようにRGB端子それぞれに信号線を接続する必要があるんですが、こちらのライブラリではDR1だけに信号線を接続するだけで済んでしまいます。

LEDマトリックスをESP32で光らせるためのプログラム

LEDマトリックスのライブラリのgithubからzipでダウンロードしてArduino IDEにインストールしましょう。
zipファイルからのインストールは スケッチ → ライブラリをインクルード → .ZIP形式のライブラリをインストールから行えます。

f:id:moutakusan:20201212170728p:plain
ライブラリのインストール

また、Adafruit GFX Libraryも必要なので、同じ手順でインストールしておきます。

では早速サンプルプログラムを動かしてみましょう。
ライブラリのReadmeのはじめでも見ることができる、"black_lives"を動かしてみます。

LEDマトリックスの仕様によってはサンプルプログラムに修正を加える必要があります。
念のため、修正を加える必要がある可能性のあるところを順番に見ていきます。

まずは、使っているLED Matrixのpixel数に合わせてサンプルプログラムの下記部分をコメントアウト/アンコメントします。

//PxMATRIX display(32,16,P_LAT, P_OE,P_A,P_B,P_C);
PxMATRIX display(64,32,P_LAT, P_OE,P_A,P_B,P_C,P_D);
//PxMATRIX display(64,64,P_LAT, P_OE,P_A,P_B,P_C,P_D,P_E);

今回使用しているのは64x32なので、デフォルトのままでOKです。

次に、LED Matrixのスキャンレイアウトに合わせてdisplay.begin(16)の引数を修正します。
今回使用しているLED Matrixは1/16なので、こちらもデフォルトのままでOKです。

これで準備完了です。
LED Matrixに電源を入れて、ESP32をUSBで接続し、プログラムを書き込んでみましょう。

すると…

f:id:moutakusan:20210126235835p:plain
表示がとびとび

映ってはいますが、表示がとびとびでおかしいですね。
この問題についてはReadmeのTroubleshootingの項にも書いてあって、使われてるマルチプレクサが低速な場合に起こることがあるらしいです。

対策としては、コード上にdisplay.setMuxDelay(1,1,1,1,1)を追加して、マルチプレクサに1us程度のディレイをかければ治るみたいです。
で、display.setMuxDelay(1,1,1,1,1)void setup()内に追加してみた結果がこちらです。

f:id:moutakusan:20210127000147g:plain
ちゃんと動いた!

無事、ちゃんと動かすことができました。
しっかりとフルカラー出ており、遅延も問題なし。
LEDの明るさについてもまぶしいくらいです。

おまけ (ドット絵を表示させてるところ)

ひげのおじさん

githubには髭のおじさんのドット絵のデータが上がっていましたので、表示させてみました。

f:id:moutakusan:20210126231547p:plain
It's-a me!!

UNDERTALEのうざい犬

UNDERTALEのうざい犬を作ってみました。
64x32のドット絵を書いて、変換サイトで変換して作りました。

f:id:moutakusan:20210128004328p:plain
うざい犬

「うざい犬」のデータはこちらです。

// Converted using the following site: http://www.rinkydinkelectronics.com/t_imageconverter565.php
uint16_t static uzaiinu[2048] ={
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0010 (16) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0020 (32) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0030 (48) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0040 (64) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0050 (80) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0060 (96) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0070 (112) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0080 (128) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0090 (144) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x00A0 (160) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x00B0 (176) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x00C0 (192) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x00D0 (208) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x00E0 (224) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x00F0 (240) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0100 (256) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0110 (272) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0120 (288) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0130 (304) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0140 (320) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF800, 0xF800, 0x0000, 0x0000, 0x0000,   // 0x0150 (336) pixels
0x0000, 0xF800, 0xF800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0160 (352) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0170 (368) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0180 (384) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF800, 0xF800, 0xF800, 0xF800, 0x0000, 0x0000,   // 0x0190 (400) pixels
0xF800, 0xF800, 0xF800, 0xF800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x01A0 (416) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x01B0 (432) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x01C0 (448) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF800, 0xF800, 0xF800, 0xF800, 0xF800, 0xF800, 0xF800,   // 0x01D0 (464) pixels
0xF800, 0xF800, 0xF800, 0xF800, 0xF800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x01E0 (480) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x01F0 (496) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0200 (512) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF800, 0xF800, 0xF800, 0xF800, 0xF800, 0xF800, 0xF800,   // 0x0210 (528) pixels
0xF800, 0xF800, 0xF800, 0xF800, 0xF800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0220 (544) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0230 (560) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0240 (576) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF800, 0xF800, 0xF800, 0xF800, 0xF800, 0xF800, 0xF800,   // 0x0250 (592) pixels
0xF800, 0xF800, 0xF800, 0xF800, 0xF800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0260 (608) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0270 (624) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0280 (640) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF800, 0xF800, 0xF800, 0xF800, 0xF800, 0xF800, 0xF800,   // 0x0290 (656) pixels
0xF800, 0xF800, 0xF800, 0xF800, 0xF800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x02A0 (672) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x02B0 (688) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x02C0 (704) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF800, 0xF800, 0xF800, 0xF800, 0xF800, 0xF800,   // 0x02D0 (720) pixels
0xF800, 0xF800, 0xF800, 0xF800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x02E0 (736) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x02F0 (752) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0300 (768) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF800, 0xF800, 0xF800, 0xF800, 0xF800,   // 0x0310 (784) pixels
0xF800, 0xF800, 0xF800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0320 (800) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0x0000,   // 0x0330 (816) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0340 (832) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF800, 0xF800, 0xF800, 0xF800,   // 0x0350 (848) pixels
0xF800, 0xF800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0360 (864) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000,   // 0x0370 (880) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0380 (896) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF800, 0xF800, 0xF800,   // 0x0390 (912) pixels
0xF800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x03A0 (928) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000,   // 0x03B0 (944) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x03C0 (960) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF800, 0xF800,   // 0x03D0 (976) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x03E0 (992) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,   // 0x03F0 (1008) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0400 (1024) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0410 (1040) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0420 (1056) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,   // 0x0430 (1072) pixels
0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0440 (1088) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0450 (1104) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0460 (1120) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,   // 0x0470 (1136) pixels
0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0480 (1152) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0490 (1168) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x04A0 (1184) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,   // 0x04B0 (1200) pixels
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x04C0 (1216) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x04D0 (1232) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x04E0 (1248) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,   // 0x04F0 (1264) pixels
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0500 (1280) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0510 (1296) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0520 (1312) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,   // 0x0530 (1328) pixels
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0540 (1344) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0550 (1360) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0560 (1376) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,   // 0x0570 (1392) pixels
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0580 (1408) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0590 (1424) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x05A0 (1440) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,   // 0x05B0 (1456) pixels
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x05C0 (1472) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x05D0 (1488) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x05E0 (1504) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,   // 0x05F0 (1520) pixels
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0600 (1536) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0610 (1552) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0620 (1568) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,   // 0x0630 (1584) pixels
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0640 (1600) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0650 (1616) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0660 (1632) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,   // 0x0670 (1648) pixels
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0680 (1664) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0690 (1680) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x06A0 (1696) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,   // 0x06B0 (1712) pixels
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x06C0 (1728) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x06D0 (1744) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x06E0 (1760) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,   // 0x06F0 (1776) pixels
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0700 (1792) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0710 (1808) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0720 (1824) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0730 (1840) pixels
0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0740 (1856) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0750 (1872) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0760 (1888) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0770 (1904) pixels
0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0780 (1920) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0790 (1936) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x07A0 (1952) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x07B0 (1968) pixels
0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x07C0 (1984) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x07D0 (2000) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x07E0 (2016) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x07F0 (2032) pixels
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,   // 0x0800 (2048) pixels
};


今回はこれで終わります。
おしまい。


[追記]
こちらで紹介した64x32LEDマトリックスを使って、テトリス風アニメーション時計を作りました。
geekyfab.com
今回紹介した内容からコードを変更するだけで作れるので、おすすめです。

ATMEGA328PをArduinoとして動かしてみる

f:id:moutakusan:20201220234311p:plain:w400

 何番煎じの内容だよって感じですが、ATMEGA328PをArduinoとして動かしてみました。
 とっても簡単でした。


 実装にあたっては下記サイトを参考にさせていただきました。

Arduino as ISP and Arduino Bootloaders | Arduino Documentation | Arduino Documentation

ATMEGA328P を Arduino として使う

Arduinoで作った回路の小型化(Arduino互換機の製作)(2) - しなぷすのハード製作記

回路を作る

 Arduino UNO R3のオリジナルの回路図がこちらになります。

https://www.arduino.cc/en/uploads/Main/Arduino_Uno_Rev3-schematic.pdf

 この回路図のZU4 (ATMEGA328P-PU)がArduinoとしてメインで動いています。
 他にICはU1,U2,U3,U5が乗っていますが、それぞれ12V->5V変換IC、5V->3.3V変換IC、USB->Serial変換IC、オペアンプ(電源選択のためのコンパレーターとLED駆動のためのボルテージフォロワとして使用)であり、純粋にArduinoとして動かす分には不要です。

 というわけで、今回作るArduino互換機の回路はこんな感じにします。

f:id:moutakusan:20201213162110p:plain
Arduino互換機 回路図

 ブレッドボードに乗せるとこんだけ。(動作確認目的なので、C2とSW1は省略)

f:id:moutakusan:20201220234311p:plain
自作Arduino互換機
 

Arduino bootloaderを書き込む

 ATMEGA328PをArduinoとして動かすにはArduinoのBootloaderを書き込む必要があります。
 手元にProMicroがあるので、こちらを使って書き込みをしてみようと思います。

 まずはProMicroにBootloader書き込み用のスケッチ(Arduino ISP)を書き込みます。

f:id:moutakusan:20201220163522p:plain
Bootloader書き込み用のスケッチ
 次にProMicroとブレッドボードで作ったArduinoの回路とを下表のように接続します。
 念のため接続はProMicroにUSBを接続していない状態で行います。

信号 ProMicro Pin名 Arduino(ATMEGA328P) Pin No.
電源 VCC 電源
GND GND GND
SCK 15 19
MISO 14 18
MOSI 16 17
RST 10 1
               ※基板上に印字されているピン名

f:id:moutakusan:20201220180553p:plain
ProMicroを接続したところ (右上のLEDマトリックスは何かの残骸)

 最後に”ツール”タブの”ボード”と”書き込み装置”でそれぞれ”Arduino UNO”と”Arduino as ISP(ATmega32U4)”を選んでから、”ブートローダーを書き込む”をクリックし書き込みを実行します。

f:id:moutakusan:20201220170312p:plain
ボードと書き込み装置を選んでからブートローダーを書き込むを実行

 これでATMEGA328PはArduinoになりました。

スケッチを書き込む

 Arduino UNOにはUSBポートがついていて直接PCと接続してスケッチを書き込めるようになっています。
 これは、UNOに乗っているATMEGA16U2がUSB→Serial変換を行ってくれているからです。
 今回のようにArduinoを自作した場合は、自分でUSB→Serial変換などを用意してATMEGA328Pへ接続する必要があります。*1
 今回は秋月電子通商さんのモジュール基板 AE-UM232Rを使用しました。

akizukidenshi.com

 接続はArduino UNO R3の回路図を参考に次のようにつなぎます。
 RST端子への接続は100 nFのコンデンサが間に入ります。(AE-232R→コンデンサ→ATMEGA328Pの接続になります。)

信号 AE-UM232R Pin No. Arduino(ATMEGA328P) Pin No.
電源 14 電源
GND 7 GND
Tx→Rx 1 2
Rx←Tx 5 3
RST 2→100nFコンデンサ 100nFコンデンサ→1

 接続すると、普通のArduino UNOのようにスケッチの書き込みができます。

 試しにATMEGA328Pのピン19にプルダウン抵抗とLEDを接続してLチカのサンプルプログラムを書き込んでみると、問題なく動きました。

f:id:moutakusan:20201220234030g:plain
自作Arduino互換機でLチカ

 今回作った構成だと1セット当たり300円しないくらいなので、何かをつくったときに気軽に組み込めますね。

 今回はこれでおわりです。




 おしまい。

*1:今時はあんまりない気がしますが、PCにシリアルポートがついていればそちらでもOKです。その場合はRS232Cをブレッドボードに取り付けられるようにする基板とか売ってるのでそちらをお使いください。

Aliexpressでキーボードキットを購入して自作キーボードに挑戦してみる ~スタビライザー取付編~

キーボードを作ったものの、スタビライザーを付けていなかったためスペースキーがすごく押しにくいので、やっぱりスタビライザーを付ける話です。

前回↓ geekyfab.com

スタビライザーを購入

スタビライザーをAliexpressで買うと届くまでに二週間はかかるので、今回は遊舎工房さんで購入しました。こちらのリンクの2Ux4, 6.25Ux1ってやつです。

MXスイッチ スタビライザーyushakobo.jp

で、届いたのでスペースキーのキースイッチを外して早速つけようと思ったんですが、どうにもつかない。
どうやらプレートを付ける前につけるのが正解のようですね…。必要になったらあとからつければいいや、という目論見が外れました…

キーキャップとキースイッチをすべて外す

ということで諦めてキーキャップとキースイッチを全部外すことにします。ホットスワップモデルにしてて助かりました。半田付けしてたらたぶん諦めてました。

キーキャップは取外し用の工具が同封されていたので簡単に外せましたが、キースイッチを外す用の工具は持っておらず、これがけっこう大変でした。というのもキースイッチは前後の爪がプレートに引っかかる形で固定されているからです。
無理やり外そうとするとキースイッチ本体の上蓋が緩み、中のばねが飛び出してパッカーンと四分五裂してしまうかもしれません(体験談)。
なので、キースイッチを外すときは↓の動画のように前後の爪の部分にピンセットなどを交互につっこみ、少しずつ緩めるように外しましょう。

 

f:id:moutakusan:20201128154413g:plain
キースイッチを外すときは慎重に

スタビライザーを取り付ける

すべてのキースイッチを外し終えたら、ケースの蓋を開けて基板にスタビライザーを取り付けます。
スタビライザーを取り付けるときは、下の画像のように、爪がある方を先に基板の穴に挿入して爪を基板に引っ掛けてから、返しのある方をもう一方の穴に挿入するようにしましょう。

f:id:moutakusan:20201128155412p:plain
スタビライザーの付け方

f:id:moutakusan:20201128154807p:plain
基板にスタビライザーを取り付けたところ

スタビライザーを取り付けたら、指でキーキャップが刺さる部分を動かしてみてスムーズに動くことを確認しましょう。
スムーズに動かなければスタビライザーが傾いていることが原因かもしれません。それぞれの足がちゃんと基板の穴に入っているか確認しましょう(これも体験談)。

さて、スタビライザーを全部取り付けたので、プレートをはめて、ちゃんと動くかどうか確認しました。結果…

f:id:moutakusan:20201128160203p:plain
キーが押されたまま戻ってこない…

はい。キーが押されたまま戻ってきてくれませんでした。シフトキーもエンターキーもスペースキーも。

なんで戻ってきてくれないの?

調査の結果、下記が原因であることが分かりました。

① プレートとスタビライザーの金属バーが干渉している。
② そもそもクリア軸のキースイッチの押し返す力が弱すぎる。

①に関してはプレートとスタビライザーの相性の問題かと思います。どうしても解消できませんでした。キーボードキットを買ったショップで売ってるやつなら、干渉しなかったのかしら?次に作ることがあればこちらで試してみます。

s.click.aliexpress.com

②に関しては、スタビライザーを使っているところには赤軸や黒軸といったもっと強めのキースイッチを選べば解消できるかと思います。
が、家にはクリア軸しかなく、新しく注文するのも時間がかかるので、面倒だなと思っていた私はひらめきました。

「ばねを二倍にすれば強さも二倍になるんじゃ…」

ということで、余っていたクリア軸を分解し、中のばねを取り出し、別のキースイッチの中に入れました(ばねの長さがそのままだとめちゃくちゃ入れにくかったので、ばねは半分に切りました)。

f:id:moutakusan:20201129071101p:plain
バラバラにされて、中のばねが半分に切られたキースイッチ。あるいは合成素材。

これによりばねの長さが1.5倍となり、キースイッチが押し返してくる強さも体感1.5倍くらいになりました。
で、早速このスーパークリア軸で動作確認をしたところ、

  • スペースキーは動くようになった!
  • その他キーの動きもよくなったが、時々引っかかって戻らなかった。

という結果になりました。その他キーについてはこの後も頑張りましたが、先ほどの①による抵抗が大きくどうしようもなかったので、スタビライザーは無しにすることにしました。もともとなくてもいいと思ってたのもあります。
スペースキーが問題なく動いてくれるようになっただけでも万々歳です。

f:id:moutakusan:20201129080530g:plain
スペースキーの端を叩いてもまっすぐ押下されるようになった

ということで、これで自作キーボードは完成です。めでたしめでたし。

おわりに

キーボードを組み立てて形にするところまではとっても簡単だったんですが、スタビライザーはめちゃくちゃ苦労しました。
これから作る方はキースイッチを付ける前にちゃんとスタビライザーをつけましょう。スタビライザーなんていらないでしょ、必要になれば後から付ければいいでしょ、とか考えてたら私みたいにとても苦労するかもしれません。

そういうわけなので、同じようにKPrepublic Storeでキットを買う方はkit3か4 (Stabilizer付、switchなし)とキースイッチを別で買うのがいいかなと思います。

s.click.aliexpress.com

s.click.aliexpress.com

kit3/4についてくるスタビライザーなら大丈夫かはわかりませんが、少なくともストアからサポートor返品対応は受けれるかなと思います。むしろ問題ないかだれか人柱になって確認してほしい…

ちなみに、ホットスワップモデルはUS配列限定です。無印の方はJIS配列対応可能らしいので、JIS配列が良い方は無印の方を選びましょう。私も本当はJIS配列が良かったですが、届いてから気づきました。確認不足です。

s.click.aliexpress.com



そういえば使い心地ですが、とーっても軽いです。ほぼ指を乗せるだけで打鍵できる感じ。スムーズに打てるととても気持ちいいです。あとは無刻印、US配列になれる時間が必要です…
 

f:id:moutakusan:20201129081141p:plain
完成した自作キーボード(テンキーレス、クリア軸、US配列、無刻印)

それでは今回はこれで終わります。お疲れ様でした。


おしまい。



自作キーボードを二台のPCで共有するためにUSB切替器を作りました。
geekyfab.com

Aliexpressでキーボードキットを購入して自作キーボードに挑戦してみる ~組立編~

前回の続きで、自作キーボード用のキット(XD87 HS)とキーキャップを組み立てていきます。
最初に書いておくと、めちゃくちゃ簡単でした。

↓前回 geekyfab.com

まずは、購入したケースはベースと蓋がカチッと組み合わされた状態なので、同封されていたピックで開けていきます。

f:id:moutakusan:20201122223912p:plain
ケース

f:id:moutakusan:20201122224012p:plain
同封されているピックを使って外していく

次にケース(ベース側)についてる基板から伸びてるハーネスを、キーボード基板上のコネクタに接続し、キーボード基板をケース(ベース側)にはめます。

f:id:moutakusan:20201122224412p:plain
ハーネスを接続する

f:id:moutakusan:20201122224623p:plain
そしてベースにはめる

次はプレートをケース(蓋側)にはめます。

f:id:moutakusan:20201122224945p:plain
プレートをケース(蓋側)にはめる

そして、基板をはめたケース(ベース側)とプレートをはめたケース(蓋側)をはめ合わせます。

f:id:moutakusan:20201122225438p:plain
ケースをはめ合わせる

次に各ソケットにスイッチを挿入していきます。ソケットは結構堅かったです。ぐりぐりしながら挿入すると上手くいきました。

f:id:moutakusan:20201122225713p:plain
スイッチを挿入していく

ときどき足が曲がっているスイッチがあったので、まっすぐにしてから挿しましょう。

f:id:moutakusan:20201122230222p:plain
ときどき足が曲がっていた

全部挿すとこんな感じ

f:id:moutakusan:20201122230322p:plain
スイッチを全部挿したところ
  私はここで全部のキースイッチが反応するかテストをしました。テストにはこちらのキーボードテスト用サイトを使わさせていただきました、

あとはキーキャップをつけて完成!

f:id:moutakusan:20201122233611p:plain
完成!!
かっこいい!Escの赤とEnterキーのメッセージ刻印がいい感じのアクセントになっています。
ちなみに、「we stand together」の刻印が入ったEnterキーキャップはキットにおまけ?で同封されていました。コロナ禍を共に乗り越えよう的な意味かと受け取り、いいなと思ったのでつけてみました。

  かなり簡単にできたなと思ってたのですが、問題がありました。スペースキーを押すと…

f:id:moutakusan:20201122232959p:plain
スペースキーの端を押すと、スペースキーが跳ね上がる
スペースキーが跳ね上がってしまい、上手く押せません。本来ならこういうことが起こらないようにスタビライザーを付けるのですが、前回書いた通りスタビライザーが付いていないキットを注文してしまったうえ、まぁ大丈夫だろうと思ってスタビライザーを付けずに組んでしまいました。これではさすがに使いにくいのでスタビライザーを付けたいと思います。

ということで、続きます。
geekyfab.com


自作キーボードを二台のPCで共有したい人にはこちらもおすすめ。
geekyfab.com

Aliexpressでキーボードキットを購入して自作キーボードに挑戦してみる ~購入編~

キーボードはずっとPC付属のものを使ってきたんですけど、そろそろちょっといいやつが欲しくなってきました。
それでお店に行っていろいろ触ってみたんですけど、正直あんまり違いわからなかったんですよね。
メカニカルキーボードだと軸の色で押し心地が違うことはわかったし、それは実感できたけど、軸が一緒ならもう全然わからない。

どうせ違いがわからないなら、自分で作るのが愛着がわくしいいかなと思って作ってみようと思ったのが今回の成り行きです。

今回は購入編になります。
組立は次回の記事で書きます。

Aliexpressで自作キーボードキットを選んでみる

調べてみたところ、自作キーボードには以下のパーツが必要なようですね。

  • キーキャップ
  • スイッチ
  • プレート
  • スタビライザー
  • 基板
  • ケース

とはいえ、初めてなのでキットがいいかなと思い、今回はキットを中心に探しました。
で、たどり着いたのがAliexpressで売っていたテンキーレスのXD87 HSキット↓です。

s.click.aliexpress.com

どのキットを買えばいいんだろう

選択肢としてkit1~kit7があり、それぞれの説明が製品ページの下の方に書いてありました。
ざっくりと以下の感じ。

  • kit1とkit2:基板 + プレート + ケース(黒/白)
  • kit3とkit4:基板 + プレート + ケース(黒/白) + スタビライザー
  • kit5:基板 + プレート + ケース + Gateronスイッチ
  • kit6:基板 + プレート + ケース + Gateronスイッチ + LED
  • kit7:基板 + プレート + ケース + Gateronスイッチ + LED + USB type Cケーブル

光らなくていいんでkit5を選択。
あと、kit5, 6, 7には一見スタビライザーが付いてなさそうだったけど、XD87(無印)のQ&Aを見ると下記のようなやりとりを発見しました。

Q: Does kit 6 or 7 come with stabilizers? It is not in the description
A: any kit come with stabs

 こちらにも付属していると期待しておきましょう。 届いたキットを確認したところ、スタビライザーは付属していませんでした。
チャットでショップに聞いてみましたが、やはりついてないとのことです。
Q&Aはあくまでユーザーが回答したものだから、正しい回答が欲しいなら直接聞いて欲しいとのこと。
チャットのレスポンスも早かったですし、他のショップでも次からそうすることにします。

もう一つ迷ったのが、kit5,6,7を選んだ時のケースとスイッチの色指定の方法ですね。 元ページでは

Kit5=XD87 PCB +Stainless steel plate+Plastic Case(Pls mark Black or White one)+90 Gateron Swithces(Pls mark type)

って書いてあるんですけど、注文確定まで選択できるタイミングはなかったです。
なので、注文後にMy Ordersのページの購入製品のところからストアへのメッセージを送れるチャット画面に飛べるので、そこで希望の色を連絡しました。

スイッチの色はどうしようか

Gateronスイッチの色は「キーボードスイッチいろいろ」を参考にさせていただき、Cherry MXの赤軸よりさらに軽いクリア軸というやつを選択しました。

ちなみに、GateronっていうのはCherry MXっていうやつの互換スイッチらしいですね。Cherry MXの特許が切れたから互換スイッチが多く出回るようになっただとか、なんとか。

ホットスワップ

そういえば、今回買ったKPrepublic Storeにもう一つほぼ同じ内容のキットがあったんですけど、こっちはホットスワップ用のパーツが付いてないタイプのようですね。

s.click.aliexpress.com

ホットスワップっていうのは、スイッチを簡単に挿抜できる機構のことみたいです。
ホットスワップ用のパーツがあらかじめ基板に実装されているため、はんだ付け不要でスイッチを付けることができて、製作も楽になりますね。

PCが電源ONのときでも周辺機器を認識できる意味のホットスワップとは別の意味みたいですね。ややこしい。

キットにはキーキャップが付属していないので、キーキャップは別でこちらを購入しました。

s.click.aliexpress.com

届きました

はい。届きました。
キットの方が注文から約2週間、キーキャップの方が約3週間くらいで来ました。

キットの中身はこんな感じ。

f:id:moutakusan:20201117222428p:plain
キーボードキット 左からケース、基板、プレート、スイッチ
他に、ケースを開けるためのピックとおまけのキーキャップが一個、予備のねじが四本ついてました。

基板の表面はこんな感じ。ねこちゃんがかわいい。

f:id:moutakusan:20201117224526p:plain
基板表面
基板の裏面はこんなん。ホットスワップ用の部品が各スイッチの位置に実装されています。
f:id:moutakusan:20201117224715p:plain
基板裏面
基板上にはAtmel製のATMEGA32U4が実装されていました。Arduino LeonardoとかProMicroでおなじみの、USBデバイスとしてふるまえるAVRマイコンですね。
f:id:moutakusan:20201117223848p:plain
マイコンはATMEGA32U4
基板の下の窓みたいになっている部分は内層の銅箔が全部抜かれていて、光にかざすとねこちゃんが透けて見えます。
表面のねこちゃんは、ねこちゃんのかたちに銅箔を抜いて書かれてるみたいですね。
周辺のランドはLED実装用っぽいので、光らせるとねこちゃんが光って見えるのかしら。遊び心が合って素敵です。
f:id:moutakusan:20201117225220p:plain
ねこちゃんが透けて見える

キーキャップはこんな感じ。調子に乗って無刻印にしてしまいました。キーキャップの取外し用の治具も付いてきました。

f:id:moutakusan:20201117225943p:plain
キーキャップ
ちゃんとお行儀よく並んでパッケージングされてました。

次回、組み立てていきたいと思います。



組立編につづく
geekyfab.com