FFT dönüşümü hakkında

Başlatan Mucit23, 31 Ocak 2014, 00:08:32

mistek

Stm32f1 serisi ile benzerdir belki örnek olması açısından

İlk olarak saat frekansı değiştirilecek. Siz en küçük bölme oranını kullanın. (2 oluyor sanırım)
RCC_ADCCLKConfig(RCC_PCLK2_Div4);   //ADCCLK = PCLK2/4;

Sonra şöyle bi fonksiyon varsa
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);//Çevrime girecek kanal, sırası ve çevrim hızı

ADC_SampleTime_55Cycles5 kısmını değiştirin. Kütüphane içerisinde tanımlı olan en küçük olanı yazın.

RM0090 numaralı dokümanda 271. sayfada şu yazılmış.
Tconv = Sampling time + 12 cycles. Yani siz sample time belirledikten sonra üzerine 12clock daha koyacaksınız bu sizin çevrim sürenizi verecek. Örnekte var o sayfada.


f407 donanımını çok bilmediğim için çat pat bilgi yazabildim.

DMA ayarında bişey yok. ADC değerinin yazılacağı değişkeni 64 elemanlı dizi yapın. Hafıza adresini 1 artacak şekilde ayarlayın.

Yine f100 den örnek kod.
uint16_t ADC_dizisi[64] = {0,0};

	DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; // Datanın alınacağı adres
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_dizisi; // Datanın yazılacağı adres
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // ADC kaynak. Veri yönü ADC->hafıza
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //Donanım adresi sabit kalacak
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //Hafıza adresi artacak
	DMA_InitStructure.DMA_MemoryDataSize =DMA_MemoryDataSize_HalfWord;//Hafıza uzunluğu 16bit
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//Okunacak data uzunluğu 16bit
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//Çember modu
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;//DMA önceliği yüksek
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//Hafızadan hafızaya kayıt yok.
	DMA_InitStructure.DMA_BufferSize = 64; // 64 eleman
boş işlerin adamı ---- OHM Kanunu: I = V/R ---- Güç Formülü: P = V*I = I^2*R = V^2/R

berat23

bence dma kullanmayabilirsin. adc'den int. ile data alırsın(veya dma ile buffer'a doldur herneyse), bunları N uzunluklu bufferda kaydedersin. buffer dolduğunda bir sinyalle bunu belirtirsin. bu sinyali alan fft taskın bu verileri alır, hesaplama yapar. hesaplama bitince sonuçlandı diye bir sinyal daha çıkar. bu sinyali alan görüntüleme taskıda görüntüyü ekrana basar. toplamda 2 task ile bu işi halledebilirsin. bence önce tasklar nasıl konuşur ona bak.

camby

Alıntı yapılan: berat23 - 13 Şubat 2014, 09:15:13
bence dma kullanmayabilirsin. adc'den int. ile data alırsın(veya dma ile buffer'a doldur herneyse)
INT ile veya benzeri yöntemle okuma zamanlama sorunlarının oluşmasına sebep olabilir.

Kesmelerin okumaların arasına başka fonksiyonlar daha yüksek öncelikli kesmeler vs girebilir.

En garanti yol ADC , DMA . DMA kesmesi geldiğinde iş bitmiş demektir.

ADC'yi full clock speed çalıştırmak istemiyorsanız , bu 2'liye Timer da ekleyebilirsiniz.

Timer'ın her dürtüsünde ADC alır , DMA yazar . N adet olunca DMA kesme verir. Bunları arka planda yapmanız önemli çünkü muhtemelen bir önceki alınan sinyalin de FFT'si alınıyor yada ekrana basılıyor olacak o sırada.

berat23

bu yorum rtos mantığına aykırı. işletim sisteminde zaten zamanlamayı sağlayacak yapılar vs. var, burada kullanılan işlemcide iç içe int. alma veya priority ayarlama gibi özellikler bunun için var. dma zamanlamayı garantiler diy birşy yok, dma int. da kaçabilir.

camby

#34
Alıntı yapılan: berat23 - 13 Şubat 2014, 10:52:01
bu yorum rtos mantığına aykırı.

Ben Rtos için yazmadım zaten, NO OS bir sistemde bu şekilde yapılabilir.

-----

ADC ölçümü yapıp sonucu yazdığında DMA bu veriyi alıp , ram'de başka bir yere yazıyor biliyorsunuz.

Yada ADC bu sonucu yazdığında INT üretiyor.

Eğer mevcut Interrupt'ı okuyamadan ( daha yüksek öncelikli işler yüzünden ) yeni interrupt gelirse aradaki veriyi kaybedersiniz ve 2 örnek orası 1us kabul ettiğimiz değer aslında 2us olur.

DMA ile yaptığımızda bu ihtimal ortadan kalkmış oluyor. Ve ADC verisi okuyup biyere yazmaya komut harcamıyoruz.

2 örnek arası nasıl olsa 1us , 1us 'de haydi haydi yetişiriz diyebilirsiniz ama bu durum program şiştikçe değişebilir. Öncelikli işleriniz daha fazla komut isteyebilir.

Yada 1MSPS örnek değilde LPC4370 ile 80MSPS ile örnek aldığımızı düşünelim. Bu durumda 2 INT arası süre 12,5ns ye kadar iner.

DMA kullanmadan bu veriyi yakalamaya çalışırsanız iş zor. Bir de işletim sistemi ile neler olur , onu hiç bilemiyorum.

Mucit23

Eğer DMA'nın bu tür yetenekleri var ise hiç timer kesmesiyle felan kendi programımı karıştırmak istemem.

Aslında anladığım kadarıyla sadece DMA+ADC ile olacak iş değil. Çünkü ADC örnekleme fekansını ayarlayamıyoruz. Bu yüzden timer kullanmak zorundayız. 
Aslında şurda güzel bir örnek buldum. Timer ile DMA tetikleniyor, DMA ise ADC den örnek alıp değişkene yazıyor.
http://www.wolinlabs.com/blog/stm32f4.adc.dsp.dac.html

Şunu anlamıyorum. Diyelim timer işlemlerini felan hallettim. istediğim frekansta DMA yı tetikliyorum. Oda ADC den örnek alıyor bana

Hala şunu nasıl yapacağımı kestiremedim. 

Timerden her tetikleme geldiğinde DMA ADC yi alır benim 64 elemanlı bufferimin sıradaki elemanına yazar. Dizinin bütün elemanlarına yazıldığı zaman baştan başlıyacak. İşte ben bunu nasıl anlayacağımı bilmiyorum.

Diyelimki Ben bufferdeki elemanları alıp FFT'ye sokacağım. Fakat bir yandan timer dma adc koşuşturup benim bufferimdeki değerleri güncelliyor. Yani Bufferdeki değerler sürekli değişeceği için bufferin yarısı eski değer yarısı yeni değer olabilir.

Ben isterimki DMA bütün diziyi doldursun sonra bir flag'ı set edip beklesin. Ben FFT rutinin başında bu set edilen flag'a bakıp DMA işini bitirmişmi ona bakayım. Bitirmişse diziyi alıp flagı resetleyip Ben FFT ile uğraşırken tekrar DMA nın çalışmasına müsade edeyim. Yapmak istediğim tam olarak böyle birşey

@Klein hocamız şu konuyu biraz aydınlatsa valla çok iyi olurdu

camby

#36
Mucit,

Basitlik açısından timer kullanma başlangıçta, sadece ADC_Prescaler_DivX değeri ile ADC nin sample sayısını datasheetteki hesaptan belirle. Ona göre FFT'ni hesapla.
Yani ADC hesaplanamıyor gibi bir durum yok, ben bu şekilde kullanıyorum , hesap tamamen Bus hızından ve datasheetteki adc ölçüm hesabından geliyor.

Diğer konu,

DMA modları var DMA_Mode_Normal veya DMA_Mode_Circular diye . DMA_Mode_Normal 'de iş bittiği zaman DMA kapanıyor. Yani şöyle diyeceksin 64 adet örnek al ve bana kesme üret. Kesme geldiğinde de artık istediğin işi yaparsın. Bülent hocanın ilk DMA örneklerinde de vardı bu.



mesaj birleştirme:: 13 Şubat 2014, 11:47:31

Bir ara konuşmuştuk  burada :

https://www.picproje.org/index.php/topic,45986.msg340626.html#msg340626

----

Hesap da Ref manuel 215. sayfada var :

Alıntı YapThe total conversion time is calculated as follows:
Tconv = Sampling time + 12 cycles
Example:
With ADCCLK = 38 MHz and sampling time = 3 cycles:
Tconv = 3 + 12 = 15 cycles = 0.5 μs with APB2 at 60 MHz

Yani sampling time 3 iken , 15 cycle de bir ölçüm yapılıyor.

Bus frekansı ile doğrudan çıkarabilirsin MSPS hızını.

Bus bölücü ile de hızı indirebilirsin. Yukarıdaki başlıkta konuştuğumuz ve ST'ye kızdığımız ise max hızın 60MHz 'lik bus hızında yakalanabiliyor olması. Halbuki bus 84MHz kullanılıyor.

Ama bunlar önemli ayrıntılar değil FFT geliştirmek için.

Mucit23

Anladım @camby teşekkürler, Akşam deemelere devam edeceğim.

Peki FFT için şunu sorayım. DMA, fifo modunda olsa, durum nasıl değişir.

Her ADC okunuşunda yeni bir eleman diziye eklenecek, Sondaki eleman silinecek. Yani dizideki elemanlar kayarak sürekli değişecek. Ben bu durumdaki iken herhangi bir zamanda dizinin FFT'sini alsam sonuç nasıl değişir. Gerçek bir sonuç elde edermiyim.

camby

FFT nin çalışması açısından soruyorsan bilemiyorum, infinite ve finite fft versiyonları olabilir.

Ama yazılımsal yapılan bu işlem FFT'nin sonucunu etkiler.

Örneğin değeri 0 - 100 arası değişen bir sinüs örnekliyor ol. Sinüsün tepe değerinden buffer yazma sırası başa döndüğünde 100 ve 0 değeri yanyana olacak ve yüksek frekansta bir pik göreceksin FFT'den. Fakat aslında böyle bir durum yok , sadece sinüs frekansında tek bir bileşenimizin olması lazım.

Kayıt yapılan buffer da FIFO olursa böyle bir durum kalmaz aslında. Yeni gelen data baştan girer , sonunca sondan çıkar , her okuma yapıldığında en güncel N adet veri olur.

DMA_FIFOMode diye bir opsiyon da var , kullanmadım ama belki buna yarıyor olabilir.

Ama şu an için : ADC+DMA kur , her DMA kesmesinde FFT al , FFT bitince tekrar ADC+DMA kur gibi bir sıralı yapı kullanabilirsin.

STM DSP libraryleri içinde hazır yazılmış örnekler var , birkaç çeşit vardı sanırım , bu örnekler hazır sinyal dizilerinden çalışıyor , görmüşsündür sende , bu dizileri kullarak ADC+DMA karıştırmadan başlanabilir aslında.

bocek

mucit şurda tam sana göre bir örnek var:

http://projectproto.blogspot.com.tr/2010/06/mini-stm32-wave-audio-player.html

CoOS kullanarak bir yandan led yakıp söndürürken bir yandan da wav dosyası çalıp spectrum grafiğini ekrana basıyor.
1 ya da 0. işte 'bit'ün mesele..

Mucit23

Biliyorum hocam o projeyi, Aslında bi ara dedim oradaki FFT kodlarını kullanayım dedim ama mantığını anlamadım. Tek bir fonksiyon yok. CoOS'u zaten oradan alıntıladım...

Mucit23

FFT ve örnek alma işlemini hallettiğimi düşünüyorum. Bundan sonra biraz görselliğe ağırlık vereceğim. Tahiminimce bargraph çizimi konusunda master yapmam gerekecek.

Görüntüyü yumuşatmak için aşağıya düşüşleri yavaşlatmak gerekiyor. Yani FFT sonucunda elde edilen peak değerine kadar bargraph dolacak, Boşalırken ise belli bir hızda inmesi gerekiyor.

Benim şuan yaptığım işlem fft sonucunda elde edilen peak değerine kadar barı'doldurup, geri kalan kısımları boşaltıyorum. Dolayısıyla çok keskin oluyor.

Bu bahsettğim işlemi  nasıl yaparım? Fikri olan varmı?

mistek

Program nasıl işliyor bilmiyorum ama şöyle bişey olabilir.

En tepe değerden aşağıya doğru döngü boyunca birer birer azalarak insin eğer yeni veri gelirse yine sıfırlanıp en tepeden aşağı doğru insin. Program zaten yavaş akıyorsa kendi halinde bi süzülme gibi görünecektir diye düşünüyorum.

Mesela 100 tepe değerse sonraki FFT çevrime kadar ana döngüde
99 göster
98 göster
97 göster

Değerlere göre birer birer değilde 3-5 gibide olabilir.



boş işlerin adamı ---- OHM Kanunu: I = V/R ---- Güç Formülü: P = V*I = I^2*R = V^2/R

z

FFT sonucunda n tane frekansin genligini buldun diyelim.

Bu noktadan sonra elektronik dusun.

Bu gerilimlerin her birini ayri ayri diyodlarla dogrultup kapasitorlere ve paralelindeki direnclere verdigini dusun.

Bu durumda kapasitor uclarindaki gerilim, yeni fft genliklerinden daha dusukse kapasitor voltajini yeni degere set et.

Aksi durumda kapasitor voltajini direnc etkisiyle yavas yavas dusur.

Bu olayi yazilimla yapacaksin.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

Mucit23

Teşekkürler, Birşeyler canlandı aklımda. Biraz çalışmam gerekiyor.

Birşey sorayım

LCD arayüzü için EMWIN tarzı bir sistem gömsem nasıl olur?