毎度痛感させられるのが、STM32のHAL Driver及びSTM32CubeMXに関する情報の少なさとそれに伴う苦労の多さ。
ホント、参ってしまいます。
更に、HAL DriverはSTM32のハード(あるいはレジスタの設定周り)をうまく隠蔽化して開発者の負担を下げるわけではなく、それは更にその上位レイヤで行う方針だろうということ。
それ故なのか、はたまた単なる設計ミスなのか、(あるいは当方の理解不足なのか)非常に使いにくい部分がある。
USARTがそうだったが、ADCもその傾向があるようだ。
前回1チャンネル分の動作についてサンプル実装と確認を行ったが、その時には何ら苦労はなかった。
今回アナログジョイスティックを購入したので早速試してみたところ、結構はまってしまった。
STM32CubeMXを使用したのだが、もしかしたらコード生成に不具合があるのかもしれない。
試しに以下のようにPB0, PB1 にADCを設定してみた。
ADC Configuration は以下のような感じ。
DMA Settings にて DMA Channel1 を割り当て。
NVIC Settings は以下のとおり。
これによりアナログ入力を定期的に行い、ADCの初期化時に指定した計測対象のチャンネルが全て計測できたらコールバック
HAL_ADC_ConvCpltCallback() が呼び出される。
注意する点としては、1チャンネルのみ使用する場合はDMAを使用せずとも計測値が得られたが、複数チャンネルの場合はDMAを使用しなければならないとのこと。
確かにSTM32L0のレジスタをみてもめぼしいものは見つからない。
以上からDMAを使用したコードを書いて動作確認を行ったのだが、どうしても1チャンネル分しか取得できなかった。
コードは以下のような感じ。
: uint32_t g_ADCValue; int g_MeasurementNumber; enum{ ADC_BUFFER_LENGTH = 1024 }; uint16_t g_ADCBuffer[ADC_BUFFER_LENGTH]; : int main(void) { /* USER CODE BEGIN 1 */ uint32_t adcValue = 0; uint32_t volt = 0; ADC_ChannelConfTypeDef sConfig; /* USER CODE END 1 */ : memset(g_ADCBuffer, 0, sizeof(g_ADCBuffer)); HAL_ADC_Start_DMA(&hadc, g_ADCBuffer, ADC_BUFFER_LENGTH); : } : : void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle) { printf("adc[0]:%04x, adc[1]:%04x\n", g_ADCBuffer[0], g_ADCBuffer[1]); }
ジョイスティックをX/Y方向に倒しても、X方向のみ反映されるという状態に。
生成されたコードを含めて眺めてみる。
すると、不可解なコードが・・・
void MX_ADC_Init(void) { ADC_ChannelConfTypeDef sConfig; : /**Configure for the selected ADC regular channel to be converted. */ sConfig.Channel = ADC_CHANNEL_9; sConfig.Rank = ADC_RANK_CHANNEL_NUMBER; HAL_ADC_ConfigChannel(&hadc, &sConfig); }
ADC_IN8/ADC_IN9 の設定を行ったはずなのだが、インスタンスhadcに設定されるのは ADC_CHANNEL_9 のみとなっていた。
STM32のレジスタを確認すると、計測対象にするチャンネルを計測順序という形式で指定でき、同時に変換するチャンネル数を指定するようになっていた。
試しに以下のように ADC_CHANNEL_8 も設定してみる。
sConfig.Channel = ADC_CHANNEL_8|ADC_CHANNEL_9; sConfig.Rank = ADC_RANK_CHANNEL_NUMBER; HAL_ADC_ConfigChannel(&hadc, &sConfig);
これにより、DMA転送先となる g_ADCBuffer には、X, Y方向の値が交互に格納されることを確認した。
別途HAL Driverのソースを確認する必要があると思われる。
が、力尽きたので今日はここまで。