macOSからPi Picoを使う - その10 [Pi Pico]
最近になってやっとcmakeがちょっとわかった。cmakeでは.oも.aも.soもコンパイル後リンク前のファイルは全部libraryと呼ぶのね。僕はずっと勘違いしてた。.cのソースファイルは全部共通の扱いで、libraryといえば.aとかだとばかり思い込んでいた。そのせいでファイルによってinclude pathが通らなかったりしてた。このせいで長いこと悩んでた。
cmakeのチュートリアルは僕にはなんだか難しすぎて、読んでも全然頭に入らないし。これは英語だからかそれとも僕の頭が悪いのかそれとも書き方が悪いのか。あ、日本語があったんだ。でも英語だから難しかったわけではないみたい。残る可能性はあとふたつ....
ADCはフリーランの状態で、ある周期で、その間ずっとデータを足し算して最終的に回数で割ることで平均化して報告する。えらそうにオーバーサンプリングなんて言い方がある(Fourier変換から言うと正しい言い方だけど)。ADCは12ビット幅で500kspsなので足し算レジスタにuint32_tを使うと約2秒で溢れてしまう。
人間が理解できるスピードだとせいぜい10msecぐらいなので、そこから2秒ほどまでの周期が選択できればいい。
また、PWMはADCの分解能とあわせてwrap値を4096にしよう。ベースクロックが125MHzなのでPWMの周波数は30.5kHzほどになる。ローパスは1次なのでこの一桁下3kHzぐらいをカットオフにしよう。それでもデューティ50%のときは30.5kHzが0.3Vぐらい漏れることになる。これが嫌ならローパスではなくてノッチにすべきなんだろうけど、そこはオーバーサンプルでカバーということにしよう。従ってオーバーサンプルの周期はPWM周期の整数倍にするのが望ましい(けどとりあえずまあいい)。
ホストからはユーザが
ADCの入力インピーダンスがどのくらいなのか、datasheetにみつからなかった。試しにたまたま手にした640kΩの抵抗のいっぽうを3.3Vにさわって反対側をADCの入力にさわってADCを読んでみると6ビット目が立つぐらいにしかならない。10kΩのオーダの入力インピーダンスということになって結構低い。
手元にあまり大きなコンデンサを持っていなかったので、しょうがない、ローパスはオペアンプでバッファしよう。つまり回路としては というようなのにする。反転型のオペアンプ回路の帰還に入れるのが普通(その方がゲインも取れる)だろうけど、抵抗が2本になるのでめんどくさいし、ゲインは正確に1のほうがこの場合望ましい。またPWMのデューティを反転する必要もないし、不安定な電源の方を基準にしなくてもよくなる。GNDがどのくらい安定かというとよくわからないけど。
たまたま手持ちであった抵抗とコンデンサとTL082で、このオペアンプは両電源でないと動かないので古い基板からMAU106を剥がしてUSBの+5Vから±5Vを作った。半田付けがめんどくさいのでブレッドボードへ。Pi Picoを一緒に乗せるとギリギリになった。 これでPWMのデューティを1ビットずつ増やしていってそれをADCで読んだらどうなるかをみてみる。
シングルショットでの精度は期待していないので、多めにA/Dして平均を取る(オーバーサンプリング)。
それほど高速の信号は外には出ていないけど、ブレッドボードなのでS/N的には厳しいかもしれない。せめてPWM出力も速めのトランジスタでバッファしたほうがいいかもしれない(でもそれだと反転するのでローパスでまた反転にすることになるな)。
一方で、PWMの電源とADCの基準電位が共通なので、電圧変動はキャンセルされてしまって良く見えることになる。
このコードもgithubにあげた。
ちょっと長くなったので、この解析は次回に。
cmakeのチュートリアルは僕にはなんだか難しすぎて、読んでも全然頭に入らないし。これは英語だからかそれとも僕の頭が悪いのかそれとも書き方が悪いのか。あ、日本語があったんだ。でも英語だから難しかったわけではないみたい。残る可能性はあとふたつ....
10 お試しコード
これまでの- ADC
- PWM
- multicore
- PWMをローパスで平滑化してアナログレベルを作る
- それをADCで読む
- それぞれを別のコアで実行する
ADCはフリーランの状態で、ある周期で、その間ずっとデータを足し算して最終的に回数で割ることで平均化して報告する。えらそうにオーバーサンプリングなんて言い方がある(Fourier変換から言うと正しい言い方だけど)。ADCは12ビット幅で500kspsなので足し算レジスタにuint32_tを使うと約2秒で溢れてしまう。
人間が理解できるスピードだとせいぜい10msecぐらいなので、そこから2秒ほどまでの周期が選択できればいい。
また、PWMはADCの分解能とあわせてwrap値を4096にしよう。ベースクロックが125MHzなのでPWMの周波数は30.5kHzほどになる。ローパスは1次なのでこの一桁下3kHzぐらいをカットオフにしよう。それでもデューティ50%のときは30.5kHzが0.3Vぐらい漏れることになる。これが嫌ならローパスではなくてノッチにすべきなんだろうけど、そこはオーバーサンプルでカバーということにしよう。従ってオーバーサンプルの周期はPWM周期の整数倍にするのが望ましい(けどとりあえずまあいい)。
ホストからはユーザが
- ADCの積分周期
- PWMのデューティ
ADCの入力インピーダンスがどのくらいなのか、datasheetにみつからなかった。試しにたまたま手にした640kΩの抵抗のいっぽうを3.3Vにさわって反対側をADCの入力にさわってADCを読んでみると6ビット目が立つぐらいにしかならない。10kΩのオーダの入力インピーダンスということになって結構低い。
手元にあまり大きなコンデンサを持っていなかったので、しょうがない、ローパスはオペアンプでバッファしよう。つまり回路としては というようなのにする。反転型のオペアンプ回路の帰還に入れるのが普通(その方がゲインも取れる)だろうけど、抵抗が2本になるのでめんどくさいし、ゲインは正確に1のほうがこの場合望ましい。またPWMのデューティを反転する必要もないし、不安定な電源の方を基準にしなくてもよくなる。GNDがどのくらい安定かというとよくわからないけど。
たまたま手持ちであった抵抗とコンデンサとTL082で、このオペアンプは両電源でないと動かないので古い基板からMAU106を剥がしてUSBの+5Vから±5Vを作った。半田付けがめんどくさいのでブレッドボードへ。Pi Picoを一緒に乗せるとギリギリになった。 これでPWMのデューティを1ビットずつ増やしていってそれをADCで読んだらどうなるかをみてみる。
シングルショットでの精度は期待していないので、多めにA/Dして平均を取る(オーバーサンプリング)。
それほど高速の信号は外には出ていないけど、ブレッドボードなのでS/N的には厳しいかもしれない。せめてPWM出力も速めのトランジスタでバッファしたほうがいいかもしれない(でもそれだと反転するのでローパスでまた反転にすることになるな)。
一方で、PWMの電源とADCの基準電位が共通なので、電圧変動はキャンセルされてしまって良く見えることになる。
このコードもgithubにあげた。
10.1 測定結果
測定はPWMのデューティの値(levelレジスタの値)に対して、ある一定期間の- 平均値(整数部)
- 最小値
- 最大値
- 変換エラーの回数
10.1.1 256回の平均の場合
256回A/D変換してそのデータの平均の整数部を結果にする。変換は500kspsでできるので余計なことをしなければ1秒間に2000個データが取れる。4096点でもあっという間に終わる。 PWMのlevelを0〜4096と変化させてADCの読みの平均値、最大最小値をプロットしたのがこれ。 0付近と最大値付近は暴れている。詳しくみるとPWMのパルス数で0〜16のところは平均値が跳ね上がっている。0が最小値の符号なしなのでノイズが乗ると普通こうなるが、上は最後の2、3個ぐらいが暴れるだけになっている。電源付近は強いらしい。ちょっと長くなったので、この解析は次回に。
2021-06-20 21:05
nice!(0)
コメント(0)
コメント 0