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 działa funkcja I2C_SetBusSpeed w AVR? Wyjaśnienie przeliczeń i rejestrów

squelch 02 Sie 2017 11:53 1593 6
REKLAMA
  • #1 16621245
    squelch
    Poziom 11  
    Witam

    Mam kilka pytań związanych z I2C na które nie jestem sobie wstanie odpowiedzieć.
    1.
    Mam taką funkcę:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Nazwa wskazuje na to że ta funkcja ustawia prędkość, TWSR to rejestr gdzie znajdują się dwa bity TWPS1 i TWPS0 i one ustawiają preskaler a TWBR też służy do podziału.
    Zgodnie ze wzorem w pdf mamy:
    SCL frequency
    CPU Clock frequency/16 + 2(TWBR) ⋅ 4^TWPS
    jak działa ta funkcja i jak działa to przeliczenie
    speed=(F_CPU/speed/100-16)/2; //speed=TWBR*4^TWPS
    a i jescze dlaczego zamiast tego zapisu
    TWSR=(TWSR & (_BV(TWPS1)|_BV(TWPS0))) | prescaler;
    nie zapisać tego tak
    TWSR=prescaler;

    2.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Chodzi mi o tą linię dlaczego tam jest I2C_Error==I2C_NoACK przecież w pętli wywołujemy funkcję I2C_SendStartAndSelect a z wnętrza tej funkcji wywołujemy I2C_SendAddr i mamy w niej zapis if(TW_STATUS!=Status) I2C_SetError(I2C_NoACK); else I2C_SetError(I2C_OK); czyli jak jest wszystko ok to tej zmiennej globalnej przypisujemy I2C_OK.
    A i to jest pętla więc możemy wysłać kilka razy adres urządzenia chyba nie powinno być to w pętli tylko poza tak abyśmy tylko jeden raz wysłali adres a jak po takim czasie nie dostaniemy ACK od slave to wtedy ponawiamy, nie wiem czy zapis w pętli jest dobry bo my sznurkiem wysyłamy ten sam adres zamiast ustawić jakiś timeout.
    Czy nie powinno być tak:
    I2C_SendStartAndSelect(addr >> 16);
    while(!(I2C_Error==I2C_OK));
    3.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    W jednej czekamy na wysłanie stop a w drugiej nie dlaczego?
    4.

    No nieogarniam tych stron tam jest coś takigo że adres bajtu możliwego do zapisu jest wielokrokrotnością tej strony czyli jak mam np. strone 64 bajtową to mogę zapisać bajty pod takie adresy 0,64,128, o to z tym chodzi czy jak działają te strony pamięci w eeprom.

    Przepraszam za dużą ilość pytań, kody są z książki Tomasza Francuza. Nie twierdzę że są to błędy tylko pewnie wynika to z moich braków i luk w technikach programowania.

    Pozdrawiam
  • REKLAMA
  • #2 16621286
    czareqpl
    Poziom 33  
    4. Blokowy układ pamięci wynika z ograniczonej przestrzeni adresowej. Dany układ nie pozwala na adresowanie każdego bajtu z osobna więc stosuje się bloki np po 64 lub 128 bajtów.
    Zatem wybierając adres powiedzmy 32, zaglądasz do szufladki w pamięci do której możesz zapisać te 64 lub 128 bajtów. Adres 33 wskazuje na inną "pustą" szufladkę w której jest kolejny blok pamięci.
  • REKLAMA
  • #3 16621565
    squelch
    Poziom 11  
    a tak to działa ale dobra no to na pewno jest tak że jak pod danym adresem mogę zapisać 64 bajty to nie muszę wszystkich. Zapisuje powiedzmy 10 ba. a potem kolejna transmisja zapisuje też 10 bajtów czy jak wyślę kolejną transmisję to nie nadpisze mi tych które zapisałem wcześniej a jak tu odczytać np 5 ba. jaki wtedy adres.
  • REKLAMA
  • Pomocny post
    #4 16622090
    tmf
    VIP Zasłużony dla elektroda
    czareqpl napisał:
    4. Blokowy układ pamięci wynika z ograniczonej przestrzeni adresowej. Dany układ nie pozwala na adresowanie każdego bajtu z osobna więc stosuje się bloki np po 64 lub 128 bajtów.
    Zatem wybierając adres powiedzmy 32, zaglądasz do szufladki w pamięci do której możesz zapisać te 64 lub 128 bajtów. Adres 33 wskazuje na inną "pustą" szufladkę w której jest kolejny blok pamięci.


    Kolega niech najpierw poczyta o zasadzie działania pamięci EEPROM I2C. Pamięci I2C umożliwiają adresację pojedynczych komórek, przy czym czas zapisu w trybie bajtowym jest równy liczbie zapisywnaych bajtów razy czas zapisu pojedynczego bajtu.W trybie zapisu blokowego, dane najpierw zapisywane są do wewnętrznego bufora RAM znajdującego się w pamięci I2C (wielkość bufora jest różna i powiązana z pojemnością pamięci - zwykle 16-128 bajtów), zawartość bufora jest przepisywana do EEPROM w momencie wysłania stanu STOP.

    Dodano po 4 [minuty]:

    squelch napisał:
    a tak to działa ale dobra no to na pewno jest tak że jak pod danym adresem mogę zapisać 64 bajty to nie muszę wszystkich. Zapisuje powiedzmy 10 ba. a potem kolejna transmisja zapisuje też 10 bajtów czy jak wyślę kolejną transmisję to nie nadpisze mi tych które zapisałem wcześniej a jak tu odczytać np 5 ba. jaki wtedy adres.


    Poczytaj noty katalogowe stosowanych układów, tam masz wszystko wyjaśnione. W trybie blokowym zapisujesz do wewnętrznego bufora. Jeśl liczba zapisywanych bajtów przekroczy pojemność bufora, to dojdzie do zawinięcia licznika i nadpisania poprzednich danych. Dane nie są fizycznie zapisane do EEPROM, zapis odbywa się po wysłaniu stanu STOP. Ponieważ zapis do EEPROM jest czasochłonny, dostęp do ukłądu możliwy jest dopiero po jego zakończeniu. Do czasu zakończenia zapisu urządzenie nie wysyła ACK, co umożliwia stwierdzenie czy zapis się zakończył, czy nie.Co przy okazji jest odpowiedzią na kolejne twoje pytanie, dlaczego po zapisie czekamy. Odczyt nie blokuje urządzenia, więc po STOP urządzenie natychmiast jest gotowe do przyjęcia kolejnych poleceń.

    Dodano po 2 [minuty]:

    squelch napisał:

    Nazwa wskazuje na to że ta funkcja ustawia prędkość, TWSR to rejestr gdzie znajdują się dwa bity TWPS1 i TWPS0 i one ustawiają preskaler a TWBR też służy do podziału.
    Zgodnie ze wzorem w pdf mamy:
    SCL frequency
    CPU Clock frequency/16 + 2(TWBR) ⋅ 4^TWPS
    jak działa ta funkcja i jak działa to przeliczenie
    speed=(F_CPU/speed/100-16)/2; //speed=TWBR*4^TWPS
    a i jescze dlaczego zamiast tego zapisu
    TWSR=(TWSR & (_BV(TWPS1)|_BV(TWPS0))) | prescaler;
    nie zapisać tego tak
    TWSR=prescaler;


    Nie można tego tak zapisać, bo bity TWPS muszą mięć wartość 0, w przeciwnym przypadku operacja sumy logicznej nie da zbyt ciekawych wyników...

    Dodano po 2 [minuty]:

    squelch napisał:

    Czy nie powinno być tak:
    I2C_SendStartAndSelect(addr >> 16);
    while(!(I2C_Error==I2C_OK));


    Nie powinno być tak. I2C_Error to w tej pętli zmienią krasnoludki? Po twoich zmoanach efekt będzie taki, że pętla ablo się nie wykona wcale, albo będzie się pętlić w nieskończoność jeśli I2C_SendStartAndSelect zwróci coś innego niż I2C_OK.
  • REKLAMA
  • #5 16625024
    squelch
    Poziom 11  
    tmf napisał:

    Nie powinno być tak. I2C_Error to w tej pętli zmienią krasnoludki? Po twoich zmoanach efekt będzie taki, że pętla ablo się nie wykona wcale, albo będzie się pętlić w nieskończoność jeśli I2C_SendStartAndSelect zwróci coś innego niż I2C_OK.

    A okej teraz dotarło chodzi o to że jak nie dostaniemy ACK to znowu wysyłamy i tak do skutku.

    Dzięki za odpowiedz i poświecony czas na jej napisanie.

    Dodano po 5 [minuty]:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    a to może można by było dodać te pętelki w po wysłaniu adresu spod którego chcemy czytać lub pod który zapisywać wtedy zapewniło by to jeszcze lepszą pewność?
  • Pomocny post
    #6 16625125
    tmf
    VIP Zasłużony dla elektroda
    Nie. Dostęp do pamięci wymaga wybrania jej, wysłania odpowiedniego polecenia i adresu. Pamięć przyjęcie polecenia potwierdza ACKiem, i dopiero wtedy możesz uzyskać dostęp do komórek, których adres podałeś. Jeśli po SendStartAndSelect nie masz ACKa, to reszta poleceń nie zadziała, co gorsze, te kolejne bajty mogą zostać nieprawidłowo zinterpretowane jako polecenie. Stąd też lepiej robić to sekwencyjnie - wysyłasz polecenie, czekasz na potwierdzenie, jeśli nie ma go to wysyłasz ponownie (oczywiście dobrze byłoby dodać jakiś warunek kończący pętlę, jesli ileś prób się nie powiedzie) i dopiero po tym przesłać adres i resztę danych.
  • #7 16625192
    squelch
    Poziom 11  
    Szczerze powiedziawszy to nie rozumiem dlaczego by nie dalo rady. Kiedy wysylam bajty do slave to slave przesyla mi ack, to ja tylko sprawdzam czy ack nadleciało jeśli nadleciało to to znaczy że ok i puszczam program,jeśli nie to retransmituje.

    Dodano po 11 [minuty]:

    tmf napisał:

    Co przy okazji jest odpowiedzią na kolejne twoje pytanie, dlaczego po zapisie czekamy. Odczyt nie blokuje urządzenia, więc po STOP urządzenie natychmiast jest gotowe do przyjęcia kolejnych poleceń.


    bo ja zawsze myślalem ze jak ten bit co jest odpowiedzialny za generowanie stop bedzie wyzerowany to modul po prostu wygenerował ten sygnal i moze teraz przyjac nasze kolejne polecenie a tu sie okazuje jezeli dobrze zeozumialem ze bedzie wyzerowany jezeli slave odpowiada na ack tak?
REKLAMA