Spi ile PIC'ler Arası Haberleşmede Sorun

Başlatan OnderGrmz, 01 Aralık 2014, 16:01:53

OnderGrmz

Merhabalar;
Spi ile haberleşme yaparken bir duruma rastladım. int8 değişken türünde birkaç tane değerim olması gerekiyor. Bu değerleri tanımladıktan sonra Spi'dan bilgi göndermeye çalıştım. Ancak normalde çalışan kodların yanlış çalıştığını gördüm. İnt8 türündeki değişkenlerin sayısı 10 olduğunda Spi iletişiminde gönderdiğim kodlar karşıya doğru bir şekilde gitmiyor. Bunların birbirleriyle ilgisini pek anlayamadım. Değişkenin değerine bağlı bir durum değil bu. Yani değişken sayısı 10'un altında olduğu sürece problem çıkmıyor. Değişken sayısı 10'un üzerine çıkınca gönderilen ve alınan bilgiler sapıtıyor. Bir anlam veremedim bu duruma. Daha önce böyle bir durumla karşılaşan var mı ?
Master:
#include <18f4680.h>     // Kullanılacak denetleyicinin başlık dosyası tanıtılıyor.
//#include <motor kontrol.c>
#fuses HS,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD // Denetleyici konfigürasyon ayarları

#use delay(clock=20000000)   // Gecikme fonksiyonu için kullanılan osilatör frekansı belirtiliyor
#define cs PIN_C2    // CS ifadesi PIN_C2 pini yerine atanıyor

int8 okuma_istek=0x05,okunan_deger,master_tx_gereksiz=0x35;  // int8 tipinde değişkenler tanımlanıyor
int8 ileri=0x50,geri=0x51,saga=0x52,sola=0x53;
int8 ileri_sag=0x54,ileri_sol=0x55;                            // Değişken sayısı 9 sıkıntı yok !!!
//int8 geri_sag=0x56,geri_sol=0x57;

void oku();
void yaz(int8 a);

#int_ssp // SPI iletişiminde yazma veya okuma yapıldığında meydana gelen kesme
void SPI_kesmesi()
{  

}

void main ()
{
   setup_psp(PSP_DISABLED);        // PSP birimi devre dışı
   setup_timer_1(T1_DISABLED);     // T1 zamanlayıcısı devre dışı
   setup_timer_2(T2_DISABLED,0,1); // T2 zamanlayıcısı devre dışı
   setup_adc_ports(NO_ANALOGS);    // ANALOG giriş yok
   setup_adc(ADC_OFF);             // ADC birimi devre dışı
   setup_CCP1(CCP_OFF);            // CCP1 birimi devre dışı
   setup_CCP2(CCP_OFF);            // CCP2 birimi devre dışı
  
   setup_spi(spi_master| spi_L_to_H | spi_clk_div_4);  // SPI iletişim ayarları belirtiliyor
   
   enable_interrupts(int_ssp);   // SPI kesmesi aktif yapılıyor
   enable_interrupts(GLOBAL);    // Aktif edilen tüm kesmelere izin ver  

   output_high(cs); // Harici EEPROM CS ucu lojik-1 yapılıyor

   while(1) // Sonsuz Döngü
   { 
       if(input(pin_b5)==1)
       {
         delay_ms(50);
         while(input(pin_b5));
         yaz(okuma_istek);
         oku();
       }          
  }       
}

void oku()
{
   okunan_deger=spi_read();
   spi_write(master_tx_gereksiz);//Bilgi almak için gerekli kodlar yazılıyor 
}

void yaz (int8 a)
{
   output_low(cs);  // Entegre seçiliyor
   spi_write(a); //Bilgi yazmak için gerekli kodlar yazılıyor
   output_high(cs);
}


Slave:
#include <18f4680.h>     // Kullanılacak denetleyicinin başlık dosyası tanıtılıyor.
#fuses HS,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD // Denetleyici konfigürasyon ayarları
#use delay(clock=20000000)   // Gecikme fonksiyonu için kullanılan osilatör frekansı belirtiliyor

#use rs232 (baud=9600, xmit=pin_C6, rcv=pin_C7, parity=N, stop=1) // RS232 iletişim ayarları belirtiliyor
  
#include <input.c>   // input.c dosyası programa ekleniyor
#include <stdlib.h>  // stdlib.h dosyası programa ekleniyor

int8 bilgi_istek=0x05,bilgi=0x10,okunan,slave_tx_gereksiz=0x12;  // int8 tipinde değişkenler tanımlanıyor


#int_ssp // SPI iletişiminde yazma veya okuma yapıldığında meydana gelen kesme
void SPI_kesmesi()
{     
       okunan=spi_read();
       spi_write(slave_tx_gereksiz); 
       printf("\n\r\Bilgi alindi !!!");
       printf("\n\r\Alinan Deger=0x%02X",okunan );
}


/******************* ANA PROGRAM FONKSİYONU *************************/
void main ()
{
   setup_psp(PSP_DISABLED);        // PSP birimi devre dışı
   setup_timer_1(T1_DISABLED);     // T1 zamanlayıcısı devre dışı
   setup_timer_2(T2_DISABLED,0,1); // T2 zamanlayıcısı devre dışı
   setup_adc_ports(NO_ANALOGS);    // ANALOG giriş yok
   setup_adc(ADC_OFF);             // ADC birimi devre dışı
   setup_CCP1(CCP_OFF);            // CCP1 birimi devre dışı
   setup_CCP2(CCP_OFF);            // CCP2 birimi devre dışı
   
   setup_spi(spi_slave| spi_L_to_H | spi_ss_disabled);  // SPI iletişim ayarları belirtiliyor
   
   enable_interrupts(int_ssp);   // SPI kesmesi aktif yapılıyor
   enable_interrupts(GLOBAL);    // Aktif edilen tüm kesmelere izin ver    

   while(1) // Sonsuz Döngü
{  
     if(okunan == 0x05)
    {         
       spi_write(bilgi);      // Belirtilen adrese yazdırılacak veri gönderiliyor
    }         
     
}


Ekran Alıntısı:
[IMG]http://i62.tinypic.com/2pynuok.png[/img]

Kodlarda sadece şu kısmı değiştirince
int8 okuma_istek=0x05,okunan_deger,master_tx_gereksiz=0x35;  // int8 tipinde değişkenler tanımlanıyor
int8 ileri=0x50,geri=0x51,saga=0x52,sola=0x53;
int8 ileri_sag=0x54,ileri_sol=0x55;                            // 10 ve üstü değişken sıkıntı yaratıyor !!!
int8 geri_sag=0x56,geri_sol=0x57;

Aşağıdaki gibi bir durum oluşuyor.
[IMG]http://i57.tinypic.com/2i6jij9.png[/img]

Burada iki önemli nokta var bence Spi Debugger'dan bakarsak Slave cihaza göndermek istediğimiz 0x05 bilgisi gönderilmiş olarak görünüyor.
Ama Virtual Terminal'e bakarsak 0x05 bilgisi değilde 0x9A bilgisi gönderilmiş olarak görünüyor. Slave kodlarındaki şu satırdan Virtual Terminal'in doğru gösterdiği sonucu çıkıyor.
if(okunan == 0x05)
    {        
       
       spi_write(bilgi);      // Belirtilen adrese yazdırılacak veri gönderiliyor
    }

Eğer Slave'e gelen veri 0x05 olsaydı Master cihaza 0x10 bilgisi gönderilmesi gerekiyordu. Yardımlarınızı bekliyorum.
Saygılarımla ...

OnderGrmz

Merhabalar;
Konu biraz eski ama bu konunun üzerine ilave olarak birkaç şey sormak istiyorum.

Spi haberleşmesinde 2 tane slave 1 tane master kullanmak istiyorum.
Slave cihazlarından bir tanesi pic ve SS pini mevcut değil. 2. slave cihazın ise SS pini mevcut. Ben 2. slave cihaza SS pinini lojik 0 yaparak bilgi gönderdiğimde dolayısıyla slave pic'te bilgiyi alıyor ve spi haberleşme protokolü gereği aynı anda MISO üzerinden birde bilgi gönderiyor. Hal böyle olunca master cihaza giden bilgiler karışıyor ve sistem patlıyor.
Sistemi ayrı ayrı denediğimde hiçbir sıkıntı yok. Master cihaz ile 2. slave, master cihaz ile slave pic ayrı ayrı iken gayet güzel çalışıyorlar.
Not: Ayrıca sistemi test ederken şunu da denedim. Slave pic in MISO pininin bağlantısını kopardığımda Master ile 2. slave gayet düzgün çalışıyor, aynı zamanda slave pic e bilgi gönderebiliyorum.
Bu problemin üstesinden nasıl gelebilirim ?
Saygılarımla ...


z

Master cihaza da kodları sen yazıyorsan sorun yok.

SS dediğin pinleri yazılımla sen harekete geçirirsin. Slave PIC'in herhangi bir pinini bu amaçla kullanırsın. Pic bu pini low görünce SPI rutinleri çalışacak şekilde düzenlersin.

Eğer bahse konu pic yazılımına müdahale edemiyorsan SCK,MOSI MISO hatlarına three state buffer vs koyarsın. SS pini bu bufferın enable ucu olur. SS low olmazsa three state buffer master ile pic bağlantısını kopartır low olduğunda bağlantıyı sağlar.

2. çözüm tamamen elektronik çözüm. İlk çözüm ise yazılımsal çözüm.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

OnderGrmz

Alıntı yapılan: z - 15 Mayıs 2015, 02:34:15
SCK,MOSI MISO hatlarına three state buffer vs koyarsın. SS pini bu bufferın enable ucu olur. SS low olmazsa three state buffer master ile pic bağlantısını kopartır low olduğunda bağlantıyı sağlar.

2. çözüm tamamen elektronik çözüm. İlk çözüm ise yazılımsal çözüm.

Hocam baskı devresini yaptığım için şu anda 2. çözüm pek uygun görünmüyor. Yazılımsal olarak halletmeye çalışacağım.
Alıntı yapılan: z - 15 Mayıs 2015, 02:34:15
Master cihaza da kodları sen yazıyorsan sorun yok.
SS dediğin pinleri yazılımla sen harekete geçirirsin. Slave PIC'in herhangi bir pinini bu amaçla kullanırsın. Pic bu pini low görünce SPI rutinleri çalışacak şekilde düzenlersin.

Master da yazılımı ben yazıyorum hocam. Sizin dediğiniz gibi bir şeyi yapmayı denedim.

Slave Pic Şema:
[IMG]http://i59.tinypic.com/24eaqh3.png[/img]

Slave Pic Kodları:
#int_ext2
void dis_kesme()
{  disable_interrupts(INT_EXT2);
   output_toggle(pin_b7);
   delay_ms(5);

//!   if(spi_data_is_in()==1)
//!   { 
//!      okunan=spi_read();
//!      output_toggle(pin_b6);
//!   }
   enable_interrupts(INT_EXT2);
}
void main ()
{ 
//setup_spi(spi_slave| spi_H_to_L|spi_xmit_l_to_h |spi_ss_disabled);
ext_int_edge(L_TO_H);
enable_interrupts(INT_EXT2);
enable_interrupts(GLOBAL);    // Aktif edilen tüm kesmelere izin ver

}

Slave pic seçmek için harici kesme 2 bacağını kullanıyorum.
Master da Slave pice veri göndereceğim zaman harici kesme bacağını 0 V'a çekiyorum. İşim bitince tekrar lojik 1 yapıyorum.

Slave pic de ise harici kesme oluştuysa spi dan bilgi oku diyorum. Fakat önce de belirttiğim gibi ben
setup_spi(spi_slave| spi_H_to_L|spi_xmit_l_to_h |spi_ss_disabled);

satırını yazdığım anda pic gelen verileri değerlendirmeye başlıyor ve MISO pininden çıkış veriyor.

Bunu aşmak için ne yapmam lazım pek kestiremedim. Eğer yazılımsal çözümünü bulamazsam sizin dediğiniz gibi donanımsal bir çözüme bakacağım.

z

SPI rutinlerini sen yazmış olsaydı iş kolaydı.

Gene  de SPI donanımı enable eden bir register vardır. Doğrudan bu registere ulaşırsın ve bir 1 bite bakar.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

OnderGrmz

Alıntı yapılan: z - 15 Mayıs 2015, 05:40:03
SPI rutinlerini sen yazmış olsaydı iş kolaydı.
Gene  de SPI donanımı enable eden bir register vardır. Doğrudan bu registere ulaşırsın ve bir 1 bite bakar.

Haklısınız hocam kullandığım denetleyicinin başlık dosyasına ve IDE'nin setup_spi fonksiyonu ile ilgili index ine baktım.  İçeride Spi birimini pasif yapan bir komut bulamadım. Bir kere ayarladıktan sonra pasif yapamıyorum.

Dediğiniz gibi registerların aldığı değerleri inceleyerek yola devam etmek lazım.
#include <18f4550.h>
////////////////////////////////////////////////////////////////// SPI
// SPI Functions: SETUP_SPI, SPI_WRITE, SPI_READ, SPI_DATA_IN
// Constants used in SETUP_SPI() are:
#define SPI_MASTER       0x20
#define SPI_SLAVE        0x24
#define SPI_L_TO_H       0
#define SPI_H_TO_L       0x10
#define SPI_CLK_DIV_4    0
#define SPI_CLK_DIV_16   1
#define SPI_CLK_DIV_64   2
#define SPI_CLK_T2       3
#define SPI_SS_DISABLED  1

#define SPI_SAMPLE_AT_END 0x8000
#define SPI_XMIT_L_TO_H  0x4000

//////////////////////////////////////////////////////////////////

z

SSPEN: Master Synchronous Serial Port Enable bit
1 = Enables serial port and configures SCK, SDO, SDI and SS as serial port pins(2)
0 = Disables serial port and configures these pins as I/O port pins(2)

http://ww1.microchip.com/downloads/en/DeviceDoc/39632e.pdf Sayfa 199

SPI disable yapmak için SSPCON1 registerini okuyup  0xDF ile andleyip geri yazmayı deneyebilirsin.
Enable etmek için gene SSPCON1 registerini okuyup 0x20 ile orlayıp geri yazmayı deneyebilisin.

Bana e^st de diyebilirsiniz.   www.cncdesigner.com

skara1214

Herkes ölür ama herkes gerçekten yaşamaz

OnderGrmz

#23
z hocam SSPCON1 register ına bakınca aklımda bir şeyler canlanmaya başladı.
Birde skara1214 hocam söylediğinde haklı.

datasheet te 204. sayfadaki
19.3.7 SLAVE SELECT SYNCHRONIZATION
başlığa bakarsak pic slave modunda çalışırken SS (Ra5 ) pini yetkilendirilirse picin spi haberleşmesini başlatan pin olduğu yazıyor.

Yine datasheet te 199. sayfaya dönüp bakarsak
gerekli ayarlar aşağıdaki gibi olmalı.

setup_spi();
fonksiyonu SSPCON1 ve SSPSTAT kaydedicilerine spi için gerekli olan parametreleri gönderiyor.

[IMG]http://i62.tinypic.com/2dt8wab.png[/img]

Master tarafında gönderici sistemimde ayarlar aşağıdaki gibi
CPOL=0;
CPHA=0;
slave picte ise
CKP=0;
CKE=1;
değerlerine tekabül ediyor.
CKE değerini SSPSTAT: MSSP STATUS REGISTER (SPI MODE) kaydedicisinin 6. biti kontrol ediyor.
bit 6 CKE: SPI Clock Select bit(1)
1 = Transmit occurs on transition from active to Idle clock state
0 = Transmit occurs on transition from Idle to active clock state
0x40 yazılmalı
#define SPI_XMIT_L_TO_H  0x4000


SSPCON1:
bit 5 SSPEN: Master Synchronous Serial Port Enable bit spi'ı aktif hale getirmek için 0x20 yazmak gerekiyor.

bit 3-0 SSPM3:SSPM0: Master Synchronous Serial Port Mode Select bits
0101 = SPI Slave mode, clock = SCK pin, SS pin control disabled, SS can be used as I/O pin(3)
0100 = SPI Slave mode, clock = SCK pin, SS pin control enabled(3)

SS pinini kullanıp slave olarak çalıştırmak istersek 0x04 bilgisi yazılmalı
#define SPI_SLAVE        0x24 // Spi birimini ve SS pinini aktif edecek bilgi mevcut




bit 4 CKP: Clock Polarity Select bit
1 = Idle state for clock is a high level
0 = Idle state for clock is a low level

Clock sinyalinin boştayken lojik 0 olması gerektiğini belirtmek için ise 0x00 yazmamız lazım.

#define SPI_L_TO_H       0     // Saat darbesi polaritesi belirtiliyor



Bunların hepsinin birleştirirsek
setup_spi(spi_slave| spi_L_to_H|SPI_XMIT_L_TO_H);  // SPI iletişim ayarları belirtiliyor 

yazmamız gerekiyor.

Ayrıca SS pinin (Ra5) bağlantısını yaptım. Böylelikle Slave pic in gereksiz yere MISO hattını boşuna meşgul etmesi problemini çözdüm.

Şu anda ise farklı bir problem oluştu. :D
Slave pic e gelen bilgiyi okuduğumda tüm spi hattı kilitleniyor.

okuma işlemini tarama ile veya kesme ile yapmayı denedim yinede kilitleniyor. Buna anlam veremedim. Biraz uzun soluklu oldu, kusura bakmayın :D

#int_ssp
void spi_kesmesi()
{
   disable_interrupts(int_ssp);
   output_toggle(pin_b7);
   delay_ms(50);
   okunan=spi_read();


   enable_interrupts(int_ssp);
}

// yada

if(spi_data_is_in()==1)
   { 
       okunan=spi_read();
       output_toggle(pin_b7);
       delay_ms(50);
   }

OnderGrmz

Öncelikle z ve skara1214 hocam sizlere teşekkürlerimi sunarım.
Dün gece fark edemediğim bir nokta varmış. Ben kodlarımı farklı bir pic için yazmıştım. Uyarlarken alt fonksiyonlara bakmayı unutmuşum. Alt fonksiyonlardan bir tanesine alınan veriye göre işlem yapılıyordu. İşlem yapılan pin ise SCK pini  :D
Bu nedenle
okunan=spi_read();
fonksiyonu ile okunan bilgi doğru olduğunda SCK pini lojik 0'a çekiliyormuş. Bunu şimdi fark ettim.
Dün gece de belirttiğim gibi
setup_spi(spi_slave| spi_L_to_H|SPI_XMIT_L_TO_H);  // SPI iletişim ayarları belirtiliyor

satırı problemi çözdü.
Saygılarımla...