前回は単一チャンネルの変換を行ったが今回はDMAを使ったものをやって行こうと思う。
とりあえずADCおさらい
ADCは変換終了フラグ(EOC)を見てDRレジスタを見に行くことで変換データを得ることができる。
上記の図のようにシーケンスの終了でもフラグが立つ(EOS)
二つのフラグを見てソフトウエア的に行うこともできるがタイミングがずれるとDRのデータが上書きされてしまう。
それを防ぐ仕組みにオーバーランというものある。
これはデータを保護できるがそのあとの変換値は破棄されてしまうので注意が必要だ
そのため複数チャンネルを変換する場合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つがあり
ワンショットは一回きりの転送になります
一方サーキュラは連続的にADCのCH変換が終わるたびにDMAリクエストが生成するので連続的なストリームが構成できる。
さっそくやっていく
CubeMXでADCを設定していく。
ADCの詳細設定
DMAの設定
ここでアドレスのインクリメントにチェックを入れておくといい感じに配列に格納できる。
コード
参考までに動いたコードを示しておく
ADC終了時に呼ばれるコールバック内にprintfを入れてUART出力している。
まとめ
3日間ぐらいかけてADCやってみたんだけど何だかんだDMAを使ったのが一番簡単だねぇ
DMAといったら結構難しいイメージあったけどCubeMXのおかげでほとんど設定してくれるのでかなり楽ですね。
3日間一緒に検討してくれたリアルテック先生には感謝です。
http://realteck-blog.netlify.com/2017/04/08/f031%E3%81%AEadc%E9%80%A3%E7%B6%9A%E5%A4%89%E6%8F%9B%E3%81%8C/realteck-blog.netlify.com
2017/5/18追記
お恥ずかしいお話なのですがオカダといろいろやってて複数のADCを使うとMainにブレーク立てても帰ってこないと2日間ぐらい悩みました。
んで上記の図のようにこいつのADCには低速チャネルもあるんです。
12ビット精度で変換する場合最低でも14サイクルかかります
高速の場合Cubeで19.5サイクルにすればよいのですが低速の部分も19.5にしてました・・・・・ほんと雑魚wwww
なので皆さんはこんなバカなことで時間とかしちゃだめですよ!
直すとちゃんと動く
追記 2019/3/12
自分の場合上記のコードで動いたのですがshyachiさんより指摘があったので載せときます
/* USER CODE BEGIN 2 */ if (HAL_ADC_Init(&hadc2) != HAL_OK) { Error_Handler(); } if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK) { Error_Handler(); }
の2つの関数はMX_ADC2_Initにてコールされているので呼ばなくて良さそうです。
特にHAL_ADC_ConfigChannelの方は呼ぶと2ch変換できなくなるケースも有るとか
動かない人はこの辺もお試しください