16X32 RGB Panel hakkında

Başlatan Mucit23, 10 Ekim 2014, 10:56:41

Mucit23

#75
Ufak bir test yaptım ve anladığım kadarıyla bu iş ekstra donanım olmadan normal yöntemlerle yapılamıyor.
Şöyle bir kod yazdım ne kadar sürede işlendiğini ölçtüm.
for(Bit_Count=0;Bit_Count<32;Bit_Count++)
		{
       if(R1_Data & 0x80000000){GPIOB->BSRR=GPIO_Pin_8;}else{GPIOB->BRR=GPIO_Pin_8;}
       if(G1_Data & 0x80000000){GPIOB->BSRR=GPIO_Pin_9;}else{GPIOB->BRR=GPIO_Pin_9;}
       if(B1_Data & 0x80000000){GPIOB->BSRR=GPIO_Pin_10;}else{GPIOB->BRR=GPIO_Pin_10;}
       if(R2_Data & 0x80000000){GPIOB->BSRR=GPIO_Pin_11;}else{GPIOB->BRR=GPIO_Pin_11;}
       if(G2_Data & 0x80000000){GPIOB->BSRR=GPIO_Pin_12;}else{GPIOB->BRR=GPIO_Pin_12;}
       if(B2_Data & 0x80000000){GPIOB->BSRR=GPIO_Pin_13;}else{GPIOB->BRR=GPIO_Pin_13;}			 
       R1_Data=(uint32_t)R1_Data<<1; 
       G1_Data=(uint32_t)G1_Data<<1; 
       B1_Data=(uint32_t)B1_Data<<1; 
       R2_Data=(uint32_t)R2_Data<<1; 
       G2_Data=(uint32_t)G2_Data<<1; 
       B2_Data=(uint32_t)B2_Data<<1;  
			 
			 GPIOB->BSRR=GPIO_Pin_14;    //CLK=1
			 GPIOB->BRR=GPIO_Pin_14;     //CLK=0
    }

Bu kod 72Mhz çalışma frekansında yaklaşık 40uS de işleniyor. Bundan daha hızlı nasıl yaparım açıkçası bir yöntem aklıma gelmedi.

Benim en çok elimi ayağımı bağlayan

1-) Yukarıdaki Seri data gönderme işlemi
2-) Duty değerlerini karşılaştırma işlemi

Bu işlemlerin donanımsal olarak yapılması lazım.

iyildirim

Yukarıdaki kod parçası 40usec tutuyorsa 1 sn. de 25K çalışabilir.

Yanlışım yoksa 16M  renk için bir tazeleme döngüsünde bu koddan 2048 kere çalışması gerektiğine göre 12Hz gibi tazeleme frekansı olur. 256K renk içinse 48 Hz gibi.
256K ve 48Hz tazeleme frekansı bence makul.
Üstelik renk döngülerinden dolayı frekans aslında çok daha yüksek, kırpışma vs. gözlenmez fikrimce. Tabii bunlar 256 veya 64 kere yenileme yapılan 1 yönteme göre..
Eğer 2.yönteme göre 8 eşit zamanda   OE ye uygulanan PWM ile  renk oluşturulacaksa neredeyse 400Hz tazeleme frekansı demek. Yani zaten olmuş.

Koda bakınca iyileştirilebilecek yerler de var üstelik. R1_Data G1..... dataları kaydırmak yerine duty sayıcısını döngü dışında kaydırmak gibi.

Tek avatajı ledleri daha parlak yakmak olsa da bir üçüncü yöntem olarak da üstünde konuşulan iki yöntemin ortak kullanılması olabilir.
İkinci yöntemdeki gibi tazeleme peryodunu 8 (veya 256k için 6) ayrı zamana bölmek. Ama eşit zamanlara değil.
Faydası 256 kere tarama yapmak yerine 8 kere yapmak olacak ve aynı sonucu verecek.
Bunun için de tazeleme peryodu 8 eşit zamana değil, 128/256, 64/256 ... 1/256 gibi 8 farklı zamana bölünecek.
Burada perfomansla ilgili sorun sadece 0 ncı biti işlemek olabilir. Bu durumda 256K renk için minimum süreyi 1/256 değil 1/64 seçmek perfomans konusu rahatlatır. 
256 kere yerine 8 kere de renkleri set etmek de putpixel vs. diğer işler için bayağı  zaman bırakır.
Yukarıdaki kodu bir timer kesmesinde çalıştırmak ve kesme için timer a sıradaki değeri yüklemek gibi. Artı global satır vs. değişkenleri..

Mucit23

Hocam benim hesaplara göre bu iş 1. yöntemle SM32F10x de olmaz. Olsa bile rutin işlere hiçbir vakit kalmıyor. Şöyleki yukarıda yaptığım işlem dediğim gibi yaklaşık 40us sürüyor. Eğer 6 bit renk derinliği olacaksa her bir seferinde 64 defa bu işlemi yapmam gerekirki bunun sonucunda tüm SR lerden sadece 1 puls'luk PWM sinyali elde ediliyor. 64x40us'den  2560us yapıyor. Şimdiden 2ms lik değer aşılıyor. Normalde 8 satır var ve her satır 2ms civarı aktif kalması gerekiyor. Yani benim 2ms içerisinde SR lerden olabildiğince çok PWM puls'i çıkarmam gerekiyor. Benim aklımda böyle bir düşünce vardı.

Ama sizin dediklerinizle bir türlü uyuşturamadım. Siz tazeleme frekansını nasıl hesaplıyorsunuz?

Neyse bu arada yukarıdaki işlemler STM32F407 & 168Mhz de 15uS civarı sürüyor.

Alıntı YapKoda bakınca iyileştirilebilecek yerler de var üstelik. R1_Data G1..... dataları kaydırmak yerine duty sayıcısını döngü dışında kaydırmak gibi.
Birde hocam burayı anlayamadım. R1_Data, G1_Data....B2_Data değişkenlerim benim 32 bitlik değişkenlerim olacaktı. Bu değişkenlerher bir döngüde  doğrudan SRlere gönderilecekti. Ben duty değerlerine göre bu değişkenlerin ilgili bitlerini 0 veya 1 yapacaktım. Aklımda böyle bir tasarı vardı.

Galiba en mantıklı çıkar yol hasan hocamızın anlattığı yöntem. Onuda şimdilik panel bir yana 74HC595'de uygulamam gerekir. Henüz mantık tam olarak oturmuş değil. Mantığını bi çözsem gerisi çorap söküğü gibi gelecek.

iyildirim

Alıntı yapılan: Mucit23 - 01 Kasım 2014, 00:08:56
Şöyleki yukarıda yaptığım işlem dediğim gibi yaklaşık 40us sürüyor. Eğer 6 bit renk derinliği olacaksa her bir seferinde 64 defa bu işlemi yapmam gerekirki bunun sonucunda tüm SR lerden sadece 1 puls'luk PWM sinyali elde ediliyor. 64x40us'den  2560us yapıyor. Şimdiden 2ms lik değer aşılıyor.

Ama sizin dediklerinizle bir türlü uyuşturamadım. Siz tazeleme frekansını nasıl hesaplıyorsunuz?
2ms karşılığı 62.5 Hz di. 2560us karşılığı 48Hz.. İllede 62.5 Hz tazeleme gerekiyormu?.

Hesap,

1/(256renk döngüsü* 8 satır * 40usec) = 12.21 Hz
1/(64renk döngüsü * 8 satır * 40usec) = 48.83 Hz şeklinde..


Alıntı yapılan: Mucit23 - 01 Kasım 2014, 00:08:56
Birde hocam burayı anlayamadım. R1_Data, G1_Data....B2_Data değişkenlerim benim 32 bitlik değişkenlerim olacaktı. Bu değişkenlerher bir döngüde  doğrudan SRlere gönderilecekti. Ben duty değerlerine göre bu değişkenlerin ilgili bitlerini 0 veya 1 yapacaktım. Aklımda böyle bir tasarı vardı.

Galiba en mantıklı çıkar yol hasan hocamızın anlattığı yöntem. Onuda şimdilik panel bir yana 74HC595'de uygulamam gerekir. Henüz mantık tam olarak oturmuş değil. Mantığını bi çözsem gerisi çorap söküğü gibi gelecek.


Konu karışıyor çünkü tam olarak hangi yönteme göre gidildiği belli değil.
Eğer 256 kere veya 64 kere tarama yapılan yöntemi uygulayacaksak, mantık aşağıdaki koda benzer olur.
                    //satır = 8, 2 satır şeklinde sutun = 2*16=32, sağ ve sol taraf için 3 renkten den 6 led 
    uint8_t ledduty [8][32][6];
    uint8_t dutyCounter;
    uint8_t rowNum, colNum;

    dutyCounter = 0;

    rowNum = 0;
    colNum = 0;
    
    while (1)
    {
        
        for (rowNum = 0;    rowNum <8;rowNum ++)
        {
            //satır seçimi ile ilgili A,B,C pin setleri 
        
            for (dutyCounter = 0;    dutyCounter<255; dutyCounter++)
            {
                //alltaki  döngü satırların sürülme sırasına ve duty bilgilerinin bellekteki yerleşimine göre 2 ayrı 16 lık döngü olabilir. 
                for (colNum = 0;    colNum <32; colNum++) //
                {
                    GPIOB->BRR=GPIO_Pin_14;     //CLK=0
                    //sağ taraf diyelim
                    if (dutyCounter >= ledduty [rowNum][colNum][0]) {GPIOB->BSRR=GPIO_Pin_8;}     else{GPIOB->BRR=GPIO_Pin_8;};
                    if (dutyCounter >= ledduty [rowNum][colNum][1]) {GPIOB->BSRR=GPIO_Pin_9;}     else{GPIOB->BRR=GPIO_Pin_9;};
                    if (dutyCounter >= ledduty [rowNum][colNum][2]) {GPIOB->BSRR=GPIO_Pin_10;}    else{GPIOB->BRR=GPIO_Pin_10;};
                    //sol taraf diyelim
                    if (dutyCounter >= ledduty [rowNum][colNum][3]) {GPIOB->BSRR=GPIO_Pin_11;}    else{GPIOB->BRR=GPIO_Pin_11;};
                    if (dutyCounter >= ledduty [rowNum][colNum][4]) {GPIOB->BSRR=GPIO_Pin_12;}    else{GPIOB->BRR=GPIO_Pin_12;};
                    if (dutyCounter >= ledduty [rowNum][colNum][5]) {GPIOB->BSRR=GPIO_Pin_13;}    else{GPIOB->BRR=GPIO_Pin_13;};

                    GPIOB->BSRR=GPIO_Pin_14;    //CLK=1 
                }
                
                GPIOB->BSRR=GPIO_Pin_15;    //LATCH=1
                __Nop();
                GPIOB->BSRR=GPIO_Pin_15;    //LATCH=0
            }    
        }
    }   


Yok Eşit zaman aralıklarında OE pinine 2 nin katları şeklinde PWM uygulayacaksak da aşağıdaki koddaki mantıkta birşey çıkar.
    uint8_t ledduty [8][32][6];
    uint8_t dutyCounter, duty;
    uint8_t rowNum, colNum;
    

    while (1)
    {
        
        for (rowNum = 0;    rowNum <8;rowNum ++)
        {

            //satır seçimi ile ilgili A,B,C pin setleri 

            //işlem gücü fazlasıyla yeteceğinden alt kısmın devamı için timer dan bir işaret beklemek gibi bir şey olabilir. 
            //veya alt kısım kesme içerisinde de çalışabilir. 
            while(timerFlag ==0); //timer 2ms de bir kesme oluşturmalı.. 2ms de bir çalışacak olan kısım aşağısı..
            timerFlag = 0;

            for (dutyCounter = 1;    dutyCounter<8; dutyCounter++)
            {
                duty = 1 << dutyCounter;
                
                //OE çıkışı low PWM disable
                
                //alltaki  döngü satırların sürülme sırasına ve duty bilgilerinin bellekteki yerleşimine göre 2 ayrı 16 lık döngü olabilir. 
                for (colNum = 0;    colNum <32; colNum++) //
                {
                    GPIOB->BRR=GPIO_Pin_14;     //CLK=0
                    //sağ taraf diyelim
                    if (duty & ledduty [rowNum][colNum][0]) {GPIOB->BSRR=GPIO_Pin_8;}     else{GPIOB->BRR=GPIO_Pin_8;};
                    if (duty & ledduty [rowNum][colNum][1]) {GPIOB->BSRR=GPIO_Pin_9;}     else{GPIOB->BRR=GPIO_Pin_9;};
                    if (duty & ledduty [rowNum][colNum][2]) {GPIOB->BSRR=GPIO_Pin_10;}    else{GPIOB->BRR=GPIO_Pin_10;};
                    //sol taraf diyelim
                    if (duty & ledduty [rowNum][colNum][3]) {GPIOB->BSRR=GPIO_Pin_11;}    else{GPIOB->BRR=GPIO_Pin_11;};
                    if (duty & ledduty [rowNum][colNum][4]) {GPIOB->BSRR=GPIO_Pin_12;}    else{GPIOB->BRR=GPIO_Pin_12;};
                    if (duty & ledduty [rowNum][colNum][5]) {GPIOB->BSRR=GPIO_Pin_13;}    else{GPIOB->BRR=GPIO_Pin_13;};

                    GPIOB->BSRR=GPIO_Pin_14;    //CLK=1 
                }
                
                GPIOB->BSRR=GPIO_Pin_15;    //LATCH=1
                __Nop();
                GPIOB->BSRR=GPIO_Pin_15;    //LATCH=0
            }
            //OE çıkışına donanımdan PWM basılacak.. 
            PWM duty = base_duty_ON_peryod * duty 
            //2ms lik zamanlarda farklı parlaklıklarda yanan veya sönen ledler renk oluşturacak..
        }
    }


Son örnek için konuşursak,
32 lik döngü 40us idi. Oda döngü içerisindeki kod fazlalıkları ile.
Dışında 8 lik duty, ve 8 lik satır döngüleri var. 40*8*8 = 2560 usec de panelin tamamı bir kez taranmış olur. 62,5 Hz lik  :) tazeleme frekansı vardı. Tüm işlem 160 ms de biter. Geriye kalan 840ms diğer işlere sanırım yeterli olur.

Bu ikinci örnekteki koddan pwm'i  çıkarıp OE pinini sürekli aktif edersek ve timer'ı toplamı 2ms edecek şekilde 8 bit için 8 ayrı değerde ikinin katları şeklinde kurarsak 1 ve 2 yöntemi birleştirmiş ve ledleri tam parlak yakmış oluruz. Karşılığında duty için 256 veya 64 yerine  8 lik bir döngüye girdiğimiz için (256K renk için 6 lık) diğer işlere yine zaman kalır. Belki 0 bit için işlem zamanında bitmeyebilir. 8 bit yerine 7 veya 6 bit kullanımı ile bu sorun da aşılabilir.


Mucit23

Hocam karışıklık olmasın. Ben çalışmalarımı 2. Yöntem üzerinden devam ettireceğim. Kasmaya gerek yok. :)


Hocam dün akşam oturdum ekranın veri yapısı için bir tablo oluşturdum. Tabloyu aşağıdaki linkten indirip inceleyebilirsiniz.
https://docs.google.com/spreadsheets/d/1gA3L6CRhEZvIhVJTa0HUKi5sRIYGjjGNbhoRD920g1M/edit#gid=496249709


R1_Data, G1_Data değişkenleride buradan geliyor aslında


Ben yukarıda bir kod örneğin vermiştim. 32 bitlik R1_Data, G1_Data gibi değişkenleri shift registerden gönderiyordum.


Panelde 6 adet Data girişi var. Her girişte toplam 2 adet SR kaskat bağlı.
R1 Girişi ilk 16 sütün içindi(1.Bölge) Dolayısıyla ABC satır seçme girişi "000" iken R1 girişindeki ilk SR 1. Satır 0-16 sütün arasına veri gönderirken diğer SR 9. satırdaki 0-16 sütün arasına veri gönderiyor. Satır tarama ile bu değişiyor. R1 girişindeki aynı SR' ler ABC girişi "001" olduğu zaman bu sefer de 2-10. satırlara veri göndermiş oluyor.


Bu yüzden ben R1_Data, G1_Data gibi 32 bitlik değişkenleri SR lere gönderiyordum. Tabi her gönderme işleminden önce butün duty değerlerini 1-64 arası sayan duty sayacıyla karşılaştırıp R1_Data, G1_Data değişkenlerinin ilgili bitlerini 1 yada 0 yapacaktım. Bu işlemi 64 defa yaparsam 6 bit çözünürlükte bir adet pwm puls'ı çıkıyor. Dolayısıyla 2ms içerisinde olabildiğince fazla bir şekilde yapmam gerekiyordu bunu çünkü sadece bir pwm puls'i yetmeyebilir diye düşünüyordum.


Fakat sizin bu döngüyü anlayamadım
   for (colNum = 0;    colNum <32; colNum++) //
                {
                    GPIOB->BRR=GPIO_Pin_14;     //CLK=0
                    //sağ taraf diyelim
                    if (dutyCounter >= ledduty [rowNum][colNum][0]) {GPIOB->BSRR=GPIO_Pin_8;}     else{GPIOB->BRR=GPIO_Pin_8;};
                    if (dutyCounter >= ledduty [rowNum][colNum][1]) {GPIOB->BSRR=GPIO_Pin_9;}     else{GPIOB->BRR=GPIO_Pin_9;};
                    if (dutyCounter >= ledduty [rowNum][colNum][2]) {GPIOB->BSRR=GPIO_Pin_10;}    else{GPIOB->BRR=GPIO_Pin_10;};
                    //sol taraf diyelim
                    if (dutyCounter >= ledduty [rowNum][colNum][3]) {GPIOB->BSRR=GPIO_Pin_11;}    else{GPIOB->BRR=GPIO_Pin_11;};
                    if (dutyCounter >= ledduty [rowNum][colNum][4]) {GPIOB->BSRR=GPIO_Pin_12;}    else{GPIOB->BRR=GPIO_Pin_12;};
                    if (dutyCounter >= ledduty [rowNum][colNum][5]) {GPIOB->BSRR=GPIO_Pin_13;}    else{GPIOB->BRR=GPIO_Pin_13;};


                    GPIOB->BSRR=GPIO_Pin_14;    //CLK=1 
                }

Siz doğrudan Duty değerlerini counter ile karşılaştırıp doğrudan çıkışa 1 yada 0 vermişsiniz. Acaba ben R1_Data gibi değişkenler kullanarak işimi uzatıyordum  ???


Hem 1. yöntem hemde 2. yöntem için SR lere veri göndermede yukarıdaki kodu kullanmışsınız. Nasıl çalıştığını, Daha doğrusu bit bazlı nasıl pwm oluştuğunu anlayamadım. Müsait bir vaktinizde bu konuda kısa bir açıklama yapabilirmisiniz?

iyildirim

Alıntı yapılan: Mucit23 - 01 Kasım 2014, 11:20:16
Hocam dün akşam oturdum ekranın veri yapısı için bir tablo oluşturdum. Tabloyu aşağıdaki linkten indirip inceleyebilirsiniz.
https://docs.google.com/spreadsheets/d/1gA3L6CRhEZvIhVJTa0HUKi5sRIYGjjGNbhoRD920g1M/edit#gid=496249709


R1_Data, G1_Data değişkenleride buradan geliyor aslında


Ben yukarıda bir kod örneğin vermiştim. 32 bitlik R1_Data, G1_Data gibi değişkenleri shift registerden gönderiyordum.


Panelde 6 adet Data girişi var. Her girişte toplam 2 adet SR kaskat bağlı.
R1 Girişi ilk 16 sütün içindi(1.Bölge) Dolayısıyla ABC satır seçme girişi "000" iken R1 girişindeki ilk SR 1. Satır 0-16 sütün arasına veri gönderirken diğer SR 9. satırdaki 0-16 sütün arasına veri gönderiyor. Satır tarama ile bu değişiyor. R1 girişindeki aynı SR' ler ABC girişi "001" olduğu zaman bu sefer de 2-10. satırlara veri göndermiş oluyor.


Bu yüzden ben R1_Data, G1_Data gibi 32 bitlik değişkenleri SR lere gönderiyordum. Tabi her gönderme işleminden önce butün duty değerlerini 1-64 arası sayan duty sayacıyla karşılaştırıp R1_Data, G1_Data değişkenlerinin ilgili bitlerini 1 yada 0 yapacaktım. Bu işlemi 64 defa yaparsam 6 bit çözünürlükte bir adet pwm puls'ı çıkıyor. Dolayısıyla 2ms içerisinde olabildiğince fazla bir şekilde yapmam gerekiyordu bunu çünkü sadece bir pwm puls'i yetmeyebilir diye düşünüyordum.

Tam olarak anlayabildiğimi söyleyemem.
R1_Data...  bu değişkenleri 16+16 bit tasarlamış olmanız 2. yöntemin 8 eşit zaman aralığından birine karşılık gelen bit değerlerini yani 1 pikselin R sinin 1 biti + 2 pikselin R sinin 1 biti gibi birleştirip 16bit bir değer elde edilmiş gibi.   Böyle ise olabilir tabii, sonuçta Roma ya tek yol da gitmez, herkesin yoğurt yemesi de farklı.

Doğru anlayabildiysem bu değişkenlerin bu şekilde tasarlanması sanki donanımsal SPI dan basılacakmış gibi düşünülmesinden kaynaklı.  6 adet senkronize çalışabilen SPI modülümüz olsaydı bu şekilde güzel olurdu.
Ancak birde putpixel işlerimiz vardı. Bu tip fonksiyonları da düşününce belleğin RGB değerlerine göre lineer kullanımı da önemli olmalı. Öte yandan yazılımsal SPI kullanımından dolayı herhangi bir avantaj da sağlamıyor.
Verdiğiniz örnekteki 0x8000000 değeri ni bir kere kaydırmak yerine 6 kere değişkenleri kaydırma gibi perfomansa olumsuz etkileri gözardı da etsek benim verdiğim 2. örnekteki koddan dan perfomans açısından bir farkı olmayacak. Üstüne belleği de dağıtmış olacağız.

Alıntı yapılan: Mucit23 - 01 Kasım 2014, 11:20:16


Fakat sizin bu döngüyü anlayamadım
   for (colNum = 0;    colNum <32; colNum++) //
                {
                    GPIOB->BRR=GPIO_Pin_14;     //CLK=0
                    //sağ taraf diyelim
                    if (dutyCounter >= ledduty [rowNum][colNum][0]) {GPIOB->BSRR=GPIO_Pin_8;}     else{GPIOB->BRR=GPIO_Pin_8;};
                    if (dutyCounter >= ledduty [rowNum][colNum][1]) {GPIOB->BSRR=GPIO_Pin_9;}     else{GPIOB->BRR=GPIO_Pin_9;};
                    if (dutyCounter >= ledduty [rowNum][colNum][2]) {GPIOB->BSRR=GPIO_Pin_10;}    else{GPIOB->BRR=GPIO_Pin_10;};
                    //sol taraf diyelim
                    if (dutyCounter >= ledduty [rowNum][colNum][3]) {GPIOB->BSRR=GPIO_Pin_11;}    else{GPIOB->BRR=GPIO_Pin_11;};
                    if (dutyCounter >= ledduty [rowNum][colNum][4]) {GPIOB->BSRR=GPIO_Pin_12;}    else{GPIOB->BRR=GPIO_Pin_12;};
                    if (dutyCounter >= ledduty [rowNum][colNum][5]) {GPIOB->BSRR=GPIO_Pin_13;}    else{GPIOB->BRR=GPIO_Pin_13;};


                    GPIOB->BSRR=GPIO_Pin_14;    //CLK=1 
                }

Siz doğrudan Duty değerlerini counter ile karşılaştırıp doğrudan çıkışa 1 yada 0 vermişsiniz. Acaba ben R1_Data gibi değişkenler kullanarak işimi uzatıyordum  ???


Hem 1. yöntem hemde 2. yöntem için SR lere veri göndermede yukarıdaki kodu kullanmışsınız. Nasıl çalıştığını, Daha doğrusu bit bazlı nasıl pwm oluştuğunu anlayamadım. Müsait bir vaktinizde bu konuda kısa bir açıklama yapabilirmisiniz?

Alıntı yaptığınız örnek 1 yöntem içindi. Gerçi alıntı yaptığınız kısım olarak bakarsak  2. yöntemde ki fark direkt karşılaştırma yerine and lemek.

Dediğim gibi sizin mantığınızı tam olarak anlayabildiğimi söyleyemem. Bu nedenle anlatmaya çalıştığım kendi mantığımı açmaya  çalışayım.

1 ve 2 yöntem arasında kod olarak ufak olsada algoritma olarak ciddi fark var. 1 sinde ledleri yakıp 256 farklı zamanda söndürme işini yapıyoruz. Led duty değeri kadar yandı ise söndürülme zamanı geldimi yi kontrol ediyoruz. Bunun için de duty sayacı ile led duty sini direkt olarak karşılaştırmak yetiyor. Burada 2ms lik zaman 256 veya 64 gibi bir değere bölünüyor.

Aslında 2 yöntemde bellek düzeni dışında sizinle aynı şeyleri yapıyoruz gibi.  Aşağıdaki açıklamalarda ki değerler 2ms yi 8 e böldüğümüz ve 16Mrenk elde ettiğimiz durum için.
2ms lik zamanı 8 eşit parçaya bölüyoruz. 
dutyCounter bu 8 eşit zaman parçasının hangisinde olduğumuzu belirtiyor.
duty ise sizin koddaki 0x80000000 'e benzer şekilde 2^dutyCounter değeri ile iş görüyor. Fark olarak ben 6 ayrı değişkeni kaydırmak yerine döngü dışında bu değişkenin içeriğini hazırlıyorum.
Döngü içerisinde de kaydırma vs. yapmadan ledlerin duty değerlerinin, bitlerinin değerine göre de 2 ms yi böldüğümüz 8 eşit zamanın her birinde o ledin yanıp yanmayacağına karar veriyoruz.
Bu noktada ledlerin bazıları yanık, bazıları sönük durumda. 2ms/8 süre boyunca  OE pinine duty değeri ile oranlı şekilde donanımsal PWM basıyoruz. Bu noktada bahsettiğimiz PWM 'in ledleri yakıp söndürme ile yani 1 yöntemdeki PWM ile ilgisi yok. Gerçek,  donanımsal,  TIMER, OC modülü ile üretilen PWM den bahsediyoruz.
Donanımsal PWM frekansını belirleyen PWM peryodu ise en fazla 2ms/8 veya katları şeklinde daha az olmalı.
Ve PWM duty = base_duty_ON_peryod * duty  dediğim yerdeki base_duty_ON_peryod değeride 2ms/8/128 veya pwm peryoduna uygun şekilde katları kadar az değer alacak.

Bu durumda 2ms/8 süreli  8 eşit zamanın herbirinde ledler kendileri için set edilen duty değerinin bitlerine göre ya yanacak yada yanmayacaklar. Yanan lar ise OE pinine ilgili bitin değerine göre uygulanan PWM nedeniyle farklı parlaklıklarda yanacaklar. 2ms/8 sürede 2 nin katları şeklindeki 8 farklı zamandaki toplam 256 PWM değeri ve parlaklık nedeni ile  16M rengimiz olacak. Veya 2ms/6 süre kullanıp 256K renk elde edilecek.
Ledleri farklı parlaklıklarda yaktığımız 2ms/8 süreli eşit zamandaki toplam duty ON değeri ancak 2ms/4 olabileceğinden ledler maks. normalin 1/4 ü kadar parlak yanabilecek.

Kısa olmadı ama umarım anlatabilmişimdir.

Buraya kadar anlaştı isek,
Bana göre çok ciddi bir avantaj sağlamayacaksa bellek düzeninin lineerliğini bozacak bir algoritma putpixel vs işlerinden dolayı uygun değil.
Ama en iç döngü içerisinde ki gerekli işlem nasıl en az olabilir diye düşünürken sizinki gibi bir bellek düzeninin perfomans sağlayıp sağlamayacağı konusuna takıldım. Sanırım bir şekilde olabilir. O da 6 ayrı biti tek tek yerine tek bir seferde paralel olarak basmak olabilir. GPIOX->ODR = xxx gibi.
Sağ ve sol panellerin aynı satır ve sütünlarındaki 3 renk den 6 ledin 1 bitleri, bir sonraki sütunun 1 bitleri, ... şeklinde 6 data pinine karşılık 6 bitlik 32 byte'lık bir diziyi 2. ve diğer bitler  için tekrarlayıp satırı arttırıp 8 kere daha takrarlayıp şeklinde elde edilmiş bir dizimiz olduğunda 1 byte tı direk pine basmak tek seferde 6 bitinde set edilmesini sağlar. Paralel veri aktarımı ve clock işleri FSMC ile sağlanırsa 32 byte da bir yani 4Khz lik kesme ile row ve latch set edilebilir. Tabii lineer belleğimizi bu düzende bir bellek alanına kopyalayacak bir fonksiyon da gerekiyor.

Artı olarak led parlaklığının az olması konusu  için bir önceki mesajda anlatmaya çalıştığım yöntem için yapılması gereken OE pinini sürekli aktif yapıp 32 lik döngüyü çalıştıracağımız zamanı bir timer kesmesi ile belirlemek, 32 lik döngüyü start edecek timer kesmesinin taşma değerini 2 nin katları şeklinde hazırlanmış 6-8 elemanlı bir diziden okumak..

İster direkt ledlerin az yandığı 2 yöntem, ister en son anlatmaya çalıştığım yöntem için Timerde FSMC tetiklemek, FSMC kesmesinde satır ve latch set etmek sanırım ideal yöntem olur. Açıkçası aklıma donanımdan da yardım alınabilecek minimum işlem zamanı gerektiren  başka bir yöntem gelmiyor.

Mucit23

Hocam cevap için teşekkürler.

Benim bu konuyu anlamam için mutlaka 74HC595 üzerinde test yapmam lazım. Diğer Türlü mantığını birtürlü oturtturamıyorum. 74HC595'in mantığını çözersem eğer aynı mantığı panel üzerinde uygulamam çok kolay olur. Şuan ne yapacağımı bilmiyorum.  :-[

Şuanda paneli boşverelim. 74HC595'den 8 Kanal 8 bit PWM almaya çalışalım.

OE'ye pwm uygulama işini anladım.
Alıntı YapDonanımsal PWM frekansını belirleyen PWM peryodu ise en fazla 2ms/8 veya katları şeklinde daha az olmalı.
Ben hemen Bu heseba göre 2000/8=250uS eder. Oda yaklaşık 4Khz civarı bir PWM Frekansı demek oluyor.
Ben PWM frekansını 8Khz yaptım. PWM de sıkıntı yok.

yine 8 adet duty değişkenim olsun.

uint8_t Duty[8];

Bundan sonra anladığım kadarıyla yukarıda tanımamış olduğum bütün duty değişkenlerinin 0. bitlerini sırayla SR nin çıkış bitlerine yazıyoruz.

Duty[0] değişkeninin 0. bitini SR 'a gönderilecek olan 8 bitlik değişkenin 0. bitine eşitiyoruz.
.
.
.
Duty[7] değişkeninin 0. bitini SR 'a gönderilecek olan 8 bitlik değişkenin 7. bitine eşitiyoruz.

Sonra Bu değeri SR ye gönderip OE'den 8 bitlik pwm için duty değerini 1 yapıp yolluyoruz.

Sonra yukarıdaki işlemlerin hepsini Duty değişkenlerinin 1. bitleri için tekrarlıyoruz. PWM duty oranını 2 katına çıkarıyoruz.

En son Duty değişkenlerinin 7. Bitlerini SR'ye gönderip  Duty değerini 128 yapıyoruz. Dolayısıyla %50 PWM uygulanmış oluyor.  (MaxDuty değeri 255)

Hocam anladığım yöntem doğrumu. Hatam varmıdır?



iyildirim

Alıntı yapılan: Mucit23 - 02 Kasım 2014, 15:36:53
yine 8 adet duty değişkenim olsun.

uint8_t Duty[8];

Bundan sonra anladığım kadarıyla yukarıda tanımamış olduğum bütün duty değişkenlerinin 0. bitlerini sırayla SR nin çıkış bitlerine yazıyoruz.

Duty[0] değişkeninin 0. bitini SR 'a gönderilecek olan 8 bitlik değişkenin 0. bitine eşitiyoruz.
.
.
.
Duty[7] değişkeninin 0. bitini SR 'a gönderilecek olan 8 bitlik değişkenin 7. bitine eşitiyoruz.

Sonra Bu değeri SR ye gönderip OE'den 8 bitlik pwm için duty değerini 1 yapıp yolluyoruz.

Sonra yukarıdaki işlemlerin hepsini Duty değişkenlerinin 1. bitleri için tekrarlıyoruz. PWM duty oranını 2 katına çıkarıyoruz.

En son Duty değişkenlerinin 7. Bitlerini SR'ye gönderip  Duty değerini 128 yapıyoruz. Dolayısıyla %50 PWM uygulanmış oluyor.  (MaxDuty değeri 255)

Hocam anladığım yöntem doğrumu. Hatam varmıdır?

Eğer Paneli unutup sadece 8 ledi farklı parlaklıklarda yakmak için konuşuyorsak  yöntem olarak doğru. Anlattığınız şekilde olurdu. 

Sadece önceki mesajlarda da dikkatimi çeken nokta SR ye basacak bir değişken oluşturma konusu. Donanım SPI kullanmadığımız için SPI modülüne aktarmamız gereken bir değişkenimiz olmak zorunda değil. O değişkeni-değeri oluşturmak için uğraşacağımız zamanda zaten SR data pinini bit bit set edebiliyoruz. Yani direkt led duty değerlerini 2^dutycounter değeri ile AND leyip SR pinini anında set edebiliyoruz.  Bu söylediğim sadece performans için.  Yoksa yöntemin doğruluğu ile ilgili değil.

Panele dönersek duty[8] dediğiniz değişken 16 satır, 32 sütun ve 3 renk için bellek de lineer düzende olsun amacı ile duty[16][32][3] şeklinde tanımlayalım.
Panelin sağ ve sol kısımlarının ayrı SR ile sürüldüğünü ve aynı anda row ve row + 8 şeklinde iki satırın sürüldüğünü de gözönüne alırsak  belleği de lineer kullanacak şekilde düzenlersek daha önce verdiğim  örneği tam olarak yazmaya çalışırsak aşağıdakine benzer bir kod çıkacak. Kod içerisine de olabildiğince açıklamalar eklemeye çalıştım. Özellikle indislere dikkat edin..
    uint8_t ledduty [16][32][3]; // 16 satır 32 sütun, 3 renk 
    uint8_t dutyCounter, duty;
    uint8_t rowNum, colNum;

    
    
    while (1)
    {
        for (rowNum = 0; rowNum <8; rowNum++ )
        {

            //satır seçimi ile ilgili A,B,C pin setleri 

            //işlem gücü fazlasıyla yeteceğinden alt kısmın devamı için timer dan bir işaret beklemek gibi bir şey olabilir. 
            //veya alt kısım kesme içerisinde de çalışabilir. 
            while(timerFlag ==0); //timer 2ms de bir kesme oluşturmalı.. 2ms de bir çalışacak olan kısım aşağısı..
            timerFlag = 0;

            base_duty_ON_peryod = TIM_X->ARR/128     //base_duty_ON_peryod Donanımsal PWM frekansı için timer a yüklediğimiz değer /128 olacak.. 
            
            
            for (dutyCounter = 1; dutyCounter<8; dutyCounter++) //16M renk için dutyCounter<8, 256K renk için  dutyCounter<6 
                                                                //buna göre timer kesmesi de 2ms/8 veya 2ms/6 
            {
                duty = 1 << dutyCounter;
            
                //OE çıkışı low PWM disable
                
                //alltaki  döngü ile daha altındaki colNum döngülerinden hangisinin önce çalışacağı, satırları süren SR nin ne şekilde kaskat bağlandığına göre değişebilir
                //ayrıca sütunları süren SR lerin kaskat bağlanış şekline göre döngü artan yerine azalan yapıda da olabilir. 4 ayrı 0-8 arası rownum döngüsü de gerekebilir.
                //SR lerin ne şekilde kaskatlandığına ve bizim pikselleri adresleme şeklimiz ile SR çıkışlarının uyumluluğuna göre..

                //0-7 arasındaki satırlara ait sütunlar 
                for (colNum = 0; colNum <16; colNum++) 
                {
                    GPIOB->BRR=GPIO_Pin_14;     //CLK=0
                    //sol taraf, diyelim ki bellekte 1.satır 1 sütün üst sol köşe olsun.. 
                    if (duty & ledduty [rowNum][colNum][0]) {GPIOB->BSRR=GPIO_Pin_8;}     else{GPIOB->BRR=GPIO_Pin_8;};
                    if (duty & ledduty [rowNum][colNum][1]) {GPIOB->BSRR=GPIO_Pin_9;}     else{GPIOB->BRR=GPIO_Pin_9;};
                    if (duty & ledduty [rowNum][colNum][2]) {GPIOB->BSRR=GPIO_Pin_10;}    else{GPIOB->BRR=GPIO_Pin_10;};

                    //sqğ taraf diyelim
                    if (duty & ledduty [rowNum][colNum+16][0]) {GPIOB->BSRR=GPIO_Pin_11;}    else{GPIOB->BRR=GPIO_Pin_11;};
                    if (duty & ledduty [rowNum][colNum+16][1]) {GPIOB->BSRR=GPIO_Pin_12;}    else{GPIOB->BRR=GPIO_Pin_12;};
                    if (duty & ledduty [rowNum][colNum+16][2]) {GPIOB->BSRR=GPIO_Pin_13;}    else{GPIOB->BRR=GPIO_Pin_13;};

                    GPIOB->BSRR=GPIO_Pin_14;    //CLK=1 
                }
                //8-15 arasındaki satırlara ait sütunlar 
                for (colNum = 0;    colNum <16; colNum++) //
                {
                    GPIOB->BRR=GPIO_Pin_14;     //CLK=0
                    //sol taraf, diyelim ki bellekte 1.satır 1 sütün üst sol köşe olsun.. 
                    if (duty & ledduty [rowNum+8][colNum][0]) {GPIOB->BSRR=GPIO_Pin_8;}     else{GPIOB->BRR=GPIO_Pin_8;};
                    if (duty & ledduty [rowNum+8][colNum][1]) {GPIOB->BSRR=GPIO_Pin_9;}     else{GPIOB->BRR=GPIO_Pin_9;};
                    if (duty & ledduty [rowNum+8][colNum][2]) {GPIOB->BSRR=GPIO_Pin_10;}    else{GPIOB->BRR=GPIO_Pin_10;};

                    //sqğ taraf diyelim
                    if (duty & ledduty [rowNum+8][colNum+16][0]) {GPIOB->BSRR=GPIO_Pin_11;}    else{GPIOB->BRR=GPIO_Pin_11;};
                    if (duty & ledduty [rowNum+8][colNum+16][1]) {GPIOB->BSRR=GPIO_Pin_12;}    else{GPIOB->BRR=GPIO_Pin_12;};
                    if (duty & ledduty [rowNum+8][colNum+16][2]) {GPIOB->BSRR=GPIO_Pin_13;}    else{GPIOB->BRR=GPIO_Pin_13;};

                    GPIOB->BSRR=GPIO_Pin_14;    //CLK=1 
                }
                
                GPIOB->BSRR=GPIO_Pin_15;    //LATCH=1
                __Nop();
                GPIOB->BSRR=GPIO_Pin_15;    //LATCH=0
            }
            //OE çıkışına donanımdan PWM basılacak.. 
            //PWM duty = base_duty_ON_peryod * duty 
            TIM_X->CCR_X    = base_duty_ON_peryod * duty ;
            //2ms lik süreler boyunca farklı parlaklıklarda yanan yada tamamen sönen ledler renk oluşturacak..
        }
    }

Mucit23

Hocam selamlar,

Mesajınıza ve verdiğiniz koda bakarak 74HC595'içi bir kod yazmaya çalıştım.
int main(void)
{ 
  Hardware_Configuration();    //Sistem ve Donanim Ayarlarini yap..
  LCD_Clear(Green);
  LCD_SetBackColor(Green);
  LCD_ShowString(0,0,"74HC595 Shift PWM");
  setOutMode(portD,0x0F00);
	
  LED_Duty[7]=255;	
  LED_Duty[0]=1;

  while(1)
  {
  
	  for(Duty_Count=0;Duty_Count<8;Duty_Count++)
	  {
		 TIM3->CCR3=0;//PWM Disable..
		 PWM_Duty = 1 << Duty_Count;
		 for(Bit_Count=0;Bit_Count<8;Bit_Count++)//Seri Olarak data gönderiliyor. 
         {
			 GPIOB->BRR=GPIO_Pin_9;//CLK=0;
			 if(PWM_Duty&LED_Duty[Bit_Count]){GPIOB->BSRR=GPIO_Pin_8;}else{GPIOB->BRR=GPIO_Pin_8;}
			 GPIOB->BSRR=GPIO_Pin_9;//CLK=1;
		 }			
		 GPIOB->BSRR=GPIO_Pin_10;//Latch=1;
		 GPIOB->BRR=GPIO_Pin_10;//Latch=0;
		 TIM3->CCR3=PWM_Duty;//PWM Enable
		 delay_ms(2);
		}
      
  }
      
}



Açıkçası düzgün çalışmadı. Şuanda Lojik analyser'im yanımda olmadığı için sebebini anlayamadım.
Görsel olarak incelersek
  LED_Duty[7]=255;   
  LED_Duty[0]=1;
7. kanalın Duty değerini 255, 0. kanalın Duty değerini 1 yaptım. Gerçekte çıkışlar Çıkışların parlakları arasında çok az ama çok çok az bir fark var. Normalde böyle olmaması gerektiğini düşünüyorum. Ama dün PWM'in çalıştığını doğrulamıştım. Frekans Yaklaşık 8Khz ve 8 bit çözünürlükte. Max duty 255 olarak ayarladım. Bunu gerekli olduğu taktirde yükseltebilirimde.

Probleme geri dönersek sizce neden kaynaklanabilir. Yukarıdaki kodlarda gözünüze çarpan bir terslik varmıdır?

bmutlu

Alıntı yapılan: Mucit23 - 14 Ekim 2014, 11:39:51
Hocam donanımsal spi ile olmuyor. Mcu da  6 adet spi olsa bile panelde tek clock girisi var. Bu yüzden soft spi şart. 

Zaten 74595 ile şuanda 100hz 8 kanal 8bit pwm çıkarıyorum.  Sıkıntı yok. Bunun sayısı artacak sadece. Oda henüz yeterince optimizasyon yapmadım. 


Siz bu pic leri araştırdınız mı spi çıkışlardan biri master olacak diğer spi çıkışları slave olacak böylece tek CLK ucu ile kontrol edilebilecek .Donanımsal gönderme işlemleri işi kolaylaştıracaktır . Bu bilgiyi de dikkate alın.
Bu yazınızı gözden kaçırmışım ..

Mucit23

Alıntı yapılan: bmutlu - 04 Kasım 2014, 14:01:27
Siz bu pic leri araştırdınız mı spi çıkışlardan biri master olacak diğer spi çıkışları slave olacak böylece tek CLK ucu ile kontrol edilebilecek .Donanımsal gönderme işlemleri işi kolaylaştıracaktır . Bu bilgiyi de dikkate alın.
Bu yazınızı gözden kaçırmışım ..

@bmutlu, O meseleyi biliyorum aslında Daha önce konuşulmuştu. Problem donanımsal spi ile olup olmayacağı değil! Elimizde hali hazırda olan mikrodenetleyicler var.

Farzedin RGB panel için bir kütüphane yazıyoruz. Bu kütüphane sadece harware spi ile çalışıyorsa ne kadar esnek olur? 6 adet donanımsal spi bulunduran mcu'ları bulup getirip öğrenmek zaten başı başına bir iş. Gerek yok...

bmutlu

Aslında PWM işlemini direkt pin üzerinde değil RAM üzerinde işlem yapıp burada gönderilecek datayı hazırlamak gönderme işlemini Donanımsal veya DMA yöntemi ile göndermek onun için zaman ayırmamanız gerekir . Oraya da bir zaman harcanmaması düşüncesindeyim .

bocek

@mucit, nette dolanırken bir şeylere rastladım belki işine yarar (ucu cevhere çıkıyor).

http://www.mikrocontroller.net/topic/346057#new
1 ya da 0. işte 'bit'ün mesele..

iyildirim

Alıntı yapılan: Mucit23 - 04 Kasım 2014, 00:52:28
Probleme geri dönersek sizce neden kaynaklanabilir. Yukarıdaki kodlarda gözünüze çarpan bir terslik varmıdır?

Bir sürü nedeni olabilir hocam. Mesela Timer doğru kurulmamış olabilir. Yaptığınız 2ms lik bekleme ile timer-PWM senkron gitmiyordur vs.
Genel olarak mantık doğru ama.

Daha önceki örneklere göre timer bekleme veya delay kısmı bir dış döngüde olmuş. Burada hata vardı. Ama sizin örneğinizde satır döngüsü olmadığından bu sorun yok.


Yazmışken tam olarak yazıp test edeyim dedim.
Timer için prescaler seçerken min duty 1 birim, frekans için timer taşması 128 birim seçildi. Böylece duty değişkeni direk PWM duy si olarak yüklenebilir ve tam senkronize oldu.  Veri gönderilip latch için timer bekleniyor. Veri gönderme zamanı PWM frekansını bozmuyor. Logic analizör ile bakarsanız pwm bir önce gönderilen veriye ait diye hatırlatayım.
Elimde SR yokmuş. Eski kart vs. bir yerlerden  bulursam fiziksel sonucuna da bir bakmak lazım.
Sanırım 32F4disco kitiniz vardır. 
#include "stm32f4xx.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_exti.h"
#include "stm32f4xx_syscfg.h"
#include "stm32f4xx_tim.h"
#include "misc.h"
#include "stm32f4xx_sdio.h"


#include "stdio.h"


volatile uint8_t timerFlag;
uint8_t ledduty [16][32][3]; // 16 satir 32 sütun, 3 renk 

    

uint8_t dutyCounter, duty, COMPARE;
uint8_t rowNum, colNum;



//  CPU frekansi 168Mhz
//  AHB frekansi 84 Mhz
//  APB frekansi 42 Mhz
// *********************************************************************************/

void InitBoard()
{
    volatile int i;
    
    
    NVIC_InitTypeDef NVIC_InitStructure;
    GPIO_InitTypeDef GPIO_Init_Struct;
//    EXTI_InitTypeDef EXTI_InitStructure;

    //CLOCK 
    RCC->APB1ENR |= 0x0006002F;        //TIM2 TIM3 TIM4 TIM5 TIM7 USART2 USART 3 CLOCK
    RCC->APB2ENR |= 0x00004000;        //SYSCFG CLOCK

    RCC->AHB1ENR |= 0x0000001F;        //GPIO A- C-D CLOCK

//GPIO D OUTPUT 13-14-15
    GPIO_Init_Struct.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; 
    GPIO_Init_Struct.GPIO_Mode = GPIO_Mode_OUT;    
    GPIO_Init_Struct.GPIO_OType= GPIO_OType_PP;
    GPIO_Init_Struct.GPIO_Speed= GPIO_Speed_100MHz;
    GPIO_Init_Struct.GPIO_PuPd=GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOD,&GPIO_Init_Struct);    


//GPIO D AF 12
    GPIO_Init_Struct.GPIO_Pin = GPIO_Pin_12; 
    GPIO_Init_Struct.GPIO_Mode = GPIO_Mode_AF;    
    GPIO_Init_Struct.GPIO_OType= GPIO_OType_PP;
    GPIO_Init_Struct.GPIO_Speed= GPIO_Speed_100MHz;
    GPIO_Init_Struct.GPIO_PuPd=GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOD,&GPIO_Init_Struct);    


    GPIOD->AFR[1] = 0x00020000; //TIM4 CH1


//TIM4 4000KHZ
    TIM4->PSC             = 163;//84E6/164
    TIM4->ARR             = 128;//84E6/164/128 -> 4000khz   ARR 128 seçildi. Min duty 1 olacak. 
    TIM4->DIER         = 0x00000001; 

    TIM4->CCMR1         = 0x0060;;    //CH1 PWM  ENABLE
    TIM4->CCER         = 0x1111;


    TIM4->CCR1         = 0;
    TIM4->CR1             = 0x0001;    
    
    NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    
}

int main(void)
{

    
    volatile uint32_t i;

    

//        uint16_t base_duty_ON_peryod;
//        base_duty_ON_peryod  = 1;


    ledduty [0][0][0] = 32;
    ledduty [0][1][0] = 64;
    ledduty [0][2][0] = 96;
    ledduty [0][3][0] = 128;
    ledduty [0][4][0] = 160;
    ledduty [0][5][0] = 192;
    ledduty [0][6][0] = 224;
    ledduty [0][7][0] = 255;

    ledduty [0][0][0] = 1;
    ledduty [0][1][0] = 2;
    ledduty [0][2][0] = 4;
    ledduty [0][3][0] = 8;
    ledduty [0][4][0] = 16;
    ledduty [0][5][0] = 32;
    ledduty [0][6][0] = 64;
    ledduty [0][7][0] = 128;

    ledduty [0][0][0] = 1;
    ledduty [0][1][0] = 3;
    ledduty [0][2][0] = 7;
    ledduty [0][3][0] = 15;
    ledduty [0][4][0] = 31;
    ledduty [0][5][0] = 63;
    ledduty [0][6][0] = 127;
    ledduty [0][7][0] = 255;


    InitBoard();

    GPIOD->BSRRL |= 1<<13;
    GPIOD->BSRRL |= 1<<14;
    GPIOD->BSRRL |= 1<<15;

    TIM4->CCR1    = 64;
    
    for (i=0;i<20000000;i++);
    
    GPIOD->BSRRH |= 1<<13;
    GPIOD->BSRRH |= 1<<14;
    GPIOD->BSRRH |= 1<<15;


    TIM4->CCR1 = 0;

    for (i=0;i<20000000;i++);

        TIM4->CCR1    = 1;


    while (1)
    {
        for (rowNum = 0; rowNum <1; rowNum++ )
        {

                        GPIOD->BSRRH = GPIO_Pin_14;

                    
            for (dutyCounter = 0; dutyCounter<8; dutyCounter++)
            {
                            duty = 1 << dutyCounter;

                            for (colNum = 0; colNum <8; colNum++) 
                            {
                                    
                                COMPARE = (duty & ledduty [rowNum][colNum][0]);
                                
                                if (COMPARE)
                                {
                                    GPIOD->BSRRL = GPIO_Pin_13;
                                }
                                else
                                {
                                    GPIOD->BSRRH = GPIO_Pin_13;
                                }                                    
                                __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
                                    

                                GPIOD->BSRRL = GPIO_Pin_14;
                                __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();

                                GPIOD->BSRRH = GPIO_Pin_14; 
                                __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();

                                GPIOD->BSRRH = GPIO_Pin_13;
                                __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();

                            }

                            while(timerFlag == 0);
                            timerFlag = 0;

                            
                            GPIOD->BSRRL = GPIO_Pin_15;
                                __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();

                            GPIOD->BSRRH = GPIO_Pin_15;
                                __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();

                            TIM4->CCR1    = duty;

            }
        }
    }
}
void TIM4_IRQHandler(void)
{

    timerFlag = 1;
    TIM4->SR     = 0x00000000;    

}


Alıntı yapılan: bmutlu - 04 Kasım 2014, 14:30:55
Aslında PWM işlemini direkt pin üzerinde değil RAM üzerinde işlem yapıp burada gönderilecek datayı hazırlamak gönderme işlemini Donanımsal veya DMA yöntemi ile göndermek onun için zaman ayırmamanız gerekir . Oraya da bir zaman harcanmaması düşüncesindeyim .
Burada ki sıkıntı 6 ayrı veri yi tek clock ile SPI a benzer şekilde aktarmak.  Tek tek pinler set edilecek olsa bile zaten performans yetmemesi gibi bir sıkıntı olmuyor. Ama donanıma yüklenmek konusunda aynı fikirdeyim. 6 pini paralel set edip tek seferde gönderilen 2 satıra ait 32 byte lık veriyi  dma ile göndermek paneli sürme ile ilgili max  işlemci yükünü  %1-2 lere indirir.

Alıntı yapılan: iyildirim - 02 Kasım 2014, 00:45:16
Sağ ve sol panellerin aynı satır ve sütünlarındaki 3 renk den 6 ledin 1 bitleri, bir sonraki sütunun 1 bitleri, ... şeklinde 6 data pinine karşılık 6 bitlik 32 byte'lık bir diziyi 2. ve diğer bitler  için tekrarlayıp satırı arttırıp 8 kere daha takrarlayıp şeklinde elde edilmiş bir dizimiz olduğunda 1 byte tı direk pine basmak tek seferde 6 bitinde set edilmesini sağlar. Paralel veri aktarımı ve clock işleri FSMC ile sağlanırsa 32 byte da bir yani 4Khz lik kesme ile row ve latch set edilebilir. Tabii lineer belleğimizi bu düzende bir bellek alanına kopyalayacak bir fonksiyon da gerekiyor.

Artı olarak led parlaklığının az olması konusu  için bir önceki mesajda anlatmaya çalıştığım yöntem için yapılması gereken OE pinini sürekli aktif yapıp 32 lik döngüyü çalıştıracağımız zamanı bir timer kesmesi ile belirlemek, 32 lik döngüyü start edecek timer kesmesinin taşma değerini 2 nin katları şeklinde hazırlanmış 6-8 elemanlı bir diziden okumak..

İster direkt ledlerin az yandığı 2 yöntem, ister en son anlatmaya çalıştığım yöntem için Timerde FSMC tetiklemek, FSMC kesmesinde satır ve latch set etmek sanırım ideal yöntem olur. Açıkçası aklıma donanımdan da yardım alınabilecek minimum işlem zamanı gerektiren  başka bir yöntem gelmiyor.

Mucit23

Hocam eger benim 74hc595 icin yazdığım kodda mantık doğru ise mesleyi anladığımı söyleyebilirim. Fakat sorunu çözemedim. 

Aslında yukarıda verdiğim kodda timer kullanmadım.  Main döngüsü içerisinde çalıştırıyordum. Kesme yerine döngü içerisinde 2ms lik gecikme yaptırdım. Belki sorun latch isleminden sonra pwm i acmamdan kaynaklaniyordur. Akşam lojik analyser ile ayrıntılı bir inceleme yapacağım.