logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[ATmega32][C]SPI, slave, odbiór kilku bajtów

Arkadyosh 03 Lut 2011 01:25 2682 4
REKLAMA
  • #1 9095568
    Arkadyosh
    Poziom 2  
    Witam,
    Chce skomunikować ze sobą dwie Atmegi32 po sprzętowym SPI, ale jakoś nie chcą ze sobą gadać tak jak ja bym chciał... Z przesłaniem i odbiorem jednego bajtu nie mam problemu, ale chce przesyłać do slave'a 2 bajty albo i więcej (tylko jak je tam odebrać?). Wydaję mi się że jest problem z odbiorem tych 2 bajtów u slave'a. Poniżej kod dla mastera:
    Konfiguracja mastera:
    
    void inicSPImaster(void)
    {
    
    	DDRB |= 1<<MOSI | 1<<SCK | 1<<SS;
    	
    	HIG_SS;
    
    	SPCR |= 1<<SPE | 1<<MSTR | 1<<SPR0; // włączone SPI, master, fsys/16, fsys = 1000000
    	
    }
    


    Przesłanie dwóch bajtów przez mastera:

    
    void dwaBajtySPI(uint8_t dane1, uint8_t dane2)
    {
    
    	LOW_SS;
    	SPDR = dane1;	
    	while(!(SPSR & (1<<SPIF)));
    
    	SPDR = dane2;	
    	while(!(SPSR & (1<<SPIF)));
    	
            HIG_SS;
    	
    }
    
    


    Kod dla slave'a
    Konfiguracja slave'a:

    
    void inicSPIslave(void)      //tryb podrzedny
    {
    	DDRB = 1<<MISO;
    
    	SPCR = 1<<SPE; 	 // wł. SPI
    
    }
    


    Odbieranie 2 bajtów przez slave'a:

    
    uint8_t bajtSPIslave(void)	// odebranie bajtu
    {
    		
    	while(!(SPSR & (1<<SPIF)));
    	
    	
    return SPDR;
    }
    
    
    uint16_t odbierz(void)           // odebranie 2 bajtow
    {
    	uint16_t odb1, odb2;
    	
    	odb1 = bajtSPIslave();
    	odb2 = bajtSPIslave();
    
    	odb1 = (odb1<<8) | (odb2);
    
    return odb1;
    }
    


    Dwa bajty odbierane są losowo i tylko przypadkiem zdarza się że otrzymywana jest odpowiednia wartość. W funkcji odbierz() zwracałem sobie również dla sprawdzenia zmienna odb2 i wyrzucałem na wyświetlacz, i wychodziło na to że jest ona losowym złożeniem bitów dwóch bajtów, tak jak gdyby brakowało synchronizacji. Czy można zrealizować przesył kilku bajtów przy użyciu zwykłych funkcji czy może trzeba użyć przerwań? Proszę o jakieś wskazówki, może ktoś miał podobny problem i udało mu się go rozwiązać. Z góry dziękuje za pomoc.
  • REKLAMA
  • #2 9096130
    rrytel
    Poziom 14  
    spróbuj odbieranie zrobić w przerwaniu (m32 ma wektor przerwania odpowiadający zakończeniu transferu przez SPI). W inicjacji slave'a:
    SPCR = (1<<SPE)||(1<<SPIE);     // wł. SPI; SPI Interrupt Enable 
  • REKLAMA
  • #3 9096180
    Arkadyosh
    Poziom 2  
    Też już tak robiłem, a w przerwaniu było tak:

    
    ISR(SPI_STC_vect)
    {
    	a+=1;
    	odb1 |= SPDR;
    	odb1<<=8;
    	if(a==2)
    	{
    		odb2 = odb1;
    		a=0;
    	}
    
    }
    


    Prędkość transmisji ustawiona w masterze 1MHz/64. Wysyłając dwa bajty, pierwszy wartość 50, drugi 60 otrzymywałem w slave'a wartość 18176. Gubi część bitów.

    Dodano po 2 [godziny] 30 [minuty]:

    No dobra, to może inaczej, może być też tak że master będzie odczytywał dwa lub więcej bajtów po SPI od slave'a. Czy to będzie z użyciem przerwań czy też nie, to już obojętne, proszę o sugestie.
  • REKLAMA
  • #4 9098267
    adamusx
    Poziom 27  
    Wklej kod dla Slave i Mastera łącznie z konfiguracją SPI.
  • #5 9098376
    Arkadyosh
    Poziom 2  
    Master:
    
    #define	MOSI	PB5		
    #define	SCK		PB7		
    #define    SS	        PB4		
    #define    MISO	PB6		
    
    
    #define HIG_SS	PORTB |= (1<<SS)
    #define LOW_SS	PORTB &= ~(1<<SS)
    
    void inicSPImaster(void) //tryb nadrzedny
    {
    
    	DDRB |= 1<<MOSI | 1<<SCK | 1<<SS;
    	
    	HIG_SS;
    
    	SPCR |= 1<<SPE | 1<<MSTR | 1<<SPR0 | 1<<SPR1; //  wł.,tryb nad, fsys/128, fsys=1MHz
    	
    }
    
    void bajtSPImaster(int dane)	// przysyl bajtu w trybie master
    {
    
    	SPDR = dane;	
    
    	while(!(SPSR & (1<<SPIF)))
    	
    			;
    	
    	SPSR |= 1<<SPIF;
    
    
    }
    
    void dwaBajty(int dane1, int dane2)
    {
    	LOW_SS;
    
    	bajtSPImaster(dane1);
    	bajtSPImaster(dane2);
    
    	HIG_SS;
    
    }
    
    


    Slave:
    
    void inicSPIslave(void)  
    {
    	DDRB |= 1<<MISO;
    
    	SPCR |= 1<<SPE | 1<<SPIE;
    
    }
    
    


    Próbowałem odbierać dwa bajty w slave'a poprzez przerwanie:
    
    ISR(SPI_STC_vect)
    {
    
    	odb1 |= SPDR;
    
    	odb1<<=8;
    	a+=1;
    	if(a==2)
    	{
    		odb2 = odb1;
    		a = 0;
    		odb1 = 0;
    	}
    
    }
    


    I w funkcji(wtedy bez włączonych przerwań dla slave'a):
    
    
    int bajtSPIslave(void)	
    {
    	
    	while(!(SPSR & (1<<SPIF)))
    	
    		;
    	
    return SPDR;
    }
    
    int odbierz(void)
    {
    	int odb1, odb2;
    	
    	odb1 = bajtSPIslave();
    	odb2 = bajtSPIslave();
    
    	odb1 = (odb1<<8) | (odb2);
    
    return odb1;
    }
    


    Dodano po 5 [minuty]:

    W main mastera:
    
    int main(void)
    {
    	inicSPImaster(); //tryb nadrzedny
    
    
    	while(1)
    	{
    		_delay_ms(250);
    		_delay_ms(250);
    		_delay_ms(250);
    		_delay_ms(250);
    
    		dwaBajty(50, 60);
    		
    	}
    
    
    return 0;
    }
    


    Main dla slave'a:
    
    int main(void)
    {
        while(1)
        {
        odebrane = odbierz();  // <--- bez przerwan
         y_x(2,2); zmienna(odebrane); znak(' '); // wyswietlenia wyniku
        }
    
    
    return 0;
    }
    
    
REKLAMA