STM32 Timer One Pulse kullanımı hakkında

Başlatan argelojik, 05 Nisan 2020, 12:48:10

argelojik

Merhaba iyi günler.  STM32 timer konusunda  5 gündür takılıp kaldığım bir durum için yardım isteyecektim. Aslında yapmak istediğim şey çok basit ama olmuyor. Timer ile 2ms de bir 220us lik bir pulse üretmek istiyorum. Bunun için TIMER ONE PULSE MODE kullanmayı istedim.  Ama inanın bir türlü yapamıyorum. YA HAL kütüphanesin de bir sıkıntı var olmuyor. HAL kütüphanesine derin bakacak birikimim maalesef şu anda yok. Bana yardım edebilir misiniz?

Cubemx'ten şu şekilde ayar yapıyorum;
Timer3 kanalı için  Kanal1 girişi olarak input capture direct mode seçiyorum. Kanal2 çıkış için de PWM channel generation CH2 seçiyorum. Sonra one pulse mode tickini işaretliyorum. Yani KANAL2 Çıkış, KANAL1 Giriş.

HAL_TIM_OnePulse_Init(&htim3, TIM_OPMODE_SINGLE);
HAL_TIM_OnePulse_ConfigChannel(&htim3, &sConfig, TIM_CHANNEL_2, TIM_CHANNEL_1);
HAL_TIM_OnePulse_Start(&htim3, TIM_CHANNEL_2);

Yukarıdaki fonksiyonları da çağırıyorum ama olmuyor. Neden olmuyor anlamıyorum? Yardımınız için şimdiden teşekkür ederim.
(Neden PWM kullanmak istemiyorum çünkü istediğim pulse PWM ile olmuyor)

SB7

#1
Hocam timer kullanarak pwm üretmek istiyorsanız prescaler ve period değerleriyle  hesap yaparak ilerlemelisiniz.
Örneğin 72 MHz denetleyici kullanıyorsanız prescaler 71 ve period değerini 2000 seçerseniz 500 Hertzlik(2ms peryotlu) pwm sinyalini elde edersiniz.(72000000 / ((71+1)*2000)=500 Hertz)
2 us için de doluluk oranını değiştireceksiniz . Yani verdiğiniz 2000 değerine göre 2 4 gibi bir değer verirseniz olur gibi geliyor bana.

Edit: Period 2 olunca istediğiniz oluyor.

https://ibb.co/z6s36Xs

 
-SB7

argelojik

Alıntı yapılan: SB7 - 05 Nisan 2020, 13:38:45Hocam timer kullanarak pwm üretmek istiyorsanız prescaler ve period değerleriyle  hesap yaparak ilerlemelisiniz.
Örneğin 72 MHz denetleyici kullanıyorsanız prescaler 71 ve period değerini 2000 seçerseniz 500 Hertzlik(2ms peryotlu) pwm sinyalini elde edersiniz.(72000000 / ((71+1)*2000)=500 Hertz)
2 us için de doluluk oranını değiştireceksiniz . Yani verdiğiniz 2000 değerine göre 2 4 gibi bir değer verirseniz olur gibi geliyor bana.

Edit: Period 2 olunca istediğiniz oluyor.

https://ibb.co/z6s36Xs

 (Resim gizlendi görmek için tıklayın.)
Cevap için teşekkür ederim ama aslında benim iki kanal PWM oluşturmam gerekiyor. Arasında faz farkı olan. Bu yüzden one pulse mode kullanmam gerekiyor. Sizin dediğiniz şekilde yapıyorum ama bu şekilde işime yaramıyor. Şekildeki gibi bir PWM sinyal istiyorum. STM32F415 kullanıyorum. Timer frekansım 60MHZ buralarda sorunum yok. Sadece pulse şeklinde bir sinyal oluşsun istiyorum. Buna da delay verebileyim. İstediğim tam olarak pulse sinyali.Bir de bu one pulse mode ben de gurur meselesi oldu. Yapamadıkça stres oldum. Teşekkür ederim.

argelojik

Korona günlerinde bugün Pazar. Günlerdir herkes evinde, birçok kişinin foruma girerek bu konuyu gördüğünü düşünüyorum. One pulse modunu projelerinde hiç kimse kullanmadı mı gerçekten? İnternette de bu mode ile ilgili de çok az bilgi var. Kullanan varsa yardımınızı bekliyorum.Teşekkürler.

Mucit23

Ben STD library ile kullandım. Dizel motorlarla uğraşırken enjektörün açılıp kapanma süresini ayarlıyordum one pulse modu ile.

Bunlar ayarlarım
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;
// Enable clock
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
  /* GPIOB clock enable */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
  /* TIM2_CH1 pin (PA.00) configuration */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	
  /* TIM2_CH2 pin (PA.01) configuration */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	// Time Base configuration
	TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
	TIM_TimeBaseStructure.TIM_Prescaler = 72-1;//1uS each tick
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;
	TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

  /* TIM2 PWM2 Mode configuration: Channel1 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 65535;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;

  TIM_OC1Init(TIM2, &TIM_OCInitStructure);
	
  /* TIM2 PWM2 Mode configuration: Channel1 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 65535;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
  TIM_OC2Init(TIM2, &TIM_OCInitStructure);

  /* One Pulse Mode selection */
  TIM_SelectOnePulseMode(TIM2, TIM_OPMode_Single);

Yukarıdaki init kodlarıyla 1uS çözünürlükte puls alabiliyorum. PSC ve ARR değerleri ile oynayarak bunu değiştirebilirsiniz. Yalnız Output Compare işlemi ters çalışıyordu. Farklı OC modlarını denemiştim ama çözememiştim. One Pulse Modunda hatırladığım kadarıyla Time Update Eventi olunca timer otomatik duruyordu.

Timeri Aktif etmek için aşağıdaki şekilde timeri kuruyorum.
   TIM2->CNT=65535-CH1_Pulse_Counter;
				 TIM2->CCR1=CH1_Pulse_Counter;
				 TIM_Cmd(TIM2,ENABLE);

CH1_Pulse_Counter değeri çıkmasını istediğim puls değeri. TIM->CNT değerini doğrudan 65535-CH1_Pulse_Counter değerinden başlatmak gerekiyor. Capture Compare registerine de puls değerini yüklemek gerekiyor. Bu şekilde çalıştırmıştım.

HAL ayarlarınıda bendeki ayarlara göre güncellersin.

argelojik

Yardımınız için teşekkür ederim. Yarın tekrar deneyeceğim. Sonucu buradan yazarım.

isoment01

#6
Neden input capture kullaniyorsun . Benim anladigim bir timer kullanilacak zaman guncellemeli modunda (timer update mode) sonra pwm den one pulse modu secilip pulse in frrkansi ayarlanacak ve bu kod timer interrupt rutinine gomulecek. Input capture secersen giristen birsey algilamadigin icin dolayisiyla bayragi set olmicak ve icine ne yazarsan yaz execute edilmicek. Ayrica Callback function kodlarini hic gormedim , input capture interrupt8ni enable ettigin set_nvicIRQ gibi bi fonksiyon vardi onu da goremedim. Belki mobilden girdigim içinde olabilir.
Interruptinin calisip calismadingini _Bool flag=reset; de callback fonksyonunda bunu set et debug modda da bu degiskeni izle bakalim. Resette kaliyorsa tetiklenmiyo demektir.

argelojik

Sayın isoment01 Usta, input capture kullanıyorum çünkü "One Pulse Mode" bu şekilde kurgulanmış. Ben de bunun için Timer5'i master olarak kullandım ve 2ms(500Hz) ye ayarladım. Timer5'i, 2 ms de bir slave olan Timer3'ü tetikleyecek şekilde ayarladım. Timer3'ün Channel1'ini "input capture direct mode" ile giriş olarak ayarladım. Channel2'yi ise "PWM Generation CH2" çıkış olarak ayarlarım. Bu şekilde Timer5'ten 2 ms de bir gelen "Update Event"lar ile  Timer3'ten kendi belirlediğim delay ve periyod'da  pulse üreteceğini zannediyorum. Ama olmuyor. Karışık gibi görünüyor ama değil. Açıklayıcı olsun diye kodları ve cubemx ayarlarımı resimledim. Ama siz de lütfen One Pulse mod nasıl çalışıyor bir inceleyin.Cevap için yine de size teşekkür ederim.





argelojik

Hocam sizin gönderdiğiniz kodlara baktım. Bu kodları Hal kütüphanesine göre benim düzenlemem çok zor. Bu konu altında kodlarımı ve ayarlarımı gönderdim. Eğer zamanınız olursa incelerseniz mutlu olurum.Teşekkür ederim. Bu konu sadece benim için değil ilerde projelerinde one pulse modunu kullacaklar içinde faydalı olacaktır. One pulse mode yazınca herkes rahatça bu konuya ulaşabilecekler diye düşünüyorum.
Alıntı yapılan: Mucit23 - 05 Nisan 2020, 22:22:50Ben STD library ile kullandım. Dizel motorlarla uğraşırken enjektörün açılıp kapanma süresini ayarlıyordum one pulse modu ile.

Bunlar ayarlarım
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
 TIM_OCInitTypeDef  TIM_OCInitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;
// Enable clock
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
  /* GPIOB clock enable */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
 
  /* TIM2_CH1 pin (PA.00) configuration */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
 
  /* TIM2_CH2 pin (PA.01) configuration */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
 
 // Time Base configuration
 TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
 TIM_TimeBaseStructure.TIM_Prescaler = 72-1;//1uS each tick
 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
 TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
 TIM_TimeBaseStructure.TIM_ClockDivision = 0;
 TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

  /* TIM2 PWM2 Mode configuration: Channel1 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 65535;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;

  TIM_OC1Init(TIM2, &TIM_OCInitStructure);
 
  /* TIM2 PWM2 Mode configuration: Channel1 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 65535;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
  TIM_OC2Init(TIM2, &TIM_OCInitStructure);

  /* One Pulse Mode selection */
  TIM_SelectOnePulseMode(TIM2, TIM_OPMode_Single);

Yukarıdaki init kodlarıyla 1uS çözünürlükte puls alabiliyorum. PSC ve ARR değerleri ile oynayarak bunu değiştirebilirsiniz. Yalnız Output Compare işlemi ters çalışıyordu. Farklı OC modlarını denemiştim ama çözememiştim. One Pulse Modunda hatırladığım kadarıyla Time Update Eventi olunca timer otomatik duruyordu.

Timeri Aktif etmek için aşağıdaki şekilde timeri kuruyorum.
  TIM2->CNT=65535-CH1_Pulse_Counter;
 TIM2->CCR1=CH1_Pulse_Counter;
 TIM_Cmd(TIM2,ENABLE);

CH1_Pulse_Counter değeri çıkmasını istediğim puls değeri. TIM->CNT değerini doğrudan 65535-CH1_Pulse_Counter değerinden başlatmak gerekiyor. Capture Compare registerine de puls değerini yüklemek gerekiyor. Bu şekilde çalıştırmıştım.

HAL ayarlarınıda bendeki ayarlara göre güncellersin.

argelojik

İnternetten Stm32 anlatan bir elektronik kitap buldum.Yazarın adı Carmine Noviello. Kitabın adı Mastering STM32. Çok güzel bir kitap. Bu kitaptan faydalanmaya başladım. Kitapta size One Pulse Mode'un  anlatıldığı bölümü paylaşıyorum.
    (1)

muhittin_kaplan

onePulse da "2sn de bir" olmaz. Alınan bir tetikleme ile, Belirlediğiniz bir süre Bir Pulse Alırsınız
http://muhittinkaplan.com/blog/2020/01/26/stm32f0disco-timer17-oneshot/

argelojik

#11
Sayın muhittin_kaplan hocam. Az önce göndermiş olduğum e-kitabın one pulse mode (OPM) anlatan bölümünde dışarıdan pulse ile delay ve periyod ayarlanarak pulse üretileceği yazıyor. Ya da ben mi yanlış yorumluyorum? Ayrıca 2 saniye değil 2ms olacak.

muhittin_kaplan

#12
Tamam işte,bir tetikleme lazım. Her 2ms de bir tetikleme vereceksiniz ki, belirlediğiniz DUTY de bir pulse olştursun.

Bunun yerine basit bir timer interrtup kuracaksınız 2ms lik. Böylece 2ms de bir puls oluşacak.

argelojik

Sayın hocam bu tetiklemeyi Timer5 ile(ITR2 ile)içeriden yapıyorum. Ama bir şeyi atlıyorum ve olmuyor.Bulamadım, Lütfen gönderdiğim resimleri inceler misiniz?

muhittin_kaplan