
前回書いたとおり、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に戻ってタイマを操作してみたいと思います。先は長いな。
