STM32F4 FatFS Bitmap Resim Basmada hız sorunu

Başlatan Mucit23, 22 Şubat 2018, 23:49:55

Mucit23

Selamlar

STM32F4'de SDIO ve FatFS aracılığıyla SD karttan bitmap resim okuyup 320x240 LCD ye basıyorum. Normalde 24 bit sıkıştırılmamış bir Bitmap dosyasında 54 byte'lık  header den sonra RGB RGB RGB..... şeklinde 24 bit den oluşan pixel dataları başlıyor. Resim uzunluğuna göre gidiyor böyle.

Ben normalde 320x240 boyutunda bir bmp resmi basmak için yine 320x240 boyutunda bir döngü kurup, döngü içinde her seferinde 3 byte dan oluşan bir pixel datalarını okuyup LCD ye gönderiyorum. Ve BMP Resmi Ekranda görüntülenmiş oluyor. Bu yöntem iyi çalışıyor. Fakat oldukça yavaş.

Bende pixel pixel okuyup basmak yerine Satır satır SD karttan veri okuyup LCD'ye basmayı düşündüm. LCD ekran 320 Pixel genişliğe sahip olduğu için 320x3=960Byte veriyi Tek seferde tanımlamış olduğum Diziye almam gerekiyor. Bunun için aşağıdaki gibi bir yapı kurdum.

Alıntı Yap
               for (i = 0; i < BMP.Height; i++)
               {
                  f_read(&fil, &rgb, 960, &bytesread);  //uint8_t rgb[960];

                   LCD_SetCursor(0,239-i);
                  for (j = 0; j < BMP.Width; j++)
                  {
                     *(__IO uint16_t *) (Bank1_LCD_D) = ASSEMBLE_RGB(rgb[j*3],rgb[j*3+1],rgb[j*3+2]);
                  }
               }      

Genel olarak düzgün çalışacak gibi fakat bu seferde anlam veremediğim başka bir sorun var. Bu kodu çalıştırdığımda resmin il 20-30 satırı düzgün basılıyor fakat sonrasında LCD ekrana bozuk veriler basılmaya başlanıyor. Sanki devamında Son gelen satır verisinin aynısı geliyor. Okumayla ilgili bir problem olmalı.
Resime bir bakın.

Bu sonucu alınca FatFS de sıralı okumayla ilgili bir sorun olduğu kanısına vardım. Resim alttan itibaren basıldığı için en alttan 20-30 satır düzgün çıkmış sonrasında bozmuş.

FatFS de f_read ile sıralı yüksek boyutlu veri okumada dikkat edilmesi gereken birşey varmı? Hata yaptığım yer neresi? f_read ile okunacak veri uzunluğunun sınırı nedir?

OptimusPrime

uint8_t rgb[960] deyince derleyici uyari veriyor mu? hayirdir ne yapacan 960 bayti diye? bu kadar uzun diziye mirin kirin etmesi lazim.

neyse

f_read in geri donusunu takip edersen ne derdi varmis anlasilabilir veya senin suphelerini dogruluyormu bakabilirsin.

birde asagidaki vatandas lcd nin isini birtirmesini bekliyormu? veya beklemesi gerekiyor mu?

*(__IO uint16_t *) (Bank1_LCD_D) = ASSEMBLE_RGB(rgb[j*3],rgb[j*3+1],rgb[j*3+2]);

test paleti versen rgb dizisinin icinde yien ayni sekilde mi davraniyor?
https://donanimveyazilim.wordpress.com || Cihân-ârâ cihân içredir ârâyı bilmezler, O mâhîler ki deryâ içredir deryâyı bilmezler ||

RaMu


Resim dosyasının verileri SD kartta sıralı olarak
bulunmuyor olabilir,
denemek için sd kart biçimlendirip
sd karta hiç bir şey yazıp silmeden
içine sadece ilgili resim dosyasını atıp
deneyebilirsin.


Normalde SD karttan sıralı veri okurken
512 byte veriden sonra 2 byte CRC geliyor,
yani her 512 bayt tan sonra 2 byte crc en azından atlanmalı,
bunu f_read fonksiyonu yapıyorda yapmıyorda olabilir.
Ama yapıyor gibi gözüküyor.


Kaç byte okuduğunu bir yerde yazmışlardır ama
içeriğini bildiğin bir dosyayı okuyup
okuduğun dizinin içeriğine ekranda veya debugger da bakmak çözüm olabilir.


Birde hızlandırabilirsin:
                  for (j = 0; j < 960; )
                  {
                     *(__IO uint16_t *) (Bank1_LCD_D) = ASSEMBLE_RGB(rgb[j],rgb[j+=1],rgb[j+=1]);
                     j++;
                  }

Hatta dahada hzılandırılır.
Sorularınıza hızlı cevap alın: http://www.picproje.org/index.php/topic,57135.0.html

Mucit23

@OptimusPrime Hocam 960 Byte diziye derleyici birşey demiyor. Zaten kullanılıyor sesini çıkarmaması lazım. Döngü içine çok ufak bir delay koymak faydalı olabilir ama LCD_Clear Fonksiyonunda koymamışlar.  Akşam deneyeceğim. 

Debug işini yapabilirim ama takibini nasıl yaparım emin değilim çünkü ekranın neresinde bozulacağı belli olmuyor. Ve işlemci donmuyorda. Sonuna kadar döngüyü ilerletip, gelen verileri LCD'ye iletip döngüden çıkıyor.

Elektroemre

#4
@Mucit23  öncelikle SD kartın, D0,D1,D2,D3 ve CMD pinlerinde Fiziksel Pull-up olmalı (47K gibi). Bundan kesinlikle kesinlikle emin ol.

İkincisi, f_read fonsiyonu durum döndürüyor. Bunu oku, eğer durum FR_OK değilse break ile döngüyü kır ve hata mesajı neymiş bak, ona göre daha net bir şey söyleyebiliriz. Aynı şekilde bytesread değişkenini de oku, oda muhtemelen 960 dönmüyor bir yerden sonra.

Şuan muhtemelen f_read FR_OK dönmediği yerden itibaren aynı buffer içeriğini basıyorsun.

Bunun dışında hız için optimizasyon önerileri:
*BMP 16 bit olursa, 24bit -> 16 bit çevrimine ihtiyaç ortadan kalkar ve Buffer'ı direkt DMA ile LCD basar hale gelirsin.
*2 adet buffer kullanırsanda, LCD'ye datalar DMA ile basılırken diğer buffer'a bir sonraki verileri okuyabilirsin.
*Her seferinde LCD'yi satır satır ayarlamışsın, buna gerek olmaması lazım. Tüm TFT'lerde, dikdörtgen alan veri basma için hazırlanabiliyor. Kısaca bir kez, -> 0,0 dan 319,239'a kadar bir dikdörtgen alanı set edeceksin. Daha sonra verileri arka arkaya basabilirsin.
*Sistemini yukarıdaki şekilde ayarlarsan, buffer uzunluğunu istediğin gibi serbest belirleme şansın oluyor, mesele 512byte, 1024 byte vb. Burada dikkat edilmesi gereken durum ise, DMA her seferinde SD kartta okunan veri adedince veriyi aktaracak şekilde konfigüre edilmeli.

Kolay gelsin.

Mucit23

Hocam Data hattını pull-up yapılmış olması gerekir demişsiniz. STM32F4'ün Dahili Pull-up dirençleri yetersizmi? Harici olarak 47K bağlayabilirim yinede.

Elektroemre

#6
Alıntı yapılan: Mucit23 - 23 Şubat 2018, 11:53:27
Hocam Data hattını pull-up yapılmış olması gerekir demişsiniz. STM32F4'ün Dahili Pull-up dirençleri yetersizmi? Harici olarak 47K bağlayabilirim yinede.

Kesinlikle fiziksel pull-up olmalı, dahili pull-up'larla bu tür sistemlerde hep sıkıntı yaşarsın başına bela olur.

Ekleme: Sadece Data hattı değil "CMD" hattıda pull-up lı olmalı.

Mucit23

Anladım


Akşam hemen pull-up dirençlerini ekleyeceğim. Sonrasında dediğiniz gibi f_read nerede çöküyor ona bakacağım.


Her satır basmada cursörü ayarlamamın sebebi ise Resim datalarının alttan üste doğru gelmesi, LCD ise cursörü yukarıdan aşağıya doğru kaydırıyor. Buda ileride optimizasyon ile çözülür. Ama ilk başta şu temel problemleri halletmem gerekiyor.

Elektroemre

Örnek bağlantı şeması, ayrıca SdCard'a yakın yere bir kaç uf'lik seramik smd kapasite atmak faydalı olur. SDIO modunda SdCard'ın güç tüketim karakteristiği bir miktar değişmekte.


Mucit23

Bağlantı şeklimde pek iyi değil aslında MicroSD-SD adaptörüne kablo lehimleyerek yaptım. Yüksek hızda buda problem çıkarıyor olabilir
Ben bunu komple elden geçirip öyle deneyeceğim.

Dün ayrıca SD kart beslemesini ölçtüm. 2.996V civarı, STM32F4 üzerindeki 3V dan alıyorum.

RaMu


Farklı yerlerde çöküyorsa
ya LCD yada SD kartta problem var.


@Elektroemre ye katılıyorum.En önemli noktalardan biri BESLEME,
kitten gelen muhtemelen yetmiyordur,
aynı problemi yaşadım,
sd kartı başka bir güç kaynağı ile ayrıca besledim
devre sorunsuz çalışmaya başladı.
Pull up kısmında çok emin değilim
ben 12MHz CLK SPI modda pull-up kullanmadan
ve de breadborad üzerinde SD kart çalıştırdım ama
bu iyi bir yöntemdir anlamına gelmiyor tabiki.


Beslemeye osiloskop ile bakmalısın yoksa
100nF kondansatör ve kulaklığı
farklı noktalarda beslemeye bağlayıp
curcunayı dinleyebilirsin,
dekuple kondansatörlerini eklediğinde
bu etkinin azaldığınıda görebilirsin.





Sorularınıza hızlı cevap alın: http://www.picproje.org/index.php/topic,57135.0.html

OptimusPrime

bence ilk once rgb ile test paterni olusturup bir dene bakalim lcd nin cevabi ne olacak. burada sorun cikmazsa f_read in geri donuslerini takip et. ne kadar data okuyor ne geri donduruyor vs vs. belki donanimda da degisiklikler yapman gerekebilir onerildigi uzere.
https://donanimveyazilim.wordpress.com || Cihân-ârâ cihân içredir ârâyı bilmezler, O mâhîler ki deryâ içredir deryâyı bilmezler ||

Mucit23

RGB test paterni derken şöyle birşey yapsam daha mantıklı olacak. Resim datalarını dışarıda aynı aynı şekilde 24 bit RGB şeklinde dönüştürüp program hafızasına kaydettikten sonra aynı döngü içerisinde aynı şekilde basarsam eğer LCD'nin tepkisini görebilirim. LCD de sorun olup olmadığı anlaşılır.

OptimusPrime

uint8_t rgb[960] ile devam etmen daha mantikli cunki bunu kullaniyorsun. maksat bu vatandas lcd yi beslediginde sorun goruyormusun bunu belirlemek.

uint8_t rgb[960] i 0xFF le doldur bas bakalim beyaz olacak mi? sadece r ye 0xFF ver balalim kirmizi olacakmi vs vs. bu testten gecerse okumada sorun var diyebilirsin.

maksat problemi izole etmek.
https://donanimveyazilim.wordpress.com || Cihân-ârâ cihân içredir ârâyı bilmezler, O mâhîler ki deryâ içredir deryâyı bilmezler ||

Mucit23

Selamlar

Dün akşam birkaç test yapabildim. İlk önce SD kart bağlantılarını yeniden elden geçirdim. Data Hattını 47K dirençlerle pull up yaptım. SD besleme pinlerine yakın 47uF ve 100nF paralel kondansatör bağladım. Aynı zamanda LCD ve SD kart beslemesini harici bir 3.3V LDO regülatör ile yaptım. Besleme girişini ise yine STM32F4 üzerindeki 5V dan aldım. 3.3V stabil hale geldi.

Şuanda SDIO ve FatFS haberleşmesi yine sağlanıyor. Ama Problem devam ediyor. Geçi dahada beter oldu desem yeridir. Önceden pixel pixel okuma yapabiliyordum şimdi orada da saçmalıyor. Herneyse onun sebebine yine bakacağım ama öncesinde debug ile elde ettiklerimi yazayım.

f_read ile geri dönüş ne oluyor onun çıktısını ekrana yazdırdım. Elde ettiğim sonuca göre Tek seferde 512 Byte'dan fazla veri okunmuyor. Bu durumu yaptığım testlerle açıklayayım.

FATFS de doyayı açtıktan sonra hemen 54 Byte dan oluşan BMP Header'i okuyorum. f_read ile gelen FRESULT çıktısı FR_OK olarak dönüyor. Hiçbir problem yok burada.

Okuduğum 54 byte'lık Header içerisinde Bitmap genişliği, yüksekliği, dosya boyutu ve Bitmap datalarının nereden başladığı gibi birçok parametreye ulaşıyorum. Bunlarda sıkıntı yok.

Daha sonra  f_lseek komutu ile okunacak başlangıç adresini Header bitimine 0x36(54) adresine alıyorum.

f_lseek(&fil, 0x36); //Pointeri ileri taşıyoruz.

Bundan sonrası ilginçleşiyor. Bu noktadan sonra aşağıdaki gibi 960 Byte okumaya çalışıyorum.

f_result=f_read(&fil, &rgb_data, 960, &bytesread);   

Daha sonra f_result çıktısının içeriğine baktığımda FR_DISK_ERR Hatasını alıyorum. Ve bytesread ile kaç byte okunduğuna baktığımda ise 458 byte okunduğunu görüyorum.

Daha önce Header için 54 byte okumuştuk. Yani Toplamda 54+458=512 Byte etti.

Bunu aynı şekilde pointeri farklı noktalara götürerek de denedim. örneğin Pointeri 0xF1(241) noktasına götürüyorum. Bundan sonra 960 byte okumak istediğimde yine FR_DISK_ERR ile birlikte sadece 271 byte okuyabildim. Yine 241+271=512 yapıyor.  Fakat 0xF1 den sonra örneğin 200 byte okumak istesem yine FR_OK cevabını alıyorum. Yani problem olmuyor.

Yaptığım Testlerden böyle bir bağlantı elde ettim.

Bu arada 0xF1 den itibaren 960 byte okuduğumda örneğin 271 byte okunabiliyorsa o okuduğum değerler gerçekten bitmap dosyasına ait rgb değerleri. Bir yandan Hex editör 0xF1 adresinde hangi veriler var vs görebiliyorum. Okuduğum ilk 10 değer Hex Editördeki değerlerle uyuşuyor.

Durum bu şekilde. Bu sorunu nasıl aşabilirim? Fikir verebilecek olan var mı?