Haberler:

Forum kuralları güncellendi LÜTFEN  okuyunuz:  https://bit.ly/2IjR3ME

Ana Menü

capture problemi

Başlatan gloin, 02 Ağustos 2007, 15:42:50

gloin

Atmelin AT91SAM7x256-EK geliştirme boardu üzerinde çalışıyorum. Timer ın capture özelliğini kullanarak gelen sinyalin süresini ölçmeye çalışıyorum. Aslında şu an ölçebiliyorum fakat sinyalin duty cycle ile oynayınca benim ölçümler garipleşiyor. bu tür bir uygulama yapan oldu mu acaba?
Gloin

picusta

Güzel bir board seçmissin.
Maalesef kaynak kodu vermedigin için thamin yürütmek zor oluyor.

gloin

static void configure_tc1(void)
{
    volatile unsigned long dummy;

    //önce PMC üzerinden timer clock u enable edilir
    AT91F_TC1_CfgPMC ();

    //pio yu konfigüre et
    AT91F_TC1_CfgPIO ();

    /* TC status biti sıfırla */
    dummy = AT91C_BASE_TC1->TC_SR;

    /* Set the Mode of the Timer Counter */
    AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK |
                             AT91C_TC_CLKI | // clock inverted
                             AT91C_TC_ETRGEDG_FALLING  | // external trigger on each edge
                             AT91C_TC_ABETRG  | // TIOA is used as an external trigger
                             AT91C_TC_LDRA_RISING | // Load RA on rising edge
                             AT91C_TC_LDRB_FALLING;  // Load RB on falling edge	

    AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN;
    /* Counter is reset and the clock is started */
    AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG;
}

unsigned long rising_time_val[100] = {0};
unsigned long rising_cnt = 0;
unsigned long time;

unsigned long falling_time_val[100] = {0};
unsigned long falling_cnt = 0;

void rising_edge(void)
{
    volatile unsigned long tc1_sr = AT91C_BASE_TC1->TC_SR; // tc1 status reg.

    if (tc1_sr & AT91C_TC_LDRAS)
    {
        rising_time_val [rising_cnt++] = AT91C_BASE_TC1->TC_RA;

        if (rising_cnt > 99)
          rising_cnt = 0;
    }
}

void falling_edge(void)
{
    volatile unsigned long tc1_sr = AT91C_BASE_TC1->TC_SR; // tc1 status reg.

    if (tc1_sr & AT91C_TC_LDRBS)
    {
        falling_time_val [falling_cnt++] = AT91C_BASE_TC1->TC_RB;

        if (falling_cnt > 99)
          falling_cnt = 0;
    }
}

void main (void)
{
//.....init fonsiyonları

    while(1)
    {
	rising_edge();
	falling_edge();
    }
}

programımın mantığı at91 işlemcinin capture özelliğine dayanıyor, tc1 timer/counter ı konfigüre ediyorum önce, clock source olarak MCK/2 yi kullanıyorum, bu da benim kartımda 24 Mhz. Capture edilecek sinyal
TIOA1 inputuna uygulanıyor.
* Uygulanan işaretin yükselen kenarında timerın içeriği RA registerına yazılıyor (AT91C_TC_LDRA_RISING)
* timer ın içeriği artmaya devam ediyor bu arada,
* sinyalin düşen kenarında ise timer içeriği RB register ına yazılıyor (AT91C_TC_LDRB_FALLING)
* ayrıca düşen kenarda timer içeriği sıfırlanıyor (AT91C_TC_ETRGEDG_FALLING  | AT91C_TC_ABETRG)
* Böylece RA registerında yükselen kenara kadar ölçülen süre, RB registerında ise peryodu elde ediyorum.
* Ben deneme amaçlı 100 tane ardışıl değer elde etmek için rising_time_val ve falling_time_val adında arrayler oluşturdum, elde ettiğim timer değerlerini buralara yazıyorum.

* Mesela 1 Mhz lik işaret için RA ( rising_time_val[0...99] ) değeri 12, RB ( falling_time_val[0...99] ) değeri 24 çıkıyor, TC nin 1 değeri 1/24MHz sn ye karşılık geldiğinden

RA = 500ns
RB = 1 us

oluyor, diğer frekanslar için de doğru değerler elde ediyorum, buraya kadar bir sorun yok.

Benim projemde ise değişik uzunluklarda ardışıl pulse lar var,

mesela 1.5us high, 1.5us low, ve daha sonra 8 tane 1us lik pulse.

bu işareti uygulayınca da yine frekans değeri olarak RA = 12, RB = 24 oluyor, 100 değer in hepsi de aynı, sanki sabit frekans uygulamışım gibi, bunun nedenini bulmaya çalışıyorum. Umarım çok karışık
anlatmamışımdır. Tecrübelerinizi paylaşırsanız sevinirim.

iyi çalışmalar,
Gloin

picusta

Söyle bir tahminde bulunayim :

falling_time_val[]
rising_time_val[]
degerlerini okumakta gecikiyorsun.
Bu degerleri nasil okudugunu belirtmemissin. Tahminen debugger kullaniyorsun.
       if (rising_cnt > 99)
          rising_cnt = 0;

yazdigin için eski degerlerin üzerine yaziyorsun, bu yüzden hep ayni çikiyor :
çalistigin frekansa bakilirsa (1MHz) sen degerleri okumadan programin eski degerleri siliyor (her 100us'de bir) hepsini okumak için sizeof(unsigned long)* 1M byte/sn'ye ihiyacin var.
USB 2.0 kullanmalisin (HID,CDC emülasyonu değil, kendi USB driverini yazmalisin).
Veya biraz daha akillica bir yöntem kullanmalisin : sIkIstIrma.  Sana RLE'yi (Run Lenght Encoding)  öneririm. En kolayi ve bu uygulamaya en uygun digebiliriz.
Kisaca söyle : eger ölçülen deger bir önceki ile ayni ise, sayiciyi arttir. değilse yeni bir girdi olustur.
Böylece mikro denetleyicide %50 daha fazla hafiza kaplayarak (2 * unsigned long [100] + 1*unsigned long [100]) ölçebilecegin :
100 adet farkli degerde PWM ve peryot degeri ve 100*18446744073709551616'ye kadar ölçüm.

gloin

teşekkürler cevabınız için, ben debugger olarak jlink kullanıyorum

http://www.iar.com/index.php?show=32887_ENG&reflogin=32887_ENG

burada Jtag hızı olarak 12mhz yazıyor, programımda bir hız sıkıntısı var onu ben de fark ediyorum, external trigger ile ra ve rb ye yazmayı interrupta dönüştürecem şimdi, bu polling metodunda status registerdaki flag 0 a inmeden sanki üst üste yazıyorum gibime geldi, biraz uğraşayım ben:)
Gloin

gloin

sorunumu çözdüm geçen hafta, buraya da yazdığım aklıma  geldi, Allah tan usb driver falan filan gerekmedi!:)
interrupt kullanmak çok sorunlu, atmel supporttan aldığım destek ile, bu kadar hızlı bir sinyalin ancak polling ile capture edilebildiğini öğrendim, 500khz den hızlı sinyallerde interrupt kaçırmaya başlıyor, bir de derleyicinin optimizasyon ayarlarını yapmak gerekiyor.

void main(void)
{
volatile unsigned int low_time_val[100] = {0}; unsigned int low_cnt = 100; volatile unsigned int period_val[100] = {0}; unsigned int period_cnt = 100;

	while (1)
	{
	    while((*AT91C_TC1_SR & AT91C_TC_LDRAS)!=AT91C_TC_LDRAS);
	    low_time_val[low_cnt--] = *AT91C_TC1_RA;
    	    if (low_cnt ==0)
	          low_cnt = 100;

    	while((*AT91C_TC1_SR & AT91C_TC_LDRBS)!=AT91C_TC_LDRBS);
	    period_val[period_cnt--] = *AT91C_TC1_RB;
    	  if (period_cnt ==0)
        	  period_cnt = 100;
     }
}


iyi çalışmalar,
Gloin

picusta

Yüksek frekanslar için kodlarini daha akillica yazmalisin.
Gösterdigin debugger 12Mbps 'de çalisabilir ama daha dikkatli bakarsan max:
• Download speed up to 600 KB/sec *
• DCC speed up to 800 KB/sec *
Son olarak yazdigin kod ile bastaki kod arasinda hiz açisindan pek bir fark yok.
Interrupt kullanacaksan interrupt latency'e bakmalisin tabii.

gloin

Gloin