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

[AVR] TWI - dziwne zjawisko, kto potwierdzi lub zaprzeczy

mirekk36 04 Sie 2008 17:02 2093 13
  • #1 5407597
    mirekk36
    Poziom 42  
    Witam

    ja ponownie z TWI Slave. Już praktycznie mam to pięknie rozgryzione na ATmegach , ale zauważyłem pewną dziwną dla mnie rzecz bo chyba nie jest ona opisana w PDFkach. Chodzi mianowicie o to jak ATmega ustawiona na sprzętowe TWI Slave reaguje na próbę odczytu z niej danych przez Mastera w trybie REPEATED START

    otóż gdy robi się zwykły odczyt bez Repeated Start to w rejestrze statusu TWSR występują kolejno podczas przerwań statusy takie jak:

    &HA8
    &HB8
    &HC0

    gdy odczytujemy ze Slave 1 bajt, i rzeczywiście wystarczy w Masterze odczytać tylko 1 bajt aby go otrzymać

    ALE już gdy użyjemy RepeatedStart tzn najpierw coś zapiszemy do Slave a potem repeatedstart i od razu dokonujemy odczytu to !!!! mamy takie statusy:

    &H60
    &H80
    &HA0
    &HB8
    &HC0

    zauważcie, że zeżarło status &HA8 a w zamian za niego Slave emituje jako pierwszy bajt danych swój własny "adres" czyli Master musi odebrać w tym przypadku 2 bajty. Pierwszy to będzie ten nieszczęsny adres, który spędził mi wiele snu z powiek a dopiero drugi to będzie bajt z odesłaną przez Slave daną

    hmmm więc jak w temacie - czy może ktoś potwierdzić takie działanie ??? czy to tylko u mnie tak? czy może coś źle robię??? ... ale generalnie teraz jak już wykryłem że tak się dzieje - to transmisja w trybie Slave śmiga mi tak pięknie że aż strach :) .... i to napisana w Bascomie
  • #2 5407765
    zumek
    Poziom 39  
    mirekk36 napisał:
    ... a potem repeatedstart i od razu dokonujemy odczytu to !!!! mamy takie statusy:

    A po repeatedstart , DEVICE ADDRESS+R/W , to koza zjadła :?: :D

    Piotrek
  • #3 5407888
    mirekk36
    Poziom 42  
    nie, no oczywiście, że po RepStart daję jeszcze to o czym mówisz ale zastanowiło mnie to, dlaczego w odpowiedzi mam ten jeden dodatkowy bajt z adresem Slave na początku.

    a te stetusy, które pokazałem powyżej to bezpośrednio z przerwania TWI po odczytaniu i zamaskowaniu statusu wypuściłem sobie na RS232 PRINT. A tak wygląda moja sekwencja do Slave wysyłana z Mastera w odpowiedzi na którą dostaję ten jakby jeden dodatkowy bajt

    Cytat:
    I2cstart
    I2cwbyte &B10000000
    I2cwbyte 50
    I2cstart
    I2cwbyte &B10000001
    I2crbyte I2c_tx_buf(1) , Ack
    I2crbyte I2c_tx_buf(2) , Nack
    I2cstop

    i w tym przypadku jak powyżej w

    I2c_tx_buf(1) - dostaję ten zwrócony adres Slave

    a w

    I2c_tx_buf(2) - jakąś tam daną, którą wysyła do mnie Slave
  • #4 5407950
    Dr.Vee
    VIP Zasłużony dla elektroda
    Witam,

    A próbowałeś zamiast repeated start zrobić zwykły STOP, START?

    Zobacz jeszcze (jeśli możesz) co za assemblera bascom generuje...

    Pozdrawiam,
    Dr.Vee
  • #5 5408072
    mirekk36
    Poziom 42  
    Dr.Vee -> hmm próbowałem zrobić zwykły STOP i START ale hmm musiałem pomiędzy nimi wstawiać sztucznie jakieś opóźnienie żeby to zadziałało. A jak już zadziałało to oczywiście wtedy nie przylatuje ten dodatkowy bajt....

    ... hmmm rzeczywiście dobrze byłoby zobaczyć jak to robi Bascom ten repeated start, ale nie wiem zabardzo gdzie podejrzeć to w asm. Bo z samego kodu binarnego ciężko coś wywnioskować
  • #6 5408164
    Dr.Vee
    VIP Zasłużony dla elektroda
    Witam,

    No jak nijak się nie da zmusić bascoma do wyplucia kodu w asemblerze, to możesz albo użyć disasemblera (jest kilka projektów w sieci), albo jakiegoś symulatora, który czyta kod wynikowy, a nie źródłowy.

    Pozdrawiam,
    Dr.Vee
  • #7 5408278
    zumek
    Poziom 39  
    Dr.Vee napisał:
    Witam,

    No jak nijak się nie da zmusić bascoma do wyplucia kodu w asemblerze, to możesz albo użyć disasemblera (jest kilka projektów w sieci), albo jakiegoś symulatora, który czyta kod wynikowy, a nie źródłowy.

    Pozdrawiam,
    Dr.Vee

    AVRStudio , to moim zdaniem najlepszy debugger/symulator kodu Bascoma , zarówno w wersji źródłowej(Basic) , jak i w kodzie wynikowym(assembler).
    I2crepstart , czy I2cstart , Bascom generuje identyczny kod , bo i dlaczego miałoby być inaczej.

    Piotrek
  • #8 5408400
    mirekk36
    Poziom 42  
    zumek -> no właśnie, więc skoro generuje taki sam kod dla jednego i drugiego przypadku - to czy wg ciebie to normalne, że Slave w postaci ATmegi w odpowiedzi podaje po repstarcie ten pierwszy dodatkowy bajt ze swoim adresem??? - tak się składa, że akurat ten tryb nie jest dokładnie rozpisany w notach pdf i dlatego tak mnie to nurtuje. Bo przecież gdy w podobny sposób odczytujemy z repstartem np czas z PCF8583 to w odpowiedzi dostajemy tylko bajty z danymi

    Dodano po 10 [minuty]:

    a przy okazji wczytałem HEXa wygenerowanego przez Bascoma do AVRStudio ;) i proszę - ładnie się zdeasemblowało bez żadnych zewnętrznych programów :)
  • #9 5408553
    zumek
    Poziom 39  
    mirekk36 napisał:
    zumek -> no właśnie, więc skoro generuje taki sam kod dla jednego i drugiego przypadku - to czy wg ciebie to normalne, że Slave w postaci ATmegi w odpowiedzi podaje po repstarcie ten pierwszy dodatkowy bajt ze swoim adresem??? -


    Mi tu wogóle coś nie pasuje , ponieważ:

    0x60 -SLA+W received, ACK returned
    0x80 - data received, ACK returned
    0xA0 - stop or repeated start condition received while selected
    powinien "nastąpić"
    0xA8 - SLA+R received, ACK returned
    a u Ciebie jest
    0xB8 - data transmitted, ACK received

    Trzeba by dokładniej przestudiować dokumentację i/lub Twój kod slave'a :P

    mirekk36 napisał:

    a przy okazji wczytałem HEXa wygenerowanego przez Bascoma do AVRStudio ;) i proszę - ładnie się zdeasemblowało bez żadnych zewnętrznych programów :)


    A czemu HEX-a , a nie OBJ :?:
  • #10 5408660
    Dr.Vee
    VIP Zasłużony dla elektroda
    Witam,

    Mirekk36 to właśnie napisał w pierwszym poście - "zeżarło status 0xa8" :)

    Ale zgadzam sie z Zumkiem, pokaż kod slave'a...

    Pozdrawiam,
    Dr.Vee
  • #11 5408809
    mirekk36
    Poziom 42  
    zumek -> masz rację, że jednak powinien wystąpić po repstracie ten status

    0xA8 - SLA+R received, ACK returned

    przed

    0xB8 - data transmitted, ACK received

    i chyba powoli dochodzę gdzie może u mnie leżeć babol,

    hmmm czy może być powodem to, że jeśli dokonuję dość długich procedur w obsłudze przerwania TWI to może się właśnie tak zdażyć, że jakby nakładają się na siebie 2 przerwania i to ze statusem &HA8 zostaje "zeżarte" ??? - i jak się okazuje wcale nie przylatuje dodatkowy bajt, tylko zamiast się wczytać coś ze Slave do pierwszego bajtu bufora odbiorczego w Masterze to nic się nie wczytuje a tam siedzi u mnie akurat adres slave, którego umieszczam tuż przed wysłaniem danych do Slave.

    otóż doszedłem już do takiej sytuacji, że gdy po statusie &HA0 czyli STOPie wykonuję w międzyczasie innych poleceń coś takiego jeszcze jak memcopy dla 8 bajtów lub jakąś pętlę dla 8 powtórzeń akurat u mnie to za każdym razem "zjada" mi właśnie ten status &HA8, ale gdy zamiast memcopy zrobię ręcznie

          Twi_tx_buf(1) = Cyfry(1)
          Twi_tx_buf(2) = Cyfry(2)
          Twi_tx_buf(3) = Cyfry(3)
          Twi_tx_buf(4) = Cyfry(4)
          Twi_tx_buf(5) = Cyfry(5)
          Twi_tx_buf(6) = Cyfry(6)
          Twi_tx_buf(7) = Cyfry(7)
          Twi_tx_buf(8) = Cyfry(8)


    to jednak pojawia się przerwanie ze statusem &HA8 i wtedy jest w porządku. Tylko że coraz bardziej muszę jakby wydłużyć obsługę w tym przerwaniu a to zjada mi sporo czasu tegoż przerwania.

    może powinno się to inaczej robić, może jakieś flagi sobie ustawiać i poza przerwaniem wykonać te czynności? tylko, że niektóre czynności polegają na tym, iż Master najpierw zapisuje do Slave jakieś polecenie zwykle 3-4 bajtowe potem repstart i wtedy chce coś odczytać ze Slave. Właśnie wpadłem na pomysł aby po odebraniu od Mastera danych - wczytać mu do bufora nadawczego to co ma pójść do mastera w zależności od polecenia. I to właśnie też robię po statusie STOP or RepStart tylko że jeszcze jedną swoją flagą działam tak aby ta moja obróbka komend z mastera działa się tylko po repstart a nie przypadkowo po stopie

    ... a gdybym to robił poza przerwaniem? na flagach jakichś? to czy bym i tak zdążył podłożyć do bufora nadawczego dane zanim nastąpiłoby ich odebranie? też może nie

    może całą obsługę przerwania TWI trzeba by było zrobić jako wstawkę asemblerową??? żeby to szybciej się odbywało?

    ....aaaa i przy okazji - wczytałem do AVRStudio - OBJ'ta - kurczę ale fajnie :)


    aha i przy okazji tak wygląda moje przerwanie TWI Slave (o ile komuś będzie chciało to się czytać)

    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    ''''''''''''                                       '''''''''''''''''''''''''
    ''''''''''''   Obsługa przerwania TWI (I2C SLAVE)  '''''''''''''''''''''''''
    ''''''''''''                                       '''''''''''''''''''''''''
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Twi_przerwanie:
    
       $asm
          'Twi_status = Twsr And &B11111000
          in   r16, twsr
          andi  r16, &b11111000
          sts   {Twi_status}, r16
       $end Asm
    
       Print "H" ; Hex(twi_status)
    
       If Twi_status = &H60 Then                                'SLA+W, ACK sended
    
          Twi_rx_cnt = 1                                      
          Twi_tx_cnt = 1
    
       Elseif Twi_status = &H80 Then                            'SLA+W data received, ACK sended
                                                              
          '---------------------------------------------------------------------------
             _can_read_rx_buf_flag = 1
    
             Twi_rx_buf(twi_rx_cnt) = Twdr                     
             If Twi_rx_cnt <= Twi_rx_buf_max Then Incr Twi_rx_cnt
    
          '---------------------------------------------------------------------------
    
       Elseif Twi_status = &HA0 Then                            'STOP or repeated START
          Set Twcr.twea
    
          If _can_read_rx_buf_flag = 1 Then
    
             If Twi_rx_buf(1) = _led Then
                Call Process_led
             Elseif Twi_rx_buf(1) = _lcd Then
                Call Process_lcd
             Elseif Twi_rx_buf(1) = _vga Then
                Call Process_vga
             End If
    
    
             _can_read_rx_buf_flag = 0
          End If
          Twi_tx_cnt = 1
    
       Elseif Twi_status = &HA8 Then                            'SLA+R, ACK sended
    
          Twdr = Twi_tx_buf(1)
          Twi_tx_cnt = 2
    
       Elseif Twi_status = &HB8 Then                            'SLA+R, ACK received
    
          Twdr = Twi_tx_buf(twi_tx_cnt)
          If Twi_tx_cnt < Twi_tx_buf_max Then Incr Twi_tx_cnt
    
    
       Elseif Twi_status = &HC0 Then                            'SLA+R,NACK received
          Twi_tx_cnt = 1
    
       Elseif Twi_status = &H00 Then                            'bus ERROR
          Set Twcr.twsto
    
       End If
    
       Twcr.twint = 1
    
    Return
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  • Pomocny post
    #12 5408844
    zumek
    Poziom 39  
    Podejrzewam , że TWI na masterze masz programowe i stąd te kłopoty.
    Przy sprzętowym TWI na masterze , transmisja nie nastąpi dopóty , dopóki slave nie jest gotowy na jej przyjęcie.

    Pomyśl nad tym.

    Piotrek
  • Pomocny post
    #13 5408852
    Dr.Vee
    VIP Zasłużony dla elektroda
    Witam,

    mirekk36 napisał:
    hmmm czy może być powodem to, że jeśli dokonuję dość długich procedur w obsłudze przerwania TWI to może się właśnie tak zdarzyć, że jakby nakładają się na siebie 2 przerwania i to ze statusem &HA8 zostaje "zeżarte" ???


    Tak to brzmi z tego co piszesz, ale z drugiej strony slave powinien "przetrzymać" SCL w stanie niskim tak długo, jak długo nie zresetujesz TWINT (a Ty robisz to na sam koniec przerwania) - wtedy master powinien czekać, aż slave zwolni magistralę. W ten sposób nie ma szans, żeby kolejne przerwanie "zaginęło", bo transmisja na magistrali zostaje zatrzymana.

    Zresztą przejmujesz się jakimś memcopy, a na początku przerwania robisz printa - to chyba trwa dłużej niż memcopy... :)

    mirekk36 napisał:
    i jak się okazuje wcale nie przylatuje dodatkowy bajt, tylko zamiast się wczytać coś ze Slave do pierwszego bajtu bufora odbiorczego w Masterze to nic się nie wczytuje a tam siedzi u mnie akurat adres slave, którego umieszczam tuż przed wysłaniem danych do Slave.


    Czyli jednak ... częściowo sam sobie odpowiedziałeś na pytanie z początku tematu :D

    mirekk36 napisał:

    ... a gdybym to robił poza przerwaniem? na flagach jakichś? to czy bym i tak zdążył podłożyć do bufora nadawczego dane zanim nastąpiłoby ich odebranie?


    Zależy, ile masz do zrobienia każdorazowo w pętli głównej programu - możesz nie zdążyć przetestować tych flag, a już przyjdzie Ci kolejne przerwanie od TWI :)

    Pozdrawiam,
    Dr.Vee
  • #14 5409049
    mirekk36
    Poziom 42  
    no właśnie koledzy - mi też się tak wydawało, że Master powinien grzecznie poczekać aż Slave zobi co ma zrobić i mu odeśle wszystko.

    zumek -> piszesz, że może w masterze używam być może programowego TWI ale aby się przed tym zabezpieczyć zrobiłem wg helpa bascoma tak:

    $lib "i2c_twi.lbx"
    Config Scl = Portc.0
    Config Sda = Portc.1
    I2cinit


    użycie tej biblioteki powinno niby spowodować, że Bascom ma działać już na sprzętowym TWI :(

    ... hmmm więc może na Masterze też zrobić własną osługę przerwania TWI dla wysyłania danych??

    Dr.Vee -> tego się też obawiam odnośnie użycia tych flag, że zanim obsłużę daną flagę to już następne przerwanie przyleci. A odnośnie tego PRINT'a w przerwaniu to o dziwo gdy on jest to nie ma takiego opóźnienia jak z głupim wydawałoby się memcopy czy jakąś prostą pętelką

    ..... aaa zumek , jeszcze jedno - czy można w Bascomie jakoś tak zadziałać, żeby zamiast wkopiowywać dane do tego mojego bufora nadawczego - to poprostu zmienić adres jego początku, który wskazywałby od razu na właściwe dane do wysłania???? (takie coś ala przekazanie wskaźnika jak w C)

    pozdrawiam

    ... dzięki za wszystkie sugestie jak dotąd - jeszcze z tym muszę powalczyć

    Dodano po 1 [godziny] 50 [minuty]:

    Panowie -> dokonałem pewnego testu, otóż wstawiłem w kodzie Slave takie obrzydliwe opóźnienie jak:

    cls
    lcd "CZEKAM SOBIE"
    wait 3


    i ciekawostka - na procku Slave ładnie wyświetla się ten napis i procek wisi na tym wait 3 - natomiast Master TWI grzecznie czeka na dane!! ... w Slave kończy wię wait 3 i transmisja leci dalej i do Mastera dolatują dane - oczywiście nadal pomijany jest ten status &HA8 (a procedura, która trwa jak widać z kodu powyżej odpala się w przerwaniu przy statusie &HA0 RepStart

    NO I UDAŁO mi się polepszyć, otóż aby "przytrzymać" Mastera tak aby chciał grzecznie czekać to można mu takie sztuczne "WaitState'y" robić ale gdy leci już co najmniej status &HA8 właśnie ! .... albo najspokojniej w świecie wstawiać nawet opóźnienia typu wait 3 ale przy statusach &HB8 - wtedy Master ładnie czeka.

    tylko, że przy &HA8 jak sprawdziłem doświadczalnie to oczekiwanie nie może się przedłużyć do ok ponad 200ms bo wtedy nadal Master pomija odebranie pierwszego bajtu. Jednak czas nawet 100ms przy statusie &HA8 to "cała wieczność" :)

    tzn tak to narazie wygląda wg moich doświadczeń empirycznych o ile coś nie poknociłem

    ale dziękuję za b.cenne uwagi kolegom - może jeszcze coś się nasunie komuś - jak to bardziej zoptymalizować ?

    działam dalej i jak uzyskam ew już w 100% satysfakcjonujące mnie wyniki to dam znać, albo jeszcze o coś dopytam
REKLAMA