Bu başlık da daha önceleri açtığımız BASIC kullanıcılarını C'ye alıştırma turları na benzer şekilde ilerleyecektir.
Amacımızın Keil ile ARM işlemcilere C kod yazmak olduğunu unutmayın.
Ancak bu kez katılımcı sayısı konusuna sınırlama getirmeyeceğim.
https://www.picproje.org/index.php/topic,35980.msg257667.html#msg257667 (https://www.picproje.org/index.php/topic,35980.msg257667.html#msg257667) başlığındaki konuları tekrardan anlatmayacağım.
Tartışmaya katılacak ASM ci arkadaşların ASM kodla örnek vermeleri yerine, hangi işlemleri yapmak istediklerini yazarak sormalarını, ve buna cevaben C kodlarını yazacağımızı hatırlatayım.
Örneğin A ve B adındaki 8 bitlik değişkenlerimde saklanan iki sayıyı toplayıp sonucu 16 bitlik X değişkenine yazmak istiyorum dediklerinde
char A,B;
int X;
// A ve B nin değer aldıklarını varsayın
X= A+B; örneğini vereceğiz.
ASM'de register olarak kullandığımız 8 bitlik saklayıcılar (A. satırdan B. satıra şeklinde), C de neye tekabul ediyor değişkene mi?
C de CPU registerleriyle normalde işimiz olmaz.
C de değişkenler tanımlar ve işlemleri doğrudan bu değişkenler üzerinde yaparız.
Bir de C de bit düzeyinde işlem yapmak mümkün mü? Yani 3. bitin 1 olduğunu anlamak için sadece 3. biti nasıl öğrenebiliriz?
Eğer işlemcinizde bit bazında işlem yapan asm komutlar yoksa siz ne yapardınız? C de de aynısını yaparız.
Eğer işlemcinin bir bazında işlem yapan komutlar varsa C'de de bu anlamda komutlar vardır.
Örneğin ASM yazımınızda B.1, 8 bitlik değişkenin 1 nolu biti demek ise muhtemelen C de de B.1 yada benzerı yazım geçerli olacaktır.
Fakat en kötü ihtimal if ((B>>3)&1) komutu, B nin 3.biti 1 ise karşılaştırmayı doğru kılacaktır.
Buradaki 3 kez sağa kaydırma, ARM işlemcide tek clock da yapılacağından zaman kaybı olmayacaktır.
(ARM işlemcinin Ram ve çevre birimi registerlerinin bazılarına bit bazında da erişilebilir.) (Sadece I/O Portlara mı yoksa hepsine mi araştıralım)
Aslında C'de doğrudan bit işleyen komutlar yok. Ama bu sorunu struct, union yapısı ile çözebiliriz.
union{
unsigned char structbyte;
struct{
unsigned char bit_1 : 1;
unsigned char bit_2 : 1;
unsigned char bit_3 : 1;
unsigned char bit_4 : 1;
unsigned char bit_5 : 1;
unsigned char bit_6 : 1;
unsigned char bit_7 : 1;
unsigned char bit_8 : 1;
};
} test;
bu şekilde bir tanımlama ile bit kullanımı mümkün.
test.bit_1 = 0 , test.bit_2 = 1;
ya da test.structbyte = 78;
IAR derleyicisi bu şekildeki bit operasyonları için işlemcinin komut setindeki bit operatörlerini kullanıyor. Belki derleyiciye göre değişiyordur.
hocam bunalmış hocamızın dediğini anladım ama sizin dediğiniz yöntemden tek bir satırı anlayamadım açıklayabilir misiniz?
Bir de bunalmış hocam işlemcide bit düzeyinde işlem varsa yada yoksa diye birşey belirtmiş. Böyle bir işlemci var mı ki bit düzeyinde işlem yapmasın?
Bu soruyu sorma amacım birçok kişi C de yazarken yazılımın çok şiştiğinden bahsetmiş forumlarda, bit düzeyinde yapılan işlemin hem düşük güç kontrolü açısından hem de yazılım boyutu açısından ekonomikliği bulunmakta. C kullanırken buna nasıl dikkat edebilirim maksadındaydı.
ARM ailesinde bazı işlemciler "bit banding " olarak geçen bir manipulasyon desteği sunuyor(ör Cortex-M3/-M4) . Bit Banding piclerde ki BSF BCF gibi.
Örneğin ben Cortex M0 kullanıyorum ve Bit Banding desteklemiyor. Bu durumda Klein Üstadımın bahsettiği gibi aynı alanı gösteren bir union ve hedefi gösteren bir Struct ile alias oluşturup hedefin istediğimiz yerine ateş edebiliyoruz.
Üst seviye Cortexler için "Bit Banding" olarak aratırsanız detay bilgi bir haylice var. ARM da bununla ilgili bir makale de vardı sanırım.
Alıntı yapılan: muhendisbey - 01 Kasım 2011, 23:43:49
hocam bunalmış hocamızın dediğini anladım ama sizin dediğiniz yöntemden tek bir satırı anlayamadım açıklayabilir misiniz?
Bir de bunalmış hocam işlemcide bit düzeyinde işlem varsa yada yoksa diye birşey belirtmiş. Böyle bir işlemci var mı ki bit düzeyinde işlem yapmasın?
Bu soruyu sorma amacım birçok kişi C de yazarken yazılımın çok şiştiğinden bahsetmiş forumlarda, bit düzeyinde yapılan işlemin hem düşük güç kontrolü açısından hem de yazılım boyutu açısından ekonomikliği bulunmakta. C kullanırken buna nasıl dikkat edebilirim maksadındaydı.
Elbette yazılımla bit manuplasyonuna gerek duyan daha açık ifade ile donanımsal olarak bit işleme komutları olmayan işlemciler var.
Mesela, bit bazında işlem yapan makine komutları, PIC ve 8051 de var fakat, 8086 ve DSP lerde yok. CM3 işlemcilerin register üzerinde bit maniplasyonu yapan komutları var.
---------------------------
Mesela 8 bitlik bir portun 0. bitine 1 yüklemek için bit erişim komutu olmayan bir işlemci kullanıyorsan
porta daha önceden yüklenmiş olan veriyi tespit edip (bu portu okumak olabilir) ardından sonucu 0x01 ile OR layıp gerisin geriye porta yazabilirsin.
Aynı şekilde 0. biti o yapmak istiyorsan portu okuyup 0xFE ile AND leyip gerisin geriye porta yazabilirsin.
Eğer işlemcinin zaten bitmanuplasyon komutları varsa ya da erişmek istediğin alan Bit Band özelliğinde ise o zaman yukarıdaki uzun yönteme gerek kalmaz.
Derleyicinin hangisini tercih edeceğini hatta bu tercihi kendisi yapabilirmi yoksa biz mi zorlayacağız konusunu bilmiyorum. En kısa zamanda bu konuyu araştırıp örnekle açıklamak istiyorum.
Çok iyi düşünülerek yazılmış ASM programların çok iyi düşünülerek C ile yazılmış programlardan daha kısa ve hızlı olacağı konusunda sanırım hemfikiriz. Ancak ARM dünyasına geçtiğimizde bu işlemciyi genellikle büyük projelerde kullanmak isteriz.
Bu durumda amaç, kısa kod yazmak yerine projeyi gerçeklemek olmalıdır. Özellikle ve özellikle, hızlı koşmasının çok da şart olmadığı rutinleri C ile kodlama fikrini benimsemekte fayda var.
Çok optimize sonuç verecek ASM yazım, fazlasıyla zahmetli ve mevcut seçenekleri kimi zaman tek tek yazıp elemeyi gerektirdiğinden, mecbur kalmadıkça tercih edilmemelidir.
Bit Banding CM4 işlemcimizde çevrebirimlerinin registerleri ile SRAM alanı üzerinde bit işlemleri yapılabilmekte. (Ancak bu işlemlerin doğrudan işlemci ile yapılması gerekiyor. DMA ile yapamıyoruz.) Word olarak erişilen alanı ister word data yükleyerek değiştirebiliyoruz istersek bit banding yaparak. (
Word alias konusuna bir ara değinelim, unutturmayın)
Hedef alanda bir biti değiştirmek için Bu bitin bit band alanındaki adresini hesaplamamız gerekiyor.
bit_word_addr = bit_band_base + (byte_offset x 32) + (bit_number × 4)
Örneğin RAM'ın ilk adresi olan 0x20000000 da 2.biti (0 dahil sayarsak 0,1,2) 1 yapalım.
Bit_Band_Base = 0x22000000, Byte_Offset = 0x0000 * 0x32, Bit_Number = 2
Bit_Word_Addr=0x22000000 + 0*32 + 2*4 =0x22000008
Bunu test etmek için aşağıdaki programı Keilde deneyin. A ve P değişkenlerini Watch1 de gözleyin.
#include "STM32F4xx.h"
unsigned short A;
void SystemInit()
{
}
unsigned short* Bit_Adr(int Wadr,char BitNum)
{
return((unsigned short*)(0x22000000 + ((Wadr - 0x20000000)<<5) + (BitNum<<2)));
}
int main()
{
unsigned short* P;
A=0;
P=Bit_Adr((int)&A,2);
*P=1;
}
Yukarıdaki program A=0 ataması ardından Anın 2.bitini set etmektedir. Basit bir bit manuplasyonu için fazlaca uzun bir işlem mi dersiniz? Devam edeceğiz.
Memoryde MyTarget adındaki 16 bitlik adresde bit manuplasyonu yapmak için;
P pointerimize P=((unsigned short*)(0x22000000 + ((MyTarget - 0x20000000)<<5))); yükleyelim. P bizim MyTarget adresinde 0. biti referans gösterir. n.pozisyondaki biti set etmek istersek word pointera 2*n eklemek ( adresi 4*n byte ilerletmek) yeterli olacaktır.
#include "STM32F4xx.h" unsigned short A;
void SystemInit()
{
}
unsigned short* Bit_Adr(int Wadr,char BitNum)
{
return((unsigned short*)(0x22000000 + ((Wadr - 0x20000000)<<5) + (BitNum<<2)));
}
int main()
{
unsigned short* P;
A=0;
P=Bit_Adr((int)&A,0);
*(P+0x000)=1; // 0. Biti set et
*(P+0x002)=1; // 1. Biti set et
*(P+0x004)=1; // 2. Biti set et
*(P+0x006)=1; // 3. Biti set et
*(P+0x008)=1; // 4. Biti set et
*(P+0x00A)=1; // 5. Biti set et
*(P+0x00C)=1; // 6. Biti set et
*(P+0x00E)=1; // 7. Biti set et
*(P+0x010)=1; // 8. Biti set et
*(P+0x012)=1; // 9. Biti set et
*(P+0x014)=1; //10. Biti set et
*(P+0x016)=1; //11. Biti set et
*(P+0x018)=1; //12. Biti set et
*(P+0x01A)=1; //13. Biti set et
*(P+0x01C)=1; //14. Biti set et
*(P+0x01E)=1; //15. Biti set et
*(P+0x020)=1; //16. Biti set et (!!! MyTarget'i takip eden adrese duhul ettik !!!)
*(P+0x022)=1; //17. Biti set et
*(P+0x024)=1; //18. Biti set et
*(P+0x026)=1; //19. Biti set et
*(P+0x028)=1; //20. Biti set et
*(P+0x02A)=1; //21. Biti set et
*(P+0x02C)=1; //22. Biti set et
*(P+0x02E)=1; //23. Biti set et
*(P+0x030)=1; //24. Biti set et
// .....
// .....
}
Şayet her bir bit değişkenin adresini sabitlersek bu durumda pointer üzerinde toplama işlemi yapmaya gerek kalmaz ve
Bit değişkenlerimiz A0,A1,A2,A3... B0,B1,B2,B3... gibi isimler alabilir.
Bunların herbirisinin adresi belli olduğundan;
B1=A1; B7=A6 & B3; vs vs işlemler, klasik yazılımla yapılacak bit manüplasyon işlemlerine kıyasla son derece hızlı yapılacaktır.
(Yukarıdaki örnek programı aynen kullansanız dahi Keil çok optimize kodlar üretmektedir)
merhab abunalmış hocam bu konuya ben de dahil olmak istiyorum . burada siz ben den bir program isteseniz ben de asm sini yazsam sonra sizde C ye çevirseniz olur mu ?
ARM asm yazacaksan olur.
C de alt program nasıl yazılır? ve bu alt programlar ana programa nasıl dahil edilir?
bunun için 200ms lik gecikmeyi ana program içinde kullanmaya örnek verebilir misiniz?
Bir diğeri tablo alt program, bunu nasıl C de yaparız?
Bunun için de seven segment display 0-9 sayıcı örneği verebilir misiniz?
Alt program dediginiz sey C deki fonksiyolar.
Ornegin CALL TOPLA gibi bir asm satirini C'de
TOPLA(); diye kullaniriz.
-------------------
200ms lik gecikme rutinini eger asm de zaman kaybeden kodlari calistirarak gercekliyorsaniz C de de bunu
for(i=0;i<10000;i++); gibi i nin volatile ekiyle tanimlandigi kodla yada benzeri ile gerceklestiririz.
Isin icine CPU clk frekansini da dahil edip 10000 gibi bir sayiyi CPU CLK degerine gore modifiye eden fonksiyonu yazmak da mumkundur.
Eger 200ms yi timer ile yaptirdiysaniz C de mantik ayni.
--------------------
Tablolari C de array olarak tanimlariz. Eger amaciniz bir tabloya fonksyonlarin adreslerini yerlestirmek ve bir indise gore bu fonksyonlari cagirmak ise
fonksiyon adreslerini array icine yazmaniz yeterli. Bu konuda ornegi bir baska mesajimda verecegim.
Hocam UART ile iletişim kurmak istesek, buna uygun porta göre bağlantımız yapılmış olsun. Mesela iletmek istediğim bir metin olsun "bunalmis" mesela bunu nasıl göndeririz? Sıfırdan kütüphane oluşturmak mı gerekir, yoksa bunu sağlayacak yapı Keil içerisinde var mı?
Bunu şu açıdan da soruyorum bluetooth üzerinden porta çıkış vermeye uğraşıyorum.
Bir de yazmayı unutmuşum yukarıda diğer mesajda yanıtlayacağınız sorumu cevaplayabilirseniz memnun olurum.
Hocam şimdi ben C de program yazarken bir değişken tanımlıyorum bu değişkenlerle işlem yaparken aslında arm işlemcimizin r0-r12 registerları ile işlem yapıyoruz değil mi?Eğer durum böyle ise değişken tanımladığımız bu r0-r2 registerlarının arasından hangisi ile işlem yapılacağı nasıl belirleniyo.Bir de bir çevre-birimine ait bir register a bir değer atayacağımız zaman ilk olarak r0-r12 registerlarına kaydedilip daha sonra mı o registera kaydoluyo yoksa direkt olarak mı kaydediliyo.
Hocam bu derleyiciyle alakalı bişey değil mi? Yani derleyiciyi kim yazdıysa onun belirlediği kurallar.
BUNALMIŞ HOCAMIZ DISCOVERY KİT HAKKINDA ÖRNEKLER VERİRKEN
// FLASH->ACR = 0x00000705; // Flash ROM icin 6 Wait state secelim ve ART yi aktif edelim (Rehber Sayfa 55) Yazmamız gereken asıl kod bu fakat çipte bug var
FLASH->ACR = 0x00000605; // Flash ROM icin 6 Wait state secelim ve ART yi aktif edelim (Rehber Sayfa 55) Mecburen bunu yazacağız.
gibi bir açıklama yapmış ancak burada neden 0x0605 değerini kullandığımızı ben anlayamadım çipte bug olması ne demek ve de neden bu değeri(PREFETCH bitini) etkiliyor? Diğer konular kilitli olduğundan buraya yazmak zorunda kaldım özür dilerim...
Alıntı yapılan: z - 02 Kasım 2011, 06:25:54
#include "STM32F4xx.h"
unsigned short A;
void SystemInit()
{
}
unsigned short* Bit_Adr(int Wadr,char BitNum)
{
return((unsigned short*)(0x22000000 + ((Wadr - 0x20000000)<<5) + (BitNum<<2)));
}
int main()
{
unsigned short* P;
A=0;
P=Bit_Adr((int)&A,2);
*P=1;
}
Hocam bu yapı ile istediğim portun bitine Bitband kullanarak yazabiliyorum ancak kafama takılan bir nokta var.
P pointer'ına sizin örneğinizde yüklenen değer 0x22000008 , benim örneğimde de 0x422201A0 gibi bir değer ( GPIOC->ODR, Bit8 ) ve sorunsuz çalışıyor gibi.
Ancak P pointerını unsigned short olarak tanımladık yani 16bit. Fakat 32 bitlik adresleri P pointer'ı ile kullanıyoruz , değeri hesapladığımız fonksiyondan 16 bit short bir değerle dönüyoruz.
Burada kaçırdığım bir şey mi var acaba diye sormak isterim size ?
mesaj birleştirme:: 04 Kasım 2012, 17:13:58
Alıntı yapılan: camby - 04 Kasım 2012, 17:13:32
Bu yapı ile istediğim portun bitine Bitband kullanarak yazabiliyorum ancak kafama takılan bir nokta var.
P pointer'ına sizin örneğinizde yüklenen değer 0x22000008 , benim örneğimde de 0x422201A0 gibi bir değer ( GPIOC->ODR, Bit8 ) ve sorunsuz çalışıyor gibi.
Ancak P pointerını unsigned short olarak tanımladık yani 16bit. Fakat 32 bitlik adresleri P pointer'ı ile kullanıyoruz , değeri hesapladığımız fonksiyondan 16 bit short bir değerle dönüyoruz.
Burada kaçırdığım bir şey mi var acaba diye sormak isterim size ?
mesaj birleştirme:: 04 Kasım 2012, 17:15:21
Burada düzenleme yapılamıyor sanırım bu sayede öğrenmiş oldum : )
Pointerin tipi ile point edilen yere yazılacak verinin uzunluğu anlaşılmalı.
ARM işlemcide memory 32 bit adreslenir. Dolayısı ile pointerler fiziksel olarak 32 bit deger saklar. Pointerin short int tanımlanması 32 bitlik ile adreslenen alana 16 bitlik veri yerleştirilmesine izin verir.
0x01
0x0001
0x00000001
0x0000000000000001
Yukarıda 1 sayısını görüyorsun. Bunların memorye yerleşimi 32 bitlik pointer ile yapılır fakat her biri memory de farklı uzunlukta alan kullanır.