TFT ekranların SPI girişli ve 8/16 bit paralel girişli tipleri var. Bunlar data girişleri, ayrıca veri akışını kontrol eden kontrol pinleri de var.
Bu yayının konusu olan SPI girişli TFT lere ilk el attığımda, TFT ye gönderdiğim her byte öncesinde ve sonrasında TFT_RS ve TFT_CS kontrol pinleri ile senkronizasyon sağlıyordum. Tabi ki bu çok yavaş ve CPU yu meşgul eden bir yöntem idi. Çok kısa bir süre içinde bu yöntemi terkederek, çoklu veri paketleri gönderdiğim, kesmeleri kullandığım yöntemlere geçtim. TFT de görüntüleme hızları konusunda katettiğim yolu anlattığım yayına ulaşmak için burayı tıklayınız.
TFT’yi daha da hızlandırıp CPU üzerindeki yükü olabildiğince hafifletmek için DMA -Direct Memory Access- yöntemini kullanmaya başladım. Bunun nasıl yapıldığını anlatacağım.
KULLANILAN CPU VE TFT
Kullandığım geliştirme kiti kendi tasarımım olan STM32F103RB 64 pin CPU tabanlı “MINIKIT_S” olarak adlandırdığım modül. Bu modül üzerinde 2.4″ ve 1.8″ SPI girişli TFT lerin doğrudan takılabileceği soketler var. Buradaki örnekte 2.4″ olan 320×240 çözünürlüklü ILI9341 sürücülü bir TFT kullanıyorum.
ULAŞILAN PERFORMANS
Sonuçta ulaştığım performansı en baştan belirterek devam edeyim. İki durumda DMA kullanılan ve kullanılmayan yöntemlerin hızlarını karşılaştırdım:
Bunlardan birincisi aşağıdaki komut ile 12 piksel fontlarla ekrana 50 karakterlik satırın yazım süresi:
TFT_ShowString(10,150,12,”**** * TFT SPI DMA R1 – SELCUK OZBAYRAKTAR *****”,YELLOW,0);
Bu satırı DMA kullanmadan yazdırdığımda 38ms, DMA kullandığımda ise 36ms sürüyor. Büyük bir fark yok. Çünkü bu satır ekrana tek bir blok olarak değil, her biri 12x6x2=48 byte’lık font paketleri halinde gönderiliyor. Bu durumda DMA nın faydası çok belirgin olmuyor. Her bir karakterin başında ve sonunda CPU font penceresini ilerletmek üzere kontrol sinyalleri ile akışa müdahil olmak zorunda kalıyor.
Bir satır uzunluğunda bir pencere tanımlayan çok daha verimli ve hızlı bir yöntem geliştirilebilir. İlk fırsatta buna el atacağım. Bunun pek bir önceliği yok bugün için. Çünkü projelerimde ekran ve kullanıcı girişlerini kotaran, yine STM32 tabanlı bir servis modülü kullanmaya başlıyorum. Böylece HMI – kullanıcı arayüzü işlerini, zamana karşı yarışarak asıl işi yapan CPU nun üzerinden alıyorum.
Güncelleme Haziran 2020 : Bu algoritma geliştirme işini yaptım. Yeni yayına ulaşmak için burayı tıklayınız : STM32 - SPI TFT HIZLARI
Diğer durum ise DMA nın etkisini çok daha belirgin olarak görmemizi sağlıyor. TFT_Fill() fonksiyonu ile ekranı tek bir pencere olarak tanımlayıp 240×320*2=154.6 kB lık bir paket halinde gönderdiğimizde : DMA anın kullanılmadığı durumda 245 ms olan süre DMA ile 85ms ye düşüyor.
Sonucu özetlersek :
TFT_RS Set, TFT_CS Reset, N adet byte gönder, TFT_CS_Set
şeklindeki veri gönderme çerçevemizde, ortadaki “N adet byte” paketi ekranın hatırı sayılır bir bölümünü dolduruyorsa DMA yöntemi, yazma hızımızı 3 kata kadar arttırabiliyor. Üstelik bu paket giderken CPU serbest kalıp başka işlerle ilgilenebiliyor. Bu şekilde ulaştığım hızları görmek için burayı tıklayınız.
Bir font büyüklüğündeki paketçikler için DMA fazla fayda sağlamıyor.
STM32 İLE SPI DMA YÖNTEMİNİN KULLANILMASI
STM32 Cube IDE yi kullanıyorum. Bu platformun kullanılışının zaten bilindiğini varsayıyorum. İlk adım SPI port ayarlarının yapılması.
SPI port aktif hale getirildikten sonra, parametreleri de aşağıdaki gibi ayarlanıyor. Aslında bunlar varsayılan ayarlar, değişiklik yapmadım.
Burada SPI baud rate hakkında bir Not: SPI hızı 18MHz ile sınırlı. CPU saatini 36MHz olarak seçtiğinizde Baudrate prescaler 2 olabiliyor, bu aşağıdaki ekran kopyasındaki gibi 18 Bit/s veriyor. Eğer daha yüksek CPU saatleri ile çalışılırsa Baudrate prescaler’i on göre ayarlamak gerekiyor. Örneğin 64 MHz de prescaleri 4 olarak seçmek zorundayız.
Sıra, asıl konumuz olan DMA ayarlarına geldi. DMA sekmesinin altında SPI_TX – DMA Channel 3 ü seçerek ayarların aşağıdaki gibi olmasını sağlıyoruz.
Sistem saat ayarlarını da aşağıdaki gibi yaptım.
Projeyi kaydedip, Generate Code seçeneği ile cubeIDE nin başlangıç dosyalarımızı oluşturmasını sağlıyoruz.
TFT ye yönelik CPU ayaklarının tanımlarını cubeIDE içinde yapmadım, zira bu tanımlar benim tft_basic.c ve tft_basic.h sürücülerim içinde yapılıyor. SPI pinlerini cubeIDE ayarlıyor, bunların dışında sadece RS, CS, ve RESET bağlantıları kalıyor.
TFT SÜRÜCÜ FONKSİYONLAR
Burada tft_basic.c içindeki bazı temel fonksiyonları vermekle yetineceğim.
Yukarıda görüldüğü gibi tek byte gönderilen durumlarda DMA yöntemini kullanmıyorum. Ama çoklu byte paketlerini aşağıdaki TFT_writeMultipleData fonksiyonu ile DMA kullanarak gönderiyorum.
Yukarıdaki kod içinde gölgelenmiş olan bölümler 8 bit paralel girişli TFT ler için, onları göz ardı ediniz.
Şimdi en başta sözünü ettiğim testleri yaparken kullandığım üç üst düzey fonksiyonu veriyorum: