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

Jak przenieść kod obsługi LPS25H z Atmega328 na Xmega128A3?

dawid.barracuda 31 Paź 2016 12:00 1020 9
  • #1 16029887
    dawid.barracuda
    Poziom 13  
    Szanowni Forumowicze,
    mam problem z przeniesieniem pewnego kodu napisanego pod atmegę328 na xmegę128A3. Chodzi tutaj o obsługę czujnika LSP25H, magistrala I2C.
    Oto kod pod atmegę328:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Chcę przeportować tylko obsługę czujnika, strumienie 'stdout' nie są mi potrzebne gdyż wynik pomiaru przesyłam sobie za pomocą nrf24l01 do centrali i potem do komputera. Oto, co napisałem i nie działa:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Wydaje mi się, że źle mam przepisany fragment pt.: "odczekanie na zakończenie pomiaru", ale nie mam pomysłu jak inaczej to zrobić. W załączniku przesyłam DS czujnika oraz bibliotekę do obslugi I2C (to biblioteka atmela bez żadnych zmian z mojej strony).
    Proszę uprzejmie o wskazówki i podrawiam.
  • #2 16031128
    dawid.barracuda
    Poziom 13  
    Dodam, że komunikacja z czujnikiem jest, tyle że odbieram kompletne głupoty. Wydaje mi się, że problem leży w tym fragmencie (i również w tej funkcji):
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    gdyż nie wiem jak to poprawnie przepisać używając atmelowskiej biblioteki.
  • Pomocny post
    #3 16031237
    grko
    Poziom 33  
    Mógłbyś sformatować ten kod? Bo średnio się to czyta. Poza tym nie wiadomo co jest w sendBufferLPS (to co jest zakomentowane?)
  • #4 16031284
    dawid.barracuda
    Poziom 13  
    Sformatowałem ten pierwszy listing.
    Tak, senBufferLPS to jest to co zakomentowane, dodałem sobie tak, żeby nie przewijać ciągle na górę. Mam dużo kodu, więc tak wygodniej.
    Biblioteka atmela wysyła rozkazy z bufora, stąd ta tablica.

    Dodano po 29 [minuty]:

    Tak wg DS czujnika powinna wyglądać ramka:
    Jak przenieść kod obsługi LPS25H z Atmega328 na Xmega128A3?

    A tak wg DS jest opisana transmisja:
    Cytat:
    I²C operation
    The transaction on the bus is started through a START (ST) signal. A start condition is
    defined as a HIGH to LOW transition on the data line while the SCL line is held HIGH. After
    this has been transmitted by the master, the bus is considered busy. The next data byte
    transmitted after the start condition contains the address of the slave in the first 7 bits and
    the eighth bit tells whether the master is receiving data from the slave or transmitting data to
    the slave. When an address is sent, each device in the system compares the first seven bits
    after a start condition with its address. If they match, the device considers itself addressed
    by the master.
    The slave address (SAD) associated to the LPS25H is 101110xb. The SDO/SA0 pad can be
    used to modify the less significant bit of the device address. If the SA0 pad is connected to
    voltage supply, LSb is ‘1’ (address 1011101b), otherwise if the SA0 pad is connected to
    ground, the LSb value is ‘0’ (address 1011100b). This solution permits to connect and
    address two different LPS25H devices to the same I²C lines.
    Data transfer with acknowledge is mandatory. The transmitter must release the SDA line
    during the acknowledge pulse. The receiver must then pull the data line LOW so that it
    remains stable low during the HIGH period of the acknowledge clock pulse. A receiver
    which has been addressed is obliged to generate an acknowledge after each byte of data
    received.
    The I²C embedded in the LPS25H behaves like a slave device and the following protocol
    must be adhered to. After the start condition (ST) a slave address is sent, once a slave
    acknowledge (SAK) has been returned, a 8-bit sub-address (SUB) will be transmitted: the 7
    LSB represents the actual register address while the MSB enables address auto increment.
    If the MSb of the SUB field is ‘1’, the SUB (register address) will be automatically increased
    to allow multiple data read/write.
    The slave address is completed with a Read/Write bit. If the bit was ‘1’ (Read), a repeated
    START (SR) condition must be issued after the two sub-address bytes; if the bit is ‘0’ (Write)
    the master will transmit to the slave with direction unchanged. Table 10 explains how the
    SAD+read/write bit pattern is composed, listing all the possible configurations.


    Dużo się zmieniło w rejestrach w stosunku do atmeg i mam przez to trochę problem z ogarnięciem I2C. Za pomocą biblioteki działa bez problemu, ale mam problem obsłużyć to ręcznie za pomocą rejestrów tj. w starych atmegach. Tam było to jakoś bardziej intuicyjne, dlatego proszę i pomoc bardziej doświadczonych Forumowiczów.

    Odnośnie samego czujnika to nie wiem w jaki sposób mam odczekać na zakończenie pomiaru.




    Spróbowałem jeszcze w taki sposób:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Spróbowałem tutaj odczytać bit P_DA rejestru STATUS_REG, gdyż wg noty ustawia się na 1 gdy jest dostępne zmierzone ciśnienie, ale wynikiem są same zera. Kończą mi się pomysły jak się za to zabrać.
  • Pomocny post
    #5 16031609
    grko
    Poziom 33  
    To może zacznij od wyszukania analogii w swoim kodzie. Na pierwszy rzut oka ciągle powtarza się zapis/odczyt rejestru układu. Wydziel to do oddzielnej funkcji. Co chwilę odmierzasz timeout transferu TWI. To również można wydzielić do tych funkcji. Na chwilę obecną trudno zrozumieć flow Twojego programu bo co chwilę powtarza się sekwencja zapisu/odczytu z różnego offsetu tablicy globalnej. Nie jest to dobry pomysł. Ponadto z jakiegoś dziwnego powodu zmienna do odmierzania timeoutu TWI nazywa się spiTimeout. Ustawiasz ją na wartość z kosmosu. Musiałaby być 64bitowa aby mogła być ustawiona na taką wartość jaką tam chcesz. Nawet jakby była 64 bitowa to wątpię abyś się kiedykolwiek doczekał na ten timeout w programie.

    Napisz takie oto funkcje:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Uprościsz w ten sposób kod pętli głównej. Testowanie rozpocznij od odczytania i weryfikacji ID układu.
  • #6 16031619
    dawid.barracuda
    Poziom 13  
    Z tym spiTimeout to jakiś zamyślony musiałem być jak to pisałem, oczywiście ma być i2cTimeout.

    Zanim jeszcze przejdę do pisania funkcji, nie rozumiem tego fragmentu:

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


    i tej funkcji:

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


    Tam jest komentarz "wait till done", czyli jak na moje "czekaj aż będzie skończone". W funkcji mam zapisanie rejestru podanego jako argument, a następnie odczytanie danej, z tym, że nie mam pojęcia co to za dana. Kręci się to w while'u tak długo, aż ta dana będzie zerem. Kompletnie nie rozumiem o co tu chodzi.

    Kod, który został napisany na Atmegę328 to ten z pierwszego listingu z pierwszego postu. Ja chcę osiągnąć to samo na XMEGA128A3 i wszelkie nowe kody jakie piszę i wysyłam są właśnie pisane na Xmegę.
  • Pomocny post
    #7 16031628
    grko
    Poziom 33  
    W dokumentacji masz napisane:
    Cytat:

    Once the measurement is done, ONE_SHOT bit will self-clear and the new
    data are available in the output registers, and the STATUS_REG bits are updated.


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


    Jest uzasadniony.

    Czego dokładnie nie rozumiesz w funkcji I2C_ReadRegister? Realizuje ona po prostu sekwencję odczytu. To co Ty próbujesz zrobić tylko wydzielone do osobnej funkcji.
  • #8 16031639
    dawid.barracuda
    Poziom 13  
    Kod, który został napisany na Atmegę328 to ten z pierwszego listingu z pierwszego postu. Ja chcę osiągnąć to samo na XMEGA128A3 i wszelkie nowe kody jakie piszę i wysyłam są właśnie pisane na Xmegę.
    W poprzednim swoim poście przytoczyłem fragment kodu na atmegę, gdyż go nie rozumiem, a muszę zrozumieć wszystko żeby przepisać na xmegę.

    No i zgadza się, i2cTimeout jest zmienną 64-bitową. Ustawiłem to na wypadek jakby czujnik został odłączony, a program chodził dalej.

    Dodano po 23 [minuty]:

    grko napisał:
    W dokumentacji masz napisane:
    Cytat:

    Once the measurement is done, ONE_SHOT bit will self-clear and the new
    data are available in the output registers, and the STATUS_REG bits are updated.



    Niech to, przeoczyłem zupełnie tę informację. Nie zauważyłem.
    Czyli po wykonanym pomiarze będę miał ten rejestr równy 0, tak? Jeśli tak, to rozumiem już czemu jest taki while.

    Z drugiej jednak strony próbowałem się dostać do informacji o zakończeniu pomiaru przez rejestr STATUS_REG, a w nim konkretnie przez bit P_DA. Czy to był dobry trop?

    w funkcji ReadRegister mam ReadNACK, ponieważ czytam tylko jeden bajt?
  • #9 16031693
    grko
    Poziom 33  
    Cytat:

    No i zgadza się, i2cTimeout jest zmienną 64-bitową. Ustawiłem to na wypadek jakby czujnik został odłączony, a program chodził dalej.

    Przy tego typu wartościach będziesz oczekiwał na timeout tydzień albo nawet dłużej. To może pomogę Ci z funkcją odczytu rejestru (wielu rejestrów).

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


    Timeout dałem na jedną sekundę. Może niezbyt to eleganckie ale na pierwszą iterację wystarczy.

    Teraz używasz tego tak:

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



    Cytat:

    w funkcji ReadRegister mam ReadNACK, ponieważ czytam tylko jeden bajt?


    Tak.
  • #10 16032246
    dawid.barracuda
    Poziom 13  
    Funkcja działa, ładnie odbiera adres czujnika.
    Analogicznie napisałem funkcję lps25h_reg_write:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Czy z punktu widzenia sztuki zabieg z utworzeniem bufora w postaci tablicy z przekazanych do funkcji argumentów jest poprawny?

    Dodano po 2 [godziny]:

    Napisałem również funkcję do odczytu ciśnienia, ale tu już coś nie działa. Oto funkcja:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    A w użyciu całość wygląda tak:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    tempBuffer to tylko nazwa robocza bufora, który przechowuje dane z czujnika temperatury, odległości i (w zamyśle) ciśnienia. Całość pcham potem na nrf'a, a on do centrali i oglądam na PC. Zmiennych reg_check czy pressBuffer nie inicjalizuję zerami, gdyż nrf jak widzi zero to kończy transmisję, więc dałem inne niezerowe wartości.

    Coś jednak nie działa. Na końcu chcę nadpisać elementy 9, 10 11 tablicy tempBuffer, jednak widzę na terminalu, że cały czas siedzą tam wartości z kontrolnych sprawdzeń rejestrów, które są dokonywane na początku. Co robię nie tak?

    Dodano po 22 [minuty]:

    Odpowiedzią czujnika są same zera. Robię coś źle z przeniesieniem wartości z twiMaster.readData do bufora pressBuffer?

    Dodano po 11 [minuty]:

    Jeśli nie wywołam funkcji lps25h_ReadPressureRaw(); to mam normalnie przypisane w tempBuffer aktualne wartości rejestrów. Jak wywołam to funkcja zeruje mi elementy 9, 10, 11 tablicy tempBuffer. Co może być nie tak?

    Dodano po 28 [minuty]:

    Odczytałem wartości rejestrów z ciśnieniem nie stosując inkrementacji, tylko każdy z osobna:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    I co się okazuje? Że coś czyta. Mam wg czujnika 1008hPa. Serwis pogodowy pokazuje, ze powinno być 1019hPa. Mieszkam na 3p., nie wiem czy aż taka różnica jest normalna. Niepokoi mnie jednak dalej dlaczego nie działa ta automatyczna inkrementacja rejestrów przy odczytywaniu.

    Dodano po 3 [godziny] 15 [minuty]:

    Dopytam jeszcze - dlaczego przy takim timeoucie jaki ustawiłem tyle to będzie trwało? Sugerowałem się tym, że mając taktowanie 32MHz dość szybko zliczy mi do zera.
REKLAMA