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

Jak odczytać dane z EEPROM 64k za pomocą TWI na Atmega8?

y0yster 16 Sie 2007 22:31 2153 10
  • #1 4185384
    y0yster
    Poziom 19  
    Posty: 471
    Pomógł: 9
    Ocena: 76
    Witam.

    Chciałem się pobawić eepromem i zaserwowałem sobie taką zabawę, że hej. Mam problem z odczytem. Najlepiej wkleję troszkę kodu.

    
    clr r16
    ldi r16, (1 << TWPS0)
    out TWSR, r16
    ldi r16, 12
    out TWBR, R16
    
    sbi PORTC, PC5
    sbi PORTC, PC4
    
    rcall twi_start
    rcall twi_set_write
    
    ldi TWI_REGISTER, 0x50
    rcall twi_send_device_address
    
    ldi r17, 0x00
    ldi TWI_REGISTER, 0x00
    rcall twi_send_address
    
    ;restart
    rcall twi_start
    rcall twi_set_read
    
    ldi TWI_REGISTER, 0x50
    rcall twi_send_device_address
    
    rcall twi_disable_acknowledgment
    rcall twi_read_data
    mov EEPROM_DATA, TWI_REGISTER
    rcall twi_stop
    


    Teraz procedury, które są używane w kodzie:

    
    ;wylaczanie flagi potwierdzen
    twi_disable_acknowledgment:
    	in TWI_REGISTER, TWCR
    	cbr TWI_REGISTER, 1 << TWEA
    	out TWCR, TWI_REGISTER
    	ret
    
    ;wysylanie STARTU
    twi_start:
    	ldi TWI_REGISTER, (1 << TWINT) | (1 << TWSTA) | (1 << TWEN) | (1 << TWEA)
    	out TWCR, TWI_REGISTER
    
    	rcall twi_busy
    
    	;wylaczamy start
    	in TWI_REGISTER, TWCR
    	cbr TWI_REGISTER, (1 << TWSTA)
    	out TWCR, TWI_REGISTER
    	
    	;koniec, powracamy
    	ret
    
    ;ustawiamy sie na odczyt
    twi_set_read:
    	ldi r16, 0x01
    	;zapisujemy to tymczasowo w rejestrze danych do wyslania przez twi
    	out TWDR, TWI_REGISTER
    	ret
    
    ;ustawiamy sie na zapis
    twi_set_write:
    	;dla zapisu wartosc to 0
    	clr TWI_REGISTER
    	out TWDR, TWI_REGISTER
    	ret
    
    ;wysylamy adres uzadzenia
    twi_send_device_address:
    	;adres uzadzenia
    	;przesowamy w lewo poniewaz musimy ustalic, czy jest to operacja odczytu, czy zapisu
    	lsl TWI_REGISTER
    	out TWAR, TWI_REGISTER
    	;pobieramy dazne z rejestru, jest tam jeden bit, odpowiedzialny za zapis/odczyt
    	;czy bedziemy odczytywac z, czy zapisywac do uzadzenia
    
    	push r17
    
    	in r17, TWDR
    	;suma logiczna, pozwala nam to na otrzymanie operacji zapisu, badz odczytu
    	or TWI_REGISTER, r17
    	;wysylanie adresu
    
    	pop r17
    
    	rcall twi_send_data
    	ret
    
    ;wysylamy dane
    twi_send_data:
    	;zapis do rejestru danych
    	out TWDR, TWI_REGISTER
    	in TWI_REGISTER, TWCR
    	sbr TWI_REGISTER, 1 << TWINT
    	;wysylamy dane na zlacze
    	out TWCR, TWI_REGISTER
    
    	rcall twi_busy
    
    	;konczymy wysylanie danych
    	ret
    
    ;ustawianie adresu z, ktorego bedziemy czytac, lub, do ktorego bedziemy zapisywac
    twi_send_address:
    	;wysylanie msb adresu
    	;tutaj przypisanie adresu do rejestru !!!
    	rcall twi_send_data
    	mov TWI_REGISTER, r17
    	rcall twi_send_data
    	ret
    
    ;operacja odcytywania bajtu
    twi_read_data:
    	;dajemy sygnal do odczytu
    	in TWI_REGISTER, TWCR
    	sbr TWI_REGISTER, 1 << TWINT
    	out TWCR, TWI_REGISTER
    	
    	rcall twi_busy
    		
    	;odczytujemy dane
    	in TWI_REGISTER, TWDR
    			
    	ret
    
    twi_stop:
    	;odczytanie bierzadzej zawartosci rejestru kontrolnego twi
    	in TWI_REGISTER, TWCR
    	;ustawienie bitu stopu i przerwania
    	sbr TWI_REGISTER, (1 << TWSTO) | (1 << TWINT)
    	;wysylamy nasze ustawienia
    	out TWCR, TWI_REGISTER
    	
    	;czekamy na zakonczenie operacji
    	rcall twi_busy
    
    	;wylacamy interfejs twi
    	cbr TWI_REGISTER, 1 << TWEN
    	out TWCR, TWI_REGISTER
    	
    	;wyslano stop, powracamy do programy		
    	ret
    
    
    ;sprawdznaie czy interfejs TWI jest zajety
    twi_busy:
    	;wczytanie rejestru kontrolnego
    	in TWI_REGISTER, TWCR
    	;porownanie bitu przerwania TWINT, jesli czysty
    	sbrs TWI_REGISTER, TWINT
    	;to omijamy skok do ponownego sprawdzenia
    	rjmp twi_busy
    
    	;powrot
    	ret
    


    Sprawdzałem, czy coś się dzieje. Wychodzi na to, że już po starcie układ się wiesza. Prawdopodobnie na sprawdzaniu TWINT. Patryłem na to dłuższy czas i doszedłem do wniosku, że w manualu do Atmegi8 dziwnie piszą. Czytałem do czego jest TWINT i tam jest napisane, że bit jest ustawiany. Jak mam to rozumieć, tak jak oni później w przykładzie, że jest tam 1, czy jak oni napiszą dalej, żę The TWINT Flag must be cleared by software by writing a logic one to it., czyli musi być wyczyszczona przez zapisanie tam 1. Jak oni chole*** piszą te posrane datasheety. A w przykładzie jest na odwrót. Nie czaję tego. Normalnie już sobie włosy wyrywam.

    Ale powracając do tematu. Już jak napisałem po wysłaniu komendy start. Wiesza mi się uC prawdopodobmnie na instrukcji twi_busy, czyli sprawdzaniu znacznika TWINT.

    Pozdrawiam i proszę o pomoc.

    Jeszce jedna ważna uwaga. Nie piszcie mi, że to było poruszane na forum. Może i było ale w c i w bascomie. A do asemblera się nie dokopałem. Swoją drogą bascom to język strasznie głupkowaty. C już mniej. Bo nie ma tej "genialnej" obsługi wszystkiego co bascom, że można by zmusić uC do zrobienia kanapki. Takie małe rączki wyjdą i ciach, kanapka .... To tak na poboczu :).
  • #2 4186044
    BoskiDialer
    Poziom 34  
    Posty: 1530
    Pomógł: 353
    Ocena: 42
    Co do kasowania przez wpisywanie jedynki - to jest jak najbardziej poprawne:
    https://www.elektroda.pl/rtvforum/topic800253.html#4104934#4104934

    Nie analizowałem kodu zbyt dokładnie, ale jakkolwiek brakuje właśnie kasowania flagi przerwania TWINT. Dodatkowo (z tego co wyczytałem) trzeba flagę kasować po wprowadzeniu dodatkowych danych do transmisji. Może lepiej przeanalizuj jakieś gotowce z sieci, co by zobaczyć jak powinna wyglądać obsługa TWI.
  • #3 4186329
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    BoskiDialer napisał:
    ...Nie analizowałem kodu zbyt dokładnie ...

    A ja TO zrobiłem i muszę stwierdzić , że kol. y0yster :
    1) wogóle nie czytał dokumentacji
    2) czytał , ale nie zrozumiał
    Widzę 2 wyjścia:
    a) powrócić do PDF-ka
    b) przesiąść się na "głupkowatego" Bascoma :twisted:

    Piotrek
  • #4 4186403
    y0yster
    Poziom 19  
    Posty: 471
    Pomógł: 9
    Ocena: 76
    Kolega y0yster czytał. Ale nie zrozumiał. Raz tam piszą wyczyść, a raz wyczyść przez wstawienie 1.

    Problem został rozwiązany.

    A to dlatego tak długo trwało jego rozwikłanie ponieważ ci z atmela dziwnie piszą.

    Popatrzmy:

    Cytat:

    This bit is set by hardware when the TWI has finished its current job and expects application
    software response. If the I-bit in SREG and TWIE in TWCR are set, the MCU will
    jump to the TWI Interrupt Vector. While the TWINT Flag is set, the SCL low period is
    stretched. The TWINT Flag must be cleared by software by writing a logic one to it. Note
    that this flag is not automatically cleared by hardware when executing the interrupt routine.
    Also note that clearing this flag starts the operation of the TWI, so all accesses to
    the TWI Address Register (TWAR), TWI Status Register (TWSR), and TWI Data Register
    (TWDR) must be complete before clearing this flag.


    Piszą, że ta flaga jest wyzerowana przez 1. A na końcu piszą, że też ma być wyzerowana, żeby zapisać do pozostałych rejestrów TWI. No to jak napisali, że wyczyścić to zostawiamy tam tą 1, ak chcieli. A tu się okazuje, że jednak nie..., chcieli tam zero. Kto ich zrozumie :D. Mniemam, że tego datasheeta pisała kobieta. A wiadomo, że kobieta zmienną jest....


    A tutaj mała riposta dla zumka.
    Precz z bascomem. Nie mówię tak bezpodstawnie. Na codzień używam c++ do programowania na PC. Można porównać używanie bascoma do programowania w visula basica, czy delphi. Jeśli chce się osiągnąć coś małym kosztem to polecam. Np. Kto to widział. Jak analizowałem źródła do wyświetlania na lcd, to patrze jedna linijka i mamy inicjalizację, cudownie :(, a zasada działania pozostaje tylko w PDF'kach :), czyż nie. Jeszcze widzę jeden nonsens w używaniu bascoma. Widziałem też kiedyś przykład inicjalizacji lcd w bascomie za pomocą wstawek w asmie. Bardzo brzydko to wygląda, nie uważasz? Lepiej już w asmie pisać od początku.
    Troszkę mam żal do c++, ale nie wiem, czy jest on uzasadniony. Z tego co patrzyłem na c++ to posiada on także jakieś super wbudowane funkcje do obsługi eeproma zewnętrnego, czy to prawda?
    Każdy język jest dobry. Widziałem także używanie bascoma do raczej pół programowej, to już coś obsługi twi. Pomogło mi to rozwiązać mój obecny problem. Oto link do postu:

    https://www.elektroda.pl/rtvforum/topic481959.html

    Jeszcze jedno odnośnie 1 i 0 w manualach. Kiedy rozpoznać o co im chodzi? Bo tego co znam angielski, to wynikało racej już jasno, że czyszczenie to ustawianie 1 w bicie.

    --edit

    I dziwi mnie jedna rzecz. Według mnie powinno działąć z 1 ponieważ mają tak w przykładzie w pdf na stronie 177, przykłady kodu. W #3 ustawiają 1 w bicie TWINT, a aż do #5 gdzie następuje zapis do TWDR to nie powinno im więc działać, bo nie zmieniają TWINT na 0, cyli nie ustawiają go. A skoro takie coś jest tam już napisane, to powinno działać, czy się mylę?


    Pozdro.
  • #5 4187665
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    y0yster napisał:
    Kolega y0yster czytał. Ale nie zrozumiał. Raz tam piszą wyczyść, a raz wyczyść przez wstawienie 1.

    Nie kolego.Oni tam piszą , że "wyczyszczenie" flagi TWINT, polega na wpisaniu do niej 1.Jeżeli dalej w tekście piszą "wyczyść" TWIN , to chyba jest logiczne(?) , że mają na myśli "wpisz do niej 1".Taki sposób "czyszczenia" flag zdarzeń , uniemożliwia ich programowe ustawianie , co w efekcie nie pozwala programowo generować zdarzeń sprzętowych :D
    y0yster napisał:

    Problem został rozwiązany.

    Jeśli rozwiązałeś problem przez jego zrozumienie , to gratuluję ;)
    y0yster napisał:

    ...Np. Kto to widział. Jak analizowałem źródła do wyświetlania na lcd, to patrze jedna linijka i mamy inicjalizację, cudownie :(

    Nie cud , tylko Bascom posiada do tego LCD "kontrolkę" ;)
    y0yster napisał:

    ... Widziałem też kiedyś przykład inicjalizacji lcd w bascomie za pomocą wstawek w asmie. Bardzo brzydko to wygląda, nie uważasz?

    Widocznie do tego LCD , "kontrolki" nie posiadał :(
    y0yster napisał:

    Pozdro.

    Ja również pozdrawiam

    Piotrek

    PS
    Radzę zaprzyjaźnić się z rejestrem TWSR ;)
    Pozwoli Ci to , uniknąć wielu rozczarowań przy współpracy z TWI.
  • #6 4187702
    y0yster
    Poziom 19  
    Posty: 471
    Pomógł: 9
    Ocena: 76
    Racja zumek. Nie zrozumiałem tam ostatniego zdania. Za dużo negacji dla mojego mózgu :).

    Chodzi mi o zdanie, w którym piszą aby przed wyczyszczeniem (wpisaniem 1) zrobić co trzeba z rejestrami.

    --edit

    Właśnie się zaprzyjaźniłem z TWSR. Na początku aż mną rzucało bo miałem inne wartości. A to wszystko, że nie zauważyłem, iż wcześniej został ustawiony prescaler. 2 bity znajdują się w TWSR, ale po przeczytaniu datasheeta olśniło mnie.

    Pozdrawiam.
  • #7 4190945
    y0yster
    Poziom 19  
    Posty: 471
    Pomógł: 9
    Ocena: 76
    Mam jeszcze mały mętlik w głowie po tym interfejsie TWI.

    Przytoczę tutaj kawałek mojego kodu:

    
    	ldi TWI_REGISTER, (1 << TWINT) | (1 << TWSTA) | (1 << TWEN) | (1 << TWEA)
    	out TWCR, TWI_REGISTER
    
            twi_busy:
    	;wczytanie rejestru kontrolnego
    	in TWI_REGISTER, TWCR
    	;porownanie bitu przerwania TWINT, jesli 1
    	sbrs TWI_REGISTER, TWINT
    	;to omijamy skok do ponownego sprawdzenia
    	rjmp twi_busy
    
    	ldi TWI_REGISTER, (0 << TWINT) | (0 << TWSTA) | (1 << TWEN) | (1 << TWEA)
    	out TWCR, TWI_REGISTER
    


    No więc w pierwszej linijce kodu wysyłamy do uC proźbę o wysłanie start. Czyścimy także TWINT, wpisując tam 1. Więc TWI zacznie działać. Prawda? Mi działa więc przyjmuję to za pewnik.

    Druga linijka to wysłanie tego do TWCR.

    Następnie pobieramy TWCR do TWI_REGISTER, jest to moja definicja rejestru roboczego.

    Teraz sprawdzamy co tam się znajduje. sbrs przeskoczy następny mnemonik jeśli bit będzie ustawiony, czyli będzie tam jedynka? A w manualu jest napisane, że bit ten jest ustawiany ( zapisywany 0) przez sprzęt po zakończeniu operacji przez TWI. Więc jak on może przeskoczyć skoro uC wisze tam 0?
    To może podczas wykonywania jakiejś operacji TWI daje tam po prostu 0? Albo sbrs działa jakoś inaczej dla tego bitu?

    Jeszcze mam jeden przykład.

    
    ldi r16, SLA_W
    out TWDR, r16
    ldi r16, (1<<TWINT) | (1<<TWEN)
    out TWCR, r16
    
    wait2:
    in r16,TWCR
    sbrs r16,TWINT
    rjmp wait2
    
    in r16,TWSR
    andi r16, 0xF8
    cpi r16, MT_SLA_ACK
    brne ERROR
    
    ldi r16, DATA
    out TWDR, r16
    ldi r16, (1<<TWINT) | (1<<TWEN)
    out TWCR, r16
    


    Najpierw do TWCR, jest zapisywana 1, powoduje to wysłanie komendy TWI.

    Potem sprawdzają, jeśli będzie 1 to przeskoczą dalej.

    Nastepnie jest sprawdzenie TWSR, mało istotne dla nas.

    W końcu widzimy że zapisują coś do TWDR. Dlaczego? Przecież w twcr, TWINT jest wciąż 1, czyli według nich nie można ponieważ flaga ta jest wyczyszczona, zapisana 1. Zgodnie z:

    Cytat:
    Also note that clearing this flag starts the operation of the TWI, so all accesses to
    the TWI Address Register (TWAR), TWI Status Register (TWSR), and TWI Data Register
    (TWDR) must be complete before clearing this flag.


    Co tu jest grane? Może mi ktoś to wytłumaczy. Może gdzieś robię błąd?

    Pozdrawiam.
  • #8 4191091
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    y0yster napisał:
    Mam jeszcze mały mętlik w głowie po tym interfejsie TWI.

    Wcale Ci się nie dziwie , bo kasowanie flag przerwań w AVR-ach , jest faktycznie trochę zakręcone :D
    Sprawa wygląda tak:
    Jeżeli bit TWINT w rejestrze TWCR jest ustawiony(równy 1) , to zapisując do tego bitu 1(jeden) , kasujemy go i przyjmuje on wtedy wartość ... 0 (zero).Gdy interfejs TWI zakończy bieżącą operacji , to ustawi go na 1(jeden).Użytkownik , NIE MA MOŻLIWOŚCI zmienić stanu tego bitu z 0(zero) na 1 (jeden) , a jedynie z 1 na 0 , przez wpisanie 1(jedynki) do tego bitu. Uffff. zrozumiałeś :?:

    y0yster napisał:

    Przytoczę tutaj kawałek mojego kodu:

    
    	ldi TWI_REGISTER, (1 << TWINT) | (1 << TWSTA) | (1 << TWEN) | (1 << TWEA)

    ...

    A po jaką cholerę ustawiasz bit TWEA :?: Ten bit ustawiasz tylko i wyłącznie wtedy , kiedy odczytujesz z urządzania bajt , który nie jest ostatnim bajtem jaki ma zamiar odczytać master ze slave-a , w bieżącej sesji.
    A teraz z cyklu "How it is made"
    
    //start
    ldi TWI_REGISTER, (1 << TWINT) |  (1 << TWEN) | (1 << TWSTA)
    
    //stop
    ldi TWI_REGISTER, (1 << TWINT) |  (1 << TWEN) | (1 << TWSTO)
    
    //zapisz
    TCDR=bajt
    ldi TWI_REGISTER, (1 << TWINT) |  (1 << TWEN)
    
    //odczytaj i potwierdź
    ldi TWI_REGISTER, (1 << TWINT) |  (1 << TWEN) | (1 << TWEA)
    bajt=TWDR
    
    //odczytaj bez potwierdzenia
    ldi TWI_REGISTER, (1 << TWINT) |  (1 << TWEN)
    bajt=TWDR
    


    Piotrek
  • #9 4192138
    y0yster
    Poziom 19  
    Posty: 471
    Pomógł: 9
    Ocena: 76
    zumek napisał:

    Sprawa wygląda tak:
    Jeżeli bit TWINT w rejestrze TWCR jest ustawiony(równy 1) , to zapisując do tego bitu 1(jeden) , kasujemy go i przyjmuje on wtedy wartość ... 0 (zero).Gdy interfejs TWI zakończy bieżącą operacji , to ustawi go na 1(jeden).Użytkownik , NIE MA MOŻLIWOŚCI zmienić stanu tego bitu z 0(zero) na 1 (jeden) , a jedynie z 1 na 0 , przez wpisanie 1(jedynki) do tego bitu. Uffff. zrozumiałeś :?:


    Dobra. Z tym, że ustawiamy do rejestru TWINT 1, to uC tam tak na prawde wpisuje 0. Ok. Czyli rozkaz sbrs ma rację bytu, bo tak naprawdę jest tam 0, które ma się zmienić na 1. Jeszcze jedna rzecz mnie tutaj zastanawia. Po zakończeniu operacji TWI ustawia, wpisuje do TWINT 1, więc potem z pętli oczekującej na zakończenie operacji można normalnie wyskoczyć. W data sheecie jest napisane, że faktycznie on to ustawia (set) wpisuje tam 1, ale pod spodem jest także napisane, że czyści przez wstawienie 1. Czy tutaj to "set" odnosi się więc do wpisania tam prawdziwej 1. A czyszczenie przez wstawianie 1, powoduje wpisanie tam 0 i wyzwolenie przerwania TWI. Czy dobrze teraz rozumiem?

    A jak się sprawa przedstawia kiedy sam TWI wpisze tam 1, czy przerwanie nie powinno się wtedy wyzwolić? Czy to się dzieje tylko wówczas programowego wstawienia 1 kiedy to muz mieniamy z 0 na 1. Więc TWI zmienia stan po operacji z 0 na jeden co nie powoduje wykonania przerwania, tak?


    Pozdrawiam.
  • Pomocny post
    #10 4192962
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    y0yster napisał:
    ...
    A jak się sprawa przedstawia kiedy sam TWI wpisze tam 1, czy przerwanie nie powinno się wtedy wyzwolić?...

    Powinno , ale pod warunkiem że : flaga I w SREG=1 i flaga TWIE w TWCR=1.Przed opuszczeniem procedury przerwania , należy wyzerować(wpisać 1) do flagi TWINT w TWCR , by uniknąć kolejnego przerwania.

    Piotrek
  • #11 4193236
    y0yster
    Poziom 19  
    Posty: 471
    Pomógł: 9
    Ocena: 76
    Dzięki wielkie zumek za pomoc przy TWI. Teraz mam już wszystko obcykane z tym. Przynajmniej mi się tak wydaje :).

    Pozdrawiam.

Podsumowanie tematu

LABEL_AI_GENERATED
Dyskusja dotyczy problemów z odczytem danych z pamięci EEPROM 64k za pomocą interfejsu TWI (I2C) na mikrokontrolerze Atmega8. Głównym zagadnieniem jest prawidłowe zarządzanie flagą przerwania TWINT w rejestrze TWCR, która jest kasowana przez wpisanie logicznej jedynki, co w praktyce zeruje bit. Uczestnicy wyjaśniają, że zgodnie z dokumentacją Atmela, flaga TWINT jest automatycznie ustawiana na 1 po zakończeniu operacji TWI i musi być ręcznie kasowana przez wpisanie 1, aby kontynuować transmisję. Podkreślono konieczność uwzględnienia preskalera w rejestrze TWSR oraz prawidłowego ustawiania bitu TWEA tylko podczas odczytu bajtów, które nie są ostatnimi w sesji. Wskazano, że błędy w obsłudze flagi TWINT i nieprawidłowe zarządzanie rejestrem TWSR mogą powodować problemy z komunikacją. Rekomendowano analizę gotowych przykładów kodu oraz dokładne studiowanie datasheetu Atmegi. Dyskusja zawiera także wyjaśnienia dotyczące działania bitów kontrolnych TWCR, w tym TWSTA i TWSTO, oraz ich wpływu na generowanie sygnałów start i stop na magistrali TWI. Ostatecznie problem został rozwiązany poprzez poprawne zrozumienie i implementację mechanizmu kasowania flagi TWINT oraz właściwej obsługi rejestrów TWI.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA