結論から言うとTIMのPWM出力をちょこちょこ動かすわけですが。
TIM2とTIM3を使用します。
TIM2でGSCLKを作り、TIM3でBLANKを作ります。
TIM2は1MHzのPWMを出力します。
STM32のPWMはPWM1とPWM2の2種類があるわけですが、今回はPWM2を使用します。PWM1と2はパルスの極性が反転します。極性はPolarity_HighやPolarity_Lowで設定できますが、今回はPWM2で設定しました。
PWM1の場合、カウンタが0だとHが出力されるため、あとでカウンタをクリアした際にその時点でHが出力されてしまうためです。
TIM3はいくつかの機能を持たせていますが、一番大きな機能はTIM2のゲートとしての機能です。
STM32のTIMはTIMマスタのPWMがHのときだけTIMスレーブを走らせる、ということが可能なので、正確な時間だけTIMを動かしたいという場合には便利です。今回はTIM2で4096個のパルスを送りたいので使用しました。BLANKパルスを送った後にGSCLKを送信したいので、PWM2でTIMの後半に送信するようにします。
前述の通りPWM以外にPolarityで極性を設定できますが、ゲートとして使うにはPWM1/2で極性を設定する必要があります。
ゲートはCH1を使いますが、他にCH3とCH4を初期化しています。CH3とCH4ではOCで割り込みを発生させており、この割り込みハンドラの中でGPIOをトグルしてBLANK信号を出力しています。本当はハードウェアで処理したかったのですが、方法がわからなかったのでソフトウェアに逃げました。
TIM2は1MHzで分解能は1usec、TIM3は20msecで1サイクルとなります。まぁサーボモータ向けの設定ですね。サーボモータを使うなら2.5msecもあれば十分ですからTIM2はもう少し高速でもいいですが、1usec単位のほうが扱いやすいのでこの設定です。
TIM3の更新割り込みなどを使えばGSCLKを送った後にハンドラを起動できるので、そこでデータの転送を開始させるなどの設定も可能です。
とりあえず必要なパルスは送れるようになったので、あとはデータを送ってやれば使えるようになるはずです。それはまた次回。
// TIM2 init { { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); } { TIM_TimeBaseInitTypeDef TIM_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_InitStructure.TIM_Period = 72 - 1; TIM_InitStructure.TIM_Prescaler = 0; TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_InitStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM2, &TIM_InitStructure); } { TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 36 - 1; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC4Init(TIM2, &TIM_OCInitStructure); TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable); } TIM_ARRPreloadConfig(TIM2, ENABLE); } // TIM3 init { const uint16_t Period = 20 * 1000; { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); } { TIM_TimeBaseInitTypeDef TIM_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); TIM_InitStructure.TIM_Period = Period - 1; TIM_InitStructure.TIM_Prescaler = 72 - 1; TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_InitStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM3, &TIM_InitStructure); } { TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable; TIM_OCInitStructure.TIM_Pulse = Period - 4096; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC1Init(TIM3, &TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); } { TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable; TIM_OCInitStructure.TIM_Pulse = Period - 6000; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC3Init(TIM3, &TIM_OCInitStructure); TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); } { TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable; TIM_OCInitStructure.TIM_Pulse = Period - 5000; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC4Init(TIM3, &TIM_OCInitStructure); TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable); } { NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } TIM_ARRPreloadConfig(TIM3, ENABLE); } TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_OC1Ref); TIM_SelectInputTrigger(TIM2, TIM_TS_ITR2); TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Gated); TIM_ITConfig(TIM3, TIM_IT_CC3, ENABLE); TIM_ITConfig(TIM3, TIM_IT_CC4, ENABLE); TIM_Cmd(TIM2, ENABLE); TIM_Cmd(TIM3, ENABLE);
***
void TIM3_IRQHandler(void) { if (TIM_GetITStatus(TIM3, TIM_IT_CC3)) { GPIO_SetBits(GPIOA, GPIO_Pin_4); TIM_ClearITPendingBit(TIM3, TIM_IT_CC3); return; } if (TIM_GetITStatus(TIM3, TIM_IT_CC4)) { GPIO_ResetBits(GPIOA, GPIO_Pin_4); TIM_GenerateEvent(TIM2, TIM_EventSource_Update); TIM_ClearITPendingBit(TIM3, TIM_IT_CC4); return; } }
0 件のコメント:
コメントを投稿