ソースに絡まるエスカルゴ

貧弱プログラマの外部記憶装置です。

【電子回路】同じ回路なのにブレッドボードと発注基板で圧電スピーカーの音が違う場合の原因

 先日ブレッドボード上で動作確認した回路をガーバーデータにして基板として発注したのですが、届いた基板にはんだ付けをして圧電スピーカーの音を鳴らしてみるとブレッドボードでの音と発注基板での音と音程というか、ブザー音に近い音になっていることに気が付きました。
 色々と調べた結果、回路の間違いなどではない別の原因であることがわかり、最終的にはブレッドボードの時に近い音に改善することができたのでその備忘録となります。


 では、始めます。


目次

0:状況説明(前提条件)

 まずは自分が遭遇した状況について説明しておきます。

 使用した圧電スピーカーは以下の表面実装かつ薄いものでした。

 また発注した基板のGNDは全てベタGNDとしてました。以下の画像は例ですが、このようにベタGNDとして銅箔部分の割合が多い形の発注基板となっていました。

 これら薄型表面実装タイプの圧電スピーカーとベタGNDという銅箔が多くの割合を占める発注基板の組み合わせで、ブレッドボードとは違ってビープ音に近い感じの音となってしまっていました。

1:考えられる原因と解決方法

1-1:基板自体や銅箔の共振

 圧電スピーカーの振動が基板やベタGNDの銅箔部分に伝わることで基板や銅箔自体も振動してしまい、音がより高く金属的な音になる場合があります。自分の場合はこれが原因でした。
 これが原因かどうかの判別として、圧電スピーカー部分を指で強く押し込んだりして基板自体が震えないようにしてみる方法があります。
 基板自体が震えないようにしてブレッドボードでの音に近づくようであれば間違いなくこれが原因です。

 解決方法は「圧電スピーカーの振動を基板に伝えないようにする(出来る限り圧電スピーカーを固定させる)」ことです。
 具体的な方法としては、シリコンやゴムなどクッションのようなもので上から押しつけて固定させたり、グルーガンなどで圧電スピーカーを固定させたりします。

 自分の場合はグルーガンを持っていたので、はんだ付けしていない2つの側面について樹脂を流し込んで固めました。こうすることでブレッドボードの時とほぼ同じ感じの音に戻りました。

1-2:波形が鋭くなっている

 金属音やビープ音とは違いますが、音が濁って聞こえたり鋭く聞こえたりする場合は圧電スピーカーに入れている波形自体がブレッドボードの時より鋭くなっていることが原因です。
 ブレッドボード時にはブレッドボード自体やジャンパ線などで微妙に抵抗などが入っているため、それにより波形に丁度良い丸みが入って自然な音になる場合があります。
 対して発注基板の場合はジャンパ線などの抵抗がなくなりより理想的な波形に近づくため、立ち上がりの角度が鋭くなることでキンキンしたような音になる場合があります。

 この場合の解決方法は「ブレッドボードと同じぐらいの値になるよう抵抗やコンデンサを入れる」ということになりますが、発注基板なので直列で抵抗を入れるのはなかなか難しいです。
 コンデンサをであれば並列に接続すればよい(圧電スピーカーの+とーに直接コンデンサをはんだ付けするなどやれなくはない)ので、まずは0.01μF程度のコンデンサを圧電スピーカーの近くに入れて音の変化を見てみて、ちょっとずつ値を増減させてブレッドボードの値に近づくかを試していきます。
 それでもダメな場合はパターンをカットして無理やり直列で抵抗を入れるか、回路を修正して基板を再発注する必要があります。

1-3:はんだ不良

 音が鳴っている時点で問題はないと思いますが、はんだ不良で信号が上手く伝わらずに音が途切れ途切れになったり、変な音になったりする場合もあります。
 はんだ付けがちゃんとできているかの確認をし、はんだ不良があれば再度しっかりはんだ付けを行うとちゃんとした音が出るようになる場合もあります。


 以上が同じ回路なのにブレッドボードと発注基板で圧電スピーカーの音が違う場合の原因と解決方法になります。

 今までは適当に繋げばブレッドボードの上と同じ動きや音をしていたので、今回このようなある意味「物理的な問題」に直面したのが初めてだったのでかなり長い間原因がわからずにいました。
 なんとなく圧電スピーカーを指で押さえてみたことで音を改善するには固定すればよいという結論に至れたのは良かったのですが「回路ではない部分が原因で意図しない動きとなる場合がある」という発想がそもそも出てこなかったので、解決できたのは本当に偶然でした。

 さらに言うとこのようなノウハウは恐らく実体験しないとわからない部類なので、検索してぱっと見つかるかといわれるとかなり難しい気がします。
 なので今回備忘録として記事にした次第です。

 同じようなことで困っている方の助けになれば幸いです。

【ATTINY】ATTINY系マイコンにArduino IDEからスケッチを書き込む

 以前取り上げた290円マイコンボードに使われているCH32V003系は非常に魅力的ですが、エネループなどの電池2本(2.4V程度)では動かせないという注意点がありました。

 比較的安くて低電圧でも動くマイコンを探していたところ、型番にもよりますがATTINY系のマイコンが1.8V~5.5Vの範囲で動かせることを知りました(型番によっては2.7V以上の電源電圧が必要な場合もあるので注意してください)。

 これならエネループ2本でもUSB給電などの5Vからでもどちらでも動かせるので、割と使い勝手が良さそうです。しかしこれもマイコンのみなので自分でUSBのポートから書き込む回路を組む必要があります。
 今回はこのATTINY系マイコンにArduino IDEからスケッチを書き込む方法の備忘録になります。


 では、始めます。


目次

0:ATTINY系の書き込みの仕組みと書き込み回路の概要

 前提としてATTINY系の書き込みの仕組みを軽く説明しておきます。

 ATTINY系のマイコンには「UPDI(Unified Program and Debug Interface)」というピンが必ずあります。例えば以下の14ピンのものであればPA0のところがUPDIになっています(データシートから引用)。

 このUPDIのピン1本で書き込み時のデータ送受信を行うため、ATTINY系マイコンの場合においてはマイコン側は電源VCC、データ送受信のためのUPDI、GNDの3本だけで書き込みが可能となります。

 そのUPDIを使った書き込み回路についてですが、調べるとArduino Unoなどを書き込み器として使用して書き込む場合などが出てきます。ただわざわざ別途Arduino Unoなどを用意するのは手間なのとその購入費もかかるため、適当なUSBシリアル変換器を使った一番楽で簡単な回路が以下になります。

 UPDIピンをTXとRXに分岐させ、USBシリアル変換器のTXとの間に4.7kΩを入れるだけです(厳密にはTXとUPDIの間の合計抵抗が4.7kΩとなるようにする必要があります)。これだけで書き込みが可能となります。

 ATTINYの書き込み回路については、以下のページに詳しく書いてあるので参照してみてください。

 これで書き込み方法がわかったので、次からは実際に書き込んでみた手順を説明していきます。

1:Arduino IDEへのボード追加

 まずはArduino IDEの設定です。ATTINY系のボードを追加します。

 Arduino IDEを起動させてメニューから「ファイル」→「基本設定」をクリックします。

 基本設定の画面が表示されるので「追加のボードマネージャのURL」の右側にあるアイコンをクリックします。

 追加のボードマネージャのURLが表示されるので、以下のURLをコピペして行を追加し、OKボタンをクリックします(※検索すると「http://drazzy.com/package_drazzy.com_index.json」を追加すると書いているところもありますが、現在はどうやら証明書が切れているらしく、自分の場合は入力してもボードをインストールできなかったため代替のURLを設定するようにしています)。

https://raw.githubusercontent.com/per1234/ReleaseScripts/refs/heads/provisional-package-index/package_drazzy.com_index.json

 URLを追加した後、左側にあるボードマネージャのアイコンをクリックして検索欄に「megaTinyCore」と入力して出てきた「megaTinyCore」のインストールボタンをクリックします。

 クリックするとボードのインストールが開始されるのでしばらく待ちます。

 以下のようにinstalledの表示が出ていれば正常にインストールされています。

2:ATTINY系マイコンに書き込むための回路を作成する

 今回は例として先に紹介したATTINY1604-SSNRを使用してLチカをやってみます。Lチカするための出力ピンはPA4を使います。

 回路は以下の通りです。

 0の前提で説明したようにUSBシリアル変換器とATTINYを繋いで後はLチカ用のLEDと抵抗を追加しているだけです。

3:ATTINY系マイコンにブートローダーを書き込む

 回路の準備ができたら、次はATTINY系マイコンにブートローダーを書き込みます。と言ってもATTINY系の場合はブートローダー自体を書き込むのではなく、ピンなどの設定値を書き込むような形となります。

 まずはボードを選択します。上部メニューの「ツール」→「ボード」→「megaTinyCore」を選択して出てきた中から使用している該当のボードを選択します。今回はATTINY1604を使用するので赤枠で囲っているものを選択します。

 ボードを選択した後に再度上部メニューの「ツール」を開いた中にある「書き込み装置」→「SerialUPDI - 230400 baud」を選択します。

 書き込み装置の選択ではSerialUPDIとついてあるものであれば基本は大丈夫だとは思いますが、書き込み速度を気にしない場合は230400 baudを選択しておくのが安心だと思います。少なくとも自分はこの設定で書き込みに失敗したことはないです。

 次に書き込むポートを選択します。「ツール」→「ポート」から書き込み先ポートを選択します。

 その他色々な設定値がありますが、特に変更する必要がなければデフォルトのままで大丈夫です。

 ここまで出来たら「ツール」→「ブートローダを書き込む」をクリックしてブートローダーを書き込みます。

 出力のところに色々とログが出ますが、以下のように「ブートローダの書き込みが完了しました」のメッセージが出ていればOKです。

 ここでエラーなどが出ていた場合は何か回路がおかしいか、ボードの選択が間違っているので再度見直しをしてみてください。

 この章の冒頭にも書いた通り、このブートローダーの書き込みはATTINY系マイコンの設定値のようなものを書き換えているため、初回書き込み時やBODなどの設定を変更した場合にはこのブートローダーの書き込みを行うようにしてください。

4:ATTINY系マイコンにスケッチを書き込む

 ブートローダーの書き込みまでできたら、最後にスケッチを書き込みます。

 今回はPA4ピンでLチカさせたいので、以下のようなスケッチになります。

・ATTINY1604_led_test.ino

const uint8_t LED_PIN = PIN_PA4;

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

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

 スケッチを書き込む場合は上部メニューの「スケッチ」→「書き込み装置を使って書き込む」を選択します。

 実際に書き込むと色々とログが表示され、最終的にエラーなく「Verify successful.」の表示が出ていれば書き込み完了となります。

 ちゃんと書き込めていれば、PA4ピンから繋がるLEDが1秒間隔で点滅します。


 以上がATTINY系マイコンにArduino IDEからスケッチを書き込む方法になります。

 書き込み時にATTINY側のピンが3本だけで済む上、簡単な回路で書き込みもできるのでかなり使い勝手は良いと思います。
 また以前の記事で書いたCH340Kを組み合わせて回路を作れば、USBシリアル変換器と一体化させたATTINYのマイコンボードを作成することも可能です。

 CH32V003系だけでなく、このATTINY系もマイコンの選択肢としては良いのではないかと思います。


参考資料

【電子部品】ICのサイズやピン間隔(ピッチ)の規格について

 今まではRaspberry Pi PicoやESP32などピン間隔が一定のものしか購入してこなかったのですが、最近マイコンを購入した際にピンの間隔(ピッチ)を間違えてしまい、再度別のものを購入するという失敗をしてしまいました。
 同じ型番(末尾が微妙に違う程度)でもピン間隔が違う製品が存在するという当たり前を知らなかったために失敗したのですが、そもそもどうやってそのピッチを確かめれば良いのかがわかりませんでした。
 なので今回はその反省も踏まえて、ピン間隔を間違えないための備忘録となります。


 では、始めます。
 

目次

規格について

 基本的には以下のページ様に書いてある内容が良くまとまっているので、より詳しく知りたい場合はこちらを参照してください。

SOP/SOIC

 SOPは「Small Outline Package」の略でリード(ピン)がIC本体の2側面から出ており、リード形状がL字形のパッケージのことです。

 概形ですが、以下のような形のものになります。

 JEITA規格のものはSOP、EDEC規格のものはSOIC(Small Outline Integrated Circuit)と呼び、どちらも同じ規格を示しています。
 また単なるSOP、SOICという表記だけの場合はピンの間隔(ピッチ)が1.27mmとなります。
 そしてSOPやSOICの前や後に数字が付いていると、その数だけピンが出ているということになります。

 例えばSOP8(SOIC8)であれば「本体から2側面に4本ずつピンが出ていて総数が8本であり、ピンの間隔は1.27mm」ということになります。

SSOP

 SOPの頭にSが付いている場合もあります。この場合はShrinkのSが付いたSOPということになり、本体サイズもピンの間隔もSOPよりもより小さいサイズになります。
 SSOPの場合はピンの間隔がSOPのように決まっていないため、データシートなどで確認する必要があります(体感的には0.65mmが多いですが確認が必要です)。

 例えば以下の2つの製品ページを見てみます。

 どちらも「ATTINY1626」というマイコンですが、ATTINY1626-XURとATTINY1626-SURとハイフン以降の型番が1文字だけ違っています。
 詳しくはデータシートを見て欲しいのですが、注目するところは製品概要のところです。

 ATTINY1626-XURは「取り付けタイプ:面実装・パッケージ/ケース:20-SSOP」、ATTINY1626-SURは「取り付けタイプ:面実装・パッケージ/ケース:20-SOIC」と書かれています。

 つまり、中身が同じマイコンでも微妙な型番の違いで形状が大きく変わってしまうので注意して選ぶようにしましょう。

その他の規格

 この他にもピン間隔が1mmであることが多いESSOPやピンを出さずにマイコン自体に表面実装するようなタイプのVFQFNなど色々な規格があります。

変換基板について

 マイコンのみだと書き込みのできないので、基本的には変換基板を購入してブレッドボード上で扱えるようにすることが多いです。

 その場合は以下のような変換基板を購入するのですが、こちらもSOPなど規格があるので合っているものを購入しましょう。

 ちなみに上記の変換基板は表面がSOP(1.27mm)、裏面がSSOP(0.65mm)と両方に対応しているので使い勝手は良いと思います。


 以上がICのサイズやピン間隔の規格についてです。

 自分の場合はSSOPとSOPを間違えて購入してしまい、SSOPだと手でのはんだ付けが非常に厳しかったのでSOPの方で購入しなおすということになってしまいました。
 頑張ればSSOPでは手はんだできそうではありますが、ピン間隔が狭いのでかなり失敗しやすい感じでした。

 個人的には安定して手はんだできる限界はピン間隔が1mm程度かなという感じがあるので、同じマイコンでも安い方が良いと購入した結果サイズを間違うこともあるので気をつけましょう(自戒)。

参考資料

【UIAPduino】最近話題の290円マイコンボードのUIAPduinoを触ってみる

 最近話題の以下の記事は読んだことがある人も多いと思います。

 290円マイコンボードという安さと手軽さに興味が湧いたため、こちらのショップにて購入してみました。

 今回はその290円マイコンボードを他のマイコンボードと比較しつつLチカまでやってみる備忘録となります。


 では、始めます。


目次

UIAPduinoのマイコンについて

スペック

 UIAPduinoの回路図を見ると「CH32V003F4U6」というマイコンが使用されています。「CH32V003F4U6(CH32V003系)」のデータシートは以下になります。

 大量買いになってしまいますが、マイコン単体でも日本で購入できます。

 スペックを見てみると、クロックが48MHzでプログラムメモリが16K、RAMが2K、I2CやSPIも使えるのでちょっとしたことであれば大体のことはこのマイコンでできそうです。

 ただ電源電圧が3.3Vか5Vとなっているため、乾電池2本で動かす場合などは3.3Vや5Vに昇圧する必要があるため注意が必要です。

 またピンが付属していないため、ブレッドボードを使いたい場合は別途ピンを買ってきてはんだづけを行う必要があります。

Raspberry Pi Picoとの大きさ比較

 安いマイコンボードと言えばRaspberry Pi Picoも出てくるので、並べて大きさを比較してみました(以下はRaspberry Pi Pico 2になっていますがPicoもPico 2もサイズは同じです)。

 ボードの長さとしてはPicoと比較して大体1/3ぐらい短く、横幅も1ピン分短くなっているため、かなりコンパクトで小さいものを作るのには向いていると思います。

環境構築

 ここからは実際に開発環境を構築していきます。と言っても、以下の公式ページにある方法そのままをやっていくだけです。

Visual C++再配布パッケージのインストール

 最初にPCにUIAPduinoを認識させるために、Visual C++の再配布パッケージをインストールします。

 以下のMicrosoftのページを開きます。

 開いたページを少しスクロールした先にある「サポートされている最新の再配布可能パッケージ バージョン」から自分のPCにあったものを選択してクリックします。多くの人の場合は64bitのWindowsのはずなので、X64のものを選択すればよいと思います。

 クリックするとインストーラがダウンロードされます。

 インストーラを起動すると以下のような画面になるので、チェックボックスにチェックを入れて「インストール」ボタンをクリックします。

 インストールが開始されるのでしばらく待ちます。

 インストールが終わると以下のように再起動が求められるので「再起動」ボタンをクリックしてPCを再起動させます。

Arduino IDEの環境構築

 次にArduino IDEの環境構築を行います。
 
 Arduino IDEをインストールした後に起動させ上部メニューの「ファイル」→「基本設定」をクリックします。

 以下の画面が出てくるので「追加のボードマネージャのURL」の右側にあるアイコンをクリックします。

 追加のボードマネージャのURLの画面が出てくるので、そこに以下のURLをコピペで追加します。

https://github.com/YuukiUmeta-UIAP/board_manager_files/raw/main/package_uiap.jp_index.json

 追加したら「OK」ボタンをクリックして画面を閉じます。

 次にArduino IDEの左側メニューの上から2番目にある「ボードマネージャ」アイコンをクリックし、検索欄に「uiap」と入力して出てきた「UIAPduino」の「インストール」ボタンをクリックしてボードをインストールします。

 インストールが始まると、最初の方は止まったかのような表示になりますが、しばらく待っていると以下のようにインストールが終了します。左側のところに「installed」のアイコンが出ていればインストール完了です。

 これでArduino IDEでUIAPduinoを使う準備ができました。

Lチカで動作確認

 環境構築が済んだのでLチカをやっていきます。

ボードの選択

 Arduino IDEの上部メニューにある「ツール」→「ボード」→「UIAPduino」→「Pro Micro CH32V003」と選択していきます。

 ボードにUIAPduinoの選択肢が出てこない場合はボードのインストールができていないので、再度ボードのインストールを行ってみてください。

 選択後、Arduino IDE上部のボード名が「Pro Micro CH32V003」になっていればOKです。

Lチカスケッチの作成

 次に以下の内容をコピペします。マイコンボードにつけられているLEDを1秒ごとに点滅させるという内容です。

#define LED_BUILTIN 2 // 内蔵LEDピン

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);    // ピンを出力モードにする
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH); // 点灯
  delay(1000);                     // 1秒待機
  digitalWrite(LED_BUILTIN, LOW);   // 消灯
  delay(1000);                     // 1秒待機
}

 コピペできたら適当な名前を付けてスケッチを保存します。自分は今回「uiapduino_test.ino」という名前で保存しました。

 

スケッチの書き込み

 スケッチの準備ができたのでボードに書き込んでいきます。

 UIAPduinoついているリセットボタン(以下の赤枠部分)を押した状態でUSBケーブルをPCに繋ぎます。

 USBケーブルをPCに繋いだらすぐにリセットボタンから手を放します。

 手を離した状態でPWRと書かれている青色LEDのみが常に点灯していることを確認します。

 確認できたらWindowsの設定を開き左側メニューにある「Bluetoothとデバイス」→「32V003」が表示されていればPC側でちゃんとデバイスとして認識できています。

 その状態でArduino IDEの上部にある「書き込み」ボタンをクリックします。

 色々とメッセージが表示されるのでしばらく待ち、以下のように「Image written.」の表示が出ていれば書き込み完了となります。

 書き込み完了後、UIAPduinoのリセットボタンを短く1回押すと、ボードがリセットされてスケッチが実行されます。

 今回だと以下のオレンジ色のLEDが1秒間隔で点滅します。


 以上が290円マイコンのUIAPduinoを触ってみた内容となります。

 Visual C++の再配布パッケージが必要だったり、他ボードと違って書き込み時にポートを指定する必要がなかったり、書き込む時にリセットボタンを押して繋げてから離す必要があるなど、色々と手間なところもありますが、290円という圧倒的安さでちょっとしたものを作りたい場合はこのUIAPduinoでも十分だと感じました。

 その低価格故に色々と議論もあるようですが、こういう安いマイコンボードも選択肢の一つとしてあるのは非常に魅力的だと思います。


参考資料

【CH340K】CH340Kを使ってブレッドボード上で自作シリアル変換器を作る

 開発ボードではなくピンだけしかないマイコンを使ってみようと思い立ち、最近触っています。

 PCにUSBケーブルに繋いでマイコンにプログラムを書き込むのですが、マイコン側にはUSBの口がないので間にUSBシリアル変換器を噛ませる必要があります。
 例えば以下のようなものです。

 これは1000円以上とお高めの部類に入るのですがピンソケットもついていて扱いやすいです。またより安いものを探そうとすると大体500円ぐらいはします。
 もっと安くできないかと思っていたところ、CH340Kというシリアル変換ICを見つけました。
 データシートを見ると、あと2個のコンデンサとUSBの口があればUSBシリアル変換器になれるようだったのでブレッドボード上で組んで動かしてみた備忘録となります。


 前置きが長くなってしまいましたが、始めます。


目次

CH340Kについて

 CH340Kの商品ページは以下です。

 先に挙げたシリアル変換器と同じピン出力があるため機能としては十分です。
 中国の会社が製造しているというのと後に説明する独自のドライバをインストールする必要があるため、そこが不安な人は避けた方が良いかと思います。
 ただし価格が70円と格安なので、気軽に自作デバイスにUSBシリアル変換器を載せることもできるようになると思います。

部品

 今回使った部品は以下の通りです。

商品名 個数
CH340K 1
マイクロBメスUSBコネクターDIP化キット 1
0.1μFの積層セラミックコンデンサ 2
ブレッドボード 1
USBケーブル(A to Micro B) 1
ジャンプワイヤ 必要数

 USBの口として以下のUSB Type AのDIP化キットを使えば更に安くできます。

回路図

 回路についてはデータシートに書いてあるそのままを組みます。

 自分なりに整理した回路図は以下になります。

 書き込みたいマイコンによっては使わないピンがあるかとは思いますが、CH340Kから出せるピンを出すと上記のようになります。

 V3ピン部分はVCCを5Vに対応させるためとパスコン用という意味で0.1μFを挟んでGNDに繋いでいます。
 VCCピン部分の0.1μFもパスコン用として0.1μFを挟んでGNDに繋いでいます。

 これらのパスコンがないとUSB機器として認識しないこともあるので0.1μFは忘れずに入れます。

 この回路をブレッドボード上に組み、USBケーブルでPCと繋ぎます。

ドライバのインストール

※2026/03/26追記:CH340Kの機器を接続した状態でデバイスマネージャーを開き1、2分ほど待つとWindows側で自動的にドライバを拾ってきて認識される場合も確認しました。しばらく待ってもデバイスマネージャーの表示が変わらない場合に以下の方法を試してみてください。

 回路ができたので、ドライバをPCに入れます。

 秋月の商品ページにドライバがありますが、かなり古いため公式ページからドライバを入れるようにします(商品ページを引用して加工)。

1:ドライバのダウンロード

 以下のダウンロードページを開きます。

 開くとこのような画面になるので「Download」ボタンをクリックします。

 CH341SER.ZIPファイルがダウンロードされます。

2:ドライバのインストール

 ダウンロードしたCH341SER.ZIPファイルを解凍します。

 解凍したフォルダの中に「SETUP.EXE」があるのでダブルクリックして起動します。

 以下のインストーラが立ち上がるので、左側にある「INSTALL」ボタンをクリックします。

 ドライバのインストールが完了すると以下のダイアログが表示されるので「OK」ボタンをクリックして、インストーラを閉じます。

3:ドライバの確認

 ドライバがちゃんとインストールされているかを確認するために、CH340Kを使用した機器をUSBポートに接続します。

 その状態でデバイスマネージャーを開き、以下のようにポート配下に「USB-SERIAL CH340K」の表示があればドライバが正常にインストールされ、CH340Kを認識できています。

 これでマイコンを繋いでArduino IDEなどでプログラムを書き込むことができます。
 書き込みできなかった場合は回路を見直してTXDとRXDを入れ替えたりなどして試してみてください。


 以上がCH340Kを使ってブレッドボード上で自作シリアル変換器を作ってみた備忘録となります。

 この回路の基板を発注してオリジナルのシリアル変換器を作ってみるのもよいですし、この値段であれば自作のマイコン回路にUSBシリアル変換器も同時に載せるのも検討できて色々と楽しみが広がると思います。


参考資料

【AWS】AWSのIaCはTerraformとCloudFormationのどちらがよいか

 昨年は忙しくて全く更新できませんでしたが、久々の更新です。

 今回はAWSの開発においてTerraformとCloudFormationの両方を使った経験から、どちらを選択した方が良いかをつらつらと書いていこうと思います。

 あくまで「個人的な意見」なので、そこは注意をお願いします。


 では、始めます。


目次

個人的な結論

 早速の結論ですが、個人的には「Terraformを選択した方が良い」と思っています。

 その理由は以下の通りです。

  • 1:Terraformの方がCloudFormationより制限が緩いので柔軟性がある
  • 2:Terraformの方がCloudFormationよりデプロイ時のシェルが簡単
  • 3:Terraformでは出来るがCloudFormationでは出来ない部分がある

 ではそれぞれの内容を詳しく掘り下げていきます。

1:Terraformの方がCloudFormationより制限が緩いので柔軟性がある

 Terraformでは一度のコマンドでデプロイを行う範囲としてルートディレクトリを作成し、その中にTerraformファイルを作成していきます。
 どのようにファイル分けをしても良く、デプロイ時は基本的にTerraform側でデプロイ順番を考慮してデプロイしてくれます。
 ファイル分けも柔軟かつAWSリソースの依存関係もルートディレクトリ単位で意識すればよい程度です。
 また引数の数やファイルサイズについても特に制限はなく、for文のような繰り返しや数が変動するような場合も一応は対応できる書き方があります。

 しかしCloudFormationの方では制限も多く、厳密に依存関係を意識する必要が出てきます。

 CloudFormationではファイル単位でデプロイするのですが、そのファイルのサイズや引数、Outputの数、スタック数(1つのAWSアカウントで実行できるCloudFormationの数)などに制限があります。
 なので大規模かつ複雑なシステムをAWSに構築する場合は必ずこの制限を意識しなければならなくなります。
 ファイルサイズ制限や引数制限により多くのAWSリソースの作成を1つのファイルに集約できないためファイル分割を強制されますし、ファイルを分割しすぎてもスタック数の制限に引っかからないように調節する必要も出てきます。
 また引数となるファイルがJSON形式なため、コメントを引数ファイル自体に書き込めないという問題もあります。

 そしてファイルを分割するということはそれだけAWSリソースの依存関係を意識する必要も出てきます。
「頻繁に変更されるAWSリソースは個別のファイルに分けておいた方が良いが、あまり変わらないAWSリソースはできるだけ1つのファイルにまとめたい。しかしそうするとファイルサイズの制限や引数制限、依存関係を気にしないといけない」というトレードオフの関係を常に頭の中に入れながらCloudFormationの開発を進めないといけなくなります
 この点はCloudFormationの明確な弱点だと思っています。

 ちなみに以下がAWS公式のCloudFormationの制限一覧となります。

 またCloudFormationにはif文に相当する書き方はできますがfor文に相当する書き方が存在しないため、個数が変動するような場合については都度都度個別のCloudFormationのファイルを作成する必要があります。

 このようにCloudFormationは制限が多くなっていますが、Terraformには基本的にファイル制限や引数制限などがなくFor文などの機能もあるためTerraformの方が優位だと思います。

2:Terraformの方がCloudFormationよりデプロイ時のシェルが簡単

 次にデプロイ時のコマンドについてです。

 1で書いたようにTerraformではルートディレクトリ単位でデプロイをします。
 Terraformはルートディレクトリ内に移動して以下のコマンドを実行するだけでデプロイもアップデートも可能です。

terraform apply <option>

 どのルートディレクトリでもこのコマンドを実行すればデプロイが可能なので、デプロイ自動化のシェルを書く場合はルートディレクトリの順番だけを意識したシェルを書けば良いので比較的簡単に書けます。

 一方CloudFormationはファイル単位でデプロイを行うため、少なくともデプロイするファイルの順番は意識する必要があります。
 加えてCloudFormationはテンプレートとして別のCloudFormationファイルを読み込む(Terraformでのmodule呼び出しのようなものの)場合、一度package化するためのコマンドを実行する必要もあります。

 一般的なCloudFormationのデプロイの流れとしては以下のようになります。

# package化
aws cloudformation package <option>

# package化したファイルをデプロイ
aws cloudformation deploy <option>

 通常であればディレクトリよりもファイルの方が細かく分かれて数が多くなるため、CloudFormationのデプロイ自動化のシェルを書く場合はファイルのデプロイ順番をTerraformの時よりも厳密に管理して書く必要があります。それにpackage化するコマンド自体が失敗する可能性もあるので、そのエラー処理も必要になってきます。

 また差分を取得する際も同様です。

 Terraformでは以下のコマンドだけで差分を取得できます。

terraform plan

 しかしCloudFormationでは以下のようにpackage化した後にChangeSetというものを作成し、その後に差分を取得するコマンドを実行する必要があります。

# package化
aws cloudformation package <option>

# package化したファイルのChangeSetを作成
aws cloudformation deploy --no-execute-changeset <option>

# 差分を取得
aws cloudformation describe-change-set <option>

 こちらも差分取得の前に2つのコマンドが実行されているため、それぞれにおいてエラー処理を入れる必要も出てきます。

 このようにデプロイや差分を取得するにもCloudFormationの方がコマンドの数が多くなりますし、その分デプロイ自動化のシェルを書く場合にはエラー処理などを書かなくてはならなくなるため、Terraformの方がデプロイ時のシェル作成はかなり楽になります。

3:Terraformでは出来るがCloudFormationでは出来ない部分がある

 ここが一番致命的な部分になるかと思います。
 いくつかあるのでそれを書いていきます。

CloudFormationはVPC Endpoint(Interface)のIPアドレスが固定できない

 例えばVPC Endpoint(Interface)のS3を「IPアドレスを固定して」作成したい場合があったとします。

 その場合、Terraformであれば以下のように書けばTerraformの記述方式で作成できます。

resource "aws_vpc_endpoint" "s3_endpoint_01" {
  service_name        = "com.amazonaws.ap-northeast-1.s3"
  vpc_endpoint_type   = "Interface"

  # --- 省略 ---
  subnet_configuration {
    ipv4      = "10.0.16.20"
    subnet_id = aws_subnet.subnet_01.id
  }
  subnet_configuration {
    ipv4      = "10.0.32.20"
    subnet_id = aws_subnet.subnet_02.id
  }
  # --- 省略 ---
}

 しかしCloudFormationの場合は以下のVPC Endpointを作成する際のCloudFormationの設定値にあるようにIPアドレスを指定する項目がありません。

 なのでこの場合はCloudFormationのみで完結できなくなり、この部分だけTerraformを使用するかAWS CLIを使ってコマンドだけで無理やり作成させるようにするかなどの回避策が必要となります。

CloudFormationは現在のAWSリソース作成状態との差分を取得するのが面倒

 Terraformではplanのコマンド自体が「現在のAWSリソース作成状態とIaCコードの差分」を取得してくれるため、AWSマネジメントコンソール上で手動で変更があったとしてもちゃんと「現状のAWS」との差分を取ってくれます。

 しかしCloudFormationでは2でやったChangeSetとの比較では「過去に実行した内容との差分」となるため、AWSマネジメントコンソール上で手動で変更があった場合と乖離が発生します。
 なのでCloudFormationでは以下のように「過去に実行した内容と現状のAWSとの差分」であるドリフトを取得する必要があります。

# ドリフト検出開始
aws cloudformation detect-stack-drift <option>

# ドリフト結果確認
aws cloudformation describe-stack-resource-drifts <option>

 ドリフトで過去に実行した内容と現状のAWSで差分がないかを確認し、その後に変更したCloudFormationコードとの差分を確認する流れになるため、かなり手間がかかります。

 Terraformであればplanコマンドだけで済むことが、CloudFormationでは現状との差分とコードの差分の両方を取得して確認する必要が出てきます。

CloudFormationは作成済みのAWSリソース情報を取得できない

 Terraformであれば既に作成されているAWSリソースについてdataを使って検索しそのIDなどを取得することが可能ですが、CloudFormationでは既存のAWSリソースについて検索して情報を取得することができません。

 CloudFormationにはTerraformでいうところのOutput機能しか存在しないため、Outputされていない情報については一切CloudFormation側で取得することができなくなっています。そのため、先に例として挙げたVPC EndpointでのIPアドレス固定などをする場合は、TerraformやAWS CLIなどで作成した時に必要な情報をParameterStoreなどに保存しておいて、その値をCloudFormationで取得して使用するという形にする必要があります。

 これらのように、Terraformに出来ることがCloudFormationでは出来ないということが色々とあります。


 以上がTerraformとCloudFormationを両方触ってみた自分なりの見解です。


 色々と書いてきましたが、冒頭に書いた通りAWSのIaCはTerraformを選択した方が良い」というのが個人的な結論です。

 もちろんCloudFormationはAWS公式ツールですしデプロイに失敗した時にはロールバックが実行されて自動的に元に戻るなど利点もありますが、実際に両方開発を経験した自分としては開発の負担が増える(意識したり考えることが多くなる)のと機能的に出来ない部分があるのが致命的な弱点だと思っています。

 小規模であまりトリッキーなことをしなくて変更するのが変数の値ぐらいというものであればCloudFormationを採用しても良い気はします。が、大規模だったりVPC EndpointのIPアドレスを固定する必要があるようなトリッキーな構成にする場合はCloudFormationを選択するとかなりつらくなるので選択しない方が良いと思います。


参考資料

【AWS/Terraform】ALBやNLBのポートと証明書の設定について

 ALBやNLBをTerraformで作成する際、ターゲットグループ、アタッチメント、リスナーでポートやプロトコルが複数出てきてどれがどう扱われるのかかなり混乱することがありました。

 なので今回はその辺りのポートやプロトコル、証明書についてまとめた内容になります。


 では、始めます。


1:ALBやNLBのTerraformコード例
 TerraformでALBやNLBを作成するコードを書くと、基本的には以下のようになるかと思います。このまま単体ではデプロイできないのであくまで各設定値がどうなっているかの例として挙げているので注意してください。

# LB本体
resource "aws_lb" "example_lb" {
  name               = "ecample-alb"
  internal           = true
  load_balancer_type = "application" # NLBの場合はnetworkを設定
  security_groups    = [aws_security_group.lb_sg.id]
  subnets            = [aws_subnet.subnet1.id, aws_subnet.subnet2.id]
}

# LBターゲットグループ
resource "aws_lb_target_group" "example_tg" {
  name     = "example-tg"
  port     = 80
  protocol = "HTTP" # ALBの場合はHTTP or HTTPS、NLBの場合はTCP or TLSなどを設定
  vpc_id   = aws_vpc.main.id
}

# LBターゲットグループアタッチメント
resource "aws_lb_target_group_attachment" "example_tg_attachment" {
  target_group_arn = aws_lb_target_group.example_tg.arn
  target_id        = aws_instance.example_ec2.id
  port             = 8000
}

# LBリスナー
resource "aws_lb_listener" "alb_listener" {
  load_balancer_arn = aws_lb.example_lb.arn
  protocol          = "HTTPS" # ALBの場合はHTTP or HTTPS、NLBの場合はTCP or TLSなどを設定
  port              = "443"

  # 証明書が必要な場合は以下を設定
  ssl_policy        = "ELBSecurityPolicy-2016-08"
  certificate_arn   = "arn:aws:iam::123456789:server-certificate/test_cert"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.example_tg.arn
  }
}

 protocolの設定がaws_lb_target_groupにもaws_lb_listenerにもあり、portの設定ではaws_lb_target_groupにもaws_lb_target_group_attachmentにもaws_lb_listenerにもあるのがわかると思います。

 これらについてどう使われるかを次に説明します。
 

2:ALBやNLBのポートと証明書の扱い
 例えば以下のように通信する場合を考えます。

EC2 → ALB → Fargate

 この時、それぞれ以下のようになります。

・ポートの扱い

通信経路 説明
EC2 → ALB リスナーで設定したポートのみ受け付ける。
ALB → Fargate アタッチメントのポートでターゲットに送信。アタッチメントのポートが設定されてない場合はターゲットグループのポートでターゲットに送信。

プロトコルや証明書の扱い

通信経路 説明
EC2 → ALB リスナーで設定したプロトコルで受け付ける。リスナーで設定した証明書を使用。
ALB → Fargate ターゲットグループで設定したプロトコルでターゲットに送信。証明書はターゲット側を使用。

 つまり、リスナーでプロトコルとポートと証明書を設定した場合はそのプロトコルとポート番号とリスナーに設定された証明書でリクエストを受け付けます。そしてターゲットに送信する際にはリスナーに設定した証明書は使わずに「ターゲット側の証明書を使用」して「アタッチメントのポートで上書きされたポート」で送信されるということになります。
 アタッチメントのポートが設定されていない場合は、ターゲットグループのポートで送信されます。

 なので1に挙げた例を考えると、以下のようになります。

  • 受付はポート443のHTTPSでリスナーに設定した証明書を使用
  • 送信はアタッチメントのポート8000が使用され、HTTPで送信される(HTTPなので証明書はなし)

 また1のアタッチメントを削除してターゲットグループのprotocolをHTTPS、portを443とすると以下のようになります。

  • 受付はポート443のHTTPSでリスナーに設定した証明書を使用
  • 送信はターゲットグループのポート443を使用したHTTPSで送信され、ターゲット側の証明書を使用


 以上がAWSにおけるALBやNLBのポートと証明書の設定についてになります。

 わかっている人からすると当然な内容かもしれませんが、インフラにもAWSにも不慣れな自分としてはかなり混乱して何をどう設定すればいいのかがわからない時があったのでまとめた次第です。
 同じように混乱している人の助けになれば幸いです。


・参考資料