Picproje Elektronik Sitesi

MİKRODENETLEYİCİLER => ARM => Konuyu başlatan: ttg - 13 Ekim 2013, 20:05:46

Başlık: stm32f407 pwm frekansını ayarlayamıyorum
Gönderen: ttg - 13 Ekim 2013, 20:05:46
Merhabalar,
STM32f407 discovery ile servo sürmek istiyorum. Muhittin Hoca'nın http://muhittinkaplan.com/2013/08/rc-servo/ (http://muhittinkaplan.com/2013/08/rc-servo/) linkindeki kodunu, Peripheral Lib in örneklerindeki kodu birlikte götürerek Prescaler ve ARR değerlerini hesaplamaya çalıştım ama işin içinden çıkamıyorum. Öncelikle,

APB'den Timer3'e apb1 prescaler 1'den farklı olduğu için kendi clock unun 2 katı geliyor ve 84 Mhz ile çalışıyor dedim. Bu durumda, linkteki kodta yer aldığı gibi, prescaler yerine 840-1'den 839 yazarak Timer 3 Counter Clock'u 100 KHz yaptım.

En son da, kodtaki ARR'yi hesaplayayım dedim, 100KHz altında 50 Hz almak istersem ARR'yi 100K/50'den 2000 buluyorum, ancak linkteki örnek kodta 400 olarak kullanılmış.

Linkteki kod sorunsuz çalışıyor, yani benim bir hatam var ama bulamadım. Sizce hangi noktayı atlıyorum?
Başlık: Ynt: stm32f407 pwm frekansını ayarlayamıyorum
Gönderen: muhittin_kaplan - 13 Ekim 2013, 20:16:30
kodlarını yazsana. bakalım
Başlık: Ynt: stm32f407 pwm frekansını ayarlayamıyorum
Gönderen: ttg - 13 Ekim 2013, 20:31:32
Hocam sitenizdeki kodun aynısı, sadece hesabı yapamıyorum.

Kütüphane kodunu editleyerek de denedim, onda da yazdığım kod şu olmuştu:


#include "stm32f4xx.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
#include "misc.h"
#include "stm32f4xx_tim.h"

TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
TIM_OCInitTypeDef  TIM_OCInitStructure;
/* 4000 % 5 = 200 ile 4000 % 10 = 4000 arası değer alabilirler */
uint16_t CCR1_Val = 300;
uint16_t CCR2_Val = 320;
uint16_t CCR3_Val = 330;
uint16_t CCR4_Val = 340;

void TIM_Config(void);

int main(void)
{
  TIM_Config();

  /* Time base configuration */
  TIM_TimeBaseStructure.TIM_Period = 4000 - 1; // 200000 Hz/4000 = 50 Hz
  TIM_TimeBaseStructure.TIM_Prescaler = 420 - 1; // 84E6/420 = 200000 Hz
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

  /* PWM1 Mode configuration: Channel1 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = CCR1_Val;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

  TIM_OC1Init(TIM3, &TIM_OCInitStructure);

  TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);

  /* PWM1 Mode configuration: Channel2 */
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = CCR2_Val;

  TIM_OC2Init(TIM3, &TIM_OCInitStructure);

  TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);

  /* PWM1 Mode configuration: Channel3 */
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = CCR3_Val;

  TIM_OC3Init(TIM3, &TIM_OCInitStructure);

  TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);

  /* PWM1 Mode configuration: Channel4 */
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = CCR4_Val;

  TIM_OC4Init(TIM3, &TIM_OCInitStructure);

  TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);

  TIM_ARRPreloadConfig(TIM3, ENABLE);

  /* TIM3 enable counter */
  TIM_Cmd(TIM3, ENABLE);

  while (1)
  {}
}

void TIM_Config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  /* TIM3 clock enable */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

  /* GPIOC clock enable */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);

  /* GPIOC Configuration: TIM3 CH1 (PC6), TIM3 CH2 (PC7), TIM3 CH3 (PC8) and TIM3 CH4 (PC9) */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
  GPIO_Init(GPIOC, &GPIO_InitStructure);

  /* Connect TIM3 pins to AF2 */
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_TIM3);
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_TIM3);
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_TIM3);
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_TIM3);
}

Başlık: Ynt: stm32f407 pwm frekansını ayarlayamıyorum
Gönderen: muhittin_kaplan - 13 Ekim 2013, 20:40:08
https://www.picproje.org/index.php/topic,48631.0.html (https://www.picproje.org/index.php/topic,48631.0.html)

baktın mı buraya
Başlık: Ynt: stm32f407 pwm frekansını ayarlayamıyorum
Gönderen: ttg - 13 Ekim 2013, 20:54:48
Hocam ilk defa linki verdiğinizde baktım, forumda farklı örneklere bakmıştım önceden.

2. mesajdaki formüle göre hesap yapıyorum, beklenen frekans 50 Hz olduğuna göre:
Kesme oluşma süresi = (PSC+1)*(ARR+1) / APB  = 4000*420/84000000 = 0.02 s (50hz)

Ben yine hata bulamadım,
konuda altta belirttiğiniz registerların değer kısıtlamalarına halihazırda dikkat ediyorum, zaten 16 bitten aşağı bir şey kullanmadım, 3999 ve 419 değerleri 0 ile 0xffff arasında olduğu için o konuda bir sıkıntı olmadığı belli zaten.
Başlık: Ynt: stm32f407 pwm frekansını ayarlayamıyorum
Gönderen: muhittin_kaplan - 13 Ekim 2013, 21:09:41
void InitTimer3(){
  RCC_APB1ENR.TIM3EN = 1;
  TIM3_CR1.CEN = 0;
  TIM3_PSC = 55;
  TIM3_ARR = 59999;

  NVIC_IntEnable(IVT_INT_TIM3);
  TIM3_DIER.UIE = 1;
  TIM3_CR1.CEN = 1;
}

50Hz dedi program.

mesaj birleştirme:: 13 Ekim 2013, 21:10:40

senin peryodun 0,01sn mi çıkıyor gerçekte
Başlık: Ynt: stm32f407 pwm frekansını ayarlayamıyorum
Gönderen: ttg - 13 Ekim 2013, 21:22:35
Evde logic analyzer veya osiloskop yok malesef şu an ölçemiyorum.

Bana da sizinle aynı rakamları vermişti program, onları da denedim sonuç yine hüsran. Şu ana kadar çalıştırabildiğim tek kod sizin blogda yer alandı.

Timer3 ün clock hızını 168mhz alırsak formüle göre 2 ms çıkıyor yazdığınız kodun sonucu. Timer clock unu 84mhz kabul etmiştim, peripheral libde şöyle bir ifade var:
"
    In this example TIM3 input clock (TIM3CLK) is set to 2 * APB1 clock (PCLK1),
    since APB1 prescaler is different from 1.
      TIM3CLK = 2 * PCLK1
      PCLK1 = HCLK / 4
      => TIM3CLK = HCLK / 2 = SystemCoreClock /2
"

Başlık: Ynt: stm32f407 pwm frekansını ayarlayamıyorum
Gönderen: muhittin_kaplan - 13 Ekim 2013, 21:39:50
heh buldum.
http://gunluk.muuzoo.gen.tr/2012/07/29/stm32f4-discovery-maceralari-7-buton-okuma-ve-timer-kullanimi/ (http://gunluk.muuzoo.gen.tr/2012/07/29/stm32f4-discovery-maceralari-7-buton-okuma-ve-timer-kullanimi/)
Başlık: Ynt: stm32f407 pwm frekansını ayarlayamıyorum
Gönderen: ttg - 13 Ekim 2013, 23:13:42
Hocam cevabınız için teşekkür ederim. Linke de baktım yaptığım hesaplardan farklı bir şey göremedim. Ama sonuç olarak benim pwm hala bu hesaplardaki gibi işlemiyor.

Bir de sizin kodu hala anlayamadım.

   TIM_TimeBaseStructure.TIM_Period=400;
    TIM_TimeBaseStructure.TIM_Prescaler=839;


84 mhz de çalışan bir timer için 401*840/84m yapınca 0.00401 geliyor. İşin garibi benim servo sizin kodla çalışıyor, bu hesaplara göre yapınca çalışmıyor. Ben hala neyi atladığımı bulamadım.
Başlık: Ynt: stm32f407 pwm frekansını ayarlayamıyorum
Gönderen: muhittin_kaplan - 13 Ekim 2013, 23:18:52
kodları nasıl hesapladım hatırlamıyorum.
ama 400*840/16800000 yapmışım gibi
Başlık: Ynt: stm32f407 pwm frekansını ayarlayamıyorum
Gönderen: ttg - 14 Ekim 2013, 00:13:13
hocam dediğiniz hesap tutuyor. En baştaki soruna dönüyorum, neden 168000000? Hangi kaynağa baksam 84mhz de çalışıyor bu arkadaş
Başlık: Ynt: stm32f407 pwm frekansını ayarlayamıyorum
Gönderen: Klein - 14 Ekim 2013, 00:34:30
Alıntı YapAPB'den Timer3'e apb1 prescaler 1'den farklı olduğu için kendi clock unun 2 katı geliyor ve 84 Mhz ile çalışıyor dedim. Bu durumda, linkteki kodta yer aldığı gibi, prescaler yerine 840-1'den 839 yazarak Timer 3 Counter Clock'u 100 KHz yaptım.

Timer3 Clock sinyali 42Mhz değil ki iki katı 84MHz olsun. İki katı geliyorsa 168MHz olur.
Başlık: Ynt: stm32f407 pwm frekansını ayarlayamıyorum
Gönderen: ttg - 14 Ekim 2013, 00:52:24
Alıntı yapılan: Klein - 14 Ekim 2013, 00:34:30
Timer3 Clock sinyali 42Mhz değil ki iki katı 84MHz olsun. İki katı geliyorsa 168MHz olur.
Hocam apb1 max. 42 mhz, timer3 için şu linkte: http://gunluk.muuzoo.gen.tr/2012/07/29/stm32f4-discovery-maceralari-7-buton-okuma-ve-timer-kullanimi/ (http://gunluk.muuzoo.gen.tr/2012/07/29/stm32f4-discovery-maceralari-7-buton-okuma-ve-timer-kullanimi/)
şöyle bir alıntı yapılmış:
"The timers connected to APB2 are clocked from TIMxCLK up to 168 MHz, while the timers connected to APB1 are clocked from TIMxCLK up to 84 MHz."

TIM3 apb1 üzerinde olduğu için hesap kitap uğraşıp bir türlü 168 yapamadım onu. Bir de kodu aldığım örnekte şu yazıyor:
"
    In this example TIM3 input clock (TIM3CLK) is set to 2 * APB1 clock (PCLK1),
    since APB1 prescaler is different from 1.
      TIM3CLK = 2 * PCLK1
      PCLK1 = HCLK / 4
      => TIM3CLK = HCLK / 2 = SystemCoreClock /2
"

Bu da Core Clock/2 den 84 diyor.
Başlık: Ynt: stm32f407 pwm frekansını ayarlayamıyorum
Gönderen: Klein - 14 Ekim 2013, 01:10:36
Programında RCC_CFGR->PPRE1 registerinin değeri nedir?
Başlık: Ynt: stm32f407 pwm frekansını ayarlayamıyorum
Gönderen: ttg - 14 Ekim 2013, 01:29:04
4 olarak ayarlanmış:

    /* PCLK1 = HCLK / 4*/
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
Başlık: Ynt: stm32f407 pwm frekansını ayarlayamıyorum
Gönderen: Klein - 14 Ekim 2013, 01:31:37
Tamam. Gayeti güzel.  Bu durumda APB1 bus hızın 42Mhz. CLK hızın da 84MHZ.

Ben sorunu tam olarak anlayamadım.
Prescaler = 840 (Hesap kolaylığı olsun diye  -1 olması gerektiğini ihmal adiyorum.)
ARR = 2000 iken, 50HZ alamıyor musun?
Başlık: Ynt: stm32f407 pwm frekansını ayarlayamıyorum
Gönderen: ttg - 14 Ekim 2013, 11:44:42
Hocam malesef alamıyorum, ARR'yi 4000 yapınca ancak alabiliyorum.

Ayrıca Muhittin Kaplan'ın kodu ve benim 4000 yaptığımdaki kodların her ikisi de motoru 90 derece kadar ancak döndürüyor. Motor 180 derecelik. %5'tir %10'dur demeden sınırları arttırınca %5 ile %30 arasında 180 dereceyi bulabildim. Tabi yaptığım iş ne kadar sağlıklı bilmiyorum.
Başlık: Ynt: stm32f407 pwm frekansını ayarlayamıyorum
Gönderen: muhittin_kaplan - 14 Ekim 2013, 12:31:15
Simdi problemi ortaya tam koyalim.  Sen 50hz aliyor ama motoru tam donduremiyormusun?
Eger oyleyse freq degil duty ile oynaman gerekir. Birde olcecek birsey lazim sinyali
Başlık: Ynt: stm32f407 pwm frekansını ayarlayamıyorum
Gönderen: ttg - 14 Ekim 2013, 12:43:32
Ölçme işini birkaç gün sonra ancak yapabilirim, tatil günü fakülteye giriş yapamıyorum.

Ben duty cycle ile oynayıp bir şekilde kodu çalıştırıyorum.

Lazım olan şey ne yaptığımızı anlamam. 168 MHz'de nasıl çalıştığını hala anlamadım TIM3'ün, APB1 max 42 mhz, tim3 de max 84 mhz iken 168 de çalışıyor. Hesapları 168'e göre yapınca 50 Hz frekans elde ediyorum, servo çalışıyor.

Servo için gereken %5-%10 arası Duty cycle olayı işi bozuyor.

Çalışan kod için değerlerim şunlar:

  TIM_TimeBaseStructure.TIM_Period = 3999;
  TIM_TimeBaseStructure.TIM_Prescaler = 83;


Bu değerlere göre ARR=4000 ve servo motor sürmek için 200 ile 400 arası değer girmem gerekiyor.

Sorun burda başlıyor. 200 ile 400 arası değer girersem 90 derece dönüyor servo. 120 ile 480 arası gibi bir maksimum aralık belirledim deneye deneye. Bu aralıkta 180 dereceyi ancak alabiliyorum.

Yani yapmak istediğim dönüşü aldım ama anlamayınca bana bir faydası yok, projeyi öğrenme amaçlı geliştiriyorum çünkü.

Son olarak da dünden beri oldukça zamanınızı aldım, ilgilendiğiniz için çok teşekkür ederim.
Başlık: Ynt: stm32f407 pwm frekansını ayarlayamıyorum
Gönderen: Klein - 14 Ekim 2013, 17:14:24
Muhtemelen Osilatör ayarlarında bir sorun var. 
Eğer CooCox kullanıyorsan; CooCox tarafından otomatik oluşturulan startup dosyasında SysInit()   çağrıı yok.Bu yüzden osilatör internal osilatör olarak kalıyor.
Bu fonksiyonu senin çağırman gerek.

1- Main rutininin başında  SystemInit()  fonksiyonunu çağır.
2- "System_stm32f4xx.h" dosyasında aşağıdaki satırdaki 25 sayısın 8 olarak değiştir. ( Kitin üzerindeki osilatör 8 MHz)
/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */
#define PLL_M      25

3- "stm32f4xx.h" dosyasında aşağıdaki satırdaki 25000000 değerini 8000000 olarak değiştir.
#if !defined  (HSE_VALUE)
  #define HSE_VALUE    ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */


Internal osilatör  16Mhz.  @Muhittin senin örnekte de muhtemelen osilatör internal. 

Üşenmedim test ettim.  aşağıdaki ayarlarla frekans  50.00Hz.

int main(void)
{
  SystemInit();
  TIM_Config();

  /* Time base configuration */
  TIM_TimeBaseStructure.TIM_Period = 1999; // 200000 Hz/4000 = 50 Hz
  TIM_TimeBaseStructure.TIM_Prescaler = 839; // 84E6/420 = 200000 Hz
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  TIM_OCInitStructure.TIM_Pulse = 1000;

  TIM_OC4Init(TIM3, &TIM_OCInitStructure);

  TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);
  TIM_ARRPreloadConfig(TIM3, ENABLE);

  /* TIM3 enable counter */
  TIM_Cmd(TIM3, ENABLE);

  while (1)
  {}
}
Başlık: Ynt: stm32f407 pwm frekansını ayarlayamıyorum
Gönderen: ttg - 14 Ekim 2013, 17:20:53
Evet CooCox ile çalışıyorum, ağzınıza sağlık hocam sorunumu çözdünüz.
Tam system_stm32f4xx.c de update clock fonksiyonunu çağırıp tmp değişkeninin 0 olduğunu farketmiştim, mesajınızı da okuyunca anladım, o sıfırken internal osilatör çalışıyormuş. Dediklerinizi denedim çalıştı.

Tekrardan çok çok teşekkür ederim. Sanırım CooCox ile anlaşmak için oldukça zaman harcamam gerekecek:)


mesaj birleştirme:: 14 Ekim 2013, 17:28:13

Benden sonra sorunu yaşayacak olanlara ek olarak yazayım:
Sizin kodunuza ek olarak duty cycle hassasiyetini artırmak için ben şu şekilde kullanıyorum:
  TIM_TimeBaseStructure.TIM_Period = 19999;
  TIM_TimeBaseStructure.TIM_Prescaler = 83;
Başlık: Ynt: stm32f407 pwm frekansını ayarlayamıyorum
Gönderen: muhittin_kaplan - 14 Ekim 2013, 18:00:07
Hocam
Coocox un oluşturduğu dosyada HSE olarak 25Mhz ayarlanmış, bizim kart 8mhz bu işlemi düzeltmek için

https://www.picproje.org/index.php/topic,48120.0.html. (https://www.picproje.org/index.php/topic,48120.0.html.)



ve doğrusun Klein Hocam systeminit i çağırmamışım.
Başlık: Ynt: stm32f407 pwm frekansını ayarlayamıyorum
Gönderen: Klein - 14 Ekim 2013, 18:13:26
Alıntı yapılan: muhittin_kaplan - 14 Ekim 2013, 18:00:07
Hocam
Coocox un oluşturduğu dosyada HSE olarak 25Mhz ayarlanmış, bizim kart 8mhz bu işlemi düzeltmek için

https://www.picproje.org/index.php/topic,48120.0.html. (https://www.picproje.org/index.php/topic,48120.0.html.)



ve doğrusun Klein Hocam systeminit i çağırmamışım.
Örneklerde HSE değeri gibi bazı değerleri yeniden tanımlamak yerine , Tanımın nerede ve nasıl yapıldığının görülmesi açısından default değerleri modifiye etmeyi tercih ediyorum.