自作Arduino 　CH340Eを使用したUSBシリアル変換の失敗・改善レポート

# 1 背景（お急ぎの方は2章へ）
社会人になり、正式にハードウェア開発者として働き始めてから早数カ月が経ちました！先輩社員の凄すぎる技術を日々見ていくうちに私も自作で技術を伸ばしていきたと感じています。
その一つとしてArduinoの自作を始めてみました。単に作るのではつまらないので、できる限り自分で部品を選定、無線機能などを付ける等の**マイ設計**を加えました。
今回はそんな開発を進める中で個人的に詰まった点をご紹介いたします。問題原因と解決策もそうですが、その解決に至ったロジックも説明していきますので読んでいただけたら幸いです。

# 2 準備
マイArduinoを作るためにはマイコンが必要です。今回はArduino UNOで使用されているAtmega328P-PUを使用しました。
(下画像[Atmega328P-PU](https://akizukidenshi.com/catalog/g/gI-03142/))
![写真1](https://akizukidenshi.com/img/goods/L/I-03142.jpg)
初めにマイコンにブートローダーを書き込みます。
ブートローダーの書き込みに関しては簡単でQiitaにもたくさんあるので調べてみてください。参考資料をいくつか置いておきます。
* [【Arduino】ATmega328P単体でスケッチを動かしてみる！その① ブレッドボードでの接続&ブートローダーの書き込みなど](https://burariweb.info/electronic-work/arduino-atmega328p-alone-operate.html#ATmega328PArduino)
* [自作Arduinoを作ろう](https://qiita.com/Potewo/items/33380a4b2d787284895a)

ブートローダーの書き込みが終わったら次にUSB接続でPCから直接プログラムを書き込みができるようにします。USBシリアル変換器でUSB形式の信号（D-とD+のシリアル信号）から、マイコンが受け取れるUART信号に変換する必要があります。
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1100334/4fd036a2-479d-4e49-b340-0f856d16e79d.png)

そこで必要になるUSBシリアル変換機を探しました。今回選定したのは[CH340E](https://akizukidenshi.com/catalog/g/gI-13543/)という安価なUSBシリアル変換ICです。これでボードができたらすごくお得だと思ったのです（まさかこれが原因になるとは...）。
![シリアル変換](https://akizukidenshi.com/img/goods/L/I-13543.jpg)
ICとマイコンを調達できたのでUSB接続ができる回路を作成しました。

**回路図はこんな感じにできました（できてません）**。
![回路図前.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1100334/87741401-9088-3f54-a616-7ff720efd729.png)

この回路図は[CH340E USBシリアル変換モジュール Type－C](https://akizukidenshi.com/catalog/g/gK-14745/)を元に作成しました。私の保有部品の関係からUSB端子はMicro bに変更しています。
お気づきの方は分かると思いますが、**この回路図は間違っていますのでこの回路図は参考にしないでください。**
そしてこれを早速接続してやってみようとしたのですが...

# 3 問題発生
上図のように回路を組んで書き込みをしてみた結果、エラーが出て書き込めませんでした...
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1100334/87e6ac73-6091-3ca4-50c2-e26d41eb9f1a.png)

過程は後にして原因を二つ挙げます。
* **RTSとDTRの違い**
* (ブートローダーの書き込み間違い)

です。重要なのは1つ目のRTSとDTRの違いです。2つ目の原因については筆者の勘違いによるものでした。

# 4 解決策
1つ目の原因を解決するために最初の回路図から下の回路図へと変更しました。変更部分は赤枠でハイライトしています。
これにより、無事書き込むことができました！！
![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1100334/ce8acda6-6953-63dd-ac90-ee4c3457b17f.png)


# 5 問題分析
では、ここからは問題原因を深堀していきます。問題原因のRTSとDTRの違いについてのみここでは記載します。

まず、この記事で重要なRTSとDTRについて簡単に説明します。RTSとDTRはRS232Cという接続規格の信号線となります。マイコンとのシリアル通信において同期を行うために必要な通信線です。

そもそもこれらの通信線が何の意味、どのような信号を出すのかという事について触れておきます。シリアル通信、中でもUARTなどは送信側と受信側でTXとRXによって結ばれ、データをやりとりします。しかし、いつどのタイミングで通信を始めるかを定義しないと通信はうまくいきません。
そこでこれらのRTSやDTRを使って送信側と受信側で意思疎通を取って「通信するよ」という事を伝えて通信を始めるのです。

## DTR(Data Terminal Rady)
次に端子一つ一つについて説明します。DTRは「端末準備完了」を意味します。送信機（今回はIC）や受信機（今回はAtmega328）が、通信相手に動作準備ができている事を伝えるものです。

この端子はDSRと対になるもので、DTRが通信相手に信号を出力してDSRが受け取ります。RS232C機器が通信する時に使います。

## RTS(Request To Send)
RTSは「送信要求」です。送信機が受信機にデータを送りたい、送っていいよの時に信号を出力します。
※注釈要参照 [^1]
信号を元に戻すとデータを送る事を中断します。

この端子はCTSと対になるもので、RTSや通信相手に信号を出力してCTSで受け取ります。この2つの信号線を使うのものをCTS/RTSフロー制御と言います。

## 同じような働きをしている...!?
そうなんです。どちらも同じような働きを持ち、通信を開始する前や送っている間に信号を送る動作をします。しかし、同じものではありません。今回の原因はこの信号線の違いによるもので、マイコンが求めていたのはDTR、しかしICが出せる信号はRTSだったのです。

また、調べた感じ（参考資料参照）、同じ通信方式でも使う通信系によってルールが変わっていることが分かりました。
※これらの信号線について詳しく知りたい方はRS-232Cの規格等調べてみてください。

# 6 必要な信号とCH340Eの出力信号
調べてきたように、欲しい信号線ではないものがICから出力されています。また、同じ名称・働きの信号線でも用いられる信号は使用される通信系によって変化することがあります。つまり、実際に出ている波形を観察してみないと何も言えません...
今回の場合も同様にAtmega特有のルールが存在する可能性があり、信号波形を実際に見てみる必要があります。（データシートをよく読めば解決できますが、ここではあえて見ない方法で解決してみます。）

そこで、Atmegaに必要なリセット信号（UART開始信号）とCH340Eが出力している信号とを比較してみましょう！
ってことで実際に調べてみました！

## 欲しい信号編
### 調べ方
市販のArduino UNOを使って測ります。写真のようにArduino UNOに搭載のAtmega328P-PUのRESETピンに、直接オシロスコープのプローブを押し込むことで測定することができます。**ここでピンソケットのRESETピンを使用するとうまく測れません**。また、接続する際には隣の端子とのショートに注意してください。
![04.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1100334/46ea116c-e191-e579-83a3-6d3f47da0df0.jpeg)

この状態でArduino IDEを起動し、USBでArduino UNOとPCを接続します。そして任意のスケッチを書き込みます。すると、RESET信号が計測できます。

### 結果
波形を計測した結果が以下の通りでした。横線のカーソルをデータシートに記載のAtmegaのRESETピンの電圧降下スレッショルド電圧値（MAX値）に設定しています。そしてその線と信号波形が重なる2つの点を縦線の2つのカーソル線で示しています。
2つのカーソル線の間Δxは2.14msということが分かりました。この情報と、<ins>データシートに記載のRESETピン最低パルス時間</ins>を考慮すると、必要な信号としては2.5µsから約2.14msの短パルスであることが分かりました。

![uno_seikirst.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1100334/1531fa50-b8b1-9d0b-2e22-2327154e6628.png)

## CH340Eの出力信号編
では次に、CH340Eが出している信号を見ていきます。

### 調べ方
調べ方はArduino UNOの時と同様に、調べたい信号が出力されるCH340EのRTS#ピンにプローブを直接指します。ですが、波形を取得するには動作させる必要があります、そのためにはUSBケーブルを接続できるコネクタを接続して動作させます。

今回の回路図ではちょうど右のAtmegaを取り除いたものに変えます。さらに画像のようにオシロスコープのプローブを当てます。
![08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1100334/5b8f4914-ae19-dcde-a0b3-58503dd316a8.png)

### 結果
取得波形はこのようになりました。
![ch340erst.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1100334/7f2335f1-bed2-cc41-d4f0-bbef237c03c5.png)
横軸カーソルは先ほどと同じようにスレッショルド電圧で合わせています。2つの縦軸カーソル間Δxは3.120sです。
見ての通り波形はまるっきり違います。後々分かることですが、この波形はUARTの通信が終わると立ち上がります。つまり、通信状態の時に常にLoの信号が出ているのです。

## 結論
皆さんお分かりなように求められている信号と使用しているICの出力信号とでは異なることが分かりました。
さて、波形が異なることが分かったのでここからどうするかですが、方法としては３つあると思います。

1. Atmegaが要求している信号を出力できるICに変更する
1. 同じICを使用して出力信号を変化させる
1. Atmega側を変える（マイコンの変更、設定の変更）

１と３においてはコストをさらにかけなければいけませんし、新しい部品を使うならその部品のデータシート等を読んで仕様を学ばなければいけません。
そんな感じで2番を選んでみました。では出力信号を変化させるのはどのようにすればよいのでしょうか？

# 7 波形変化
ここからは電気回路の話に移ります。結論から申しますとここではズバリ！！**ハイパスフィルタ**を使用します。
ハイパスフィルタとは高い周波数の信号を通して、低い周波数の信号を通さない回路のことを言います。
ハイパスフィルタの説明については詳しくお話ししていると本題とずれてしまうのでここでは割愛しますが下の資料をみてください。

* [CRハイパスフィルタの『伝達関数』や『周波数特性』について](https://detail-infomation.com/cr-high-pass-filter/)
* [ローパスフィルタとハイパスフィルタを学ぶ](https://www.aps-web.jp/academy/ec/539/)

正直とても奥が深いです。

では、ハイパスフィルタを用いた解決方法のロジックを説明します。

まず必要な信号としてはUART通信開始前に短パルス（短Loパルス）を受け取りたい。
↓
今ICから出てくる長いパルス信号の高周波成分、つまり立下りの部分だけをAtmegaに流したい
↓
ハイパスフィルタで高周波成分だけをAtmegaに通す
![06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1100334/50f2336f-e15a-b682-36d6-79901e2d017f.png)

ではハイパスフィルタを作るにはどうすればよいかですが、それはコンデンサをUSBシリアル変換ICとマイコンの間に直列に挿入するだけです！
![07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1100334/14b49a59-6956-4da4-c163-5bb95db751e1.png)

これによって高周波信号を取り出すことができます。

## 補足　パラメータ設定
ここからは私もよくわかっていない部分と回路のちょっと深い話になるので補足としました。コンデンサを使うことはここまで読んで頂いてお分かりかと思いますが、では**容量値**はどのくらいになるのかを検討する必要があります。

ハイパスフィルタのカットオフ周波数は次の式で計算できます。
```math
f_c=\frac{1}{2\pi RC}
```
今回抽出したい周波数はf=1/1Δ=467Hzなので、高調波成分も含めると余裕を取って5倍の2.5kHzを透過させられるハイパスフィルタを設計したいです。

【ここからは不確定】ここで、Rの値なのですがICの入力インピーダンスを仮に10kΩ~と考えると、カットオフ周波数からCは0.0062µF以上あれば良いとなるので求めやすい市販の0.1uFを使用します。
※この考察は正しいか不明なのでよければ分かる方教えてください...
考えの元は以下の資料を参考にしました。
* [LCフィルタ設計技法](http://www.azuma-sano.x0.com/electric/filter/filter.pdf)

# 8 高電圧保護
はい、ではこれで完成...ではないんですね。
実はこの状態だと危ないです。
回路図を見ると、パルスが立ち上がった瞬間は予想通り立下りの部分だけがマイコンに流れます。しかし、パルスが戻った時にはどうでしょう？コンデンサには電荷が充電されており、急な電圧変動が起きた場合にはコンデンサの放電によりRESETピンに過電圧がかかってしまいます。

よって、問題のロジックは次のようになります。
RTS#ピンがHiに戻る＝5Vになる
↓
コンデンサがRTS#ピンとマイコンのRESETピンの両端の電位差を5Vに留めようとする
↓
RESETピンにはRTS#の5Vとコンデンサが維持しようとする電圧の5Vの10Vがかかる

この対策のためにRESETピンとVCC(5V)の間にダイオードを挿入します。

これにより、次のようロジックで対処することができます。
RTS#ピンがHiに戻る＝5Vになる
↓
コンデンサがRTS#ピンとマイコンのRESETピンの両端の電位差を5Vに留めようとする
↓
RTS#の5Vとコンデンサの5Vにより、RESETピンには10Vがかかろうとする
↓
**ダイオードにより、Vccより高い電圧成分はVccに流れて5Vが維持される。**

実際にはダイオードの順方向電圧の0.6V~がVccに上乗せされた状態になった時にRESETピンにかかる過電圧成分が除去されます。

# 9 結果
ではここまでの話を整理して回路を作ってみるとこんな感じになりました。
追加した部分は赤くハイライトしています。
![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1100334/9fd8de94-7a99-a363-aacb-5bc189609d4c.png)

これでRESETピンとRTS#ピンのところの波形を見てみると...
![09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1100334/cce0c439-ee78-edd6-5766-9221c0b8e9ef.png)
無事立下りの部分だけがマイコンに伝わっていることが確認できました！
この状態でArduino IDEで書き込み動作を行ったところ無事書き込むことができました。本当に良かったです！！

ちなみに、このRTS#ピンの信号とマイコンのUARTのRXピンの波形を見たところ、下図のようになっていました。
![05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1100334/c28f1759-477b-4ec2-876e-ee1d5bdd54f9.png)
一番右側のRXの立下りパルスがマイコンのループ動作にあるシリアル通信の波形であると思います。その通信が始まる直前にRTS#ピンのパルスが戻っていますので、ICはUARTの通信が行われている時に常に信号が立ち下がるものであるということが分かりました。

# 10 最後に
はい、いかがだったでしょうか？極論言うと自作Arduinoを設計する段階から仕様を決めて、部品を選定しなければいけないということです。今回の場合はハイパスフィルタを使用することで対応しましたが本来の対応の仕方はマイコンの仕様にあったICを選べということですね。

CH340Eはとても安いので何も考えずに選んでしまいました。まさか、こんなに苦労するとは...でも一つ成長できました！

そしてこのレポートを書くことで「なぜなぜ分析」ができて問題原因の明確化、対策の検討と実施ができました。時間はかかりましたが初めのうちはしょうがないですね。今後は同じ問題に引っかからないように対処していきます！

**実際のところは様々なネット情報を見て、それを参考にして真似と確認したりする作業が大半だったのであんまり自分で考えた内容ってのは薄いのが本当のところです。**

何か間違っている点、不明点などございましたら本記事のコメントに書いていただけると幸いです。では良い電子工作ライフを！

# 参考資料

* [Atmegaのデータシート](https://akizukidenshi.com/download/ds/microchip/atmega328.pdf) 
* [CH340シリーズのデータシート](https://akizukidenshi.com/download/ds/wch/ch340.pdf) 
* [RTSについて](https://lipoyang.hatenablog.com/entry/20130530/p1) 
* [Arduinoに書き込めない問題を修正する方法[not in sync]](https://memoteki.net/archives/157) 
* [USB<->シリアル (USB to TTL)](https://ht-deko.com/arduino/usb2serial.html) 
* [RS232Cについて](https://www.sacom.co.jp/lecture/rs232c.html) 
* [Arduino互換機を作りたい](http://kutsushita-neko.cocolog-nifty.com/blog/2013/09/arduino-e10d.html) 
* [avr-netino - AddAutoReset.wiki](https://code.google.com/archive/p/avr-netino/wikis/AddAutoReset.wiki) 
* [arduinoの勉強部屋](http://kuman2600.web.fc2.com/a_kyuu/o18arduino.html)



[^1]: RS-232Cの規格では送りたい時に信号を送る（Hiにする）とされていますが、実際のところはその通信系によってルールは変化している場合があります
参考：https://lipoyang.hatenablog.com/entry/20130530/p1