記事の数が100件を超えていました

いつの間にか、記事の数が100件を超えていました。

ただし、過去にブログを始めて三日坊主になって、 というのを繰り返したものを全部ここにまとめたので、 「ブログ始めました」という記事が10%くらい占めている気がします・・・

まあ、それも含めて私らしさ、ということでしょう

PWM

A-D変換でやってみたいことはあるのですが、先にPWMを試してみます。

ごく単純にLEDの明るさを変えるプログラムを作ります。 PB4にLEDがつながっていて、PB4はTIM3のCH1でもあるので TIM3を使ってPWMを実現します。

大量にあるPWMの情報の中から、今回参考にしたのはこちら。 参考にしたというより、ほぼそのままかと。

ropot.hatenablog.com

まずタイマの設定はこんなの。PB4につながっているChannel1をPWMにしています。 Clock Sourceをinternalに変えるのかと思っていましたが、 disableのままで問題ないようです。ソースを追いかけたところ、 disableというよりdefaultと言った方が良いかも。

タイマのクロックが16MHzで、PWM周期が1KHzになるよう 設定しています。せっかくの16ビットタイマを生かすには 周期を10KHzにしたほうがよかったかもしれません。

f:id:yamamoto-works:20190512115651p:plain

channel1のpulseの値をプログラムで書き換えることになります。 これでソースコードを生成して次のようなプログラムを作りました。

f:id:yamamoto-works:20190512120335p:plain

__HAL_TIM_SET_COMPAREというマクロがあるのを 知っているかどうかが勝負の分かれ目? という感じです。 CubeMXも面倒な処理を自動生成してくれるところは うれしいのですが、このようにレジスタ(今回はCCR1レジスタ)に 値を代入するだけで、しかもどのレジスタを操作すれば良いか 私が知っている場合は面倒なだけの存在に感じてしまいます。 人によって感じ方も違うので、なかなかバランスが難しいとも思いますが。

検索していると、このpulseの値をDMAで設定する、ということも できるようです。まあ今回はここまで。

A-D変換 DMAの利用

今回は驚異的な進み方ですね。

次に、DMAを使ってみます。 A-D変換が完了したとき、これまではHAL_ADC_GetValueを呼び出して変換結果を取り出していましたが、わざわざ呼び出さなくても変数に格納してもらえるとうれしいわけです。DMAを使えばそれが可能になります。

なお、DMAはA-D変換専用の機能ではなく、さまざまな場面で利用できます。

さすがにADCの設定も今までのようにすべてデフォルト値というわけにはいかず、いくつか設定が必要になります。まずScan Conversion Modeをenableにしています。今回おこなうことに限ればこの設定はなくてもかまいませんが、今後のことを考えてenableにしています。

DMA Continuous Requestsもenableにしています。これは必須です。この設定を行わないと、DMAが途中で止まってしまいます。

それから、ADC_Regular_ConversionModeの設定を行っています。今回はチャネル一つですが、複数チャネルをA-D変換するときはここに並べて書くことになります。

f:id:yamamoto-works:20190511192223p:plain

本題のDMA設定は次のようにしました。 今回の使い方ではリングバッファとか作らないので ModeはNormalで、 Memoryのアドレスをインクリメントしています。 今回はチャネルが一つしかないので、インクリメントは不要ですが、 複数チャネルのときのためにこうしています。

f:id:yamamoto-works:20190511192845p:plain

プログラムは、相も変わらず次のような感じにしました。 HAL_ADC_Start_DMAでA-D変換を開始しています。 単発の変換にしてあり、変換結果がDMAで書き込まれたら その値を表示して1秒待って再度A-D変換を起動しています。

f:id:yamamoto-works:20190511193233p:plain

このadcIntrCountという変数は、DMA割り込みが呼ばれるたびに +1しています。何回も呼ばれるのかと思ってこうしたのですが、 1回しか呼ばれないようです。

実はこの状態にたどり着くまでに相当試行錯誤しました。 先人の知恵も見たのですが、私が行いたいことを見つけることが できず、遠回りした印象です。 その分、理解が深まっていれば良いのですが・・・

A-D変換 変換完了割り込みの利用

次に、変換完了割り込みを使います。

前回とは、CubeMXでADC1の割り込みを有効にする点が 大きく違います。 Preemption Levelは、以前のタイマの時と同様にデフォルトの0から1に変更します。

ソースコードは、割り込みハンドラではフラグadcDoneFlagを立てるだけで、 メインルーチンでA-D変換結果を取得して表示しています。 前回のポーリングが、割り込み処理に置き換わっただけですね。

f:id:yamamoto-works:20190511110018p:plain

という感じで、全然問題なく進みましたよ、という風に書きましたが 最初はなぜかUSB通信ができなくなり、いろいろ試しているうちに 通信できるようになってその後再現しない、ということがありました。 何か問題がありそうな気がします。

A-D変換 基本編

続いて、A-D変換に取り組みます。 検索してみると何か難しいところがあるようなので 注意が必要ですね。 簡単なところから、順番に進めていきます。

先人の知恵によると、 A-D変換を起動するトリガ、A-D変換完了時の割り込み、 A-D変換結果のDMA転送の3つがポイントのようです。 そこで、まずは基本編として最低限のところからやってみます。 つまり、トリガは手動、割り込みなし、DMAなし、ということです。 このあたりを参考にしました。

www.controllerstech.com

CubeMXで、ADC1を使うように設定します。 ここではADC1のIN10を選びました。 パラメータはすべてデフォルト値です。

f:id:yamamoto-works:20190509222559p:plain

A-D変換結果をUSB経由で表示するように、 以前に書いたのと同じ手順でUSBの設定を行いました。

yamamoto-works.hatenablog.com

ソースコードは次のようにしています。 まずA-D変換を開始して、変換完了をポーリングで待って、 変換結果を取得して、 その値をPCに表示して、 1秒待つ、ということを繰り返しています。

f:id:yamamoto-works:20190509222928p:plain

動かしてみると問題ないようです。 基本編だから動いて当然ですね(フラグ)