STM32のADCとDMAについてです.
net検索しても以下のissueは見かけないんだけどなんでだろ?
①まずはフツーのAD変換と割り込み周期の関係
↓STMのADCには1ch変換するsingle modeと、多ch変換するscan modeがあります.
この例ではサンプリング周波数1kHzですから、出力data数に1個か3個かの違いはあれど、変換完了割り込みは1kHz周期です.HAL_ADC_ConvCpltCallback()が変換完了割り込みです.
ただし、scan ch毎に割り込ませることも可能で、その場合の割り込み周期は3kHzになる.でもあまり高速な割り込みは嫌いです.
↓②次に、DMAと組み合わせて動かしたいとき
STM32をちゃちゃっと設定して自走させるとこれになっちゃうことが多いです.でもこれだったら①と同じ逐次割り込みですからDMAする意味が薄いですよね?
うぇ~ん、もう眠いので明日続きを書きます
ーーーー
翌朝
健康診断のためM先生のところへ来ています。
実はSTM32F401を使っていた時は、DMA②になってしまって「冴えないDMA」と思いつつも、fs=1kHzだったので放置しました。
しかし今STM32H723のADCをfs=32kHzで動かそうとしているので、DMA②だと忙しくてもう嫌になりました。
演算で32k→4kに間引きます。位相回転を避けるため。
検診終わった、お腹すいた〜
↓
サイゼリヤ。中目黒民はサイゼが好きな様で常に満席。ホールの人の忙しさは中目黒最強なのではと、この店に来るといつも思ふ。
ドリア食ってたら飲み会の誘いが来て、久しぶりの人が来るというので行きたかったが、奥さんがパートに出る日なので欠席になりました。残念です。
お釣りを貰うと新札がちらほら混じるこの頃ですが、新札未対応のマシンがそこら中にあるので新札だと「チッ」と思います。
ーーーー
帰宅して一息ついたのでSTM32 ADC/DMAの件に戻ります.
↓DMA③を実現できた様子です.
条件は、、、
・TIM15で32kHzのADC trigger
・ADCはTIM15 triggerでharware自走
・DMAで1024wordのメモリに積む
・1024word積んだら割り込み
・ゆえに割り込み周期は32Hz
・オシロ表示はHAL_ADC_ConvCpltCallback()でport toggleしたもの
設定はこの5つから成ります.
1)ADC init
2)DMA init
3)TIM15 init
4)main()
5)HAL_ADC_ConvCpltCallback()
1)ADC init
static void MX_ADC1_Init(void){
↓IN5のみの1ch入力なのでscanはdisableです
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
↓ADC自身がグルグル自走するmodeにしない 重要
hadc1.Init.ContinuousConvMode = DISABLE;
↓IN5のみなので1回変換
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DiscontinuousConvMode = DISABLE; ←これ知らない
↓TIM15でトリガされる
hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T15_TRGO;
↓データをDMAに送り、DMAの送り先はリングバッファ
hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;
↓IN5の設定
sConfig.Channel = ADC_CHANNEL_5;
↓ADC速度最速だが遅くしてもいいんじゃね?
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
↓IN5はシングルエンド(差動ではない)
sConfig.SingleDiff = ADC_SINGLE_ENDED;
DMA②かDMA③かの設定の違いは、ContinuousConvMode です.注意しましょう!
2)DMA init
STM32CubeMXの画面です.お好みでどうぞ.DMA1 stream1がADC1の担当です.
static void MX_TIM15_Init(void){
↓STM32H723を最高clockで動かすと、TIM15 clock=275MHzになります.275MHz/8593=32kHzになります
htim15.Init.Prescaler = 0;
htim15.Init.CounterMode = TIM_COUNTERMODE_UP;
htim15.Init.Period = 8592;
htim15.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim15.Init.RepetitionCounter = 0;
↓自走してグルグル回る
htim15.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
↓トリガ=updateにするとカウンタフルでトリガが出る=32kHz
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
4)main()
int main(void){
uint32_t ADCfifo[1030]; DMAの積み先確保
HAL_TIM_Base_Start_IT(&htim15); TIM15スタート
↓ADC/DMAスタート 1024回まとめてDMAしてね
HAL_ADC_Start_DMA(&hadc1, &ADCfifo[0], 1024);
while (1) {
}
5)HAL_ADC_ConvCpltCallback()
DMAに1024個積み終わったら呼ばれる割り込み関数です.
HALライブラリでweak宣言されているので、自分のsource codeに同名で記述するとそれが採用されます.
いろいろな信号処理を記述すればいいでしょう.
以上です.
かしこ
>DMA③
返信削除https://blog.haru3.me/posts/20220913-stm32-timer-based-adc/
STM32で一定周期のADC変換を行いたい
が、これじゃないでしょうか?
※確かに、よく出てくるのは、DMA②(ch数=サンプル数)ばかりですね。
HAL_ADC_Start_DMA(&hadc,(uint32_t *)adcData, count)
で、count≠ch数 でも、OKのようです。(count > ch数 のときは、同じチャンネルで繰り返しサンプルする模様)あと、「タイマーを併用する」のが、ミソみたいです。
(タイマーを使わなくても出来るが、バス使用率?が上がって、CPU処理が遅くなる模様。参考文献のところに書いてある)
これじゃぁ
削除Continuous Conversion=Disabled
これがポイント!
↑の参考文献の、
削除DMAで連続変換するときの鍵、によると
・continuous conversion enableにしてDMA continuous request enableにしておくとDMA割り込みが入りまくることに注意.ADCが終わるたびにDMA走る.
にしておくと、「勝手に次のADC&DMAが走る」みたいですね
(勝手に「リングバッファ処理」と、同じことしてくれるので使い方によっては、こっちの方がいいみたいですが。)
※CubeMX って、ホントによく出来てるな
CubeMXがあるからSTM32を使っています.無料でサンクス
削除細かい設定は型番によって微妙に違っていて、たとえばH723には、
DMA continuous request enable
が無かったりするんです
面食らいます