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

Jak rozwiązać problem z nieskończoną pętlą I2C na ATMega?

valarian 10 Wrz 2007 16:54 2616 8
REKLAMA
  • #1 4269625
    valarian
    Poziom 22  
    Posty: 647
    Pomógł: 33
    Ocena: 112
    Witam,

    Próbuję dogadać ze sobą dwie ATMegi za pomocą I2C [TWI]. Przeczytałem o tym sporo w dokumentacji, przejrzałem sporo postów na elektrodzie i dalej nie wiem, czemu to nie chce mi działać. Wg symulacji w VMLab program wchodzi w nieskończoną pętlę w zaznaczonym miejscu drugiej funkji (pierwsza przechodzi bez zarzutu).
    Czy ktoś może mi pomoc, byłbym bardzo wdzięczny.

    To działa OK:

    void i2c_init(void)
    {
      TWSR = 0;                         //brak preskalera
      TWBR = ((F_CPU/SCL_CLOCK)-16)/2;
    }


    To już nie:

    unsigned char i2c_start(unsigned char address)
    {
        uint8_t   twst;
    	//START
    	TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
    	// czekaj na zakonczenie transmisji
    	while(!(TWCR & (1<<TWINT)));  <----TUTAJ WCHODZI W PĘTLĘ
    
    	twst = TW_STATUS & 0xF8;
    	//wystapil blad, zwroc 1
    	if ( (twst != TW_START) && (twst != TW_REP_START)) {return 1;}
    	// wyslij adres urzadzenia
    	TWDR = address;
    	TWCR = (1<<TWINT) | (1<<TWEN);
    
    	while(!(TWCR & (1<<TWINT)));
    
    	twst = TW_STATUS & 0xF8;
    
    	if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ){return 1;}
    
    	return 0;
    }
  • REKLAMA
  • #2 4269635
    rmajda
    Poziom 20  
    Posty: 485
    Pomógł: 13
    Ocena: 17
    Czy ustawiłeś jedną atmege jako master a drugą jako slave?
  • #3 4269710
    valarian
    Poziom 22  
    Posty: 647
    Pomógł: 33
    Ocena: 112
    Tak, powyższy kod dotyczy mastera, slave natomiast jest ustawiany kodem:
    
    sei();
    TWAR=address;
    TWCR = (1<<TWEN) | (1<<TWEA) | (1<<TWIE);
    


    Odbiór natomiast przeprowadzam w przerwaniu:

    
    char rec='0';
    
    SIGNAL(SIG_2WIRE_SERIAL)
    {
     rec=TWDR;
     TWCR = (1<<TWINT);
    }
    
  • REKLAMA
  • #4 4271838
    Ch.M.
    Poziom 27  
    Posty: 1009
    Pomógł: 62
    Ocena: 15
    Przyjacielu wydaje mi się że jednak nie czytałeś zbyt wiele o TWI Atmeli, a przynajmniej nie na elektrodzie ani nie w datasheecie...
    Jakbyś przeczytał to byś wiedział ,że trzeba wyzerować bit STARTu przed oczekiwaniem na ACK
    przykład ASM
    
    i2c_START:
    ldi R16, 0b10100100		//(1<<TWINT)|(1<<TWSTA)|(1<<TWEN) 
    sts TWCR,R16            ; envoi condition de start sur le bus
    
    ldi R16,0b10000100		// zeruje komendę start
    sts TWCR,R16
    
    rcall i2c_WAIT
    ret
    
    i2c_WAIT:                  ; Attente extinction de twint (twint a 1 voir doc)
    lds R16,TWCR              ; et si ack ou nack 
    sbrs R16,TWINT           ;
    rjmp i2c_WAIT
    ret
    


    Inna sprawa to użyte komendy do nastawy bitów... operuj zmieniając cały bajt a nie tylko stany poszczególnych bitów, dlaczego?
    pozdrawiam
  • #5 4271884
    valarian
    Poziom 22  
    Posty: 647
    Pomógł: 33
    Ocena: 112
    Nadal przeglądam dokumentację i nigdzie nie widzę informacji o zerowaniu bitu startu przed oczekiwaniem.

    I dlaczego należy operować całym bajtem, a niezalecane są operacje na bitach?
  • REKLAMA
  • #6 4271912
    Ch.M.
    Poziom 27  
    Posty: 1009
    Pomógł: 62
    Ocena: 15
    AD1:
    M128 patrz koniec strony 207
    M32 patrz koniec strony 175
    M88 patrz strona 237
    M8 patrz strona 172
    • Bit 5 – TWSTA: TWI START Condition Bit
    The application writes the TWSTA bit to one when it desires to become a master on the
    Two-wire Serial Bus. The TWI hardware checks if the bus is available, and generates a
    START condition on the bus if it is free. However, if the bus is not free, the TWI waits
    until a STOP condition is detected, and then generates a new START condition to claim the bus Master status. TWSTA must be cleared by software when the START condition
    has been transmitted.

    Ad2:
    Ponieważ operując na wybranych bitach, nie wiesz co się dzieje z innymi (np nie zerujesz TWINT)
  • #7 4272134
    valarian
    Poziom 22  
    Posty: 647
    Pomógł: 33
    Ocena: 112
    Doszedłem do czegoś takiego (uproszczone do minimum):

    Program wysyłający:

    
    int main(void)
    {
     sei();
     TWSR = 0;
     TWBR = ((F_CPU/SCL_CLOCK)-16)/2;
     while(1)
     {
      TWCR = 0b10100100; //(1<<TWSTA) | (1<<TWEN) | (1<<TWINT);
      TWCR = 0b10000100;
      while( !(TWCR & (1<<TWINT)) );
      TWDR=address & 0xFE;
      TWCR = (1<<TWINT) | (1<<TWEN);
      while( !(TWCR & (1<<TWINT)) );
      TWDR='X';
      TWCR = (1<<TWINT) | (1<<TWEN);
      while( !(TWCR & (1<<TWINT)) );
      TWCR = (1<<TWSTO) | (1<<TWEN) | (1<<TWINT);
     }
    }
    


    A po stronie programu odbierającego:

    
    char rec='0';
    
    SIGNAL(SIG_2WIRE_SERIAL)
    {
      status=TWSR & 0xF8;
    
      switch(status)
      {
    	case TW_SR_SLA_ACK:	  	 	
    	case TW_SR_ARB_LOST_SLA_ACK:		
    	case TW_SR_GCALL_ACK:				
    	case TW_SR_ARB_LOST_GCALL_ACK:				
     	
    		TWCR = (1<<TWINT) | (1<<TWEA)| (1<<TWIE) | (1<<TWEN);   	
    		break;
    	case TW_SR_DATA_ACK:		  		
    	case TW_SR_GCALL_DATA_ACK:			
          	rec = TWDR;	 
    	USART_Transmit(rec); 
    	TWCR = (1<<TWINT) | (1<<TWEA)| (1<<TWIE) | (1<<TWEN);
    		break;
    	case TW_SR_DATA_NACK:	   		
    	case TW_SR_GCALL_DATA_NACK:			
    	TWCR = (1<<TWINT) | (1<<TWIE) | (1<<TWEN);
    		break;
    	case TW_SR_STOP:		
    	TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWIE) | (1<<TWEN);
    		break;
      }
    }
    
    int main(void)
    {
     sei();
     TWAR=4;
     TWCR=(1<<TWEA) | (1<<TWEN) | (1<<TWIE);
     while(1)
     {
     }
    }
    


    Jak widać, program powinien wysyłać przez USART otrzymane znaki ('X' w tym wypadku), a nie wysyła nic. RS232 sprawne, każdy moduł sprawdzony osobno w symulatorze VMLab DZIAŁA, tzn. znak wysyłany przez pierwszy program jest odbierany przez wewętrzny monitor i2c VMLab'a, a wysyłanie znaku do drugiego programu powoduje jego wypisanie na terminalu. Wszystko chodzi w obrębie PC'ta.
    Sprzętowo już nie...
  • REKLAMA
  • #8 4272156
    rmajda
    Poziom 20  
    Posty: 485
    Pomógł: 13
    Ocena: 17
    Zobacz sobie załącznik.
    Załączniki:
    • I2C_routines_in_GCC.zip (6.46 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • #9 4272368
    valarian
    Poziom 22  
    Posty: 647
    Pomógł: 33
    Ocena: 112
    Funkcje tam użyte w sumie niczym tam nie różnią się od moich, tym bardziej nie wiem, co jest nie tak. Podejrzewam coś ze sprzętem, skoro symulacje są OK. Ale co może być nie tak w dwóch uC połączonych kablem (+ dwa rezystory 10k)?

    VMLab posiada też opcję odpalenia dwóch kopii programu, każdej z inną aplikacją i interakcji między nimi (przez ustawienie, które piny są połączone). Sprawdzałem tą opcję i komunikacja działa (tylko gubi znaki).

    Dodano po 4 [godziny] 59 [minuty]:

    Męczę się z tym cały dzień, wszystko jest sprawdzone 10 razy i działa w VMLabie... A sprzętowo dalej nie.

    Postanowiłem wymienić rezystory podciągające z 10kOhm na 4.7kOhm i dostałem ciekawy efekt:
    Po włączeniu zasilania całego układu nic się nie dzieje, terminal jest czysty, żadne znaki nie są wysyłane. Po wyłączeniu zasilania do terminalu orzesyłanych jest prawidłowo ok. 20 znaków! :-)
    W chwili przełączenia włącznika i odłączeniu napięcia w układzie dzieje się "coś" i przez ułamek sekundy wszystko działa :-)
    Nie było tak przed wymianą rezystorów na mniejsze.

    Co to może być?

    Dodano po 4 [godziny] 31 [minuty]:

    Uff, w końcu sobie poradziłem. Wina nie tkwiła jednak w niezerowaniu bitu startu.
    Po zmianie rezystorów na jeszcze mniejsze (1.5kOhm) wszystko śmiga bez problemów :-)

    Dziękuję wszystkim za pomoc, temat do zamknięcia.

Podsumowanie tematu

LABEL_AI_GENERATED
Dyskusja dotyczy problemu nieskończonej pętli podczas inicjalizacji magistrali I2C (TWI) na mikrokontrolerach ATMega. Użytkownik próbuje połączyć dwie ATMegi, jedną jako master, drugą jako slave, jednak program wchodzi w nieskończoną pętlę oczekiwania na ustawienie bitu TWINT po wysłaniu sygnału START. Wskazano, że konieczne jest wyzerowanie bitu TWSTA (START) w rejestrze TWCR po wygenerowaniu warunku START, co jest wymagane przez dokumentację Atmela. Zalecane jest operowanie na całym bajcie rejestru TWCR zamiast manipulacji pojedynczymi bitami, aby uniknąć niezamierzonych efektów, np. niezerowania bitu TWINT. Przykłady kodu w asemblerze i C pokazują prawidłową sekwencję ustawiania i zerowania bitów TWCR. Autor potwierdza, że w symulacji VMLab komunikacja działa, natomiast na sprzęcie pojawiają się problemy, które mogą wynikać z niewłaściwych rezystorów podciągających (10kΩ vs 4.7kΩ). Zauważono nietypowe zachowanie przy zmianie rezystorów, gdzie po wyłączeniu zasilania pojawia się transmisja danych, co sugeruje problemy sprzętowe lub z połączeniami. Wskazano również, że w trybie slave odbiór danych powinien być realizowany w przerwaniu, a rejestr TWCR odpowiednio ustawiany do potwierdzania odbioru. Dokumentacja Atmela dla różnych modeli ATMega (M128, M32, M88, M8) potwierdza konieczność zerowania bitu TWSTA po wygenerowaniu warunku START.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA