STM32 Timer One Pulse Mode Hakkında

Başlatan Mucit23, 22 Temmuz 2018, 13:29:49

Mucit23

Selamlar

STM32F103 Timerinde Tek bir Puls'lık Periyodik olmayan darbeler üretmem gerekiyor. Bu darbeleri yazılımda bir şart gerçekleştiğinde üreteceğim. Değişen şey Puls genişliği

Benim için 0-25ms arasında 100uS çözünürlüklü darbeler yeterli olacak gibi. yani 10.1mS vs

F1 STD library içerisindeki örneklere baktım Orada One Pulse Mode ile ilgili bir örnek var.

  /* TIM4 configuration: One Pulse mode ------------------------
     The external signal is connected to TIM4_CH2 pin (PB.07), 
     The Rising edge is used as active edge,
     The One Pulse signal is output on TIM4_CH1 pin (PB.06)
     The TIM_Pulse defines the delay value 
     The (TIM_Period -  TIM_Pulse) defines the One Pulse value.
     TIM2CLK = SystemCoreClock, we want to get TIM2 counter clock at 24 MHz:
     - Prescaler = (TIM2CLK / TIM2 counter clock) - 1
     The Autoreload value is 65535 (TIM4->ARR), so the maximum frequency value 
     to trigger the TIM4 input is 24000000/65535 = 300 Hz.

     The TIM_Pulse defines the delay value, the delay value is fixed 
     to 682.6 us:
     delay =  CCR1/TIM4 counter clock = 682.6 us. 
     The (TIM_Period - TIM_Pulse) defines the One Pulse value, 
     the pulse value is fixed to 2.048 ms:
     One Pulse value = (TIM_Period - TIM_Pulse) / TIM4 counter clock = 2.048 ms.

  * SystemCoreClock is set to 72 MHz for Low-density, Medium-density, High-density
    and Connectivity line devices and to 24 MHz for Value line devices
  ------------------------------------------------------------ */

  /* Compute the prescaler value */
  PrescalerValue = (uint16_t) (SystemCoreClock / 24000000) - 1;
  /* Time base configuration */
  TIM_TimeBaseStructure.TIM_Period = 65535;
  TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

  /* TIM4 PWM2 Mode configuration: Channel1 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 16383;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

  TIM_OC1Init(TIM4, &TIM_OCInitStructure);

  /* TIM4 configuration in Input Capture Mode */

  TIM_ICStructInit(&TIM_ICInitStructure);

  TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  TIM_ICInitStructure.TIM_ICFilter = 0;

  TIM_ICInit(TIM4, &TIM_ICInitStructure);

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

  /* Input Trigger selection */
  TIM_SelectInputTrigger(TIM4, TIM_TS_TI2FP2);

  /* Slave Mode selection: Trigger Mode */
  TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Trigger);

Ordaki ayarlar bu şekilde fakat burada Timeri Input Capture ile tetiklemiş. Yani başka bir yerden gelen bir sinyal ile timer tetikleniyor. Benim ise bu tetikleme işlemini yazılımla yapmam gerekiyor. Burada Timeri Manuel olarak nasıl tetikleyeceğimi çözemedim.

Daha önce bu konuda çalışması olan varmı? Tek puls'luk darbeler üretmem gerekiyor anlık olarak.

Mucit23

STM32F103 Çipimde Timer2'yi Yazılımsal olarak nasıl tetiklerim? Örnek vermek Gerekirse Timer'larda ITR0-ITR3 şeklinde 3 adet dahili tetikleme kanalları bulunuyor. Bunlara yazılımsal müdahale mümkünmüdür? Anladığım kadarıyla başka timer'lar ile tetiklemek için bu kanallar kullanılıyor.

STM32'de bir Timeri Software olarak nasıl tetiklerim?

magnetron

 TIM_Cmd(TIM1, ENABLE);

bununla timeri start etsen olmuyor mu ?

 TIM_Cmd(TIM1, DISABLE); bununla da durdurursun

ayrıca Timeri sıfırdan başlatmak için

TIM1->CNT=0

Mucit23

Şuanda zaten o şekilde yapıyorum. One Pulse Modu ile otomatik yapmak istedim. Fakat yapıyı henüz tam çözemedim.

Tagli

#4
Bence de magnetron'un dediği şekilde olmalı. One Pulse modunun anlamı, update event (UE) oluştuktan sonra timer'ın kendi kendini kapatması. Onun dışında normal kullanımdan bir farkı yok. Emin değilim ama belki TIM1->CNT = 0 ifadesine gerek kalmayabilir.
Gökçe Tağlıoğlu

Mucit23

Ben şu şekilde yaptım. Timer bölücü oranını ayarlayarak timer giriş frekansını 1mhz'e düşürdüm. Daha sonra Tim ARR değerine pulls genişliğini Us cinsinden girdim. 10ms için ARR değerini 10000 olarak girdim. Aynı zamanda Tim update kesmesini aktif ettim. Sistemi çalıştırmak istediğimde ARR değerini girip  hangi çıkışı kullanacaksam onu set edip sayacı sıfırladıktan sonra timeri çalıştırıyorum. Daha sonra sayaç ARR değerine ulaştığında update kesmesi oluşuyor bende kesmede gidip çıkışı resetleyip timeri durduruyorum. Iyi çalışıyor gibi ama işte sistemi kapatmak için bir daha kesmeye gitmek gerekiyor. One pulse modu ile buna gerek kalmaz diye düşünmüştüm.

Tagli

One Pulse modunu Output Compare modu ile birlikte kullanırsan çıkışın otomatik olarak kapanmasını sağlayabilirsin bence. Bunun için çıkışı önce "force active level" olacak şekilde ayarlamalı (1 yapmalı), hemen ardından da "Set channel x to inactive level on match" demelisin. Bu modlar OCxM (x yerine 1, 2, 3 falan) bitleri ile ayarlanıyor. İki komut arasında bekleme yapmana gerek yok. Muhtemelen ek birkaç ayar daha gerekecektir. Ama tabi bunu yapabilmek için TIM kanallarından birini kullanmak gerekiyor, yani rastgele bir bacaktan yapamazsın.

Elbette output compare özelliğini kullandığında süreyi belirlemek için TIMx_ARR değil TIMx_CCRx register'ını kullanmak gerekiyor. Kesme kullanmana gerek yok. Ama elbette ARR değeri CCR'den büyük olmalı, yoksa CCR'yi göremeden sayaç sıfırlanır.
Gökçe Tağlıoğlu

Mucit23

#7
Şöyle bir ihtiyacım var fikrinizi alayım. Yine bu konu ile ilgili. TIM3 ile Enkoder okuması yapıyorum. Kullandığım Enkoder tur başına 1024 puls üretiyor. TIM Enkoder girişinde xor fonksiyonu olduğu için gelen puls lar 4x şekilde counteri arttırıyor. Yani tam 1 turda TIM Counter değeri 4095 oluyor. Burası güzel çalışıyor.

Şöyle birşey yapmak istiyorum. Enkoder her iki tur döndüğünde sayaç otomatik sıfırlansın. Bunu TIM ARR Değerini 8192(4096*2)yaparak çözebilirim. Yani 8192 puls sonra timer sıfırlanacak.

Aynı zamanda cnt değeri örneğin 5150 olduğunda başka bir timer tetikleyip one puls modunda olduğu gibi bir puls üretmek istiyorum. Puls genişliği yine ayarlanabilir olacak.

Bunu Output Compare ile yaparım diye düşündüm. Fakat Output Compare ile slave timer Nasıl tetikleyeceğimi çözemedim. Slave mod da timer in ITR0 ITR1 ITR2 ITR3 gibi internal tetikler kanalları var. Bu tetikleme kanallarına başka bir master timer in Output Compare çıkışını bağlayabilirmiyim?

Tagli

#8
Mümkün gözüküyor, ama daha önce denemediğim için nasıl yapıldığından emin değilim. Referans dokümanının (benim baktığım RM0008, DocID13902 Rev 16) 398. sayfasında ilgili bir örnek de verilmiş. TIMx_CR2 içindeki MMS (master mode selection) bitleri ile TRGO'nun hangi durumlarda çıkış vereceği seçilebiliyor. Buradaki compare pulse veya compare modlarından biri seçilmeli ama hangisi uygun olur veya aralarındaki fark tam nedir anlayamadım. Bir denemek lazım.

One pulse modundaki slave timer da uygun numaralı ITR ile başlayacak şekilde ayarlanmalı tabi.
Gökçe Tağlıoğlu

Mucit23

#9
Olmadı. Daha doğrusu yapamadım.

Konuya yeni dahil olanlar için yapmak istediklerimi tekrarlayayım. Belki bilen birileri çıkar.

TIM3 ile Enkoder okuması yapıyorum. Enkoderim tam 1 tur döndüğünde TIM3->CNT değeri 4095 oluyor. Buraya kadar gayet iyi çalışıyor. Benim amacım Enkoder yarım tur döndüğü anda yada TIM3->CNT değeri 2048 olduğunda Başka bir Timer Aracılığıyla 0-25ms arası puls lar üretmek. Bunun için TIM2'yi kullandım. TIM2 One Puls modunda çalıştırmak için uğraşıyorum. Yaptıklarımı anlatayım belki yanlış yaptığım bir yer göze çarpar.

TIM3'de Output Compare birimini kullandım. OC1'de pulse değerini 2048 yaptım. Daha sonra TIM3'ün Trigger çıkışını TIM_TRGOSource_OC1Ref olacak şekilde ayarladım. TIM3'ü aktif edip buradan çıktım.

Daha sonra TIM2'nin ayarlarını yaptım. Prescaller değerini ayarlayarak 1Mhz'de çalışmasını sağladım. Dolayısıyla OC1->Pulse değerini 0-25000 yaparak istediğim puls genişliğini ayarlayabileceğimi düşündüm. OC mode PWM1'de bu arada.

TIM2 Input Trigger seçeneğini TIM_TS_ITR0 olarak ayarladım. Buraya kadar sorun yok gibi ama ben hala TIM3'ün Output Trigger çıkışının nasıl TIM2'nin Trigger girişine bağlanacağını çözemedim. Debugdan anladığım kadarıyla zaten TIM2 tetiklenmiyor.

Genel olarak ayarlarım aşağıdaki gibi.

Enkoderi okudğum ve master olan TIM3'ün ayarları böyle
void Encoder_Init(void)
{
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);

	// Step 1: Initialize GPIO as input for rotary encoder
	//PA6 (TIM3_CH1) (encoder pin A), PA7 (TIM3_CH2) (encoder pin B)
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	TIM_TimeBaseStructure.TIM_Prescaler = 0;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up | TIM_CounterMode_Down;
	TIM_TimeBaseStructure.TIM_Period = 4095;
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;
	TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
	
  /* Output Compare Active Mode configuration: Channel1 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 1000;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  TIM_OC1Init(TIM3, &TIM_OCInitStructure);
	
	TIM_SetCounter(TIM3,0);

	TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
	
	TIM_SelectOutputTrigger(TIM3,TIM_TRGOSource_OC1Ref);
	
	TIM_Cmd(TIM3, ENABLE);
	
}



Diğer Slave Timerin ayarıda bu şekilde
void SlaveTimerInit(void)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_OCInitTypeDef  TIM_OCInitStructure;
  GPIO_InitTypeDef GPIO_InitStruct;
	
  // Enable clock
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA, &GPIO_InitStruct);
	
	  // Time Base configuration
	TIM_TimeBaseStructure.TIM_Prescaler = 72-1;
	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_PWM2;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 20000;  //20ms
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

  TIM_OC1Init(TIM2, &TIM_OCInitStructure);
	
  /* One Pulse Mode selection */
  TIM_SelectOnePulseMode(TIM2, TIM_OPMode_Single);
	
  /* Input Trigger selection */
  TIM_SelectInputTrigger(TIM2, TIM_TS_ITR0);

  /* Slave Mode selection: Trigger Mode */
  TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Trigger);
	
}

Yardım ederseniz sevinirim. Nerde hata yapıyorum çıkamadım işin içinden.

Mucit23


Tagli

ITR0 değil de ITR2'yi kullanman gerekiyor bence. Dokümanda "Table 86. TIMx Internal trigger connection" var. Eğer TIM3'ün master, TIM2'nin slave olmasını istiyorsan TIM2'de ITR2 seçilmeli.
Gökçe Tağlıoğlu

fatal16

Tim3'ün pwm ve enkoder için kullanılması nasıl mümkün oluyor ?

Mucit23

@Tagli Hocam Tekrar bir deneme yapacağım. Bunu atlamışım.

@fatal16 TIM3 Sadece Enkoder okuması için kullanılıyor.