暮らしに役立つ情報満載の当ブログの目玉といえば、アニメと回路でございます.
今回は、STM32H723のADC1/ADC2のdual modeで18ch scanをし、DMAで3000サンプル積むまで返ってくるな~っ! 帰って来たらcallbackよろしく、という仕組みを実装する方法です.
暮らしに役立ちます.
本件については、netにまとまった情報が見当たらず、「無理」「ガセ」とか書いてる情報もあるかと思へば、尻切れトンボめいたページなど、どうにもケリがつかない雰囲気が漂います.
以下では、STM32CubeMXを活用してdual ADC 18ch DMAのやり方を解説します.
もしかしたら20chまで出来るのかもしれませんが、18chしかやってません.
ーーーー
dual modeで18chをやりたい事情いろいろ.
STM32H723V(100pin)ですと、外部pinの不足により、18chは無理と考えています.
STM32H723Z(144pin)ですと、18ch pin assignが可能でした.
H723にはADC1/ADC2/ADC3が載っています.
1と2は16bit、3が12bitなので、1と2を使います.
ADC1単独で最大16入力をassignできますが、やりたいのは18chなので1と2を併用しなくちゃいけません.
ADC1:ADC2=16ch:2chでよいかと思いますが、とある事情により9ch:9chにします.つまり、ADC1が9ch scan、ADC2が9ch scanということです.
1と2がassign可能なADC pinは重複してたりしてなかったり、番号が飛んでたりと統一感が無いです.この表のassignで9:9にしました.ADCのRank設定のところでこの表に従います.
IN# 重複1/2 1と2のassign
2 o o 1 2
3 o o 1
4 o o 1
5 o o 1
6 o o 1 2
7 o o 1
8 o o 1
9 o o 2
10 o o 2
11 o o 2
14 o o 2
15 o o 2
16 o 1
17 o 1
18 o o 2
19 o o 2
DMAは必須です.毎sample soft処理なんつう雑魚仕事をCPUにやらせるのは忍びない.
DMAに関連して、デュアルモードというのが便利そうです.
フツーにADC1/ADC2のDMAを考えると、bufferを2本用意して、DMAも2本動かして、「2系統が同期動作してくれるものかしら」と不安を抱きながら使います.
しかし、デュアルモードでは、ADC1/ADC2が同期動作してくれます.
デュアルモードのDMA bufferには特徴があります.
16bit dataがADC1/ADC2の順にインターリーブされるのかと思ったら違います.
32bit bufferの[31:16][15:0]にADC1/ADC2が積まれます.なので、変換完了callbackで上下をバラさなくちゃいけません.
バラしについていうとこんなコンテナ構造をバラすお仕事になります.1scan=1sampleのデータです.なお順番は違ってるかも.
わたしの設定では、3kHzサンプリングで、DMAには3000サンプル積めと命令します.ゆえにbufferは毎秒満タンになり、bufferは2x18x3000=108kBYTEです.メモリを喰います.
ーーーー
以下では設定を説明します.
STM32H723ZGT6のADC pinをこのようにassignしました.
↓ADC1の設定.Rankは途中で打ち切ってます.
↓ADC2の設定
↓DMAはADC1だけです.data widthはword、つまり32bitです.グルグル自走させるのでcircularです.
自走といえば、ADC1もADC2も自走させますので、TIM4で3kHzを作り、TIM4 TRIGでADCが動くにしてます.上記参照.TIM4の設定は割愛します.TRIG出力するようにしときや.
↓親切にTIM4の設定も載せとくね.なお、TIM CLOCKは275MHzです.
STM32CubeMXの設定のキモのところはこんなところかと思う.
ーーーー
source codeについて.
STM32CubeMXによりmain.cにはこんなハンドラが作られます.DMAはADC1のみです.
ADC_HandleTypeDef hadc1;
ADC_HandleTypeDef hadc2;
DMA_HandleTypeDef hdma_adc1;
dual mode DMAをどうやって起動するのか?
HAL driverのEXにその関数がありました.(盲点)
uint32_t ADC_ringbuf[27000];
HAL_ADCEx_MultiModeStart_DMA(hadc1, ADC_ringbuf, 27000);
ADC2の起動コマンドは不要です.
27000という数字は、上述のコンテナが36BYTEだったので、27000*4/36=3000サンプルとなる関係です.これで起動したDMAは1秒毎に満タンになり、割り込みます.放ったらかしで永久に自走します.
callback関数について.
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
どこかでweak宣言されている関数を上書きします.
2つあるのですが、buffer halfとbuffer fullで割り込んでくるので2つです.
毎秒割り込みとさんざ書きましたが嘘で、実際は0.5秒毎の割り込みとなります.
コンテナばらしなどお好きにおやりください.
ーーーー
説明は以上です.
ADC dual modeなんかに迂闊に近づくような人ならばこれだけの情報で応用できると思います.
かしこ