読者です 読者をやめる 読者になる 読者になる

ガレスタさんのDIY日記

電子回路、Web、組み込み、自作エフェクターを語るblog

C言語可変引数マクロについて

マイコンのDEBUG関数関連見てて

#if defined(DEBUG_ENABLE)
#if defined(DEBUG_SEMIHOSTING)
#define DEBUGINIT()
#define DEBUGOUT(...) printf(__VA_ARGS__)
#define DEBUGSTR(str) printf(str)
#define DEBUGIN() (int) EOF

#else
#define DEBUGINIT() Board_Debug_Init()
#define DEBUGOUT(...) printf(__VA_ARGS__)
#define DEBUGSTR(str) Board_UARTPutSTR(str)
#define DEBUGIN() Board_UARTGetChar()
#endif /* defined(DEBUG_SEMIHOSTING) */

的な”・・・”を多用したやつ見かけて調べてみた。

可変引数と呼ばれているみたいだ。

gccでは __VA_ARGS__ という記述でできるみたい。

printfなんかは引数が変化するのでラッピングするのは結構難しいけどこれ使うと結構いい感じにできるっぽい

STM32でADCをやってみる2(DMAを使ったレギュラ変換)

前回は単一チャンネルの変換を行ったが今回はDMAを使ったものをやって行こうと思う。

とりあえずADCおさらい

ADCは変換終了フラグ(EOC)を見てDRでジスタを見に行くことで変換データを得ることができる。

f:id:gsmcustomeffects:20170409035725p:plain

上記の図のようにシーケンスの終了でもフラグが立つ(EOS)
二つのフラグを見てソフトウエア的に行うこともできるがタイミングがずれるとDRのデータが上書きされてしまう。

それを防ぐ仕組みにオーバーランというものある。
これはデータを保護できるがそのあとの変換値は破棄されてしまうので注意が必要だ

f:id:gsmcustomeffects:20170409040231p:plain

そのため複数チャンネルを変換する場合EOCフラグをトリガとしてDMAでレジスタ→メモリを実現したほうがソフト的な介在がなくなるので楽に処理できる。

マニュアル曰く(RM0316 345ページ)

変換されたチャネルの値は特定のデータレジスタに格納されるので、複数のチャネルの変換には
DMA の使用が便利です。これによって、ADCx_DR レジスタにすでに格納されているデータの損失を防ぐことができます。
DMA モードが有効なとき(ADCx_CFGR レジスタの DMAEN ビットがシングル ADC モードで 1 にセットされている場合、またはデュアル ADC モードで MDMAが0b00 以外に設定されている場合)、
各チャネルの変換後、DMA リクエストが生成されます。これにより、変換データを ADCx_DR レジスタからソフトウェアで選択した場所へ転送することができます。
これにもかかわらず、DMA が DMA 転送リクエストを時間内に処理できなかったためにオーバーランが発生した場合(OVR=1)、ADC は DMA リクエストの生成を停止し、新しい変換に対応するデータ
は DMA によって転送されません。
これは、RAM に転送されるすべてのデータを有効とみなすことができることを意味します。

要するにCH変換ごとにDMAリクエストが生成されるということ。
オーバーランが発生するとDMAがとまる。
OVRMODを適切に処理するか頻繁に止まるようならDMAを時間内に処理できるように変換自体の速度を下げておくなど工夫が必要だ。

DMAのモードには

  • DMA ワンショットモード(DMACFG=0)
  • DMA サーキュラモード(DMACFG=1)

の2つがあり

ワンショットは一回きりの転送になります

f:id:gsmcustomeffects:20170409042453p:plain

一方サーキュラは連続的にADCのCH変換が終わるたびにDMAリクエストが生成するので連続的なストリームが構成できる。

f:id:gsmcustomeffects:20170409042740p:plain

さっそくやっていく

CubeMXでADCを設定していく。

f:id:gsmcustomeffects:20170409043833p:plain

ADCの詳細設定

f:id:gsmcustomeffects:20170409043955p:plain

DMAの設定

f:id:gsmcustomeffects:20170409044035p:plain

ここでアドレスのインクリメントにチェックを入れておくといい感じに配列に格納できる。

ハードウエア

前回と同じでこれにPA_5、PA_4を追加して2CHを読んでいる点だ

f:id:gsmcustomeffects:20170408045403j:plain

コード

参考までに動いたコードを示しておく
ADC終了時に呼ばれるコールバック内にprintfを入れてUART出力している。


動作例

Teratermではこんな感じに2CH読めている。

f:id:gsmcustomeffects:20170409050119p:plain

Expressionではこんな感じ

f:id:gsmcustomeffects:20170409050225p:plain

まとめ

3日間ぐらいかけてADCやってみたんだけど何だかんだDMAを使ったのが一番簡単だねぇ
DMAといったら結構難しいイメージあったけどCubeMXのおかげでほとんど設定してくれるのでかなり楽ですね。

3日間一緒に検討してくれたリアルテック先生には感謝です。

realteck-blog.netlify.com

STM32でADCをやってみる1(レギュラ変換)

今回は一番簡単なやつやってみます。

やったことを雑に書くとこんな感じ

  • レギュラ変換
  • ADC2の1CHだけを使った連続変換
  • PB4ピンにポテンショメータをつなぎそれを読む
  • 変換値をUARTでTeratermに表示する。

CubeMXでの設定

今回は一個しか読まないのでこのようにPA4にアサインする
一応UARTも使ってるのでそれも設定する

f:id:gsmcustomeffects:20170408045027p:plain

各種設定はこんな感じ

f:id:gsmcustomeffects:20170408045044p:plain

要所要所説明挟むとこんなもん

ADC_Setting

設定 機能 説明
mode independent mode 独立モードで動く、その他速度を上げるDualModeがある
Clock Prescaler 非同期、1~4分周 読んで字のごとくクロック分周器
Resolution 6~12bit ADCの分解能
Data Alignment 右詰め、左詰め データの詰め方
Scan Coversion Enable,Disable 一回のシーケンスですべてのCHを変換するかどうか
Continuos Conversion Mode Enable,Disable 連続変換
Dis Continuos Conversion Mode Enable,Disable 不連続変換
End Of Conversion Selection シングルごとかシーケンスごとか両方か 変換終了フラグの有無 データシートEOCフラグの部分読んだほうが図もあってわかりやすい
Low Power Auto Wait Enable,Disable 自動遅延変換モードの有無。ADC オーバーランが発生するリスクのある低周波数のクロックで動作しているアプリケーションのパフォーマンスを最適化する場合に有効

ADC_Regular_Conversion_Mode

設定 機能 説明
Enable Regular Conversion Enable,Disable レギュラー変換の有効化
Number of conversion 変換数 チャンネル数分設定できる
External Trigger Conversion Source ソフトおよびタイマートリガ 変換トリガソースの設定。 タイマーとかに連動できる
External Trigger Conversion Edge 立ち上がりか立下りかソフトか 外部割り込みの設定

Rankの設定

RankはCH分だけ個別設定ができる

設定 機能 説明
Channel チャンネル数分設定できる 設定したいCHを入れる
SamplingTime 1.5~601.5サイクル サンプリングタイム
OffsetNumber 1~4 オフセットするCHの選択
Offset 1~4056 変換値のオフセット

ハード構成

一応紹介しておく
POTの2番ピンをA3ピンにつないでいるだけだが

f:id:gsmcustomeffects:20170408045403j:plain

コードを書いていく

参考までにコードを貼っておく