Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

TWI nie działa. ATmega8, obsługa pamięci eeprom 24c512. Program się zapętla.

dscreator 28 Mar 2006 10:22 2078 8
  • #1
    dscreator
    Level 10  
    Napisałem program do obsługi TWI pod atmega8. SDA i SCL mam podciągnięte pod +5V przez rezystory 10kohm. Wydaje się, że jest wszystko dobrze jednak 2 dni nie mogę tego uruchomić. Niżej zamieszczam pełny program do obsługi TWI:
    	
    
    rcall i2c_init
    rcall i2c_start
    ldi r16,eeprom_adres_zapis	;adres eeprom
    rcall i2c_wyslij
    ldi r16,0				;starszy adres pamięci
    rcall i2c_wyslij
    ldi r16,0				;młodszy adres pamięci
    rcall i2c_wyslij
    rcall i2c_start
    ldi r16,eeprom_adres_odczyt	;adres eeprom
    rcall i2c_wyslij
    rcall i2c_czytaj		;czytaj pamięć
    rcall i2c_stop
    
    .equ	eeprom_adres_odczyt = 0b10100001
    .equ	eeprom_adres_zapis =  0b10100000
    
    i2c_init:
    
    	;Częstotliwość magistrali F=f_sys/(16+2*TWBR*4^TWPS)
    	;100kHz - 400kHz
    
    	ldi 	r16,(1<<TWPS0)					
    	sts 	TWSR,r16	
    	ldi 	r16,18				
    	sts 	TWBR,r16
    
    				
    	ret
    
    i2c_start:
    	ldi 	r16,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)		;sygnał start
    	sts 	TWCR,r16
    	rcall 	i2c_gotowy					
     	ret
    
    i2c_stop:
    	ldi 	R16,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
    	sts 	TWCR,R16					; sygnał stop
    	ret
    
    i2c_wyslij:
    	sts 	TWDR,r16					;ładuj twdr zawartością rejestru r16
    	ldi 	r16,(1<<TWINT)|(1<<TWEN)			;Ack
    	sts 	TWCR,r16
    	rcall 	i2c_gotowy					;czekaj
    	ret
    
    i2c_czytaj:
    	ldi	r16,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)		;Ack
    	sts 	TWCR,r16
    	rcall 	i2c_gotowy					;czekaj
    	lds	r25,TWDR					;czytaj dane
    	ret
    
    i2c_gotowy:				;czekaj na zwolnienie magistrali
    	lds 	r16,TWCR
    	sbrs 	r16,TWINT
    	rjmp 	i2c_gotowy
    	ret
    
    
    


    Jest to program obsługi pamięci szeregowej eeprom 24c512. Program zapętla się w pierwszym oczekiwaniu na gotowość magistrali. Jeżeli ustawiam wewnętrzny rezonator 1MHZ to program przechodzi przez podprogram i2c_gotowy, ale za każdym razem odczytana wartość to 161. Sprawdzałem i nie jest generowany sygnał start. Natomiast jak ustawiam 4MHZ lub więcej program wisi w i2c_gotowy.
    Czy program jest właściwy a jeżeli tak to może coś nie tak jest ze sprzętem? Czy w przypadku sprzętowego TWI należy ustawiać linie SDA i SCL na wejściowe lub wyjściowe czy tym zajmuje się mikrokontroler automatycznie?
  • Helpful post
    #2
    hunterhouse
    Level 26  
    ldi    r16,(1<<TWPS0)                
    sts    TWSR,r16    
    ldi    r16,18             
    sts    TWBR,r16        
    ret 

    z tego wychodzi preskaler 160 czyli przy 1Mhz sygnał clk ma czestotliwość 6250Hz. niby nic nie szkodzi że tak wolno ale sprubuj dać wiecej.


    dodał bym jeszcze
    ldi    r16,(1<<TWEN)
    sts    TWCR,r16 

    w procedurze inicjalizacji i jakieś jakieś małe opuźnienie.

    jak bede w domu to jeszcze poruwnam to co napisałeś do tego co ja ostatnio napisałem. co prawda w bacomie ale operuje bezpośrednio na rejestrach.
  • #3
    dscreator
    Level 10  
    Dodałem opóźnienie i włączyłem TWI (chociaż niepotrzebnie bo instrukcja start włącza go) po ustawieniu prędkości i nie pomogło. Musi być coś innego. Próbowałem też zamiast podprogramu i2c_gotowy dać jakieś opóźnienie 10ms i za każdym razem na wyświetlacz wyrzuca mi 161. Czyli odczyt jest nieprawidlowy bo w pamieci mam zapisane wartosci od 0 do 20. Pamięć ładnie programuje się w programatorze natomiast tu wygląda na brak działania TWI.
    Dziwna sprawa przeczytałem też opinie, że program działający pod atmega128 nie chcę działać pod atmega8. Ja używam właśnie atmega8, może trzeba w tym procku jeszcze coś ustawić?
  • Helpful post
    #4
    hunterhouse
    Level 26  
    a wiec tak.
    jeśli dalej nie działa to mam jeszcze 2 pomysły.
    1. zmniejszyć rezystory podciagające do 4,7Kohma
    2.gdzieś czytałem że zapis w rejestrze TWDR jest możliwy tylko gdy bit TWINT w rejesrze TWCR jest zerem. gdy chcemy cos wpisać do TWDR to najpierw musimy go ręcznie wyzerować (bit TWINT). niech kolega spróbuje to uwzględnić. ja w moim programie tak robie i program działa.

    
    'start
    Twcr = &B10100100
    Bitwait Twcr.twint , Set
    
    'write adr+w
    Twcr = &B00000100
    Twdr = Adr Or I2cwrite
    Twcr = &B10000100
    Bitwait Twcr.twint , Set
    If Twsr <> &H18 Then Goto Exit1
    
    'write cmd
    Twcr = &B00000100
    Twdr = Cmd
    Twcr = &B10000100
    Bitwait Twcr.twint , Set
    
    're start
    Twcr = &B10100100
    Bitwait Twcr.twint , Set
    
    'write adr+r
    Twcr = &B00000100
    Twdr = Adr Or I2cread
    Twcr = &B11000100
    Bitwait Twcr.twint , Set
    If Twsr <> &H40 Then Goto Exit1
    
    'read cmd
    Twcr = &B10000100
    Bitwait Twcr.twint , Set
    Twcr = &B00000100
    Cmd = Twdr
    
    Exit1:
    'stop
    Twcr = &B10010100


    to jest prosty programik który komunikuje sie z innym AVR'em po i2c.
    adresuje go do zapisu i wysyła 1 bajt potem robi drugi start i adresuje go do odczytu i odczytuje 1 bajt. potem konczy transmisje.
  • #5
    dscreator
    Level 10  
    Problem polegał na braku zerowania TWINT przed użyciem rejestru TWDR. Zazwyczaj zerowanie odbywało się w przypadku TWCR przez wpisanie jedynki, jednak w tym przypadku chodziło o dosłowne zerowanie i to mnie zmyliło :). Mylące są te noty katalogowe czasami nie wiadomo już czy jedynka to zero, czy zupełnie normalnie :D.
  • #6
    MAREK74
    Level 20  
    sts TWCR,r16

    STS to zapis do SRAMU a nie do rejestru

    ma być
    OUT TWCR,R16

    czy nie ??
  • #8
    MAREK74
    Level 20  
    ale zapewne w "incu" zdefiniowane są od $00 do $3F i wtenczas lipa
  • #9
    Halftheman
    Level 16  
    Mam nadzieje, ze nikt sie nie obrazi ze odgrzewam starocie.

    Mam nadzieje, ze ktoś mnie poprawi jak źle rozumiem co tu jest:
    -kod wklejony tutaj jest dla trybu master i zadaniem jego jest wysylanie danych
    -dane pobierane sa z EEPROMu.
    -żeby sie nie zapętlał w i2c_gotowy wystarczy zmienić lds r16, TWCR na in r16,TWCR.

    Zgadza się?

    Da sie to teraz łatwo zamienić, żeby być w trybie slave?
    Jak zapisywać odczytane dane do rejestrów?

    Z gory dziekuje, za rozwianie watpliwości :)