前回書いたとおり、WCHのRISC-V搭載マイコンCH32Vは、STM32をリスペクトしているのか、HALレイヤの関数がクリソツです。先にSTM32のHALレイヤで予習しておいたらCH32VでHALレイヤを使うのも楽なんでないかと。学習教材としてはタイマからPWM出力するのをHALレベルでやってみようと。メンドイけど。
Arduino環境からHALレベルのAPIを使えることはCH32VでもSTM32でも確かめましたが、直接使うのはメンドイです。しかし、STM32では「ラッパ」レイヤが準備されているので、そいつらを呼び出してやれば、ArduinoのAPIほどお手軽ではないけれど、結構簡単に制御が可能でした。今回は、STM32の「ラッパ」レイヤの関数を「毟って」、HALレベルのAPIもしくは、直接ハードウエアレジスタを読み書きするレベルでPWM出力してみたいと思います。使用するハードウエアは以下のとおりです。
-
- タイマ=TIM2
- コンペア・キャプチャ・チャネル=CH1
- CH1出力先=PA_5端子(STM32名。)Arduino的にはD13端子。ここにオンボードのLEDが接続されている
ここに対して、LEDの点滅が分かる比較的遅い周期(10Hzくらい)で、デューティ10%のPWM波形をPA_5に出力するのが当座の目標です。
実験に使用したソースコード
STM32の「ラッパ」レイヤのソースコードをカンニングさせていただきながら書いてみたものです。HALもしくは直接のハードウエアの読み書きをするマクロなどで書いてみたソースが以下に。
#if defined(LED_BUILTIN) #define pin LED_BUILTIN #else #define pin D2 #endif int counter = 0; uint32_t channel; timerObj_t _timerObj; void sprin(const char *msg, uint16_t v) { Serial.print(msg); Serial.println(v, HEX); } void setupTimer(TIM_TypeDef *instance) { _timerObj.handle.Instance = nullptr; _timerObj.handle.Instance = instance; _timerObj.handle.Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED; _timerObj.handle.hdma[0] = NULL; _timerObj.handle.hdma[1] = NULL; _timerObj.handle.hdma[2] = NULL; _timerObj.handle.hdma[3] = NULL; _timerObj.handle.hdma[4] = NULL; _timerObj.handle.hdma[5] = NULL; _timerObj.handle.hdma[6] = NULL; _timerObj.handle.Lock = HAL_UNLOCKED; _timerObj.handle.State = HAL_TIM_STATE_RESET; _timerObj.preemptPriority = TIM_IRQ_PRIO; _timerObj.subPriority = TIM_IRQ_SUBPRIO; __HAL_RCC_TIM2_CLK_ENABLE(); _timerObj.handle.Init.Prescaler = 0; _timerObj.handle.Init.Period = 0xFFFF; _timerObj.handle.Init.CounterMode = TIM_COUNTERMODE_UP; _timerObj.handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; _timerObj.handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; HAL_TIM_Base_Init(&(_timerObj.handle)); } void setMode(PinName pinx) { int timChannel = TIM_CHANNEL_1; int timAssociatedInputChannel; TIM_OC_InitTypeDef channelOC; TIM_IC_InitTypeDef channelIC; channelOC.OCMode = TIMER_NOT_USED; channelOC.Pulse = __HAL_TIM_GET_COMPARE(&(_timerObj.handle), timChannel); channelOC.OCPolarity = TIM_OCPOLARITY_HIGH; channelOC.OCFastMode = TIM_OCFAST_DISABLE; channelIC.ICPolarity = TIM_ICPOLARITY_RISING; channelIC.ICSelection = TIM_ICSELECTION_DIRECTTI; channelIC.ICPrescaler = TIM_ICPSC_DIV1; channelIC.ICFilter = 0; channelOC.OCMode = TIM_OCMODE_PWM1; HAL_TIM_PWM_ConfigChannel(&(_timerObj.handle), &channelOC, timChannel); if (pinx != NC) { if ((int)getTimerChannel(pinx) == timChannel) { pinmap_pinout(pinx, PinMap_TIM); } } } void setCaptureCompare(uint32_t compare) { int timChannel = TIM_CHANNEL_1; uint32_t Prescalerfactor = LL_TIM_GetPrescaler(_timerObj.handle.Instance) + 1; uint32_t CCR_RegisterValue; CCR_RegisterValue = ((__HAL_TIM_GET_AUTORELOAD(&(_timerObj.handle)) + 1) * compare) / 100; if ((__HAL_TIM_GET_AUTORELOAD(&(_timerObj.handle)) == 0xFFFF) && (CCR_RegisterValue == 0xFFFF + 1)) { CCR_RegisterValue = 0xFFFF; } __HAL_TIM_SET_COMPARE(&(_timerObj.handle), timChannel, CCR_RegisterValue); } void setPWM_T2C1(uint32_t frequency, uint32_t dutycycle) { int timChannel = TIM_CHANNEL_1; setMode(PA_5); LL_TIM_SetPrescaler(_timerObj.handle.Instance, 63); __HAL_TIM_SET_AUTORELOAD(&_timerObj.handle, 0xFF19); setCaptureCompare(dutycycle); HAL_TIM_PWM_Start(&(_timerObj.handle), timChannel); } void setup() { Serial.begin(9600); while (!Serial) { } Serial.println("STM32, PWM output settings check <DIRECT>."); TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(pin), PinMap_PWM); setupTimer(Instance); setPWM_T2C1(5, 10); } // the loop function runs over and over again forever void loop() { Serial.println(counter++); sprin("Chan : ", channel); sprin("CNT : ", TIM2->CNT); sprin("ARR : ", TIM2->ARR); sprin("CR1 : ", TIM2->CR1); sprin("CCMR1: ", TIM2->CCMR1); sprin("CCR1 : ", TIM2->CCR1); sprin("CCER : ", TIM2->CCER); delay(10000); }
メインループの中では、TIM2の主要なレジスタを直接読み出して表示してます。
実験結果
上記のソースをArduino IDE環境でビルド後、ターゲット機 Nucleo-F072RB(STM32F072RBマイコン搭載)に書き込みました。
シリアルモニタに出力されたレジスタ値は以下のようです。CNTみているとちゃんとカウントアップされているみたいデス。
一方、ArduinoのD13端子出力をオシロで観察した結果が以下に。約11.5Hz、デューティ約10%の波形が観察できます。やったね。
やったね、といって今回は動いて当然のSTM32機。次回こそは小ピンマイコンCH32V003に戻ってタイマを操作してみたいと思います。先は長いな。