STM32F407 Cortex M4 şamataları

Başlatan bunalmis, 16 Ekim 2011, 17:14:50

fatih6761

Implicit Declaration sadece bir örnek. Türkçesiyle Üstü kapalı bildirim demek. C de ise Method ody'si yani kodları ile tanımlanmamış fonksiyon var anlamına geliyor. Kısaca önceden tanımlanmamış fonksiyon. Bu uyarı/hata(derleyiciye göre değişir) derleme sırasında çıkar.  Derleyici bize böyle bir fonksiyon için metod içeriğinin tanımlanmadığını söyler. Eğer bağlama sırasında da derlenmiş dosyalarda bulunamazsa linker hata verir. Bunun gibi C özelliklerinden, bir programın nasıl derlendiği, nasıl çalıştırıldığı gibi konuları bilmeden yazılan programlarda bir sürü hata çıkması normaldir. Bunları açıklayan bir sürü döküman var(çoğunluğu İngilizce maalesef).
Bana kalırsa bunları öğrenmek iki aşamada... İlk aşama yanlış kod yazımı ve hatayla karşılaşma. İkinci aşama ise araştırma yapıp çözümü bulmai sorun hakkında ve ilişkili konular hakkında bilgi edinme. İnternette hata iletisini aramak bile çok faydalı sonuçlar gösterecktir. İyi çalışmalar...

cooldoubtless

anladım hocam farklı bir anlamı yok yani bildiğimiz gibi bildirimi yapılmamış ya da istenmeyen biçimde yapılmış bildirimler..açıklama için teşekkür ederim hocam..size de iyi çalışmalar..

ergen

#1067
Alıntı yapılan: gerbay - 11 Eylül 2012, 11:11:58
benim yazdıklarım sanırım tam anlaşılmadı ya da ben tam anlatamadım..

yazdıklarımı direk copy/paste ederek denemeyeceksiniz, onlar biraz pseudo kod olarak, mantığı açıklamak için yazılmış ifadeler..

kendi interrupt handler ınızı kullanacaksınız ve int1_DoWork, int2_DoWork gibi gördüğünüz kısımlarda da ilgili interrupt handler üzerinden yapmak  istediğiniz işi yapacaksınız..

interrupt handler lar mümkün olduğunca kısa tutulmak zorunda olduğundan bu şekilde bir yaklaşım ile ilgili interrupt ın işini interrupt context inde değil de CPU nun normal çalışma context inde gerçekleştirmiş oluyorsunuz.

Kendi kodunuza o mantığı uygulayacaksınız..
teşekkürler hocam şimdi daha iyi anladım biraz daha araştırma yapıcam ;)

mesaj birleştirme:: 11 Eylül 2012, 23:49:10

Alıntı yapılan: fatih6761 - 11 Eylül 2012, 14:21:16
Gerbay hocam, bu sıkıntılar arkadaşların C yi iyi bilmemesinden kaynaklanıyor. Projelere girişmeden önce en azından bir yere kadar C öğrenseler, bu sıkıntıları yaşamayacaklar. Yani Implicit Declaration'ın ne olduğunu bilmeden program yazmak yerine kitaplardan veya internetten biraz daha C öğrenrek, temel örnekleri uygulayarak kendilerini geliştirseler... Haksız mıyım hocam? Arkadaşlar bu arada yanlış anlamayın tavsiye amacıyla söylüyorum...
fatih hocam sizinle hemfikir olduğumu söylemek istiyorum ben de şuan sizin bahsetmekte olduğunuz aşamadayım çeşitli uygulamalar yapıyorum c yi ögrenmek içn. bu forumdaki bülent hocamızın yazdığı bütün yazıları okudum ve uyguladım vakit buldukça yeni kaynaklar da arıyorm.ben sorularımın tabiki de tam karşılığını istemiyorum öyle bir lüksüm yok fakat en azından yol göstermesi açısından çok faydalı olduğunu düşüyorum.neyi araştırcağımı ögrenmem yeterli oluyor.her yeni bişey sorduğumda birönceki sorumun ne kadar saçma bir soru olduğunu ben de farkediyorum.bu da öğreniyor olduğumu gösteriyor.ben böyle düşünüyorum yardımlarınızı esirgemezseniz sevinirim.

cooldoubtless

Interrupt kullanarak yazılımsal PWM sinyalleri üretmek

Aşağıda 8 kanallı yazılımsal olarak PWM sinyal üreten örnek yazılım görülmektedir. RC Servo çalışması yapmak isteyenler için PWM peryodu  20 mili saniye seçilmiş olup her bir PWM  0..1000 aralığında değer alabilir. Programda değişiklik yapıp, PWM kanallarının sayısını dilediğiniz kadar artırabilirsiniz.
#include "STM32F4xx.h"
 
unsigned short PWM[8];  // PWM registerler
unsigned short SRG[8];  // Shadow Registerler
unsigned short CNTR;    // PWM Counter

/*****************************************************************************************************
         CPU PLL ile 168Mhz de kosturulur
         AHB frekansy 168 Mhz
         APB1 frekansy 42 Mhz
         APB2 frekansy 84 Mhz
*****************************************************************************************************/
void SystemInit()
{
unsigned int i;
     for (i=0;i<0x00100000;i++);     // OSC oturtma ve kurtarma rutini
     RCC->CFGR |= 0x00009400;        // AHB ve APB hizlarini max degerlere set edelim
     RCC->CR |= 0x00010000;          // HSE Xtal osc calismaya baslasin        
     while (!(RCC->CR & 0x00020000));// Xtal osc stabil hale gelsin
     RCC->PLLCFGR = 0x07402A04;      // PLL katsayilarini M=4, N=168, P=2 ve Q=7 yapalim
     RCC->CR |= 0x01000000;          // PLL calismaya baslasin  (Rehber Sayfa 95)
     while(!(RCC->CR & 0x02000000)); // Pll hazir oluncaya kadar bekle
     FLASH->ACR = 0x00000605;        // Flash ROM icin 5 Wait state secelim ve ART yi aktif edelim (Rehber Sayfa 55)
     RCC->CFGR |= 0x00000002;        // Sistem Clk u PLL uzerinden besleyelim
     while ((RCC->CFGR & 0x0000000F) != 0x0000000A); // Besleninceye kadar bekle
     RCC->AHB1ENR |= 0x0000000F;     // GPIO A,B,C,D clock'u aktif edelim 
     GPIOD->MODER  = 0x55550000;     // GPIOD nin 15, 14, 13, 12, 11, 10, 9, 8 pinleri cikis tanimlandi (LEDler icin)
     GPIOD->OSPEEDR= 0xFFFFFFFF;     // GPIOD nin tum cikislari en yuksek hizda kullanacagiz 

     RCC->APB1ENR|=0x00000020;       // Timer7 CLK'u aktif edelim (84 Mhz)
     TIM7->CR1=0x0080;               // Otomatik Reload
     TIM7->PSC =839;                 // Prescaler degerimiz 839, Count frekansimiz = fCK_PSC / (Yuklenen Deger + 1) 84E6 / (840) = 100 KHz
     TIM7->ARR =1;                   // Counter, Decimal 1 olunca basa donsun. Her 20 mikrosaniye de bir timer int olusacak.
     TIM7->DIER=0x0001;              // Update Int enable
     NVIC->ISER[1] = 0X00800000;     // NVIC de Timer 7 interrupta izin verelim
     TIM7->CR1|=0x0001;              // Counter Enable
     
} 

 
void TIM7_IRQHandler()
{
unsigned short d,i,j;
 
    TIM7->SR=0;                       // Timer Int Flagini silelim 
    d=GPIOD->ODR & 0x00FF;
    CNTR++;
    if(CNTR>=1000)
      {
        CNTR=0;
        for(i=0;i<8;i++) 
         { 
           if(PWM[i]>1000) PWM[i]=1000;
           SRG[i]=PWM[i]; 
         }  
      }
    j=0x8000;
    for(i=0;i<8;i++)
      {
       if (CNTR>=SRG[i]) d|=j;
       j=j>>1;
      } 
    GPIOD->ODR=d;
} 

int main()
{
    
    PWM[0]=100;
    PWM[1]=200;
    PWM[2]=300;
    PWM[3]=400;
    PWM[4]=500;
    PWM[5]=600;
    PWM[6]=700;
    PWM[7]=800;
    
    while(1);
}


tahmin ettiğiniz gibi bu örnek bunalmış hocamızın yazdığı örnek..başlangıçta rc servo çalışmaları için 20 ms lik periyot demiş ancak daha sonra programda 20us lik periyotlar oluşturmuş..100khz yani..burada minik bir yanlışlık var sanırım..şimdi asıl sormak istediğim şu..burada yazılımsal pwm üretme çabasında değilim..donanımda zaten mevcut ancak sonucta orada da prescaler arr gibi değerler bildirerek bu değerlere ulaşmam gerekiyor..dolayısıyla 84 Mhz lik bir timer ile çıkışta 100 hz lik yani 20 ms lik çıkış veren bir dalga üretmem gerek.. bu durumda prescaler değerim 65 binin üzerinde bir değer oluyor ki bu imkansız . sizce nasıl bir yöntem izlemeliyim?

fatih6761

@coldoubtless zamanlayıcıları hesaplarını tekrar yapsak iyi olur.
İstediğimiz PWM frekansı 50 Hz.
Timer 84 MHz ile besleniyor. PSC ve ARR registerları 16 bit. Yani maksimum 65535 olabilir.
Formül.1 :: Prescaler = (TIM3CLK / TIM3 counter clock) - 1
Burada TIM3CLK 84 MHz oluyor. TIM3 Counter clock ise istediğimiz timer frekansı. Eğer ön bölücü değerini 42.000 olarak ayarlarsak, Timer frekansı 2000 Hz olur.
TIMx->PSC = 41999; // 42000 - 1
Timer 2000 Hz ile çalışıyor. Biz ise 50 Hz istiyoruz.
Formül.2 ::ARR = (TIM3 counter clock / TIM3 output clock) - 1
Burada Counter Clock'u 2000 olarak belirledik. Output clock ise 50 olacak. Formülden
TIMx->ARR = 39; // 2000/50 = 40, 40 - 1  = 39
Ve bu şekilde 50 Hz de, yaklaşık 5,32 bit çözünürlükte ( log2(40) ) bir PWM sinyalimiz oluyor. CCR değerine ise 40 ta X olacak şekilde Duty değerini yüklüyoruz.
Donanımsal PWM nin nasıl çalıştığını biliyorsanız bu hesapları kolaylıkla yapabilmeniz gerekir. Bu PWM sistemini örnek alan 74hc serisinden bir pwm donanımı yapmıştım. Eğer isterseniz devreyi gösterebilirim daha net anlayabilmeniz için.Bu arada 20 ms lik çıkış için 100 hz değil 50 hz kullanmanız gerekir : T = 1/f

cooldoubtless

sağolun fatih hocam hayır sağolun bu dediğinizi denedim ancak yine esc den tepki alamayınca yanlış olduğunu düşünmüştüm..bu 100 hz olayını da son incelediğim bir kaç örnekte gördüm. özellikle bunalmış hocamızın gösterdiği..burada arr değeri reload yapıldığında tekrar bir okadr sürenin geçtiğini gösteriyor..yanii 10ms beklerken 20ms oluyor..yani direk istediğimiz değer için 1/f yapamıyoruz eğer verilen örnekler yanlış değil ise tabiki..2 ileti önce paylaştığım örnekte de  görüldüğü gibi 100khz yani 10mikro saniye oluyor ancak 20 mikro saniye olarak periyot belirleniyor..bu arr sadece 1 olduğunda geçerli olan bir durum mu?

fatih6761

#1071
Arr yi bir yapmak zaten yanlış bir durum. İsterseniz ben size sistemi anlatayım.
Sistemden Timer'a 84 MHz lik bir saat sinyali geliyor. Bizim PSC ön bölücümüzün count register'ı her saat sinyali geldiğinde bir artıyor. Ta ki Count = PSC olana kadar. Count = PSC olduğunda Timer Count register'ı bir artıyor. Başta çıkış 0. Timer sayıyor, devam ediyor ve bir anda Count = CCR oluyor. Bu anda çıkış tersleniyor. Yani çıkış 1 oluyor. Saymaya devam ediliyor ve Count = ARR olduğunda çıkış tekrar tersleniyor.
Yani (CCR / ARR) * 100 = % Duty oluyor.
Devre şemasında:

Çalışma sırasında ARR = 8 ve CCR = 2

Resimde de toplam periyot 800 mikrosaniye, Duty süresi ise 200 mikrosaniye. Sistem bu şekilde çalışıyor. Çıkış frekansı PSC ve ARR ile belirleniyor. Çözünürlük ise ARR ile belirleniyor. Önceki mesajımda verdiğim örnekte 40 çözünürlükte ( yaklaşık 5.32 bit ) 50 Hz lik frekansı üretir. Arr yi bir yaparsanız CCR değerine göre ya %50 yada %100 duty üretebilirsiniz. Benim verdiğim hesap ile istediğiniz gibi sürebilirsiniz.

ergen

#include "STM32F4xx.h"

// FCPU =168Mhz
// FAHB =FCPU
// FAPB2=FCPU/2
// FAPB1=FCPU/4

void SystemInit()
{
unsigned int i;

    for (i=0;i<0x00100000;i++);     // OSC oturtma ve kurtarma rutini
    RCC->CFGR |= 0x00009400;        // AHB ve APB hizlarini max degerlere set edelim
    RCC->CR |= 0x00010000;          // HSE Xtal osc calismaya baslasin        
    while (!(RCC->CR & 0x00020000));// Xtal osc stabil hale gelsin
    RCC->PLLCFGR = 0x07402A04;      // PLL katsayilarini M=4, N=168, P=2 ve Q=7 yapalim
    RCC->CR |= 0x01000000;          // PLL calismaya baslasin  (Rehber Sayfa 95)
    while(!(RCC->CR & 0x02000000)); // Pll hazir oluncaya kadar bekle
    FLASH->ACR = 0x00000605;        // Flash ROM icin 5 Wait state secelim ve ART yi aktif edelim (Rehber Sayfa 55)
    RCC->CFGR |= 0x00000002;        // Sistem Clk u PLL uzerinden besleyelim
    while ((RCC->CFGR & 0x0000000F) != 0x0000000A); // Besleninceye kadar bekle
    RCC->AHB1ENR |= 0x0000000F;     // GPIO A,B,C,D clock'u aktif edelim 
    GPIOB->MODER = 0x00000015;      // GPIOB nin 0,1,2 pinleri cikis tanimlandi (LEDler icin)
    GPIOB->OSPEEDR= 0xFFFFFFFF;     // GPIOD nin tum cikislari en yuksek hizda kullanacagiz 
	  RCC->APB2ENR|=0x4000;           // SYSCFG Enable
	  GPIOA->PUPDR |= 0x00000008;
} 

volatile int countingSemaphore1 = 0;

void EXTI1_IRQHandler ()
{
	  countingSemaphore1++;
    
} 
void ledyak(void)
{
	  EXTI->PR|=0x00000002;           // EXTI1 INT flagimizi silelim
	  GPIOB->ODR^=0x00000007;         // Toggle islemi
}


int main()
{
		
//  Butona basinca pinimiz H oluyor
    GPIOA->MODER &=~0x0000000C;      // GPIO pin ancak inp modunda interrupt uretebilir (Rehber 143)
	  
    SYSCFG->EXTICR[0]&=~0x000000F0; // GPIO A1 interrupt uretecek
	  EXTI->RTSR=0x00000002;          // Yukselen kenar tetiklemesi yapacagiz. (EXTI1)
	  EXTI->FTSR=0;                   // Dusen kenar tetiklemesi istemiyoruz.  (EXTI1)
    EXTI->IMR=0x00000002;           // EXTI1 Int enable (Rehber 202-203)
    EXTI->EMR=0;                    // Event istemiyoruz
    NVIC->ISER[0] = 0x00000080;     // NVIC EXTI1_IRQ interrupti acalim
 	  while(1)
	  {
			if(countingSemaphore1 > 0)
			{
				 countingSemaphore1--;
				 ledyak();
      }
    }
}


Birz araştırma yaptıktan sonra bu kodları yazdım yalnız şöyle bi problem var butona bastığımda interrupt a girip countingSemaphore1 değişkenini 1 artırma yapmıyor o yüzden led yanmıyor.debug yaparken değişkeni artırıyorum bu sefer normal çalışıyor.neden interrupt a girmez anlamadım yardımcı olurmusunuz.

cooldoubtless

#1073
tamam o halde arr yi 1 yapmadığımız sürece iki katı çıkma gibi bir olay da yok her şey bildiğimiz gibi yürüyor diye kabul ediyorum fatih hocam çok teşekkür ederim uğraşıp yazmışsınız o kadar..açıklamalar yeterli oldu ancak eklediğiniz resimler çıkmıyor söleyeyim dedim :)

mesaj birleştirme:: 12 Eylül 2012, 19:04:41

@ergen interruptlara izin verme işlemini  SystemInit fonksiyonunun sonunda yaparak denermisin bir de..saymasını istiyorsun ama interrupta programın sonunda izin veriyorsun..çok anlamam ama böyle bakınca sıkıntılı olmuş gibi geldi..hocalarımız daha iyi bilir tabi..

mesaj birleştirme:: 12 Eylül 2012, 20:01:40

fatih hocam dediğiniz ayarlarla da denedim yine motoru döndüremedim..aslında sıkıntı bu esc lerde kaynaklanıyor..yani programda sıkıntı yok belli..bana bu esc lerle çalışmış bir yol gösterici gerek :) aşağıda bu konuda türkçe bulunan tek bilgiyi paylaşıyorum...

ESC'lerin hepsi aynı aralıkta çalışmasa da genelde 0.9ms – 1.8ms high (yani lojik 1) ve ardından göndereceğiniz 20ms'lik low (yani lojik 0) sinyali ve bunun devamlı olarak ESC'ye iletilmesi ile çalışırlar. Güvenlik açısından motorun başlangıçta hızlı dönmeye başlamasını engellemek için kumandanız dahi olsaydı throttle kolunu en aşağı yani minimum düzeye getirerek çalıştırmanız gerekecekti. Minimum throttle konumuna getirilmeyen bir kumanda ile motorların başlaması için gereken sesi duymak mümkün olmayacaktır. (şu beep-biip-beep-biip sesi yani  ) İşte bunu mikroişlemciyle de böyle yapmalıyız ki motorlar güvenli bir şekilde çalışmaya hazır olsunlar. Bunun için başlangıçta ESC'nin BEC'inin sinyal ucuna 0.9ms kadar lojik 1 ve 20ms lojik 0 bilgisi göndermeliyiz. Bu aşamada motordan o başlamaya hazır oldugunu bildiren sesi duymalıyız. Ardından motorlar nihayet çalışmaya hazır olacaklar. Tek yapmanız gereken 0.9ms olan lojik 1 bilgisini 0.9ms değerinden daha yüksek bir değere çıkarmak.

Sizce sorun bu mudur? sadece motordan bipp bipp bipp diye sürekli ses geliyor baktım anlamına bu ses "throttle signal is abnormal" diyor..uğraşmış birisi varsa bu konuda lütfen yardım bekliyorum..

fatih6761

#1074
Başka bir forumda şöyle denmiş:
Sadece ESC'nin sinyal girişine %10'luk 50hz'de PWM darbesi girmen gerekiyor. Darbe genişliğin 1 ile 2.2 milisaniye arasında olmalı.
Cevap net: %10 luk 50 hz pwm.  CCR değerine 4 yükleyip aynı değerlerle tekrar deneyin. Olmazsa yazılımsal PWM kullanarak çalışıyor mu onu görelim..
Not : Resimleri düzelttim...

cooldoubtless

ne yazık ki olmadı hocam esc de korkunç ısındı çok ilginç gerçekten..motor biipp bipp bipp sesine sürekli devam ediyor her ses geldiğinde de motor sanki döncek gibi bir titriyor ama dönmüyor :s

marecrisium

Elimdeki ESC ve uzaktan kumandadan aldığım ölçümlere göre,alıcıdan ESC ye giden data kablosunda 50 Hz'lik bir PWM var.Başlangıçta %5 genişlikte ve motor hızlandıkça değer artıyor. En fazla %10 oluyor. Bundan yüksek değerler ESC yi yakabilir bence. PWM'in genliği de 5 V.

cooldoubtless

#1077
hocam 5 v genlik ve isterse %100 doluluk oranı olsun en fazla 5v olabilir esc gerilimi..5v ile de yanmaz heralde diye düşünüyorum..en sonunda heralde artık receiver ile kontrol edicem bu motorları..

NOT= %5 ile de denendi..yine tepki yok..

marecrisium

Hocam biraz önce denedim Discovery kartı ile kontrol ettim ESC'yi. 3 volt ile de sinyal iletiliyormuş. 50 Hz %5-%10 PWM ile hız kontrolü yapılabiliyor.

cooldoubtless

ciddi olamazsın hocam hemen bana bir vidyo resim bir şeyler gönder nasıl heyecanlandım :D kodlar bizim kodlar değil mi yoksa kendin mi yazdın? ben benim vidyoyu ekliyorum izlerseniz bir zahmet motor aynen bole oldgu yerde debeleniyor..

SNC00208